varnish-cache/lib/libvarnishapi/vxp_parse.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Martin Blix Grydeland <martin@varnish-software.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 <ctype.h>
35
#include <math.h>
36
#include <stdio.h>
37
38
#include "vdef.h"
39
#include "vas.h"
40
#include "miniobj.h"
41
42
#include "vbm.h"
43
#include "vnum.h"
44
#include "vqueue.h"
45
#include "vre.h"
46
#include "vsb.h"
47
48
#include "vapi/vsl.h"
49
50
#include "vsl_api.h"
51
#include "vxp.h"
52
53
static void vxp_expr_or(struct vxp *vxp, struct vex **pvex);
54
55
static struct vex *
56 5250
vex_alloc(const struct vxp *vxp)
57
{
58
        struct vex *vex;
59
60 5250
        ALLOC_OBJ(vex, VEX_MAGIC);
61 5250
        AN(vex);
62 5250
        vex->options = vxp->vex_options;
63 5250
        return (vex);
64
}
65
66
static void
67 4700
vxp_expr_lhs(struct vxp *vxp, struct vex_lhs **plhs)
68
{
69
        char *p;
70
        int i;
71
72 4700
        AN(plhs);
73 4700
        AZ(*plhs);
74 4700
        ALLOC_OBJ(*plhs, VEX_LHS_MAGIC);
75 4700
        AN(*plhs);
76 4700
        (*plhs)->tags = vbit_new(SLT__MAX);
77 4700
        (*plhs)->level = -1;
78
79 4700
        if (vxp->t->tok == '{') {
80
                /* Transaction level limits */
81 175
                vxp_NextToken(vxp);
82 175
                if (vxp->t->tok != VAL) {
83 50
                        VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
84 25
                            PF(vxp->t));
85 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
86 25
                        return;
87
                }
88 150
                (*plhs)->level = (int)strtol(vxp->t->dec, &p, 0);
89 150
                if ((*plhs)->level < 0) {
90 25
                        VSB_cat(vxp->sb, "Expected positive integer ");
91 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
92 25
                        return;
93
                }
94 125
                if (*p == '-') {
95 25
                        (*plhs)->level_pm = -1;
96 25
                        p++;
97 125
                } else if (*p == '+') {
98 25
                        (*plhs)->level_pm = 1;
99 25
                        p++;
100 25
                }
101 125
                if (*p) {
102 25
                        VSB_cat(vxp->sb, "Syntax error in level limit ");
103 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
104 25
                        return;
105
                }
106 100
                vxp_NextToken(vxp);
107 100
                ExpectErr(vxp, '}');
108 100
                vxp_NextToken(vxp);
109 100
        }
110
111 4700
        while (1) {
112
                /* The tags this expression applies to */
113 4700
                if (vxp->t->tok == VXID) {
114 675
                        (*plhs)->vxid++;
115 675
                        i = 0;
116 4700
                } else if (vxp->t->tok != VAL) {
117 50
                        VSB_printf(vxp->sb, "Expected VSL tag name got '%.*s' ",
118 25
                            PF(vxp->t));
119 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
120 25
                        return;
121
                } else {
122 4000
                        (*plhs)->taglist++;
123 8000
                        i = VSL_Glob2Tags(vxp->t->dec, -1, vsl_vbm_bitset,
124 4000
                            (*plhs)->tags);
125
                }
126 4675
                if (i == -1) {
127 50
                        VSB_cat(vxp->sb, "Tag name matches zero tags ");
128 50
                        vxp_ErrWhere(vxp, vxp->t, -1);
129 50
                        return;
130
                }
131 4625
                if (i == -2) {
132 25
                        VSB_cat(vxp->sb, "Tag name is ambiguous ");
133 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
134 25
                        return;
135
                }
136 4600
                if (i == -3) {
137 25
                        VSB_cat(vxp->sb, "Syntax error in tag name ");
138 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
139 25
                        return;
140
                }
141 4575
                assert(i > 0 || vxp->t->tok == VXID);
142 4575
                vxp_NextToken(vxp);
143 4575
                if (vxp->t->tok != ',')
144 4500
                        break;
145 75
                vxp_NextToken(vxp);
146
        }
