Line data Source code
1 : /*
2 : * macros.c - a simple macro expander
3 : *
4 : * Copyright (c) 2010-2020 Cisco and/or its affiliates.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at:
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include <vppinfra/macros.h>
20 :
21 : static inline int
22 0 : macro_isalnum (i8 c)
23 : {
24 0 : if ((c >= 'A' && c <= 'Z')
25 0 : || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_'))
26 0 : return 1;
27 0 : return 0;
28 : }
29 :
30 : static i8 *
31 0 : builtin_eval (clib_macro_main_t * mm, i8 * varname, i32 complain)
32 : {
33 : uword *p;
34 : i8 *(*fp) (clib_macro_main_t *, i32);
35 :
36 0 : p = hash_get_mem (mm->the_builtin_eval_hash, varname);
37 0 : if (p == 0)
38 0 : return 0;
39 0 : fp = (void *) (p[0]);
40 0 : return (*fp) (mm, complain);
41 : }
42 :
43 : __clib_export int
44 0 : clib_macro_unset (clib_macro_main_t * mm, char *name)
45 : {
46 : hash_pair_t *p;
47 : u8 *key, *value;
48 :
49 0 : p = hash_get_pair (mm->the_value_table_hash, name);
50 :
51 0 : if (p == 0)
52 0 : return 1;
53 :
54 0 : key = (u8 *) (p->key);
55 0 : value = (u8 *) (p->value[0]);
56 0 : hash_unset_mem (mm->the_value_table_hash, name);
57 :
58 0 : vec_free (value);
59 0 : vec_free (key);
60 0 : return 0;
61 : }
62 :
63 : __clib_export int
64 0 : clib_macro_set_value (clib_macro_main_t * mm, char *name, char *value)
65 : {
66 : u8 *key_copy, *value_copy;
67 : int rv;
68 :
69 0 : rv = clib_macro_unset (mm, name);
70 :
71 0 : key_copy = format (0, "%s%c", name, 0);
72 0 : value_copy = format (0, "%s%c", value, 0);
73 :
74 0 : hash_set_mem (mm->the_value_table_hash, key_copy, value_copy);
75 0 : return rv;
76 : }
77 :
78 : i8 *
79 0 : clib_macro_get_value (clib_macro_main_t * mm, char *name)
80 : {
81 : uword *p;
82 :
83 0 : p = hash_get_mem (mm->the_value_table_hash, name);
84 0 : if (p)
85 0 : return (i8 *) (p[0]);
86 : else
87 0 : return 0;
88 : }
89 :
90 : /*
91 : * eval: takes a string, returns a vector.
92 : * looks up $foobar in the variable table.
93 : */
94 : __clib_export i8 *
95 0 : clib_macro_eval (clib_macro_main_t * mm, i8 * s, i32 complain, u16 level,
96 : u16 max_level)
97 : {
98 0 : i8 *rv = 0;
99 : i8 *varname, *varvalue;
100 : i8 *ts;
101 :
102 0 : if (level >= max_level)
103 : {
104 0 : if (complain)
105 0 : clib_warning ("circular definition, level %d", level);
106 0 : return (i8 *) format (0, " CIRCULAR ");
107 : }
108 :
109 0 : while (*s)
110 : {
111 0 : switch (*s)
112 : {
113 0 : case '\\':
114 0 : s++;
115 : /* fallthrough */
116 :
117 0 : default:
118 0 : vec_add1 (rv, *s);
119 0 : s++;
120 0 : break;
121 :
122 0 : case '$':
123 0 : s++;
124 0 : varname = 0;
125 : /*
126 : * Make vector with variable name in it.
127 : */
128 0 : while (*s && (macro_isalnum (*s) || (*s == '_') || (*s == '(')))
129 : {
130 :
131 : /* handle $(foo) */
132 0 : if (*s == '(')
133 : {
134 0 : s++; /* skip '(' */
135 0 : while (*s && *s != ')')
136 : {
137 0 : vec_add1 (varname, *s);
138 0 : s++;
139 : }
140 0 : if (*s)
141 0 : s++; /* skip ')' */
142 0 : break;
143 : }
144 0 : vec_add1 (varname, *s);
145 0 : s++;
146 : }
147 : /* null terminate */
148 0 : vec_add1 (varname, 0);
149 : /* Look for a builtin, e.g. $my_hostname */
150 0 : if (!(varvalue = builtin_eval (mm, varname, complain)))
151 : {
152 : /* Look in value table */
153 0 : if (!varvalue)
154 : {
155 0 : i8 *tmp = clib_macro_get_value (mm, (char *) varname);
156 0 : if (tmp)
157 0 : varvalue = (i8 *) format (0, "%s%c", tmp, 0);
158 : }
159 : #ifdef CLIB_UNIX
160 : /* Look in environment. */
161 0 : if (!varvalue)
162 : {
163 0 : char *tmp = getenv ((char *) varname);
164 0 : if (tmp)
165 0 : varvalue = (i8 *) format (0, "%s%c", tmp, 0);
166 : }
167 : #endif /* CLIB_UNIX */
168 : }
169 0 : if (varvalue)
170 : {
171 : /* recursively evaluate */
172 0 : ts = clib_macro_eval (mm, varvalue, complain, level + 1,
173 : max_level);
174 0 : vec_free (varvalue);
175 : /* add results to answer */
176 0 : vec_append (rv, ts);
177 : /* Remove NULL termination or the results are sad */
178 0 : vec_set_len (rv, vec_len (rv) - 1);
179 0 : vec_free (ts);
180 : }
181 : else
182 : {
183 0 : if (complain)
184 0 : clib_warning ("Undefined Variable Reference: %s\n", varname);
185 0 : vec_append (rv, format (0, "UNSET "));
186 0 : vec_set_len (rv, vec_len (rv) - 1);
187 : }
188 0 : vec_free (varname);
189 : }
190 : }
191 0 : vec_add1 (rv, 0);
192 0 : return (rv);
193 : }
194 :
195 : /*
196 : * eval: takes a string, returns a vector.
197 : * looks up $foobar in the variable table.
198 : */
199 : __clib_export i8 *
200 0 : clib_macro_eval_dollar (clib_macro_main_t *mm, i8 *s, i32 complain)
201 : {
202 : i8 *s2;
203 : i8 *rv;
204 :
205 0 : s2 = (i8 *) format (0, "$(%s)%c", s, 0);
206 0 : rv = clib_macro_eval (mm, s2, complain, 0 /* level */ , 8 /* max_level */ );
207 0 : vec_free (s2);
208 0 : return (rv);
209 : }
210 :
211 : __clib_export void
212 0 : clib_macro_add_builtin (clib_macro_main_t * mm, char *name, void *eval_fn)
213 : {
214 0 : hash_set_mem (mm->the_builtin_eval_hash, name, (uword) eval_fn);
215 0 : }
216 :
217 : #ifdef CLIB_UNIX
218 : static i8 *
219 0 : eval_hostname (clib_macro_main_t * mm, i32 complain)
220 : {
221 : char tmp[128];
222 0 : if (gethostname (tmp, sizeof (tmp)))
223 0 : return ((i8 *) format (0, "gethostname-error%c", 0));
224 0 : return ((i8 *) format (0, "%s%c", tmp, 0));
225 : }
226 : #endif
227 :
228 : __clib_export void
229 575 : clib_macro_init (clib_macro_main_t * mm)
230 : {
231 575 : if (mm->the_builtin_eval_hash != 0)
232 : {
233 0 : clib_warning ("mm %p already initialized", mm);
234 0 : return;
235 : }
236 :
237 575 : mm->the_builtin_eval_hash = hash_create_string (0, sizeof (uword));
238 575 : mm->the_value_table_hash = hash_create_string (0, sizeof (uword));
239 :
240 : #ifdef CLIB_UNIX
241 1150 : hash_set_mem (mm->the_builtin_eval_hash, "hostname", (uword) eval_hostname);
242 : #endif
243 : }
244 :
245 : __clib_export void
246 0 : clib_macro_free (clib_macro_main_t * mm)
247 : {
248 : hash_pair_t *p;
249 0 : u8 **strings_to_free = 0;
250 : int i;
251 :
252 0 : hash_free (mm->the_builtin_eval_hash);
253 :
254 : /* *INDENT-OFF* */
255 0 : hash_foreach_pair (p, mm->the_value_table_hash,
256 : ({
257 : vec_add1 (strings_to_free, (u8 *) (p->key));
258 : vec_add1 (strings_to_free, (u8 *) (p->value[0]));
259 : }));
260 : /* *INDENT-ON* */
261 :
262 0 : for (i = 0; i < vec_len (strings_to_free); i++)
263 0 : vec_free (strings_to_free[i]);
264 0 : vec_free (strings_to_free);
265 0 : hash_free (mm->the_value_table_hash);
266 0 : }
267 :
268 : typedef struct
269 : {
270 : u8 *name;
271 : u8 *value;
272 : } name_sort_t;
273 :
274 : static int
275 0 : name_compare (void *a1, void *a2)
276 : {
277 0 : name_sort_t *ns1 = a1;
278 0 : name_sort_t *ns2 = a2;
279 :
280 0 : return strcmp ((char *) ns1->name, (char *) ns2->name);
281 : }
282 :
283 :
284 : __clib_export u8 *
285 0 : format_clib_macro_main (u8 * s, va_list * args)
286 : {
287 0 : clib_macro_main_t *mm = va_arg (*args, clib_macro_main_t *);
288 0 : int evaluate = va_arg (*args, int);
289 : hash_pair_t *p;
290 0 : name_sort_t *nses = 0, *ns;
291 : int i;
292 :
293 : /* *INDENT-OFF* */
294 0 : hash_foreach_pair (p, mm->the_value_table_hash,
295 : ({
296 : vec_add2 (nses, ns, 1);
297 : ns->name = (u8 *)(p->key);
298 : ns->value = (u8 *)(p->value[0]);
299 : }));
300 : /* *INDENT-ON* */
301 :
302 0 : if (vec_len (nses) == 0)
303 0 : return s;
304 :
305 0 : vec_sort_with_function (nses, name_compare);
306 :
307 0 : for (i = 0; i < vec_len (nses); i++)
308 : {
309 0 : s = format (s, "%-20s", nses[i].name);
310 0 : if (evaluate == 0)
311 0 : s = format (s, "%s\n", nses[i].value);
312 : else
313 : {
314 0 : u8 *rv = (u8 *) clib_macro_eval_dollar (mm, (i8 *) nses[i].name,
315 : 0 /* no complain */ );
316 0 : s = format (s, "%s\n", rv);
317 0 : vec_free (rv);
318 : }
319 : }
320 0 : return s;
321 : }
322 :
323 :
324 : /*
325 : * fd.io coding-style-patch-verification: ON
326 : *
327 : * Local Variables:
328 : * eval: (c-set-style "gnu")
329 : * End:
330 : */
|