varnish-cache/lib/libvarnish/vav.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * const char **VAV_Parse(const char *s, int *argc, int flag)
30
 *      Parse a command like line into an argv[]
31
 *      Index zero contains NULL or an error message
32
 *      "double quotes" and backslash substitution is handled.
33
 *
34
 * void VAV_Free(const char **argv)
35
 *      Free the result of VAV_Parse()
36
 *
37
 */
38
39
#include "config.h"
40
41
#include <ctype.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
46
#include "vdef.h"
47
48
#include "vas.h"
49
#include "vav.h"
50
51
int
52 7398
VAV_BackSlash(const char *s, char *res)
53
{
54
        int r;
55
        char c;
56
        unsigned u;
57
58 7398
        assert(*s == '\\');
59 7398
        r = c = 0;
60 7398
        switch (s[1]) {
61
        case 'n':
62 3480
                c = '\n';
63 3480
                r = 2;
64 3480
                break;
65
        case 'r':
66 2865
                c = '\r';
67 2865
                r = 2;
68 2865
                break;
69
        case 't':
70 18
                c = '\t';
71 18
                r = 2;
72 18
                break;
73
        case '"':
74 306
                c = '"';
75 306
                r = 2;
76 306
                break;
77
        case '\\':
78 87
                c = '\\';
79 87
                r = 2;
80 87
                break;
81
        case '0': case '1': case '2': case '3':
82
        case '4': case '5': case '6': case '7':
83 42
                for (r = 1; r < 4; r++) {
84 33
                        if (!isdigit(s[r]))
85 3
                                break;
86 30
                        if (s[r] - '0' > 7)
87 0
                                break;
88 30
                        c <<= 3;        /*lint !e701 signed left shift */
89 30
                        c |= s[r] - '0';
90
                }
91 12
                break;
92
        case 'x':
93 618
                if (1 == sscanf(s + 1, "x%02x", &u)) {
94 618
                        AZ(u & ~0xff);
95 618
                        c = u;  /*lint !e734 loss of precision */
96 618
                        r = 4;
97
                }
98 618
                break;
99
        default:
100 12
                break;
101
        }
102 7398
        if (res != NULL)
103 7290
                *res = c;
104 7398
        return (r);
105
}
106
107
char *
108 1137029
VAV_BackSlashDecode(const char *s, const char *e)
109
{
110
        const char *q;
111
        char *p, *r;
112
        int i;
113
114 1137029
        if (e == NULL)
115 0
                e = strchr(s, '\0');
116 1137029
        assert(e != NULL);
117 1137029
        p = calloc(1, (e - s) + 1L);
118 1137029
        if (p == NULL)
119 0
                return (p);
120 11427954
        for (r = p, q = s; q < e; ) {
121 9153896
                if (*q != '\\') {
122 9153800
                        *r++ = *q++;
123 9153800
                        continue;
124
                }
125 96
                i = VAV_BackSlash(q, r);
126 96
                q += i;
127 96
                r++;
128
        }
129 1137029
        *r = '\0';
130 1137029
        return (p);
131
}
132
133
static char err_invalid_backslash[] = "Invalid backslash sequence";
134
static char err_missing_quote[] = "Missing '\"'";
135
136
char **
137 274340
VAV_Parse(const char *s, int *argc, int flag)
138
{
139
        char **argv;
140
        const char *p;
141
        int nargv, largv;
142
        int i, quote;
143
144 274340
        assert(s != NULL);
145 274340
        nargv = 1;
146 274340
        largv = 16;
147 274340
        argv = calloc(largv, sizeof *argv);
148 274340
        if (argv == NULL)
149 0
                return (NULL);
150
151
        for (;;) {
152 2563370
                if (*s == '\0')
153 274313
                        break;
154 1144542
                if (isspace(*s)) {
155 7255
                        s++;
156 7255
                        continue;
157
                }
158 1137287
                if ((flag & ARGV_COMMENT) && *s == '#')
159 0
                        break;
160 1137287
                if (*s == '"' && !(flag & ARGV_NOESC)) {
161 4206
                        p = ++s;
162 4206
                        quote = 1;
163
                } else {
164 1133081
                        p = s;
165 1133081
                        quote = 0;
166
                }
167
                while (1) {
168 19447143
                        if (*s == '\\' && !(flag & ARGV_NOESC)) {
169 108
                                i = VAV_BackSlash(s, NULL);
170 108
                                if (i == 0) {
171 12
                                        argv[0] = err_invalid_backslash;
172 12
                                        return (argv);
173
                                }
174 96
                                s += i;
175 96
                                continue;
176
                        }
177 10292107
                        if (!quote) {
178 10269595
                                if (*s == '\0' || isspace(*s))
179
                                        break;
180 9153665
                                if ((flag & ARGV_COMMA) && *s == ',')
181 17139
                                        break;
182 9136526
                                s++;
183 9136526
                                continue;
184
                        }
185 22512
                        if (*s == '"' && !(flag & ARGV_NOESC))
186 4191
                                break;
187 18321
                        if (*s == '\0') {
188 15
                                argv[0] = err_missing_quote;
189 15
                                return (argv);
190
                        }
191 18306
                        s++;
192
                }
193 1137260
                if (nargv + 1 >= largv) {
194 0
                        argv = realloc(argv, sizeof (*argv) * (largv += largv));
195 0
                        assert(argv != NULL);
196
                }
197 1137260
                if (flag & ARGV_NOESC) {
198 231
                        argv[nargv] = malloc(1L + (s - p));
199 231
                        assert(argv[nargv] != NULL);
200 231
                        memcpy(argv[nargv], p, s - p);
201 231
                        argv[nargv][s - p] = '\0';
202 231
                        nargv++;
203
                } else {
204 1137029
                        argv[nargv++] = VAV_BackSlashDecode(p, s);
205
                }
206 1137260
                if (*s != '\0')
207 886266
                        s++;
208
        }
209 274313
        argv[nargv] = NULL;
210 274313
        if (argc != NULL)
211 255983
                *argc = nargv;
212 274313
        return (argv);
213
}
214
215
void
216 266273
VAV_Free(char **argv)
217
{
218
        int i;
219
220 1381147
        for (i = 1; argv[i] != NULL; i++)
221 1114874
                free(argv[i]);
222 266273
        free(argv);
223 266273
}
224
225
#ifdef TESTPROG
226
227
#include <printf.h>
228
229
static void
230
VAV_Print(char **argv)
231
{
232
        int i;
233
234
        printf("---- %p\n", argv);
235
        if (argv[0] != NULL)
236
                printf("err %V\n", argv[0]);
237
        for (i = 1; argv[i] != NULL; i++)
238
                printf("%3d %V\n", i, argv[i]);
239
}
240
241
static void
242
Test(const char *str)
243
{
244
        char **av;
245
246
        printf("Test: <%V>\n", str);
247
        av = VAV_Parse(str, NULL, 0);
248
        VAV_Print(av);
249
}
250
251
#if defined __linux__
252
int
253
printf_v(FILE *stream, const struct printf_info *info,
254
    const void *const *args)
255
{
256
        const char *v = *((char **)args[0]);
257
        return (fprintf(stream, "%*s",
258
            info->left ? -info->width : info->width, v));
259
}
260
261
int
262
printf_v_info(const struct printf_info *info, size_t n, int *argtypes,
263
    int *size)
264
{
265
        if (n > 0)
266
                argtypes[0] = PA_STRING;
267
        return (1);
268
}
269
#endif
270
271
int
272
main(int argc, char **argv)
273
{
274
        char buf[BUFSIZ];
275
276
        (void)argc;
277
        (void)argv;
278
279
#if defined __FreeBSD__
280
        register_printf_render_std("V");
281
#elif defined __linux__
282
        register_printf_specifier('V', printf_v, printf_v_info);
283
#else
284
#error Unsupported platform
285
#endif
286
287
        while (fgets(buf, sizeof buf, stdin))
288
                Test(buf);
289
290
        return (0);
291
}
292
#endif