Coverage Report

Created: 2026-10-13 07:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/augeas/src/pathx.c
Line
Count
Source
1
/*
2
 * pathx.c: handling path expressions
3
 *
4
 * Copyright (C) 2007-2016 David Lutterkort
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19
 *
20
 * Author: David Lutterkort <dlutter@redhat.com>
21
 */
22
23
#include <config.h>
24
#include <internal.h>
25
#include <stdint.h>
26
#include <stdbool.h>
27
#include <memory.h>
28
#include <ctype.h>
29
30
#include "ref.h"
31
#include "regexp.h"
32
#include "errcode.h"
33
34
static const char *const errcodes[] = {
35
    "no error",
36
    "empty name",
37
    "illegal string literal",
38
    "illegal number",                             /* PATHX_ENUMBER */
39
    "string missing ending ' or \"",
40
    "expected '='",
41
    "allocation failed",
42
    "unmatched '['",
43
    "unmatched '('",
44
    "expected a '/'",
45
    "internal error",                             /* PATHX_EINTERNAL */
46
    "type error",                                 /* PATHX_ETYPE */
47
    "undefined variable",                         /* PATHX_ENOVAR */
48
    "garbage at end of path expression",          /* PATHX_EEND */
49
    "no match for path expression",               /* PATHX_ENOMATCH */
50
    "wrong number of arguments in function call", /* PATHX_EARITY */
51
    "invalid regular expression",                 /* PATHX_EREGEXP */
52
    "too many matches",                           /* PATHX_EMMATCH */
53
    "wrong flag for regexp"                       /* PATHX_EREGEXPFLAG */
54
};
55
56
/*
57
 * Path expressions are strings that use a notation modelled on XPath.
58
 */
59
60
enum type {
61
    T_NONE = 0,     /* Not a type */
62
    T_NODESET,
63
    T_BOOLEAN,
64
    T_NUMBER,
65
    T_STRING,
66
    T_REGEXP
67
};
68
69
enum expr_tag {
70
    E_FILTER,
71
    E_BINARY,
72
    E_VALUE,
73
    E_VAR,
74
    E_APP
75
};
76
77
enum binary_op {
78
    OP_EQ,         /* '='  */
79
    OP_NEQ,        /* '!=' */
80
    OP_LT,         /* '<'  */
81
    OP_LE,         /* '<=' */
82
    OP_GT,         /* '>'  */
83
    OP_GE,         /* '>=' */
84
    OP_PLUS,       /* '+'  */
85
    OP_MINUS,      /* '-'  */
86
    OP_STAR,       /* '*'  */
87
    OP_AND,        /* 'and' */
88
    OP_OR,         /* 'or' */
89
    OP_ELSE,       /* 'else' */
90
    OP_RE_MATCH,   /* '=~' */
91
    OP_RE_NOMATCH, /* '!~' */
92
    OP_UNION       /* '|' */
93
};
94
95
struct pred {
96
    int               nexpr;
97
    struct expr     **exprs;
98
};
99
100
enum axis {
101
    SELF,
102
    CHILD,
103
    SEQ,
104
    DESCENDANT,
105
    DESCENDANT_OR_SELF,
106
    PARENT,
107
    ANCESTOR,
108
    ROOT,
109
    PRECEDING_SIBLING,
110
    FOLLOWING_SIBLING
111
};
112
113
/* This array is indexed by enum axis */
114
static const char *const axis_names[] = {
115
    "self",
116
    "child",
117
    "seq",        /* Like child, but only selects node-names which are integers */
118
    "descendant",
119
    "descendant-or-self",
120
    "parent",
121
    "ancestor",
122
    "root",
123
    "preceding-sibling",
124
    "following-sibling"
125
};
126
127
/* The characters that can follow a name in a location expression (aka path)
128
 * The parser will assume that name (path component) is finished when it
129
 * encounters any of these characters, unless they are escaped by preceding
130
 * them with a '\\'.
131
 *
132
 * See parse_name for the gory details
133
 */
134
static const char name_follow[] = "][|/=()!,";
135
136
/* Doubly linked list of location steps. Besides the information from the
137
 * path expression, also contains information to iterate over a node set,
138
 * in particular, the context node CTX for the step, and the current node
139
 * CUR within that context.
140
 */
141
struct step {
142
    struct step *next;
143
    enum axis    axis;
144
    char        *name;              /* NULL to match any name */
145
    struct pred *predicates;
146
};
147
148
/* Initialise the root nodeset with the first step */
149
static struct tree *step_root(struct step *step, struct tree *ctx,
150
                              struct tree *root_ctx);
151
/* Iteration over the nodes on a step, ignoring the predicates */
152
static struct tree *step_first(struct step *step, struct tree *ctx);
153
static struct tree *step_next(struct step *step, struct tree *ctx,
154
                              struct tree *node);
155
156
struct pathx_symtab {
157
    struct pathx_symtab *next;
158
    char                *name;
159
    struct value        *value;
160
};
161
162
struct pathx {
163
    struct state   *state;
164
    struct nodeset *nodeset;
165
    int             node;
166
    struct tree    *origin;
167
};
168
169
5.05M
#define L_BRACK '['
170
24.1k
#define R_BRACK ']'
171
172
struct locpath {
173
    struct step *steps;
174
};
175
176
struct nodeset {
177
    struct tree **nodes;
178
    size_t        used;
179
    size_t        size;
180
};
181
182
typedef uint32_t value_ind_t;
183
184
struct value {
185
    enum type tag;
186
    union {
187
        struct nodeset  *nodeset;     /* T_NODESET */
188
        int64_t          number;      /* T_NUMBER  */
189
        char            *string;      /* T_STRING  */
190
        bool             boolval;     /* T_BOOLEAN */
191
        struct regexp   *regexp;      /* T_REGEXP  */
192
    };
193
};
194
195
struct expr {
196
    enum expr_tag tag;
197
    enum type     type;
198
    union {
199
        struct {                       /* E_FILTER */
200
            struct expr     *primary;
201
            struct pred     *predicates;
202
            struct locpath  *locpath;
203
        };
204
        struct {                       /* E_BINARY */
205
            enum binary_op op;
206
            struct expr *left;
207
            struct expr *right;
208
            bool   left_matched;
209
        };
210
        value_ind_t      value_ind;    /* E_VALUE */
211
        char            *ident;        /* E_VAR */
212
        struct {                       /* E_APP */
213
            const struct func *func;
214
            struct expr       **args;
215
            /* If fold is true, replace this function invocation
216
             * with its value after the first time we evaluate this
217
             * expression */
218
            bool              fold;
219
        };
220
    };
221
};
222
223
struct locpath_trace {
224
    unsigned int      maxns;
225
    struct nodeset  **ns;
226
    struct locpath   *lp;
227
};
228
229
/* Internal state of the evaluator/parser */
230
struct state {
231
    pathx_errcode_t errcode;
232
    const char     *file;
233
    int             line;
234
    char           *errmsg;
235
236
    const char     *txt;  /* Entire expression */
237
    const char     *pos;  /* Current position within TXT during parsing */
238
239
    struct tree *ctx; /* The current node */
240
    uint            ctx_pos;
241
    uint            ctx_len;
242
243
    struct tree *root_ctx; /* Root context for relative paths */
244
245
    /* A table of all values. The table is dynamically reallocated, i.e.
246
     * pointers to struct value should not be used across calls that
247
     * might allocate new values
248
     *
249
     * value_pool[0] is always the boolean false, and value_pool[1]
250
     * always the boolean true
251
     */
252
    struct value  *value_pool;
253
    value_ind_t    value_pool_used;
254
    value_ind_t    value_pool_size;
255
    /* Stack of values (as indices into value_pool), with bottom of
256
       stack in values[0] */
257
    value_ind_t   *values;
258
    size_t         values_used;
259
    size_t         values_size;
260
    /* Stack of expressions, with bottom of stack in exprs[0] */
261
    struct expr  **exprs;
262
    size_t         exprs_used;
263
    size_t         exprs_size;
264
    /* Trace of a locpath evaluation, needed by pathx_expand_tree.
265
       Generally NULL, unless a trace is needed.
266
     */
267
    struct locpath_trace *locpath_trace;
268
    /* Symbol table for variable lookups */
269
    struct pathx_symtab *symtab;
270
    /* Error structure, used to communicate errors to struct augeas;
271
     * we never own this structure, and therefore never free it */
272
    struct error        *error;
273
    /* If a filter-expression contains the 'else' operator, we need
274
     * we need to evaluate the filter twice. The has_else flag
275
     * means we don't do this unless we really need to */
276
    bool                 has_else;
277
};
278
279
/* We consider NULL and the empty string to be equal */
280
ATTRIBUTE_PURE
281
13.1M
static inline int streqx(const char *s1, const char *s2) {
282
13.1M
    if (s1 == NULL)
283
0
        return (s2 == NULL || strlen(s2) == 0);
284
13.1M
    if (s2 == NULL)
285
77
        return strlen(s1) == 0;
286
13.1M
    return STREQ(s1, s2);
287
13.1M
}
288
289
/* Functions */
290
291
typedef void (*func_impl_t)(struct state *state, int nargs);
292
293
struct func {
294
    const char      *name;
295
    unsigned int     arity;
296
    enum type        type;
297
    bool             pure;      /* Result only depends on args */
298
    const enum type *arg_types;
299
    func_impl_t      impl;
300
};
301
302
static void func_last(struct state *state, int nargs);
303
static void func_position(struct state *state, int nargs);
304
static void func_count(struct state *state, int nargs);
305
static void func_label(struct state *state, int nargs);
306
static void func_regexp(struct state *state, int nargs);
307
static void func_regexp_flag(struct state *state, int nargs);
308
static void func_glob(struct state *state, int nargs);
309
static void func_int(struct state *state, int nargs);
310
static void func_not(struct state *state, int nargs);
311
static void func_modified(struct state *state, int nargs);
312
313
static const enum type arg_types_nodeset[] = { T_NODESET };
314
static const enum type arg_types_string[] = { T_STRING };
315
static const enum type arg_types_bool[] = { T_BOOLEAN };
316
static const enum type arg_types_string_string[] = { T_STRING, T_STRING };
317
static const enum type arg_types_nodeset_string[] = { T_NODESET, T_STRING };
318
319
static const struct func builtin_funcs[] = {
320
    { .name = "last", .arity = 0, .type = T_NUMBER, .arg_types = NULL,
321
      .impl = func_last, .pure = false },
322
    { .name = "position", .arity = 0, .type = T_NUMBER, .arg_types = NULL,
323
      .impl = func_position, .pure = false },
324
    { .name = "label", .arity = 0, .type = T_STRING, .arg_types = NULL,
325
      .impl = func_label, .pure = false },
326
    { .name = "count", .arity = 1, .type = T_NUMBER,
327
      .arg_types = arg_types_nodeset,
328
      .impl = func_count, .pure = false },
329
    { .name = "regexp", .arity = 1, .type = T_REGEXP,
330
      .arg_types = arg_types_string,
331
      .impl = func_regexp, .pure = true },
332
    { .name = "regexp", .arity = 1, .type = T_REGEXP,
333
      .arg_types = arg_types_nodeset,
334
      .impl = func_regexp, .pure = true },
335
    { .name = "regexp", .arity = 2, .type = T_REGEXP,
336
      .arg_types = arg_types_string_string,
337
      .impl = func_regexp_flag, .pure = true },
338
    { .name = "regexp", .arity = 2, .type = T_REGEXP,
339
      .arg_types = arg_types_nodeset_string,
340
      .impl = func_regexp_flag, .pure = true },
341
    { .name = "glob", .arity = 1, .type = T_REGEXP,
342
      .arg_types = arg_types_string,
343
      .impl = func_glob, .pure = true },
344
    { .name = "glob", .arity = 1, .type = T_REGEXP,
345
      .arg_types = arg_types_nodeset,
346
      .impl = func_glob, .pure = true },
347
    { .name = "int", .arity = 1, .type = T_NUMBER,
348
      .arg_types = arg_types_string, .impl = func_int, .pure = false },
349
    { .name = "int", .arity = 1, .type = T_NUMBER,
350
      .arg_types = arg_types_nodeset, .impl = func_int, .pure = false },
351
    { .name = "int", .arity = 1, .type = T_NUMBER,
352
      .arg_types = arg_types_bool, .impl = func_int, .pure = false },
353
    { .name = "modified", .arity = 0, .type = T_BOOLEAN,
354
      .arg_types = NULL, .impl = func_modified, .pure = false },
355
    { .name = "not", .arity = 1, .type = T_BOOLEAN,
356
      .arg_types = arg_types_bool, .impl = func_not, .pure = true }
357
};
358
359
#define RET_ON_ERROR                                                    \
360
32.4M
    if (state->errcode != PATHX_NOERROR) return
361
362
#define RET0_ON_ERROR                                                   \
363
762k
    if (state->errcode != PATHX_NOERROR) return 0
364
365
#define STATE_ERROR(state, err)                                         \
366
1.14k
    do {                                                                \
367
1.14k
        state->errcode = err;                                           \
368
1.14k
        state->file = __FILE__;                                         \
369
1.14k
        state->line = __LINE__;                                         \
370
1.14k
    } while (0)
371
372
19.3M
#define HAS_ERROR(state) (state->errcode != PATHX_NOERROR)
373
374
0
#define STATE_ENOMEM STATE_ERROR(state, PATHX_ENOMEM)
375
376
/*
377
 * Free the various data structures
378
 */
379
380
static void free_expr(struct expr *expr);
381
382
4.46M
static void free_pred(struct pred *pred) {
383
4.46M
    if (pred == NULL)
384
4.43M
        return;
385
386
48.2k
    for (int i=0; i < pred->nexpr; i++) {
387
24.1k
        free_expr(pred->exprs[i]);
388
24.1k
    }
389
24.1k
    free(pred->exprs);
390
24.1k
    free(pred);
391
24.1k
}
392
393
466k
static void free_step(struct step *step) {
394
700k
    while (step != NULL) {
395
233k
        struct step *del = step;
396
233k
        step = del->next;
397
233k
        free(del->name);
398
233k
        free_pred(del->predicates);
399
233k
        free(del);
400
233k
    }
401
466k
}
402
403
2.07M
static void free_locpath(struct locpath *locpath) {
404
2.07M
    if (locpath == NULL)
405
466k
        return;
406
3.99M
    while (locpath->steps != NULL) {
407
2.38M
        struct step *step = locpath->steps;
408
2.38M
        locpath->steps = step->next;
409
2.38M
        free(step->name);
410
2.38M
        free_pred(step->predicates);
411
2.38M
        free(step);
412
2.38M
    }
413
1.60M
    free(locpath);
414
1.60M
}
415
416
10.1M
static void free_expr(struct expr *expr) {
417
10.1M
    if (expr == NULL)
418
1.83M
        return;
419
8.26M
    switch (expr->tag) {
420
1.83M
    case E_FILTER:
421
1.83M
        free_expr(expr->primary);
422
1.83M
        free_pred(expr->predicates);
423
1.83M
        free_locpath(expr->locpath);
424
1.83M
        break;
425
3.64M
    case E_BINARY:
426
3.64M
        free_expr(expr->left);
427
3.64M
        free_expr(expr->right);
428
3.64M
        break;
429
2.77M
    case E_VALUE:
430
2.77M
        break;
431
848
    case E_VAR:
432
848
        free(expr->ident);
433
848
        break;
434
290
    case E_APP:
435
671
        for (int i=0; i < expr->func->arity; i++)
436
381
            free_expr(expr->args[i]);
437
290
        free(expr->args);
438
290
        break;
439
0
    default:
440
0
        assert(0);
441
8.26M
    }
442
8.26M
    free(expr);
443
8.26M
}
444
445
3.44M
static void free_nodeset(struct nodeset *ns) {
446
3.44M
    if (ns != NULL) {
447
3.44M
        free(ns->nodes);
448
3.44M
        free(ns);
449
3.44M
    }
450
3.44M
}
451
452
/* Free all objects used by VALUE, but not VALUE itself */
453
4.49M
static void release_value(struct value *v) {
454
4.49M
    if (v == NULL)
455
2
        return;
456
457
4.49M
    switch (v->tag) {
458
1.03M
    case T_NODESET:
459
1.03M
        free_nodeset(v->nodeset);
460
1.03M
        break;
461
2.60k
    case T_STRING:
462
2.60k
        free(v->string);
463
2.60k
        break;
464
656k
    case T_BOOLEAN:
465
3.45M
    case T_NUMBER:
466
3.45M
        break;
467
3.67k
    case T_REGEXP:
468
3.67k
        unref(v->regexp, regexp);
469
3.67k
        break;
470
3.67k
    default:
471
0
        assert(0);
472
4.49M
    }
473
4.49M
}
474
475
328k
static void free_state(struct state *state) {
476
328k
    if (state == NULL)
477
0
        return;
478
479
1.27M
    for(int i=0; i < state->exprs_used; i++)
480
950k
        free_expr(state->exprs[i]);
481
328k
    free(state->exprs);
482
483
4.81M
    for(int i=0; i < state->value_pool_used; i++)
484
4.49M
        release_value(state->value_pool + i);
485
328k
    free(state->value_pool);
486
328k
    free(state->values);
487
328k
    free(state);
488
328k
}
489
490
328k
void free_pathx(struct pathx *pathx) {
491
328k
    if (pathx == NULL)
492
58
        return;
493
328k
    free_state(pathx->state);
494
328k
    free(pathx);
495
328k
}
496
497
/*
498
 * Nodeset helpers
499
 */
