properties: add color support for dumping properties

This commit is contained in:
Wim Taymans 2023-04-20 10:02:08 +02:00
parent dd21ebf6b8
commit 2d388c6908
3 changed files with 80 additions and 44 deletions

View file

@ -4,6 +4,8 @@
#include <stdio.h>
#include <stdarg.h>
#include <spa/utils/ansi.h>
#include <spa/utils/json.h>
#include <spa/utils/string.h>
@ -640,10 +642,27 @@ const char *pw_properties_iterate(const struct pw_properties *properties, void *
return pw_array_get_unchecked(&impl->items, index, struct spa_dict_item)->key;
}
static int encode_string(FILE *f, const char *val, int size)
#define NORMAL(c) ((c)->colors ? SPA_ANSI_RESET : "")
#define LITERAL(c) ((c)->colors ? SPA_ANSI_BRIGHT_MAGENTA : "")
#define NUMBER(c) ((c)->colors ? SPA_ANSI_BRIGHT_CYAN : "")
#define STRING(c) ((c)->colors ? SPA_ANSI_BRIGHT_GREEN : "")
#define KEY(c) ((c)->colors ? SPA_ANSI_BRIGHT_BLUE : "")
#define CONTAINER(c) ((c)->colors ? SPA_ANSI_BRIGHT_YELLOW : "")
struct dump_config {
FILE *file;
int indent;
const char *sep;
bool colors;
bool recurse;
};
static int encode_string(struct dump_config *c, const char *before,
const char *val, int size, const char *after)
{
FILE *f = c->file;
int i, len = 0;
len += fprintf(f, "\"");
len += fprintf(f, "%s\"", before);
for (i = 0; i < size; i++) {
char v = val[i];
switch (v) {
@ -673,16 +692,10 @@ static int encode_string(FILE *f, const char *val, int size)
break;
}
}
len += fprintf(f, "\"");
len += fprintf(f, "\"%s", after);
return len-1;
}
struct dump_config {
FILE *file;
int indent;
const char *sep;
};
static int dump(struct dump_config *c, int indent, struct spa_json *it, const char *value, int len)
{
FILE *file = c->file;
@ -690,8 +703,11 @@ static int dump(struct dump_config *c, int indent, struct spa_json *it, const ch
int count = 0;
char key[1024];
if (value == NULL) {
fprintf(file, "null");
if (value == NULL || len == 0) {
fprintf(file, "%snull%s", LITERAL(c), NORMAL(c));
} else if (spa_json_is_container(value, len) && !c->recurse) {
len = spa_json_container_len(it, value, len);
fprintf(file, "%s%.*s%s", CONTAINER(c), len, value, NORMAL(c));
} else if (spa_json_is_array(value, len)) {
fprintf(file, "[");
spa_json_enter(it, &sub);
@ -712,7 +728,7 @@ static int dump(struct dump_config *c, int indent, struct spa_json *it, const ch
fprintf(file, "%s%s%*s",
count++ > 0 ? "," : "",
c->sep, indent, "");
encode_string(file, key, strlen(key));
encode_string(c, KEY(c), key, strlen(key), NORMAL(c));
fprintf(file, ": ");
if ((len = spa_json_next(&sub, &value)) <= 0)
break;
@ -721,19 +737,20 @@ static int dump(struct dump_config *c, int indent, struct spa_json *it, const ch
indent -= c->indent;
fprintf(file, "%s%*s}", count > 0 ? c->sep : "",
count > 0 ? indent : 0, "");
} else if (spa_json_is_string(value, len) ||
spa_json_is_null(value, len) ||
spa_json_is_bool(value, len) ||
spa_json_is_int(value, len) ||
} else if (spa_json_is_null(value, len) ||
spa_json_is_bool(value, len)) {
fprintf(file, "%s%.*s%s", LITERAL(c), len, value, NORMAL(c));
} else if (spa_json_is_int(value, len) ||
spa_json_is_float(value, len)) {
fprintf(file, "%.*s", len, value);
fprintf(file, "%s%.*s%s", NUMBER(c), len, value, NORMAL(c));
} else if (spa_json_is_string(value, len)) {
fprintf(file, "%s%.*s%s", STRING(c), len, value, NORMAL(c));
} else {
encode_string(file, value, len);
encode_string(c, STRING(c), value, len, NORMAL(c));
}
return 0;
}
SPA_EXPORT
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags)
{
@ -742,8 +759,10 @@ int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t
struct dump_config cfg = {
.file = f,
.indent = flags & PW_PROPERTIES_FLAG_NL ? 2 : 0,
.sep = flags & PW_PROPERTIES_FLAG_NL ? "\n" : " "
};
.sep = flags & PW_PROPERTIES_FLAG_NL ? "\n" : " ",
.colors = SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_COLORS),
.recurse = SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_RECURSE),
}, *c = &cfg;
const char *enc = flags & PW_PROPERTIES_FLAG_ARRAY ? "[]" : "{}";
if (SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_ENCLOSE))
@ -751,37 +770,28 @@ int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t
spa_dict_for_each(it, dict) {
char key[1024];
int len = it->value ? strlen(it->value) : 0;
int len;
const char *value;
struct spa_json sub;
fprintf(f, "%s%s%*s", count == 0 ? "" : ",", cfg.sep, cfg.indent, "");
fprintf(f, "%s%s%*s", count == 0 ? "" : ",", c->sep, c->indent, "");
if (!(flags & PW_PROPERTIES_FLAG_ARRAY)) {
if (spa_json_encode_string(key, sizeof(key)-1, it->key) >= (int)sizeof(key)-1)
continue;
fprintf(f, "%s: ", key);
fprintf(f, "%s%s%s: ", KEY(c), key, NORMAL(c));
}
value = it->value;
if (it->value == NULL) {
fprintf(f, "null");
} else if (SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_RECURSE)) {
struct spa_json sub;
spa_json_init(&sub, it->value, len);
if ((len = spa_json_next(&sub, &value)) <= 0)
break;
dump(&cfg, cfg.indent, &sub, value, len);
} else if (spa_json_is_null(it->value, len) ||
spa_json_is_float(it->value, len) ||
spa_json_is_bool(it->value, len) ||
spa_json_is_container(it->value, len) ||
spa_json_is_string(it->value, len)) {
fprintf(f, "%s", it->value);
} else {
encode_string(f, it->value, len);
}
len = value ? strlen(value) : 0;
spa_json_init(&sub, value, len);
if ((len = spa_json_next(&sub, &value)) < 0)
break;
dump(c, c->indent, &sub, value, len);
count++;
}
if (SPA_FLAG_IS_SET(flags, PW_PROPERTIES_FLAG_ENCLOSE))
fprintf(f, "%s%c", cfg.sep, enc[1]);
fprintf(f, "%s%c", c->sep, enc[1]);
return count;
}

