28 |
symbol is represented by `struct m4_symbol', which is stored in the hash |
symbol is represented by `struct m4_symbol', which is stored in the hash |
29 |
table keyed by the symbol name. As a special case, to facilitate the |
table keyed by the symbol name. As a special case, to facilitate the |
30 |
"pushdef" and "popdef" builtins, the value stored against each key is a |
"pushdef" and "popdef" builtins, the value stored against each key is a |
31 |
stack of `struct m4_token'. All the value entries for a symbol name are |
stack of `struct m4_symbol_value'. All the value entries for a symbol name are |
32 |
simply ordered on the stack by age. The most recently pushed definition |
simply ordered on the stack by age. The most recently pushed definition |
33 |
will then always be the first found. |
will then always be the first found. |
34 |
|
|
43 |
value stacks) are invisible to the users of this module. */ |
value stacks) are invisible to the users of this module. */ |
44 |
|
|
45 |
#define M4_SYMTAB_DEFAULT_SIZE 2047 |
#define M4_SYMTAB_DEFAULT_SIZE 2047 |
|
#define M4_ARG_SIGNATURE_DEFAULT_SIZE 7 |
|
46 |
|
|
47 |
static m4_symbol *symtab_fetch (m4_symtab*, const char *); |
static m4_symbol *symtab_fetch (m4_symtab*, const char *); |
48 |
static void symbol_popval (m4_symbol *symbol); |
static void symbol_popval (m4_symbol *symbol); |
49 |
static int symbol_destroy (m4_hash *hash, const void *name, |
static void * symbol_destroy (m4_hash *hash, const void *name, |
50 |
void *symbol, void *ignored); |
void *symbol, void *ignored); |
51 |
static int arg_destroy (m4_hash *hash, const void *name, |
static void * arg_destroy (m4_hash *hash, const void *name, |
52 |
void *arg, void *ignored); |
void *arg, void *ignored); |
53 |
static m4_hash * arg_signature_parse (const char *name, const char *param); |
static void * arg_copy (m4_hash *src, const void *name, |
54 |
|
void *arg, m4_hash *dest); |
55 |
|
|
56 |
|
|
57 |
/* -- SYMBOL TABLE MANAGEMENT -- |
/* -- SYMBOL TABLE MANAGEMENT -- |
107 |
assert (handle); |
assert (handle); |
108 |
|
|
109 |
/* Traverse each symbol name in the hash table. */ |
/* Traverse each symbol name in the hash table. */ |
110 |
while ((place = m4_hash_iterator_next (symtab, place))) |
while ((place = m4_get_hash_iterator_next (symtab, place))) |
111 |
{ |
{ |
112 |
m4_symbol *symbol = (m4_symbol *) m4_hash_iterator_value (place); |
m4_symbol *symbol = (m4_symbol *) m4_get_hash_iterator_value (place); |
113 |
m4_token *data = SYMBOL_TOKEN (symbol); |
m4_symbol_value *data = SYMBOL_VALUE (symbol); |
114 |
|
|
115 |
/* For symbols that have token data... */ |
/* For symbols that have token data... */ |
116 |
if (data) |
if (data) |
117 |
{ |
{ |
118 |
/* Purge any shadowed references. */ |
/* Purge any shadowed references. */ |
119 |
while (TOKEN_NEXT (data)) |
while (VALUE_NEXT (data)) |
120 |
{ |
{ |
121 |
m4_token *next = TOKEN_NEXT (data); |
m4_symbol_value *next = VALUE_NEXT (data); |
122 |
|
|
123 |
if (TOKEN_HANDLE (next) == handle) |
if (VALUE_HANDLE (next) == handle) |
124 |
{ |
{ |
125 |
TOKEN_NEXT (data) = TOKEN_NEXT (next); |
VALUE_NEXT (data) = VALUE_NEXT (next); |
126 |
|
|
127 |
if (TOKEN_TYPE (next) == M4_TOKEN_TEXT) |
if (VALUE_TYPE (next) == M4_SYMBOL_TEXT) |
128 |
XFREE (TOKEN_TEXT (next)); |
XFREE (VALUE_TEXT (next)); |
129 |
XFREE (next); |
XFREE (next); |
130 |
} |
} |
131 |
else |
else |
134 |
|
|
135 |
/* Purge the live reference if necessary. */ |
/* Purge the live reference if necessary. */ |
136 |
if (SYMBOL_HANDLE (symbol) == handle) |
if (SYMBOL_HANDLE (symbol) == handle) |
137 |
m4_symbol_popdef (symtab, m4_hash_iterator_key (place)); |
m4_symbol_popdef (symtab, m4_get_hash_iterator_key (place)); |
138 |
} |
} |
139 |
} |
} |
140 |
} |
} |
141 |
|
|
142 |
|
|
143 |
/* This callback is used exclusively by m4__symtab_exit(), to cleanup |
/* This callback is used exclusively by m4_symtab_delete(), to cleanup |
144 |
the memory used by the symbol table. As such, the trace bit is reset |
the memory used by the symbol table. As such, the trace bit is reset |
145 |
on every symbol so that m4_symbol_popdef() doesn't try to preserve |
on every symbol so that m4_symbol_popdef() doesn't try to preserve |
146 |
the table entry. */ |
the table entry. */ |
147 |
static int |
static void * |
148 |
symbol_destroy (m4_hash *hash, const void *name, void *symbol, void *ignored) |
symbol_destroy (m4_hash *hash, const void *name, void *symbol, void *ignored) |
149 |
{ |
{ |
150 |
char *key = xstrdup ((char *) name); |
char *key = xstrdup ((char *) name); |
156 |
|
|
157 |
XFREE (key); |
XFREE (key); |
158 |
|
|
159 |
return 0; |
return NULL; |
160 |
} |
} |
161 |
|
|
162 |
|
|
175 |
|
|
176 |
/* If just searching, return status of search -- if only an empty |
/* If just searching, return status of search -- if only an empty |
177 |
struct is returned, that is treated as a failed lookup. */ |
struct is returned, that is treated as a failed lookup. */ |
178 |
return (psymbol && SYMBOL_TOKEN (*psymbol)) ? *psymbol : 0; |
return (psymbol && SYMBOL_VALUE (*psymbol)) ? *psymbol : 0; |
179 |
} |
} |
180 |
|
|
181 |
|
|
183 |
associated with NAME, push the new VALUE on top of the value stack |
associated with NAME, push the new VALUE on top of the value stack |
184 |
for this symbol. Otherwise create a new association. */ |
for this symbol. Otherwise create a new association. */ |
185 |
m4_symbol * |
m4_symbol * |
186 |
m4_symbol_pushdef (m4_symtab *symtab, const char *name, m4_token *value) |
m4_symbol_pushdef (m4_symtab *symtab, const char *name, m4_symbol_value *value) |
187 |
{ |
{ |
188 |
m4_symbol *symbol; |
m4_symbol *symbol; |
189 |
|
|
192 |
assert (value); |
assert (value); |
193 |
|
|
194 |
symbol = symtab_fetch (symtab, name); |
symbol = symtab_fetch (symtab, name); |
195 |
TOKEN_NEXT (value) = SYMBOL_TOKEN (symbol); |
VALUE_NEXT (value) = SYMBOL_VALUE (symbol); |
196 |
SYMBOL_TOKEN (symbol) = value; |
SYMBOL_VALUE (symbol) = value; |
197 |
|
|
198 |
assert (SYMBOL_TOKEN (symbol)); |
assert (SYMBOL_VALUE (symbol)); |
199 |
|
|
200 |
return symbol; |
return symbol; |
201 |
} |
} |
203 |
/* Return the symbol associated with NAME in the symbol table, creating |
/* Return the symbol associated with NAME in the symbol table, creating |
204 |
a new symbol if necessary. In either case set the symbol's VALUE. */ |
a new symbol if necessary. In either case set the symbol's VALUE. */ |
205 |
m4_symbol * |
m4_symbol * |
206 |
m4_symbol_define (m4_symtab *symtab, const char *name, m4_token *value) |
m4_symbol_define (m4_symtab *symtab, const char *name, m4_symbol_value *value) |
207 |
{ |
{ |
208 |
m4_symbol *symbol; |
m4_symbol *symbol; |
209 |
|
|
212 |
assert (value); |
assert (value); |
213 |
|
|
214 |
symbol = symtab_fetch (symtab, name); |
symbol = symtab_fetch (symtab, name); |
215 |
if (SYMBOL_TOKEN (symbol)) |
if (SYMBOL_VALUE (symbol)) |
216 |
symbol_popval (symbol); |
symbol_popval (symbol); |
217 |
|
|
218 |
TOKEN_NEXT (value) = SYMBOL_TOKEN (symbol); |
VALUE_NEXT (value) = SYMBOL_VALUE (symbol); |
219 |
SYMBOL_TOKEN (symbol) = value; |
SYMBOL_VALUE (symbol) = value; |
220 |
|
|
221 |
assert (SYMBOL_TOKEN (symbol)); |
assert (SYMBOL_VALUE (symbol)); |
222 |
|
|
223 |
return symbol; |
return symbol; |
224 |
} |
} |
252 |
|
|
253 |
/* Only remove the hash table entry if the last value in the |
/* Only remove the hash table entry if the last value in the |
254 |
symbol value stack was successfully removed. */ |
symbol value stack was successfully removed. */ |
255 |
if (!SYMBOL_TOKEN (*psymbol)) |
if (!SYMBOL_VALUE (*psymbol)) |
256 |
if (no_gnu_extensions || !SYMBOL_TRACED (*psymbol)) |
if (no_gnu_extensions || !SYMBOL_TRACED (*psymbol)) |
257 |
{ |
{ |
258 |
XFREE (*psymbol); |
XFREE (*psymbol); |
264 |
static void |
static void |
265 |
symbol_popval (m4_symbol *symbol) |
symbol_popval (m4_symbol *symbol) |
266 |
{ |
{ |
267 |
m4_token *stale; |
m4_symbol_value *stale; |
268 |
|
|
269 |
assert (symbol); |
assert (symbol); |
270 |
|
|
271 |
stale = SYMBOL_TOKEN (symbol); |
stale = SYMBOL_VALUE (symbol); |
272 |
|
|
273 |
if (stale) |
if (stale) |
274 |
{ |
{ |
275 |
SYMBOL_TOKEN (symbol) = TOKEN_NEXT (stale); |
SYMBOL_VALUE (symbol) = VALUE_NEXT (stale); |
276 |
|
|
277 |
if (TOKEN_ARG_SIGNATURE (stale)) |
if (VALUE_ARG_SIGNATURE (stale)) |
278 |
{ |
{ |
279 |
m4_hash_apply (TOKEN_ARG_SIGNATURE (stale), arg_destroy, NULL); |
m4_hash_apply (VALUE_ARG_SIGNATURE (stale), arg_destroy, NULL); |
280 |
m4_hash_delete (TOKEN_ARG_SIGNATURE (stale)); |
m4_hash_delete (VALUE_ARG_SIGNATURE (stale)); |
281 |
} |
} |
282 |
if (TOKEN_TYPE (stale) == M4_TOKEN_TEXT) |
if (VALUE_TYPE (stale) == M4_SYMBOL_TEXT) |
283 |
XFREE (TOKEN_TEXT (stale)); |
XFREE (VALUE_TEXT (stale)); |
284 |
XFREE (stale); |
XFREE (stale); |
285 |
} |
} |
286 |
} |
} |
287 |
|
|
288 |
/* Callback used by m4_symbol_popdef () to release the memory used |
/* Callback used by m4_symbol_popdef () to release the memory used |
289 |
by values in the arg_signature hash. */ |
by values in the arg_signature hash. */ |
290 |
static int |
static void * |
291 |
arg_destroy (m4_hash *hash, const void *name, void *arg, void *ignored) |
arg_destroy (m4_hash *hash, const void *name, void *arg, void *ignored) |
292 |
{ |
{ |
293 |
struct m4_token_arg *token_arg = (struct m4_token_arg *) arg; |
struct m4_symbol_arg *token_arg = (struct m4_symbol_arg *) arg; |
294 |
|
|
295 |
assert (name); |
assert (name); |
296 |
assert (hash); |
assert (hash); |
297 |
|
|
298 |
if (TOKEN_ARG_DEFAULT (token_arg)) |
if (SYMBOL_ARG_DEFAULT (token_arg)) |
299 |
XFREE (TOKEN_ARG_DEFAULT (token_arg)); |
XFREE (SYMBOL_ARG_DEFAULT (token_arg)); |
300 |
xfree (token_arg); |
xfree (token_arg); |
301 |
xfree (m4_hash_remove (hash, (const char *) name)); |
xfree (m4_hash_remove (hash, (const char *) name)); |
302 |
|
|
303 |
return 0; |
return NULL; |
|
} |
|
|
|
|
|
#if 0 |
|
|
m4_symbol * |
|
|
m4_symbol_push_token (m4_symtab *symtab, const char *name, m4_token *token) |
|
|
{ |
|
|
m4_token *next; |
|
|
|
|
|
assert (symtab); |
|
|
assert (name); |
|
|
assert (token); |
|
|
|
|
|
/* If it's a function, it must have come from a module. */ |
|
|
assert ((TOKEN_TYPE (token) != M4_TOKEN_FUNC) || TOKEN_HANDLE (token)); |
|
|
|
|
|
#if M4PARAMS |
|
|
const char *openp = NULL; |
|
|
const char *params = NULL; |
|
|
|
|
|
if (!no_gnu_extensions) |
|
|
{ |
|
|
/* If name contains an open paren, then parse before that paren |
|
|
as the actual name, and the rest as a formal parameter list. */ |
|
|
size_t len = 0; |
|
|
for (openp = name; *openp && !M4_IS_OPEN (*openp); ++openp) |
|
|
++len; |
|
|
|
|
|
if (*openp) |
|
|
{ |
|
|
name = xstrzdup (name, len); |
|
|
params = 1+ openp; |
|
|
} |
|
|
} |
|
|
|
|
|
if (params) |
|
|
{ |
|
|
/* Make a hash table to map formal parameter names to |
|
|
argv offsets, and store that in the symbol's token. */ |
|
|
TOKEN_ARG_SIGNATURE (token) = arg_signature_parse (name, params); |
|
|
} |
|
|
#endif |
|
|
|
|
|
SYMBOL_TOKEN (symbol) = token; |
|
|
|
|
|
#if M4PARAMS |
|
|
/* If we split name on open paren, free the copied substring. */ |
|
|
if (params) |
|
|
xfree ((char *) name); |
|
|
#endif |
|
|
|
|
|
return symbol; |
|
304 |
} |
} |
|
#endif |
|
305 |
|
|
306 |
void |
void |
307 |
m4_token_copy (m4_token *dest, m4_token *src) |
m4_symbol_value_copy (m4_symbol_value *dest, m4_symbol_value *src) |
308 |
{ |
{ |
309 |
m4_token *next; |
m4_symbol_value *next; |
310 |
|
|
311 |
assert (dest); |
assert (dest); |
312 |
assert (src); |
assert (src); |
313 |
|
|
314 |
if (TOKEN_TYPE (dest) == M4_TOKEN_TEXT) |
if (VALUE_TYPE (dest) == M4_SYMBOL_TEXT) |
315 |
xfree (TOKEN_TEXT (dest)); |
xfree (VALUE_TEXT (dest)); |
316 |
|
|
317 |
#if M4PARAMS |
if (VALUE_ARG_SIGNATURE (dest)) |
|
if (TOKEN_ARG_SIGNATURE (dest)) |
|
318 |
{ |
{ |
319 |
m4_hash_apply (TOKEN_ARG_SIGNATURE (dest), arg_destroy, NULL); |
m4_hash_apply (VALUE_ARG_SIGNATURE (dest), arg_destroy, NULL); |
320 |
m4_hash_delete (TOKEN_ARG_SIGNATURE (dest)); |
m4_hash_delete (VALUE_ARG_SIGNATURE (dest)); |
321 |
} |
} |
|
#endif |
|
322 |
|
|
323 |
/* Copy the token contents over, being careful to preserve |
/* Copy the token contents over, being careful to preserve |
324 |
the next pointer. */ |
the next pointer. */ |
325 |
next = TOKEN_NEXT (dest); |
next = VALUE_NEXT (dest); |
326 |
bcopy (src, dest, sizeof (m4_token)); |
bcopy (src, dest, sizeof (m4_symbol_value)); |
327 |
TOKEN_NEXT (dest) = next; |
VALUE_NEXT (dest) = next; |
328 |
|
|
329 |
/* Caller is supposed to free text token strings, so we have to |
/* Caller is supposed to free text token strings, so we have to |
330 |
copy the string not just its address in that case. */ |
copy the string not just its address in that case. */ |
331 |
if (TOKEN_TYPE (src) == M4_TOKEN_TEXT) |
if (VALUE_TYPE (src) == M4_SYMBOL_TEXT) |
332 |
TOKEN_TEXT (dest) = xstrdup (TOKEN_TEXT (src)); |
VALUE_TEXT (dest) = xstrdup (VALUE_TEXT (src)); |
333 |
|
|
334 |
#if M4PARAMS |
if (VALUE_ARG_SIGNATURE (src)) |
335 |
if (TOKEN_ARG_SIGNATURE (src)) |
VALUE_ARG_SIGNATURE (dest) = m4_hash_dup (VALUE_ARG_SIGNATURE (src), |
336 |
TOKEN_ARG_SIGNATURE (dest) = m4_hash_dup (TOKEN_ARG_SIGNATURE (token)); |
arg_copy); |
|
#endif |
|
337 |
} |
} |
338 |
|
|
339 |
#if M4PARAMS |
static void * |
340 |
static m4_hash * |
arg_copy (m4_hash *src, const void *name, void *arg, m4_hash *dest) |
|
arg_signature_parse (const char *name, const char *params) |
|
341 |
{ |
{ |
342 |
m4_hash *arg_signature; |
m4_hash_insert ((m4_hash *) dest, name, arg); |
343 |
const char *commap; |
return NULL; |
|
int offset; |
|
|
|
|
|
assert (params); |
|
|
|
|
|
arg_signature = m4_hash_new (M4_ARG_SIGNATURE_DEFAULT_SIZE, |
|
|
m4_hash_string_hash, m4_hash_string_cmp); |
|
|
|
|
|
for (offset = 1; *params && !M4_IS_CLOSE (*params); ++offset) |
|
|
{ |
|
|
size_t len = 0; |
|
|
|
|
|
/* Skip leading whitespace. */ |
|
|
while (M4_IS_SPACE (*params)) |
|
|
++params; |
|
|
|
|
|
for (commap = params; *commap && M4_IS_IDENT (*commap); ++commap) |
|
|
++len; |
|
|
|
|
|
/* Skip trailing whitespace. */ |
|
|
while (M4_IS_SPACE (*commap)) |
|
|
++commap; |
|
|
|
|
|
if (!M4_IS_COMMA (*commap) && !M4_IS_CLOSE (*commap)) |
|
|
M4ERROR ((EXIT_FAILURE, 0, |
|
|
_("Error: %s: syntax error in parameter list at char `%c'"), |
|
|
name, *commap)); |
|
|
|
|
|
/* Skip parameter delimiter. */ |
|
|
if (M4_IS_COMMA (*commap)) |
|
|
++commap; |
|
|
|
|
|
if (len) |
|
|
{ |
|
|
struct m4_token_arg *arg = XCALLOC (struct m4_token_arg, 1); |
|
|
|
|
|
TOKEN_ARG_INDEX (arg) = offset; |
|
|
|
|
|
m4_hash_insert (arg_signature, xstrzdup (params, len), arg); |
|
|
|
|
|
params = commap; |
|
|
} |
|
|
} |
|
|
|
|
|
if (!M4_IS_CLOSE (*commap)) |
|
|
M4WARN ((warning_status, 0, |
|
|
_("Warning: %s: unterminated parameter list"), name)); |
|
|
|
|
|
return arg_signature; |
|
344 |
} |
} |
|
#endif |
|
|
|
|
345 |
|
|
346 |
|
|
347 |
#ifdef DEBUG_SYM |
#ifdef DEBUG_SYM |
356 |
{ |
{ |
357 |
m4_hash_iterator *place = 0; |
m4_hash_iterator *place = 0; |
358 |
|
|
359 |
while ((place = m4_hash_iterator_next ((m4_hash *) symtab, place))) |
while ((place = m4_get_hash_iterator_next ((m4_hash *) symtab, place))) |
360 |
{ |
{ |
361 |
const char *symbol_name = (const char *) m4_hash_iterator_key (place); |
const char *symbol_name = (const char *) m4_get_hash_iterator_key (place); |
362 |
m4_symbol *symbol = m4_hash_iterator_value (place); |
m4_symbol *symbol = m4_get_hash_iterator_value (place); |
363 |
m4_token *token = SYMBOL_TOKEN (symbol); |
m4_symbol_value *token = SYMBOL_VALUE (symbol); |
364 |
int flags = token ? SYMBOL_FLAGS (symbol) : 0; |
int flags = token ? SYMBOL_FLAGS (symbol) : 0; |
365 |
lt_dlhandle handle = token ? SYMBOL_HANDLE (symbol) : 0; |
lt_dlhandle handle = token ? SYMBOL_HANDLE (symbol) : 0; |
366 |
const char *module_name = handle ? m4_get_module_name (handle) : "NONE"; |
const char *module_name = handle ? m4_get_module_name (handle) : "NONE"; |
375 |
else |
else |
376 |
switch (SYMBOL_TYPE (symbol)) |
switch (SYMBOL_TYPE (symbol)) |
377 |
{ |
{ |
378 |
case M4_TOKEN_TEXT: |
case M4_SYMBOL_TEXT: |
379 |
fputs (SYMBOL_TEXT (symbol), stderr); |
fputs (SYMBOL_TEXT (symbol), stderr); |
380 |
break; |
break; |
381 |
|
|
382 |
case M4_TOKEN_FUNC: |
case M4_SYMBOL_FUNC: |
383 |
bp = m4_builtin_find_by_func (m4_get_module_builtin_table (handle), |
bp = m4_builtin_find_by_func (m4_get_module_builtin_table (handle), |
384 |
SYMBOL_FUNC (symbol)); |
SYMBOL_FUNC (symbol)); |
385 |
fprintf (stderr, "<%s>", |
fprintf (stderr, "<%s>", |
386 |
bp ? bp->name : "!ERROR!"); |
bp ? bp->name : "!ERROR!"); |
387 |
break; |
break; |
388 |
case M4_TOKEN_VOID: |
case M4_SYMBOL_VOID: |
389 |
fputs ("<!VOID!>", stderr); |
fputs ("<!VOID!>", stderr); |
390 |
break; |
break; |
391 |
} |
} |
392 |
fputc ('\n', stderr); |
fputc ('\n', stderr); |
393 |
} |
} |
394 |
} |
} |
|
|
|
|
static void |
|
|
symtab_debug (m4_symtab *symtab) |
|
|
{ |
|
|
m4__token_type type; |
|
|
m4_token token; |
|
|
const char *text; |
|
|
m4_symbol *symbol; |
|
|
int delete; |
|
|
|
|
|
while ((type = m4_next_token (&token)) != M4_TOKEN_EOF) |
|
|
{ |
|
|
if (type != M4_TOKEN_WORD) |
|
|
continue; |
|
|
text = TOKEN_TEXT (&token); |
|
|
if (*text == '_') |
|
|
{ |
|
|
delete = 1; |
|
|
text++; |
|
|
} |
|
|
else |
|
|
delete = 0; |
|
|
|
|
|
symbol = m4_symbol_lookup (symtab, text); |
|
|
|
|
|
if (symbol == NULL) |
|
|
printf (_("Name `%s' is unknown\n"), text); |
|
|
|
|
|
if (delete) |
|
|
m4_symbol_delete (symtab, text); |
|
|
else |
|
|
symtab_fetch (symtab, text); |
|
|
} |
|
|
m4_symtab_apply (symtab, symtab_print_list, NULL); |
|
|
} |
|
|
|
|
|
static int |
|
|
symtab_print_list (m4_hash *hash, const void *name, void *symbol, |
|
|
void *ignored) |
|
|
{ |
|
|
printf ("\tname %s, addr %#x, flags: %d %s\n", |
|
|
(char *) name, (unsigned) symbol, |
|
|
SYMBOL_FLAGS ((m4_symbol *) symbol), |
|
|
SYMBOL_TRACED ((m4_symbol *) symbol) ? " traced" : "<none>"); |
|
|
return 0; |
|
|
} |
|
|
|
|
395 |
#endif /* DEBUG_SYM */ |
#endif /* DEBUG_SYM */ |
396 |
|
|
397 |
/* Define these functions at the end, so that calls in the file use the |
/* Define these functions at the end, so that calls in the file use the |
398 |
faster macro version from m4module.h. */ |
faster macro version from m4module.h. */ |
399 |
#undef m4_symtab_apply |
#undef m4_symtab_apply |
400 |
int |
void * |
401 |
m4_symtab_apply (m4_symtab *symtab, m4_symtab_apply_func *func, void *userdata) |
m4_symtab_apply (m4_symtab *symtab, m4_symtab_apply_func *func, void *userdata) |
402 |
{ |
{ |
403 |
return m4_hash_apply ((m4_hash *) symtab, (m4_hash_apply_func *) func, |
return m4_hash_apply ((m4_hash *) symtab, (m4_hash_apply_func *) func, |