500
3.36M
static struct nodeset *make_nodeset(struct state *state) {
501
3.36M
    struct nodeset *result;
502
3.36M
    if (ALLOC(result) < 0)
503
3.36M
        STATE_ENOMEM;
504
3.36M
    return result;
505
3.36M
}
506
507
/* Add NODE to NS if it is not in NS yet. This relies on the flag
508
 * NODE->ADDED and care must be taken that NS_CLEAR_ADDED is called on NS
509
 * as soon as we are done adding nodes to it.
510
 */
511
static void ns_add(struct nodeset *ns, struct tree *node,
512
14.0M
                   struct state *state) {
513
14.0M
    if (node->added)
514
0
        return;
515
14.0M
    if (ns->used >= ns->size) {
516
2.56M
        size_t size = 2 * ns->size;
517
2.56M
        if (size < 10) size = 10;
518
2.56M
        if (REALLOC_N(ns->nodes, size) < 0)
519
2.56M
            STATE_ENOMEM;
520
2.56M
        ns->size = size;
521
2.56M
    }
522
14.0M
    ns->nodes[ns->used] = node;
523
14.0M
    node->added = 1;
524
14.0M
    ns->used += 1;
525
14.0M
}
526
527
3.41M
static void ns_clear_added(struct nodeset *ns) {
528
17.5M
    for (int i=0; i < ns->used; i++)
529
14.1M
        ns->nodes[i]->added = 0;
530
3.41M
}
531
532
static struct nodeset *
533
clone_nodeset(struct nodeset *ns, struct state *state)
534
73.9k
{
535
73.9k
    struct nodeset *clone;
536
73.9k
    if (ALLOC(clone) < 0) {
537
0
        STATE_ENOMEM;
538
0
        return NULL;
539
0
    }
540
73.9k
    if (ALLOC_N(clone->nodes, ns->used) < 0) {
541
0
        free(clone);
542
0
        STATE_ENOMEM;
543
0
        return NULL;
544
0
    }
545
73.9k
    clone->used = ns->used;
546
73.9k
    clone->size = ns->used;
547
135k
    for (int i=0; i < ns->used; i++)
548
61.9k
        clone->nodes[i] = ns->nodes[i];
549
73.9k
    return clone;
550
73.9k
}
551
552
/*
553
 * Handling values
554
 */
555
3.83M
static value_ind_t make_value(enum type tag, struct state *state) {
556
3.83M
    assert(tag != T_BOOLEAN);
557
558
3.83M
    if (state->value_pool_used >= state->value_pool_size) {
559
2.08k
        value_ind_t new_size = 2*state->value_pool_size;
560
2.08k
        if (new_size <= state->value_pool_size) {
561
0
            STATE_ENOMEM;
562
0
            return 0;
563
0
        }
564
2.08k
        if (REALLOC_N(state->value_pool, new_size) < 0) {
565
0
            STATE_ENOMEM;
566
0
            return 0;
567
0
        }
568
2.08k
        state->value_pool_size = new_size;
569
2.08k
    }
570
3.83M
    state->value_pool[state->value_pool_used].tag = tag;
571
3.83M
    state->value_pool[state->value_pool_used].nodeset = NULL;
572
3.83M
    return state->value_pool_used++;
573
3.83M
}
574
575
0
static value_ind_t clone_value(struct value *v, struct state *state) {
576
0
    value_ind_t vind = make_value(v->tag, state);
577
0
    RET0_ON_ERROR;
578
0
    struct value *clone = state->value_pool + vind;
579
580
0
    switch (v->tag) {
581
0
    case T_NODESET:
582
0
        clone->nodeset = clone_nodeset(v->nodeset, state);
583
0
        break;
584
0
    case T_NUMBER:
585
0
        clone->number = v->number;
586
0
        break;
587
0
    case T_STRING:
588
0
        clone->string = strdup(v->string);
589
0
        if (clone->string == NULL) {
590
0
            STATE_ENOMEM;
591
0
        }
592
0
        break;
593
0
    case T_BOOLEAN:
594
0
        clone->boolval = v->boolval;
595
0
        break;
596
0
    case T_REGEXP:
597
0
        clone->regexp = ref(v->regexp);
598
0
        break;
599
0
    default:
600
0
        assert(0);
601
0
    }
602
0
    return vind;
603
0
}
604
605
2.05M
static value_ind_t pop_value_ind(struct state *state) {
606
2.05M
    if (state->values_used > 0) {
607
2.05M
        state->values_used -= 1;
608
2.05M
        return state->values[state->values_used];
609
2.05M
    } else {
610
0
        STATE_ERROR(state, PATHX_EINTERNAL);
611
0
        assert(0);
612
0
        return 0;
613
0
    }
614
2.05M
}
615
616
2.05M
static struct value *pop_value(struct state *state) {
617
2.05M
    value_ind_t vind = pop_value_ind(state);
618
2.05M
    if (HAS_ERROR(state))
619
0
        return NULL;
620
2.05M
    return state->value_pool + vind;
621
2.05M
}
622
623
2.05M
static void push_value(value_ind_t vind, struct state *state) {
624
2.05M
    if (state->values_used >= state->values_size) {
625
327k
        size_t new_size = 2*state->values_size;
626
327k
        if (new_size == 0) new_size = 8;
627
327k
        if (REALLOC_N(state->values, new_size) < 0) {
628
0
            STATE_ENOMEM;
629
0
            return;
630
0
        }
631
327k
        state->values_size = new_size;
632
327k
    }
633
2.05M
    state->values[state->values_used++] = vind;
634
2.05M
}
635
636
520k
static void push_boolean_value(int b, struct state *state) {
637
520k
    push_value(b != 0, state);
638
520k
}
639
640
ATTRIBUTE_PURE
641
4.22M
static struct value *expr_value(struct expr *expr, struct state *state) {
642
4.22M
    return state->value_pool + expr->value_ind;
643
4.22M
}
644
645
/*************************************************************************
646
 * Evaluation
647
 ************************************************************************/
648
static void eval_expr(struct expr *expr, struct state *state);
649
650
651
#define ensure_arity(min, max)                                          \
652
24.4k
    if (nargs < min || nargs > max) {                                   \
653
0
        STATE_ERROR(state, PATHX_EINTERNAL);                            \
654
0
        return;                                                         \
655
0
    }