147
148 4500
        if (vxp->t->tok == ':') {
149
                /* Record prefix */
150 500
                vxp_NextToken(vxp);
151 500
                if (vxp->t->tok != VAL) {
152 50
                        VSB_printf(vxp->sb, "Expected string got '%.*s' ",
153 25
                            PF(vxp->t));
154 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
155 25
                        return;
156
                }
157 475
                AN(vxp->t->dec);
158 475
                (*plhs)->prefix = strdup(vxp->t->dec);
159 475
                AN((*plhs)->prefix);
160 475
                (*plhs)->prefixlen = strlen((*plhs)->prefix);
161 475
                vxp_NextToken(vxp);
162 475
        }
163
164 4475
        if (vxp->t->tok == '[') {
165
                /* LHS field [] */
166 300
                vxp_NextToken(vxp);
167 300
                if (vxp->t->tok != VAL) {
168 50
                        VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
169 25
                            PF(vxp->t));
170 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
171 25
                        return;
172
                }
173 275
                (*plhs)->field = (int)strtol(vxp->t->dec, &p, 0);
174 275
                if (*p || (*plhs)->field <= 0) {
175 25
                        VSB_cat(vxp->sb, "Expected positive integer ");
176 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
177 25
                        return;
178
                }
179 250
                vxp_NextToken(vxp);
180 250
                ExpectErr(vxp, ']');
181 250
                vxp_NextToken(vxp);
182 250
        }
183
184 4425
        if ((*plhs)->vxid == 0)
185 3775
                return;
186
187 1225
        if ((*plhs)->vxid > 1 || (*plhs)->level >= 0 ||
188 600
            (*plhs)->field > 0 || (*plhs)->prefixlen > 0 ||
189 575
            (*plhs)->taglist > 0) {
190 100
                VSB_cat(vxp->sb, "Unexpected taglist selection for vxid ");
191 100
                vxp_ErrWhere(vxp, vxp->t, -1);
192 100
        }
193 4700
}
194
195
static void
196 1825
vxp_expr_num(struct vxp *vxp, struct vex_rhs **prhs, unsigned vxid)
197
{
198
        char *endptr;
199
200 1825
        AN(prhs);
201 1825
        AZ(*prhs);
202 1825
        if (vxp->t->tok != VAL) {
203 25
                VSB_printf(vxp->sb, "Expected number got '%.*s' ", PF(vxp->t));
204 25
                vxp_ErrWhere(vxp, vxp->t, -1);
205 25
                return;
206
        }
207 1800
        AN(vxp->t->dec);
208 1800
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
209 1800
        AN(*prhs);
210 1800
        if (strchr(vxp->t->dec, '.')) {
211 275
                (*prhs)->type = VEX_FLOAT;
212 275
                (*prhs)->val_float = VNUM(vxp->t->dec);
213 275
                if (isnan((*prhs)->val_float)) {
214 25
                        VSB_cat(vxp->sb, "Floating point parse error ");
215 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
216 25
                        return;
217
                }
218 250
        } else {
219 1525
                (*prhs)->type = VEX_INT;
220 1525
                (*prhs)->val_int = strtoll(vxp->t->dec, &endptr, 0);
221 1525
                while (isspace(*endptr))
222 0
                        endptr++;
223 1525
                if (*endptr != '\0') {
224 25
                        VSB_cat(vxp->sb, "Integer parse error ");
225 25
                        vxp_ErrWhere(vxp, vxp->t, -1);
226 25
                        return;
227
                }
228
        }
229 1750
        if (vxid && (*prhs)->type != VEX_INT) {
230 50
                VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
231 25
                    PF(vxp->t));
232 25
                vxp_ErrWhere(vxp, vxp->t, 0);
233 25
                return;
234
        }
235 1725
        vxp_NextToken(vxp);
