1 /* $NetBSD: split_qnameval.c,v 1.2 2020/03/18 19:05:22 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* split_qnameval 3
6 /* SUMMARY
7 /* name-value splitter
8 /* SYNOPSIS
9 /* #include <stringops.h>
10 /*
11 /* const char *split_qnameval(buf, name, value)
12 /* char *buf;
13 /* char **name;
14 /* char **value;
15 /* DESCRIPTION
16 /* split_qnameval() expects text of the form "key = value"
17 /* or "key =", where the key may be quoted with backslash or
18 /* double quotes. The buffer argument is broken up into the key
19 /* and value substrings.
20 /*
21 /* Arguments:
22 /* .IP buf
23 /* Result from readlline() or equivalent. The buffer is modified.
24 /* .IP key
25 /* Upon successful completion, this is set to the key
26 /* substring.
27 /* .IP value
28 /* Upon successful completion, this is set to the value
29 /* substring.
30 /* SEE ALSO
31 /* split_nameval(3) name-value splitter
32 /* BUGS
33 /* DIAGNOSTICS
34 /* The result is a null pointer in case of success, a string
35 /* describing the error otherwise: missing '=' after attribute
36 /* name; missing attribute name.
37 /* LICENSE
38 /* .ad
39 /* .fi
40 /* The Secure Mailer license must be distributed with this software.
41 /* AUTHOR(S)
42 /* Wietse Venema
43 /* Google, Inc.
44 /* 111 8th Avenue
45 /* New York, NY 10011, USA
46 /*--*/
47
48 /* System libraries. */
49
50 #include <sys_defs.h>
51 #include <ctype.h>
52 #include <string.h>
53
54 /* Utility library. */
55
56 #include <msg.h>
57 #include <stringops.h>
58
59 /* split_qnameval - split "key = value", support quoted key */
60
split_qnameval(char * buf,char ** pkey,char ** pvalue)61 const char *split_qnameval(char *buf, char **pkey, char **pvalue)
62 {
63 int in_quotes = 0;
64 char *key;
65 char *key_end;
66 char *value;
67
68 for (key = buf; *key && ISSPACE(*key); key++)
69 /* void */ ;
70 if (*key == 0)
71 return ("no key found; expected format: key = value");
72
73 for (key_end = key; *key_end; key_end++) {
74 if (*key_end == '\\') {
75 if (*++key_end == 0)
76 break;
77 } else if (ISSPACE(*key_end) || *key_end == '=') {
78 if (!in_quotes)
79 break;
80 } else if (*key_end == '"') {
81 in_quotes = !in_quotes;
82 }
83 }
84 if (in_quotes) {
85 return ("unbalanced '\"\'");
86 }
87 value = key_end;
88 while (ISSPACE(*value))
89 value++;
90 if (*value != '=')
91 return ("missing '=' after attribute name");
92 *key_end = 0;
93 do {
94 value++;
95 } while (ISSPACE(*value));
96 trimblanks(value, 0)[0] = 0;
97 *pkey = key;
98 *pvalue = value;
99 return (0);
100 }
101
102 #ifdef TEST
103
104 #include <stdlib.h>
105 #include <unistd.h>
106 #include <string.h>
107
108 #include <mymalloc.h>
109
compare(int test_number,const char * what,const char * expect,const char * real)110 static int compare(int test_number, const char *what,
111 const char *expect, const char *real)
112 {
113 if ((expect == 0 && real == 0)
114 || (expect != 0 && real != 0 && strcmp(expect, real) == 0)) {
115 return (0);
116 } else {
117 msg_warn("test %d: %s mis-match: expect='%s', real='%s'",
118 test_number, what, expect ? expect : "(null)",
119 real ? real : "(null)");
120 return (1);
121 }
122 }
123
main(int argc,char ** argv)124 int main(int argc, char **argv)
125 {
126 struct test_info {
127 const char *input;
128 const char *expect_result;
129 const char *expect_key;
130 const char *expect_value;
131 };
132 static const struct test_info test_info[] = {
133 /* Unquoted keys. */
134 {"xx = yy", 0, "xx", "yy"},
135 {"xx=yy", 0, "xx", "yy"},
136 {"xx =", 0, "xx", ""},
137 {"xx=", 0, "xx", ""},
138 {"xx", "missing '=' after attribute name", 0, 0},
139 /* Quoted keys. */
140 {"\"xx \" = yy", 0, "\"xx \"", "yy"},
141 {"\"xx \"= yy", 0, "\"xx \"", "yy"},
142 {"\"xx \" =", 0, "\"xx \"", ""},
143 {"\"xx \"=", 0, "\"xx \"", ""},
144 {"\"xx \"", "missing '=' after attribute name", 0, 0},
145 {"\"xx ", "unbalanced '\"'", 0, 0},
146 /* Backslash escapes. */
147 {"\"\\\"xx \" = yy", 0, "\"\\\"xx \"", "yy"},
148 {0,},
149 };
150
151 int errs = 0;
152 const struct test_info *tp;
153
154 for (tp = test_info; tp->input != 0; tp++) {
155 const char *result;
156 char *key = 0;
157 char *value = 0;
158 char *buf = mystrdup(tp->input);
159 int test_number = (int) (tp - test_info);
160
161 result = split_qnameval(buf, &key, &value);
162 errs += compare(test_number, "result", tp->expect_result, result);
163 errs += compare(test_number, "key", tp->expect_key, key);
164 errs += compare(test_number, "value", tp->expect_value, value);
165 myfree(buf);
166 }
167 exit(errs);
168 }
169
170 #endif
171