656
657
0
static void func_last(struct state *state, int nargs) {
658
0
    ensure_arity(0, 0);
659
0
    value_ind_t vind = make_value(T_NUMBER, state);
660
0
    RET_ON_ERROR;
661
662
0
    state->value_pool[vind].number = state->ctx_len;
663
0
    push_value(vind, state);
664
0
}
665
666
0
static void func_position(struct state *state, int nargs) {
667
0
    ensure_arity(0, 0);
668
0
    value_ind_t vind = make_value(T_NUMBER, state);
669
0
    RET_ON_ERROR;
670
671
0
    state->value_pool[vind].number = state->ctx_pos;
672
0
    push_value(vind, state);
673
0
}
674
675
0
static void func_count(struct state *state, int nargs) {
676
0
    ensure_arity(1, 1);
677
0
    value_ind_t vind = make_value(T_NUMBER, state);
678
0
    RET_ON_ERROR;
679
680
0
    struct value *ns = pop_value(state);
681
0
    state->value_pool[vind].number = ns->nodeset->used;
682
0
    push_value(vind, state);
683
0
}
684
685
0
static void func_label(struct state *state, int nargs) {
686
0
    ensure_arity(0, 0);
687
0
    value_ind_t vind = make_value(T_STRING, state);
688
0
    char *s;
689
690
0
    RET_ON_ERROR;
691
692
0
    if (state->ctx->label)
693
0
        s = strdup(state->ctx->label);
694
0
    else
695
0
        s = strdup("");
696
0
    if (s == NULL) {
697
0
        STATE_ENOMEM;
698
0
        return;
699
0
    }
700
0
    state->value_pool[vind].string = s;
701
0
    push_value(vind, state);
702
0
}
703
704
20.8k
static void func_int(struct state *state, int nargs) {
705
20.8k
    ensure_arity(1, 1);
706
20.8k
    value_ind_t vind = make_value(T_NUMBER, state);
707
20.8k
    int64_t i = -1;
708
20.8k
    RET_ON_ERROR;
709
710
20.8k
    struct value *v = pop_value(state);
711
20.8k
    if (v->tag == T_BOOLEAN) {
712
20.8k
        i = v->boolval;
713
20.8k
    } else {
714
0
        const char *s = NULL;
715
0
        if (v->tag == T_STRING) {
716
0
            s = v->string;
717
0
        } else {
718
            /* T_NODESET */
719
0
            if (v->nodeset->used != 1) {
720
0
                STATE_ERROR(state, PATHX_EMMATCH);
721
0
                return;
722
0
            }
723
0
            s = v->nodeset->nodes[0]->value;
724
0
        }
725
0
        if (s != NULL) {
726
0
            int r;
727
0
            r = xstrtoint64(s, 10, &i);
728
0
            if (r < 0) {
729
0
                STATE_ERROR(state, PATHX_ENUMBER);
730
0
                return;
731
0
            }
732
0
        }
733
0
    }
734
20.8k
    state->value_pool[vind].number = i;
735
20.8k
    push_value(vind, state);
736
20.8k
}
737
738
0
static void func_modified(struct state *state, int nargs) {
739
0
    ensure_arity(0, 0);
740
741
0
    push_boolean_value(state->ctx->dirty , state);
742
0
}
743
744
0
static void func_not(struct state *state, int nargs) {
745
0
    ensure_arity(1, 1);
746
0
    RET_ON_ERROR;
747
748
0
    struct value *v = pop_value(state);
749
0
    if (v->tag == T_BOOLEAN) {
750
0
        push_boolean_value(! v->boolval, state);
751
0
    }
752
0
}
753
754
static struct regexp *
755
3.56k
nodeset_as_regexp(struct info *info, struct nodeset *ns, int glob, int nocase) {
756
3.56k
    struct regexp *result = NULL;
757
3.56k
    struct regexp **rx = NULL;
758
3.56k
    int used = 0;
759
760
4.10k
    for (int i = 0; i < ns->used; i++) {
761
549
        if (ns->nodes[i]->value != NULL)
762
183
            used += 1;
763
549
    }
764
765
3.56k
    if (used == 0) {
766
        /* If the nodeset is empty, make sure we produce a regexp
767
         * that never matches anything */
768
3.49k
        result = make_regexp_unescape(info, "[^\001-\7ff]", nocase);
769
3.49k
    } else {
770
68
        if (ALLOC_N(rx, ns->used) < 0)
771
0
            goto error;
772
269
        for (int i=0; i < ns->used; i++) {
773
201
            if (ns->nodes[i]->value == NULL)
774
18
                continue;
775
776
183
            if (glob)
777
0
                rx[i] = make_regexp_from_glob(info, ns->nodes[i]->value);
778
183
            else
779
183
                rx[i] = make_regexp_unescape(info, ns->nodes[i]->value, 0);
780
183
            if (rx[i] == NULL)
781
0
                goto error;
782
183
        }
783
68
        result = regexp_union_n(info, ns->used, rx);
784
68
    }
785
786
3.56k
 error:
787
3.56k
    if (rx != NULL) {
788
269
        for (int i=0; i < ns->used; i++)
789
201
            unref(rx[i], regexp);
790
68
        free(rx);
791
68
    }
792
3.56k
    return result;
793
3.56k
}
794
795
3.67k
static void func_regexp_or_glob(struct state *state, int glob, int nocase) {
796
3.67k
    value_ind_t vind = make_value(T_REGEXP, state);
797
3.67k
    int r;
798
799
3.67k
    RET_ON_ERROR;
800
801
3.67k
    struct value *v = pop_value(state);
802
3.67k
    struct regexp *rx = NULL;
803
804
3.67k
    if (v->tag == T_STRING) {
805
114
        if (glob)
806
0
            rx = make_regexp_from_glob(state->error->info, v->string);
807
114
        else
808
114
            rx = make_regexp_unescape(state->error->info, v->string, nocase);
809
3.56k
    } else if (v->tag == T_NODESET) {
810
3.56k
        rx = nodeset_as_regexp(state->error->info, v->nodeset, glob, nocase);
811
3.56k
    } else {
812
0
        assert(0);
813
0
    }
814
815
3.67k
    if (rx == NULL) {
816
0
        STATE_ENOMEM;
817
0
        return;
818
0
    }
819
820
3.67k
    state->value_pool[vind].regexp = rx;
821
3.67k
    r = regexp_compile(rx);
822
3.67k
    if (r < 0) {
823
5
        const char *msg;
824
5
        regexp_check(rx, &msg);
825
5
        state->errmsg = strdup(msg);
826
5
        STATE_ERROR(state, PATHX_EREGEXP);
827
5
        return;
828
5
    }
829
3.66k
    push_value(vind, state);
830
3.66k
}
831
832
797
static void func_regexp(struct state *state, int nargs) {
833
797
    ensure_arity(1, 1);
834
797
    func_regexp_or_glob(state, 0, 0);
835
797
}
836
837
2.87k
static void func_regexp_flag(struct state *state, int nargs) {
838
2.87k
    ensure_arity(2, 2);
839
2.87k
    int nocase = 0;
840
2.87k
    struct value *f = pop_value(state);
841
842
2.87k
    if (STREQ("i", f->string))
843
2.87k
        nocase = 1;
844
0
    else
845
0
        STATE_ERROR(state, PATHX_EREGEXPFLAG);
846
847
2.87k
    func_regexp_or_glob(state, 0, nocase);
848
2.87k
}
849
850
0
static void func_glob(struct state *state, int nargs) {
851
0
    ensure_arity(1, 1);
852
0
    func_regexp_or_glob(state, 1, 0);
853
0
}
854
855
41.6k
static bool coerce_to_bool(struct value *v) {
856
41.6k
    switch (v->tag) {
857
20.8k
    case T_NODESET:
858
20.8k
        return v->nodeset->used > 0;
859
0
        break;
860
20.8k
    case T_BOOLEAN:
861
20.8k
        return v->boolval;
862
0
        break;
863
0
    case T_NUMBER:
864
0
        return v->number > 0;
865
0
        break;
866
0
    case T_STRING:
867
0
        return strlen(v->string) > 0;
868
0
        break;
869
0
    case T_REGEXP:
870
0
        return true;
871
0
    default:
872
0
        assert(0);
873
0
        return false;
874
41.6k
    }
875
41.6k
}
876
877
static int calc_eq_nodeset_nodeset(struct nodeset *ns1, struct nodeset *ns2,
878
20.8k
                                   int neq) {
879
20.8k
    for (int i1=0; i1 < ns1->used; i1++) {
880
0
        struct tree *t1 = ns1->nodes[i1];
881
0
        for (int i2=0; i2 < ns2->used; i2++) {
882
0
            struct tree *t2 = ns2->nodes[i2];
883
0
            if (neq) {
884
0
                if (!streqx(t1->value, t2->value))
885
0
                    return 1;
886
0
            } else {
887
0
                if (streqx(t1->value, t2->value))
888
0
                    return 1;
889
0
            }
890
0
        }
891
0
    }
892
20.8k
    return 0;
893
20.8k
}
894
895
static int calc_eq_nodeset_string(struct nodeset *ns, const char *s,
896
0
                                  int neq) {
897
0
    for (int i=0; i < ns->used; i++) {
898
0
        struct tree *t = ns->nodes[i];
899
0
        if (neq) {
900
0
            if (!streqx(t->value, s))
901
0
                return 1;
902
0
        } else {
903
0
            if (streqx(t->value, s))
904
0
                return 1;
905
0
        }
906
0
    }
907
0
    return 0;
908
0
}
909
910
20.8k
static void eval_eq(struct state *state, int neq) {
911
20.8k
    struct value *r = pop_value(state);
912
20.8k
    struct value *l = pop_value(state);
913
20.8k
    int res;
914
915
20.8k
    if (l->tag == T_NODESET && r->tag == T_NODESET) {
916
20.8k
        res = calc_eq_nodeset_nodeset(l->nodeset, r->nodeset, neq);
917
20.8k
    } else if (l->tag == T_NODESET) {
918
0
        res = calc_eq_nodeset_string(l->nodeset, r->string, neq);
919
0
    } else if (r->tag == T_NODESET) {
920
0
        res = calc_eq_nodeset_string(r->nodeset, l->string, neq);
921
0
    } else if (l->tag == T_NUMBER && r->tag == T_NUMBER) {
922
0
        if (neq)
923
0
            res = (l->number != r->number);
924
0
        else
925
0
            res = (l->number == r->number);
926
0
    } else {
927
0
        assert(l->tag == T_STRING);
928
0
        assert(r->tag == T_STRING);
929
0
        res = streqx(l->string, r->string);
930
0
        if (neq)
931
0
            res = !res;
932
0
    }
933
20.8k
    RET_ON_ERROR;
934
935
20.8k
    push_boolean_value(res, state);
936
20.8k
}
937
938
0
static void eval_arith(struct state *state, enum binary_op op) {
939
0
    value_ind_t vind = make_value(T_NUMBER, state);
940
0
    struct value *r = pop_value(state);
941
0
    struct value *l = pop_value(state);
942
0
    int res;
943
944
0
    assert(l->tag == T_NUMBER);
945
0
    assert(r->tag == T_NUMBER);
946
947
0
    RET_ON_ERROR;
948
949
0
    if (op == OP_PLUS)
950
0
        res = l->number + r->number;
951
0
    else if (op == OP_MINUS)
952
0
        res = l->number - r->number;
953
0
    else if (op == OP_STAR)
954
0
        res = l->number * r->number;
955
0
    else
956
0
        assert(0);
957
958
0
    state->value_pool[vind].number = res;
959
0
    push_value(vind, state);
960
0
}
961
962
0
static void eval_rel(struct state *state, bool greater, bool equal) {
963
0
    struct value *r, *l;
964
0
    int res;
965
966
    /* We always check l < r or l <= r */
967
0
    if (greater) {
968
0
        l = pop_value(state);
969
0
        r = pop_value(state);
970
0
    } else {
971
0
        r = pop_value(state);
972
0
        l = pop_value(state);
973
0
    }
974
0
    if (l->tag == T_NUMBER) {
975
0
        if (equal)
976
0
            res = (l->number <= r->number);
977
0
        else
978
0
            res = (l->number < r->number);
979
0
    } else if (l->tag == T_STRING) {
980
0
        int cmp = strcmp(l->string, r->string);
981
0
        if (equal)
982
0
            res = cmp <= 0;
983
0
        else
984
0
            res = cmp < 0;
985
0
    } else {
986
0
        assert(0);
987
0
    }
988
989
0
    push_boolean_value(res, state);
990
0
}
991
992
0
static void eval_and_or(struct state *state, enum binary_op op) {
993
0
    struct value *r = pop_value(state);
994
0
    struct value *l = pop_value(state);
995
0
    bool left = coerce_to_bool(l);
996
0
    bool right = coerce_to_bool(r);
997
998
999
0
    if (op == OP_AND)
1000
0
        push_boolean_value(left && right, state);
1001
0
    else
1002
0
        push_boolean_value(left || right, state);
1003
0
}
1004
1005
20.8k
static void eval_else(struct state *state, struct expr *expr, struct locpath_trace *lpt_right) {
1006
20.8k
    struct value *r = pop_value(state);
1007
20.8k
    struct value *l = pop_value(state);
1008
1009
20.8k
    if ( l->tag == T_NODESET && r->tag == T_NODESET ) {
1010
38
        int discard_maxns=0;
1011
38
        struct nodeset **discard_ns=NULL;
1012
38
        struct locpath_trace *lpt = state->locpath_trace;
1013
38
        value_ind_t vind = make_value(T_NODESET, state);
1014
38
        if (l->nodeset->used >0 || expr->left_matched) {
1015
16
            expr->left_matched = 1;
1016
16
            state->value_pool[vind].nodeset = clone_nodeset(l->nodeset, state);
1017
16
            if( lpt_right != NULL ) {
1018
16
                discard_maxns = lpt_right->maxns;
1019
16
                discard_ns    = lpt_right->ns;
1020
16
            }
1021
22
        } else {
1022
22
            state->value_pool[vind].nodeset = clone_nodeset(r->nodeset, state);
1023
22
            if( lpt != NULL && lpt_right != NULL ) {
1024
0
                discard_maxns = lpt->maxns;
1025
0
                discard_ns    = lpt->ns;
1026
0
                lpt->maxns = lpt_right->maxns;
1027
0
                lpt->ns    = lpt_right->ns;
1028
0
                lpt->lp    = lpt_right->lp;
1029
0
            }
1030
22
        }
1031
38
        push_value(vind, state);
1032
38
        if ( lpt != NULL && lpt_right != NULL ) {
1033
0
            for (int i=0; i < discard_maxns; i++)
1034
0
                free_nodeset(discard_ns[i]);
1035
0
            FREE(discard_ns);
1036
0
        }
1037
20.8k
    } else {
1038
20.8k
        bool left = coerce_to_bool(l);
1039
20.8k
        bool right = coerce_to_bool(r);
1040
1041
20.8k
        expr->left_matched = expr->left_matched || left;
1042
20.8k
        if (expr->left_matched) {
1043
            /* One or more LHS have matched, so we're not interested in the right expr */
1044
0
            push_boolean_value(left, state);
1045
20.8k
        } else {
1046
            /* no LHS has matched (yet), so keep the right expr */
1047
            /* If this is the 2nd pass, and expr->left_matched is true, no RHS nodes will be included */
1048
20.8k
            push_boolean_value(right, state);
1049
20.8k
        }
1050
20.8k
    }
1051
20.8k
}
1052
1053
static bool eval_re_match_str(struct state *state, struct regexp *rx,
1054
479k
                              const char *str) {
1055
479k
    int r;
1056
1057
479k
    if (str == NULL)
1058
272k
        str = "";
1059
1060
479k
    r = regexp_match(rx, str, strlen(str), 0, NULL);
1061
479k
    if (r == -2) {
1062
0
        STATE_ERROR(state, PATHX_EINTERNAL);
1063
479k
    } else if (r == -3) {
1064
        /* We should never get this far; func_regexp should catch
1065
         * invalid regexps */
1066
0
        assert(false);
1067
0
    }
1068
479k
    return r == strlen(str);
1069
479k
}
1070
1071
73.9k
static void eval_union(struct state *state, struct locpath_trace *lpt_right) {
1072
73.9k
    value_ind_t vind = make_value(T_NODESET, state);
1073
73.9k
    struct value *r = pop_value(state);
1074
73.9k
    struct value *l = pop_value(state);
1075
73.9k
    struct nodeset *res = NULL;
1076
73.9k
    struct locpath_trace *lpt = state->locpath_trace;
1077
1078
73.9k
    assert(l->tag == T_NODESET);
1079
73.9k
    assert(r->tag == T_NODESET);
1080
1081
73.9k
    RET_ON_ERROR;
1082
1083
73.9k
    res = clone_nodeset(l->nodeset, state);
1084
73.9k
    RET_ON_ERROR;
1085
76.1k
    for (int i=0; i < r->nodeset->used; i++) {
1086
2.25k
        ns_add(res, r->nodeset->nodes[i], state);
1087
2.25k
        if (HAS_ERROR(state))
1088
0
            goto error;
1089
2.25k
    }
1090
73.9k
    state->value_pool[vind].nodeset = res;
1091
73.9k
    push_value(vind, state);
1092
1093
73.9k
    if( lpt != NULL && lpt_right != NULL ) {
1094
0
        STATE_ERROR(state, PATHX_EMMATCH);
1095
0
        for (int i=0; i < lpt_right->maxns; i++)
1096
0
            free_nodeset(lpt_right->ns[i]);
1097
0
        FREE(lpt_right->ns);
1098
0
    }
1099
73.9k
 error:
1100
73.9k
    ns_clear_added(res);
1101
73.9k
}
1102
1103
0
static void eval_concat_string(struct state *state) {
1104
0
    value_ind_t vind = make_value(T_STRING, state);
1105
0
    struct value *r = pop_value(state);
1106
0
    struct value *l = pop_value(state);
1107
0
    char *res = NULL;
1108
1109
0
    RET_ON_ERROR;
1110
1111
0
    if (ALLOC_N(res, strlen(l->string) + strlen(r->string) + 1) < 0) {
1112
0
        STATE_ENOMEM;
1113
0
        return;
1114
0
    }
1115
0
    strcpy(res, l->string);
1116
0
    strcat(res, r->string);
1117
0
    state->value_pool[vind].string = res;
1118
0
    push_value(vind, state);
1119
0
}
1120
1121
0
static void eval_concat_regexp(struct state *state) {
1122
0
    value_ind_t vind = make_value(T_REGEXP, state);
1123
0
    struct value *r = pop_value(state);
1124
0
    struct value *l = pop_value(state);
1125
0
    struct regexp *rx = NULL;
1126
1127
0
    RET_ON_ERROR;
1128
1129
0
    rx = regexp_concat(state->error->info, l->regexp, r->regexp);
1130
0
    if (rx == NULL) {
1131
0
        STATE_ENOMEM;
1132
0
        return;
1133
0
    }
1134
1135
0
    state->value_pool[vind].regexp = rx;
1136
0
    push_value(vind, state);
1137
0
}
1138
1139
479k
static void eval_re_match(struct state *state, enum binary_op op) {
1140
479k
    struct value *rx  = pop_value(state);
1141
479k
    struct value *v = pop_value(state);
1142
1143
479k
    bool result = false;
1144
1145
479k
    if (v->tag == T_STRING) {
1146
586
        result = eval_re_match_str(state, rx->regexp, v->string);
1147
586
        RET_ON_ERROR;
1148
478k
    } else if (v->tag == T_NODESET) {
1149
957k
        for (int i=0; i < v->nodeset->used && result == false; i++) {
1150
478k
            struct tree *t = v->nodeset->nodes[i];
1151
478k
            result = eval_re_match_str(state, rx->regexp, t->value);
1152
478k
            RET_ON_ERROR;
1153
478k
        }
1154
478k
    }
1155
479k
    if (op == OP_RE_NOMATCH)
1156
479k
        result = !result;
1157
479k
    push_boolean_value(result, state);
1158
479k
}
1159
1160
594k
static void eval_binary(struct expr *expr, struct state *state) {
1161
594k
    struct locpath_trace *lpt = state->locpath_trace;
1162
594k
    struct locpath_trace lpt_right;
1163
1164
594k
    eval_expr(expr->left, state);
1165
594k
    if ( lpt != NULL && expr->type == T_NODESET ) {
1166
0
       MEMZERO(&lpt_right, 1);
1167
0
       state->locpath_trace = &lpt_right;
1168
0
    }
1169
594k
    eval_expr(expr->right, state);
1170
594k
    state->locpath_trace = lpt;
1171
594k
    RET_ON_ERROR;
1172
1173
594k
    switch (expr->op) {
1174
20.8k
    case OP_EQ:
1175
20.8k
        eval_eq(state, 0);
1176
20.8k
        break;
1177
0
    case OP_NEQ:
1178
0
        eval_eq(state, 1);
1179
0
        break;
1180
0
    case OP_LT:
1181
0
        eval_rel(state, false, false);
1182
0
        break;
1183
0
    case OP_LE:
1184
0
        eval_rel(state, false, true);
1185
0
        break;
1186
0
    case OP_GT:
1187
0
        eval_rel(state, true, false);
1188
0
        break;
1189
0
    case OP_GE:
1190
0
        eval_rel(state, true, true);
1191
0
        break;
1192
0
    case OP_PLUS:
1193
0
        if (expr->type == T_NUMBER)
1194
0
            eval_arith(state, expr->op);
1195
0
        else if (expr->type == T_STRING)
1196
0
            eval_concat_string(state);
1197
0
        else if (expr->type == T_REGEXP)
1198
0
            eval_concat_regexp(state);
1199
0
        break;
1200
0
    case OP_MINUS:
1201
0
    case OP_STAR:
1202
0
        eval_arith(state, expr->op);
1203
0
        break;
1204
0
    case OP_AND:
1205
0
    case OP_OR:
1206
0
        eval_and_or(state, expr->op);
1207
0
        break;
1208
20.8k
    case OP_ELSE:
1209
20.8k
        eval_else(state, expr, &lpt_right);
1210
20.8k
        break;
1211
73.9k
    case OP_UNION:
1212
73.9k
        eval_union(state, &lpt_right);
1213
73.9k
        break;
1214
0
    case OP_RE_MATCH:
1215
479k
    case OP_RE_NOMATCH:
1216
479k
        eval_re_match(state, expr->op);
1217
479k
        break;
1218
0
    default:
1219
0
        assert(0);
1220
594k
    }
1221
594k
}
1222
1223
24.4k
static void eval_app(struct expr *expr, struct state *state) {
1224
24.4k
    assert(expr->tag == E_APP);
1225
1226
51.8k
    for (int i=0; i < expr->func->arity; i++) {
1227
27.3k
        eval_expr(expr->args[i], state);
1228
27.3k
        RET_ON_ERROR;
1229
27.3k
    }
1230
24.4k
    expr->func->impl(state, expr->func->arity);
1231
24.4k
}
1232
1233
505k
static bool eval_pred(struct expr *expr, struct state *state) {
1234
505k
    eval_expr(expr, state);
1235
505k
    RET0_ON_ERROR;
1236
1237
505k
    struct value *v = pop_value(state);
1238
505k
    switch(v->tag) {
1239
479k
    case T_BOOLEAN:
1240
479k
        return v->boolval;
1241
20.8k
    case T_NUMBER:
1242
20.8k
        return (state->ctx_pos == v->number);
1243
5.20k
    case T_NODESET:
1244
5.20k
        return v->nodeset->used > 0;
1245
0
    case T_STRING:
1246
0
        return streqv(state->ctx->value, v->string);
1247
0
    default:
1248
0
        assert(0);
1249
0
        return false;
1250
505k
    }
1251
505k
}
1252
1253
/* Remove COUNT successive entries from NS. The first entry to remove is at
1254
   IND */
1255
24.8k
static void ns_remove(struct nodeset *ns, int ind, int count) {
1256
24.8k
    if (count < 1)
1257
0
        return;
1258
24.8k
    memmove(ns->nodes + ind, ns->nodes + ind+count,
1259
24.8k
            sizeof(ns->nodes[0]) * (ns->used - (ind+count)));
1260
24.8k
    ns->used -= count;
1261
24.8k
}
1262
1263
/*
1264
 * Remove all nodes from NS for which one of PRED is false
1265
 */
