chiark / gitweb /
Doxygen for C test infrastructure
[disorder] / lib / kvp.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
5aff007d 3 * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
460b9539 4 *
e7eb3a27 5 * This program is free software: you can redistribute it and/or modify
460b9539 6 * it under the terms of the GNU General Public License as published by
e7eb3a27 7 * the Free Software Foundation, either version 3 of the License, or
460b9539 8 * (at your option) any later version.
e7eb3a27
RK
9 *
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.
14 *
460b9539 15 * You should have received a copy of the GNU General Public License
e7eb3a27 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
460b9539 17 */
132a5a4a
RK
18/** @file lib/kvp.c
19 * @brief Linked list of key-value pairs
20 *
21 * Also supports URL encoding/decoding (of raw strings and kvp lists).
22 *
23 * For large sets of keys, see @ref lib/hash.c.
24 */
460b9539 25
05b75f8d 26#include "common.h"
460b9539 27
28#include "mem.h"
29#include "kvp.h"
30#include "log.h"
31#include "vector.h"
32#include "hex.h"
33#include "sink.h"
34
35int urldecode(struct sink *sink, const char *ptr, size_t n) {
36 int c, d1, d2;
37
38 while(n-- > 0) {
39 switch(c = *ptr++) {
40 case '%':
41 if((d1 = unhexdigit(ptr[0])) == -1
42 || (d2 = unhexdigit(ptr[1])) == -1)
43 return -1;
44 c = d1 * 16 + d2;
45 ptr += 2;
46 n -= 2;
47 break;
48 case '+':
49 c = ' ';
50 break;
51 default:
52 break;
53 }
54 if(sink_writec(sink,c) < 0)
55 return -1;
56 }
57 return 0;
58}
59
60static char *decode(const char *ptr, size_t n) {
61 struct dynstr d;
62 struct sink *s;
63
64 dynstr_init(&d);
65 s = sink_dynstr(&d);
66 if(urldecode(s, ptr, n))
67 return 0;
68 dynstr_terminate(&d);
69 return d.vec;
70}
71
72struct kvp *kvp_urldecode(const char *ptr, size_t n) {
73 struct kvp *kvp, **kk = &kvp, *k;
74 const char *q, *r, *top = ptr + n, *next;
75
76 while(ptr < top) {
77 *kk = k = xmalloc(sizeof *k);
78 if(!(q = memchr(ptr, '=', top - ptr)))
79 break;
80 if(!(k->name = decode(ptr, q - ptr))) break;
81 if((r = memchr(ptr, '&', top - ptr)))
82 next = r + 1;
83 else
84 next = r = top;
85 if(r < q)
86 break;
87 if(!(k->value = decode(q + 1, r - (q + 1)))) break;
88 kk = &k->next;
89 ptr = next;
90 }
91 *kk = 0;
92 return kvp;
93}
94
95int urlencode(struct sink *sink, const char *s, size_t n) {
96 unsigned char c;
97
98 while(n > 0) {
99 c = *s++;
100 n--;
101 switch(c) {
102 default:
103 if((c >= '0' && c <= '9')
104 || (c >= 'a' && c <= 'z')
105 || (c >= 'A' && c <= 'Z')) {
106 /* RFC2396 2.3 unreserved characters */
107 case '-':
108 case '_':
109 case '.':
110 case '!':
111 case '~':
112 case '*':
113 case '\'':
114 case '(':
115 case ')':
116 /* additional unreserved characters */
117 case '/':
118 if(sink_writec(sink, c) < 0)
119 return -1;
120 } else
121 if(sink_printf(sink, "%%%02x", (unsigned int)c) < 0)
122 return -1;
123 }
124 }
125 return 0;
126}
127
b12be54a
RK
128/** @brief URL-encode @p s
129 * @param s String to encode
130 * @return Encoded string
131 */
36bde473 132char *urlencodestring(const char *s) {
460b9539 133 struct dynstr d;
134
135 dynstr_init(&d);
136 urlencode(sink_dynstr(&d), s, strlen(s));
137 dynstr_terminate(&d);
138 return d.vec;
139}
140
b12be54a
RK
141/** @brief URL-decode @p s
142 * @param s String to decode
143 * @param ns Length of string
36bde473 144 * @return Decoded string or NULL
b12be54a 145 */
36bde473 146char *urldecodestring(const char *s, size_t ns) {
b12be54a
RK
147 struct dynstr d;
148
149 dynstr_init(&d);
36bde473 150 if(urldecode(sink_dynstr(&d), s, ns))
151 return NULL;
b12be54a
RK
152 dynstr_terminate(&d);
153 return d.vec;
154}
155
460b9539 156char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
157 struct dynstr d;
158 struct sink *sink;
159
160 dynstr_init(&d);
161 sink = sink_dynstr(&d);
162 while(kvp) {
163 urlencode(sink, kvp->name, strlen(kvp->name));
164 dynstr_append(&d, '=');
165 urlencode(sink, kvp->value, strlen(kvp->value));
166 if((kvp = kvp->next))
167 dynstr_append(&d, '&');
168
169 }
170 dynstr_terminate(&d);
171 if(np)
172 *np = d.nvec;
173 return d.vec;
174}
175
176int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
177 struct kvp *k, **kk;
178
179 for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next)
180 ;
181 if(k) {
182 if(value) {
183 if(strcmp(k->value, value)) {
184 k->value = xstrdup(value);
185 return 1;
186 } else
187 return 0;
188 } else {
189 *kk = k->next;
190 return 1;
191 }
192 } else {
193 if(value) {
194 *kk = k = xmalloc(sizeof *k);
195 k->name = xstrdup(name);
196 k->value = xstrdup(value);
197 return 1;
198 } else
199 return 0;
200 }
201}
202
203const char *kvp_get(const struct kvp *kvp, const char *name) {
204 for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
205 ;
206 return kvp ? kvp->value : 0;
207}
208
b5b7e0bf
RK
209struct kvp *kvp_make(const char *name, ...) {
210 const char *value;
211 struct kvp *kvp = 0, *k;
212 va_list ap;
213
214 va_start(ap, name);
215 while(name) {
216 value = va_arg(ap, const char *);
217 k = xmalloc(sizeof *k);
218 k->name = name;
219 k->value = value ? xstrdup(value) : value;
220 k->next = kvp;
221 kvp = k;
222 name = va_arg(ap, const char *);
223 }
224 va_end(ap);
225 return kvp;
226}
227
460b9539 228/*
229Local Variables:
230c-basic-offset:2
231comment-column:40
232End:
233*/