xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/split_qnameval.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
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