1266
static void ns_filter(struct nodeset *ns, struct pred *predicates,
1267
2.38M
                      struct state *state) {
1268
2.38M
    if (predicates == NULL)
1269
2.36M
        return;
1270
1271
26.3k
    struct tree *old_ctx = state->ctx;
1272
26.3k
    uint old_ctx_len = state->ctx_len;
1273
26.3k
    uint old_ctx_pos = state->ctx_pos;
1274
1275
52.7k
    for (int p=0; p < predicates->nexpr; p++) {
1276
26.3k
        if ( state->has_else) {
1277
278k
            for (int i=0; i < ns->used; i++) {
1278
                /* 1st pass, check if any else statements have match on the left */
1279
                /* Don't delete any nodes (yet) */
1280
251k
                state->ctx = ns->nodes[i];
1281
251k
                eval_pred(predicates->exprs[p], state);
1282
251k
            }
1283
26.1k
        }
1284
26.3k
        int first_bad = -1;  /* The index of the first non-matching node */
1285
26.3k
        state->ctx_len = ns->used;
1286
26.3k
        state->ctx_pos = 1;
1287
279k
        for (int i=0; i < ns->used; state->ctx_pos++) {
1288
253k
            state->ctx = ns->nodes[i];
1289
253k
            bool match = eval_pred(predicates->exprs[p], state);
1290
253k
            RET_ON_ERROR;
1291
            /* We remove non-matching nodes from NS in batches; this logic
1292
             * makes sure that we only call ns_remove at the end of a run
1293
             * of non-matching nodes
1294
             */
1295
253k
            if (match) {
1296
22.2k
                if (first_bad >= 0) {
1297
9.09k
                    ns_remove(ns, first_bad, i - first_bad);
1298
9.09k
                    i = first_bad + 1;
1299
13.1k
                } else {
1300
13.1k
                    i += 1;
1301
13.1k
                }
1302
22.2k
                first_bad = -1;
1303
231k
            } else {
1304
231k
                if (first_bad == -1)
1305
24.8k
                    first_bad = i;
1306
231k
                i += 1;
1307
231k
            }
1308
253k
        }
1309
26.3k
        if (first_bad >= 0) {
1310
15.7k
            ns_remove(ns, first_bad, ns->used - first_bad);
1311
15.7k
        }
1312
26.3k
    }
1313
1314
26.3k
    state->ctx = old_ctx;
1315
26.3k
    state->ctx_pos = old_ctx_pos;
1316
26.3k
    state->ctx_len = old_ctx_len;
1317
26.3k
}
1318
1319
/* Return true if PRED is solely the predicate '[n]' as in 'foo[17]' */
1320
2.41M
static bool position_pred(struct pred *pred) {
1321
2.41M
    return pred != NULL &&
1322
49.9k
        pred->nexpr == 1 &&
1323
49.9k
        pred->exprs[0]->tag == E_VALUE &&
1324
23.5k
        pred->exprs[0]->type == T_NUMBER;
1325
2.41M
}
1326
1327
/* Return the tree node at the position implied by STEP->PREDICATES. It is
1328
   assumed and required that STEP->PREDICATES is actually a
1329
   POSITION_PRED.
1330
1331
   This method hand-optimizes the important case of a path expression like
1332
   'service[42]'
1333
*/
1334
static struct tree *position_filter(struct nodeset *ns,
1335
                                    struct step *step,
1336
23.5k
                                    struct state *state) {
1337
23.5k
    int value_ind = step->predicates->exprs[0]->value_ind;
1338
23.5k
    int number = state->value_pool[value_ind].number;
1339
1340
23.5k
    int pos = 1;
1341
41.2k
    for (int i=0; i < ns->used; i++) {
1342
17.6k
        for (struct tree *node = step_first(step, ns->nodes[i]);
1343
53.0k
             node != NULL;
1344
35.3k
             node = step_next(step, ns->nodes[i], node), pos++) {
1345
35.3k
            if (pos == number)
1346
0
                return node;
1347
35.3k
        }
1348
17.6k
    }
1349
1350
23.5k
    return NULL;
1351
23.5k
}
1352
1353
/* Return an array of nodesets, one for each step in the locpath.
1354
 *
1355
 * On return, (*NS)[0] will contain state->ctx, and (*NS)[*MAXNS] will
1356
 * contain the nodes that matched the entire locpath
1357
 */
1358
static void ns_from_locpath(struct locpath *lp, uint *maxns,
1359
                            struct nodeset ***ns,
1360
                            const struct nodeset *root,
1361
956k
                            struct state *state) {
1362
956k
    struct tree *old_ctx = state->ctx;
1363
956k
    *maxns = 0;
1364
1365
956k
    ensure(lp != NULL, state);
1366
1367
956k
    *ns = NULL;
1368
956k
    list_for_each(step, lp->steps)
1369
2.41M
        *maxns += 1;
1370
956k
    if (ALLOC_N(*ns, *maxns+1) < 0) {
1371
0
        STATE_ERROR(state, PATHX_ENOMEM);
1372
0
        goto error;
1373
0
    }
1374
4.32M
    for (int i=0; i <= *maxns; i++) {
1375
3.36M
        (*ns)[i] = make_nodeset(state);
1376
3.36M
        if (HAS_ERROR(state))
1377
0
            goto error;
1378
3.36M
    }
1379
1380
956k
    if (root == NULL) {
1381
956k
        struct step *first_step = NULL;
1382
956k
        first_step = lp->steps;
1383
1384
956k
        struct tree *root_tree;
1385
956k
        root_tree = step_root(first_step, state->ctx, state->root_ctx);
1386
956k
        ns_add((*ns)[0], root_tree, state);
1387
956k
        ns_clear_added((*ns)[0]);
1388
956k
    } else {
1389
0
        for (int i=0; i < root->used; i++)
1390
0
            ns_add((*ns)[0], root->nodes[i], state);
1391
0
        ns_clear_added((*ns)[0]);
1392
0
    }
1393
1394
956k
    if (HAS_ERROR(state))
1395
0
        goto error;
1396
1397
956k
    uint cur_ns = 0;
1398
2.41M
    list_for_each(step, lp->steps) {
1399
2.41M
        struct nodeset *work = (*ns)[cur_ns];
1400
2.41M
        struct nodeset *next = (*ns)[cur_ns + 1];
1401
2.41M
        if (position_pred(step->predicates)) {
1402
23.5k
            struct tree *node = position_filter(work, step, state);
1403
23.5k
            if (node) {
1404
0
                ns_add(next, node, state);
1405
0
                ns_clear_added(next);
1406
0
            }
1407
2.38M
        } else {
1408
15.5M
            for (int i=0; i < work->used; i++) {
1409
13.1M
                for (struct tree *node = step_first(step, work->nodes[i]);
1410
26.2M
                     node != NULL;
1411
13.1M
                     node = step_next(step, work->nodes[i], node)) {
1412
13.1M
                    ns_add(next, node, state);
1413
13.1M
                }
1414
13.1M
            }
1415
2.38M
            ns_clear_added(next);
1416
2.38M
            ns_filter(next, step->predicates, state);
1417
2.38M
            if (HAS_ERROR(state))
1418
4
                goto error;
1419
2.38M
        }
1420
2.41M
        cur_ns += 1;
1421
2.41M
    }
1422
1423
956k
    state->ctx = old_ctx;
1424
956k
    return;
1425
4
 error:
1426
4
    if (*ns != NULL) {
1427
16
        for (int i=0; i <= *maxns; i++)
1428
12
            free_nodeset((*ns)[i]);
1429
4
        FREE(*ns);
1430
4
    }
1431
4
    state->ctx = old_ctx;
1432
4
    return;
1433
956k
}
1434
1435
956k
static void eval_filter(struct expr *expr, struct state *state) {
1436
956k
    struct locpath *lp = expr->locpath;
1437
956k
    struct nodeset **ns = NULL;
1438
956k
    struct locpath_trace *lpt = state->locpath_trace;
1439
956k
    uint maxns;
1440
1441
956k
    state->locpath_trace = NULL;
1442
956k
    if (expr->primary == NULL) {
1443
956k
        ns_from_locpath(lp, &maxns, &ns, NULL, state);
1444
956k
    } else {
1445
0
        eval_expr(expr->primary, state);
1446
0
        RET_ON_ERROR;
1447
0
        value_ind_t primary_ind = pop_value_ind(state);
1448
0
        struct value *primary = state->value_pool + primary_ind;
1449
0
        assert(primary->tag == T_NODESET);
1450
0
        ns_filter(primary->nodeset, expr->predicates, state);
1451
        /* Evaluating predicates might have reallocated the value_pool */
1452
0
        primary = state->value_pool + primary_ind;
1453
0
        ns_from_locpath(lp, &maxns, &ns, primary->nodeset, state);
1454
0
    }
1455
956k
    RET_ON_ERROR;
1456
1457
956k
    value_ind_t vind = make_value(T_NODESET, state);
1458
956k
    RET_ON_ERROR;
1459
956k
    state->value_pool[vind].nodeset = ns[maxns];
1460
956k
    push_value(vind, state);
1461
1462
956k
    if (lpt != NULL) {
1463
117k
        assert(lpt->ns == NULL);
1464
117k
        assert(lpt->lp == NULL);
1465
117k
        lpt->maxns = maxns;
1466
117k
        lpt->ns = ns;
1467
117k
        lpt->lp = lp;
1468
117k
        state->locpath_trace = lpt;
1469
838k
    } else {
1470
2.72M
        for (int i=0; i < maxns; i++)
1471
1.88M
            free_nodeset(ns[i]);
1472
838k
        FREE(ns);
1473
838k
    }
1474
956k
}
1475
1476
static struct value *lookup_var(const char *ident,
1477
57
                                const struct pathx_symtab *symtab) {
1478
57
    list_for_each(tab, symtab) {
1479
0
        if (STREQ(ident, tab->name))
1480
0
            return tab->value;
1481
0
    }
1482
57
    return NULL;
1483
57
}
1484
1485
0
static void eval_var(struct expr *expr, struct state *state) {
1486
0
    struct value *v = lookup_var(expr->ident, state->symtab);
1487
0
    value_ind_t vind = clone_value(v, state);
1488
0
    RET_ON_ERROR;
1489
0
    push_value(vind, state);
1490
0
}
1491
1492
2.05M
static void eval_expr(struct expr *expr, struct state *state) {
1493
2.05M
    RET_ON_ERROR;
1494
2.05M
    switch (expr->tag) {
1495
956k
    case E_FILTER:
1496
956k
        eval_filter(expr, state);
1497
956k
        break;
1498
594k
    case E_BINARY:
1499
594k
        eval_binary(expr, state);
1500
594k
        break;
1501
479k
    case E_VALUE:
1502
479k
        push_value(expr->value_ind, state);
1503
479k
        break;
1504
0
    case E_VAR:
1505
0
        eval_var(expr, state);
1506
0
        break;
1507
24.4k
    case E_APP:
1508
24.4k
        eval_app(expr, state);
1509
24.4k
        if (expr->fold) {
1510
            /* Do constant folding: replace the function application with
1511
             * a reference to the value that resulted from evaluating it */
1512
228
            for (int i=0; i < expr->func->arity; i++)
1513
114
                free_expr(expr->args[i]);
1514
114
            free(expr->args);
1515
114
            value_ind_t vind = state->values_used - 1;
1516
114
            expr->tag = E_VALUE;
1517
114
            expr->value_ind = state->values[vind];
1518
114
        }
1519
24.4k
        break;
1520
0
    default:
1521
0
        assert(0);
1522
2.05M
    }
1523
2.05M
}
1524
1525
/*************************************************************************
1526
 * Typechecker
1527
 *************************************************************************/
1528
1529
static void check_expr(struct expr *expr, struct state *state);
1530
1531
/* Typecheck a list of predicates. A predicate is a function of
1532
 * one of the following types:
1533
 *
1534
 * T_NODESET -> T_BOOLEAN
1535
 * T_NUMBER  -> T_BOOLEAN  (position test)
1536
 * T_BOOLEAN -> T_BOOLEAN
1537
 */
1538
1.12M
static void check_preds(struct pred *pred, struct state *state) {
1539
1.12M
    if (pred == NULL)
1540
1.10M
        return;
1541
48.2k
    for (int i=0; i < pred->nexpr; i++) {
1542
24.1k
        struct expr *e = pred->exprs[i];
1543
24.1k
        check_expr(e, state);
1544
24.1k
        RET_ON_ERROR;
1545
24.1k
        if (e->type != T_NODESET && e->type != T_NUMBER &&
1546
267
            e->type != T_BOOLEAN && e->type != T_STRING) {
1547
0
            STATE_ERROR(state, PATHX_ETYPE);
1548
0
            return;
1549
0
        }
1550
24.1k
    }
1551
24.1k
}
1552
1553
360k
static void check_filter(struct expr *expr, struct state *state) {
1554
360k
    assert(expr->tag == E_FILTER);
1555
360k
    struct locpath *locpath = expr->locpath;
1556
1557
360k
    if (expr->primary != NULL) {
1558
0
        check_expr(expr->primary, state);
1559
0
        if (expr->primary->type != T_NODESET) {
1560
0
            STATE_ERROR(state, PATHX_ETYPE);
1561
0
            return;
1562
0
        }
1563
0
        check_preds(expr->predicates, state);
1564
0
        RET_ON_ERROR;
1565
0
    }
1566
1.12M
    list_for_each(s, locpath->steps) {
1567
1.12M
        check_preds(s->predicates, state);
1568
1.12M
        RET_ON_ERROR;
1569
1.12M
    }
1570
360k
    expr->type = T_NODESET;
1571
360k
}
1572
1573
402
static void check_app(struct expr *expr, struct state *state) {
1574
402
    assert(expr->tag == E_APP);
1575
1576
895
    for (int i=0; i < expr->func->arity; i++) {
1577
493
        check_expr(expr->args[i], state);
1578
493
        RET_ON_ERROR;
1579
493
    }
1580
1581
402
    int f;
1582
3.39k
    for (f=0; f < ARRAY_CARDINALITY(builtin_funcs); f++) {
1583
3.39k
        const struct func *fn = builtin_funcs + f;
1584
3.39k
        if (STRNEQ(expr->func->name, fn->name))
1585
2.40k
            continue;
1586
986
        if (expr->func->arity != fn->arity)
1587
182
            continue;
1588
1589
804
        int match = 1;
1590
1.29k
        for (int i=0; i < expr->func->arity; i++) {
1591
895
            if (expr->args[i]->type != fn->arg_types[i]) {
1592
402
                match = 0;
1593
402
                break;
1594
402
            }
1595
895
        }
1596
804
        if (match)
1597
402
            break;
1598
804
    }
1599
1600
402
    if (f < ARRAY_CARDINALITY(builtin_funcs)) {
1601
402
        expr->func = builtin_funcs + f;
1602
402
        expr->type = expr->func->type;
1603
402
        expr->fold = expr->func->pure;
1604
402
        if (expr->fold) {
1605
            /* We only do constant folding for invocations of pure functions
1606
             * whose arguments are literal values. That misses opportunities
1607
             * for constant folding, e.g., "regexp('foo' + 'bar')" but is
1608
             * a bit simpler than doing full tracking of constants
1609
             */
1610
629
            for (int i=0; i < expr->func->arity; i++) {
1611
360
                if (expr->args[i]->tag != E_VALUE)
1612
136
                    expr->fold = false;
1613
360
            }
1614
269
        }
1615
402
    } else {
1616
0
        STATE_ERROR(state, PATHX_ETYPE);
1617
0
    }
1618
402
}
1619
1620
/* Check the binary operators. Type rules:
1621
 *
1622
 * '=', '!='  : T_NODESET -> T_NODESET -> T_BOOLEAN
1623
 *              T_STRING  -> T_NODESET -> T_BOOLEAN
1624
 *              T_NODESET -> T_STRING  -> T_BOOLEAN
1625
 *              T_NUMBER  -> T_NUMBER  -> T_BOOLEAN
1626
 *
1627
 * '>', '>=',
1628
 * '<', '<='  : T_NUMBER -> T_NUMBER -> T_BOOLEAN
1629
 *              T_STRING -> T_STRING -> T_BOOLEAN
1630
 * '+'        : T_NUMBER -> T_NUMBER -> T_NUMBER
1631
 *              T_STRING -> T_STRING -> T_STRING
1632
 *              T_REGEXP -> T_REGEXP -> T_REGEXP
1633
 * '+', '-', '*': T_NUMBER -> T_NUMBER -> T_NUMBER
1634
 *
1635
 * 'and', 'or': T_BOOLEAN -> T_BOOLEAN -> T_BOOLEAN
1636
 * '=~', '!~' : T_STRING  -> T_REGEXP  -> T_BOOLEAN
1637
 *              T_NODESET -> T_REGEXP  -> T_BOOLEAN
1638
 *
1639
 * '|'        : T_NODESET -> T_NODESET -> T_NODESET
1640
 *
1641
 * Any type can be coerced to T_BOOLEAN (see coerce_to_bool)
1642
 */
