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