varnish-cache/lib/libvarnish/vte.c
0
/*-
1
 * Copyright (c) 2019 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 * Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <errno.h>
35
#include <limits.h>
36
#include <stdarg.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <sys/types.h> /* for MUSL (ssize_t) */
40
41
#include "vdef.h"
42
#include "miniobj.h"
43
44
#include "vas.h"
45
#include "vsb.h"
46
#include "vte.h"
47
48
#define MINSEP 1
49
#define MAXSEP 3
50
51
struct vte {
52
        unsigned        magic;
53
#define VTE_MAGIC       0xedf42b97
54
        struct vsb      *vsb;
55
        int             c_off;          /* input char offset */
56
        int             l_sz;           /* input line size */
57
        int             l_maxsz;        /* maximum input line size */
58
        int             o_sz;           /* output sz */
59
        int             o_sep;          /* output field separators */
60
        int             f_off;          /* input field offset */
61
        int             f_sz;           /* input field size */
62
        int             f_cnt;          /* actual number of fields */
63
        int             f_maxcnt;       /* maximum number of fields */
64
        int             f_maxsz[]
65
            v_counted_by_(f_maxcnt);    /* maximum size per field */
66
};
67
68
struct vte *
69 17034
VTE_new(int maxfields, int width)
70
{
71
        struct vte *vte;
72
73 17034
        assert(maxfields > 0);
74 17034
        assert(width > 0);
75
76 17034
        ALLOC_FLEX_OBJ(vte, f_maxsz, maxfields, VTE_MAGIC);
77 17034
        if (vte != NULL) {
78 17034
                vte->o_sz = width;
79 17034
                vte->f_maxcnt = maxfields;
80 17034
                vte->vsb = VSB_new_auto();
81 17034
                AN(vte->vsb);
82 17034
        }
83 17034
        return (vte);
84
}
85
86
void
87 17034
VTE_destroy(struct vte **vtep)
88
{
89
        struct vte *vte;
90
91 17034
        TAKE_OBJ_NOTNULL(vte, vtep, VTE_MAGIC);
92 17034
        AN(vte->vsb);
93 17034
        VSB_destroy(&vte->vsb);
94 17034
        FREE_OBJ(vte);
95 17034
}
96
97
static int
98 108934
vte_update(struct vte *vte)
99
{
100
        const char *p, *q;
101
        int len, fno;
102
103 108934
        AZ(vte->o_sep);
104
105 108934
        len = VSB_len(vte->vsb);
106 108934
        assert(len >= vte->c_off);
107
108 108934
        p = vte->vsb->s_buf + vte->c_off;
109 108934
        q = vte->vsb->s_buf + len;
110 2139411
        for (; p < q; p++) {
111 2030477
                if (vte->f_off < 0) {
112 80308
                        while (p < q && *p != '\n')
113 79084
                                p++;
114 1224
                }
115 2030477
                if (vte->l_sz == 0 && *p == ' ') {
116 1224
                        vte->f_off = -1;
117 1224
                        continue;
118
                }
119 2029253
                if (vte->f_off >= 0 && vte->f_sz == 0 && *p == '\v')
120 2906
                        p++;
121 2029253
                if (*p == '\t' || *p == '\n') {
122 205831
                        fno = vte->f_off;
123 205831
                        if (fno >= 0 && vte->f_sz > vte->f_maxsz[fno])
124 129360
                                vte->f_maxsz[fno] = vte->f_sz;
125 205831
                        fno++;
126 205831
                        assert(fno <= vte->f_maxcnt);
127 205831
                        if (*p == '\t' && fno == vte->f_maxcnt) {
128 0
                                errno = EOVERFLOW;
129 0
                                vte->o_sep = -1;
130 0
                                return (-1);
131
                        }
132 205831
                        vte->f_off = fno;
133 205831
                        vte->f_sz = 0;
134 205831
                }
135 2029253
                if (*p == '\n') {
136 42431
                        vte->f_cnt = vmax(vte->f_cnt, vte->f_off);
137 42431
                        vte->l_maxsz = vmax(vte->l_maxsz, vte->l_sz);
138 42431
                        vte->f_off = 0;
139 42431
                        vte->f_sz = 0;
140 42431
                        vte->l_sz = 0;
141 2029253
                } else if (*p != '\t') {
142 1823422
                        vte->f_sz++;
143 1823422
                        vte->l_sz++;
144 1823422
                }
145 2029253
        }
146
147 108934
        vte->c_off = len;
148 108934
        return (0);
149 108934
}
150
151
int
152 0
VTE_putc(struct vte *vte, char c)
153
{
154
155 0
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
156 0
        AN(c);
157
158 0
        if (vte->o_sep != 0)
159 0
                return (-1);
160
161 0
        if (VSB_putc(vte->vsb, c) < 0) {
162 0
                vte->o_sep = -1;
163 0
                return (-1);
164
        }
165
166 0
        return (vte_update(vte));
167 0
}
168
169
int
170 45814
VTE_cat(struct vte *vte, const char *s)
171
{
172
173 45814
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
174 45814
        AN(s);
175
176 45814
        if (vte->o_sep != 0)
177 0
                return (-1);
178
179 45814
        if (VSB_cat(vte->vsb, s) < 0) {
180 0
                vte->o_sep = -1;
181 0
                return (-1);
182
        }
183
184 45814
        return (vte_update(vte));
185 45814
}
186
187
int
188 63120
VTE_printf(struct vte *vte, const char *fmt, ...)
189
{
190
        va_list ap;
191
        int res;
192
193 63120
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
194 63120
        AN(fmt);
195
196 63120
        if (vte->o_sep != 0)
197 0
                return (-1);
198
199 63120
        va_start(ap, fmt);
200 63120
        res = VSB_vprintf(vte->vsb, fmt, ap);
201 63120
        va_end(ap);
202
203 63120
        if (res < 0) {
204 0
                vte->o_sep = -1;
205 0
                return (-1);
206
        }
207
208 63120
        return (vte_update(vte));
209 63120
}
210
211
int
212 17034
VTE_finish(struct vte *vte)
213
{
214
        int sep;
215
216 17034
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
217
218 17034
        if (vte->o_sep != 0)
219 0
                return (-1);
220
221 17034
        if (VSB_finish(vte->vsb) < 0) {
222 0
                vte->o_sep = -1;
223 0
                return (-1);
224
        }
225
226 17034
        if (vte->f_cnt == 0) {
227 34
                vte->o_sep = INT_MAX;
228 34
                return (0);
229
        }
230
231 17000
        sep = (vte->o_sz - vte->l_maxsz) / vte->f_cnt;
232 17000
        vte->o_sep = vlimit_t(int, sep, MINSEP, MAXSEP);
233 17000
        return (0);
234 17034
}
235
236
#define VTE_FORMAT(func, priv, ...)                     \
237
        do {                                            \
238
                if (func(priv, __VA_ARGS__) < 0)        \
239
                        return (-1);                    \
240
        } while (0)
