1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdbool.h> 3 #include <assert.h> 4 #include "expr.h" 5 #include "expr-bison.h" 6 #include "expr-flex.h" 7 8 #ifdef PARSER_DEBUG 9 extern int expr_debug; 10 #endif 11 12 /* Caller must make sure id is allocated */ 13 void expr__add_id(struct expr_parse_ctx *ctx, const char *name, double val) 14 { 15 int idx; 16 17 assert(ctx->num_ids < MAX_PARSE_ID); 18 idx = ctx->num_ids++; 19 ctx->ids[idx].name = name; 20 ctx->ids[idx].val = val; 21 } 22 23 void expr__ctx_init(struct expr_parse_ctx *ctx) 24 { 25 ctx->num_ids = 0; 26 } 27 28 static int 29 __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, 30 int start) 31 { 32 struct expr_scanner_ctx scanner_ctx = { 33 .start_token = start, 34 }; 35 YY_BUFFER_STATE buffer; 36 void *scanner; 37 int ret; 38 39 ret = expr_lex_init_extra(&scanner_ctx, &scanner); 40 if (ret) 41 return ret; 42 43 buffer = expr__scan_string(expr, scanner); 44 45 #ifdef PARSER_DEBUG 46 expr_debug = 1; 47 #endif 48 49 ret = expr_parse(val, ctx, scanner); 50 51 expr__flush_buffer(buffer, scanner); 52 expr__delete_buffer(buffer, scanner); 53 expr_lex_destroy(scanner); 54 return ret; 55 } 56 57 int expr__parse(double *final_val, struct expr_parse_ctx *ctx, const char *expr) 58 { 59 return __expr__parse(final_val, ctx, expr, EXPR_PARSE) ? -1 : 0; 60 } 61 62 static bool 63 already_seen(const char *val, const char *one, const char **other, 64 int num_other) 65 { 66 int i; 67 68 if (one && !strcasecmp(one, val)) 69 return true; 70 for (i = 0; i < num_other; i++) 71 if (!strcasecmp(other[i], val)) 72 return true; 73 return false; 74 } 75 76 int expr__find_other(const char *expr, const char *one, const char ***other, 77 int *num_other) 78 { 79 int err, i = 0, j = 0; 80 struct expr_parse_ctx ctx; 81 82 expr__ctx_init(&ctx); 83 err = __expr__parse(NULL, &ctx, expr, EXPR_OTHER); 84 if (err) 85 return -1; 86 87 *other = malloc((ctx.num_ids + 1) * sizeof(char *)); 88 if (!*other) 89 return -ENOMEM; 90 91 for (i = 0, j = 0; i < ctx.num_ids; i++) { 92 const char *str = ctx.ids[i].name; 93 94 if (already_seen(str, one, *other, j)) 95 continue; 96 97 str = strdup(str); 98 if (!str) 99 goto out; 100 (*other)[j++] = str; 101 } 102 (*other)[j] = NULL; 103 104 out: 105 if (i != ctx.num_ids) { 106 while (--j) 107 free((char *) (*other)[i]); 108 free(*other); 109 err = -1; 110 } 111 112 *num_other = j; 113 return err; 114 } 115