chiark / gitweb /
Switch to GPL v3
[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 */
18
05b75f8d 19#include "common.h"
460b9539 20
21#include "mem.h"
22#include "kvp.h"
23#include "log.h"
24#include "vector.h"
25#include "hex.h"
26#include "sink.h"
27
28int urldecode(struct sink *sink, const char *ptr, size_t n) {
29 int c, d1, d2;
30
31 while(n-- > 0) {
32 switch(c = *ptr++) {
33 case '%':
34 if((d1 = unhexdigit(ptr[0])) == -1
35 || (d2 = unhexdigit(ptr[1])) == -1)
36 return -1;
37 c = d1 * 16 + d2;
38 ptr += 2;
39 n -= 2;
40 break;
41 case '+':
42 c = ' ';
43 break;
44 default:
45 break;
46 }
47 if(sink_writec(sink,c) < 0)
48 return -1;
49 }
50 return 0;
51}
52
53static char *decode(const char *ptr, size_t n) {
54 struct dynstr d;
55 struct sink *s;
56
57 dynstr_init(&d);
58 s = sink_dynstr(&d);
59 if(urldecode(s, ptr, n))
60 return 0;
61 dynstr_terminate(&d);
62 return d.vec;
63}
64
65struct kvp *kvp_urldecode(const char *ptr, size_t n) {
66 struct kvp *kvp, **kk = &kvp, *k;
67 const char *q, *r, *top = ptr + n, *next;
68
69 while(ptr < top) {
70 *kk = k = xmalloc(sizeof *k);
71 if(!(q = memchr(ptr, '=', top - ptr)))
72 break;
73 if(!(k->name = decode(ptr, q - ptr))) break;
74 if((r = memchr(ptr, '&', top - ptr)))
75 next = r + 1;
76 else
77 next = r = top;
78 if(r < q)
79 break;
80 if(!(k->value = decode(q + 1, r - (q + 1)))) break;
81 kk = &k->next;
82 ptr = next;
83 }
84 *kk = 0;
85 return kvp;
86}
87
88int urlencode(struct sink *sink, const char *s, size_t n) {
89 unsigned char c;
90
91 while(n > 0) {
92 c = *s++;
93 n--;
94 switch(c) {
95 default:
96 if((c >= '0' && c <= '9')
97 || (c >= 'a' && c <= 'z')
98 || (c >= 'A' && c <= 'Z')) {
99 /* RFC2396 2.3 unreserved characters */
100 case '-':
101 case '_':
102 case '.':
103 case '!':
104 case '~':
105 case '*':
106 case '\'':
107 case '(':
108 case ')':
109 /* additional unreserved characters */
110 case '/':
111 if(sink_writec(sink, c) < 0)
112 return -1;
113 } else
114 if(sink_printf(sink, "%%%02x", (unsigned int)c) < 0)
115 return -1;
116 }
117 }
118 return 0;
119}
120
b12be54a
RK
121/** @brief URL-encode @p s
122 * @param s String to encode
123 * @return Encoded string
124 */
36bde473 125char *urlencodestring(const char *s) {
460b9539 126 struct dynstr d;
127
128 dynstr_init(&d);
129 urlencode(sink_dynstr(&d), s, strlen(s));
130 dynstr_terminate(&d);
131 return d.vec;
132}
133
b12be54a
RK
134/** @brief URL-decode @p s
135 * @param s String to decode
136 * @param ns Length of string
36bde473 137 * @return Decoded string or NULL
b12be54a 138 */
36bde473 139char *urldecodestring(const char *s, size_t ns) {
b12be54a
RK
140 struct dynstr d;
141
142 dynstr_init(&d);
36bde473 143 if(urldecode(sink_dynstr(&d), s, ns))
144 return NULL;
b12be54a
RK
145 dynstr_terminate(&d);
146 return d.vec;
147}
148
460b9539 149char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
150 struct dynstr d;
151 struct sink *sink;
152
153 dynstr_init(&d);
154 sink = sink_dynstr(&d);
155 while(kvp) {
156 urlencode(sink, kvp->name, strlen(kvp->name));
157 dynstr_append(&d, '=');
158 urlencode(sink, kvp->value, strlen(kvp->value));
159 if((kvp = kvp->next))
160 dynstr_append(&d, '&');
161
162 }
163 dynstr_terminate(&d);
164 if(np)
165 *np = d.nvec;
166 return d.vec;
167}
168
169int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
170 struct kvp *k, **kk;
171
172 for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next)
173 ;
174 if(k) {
175 if(value) {
176 if(strcmp(k->value, value)) {
177 k->value = xstrdup(value);
178 return 1;
179 } else
180 return 0;
181 } else {
182 *kk = k->next;
183 return 1;
184 }
185 } else {
186 if(value) {
187 *kk = k = xmalloc(sizeof *k);
188 k->name = xstrdup(name);
189 k->value = xstrdup(value);
190 return 1;
191 } else
192 return 0;
193 }
194}
195
196const char *kvp_get(const struct kvp *kvp, const char *name) {
197 for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
198 ;
199 return kvp ? kvp->value : 0;
200}
201
b5b7e0bf
RK
202struct kvp *kvp_make(const char *name, ...) {
203 const char *value;
204 struct kvp *kvp = 0, *k;
205 va_list ap;
206
207 va_start(ap, name);
208 while(name) {
209 value = va_arg(ap, const char *);
210 k = xmalloc(sizeof *k);
211 k->name = name;
212 k->value = value ? xstrdup(value) : value;
213 k->next = kvp;
214 kvp = k;
215 name = va_arg(ap, const char *);
216 }
217 va_end(ap);
218 return kvp;
219}
220
460b9539 221/*
222Local Variables:
223c-basic-offset:2
224comment-column:40
225End:
226*/