summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--ast.c25
-rw-r--r--ast.h2
-rw-r--r--lib.c16
4 files changed, 37 insertions, 10 deletions
diff --git a/README.md b/README.md
index 74ea217..07b384f 100644
--- a/README.md
+++ b/README.md
@@ -873,6 +873,9 @@ Utpl supports a restricted subset of the formats allowed by the underlying
libc's `printf()` implementation, namely it allows the `d`, `i`, `o`, `u`, `x`,
`X`, `e`, `E`, `f`, `F`, `g`, `G`, `c` and `s` conversions.
+Additionally, an utpl specific `J` format is implemented, which causes the
+corresponding value to be formatted as JSON string.
+
Other format specifiers such as `n` or `z` are not accepted and returned
verbatim. Format specifiers including `*` and `$` directives are rejected as
well.
@@ -883,6 +886,7 @@ well.
printf("%08x\n", 123); // 0000007b
printf("%c%c%c\n", 65, 98, 99); // Abc
printf("%g\n", 10 / 3.0); // 3.33333
+ printf("%J", [1,2,3]); // [ 1, 2, 3 ]
%}
```
diff --git a/ast.c b/ast.c
index 4e6ea9b..8efc370 100644
--- a/ast.c
+++ b/ast.c
@@ -125,16 +125,17 @@ ut_append_op(struct ut_state *s, uint32_t a, uint32_t b)
static int
double_rounded_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
{
+ bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT);
double d = json_object_get_double(v);
if (isnan(d))
- return sprintbuf(pb, level ? "\"NaN\"" : "NaN");
+ return sprintbuf(pb, strict ? "\"NaN\"" : "NaN");
if (d == INFINITY)
- return sprintbuf(pb, level ? "1e309" : "Infinity");
+ return sprintbuf(pb, strict ? "1e309" : "Infinity");
if (d == -INFINITY)
- return sprintbuf(pb, level ? "-1e309" : "-Infinity");
+ return sprintbuf(pb, strict ? "-1e309" : "-Infinity");
return sprintbuf(pb, "%g", d);
}
@@ -211,17 +212,18 @@ re_free(struct json_object *v, void *ud)
static int
re_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
{
+ bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT);
struct ut_op *op = json_object_get_userdata(v);
struct json_object *s;
const char *p;
size_t len;
- sprintbuf(pb, "%s/", level ? "\"" : "");
+ sprintbuf(pb, "%s/", strict ? "\"" : "");
s = json_object_new_string((char *)op + sizeof(*op) + sizeof(regex_t));
if (s) {
- if (level) {
+ if (strict) {
for (p = json_object_to_json_string(s) + 1, len = strlen(p) - 1; len > 0; len--, p++)
sprintbuf(pb, "%c", *p);
}
@@ -239,7 +241,7 @@ re_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
op->is_reg_global ? "g" : "",
op->is_reg_icase ? "i" : "",
op->is_reg_newline ? "s" : "",
- level ? "\"" : "");
+ strict ? "\"" : "");
}
struct json_object *
@@ -300,6 +302,7 @@ ut_new_regexp(const char *source, bool icase, bool newline, bool global, char **
static int
func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
{
+ bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT);
struct ut_op *op = json_object_get_userdata(v);
struct ut_op *base, *decl, *name, *args, *arg;
@@ -314,7 +317,7 @@ func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
args = base + (decl->tree.operand[1] ? decl->tree.operand[1] - 1 : 0);
sprintbuf(pb, "%sfunction%s%s(",
- level ? "\"" : "",
+ strict ? "\"" : "",
(name != base) ? " " : "",
(name != base) ? json_object_get_string(name->val) : "");
@@ -323,7 +326,7 @@ func_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
(arg != args) ? ", " : "",
json_object_get_string(arg->val));
- return sprintbuf(pb, ") { ... }%s", level ? "\"" : "");
+ return sprintbuf(pb, ") { ... }%s", strict ? "\"" : "");
}
struct json_object *
@@ -466,6 +469,7 @@ ut_register_extended_type(const char *name, struct json_object *proto, void (*fr
static int
ut_extended_type_to_string(struct json_object *v, struct printbuf *pb, int level, int flags)
{
+ bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT);
struct ut_op *op = json_object_get_userdata(v);
struct ut_extended_type *et;
@@ -474,7 +478,10 @@ ut_extended_type_to_string(struct json_object *v, struct printbuf *pb, int level
et = &ut_ext_types[op->tag.type - 1];
- return sprintbuf(pb, "%s<%s %p>%s", level ? "\"" : "", et->name, op->tag.data, level ? "\"" : "");
+ return sprintbuf(pb, "%s<%s %p>%s",
+ strict ? "\"" : "",
+ et->name, op->tag.data,
+ strict ? "\"" : "");
}
static void
diff --git a/ast.h b/ast.h
index c6d5aeb..92e021e 100644
--- a/ast.h
+++ b/ast.h
@@ -27,6 +27,8 @@
#include <json-c/json.h>
#endif
+#define JSON_C_TO_STRING_STRICT (1<<31)
+
#define UT_ERRMSG_OOM "Runtime error: Memory allocation failure"
enum ut_error_type {
diff --git a/lib.c b/lib.c
index 5a17d52..4b1d391 100644
--- a/lib.c
+++ b/lib.c
@@ -1451,6 +1451,20 @@ ut_printf_common(struct ut_state *s, uint32_t off, struct json_object *args, cha
break;
+ case 'J':
+ t = json_type_string;
+
+ if (argidx < arglen)
+ arg.s = json_object_to_json_string_ext(
+ json_object_array_get_idx(args, argidx++),
+ JSON_C_TO_STRING_SPACED|JSON_C_TO_STRING_NOSLASHESCAPE|JSON_C_TO_STRING_STRICT);
+ else
+ arg.s = NULL;
+
+ arg.s = arg.s ? arg.s : "null";
+
+ break;
+
case '%':
t = json_type_null;
@@ -1463,7 +1477,7 @@ ut_printf_common(struct ut_state *s, uint32_t off, struct json_object *args, cha
if (fp + 2 >= sfmt + sizeof(sfmt))
goto next;
- *fp++ = *p;
+ *fp++ = (t == json_type_string) ? 's' : *p;
*fp = 0;
switch (t) {