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 1856
VAV_BackSlash(const char *s, char *res)
53
{
54
        int r;
55
        char c;
56
        unsigned u;
57
58 1856
        assert(*s == '\\');
59 1856
        r = c = 0;
60 1856
        switch (s[1]) {
61
        case 'n':
62 964
                c = '\n';
63 964
                r = 2;
64 964
                break;
65
        case 'r':
66 654
                c = '\r';
67 654
                r = 2;
68 654
                break;
69
        case 't':
70 2
                c = '\t';
71 2
                r = 2;
72 2
                break;
73
        case '"':
74 180
                c = '"';
75 180
                r = 2;
76 180
                break;
77
        case '\\':
78 10
                c = '\\';
79 10
                r = 2;
80 10
                break;
81
        case '0': case '1': case '2': case '3':
82
        case '4': case '5': case '6': case '7':
83 20
                for (r = 1; r < 4; r++) {
84 16
                        if (!isdigit(s[r]))
85 2
                                break;
86 14
                        if (s[r] - '0' > 7)
87 0
                                break;
88 14
                        c <<= 3;        /*lint !e701 signed left shift */
89 14
                        c |= s[r] - '0';
90
                }
91 6
                break;
92
        case 'x':
93 32
                if (1 == sscanf(s + 1, "x%02x", &u)) {
94 32
                        AZ(u & ~0xff);
95 32
                        c = u;  /*lint !e734 loss of precision */
96 32
                        r = 4;
97
                }
98 32
                break;
99
        default:
100 8
                break;
101
        }
102 1856
        if (res != NULL)
103 1796
                *res = c;
104 1856
        return (r);
105
}
106
107
char *
108 439865
VAV_BackSlashDecode(const char *s, const char *e)
109
{
110
        const char *q;
111
        char *p, *r;
112
        int i;
113
114 439865
        if (e == NULL)
115 0
                e = strchr(s, '\0');
116 439865
        assert(e != NULL);
117 439865
        p = calloc(1, (e - s) + 1L);
118 439865
        if (p == NULL)
119 0
                return (p);
120 5038421
        for (r = p, q = s; q < e; ) {
121 4158691
                if (*q != '\\') {
122 4158639
                        *r++ = *q++;
123 4158639
                        continue;
124
                }
125 52
                i = VAV_BackSlash(q, r);
126 52
                q += i;
127 52
                r++;
128
        }
129 439865
        *r = '\0';
130 439865
        return (p);
131
}
132
133
static char err_invalid_backslash[] = "Invalid backslash sequence";
134
static char err_missing_quote[] = "Missing '\"'";
135
136
char **
137 132833
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 132833
        assert(s != NULL);
145 132833
        nargv = 1;
146 132833
        largv = 16;
147 132833
        argv = calloc(largv, sizeof *argv);
148 132833
        if (argv == NULL)
149 0
                return (NULL);
150
151
        for (;;) {
152 574120
                if (*s == '\0')
153 132815
                        break;
154 441305
                if (isspace(*s)) {
155 1268
                        s++;
156 1268
                        continue;
157
                }
158 440037
                if ((flag & ARGV_COMMENT) && *s == '#')
159 0
                        break;
160 440037
                if (*s == '"' && !(flag & ARGV_NOESC)) {
161 2512
                        p = ++s;
162 2512
                        quote = 1;
163
                } else {
164 437525
                        p = s;
165 437525
                        quote = 0;
166
                }
167
                while (1) {
168 4599416
                        if (*s == '\\' && !(flag & ARGV_NOESC)) {
169 60
                                i = VAV_BackSlash(s, NULL);
170 60
                                if (i == 0) {
171 8
                                        argv[0] = err_invalid_backslash;
172 8
                                        return (argv);
173
                                }
174 52
                                s += i;
175 52
                                continue;
176
                        }
177 4599356
                        if (!quote) {
178 4586046
                                if (*s == '\0' || isspace(*s))
179
                                        break;
180 4158393
                                if ((flag & ARGV_COMMA) && *s == ',')
181 9864
                                        break;
182 4148529
                                s++;
183 4148529
                                continue;
184
                        }
185 13310
                        if (*s == '"' && !(flag & ARGV_NOESC))
186 2502
                                break;
187 10808
                        if (*s == '\0') {
188 10
                                argv[0] = err_missing_quote;
189 10
                                return (argv);
190
                        }
191 10798
                        s++;
192 4159379
                }
193 440019
                if (nargv + 1 >= largv) {
194 0
                        argv = realloc(argv, sizeof (*argv) * (largv += largv));
195 0
                        assert(argv != NULL);
196
                }
197 440019
                if (flag & ARGV_NOESC) {
198 154
                        argv[nargv] = malloc(1L + (s - p));
199 154
                        assert(argv[nargv] != NULL);
200 154
                        memcpy(argv[nargv], p, s - p);
201 154
                        argv[nargv][s - p] = '\0';
202 154
                        nargv++;
203
                } else {
204 439865
                        argv[nargv++] = VAV_BackSlashDecode(p, s);
205
                }
206 440019
                if (*s != '\0')
207 317759
                        s++;
208 441287
        }
209 132815
        argv[nargv] = NULL;
210 132815
        if (argc != NULL)
211 122187
                *argc = nargv;
212 132815
        return (argv);
213
}
214
215
void
216 128423
VAV_Free(char **argv)
217
{
218
        int i;
219
220 557430
        for (i = 1; argv[i] != NULL; i++)
221 429007
                free(argv[i]);
222 128423
        free(argv);
223 128423
}
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