chiark / gitweb /
struct/buf.c: Add functions for serializing and deserializing `kludge64'.
[mLib] / codec / 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"
36188114 36#include "macros.h"
0f2a8846 37#include "url.h"
38
39/*----- Main code ---------------------------------------------------------*/
40
41/* --- @url_initenc@ --- *
42 *
43 * Arguments: @url_ectx *ctx@ = pointer to context block
44 *
45 * Returns: ---
46 *
47 * Use: Initializes a URL encoding context.
48 */
49
0ddebb8f 50void url_initenc(url_ectx *ctx) { ctx->f = 0; }
0f2a8846 51
52/* --- @encode@ --- *
53 *
7e4708e4
MW
54 * Arguments: @url_ectx *ctx@ = encoding context
55 * @dstr *d@ = pointer to output string
0f2a8846 56 * @const char *p@ = pointer to thing to encode
57 *
58 * Returns: ---
59 *
60 * Use: Encodes the input string into the output string.
61 */
62
7e4708e4 63static void encode(url_ectx *ctx, dstr *d, const char *p)
0f2a8846 64{
65 while (*p) {
66 switch (*p) {
96e10f28 67 case ' ': DPUTC(d, '+');
d4efbcd9 68 break;
0f2a8846 69 default:
36188114
MW
70 if (ISSPACE(*p)) goto unsafe;
71 else if (ISALNUM(*p)) goto safe;
96e10f28
MW
72 else if (ctx->f&URLF_LAX) goto safe;
73 else goto unsafe;
74 case '/': case '~':
75 if (ctx->f&URLF_STRICT) goto unsafe; /* else fall through... */
76 safe: case '-': case '.': case '_':
77 DPUTC(d, *p); break;
78 unsafe: case '+': case '%': case '=': case '&': case ';':
79 dstr_putf(d, "%%%02x", *p); break;
0f2a8846 80 }
81 p++;
82 }
83}
84
85/* --- @url_enc@ --- *
86 *
87 * Arguments: @url_ectx *ctx@ = pointer to encoding context
88 * @dstr *d@ = pointer to output string
89 * @const char *name@ = pointer to name
90 * @const char *value@ = pointer to value
91 *
92 * Returns: ---
93 *
94 * Use: Writes an assignment between @name@ and @value@ to the
95 * output string, encoding the values properly.
96 */
97
98void url_enc(url_ectx *ctx, dstr *d, const char *name, const char *value)
99{
100 if (ctx->f & URLF_SEP)
9dc511e4 101 DPUTC(d, (ctx->f & URLF_SEMI) ? ';' : '&');
7e4708e4 102 encode(ctx, d, name);
0f2a8846 103 DPUTC(d, '=');
7e4708e4 104 encode(ctx, d, value);
0f2a8846 105 DPUTZ(d);
106 ctx->f |= URLF_SEP;
107}
108
109/* --- @url_initdec@ --- *
110 *
111 * Arguments: @url_dctx *ctx@ = pointer to context block
112 * @const char *p@ = string to read data from
113 *
114 * Returns: ---
115 *
116 * Use: Initializes a URL decoding context.
117 */
118
9dc511e4 119void url_initdec(url_dctx *ctx, const char *p) { ctx->p = p; ctx->f = 0; }
0f2a8846 120
121/* --- @decode@ --- *
122 *
9dc511e4
MW
123 * Arguments: @url_dctx *ctx@ = pointer to the context
124 * @dstr *d@ = pointer to output string
0f2a8846 125 * @const char *p@ = pointer to input data
126 * @int eq@ = whether to stop at `=' characters
127 *
128 * Returns: Pointer to next available character.
129 *
130 * Use: Does a URL decode.
131 */
132
9dc511e4 133static const char *decode(url_dctx *ctx, dstr *d, const char *p, int eq)
0f2a8846 134{
135 if (!*p)
136 return (0);
137 for (;;) {
138 switch (*p) {
139 case '=':
140 if (eq)
141 return (p);
9dc511e4
MW
142 goto boring;
143 case ';':
144 if (ctx->f & URLF_SEMI)
145 return (p);
146 goto boring;
0f2a8846 147 case 0:
148 case '&':
149 return (p);
150 case '+':
151 DPUTC(d, ' ');
152 break;
153 case '%': {
154 unsigned int ch;
155 int n;
156 int x = sscanf(p + 1, "%2x%n", &ch, &n);
157 if (x == 1) {
158 DPUTC(d, ch);
159 p += n;
160 break;
161 }
162 }
163 default:
9dc511e4 164 boring:
0f2a8846 165 DPUTC(d, *p);
166 break;
167 }
168 p++;
169 }
170}
171
172/* --- @url_dec@ --- *
173 *
174 * Arguments: @url_dctx *ctx@ = pointer to decode context
175 * @dstr *n@ = pointer to output string for name
176 * @dstr *v@ = pointer to output string for value
177 *
178 * Returns: Nonzero if it read something, zero if there's nothing left
179 *
180 * Use: Decodes the next name/value pair from a urlencoded string.
181 */
182
183int url_dec(url_dctx *ctx, dstr *n, dstr *v)
184{
185 const char *p = ctx->p;
186 size_t l = n->len;
187
188again:
9dc511e4 189 if ((p = decode(ctx, n, p, 1)) == 0 || *p == 0)
0f2a8846 190 return (0);
191 if (*p != '=') {
192 p++;
193 n->len = l;
194 goto again;
195 }
196 p++;
9dc511e4 197 if ((p = decode(ctx, v, p, 0)) == 0)
0f2a8846 198 return (0);
199 DPUTZ(n);
200 DPUTZ(v);
201 ctx->p = p;
202 return (1);
203}
204
205/*----- That's all, folks -------------------------------------------------*/