5a116deab632720b1c31c31d1ac4dc495961d457
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 static char *decode(const char *ptr
, size_t n
) {
72 if(urldecode(s
, ptr
, n
))
78 /** @brief Decode a URL-decoded key-value pair list
79 * @param ptr Start of input string
80 * @param n Length of input string
81 * @return @ref kvp of values from input
83 * The KVP is in the same order as the original input.
85 * If the original input contains duplicates names, so will the KVP.
87 struct kvp
*kvp_urldecode(const char *ptr
, size_t n
) {
88 struct kvp
*kvp
, **kk
= &kvp
, *k
;
89 const char *q
, *r
, *top
= ptr
+ n
, *next
;
92 *kk
= k
= xmalloc(sizeof *k
);
93 if(!(q
= memchr(ptr
, '=', top
- ptr
)))
95 if(!(k
->name
= decode(ptr
, q
- ptr
))) break;
96 if((r
= memchr(ptr
, '&', top
- ptr
)))
102 if(!(k
->value
= decode(q
+ 1, r
- (q
+ 1)))) break;
110 /** @brief URL-encode a string to a sink
111 * @param sink Where to send output
112 * @param s String to encode
113 * @param n Length of string to encode
114 * @return 0 on success or non-0 if sink write failed
116 int urlencode(struct sink
*sink
, const char *s
, size_t n
) {
124 if((c
>= '0' && c
<= '9')
125 || (c
>= 'a' && c
<= 'z')
126 || (c
>= 'A' && c
<= 'Z')) {
127 /* RFC2396 2.3 unreserved characters */
137 /* additional unreserved characters */
139 if(sink_writec(sink
, c
) < 0)
142 if(sink_printf(sink
, "%%%02x", (unsigned int)c
) < 0)
149 /** @brief URL-encode @p s
150 * @param s String to encode
151 * @return Encoded string
153 char *urlencodestring(const char *s
) {
157 urlencode(sink_dynstr(&d
), s
, strlen(s
));
158 dynstr_terminate(&d
);
162 /** @brief URL-decode @p s
163 * @param s String to decode
164 * @param ns Length of string
165 * @return Decoded string or NULL
167 char *urldecodestring(const char *s
, size_t ns
) {
171 if(urldecode(sink_dynstr(&d
), s
, ns
))
173 dynstr_terminate(&d
);
177 /** @brief URL-encode a KVP
178 * @param kvp Linked list to encode
179 * @param np Where to store length (or NULL)
180 * @return Newly created string
182 char *kvp_urlencode(const struct kvp
*kvp
, size_t *np
) {
187 sink
= sink_dynstr(&d
);
189 urlencode(sink
, kvp
->name
, strlen(kvp
->name
));
190 dynstr_append(&d
, '=');
191 urlencode(sink
, kvp
->value
, strlen(kvp
->value
));
192 if((kvp
= kvp
->next
))
193 dynstr_append(&d
, '&');
196 dynstr_terminate(&d
);
202 /** @brief Set or remove a value in a @ref kvp
203 * @param kvpp Address of KVP head to modify
204 * @param name Key to search for
205 * @param value New value or NULL to delete
206 * @return 1 if any change was made otherwise 0
208 * If @p value is not NULL then the first matching key is replaced; if
209 * there was no matching key a new one is added at the end.
211 * If @p value is NULL then the first matching key is removed.
213 * If anything actually changes the return value is 1. If no actual
214 * change is made then 0 is returned instead.
216 int kvp_set(struct kvp
**kvpp
, const char *name
, const char *value
) {
219 for(kk
= kvpp
; (k
= *kk
) && strcmp(name
, k
->name
); kk
= &k
->next
)
223 if(strcmp(k
->value
, value
)) {
224 k
->value
= xstrdup(value
);
234 *kk
= k
= xmalloc(sizeof *k
);
235 k
->name
= xstrdup(name
);
236 k
->value
= xstrdup(value
);
243 /** @brief Look up a value in a @ref kvp
244 * @param kvp Head of KVP linked list
245 * @param name Key to search for
246 * @return Value or NULL
248 * The returned value is owned by the KVP so must not be modified or
251 const char *kvp_get(const struct kvp
*kvp
, const char *name
) {
252 for(;kvp
&& strcmp(kvp
->name
, name
); kvp
= kvp
->next
)
254 return kvp ? kvp
->value
: 0;
257 /** @brief Construct a KVP from arguments
258 * @param name First name
259 * @return Newly created KVP
261 * Arguments must come in name/value pairs and must be followed by a (char *)0.
263 * The order of the new KVP is not formally defined though the test
264 * programs rely on it nonetheless so update them if you change it.
266 struct kvp
*kvp_make(const char *name
, ...) {
268 struct kvp
*kvp
= 0, *k
;
273 value
= va_arg(ap
, const char *);
274 k
= xmalloc(sizeof *k
);
276 k
->value
= value ?
xstrdup(value
) : "";
279 name
= va_arg(ap
, const char *);