241
242
int
243 0
VTE_dump(const struct vte *vte, VTE_format_f *func, void *priv)
244
{
245
        const char *p;
246
247 0
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
248 0
        AN(func);
249
250 0
        if (vte->o_sep <= 0)
251 0
                return (-1);
252
253 0
        p = VSB_data(vte->vsb);
254 0
        AN(p);
255 0
        VTE_FORMAT(func, priv, "%s", p);
256 0
        return (0);
257 0
}
258
259
int
260 17034
VTE_format(const struct vte *vte, VTE_format_f *func, void *priv)
261
{
262
        int fno, fsz, nsp, just_left;
263
        const char *p, *q, *sep;
264
265 17034
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
266 17034
        AN(func);
267
268 17034
        if (vte->o_sep <= 0)
269 0
                return (-1);
270
271 17034
        nsp = vte->o_sep;
272 17034
        p = VSB_data(vte->vsb);
273 17034
        AN(p);
274 17034
        q = p;
275
276 17034
        fno = 0;
277 17034
        sep = "";
278 17034
        just_left = 0;
279 222882
        while (*p != 0) {
280 205848
                if (*p == '\v') {
281 2906
                        if (p > q) {
282 17
                                VTE_FORMAT(func, priv, "%.*s%s",
283
                                    (int)((p - 1) - q), q, sep);
284 17
                        }
285 2906
                        q = ++p;
286 2906
                        just_left = 1;
287 2906
                }
288 205848
                if (!just_left && fno == 0 && *p == ' ')
289 1224
                        fsz = strcspn(p, "\n");
290
                else
291 204624
                        fsz = strcspn(p, "\t\n");
292 205848
                p += fsz;
293 205848
                if (*p == '\t') {
294 163400
                        assert(vte->f_maxsz[fno] + nsp > fsz);
295 163400
                        if (just_left) {
296 2906
                                VTE_FORMAT(func, priv, "%*s%.*s%*s",
297
                                    vte->f_maxsz[fno] - fsz, "",
298
                                    (int)(p - q), q,
299
                                    nsp, "");
300 2906
                                just_left = 0;
301 2906
                        } else {
302 160494
                                VTE_FORMAT(func, priv, "%.*s%*s",
303
                                    (int)(p - q), q,
304
                                    vte->f_maxsz[fno] + nsp - fsz, "");
305
                        }
306 163400
                        fno++;
307 163400
                        q = ++p;
308 163400
                        sep = "";
309 205848
                } else if (*p == '\n') {
310 42431
                        fno = 0;
311 42431
                        p++;
312 42431
                        sep = "\n";
313 42431
                }
314
        }
315
316 17034
        if (q < p)
317 17000
                VTE_FORMAT(func, priv, "%s", q);
318 17034
        return (0);
319 17034
}
320
321
#ifdef TEST_DRIVER
322
323
#include <stdio.h>
324
325
static const char *test_vte =
326
    "name\tref\tcomment\n"
