2 * This file is part of DisOrder.
3 * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * @brief Linked list of key-value pairs
21 * Also supports URL encoding/decoding (of raw strings and kvp lists).
23 * For large sets of keys, see @ref lib/hash.c.
35 /** @brief Decode a URL-encoded string to a ink
36 * @param sink Where to store result
37 * @param ptr Start of string
38 * @param n Length of string
39 * @return 0 on success, non-0 if string could not be decoded or sink write failed
41 int urldecode(struct sink *sink, const char *ptr, size_t n) {
47 if((d1 = unhexdigit(ptr[0])) == -1
48 || (d2 = unhexdigit(ptr[1])) == -1)
60 if(sink_writec(sink,c) < 0)
66 /** @brief URL-decode a string
67 * @param ptr Start of URL-encoded string
68 * @param n Length of @p ptr
69 * @return Decoded string (0-terminated)
71 static char *decode(const char *ptr, size_t n) {
77 if(urldecode(s, ptr, n))
83 /** @brief Decode a URL-decoded key-value pair list
84 * @param ptr Start of input string
85 * @param n Length of input string
86 * @return @ref kvp of values from input
88 * The KVP is in the same order as the original input.
90 * If the original input contains duplicates names, so will the KVP.
92 struct kvp *kvp_urldecode(const char *ptr, size_t n) {
93 struct kvp *kvp, **kk = &kvp, *k;
94 const char *q, *r, *top = ptr + n, *next;
97 *kk = k = xmalloc(sizeof *k);
98 if(!(q = memchr(ptr, '=', top - ptr)))
100 if(!(k->name = decode(ptr, q - ptr))) break;
101 if((r = memchr(ptr, '&', top - ptr)))
107 if(!(k->value = decode(q + 1, r - (q + 1)))) break;
115 /** @brief URL-encode a string to a sink
116 * @param sink Where to send output
117 * @param s String to encode
118 * @param n Length of string to encode
119 * @return 0 on success or non-0 if sink write failed
121 int urlencode(struct sink *sink, const char *s, size_t n) {
129 if((c >= '0' && c <= '9')
130 || (c >= 'a' && c <= 'z')
131 || (c >= 'A' && c <= 'Z')) {
132 /* RFC2396 2.3 unreserved characters */
142 /* additional unreserved characters */
144 if(sink_writec(sink, c) < 0)
147 if(sink_printf(sink, "%%%02x", (unsigned int)c) < 0)
154 /** @brief URL-encode @p s
155 * @param s String to encode
156 * @return Encoded string
158 char *urlencodestring(const char *s) {
162 urlencode(sink_dynstr(&d), s, strlen(s));
163 dynstr_terminate(&d);
167 /** @brief URL-decode @p s
168 * @param s String to decode
169 * @param ns Length of string
170 * @return Decoded string or NULL
172 char *urldecodestring(const char *s, size_t ns) {
176 if(urldecode(sink_dynstr(&d), s, ns))
178 dynstr_terminate(&d);
182 /** @brief URL-encode a KVP
183 * @param kvp Linked list to encode
184 * @param np Where to store length (or NULL)
185 * @return Newly created string
187 char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
192 sink = sink_dynstr(&d);
194 urlencode(sink, kvp->name, strlen(kvp->name));
195 dynstr_append(&d, '=');
196 urlencode(sink, kvp->value, strlen(kvp->value));
197 if((kvp = kvp->next))
198 dynstr_append(&d, '&');
201 dynstr_terminate(&d);
207 /** @brief Set or remove a value in a @ref kvp
208 * @param kvpp Address of KVP head to modify
209 * @param name Key to search for
210 * @param value New value or NULL to delete
211 * @return 1 if any change was made otherwise 0
213 * If @p value is not NULL then the first matching key is replaced; if
214 * there was no matching key a new one is added at the end.
216 * If @p value is NULL then the first matching key is removed.
218 * If anything actually changes the return value is 1. If no actual
219 * change is made then 0 is returned instead.
221 int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
224 for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next)
228 if(strcmp(k->value, value)) {
229 k->value = xstrdup(value);
239 *kk = k = xmalloc(sizeof *k);
240 k->name = xstrdup(name);
241 k->value = xstrdup(value);
248 /** @brief Look up a value in a @ref kvp
249 * @param kvp Head of KVP linked list
250 * @param name Key to search for
251 * @return Value or NULL
253 * The returned value is owned by the KVP so must not be modified or
256 const char *kvp_get(const struct kvp *kvp, const char *name) {
257 for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
259 return kvp ? kvp->value : 0;
262 /** @brief Construct a KVP from arguments
263 * @param name First name
264 * @return Newly created KVP
266 * Arguments must come in name/value pairs and must be followed by a (char *)0.
268 * The order of the new KVP is not formally defined though the test
269 * programs rely on it nonetheless so update them if you change it.
271 struct kvp *kvp_make(const char *name, ...) {
273 struct kvp *kvp = 0, *k;
278 value = va_arg(ap, const char *);
279 k = xmalloc(sizeof *k);
281 k->value = value ? xstrdup(value) : "";
284 name = va_arg(ap, const char *);