chiark / gitweb /
Headers: Guard inclusion of mLib headers.
[mLib] / url.c
CommitLineData
0f2a8846 1/* -*-c-*-
0f2a8846 2 *
3 * Parsing and construction of url-encoded name/value pairs
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
d4efbcd9 8/*----- Licensing notice --------------------------------------------------*
0f2a8846 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.
d4efbcd9 16 *
0f2a8846 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.
d4efbcd9 21 *
0f2a8846 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
0f2a8846 28/*----- Header files ------------------------------------------------------*/
29
78b1464e 30#include <ctype.h>
0f2a8846 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
0ddebb8f 49void url_initenc(url_ectx *ctx) { ctx->f = 0; }
0f2a8846 50
51/* --- @encode@ --- *
52 *
7e4708e4
MW
53 * Arguments: @url_ectx *ctx@ = encoding context
54 * @dstr *d@ = pointer to output string
0f2a8846 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
7e4708e4 62static void encode(url_ectx *ctx, dstr *d, const char *p)
0f2a8846 63{
64 while (*p) {
65 switch (*p) {
66 case ' ':
67 DPUTC(d, '+');
d4efbcd9 68 break;
0f2a8846 69 default:
d4efbcd9 70 if ((ctx->f & URLF_LAX) || isalnum((unsigned char)*p))
7e4708e4
MW
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;
0f2a8846 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
110void url_enc(url_ectx *ctx, dstr *d, const char *name, const char *value)
111{
112 if (ctx->f & URLF_SEP)
9dc511e4 113 DPUTC(d, (ctx->f & URLF_SEMI) ? ';' : '&');
7e4708e4 114 encode(ctx, d, name);
0f2a8846 115 DPUTC(d, '=');
7e4708e4 116 encode(ctx, d, value);
0f2a8846 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
9dc511e4 131void url_initdec(url_dctx *ctx, const char *p) { ctx->p = p; ctx->f = 0; }
0f2a8846 132
133/* --- @decode@ --- *
134 *
9dc511e4
MW
135 * Arguments: @url_dctx *ctx@ = pointer to the context
136 * @dstr *d@ = pointer to output string
0f2a8846 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
9dc511e4 145static const char *decode(url_dctx *ctx, dstr *d, const char *p, int eq)
0f2a8846 146{
147 if (!*p)
148 return (0);
149 for (;;) {
150 switch (*p) {
151 case '=':
152 if (eq)
153 return (p);
9dc511e4
MW
154 goto boring;
155 case ';':
156 if (ctx->f & URLF_SEMI)
157 return (p);
158 goto boring;
0f2a8846 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:
9dc511e4 176 boring:
0f2a8846 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
195int url_dec(url_dctx *ctx, dstr *n, dstr *v)
196{
197 const char *p = ctx->p;
198 size_t l = n->len;
199
200again:
9dc511e4 201 if ((p = decode(ctx, n, p, 1)) == 0 || *p == 0)
0f2a8846 202 return (0);
203 if (*p != '=') {
204 p++;
205 n->len = l;
206 goto again;
207 }
208 p++;
9dc511e4 209 if ((p = decode(ctx, v, p, 0)) == 0)
0f2a8846 210 return (0);
211 DPUTZ(n);
212 DPUTZ(v);
213 ctx->p = p;
214 return (1);
215}
216
217/*----- That's all, folks -------------------------------------------------*/