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 39720
VTE_new(int maxfields, int width)
70
{
71
        struct vte *vte;
72
73 39720
        assert(maxfields > 0);
74 39720
        assert(width > 0);
75
76 39720
        ALLOC_FLEX_OBJ(vte, f_maxsz, maxfields, VTE_MAGIC);
77 39720
        if (vte != NULL) {
78 39720
                vte->o_sz = width;
79 39720
                vte->f_maxcnt = maxfields;
80 39720
                vte->vsb = VSB_new_auto();
81 39720
                AN(vte->vsb);
82 39720
        }
83 39720
        return (vte);
84
}
85
86
void
87 39720
VTE_destroy(struct vte **vtep)
88
{
89
        struct vte *vte;
90
91 39720
        TAKE_OBJ_NOTNULL(vte, vtep, VTE_MAGIC);
92 39720
        AN(vte->vsb);
93 39720
        VSB_destroy(&vte->vsb);
94 39720
        FREE_OBJ(vte);
95 39720
}
96
97
static int
98 254522
vte_update(struct vte *vte)
99
{
100
        const char *p, *q;
101
        int len, fno;
102
103 254522
        AZ(vte->o_sep);
104
105 254522
        len = VSB_len(vte->vsb);
106 254522
        assert(len >= vte->c_off);
107
108 254522
        p = vte->vsb->s_buf + vte->c_off;
109 254522
        q = vte->vsb->s_buf + len;
110 4995086
        for (; p < q; p++) {
111 4740564
                if (vte->f_off < 0) {
112 188960
                        while (p < q && *p != '\n')
113 186080
                                p++;
114 2880
                }
115 4740564
                if (vte->l_sz == 0 && *p == ' ') {
116 2880
                        vte->f_off = -1;
117 2880
                        continue;
118
                }
119 4737684
                if (vte->f_off >= 0 && vte->f_sz == 0 && *p == '\v')
120 6841
                        p++;
121 4737684
                if (*p == '\t' || *p == '\n') {
122 480725
                        fno = vte->f_off;
123 480725
                        if (fno >= 0 && vte->f_sz > vte->f_maxsz[fno])
124 301572
                                vte->f_maxsz[fno] = vte->f_sz;
125 480725
                        fno++;
126 480725
                        assert(fno <= vte->f_maxcnt);
127 480725
                        if (*p == '\t' && fno == vte->f_maxcnt) {
128 0
                                errno = EOVERFLOW;
129 0
                                vte->o_sep = -1;
130 0
                                return (-1);
131
                        }
132 480725
                        vte->f_off = fno;
133 480725
                        vte->f_sz = 0;
134 480725
                }
135 4737684
                if (*p == '\n') {
136 99121
                        vte->f_cnt = vmax(vte->f_cnt, vte->f_off);
137 99121
                        vte->l_maxsz = vmax(vte->l_maxsz, vte->l_sz);
138 99121
                        vte->f_off = 0;
139 99121
                        vte->f_sz = 0;
140 99121
                        vte->l_sz = 0;
141 4737684
                } else if (*p != '\t') {
142 4256959
                        vte->f_sz++;
143 4256959
                        vte->l_sz++;
144 4256959
                }
145 4737684
        }
146
147 254522
        vte->c_off = len;
148 254522
        return (0);
149 254522
}
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 107081
VTE_cat(struct vte *vte, const char *s)
171
{
172
173 107081
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
174 107081
        AN(s);
175
176 107081
        if (vte->o_sep != 0)
177 0
                return (-1);
178
179 107081
        if (VSB_cat(vte->vsb, s) < 0) {
180 0
                vte->o_sep = -1;
181 0
                return (-1);
182
        }
183
184 107081
        return (vte_update(vte));
185 107081
}
186
187
int
188 147441
VTE_printf(struct vte *vte, const char *fmt, ...)
189
{
190
        va_list ap;
191
        int res;
192
193 147441
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
194 147441
        AN(fmt);
195
196 147441
        if (vte->o_sep != 0)
197 0
                return (-1);
198
199 147441
        va_start(ap, fmt);
200 147441
        res = VSB_vprintf(vte->vsb, fmt, ap);
201 147441
        va_end(ap);
202
203 147441
        if (res < 0) {
204 0
                vte->o_sep = -1;
205 0
                return (-1);
206
        }
207
208 147441
        return (vte_update(vte));
209 147441
}
210
211
int
212 39720
VTE_finish(struct vte *vte)
213
{
214
        int sep;
215
216 39720
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
217
218 39720
        if (vte->o_sep != 0)
219 0
                return (-1);
220
221 39720
        if (VSB_finish(vte->vsb) < 0) {
222 0
                vte->o_sep = -1;
223 0
                return (-1);
224
        }
225
226 39720
        if (vte->f_cnt == 0) {
227 80
                vte->o_sep = INT_MAX;
228 80
                return (0);
229
        }
230
231 39640
        sep = (vte->o_sz - vte->l_maxsz) / vte->f_cnt;
232 39640
        vte->o_sep = vlimit_t(int, sep, MINSEP, MAXSEP);
233 39640
        return (0);
234 39720
}
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 39720
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 39720
        CHECK_OBJ_NOTNULL(vte, VTE_MAGIC);