1643
2.16M
static void check_binary(struct expr *expr, struct state *state) {
1644
2.16M
    check_expr(expr->left, state);
1645
2.16M
    check_expr(expr->right, state);
1646
2.16M
    RET_ON_ERROR;
1647
1648
1.45M
    enum type l = expr->left->type;
1649
1.45M
    enum type r = expr->right->type;
1650
1.45M
    int  ok = 1;
1651
1.45M
    enum type res;
1652
1653
1.45M
    switch(expr->op) {
1654
134
    case OP_EQ:
1655
134
    case OP_NEQ:
1656
134
        ok = ((l == T_NODESET || l == T_STRING)
1657
134
              && (r == T_NODESET || r == T_STRING))
1658
0
            || (l == T_NUMBER && r == T_NUMBER);;
1659
134
        res = T_BOOLEAN;
1660
134
        break;
1661
519
    case OP_LT:
1662
519
    case OP_LE:
1663
1.00k
    case OP_GT:
1664
1.00k
    case OP_GE:
1665
1.00k
        ok = (l == T_NUMBER && r == T_NUMBER)
1666
283
            || (l == T_STRING && r == T_STRING);
1667
1.00k
        res = T_BOOLEAN;
1668
1.00k
        break;
1669
1.94k
    case OP_PLUS:
1670
1.94k
        ok = (l == r && (l == T_NUMBER || l == T_STRING || l == T_REGEXP));
1671
1.94k
        res = l;
1672
1.94k
        break;
1673
55.9k
    case OP_MINUS:
1674
1.41M
    case OP_STAR:
1675
1.41M
        ok =  (l == T_NUMBER && r == T_NUMBER);
1676
1.41M
        res = T_NUMBER;
1677
1.41M
        break;
1678
25.7k
    case OP_UNION:
1679
25.7k
        ok = (l == T_NODESET && r == T_NODESET);
1680
25.7k
        res = T_NODESET;
1681
25.7k
        break;
1682
392
    case OP_AND:
1683
5.21k
    case OP_OR:
1684
5.21k
        ok = 1;
1685
5.21k
        res = T_BOOLEAN;
1686
5.21k
        break;
1687
1.81k
    case OP_ELSE:
1688
1.81k
        if (l == T_NODESET && r == T_NODESET) {
1689
455
            res = T_NODESET;
1690
1.36k
        } else {
1691
1.36k
            res = T_BOOLEAN;
1692
1.36k
        }
1693
1.81k
        ok = 1;
1694
1.81k
        break;
1695
0
    case OP_RE_MATCH:
1696
269
    case OP_RE_NOMATCH:
1697
269
        ok = ((l == T_STRING || l == T_NODESET) && r == T_REGEXP);
1698
269
        res = T_BOOLEAN;
1699
269
        break;
1700
0
    default:
1701
0
        assert(0);
1702
1.45M
    }
1703
1.45M
    if (! ok) {
1704
261
        STATE_ERROR(state, PATHX_ETYPE);
1705
1.45M
    } else {
1706
1.45M
        expr->type = res;
1707
1.45M
    }
1708
1.45M
}
1709
1710
57
static void check_var(struct expr *expr, struct state *state) {
1711
57
    struct value *v = lookup_var(expr->ident, state->symtab);
1712
57
    if (v == NULL) {
1713
57
        STATE_ERROR(state, PATHX_ENOVAR);
1714
57
        return;
1715
57
    }
1716
0
    expr->type = v->tag;
1717
0
}
1718
1719
/* Typecheck an expression */
1720
4.69M
static void check_expr(struct expr *expr, struct state *state) {
1721
4.69M
    RET_ON_ERROR;
1722
3.97M
    switch(expr->tag) {
1723
360k
    case E_FILTER:
1724
360k
        check_filter(expr, state);
1725
360k
        break;
1726
2.16M
    case E_BINARY:
1727
2.16M
        check_binary(expr, state);
1728
2.16M
        break;
1729
1.44M
    case E_VALUE:
1730
1.44M
        expr->type = expr_value(expr, state)->tag;
1731
1.44M
        break;
1732
57
    case E_VAR:
1733
57
        check_var(expr, state);
1734
57
        break;
1735
402
    case E_APP:
1736
402
        check_app(expr, state);
1737
402
        break;
1738
0
    default:
1739
0
        assert(0);
1740
3.97M
    }
1741
3.97M
}
1742
1743
/*
1744
 * Utility functions for the parser
1745
 */
1746
1747
23.5M
static void skipws(struct state *state) {
1748
23.5M
    while (isspace((unsigned char) *state->pos)) state->pos += 1;
1749
23.5M
}
1750
1751
22.5M
static int match(struct state *state, char m) {
1752
22.5M
    skipws(state);
1753
1754
22.5M
    if (*state->pos == '\0')
1755
1.31M
        return 0;
1756
21.2M
    if (*state->pos == m) {
1757
5.67M
        state->pos += 1;
1758
5.67M
        return 1;
1759
5.67M
    }
1760
15.5M
    return 0;
1761
21.2M
}
1762
1763
10.2M
static int peek(struct state *state, const char *chars) {
1764
10.2M
    return strchr(chars, *state->pos) != NULL;
1765
10.2M
}
1766
1767
/* Return 1 if STATE->POS starts with TOKEN, followed by optional
1768
 * whitespace, followed by FOLLOW. In that case, STATE->POS is set to the
1769
 * first character after FOLLOW. Return 0 otherwise and leave STATE->POS
1770
 * unchanged.
1771
 */
1772
static int looking_at(struct state *state, const char *token,
1773
22.5M
                      const char *follow) {
1774
22.5M
    if (STREQLEN(state->pos, token, strlen(token))) {
1775
47.5k
        const char *p = state->pos + strlen(token);
1776
47.5k
        while (isspace((unsigned char) *p)) p++;
1777
47.5k
        if (STREQLEN(p, follow, strlen(follow))) {
1778
18.2k
            state->pos = p + strlen(follow);
1779
18.2k
            return 1;
1780
18.2k
        }
1781
47.5k
    }
1782
22.5M
    return 0;
1783
22.5M
}
1784
1785
/*************************************************************************
1786
 * The parser
1787
 *************************************************************************/
1788
1789
static void parse_expr(struct state *state);
1790
1791
7.31M
static struct expr* pop_expr(struct state *state) {
1792
7.31M
    if (state->exprs_used > 0) {
1793
7.31M
        state->exprs_used -= 1;
1794
7.31M
        return state->exprs[state->exprs_used];
1795
7.31M
    } else {
1796
0
        STATE_ERROR(state, PATHX_EINTERNAL);
1797
0
        assert(0);
1798
0
        return NULL;
1799
0
    }
1800
7.31M
}
1801
1802
8.26M
static void push_expr(struct expr *expr, struct state *state) {
1803
8.26M
    if (state->exprs_used >= state->exprs_size) {
1804
328k
        size_t new_size = 2*state->exprs_size;
1805
328k
        if (new_size == 0) new_size = 8;
1806
328k
        if (REALLOC_N(state->exprs, new_size) < 0) {
1807
0
            STATE_ENOMEM;
1808
0
            return;
1809
0
        }
1810
328k
        state->exprs_size = new_size;
1811
328k
    }
1812
8.26M
    state->exprs[state->exprs_used++] = expr;
1813
8.26M
}
1814
1815
3.64M
static void push_new_binary_op(enum binary_op op, struct state *state) {
1816
3.64M
    struct expr *expr = NULL;
1817
3.64M
    if (ALLOC(expr) < 0) {
1818
0
        STATE_ENOMEM;
1819
0
        return;
1820
0
    }
1821
1822
3.64M
    expr->tag = E_BINARY;
1823
3.64M
    expr->op  = op;
1824
3.64M
    expr->right = pop_expr(state);
1825
3.64M
    expr->left = pop_expr(state);
1826
3.64M
    expr->left_matched = false;  /* for 'else' operator only, true if any matches on LHS */
1827
3.64M
    push_expr(expr, state);
1828
3.64M
}
1829
1830
7.34k
int pathx_escape_name(const char *in, char **out) {
1831
7.34k
    const char *p;
1832
7.34k
    int num_to_escape = 0;
1833
7.34k
    char *s;
1834
1835
7.34k
    *out = NULL;
1836
1837
26.1M
    for (p = in; *p; p++) {
1838
26.0M
        if (strchr(name_follow, *p) || isspace((unsigned char) *p) || *p == '\\')
1839
14.5M
            num_to_escape += 1;
1840
26.0M
    }
1841
1842
7.34k
    if (num_to_escape == 0)
1843
3.84k
        return 0;
1844
1845
3.50k
    if (ALLOC_N(*out, strlen(in) + num_to_escape + 1) < 0)
1846
0
        return -1;
1847
1848
18.1M
    for (p = in, s = *out; *p; p++) {
1849
18.1M
        if (strchr(name_follow, *p) || isspace((unsigned char) *p) || *p == '\\')
1850
14.5M
            *s++ = '\\';
1851
18.1M
        *s++ = *p;
1852
18.1M
    }
1853
3.50k
    *s = '\0';
1854
3.50k
    return 0;
1855
3.50k
}
1856
1857
/* Return true if POS is preceded by an odd number of backslashes, i.e., if
1858
 * POS is escaped. Stop the search when we get to START */
1859
246k
static bool backslash_escaped(const char *pos, const char *start) {
1860
246k
    bool result=false;
1861
247k
    while (pos-- > start && *pos == '\\') {
1862
540
        result = !result;
1863
540
    }
1864
246k
    return result;
1865
246k
}
1866
1867
/*
1868
 * NameNoWS ::= [^][|/\= \t\n] | \\.
1869
 * NameWS   ::= [^][|/\=] | \\.
1870
 * Name ::= NameNoWS NameWS* NameNoWS | NameNoWS
1871
 */
1872
1.31M
static char *parse_name(struct state *state) {
1873
1.31M
    const char *s = state->pos;
1874
1.31M
    char *result;
1875
1876
    /* Advance state->pos until it points to the first character that is
1877
     * not part of a name. */
1878
34.9M
    while (*state->pos != '\0' && strchr(name_follow, *state->pos) == NULL) {
1879
        /* Since we allow spaces in names, we need to avoid gobbling up
1880
         * stuff that is in follow(Name), e.g. 'or' so that things like
1881
         * [name1 or name2] still work. In other words, we'll parse 'x frob
1882
         * y' as one name, but for 'x or y', we consider 'x' a name in its
1883
         * own right. */
1884
33.6M
        if (STREQLEN(state->pos, " or ", strlen(" or ")) ||
1885
33.6M
            STREQLEN(state->pos, " and ", strlen(" and ")) ||
1886
33.6M
            STREQLEN(state->pos, " else ", strlen(" else ")))
1887
931
            break;
1888
1889
33.6M
        if (*state->pos == '\\') {
1890
3.29M
            state->pos += 1;
1891
3.29M
            if (*state->pos == '\0') {
1892
0
                STATE_ERROR(state, PATHX_ENAME);
1893
0
                return NULL;
1894
0
            }
1895
3.29M
        }
1896
33.6M
        state->pos += 1;
1897
33.6M
    }
1898
1899
    /* Strip trailing white space. Make sure we respect escaped whitespace
1900
     * and don't strip it as in "x\\ " */
1901
1.31M
    if (state->pos > s) {
1902
1.31M
        state->pos -= 1;
1903
1.56M
        while (isspace((unsigned char) *state->pos) && state->pos > s
1904
246k
               && !backslash_escaped(state->pos, s))
1905
246k
            state->pos -= 1;
1906
1.31M
        state->pos += 1;
1907
1.31M
    }
1908
1909
1.31M
    if (state->pos == s) {
1910
42
        STATE_ERROR(state, PATHX_ENAME);
1911
42
        return NULL;
1912
42
    }
1913
1914
1.31M
    result = strndup(s, state->pos - s);
1915
1.31M
    if (result == NULL) {
1916
0
        STATE_ENOMEM;
1917
0
        return NULL;
1918
0
    }
1919
1920
1.31M
    char *p = result;
1921
34.7M
    for (char *t = result; *t != '\0'; t++, p++) {
1922
33.3M
        if (*t == '\\')
1923
3.29M
            t += 1;
1924
33.3M
        *p = *t;
1925
33.3M
    }
1926
1.31M
    *p = '\0';
1927
1928
1.31M
    return result;
1929
1.31M
}
1930
1931
/*
1932
 * Predicate    ::= "[" Expr "]" *
1933
 */
1934
5.02M
static struct pred *parse_predicates(struct state *state) {
1935
5.02M
    struct pred *pred = NULL;
1936
5.02M
    int nexpr = 0;
1937
1938
5.05M
    while (match(state, L_BRACK)) {
1939
257k
        parse_expr(state);
1940
257k
        nexpr += 1;
1941
257k
        RET0_ON_ERROR;
1942
1943
24.1k
        if (! match(state, R_BRACK)) {
1944
27
            STATE_ERROR(state, PATHX_EPRED);
1945
27
            return NULL;
1946
27
        }
1947
24.1k
        skipws(state);
1948
24.1k
    }
1949
1950
4.79M
    if (nexpr == 0)
1951
4.77M
        return NULL;
1952
1953
24.1k
    if (ALLOC(pred) < 0) {
1954
0
        STATE_ENOMEM;
1955
0
        return NULL;
1956
0
    }
1957
24.1k
    pred->nexpr = nexpr;
1958
1959
24.1k
    if (ALLOC_N(pred->exprs, nexpr) < 0) {
1960
0
        free_pred(pred);
1961
0
        STATE_ENOMEM;
1962
0
        return NULL;
1963
0
    }
1964
1965
48.2k
    for (int i = nexpr - 1; i >= 0; i--)
1966
24.1k
        pred->exprs[i] = pop_expr(state);
1967
1968
24.1k
    return pred;
1969
24.1k
}
1970
1971
/*
1972
 * Step ::= AxisSpecifier NameTest Predicate* | '.' | '..'
1973
 * AxisSpecifier ::= AxisName '::' | <epsilon>
1974
 * AxisName ::= 'ancestor'
1975
 *            | 'ancestor-or-self'
1976
 *            | 'child'
1977
 *            | 'descendant'
1978
 *            | 'descendant-or-self'
1979
 *            | 'parent'
1980
 *            | 'self'
1981
 *            | 'root'
1982
 */
1983
2.25M
static struct step *parse_step(struct state *state) {
1984
2.25M
    struct step *step;
1985
2.25M
    int explicit_axis = 0, allow_predicates = 1;
1986
1987
2.25M
    if (ALLOC(step) < 0) {
1988
0
        STATE_ENOMEM;
1989
0
        return NULL;
1990
0
    }
1991
1992
2.25M
    step->axis = CHILD;
1993
24.7M
    for (int i = 0; i < ARRAY_CARDINALITY(axis_names); i++) {
1994
22.5M
        if (looking_at(state, axis_names[i], "::")) {
1995
565
            step->axis = i;
1996
565
            explicit_axis = 1;
1997
565
            break;
1998
565
        }
1999
22.5M
    }
2000
2001
2.25M
    if (! match(state, '*')) {
2002
1.31M
        step->name = parse_name(state);
2003
1.31M
        if (HAS_ERROR(state))
2004
42
            goto error;
2005
1.31M
        if (! explicit_axis) {
2006
1.31M
            if (STREQ(step->name, ".") || STREQ(step->name, "..")) {
2007
1.47k
                step->axis = STREQ(step->name, ".") ? SELF : PARENT;
2008
1.47k
                FREE(step->name);
2009
1.47k
                allow_predicates = 0;
2010
1.47k
            }
2011
1.31M
        }
2012
1.31M
    }
2013
2014
2.25M
    if (allow_predicates) {
2015
2.24M
        step->predicates = parse_predicates(state);
2016
2.24M
        if (HAS_ERROR(state))
2017
233k
            goto error;
2018
2.24M
    }
2019
2020
2.01M
    return step;
2021
2022
233k
 error:
2023
233k
    free_step(step);
2024
233k
    return NULL;
2025
2.25M
}
2026
2027
370k
static struct step *make_step(enum axis axis, struct state *state) {
2028
370k
    struct step *result = NULL;
2029
2030
370k
    if (ALLOC(result) < 0) {
2031
0
        STATE_ENOMEM;
2032
0
        return NULL;
2033
0
    }
2034
370k
    result->axis = axis;
2035
370k
    return result;
2036
370k
}
2037
2038
/*
2039
 * RelativeLocationPath ::= Step
2040
 *                        | RelativeLocationPath '/' Step
2041
 *                        | AbbreviatedRelativeLocationPath
2042
 * AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
2043
 *
2044
 * The above is the same as
2045
 * RelativeLocationPath ::= Step ('/' Step | '//' Step)*
2046
 */
