summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-09-16 23:39:37 +0200
committerJo-Philipp Wich <jo@mein.io>2020-09-16 23:40:42 +0200
commit5e1affb4ed61df9e01df979573fe05c0e2c84ea0 (patch)
tree1cb94e027683b19f9148b88e308722ccb5793f31
parent0e67bdaa847c6d67497016db52e06af357f2e85c (diff)
eval: implement -e and -E options to set global vars from JSON
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--eval.c7
-rw-r--r--eval.h2
-rw-r--r--main.c132
3 files changed, 106 insertions, 35 deletions
diff --git a/eval.c b/eval.c
index 4410d2d..0c44727 100644
--- a/eval.c
+++ b/eval.c
@@ -1531,7 +1531,7 @@ ut_globals_init(struct ut_state *state, struct json_object *scope)
}
enum ut_error_type
-ut_run(struct ut_state *state)
+ut_run(struct ut_state *state, struct json_object *env)
{
struct json_object *entry = NULL, *scope = NULL, *args = NULL, *rv = NULL;
struct ut_op *op = ut_get_op(state, state->main);
@@ -1545,6 +1545,11 @@ ut_run(struct ut_state *state)
state->ctx = NULL;
+ if (env) {
+ json_object_object_foreach(env, key, val)
+ json_object_object_add(scope, key, val);
+ }
+
ut_globals_init(state, scope);
ut_lib_init(state, scope);
diff --git a/eval.h b/eval.h
index 30d29d5..2bd8dd0 100644
--- a/eval.h
+++ b/eval.h
@@ -43,6 +43,6 @@ struct json_object *
ut_invoke(struct ut_state *, uint32_t, struct json_object *, struct json_object *, struct json_object *);
enum ut_error_type
-ut_run(struct ut_state *state);
+ut_run(struct ut_state *state, struct json_object *env);
#endif
diff --git a/main.c b/main.c
index 18db4a7..f065bf6 100644
--- a/main.c
+++ b/main.c
@@ -38,14 +38,16 @@ print_usage(char *app)
{
printf(
"== Usage ==\n\n"
- " # %s [-d] [-l] [-r] [-S] {-i <file> | -s \"utpl script...\"}\n"
+ " # %s [-d] [-l] [-r] [-S] [-e '{\"var\": ...}'] [-E env.json] {-i <file> | -s \"utpl script...\"}\n"
" -h, --help Print this help\n"
" -i file Specify an utpl script to parse\n"
" -s \"utpl script...\" Specify an utpl code fragment to parse\n"
" -d Instead of executing the script, dump the resulting AST as dot\n"
" -l Do not strip leading block whitespace\n"
" -r Do not trim trailing block newlines\n"
- " -S Enable strict mode\n",
+ " -S Enable strict mode\n"
+ " -e Set global variables from given JSON object\n"
+ " -E Set global variables from given JSON file\n",
app);
}
@@ -139,7 +141,7 @@ static void dump(struct ut_state *s, uint32_t off, int level) {
#endif /* NDEBUG */
static enum ut_error_type
-parse(struct ut_state *state, const char *source, bool dumponly)
+parse(struct ut_state *state, const char *source, bool dumponly, struct json_object *env)
{
enum ut_error_type err;
char *msg;
@@ -156,7 +158,7 @@ parse(struct ut_state *state, const char *source, bool dumponly)
#endif /* NDEBUG */
}
else {
- err = ut_run(state);
+ err = ut_run(state, env);
}
}
@@ -172,15 +174,67 @@ parse(struct ut_state *state, const char *source, bool dumponly)
return err;
}
+static bool stdin_used = false;
+
+static char *
+read_file(const char *path) {
+ char buf[64], *s = NULL, *tmp;
+ size_t rlen, tlen = 0;
+ FILE *fp = NULL;
+
+ if (!strcmp(path, "-")) {
+ if (stdin_used) {
+ fprintf(stderr, "Can read from stdin only once\n");
+ goto out;
+ }
+
+ fp = stdin;
+ stdin_used = true;
+ }
+ else {
+ fp = fopen(path, "r");
+
+ if (!fp) {
+ fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
+ goto out;
+ }
+ }
+
+ while (1) {
+ rlen = fread(buf, 1, sizeof(buf), fp);
+
+ if (rlen == 0)
+ break;
+
+ tmp = realloc(s, tlen + rlen + 1);
+
+ if (!tmp) {
+ fprintf(stderr, "Out or memory\n");
+ free(s);
+ s = NULL;
+ goto out;
+ }
+
+ s = tmp;
+ memcpy(s + tlen, buf, rlen);
+ s[tlen + rlen] = 0;
+ tlen += rlen;
+ }
+
+out:
+ if (fp != NULL && fp != stdin)
+ fclose(fp);
+
+ return s;
+}
+
int
main(int argc, char **argv)
{
+ char *srcstr = NULL, *srcfile = NULL, *envstr = NULL;
+ struct json_object *env = NULL, *o;
struct ut_state *state;
bool dumponly = false;
- size_t rlen, tlen = 0;
- char buf[1024], *tmp;
- char *source = NULL;
- FILE *input = NULL;
int opt, rv = 0;
if (argc == 1)
@@ -199,7 +253,7 @@ main(int argc, char **argv)
state->lstrip_blocks = 1;
state->trim_blocks = 1;
- while ((opt = getopt(argc, argv, "dhlrSi:s:")) != -1)
+ while ((opt = getopt(argc, argv, "dhlrSe:E:i:s:")) != -1)
{
switch (opt) {
case 'h':
@@ -207,10 +261,9 @@ main(int argc, char **argv)
goto out;
case 'i':
- input = strcmp(optarg, "-") ? fopen(optarg, "r") : stdin;
+ srcfile = read_file(optarg);
- if (!input) {
- fprintf(stderr, "Failed to open %s: %s\n", optarg, strerror(errno));
+ if (!srcfile) {
rv = UT_ERROR_EXCEPTION;
goto out;
}
@@ -230,46 +283,59 @@ main(int argc, char **argv)
break;
case 's':
- source = optarg;
+ srcstr = optarg;
break;
case 'S':
state->strict_declarations = 1;
break;
- }
- }
- if (!source) {
- while (1) {
- rlen = fread(buf, 1, sizeof(buf), input);
+ case 'e':
+ envstr = optarg;
+ /* fallthrough */
- if (rlen == 0)
- break;
+ case 'E':
+ if (!envstr) {
+ envstr = read_file(optarg);
+
+ if (!envstr) {
+ rv = UT_ERROR_EXCEPTION;
+ goto out;
+ }
+ }
- tmp = realloc(source, tlen + rlen + 1);
+ o = json_tokener_parse(envstr);
- if (!tmp) {
- tmp = ut_format_error(NULL, "");
+ if (envstr != optarg)
+ free(envstr);
- fprintf(stderr, "%s\n", tmp);
- free(tmp);
+ if (!json_object_is_type(o, json_type_object)) {
+ fprintf(stderr, "Option -%c must point to a valid JSON object\n", opt);
- rv = UT_ERROR_OUT_OF_MEMORY;
+ rv = UT_ERROR_EXCEPTION;
goto out;
}
- source = tmp;
- memcpy(source + tlen, buf, rlen);
- source[tlen + rlen] = 0;
- tlen += rlen;
+ env = env ? env : json_object_new_object();
+
+ json_object_object_foreach(o, key, val)
+ json_object_object_add(env, key, val);
+
+ break;
}
}
- rv = source ? parse(state, source, dumponly) : 0;
+ if ((srcstr && srcfile) || (!srcstr && !srcfile)) {
+ fprintf(stderr, srcstr ? "Options -i and -s are exclusive\n" : "One of -i or -s is required\n");
+
+ rv = UT_ERROR_EXCEPTION;
+ goto out;
+ }
+
+ rv = parse(state, srcstr ? srcstr : srcfile, dumponly, env);
out:
- if (input && input != stdin)
- fclose(input);
+ free(srcfile);
return rv;
}