2 * This file is part of DisOrder.
3 * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
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 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 int urldecode(struct sink *sink, const char *ptr, size_t n) {
34 if((d1 = unhexdigit(ptr[0])) == -1
35 || (d2 = unhexdigit(ptr[1])) == -1)
47 if(sink_writec(sink,c) < 0)
53 static char *decode(const char *ptr, size_t n) {
59 if(urldecode(s, ptr, n))
65 struct 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;
70 *kk = k = xmalloc(sizeof *k);
71 if(!(q = memchr(ptr, '=', top - ptr)))
73 if(!(k->name = decode(ptr, q - ptr))) break;
74 if((r = memchr(ptr, '&', top - ptr)))
80 if(!(k->value = decode(q + 1, r - (q + 1)))) break;
88 int urlencode(struct sink *sink, const char *s, size_t n) {
96 if((c >= '0' && c <= '9')
97 || (c >= 'a' && c <= 'z')
98 || (c >= 'A' && c <= 'Z')) {
99 /* RFC2396 2.3 unreserved characters */
109 /* additional unreserved characters */
111 if(sink_writec(sink, c) < 0)
114 if(sink_printf(sink, "%%%02x", (unsigned int)c) < 0)
121 /** @brief URL-encode @p s
122 * @param s String to encode
123 * @return Encoded string
125 char *urlencodestring(const char *s) {
129 urlencode(sink_dynstr(&d), s, strlen(s));
130 dynstr_terminate(&d);
134 /** @brief URL-decode @p s
135 * @param s String to decode
136 * @param ns Length of string
137 * @return Decoded string or NULL
139 char *urldecodestring(const char *s, size_t ns) {
143 if(urldecode(sink_dynstr(&d), s, ns))
145 dynstr_terminate(&d);
149 char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
154 sink = sink_dynstr(&d);
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, '&');
163 dynstr_terminate(&d);
169 int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
172 for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next)
176 if(strcmp(k->value, value)) {
177 k->value = xstrdup(value);
187 *kk = k = xmalloc(sizeof *k);
188 k->name = xstrdup(name);
189 k->value = xstrdup(value);
196 const char *kvp_get(const struct kvp *kvp, const char *name) {
197 for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
199 return kvp ? kvp->value : 0;
202 struct kvp *kvp_make(const char *name, ...) {
204 struct kvp *kvp = 0, *k;
209 value = va_arg(ap, const char *);
210 k = xmalloc(sizeof *k);
212 k->value = value ? xstrdup(value) : value;
215 name = va_arg(ap, const char *);