266 39720
        AN(func);
267
268 39720
        if (vte->o_sep <= 0)
269 0
                return (-1);
270
271 39720
        nsp = vte->o_sep;
272 39720
        p = VSB_data(vte->vsb);
273 39720
        AN(p);
274 39720
        q = p;
275
276 39720
        fno = 0;
277 39720
        sep = "";
278 39720
        just_left = 0;
279 520485
        while (*p != 0) {
280 480765
                if (*p == '\v') {
281 6841
                        if (p > q) {
282 40
                                VTE_FORMAT(func, priv, "%.*s%s",
283
                                    (int)((p - 1) - q), q, sep);
284 40
                        }
285 6841
                        q = ++p;
286 6841
                        just_left = 1;
287 6841
                }
288 480765
                if (!just_left && fno == 0 && *p == ' ')
289 2880
                        fsz = strcspn(p, "\n");
290
                else
291 477885
                        fsz = strcspn(p, "\t\n");
292 480765
                p += fsz;
293 480765
                if (*p == '\t') {
294 381604
                        assert(vte->f_maxsz[fno] + nsp > fsz);
295 381604
                        if (just_left) {
296 6841
                                VTE_FORMAT(func, priv, "%*s%.*s%*s",
297
                                    vte->f_maxsz[fno] - fsz, "",
298
                                    (int)(p - q), q,
299
                                    nsp, "");
300 6841
                                just_left = 0;
301 6841
                        } else {
302 374763
                                VTE_FORMAT(func, priv, "%.*s%*s",
303
                                    (int)(p - q), q,
304
                                    vte->f_maxsz[fno] + nsp - fsz, "");
305
                        }
306 381604
                        fno++;
307 381604
                        q = ++p;
308 381604
                        sep = "";
309 480765
                } else if (*p == '\n') {
310 99121
                        fno = 0;
311 99121
                        p++;
312 99121
                        sep = "\n";
313 99121
                }
314
        }
315
316 39720
        if (q < p)
317 39640
                VTE_FORMAT(func, priv, "%s", q);
318 39720
        return (0);
319 39720
}
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 560
test_vsb_format(void *priv, const char *fmt, ...)
343
{
344
        struct vsb *vsb;
345
        va_list ap;
346
        int res;
347
348 560
        CAST_OBJ_NOTNULL(vsb, priv, VSB_MAGIC);
349 560
        AN(fmt);
350
351 560
        va_start(ap, fmt);
352 560
        res = VSB_vprintf(vsb, fmt, ap);
353 560
        va_end(ap);
354
355 560
        return (res);
356
}
357
358
int
359 40
main(int argc, char **argv)
360
{
361
        struct vte *vte;
362
        struct vsb *vsb;
363 40
        int err = 0;
364
365 40
        (void)argc;
366 40
        (void)argv;
367
368 40
        vte = VTE_new(3, 20);
369 40
        AN(vte);
370 40
        AZ(VTE_cat(vte, test_vte));
371 40
        AZ(VTE_finish(vte));
372
373 40
        vsb = VSB_new_auto();
374 40
        AN(vsb);
375 40
        AZ(VTE_format(vte, test_vsb_format, vsb));
376 40
        AZ(VSB_finish(vsb));
377
378 40
        assert(vte->o_sep == 2);
379 40
        assert(vte->f_maxsz[0] == 4);
380 40
        assert(vte->f_maxsz[1] == 3);
381 40
        assert(vte->f_maxsz[2] == 8);
382
383 40
        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 40
        VSB_destroy(&vsb);
397 40
        VTE_destroy(&vte);
398 40
        if (!err)
399 40
                printf("PASS\n");
400 40
        return (err);
401
}
402
403
#endif