diff options
Diffstat (limited to '')
-rw-r--r-- | src/util/split_qnameval.c | 168 |
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 |