vxlan:offload RX flow
[vpp.git] / src / vppinfra / macros.c
1 /*
2   macros.c - a simple macro expander
3
4   Copyright (c) 2010, 2014 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 macro_isalnum (i8 c)
23 {
24   if ((c >= 'A' && c <= 'Z')
25       || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_'))
26     return 1;
27   return 0;
28 }
29
30 static i8 *
31 builtin_eval (macro_main_t * mm, i8 * varname, i32 complain)
32 {
33   uword *p;
34   i8 *(*fp) (macro_main_t *, i32);
35
36   p = hash_get_mem (mm->the_builtin_eval_hash, varname);
37   if (p == 0)
38     return 0;
39   fp = (void *) (p[0]);
40   return (*fp) (mm, complain);
41 }
42
43 int
44 clib_macro_unset (macro_main_t * mm, char *name)
45 {
46   hash_pair_t *p;
47   u8 *key, *value;
48
49   p = hash_get_pair (mm->the_value_table_hash, name);
50
51   if (p == 0)
52     return 1;
53
54   key = (u8 *) (p->key);
55   value = (u8 *) (p->value[0]);
56   hash_unset_mem (mm->the_value_table_hash, name);
57
58   vec_free (value);
59   vec_free (key);
60   return 0;
61 }
62
63 int
64 clib_macro_set_value (macro_main_t * mm, char *name, char *value)
65 {
66   u8 *key_copy, *value_copy;
67   int rv;
68
69   rv = clib_macro_unset (mm, name);
70
71   key_copy = format (0, "%s%c", name, 0);
72   value_copy = format (0, "%s%c", value, 0);
73
74   hash_set_mem (mm->the_value_table_hash, key_copy, value_copy);
75   return rv;
76 }
77
78 i8 *
79 clib_macro_get_value (macro_main_t * mm, char *name)
80 {
81   uword *p;
82
83   p = hash_get_mem (mm->the_value_table_hash, name);
84   if (p)
85     return (i8 *) (p[0]);
86   else
87     return 0;
88 }
89
90 /*
91  * eval: takes a string, returns a vector.
92  * looks up $foobar in the variable table.
93  */
94 i8 *
95 clib_macro_eval (macro_main_t * mm, i8 * s, i32 complain)
96 {
97   i8 *rv = 0;
98   i8 *varname, *varvalue;
99   i8 *ts;
100
101   while (*s)
102     {
103       switch (*s)
104         {
105         case '\\':
106           s++;
107           /* fallthrough */
108
109         default:
110           vec_add1 (rv, *s);
111           s++;
112           break;
113
114         case '$':
115           s++;
116           varname = 0;
117           /*
118            * Make vector with variable name in it.
119            */
120           while (*s && (macro_isalnum (*s) || (*s == '_') || (*s == '(')))
121             {
122
123               /* handle $(foo) */
124               if (*s == '(')
125                 {
126                   s++;          /* skip '(' */
127                   while (*s && *s != ')')
128                     {
129                       vec_add1 (varname, *s);
130                       s++;
131                     }
132                   if (*s)
133                     s++;        /* skip ')' */
134                   break;
135                 }
136               vec_add1 (varname, *s);
137               s++;
138             }
139           /* null terminate */
140           vec_add1 (varname, 0);
141           /* Look for a builtin, e.g. $my_hostname */
142           if (!(varvalue = builtin_eval (mm, varname, complain)))
143             {
144               /* Look in value table */
145               if (!varvalue)
146                 {
147                   i8 *tmp = clib_macro_get_value (mm, (char *) varname);
148                   if (tmp)
149                     varvalue = (i8 *) format (0, "%s%c", tmp, 0);
150                 }
151 #ifdef CLIB_UNIX
152               /* Look in environment. */
153               if (!varvalue)
154                 {
155                   char *tmp = getenv ((char *) varname);
156                   if (tmp)
157                     varvalue = (i8 *) format (0, "%s%c", tmp, 0);
158                 }
159 #endif /* CLIB_UNIX */
160             }
161           if (varvalue)
162             {
163               /* recursively evaluate */
164               ts = clib_macro_eval (mm, varvalue, complain);
165               vec_free (varvalue);
166               /* add results to answer */
167               vec_append (rv, ts);
168               /* Remove NULL termination or the results are sad */
169               _vec_len (rv) = vec_len (rv) - 1;
170               vec_free (ts);
171             }
172           else
173             {
174               if (complain)
175                 clib_warning ("Undefined Variable Reference: %s\n", varname);
176               vec_append (rv, format (0, "UNSET "));
177               _vec_len (rv) = vec_len (rv) - 1;
178
179             }
180           vec_free (varname);
181         }
182     }
183   vec_add1 (rv, 0);
184   return (rv);
185 }
186
187 /*
188  * eval: takes a string, returns a vector.
189  * looks up $foobar in the variable table.
190  */
191 i8 *
192 clib_macro_eval_dollar (macro_main_t * mm, i8 * s, i32 complain)
193 {
194   i8 *s2;
195   i8 *rv;
196
197   s2 = (i8 *) format (0, "$(%s)%c", s, 0);
198   rv = clib_macro_eval (mm, s2, complain);
199   vec_free (s2);
200   return (rv);
201 }
202
203 void
204 clib_macro_add_builtin (macro_main_t * mm, char *name, void *eval_fn)
205 {
206   hash_set_mem (mm->the_builtin_eval_hash, name, (uword) eval_fn);
207 }
208
209 #ifdef CLIB_UNIX
210 static i8 *
211 eval_hostname (macro_main_t * mm, i32 complain)
212 {
213   char tmp[128];
214   if (gethostname (tmp, sizeof (tmp)))
215     return ((i8 *) format (0, "gethostname-error%c", 0));
216   return ((i8 *) format (0, "%s%c", tmp, 0));
217 }
218 #endif
219
220 void
221 clib_macro_init (macro_main_t * mm)
222 {
223   if (mm->the_builtin_eval_hash != 0)
224     {
225       clib_warning ("mm %p already initialized", mm);
226       return;
227     }
228
229   mm->the_builtin_eval_hash = hash_create_string (0, sizeof (uword));
230   mm->the_value_table_hash = hash_create_string (0, sizeof (uword));
231
232 #ifdef CLIB_UNIX
233   hash_set_mem (mm->the_builtin_eval_hash, "hostname", (uword) eval_hostname);
234 #endif
235 }
236
237 void
238 clib_macro_free (macro_main_t * mm)
239 {
240   hash_pair_t *p;
241   u8 **strings_to_free = 0;
242   int i;
243
244   hash_free (mm->the_builtin_eval_hash);
245
246   /* *INDENT-OFF* */
247   hash_foreach_pair (p, mm->the_value_table_hash,
248   ({
249     vec_add1 (strings_to_free, (u8 *) (p->key));
250     vec_add1 (strings_to_free, (u8 *) (p->value[0]));
251   }));
252   /* *INDENT-ON* */
253
254   for (i = 0; i < vec_len (strings_to_free); i++)
255     vec_free (strings_to_free[i]);
256   vec_free (strings_to_free);
257   hash_free (mm->the_value_table_hash);
258 }
259
260 /*
261  * fd.io coding-style-patch-verification: ON
262  *
263  * Local Variables:
264  * eval: (c-set-style "gnu")
265  * End:
266  */