1cb9cadadSEd Warnicke/*
2cb9cadadSEd Warnicke  macros.c - a simple macro expander
3c3799996SDave Barach
4cb9cadadSEd Warnicke  Copyright (c) 2010, 2014 Cisco and/or its affiliates.
5c3799996SDave Barach
6cb9cadadSEd Warnicke  * Licensed under the Apache License, Version 2.0 (the "License");
7cb9cadadSEd Warnicke * you may not use this file except in compliance with the License.
8cb9cadadSEd Warnicke * You may obtain a copy of the License at:
9cb9cadadSEd Warnicke *
10cb9cadadSEd Warnicke *     http://www.apache.org/licenses/LICENSE-2.0
11cb9cadadSEd Warnicke *
12cb9cadadSEd Warnicke * Unless required by applicable law or agreed to in writing, software
13cb9cadadSEd Warnicke * distributed under the License is distributed on an "AS IS" BASIS,
14cb9cadadSEd Warnicke * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15cb9cadadSEd Warnicke * See the License for the specific language governing permissions and
16cb9cadadSEd Warnicke * limitations under the License.
17cb9cadadSEd Warnicke*/
18cb9cadadSEd Warnicke
19cb9cadadSEd Warnicke#include <vppinfra/macros.h>
20cb9cadadSEd Warnicke
21c3799996SDave Barachstatic inline int
22c3799996SDave Barachmacro_isalnum (i8 c)
23cb9cadadSEd Warnicke{
24cb9cadadSEd Warnicke  if ((c >= 'A' && c <= 'Z')
25c3799996SDave Barach      || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_'))
26cb9cadadSEd Warnicke    return 1;
27cb9cadadSEd Warnicke  return 0;
28cb9cadadSEd Warnicke}
29cb9cadadSEd Warnicke
30c3799996SDave Barachstatic i8 *
31c3799996SDave Barachbuiltin_eval (macro_main_t * mm, i8 * varname, i32 complain)
32cb9cadadSEd Warnicke{
33c3799996SDave Barach  uword *p;
34c3799996SDave Barach  i8 *(*fp) (macro_main_t *, i32);
35c3799996SDave Barach
36c3799996SDave Barach  p = hash_get_mem (mm->the_builtin_eval_hash, varname);
37c3799996SDave Barach  if (p == 0)
38c3799996SDave Barach    return 0;
39c3799996SDave Barach  fp = (void *) (p[0]);
40c3799996SDave Barach  return (*fp) (mm, complain);
41cb9cadadSEd Warnicke}
42cb9cadadSEd Warnicke
43c3799996SDave Barachint
44c3799996SDave Barachclib_macro_unset (macro_main_t * mm, char *name)
45cb9cadadSEd Warnicke{
46c3799996SDave Barach  hash_pair_t *p;
47c3799996SDave Barach  u8 *key, *value;
48cb9cadadSEd Warnicke
49cb9cadadSEd Warnicke  p = hash_get_pair (mm->the_value_table_hash, name);
50c3799996SDave Barach
51cb9cadadSEd Warnicke  if (p == 0)
52cb9cadadSEd Warnicke    return 1;
53cb9cadadSEd Warnicke
54c3799996SDave Barach  key = (u8 *) (p->key);
55cb9cadadSEd Warnicke  value = (u8 *) (p->value[0]);
56cb9cadadSEd Warnicke  hash_unset_mem (mm->the_value_table_hash, name);
57cb9cadadSEd Warnicke
58cb9cadadSEd Warnicke  vec_free (value);
59cb9cadadSEd Warnicke  vec_free (key);
60cb9cadadSEd Warnicke  return 0;
61cb9cadadSEd Warnicke}
62cb9cadadSEd Warnicke
63c3799996SDave Barachint
64c3799996SDave Barachclib_macro_set_value (macro_main_t * mm, char *name, char *value)
65cb9cadadSEd Warnicke{
66c3799996SDave Barach  u8 *key_copy, *value_copy;
67cb9cadadSEd Warnicke  int rv;
68cb9cadadSEd Warnicke
69cb9cadadSEd Warnicke  rv = clib_macro_unset (mm, name);
70cb9cadadSEd Warnicke
71cb9cadadSEd Warnicke  key_copy = format (0, "%s%c", name, 0);
72cb9cadadSEd Warnicke  value_copy = format (0, "%s%c", value, 0);
73cb9cadadSEd Warnicke
74cb9cadadSEd Warnicke  hash_set_mem (mm->the_value_table_hash, key_copy, value_copy);
75cb9cadadSEd Warnicke  return rv;
76cb9cadadSEd Warnicke}
77cb9cadadSEd Warnicke
78c3799996SDave Barachi8 *
79c3799996SDave Barachclib_macro_get_value (macro_main_t * mm, char *name)
80cb9cadadSEd Warnicke{
81c3799996SDave Barach  uword *p;
82cb9cadadSEd Warnicke
83cb9cadadSEd Warnicke  p = hash_get_mem (mm->the_value_table_hash, name);
84cb9cadadSEd Warnicke  if (p)
85c3799996SDave Barach    return (i8 *) (p[0]);
86cb9cadadSEd Warnicke  else
87cb9cadadSEd Warnicke    return 0;
88cb9cadadSEd Warnicke}
89cb9cadadSEd Warnicke
90cb9cadadSEd Warnicke/*
91cb9cadadSEd Warnicke * eval: takes a string, returns a vector.
92cb9cadadSEd Warnicke * looks up $foobar in the variable table.
93cb9cadadSEd Warnicke */
94c3799996SDave Barachi8 *
95c3799996SDave Barachclib_macro_eval (macro_main_t * mm, i8 * s, i32 complain)
96cb9cadadSEd Warnicke{
97c3799996SDave Barach  i8 *rv = 0;
98cb9cadadSEd Warnicke  i8 *varname, *varvalue;
99cb9cadadSEd Warnicke  i8 *ts;
100cb9cadadSEd Warnicke
101c3799996SDave Barach  while (*s)
102cb9cadadSEd Warnicke    {
103c3799996SDave Barach      switch (*s)
104c3799996SDave Barach	{
105c3799996SDave Barach	case '\\':
106c3799996SDave Barach	  s++;
107c3799996SDave Barach	  /* fallthrough */
108c3799996SDave Barach
109c3799996SDave Barach	default:
110c3799996SDave Barach	  vec_add1 (rv, *s);
111c3799996SDave Barach	  s++;
112c3799996SDave Barach	  break;
113c3799996SDave Barach
114c3799996SDave Barach	case '$':
115c3799996SDave Barach	  s++;
116c3799996SDave Barach	  varname = 0;
117c3799996SDave Barach	  /*
118c3799996SDave Barach	   * Make vector with variable name in it.
119c3799996SDave Barach	   */
120c3799996SDave Barach	  while (*s && (macro_isalnum (*s) || (*s == '_') || (*s == '(')))
121c3799996SDave Barach	    {
122c3799996SDave Barach
123c3799996SDave Barach	      /* handle $(foo) */
124c3799996SDave Barach	      if (*s == '(')
125c3799996SDave Barach		{
126c3799996SDave Barach		  s++;		/* skip '(' */
127c3799996SDave Barach		  while (*s && *s != ')')
128c3799996SDave Barach		    {
129c3799996SDave Barach		      vec_add1 (varname, *s);
130c3799996SDave Barach		      s++;
131c3799996SDave Barach		    }
132c3799996SDave Barach		  if (*s)
133c3799996SDave Barach		    s++;	/* skip ')' */
134c3799996SDave Barach		  break;
135c3799996SDave Barach		}
136c3799996SDave Barach	      vec_add1 (varname, *s);
137c3799996SDave Barach	      s++;
138c3799996SDave Barach	    }
139c3799996SDave Barach	  /* null terminate */
140c3799996SDave Barach	  vec_add1 (varname, 0);
141c3799996SDave Barach	  /* Look for a builtin, e.g. $my_hostname */
142c3799996SDave Barach	  if (!(varvalue = builtin_eval (mm, varname, complain)))
143c3799996SDave Barach	    {
144c3799996SDave Barach	      /* Look in value table */
145c3799996SDave Barach	      if (!varvalue)
146c3799996SDave Barach		{
147ffe9d21bSDamjan Marion		  i8 *tmp = clib_macro_get_value (mm, (char *) varname);
148c3799996SDave Barach		  if (tmp)
149c3799996SDave Barach		    varvalue = (i8 *) format (0, "%s%c", tmp, 0);
150c3799996SDave Barach		}
151cb9cadadSEd Warnicke#ifdef CLIB_UNIX
152c3799996SDave Barach	      /* Look in environment. */
153c3799996SDave Barach	      if (!varvalue)
154c3799996SDave Barach		{
155ffe9d21bSDamjan Marion		  char *tmp = getenv ((char *) varname);
156c3799996SDave Barach		  if (tmp)
157c3799996SDave Barach		    varvalue = (i8 *) format (0, "%s%c", tmp, 0);
158c3799996SDave Barach		}
159cb9cadadSEd Warnicke#endif /* CLIB_UNIX */
160c3799996SDave Barach	    }
161c3799996SDave Barach	  if (varvalue)
162c3799996SDave Barach	    {
163c3799996SDave Barach	      /* recursively evaluate */
164c3799996SDave Barach	      ts = clib_macro_eval (mm, varvalue, complain);
165c3799996SDave Barach	      vec_free (varvalue);
166c3799996SDave Barach	      /* add results to answer */
167c3799996SDave Barach	      vec_append (rv, ts);
168c3799996SDave Barach	      /* Remove NULL termination or the results are sad */
169c3799996SDave Barach	      _vec_len (rv) = vec_len (rv) - 1;
170c3799996SDave Barach	      vec_free (ts);
171c3799996SDave Barach	    }
172c3799996SDave Barach	  else
173c3799996SDave Barach	    {
174c3799996SDave Barach	      if (complain)
175c3799996SDave Barach		clib_warning ("Undefined Variable Reference: %s\n", varname);
176c3799996SDave Barach	      vec_append (rv, format (0, "UNSET "));
177c3799996SDave Barach	      _vec_len (rv) = vec_len (rv) - 1;
178c3799996SDave Barach
179c3799996SDave Barach	    }
180c3799996SDave Barach	  vec_free (varname);
181c3799996SDave Barach	}
182cb9cadadSEd Warnicke    }
183c3799996SDave Barach  vec_add1 (rv, 0);
184c3799996SDave Barach  return (rv);
185cb9cadadSEd Warnicke}
186cb9cadadSEd Warnicke
187cb9cadadSEd Warnicke/*
188cb9cadadSEd Warnicke * eval: takes a string, returns a vector.
189cb9cadadSEd Warnicke * looks up $foobar in the variable table.
190cb9cadadSEd Warnicke */
191c3799996SDave Barachi8 *
192c3799996SDave Barachclib_macro_eval_dollar (macro_main_t * mm, i8 * s, i32 complain)
193cb9cadadSEd Warnicke{
194cb9cadadSEd Warnicke  i8 *s2;
195cb9cadadSEd Warnicke  i8 *rv;
196cb9cadadSEd Warnicke
197c3799996SDave Barach  s2 = (i8 *) format (0, "$(%s)%c", s, 0);
198c3799996SDave Barach  rv = clib_macro_eval (mm, s2, complain);
199cb9cadadSEd Warnicke  vec_free (s2);
200cb9cadadSEd Warnicke  return (rv);
201cb9cadadSEd Warnicke}
202cb9cadadSEd Warnicke
203c3799996SDave Barachvoid
204c3799996SDave Barachclib_macro_add_builtin (macro_main_t * mm, char *name, void *eval_fn)
205cb9cadadSEd Warnicke{
206c3799996SDave Barach  hash_set_mem (mm->the_builtin_eval_hash, name, (uword) eval_fn);
207cb9cadadSEd Warnicke}
208cb9cadadSEd Warnicke
209cb9cadadSEd Warnicke#ifdef CLIB_UNIX
210c3799996SDave Barachstatic i8 *
211c3799996SDave Baracheval_hostname (macro_main_t * mm, i32 complain)
212cb9cadadSEd Warnicke{
213cb9cadadSEd Warnicke  char tmp[128];
214c3799996SDave Barach  if (gethostname (tmp, sizeof (tmp)))
215cb9cadadSEd Warnicke    return ((i8 *) format (0, "gethostname-error%c", 0));
216cb9cadadSEd Warnicke  return ((i8 *) format (0, "%s%c", tmp, 0));
217cb9cadadSEd Warnicke}
218cb9cadadSEd Warnicke#endif
219cb9cadadSEd Warnicke
220c3799996SDave Barachvoid
221c3799996SDave Barachclib_macro_init (macro_main_t * mm)
222cb9cadadSEd Warnicke{
223cb9cadadSEd Warnicke  if (mm->the_builtin_eval_hash != 0)
224cb9cadadSEd Warnicke    {
225fef15b4bSChristophe Fontaine      clib_warning ("mm %p already initialized", mm);
226cb9cadadSEd Warnicke      return;
227cb9cadadSEd Warnicke    }
228cb9cadadSEd Warnicke
229c3799996SDave Barach  mm->the_builtin_eval_hash = hash_create_string (0, sizeof (uword));
230c3799996SDave Barach  mm->the_value_table_hash = hash_create_string (0, sizeof (uword));
231c3799996SDave Barach
232cb9cadadSEd Warnicke#ifdef CLIB_UNIX
233c3799996SDave Barach  hash_set_mem (mm->the_builtin_eval_hash, "hostname", (uword) eval_hostname);
234cb9cadadSEd Warnicke#endif
235cb9cadadSEd Warnicke}
236cb9cadadSEd Warnicke
237c3799996SDave Barachvoid
238c3799996SDave Barachclib_macro_free (macro_main_t * mm)
239cb9cadadSEd Warnicke{
240c3799996SDave Barach  hash_pair_t *p;
241c3799996SDave Barach  u8 **strings_to_free = 0;
242cb9cadadSEd Warnicke  int i;
243cb9cadadSEd Warnicke
244cb9cadadSEd Warnicke  hash_free (mm->the_builtin_eval_hash);
245cb9cadadSEd Warnicke
246c3799996SDave Barach  /* *INDENT-OFF* */
247c3799996SDave Barach  hash_foreach_pair (p, mm->the_value_table_hash,
248cb9cadadSEd Warnicke  ({
249cb9cadadSEd Warnicke    vec_add1 (strings_to_free, (u8 *) (p->key));
250cb9cadadSEd Warnicke    vec_add1 (strings_to_free, (u8 *) (p->value[0]));
251cb9cadadSEd Warnicke  }));
252c3799996SDave Barach  /* *INDENT-ON* */
253cb9cadadSEd Warnicke
254cb9cadadSEd Warnicke  for (i = 0; i < vec_len (strings_to_free); i++)
255cb9cadadSEd Warnicke    vec_free (strings_to_free[i]);
256cb9cadadSEd Warnicke  vec_free (strings_to_free);
257cb9cadadSEd Warnicke  hash_free (mm->the_value_table_hash);
258cb9cadadSEd Warnicke}
259c3799996SDave Barach
260c3799996SDave Barach/*
261c3799996SDave Barach * fd.io coding-style-patch-verification: ON
262c3799996SDave Barach *
263c3799996SDave Barach * Local Variables:
264c3799996SDave Barach * eval: (c-set-style "gnu")
265c3799996SDave Barach * End:
266c3799996SDave Barach */