236 1825
}
237
238
static void
239 325
vxp_expr_str(struct vxp *vxp, struct vex_rhs **prhs)
240
{
241
242 325
        AN(prhs);
243 325
        AZ(*prhs);
244 325
        if (vxp->t->tok != VAL) {
245 25
                VSB_printf(vxp->sb, "Expected string got '%.*s' ", PF(vxp->t));
246 25
                vxp_ErrWhere(vxp, vxp->t, -1);
247 25
                return;
248
        }
249 300
        AN(vxp->t->dec);
250 300
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
251 300
        AN(*prhs);
252 300
        (*prhs)->type = VEX_STRING;
253 300
        (*prhs)->val_string = strdup(vxp->t->dec);
254 300
        AN((*prhs)->val_string);
255 300
        (*prhs)->val_stringlen = strlen((*prhs)->val_string);
256 300
        vxp_NextToken(vxp);
257 325
}
258
259
static void
260 1325
vxp_expr_regex(struct vxp *vxp, struct vex_rhs **prhs)
261
{
262
        int err, erroff;
263
264
        /* XXX: Caseless option */
265
266 1325
        AN(prhs);
267 1325
        AZ(*prhs);
268 1325
        if (vxp->t->tok != VAL) {
269 50
                VSB_printf(vxp->sb, "Expected regular expression got '%.*s' ",
270 25
                    PF(vxp->t));
271 25
                vxp_ErrWhere(vxp, vxp->t, -1);
272 25
                return;
273
        }
274 1300
        AN(vxp->t->dec);
275 1300
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
276 1300
        AN(*prhs);
277 1300
        (*prhs)->type = VEX_REGEX;
278 1300
        (*prhs)->val_string = strdup(vxp->t->dec);
279 1300
        (*prhs)->val_regex = VRE_compile(vxp->t->dec, vxp->vre_options,
280
            &err, &erroff, 1);
281 1300
        if ((*prhs)->val_regex == NULL) {
282 25
                VSB_cat(vxp->sb, "Regular expression error: ");
283 25
                AZ(VRE_error(vxp->sb, err));
284 25
                VSB_putc(vxp->sb, ' ');
285 25
                vxp_ErrWhere(vxp, vxp->t, erroff);
286 25
                return;
287
        }
288 1275
        vxp_NextToken(vxp);
289 1325
}
290
291
static void
292 550
vxp_vxid_cmp(struct vxp *vxp)
293
{
294
295 550
        switch (vxp->t->tok) {
296
        /* Valid operators */
297
        case T_EQ:              /* == */
298
        case '<':               /* < */
299
        case '>':               /* > */
300
        case T_GEQ:             /* >= */
301
        case T_LEQ:             /* <= */
302
        case T_NEQ:             /* != */
303 450
                break;
304
305
        /* Error */
306
        default:
307 200
                VSB_printf(vxp->sb, "Expected vxid operator got '%.*s' ",
308 100
                    PF(vxp->t));
309 100
                vxp_ErrWhere(vxp, vxp->t, -1);
310 100
        }
311 550
}
312
313
/*
314
 * SYNTAX:
315
 *   expr_cmp:
316
 *     lhs
317
 *     lhs <operator> num|str|regex
318
 */
