1 | /* GNU m4 -- A simple macro processor
|
---|
2 |
|
---|
3 | Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2000, 2004, 2006
|
---|
4 | Free Software Foundation, Inc.
|
---|
5 |
|
---|
6 | This program is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2 of the License, or
|
---|
9 | (at your option) any later version.
|
---|
10 |
|
---|
11 | This program is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with this program; if not, write to the Free Software
|
---|
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
---|
19 | 02110-1301 USA
|
---|
20 | */
|
---|
21 |
|
---|
22 | /* Code for all builtin macros, initialization of symbol table, and
|
---|
23 | expansion of user defined macros. */
|
---|
24 |
|
---|
25 | #include "m4.h"
|
---|
26 |
|
---|
27 | extern FILE *popen ();
|
---|
28 |
|
---|
29 | #include "regex.h"
|
---|
30 | #include "strstr.h"
|
---|
31 |
|
---|
32 | #if HAVE_SYS_WAIT_H
|
---|
33 | # include <sys/wait.h>
|
---|
34 | #endif
|
---|
35 |
|
---|
36 | #define ARG(i) (argc > (i) ? TOKEN_DATA_TEXT (argv[i]) : "")
|
---|
37 |
|
---|
38 | /* Initialization of builtin and predefined macros. The table
|
---|
39 | "builtin_tab" is both used for initialization, and by the "builtin"
|
---|
40 | builtin. */
|
---|
41 |
|
---|
42 | #define DECLARE(name) \
|
---|
43 | static void name (struct obstack *, int, token_data **)
|
---|
44 |
|
---|
45 | DECLARE (m4___file__);
|
---|
46 | DECLARE (m4___line__);
|
---|
47 | DECLARE (m4___program__);
|
---|
48 | DECLARE (m4_builtin);
|
---|
49 | DECLARE (m4_changecom);
|
---|
50 | DECLARE (m4_changequote);
|
---|
51 | #ifdef ENABLE_CHANGEWORD
|
---|
52 | DECLARE (m4_changeword);
|
---|
53 | #endif
|
---|
54 | DECLARE (m4_debugmode);
|
---|
55 | DECLARE (m4_debugfile);
|
---|
56 | DECLARE (m4_decr);
|
---|
57 | DECLARE (m4_define);
|
---|
58 | DECLARE (m4_defn);
|
---|
59 | DECLARE (m4_divert);
|
---|
60 | DECLARE (m4_divnum);
|
---|
61 | DECLARE (m4_dnl);
|
---|
62 | DECLARE (m4_dumpdef);
|
---|
63 | DECLARE (m4_errprint);
|
---|
64 | DECLARE (m4_esyscmd);
|
---|
65 | DECLARE (m4_eval);
|
---|
66 | DECLARE (m4_format);
|
---|
67 | DECLARE (m4_ifdef);
|
---|
68 | DECLARE (m4_ifelse);
|
---|
69 | DECLARE (m4_include);
|
---|
70 | DECLARE (m4_incr);
|
---|
71 | DECLARE (m4_index);
|
---|
72 | DECLARE (m4_indir);
|
---|
73 | DECLARE (m4_len);
|
---|
74 | DECLARE (m4_m4exit);
|
---|
75 | DECLARE (m4_m4wrap);
|
---|
76 | DECLARE (m4_maketemp);
|
---|
77 | DECLARE (m4_mkstemp);
|
---|
78 | DECLARE (m4_patsubst);
|
---|
79 | DECLARE (m4_popdef);
|
---|
80 | DECLARE (m4_pushdef);
|
---|
81 | DECLARE (m4_regexp);
|
---|
82 | DECLARE (m4_shift);
|
---|
83 | DECLARE (m4_sinclude);
|
---|
84 | DECLARE (m4_substr);
|
---|
85 | DECLARE (m4_syscmd);
|
---|
86 | DECLARE (m4_sysval);
|
---|
87 | DECLARE (m4_traceoff);
|
---|
88 | DECLARE (m4_traceon);
|
---|
89 | DECLARE (m4_translit);
|
---|
90 | DECLARE (m4_undefine);
|
---|
91 | DECLARE (m4_undivert);
|
---|
92 |
|
---|
93 | #undef DECLARE
|
---|
94 |
|
---|
95 | static builtin
|
---|
96 | builtin_tab[] =
|
---|
97 | {
|
---|
98 |
|
---|
99 | /* name GNUext macros blind function */
|
---|
100 |
|
---|
101 | { "__file__", true, false, false, m4___file__ },
|
---|
102 | { "__line__", true, false, false, m4___line__ },
|
---|
103 | { "__program__", true, false, false, m4___program__ },
|
---|
104 | { "builtin", true, true, true, m4_builtin },
|
---|
105 | { "changecom", false, false, false, m4_changecom },
|
---|
106 | { "changequote", false, false, false, m4_changequote },
|
---|
107 | #ifdef ENABLE_CHANGEWORD
|
---|
108 | { "changeword", true, false, true, m4_changeword },
|
---|
109 | #endif
|
---|
110 | { "debugmode", true, false, false, m4_debugmode },
|
---|
111 | { "debugfile", true, false, false, m4_debugfile },
|
---|
112 | { "decr", false, false, true, m4_decr },
|
---|
113 | { "define", false, true, true, m4_define },
|
---|
114 | { "defn", false, false, true, m4_defn },
|
---|
115 | { "divert", false, false, false, m4_divert },
|
---|
116 | { "divnum", false, false, false, m4_divnum },
|
---|
117 | { "dnl", false, false, false, m4_dnl },
|
---|
118 | { "dumpdef", false, false, false, m4_dumpdef },
|
---|
119 | { "errprint", false, false, true, m4_errprint },
|
---|
120 | { "esyscmd", true, false, true, m4_esyscmd },
|
---|
121 | { "eval", false, false, true, m4_eval },
|
---|
122 | { "format", true, false, true, m4_format },
|
---|
123 | { "ifdef", false, false, true, m4_ifdef },
|
---|
124 | { "ifelse", false, false, true, m4_ifelse },
|
---|
125 | { "include", false, false, true, m4_include },
|
---|
126 | { "incr", false, false, true, m4_incr },
|
---|
127 | { "index", false, false, true, m4_index },
|
---|
128 | { "indir", true, true, true, m4_indir },
|
---|
129 | { "len", false, false, true, m4_len },
|
---|
130 | { "m4exit", false, false, false, m4_m4exit },
|
---|
131 | { "m4wrap", false, false, true, m4_m4wrap },
|
---|
132 | { "maketemp", false, false, true, m4_maketemp },
|
---|
133 | { "mkstemp", false, false, true, m4_mkstemp },
|
---|
134 | { "patsubst", true, false, true, m4_patsubst },
|
---|
135 | { "popdef", false, false, true, m4_popdef },
|
---|
136 | { "pushdef", false, true, true, m4_pushdef },
|
---|
137 | { "regexp", true, false, true, m4_regexp },
|
---|
138 | { "shift", false, false, true, m4_shift },
|
---|
139 | { "sinclude", false, false, true, m4_sinclude },
|
---|
140 | { "substr", false, false, true, m4_substr },
|
---|
141 | { "syscmd", false, false, true, m4_syscmd },
|
---|
142 | { "sysval", false, false, false, m4_sysval },
|
---|
143 | { "traceoff", false, false, false, m4_traceoff },
|
---|
144 | { "traceon", false, false, false, m4_traceon },
|
---|
145 | { "translit", false, false, true, m4_translit },
|
---|
146 | { "undefine", false, false, true, m4_undefine },
|
---|
147 | { "undivert", false, false, false, m4_undivert },
|
---|
148 |
|
---|
149 | { 0, false, false, false, 0 },
|
---|
150 |
|
---|
151 | /* placeholder is intentionally stuck after the table end delimiter,
|
---|
152 | so that we can easily find it, while not treating it as a real
|
---|
153 | builtin. */
|
---|
154 | { "placeholder", true, false, false, m4_placeholder },
|
---|
155 | };
|
---|
156 |
|
---|
157 | static predefined const
|
---|
158 | predefined_tab[] =
|
---|
159 | {
|
---|
160 | #if UNIX
|
---|
161 | { "unix", "__unix__", "" },
|
---|
162 | #elif W32_NATIVE
|
---|
163 | { "windows", "__windows__", "" },
|
---|
164 | #elif OS2
|
---|
165 | { "os2", "__os2__", "" },
|
---|
166 | #else
|
---|
167 | # warning Platform macro not provided
|
---|
168 | #endif
|
---|
169 | { NULL, "__gnu__", "" },
|
---|
170 |
|
---|
171 | { NULL, NULL, NULL },
|
---|
172 | };
|
---|
173 | |
---|
174 |
|
---|
175 | /*----------------------------------------.
|
---|
176 | | Find the builtin, which lives on ADDR. |
|
---|
177 | `----------------------------------------*/
|
---|
178 |
|
---|
179 | const builtin *
|
---|
180 | find_builtin_by_addr (builtin_func *func)
|
---|
181 | {
|
---|
182 | const builtin *bp;
|
---|
183 |
|
---|
184 | for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
|
---|
185 | if (bp->func == func)
|
---|
186 | return bp;
|
---|
187 | if (func == m4_placeholder)
|
---|
188 | return bp + 1;
|
---|
189 | return NULL;
|
---|
190 | }
|
---|
191 |
|
---|
192 | /*----------------------------------------------------------.
|
---|
193 | | Find the builtin, which has NAME. On failure, return the |
|
---|
194 | | placeholder builtin. |
|
---|
195 | `----------------------------------------------------------*/
|
---|
196 |
|
---|
197 | const builtin *
|
---|
198 | find_builtin_by_name (const char *name)
|
---|
199 | {
|
---|
200 | const builtin *bp;
|
---|
201 |
|
---|
202 | for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
|
---|
203 | if (strcmp (bp->name, name) == 0)
|
---|
204 | return bp;
|
---|
205 | return bp + 1;
|
---|
206 | }
|
---|
207 | |
---|
208 |
|
---|
209 | /*-------------------------------------------------------------------------.
|
---|
210 | | Install a builtin macro with name NAME, bound to the C function given in |
|
---|
211 | | BP. MODE is SYMBOL_INSERT or SYMBOL_PUSHDEF. TRACED defines whether |
|
---|
212 | | NAME is to be traced. |
|
---|
213 | `-------------------------------------------------------------------------*/
|
---|
214 |
|
---|
215 | void
|
---|
216 | define_builtin (const char *name, const builtin *bp, symbol_lookup mode)
|
---|
217 | {
|
---|
218 | symbol *sym;
|
---|
219 |
|
---|
220 | sym = lookup_symbol (name, mode);
|
---|
221 | SYMBOL_TYPE (sym) = TOKEN_FUNC;
|
---|
222 | SYMBOL_MACRO_ARGS (sym) = bp->groks_macro_args;
|
---|
223 | SYMBOL_BLIND_NO_ARGS (sym) = bp->blind_if_no_args;
|
---|
224 | SYMBOL_FUNC (sym) = bp->func;
|
---|
225 | }
|
---|
226 |
|
---|
227 | /*-------------------------------------------------------------------------.
|
---|
228 | | Define a predefined or user-defined macro, with name NAME, and expansion |
|
---|
229 | | TEXT. MODE destinguishes between the "define" and the "pushdef" case. |
|
---|
230 | | It is also used from main (). |
|
---|
231 | `-------------------------------------------------------------------------*/
|
---|
232 |
|
---|
233 | void
|
---|
234 | define_user_macro (const char *name, const char *text, symbol_lookup mode)
|
---|
235 | {
|
---|
236 | symbol *s;
|
---|
237 |
|
---|
238 | s = lookup_symbol (name, mode);
|
---|
239 | if (SYMBOL_TYPE (s) == TOKEN_TEXT)
|
---|
240 | free (SYMBOL_TEXT (s));
|
---|
241 |
|
---|
242 | SYMBOL_TYPE (s) = TOKEN_TEXT;
|
---|
243 | SYMBOL_TEXT (s) = xstrdup (text ? text : "");
|
---|
244 | }
|
---|
245 |
|
---|
246 | /*-----------------------------------------------.
|
---|
247 | | Initialize all builtin and predefined macros. |
|
---|
248 | `-----------------------------------------------*/
|
---|
249 |
|
---|
250 | void
|
---|
251 | builtin_init (void)
|
---|
252 | {
|
---|
253 | const builtin *bp;
|
---|
254 | const predefined *pp;
|
---|
255 | char *string;
|
---|
256 |
|
---|
257 | for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
|
---|
258 | if (!no_gnu_extensions || !bp->gnu_extension)
|
---|
259 | {
|
---|
260 | if (prefix_all_builtins)
|
---|
261 | {
|
---|
262 | string = (char *) xmalloc (strlen (bp->name) + 4);
|
---|
263 | strcpy (string, "m4_");
|
---|
264 | strcat (string, bp->name);
|
---|
265 | define_builtin (string, bp, SYMBOL_INSERT);
|
---|
266 | free (string);
|
---|
267 | }
|
---|
268 | else
|
---|
269 | define_builtin (bp->name, bp, SYMBOL_INSERT);
|
---|
270 | }
|
---|
271 |
|
---|
272 | for (pp = &predefined_tab[0]; pp->func != NULL; pp++)
|
---|
273 | if (no_gnu_extensions)
|
---|
274 | {
|
---|
275 | if (pp->unix_name != NULL)
|
---|
276 | define_user_macro (pp->unix_name, pp->func, SYMBOL_INSERT);
|
---|
277 | }
|
---|
278 | else
|
---|
279 | {
|
---|
280 | if (pp->gnu_name != NULL)
|
---|
281 | define_user_macro (pp->gnu_name, pp->func, SYMBOL_INSERT);
|
---|
282 | }
|
---|
283 | }
|
---|
284 |
|
---|
285 | /*------------------------------------------------------------------------.
|
---|
286 | | Give friendly warnings if a builtin macro is passed an inappropriate |
|
---|
287 | | number of arguments. NAME is macro name for messages, ARGC is actual |
|
---|
288 | | number of arguments, MIN is the minimum number of acceptable arguments, |
|
---|
289 | | negative if not applicable, MAX is the maximum number, negative if not |
|
---|
290 | | applicable. |
|
---|
291 | `------------------------------------------------------------------------*/
|
---|
292 |
|
---|
293 | static bool
|
---|
294 | bad_argc (token_data *name, int argc, int min, int max)
|
---|
295 | {
|
---|
296 | bool isbad = false;
|
---|
297 |
|
---|
298 | if (min > 0 && argc < min)
|
---|
299 | {
|
---|
300 | if (!suppress_warnings)
|
---|
301 | M4ERROR ((warning_status, 0,
|
---|
302 | "Warning: too few arguments to builtin `%s'",
|
---|
303 | TOKEN_DATA_TEXT (name)));
|
---|
304 | isbad = true;
|
---|
305 | }
|
---|
306 | else if (max > 0 && argc > max && !suppress_warnings)
|
---|
307 | M4ERROR ((warning_status, 0,
|
---|
308 | "Warning: excess arguments to builtin `%s' ignored",
|
---|
309 | TOKEN_DATA_TEXT (name)));
|
---|
310 |
|
---|
311 | return isbad;
|
---|
312 | }
|
---|
313 |
|
---|
314 | /*--------------------------------------------------------------------------.
|
---|
315 | | The function numeric_arg () converts ARG to an int pointed to by VALUEP. |
|
---|
316 | | If the conversion fails, print error message for macro MACRO. Return |
|
---|
317 | | true iff conversion succeeds. |
|
---|
318 | `--------------------------------------------------------------------------*/
|
---|
319 |
|
---|
320 | static bool
|
---|
321 | numeric_arg (token_data *macro, const char *arg, int *valuep)
|
---|
322 | {
|
---|
323 | char *endp;
|
---|
324 |
|
---|
325 | if (*arg == '\0')
|
---|
326 | {
|
---|
327 | *valuep = 0;
|
---|
328 | M4ERROR ((warning_status, 0,
|
---|
329 | "empty string treated as 0 in builtin `%s'",
|
---|
330 | TOKEN_DATA_TEXT (macro)));
|
---|
331 | }
|
---|
332 | else
|
---|
333 | {
|
---|
334 | errno = 0;
|
---|
335 | *valuep = strtol (arg, &endp, 10);
|
---|
336 | if (*endp != '\0')
|
---|
337 | {
|
---|
338 | M4ERROR ((warning_status, 0,
|
---|
339 | "non-numeric argument to builtin `%s'",
|
---|
340 | TOKEN_DATA_TEXT (macro)));
|
---|
341 | return false;
|
---|
342 | }
|
---|
343 | if (isspace (to_uchar (*arg)))
|
---|
344 | M4ERROR ((warning_status, 0,
|
---|
345 | "leading whitespace ignored in builtin `%s'",
|
---|
346 | TOKEN_DATA_TEXT (macro)));
|
---|
347 | else if (errno == ERANGE)
|
---|
348 | M4ERROR ((warning_status, 0,
|
---|
349 | "numeric overflow detected in builtin `%s'",
|
---|
350 | TOKEN_DATA_TEXT (macro)));
|
---|
351 | }
|
---|
352 | return true;
|
---|
353 | }
|
---|
354 |
|
---|
355 | /*------------------------------------------------------------------------.
|
---|
356 | | The function ntoa () converts VALUE to a signed ascii representation in |
|
---|
357 | | radix RADIX. |
|
---|
358 | `------------------------------------------------------------------------*/
|
---|
359 |
|
---|
360 | /* Digits for number to ascii conversions. */
|
---|
361 | static char const digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
---|
362 |
|
---|
363 | static const char *
|
---|
364 | ntoa (eval_t value, int radix)
|
---|
365 | {
|
---|
366 | bool negative;
|
---|
367 | unsigned_eval_t uvalue;
|
---|
368 | static char str[256];
|
---|
369 | char *s = &str[sizeof str];
|
---|
370 |
|
---|
371 | *--s = '\0';
|
---|
372 |
|
---|
373 | if (value < 0)
|
---|
374 | {
|
---|
375 | negative = true;
|
---|
376 | uvalue = (unsigned_eval_t) -value;
|
---|
377 | }
|
---|
378 | else
|
---|
379 | {
|
---|
380 | negative = false;
|
---|
381 | uvalue = (unsigned_eval_t) value;
|
---|
382 | }
|
---|
383 |
|
---|
384 | do
|
---|
385 | {
|
---|
386 | *--s = digits[uvalue % radix];
|
---|
387 | uvalue /= radix;
|
---|
388 | }
|
---|
389 | while (uvalue > 0);
|
---|
390 |
|
---|
391 | if (negative)
|
---|
392 | *--s = '-';
|
---|
393 | return s;
|
---|
394 | }
|
---|
395 |
|
---|
396 | /*----------------------------------------------------------------------.
|
---|
397 | | Format an int VAL, and stuff it into an obstack OBS. Used for macros |
|
---|
398 | | expanding to numbers. |
|
---|
399 | `----------------------------------------------------------------------*/
|
---|
400 |
|
---|
401 | static void
|
---|
402 | shipout_int (struct obstack *obs, int val)
|
---|
403 | {
|
---|
404 | const char *s;
|
---|
405 |
|
---|
406 | s = ntoa ((eval_t) val, 10);
|
---|
407 | obstack_grow (obs, s, strlen (s));
|
---|
408 | }
|
---|
409 |
|
---|
410 | /*----------------------------------------------------------------------.
|
---|
411 | | Print ARGC arguments from the table ARGV to obstack OBS, separated by |
|
---|
412 | | SEP, and quoted by the current quotes, if QUOTED is true. |
|
---|
413 | `----------------------------------------------------------------------*/
|
---|
414 |
|
---|
415 | static void
|
---|
416 | dump_args (struct obstack *obs, int argc, token_data **argv,
|
---|
417 | const char *sep, bool quoted)
|
---|
418 | {
|
---|
419 | int i;
|
---|
420 | size_t len = strlen (sep);
|
---|
421 |
|
---|
422 | for (i = 1; i < argc; i++)
|
---|
423 | {
|
---|
424 | if (i > 1)
|
---|
425 | obstack_grow (obs, sep, len);
|
---|
426 | if (quoted)
|
---|
427 | obstack_grow (obs, lquote.string, lquote.length);
|
---|
428 | obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]),
|
---|
429 | strlen (TOKEN_DATA_TEXT (argv[i])));
|
---|
430 | if (quoted)
|
---|
431 | obstack_grow (obs, rquote.string, rquote.length);
|
---|
432 | }
|
---|
433 | }
|
---|
434 | |
---|
435 |
|
---|
436 | /* The rest of this file is code for builtins and expansion of user
|
---|
437 | defined macros. All the functions for builtins have a prototype as:
|
---|
438 |
|
---|
439 | void m4_MACRONAME (struct obstack *obs, int argc, char *argv[]);
|
---|
440 |
|
---|
441 | The function are expected to leave their expansion on the obstack OBS,
|
---|
442 | as an unfinished object. ARGV is a table of ARGC pointers to the
|
---|
443 | individual arguments to the macro. Please note that in general
|
---|
444 | argv[argc] != NULL. */
|
---|
445 |
|
---|
446 | /* The first section are macros for definining, undefining, examining,
|
---|
447 | changing, ... other macros. */
|
---|
448 |
|
---|
449 | /*-------------------------------------------------------------------------.
|
---|
450 | | The function define_macro is common for the builtins "define", |
|
---|
451 | | "undefine", "pushdef" and "popdef". ARGC and ARGV is as for the caller, |
|
---|
452 | | and MODE argument determines how the macro name is entered into the |
|
---|
453 | | symbol table. |
|
---|
454 | `-------------------------------------------------------------------------*/
|
---|
455 |
|
---|
456 | static void
|
---|
457 | define_macro (int argc, token_data **argv, symbol_lookup mode)
|
---|
458 | {
|
---|
459 | const builtin *bp;
|
---|
460 |
|
---|
461 | if (bad_argc (argv[0], argc, 2, 3))
|
---|
462 | return;
|
---|
463 |
|
---|
464 | if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
|
---|
465 | {
|
---|
466 | M4ERROR ((warning_status, 0,
|
---|
467 | "Warning: %s: invalid macro name ignored", ARG (0)));
|
---|
468 | return;
|
---|
469 | }
|
---|
470 |
|
---|
471 | if (argc == 2)
|
---|
472 | {
|
---|
473 | define_user_macro (ARG (1), "", mode);
|
---|
474 | return;
|
---|
475 | }
|
---|
476 |
|
---|
477 | switch (TOKEN_DATA_TYPE (argv[2]))
|
---|
478 | {
|
---|
479 | case TOKEN_TEXT:
|
---|
480 | define_user_macro (ARG (1), ARG (2), mode);
|
---|
481 | break;
|
---|
482 |
|
---|
483 | case TOKEN_FUNC:
|
---|
484 | bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[2]));
|
---|
485 | if (bp == NULL)
|
---|
486 | return;
|
---|
487 | else
|
---|
488 | define_builtin (ARG (1), bp, mode);
|
---|
489 | break;
|
---|
490 |
|
---|
491 | default:
|
---|
492 | M4ERROR ((warning_status, 0,
|
---|
493 | "INTERNAL ERROR: bad token data type in define_macro ()"));
|
---|
494 | abort ();
|
---|
495 | }
|
---|
496 | }
|
---|
497 |
|
---|
498 | static void
|
---|
499 | m4_define (struct obstack *obs, int argc, token_data **argv)
|
---|
500 | {
|
---|
501 | define_macro (argc, argv, SYMBOL_INSERT);
|
---|
502 | }
|
---|
503 |
|
---|
504 | static void
|
---|
505 | m4_undefine (struct obstack *obs, int argc, token_data **argv)
|
---|
506 | {
|
---|
507 | int i;
|
---|
508 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
509 | return;
|
---|
510 | for (i = 1; i < argc; i++)
|
---|
511 | lookup_symbol (ARG (i), SYMBOL_DELETE);
|
---|
512 | }
|
---|
513 |
|
---|
514 | static void
|
---|
515 | m4_pushdef (struct obstack *obs, int argc, token_data **argv)
|
---|
516 | {
|
---|
517 | define_macro (argc, argv, SYMBOL_PUSHDEF);
|
---|
518 | }
|
---|
519 |
|
---|
520 | static void
|
---|
521 | m4_popdef (struct obstack *obs, int argc, token_data **argv)
|
---|
522 | {
|
---|
523 | int i;
|
---|
524 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
525 | return;
|
---|
526 | for (i = 1; i < argc; i++)
|
---|
527 | lookup_symbol (ARG (i), SYMBOL_POPDEF);
|
---|
528 | }
|
---|
529 | |
---|
530 |
|
---|
531 | /*---------------------.
|
---|
532 | | Conditionals of m4. |
|
---|
533 | `---------------------*/
|
---|
534 |
|
---|
535 | static void
|
---|
536 | m4_ifdef (struct obstack *obs, int argc, token_data **argv)
|
---|
537 | {
|
---|
538 | symbol *s;
|
---|
539 | const char *result;
|
---|
540 |
|
---|
541 | if (bad_argc (argv[0], argc, 3, 4))
|
---|
542 | return;
|
---|
543 | s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
|
---|
544 |
|
---|
545 | if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
|
---|
546 | result = ARG (2);
|
---|
547 | else if (argc >= 4)
|
---|
548 | result = ARG (3);
|
---|
549 | else
|
---|
550 | result = NULL;
|
---|
551 |
|
---|
552 | if (result != NULL)
|
---|
553 | obstack_grow (obs, result, strlen (result));
|
---|
554 | }
|
---|
555 |
|
---|
556 | static void
|
---|
557 | m4_ifelse (struct obstack *obs, int argc, token_data **argv)
|
---|
558 | {
|
---|
559 | const char *result;
|
---|
560 | token_data *argv0;
|
---|
561 |
|
---|
562 | if (argc == 2)
|
---|
563 | return;
|
---|
564 |
|
---|
565 | if (bad_argc (argv[0], argc, 4, -1))
|
---|
566 | return;
|
---|
567 | else
|
---|
568 | /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */
|
---|
569 | bad_argc (argv[0], (argc + 2) % 3, -1, 1);
|
---|
570 |
|
---|
571 | argv0 = argv[0];
|
---|
572 | argv++;
|
---|
573 | argc--;
|
---|
574 |
|
---|
575 | result = NULL;
|
---|
576 | while (result == NULL)
|
---|
577 |
|
---|
578 | if (strcmp (ARG (0), ARG (1)) == 0)
|
---|
579 | result = ARG (2);
|
---|
580 |
|
---|
581 | else
|
---|
582 | switch (argc)
|
---|
583 | {
|
---|
584 | case 3:
|
---|
585 | return;
|
---|
586 |
|
---|
587 | case 4:
|
---|
588 | case 5:
|
---|
589 | result = ARG (3);
|
---|
590 | break;
|
---|
591 |
|
---|
592 | default:
|
---|
593 | argc -= 3;
|
---|
594 | argv += 3;
|
---|
595 | }
|
---|
596 |
|
---|
597 | obstack_grow (obs, result, strlen (result));
|
---|
598 | }
|
---|
599 | |
---|
600 |
|
---|
601 | /*---------------------------------------------------------------------.
|
---|
602 | | The function dump_symbol () is for use by "dumpdef". It builds up a |
|
---|
603 | | table of all defined, un-shadowed, symbols. |
|
---|
604 | `---------------------------------------------------------------------*/
|
---|
605 |
|
---|
606 | /* The structure dump_symbol_data is used to pass the information needed
|
---|
607 | from call to call to dump_symbol. */
|
---|
608 |
|
---|
609 | struct dump_symbol_data
|
---|
610 | {
|
---|
611 | struct obstack *obs; /* obstack for table */
|
---|
612 | symbol **base; /* base of table */
|
---|
613 | int size; /* size of table */
|
---|
614 | };
|
---|
615 |
|
---|
616 | static void
|
---|
617 | dump_symbol (symbol *sym, void *arg)
|
---|
618 | {
|
---|
619 | struct dump_symbol_data *data = (struct dump_symbol_data *) arg;
|
---|
620 | if (!SYMBOL_SHADOWED (sym) && SYMBOL_TYPE (sym) != TOKEN_VOID)
|
---|
621 | {
|
---|
622 | obstack_blank (data->obs, sizeof (symbol *));
|
---|
623 | data->base = (symbol **) obstack_base (data->obs);
|
---|
624 | data->base[data->size++] = sym;
|
---|
625 | }
|
---|
626 | }
|
---|
627 |
|
---|
628 | /*------------------------------------------------------------------------.
|
---|
629 | | qsort comparison routine, for sorting the table made in m4_dumpdef (). |
|
---|
630 | `------------------------------------------------------------------------*/
|
---|
631 |
|
---|
632 | static int
|
---|
633 | dumpdef_cmp (const void *s1, const void *s2)
|
---|
634 | {
|
---|
635 | return strcmp (SYMBOL_NAME (* (symbol *const *) s1),
|
---|
636 | SYMBOL_NAME (* (symbol *const *) s2));
|
---|
637 | }
|
---|
638 |
|
---|
639 | /*-------------------------------------------------------------------------.
|
---|
640 | | Implementation of "dumpdef" itself. It builds up a table of pointers to |
|
---|
641 | | symbols, sorts it and prints the sorted table. |
|
---|
642 | `-------------------------------------------------------------------------*/
|
---|
643 |
|
---|
644 | static void
|
---|
645 | m4_dumpdef (struct obstack *obs, int argc, token_data **argv)
|
---|
646 | {
|
---|
647 | symbol *s;
|
---|
648 | int i;
|
---|
649 | struct dump_symbol_data data;
|
---|
650 | const builtin *bp;
|
---|
651 |
|
---|
652 | data.obs = obs;
|
---|
653 | data.base = (symbol **) obstack_base (obs);
|
---|
654 | data.size = 0;
|
---|
655 |
|
---|
656 | if (argc == 1)
|
---|
657 | {
|
---|
658 | hack_all_symbols (dump_symbol, &data);
|
---|
659 | }
|
---|
660 | else
|
---|
661 | {
|
---|
662 | for (i = 1; i < argc; i++)
|
---|
663 | {
|
---|
664 | s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP);
|
---|
665 | if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
|
---|
666 | dump_symbol (s, &data);
|
---|
667 | else
|
---|
668 | M4ERROR ((warning_status, 0,
|
---|
669 | "undefined macro `%s'", TOKEN_DATA_TEXT (argv[i])));
|
---|
670 | }
|
---|
671 | }
|
---|
672 |
|
---|
673 | /* Make table of symbols invisible to expand_macro (). */
|
---|
674 |
|
---|
675 | obstack_finish (obs);
|
---|
676 |
|
---|
677 | qsort (data.base, data.size, sizeof (symbol *), dumpdef_cmp);
|
---|
678 |
|
---|
679 | for (; data.size > 0; --data.size, data.base++)
|
---|
680 | {
|
---|
681 | DEBUG_PRINT1 ("%s:\t", SYMBOL_NAME (data.base[0]));
|
---|
682 |
|
---|
683 | switch (SYMBOL_TYPE (data.base[0]))
|
---|
684 | {
|
---|
685 | case TOKEN_TEXT:
|
---|
686 | if (debug_level & DEBUG_TRACE_QUOTE)
|
---|
687 | DEBUG_PRINT3 ("%s%s%s\n",
|
---|
688 | lquote.string, SYMBOL_TEXT (data.base[0]), rquote.string);
|
---|
689 | else
|
---|
690 | DEBUG_PRINT1 ("%s\n", SYMBOL_TEXT (data.base[0]));
|
---|
691 | break;
|
---|
692 |
|
---|
693 | case TOKEN_FUNC:
|
---|
694 | bp = find_builtin_by_addr (SYMBOL_FUNC (data.base[0]));
|
---|
695 | if (bp == NULL)
|
---|
696 | {
|
---|
697 | M4ERROR ((warning_status, 0, "\
|
---|
698 | INTERNAL ERROR: builtin not found in builtin table"));
|
---|
699 | abort ();
|
---|
700 | }
|
---|
701 | DEBUG_PRINT1 ("<%s>\n", bp->name);
|
---|
702 | break;
|
---|
703 |
|
---|
704 | default:
|
---|
705 | M4ERROR ((warning_status, 0,
|
---|
706 | "INTERNAL ERROR: bad token data type in m4_dumpdef ()"));
|
---|
707 | abort ();
|
---|
708 | break;
|
---|
709 | }
|
---|
710 | }
|
---|
711 | }
|
---|
712 |
|
---|
713 | /*---------------------------------------------------------------------.
|
---|
714 | | The builtin "builtin" allows calls to builtin macros, even if their |
|
---|
715 | | definition has been overridden or shadowed. It is thus possible to |
|
---|
716 | | redefine builtins, and still access their original definition. This |
|
---|
717 | | macro is not available in compatibility mode. |
|
---|
718 | `---------------------------------------------------------------------*/
|
---|
719 |
|
---|
720 | static void
|
---|
721 | m4_builtin (struct obstack *obs, int argc, token_data **argv)
|
---|
722 | {
|
---|
723 | const builtin *bp;
|
---|
724 | const char *name;
|
---|
725 |
|
---|
726 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
727 | return;
|
---|
728 | if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
|
---|
729 | {
|
---|
730 | M4ERROR ((warning_status, 0,
|
---|
731 | "Warning: %s: invalid macro name ignored", ARG (0)));
|
---|
732 | return;
|
---|
733 | }
|
---|
734 |
|
---|
735 | name = ARG (1);
|
---|
736 | bp = find_builtin_by_name (name);
|
---|
737 | if (bp->func == m4_placeholder)
|
---|
738 | M4ERROR ((warning_status, 0,
|
---|
739 | "undefined builtin `%s'", name));
|
---|
740 | else
|
---|
741 | {
|
---|
742 | int i;
|
---|
743 | if (! bp->groks_macro_args)
|
---|
744 | for (i = 2; i < argc; i++)
|
---|
745 | if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT)
|
---|
746 | {
|
---|
747 | TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT;
|
---|
748 | TOKEN_DATA_TEXT (argv[i]) = (char *) "";
|
---|
749 | }
|
---|
750 | bp->func (obs, argc - 1, argv + 1);
|
---|
751 | }
|
---|
752 | }
|
---|
753 |
|
---|
754 | /*------------------------------------------------------------------------.
|
---|
755 | | The builtin "indir" allows indirect calls to macros, even if their name |
|
---|
756 | | is not a proper macro name. It is thus possible to define macros with |
|
---|
757 | | ill-formed names for internal use in larger macro packages. This macro |
|
---|
758 | | is not available in compatibility mode. |
|
---|
759 | `------------------------------------------------------------------------*/
|
---|
760 |
|
---|
761 | static void
|
---|
762 | m4_indir (struct obstack *obs, int argc, token_data **argv)
|
---|
763 | {
|
---|
764 | symbol *s;
|
---|
765 | const char *name;
|
---|
766 |
|
---|
767 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
768 | return;
|
---|
769 | if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
|
---|
770 | {
|
---|
771 | M4ERROR ((warning_status, 0,
|
---|
772 | "Warning: %s: invalid macro name ignored", ARG (0)));
|
---|
773 | return;
|
---|
774 | }
|
---|
775 |
|
---|
776 | name = ARG (1);
|
---|
777 | s = lookup_symbol (name, SYMBOL_LOOKUP);
|
---|
778 | if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
|
---|
779 | M4ERROR ((warning_status, 0,
|
---|
780 | "undefined macro `%s'", name));
|
---|
781 | else
|
---|
782 | {
|
---|
783 | int i;
|
---|
784 | if (! SYMBOL_MACRO_ARGS (s))
|
---|
785 | for (i = 2; i < argc; i++)
|
---|
786 | if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT)
|
---|
787 | {
|
---|
788 | TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT;
|
---|
789 | TOKEN_DATA_TEXT (argv[i]) = (char *) "";
|
---|
790 | }
|
---|
791 | call_macro (s, argc - 1, argv + 1, obs);
|
---|
792 | }
|
---|
793 | }
|
---|
794 |
|
---|
795 | /*-------------------------------------------------------------------------.
|
---|
796 | | The macro "defn" returns the quoted definition of the macro named by the |
|
---|
797 | | first argument. If the macro is builtin, it will push a special |
|
---|
798 | | macro-definition token on the input stack. |
|
---|
799 | `-------------------------------------------------------------------------*/
|
---|
800 |
|
---|
801 | static void
|
---|
802 | m4_defn (struct obstack *obs, int argc, token_data **argv)
|
---|
803 | {
|
---|
804 | symbol *s;
|
---|
805 | builtin_func *b;
|
---|
806 |
|
---|
807 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
808 | return;
|
---|
809 |
|
---|
810 | s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
|
---|
811 | if (s == NULL)
|
---|
812 | return;
|
---|
813 |
|
---|
814 | switch (SYMBOL_TYPE (s))
|
---|
815 | {
|
---|
816 | case TOKEN_TEXT:
|
---|
817 | obstack_grow (obs, lquote.string, lquote.length);
|
---|
818 | obstack_grow (obs, SYMBOL_TEXT (s), strlen (SYMBOL_TEXT (s)));
|
---|
819 | obstack_grow (obs, rquote.string, rquote.length);
|
---|
820 | break;
|
---|
821 |
|
---|
822 | case TOKEN_FUNC:
|
---|
823 | b = SYMBOL_FUNC (s);
|
---|
824 | if (b == m4_placeholder)
|
---|
825 | M4ERROR ((warning_status, 0, "\
|
---|
826 | builtin `%s' requested by frozen file is not supported", ARG (1)));
|
---|
827 | else
|
---|
828 | push_macro (b);
|
---|
829 | break;
|
---|
830 |
|
---|
831 | case TOKEN_VOID:
|
---|
832 | break;
|
---|
833 |
|
---|
834 | default:
|
---|
835 | M4ERROR ((warning_status, 0,
|
---|
836 | "INTERNAL ERROR: bad symbol type in m4_defn ()"));
|
---|
837 | abort ();
|
---|
838 | }
|
---|
839 | }
|
---|
840 | |
---|
841 |
|
---|
842 | /*------------------------------------------------------------------------.
|
---|
843 | | This section contains macros to handle the builtins "syscmd", "esyscmd" |
|
---|
844 | | and "sysval". "esyscmd" is GNU specific. |
|
---|
845 | `------------------------------------------------------------------------*/
|
---|
846 |
|
---|
847 | /* Helper macros for readability. */
|
---|
848 | #if UNIX || defined WEXITSTATUS
|
---|
849 | # define M4SYSVAL_EXITBITS(status) \
|
---|
850 | (WIFEXITED (status) ? WEXITSTATUS (status) : 0)
|
---|
851 | # define M4SYSVAL_TERMSIGBITS(status) \
|
---|
852 | (WIFSIGNALED (status) ? WTERMSIG (status) << 8 : 0)
|
---|
853 |
|
---|
854 | #else /* ! UNIX && ! defined WEXITSTATUS */
|
---|
855 | /* Platforms such as mingw do not support the notion of reporting
|
---|
856 | which signal terminated a process. Furthermore if WEXITSTATUS was
|
---|
857 | not provided, then the exit value is in the low eight bits. */
|
---|
858 | # define M4SYSVAL_EXITBITS(status) status
|
---|
859 | # define M4SYSVAL_TERMSIGBITS(status) 0
|
---|
860 | #endif /* ! UNIX && ! defined WEXITSTATUS */
|
---|
861 |
|
---|
862 | /* Fallback definitions if <stdlib.h> or <sys/wait.h> are inadequate. */
|
---|
863 | #ifndef WEXITSTATUS
|
---|
864 | # define WEXITSTATUS(status) (((status) >> 8) & 0xff)
|
---|
865 | #endif
|
---|
866 | #ifndef WTERMSIG
|
---|
867 | # define WTERMSIG(status) ((status) & 0x7f)
|
---|
868 | #endif
|
---|
869 | #ifndef WIFSIGNALED
|
---|
870 | # define WIFSIGNALED(status) (WTERMSIG (status) != 0)
|
---|
871 | #endif
|
---|
872 | #ifndef WIFEXITED
|
---|
873 | # define WIFEXITED(status) (WTERMSIG (status) == 0)
|
---|
874 | #endif
|
---|
875 |
|
---|
876 | /* Exit code from last "syscmd" command. */
|
---|
877 | static int sysval;
|
---|
878 |
|
---|
879 | static void
|
---|
880 | m4_syscmd (struct obstack *obs, int argc, token_data **argv)
|
---|
881 | {
|
---|
882 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
883 | {
|
---|
884 | /* The empty command is successful. */
|
---|
885 | sysval = 0;
|
---|
886 | return;
|
---|
887 | }
|
---|
888 |
|
---|
889 | debug_flush_files ();
|
---|
890 | sysval = system (ARG (1));
|
---|
891 | #if FUNC_SYSTEM_BROKEN
|
---|
892 | /* OS/2 has a buggy system() that returns exit status in the lowest eight
|
---|
893 | bits, although pclose() and WEXITSTATUS are defined to return exit
|
---|
894 | status in the next eight bits. This approach can't detect signals, but
|
---|
895 | at least syscmd(`ls') still works when stdout is a terminal. An
|
---|
896 | alternate approach is popen/insert_file/pclose, but that makes stdout
|
---|
897 | a pipe, which can change how some child processes behave. */
|
---|
898 | if (sysval != -1)
|
---|
899 | sysval <<= 8;
|
---|
900 | #endif /* FUNC_SYSTEM_BROKEN */
|
---|
901 | }
|
---|
902 |
|
---|
903 | static void
|
---|
904 | m4_esyscmd (struct obstack *obs, int argc, token_data **argv)
|
---|
905 | {
|
---|
906 | FILE *pin;
|
---|
907 | int ch;
|
---|
908 |
|
---|
909 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
910 | {
|
---|
911 | /* The empty command is successful. */
|
---|
912 | sysval = 0;
|
---|
913 | return;
|
---|
914 | }
|
---|
915 |
|
---|
916 | debug_flush_files ();
|
---|
917 | errno = 0;
|
---|
918 | pin = popen (ARG (1), "r");
|
---|
919 | if (pin == NULL)
|
---|
920 | {
|
---|
921 | M4ERROR ((warning_status, errno,
|
---|
922 | "cannot open pipe to command `%s'", ARG (1)));
|
---|
923 | sysval = -1;
|
---|
924 | }
|
---|
925 | else
|
---|
926 | {
|
---|
927 | while ((ch = getc (pin)) != EOF)
|
---|
928 | obstack_1grow (obs, (char) ch);
|
---|
929 | sysval = pclose (pin);
|
---|
930 | }
|
---|
931 | }
|
---|
932 |
|
---|
933 | static void
|
---|
934 | m4_sysval (struct obstack *obs, int argc, token_data **argv)
|
---|
935 | {
|
---|
936 | shipout_int (obs, (sysval == -1 ? 127
|
---|
937 | : (M4SYSVAL_EXITBITS (sysval)
|
---|
938 | | M4SYSVAL_TERMSIGBITS (sysval))));
|
---|
939 | }
|
---|
940 | |
---|
941 |
|
---|
942 | /*-------------------------------------------------------------------------.
|
---|
943 | | This section contains the top level code for the "eval" builtin. The |
|
---|
944 | | actual work is done in the function evaluate (), which lives in eval.c. |
|
---|
945 | `-------------------------------------------------------------------------*/
|
---|
946 |
|
---|
947 | static void
|
---|
948 | m4_eval (struct obstack *obs, int argc, token_data **argv)
|
---|
949 | {
|
---|
950 | eval_t value = 0;
|
---|
951 | int radix = 10;
|
---|
952 | int min = 1;
|
---|
953 | const char *s;
|
---|
954 |
|
---|
955 | if (bad_argc (argv[0], argc, 2, 4))
|
---|
956 | return;
|
---|
957 |
|
---|
958 | if (*ARG (2) && !numeric_arg (argv[0], ARG (2), &radix))
|
---|
959 | return;
|
---|
960 |
|
---|
961 | if (radix < 1 || radix > (int) strlen (digits))
|
---|
962 | {
|
---|
963 | M4ERROR ((warning_status, 0,
|
---|
964 | "radix in builtin `%s' out of range (radix = %d)",
|
---|
965 | ARG (0), radix));
|
---|
966 | return;
|
---|
967 | }
|
---|
968 |
|
---|
969 | if (argc >= 4 && !numeric_arg (argv[0], ARG (3), &min))
|
---|
970 | return;
|
---|
971 | if (min < 0)
|
---|
972 | {
|
---|
973 | M4ERROR ((warning_status, 0,
|
---|
974 | "negative width to builtin `%s'", ARG (0)));
|
---|
975 | return;
|
---|
976 | }
|
---|
977 |
|
---|
978 | if (!*ARG (1))
|
---|
979 | M4ERROR ((warning_status, 0,
|
---|
980 | "empty string treated as 0 in builtin `%s'", ARG (0)));
|
---|
981 | else if (evaluate (ARG (1), &value))
|
---|
982 | return;
|
---|
983 |
|
---|
984 | if (radix == 1)
|
---|
985 | {
|
---|
986 | if (value < 0)
|
---|
987 | {
|
---|
988 | obstack_1grow (obs, '-');
|
---|
989 | value = -value;
|
---|
990 | }
|
---|
991 | /* This assumes 2's-complement for correctly handling INT_MIN. */
|
---|
992 | while (min-- - value > 0)
|
---|
993 | obstack_1grow (obs, '0');
|
---|
994 | while (value-- != 0)
|
---|
995 | obstack_1grow (obs, '1');
|
---|
996 | obstack_1grow (obs, '\0');
|
---|
997 | return;
|
---|
998 | }
|
---|
999 |
|
---|
1000 | s = ntoa (value, radix);
|
---|
1001 |
|
---|
1002 | if (*s == '-')
|
---|
1003 | {
|
---|
1004 | obstack_1grow (obs, '-');
|
---|
1005 | s++;
|
---|
1006 | }
|
---|
1007 | for (min -= strlen (s); --min >= 0;)
|
---|
1008 | obstack_1grow (obs, '0');
|
---|
1009 |
|
---|
1010 | obstack_grow (obs, s, strlen (s));
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | static void
|
---|
1014 | m4_incr (struct obstack *obs, int argc, token_data **argv)
|
---|
1015 | {
|
---|
1016 | int value;
|
---|
1017 |
|
---|
1018 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1019 | return;
|
---|
1020 |
|
---|
1021 | if (!numeric_arg (argv[0], ARG (1), &value))
|
---|
1022 | return;
|
---|
1023 |
|
---|
1024 | shipout_int (obs, value + 1);
|
---|
1025 | }
|
---|
1026 |
|
---|
1027 | static void
|
---|
1028 | m4_decr (struct obstack *obs, int argc, token_data **argv)
|
---|
1029 | {
|
---|
1030 | int value;
|
---|
1031 |
|
---|
1032 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1033 | return;
|
---|
1034 |
|
---|
1035 | if (!numeric_arg (argv[0], ARG (1), &value))
|
---|
1036 | return;
|
---|
1037 |
|
---|
1038 | shipout_int (obs, value - 1);
|
---|
1039 | }
|
---|
1040 | |
---|
1041 |
|
---|
1042 | /* This section contains the macros "divert", "undivert" and "divnum" for
|
---|
1043 | handling diversion. The utility functions used lives in output.c. */
|
---|
1044 |
|
---|
1045 | /*-----------------------------------------------------------------------.
|
---|
1046 | | Divert further output to the diversion given by ARGV[1]. Out of range |
|
---|
1047 | | means discard further output. |
|
---|
1048 | `-----------------------------------------------------------------------*/
|
---|
1049 |
|
---|
1050 | static void
|
---|
1051 | m4_divert (struct obstack *obs, int argc, token_data **argv)
|
---|
1052 | {
|
---|
1053 | int i = 0;
|
---|
1054 |
|
---|
1055 | if (bad_argc (argv[0], argc, 1, 2))
|
---|
1056 | return;
|
---|
1057 |
|
---|
1058 | if (argc >= 2 && !numeric_arg (argv[0], ARG (1), &i))
|
---|
1059 | return;
|
---|
1060 |
|
---|
1061 | make_diversion (i);
|
---|
1062 | }
|
---|
1063 |
|
---|
1064 | /*-----------------------------------------------------.
|
---|
1065 | | Expand to the current diversion number, -1 if none. |
|
---|
1066 | `-----------------------------------------------------*/
|
---|
1067 |
|
---|
1068 | static void
|
---|
1069 | m4_divnum (struct obstack *obs, int argc, token_data **argv)
|
---|
1070 | {
|
---|
1071 | if (bad_argc (argv[0], argc, 1, 1))
|
---|
1072 | return;
|
---|
1073 | shipout_int (obs, current_diversion);
|
---|
1074 | }
|
---|
1075 |
|
---|
1076 | /*-----------------------------------------------------------------------.
|
---|
1077 | | Bring back the diversion given by the argument list. If none is |
|
---|
1078 | | specified, bring back all diversions. GNU specific is the option of |
|
---|
1079 | | undiverting named files, by passing a non-numeric argument to undivert |
|
---|
1080 | | (). |
|
---|
1081 | `-----------------------------------------------------------------------*/
|
---|
1082 |
|
---|
1083 | static void
|
---|
1084 | m4_undivert (struct obstack *obs, int argc, token_data **argv)
|
---|
1085 | {
|
---|
1086 | int i, file;
|
---|
1087 | FILE *fp;
|
---|
1088 | char *endp;
|
---|
1089 |
|
---|
1090 | if (argc == 1)
|
---|
1091 | undivert_all ();
|
---|
1092 | else
|
---|
1093 | for (i = 1; i < argc; i++)
|
---|
1094 | {
|
---|
1095 | file = strtol (ARG (i), &endp, 10);
|
---|
1096 | if (*endp == '\0' && !isspace (to_uchar (*ARG (i))))
|
---|
1097 | insert_diversion (file);
|
---|
1098 | else if (no_gnu_extensions)
|
---|
1099 | M4ERROR ((warning_status, 0,
|
---|
1100 | "non-numeric argument to builtin `%s'", ARG (0)));
|
---|
1101 | else
|
---|
1102 | {
|
---|
1103 | fp = m4_path_search (ARG (i), NULL);
|
---|
1104 | if (fp != NULL)
|
---|
1105 | {
|
---|
1106 | insert_file (fp);
|
---|
1107 | if (fclose (fp) == EOF)
|
---|
1108 | M4ERROR ((warning_status, errno,
|
---|
1109 | "error undiverting `%s'", ARG (i)));
|
---|
1110 | }
|
---|
1111 | else
|
---|
1112 | M4ERROR ((warning_status, errno,
|
---|
1113 | "cannot undivert `%s'", ARG (i)));
|
---|
1114 | }
|
---|
1115 | }
|
---|
1116 | }
|
---|
1117 | |
---|
1118 |
|
---|
1119 | /* This section contains various macros, which does not fall into any
|
---|
1120 | specific group. These are "dnl", "shift", "changequote", "changecom"
|
---|
1121 | and "changeword". */
|
---|
1122 |
|
---|
1123 | /*------------------------------------------------------------------------.
|
---|
1124 | | Delete all subsequent whitespace from input. The function skip_line () |
|
---|
1125 | | lives in input.c. |
|
---|
1126 | `------------------------------------------------------------------------*/
|
---|
1127 |
|
---|
1128 | static void
|
---|
1129 | m4_dnl (struct obstack *obs, int argc, token_data **argv)
|
---|
1130 | {
|
---|
1131 | if (bad_argc (argv[0], argc, 1, 1))
|
---|
1132 | return;
|
---|
1133 |
|
---|
1134 | skip_line ();
|
---|
1135 | }
|
---|
1136 |
|
---|
1137 | /*-------------------------------------------------------------------------.
|
---|
1138 | | Shift all argument one to the left, discarding the first argument. Each |
|
---|
1139 | | output argument is quoted with the current quotes. |
|
---|
1140 | `-------------------------------------------------------------------------*/
|
---|
1141 |
|
---|
1142 | static void
|
---|
1143 | m4_shift (struct obstack *obs, int argc, token_data **argv)
|
---|
1144 | {
|
---|
1145 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
1146 | return;
|
---|
1147 | dump_args (obs, argc - 1, argv + 1, ",", true);
|
---|
1148 | }
|
---|
1149 |
|
---|
1150 | /*--------------------------------------------------------------------------.
|
---|
1151 | | Change the current quotes. The function set_quotes () lives in input.c. |
|
---|
1152 | `--------------------------------------------------------------------------*/
|
---|
1153 |
|
---|
1154 | static void
|
---|
1155 | m4_changequote (struct obstack *obs, int argc, token_data **argv)
|
---|
1156 | {
|
---|
1157 | if (bad_argc (argv[0], argc, 1, 3))
|
---|
1158 | return;
|
---|
1159 |
|
---|
1160 | /* Explicit NULL distinguishes between empty and missing argument. */
|
---|
1161 | set_quotes ((argc >= 2) ? TOKEN_DATA_TEXT (argv[1]) : NULL,
|
---|
1162 | (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL);
|
---|
1163 | }
|
---|
1164 |
|
---|
1165 | /*--------------------------------------------------------------------.
|
---|
1166 | | Change the current comment delimiters. The function set_comment () |
|
---|
1167 | | lives in input.c. |
|
---|
1168 | `--------------------------------------------------------------------*/
|
---|
1169 |
|
---|
1170 | static void
|
---|
1171 | m4_changecom (struct obstack *obs, int argc, token_data **argv)
|
---|
1172 | {
|
---|
1173 | if (bad_argc (argv[0], argc, 1, 3))
|
---|
1174 | return;
|
---|
1175 |
|
---|
1176 | /* Explicit NULL distinguishes between empty and missing argument. */
|
---|
1177 | set_comment ((argc >= 2) ? TOKEN_DATA_TEXT (argv[1]) : NULL,
|
---|
1178 | (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL);
|
---|
1179 | }
|
---|
1180 |
|
---|
1181 | #ifdef ENABLE_CHANGEWORD
|
---|
1182 |
|
---|
1183 | /*-----------------------------------------------------------------------.
|
---|
1184 | | Change the regular expression used for breaking the input into words. |
|
---|
1185 | | The function set_word_regexp () lives in input.c. |
|
---|
1186 | `-----------------------------------------------------------------------*/
|
---|
1187 |
|
---|
1188 | static void
|
---|
1189 | m4_changeword (struct obstack *obs, int argc, token_data **argv)
|
---|
1190 | {
|
---|
1191 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1192 | return;
|
---|
1193 |
|
---|
1194 | set_word_regexp (TOKEN_DATA_TEXT (argv[1]));
|
---|
1195 | }
|
---|
1196 |
|
---|
1197 | #endif /* ENABLE_CHANGEWORD */
|
---|
1198 | |
---|
1199 |
|
---|
1200 | /* This section contains macros for inclusion of other files -- "include"
|
---|
1201 | and "sinclude". This differs from bringing back diversions, in that
|
---|
1202 | the input is scanned before being copied to the output. */
|
---|
1203 |
|
---|
1204 | /*-------------------------------------------------------------------------.
|
---|
1205 | | Generic include function. Include the file given by the first argument, |
|
---|
1206 | | if it exists. Complain about inaccesible files iff SILENT is false. |
|
---|
1207 | `-------------------------------------------------------------------------*/
|
---|
1208 |
|
---|
1209 | static void
|
---|
1210 | include (int argc, token_data **argv, bool silent)
|
---|
1211 | {
|
---|
1212 | FILE *fp;
|
---|
1213 | char *name;
|
---|
1214 |
|
---|
1215 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1216 | return;
|
---|
1217 |
|
---|
1218 | fp = m4_path_search (ARG (1), &name);
|
---|
1219 | if (fp == NULL)
|
---|
1220 | {
|
---|
1221 | if (!silent)
|
---|
1222 | M4ERROR ((warning_status, errno,
|
---|
1223 | "cannot open `%s'", ARG (1)));
|
---|
1224 | return;
|
---|
1225 | }
|
---|
1226 |
|
---|
1227 | push_file (fp, name, true);
|
---|
1228 | free (name);
|
---|
1229 | }
|
---|
1230 |
|
---|
1231 | /*------------------------------------------------.
|
---|
1232 | | Include a file, complaining in case of errors. |
|
---|
1233 | `------------------------------------------------*/
|
---|
1234 |
|
---|
1235 | static void
|
---|
1236 | m4_include (struct obstack *obs, int argc, token_data **argv)
|
---|
1237 | {
|
---|
1238 | include (argc, argv, false);
|
---|
1239 | }
|
---|
1240 |
|
---|
1241 | /*----------------------------------.
|
---|
1242 | | Include a file, ignoring errors. |
|
---|
1243 | `----------------------------------*/
|
---|
1244 |
|
---|
1245 | static void
|
---|
1246 | m4_sinclude (struct obstack *obs, int argc, token_data **argv)
|
---|
1247 | {
|
---|
1248 | include (argc, argv, true);
|
---|
1249 | }
|
---|
1250 | |
---|
1251 |
|
---|
1252 | /* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
|
---|
1253 | "__line__", and "__program__". The last three are GNU specific. */
|
---|
1254 |
|
---|
1255 | /*------------------------------------------------------------------.
|
---|
1256 | | Use the first argument as at template for a temporary file name. |
|
---|
1257 | `------------------------------------------------------------------*/
|
---|
1258 |
|
---|
1259 | /* Add trailing 'X' to NAME if necessary, securely create the file,
|
---|
1260 | and place the new file name on OBS. */
|
---|
1261 | static void
|
---|
1262 | mkstemp_helper (struct obstack *obs, const char *name)
|
---|
1263 | {
|
---|
1264 | int fd;
|
---|
1265 | int len;
|
---|
1266 | int i;
|
---|
1267 |
|
---|
1268 | /* Guarantee that there are six trailing 'X' characters, even if the
|
---|
1269 | user forgot to supply them. */
|
---|
1270 | len = strlen (name);
|
---|
1271 | obstack_grow (obs, name, len);
|
---|
1272 | for (i = 0; len > 0 && i < 6; i++)
|
---|
1273 | if (name[--len] != 'X')
|
---|
1274 | break;
|
---|
1275 | for (; i < 6; i++)
|
---|
1276 | obstack_1grow (obs, 'X');
|
---|
1277 | obstack_1grow (obs, '\0');
|
---|
1278 |
|
---|
1279 | errno = 0;
|
---|
1280 | fd = mkstemp ((char *) obstack_base (obs));
|
---|
1281 | if (fd < 0)
|
---|
1282 | {
|
---|
1283 | M4ERROR ((0, errno, "cannot create tempfile `%s'", name));
|
---|
1284 | obstack_free (obs, obstack_finish (obs));
|
---|
1285 | }
|
---|
1286 | else
|
---|
1287 | close (fd);
|
---|
1288 | }
|
---|
1289 |
|
---|
1290 | static void
|
---|
1291 | m4_maketemp (struct obstack *obs, int argc, token_data **argv)
|
---|
1292 | {
|
---|
1293 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1294 | return;
|
---|
1295 | if (no_gnu_extensions)
|
---|
1296 | {
|
---|
1297 | /* POSIX states "any trailing 'X' characters [are] replaced with
|
---|
1298 | the current process ID as a string", without referencing the
|
---|
1299 | file system. Horribly insecure, but we have to do it when we
|
---|
1300 | are in traditional mode.
|
---|
1301 |
|
---|
1302 | For reference, Solaris m4 does:
|
---|
1303 | maketemp() -> `'
|
---|
1304 | maketemp(X) -> `X'
|
---|
1305 | maketemp(XX) -> `Xn', where n is last digit of pid
|
---|
1306 | maketemp(XXXXXXXX) -> `X00nnnnn', where nnnnn is 16-bit pid
|
---|
1307 | */
|
---|
1308 | const char *str = ARG (1);
|
---|
1309 | int len = strlen (str);
|
---|
1310 | int i;
|
---|
1311 | int len2;
|
---|
1312 |
|
---|
1313 | M4ERROR ((warning_status, 0, "recommend using mkstemp instead"));
|
---|
1314 | for (i = len; i > 1; i--)
|
---|
1315 | if (str[i - 1] != 'X')
|
---|
1316 | break;
|
---|
1317 | obstack_grow (obs, str, i);
|
---|
1318 | str = ntoa ((eval_t) getpid (), 10);
|
---|
1319 | len2 = strlen (str);
|
---|
1320 | if (len2 > len - i)
|
---|
1321 | obstack_grow0 (obs, str + len2 - (len - i), len - i);
|
---|
1322 | else
|
---|
1323 | {
|
---|
1324 | while (i++ < len - len2)
|
---|
1325 | obstack_1grow (obs, '0');
|
---|
1326 | obstack_grow0 (obs, str, len2);
|
---|
1327 | }
|
---|
1328 | }
|
---|
1329 | else
|
---|
1330 | mkstemp_helper (obs, ARG (1));
|
---|
1331 | }
|
---|
1332 |
|
---|
1333 | static void
|
---|
1334 | m4_mkstemp (struct obstack *obs, int argc, token_data **argv)
|
---|
1335 | {
|
---|
1336 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1337 | return;
|
---|
1338 | mkstemp_helper (obs, ARG (1));
|
---|
1339 | }
|
---|
1340 |
|
---|
1341 | /*----------------------------------------.
|
---|
1342 | | Print all arguments on standard error. |
|
---|
1343 | `----------------------------------------*/
|
---|
1344 |
|
---|
1345 | static void
|
---|
1346 | m4_errprint (struct obstack *obs, int argc, token_data **argv)
|
---|
1347 | {
|
---|
1348 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
1349 | return;
|
---|
1350 | dump_args (obs, argc, argv, " ", false);
|
---|
1351 | obstack_1grow (obs, '\0');
|
---|
1352 | debug_flush_files ();
|
---|
1353 | fprintf (stderr, "%s", (char *) obstack_finish (obs));
|
---|
1354 | fflush (stderr);
|
---|
1355 | }
|
---|
1356 |
|
---|
1357 | static void
|
---|
1358 | m4___file__ (struct obstack *obs, int argc, token_data **argv)
|
---|
1359 | {
|
---|
1360 | if (bad_argc (argv[0], argc, 1, 1))
|
---|
1361 | return;
|
---|
1362 | obstack_grow (obs, lquote.string, lquote.length);
|
---|
1363 | obstack_grow (obs, current_file, strlen (current_file));
|
---|
1364 | obstack_grow (obs, rquote.string, rquote.length);
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | static void
|
---|
1368 | m4___line__ (struct obstack *obs, int argc, token_data **argv)
|
---|
1369 | {
|
---|
1370 | if (bad_argc (argv[0], argc, 1, 1))
|
---|
1371 | return;
|
---|
1372 | shipout_int (obs, current_line);
|
---|
1373 | }
|
---|
1374 |
|
---|
1375 | static void
|
---|
1376 | m4___program__ (struct obstack *obs, int argc, token_data **argv)
|
---|
1377 | {
|
---|
1378 | if (bad_argc (argv[0], argc, 1, 1))
|
---|
1379 | return;
|
---|
1380 | obstack_grow (obs, lquote.string, lquote.length);
|
---|
1381 | obstack_grow (obs, program_name, strlen (program_name));
|
---|
1382 | obstack_grow (obs, rquote.string, rquote.length);
|
---|
1383 | }
|
---|
1384 | |
---|
1385 |
|
---|
1386 | /* This section contains various macros for exiting, saving input until
|
---|
1387 | EOF is seen, and tracing macro calls. That is: "m4exit", "m4wrap",
|
---|
1388 | "traceon" and "traceoff". */
|
---|
1389 |
|
---|
1390 | /*-------------------------------------------------------------------------.
|
---|
1391 | | Exit immediately, with exitcode specified by the first argument, 0 if no |
|
---|
1392 | | arguments are present. |
|
---|
1393 | `-------------------------------------------------------------------------*/
|
---|
1394 |
|
---|
1395 | static void
|
---|
1396 | m4_m4exit (struct obstack *obs, int argc, token_data **argv)
|
---|
1397 | {
|
---|
1398 | int exit_code = EXIT_SUCCESS;
|
---|
1399 |
|
---|
1400 | /* Warn on bad arguments, but still exit. */
|
---|
1401 | bad_argc (argv[0], argc, 1, 2);
|
---|
1402 | if (argc >= 2 && !numeric_arg (argv[0], ARG (1), &exit_code))
|
---|
1403 | exit_code = EXIT_FAILURE;
|
---|
1404 | if (exit_code < 0 || exit_code > 255)
|
---|
1405 | {
|
---|
1406 | M4ERROR ((warning_status, 0,
|
---|
1407 | "exit status out of range: `%d'", exit_code));
|
---|
1408 | exit_code = EXIT_FAILURE;
|
---|
1409 | }
|
---|
1410 | /* Change debug stream back to stderr, to force flushing debug stream and
|
---|
1411 | detect any errors it might have encountered. */
|
---|
1412 | debug_set_output (NULL);
|
---|
1413 | debug_flush_files ();
|
---|
1414 | if (exit_code == EXIT_SUCCESS && retcode != EXIT_SUCCESS)
|
---|
1415 | exit_code = retcode;
|
---|
1416 | /* Propagate non-zero status to atexit handlers. */
|
---|
1417 | if (exit_code != EXIT_SUCCESS)
|
---|
1418 | exit_failure = exit_code;
|
---|
1419 | exit (exit_code);
|
---|
1420 | }
|
---|
1421 |
|
---|
1422 | /*-------------------------------------------------------------------------.
|
---|
1423 | | Save the argument text until EOF has been seen, allowing for user |
|
---|
1424 | | specified cleanup action. GNU version saves all arguments, the standard |
|
---|
1425 | | version only the first. |
|
---|
1426 | `-------------------------------------------------------------------------*/
|
---|
1427 |
|
---|
1428 | static void
|
---|
1429 | m4_m4wrap (struct obstack *obs, int argc, token_data **argv)
|
---|
1430 | {
|
---|
1431 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
1432 | return;
|
---|
1433 | if (no_gnu_extensions)
|
---|
1434 | obstack_grow (obs, ARG (1), strlen (ARG (1)));
|
---|
1435 | else
|
---|
1436 | dump_args (obs, argc, argv, " ", false);
|
---|
1437 | obstack_1grow (obs, '\0');
|
---|
1438 | push_wrapup ((char *) obstack_finish (obs));
|
---|
1439 | }
|
---|
1440 | |
---|
1441 |
|
---|
1442 | /* Enable tracing of all specified macros, or all, if none is specified.
|
---|
1443 | Tracing is disabled by default, when a macro is defined. This can be
|
---|
1444 | overridden by the "t" debug flag. */
|
---|
1445 |
|
---|
1446 | /*-----------------------------------------------------------------------.
|
---|
1447 | | Set_trace () is used by "traceon" and "traceoff" to enable and disable |
|
---|
1448 | | tracing of a macro. It disables tracing if DATA is NULL, otherwise it |
|
---|
1449 | | enable tracing. |
|
---|
1450 | `-----------------------------------------------------------------------*/
|
---|
1451 |
|
---|
1452 | static void
|
---|
1453 | set_trace (symbol *sym, void *data)
|
---|
1454 | {
|
---|
1455 | SYMBOL_TRACED (sym) = data != NULL;
|
---|
1456 | /* Remove placeholder from table if macro is undefined and untraced. */
|
---|
1457 | if (SYMBOL_TYPE (sym) == TOKEN_VOID && data == NULL)
|
---|
1458 | lookup_symbol (SYMBOL_NAME (sym), SYMBOL_POPDEF);
|
---|
1459 | }
|
---|
1460 |
|
---|
1461 | static void
|
---|
1462 | m4_traceon (struct obstack *obs, int argc, token_data **argv)
|
---|
1463 | {
|
---|
1464 | symbol *s;
|
---|
1465 | int i;
|
---|
1466 |
|
---|
1467 | if (argc == 1)
|
---|
1468 | hack_all_symbols (set_trace, obs);
|
---|
1469 | else
|
---|
1470 | for (i = 1; i < argc; i++)
|
---|
1471 | {
|
---|
1472 | s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_INSERT);
|
---|
1473 | set_trace (s, obs);
|
---|
1474 | }
|
---|
1475 | }
|
---|
1476 |
|
---|
1477 | /*------------------------------------------------------------------------.
|
---|
1478 | | Disable tracing of all specified macros, or all, if none is specified. |
|
---|
1479 | `------------------------------------------------------------------------*/
|
---|
1480 |
|
---|
1481 | static void
|
---|
1482 | m4_traceoff (struct obstack *obs, int argc, token_data **argv)
|
---|
1483 | {
|
---|
1484 | symbol *s;
|
---|
1485 | int i;
|
---|
1486 |
|
---|
1487 | if (argc == 1)
|
---|
1488 | hack_all_symbols (set_trace, NULL);
|
---|
1489 | else
|
---|
1490 | for (i = 1; i < argc; i++)
|
---|
1491 | {
|
---|
1492 | s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP);
|
---|
1493 | if (s != NULL)
|
---|
1494 | set_trace (s, NULL);
|
---|
1495 | }
|
---|
1496 | }
|
---|
1497 |
|
---|
1498 | /*----------------------------------------------------------------------.
|
---|
1499 | | On-the-fly control of the format of the tracing output. It takes one |
|
---|
1500 | | argument, which is a character string like given to the -d option, or |
|
---|
1501 | | none in which case the debug_level is zeroed. |
|
---|
1502 | `----------------------------------------------------------------------*/
|
---|
1503 |
|
---|
1504 | static void
|
---|
1505 | m4_debugmode (struct obstack *obs, int argc, token_data **argv)
|
---|
1506 | {
|
---|
1507 | int new_debug_level;
|
---|
1508 | int change_flag;
|
---|
1509 |
|
---|
1510 | if (bad_argc (argv[0], argc, 1, 2))
|
---|
1511 | return;
|
---|
1512 |
|
---|
1513 | if (argc == 1)
|
---|
1514 | debug_level = 0;
|
---|
1515 | else
|
---|
1516 | {
|
---|
1517 | if (ARG (1)[0] == '+' || ARG (1)[0] == '-')
|
---|
1518 | {
|
---|
1519 | change_flag = ARG (1)[0];
|
---|
1520 | new_debug_level = debug_decode (ARG (1) + 1);
|
---|
1521 | }
|
---|
1522 | else
|
---|
1523 | {
|
---|
1524 | change_flag = 0;
|
---|
1525 | new_debug_level = debug_decode (ARG (1));
|
---|
1526 | }
|
---|
1527 |
|
---|
1528 | if (new_debug_level < 0)
|
---|
1529 | M4ERROR ((warning_status, 0,
|
---|
1530 | "Debugmode: bad debug flags: `%s'", ARG (1)));
|
---|
1531 | else
|
---|
1532 | {
|
---|
1533 | switch (change_flag)
|
---|
1534 | {
|
---|
1535 | case 0:
|
---|
1536 | debug_level = new_debug_level;
|
---|
1537 | break;
|
---|
1538 |
|
---|
1539 | case '+':
|
---|
1540 | debug_level |= new_debug_level;
|
---|
1541 | break;
|
---|
1542 |
|
---|
1543 | case '-':
|
---|
1544 | debug_level &= ~new_debug_level;
|
---|
1545 | break;
|
---|
1546 | }
|
---|
1547 | }
|
---|
1548 | }
|
---|
1549 | }
|
---|
1550 |
|
---|
1551 | /*-------------------------------------------------------------------------.
|
---|
1552 | | Specify the destination of the debugging output. With one argument, the |
|
---|
1553 | | argument is taken as a file name, with no arguments, revert to stderr. |
|
---|
1554 | `-------------------------------------------------------------------------*/
|
---|
1555 |
|
---|
1556 | static void
|
---|
1557 | m4_debugfile (struct obstack *obs, int argc, token_data **argv)
|
---|
1558 | {
|
---|
1559 | if (bad_argc (argv[0], argc, 1, 2))
|
---|
1560 | return;
|
---|
1561 |
|
---|
1562 | if (argc == 1)
|
---|
1563 | debug_set_output (NULL);
|
---|
1564 | else if (!debug_set_output (ARG (1)))
|
---|
1565 | M4ERROR ((warning_status, errno,
|
---|
1566 | "cannot set error file: `%s'", ARG (1)));
|
---|
1567 | }
|
---|
1568 | |
---|
1569 |
|
---|
1570 | /* This section contains text processing macros: "len", "index",
|
---|
1571 | "substr", "translit", "format", "regexp" and "patsubst". The last
|
---|
1572 | three are GNU specific. */
|
---|
1573 |
|
---|
1574 | /*---------------------------------------------.
|
---|
1575 | | Expand to the length of the first argument. |
|
---|
1576 | `---------------------------------------------*/
|
---|
1577 |
|
---|
1578 | static void
|
---|
1579 | m4_len (struct obstack *obs, int argc, token_data **argv)
|
---|
1580 | {
|
---|
1581 | if (bad_argc (argv[0], argc, 2, 2))
|
---|
1582 | return;
|
---|
1583 | shipout_int (obs, strlen (ARG (1)));
|
---|
1584 | }
|
---|
1585 |
|
---|
1586 | /*-------------------------------------------------------------------------.
|
---|
1587 | | The macro expands to the first index of the second argument in the first |
|
---|
1588 | | argument. |
|
---|
1589 | `-------------------------------------------------------------------------*/
|
---|
1590 |
|
---|
1591 | static void
|
---|
1592 | m4_index (struct obstack *obs, int argc, token_data **argv)
|
---|
1593 | {
|
---|
1594 | const char *haystack;
|
---|
1595 | const char *result;
|
---|
1596 | int retval;
|
---|
1597 |
|
---|
1598 | if (bad_argc (argv[0], argc, 3, 3))
|
---|
1599 | {
|
---|
1600 | /* builtin(`index') is blank, but index(`abc') is 0. */
|
---|
1601 | if (argc == 2)
|
---|
1602 | shipout_int (obs, 0);
|
---|
1603 | return;
|
---|
1604 | }
|
---|
1605 |
|
---|
1606 | haystack = ARG (1);
|
---|
1607 | result = strstr (haystack, ARG (2));
|
---|
1608 | retval = result ? result - haystack : -1;
|
---|
1609 |
|
---|
1610 | shipout_int (obs, retval);
|
---|
1611 | }
|
---|
1612 |
|
---|
1613 | /*-------------------------------------------------------------------------.
|
---|
1614 | | The macro "substr" extracts substrings from the first argument, starting |
|
---|
1615 | | from the index given by the second argument, extending for a length |
|
---|
1616 | | given by the third argument. If the third argument is missing, the |
|
---|
1617 | | substring extends to the end of the first argument. |
|
---|
1618 | `-------------------------------------------------------------------------*/
|
---|
1619 |
|
---|
1620 | static void
|
---|
1621 | m4_substr (struct obstack *obs, int argc, token_data **argv)
|
---|
1622 | {
|
---|
1623 | int start = 0;
|
---|
1624 | int length, avail;
|
---|
1625 |
|
---|
1626 | if (bad_argc (argv[0], argc, 3, 4))
|
---|
1627 | {
|
---|
1628 | /* builtin(`substr') is blank, but substr(`abc') is abc. */
|
---|
1629 | if (argc == 2)
|
---|
1630 | obstack_grow (obs, ARG (1), strlen (ARG (1)));
|
---|
1631 | return;
|
---|
1632 | }
|
---|
1633 |
|
---|
1634 | length = avail = strlen (ARG (1));
|
---|
1635 | if (!numeric_arg (argv[0], ARG (2), &start))
|
---|
1636 | return;
|
---|
1637 |
|
---|
1638 | if (argc >= 4 && !numeric_arg (argv[0], ARG (3), &length))
|
---|
1639 | return;
|
---|
1640 |
|
---|
1641 | if (start < 0 || length <= 0 || start >= avail)
|
---|
1642 | return;
|
---|
1643 |
|
---|
1644 | if (start + length > avail)
|
---|
1645 | length = avail - start;
|
---|
1646 | obstack_grow (obs, ARG (1) + start, length);
|
---|
1647 | }
|
---|
1648 |
|
---|
1649 | /*------------------------------------------------------------------------.
|
---|
1650 | | For "translit", ranges are allowed in the second and third argument. |
|
---|
1651 | | They are expanded in the following function, and the expanded strings, |
|
---|
1652 | | without any ranges left, are used to translate the characters of the |
|
---|
1653 | | first argument. A single - (dash) can be included in the strings by |
|
---|
1654 | | being the first or the last character in the string. If the first |
|
---|
1655 | | character in a range is after the first in the character set, the range |
|
---|
1656 | | is made backwards, thus 9-0 is the string 9876543210. |
|
---|
1657 | `------------------------------------------------------------------------*/
|
---|
1658 |
|
---|
1659 | static const char *
|
---|
1660 | expand_ranges (const char *s, struct obstack *obs)
|
---|
1661 | {
|
---|
1662 | unsigned char from;
|
---|
1663 | unsigned char to;
|
---|
1664 |
|
---|
1665 | for (from = '\0'; *s != '\0'; from = to_uchar (*s++))
|
---|
1666 | {
|
---|
1667 | if (*s == '-' && from != '\0')
|
---|
1668 | {
|
---|
1669 | to = to_uchar (*++s);
|
---|
1670 | if (to == '\0')
|
---|
1671 | {
|
---|
1672 | /* trailing dash */
|
---|
1673 | obstack_1grow (obs, '-');
|
---|
1674 | break;
|
---|
1675 | }
|
---|
1676 | else if (from <= to)
|
---|
1677 | {
|
---|
1678 | while (from++ < to)
|
---|
1679 | obstack_1grow (obs, from);
|
---|
1680 | }
|
---|
1681 | else
|
---|
1682 | {
|
---|
1683 | while (--from >= to)
|
---|
1684 | obstack_1grow (obs, from);
|
---|
1685 | }
|
---|
1686 | }
|
---|
1687 | else
|
---|
1688 | obstack_1grow (obs, *s);
|
---|
1689 | }
|
---|
1690 | obstack_1grow (obs, '\0');
|
---|
1691 | return (char *) obstack_finish (obs);
|
---|
1692 | }
|
---|
1693 |
|
---|
1694 | /*----------------------------------------------------------------------.
|
---|
1695 | | The macro "translit" translates all characters in the first argument, |
|
---|
1696 | | which are present in the second argument, into the corresponding |
|
---|
1697 | | character from the third argument. If the third argument is shorter |
|
---|
1698 | | than the second, the extra characters in the second argument, are |
|
---|
1699 | | deleted from the first (pueh). |
|
---|
1700 | `----------------------------------------------------------------------*/
|
---|
1701 |
|
---|
1702 | static void
|
---|
1703 | m4_translit (struct obstack *obs, int argc, token_data **argv)
|
---|
1704 | {
|
---|
1705 | const char *data;
|
---|
1706 | const char *from;
|
---|
1707 | const char *to;
|
---|
1708 | char map[256] = {0};
|
---|
1709 | char found[256] = {0};
|
---|
1710 | unsigned char ch;
|
---|
1711 |
|
---|
1712 | if (bad_argc (argv[0], argc, 3, 4))
|
---|
1713 | {
|
---|
1714 | /* builtin(`translit') is blank, but translit(`abc') is abc. */
|
---|
1715 | if (argc == 2)
|
---|
1716 | obstack_grow (obs, ARG (1), strlen (ARG (1)));
|
---|
1717 | return;
|
---|
1718 | }
|
---|
1719 |
|
---|
1720 | from = ARG (2);
|
---|
1721 | if (strchr (from, '-') != NULL)
|
---|
1722 | {
|
---|
1723 | from = expand_ranges (from, obs);
|
---|
1724 | if (from == NULL)
|
---|
1725 | return;
|
---|
1726 | }
|
---|
1727 |
|
---|
1728 | to = ARG (3);
|
---|
1729 | if (strchr (to, '-') != NULL)
|
---|
1730 | {
|
---|
1731 | to = expand_ranges (to, obs);
|
---|
1732 | if (to == NULL)
|
---|
1733 | return;
|
---|
1734 | }
|
---|
1735 |
|
---|
1736 | /* Calling strchr(from) for each character in data is quadratic,
|
---|
1737 | since both strings can be arbitrarily long. Instead, create a
|
---|
1738 | from-to mapping in one pass of from, then use that map in one
|
---|
1739 | pass of data, for linear behavior. Traditional behavior is that
|
---|
1740 | only the first instance of a character in from is consulted,
|
---|
1741 | hence the found map. */
|
---|
1742 | for ( ; (ch = *from) != '\0'; from++)
|
---|
1743 | {
|
---|
1744 | if (! found[ch])
|
---|
1745 | {
|
---|
1746 | found[ch] = 1;
|
---|
1747 | map[ch] = *to;
|
---|
1748 | }
|
---|
1749 | if (*to != '\0')
|
---|
1750 | to++;
|
---|
1751 | }
|
---|
1752 |
|
---|
1753 | for (data = ARG (1); (ch = *data) != '\0'; data++)
|
---|
1754 | {
|
---|
1755 | if (! found[ch])
|
---|
1756 | obstack_1grow (obs, ch);
|
---|
1757 | else if (map[ch])
|
---|
1758 | obstack_1grow (obs, map[ch]);
|
---|
1759 | }
|
---|
1760 | }
|
---|
1761 |
|
---|
1762 | /*----------------------------------------------------------------------.
|
---|
1763 | | Frontend for printf like formatting. The function format () lives in |
|
---|
1764 | | the file format.c. |
|
---|
1765 | `----------------------------------------------------------------------*/
|
---|
1766 |
|
---|
1767 | static void
|
---|
1768 | m4_format (struct obstack *obs, int argc, token_data **argv)
|
---|
1769 | {
|
---|
1770 | if (bad_argc (argv[0], argc, 2, -1))
|
---|
1771 | return;
|
---|
1772 | format (obs, argc - 1, argv + 1);
|
---|
1773 | }
|
---|
1774 |
|
---|
1775 | /*-------------------------------------------------------------------------.
|
---|
1776 | | Function to perform substitution by regular expressions. Used by the |
|
---|
1777 | | builtins regexp and patsubst. The changed text is placed on the |
|
---|
1778 | | obstack. The substitution is REPL, with \& substituted by this part of |
|
---|
1779 | | VICTIM matched by the last whole regular expression, taken from REGS[0], |
|
---|
1780 | | and \N substituted by the text matched by the Nth parenthesized |
|
---|
1781 | | sub-expression, taken from REGS[N]. |
|
---|
1782 | `-------------------------------------------------------------------------*/
|
---|
1783 |
|
---|
1784 | static int substitute_warned = 0;
|
---|
1785 |
|
---|
1786 | static void
|
---|
1787 | substitute (struct obstack *obs, const char *victim, const char *repl,
|
---|
1788 | struct re_registers *regs)
|
---|
1789 | {
|
---|
1790 | int ch;
|
---|
1791 |
|
---|
1792 | for (;;)
|
---|
1793 | {
|
---|
1794 | while ((ch = *repl++) != '\\')
|
---|
1795 | {
|
---|
1796 | if (ch == '\0')
|
---|
1797 | return;
|
---|
1798 | obstack_1grow (obs, ch);
|
---|
1799 | }
|
---|
1800 |
|
---|
1801 | switch ((ch = *repl++))
|
---|
1802 | {
|
---|
1803 | case '0':
|
---|
1804 | if (!substitute_warned)
|
---|
1805 | {
|
---|
1806 | M4ERROR ((warning_status, 0, "\
|
---|
1807 | Warning: \\0 will disappear, use \\& instead in replacements"));
|
---|
1808 | substitute_warned = 1;
|
---|
1809 | }
|
---|
1810 | /* Fall through. */
|
---|
1811 |
|
---|
1812 | case '&':
|
---|
1813 | obstack_grow (obs, victim + regs->start[0],
|
---|
1814 | regs->end[0] - regs->start[0]);
|
---|
1815 | break;
|
---|
1816 |
|
---|
1817 | case '1': case '2': case '3': case '4': case '5': case '6':
|
---|
1818 | case '7': case '8': case '9':
|
---|
1819 | ch -= '0';
|
---|
1820 | if (regs->num_regs - 1 <= ch)
|
---|
1821 | M4ERROR ((warning_status, 0, "\
|
---|
1822 | Warning: sub-expression %d not present", ch));
|
---|
1823 | else if (regs->end[ch] > 0)
|
---|
1824 | obstack_grow (obs, victim + regs->start[ch],
|
---|
1825 | regs->end[ch] - regs->start[ch]);
|
---|
1826 | break;
|
---|
1827 |
|
---|
1828 | case '\0':
|
---|
1829 | M4ERROR ((warning_status, 0, "\
|
---|
1830 | Warning: trailing \\ ignored in replacement"));
|
---|
1831 | return;
|
---|
1832 |
|
---|
1833 | default:
|
---|
1834 | obstack_1grow (obs, ch);
|
---|
1835 | break;
|
---|
1836 | }
|
---|
1837 | }
|
---|
1838 | }
|
---|
1839 |
|
---|
1840 | /*------------------------------------------.
|
---|
1841 | | Initialize regular expression variables. |
|
---|
1842 | `------------------------------------------*/
|
---|
1843 |
|
---|
1844 | static void
|
---|
1845 | init_pattern_buffer (struct re_pattern_buffer *buf, struct re_registers *regs)
|
---|
1846 | {
|
---|
1847 | buf->translate = NULL;
|
---|
1848 | buf->fastmap = NULL;
|
---|
1849 | buf->buffer = NULL;
|
---|
1850 | buf->allocated = 0;
|
---|
1851 | regs->start = NULL;
|
---|
1852 | regs->end = NULL;
|
---|
1853 | }
|
---|
1854 |
|
---|
1855 | /*----------------------------------------.
|
---|
1856 | | Clean up regular expression variables. |
|
---|
1857 | `----------------------------------------*/
|
---|
1858 |
|
---|
1859 | static void
|
---|
1860 | free_pattern_buffer (struct re_pattern_buffer *buf, struct re_registers *regs)
|
---|
1861 | {
|
---|
1862 | regfree (buf);
|
---|
1863 | free (regs->start);
|
---|
1864 | free (regs->end);
|
---|
1865 | }
|
---|
1866 |
|
---|
1867 | /*--------------------------------------------------------------------------.
|
---|
1868 | | Regular expression version of index. Given two arguments, expand to the |
|
---|
1869 | | index of the first match of the second argument (a regexp) in the first. |
|
---|
1870 | | Expand to -1 if here is no match. Given a third argument, is changes |
|
---|
1871 | | the expansion to this argument. |
|
---|
1872 | `--------------------------------------------------------------------------*/
|
---|
1873 |
|
---|
1874 | static void
|
---|
1875 | m4_regexp (struct obstack *obs, int argc, token_data **argv)
|
---|
1876 | {
|
---|
1877 | const char *victim; /* first argument */
|
---|
1878 | const char *regexp; /* regular expression */
|
---|
1879 | const char *repl; /* replacement string */
|
---|
1880 |
|
---|
1881 | struct re_pattern_buffer buf; /* compiled regular expression */
|
---|
1882 | struct re_registers regs; /* for subexpression matches */
|
---|
1883 | const char *msg; /* error message from re_compile_pattern */
|
---|
1884 | int startpos; /* start position of match */
|
---|
1885 | int length; /* length of first argument */
|
---|
1886 |
|
---|
1887 | if (bad_argc (argv[0], argc, 3, 4))
|
---|
1888 | {
|
---|
1889 | /* builtin(`regexp') is blank, but regexp(`abc') is 0. */
|
---|
1890 | if (argc == 2)
|
---|
1891 | shipout_int (obs, 0);
|
---|
1892 | return;
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | victim = TOKEN_DATA_TEXT (argv[1]);
|
---|
1896 | regexp = TOKEN_DATA_TEXT (argv[2]);
|
---|
1897 |
|
---|
1898 | init_pattern_buffer (&buf, ®s);
|
---|
1899 | msg = re_compile_pattern (regexp, strlen (regexp), &buf);
|
---|
1900 |
|
---|
1901 | if (msg != NULL)
|
---|
1902 | {
|
---|
1903 | M4ERROR ((warning_status, 0,
|
---|
1904 | "bad regular expression: `%s': %s", regexp, msg));
|
---|
1905 | free_pattern_buffer (&buf, ®s);
|
---|
1906 | return;
|
---|
1907 | }
|
---|
1908 |
|
---|
1909 | length = strlen (victim);
|
---|
1910 | /* Avoid overhead of allocating regs if we won't use it. */
|
---|
1911 | startpos = re_search (&buf, victim, length, 0, length,
|
---|
1912 | argc == 3 ? NULL : ®s);
|
---|
1913 |
|
---|
1914 | if (startpos == -2)
|
---|
1915 | M4ERROR ((warning_status, 0,
|
---|
1916 | "error matching regular expression `%s'", regexp));
|
---|
1917 | else if (argc == 3)
|
---|
1918 | shipout_int (obs, startpos);
|
---|
1919 | else if (startpos >= 0)
|
---|
1920 | {
|
---|
1921 | repl = TOKEN_DATA_TEXT (argv[3]);
|
---|
1922 | substitute (obs, victim, repl, ®s);
|
---|
1923 | }
|
---|
1924 |
|
---|
1925 | free_pattern_buffer (&buf, ®s);
|
---|
1926 | }
|
---|
1927 |
|
---|
1928 | /*--------------------------------------------------------------------------.
|
---|
1929 | | Substitute all matches of a regexp occuring in a string. Each match of |
|
---|
1930 | | the second argument (a regexp) in the first argument is changed to the |
|
---|
1931 | | third argument, with \& substituted by the matched text, and \N |
|
---|
1932 | | substituted by the text matched by the Nth parenthesized sub-expression. |
|
---|
1933 | `--------------------------------------------------------------------------*/
|
---|
1934 |
|
---|
1935 | static void
|
---|
1936 | m4_patsubst (struct obstack *obs, int argc, token_data **argv)
|
---|
1937 | {
|
---|
1938 | const char *victim; /* first argument */
|
---|
1939 | const char *regexp; /* regular expression */
|
---|
1940 |
|
---|
1941 | struct re_pattern_buffer buf; /* compiled regular expression */
|
---|
1942 | struct re_registers regs; /* for subexpression matches */
|
---|
1943 | const char *msg; /* error message from re_compile_pattern */
|
---|
1944 | int matchpos; /* start position of match */
|
---|
1945 | int offset; /* current match offset */
|
---|
1946 | int length; /* length of first argument */
|
---|
1947 |
|
---|
1948 | if (bad_argc (argv[0], argc, 3, 4))
|
---|
1949 | {
|
---|
1950 | /* builtin(`patsubst') is blank, but patsubst(`abc') is abc. */
|
---|
1951 | if (argc == 2)
|
---|
1952 | obstack_grow (obs, ARG (1), strlen (ARG (1)));
|
---|
1953 | return;
|
---|
1954 | }
|
---|
1955 |
|
---|
1956 | regexp = TOKEN_DATA_TEXT (argv[2]);
|
---|
1957 |
|
---|
1958 | init_pattern_buffer (&buf, ®s);
|
---|
1959 | msg = re_compile_pattern (regexp, strlen (regexp), &buf);
|
---|
1960 |
|
---|
1961 | if (msg != NULL)
|
---|
1962 | {
|
---|
1963 | M4ERROR ((warning_status, 0,
|
---|
1964 | "bad regular expression `%s': %s", regexp, msg));
|
---|
1965 | free (buf.buffer);
|
---|
1966 | return;
|
---|
1967 | }
|
---|
1968 |
|
---|
1969 | victim = TOKEN_DATA_TEXT (argv[1]);
|
---|
1970 | length = strlen (victim);
|
---|
1971 |
|
---|
1972 | offset = 0;
|
---|
1973 | matchpos = 0;
|
---|
1974 | while (offset <= length)
|
---|
1975 | {
|
---|
1976 | matchpos = re_search (&buf, victim, length,
|
---|
1977 | offset, length - offset, ®s);
|
---|
1978 | if (matchpos < 0)
|
---|
1979 | {
|
---|
1980 |
|
---|
1981 | /* Match failed -- either error or there is no match in the
|
---|
1982 | rest of the string, in which case the rest of the string is
|
---|
1983 | copied verbatim. */
|
---|
1984 |
|
---|
1985 | if (matchpos == -2)
|
---|
1986 | M4ERROR ((warning_status, 0,
|
---|
1987 | "error matching regular expression `%s'", regexp));
|
---|
1988 | else if (offset < length)
|
---|
1989 | obstack_grow (obs, victim + offset, length - offset);
|
---|
1990 | break;
|
---|
1991 | }
|
---|
1992 |
|
---|
1993 | /* Copy the part of the string that was skipped by re_search (). */
|
---|
1994 |
|
---|
1995 | if (matchpos > offset)
|
---|
1996 | obstack_grow (obs, victim + offset, matchpos - offset);
|
---|
1997 |
|
---|
1998 | /* Handle the part of the string that was covered by the match. */
|
---|
1999 |
|
---|
2000 | substitute (obs, victim, ARG (3), ®s);
|
---|
2001 |
|
---|
2002 | /* Update the offset to the end of the match. If the regexp
|
---|
2003 | matched a null string, advance offset one more, to avoid
|
---|
2004 | infinite loops. */
|
---|
2005 |
|
---|
2006 | offset = regs.end[0];
|
---|
2007 | if (regs.start[0] == regs.end[0])
|
---|
2008 | obstack_1grow (obs, victim[offset++]);
|
---|
2009 | }
|
---|
2010 | obstack_1grow (obs, '\0');
|
---|
2011 |
|
---|
2012 | free_pattern_buffer (&buf, ®s);
|
---|
2013 | }
|
---|
2014 | |
---|
2015 |
|
---|
2016 | /* Finally, a placeholder builtin. This builtin is not installed by
|
---|
2017 | default, but when reading back frozen files, this is associated
|
---|
2018 | with any builtin we don't recognize (for example, if the frozen
|
---|
2019 | file was created with a changeword capable m4, but is then loaded
|
---|
2020 | by a different m4 that does not support changeword). This way, we
|
---|
2021 | can keep 'm4 -R' quiet in the common case that the user did not
|
---|
2022 | know or care about the builtin when the frozen file was created,
|
---|
2023 | while still flagging it as a potential error if an attempt is made
|
---|
2024 | to actually use the builtin. */
|
---|
2025 |
|
---|
2026 | /*--------------------------------------------------------------------.
|
---|
2027 | | Issue a warning that this macro is a placeholder for an unsupported |
|
---|
2028 | | builtin that was requested while reloading a frozen file. |
|
---|
2029 | `--------------------------------------------------------------------*/
|
---|
2030 |
|
---|
2031 | void
|
---|
2032 | m4_placeholder (struct obstack *obs, int argc, token_data **argv)
|
---|
2033 | {
|
---|
2034 | M4ERROR ((warning_status, 0, "\
|
---|
2035 | builtin `%s' requested by frozen file is not supported", ARG (0)));
|
---|
2036 | }
|
---|
2037 | |
---|
2038 |
|
---|
2039 | /*-------------------------------------------------------------------------.
|
---|
2040 | | This function handles all expansion of user defined and predefined |
|
---|
2041 | | macros. It is called with an obstack OBS, where the macros expansion |
|
---|
2042 | | will be placed, as an unfinished object. SYM points to the macro |
|
---|
2043 | | definition, giving the expansion text. ARGC and ARGV are the arguments, |
|
---|
2044 | | as usual. |
|
---|
2045 | `-------------------------------------------------------------------------*/
|
---|
2046 |
|
---|
2047 | void
|
---|
2048 | expand_user_macro (struct obstack *obs, symbol *sym,
|
---|
2049 | int argc, token_data **argv)
|
---|
2050 | {
|
---|
2051 | const char *text;
|
---|
2052 | int i;
|
---|
2053 |
|
---|
2054 | for (text = SYMBOL_TEXT (sym); *text != '\0';)
|
---|
2055 | {
|
---|
2056 | if (*text != '$')
|
---|
2057 | {
|
---|
2058 | obstack_1grow (obs, *text);
|
---|
2059 | text++;
|
---|
2060 | continue;
|
---|
2061 | }
|
---|
2062 | text++;
|
---|
2063 | switch (*text)
|
---|
2064 | {
|
---|
2065 | case '0': case '1': case '2': case '3': case '4':
|
---|
2066 | case '5': case '6': case '7': case '8': case '9':
|
---|
2067 | if (no_gnu_extensions)
|
---|
2068 | {
|
---|
2069 | i = *text++ - '0';
|
---|
2070 | }
|
---|
2071 | else
|
---|
2072 | {
|
---|
2073 | for (i = 0; isdigit (to_uchar (*text)); text++)
|
---|
2074 | i = i*10 + (*text - '0');
|
---|
2075 | }
|
---|
2076 | if (i < argc)
|
---|
2077 | obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]),
|
---|
2078 | strlen (TOKEN_DATA_TEXT (argv[i])));
|
---|
2079 | break;
|
---|
2080 |
|
---|
2081 | case '#': /* number of arguments */
|
---|
2082 | shipout_int (obs, argc - 1);
|
---|
2083 | text++;
|
---|
2084 | break;
|
---|
2085 |
|
---|
2086 | case '*': /* all arguments */
|
---|
2087 | case '@': /* ... same, but quoted */
|
---|
2088 | dump_args (obs, argc, argv, ",", *text == '@');
|
---|
2089 | text++;
|
---|
2090 | break;
|
---|
2091 |
|
---|
2092 | default:
|
---|
2093 | obstack_1grow (obs, '$');
|
---|
2094 | break;
|
---|
2095 | }
|
---|
2096 | }
|
---|
2097 | }
|
---|