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