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

Reply via email to