diff --git a/Makefile b/Makefile index 1381676..ab003b0 100755 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ EXECUTABLE=uclcmd all: $(SRCS) $(EXECUTABLE) -$(EXECUTABLE): $(OBJS) +$(EXECUTABLE): $(OBJS) uclcmd.h $(CC) $(LDFLAGS) $(LIBS) -o $(EXECUTABLE) $(OBJS) clean: diff --git a/tests/include-merge-high_01.res b/tests/include-merge-high_01.res index b803022..4a213e5 100644 --- a/tests/include-merge-high_01.res +++ b/tests/include-merge-high_01.res @@ -1,16 +1,10 @@ vm1 { - cpus [ - 1, - 2, - ] + cpus = 2; origin = 4; mode = "merge"; sub { a = "b"; - c [ - "d", - "e", - ] + c = "e"; foo = "bar"; } from = "test"; diff --git a/tests/include-merge-low_01.res b/tests/include-merge-low_01.res index b803022..55bbb37 100644 --- a/tests/include-merge-low_01.res +++ b/tests/include-merge-low_01.res @@ -1,16 +1,10 @@ vm1 { - cpus [ - 1, - 2, - ] + cpus = 1; origin = 4; mode = "merge"; sub { a = "b"; - c [ - "d", - "e", - ] + c = "d"; foo = "bar"; } from = "test"; diff --git a/tests/set_08.res b/tests/set_08.res index 924e23e..1e3e8ce 100644 --- a/tests/set_08.res +++ b/tests/set_08.res @@ -8,5 +8,5 @@ rootkey { "b", "c", ] - new = 1103760000.0; + new = 157680000.0; } diff --git a/uclcmd.c b/uclcmd.c index d68c930..cf084e1 100755 --- a/uclcmd.c +++ b/uclcmd.c @@ -36,6 +36,7 @@ int debug = 0, expand = 0, mode = 0, noop = 0, nonewline = 0; int show_keys = 0, show_raw = 0; +int pflags = 0; bool firstline = true, shvars = false; int output_type = 254; ucl_object_t *root_obj = NULL; @@ -70,6 +71,7 @@ main(int argc, char *argv[]) { "del", remove_main }, { "dump", output_main }, { "help", (verb_func_t) usage }, + { "version", (verb_func_t) version }, { NULL, NULL } }; @@ -109,10 +111,10 @@ void usage() { fprintf(stderr, "%s\n", -"Usage: uclcmd get [-cdejklmNquy] [-D char] [-f file] [-o file] variable\n" -" uclcmd set [-cdjmnuy] [-t type] [-D char] [-f file] [-i file] [-o file] variable [UCL]\n" -" uclcmd merge [-cdjmnuy] [-D char] [-f file] [-i file] [-o file] variable\n" -" uclcmd remove [-cdjmnuy] [-D char] [-f file] [-o file] variable\n" +"Usage: uclcmd get [-cdeIjklmNquy] [-D char] [-f file] [-o file] variable\n" +" uclcmd set [-cdIjmnuy] [-t type] [-D char] [-f file] [-i file] [-o file] variable [UCL]\n" +" uclcmd merge [-cdIjmnuy] [-D char] [-f file] [-i file] [-o file] variable\n" +" uclcmd remove [-cdIjmnuy] [-D char] [-f file] [-o file] variable\n" "\n" "COMMON OPTIONS:\n" " -c --cjson output compacted JSON\n" @@ -120,6 +122,7 @@ usage() " -D --delimiter character to use as element delimiter (default is .)\n" " -e --expand Output the list of keys when encountering an object\n" " -f --file path to a file to read or write\n" +" -I --foldcase fold all keys to lowercase (make matching insensitive)\n" " -j --json output pretty JSON\n" " -k --keys show key=value rather than just the value\n" " -l --shellvars keys are output with underscores as delimiter\n" @@ -157,6 +160,13 @@ usage() exit(1); } +void +version() +{ + + fprintf(stderr, "uclcmd version %s\n", UCLCMD_VERSION_STRING); +} + void cleanup() { diff --git a/uclcmd.h b/uclcmd.h index 5b3a63c..240f6dd 100755 --- a/uclcmd.h +++ b/uclcmd.h @@ -47,14 +47,23 @@ #include +#define QUOTE(str) #str +#define EXPAND_AND_QUOTE(str) QUOTE(str) #ifndef __DECONST #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) #endif +#define UCLCMD_VERSION_MAJOR 0 +#define UCLCMD_VERSION_MINOR 2 +#define UCLCMD_VERSION_PATCH 20211204 +#define UCLCMD_VERSION UCLCMD_VERSION_MAJOR.UCLCMD_VERSION_MINOR.UCLCMD_VERSION_PATCH +#define UCLCMD_VERSION_STRING EXPAND_AND_QUOTE(UCLCMD_VERSION) + #define UCLCMD_PARSER_FLAGS UCL_PARSER_NO_IMPLICIT_ARRAYS | \ UCL_PARSER_SAVE_COMMENTS extern int debug, expand, noop, nonewline, show_keys, show_raw; +extern int pflags; extern bool firstline, shvars; extern int output_type; extern ucl_object_t *root_obj; @@ -106,6 +115,7 @@ char * objtype_as_string (const ucl_object_t *obj); void ucl_obj_dump(const ucl_object_t *obj, unsigned int shift); void ucl_obj_dump_safe(const ucl_object_t *obj, unsigned int shift); void usage(); +void version(); int get_cmd_each(const ucl_object_t *obj, char *nodepath, const char *command_str, char *remaining_commands, int recurse); diff --git a/uclcmd_get.c b/uclcmd_get.c index 22d9050..ee3c51d 100755 --- a/uclcmd_get.c +++ b/uclcmd_get.c @@ -33,9 +33,6 @@ get_main(int argc, char *argv[]) { int ret = 0, k = 0, ch; - /* Initialize parser */ - parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | UCL_PARSER_KEY_LOWERCASE); - /* options descriptor */ static struct option longopts[] = { { "cjson", no_argument, &output_type, @@ -48,6 +45,7 @@ get_main(int argc, char *argv[]) UCL_EMIT_JSON }, { "keys", no_argument, &show_keys, 1 }, { "input", no_argument, NULL, 'i' }, + { "foldcase", no_argument, NULL, 'I' }, { "msgpack", no_argument, &output_type, UCL_EMIT_MSGPACK }, { "noop", no_argument, &noop, 1 }, @@ -61,7 +59,7 @@ get_main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - while ((ch = getopt_long(argc, argv, "cdD:ef:i:jklmnNo:quy", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "cdD:ef:i:IjklmnNo:quy", longopts, NULL)) != -1) { switch (ch) { case 'c': output_type = UCL_EMIT_JSON_COMPACT; @@ -82,17 +80,14 @@ get_main(int argc, char *argv[]) break; case 'f': filename = optarg; - if (strcmp(optarg, "-") == 0) { - /* Input from STDIN */ - root_obj = parse_input(parser, stdin); - } else { - root_obj = parse_file(parser, filename); - } break; case 'i': fprintf(stderr, "Not implemented yet\n"); exit(1); break; + case 'I': + pflags |= UCL_PARSER_KEY_LOWERCASE; + break; case 'j': output_type = UCL_EMIT_JSON; break; @@ -140,8 +135,14 @@ get_main(int argc, char *argv[]) usage(); } - if (filename == NULL) { + /* Initialize parser */ + parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | pflags); + + if (filename == NULL || strcmp(filename, "-") == 0) { + /* Input from STDIN */ root_obj = parse_input(parser, stdin); + } else { + root_obj = parse_file(parser, filename); } for (k = 0; k < argc; k++) { diff --git a/uclcmd_merge.c b/uclcmd_merge.c index a57d949..32b80d5 100755 --- a/uclcmd_merge.c +++ b/uclcmd_merge.c @@ -34,9 +34,6 @@ merge_main(int argc, char *argv[]) int ret = 0, ch; bool success = false; - /* Initialize parser */ - parser = ucl_parser_new(UCLCMD_PARSER_FLAGS); - /* Set the default output type */ output_type = UCL_EMIT_CONFIG; @@ -52,6 +49,7 @@ merge_main(int argc, char *argv[]) UCL_EMIT_JSON }, { "keys", no_argument, &show_keys, 1 }, { "input", no_argument, NULL, 'i' }, + { "foldcase", no_argument, NULL, 'I' }, { "msgpack", no_argument, &output_type, UCL_EMIT_MSGPACK }, { "noop", no_argument, &noop, 1 }, @@ -65,7 +63,7 @@ merge_main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - while ((ch = getopt_long(argc, argv, "cdD:ef:i:jklmnNo:quy", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "cdD:ef:i:IjklmnNo:quy", longopts, NULL)) != -1) { switch (ch) { case 'c': output_type = UCL_EMIT_JSON_COMPACT; @@ -86,16 +84,13 @@ merge_main(int argc, char *argv[]) break; case 'f': filename = optarg; - if (strcmp(optarg, "-") == 0) { - /* Input from STDIN */ - root_obj = parse_input(parser, stdin); - } else { - root_obj = parse_file(parser, filename); - } break; case 'i': include_file = optarg; break; + case 'I': + pflags |= UCL_PARSER_KEY_LOWERCASE; + break; case 'j': output_type = UCL_EMIT_JSON; break; @@ -142,8 +137,14 @@ merge_main(int argc, char *argv[]) usage(); } - if (filename == NULL) { + /* Initialize parser */ + parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | pflags); + + if (filename == NULL || strcmp(filename, "-") == 0) { + /* Input from STDIN */ root_obj = parse_input(parser, stdin); + } else { + root_obj = parse_file(parser, filename); } if (argc > 1) { /* XXX: need test for if > 2 inputs */ diff --git a/uclcmd_output.c b/uclcmd_output.c index c858929..947dfe1 100755 --- a/uclcmd_output.c +++ b/uclcmd_output.c @@ -34,31 +34,26 @@ output_main(int argc, char *argv[]) const char *filename = NULL; int ret = 0, ch; - /* Initialize parser */ - parser = ucl_parser_new(UCLCMD_PARSER_FLAGS); - /* options descriptor */ static struct option longopts[] = { { "file", required_argument, NULL, 'f' }, { "input", no_argument, NULL, 'i' }, + { "foldcase", no_argument, NULL, 'I' }, { NULL, 0, NULL, 0 } }; - while ((ch = getopt_long(argc, argv, "f:i:", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "f:i:I", longopts, NULL)) != -1) { switch (ch) { case 'f': filename = optarg; - if (strcmp(optarg, "-") == 0) { - /* Input from STDIN */ - root_obj = parse_input(parser, stdin); - } else { - root_obj = parse_file(parser, filename); - } break; case 'i': fprintf(stderr, "Not implemented yet\n"); exit(1); break; + case 'I': + pflags |= UCL_PARSER_KEY_LOWERCASE; + break; default: fprintf(stderr, "Error: Unexpected option: %i\n", ch); usage(); @@ -68,8 +63,14 @@ output_main(int argc, char *argv[]) argc -= optind; argv += optind; - if (filename == NULL) { + /* Initialize parser */ + parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | pflags); + + if (filename == NULL || strcmp(filename, "-") == 0) { + /* Input from STDIN */ root_obj = parse_input(parser, stdin); + } else { + root_obj = parse_file(parser, filename); } ucl_obj_dump(root_obj, 0); diff --git a/uclcmd_parse.c b/uclcmd_parse.c index 5c6ed10..f5c9d1a 100755 --- a/uclcmd_parse.c +++ b/uclcmd_parse.c @@ -32,10 +32,11 @@ ucl_object_t* parse_file(struct ucl_parser *parser, const char *filename) { ucl_object_t *obj = NULL; + bool success = false; - ucl_parser_add_file(parser, filename); + success = ucl_parser_add_file(parser, filename); - if (ucl_parser_get_error(parser)) { + if (!success) { fprintf(stderr, "Error occured: %s\n", ucl_parser_get_error(parser)); cleanup(); @@ -68,19 +69,32 @@ parse_input(struct ucl_parser *parser, FILE *source) success = ucl_parser_add_chunk(parser, inbuf, r); fclose(source); - if (ucl_parser_get_error_code(parser) == UCL_EMERGE) { - fprintf(stderr, "Error: Parse Error occured: %s\n", - ucl_parser_get_error(parser)); - cleanup(); - exit(3); - } - - if (success == false) { - /* There must be a better way to detect a string */ - ucl_parser_clear_error(parser); - success = true; - uclcmd_asprintf(&data, "%s", inbuf); - obj = ucl_object_fromstring_common(data, 0, UCL_STRING_PARSE); + if (!success) { + switch (ucl_parser_get_error_code(parser)) { + case UCL_EOK: + fprintf(stderr, "Error: Unexpected parse error occured: %s\n", + ucl_parser_get_error(parser)); + break; + case UCL_EMERGE: + fprintf(stderr, "Unable to merge: %s\n", + ucl_parser_get_error(parser)); + break; + case UCL_ESYNTAX: + /* The input was not a valid UCL object, treat is as a string */ + ucl_parser_clear_error(parser); + success = true; + uclcmd_asprintf(&data, "%s", inbuf); + obj = ucl_object_fromstring_common(data, 0, UCL_STRING_PARSE); + break; + default: + fprintf(stderr, "Error: Parse Error occured: %s\n", + ucl_parser_get_error(parser)); + break; + } + if (!success) { + cleanup(); + exit(3); + } } else { obj = ucl_parser_get_object(parser); } @@ -103,18 +117,31 @@ parse_string(struct ucl_parser *parser, char *data) success = ucl_parser_add_string(parser, data, 0); - if (ucl_parser_get_error_code(parser) == UCL_EMERGE) { - fprintf(stderr, "Error: Parse Error occured: %s\n", - ucl_parser_get_error(parser)); - cleanup(); - exit(3); - } - - if (success == false) { - /* There must be a better way to detect a string */ - ucl_parser_clear_error(parser); - success = true; - obj = ucl_object_fromstring_common(data, 0, UCL_STRING_PARSE); + if (!success) { + switch (ucl_parser_get_error_code(parser)) { + case UCL_EOK: + fprintf(stderr, "Error: Unexpected parse error occured: %s\n", + ucl_parser_get_error(parser)); + break; + case UCL_EMERGE: + fprintf(stderr, "Unable to merge: %s\n", + ucl_parser_get_error(parser)); + break; + case UCL_ESYNTAX: + /* The input was not a valid UCL object, treat is as a string */ + ucl_parser_clear_error(parser); + success = true; + obj = ucl_object_fromstring_common(data, 0, UCL_STRING_PARSE); + break; + default: + fprintf(stderr, "Error: Parse Error occured: %s\n", + ucl_parser_get_error(parser)); + break; + } + if (!success) { + cleanup(); + exit(3); + } } else { obj = ucl_parser_get_object(parser); } diff --git a/uclcmd_remove.c b/uclcmd_remove.c index 6784d71..065c4ca 100755 --- a/uclcmd_remove.c +++ b/uclcmd_remove.c @@ -35,8 +35,8 @@ remove_main(int argc, char *argv[]) ucl_object_t *obj_parent = NULL, *obj_child = NULL, *obj_temp = NULL; bool success = false; - /* Initialize parser */ - parser = ucl_parser_new(UCLCMD_PARSER_FLAGS); + /* When removing, don't expand macros */ + pflags |= UCL_PARSER_DISABLE_MACRO; /* Set the default output type */ output_type = UCL_EMIT_CONFIG; @@ -52,6 +52,7 @@ remove_main(int argc, char *argv[]) { "json", no_argument, &output_type, UCL_EMIT_JSON }, { "keys", no_argument, &show_keys, 1 }, + { "foldcase", no_argument, NULL, 'I' }, { "msgpack", no_argument, &output_type, UCL_EMIT_MSGPACK }, { "noop", no_argument, &noop, 1 }, @@ -65,7 +66,7 @@ remove_main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - while ((ch = getopt_long(argc, argv, "cdD:ef:jklmnNo:quy", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "cdD:ef:IjklmnNo:quy", longopts, NULL)) != -1) { switch (ch) { case 'c': output_type = UCL_EMIT_JSON_COMPACT; @@ -86,12 +87,9 @@ remove_main(int argc, char *argv[]) break; case 'f': filename = optarg; - if (strcmp(optarg, "-") == 0) { - /* Input from STDIN */ - root_obj = parse_input(parser, stdin); - } else { - root_obj = parse_file(parser, filename); - } + break; + case 'I': + pflags |= UCL_PARSER_KEY_LOWERCASE; break; case 'j': output_type = UCL_EMIT_JSON; @@ -139,9 +137,15 @@ remove_main(int argc, char *argv[]) usage(); } + /* Initialize parser */ + parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | pflags); + /* Parse the original UCL */ - if (filename == NULL) { + if (filename == NULL || strcmp(filename, "-") == 0) { + /* Input from STDIN */ root_obj = parse_input(parser, stdin); + } else { + root_obj = parse_file(parser, filename); } for (k = 0; k < argc; k++) { diff --git a/uclcmd_set.c b/uclcmd_set.c index c18d628..5e12436 100755 --- a/uclcmd_set.c +++ b/uclcmd_set.c @@ -35,8 +35,8 @@ set_main(int argc, char *argv[]) bool success = false; ucl_type_t want_type = UCL_NULL; - /* Initialize parser */ - parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | UCL_PARSER_DISABLE_MACRO); + /* When modifying, don't expand macros */ + pflags |= UCL_PARSER_DISABLE_MACRO; /* Set the default output type */ output_type = UCL_EMIT_CONFIG; @@ -53,6 +53,7 @@ set_main(int argc, char *argv[]) UCL_EMIT_JSON }, { "keys", no_argument, &show_keys, 1 }, { "input", no_argument, NULL, 'i' }, + { "foldcase", no_argument, NULL, 'I' }, { "msgpack", no_argument, &output_type, UCL_EMIT_MSGPACK }, { "noop", no_argument, &noop, 1 }, @@ -67,7 +68,7 @@ set_main(int argc, char *argv[]) { NULL, 0, NULL, 0 } }; - while ((ch = getopt_long(argc, argv, "cdD:ef:i:jklmnNo:qt:uy", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "cdD:ef:i:IjklmnNo:qt:uy", longopts, NULL)) != -1) { switch (ch) { case 'c': output_type = UCL_EMIT_JSON_COMPACT; @@ -88,16 +89,13 @@ set_main(int argc, char *argv[]) break; case 'f': filename = optarg; - if (strcmp(optarg, "-") == 0) { - /* Input from STDIN */ - root_obj = parse_input(parser, stdin); - } else { - root_obj = parse_file(parser, filename); - } break; case 'i': include_file = optarg; break; + case 'I': + pflags |= UCL_PARSER_KEY_LOWERCASE; + break; case 'j': output_type = UCL_EMIT_JSON; break; @@ -147,8 +145,15 @@ set_main(int argc, char *argv[]) usage(); } - if (filename == NULL) { + /* Initialize parser */ + parser = ucl_parser_new(UCLCMD_PARSER_FLAGS | pflags); + + /* Parse the original UCL */ + if (filename == NULL || strcmp(filename, "-") == 0) { + /* Input from STDIN */ root_obj = parse_input(parser, stdin); + } else { + root_obj = parse_file(parser, filename); } if (argc > 1) {