}
}
-static char* string_to_json_field_name(const char *f) {
+char* table_mangle_to_json_field_name(const char *str) {
/* Tries to make a string more suitable as JSON field name. There are no strict rules defined what a
- * field name can be hence this is a bit vague and black magic. Right now we only convert spaces to
- * underscores and leave everything as is. */
+ * field name can be hence this is a bit vague and black magic. Here's what we do:
+ * - Convert spaces to underscores
+ * - Convert dashes to underscores (some JSON parsers don't like dealing with dashes)
+ * - Convert most other symbols to underscores (for similar reasons)
+ * - Make the first letter of each word lowercase (unless it looks like the whole word is uppercase)
+ */
- char *c = strdup(f);
+ bool new_word = true;
+ char *c;
+
+ assert(str);
+
+ c = strdup(str);
if (!c)
return NULL;
- for (char *x = c; *x; x++)
- if (isspace(*x))
+ for (char *x = c; *x; x++) {
+ if (!strchr(ALPHANUMERICAL, *x)) {
*x = '_';
+ new_word = true;
+ continue;
+ }
+
+ if (new_word) {
+ if (ascii_tolower(*(x + 1)) == *(x + 1)) /* Heuristic: if next char is upper-case
+ * then we assume the whole word is all-caps
+ * and avoid lowercasing it. */
+ *x = ascii_tolower(*x);
+ new_word = false;
+ }
+ }
return c;
}
return -ENOMEM;
}
- mangled = string_to_json_field_name(n);
+ mangled = table_mangle_to_json_field_name(n);
if (!mangled)
return -ENOMEM;
int table_print_with_pager(Table *t, sd_json_format_flags_t json_format_flags, PagerFlags pager_flags, bool show_header);
+char* table_mangle_to_json_field_name(const char *str);
int table_set_json_field_name(Table *t, size_t idx, const char *name);
#define table_log_add_error(r) \
assert_se(sd_json_variant_equal(v, w));
}
+TEST(json_mangling) {
+ static const struct {
+ const char *arg;
+ const char *exp;
+ } cases[] = {
+ /* Not Mangled */
+ { "foo", "foo" },
+ { "foo_bar", "foo_bar" },
+ { "fooBar", "fooBar" },
+ { "fooBar123", "fooBar123" },
+ { "foo_bar123", "foo_bar123" },
+ { ALPHANUMERICAL, ALPHANUMERICAL },
+ { "_123", "_123" },
+
+ /* Mangled */
+ { "Foo Bar", "foo_bar" },
+ { "Foo-Bar", "foo_bar" },
+ { "Foo@Bar", "foo_bar" },
+ { "Foo (Bar)", "foo__bar_"},
+ { "MixedCase ALLCAPS", "mixedCase_ALLCAPS" },
+ { "_X", "_x" },
+ { "_Foo", "_foo" },
+ };
+
+ FOREACH_ELEMENT(i, cases) {
+ _cleanup_free_ char *ret = NULL;
+ assert_se(ret = table_mangle_to_json_field_name(i->arg));
+ printf("\"%s\" -> \"%s\"\n", i->arg, ret);
+ assert_se(streq(ret, i->exp));
+ }
+}
+
TEST(table) {
_cleanup_(table_unrefp) Table *t = NULL;
_cleanup_free_ char *formatted = NULL;