chiark / gitweb /
Infrastructure: Strip away crufty CVS $Id$ tags.
[mLib] / url.c
1 /* -*-c-*-
2  *
3  * Parsing and construction of url-encoded name/value pairs
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "dstr.h"
36 #include "url.h"
37
38 /*----- Main code ---------------------------------------------------------*/
39
40 /* --- @url_initenc@ --- *
41  *
42  * Arguments:   @url_ectx *ctx@ = pointer to context block
43  *
44  * Returns:     ---
45  *
46  * Use:         Initializes a URL encoding context.
47  */
48
49 void url_initenc(url_ectx *ctx) { ctx->f = 0; }
50
51 /* --- @encode@ --- *
52  *
53  * Arguments:   @url_ectx *ctx@ = encoding context
54  *              @dstr *d@ = pointer to output string
55  *              @const char *p@ = pointer to thing to encode
56  *
57  * Returns:     ---
58  *
59  * Use:         Encodes the input string into the output string.
60  */
61
62 static void encode(url_ectx *ctx, dstr *d, const char *p)
63 {
64   while (*p) {
65     switch (*p) {
66       case ' ':
67         DPUTC(d, '+');
68         break;
69       default:
70         if ((ctx->f & URLF_LAX) || isalnum((unsigned char)*p))
71           goto safe;
72         else
73           goto unsafe;
74       case '/':
75       case '~':
76         if (ctx->f & URLF_STRICT)
77           goto unsafe;
78       case '-':
79       case '.':
80       case '_':
81       safe:
82         DPUTC(d, *p);
83         break;
84       unsafe:
85       case '+':
86       case '%':
87       case '=':
88       case '&':
89       case ';':
90         dstr_putf(d, "%%%02x", *p);
91         break;
92     }
93     p++;
94   }
95 }
96
97 /* --- @url_enc@ --- *
98  *
99  * Arguments:   @url_ectx *ctx@ = pointer to encoding context
100  *              @dstr *d@ = pointer to output string
101  *              @const char *name@ = pointer to name
102  *              @const char *value@ = pointer to value
103  *
104  * Returns:     ---
105  *
106  * Use:         Writes an assignment between @name@ and @value@ to the
107  *              output string, encoding the values properly.
108  */
109
110 void url_enc(url_ectx *ctx, dstr *d, const char *name, const char *value)
111 {
112   if (ctx->f & URLF_SEP)
113     DPUTC(d, (ctx->f & URLF_SEMI) ? ';' : '&');
114   encode(ctx, d, name);
115   DPUTC(d, '=');
116   encode(ctx, d, value);
117   DPUTZ(d);
118   ctx->f |= URLF_SEP;
119 }
120
121 /* --- @url_initdec@ --- *
122  *
123  * Arguments:   @url_dctx *ctx@ = pointer to context block
124  *              @const char *p@ = string to read data from
125  *
126  * Returns:     ---
127  *
128  * Use:         Initializes a URL decoding context.
129  */
130
131 void url_initdec(url_dctx *ctx, const char *p) { ctx->p = p; ctx->f = 0; }
132
133 /* --- @decode@ --- *
134  *
135  * Arguments:   @url_dctx *ctx@ = pointer to the context
136  *              @dstr *d@ = pointer to output string
137  *              @const char *p@ = pointer to input data
138  *              @int eq@ = whether to stop at `=' characters
139  *
140  * Returns:     Pointer to next available character.
141  *
142  * Use:         Does a URL decode.
143  */
144
145 static const char *decode(url_dctx *ctx, dstr *d, const char *p, int eq)
146 {
147   if (!*p)
148     return (0);
149   for (;;) {
150     switch (*p) {
151       case '=':
152         if (eq)
153           return (p);
154         goto boring;
155       case ';':
156         if (ctx->f & URLF_SEMI)
157           return (p);
158         goto boring;
159       case 0:
160       case '&':
161         return (p);
162       case '+':
163         DPUTC(d, ' ');
164         break;
165       case '%': {
166         unsigned int ch;
167         int n;
168         int x = sscanf(p + 1, "%2x%n", &ch, &n);
169         if (x == 1) {
170           DPUTC(d, ch);
171           p += n;
172           break;
173         }
174       }
175       default:
176       boring:
177         DPUTC(d, *p);
178         break;
179     }
180     p++;
181   }
182 }
183
184 /* --- @url_dec@ --- *
185  *
186  * Arguments:   @url_dctx *ctx@ = pointer to decode context
187  *              @dstr *n@ = pointer to output string for name
188  *              @dstr *v@ = pointer to output string for value
189  *
190  * Returns:     Nonzero if it read something, zero if there's nothing left
191  *
192  * Use:         Decodes the next name/value pair from a urlencoded string.
193  */
194
195 int url_dec(url_dctx *ctx, dstr *n, dstr *v)
196 {
197   const char *p = ctx->p;
198   size_t l = n->len;
199
200 again:
201   if ((p = decode(ctx, n, p, 1)) == 0 || *p == 0)
202     return (0);
203   if (*p != '=') {
204     p++;
205     n->len = l;
206     goto again;
207   }
208   p++;
209   if ((p = decode(ctx, v, p, 0)) == 0)
210     return (0);
211   DPUTZ(n);
212   DPUTZ(v);
213   ctx->p = p;
214   return (1);
215 }
216
217 /*----- That's all, folks -------------------------------------------------*/