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