Envs are needed only for jshn_format(). But jshn anyway loads them even if jshn_parse() called. This makes JSON reading slower. The patch extract a new func load_vars_from_envs() that is called directly from jshn_format()
Signed-off-by: Sergey Ponomarev <stok...@gmail.com> --- jshn.c | 87 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/jshn.c b/jshn.c index 061fc7f..8fdd290 100644 --- a/jshn.c +++ b/jshn.c @@ -44,6 +44,8 @@ struct env_var { struct avl_node avl; char *val; }; +struct env_var *vars; +static void load_vars_from_envs(); static int add_json_object(json_object *obj) { @@ -286,6 +288,7 @@ static int jshn_format(bool no_newline, bool indent, FILE *stream) if (!(obj = json_object_new_object())) return -1; + load_vars_from_envs(); jshn_add_objects(obj, "J_V", false); if (!(output = json_object_to_json_string(obj))) goto out; @@ -303,6 +306,7 @@ static int jshn_format(bool no_newline, bool indent, FILE *stream) ret = 0; out: + free(vars); json_object_put(obj); return ret; } @@ -313,6 +317,12 @@ static int usage(const char *progname) return 2; } +/** + * Compare env vars by keys + * + * The key in AVL tree is the env itself with KEY=VALUE pair. + * So to compare we must compare until the '=' separator. + */ static int avl_strcmp_var(const void *k1, const void *k2, void *ptr) { const char *s1 = k1; @@ -334,6 +344,37 @@ static int avl_strcmp_var(const void *k1, const void *k2, void *ptr) return c1 - c2; } +/** + * JSON variables are passed via environment variables. + * But getenv() makes a linear search so for faster lookups we store envs into AVL tree. + * + * The function allocates `vars` variable and it should be freed afterwards. + */ +static void load_vars_from_envs() { + int i; + extern char **environ; + avl_init(&env_vars, avl_strcmp_var, false, NULL); + // count env vars + for (i = 0; environ[i]; i++); + + vars = calloc(i, sizeof(*vars)); + if (!vars) { + fprintf(stderr, "%m\n"); + exit(EXIT_FAILURE); + } + for (i = 0; environ[i]; i++) { + char *c; + // env var will be a key but we'll ignore it's value part in avl_strcmp_var() + vars[i].avl.key = environ[i]; + c = strchr(environ[i], '='); + if (!c) + continue; + // value comes after '=' separator + vars[i].val = c + 1; + avl_insert(&env_vars, &vars[i].avl); + } +} + static int jshn_parse_file(const char *path) { struct stat sb; @@ -391,34 +432,10 @@ static int jshn_format_file(const char *path, bool no_newline, bool indent) int main(int argc, char **argv) { - extern char **environ; bool no_newline = false; bool indent = false; - struct env_var *vars; - int i; - int ret = 0; int ch; - avl_init(&env_vars, avl_strcmp_var, false, NULL); - for (i = 0; environ[i]; i++); - - vars = calloc(i, sizeof(*vars)); - if (!vars) { - fprintf(stderr, "%m\n"); - return -1; - } - for (i = 0; environ[i]; i++) { - char *c; - - vars[i].avl.key = environ[i]; - c = strchr(environ[i], '='); - if (!c) - continue; - - vars[i].val = c + 1; - avl_insert(&env_vars, &vars[i].avl); - } - while ((ch = getopt(argc, argv, "p:nir:R:o:w")) != -1) { switch(ch) { case 'p': @@ -426,17 +443,13 @@ int main(int argc, char **argv) var_prefix_len = strlen(var_prefix); break; case 'r': - ret = jshn_parse(optarg); - goto exit; + return jshn_parse(optarg); case 'R': - ret = jshn_parse_file(optarg); - goto exit; + return jshn_parse_file(optarg); case 'w': - ret = jshn_format(no_newline, indent, stdout); - goto exit; + return jshn_format(no_newline, indent, stdout); case 'o': - ret = jshn_format_file(optarg, no_newline, indent); - goto exit; + return jshn_format_file(optarg, no_newline, indent); case 'n': no_newline = true; break; @@ -444,15 +457,11 @@ int main(int argc, char **argv) indent = true; break; default: - free(vars); - return usage(argv[0]); + // unknown param, show usage + goto show_usage; } } - free(vars); +show_usage: return usage(argv[0]); - -exit: - free(vars); - return ret; } -- 2.27.0 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel