chiark / gitweb /
totally untested multicast support
[disorder] / lib / kvp.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004, 2005 Richard Kettlewell
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
34 int 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
59 static 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
71 struct 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
94 int 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
127 const char *urlencodestring(const char *s) {
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
136 char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
137   struct dynstr d;
138   struct sink *sink;
139
140   dynstr_init(&d);
141   sink = sink_dynstr(&d);
142   while(kvp) {
143     urlencode(sink, kvp->name, strlen(kvp->name));
144     dynstr_append(&d, '=');
145     urlencode(sink, kvp->value, strlen(kvp->value));
146     if((kvp = kvp->next))
147       dynstr_append(&d, '&');
148     
149   }
150   dynstr_terminate(&d);
151   if(np)
152     *np = d.nvec;
153   return d.vec;
154 }
155
156 int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
157   struct kvp *k, **kk;
158
159   for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next)
160     ;
161   if(k) {
162     if(value) {
163       if(strcmp(k->value, value)) {
164         k->value = xstrdup(value);
165         return 1;
166       } else
167         return 0;
168     } else {
169       *kk = k->next;
170       return 1;
171     }
172   } else {
173     if(value) {
174       *kk = k = xmalloc(sizeof *k);
175       k->name = xstrdup(name);
176       k->value = xstrdup(value);
177       return 1;
178     } else
179       return 0;
180   }
181 }
182
183 const char *kvp_get(const struct kvp *kvp, const char *name) {
184   for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
185     ;
186   return kvp ? kvp->value : 0;
187 }
188
189 /*
190 Local Variables:
191 c-basic-offset:2
192 comment-column:40
193 End:
194 */