[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