2047
static struct locpath *
2048
1.83M
parse_relative_location_path(struct state *state) {
2049
1.83M
    struct step *step = NULL;
2050
1.83M
    struct locpath *locpath = NULL;
2051
2052
1.83M
    step = parse_step(state);
2053
1.83M
    if (HAS_ERROR(state))
2054
233k
        goto error;
2055
2056
1.60M
    if (ALLOC(locpath) < 0) {
2057
0
        STATE_ENOMEM;
2058
0
        goto error;
2059
0
    }
2060
1.60M
    list_append(locpath->steps, step);
2061
1.60M
    step = NULL;
2062
2063
2.01M
    while (match(state, '/')) {
2064
411k
        if (*state->pos == '/') {
2065
1.52k
            state->pos += 1;
2066
1.52k
            step = make_step(DESCENDANT_OR_SELF, state);
2067
1.52k
            if (step == NULL) {
2068
0
                STATE_ENOMEM;
2069
0
                goto error;
2070
0
            }
2071
1.52k
            list_append(locpath->steps, step);
2072
1.52k
        }
2073
411k
        step = parse_step(state);
2074
411k
        if (HAS_ERROR(state))
2075
0
            goto error;
2076
411k
        list_append(locpath->steps, step);
2077
411k
        step = NULL;
2078
411k
    }
2079
1.60M
    return locpath;
2080
2081
233k
 error:
2082
233k
    free_step(step);
2083
233k
    free_locpath(locpath);
2084
233k
    return NULL;
2085
1.60M
}
2086
2087
/*
2088
 * LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
2089
 * AbsoluteLocationPath ::= '/' RelativeLocationPath?
2090
 *                        | AbbreviatedAbsoluteLocationPath
2091
 * AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
2092
 *
2093
 */
2094
1.83M
static void parse_location_path(struct state *state) {
2095
1.83M
    struct expr *expr = NULL;
2096
1.83M
    struct locpath *locpath = NULL;
2097
2098
1.83M
    if (match(state, '/')) {
2099
368k
        if (*state->pos == '/') {
2100
41.4k
            state->pos += 1;
2101
41.4k
            locpath = parse_relative_location_path(state);
2102
41.4k
            if (HAS_ERROR(state))
2103
0
                goto error;
2104
41.4k
            struct step *step = make_step(DESCENDANT_OR_SELF, state);
2105
41.4k
            if (HAS_ERROR(state))
2106
0
                goto error;
2107
41.4k
            list_cons(locpath->steps, step);
2108
327k
        } else {
2109
327k
            if (*state->pos != '\0') {
2110
327k
                locpath = parse_relative_location_path(state);
2111
327k
            } else {
2112
0
                if (ALLOC(locpath) < 0)
2113
0
                    goto err_nomem;
2114
0
            }
2115
327k
            struct step *step = make_step(ROOT, state);
2116
327k
            if (HAS_ERROR(state)) {
2117
0
                free_step(step);
2118
0
                goto error;
2119
0
            }
2120
327k
            list_cons(locpath->steps, step);
2121
327k
        }
2122
1.47M
    } else {
2123
1.47M
        locpath = parse_relative_location_path(state);
2124
1.47M
    }
2125
2126
1.83M
    if (ALLOC(expr) < 0)
2127
0
        goto err_nomem;
2128
1.83M
    expr->tag = E_FILTER;
2129
1.83M
    expr->locpath = locpath;
2130
1.83M
    push_expr(expr, state);
2131
1.83M
    return;
2132
2133
0
 err_nomem:
2134
0
    STATE_ENOMEM;
2135
0
 error:
2136
0
    free_expr(expr);
2137
0
    free_locpath(locpath);
2138
0
    return;
2139
0
}
2140
2141
/*
2142
 * Number       ::= /[0-9]+/
2143
 */
2144
2.77M
static void parse_number(struct state *state) {
2145
2.77M
    struct expr *expr = NULL;
2146
2.77M
    unsigned long val;
2147
2.77M
    char *end;
2148
2149
2.77M
    errno = 0;
2150
2.77M
    val = strtoul(state->pos, &end, 10);
2151
2.77M
    if (errno || end == state->pos || (int) val != val) {
2152
67
        STATE_ERROR(state, PATHX_ENUMBER);
2153
67
        return;
2154
67
    }
2155
2156
2.77M
    state->pos = end;
2157
2158
2.77M
    if (ALLOC(expr) < 0)
2159
0
        goto err_nomem;
2160
2.77M
    expr->tag = E_VALUE;
2161
2.77M
    expr->value_ind = make_value(T_NUMBER, state);
2162
2.77M
    if (HAS_ERROR(state))
2163
0
        goto error;
2164
2.77M
    expr_value(expr, state)->number = val;
2165
2166
2.77M
    push_expr(expr, state);
2167
2.77M
    return;
2168
2169
0
 err_nomem:
2170
0
    STATE_ENOMEM;
2171
0
 error:
2172
0
    free_expr(expr);
2173
0
    return;
2174
0
}
2175
2176
/*
2177
 * Literal ::= '"' /[^"]* / '"' | "'" /[^']* / "'"
2178
 */
2179
2.80k
static void parse_literal(struct state *state) {
2180
2.80k
    char delim;
2181
2.80k
    const char *s;
2182
2.80k
    struct expr *expr = NULL;
2183
2184
2.80k
    if (*state->pos == '"')
2185
1.65k
        delim = '"';
2186
1.14k
    else if (*state->pos == '\'')
2187
1.00k
        delim = '\'';
2188
144
    else {
2189
144
        STATE_ERROR(state, PATHX_ESTRING);
2190
144
        return;
2191
144
    }
2192
2.65k
    state->pos += 1;
2193
2194
2.65k
    s = state->pos;
2195
4.59M
    while (*state->pos != '\0' && *state->pos != delim) state->pos += 1;
2196
2197
2.65k
    if (*state->pos != delim) {
2198
50
        STATE_ERROR(state, PATHX_EDELIM);
2199
50
        return;
2200
50
    }
2201
2.60k
    state->pos += 1;
2202
2203
2.60k
    if (ALLOC(expr) < 0)
2204
0
        goto err_nomem;
2205
2.60k
    expr->tag = E_VALUE;
2206
2.60k
    expr->value_ind = make_value(T_STRING, state);
2207
2.60k
    if (HAS_ERROR(state))
2208
0
        goto error;
2209
2.60k
    expr_value(expr, state)->string = strndup(s, state->pos - s - 1);
2210
2.60k
    if (expr_value(expr, state)->string == NULL)
2211
0
        goto err_nomem;
2212
2213
2.60k
    push_expr(expr, state);
2214
2.60k
    return;
2215
2216
0
 err_nomem:
2217
0
    STATE_ENOMEM;
2218
0
 error:
2219
0
    free_expr(expr);
2220
0
    return;
2221
0
}
2222
2223
/*
2224
 * FunctionCall ::= Name '(' ( Expr ( ',' Expr )* )? ')'
2225
 */
2226
17.6k
static void parse_function_call(struct state *state) {
2227
17.6k
    const struct func *func = NULL;
2228
17.6k
    struct expr *expr = NULL;
2229
17.6k
    int nargs = 0, find = 0;
2230
2231
89.3k
    for (; find < ARRAY_CARDINALITY(builtin_funcs); find++) {
2232
89.3k
        if (looking_at(state, builtin_funcs[find].name, "(")) {
2233
17.6k
            func = builtin_funcs + find;
2234
17.6k
            break;
2235
17.6k
        }
2236
89.3k
    }
2237
17.6k
    if (func == NULL) {
2238
3
        STATE_ERROR(state, PATHX_ENAME);
2239
3
        return;
2240
3
    }
2241
2242
17.6k
    if (! match(state, ')')) {
2243
17.7k
        do {
2244
17.7k
            nargs += 1;
2245
17.7k
            parse_expr(state);
2246
17.7k
            RET_ON_ERROR;
2247
17.7k
        } while (match(state, ','));
2248
2249
406
        if (! match(state, ')')) {
2250
2
            STATE_ERROR(state, PATHX_EPAREN);
2251
2
            return;
2252
2
        }
2253
406
    }
2254
2255
404
    int found = 0; /* Whether there is a builtin matching in name and arity */
2256
586
    for (int i=find; i < ARRAY_CARDINALITY(builtin_funcs); i++) {
2257
586
        if (STRNEQ(func->name, builtin_funcs[i].name))
2258
0
            break;
2259
586
        if (builtin_funcs[i].arity == nargs) {
2260
404
            func = builtin_funcs + i;
2261
404
            found = 1;
2262
404
            break;
2263
404
        }
2264
586
    }
2265
2266
404
    if (! found) {
2267
0
        STATE_ERROR(state, PATHX_EARITY);
2268
0
        return;
2269
0
    }
2270
2271
404
    if (ALLOC(expr) < 0) {
2272
0
        STATE_ENOMEM;
2273
0
        return;
2274
0
    }
2275
404
    expr->tag = E_APP;
2276
404
    if (ALLOC_N(expr->args, nargs) < 0) {
2277
0
        free_expr(expr);
2278
0
        STATE_ENOMEM;
2279
0
        return;
2280
0
    }
2281
404
    expr->func = func;
2282
899
    for (int i = nargs - 1; i >= 0; i--)
2283
495
        expr->args[i] = pop_expr(state);
2284
2285
404
    push_expr(expr, state);
2286
404
}
2287
2288
/*
2289
 * VariableReference ::= '$' /[a-zA-Z_][a-zA-Z0-9_]* /
2290
 *
2291
 * The '$' is consumed by parse_primary_expr
2292
 */
2293
879
static void parse_var(struct state *state) {
2294
879
    const char *id = state->pos;
2295
879
    struct expr *expr = NULL;
2296
2297
879
    if (!isalpha((unsigned char) *id) && *id != '_') {
2298
31
        STATE_ERROR(state, PATHX_ENAME);
2299
31
        return;
2300
31
    }
2301
848
    id++;
2302
1.43k
    while (isalpha((unsigned char) *id) || isdigit((unsigned char) *id) || *id == '_')
2303
584
        id += 1;
2304
2305
848
    if (ALLOC(expr) < 0)
2306
0
        goto err_nomem;
2307
848
    expr->tag = E_VAR;
2308
848
    expr->ident = strndup(state->pos, id - state->pos);
2309
848
    if (expr->ident == NULL)
2310
0
        goto err_nomem;
2311
2312
848
    push_expr(expr, state);
2313
848
    state->pos = id;
2314
848
    return;
2315
0
 err_nomem:
2316
0
    STATE_ENOMEM;
2317
0
    free_expr(expr);
2318
0
    return;
2319
848
}
2320
2321
/*
2322
 * PrimaryExpr ::= Literal
2323
 *               | Number
2324
 *               | FunctionCall
2325
 *               | VariableReference
2326
 *               | '(' Expr ')'
2327
 *
2328
 */
2329
2.79M
static void parse_primary_expr(struct state *state) {
2330
2.79M
    if (peek(state, "'\"")) {
2331
2.80k
        parse_literal(state);
2332
2.79M
    } else if (peek(state, "0123456789")) {
2333
2.77M
        parse_number(state);
2334
2.77M
    } else if (match(state, '(')) {
2335
0
        parse_expr(state);
2336
0
        RET_ON_ERROR;
2337
0
        if (! match(state, ')')) {
2338
0
            STATE_ERROR(state, PATHX_EPAREN);
2339
0
            return;
2340
0
        }
2341
18.5k
    } else if (match(state, '$')) {
2342
879
        parse_var(state);
2343
17.6k
    } else {
2344
17.6k
        parse_function_call(state);
2345
17.6k
    }
2346
2.79M
}
2347
2348
4.63M
static int looking_at_primary_expr(struct state *state) {
2349
4.63M
    const char *s = state->pos;
2350
    /* Is it a Number, Literal or VariableReference ? */
2351
4.63M
    if (peek(state, "$'\"0123456789"))
2352
2.77M
        return 1;
2353
2354
    /* Or maybe a function call, i.e. a word followed by a '(' ?
2355
     * Note that our function names are only [a-zA-Z]+
2356
     */
2357
2.21M
    while (*s != '\0' && isalpha((unsigned char) *s)) s++;
2358
1.87M
    while (*s != '\0' && isspace((unsigned char) *s)) s++;
2359
1.85M
    return *s == '(';
2360
4.63M
}
2361
2362
/*
2363
 * PathExpr ::= LocationPath
2364
 *            | FilterExpr
2365
 *            | FilterExpr '/' RelativeLocationPath
2366
 *            | FilterExpr '//' RelativeLocationPath
2367
 *
2368
 * FilterExpr ::= PrimaryExpr Predicate
2369
 *
2370
 * The grammar is ambiguous here: the expression '42' can either be the
2371
 * number 42 (a PrimaryExpr) or the RelativeLocationPath 'child::42'. The
2372
 * reason for this ambiguity is that we allow node names like '42' in the
2373
 * tree; rather than forbid them, we resolve the ambiguity by always
2374
 * parsing '42' as a number, and requiring that the user write the
2375
 * RelativeLocationPath in a different form, e.g. 'child::42' or './42'.
2376
 */
2377
4.63M
static void parse_path_expr(struct state *state) {
2378
4.63M
    struct expr *expr = NULL;
2379
4.63M
    struct pred *predicates = NULL;
2380
4.63M
    struct locpath *locpath = NULL;
2381
2382
4.63M
    if (looking_at_primary_expr(state)) {
2383
2.79M
        parse_primary_expr(state);
2384
2.79M
        RET_ON_ERROR;
2385
2.77M
        predicates = parse_predicates(state);
2386
2.77M
        RET_ON_ERROR;
2387
2.77M
        if (match(state, '/')) {
2388
0
            if (match(state, '/')) {
2389
0
                locpath = parse_relative_location_path(state);
2390
0
                if (HAS_ERROR(state))
2391
0
                    goto error;
2392
2393
0
                struct step *step = make_step(DESCENDANT_OR_SELF, state);
2394
0
                if (HAS_ERROR(state))
2395
0
                    return;
2396
0
                list_cons(locpath->steps, step);
2397
0
            } else {
2398
0
                if (*state->pos == '\0') {
2399
0
                    STATE_ERROR(state, PATHX_EEND);
2400
0
                    goto error;
2401
0
                }
2402
0
                locpath = parse_relative_location_path(state);
2403
0
            }
2404
0
        }
2405
        /* A PathExpr without predicates and locpath is
2406
         * just a PrimaryExpr
2407
         */
2408
2.77M
        if (predicates == NULL && locpath == NULL)
2409
2.77M
            return;
2410
        /* To make evaluation easier, we parse something like
2411
         *   $var[pred] as $var[pred]/.
2412
         */
2413
0
        if (locpath == NULL) {
2414
0
            if (ALLOC(locpath) < 0)
2415
0
                goto error;
2416
0
            if (ALLOC(locpath->steps) < 0)
2417
0
                goto error;
2418
0
            locpath->steps->axis = SELF;
2419
0
        }
2420
0
        if (ALLOC(expr) < 0)
2421
0
            goto error;
2422
0
        expr->tag = E_FILTER;
2423
0
        expr->predicates = predicates;
2424
0
        expr->primary    = pop_expr(state);
2425
0
        expr->locpath    = locpath;
2426
0
        push_expr(expr, state);
2427
1.83M
    } else {
2428
1.83M
        parse_location_path(state);
2429
1.83M
    }
2430
1.83M
    return;
2431
1.83M
 error:
2432
0
    free_expr(expr);
2433
0
    free_pred(predicates);
2434
0
    free_locpath(locpath);
2435
0
    return;
2436
4.63M
}
2437
2438
/*
2439
 * UnionExpr ::= PathExpr ('|' PathExpr)*
2440
 */
2441
4.36M
static void parse_union_expr(struct state *state) {
2442
4.36M
    parse_path_expr(state);
2443
4.36M
    RET_ON_ERROR;
2444
4.38M
    while (match(state, '|')) {
2445
267k
        parse_path_expr(state);
2446
267k
        RET_ON_ERROR;
2447
160k
        push_new_binary_op(OP_UNION, state);
2448
160k
    }
2449
4.22M
}
2450
2451
/*
2452
 * MultiplicativeExpr ::= UnionExpr ('*' UnionExpr)*
2453
 */
