summaryrefslogtreecommitdiffstats
path: root/src/util/split_qnameval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/split_qnameval.c')
-rw-r--r--src/util/split_qnameval.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/util/split_qnameval.c b/src/util/split_qnameval.c
new file mode 100644
index 0000000..b166125
--- /dev/null
+++ b/src/util/split_qnameval.c
@@ -0,0 +1,168 @@
+/*++
+/* NAME
+/* split_qnameval 3
+/* SUMMARY
+/* name-value splitter
+/* SYNOPSIS
+/* #include <stringops.h>
+/*
+/* const char *split_qnameval(buf, name, value)
+/* char *buf;
+/* char **name;
+/* char **value;
+/* DESCRIPTION
+/* split_qnameval() expects text of the form "key = value"
+/* or "key =", where the key may be quoted with backslash or
+/* double quotes. The buffer argument is broken up into the key
+/* and value substrings.
+/*
+/* Arguments:
+/* .IP buf
+/* Result from readlline() or equivalent. The buffer is modified.
+/* .IP key
+/* Upon successful completion, this is set to the key
+/* substring.
+/* .IP value
+/* Upon successful completion, this is set to the value
+/* substring.
+/* SEE ALSO
+/* split_nameval(3) name-value splitter
+/* BUGS
+/* DIAGNOSTICS
+/* The result is a null pointer in case of success, a string
+/* describing the error otherwise: missing '=' after attribute
+/* name; missing attribute name.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <ctype.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <stringops.h>
+
+/* split_qnameval - split "key = value", support quoted key */
+
+const char *split_qnameval(char *buf, char **pkey, char **pvalue)
+{
+ int in_quotes = 0;
+ char *key;
+ char *key_end;
+ char *value;
+
+ for (key = buf; *key && ISSPACE(*key); key++)
+ /* void */ ;
+ if (*key == 0)
+ return ("no key found; expected format: key = value");
+
+ for (key_end = key; *key_end; key_end++) {
+ if (*key_end == '\\') {
+ if (*++key_end == 0)
+ break;
+ } else if (ISSPACE(*key_end) || *key_end == '=') {
+ if (!in_quotes)
+ break;
+ } else if (*key_end == '"') {
+ in_quotes = !in_quotes;
+ }
+ }
+ if (in_quotes) {
+ return ("unbalanced '\"\'");
+ }
+ value = key_end;
+ while (ISSPACE(*value))
+ value++;
+ if (*value != '=')
+ return ("missing '=' after attribute name");
+ *key_end = 0;
+ do {
+ value++;
+ } while (ISSPACE(*value));
+ trimblanks(value, 0)[0] = 0;
+ *pkey = key;
+ *pvalue = value;
+ return (0);
+}
+
+#ifdef TEST
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mymalloc.h>
+
+static int compare(int test_number, const char *what,
+ const char *expect, const char *real)
+{
+ if ((expect == 0 && real == 0)
+ || (expect != 0 && real != 0 && strcmp(expect, real) == 0)) {
+ return (0);
+ } else {
+ msg_warn("test %d: %s mis-match: expect='%s', real='%s'",
+ test_number, what, expect ? expect : "(null)",
+ real ? real : "(null)");
+ return (1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct test_info {
+ const char *input;
+ const char *expect_result;
+ const char *expect_key;
+ const char *expect_value;
+ };
+ static const struct test_info test_info[] = {
+ /* Unquoted keys. */
+ {"xx = yy", 0, "xx", "yy"},
+ {"xx=yy", 0, "xx", "yy"},
+ {"xx =", 0, "xx", ""},
+ {"xx=", 0, "xx", ""},
+ {"xx", "missing '=' after attribute name", 0, 0},
+ /* Quoted keys. */
+ {"\"xx \" = yy", 0, "\"xx \"", "yy"},
+ {"\"xx \"= yy", 0, "\"xx \"", "yy"},
+ {"\"xx \" =", 0, "\"xx \"", ""},
+ {"\"xx \"=", 0, "\"xx \"", ""},
+ {"\"xx \"", "missing '=' after attribute name", 0, 0},
+ {"\"xx ", "unbalanced '\"'", 0, 0},
+ /* Backslash escapes. */
+ {"\"\\\"xx \" = yy", 0, "\"\\\"xx \"", "yy"},
+ {0,},
+ };
+
+ int errs = 0;
+ const struct test_info *tp;
+
+ for (tp = test_info; tp->input != 0; tp++) {
+ const char *result;
+ char *key = 0;
+ char *value = 0;
+ char *buf = mystrdup(tp->input);
+ int test_number = (int) (tp - test_info);
+
+ result = split_qnameval(buf, &key, &value);
+ errs += compare(test_number, "result", tp->expect_result, result);
+ errs += compare(test_number, "key", tp->expect_key, key);
+ errs += compare(test_number, "value", tp->expect_value, value);
+ myfree(buf);
+ }
+ exit(errs);
+}
+
+#endif