]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
include/optstr: improve optstr parsing
authorKarel Zak <kzak@redhat.com>
Wed, 27 Nov 2024 13:02:25 +0000 (14:02 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 27 Nov 2024 13:10:24 +0000 (14:10 +0100)
* make sure option cannot start with '='
* add ul_optstr_is_valid()
* add regression test

Signed-off-by: Karel Zak <kzak@redhat.com>
include/strutils.h
lib/strutils.c
tests/expected/misc/optstr [new file with mode: 0644]
tests/ts/misc/optstr [new file with mode: 0755]

index e5ddbcf1bf83f36efd6f67be8ad45098b985b6cd..aa8c002d59817d4e70cd0a31ab0ef03fe411013d 100644 (file)
@@ -456,5 +456,6 @@ extern int skip_fline(FILE *fp);
 extern int ul_stralnumcmp(const char *p1, const char *p2);
 
 extern int ul_optstr_next(char **optstr, char **name, size_t *namesz, char **value, size_t *valsz);
+extern int ul_optstr_is_valid(const char *optstr);
 
 #endif
index e3a059145a72d55f1c33964f7e1547f5efe28541..4590aa9114cce0777b9e65f533055faaaa48aeac 100644 (file)
@@ -1217,6 +1217,8 @@ int ul_optstr_next(char **optstr, char **name, size_t *namesz,
                optstr0++;
 
        for (p = optstr0; p && *p; p++) {
+               if (!start && *p == '=')
+                       return -EINVAL;
                if (!start)
                        start = p;              /* beginning of the option item */
                if (*p == '"')
@@ -1252,6 +1254,15 @@ int ul_optstr_next(char **optstr, char **name, size_t *namesz,
        return 1;                               /* end of optstr */
 }
 
+int ul_optstr_is_valid(const char *optstr)
+{
+       int rc;
+       char *p = (char *) optstr;
+
+       while ((rc = ul_optstr_next(&p, NULL, NULL, NULL, NULL)) == 0);
+       return rc < 0 ? 0 : 1;
+}
+
 #ifdef TEST_PROGRAM_STRUTILS
 
 #include "cctype.h"
@@ -1430,6 +1441,24 @@ int main(int argc, char *argv[])
                        printf("str: '%s'\n", p);
                } while ((p = ul_next_string(p, end)));
 
+               return EXIT_SUCCESS;
+
+       } else if (argc == 3 && strcmp(argv[1], "--optstr") == 0) {
+
+               size_t namesz, valsz;
+               char *name = NULL, *val = NULL;
+               char *p = argv[2];
+               int rc;
+
+               if (!ul_optstr_is_valid(p))
+                       errx(EXIT_FAILURE, _("unsupported option format: %s"), p);
+
+               while ((rc = ul_optstr_next(&p, &name, &namesz, &val, &valsz)) == 0) {
+                       printf("'%.*s' : '%.*s'\n", (int) namesz, name,
+                                                  (int) valsz, val);
+               }
+               if (rc == 1)
+                       return EXIT_SUCCESS;
        } else {
                fprintf(stderr, "usage: %1$s --size <number>[suffix]\n"
                                "       %1$s --cmp-paths <path> <path>\n"
diff --git a/tests/expected/misc/optstr b/tests/expected/misc/optstr
new file mode 100644 (file)
index 0000000..86d094e
--- /dev/null
@@ -0,0 +1,4 @@
+'key' : '"v,a,l,u,e"'
+'foo' : ''
+'bar' : 'BAR'
+'"/path/with/,comma"' : 'data'
diff --git a/tests/ts/misc/optstr b/tests/ts/misc/optstr
new file mode 100755 (executable)
index 0000000..edc2f4c
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="optstr"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_HELPER_STRUTILS"
+
+$TS_HELPER_STRUTILS --optstr "key=\"v,a,l,u,e\",foo,bar=BAR,\"/path/with/,comma\"=data" >> $TS_OUTPUT 2>> $TS_ERRLOG
+
+ts_finalize
+