1
/* mp4h -- A macro processor for HTML documents
2
Copyright 2000-2003, Denis Barbier
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2, or (at your option)
10
This program is a work based on GNU m4 version 1.4n. Below is the
13
/* GNU m4 -- A simple macro processor
14
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
16
This program is free software; you can redistribute it and/or modify
17
it under the terms of the GNU General Public License as published by
18
the Free Software Foundation; either version 2, or (at your option)
21
This program is distributed in the hope that it will be useful,
22
but WITHOUT ANY WARRANTY; without even the implied warranty of
23
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
GNU General Public License for more details.
26
You should have received a copy of the GNU General Public License
27
along with this program; if not, write to the Free Software
28
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
/* This file contains the functions, that performs the basic argument
32
parsing and macro expansion. */
36
static void expand_macro __P ((symbol *, read_type));
37
static void expand_unknown_tag __P ((char *, read_type));
38
static void expand_entity __P ((symbol *, read_type));
39
static void expand_token __P ((struct obstack *, read_type, token_type, token_data *));
41
/* Current recursion level in expand_macro (). */
42
int expansion_level = 0;
44
/* The number of the current call of expand_macro (). */
45
static int macro_call_id = 0;
47
/* global variable to abort expansion */
48
static boolean internal_abort = FALSE;
50
/*----------------------------------------------------------------------.
51
| This function read all input, and expands each token, one at a time. |
52
`----------------------------------------------------------------------*/
60
while ((t = next_token (&td, READ_NORMAL, FALSE)) != TOKEN_EOF)
61
expand_token ((struct obstack *) NULL, READ_NORMAL, t, &td);
65
/*------------------------------------------------------------------------.
66
| Expand one token, according to its type. Potential macro names |
67
| (TOKEN_WORD) are looked up in the symbol table, to see if they have a |
68
| macro definition. If they have, they are expanded as macros, otherwise |
69
| the text are just copied to the output. |
70
`------------------------------------------------------------------------*/
73
expand_token (struct obstack *obs, read_type expansion, token_type t,
77
char *append_semicolon;
78
char *text = TOKEN_DATA_TEXT (td);
92
if (expansion_level > 0 && t == TOKEN_QUOTED)
93
obstack_1grow (obs, CHAR_LQUOTE);
94
shipout_text (obs, text);
95
if (expansion_level > 0 && t == TOKEN_QUOTED)
96
obstack_1grow (obs, CHAR_RQUOTE);
103
MP4HERROR ((warning_status, 0,
104
"INTERNAL ERROR: macro has no leading '<' in expand_token ()"));
106
/* macro names must begin with a letter or an underscore.
107
If another character is found, this string is not a
110
if (IS_ALPHA (*text))
112
sym = lookup_symbol (text, SYMBOL_LOOKUP);
113
if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID)
115
if (exp_flags & EXP_NO_HTMLTAG)
116
shipout_text (obs, TOKEN_DATA_TEXT (td));
118
expand_unknown_tag (text, expansion);
121
expand_macro (sym, expansion);
123
else if (*text == '/' && IS_ALPHA (*(text+1)))
125
sym = lookup_symbol (text+1, SYMBOL_LOOKUP);
128
MP4HERROR ((warning_status, 0,
129
_("Warning:%s:%d: `<%s>' found without begin tag"),
130
CURRENT_FILE_LINE, text));
132
expand_unknown_tag (text, expansion);
135
shipout_text (obs, TOKEN_DATA_TEXT (td));
139
/* entity names must begin with a letter or an underscore.
140
If another character is found, this string is not an
143
if (IS_ENTITY(*text))
146
MP4HERROR ((warning_status, 0,
147
"INTERNAL ERROR: entity has no leading '&' in expand_token ()"));
149
if (IS_ALPHA (*text))
151
append_semicolon = NULL;
152
if (LAST_CHAR (text) == ';')
154
append_semicolon = text + strlen (text) - 1;
155
*append_semicolon = '\0';
158
sym = lookup_entity (text, SYMBOL_LOOKUP);
159
if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID)
161
if (append_semicolon)
162
*(append_semicolon) = ';';
163
shipout_text (obs, TOKEN_DATA_TEXT (td));
166
expand_entity (sym, expansion);
169
shipout_text (obs, TOKEN_DATA_TEXT (td));
173
MP4HERROR ((warning_status, 0,
174
"INTERNAL ERROR: Bad token type in expand_token ()"));
181
/*-------------------------------------------------------------------------.
182
| This function parses one argument to a macro call. It skips leading |
183
| whitespace and reads and expands tokens until it finds a space outside |
184
| of any group, or a right angle bracket. It returns a flag indicating |
185
| whether the argument read are the last for the active macro call. The |
186
| argument read are the last for the active macro call. The argument are |
187
| on the obstack OBS, indirectly through expand_token (). |
188
| On exit, this function returns |
189
| 0: close bracket found |
191
| 2: other arguments follow |
192
`-------------------------------------------------------------------------*/
195
expand_argument (struct obstack *obs, read_type expansion, token_data *argp,
203
boolean in_string = FALSE;
205
*last_char_ptr = ' ';
206
TOKEN_DATA_TYPE (argp) = TOKEN_VOID;
208
/* Skip leading white space. */
209
t = next_token (&td, expansion, FALSE);
210
if (t == TOKEN_SPACE)
212
if (expansion == READ_ATTR_ASIS || expansion == READ_ATTR_QUOT)
214
/* We are parsing attributes of a command which will be
215
rescanned, so whitepsaces are preserved. */
216
obstack_grow (obs, TOKEN_DATA_TEXT (&td),
217
strlen (TOKEN_DATA_TEXT (&td)));
219
t = next_token (&td, expansion, FALSE);
229
text = TOKEN_DATA_TEXT (&td);
230
if ((IS_SPACE(*text) || IS_CLOSE(*text))
231
&& !in_string && (group_level == 0))
234
if (t == TOKEN_SPACE &&
235
(expansion == READ_ATTR_ASIS || expansion == READ_ATTR_QUOT))
237
obstack_grow (obs, TOKEN_DATA_TEXT (&td),
238
strlen (TOKEN_DATA_TEXT (&td)));
241
/* The argument MUST be finished, whether we want it or not. */
242
obstack_1grow (obs, '\0');
244
if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID)
246
TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
247
TOKEN_DATA_TEXT (argp) = obstack_finish (obs);
249
if (IS_SPACE(*TOKEN_DATA_TEXT (&td)))
253
expand_token (obs, expansion, t, &td);
257
internal_abort = TRUE;
262
if (expansion == READ_ATTR_ASIS && group_level == 0)
263
obstack_1grow (obs, CHAR_BGROUP);
269
if (expansion == READ_ATTR_ASIS && group_level == 0)
270
obstack_1grow (obs, CHAR_EGROUP);
274
in_string = !in_string;
275
obstack_grow (obs, TOKEN_DATA_TEXT (&td),
276
strlen (TOKEN_DATA_TEXT (&td)));
281
if (expansion_level > 0 && t == TOKEN_QUOTED)
282
obstack_1grow (obs, CHAR_LQUOTE);
283
obstack_grow (obs, TOKEN_DATA_TEXT (&td),
284
strlen (TOKEN_DATA_TEXT (&td)));
285
if (expansion_level > 0 && t == TOKEN_QUOTED)
286
obstack_1grow (obs, CHAR_RQUOTE);
291
expand_token (obs, expansion, t, &td);
295
if (obstack_object_size (obs) == 0)
297
TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
298
TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td);
299
TOKEN_DATA_FUNC_TRACED (argp) = TOKEN_DATA_FUNC_TRACED (&td);
304
MP4HERROR ((warning_status, 0,
305
"INTERNAL ERROR: Bad token type in expand_argument ()"));
309
text = TOKEN_DATA_TEXT (&td);
311
*last_char_ptr = '\0';
313
*last_char_ptr = LAST_CHAR (text);
314
t = next_token (&td, expansion, in_string);
319
/*-------------------------------------------------------------------------.
320
| Collect all the arguments to a call of the macro SYM. The arguments are |
321
| stored on the obstack ARGUMENTS and a table of pointers to the arguments |
322
| on the obstack ARGPTR. |
323
| If there is a slash character before closing bracket, this function |
324
| returns TRUE, otherwise FALSE. |
325
`-------------------------------------------------------------------------*/
328
collect_arguments (char *symbol_name, read_type expansion,
329
struct obstack *argptr, struct obstack *arguments)
336
char last_char = ' ';
338
TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
339
TOKEN_DATA_TEXT (&td) = symbol_name;
340
tdp = (token_data *) obstack_copy (arguments, (voidstar) &td, sizeof (td));
341
obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
342
TOKEN_DATA_TYPE (&td) = TOKEN_VOID;
346
(void) next_token (&td, READ_BODY, FALSE);
347
else if (IS_SPACE(ch) || IS_TAG(ch) || IS_SLASH(ch))
351
/* remember last address in use to remove the last
352
argument if it is empty. */
353
last_addr = argptr->next_free;
354
more_args = expand_argument (arguments, expansion, &td, &last_char);
357
MP4HERROR ((EXIT_FAILURE, 0,
358
_("ERROR:%s:%d: EOF when reading argument of the <%s> tag"),
359
CURRENT_FILE_LINE, symbol_name));
363
obstack_copy (arguments, (voidstar) &td, sizeof (td));
364
obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
366
while (more_args == 2);
368
/* If the last argument is empty, it is removed. We need it to
369
remove white spaces before closing brackets. */
371
argptr->next_free = last_addr;
375
MP4HERROR ((warning_status, 0,
376
"INTERNAL ERROR: Bad tag expression in `%s'", symbol_name));
378
return (IS_SLASH(last_char));
381
/*-----------------------------------------------------------------.
382
| Collect the body of a container tag. No expansion is performed, |
383
| but when a macro is found its arguments are collected. This is |
384
| necessary to deal with nested expressions. |
385
`-----------------------------------------------------------------*/
387
collect_body (char *symbol_name, read_type expansion,
388
struct obstack *argptr, struct obstack *bodyptr)
398
t = next_token (&td, expansion, FALSE);
399
text = TOKEN_DATA_TEXT (&td);
404
MP4HERROR ((EXIT_FAILURE, 0,
405
_("ERROR:%s:%d: EOF when reading body of the <%s> tag"),
406
CURRENT_FILE_LINE, symbol_name));
414
obstack_1grow (bodyptr, CHAR_QUOTE);
422
if (expansion_level > 0 && t == TOKEN_QUOTED)
423
obstack_1grow (bodyptr, CHAR_LQUOTE);
424
shipout_text (bodyptr, text);
425
if (expansion_level > 0 && t == TOKEN_QUOTED)
426
obstack_1grow (bodyptr, CHAR_RQUOTE);
436
if (strcasecmp (text, symbol_name) == 0)
438
/* gobble closing bracket */
441
t = next_token (&td, expansion, FALSE);
443
while (! IS_CLOSE(*TOKEN_DATA_TEXT (&td)))
446
obstack_1grow (bodyptr, '\0');
448
/* Add body to argptr */
449
TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
450
TOKEN_DATA_TEXT (&td) = obstack_finish (bodyptr);
451
tdp = (token_data *) obstack_copy (bodyptr,
452
(voidstar) &td, sizeof (td));
453
obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
459
newsym = lookup_symbol (text, SYMBOL_LOOKUP);
462
if (!(exp_flags & EXP_NOWARN_NEST))
463
MP4HERROR ((warning_status, 0,
464
_("Warning:%s:%d: `</%s>' found when `</%s>' expected"),
465
CURRENT_FILE_LINE, text, symbol_name));
466
if (exp_flags & EXP_UNM_BREAK)
468
/* Premature end of body parsing. */
469
obstack_1grow (bodyptr, '\0');
470
TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
471
TOKEN_DATA_TEXT (&td) = obstack_finish (bodyptr);
472
tdp = (token_data *) obstack_copy (bodyptr,
473
(voidstar) &td, sizeof (td));
474
obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
476
/* Push read input back on the stack */
477
unget_string (text-2);
482
obstack_grow (bodyptr, TOKEN_DATA_TEXT (&td),
483
strlen(TOKEN_DATA_TEXT (&td)) );
484
/* gobble closing bracket */
487
t = next_token (&td, expansion, FALSE);
488
obstack_grow (bodyptr, TOKEN_DATA_TEXT (&td),
489
strlen(TOKEN_DATA_TEXT (&td)) );
491
while (! IS_CLOSE(*TOKEN_DATA_TEXT (&td)))
497
newsym = lookup_symbol (text, SYMBOL_LOOKUP);
498
if (newsym == NULL || SYMBOL_TYPE (newsym) == TOKEN_VOID)
500
if (exp_flags & EXP_NO_HTMLTAG)
501
shipout_text (bodyptr, TOKEN_DATA_TEXT (&td));
503
expand_unknown_tag (text, expansion);
506
expand_macro (newsym, expansion);
511
MP4HERROR ((warning_status, 0,
512
"INTERNAL ERROR:%d: Bad token type in collect_body ()", t));
519
/*------------------------------------------------------------------------.
520
| The actual call of a macro is handled by call_macro (). call_macro () |
521
| is passed a symbol SYM, whose type is used to call either a builtin |
522
| function, or the user macro expansion function expand_user_macro () |
523
| (lives in builtin.c). There are ARGC arguments to the call, stored in |
524
| the ARGV table. The expansion is left on the obstack EXPANSION. Macro |
525
| tracing is also handled here. |
526
`------------------------------------------------------------------------*/
529
call_macro (symbol *sym, struct obstack *obs, int argc, token_data **argv,
532
if (SYMBOL_HOOK_BEGIN (sym))
533
obstack_grow (obs, SYMBOL_HOOK_BEGIN (sym),
534
strlen (SYMBOL_HOOK_BEGIN (sym)));
535
switch (SYMBOL_TYPE (sym))
538
(*SYMBOL_FUNC (sym)) (obs, argc, argv, expansion);
542
expand_user_macro (obs, sym, argc, argv, expansion);
546
MP4HERROR ((warning_status, 0,
547
"INTERNAL ERROR: Bad symbol type in call_macro ()"));
550
if (SYMBOL_HOOK_END (sym))
551
obstack_grow (obs, SYMBOL_HOOK_END (sym),
552
strlen (SYMBOL_HOOK_END (sym)));
555
/*-------------------------------------------------------------------------.
556
| The macro expansion is handled by expand_macro (). It parses the |
557
| arguments, using collect_arguments (), and builds a table of pointers to |
558
| the arguments. The arguments themselves are stored on a local obstack. |
559
| Expand_macro () uses call_macro () to do the call of the macro. |
561
| Expand_macro () is potentially recursive, since it calls expand_argument |
562
| (), which might call expand_token (), which might call expand_macro (). |
563
`-------------------------------------------------------------------------*/
566
expand_macro (symbol *sym, read_type expansion)
568
struct obstack arguments, argptr, body;
573
struct obstack *obs_expansion;
574
const char *expanded;
576
boolean traced, slash;
578
read_type attr_expansion;
581
if (expansion_level > nesting_limit)
582
MP4HERROR ((EXIT_FAILURE, 0,
583
_("ERROR: Recursion limit of %d exceeded, use -L<N> to change it"),
586
array_current_line[expansion_level] = current_line;
587
xfree((voidstar) array_current_file[expansion_level]);
588
array_current_file[expansion_level] = xstrdup(current_file);
591
my_call_id = macro_call_id;
593
traced = (boolean) ((debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym));
595
obstack_init (&arguments);
596
obstack_init (&argptr);
597
obstack_init (&body);
599
if (traced && (debug_level & DEBUG_TRACE_CALL))
600
trace_prepre (SYMBOL_NAME (sym), my_call_id);
602
if (expansion == READ_ATTR_ASIS || expansion == READ_ATTR_VERB
603
|| expansion == READ_BODY)
604
attr_expansion = READ_ATTR_ASIS;
605
else if (! SYMBOL_EXPAND_ARGS (sym))
606
attr_expansion = READ_ATTR_VERB;
608
attr_expansion = READ_ATTRIBUTE;
610
slash = collect_arguments (SYMBOL_NAME (sym), attr_expansion, &argptr,
612
argc = obstack_object_size (&argptr) / sizeof (token_data *);
614
if (SYMBOL_CONTAINER (sym) && !slash)
616
collect_body (SYMBOL_NAME (sym), READ_BODY, &argptr, &body);
617
argv = (token_data **) obstack_finish (&argptr);
621
if (SYMBOL_CONTAINER (sym))
623
TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
624
TOKEN_DATA_TEXT (&td) = "";
625
tdp = (token_data *) obstack_copy (&arguments,
626
(voidstar) &td, sizeof (td));
627
obstack_grow (&argptr, (voidstar) &tdp, sizeof (tdp));
630
argv = (token_data **) obstack_finish (&argptr);
633
cp = TOKEN_DATA_TEXT (argv[argc-1]);
634
if (IS_SLASH(*cp) && *(cp+1) == '\0')
639
else if (IS_SLASH (LAST_CHAR (cp)))
641
if (IS_SPACE (*(cp+strlen(cp)-2)))
642
*(cp+strlen(cp)-2) = '\0';
644
LAST_CHAR (cp) = '\0';
647
else if (!(exp_flags & EXP_NOWARN_SLASH))
648
MP4HERROR ((warning_status, 0,
649
_("Warning:%s:%d: `<%s>' requires a trailing slash"),
650
CURRENT_FILE_LINE, SYMBOL_NAME (sym)));
654
trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv);
656
obs_expansion = push_string_init ();
657
if (expansion == READ_NORMAL || expansion == READ_ATTRIBUTE
658
|| expansion == READ_ATTR_QUOT)
660
if (expansion_level > 1)
661
obstack_1grow (obs_expansion, CHAR_BGROUP);
662
call_macro (sym, obs_expansion, argc, argv, expansion);
663
if (expansion_level > 1)
664
obstack_1grow (obs_expansion, CHAR_EGROUP);
668
obstack_1grow (obs_expansion, '<');
669
shipout_string (obs_expansion, SYMBOL_NAME (sym), 0);
671
for (i = 1; i < argc; i++)
673
shipout_string (obs_expansion, TOKEN_DATA_TEXT (argv[i]), 0);
677
obstack_1grow (obs_expansion, CHAR_SLASH);
680
obstack_1grow (obs_expansion, '>');
681
if (SYMBOL_CONTAINER (sym) && !slash)
683
shipout_string (obs_expansion, TOKEN_DATA_TEXT (argv[argc]), 0);
684
obstack_grow (obs_expansion, "</", 2);
685
shipout_string (obs_expansion, SYMBOL_NAME (sym), 0);
686
obstack_1grow (obs_expansion, '>');
689
expanded = push_string_finish (expansion);
692
trace_post (SYMBOL_NAME (sym), my_call_id, argc, argv, expanded);
696
obstack_free (&arguments, NULL);
697
obstack_free (&argptr, NULL);
698
obstack_free (&body, NULL);
700
if (expansion_level == 0)
704
/*-------------------------------------------------------------------------.
705
| This macro reads attributes without expanding macro. It is useful to |
706
| print unknown tags. |
707
`-------------------------------------------------------------------------*/
710
expand_unknown_tag (char *name, read_type expansion)
712
struct obstack arguments, argptr, body;
715
struct obstack *obs_expansion;
716
const char *expanded;
717
char *symbol_name, *cp;
718
read_type attr_expansion;
719
boolean slash, single;
722
if (expansion_level > nesting_limit)
723
MP4HERROR ((EXIT_FAILURE, 0,
724
_("ERROR: Recursion limit of %d exceeded, use -L<N> to change it"),
727
array_current_line[expansion_level] = current_line;
728
xfree((voidstar) array_current_file[expansion_level]);
729
array_current_file[expansion_level] = xstrdup(current_file);
731
symbol_name = xstrdup (name);
733
obstack_init (&arguments);
734
obstack_init (&argptr);
735
obstack_init (&body);
737
if (expansion == READ_NORMAL || expansion == READ_ATTRIBUTE
738
|| expansion == READ_ATTR_QUOT)
739
attr_expansion = READ_ATTR_QUOT;
741
attr_expansion = READ_ATTR_ASIS;
743
slash = collect_arguments (symbol_name, attr_expansion, &argptr, &arguments);
744
argc = obstack_object_size (&argptr) / sizeof (token_data *);
747
This tag is a simple tag if either
748
- tag name begins with a slash (i.e. this is an end tag)
749
- tag name last character is a star
750
- attributes are ended by a trailing slash
753
if (*(symbol_name) == '/')
756
if (!single && !(exp_flags & EXP_STAR_COMPLEX))
757
single = (LAST_CHAR (symbol_name) == '*');
759
if (!single && !(exp_flags & EXP_DFT_SIMPLE))
760
collect_body (symbol_name, expansion, &argptr, &body);
762
argv = (token_data **) obstack_finish (&argptr);
764
/* Remove the trailing slash in single tags. */
767
cp = TOKEN_DATA_TEXT (argv[argc-1]);
768
if (IS_SLASH (*cp) && *(cp+1) == '\0')
770
else if (IS_SLASH (LAST_CHAR (cp)))
772
if (IS_SPACE (*(cp+strlen(cp)-2)))
773
*(cp+strlen(cp)-2) = '\0';
775
LAST_CHAR (cp) = '\0';
779
if (expansion == READ_ATTR_ASIS
780
|| expansion == READ_ATTR_VERB || expansion == READ_BODY)
781
expansion = READ_BODY;
783
obs_expansion = push_string_init ();
785
if (expansion != READ_BODY)
786
obstack_1grow (obs_expansion, CHAR_LQUOTE);
787
obstack_1grow (obs_expansion, '<');
788
shipout_string (obs_expansion, symbol_name, 0);
790
/* Whitespaces between attributes have been put into
791
attributes text, so there is no need to insert a space
793
for (i = 1; i < argc; i++)
794
shipout_string (obs_expansion, TOKEN_DATA_TEXT (argv[i]), 0);
798
if (! (exp_flags & EXP_NOSPACE_BSLASH))
799
obstack_1grow (obs_expansion, ' ');
800
obstack_1grow (obs_expansion, CHAR_SLASH);
802
obstack_1grow (obs_expansion, '>');
803
if (expansion != READ_BODY)
804
obstack_1grow (obs_expansion, CHAR_RQUOTE);
805
if (!single && !(exp_flags & EXP_DFT_SIMPLE))
807
shipout_string (obs_expansion, TOKEN_DATA_TEXT (argv[argc]), 0);
808
if (expansion != READ_BODY)
809
obstack_1grow (obs_expansion, CHAR_LQUOTE);
810
obstack_grow (obs_expansion, "</", 2);
811
shipout_string (obs_expansion, symbol_name, 0);
812
obstack_1grow (obs_expansion, '>');
813
if (expansion != READ_BODY)
814
obstack_1grow (obs_expansion, CHAR_RQUOTE);
817
expanded = push_string_finish (expansion);
821
obstack_free (&arguments, NULL);
822
obstack_free (&argptr, NULL);
823
obstack_free (&body, NULL);
825
xfree ((voidstar) symbol_name);
829
/*-------------------------------------------------------------------------.
830
| The entity expansion is handled by expand_entity (). Entities are |
831
| treated similarly to macros, they just do not have arguments and the |
832
| symbol text is output directly. |
834
| Expand_entity () is not recursive. |
835
`-------------------------------------------------------------------------*/
838
expand_entity (symbol *sym, read_type expansion)
840
struct obstack *obs_expansion;
841
const char *expanded;
846
if (expansion_level > nesting_limit)
847
MP4HERROR ((EXIT_FAILURE, 0,
848
_("ERROR: Recursion limit of %d exceeded, use -L<N> to change it"),
851
array_current_line[expansion_level] = current_line;
852
xfree((voidstar) array_current_file[expansion_level]);
853
array_current_file[expansion_level] = xstrdup(current_file);
856
my_call_id = macro_call_id;
858
traced = (boolean) ((debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym));
860
if (traced && (debug_level & DEBUG_TRACE_CALL))
861
trace_prepre (SYMBOL_NAME (sym), my_call_id);
863
obs_expansion = push_string_init ();
864
if (expansion_level > 1)
865
obstack_1grow (obs_expansion, CHAR_BGROUP);
866
shipout_string (obs_expansion, SYMBOL_TEXT (sym), 0);
867
if (expansion_level > 1)
868
obstack_1grow (obs_expansion, CHAR_EGROUP);
869
expanded = push_string_finish (expansion);
872
trace_post (SYMBOL_NAME (sym), my_call_id, 0, NULL, expanded);