View file

@ -140,6 +140,7 @@ pw_properties_iterate(const struct pw_properties *properties, void **state);
#define PW_PROPERTIES_FLAG_RECURSE (1<<1)
#define PW_PROPERTIES_FLAG_ENCLOSE (1<<2)
#define PW_PROPERTIES_FLAG_ARRAY (1<<3)
#define PW_PROPERTIES_FLAG_COLORS (1<<4)
int pw_properties_serialize_dict(FILE *f, const struct spa_dict *dict, uint32_t flags);
static inline bool pw_properties_parse_bool(const char *value) {

View file

@ -23,6 +23,7 @@ struct data {
const char *opt_cmd;
bool opt_recurse;
bool opt_newline;
bool opt_colors;
struct pw_properties *conf;
struct pw_properties *assemble;
int count;
@ -35,6 +36,7 @@ static void print_all_properties(struct data *d, struct pw_properties *props)
&props->dict,
(d->opt_newline ? PW_PROPERTIES_FLAG_NL : 0) |
(d->opt_recurse ? PW_PROPERTIES_FLAG_RECURSE : 0) |
(d->opt_colors ? PW_PROPERTIES_FLAG_COLORS : 0) |
(d->array ? PW_PROPERTIES_FLAG_ARRAY : 0) |
PW_PROPERTIES_FLAG_ENCLOSE);
fprintf(stdout, "\n");
@ -124,7 +126,9 @@ static void show_help(const char *name, bool error)
" -n, --name Config Name (default '%2$s')\n"
" -p, --prefix Config Prefix (default '%3$s')\n"
" -L, --no-newline Omit newline after values\n"
" -r, --recurse Dump values recursively\n",
" -r, --recurse Dump values recursively\n"
" -N, --no-colors disable color output\n"
" -C, --color[=WHEN] whether to enable color support. WHEN is `never`, `always`, or `auto`\n",
name, DEFAULT_NAME, DEFAULT_PREFIX);
}
@ -140,6 +144,8 @@ int main(int argc, char *argv[])
{ "prefix", required_argument, NULL, 'p' },
{ "no-newline", no_argument, NULL, 'L' },
{ "recurse", no_argument, NULL, 'r' },
{ "no-colors", no_argument, NULL, 'N' },
{ "color", optional_argument, NULL, 'C' },
{ NULL, 0, NULL, 0}
};
@ -147,11 +153,13 @@ int main(int argc, char *argv[])
d.opt_prefix = NULL;
d.opt_recurse = false;
d.opt_newline = true;
if (isatty(fileno(stdout)) && getenv("NO_COLOR") == NULL)
d.opt_colors = true;
d.opt_cmd = "paths";
pw_init(&argc, &argv);
while ((c = getopt_long(argc, argv, "hVn:p:Lr", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "hVn:p:LrNC", long_options, NULL)) != -1) {
switch (c) {
case 'h':
show_help(argv[0], false);
@ -176,6 +184,23 @@ int main(int argc, char *argv[])
case 'r':
d.opt_recurse = true;
break;
case 'N' :
d.opt_colors = false;
break;
case 'C' :
if (optarg == NULL || !strcmp(optarg, "auto"))
break; /* nothing to do, tty detection was done
before parsing options */
else if (!strcmp(optarg, "never"))
d.opt_colors = false;
else if (!strcmp(optarg, "always"))
d.opt_colors = true;
else {
fprintf(stderr, "Unknown color: %s\n", optarg);
show_help(argv[0], true);
return -1;
}
break;
default:
show_help(argv[0], true);
return -1;