319
320
static void
321 4700
vxp_expr_cmp(struct vxp *vxp, struct vex **pvex)
322
{
323
324 4700
        AN(pvex);
325 4700
        AZ(*pvex);
326 4700
        *pvex = vex_alloc(vxp);
327 4700
        AN(*pvex);
328 4700
        vxp_expr_lhs(vxp, &(*pvex)->lhs);
329 4700
        ERRCHK(vxp);
330
331 4325
        if ((*pvex)->lhs->vxid) {
332 550
                vxp_vxid_cmp(vxp);
333 550
                ERRCHK(vxp);
334 450
        }
335
336
        /* Test operator */
337 4225
        switch (vxp->t->tok) {
338
339
        /* Single lhs expressions don't take any more tokens */
340
        case EOI:
341
        case T_AND:
342
        case T_OR:
343
        case ')':
344 725
                (*pvex)->tok = T_TRUE;
345 725
                return;
346
347
        /* Valid operators */
348
        case T_EQ:              /* == */
349
        case '<':               /* < */
350
        case '>':               /* > */
351
        case T_GEQ:             /* >= */
352
        case T_LEQ:             /* <= */
353
        case T_NEQ:             /* != */
354
        case T_SEQ:             /* eq */
355
        case T_SNEQ:            /* ne */
356
        case '~':               /* ~ */
357
        case T_NOMATCH:         /* !~ */
358 3475
                (*pvex)->tok = vxp->t->tok;
359 3475
                break;
360
361
        /* Error */
362
        default:
363 50
                VSB_printf(vxp->sb, "Expected operator got '%.*s' ",
364 25
                    PF(vxp->t));
365 25
                vxp_ErrWhere(vxp, vxp->t, -1);
366 25
                return;
367
        }
368 3475
        vxp_NextToken(vxp);
369 3475
        ERRCHK(vxp);
370
371
        /* Value */
372 3475
        switch ((*pvex)->tok) {
373
        case '\0':
374 0
                WRONG("Missing token");
375 0
                break;
376
        case T_EQ:              /* == */
377
        case '<':               /* < */
378
        case '>':               /* > */
379
        case T_GEQ:             /* >= */
380
        case T_LEQ:             /* <= */
381
        case T_NEQ:             /* != */
382 1825
                vxp_expr_num(vxp, &(*pvex)->rhs, (*pvex)->lhs->vxid);
383 1825
                break;
384
        case T_SEQ:             /* eq */
385
        case T_SNEQ:            /* ne */
386 325
                vxp_expr_str(vxp, &(*pvex)->rhs);
387 325
                break;
388
        case '~':               /* ~ */
389
        case T_NOMATCH:         /* !~ */
390 1325
                vxp_expr_regex(vxp, &(*pvex)->rhs);
391 1325
                break;
392
        default:
393 0
                INCOMPL();
394 0
        }
395 4700
}
396
397
/*
398
 * SYNTAX:
399
 *   expr_group:
400
 *     '(' expr_or ')'
401
 *     expr_not
402
 */
403
404
static void
405 4825
vxp_expr_group(struct vxp *vxp, struct vex **pvex)
406
{
407
408 4825
        AN(pvex);
409 4825
        AZ(*pvex);
410
411 4825
        if (vxp->t->tok == '(') {
412 125
                SkipToken(vxp, '(');
413 125
                vxp_expr_or(vxp, pvex);
414 125
                ERRCHK(vxp);
415 125
                SkipToken(vxp, ')');
416 125
                return;
417
        }
418
419 4700
        vxp_expr_cmp(vxp, pvex);
420 4825
}
421
422
/*
423
 * SYNTAX:
424
 *   expr_not:
425
 *     'not' expr_group
426
 *     expr_group
427
 */
428
429
static void
430 4825
vxp_expr_not(struct vxp *vxp, struct vex **pvex)
431
{
432
433 4825
        AN(pvex);
434 4825
        AZ(*pvex);
435
436 4825
        if (vxp->t->tok == T_NOT) {
437 25
                *pvex = vex_alloc(vxp);
438 25
                AN(*pvex);
439 25
                (*pvex)->tok = vxp->t->tok;
440 25
                vxp_NextToken(vxp);
441 25
                vxp_expr_group(vxp, &(*pvex)->a);
442 25
                return;
443
        }
444
445 4800
        vxp_expr_group(vxp, pvex);
446 4825
}
447
448
/*
449
 * SYNTAX:
450
 *   expr_and:
451
 *     expr_not { 'and' expr_not }*
452
 */
453
454
static void
455 4625
vxp_expr_and(struct vxp *vxp, struct vex **pvex)
456
{
457
        struct vex *a;
458
459 4625
        AN(pvex);
460 4625
        AZ(*pvex);
461 4625
        vxp_expr_not(vxp, pvex);
462 4625
        ERRCHK(vxp);
463 4150
        while (vxp->t->tok == T_AND) {
464 200
                a = *pvex;
465 200
                *pvex = vex_alloc(vxp);
466 200
                AN(*pvex);
467 200
                (*pvex)->tok = vxp->t->tok;
468 200
                (*pvex)->a = a;
469 200
                vxp_NextToken(vxp);
470 200
                ERRCHK(vxp);
471 200
                vxp_expr_not(vxp, &(*pvex)->b);
472 200
                ERRCHK(vxp);
473
        }
474 4625
}
475
476
/*
477
 * SYNTAX:
478
 *   expr_or:
479
 *     expr_and { 'or' expr_and }*
480
 */