327
    "foo\t\v1\tthe foo\n"
328
    "bar\t\v10\tthe bars\n"
329
    "baz\t\v0\t\n"
330
    "\v0\t\v0\t\n"
331
    "qux\t\v-1\tno eol";
332
333
static const char *test_fmt =
334
    "name  ref  comment\n"
335
    "foo     1  the foo\n"
336
    "bar    10  the bars\n"
337
    "baz     0  \n"
338
    "   0    0  \n"
339
    "qux    -1  no eol";
340
341
static int
342 238
test_vsb_format(void *priv, const char *fmt, ...)
343
{
344
        struct vsb *vsb;
345
        va_list ap;
346
        int res;
347
348 238
        CAST_OBJ_NOTNULL(vsb, priv, VSB_MAGIC);
349 238
        AN(fmt);
350
351 238
        va_start(ap, fmt);
352 238
        res = VSB_vprintf(vsb, fmt, ap);
353 238
        va_end(ap);
354
355 238
        return (res);
356
}
357
358
int
359 17
main(int argc, char **argv)
360
{
361
        struct vte *vte;
362
        struct vsb *vsb;
363 17
        int err = 0;
364
365 17
        (void)argc;
366 17
        (void)argv;
367
368 17
        vte = VTE_new(3, 20);
369 17
        AN(vte);
370 17
        AZ(VTE_cat(vte, test_vte));
371 17
        AZ(VTE_finish(vte));
372
373 17
        vsb = VSB_new_auto();
374 17
        AN(vsb);
375 17
        AZ(VTE_format(vte, test_vsb_format, vsb));
376 17
        AZ(VSB_finish(vsb));
377
378 17
        assert(vte->o_sep == 2);
379 17
        assert(vte->f_maxsz[0] == 4);
380 17
        assert(vte->f_maxsz[1] == 3);
381 17
        assert(vte->f_maxsz[2] == 8);
382
383 17
        if (strcmp(VSB_data(vsb), test_fmt)) {
384 0
                fprintf(stderr,
385
                    "Error: VTE output mismatch\n"
386
                    "<<<<<<<\n"
387
                    "%s\n"
388
                    "=======\n"
389
                    "%s\n"
390
                    ">>>>>>>\n"
391
                    "FAIL\n",
392 0
                    VSB_data(vsb), test_fmt);
393 0
                err = 1;
394 0
        }
395
396 17
        VSB_destroy(&vsb);
397 17
        VTE_destroy(&vte);
398 17
        if (!err)
399 17
                printf("PASS\n");
400 17
        return (err);
401
}
402
403
#endif