blob: b3b8927113cafeac857124cc7595e989e758507d [file] [log] [blame]
Doug Zongker37bee622009-06-08 17:35:39 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string.h>
18#include <stdbool.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22
23#include "expr.h"
24
25// Functions should:
26//
27// - return a malloc()'d string
28// - if Evaluate() on any argument returns NULL, return NULL.
29
30int BooleanString(const char* s) {
31 return s[0] != '\0';
32}
33
34char* Evaluate(void* cookie, Expr* expr) {
35 return expr->fn(expr->name, cookie, expr->argc, expr->argv);
36}
37
38char* ConcatFn(const char* name, void* cookie, int argc, Expr* argv[]) {
39 if (argc == 0) {
40 return strdup("");
41 }
42 char** strings = malloc(argc * sizeof(char*));
43 int i;
44 for (i = 0; i < argc; ++i) {
45 strings[i] = NULL;
46 }
47 char* result = NULL;
48 int length = 0;
49 for (i = 0; i < argc; ++i) {
50 strings[i] = Evaluate(cookie, argv[i]);
51 if (strings[i] == NULL) {
52 goto done;
53 }
54 length += strlen(strings[i]);
55 }
56
57 result = malloc(length+1);
58 int p = 0;
59 for (i = 0; i < argc; ++i) {
60 strcpy(result+p, strings[i]);
61 p += strlen(strings[i]);
62 }
63 result[p] = '\0';
64
65done:
66 for (i = 0; i < argc; ++i) {
67 free(strings[i]);
68 }
69 return result;
70}
71
72char* IfElseFn(const char* name, void* cookie, int argc, Expr* argv[]) {
73 if (argc != 2 && argc != 3) {
74 return NULL;
75 }
76 char* cond = Evaluate(cookie, argv[0]);
77 if (cond == NULL) {
78 return NULL;
79 }
80
81 if (BooleanString(cond) == true) {
82 free(cond);
83 return Evaluate(cookie, argv[1]);
84 } else {
85 if (argc == 3) {
86 free(cond);
87 return Evaluate(cookie, argv[2]);
88 } else {
89 return cond;
90 }
91 }
92}
93
94char* AbortFn(const char* name, void* cookie, int argc, Expr* argv[]) {
95 return NULL;
96}
97
98char* AssertFn(const char* name, void* cookie, int argc, Expr* argv[]) {
99 int i;
100 for (i = 0; i < argc; ++i) {
101 char* v = Evaluate(cookie, argv[i]);
102 if (v == NULL) {
103 return NULL;
104 }
105 int b = BooleanString(v);
106 free(v);
107 if (!b) {
108 return NULL;
109 }
110 }
111 return strdup("");
112}
113
114char* PrintFn(const char* name, void* cookie, int argc, Expr* argv[]) {
115 int i;
116 for (i = 0; i < argc; ++i) {
117 char* v = Evaluate(cookie, argv[i]);
118 if (v == NULL) {
119 return NULL;
120 }
121 fputs(v, stdout);
122 free(v);
123 }
124 return strdup("");
125}
126
127char* LogicalAndFn(const char* name, void* cookie,
128 int argc, Expr* argv[]) {
129 char* left = Evaluate(cookie, argv[0]);
130 if (left == NULL) return NULL;
131 if (BooleanString(left) == true) {
132 free(left);
133 return Evaluate(cookie, argv[1]);
134 } else {
135 return left;
136 }
137}
138
139char* LogicalOrFn(const char* name, void* cookie,
140 int argc, Expr* argv[]) {
141 char* left = Evaluate(cookie, argv[0]);
142 if (left == NULL) return NULL;
143 if (BooleanString(left) == false) {
144 free(left);
145 return Evaluate(cookie, argv[1]);
146 } else {
147 return left;
148 }
149}
150
151char* LogicalNotFn(const char* name, void* cookie,
152 int argc, Expr* argv[]) {
153 char* val = Evaluate(cookie, argv[0]);
154 if (val == NULL) return NULL;
155 bool bv = BooleanString(val);
156 free(val);
157 if (bv) {
158 return strdup("");
159 } else {
160 return strdup("t");
161 }
162}
163
164char* SubstringFn(const char* name, void* cookie,
165 int argc, Expr* argv[]) {
166 char* needle = Evaluate(cookie, argv[0]);
167 if (needle == NULL) return NULL;
168 char* haystack = Evaluate(cookie, argv[1]);
169 if (haystack == NULL) {
170 free(needle);
171 return NULL;
172 }
173
174 char* result = strdup(strstr(haystack, needle) ? "t" : "");
175 free(needle);
176 free(haystack);
177 return result;
178}
179
180char* EqualityFn(const char* name, void* cookie, int argc, Expr* argv[]) {
181 char* left = Evaluate(cookie, argv[0]);
182 if (left == NULL) return NULL;
183 char* right = Evaluate(cookie, argv[1]);
184 if (right == NULL) {
185 free(left);
186 return NULL;
187 }
188
189 char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
190 free(left);
191 free(right);
192 return result;
193}
194
195char* InequalityFn(const char* name, void* cookie, int argc, Expr* argv[]) {
196 char* left = Evaluate(cookie, argv[0]);
197 if (left == NULL) return NULL;
198 char* right = Evaluate(cookie, argv[1]);
199 if (right == NULL) {
200 free(left);
201 return NULL;
202 }
203
204 char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
205 free(left);
206 free(right);
207 return result;
208}
209
210char* SequenceFn(const char* name, void* cookie, int argc, Expr* argv[]) {
211 char* left = Evaluate(cookie, argv[0]);
212 if (left == NULL) return NULL;
213 free(left);
214 return Evaluate(cookie, argv[1]);
215}
216
217char* Literal(const char* name, void* cookie, int argc, Expr* argv[]) {
218 return strdup(name);
219}
220
221Expr* Build(Function fn, int count, ...) {
222 va_list v;
223 va_start(v, count);
224 Expr* e = malloc(sizeof(Expr));
225 e->fn = fn;
226 e->name = "(operator)";
227 e->argc = count;
228 e->argv = malloc(count * sizeof(Expr*));
229 int i;
230 for (i = 0; i < count; ++i) {
231 e->argv[i] = va_arg(v, Expr*);
232 }
233 va_end(v);
234 return e;
235}
236
237static int fn_entries = 0;
238static int fn_size = 0;
239NamedFunction* fn_table = NULL;
240
241void RegisterFunction(const char* name, Function fn) {
242 if (fn_entries <= fn_size) {
243 fn_size = fn_size*2 + 1;
244 fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction));
245 }
246 fn_table[fn_entries].name = name;
247 fn_table[fn_entries].fn = fn;
248 ++fn_entries;
249}
250
251static int fn_entry_compare(const void* a, const void* b) {
252 const char* na = ((const NamedFunction*)a)->name;
253 const char* nb = ((const NamedFunction*)b)->name;
254 return strcmp(na, nb);
255}
256
257void FinishRegistration() {
258 qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare);
259}
260
261Function FindFunction(const char* name) {
262 NamedFunction key;
263 key.name = name;
264 NamedFunction* nf = bsearch(&key, fn_table, fn_entries, sizeof(NamedFunction),
265 fn_entry_compare);
266 if (nf == NULL) {
267 return NULL;
268 }
269 return nf->fn;
270}
271
272void RegisterBuiltins() {
273 RegisterFunction("ifelse", IfElseFn);
274 RegisterFunction("abort", AbortFn);
275 RegisterFunction("assert", AssertFn);
276 RegisterFunction("concat", ConcatFn);
277 RegisterFunction("is_substring", SubstringFn);
278 RegisterFunction("print", PrintFn);
279}