481
482
static void
483 4450
vxp_expr_or(struct vxp *vxp, struct vex **pvex)
484
{
485
        struct vex *a;
486
487 4450
        AN(pvex);
488 4450
        AZ(*pvex);
489 4450
        vxp_expr_and(vxp, pvex);
490 4450
        ERRCHK(vxp);
491 3950
        while (vxp->t->tok == T_OR) {
492 175
                a = *pvex;
493 175
                *pvex = vex_alloc(vxp);
494 175
                AN(*pvex);
495 175
                (*pvex)->tok = vxp->t->tok;
496 175
                (*pvex)->a = a;
497 175
                vxp_NextToken(vxp);
498 175
                ERRCHK(vxp);
499 175
                vxp_expr_and(vxp, &(*pvex)->b);
500 175
                ERRCHK(vxp);
501
        }
502 4450
}
503
504
/*
505
 * SYNTAX:
506
 *   expr:
507
 *     expr_or EOI { 'or' expr_or EOI }?
508
 */
509
510
static void
511 4475
vxp_expr(struct vxp *vxp, struct vex **pvex)
512
{
513 4475
        struct vex *a = NULL, *or;
514
515 4475
        if (*pvex == NULL) {
516 4325
                vxp_expr_or(vxp, pvex);
517 4325
                ERRCHK(vxp);
518 3650
                ExpectErr(vxp, EOI);
519 3650
                return;
520
        }
521
522 150
        vxp_expr(vxp, &a);
523 150
        ERRCHK(vxp);
524
525 150
        or = vex_alloc(vxp);
526 150
        AN(or);
527 150
        or->tok = T_OR;
528 150
        or->b = *pvex;
529 150
        or->a = a;
530 150
        *pvex = or;
531 4475
}
532
533
/*
534
 * Build a struct vex tree from the token list in vxp
535
 */
536
537
struct vex *
538 4225
vxp_Parse(struct vxp *vxp)
539
{
540 4225
        struct vex *vex = NULL;
541
542 4225
        AZ(vxp->err);
543 4225
        vxp->t = VTAILQ_FIRST(&vxp->tokens);
544
545 7875
        while (vxp->t != NULL) {
546
                /* Ignore empty queries */
547 5100
                while (vxp->t != NULL && vxp->t->tok == EOI)
548 600
                        vxp->t = VTAILQ_NEXT(vxp->t, list);
549
550 4500
                if (vxp->t == NULL)
551 175
                        break;
552
553 4325
                vxp_expr(vxp, &vex);
554
555 4325
                if (vxp->err) {
556 675
                        if (vex)
557 675
                                vex_Free(&vex);
558 675
                        AZ(vex);
559 675
                        return (NULL);
560
                }
561
562 3650
                vxp->t = VTAILQ_NEXT(vxp->t, list);
563
        }
564
565 3550
        return (vex);
566 4225
}
567
568
/*
569
 * Free a struct vex tree
570
 */
