[PATCH 2/3] jshn.c: load envs only when -w
Sergey Ponomarev
stokito at gmail.com
Mon Feb 22 17:47:54 EST 2021
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 <stokito at 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
More information about the openwrt-devel
mailing list