2454
962k
static void parse_multiplicative_expr(struct state *state) {
2455
962k
    parse_union_expr(state);
2456
962k
    RET_ON_ERROR;
2457
4.11M
    while (match(state, '*')) {
2458
3.40M
        parse_union_expr(state);
2459
3.40M
        RET_ON_ERROR;
2460
3.40M
        push_new_binary_op(OP_STAR, state);
2461
3.40M
    }
2462
711k
}
2463
2464
/*
2465
 * AdditiveExpr ::= MultiplicativeExpr (AdditiveOp MultiplicativeExpr)*
2466
 * AdditiveOp   ::= '+' | '-'
2467
 */
2468
822k
static void parse_additive_expr(struct state *state) {
2469
822k
    parse_multiplicative_expr(state);
2470
822k
    RET_ON_ERROR;
2471
711k
    while (*state->pos == '+' || *state->pos == '-') {
2472
140k
        enum binary_op op = (*state->pos == '+') ? OP_PLUS : OP_MINUS;
2473
140k
        state->pos += 1;
2474
140k
        skipws(state);
2475
140k
        parse_multiplicative_expr(state);
2476
140k
        RET_ON_ERROR;
2477
61.6k
        push_new_binary_op(op, state);
2478
61.6k
    }
2479
650k
}
2480
2481
/*
2482
 * RelationalExpr ::= AdditiveExpr (RelationalOp AdditiveExpr)?
2483
 * RelationalOp ::= ">" | "<" | ">=" | "<="
2484
 */
2485
718k
static void parse_relational_expr(struct state *state) {
2486
718k
    parse_additive_expr(state);
2487
718k
    RET_ON_ERROR;
2488
568k
    if (*state->pos == '<' || *state->pos == '>') {
2489
103k
        enum binary_op op = (*state->pos == '<') ? OP_LT : OP_GT;
2490
103k
        state->pos += 1;
2491
103k
        if (*state->pos == '=') {
2492
0
            op = (op == OP_LT) ? OP_LE : OP_GE;
2493
0
            state->pos += 1;
2494
0
        }
2495
103k
        skipws(state);
2496
103k
        parse_additive_expr(state);
2497
103k
        RET_ON_ERROR;
2498
2.77k
        push_new_binary_op(op, state);
2499
2.77k
    }
2500
568k
}
2501
2502
/*
2503
 * EqualityExpr ::= RelationalExpr (EqualityOp RelationalExpr)? | ReMatchExpr
2504
 * EqualityOp ::= "=" | "!="
2505
 * ReMatchExpr ::= RelationalExpr MatchOp RelationalExpr
2506
 * MatchOp ::= "=~" | "!~"
2507
 */
2508
617k
static void parse_equality_expr(struct state *state) {
2509
617k
    parse_relational_expr(state);
2510
617k
    RET_ON_ERROR;
2511
467k
    if ((*state->pos == '=' || *state->pos == '!') && state->pos[1] == '~') {
2512
101k
        enum binary_op op = (*state->pos == '=') ? OP_RE_MATCH : OP_RE_NOMATCH;
2513
101k
        state->pos += 2;
2514
101k
        skipws(state);
2515
101k
        parse_relational_expr(state);
2516
101k
        RET_ON_ERROR;
2517
296
        push_new_binary_op(op, state);
2518
365k
    } else if (*state->pos == '=' ||
2519
365k
        (*state->pos == '!' && state->pos[1] == '=')) {
2520
162
        enum binary_op op = (*state->pos == '=') ? OP_EQ : OP_NEQ;
2521
162
        state->pos += (op == OP_EQ) ? 1 : 2;
2522
162
        skipws(state);
2523
162
        parse_relational_expr(state);
2524
162
        RET_ON_ERROR;
2525
134
        push_new_binary_op(op, state);
2526
134
    }
2527
467k
}
2528
2529
/*
2530
 * AndExpr ::= EqualityExpr ('and' EqualityExpr)*
2531
 */
2532
615k
static void parse_and_expr(struct state *state) {
2533
615k
    parse_equality_expr(state);
2534
615k
    RET_ON_ERROR;
2535
366k
    while (*state->pos == 'a' && state->pos[1] == 'n'
2536
1.73k
        && state->pos[2] == 'd') {
2537
1.69k
        state->pos += 3;
2538
1.69k
        skipws(state);
2539
1.69k
        parse_equality_expr(state);
2540
1.69k
        RET_ON_ERROR;
2541
884
        push_new_binary_op(OP_AND, state);
2542
884
    }
2543
365k
}
2544
2545
/*
2546
 * OrExpr ::= AndExpr ('or' AndExpr)*
2547
 */
2548
607k
static void parse_or_expr(struct state *state) {
2549
607k
    parse_and_expr(state);
2550
607k
    RET_ON_ERROR;
2551
364k
    while (*state->pos == 'o' && state->pos[1] == 'r') {
2552
8.25k
        state->pos += 2;
2553
8.25k
        skipws(state);
2554
8.25k
        parse_and_expr(state);
2555
8.25k
        RET_ON_ERROR;
2556
8.21k
        push_new_binary_op(OP_OR, state);
2557
8.21k
    }
2558
356k
}
2559
2560
/*
2561
 * ElseExpr ::= OrExpr ('else' OrExpr)*
2562
 */
2563
603k
static void parse_else_expr(struct state *state) {
2564
603k
    parse_or_expr(state);
2565
603k
    RET_ON_ERROR;
2566
356k
    while (*state->pos == 'e' && state->pos[1] == 'l'
2567
3.54k
        && state->pos[2] == 's' && state->pos[3] == 'e' ) {
2568
3.51k
        state->pos += 4;
2569
3.51k
        skipws(state);
2570
3.51k
        parse_or_expr(state);
2571
3.51k
        RET_ON_ERROR;
2572
3.49k
        push_new_binary_op(OP_ELSE, state);
2573
3.49k
        state->has_else = 1;
2574
3.49k
    }
2575
352k
}
2576
2577
/*
2578
 * Expr ::= ElseExpr
2579
 */
2580
603k
static void parse_expr(struct state *state) {
2581
603k
    skipws(state);
2582
603k
    parse_else_expr(state);
2583
603k
}
2584
2585
328k
static void store_error(struct pathx *pathx) {
2586
328k
    const char *pathx_msg = NULL;
2587
328k
    const char *path = pathx->state->txt;
2588
328k
    const pathx_errcode_t errcode = pathx->state->errcode;
2589
328k
    struct error *err = pathx->state->error;
2590
2591
328k
    char *pos_str = pathx->state->errmsg;
2592
328k
    pathx->state->errmsg = NULL;
2593
2594
328k
    if (err == NULL || errcode == PATHX_NOERROR || err->code != AUG_NOERROR)
2595
327k
        return;
2596
2597
1.14k
    switch (errcode) {
2598
0
    case PATHX_ENOMEM:
2599
0
        err->code = AUG_ENOMEM;
2600
0
        break;
2601
0
    case PATHX_EMMATCH:
2602
0
        err->code = AUG_EMMATCH;
2603
0
        break;
2604
0
    case PATHX_ENOMATCH:
2605
0
        err->code = AUG_ENOMATCH;
2606
0
        break;
2607
1.14k
    default:
2608
1.14k
        err->code = AUG_EPATHX;
2609
1.14k
        break;
2610
1.14k
    }
2611
2612
    /* We only need details for pathx syntax errors */
2613
1.14k
    if (err->code != AUG_EPATHX)
2614
0
        return;
2615
2616
1.14k
    int pos;
2617
1.14k
    pathx_msg = pathx_error(pathx, NULL, &pos);
2618
2619
1.14k
    bool has_msg = pos_str != NULL;
2620
1.14k
    int pos_str_len = pos_str == NULL ? 0 : strlen(pos_str);
2621
1.14k
    if (REALLOC_N(pos_str, pos_str_len + strlen(path) + 8) >= 0) {
2622
1.14k
        if (has_msg) {
2623
5
            strcat(pos_str, " in ");
2624
5
            strncat(pos_str, path, pos);
2625
1.13k
        } else {
2626
            /* initialize pos_str explicitly, path might be "" */
2627
1.13k
            pos_str[0] = '\0';
2628
1.13k
            strncat(pos_str, path, pos);
2629
1.13k
        }
2630
1.14k
        strcat(pos_str, "|=|");
2631
1.14k
        strcat(pos_str, path + pos);
2632
1.14k
    }
2633
2634
1.14k
    err->minor = errcode;
2635
1.14k
    err->details = pos_str;
2636
1.14k
    pos_str = NULL;
2637
1.14k
    err->minor_details = pathx_msg;
2638
1.14k
}
2639
2640
int pathx_parse(const struct tree *tree,
2641
                struct error *err,
2642
                const char *txt,
2643
                bool need_nodeset,
2644
                struct pathx_symtab *symtab,
2645
                struct tree *root_ctx,
2646
328k
                struct pathx **pathx) {
2647
328k
    struct state *state = NULL;
2648
2649
328k
    *pathx = NULL;
2650
2651
328k
    if (ALLOC(*pathx) < 0)
2652
0
        goto oom;
2653
2654
328k
    (*pathx)->origin = (struct tree *) tree;
2655
2656
    /* Set up state */
2657
328k
    if (ALLOC((*pathx)->state) < 0)
2658
0
        goto oom;
2659
328k
    state = (*pathx)->state;
2660
2661
328k
    state->errcode = PATHX_NOERROR;
2662
328k
    state->errmsg = NULL;
2663
328k
    state->txt = txt;
2664
328k
    state->pos = txt;
2665
328k
    state->symtab = symtab;
2666
328k
    state->root_ctx = root_ctx;
2667
328k
    state->error = err;
2668
2669
328k
    if (ALLOC_N(state->value_pool, 8) < 0) {
2670
0
        STATE_ENOMEM;
2671
0
        goto done;
2672
0
    }
2673
328k
    state->value_pool_size = 8;
2674
328k
    state->value_pool[0].tag = T_BOOLEAN;
2675
328k
    state->value_pool[0].boolval = 0;
2676
328k
    state->value_pool[1].tag = T_BOOLEAN;
2677
328k
    state->value_pool[1].boolval = 1;
2678
328k
    state->value_pool_used = 2;
2679
2680
    /* Parse */
2681
328k
    parse_expr(state);
2682
328k
    if (HAS_ERROR(state))
2683
366
        goto done;
2684
327k
    if (state->pos != state->txt + strlen(state->txt)) {
2685
219
        STATE_ERROR(state, PATHX_EEND);
2686
219
        goto done;
2687
219
    }
2688
2689
327k
    if (state->exprs_used != 1) {
2690
0
        STATE_ERROR(state, PATHX_EINTERNAL);
2691
0
        goto done;
2692
0
    }
2693
2694
    /* Typecheck */
2695
327k
    check_expr(state->exprs[0], state);
2696
327k
    if (HAS_ERROR(state))
2697
318
        goto done;
2698
2699
327k
    if (need_nodeset && state->exprs[0]->type != T_NODESET) {
2700
234
        STATE_ERROR(state, PATHX_ETYPE);
2701
234
        goto done;
2702
234
    }
2703
2704
328k
 done:
2705
328k
    store_error(*pathx);
2706
328k
    return state->errcode;
2707
0
 oom:
2708
0
    free_pathx(*pathx);
2709
0
    *pathx = NULL;
2710
0
    if (err != NULL)
2711
0
        err->code = AUG_ENOMEM;
2712
0
    return PATHX_ENOMEM;
2713
327k
}
2714
2715
/*************************************************************************
2716
 * Searching in the tree
2717
 *************************************************************************/
2718
2719
25.7M
static bool step_matches(struct step *step, struct tree *tree) {
2720
25.7M
    if ( step->axis == SEQ && step->name == NULL ) {
2721
0
        if ( tree->label == NULL )
2722
0
            return false;
2723
        /* label matches if it consists of numeric digits only */
2724
0
        for( char *s = tree->label; *s ; s++) {
2725
0
            if ( ! isdigit((unsigned char) *s) )
2726
0
                return false;
2727
0
        }
2728
0
        return true;
2729
25.7M
    } else if (step->name == NULL) {
2730
12.5M
        return step->axis == ROOT || tree->label != NULL;
2731
13.1M
    } else {
2732
13.1M
        return streqx(step->name, tree->label);
2733
13.1M
    }
2734
25.7M
}
2735
2736
32
static struct tree *tree_prev(struct tree *pos) {
2737
32
    struct tree *node = NULL;
2738
32
    if (pos != pos->parent->children) {
2739
16
        for (node = pos->parent->children;
2740
16
             node->next != pos;
2741
16
             node = node->next);
2742
16
    }
2743
32
    return node;
2744
32
}
2745
2746
/* When the first step doesn't begin with ROOT then use relative root context
2747
 * instead. */
2748
static struct tree *step_root(struct step *step, struct tree *ctx,
2749
956k
                              struct tree *root_ctx) {
2750
956k
    struct tree *node = NULL;
2751
956k
    switch (step->axis) {
2752
478k
    case SELF:
2753
556k
    case CHILD:
2754
556k
    case SEQ:
2755
556k
    case DESCENDANT:
2756
556k
    case PARENT:
2757
556k
    case ANCESTOR:
2758
556k
    case PRECEDING_SIBLING:
2759
556k
    case FOLLOWING_SIBLING:
2760
        /* only use root_ctx when ctx is the absolute tree root */
2761
556k
        if (ctx == ctx->parent && root_ctx != NULL)
2762
648
            node = root_ctx;
2763
555k
        else
2764
555k
            node = ctx;
2765
556k
        break;
2766
359k
    case ROOT:
2767
400k
    case DESCENDANT_OR_SELF:
2768
400k
        node = ctx;
2769
400k
        break;
2770
0
    default:
2771
0
        assert(0);
2772
956k
    }
2773
956k
    if (node == NULL)
2774
0
        return NULL;
2775
956k
    return node;
2776
956k
}
2777
2778
13.1M
static struct tree *step_first(struct step *step, struct tree *ctx) {
2779
13.1M
    struct tree *node = NULL;
2780
13.1M
    switch (step->axis) {
2781
480k
    case SELF:
2782
522k
    case DESCENDANT_OR_SELF:
2783
522k
        node = ctx;
2784
522k
        break;
2785
12.2M
    case CHILD:
2786
12.2M
    case SEQ:
2787
12.2M
    case DESCENDANT:
2788
12.2M
        node = ctx->children;
2789
12.2M
        break;
2790
6
    case PARENT:
2791
12
    case ANCESTOR:
2792
12
        node = ctx->parent;
2793
12
        break;
2794
359k
    case ROOT:
2795
398k
        while (ctx->parent != ctx)
2796
39.6k
            ctx = ctx->parent;
2797
359k
        node = ctx;
2798
359k
        break;
2799
16
    case PRECEDING_SIBLING:
2800
16
        node = tree_prev(ctx);
2801
16
        break;
2802
6
    case FOLLOWING_SIBLING:
2803
6
        node = ctx->next;
2804
6
        break;
2805
0
    default:
2806
0
        assert(0);
2807
13.1M
    }
2808
13.1M
    if (node == NULL)
2809
648k
        return NULL;
2810
12.5M
    if (step_matches(step, node))
2811
1.22M
        return node;
2812
11.2M
    return step_next(step, ctx, node);
2813
12.5M
}
2814
2815
static struct tree *step_next(struct step *step, struct tree *ctx,
2816
24.4M
                              struct tree *node) {
2817
38.2M
    while (node != NULL) {
2818
25.7M
        switch (step->axis) {
2819
480k
        case SELF:
2820
480k
            node = NULL;
2821
480k
            break;
2822
0
        case SEQ:
2823
13.3M
        case CHILD:
2824
13.3M
            node = node->next;
2825
13.3M
            break;
2826
0
        case DESCENDANT:
2827
11.4M
        case DESCENDANT_OR_SELF:
2828
11.4M
            if (node->children != NULL) {
2829
10.9M
                node = node->children;
2830
10.9M
            } else {
2831
11.4M
                while (node->next == NULL && node != ctx)
2832
10.9M
                    node = node->parent;
2833
570k
                if (node == ctx)
2834
41.7k
                    node = NULL;
2835
529k
                else
2836
529k
                    node = node->next;
2837
570k
            }
2838
11.4M
            break;
2839
6
        case PARENT:
2840
359k
        case ROOT:
2841
359k
            node = NULL;
2842
359k
            break;
2843
6
        case ANCESTOR:
2844
6
            if (node->parent == node)
2845
6
                node = NULL;
2846
0
            else
2847
0
                node = node->parent;
2848
6
            break;
2849
16
        case PRECEDING_SIBLING:
2850
16
            node = tree_prev(node);
2851
16
            break;
2852
0
        case FOLLOWING_SIBLING:
2853
0
            node = node->next;
2854
0
            break;
2855
0
        default:
2856
0
            assert(0);
2857
25.7M
        }
2858
25.7M
        if (node != NULL && step_matches(step, node))
2859
11.9M
            break;
2860
25.7M
    }
2861
24.4M
    return node;
2862
24.4M
}
2863
2864
333k
static struct value *pathx_eval(struct pathx *pathx) {
2865
333k
    struct state *state = pathx->state;
2866
333k
    state->ctx = pathx->origin;
2867
333k
    state->ctx_pos = 1;
2868
333k
    state->ctx_len = 1;
2869
333k
    eval_expr(state->exprs[0], state);
2870
333k
    if (HAS_ERROR(state))
2871
5
        return NULL;
2872
2873
333k
    if (state->values_used != 1) {
2874
0
        STATE_ERROR(state, PATHX_EINTERNAL);
2875
0
        return NULL;
2876
0
    }
2877
333k
    return pop_value(state);
2878
333k
}
2879
2880
1.12k
struct tree *pathx_next(struct pathx *pathx) {
2881
1.12k
    if (pathx->node + 1 < pathx->nodeset->used)
2882
1.06k
        return pathx->nodeset->nodes[++pathx->node];
2883
53
    return NULL;
2884
1.12k
}
2885
2886
/* Find the first node in TREE matching PATH. */
2887
312k
struct tree *pathx_first(struct pathx *pathx) {
2888
312k
    if (pathx->nodeset == NULL) {
2889
215k
        struct value *v = pathx_eval(pathx);
2890
2891
215k
        if (HAS_ERROR(pathx->state))
2892
4
            goto error;
2893
215k
        assert(v->tag == T_NODESET);
2894
215k
        pathx->nodeset = v->nodeset;
2895
215k
    }
2896
312k
    pathx->node = 0;
2897
312k
    if (pathx->nodeset->used == 0)
2898
12.2k
        return NULL;
2899
300k
    else
2900
300k
        return pathx->nodeset->nodes[0];
2901
4
 error:
2902
4
    store_error(pathx);
2903
4
    return NULL;
2904
312k
}
2905
2906
/* Find a node in the tree that matches the longest prefix of PATH.
2907
 *
2908
 * Return 1 if a node was found that exactly matches PATH, 0 if an incomplete
2909
 * prefix matches, and -1 if more than one node in the tree match.
2910
 *
2911
 * TMATCH is set to the tree node that matches, and SMATCH to the next step
2912
 * after the one where TMATCH matched. If no node matches or multiple nodes
2913
 * at the same depth match, TMATCH and SMATCH will be NULL. When exactly
2914
 * one node matches, TMATCH will be that node, and SMATCH will be NULL.
2915
 */