571
572
void
573 5250
vex_Free(struct vex **pvex)
574
{
575
        struct vex *vex;
576
        struct vex_lhs *lhs;
577
        struct vex_rhs *rhs;
578
579 5250
        TAKE_OBJ_NOTNULL(vex, pvex, VEX_MAGIC);
580
581 5250
        if (vex->lhs) {
582 4700
                CAST_OBJ_NOTNULL(lhs, vex->lhs, VEX_LHS_MAGIC);
583 4700
                if (lhs->tags)
584 4700
                        vbit_destroy(lhs->tags);
585 4700
                if (lhs->prefix)
586 475
                        free(lhs->prefix);
587 4700
                FREE_OBJ(lhs);
588 4700
        }
589 5250
        if (vex->rhs) {
590 3400
                CAST_OBJ_NOTNULL(rhs, vex->rhs, VEX_RHS_MAGIC);
591 3400
                if (rhs->val_string)
592 1600
                        free(rhs->val_string);
593 3400
                if (rhs->val_regex)
594 1275
                        VRE_free(&rhs->val_regex);
595 3400
                FREE_OBJ(rhs);
596 3400
        }
597 5250
        if (vex->a) {
598 550
                vex_Free(&vex->a);
599 550
                AZ(vex->a);
600 550
        }
601 5250
        if (vex->b) {
602 525
                vex_Free(&vex->b);
603 525
                AZ(vex->b);
604 525
        }
605 5250
        FREE_OBJ(vex);
606 5250
}
607
608
#ifdef VXP_DEBUG
609
610
static void
611 75
vex_print_rhs(const struct vex_rhs *rhs)
612
{
613
614 75
        CHECK_OBJ_NOTNULL(rhs, VEX_RHS_MAGIC);
615 75
        fprintf(stderr, "rhs=");
616 75
        switch (rhs->type) {
617
        case VEX_INT:
618 50
                fprintf(stderr, "INT(%jd)", (intmax_t)rhs->val_int);
619 50
                break;
620
        case VEX_FLOAT:
621 0
                fprintf(stderr, "FLOAT(%f)", rhs->val_float);
622 0
                break;
623
        case VEX_STRING:
624 0
                AN(rhs->val_string);
625 0
                fprintf(stderr, "STRING(%s)", rhs->val_string);
626 0
                break;
627
        case VEX_REGEX:
628 25
                AN(rhs->val_string);
629 25
                AN(rhs->val_regex);
630 25
                fprintf(stderr, "REGEX(%s)", rhs->val_string);
631 25
                break;
632
        default:
633 0
                WRONG("rhs type");
634 0
                break;
635
        }
636 75
}
637
638
static void
639 100
vex_print_tags(const struct vbitmap *vbm)
640
{
641
        int i;
642 100
        int first = 1;
643
644 25700
        for (i = 0; i < SLT__MAX; i++) {
645 25600
                if (VSL_tags[i] == NULL)
646 16300
                        continue;
647 9300
                if (!vbit_test(vbm, i))
648 9100
                        continue;
649 200
                if (first)
650 100
                        first = 0;
651
                else
652 100
                        fprintf(stderr, ",");
653 200
                fprintf(stderr, "%s", VSL_tags[i]);
654 200
        }
655 100
}
656
657
static void
658 150
vex_print(const struct vex *vex, int indent)
659
{
660 150
        CHECK_OBJ_NOTNULL(vex, VEX_MAGIC);
661
662 150
        fprintf(stderr, "%*s%s", indent, "", vxp_tnames[vex->tok]);
663 150
        if (vex->lhs != NULL) {
664 100
                CHECK_OBJ(vex->lhs, VEX_LHS_MAGIC);
665 100
                AN(vex->lhs->tags);
666 100
                fprintf(stderr, " lhs=");
667 100
                if (vex->lhs->level >= 0)
668 0
                        fprintf(stderr, "{%d%s}", vex->lhs->level,
669 0
                            vex->lhs->level_pm < 0 ? "-" :
670 0
                            vex->lhs->level_pm > 0 ? "+" : "");
671 100
                fprintf(stderr, "(");
672 100
                vex_print_tags(vex->lhs->tags);
673 100
                fprintf(stderr, ")");
674 100
                if (vex->lhs->prefix) {
675 50
                        assert(vex->lhs->prefixlen == strlen(vex->lhs->prefix));
676 50
                        fprintf(stderr, ":%s", vex->lhs->prefix);
677 50
                }
678 100
                if (vex->lhs->field > 0)
679 25
                        fprintf(stderr, "[%d]", vex->lhs->field);
680 100
        }
681 150
        if (vex->rhs != NULL) {
682 75
                fprintf(stderr, " ");
683 75
                vex_print_rhs(vex->rhs);
684 75
        }
685 150
        fprintf(stderr, "\n");
686 150
        if (vex->a != NULL)
687 50
                vex_print(vex->a, indent + 2);
688 150
        if (vex->b != NULL)
689 50
                vex_print(vex->b, indent + 2);
690 150
}
691
692
void
693 50
vex_PrintTree(const struct vex *vex)
694
{
695
696 50
        CHECK_OBJ_NOTNULL(vex, VEX_MAGIC);
697 50
        fprintf(stderr, "VEX tree:\n");
698 50
        vex_print(vex, 2);
699 50
}
700
701
#endif /* VXP_DEBUG */