2916
static int locpath_search(struct locpath_trace *lpt,
2917
117k
                          struct tree **tmatch, struct step **smatch) {
2918
117k
    int last;
2919
117k
    int result = -1;
2920
2921
253k
    for (last=lpt->maxns; last >= 0 && lpt->ns[last]->used == 0; last--);
2922
117k
    if (last < 0) {
2923
0
        *smatch = lpt->lp->steps;
2924
0
        result = 1;
2925
0
        goto done;
2926
0
    }
2927
117k
    if (lpt->ns[last]->used > 1) {
2928
0
        result = -1;
2929
0
        goto done;
2930
0
    }
2931
117k
    result = 0;
2932
117k
    *tmatch = lpt->ns[last]->nodes[0];
2933
117k
    *smatch = lpt->lp->steps;
2934
507k
    for (int i=0; i < last; i++)
2935
389k
        *smatch = (*smatch)->next;
2936
117k
 done:
2937
642k
    for (int i=0; i < lpt->maxns; i++)
2938
525k
        free_nodeset(lpt->ns[i]);
2939
117k
    FREE(lpt->ns);
2940
117k
    return result;
2941
117k
}
2942
2943
static char *step_seq_choose_name(struct pathx *path, struct tree *tree);
2944
2945
/* Expand the tree ROOT so that it contains all components of PATH. PATH
2946
 * must have been initialized against ROOT by a call to PATH_FIND_ONE.
2947
 *
2948
 * Return the first segment that was created by this operation, or NULL on
2949
 * error.
2950
 */
2951
117k
int pathx_expand_tree(struct pathx *path, struct tree **tree) {
2952
117k
    int r;
2953
117k
    struct step *step = NULL;
2954
117k
    struct locpath_trace lpt;
2955
117k
    struct tree *first_child = NULL;
2956
117k
    struct value *v = NULL;
2957
2958
117k
    MEMZERO(&lpt, 1);
2959
117k
    path->state->locpath_trace = &lpt;
2960
117k
    v = pathx_eval(path);
2961
117k
    path->state->locpath_trace = NULL;
2962
117k
    if (HAS_ERROR(path->state))
2963
0
        goto error;
2964
2965
117k
    if (lpt.maxns == 0) {
2966
0
        if (v->tag != T_NODESET || v->nodeset->used == 0) {
2967
0
            STATE_ERROR(path->state, PATHX_ENOMATCH);
2968
0
            goto error;
2969
0
        }
2970
0
        if (v->nodeset->used > 1)
2971
0
            goto error;
2972
0
        *tree = v->nodeset->nodes[0];
2973
0
        return 0;
2974
0
    }
2975
2976
117k
    *tree = path->origin;
2977
117k
    r = locpath_search(&lpt, tree, &step);
2978
117k
    if (r == -1) {
2979
0
        STATE_ERROR(path->state, PATHX_EMMATCH);
2980
0
        goto error;
2981
0
    }
2982
2983
117k
    if (step == NULL)
2984
5.89k
        return 0;
2985
2986
112k
    struct tree *parent = *tree;
2987
112k
    if (parent == NULL)
2988
0
        parent = path->origin;
2989
2990
135k
    list_for_each(s, step) {
2991
135k
        if (s->axis != CHILD && s->axis != SEQ)
2992
0
            goto error;
2993
135k
        if (s->axis==SEQ && s->name == NULL) {
2994
0
            s->name = step_seq_choose_name(path, parent);
2995
0
        }
2996
135k
        if (s->name == NULL )
2997
0
            goto error;
2998
135k
        struct tree *t = make_tree(strdup(s->name), NULL, parent, NULL);
2999
135k
        if (first_child == NULL)
3000
112k
            first_child = t;
3001
135k
        if (t == NULL || t->label == NULL)
3002
0
            goto error;
3003
135k
        list_append(parent->children, t);
3004
135k
        parent = t;
3005
135k
    }
3006
3007
135k
    while (first_child->children != NULL)
3008
23.5k
        first_child = first_child->children;
3009
3010
112k
    *tree = first_child;
3011
112k
    return 1;
3012
3013
0
 error:
3014
0
    if (first_child != NULL) {
3015
0
        list_remove(first_child, first_child->parent->children);
3016
0
        free_tree(first_child);
3017
0
    }
3018
0
    *tree = NULL;
3019
0
    store_error(path);
3020
0
    return -1;
3021
112k
}
3022
3023
/* Generate a numeric string to use for step->name
3024
 * Scan tree->children for the highest numbered label, and add 1 to that
3025
 * numeric labels may be interspersed with #comment or other labels
3026
 */
3027
0
static char *step_seq_choose_name(struct pathx *path, struct tree *tree) {
3028
0
    unsigned long int max_node_n=0;
3029
0
    unsigned long int node_n;
3030
0
    char *step_name;
3031
0
    char *label_end;
3032
0
    for(tree=tree->children; tree!=NULL; tree=tree->next) {
3033
0
        if ( tree->label == NULL)
3034
0
          continue;
3035
0
        node_n=strtoul(tree->label, &label_end, 10);
3036
0
        if ( label_end == tree->label || *label_end != '\0' )
3037
          /* label is not a number - ignore it */
3038
0
          continue;
3039
0
        if ( node_n >= ULONG_MAX ) {
3040
0
          STATE_ERROR(path->state, PATHX_ENUMBER);
3041
0
          return NULL;
3042
0
        }
3043
0
        if( node_n > max_node_n )
3044
0
            max_node_n = node_n;
3045
0
    }
3046
0
    if (asprintf(&step_name,"%lu",max_node_n+1) >= 0)
3047
0
        return step_name;
3048
0
    else
3049
0
        return NULL;
3050
0
}
3051
3052
208k
int pathx_find_one(struct pathx *path, struct tree **tree) {
3053
208k
    *tree = pathx_first(path);
3054
208k
    if (HAS_ERROR(path->state))
3055
2
        return -1;
3056
208k
    return path->nodeset->used;
3057
208k
}
3058
3059
0
struct error *err_of_pathx(struct pathx *px) {
3060
0
    return px->state->error;
3061
0
}
3062
3063
1.14k
const char *pathx_error(struct pathx *path, const char **txt, int *pos) {
3064
1.14k
    int errcode = PATHX_ENOMEM;
3065
3066
1.14k
    if (path != NULL) {
3067
1.14k
        if (path->state->errcode < ARRAY_CARDINALITY(errcodes))
3068
1.14k
            errcode = path->state->errcode;
3069
0
        else
3070
0
            errcode = PATHX_EINTERNAL;
3071
3072
1.14k
        if (txt)
3073
0
            *txt = path->state->txt;
3074
3075
1.14k
        if (pos)
3076
1.14k
            *pos = path->state->pos - path->state->txt;
3077
1.14k
    }
3078
1.14k
    return errcodes[errcode];
3079
1.14k
}
3080
3081
/*
3082
 * Symbol tables
3083
 */
3084
static struct pathx_symtab
3085
*make_symtab(struct pathx_symtab *symtab, const char *name,
3086
             struct value *value)
3087
23
{
3088
23
    struct pathx_symtab *new;
3089
23
    char *n = NULL;
3090
3091
23
    n = strdup(name);
3092
23
    if (n == NULL)
3093
0
        return NULL;
3094
3095
23
    if (ALLOC(new) < 0) {
3096
0
        free(n);
3097
0
        return NULL;
3098
0
    }
3099
23
    new->name = n;
3100
23
    new->value = value;
3101
23
    if (symtab == NULL) {
3102
23
        return new;
3103
23
    } else {
3104
0
        new->next = symtab->next;
3105
0
        symtab->next = new;
3106
0
    }
3107
0
    return symtab;
3108
23
}
3109
3110
5.89k
void free_symtab(struct pathx_symtab *symtab) {
3111
3112
5.92k
    while (symtab != NULL) {
3113
23
        struct pathx_symtab *del = symtab;
3114
23
        symtab = del->next;
3115
23
        free(del->name);
3116
23
        release_value(del->value);
3117
23
        free(del->value);
3118
23
        free(del);
3119
23
    }
3120
5.89k
}
3121
3122
0
struct pathx_symtab *pathx_get_symtab(struct pathx *pathx) {
3123
0
    return pathx->state->symtab;
3124
0
}
3125
3126
static int pathx_symtab_set(struct pathx_symtab **symtab,
3127
23
                            const char *name, struct value *v) {
3128
23
    int found = 0;
3129
3130
23
    list_for_each(tab, *symtab) {
3131
0
        if (STREQ(tab->name, name)) {
3132
0
            release_value(tab->value);
3133
0
            free(tab->value);
3134
0
            tab->value = v;
3135
0
            found = 1;
3136
0
            break;
3137
0
        }
3138
0
    }
3139
3140
23
    if (!found) {
3141
23
        struct pathx_symtab *new = NULL;
3142
3143
23
        new = make_symtab(*symtab, name, v);
3144
23
        if (new == NULL)
3145
0
            goto error;
3146
23
        *symtab = new;
3147
23
    }
3148
23
    return 0;
3149
0
 error:
3150
0
    return -1;
3151
23
}
3152
3153
int pathx_symtab_define(struct pathx_symtab **symtab,
3154
24
                        const char *name, struct pathx *px) {
3155
24
    int r;
3156
24
    struct value *value = NULL, *v = NULL;
3157
24
    struct state *state = px->state;
3158
3159
24
    value = pathx_eval(px);
3160
24
    if (HAS_ERROR(px->state))
3161
1
        goto error;
3162
3163
23
    if (ALLOC(v) < 0) {
3164
0
        STATE_ENOMEM;
3165
0
        goto error;
3166
0
    }
3167
3168
23
    *v = *value;
3169
23
    value->tag = T_BOOLEAN;
3170
3171
23
    r = pathx_symtab_set(symtab, name, v);
3172
23
    if (r < 0) {
3173
0
        STATE_ENOMEM;
3174
0
        goto error;
3175
0
    }
3176
3177
23
    if (v->tag == T_NODESET)
3178
23
        return v->nodeset->used;
3179
0
    else
3180
0
        return 0;
3181
1
 error:
3182
1
    release_value(value);
3183
1
    free(value);
3184
1
    release_value(v);
3185
1
    free(v);
3186
1
    store_error(px);
3187
1
    return -1;
3188
23
}
3189
3190
0
int pathx_symtab_undefine(struct pathx_symtab **symtab, const char *name) {
3191
0
    struct pathx_symtab *del = NULL;
3192
3193
0
    for(del = *symtab;
3194
0
        del != NULL && !STREQ(del->name, name);
3195
0
        del = del->next);
3196
0
    if (del == NULL)
3197
0
        return 0;
3198
0
    list_remove(del, *symtab);
3199
0
    free_symtab(del);
3200
0
    return 0;
3201
0
}
3202
3203
int pathx_symtab_assign_tree(struct pathx_symtab **symtab,
3204
0
                             const char *name, struct tree *tree) {
3205
0
    struct value *v = NULL;
3206
0
    int r;
3207
3208
0
    if (ALLOC(v) < 0)
3209
0
        goto error;
3210
3211
0
    v->tag = T_NODESET;
3212
0
    if (ALLOC(v->nodeset) < 0)
3213
0
        goto error;
3214
0
    if (ALLOC_N(v->nodeset->nodes, 1) < 0)
3215
0
        goto error;
3216
0
    v->nodeset->used = 1;
3217
0
    v->nodeset->size = 1;
3218
0
    v->nodeset->nodes[0] = tree;
3219
3220
0
    r = pathx_symtab_set(symtab, name, v);
3221
0
    if (r < 0)
3222
0
        goto error;
3223
0
    return 1;
3224
0
 error:
3225
0
    release_value(v);
3226
0
    free(v);
3227
0
    return -1;
3228
0
}
3229
3230
int
3231
0
pathx_symtab_count(const struct pathx_symtab *symtab, const char *name) {
3232
0
    struct value *v = lookup_var(name, symtab);
3233
3234
0
    if (v == NULL || v->tag != T_NODESET)
3235
0
        return -1;
3236
3237
0
    return v->nodeset->used;
3238
0
}
3239
3240
struct tree *
3241
pathx_symtab_get_tree(struct pathx_symtab *symtab,
3242
0
                      const char *name, int i) {
3243
0
    struct value *v = lookup_var(name, symtab);
3244
0
    if (v == NULL)
3245
0
        return NULL;
3246
0
    if (v->tag != T_NODESET)
3247
0
        return NULL;
3248
0
    if (i >= v->nodeset->used)
3249
0
        return NULL;
3250
0
    return v->nodeset->nodes[i];
3251
0
}
3252
3253
void pathx_symtab_remove_descendants(struct pathx_symtab *symtab,
3254
0
                                     const struct tree *tree) {
3255
0
    list_for_each(tab, symtab) {
3256
0
        if (tab->value->tag != T_NODESET)
3257
0
            continue;
3258
0
        struct nodeset *ns = tab->value->nodeset;
3259
0
        for (int i=0; i < ns->used;) {
3260
0
            struct tree *t = ns->nodes[i];
3261
0
            while (t != t->parent && t != tree)
3262
0
                t = t->parent;
3263
0
            if (t == tree)
3264
0
                ns_remove(ns, i, 1);
3265
0
            else
3266
0
                i += 1;
3267
0
        }
3268
0
    }
3269
0
}
3270
3271
/*
3272
 * Local variables:
3273
 *  indent-tabs-mode: nil
3274
 *  c-indent-level: 4
3275
 *  c-basic-offset: 4
3276
 *  tab-width: 4
3277
 * End:
3278
 */