]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/texinfo/makeinfo/macro.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / texinfo / makeinfo / macro.c
1 /* macro.c -- user-defined macros for Texinfo.
2    $Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp $
3
4    Copyright (C) 1998, 1999, 2002, 2003 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, or (at your option)
9    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 Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "system.h"
21 #include "cmds.h"
22 #include "files.h"
23 #include "macro.h"
24 #include "makeinfo.h"
25 #include "insertion.h"
26
27 /* If non-NULL, this is an output stream to write the full macro expansion
28    of the input text to.  The result is another texinfo file, but
29    missing @include, @infoinclude, @macro, and macro invocations.  Instead,
30    all of the text is placed within the file. */
31 FILE *macro_expansion_output_stream = NULL;
32
33 /* Output file for -E.  */
34 char *macro_expansion_filename;
35
36 /* Nonzero means a macro string is in execution, as opposed to a file. */
37 int me_executing_string = 0;
38
39 /* Nonzero means we want only to expand macros and
40    leave everything else intact.  */
41 int only_macro_expansion = 0;
42
43 static ITEXT **itext_info = NULL;
44 static int itext_size = 0;
45
46 /* Return the arglist on the current line.  This can behave in two different
47    ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
48 int braces_required_for_macro_args = 0;
49
50 /* Array of macros and definitions. */
51 MACRO_DEF **macro_list = NULL;
52
53 int macro_list_len = 0;         /* Number of elements. */
54 int macro_list_size = 0;        /* Number of slots in total. */
55 \f
56 /* Return the length of the array in ARRAY. */
57 int
58 array_len (char **array)
59 {
60   int i = 0;
61
62   if (array)
63     for (i = 0; array[i]; i++);
64
65   return i;
66 }
67
68 void
69 free_array (char **array)
70 {
71   if (array)
72     {
73       int i;
74       for (i = 0; array[i]; i++)
75         free (array[i]);
76
77       free (array);
78     }
79 }
80 \f
81 /* Return the macro definition of NAME or NULL if NAME is not defined. */
82 MACRO_DEF *
83 find_macro (char *name)
84 {
85   int i;
86   MACRO_DEF *def;
87
88   def = NULL;
89   for (i = 0; macro_list && (def = macro_list[i]); i++)
90     {
91       if ((!def->inhibited) && (strcmp (def->name, name) == 0))
92         break;
93     }
94   return def;
95 }
96
97 /* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
98    SOURCE_FILE is the name of the file where this definition can be found,
99    and SOURCE_LINENO is the line number within that file.  If a macro already
100    exists with NAME, then a warning is produced, and that previous
101    definition is overwritten. */
102 static void
103 add_macro (char *name, char **arglist, char *body, char *source_file,
104     int source_lineno, int flags)
105 {
106   MACRO_DEF *def;
107
108   def = find_macro (name);
109
110   if (!def)
111     {
112       if (macro_list_len + 2 >= macro_list_size)
113         macro_list = xrealloc
114           (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
115
116       macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
117       macro_list[macro_list_len + 1] = NULL;
118
119       def = macro_list[macro_list_len];
120       macro_list_len += 1;
121       def->name = name;
122     }
123   else
124     {
125       char *temp_filename = input_filename;
126       int temp_line = line_number;
127
128       warning (_("macro `%s' previously defined"), name);
129
130       input_filename = def->source_file;
131       line_number = def->source_lineno;
132       warning (_("here is the previous definition of `%s'"), name);
133
134       input_filename = temp_filename;
135       line_number = temp_line;
136
137       if (def->arglist)
138         {
139           int i;
140
141           for (i = 0; def->arglist[i]; i++)
142             free (def->arglist[i]);
143
144           free (def->arglist);
145         }
146       free (def->source_file);
147       free (def->body);
148     }
149
150   def->source_file = xstrdup (source_file);
151   def->source_lineno = source_lineno;
152   def->body = body;
153   def->arglist = arglist;
154   def->inhibited = 0;
155   def->flags = flags;
156 }
157
158
159 char **
160 get_brace_args (int quote_single)
161 {
162   char **arglist, *word;
163   int arglist_index, arglist_size;
164   int character, escape_seen, start;
165   int depth = 1;
166
167   /* There is an arglist in braces here, so gather the args inside of it. */
168   skip_whitespace_and_newlines ();
169   input_text_offset++;
170   arglist = NULL;
171   arglist_index = arglist_size = 0;
172
173  get_arg:
174   skip_whitespace_and_newlines ();
175   start = input_text_offset;
176   escape_seen = 0;
177
178   while ((character = curchar ()))
179     {
180       if (character == '\\')
181         {
182           input_text_offset += 2;
183           escape_seen = 1;
184         }
185       else if (character == '{')
186         {
187           depth++;
188           input_text_offset++;
189         }
190       else if ((character == ',' && !quote_single) ||
191                ((character == '}') && depth == 1))
192         {
193           int len = input_text_offset - start;
194
195           if (len || (character != '}'))
196             {
197               word = xmalloc (1 + len);
198               memcpy (word, input_text + start, len);
199               word[len] = 0;
200
201               /* Clean up escaped characters. */
202               if (escape_seen)
203                 {
204                   int i;
205                   for (i = 0; word[i]; i++)
206                     if (word[i] == '\\')
207                       memmove (word + i, word + i + 1,
208                                1 + strlen (word + i + 1));
209                 }
210
211               if (arglist_index + 2 >= arglist_size)
212                 arglist = xrealloc
213                   (arglist, (arglist_size += 10) * sizeof (char *));
214
215               arglist[arglist_index++] = word;
216               arglist[arglist_index] = NULL;
217             }
218
219           input_text_offset++;
220           if (character == '}')
221             break;
222           else
223             goto get_arg;
224         }
225       else if (character == '}')
226         {
227           depth--;
228           input_text_offset++;
229         }
230       else
231         {
232           input_text_offset++;
233           if (character == '\n') line_number++;
234         }
235     }
236   return arglist;
237 }
238
239 static char **
240 get_macro_args (MACRO_DEF *def)
241 {
242   int i;
243   char *word;
244
245   /* Quickly check to see if this macro has been invoked with any arguments.
246      If not, then don't skip any of the following whitespace. */
247   for (i = input_text_offset; i < input_text_length; i++)
248     if (!cr_or_whitespace (input_text[i]))
249       break;
250
251   if (input_text[i] != '{')
252     {
253       if (braces_required_for_macro_args)
254         {
255           return NULL;
256         }
257       else
258         {
259           /* Braces are not required to fill out the macro arguments.  If
260              this macro takes one argument, it is considered to be the
261              remainder of the line, sans whitespace. */
262           if (def->arglist && def->arglist[0] && !def->arglist[1])
263             {
264               char **arglist;
265
266               get_rest_of_line (0, &word);
267               if (input_text[input_text_offset - 1] == '\n')
268                 {
269                   input_text_offset--;
270                   line_number--;
271                 }
272               /* canon_white (word); */
273               arglist = xmalloc (2 * sizeof (char *));
274               arglist[0] = word;
275               arglist[1] = NULL;
276               return arglist;
277             }
278           else
279             {
280               /* The macro either took no arguments, or took more than
281                  one argument.  In that case, it must be invoked with
282                  arguments surrounded by braces. */
283               return NULL;
284             }
285         }
286     }
287   return get_brace_args (def->flags & ME_QUOTE_ARG);
288 }
289
290 /* Substitute actual parameters for named parameters in body.
291    The named parameters which appear in BODY must by surrounded
292    reverse slashes, as in \foo\. */
293 static char *
294 apply (char **named, char **actuals, char *body)
295 {
296   int i;
297   int new_body_index, new_body_size;
298   char *new_body, *text;
299   int length_of_actuals;
300
301   length_of_actuals = array_len (actuals);
302   new_body_size = strlen (body);
303   new_body = xmalloc (1 + new_body_size);
304
305   /* Copy chars from BODY into NEW_BODY. */
306   i = 0;
307   new_body_index = 0;
308
309   while (body[i])
310     { /* Anything but a \ is easy.  */
311       if (body[i] != '\\')
312         new_body[new_body_index++] = body[i++];
313       else
314         { /* Snarf parameter name, check against named parameters. */
315           char *param;
316           int param_start, len;
317
318           param_start = ++i;
319           while (body[i] && body[i] != '\\')
320             i++;
321
322           len = i - param_start;
323           param = xmalloc (1 + len);
324           memcpy (param, body + param_start, len);
325           param[len] = 0;
326
327           if (body[i]) /* move past \ */
328             i++;
329
330           if (len == 0)
331             { /* \\ always means \, even if macro has no args.  */
332               len++;
333               text = xmalloc (1 + len);
334               sprintf (text, "\\%s", param);
335             }
336           else
337             {
338               int which;
339               
340               /* Check against named parameters. */
341               for (which = 0; named && named[which]; which++)
342                 if (STREQ (named[which], param))
343                   break;
344
345               if (named && named[which])
346                 {
347                   text = which < length_of_actuals ? actuals[which] : NULL;
348                   if (!text)
349                     text = "";
350                   len = strlen (text);
351                   text = xstrdup (text);  /* so we can free it */
352                 }
353               else
354                 { /* not a parameter, so it's an error.  */
355                   warning (_("\\ in macro expansion followed by `%s' instead of parameter name"),
356                              param); 
357                   len++;
358                   text = xmalloc (1 + len);
359                   sprintf (text, "\\%s", param);
360                 }
361             }
362
363           if (strlen (param) + 2 < len)
364             {
365               new_body_size += len + 1;
366               new_body = xrealloc (new_body, new_body_size);
367             }
368
369           free (param);
370
371           strcpy (new_body + new_body_index, text);
372           new_body_index += len;
373
374           free (text);
375         }
376     }
377
378   new_body[new_body_index] = 0;
379   return new_body;
380 }
381
382 /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
383    return its expansion as a string.  */
384 char *
385 expand_macro (MACRO_DEF *def)
386 {
387   char **arglist;
388   int num_args;
389   char *execution_string = NULL;
390   int start_line = line_number;
391
392   /* Find out how many arguments this macro definition takes. */
393   num_args = array_len (def->arglist);
394
395   /* Gather the arguments present on the line if there are any. */
396   arglist = get_macro_args (def);
397
398   if (num_args < array_len (arglist))
399     {
400       free_array (arglist);
401       line_error (_("Macro `%s' called on line %d with too many args"),
402                   def->name, start_line);
403       return execution_string;
404     }
405
406   if (def->body)
407     execution_string = apply (def->arglist, arglist, def->body);
408
409   free_array (arglist);
410   return execution_string;
411 }
412
413 /* Execute the macro passed in DEF, a pointer to a MACRO_DEF.  */
414 void
415 execute_macro (MACRO_DEF *def)
416 {
417   char *execution_string;
418   int start_line = line_number, end_line;
419
420   if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
421     me_append_before_this_command ();
422
423   execution_string = expand_macro (def);
424   if (!execution_string)
425     return;
426
427   if (def->body)
428     {
429       /* Reset the line number to where the macro arguments began.
430          This makes line numbers reported in error messages correct in
431          case the macro arguments span several lines and the expanded
432          arguments invoke other commands.  */
433       end_line = line_number;
434       line_number = start_line;
435
436       if (macro_expansion_output_stream
437           && !executing_string && !me_inhibit_expansion)
438         {
439           remember_itext (input_text, input_text_offset);
440           me_execute_string (execution_string);
441         }
442       else
443         execute_string ("%s", execution_string);
444
445       free (execution_string);
446       line_number = end_line;
447     }
448 }
449
450 \f
451 /* Read and remember the definition of a macro.  If RECURSIVE is set,
452    set the ME_RECURSE flag.  MACTYPE is either "macro" or "rmacro", and
453    tells us what the matching @end should be.  */
454 static void
455 define_macro (char *mactype, int recursive)
456 {
457   int i, start;
458   char *name, *line;
459   char *last_end = NULL;
460   char *body = NULL;
461   char **arglist = NULL;
462   int body_size = 0, body_index = 0;
463   int depth = 1;
464   int flags = 0;
465   int defining_line = line_number;
466
467   if (macro_expansion_output_stream && !executing_string)
468     me_append_before_this_command ();
469
470   skip_whitespace ();
471
472   /* Get the name of the macro.  This is the set of characters which are
473      not whitespace and are not `{' immediately following the @macro. */
474   start = input_text_offset;
475   {
476     int len;
477
478     for (i = start; i < input_text_length && input_text[i] != '{'
479                     && !cr_or_whitespace (input_text[i]);
480          i++) ;
481
482     len = i - start;
483     name = xmalloc (1 + len);
484     memcpy (name, input_text + start, len);
485     name[len] = 0;
486     input_text_offset = i;
487   }
488
489   skip_whitespace ();
490
491   /* It is not required that the definition of a macro includes an arglist.
492      If not, don't try to get the named parameters, just use a null list. */
493   if (curchar () == '{')
494     {
495       int character;
496       int arglist_index = 0, arglist_size = 0;
497       int gathering_words = 1;
498       char *word = NULL;
499
500       /* Read the words inside of the braces which determine the arglist.
501          These words will be replaced within the body of the macro at
502          execution time. */
503
504       input_text_offset++;
505       skip_whitespace_and_newlines ();
506
507       while (gathering_words)
508         {
509           int len;
510
511           for (i = input_text_offset;
512                (character = input_text[i]);
513                i++)
514             {
515               switch (character)
516                 {
517                 case '\n':
518                   line_number++;
519                 case ' ':
520                 case '\t':
521                 case ',':
522                 case '}':
523                   /* Found the end of the current arglist word.  Save it. */
524                   len = i - input_text_offset;
525                   word = xmalloc (1 + len);
526                   memcpy (word, input_text + input_text_offset, len);
527                   word[len] = 0;
528                   input_text_offset = i;
529
530                   /* Advance to the comma or close-brace that signified
531                      the end of the argument. */
532                   while ((character = curchar ())
533                          && character != ','
534                          && character != '}')
535                     {
536                       input_text_offset++;
537                       if (character == '\n')
538                         line_number++;
539                     }
540
541                   /* Add the word to our list of words. */
542                   if (arglist_index + 2 >= arglist_size)
543                     {
544                       arglist_size += 10;
545                       arglist = xrealloc (arglist,
546                                           arglist_size * sizeof (char *));
547                     }
548
549                   arglist[arglist_index++] = word;
550                   arglist[arglist_index] = NULL;
551                   break;
552                 }
553
554               if (character == '}')
555                 {
556                   input_text_offset++;
557                   gathering_words = 0;
558                   break;
559                 }
560
561               if (character == ',')
562                 {
563                   input_text_offset++;
564                   skip_whitespace_and_newlines ();
565                   i = input_text_offset - 1;
566                 }
567             }
568         }
569       
570       /* If we have exactly one argument, do @quote-arg implicitly.  Not
571          only does this match TeX's behavior (which can't feasibly be
572          changed), but it's a good idea.  */
573       if (arglist_index == 1)
574         flags |= ME_QUOTE_ARG;
575     }
576
577   /* Read the text carefully until we find an "@end macro" which
578      matches this one.  The text in between is the body of the macro. */
579   skip_whitespace_and_newlines ();
580
581   while (depth)
582     {
583       if ((input_text_offset + 9) > input_text_length)
584         {
585           file_line_error (input_filename, defining_line,
586                            _("%cend macro not found"), COMMAND_PREFIX);
587           return;
588         }
589
590       get_rest_of_line (0, &line);
591
592       /* Handle commands only meaningful within a macro. */
593       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
594           (strncmp (line + 1, "allow-recursion", 15) == 0) &&
595           (line[16] == 0 || whitespace (line[16])))
596         {
597           for (i = 16; whitespace (line[i]); i++);
598           strcpy (line, line + i);
599           flags |= ME_RECURSE;
600           if (!*line)
601             {
602               free (line);
603               continue;
604             }
605         }
606
607       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
608           (strncmp (line + 1, "quote-arg", 9) == 0) &&
609           (line[10] == 0 || whitespace (line[10])))
610         {
611           for (i = 10; whitespace (line[i]); i++);
612           strcpy (line, line + i);
613
614           if (arglist && arglist[0] && !arglist[1])
615             {
616               flags |= ME_QUOTE_ARG;
617               if (!*line)
618                 {
619                   free (line);
620                   continue;
621                 }
622             }
623           else
624            line_error (_("@quote-arg only useful for single-argument macros"));
625         }
626
627       if (*line == COMMAND_PREFIX
628           && (strncmp (line + 1, "macro ", 6) == 0
629               || strncmp (line + 1, "rmacro ", 7) == 0))
630         depth++;
631
632       /* Incorrect implementation of nesting -- just check that the last
633          @end matches what we started with.  Since nested macros don't
634          work in TeX anyway, this isn't worth the trouble to get right.  */
635       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0)
636         {
637           depth--;
638           last_end = "macro";
639         }
640       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0)
641         {
642           depth--;
643           last_end = "rmacro";
644         }
645
646       if (depth)
647         {
648           if ((body_index + strlen (line) + 3) >= body_size)
649             body = xrealloc (body, body_size += 3 + strlen (line));
650           strcpy (body + body_index, line);
651           body_index += strlen (line);
652           body[body_index++] = '\n';
653           body[body_index] = 0;
654         }
655       free (line);
656     }
657
658   /* Check that @end matched the macro command.  */
659   if (!STREQ (last_end, mactype))
660     warning (_("mismatched @end %s with @%s"), last_end, mactype);
661
662   /* If it was an empty macro like
663      @macro foo
664      @end macro
665      create an empty body.  (Otherwise, the macro is not expanded.)  */
666   if (!body)
667     {
668       body = (char *)malloc(1);
669       *body = 0;
670     }
671
672   /* We now have the name, the arglist, and the body.  However, BODY
673      includes the final newline which preceded the `@end macro' text.
674      Delete it. */
675   if (body && strlen (body))
676     body[strlen (body) - 1] = 0;
677
678   if (recursive)
679     flags |= ME_RECURSE;
680     
681   add_macro (name, arglist, body, input_filename, defining_line, flags);
682
683   if (macro_expansion_output_stream && !executing_string)
684     {
685       /* Remember text for future expansions.  */
686       remember_itext (input_text, input_text_offset);
687
688       /* Bizarrely, output the @macro itself.  This is so texinfo.tex
689          will have a chance to read it when texi2dvi calls makeinfo -E.
690          The problem is that we don't really expand macros in all
691          contexts; a @table's @item is one.  And a fix is not obvious to
692          me, since it appears virtually identical to any other internal
693          expansion.  Just setting a variable in cm_item caused other
694          strange expansion problems.  */
695       write_region_to_macro_output ("@", 0, 1);
696       write_region_to_macro_output (mactype, 0, strlen (mactype));
697       write_region_to_macro_output (" ", 0, 1);
698       write_region_to_macro_output (input_text, start, input_text_offset);
699     }
700 }
701
702 void 
703 cm_macro (void)
704 {
705   define_macro ("macro", 0);
706 }
707
708 void 
709 cm_rmacro (void)
710 {
711   define_macro ("rmacro", 1);
712 }
713 \f
714 /* Delete the macro with name NAME.  The macro is deleted from the list,
715    but it is also returned.  If there was no macro defined, NULL is
716    returned. */
717
718 static MACRO_DEF *
719 delete_macro (char *name)
720 {
721   int i;
722   MACRO_DEF *def;
723
724   def = NULL;
725
726   for (i = 0; macro_list && (def = macro_list[i]); i++)
727     if (strcmp (def->name, name) == 0)
728       {
729         memmove (macro_list + i, macro_list + i + 1,
730                ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
731         macro_list_len--;
732         break;
733       }
734   return def;
735 }
736
737 void
738 cm_unmacro (void)
739 {
740   int i;
741   char *line, *name;
742   MACRO_DEF *def;
743
744   if (macro_expansion_output_stream && !executing_string)
745     me_append_before_this_command ();
746
747   get_rest_of_line (0, &line);
748
749   for (i = 0; line[i] && !whitespace (line[i]); i++);
750   name = xmalloc (i + 1);
751   memcpy (name, line, i);
752   name[i] = 0;
753
754   def = delete_macro (name);
755
756   if (def)
757     {
758       free (def->source_file);
759       free (def->name);
760       free (def->body);
761
762       if (def->arglist)
763         {
764           int i;
765
766           for (i = 0; def->arglist[i]; i++)
767             free (def->arglist[i]);
768
769           free (def->arglist);
770         }
771
772       free (def);
773     }
774
775   free (line);
776   free (name);
777
778   if (macro_expansion_output_stream && !executing_string)
779     remember_itext (input_text, input_text_offset);
780 }
781 \f
782 /* How to output sections of the input file verbatim. */
783
784 /* Set the value of POINTER's offset to OFFSET. */
785 ITEXT *
786 remember_itext (char *pointer, int offset)
787 {
788   int i;
789   ITEXT *itext = NULL;
790
791   /* If we have no info, initialize a blank list. */
792   if (!itext_info)
793     {
794       itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
795       for (i = 0; i < itext_size; i++)
796         itext_info[i] = NULL;
797     }
798
799   /* If the pointer is already present in the list, then set the offset. */
800   for (i = 0; i < itext_size; i++)
801     if ((itext_info[i]) &&
802         (itext_info[i]->pointer == pointer))
803       {
804         itext = itext_info[i];
805         itext_info[i]->offset = offset;
806         break;
807       }
808
809   if (i == itext_size)
810     {
811       /* Find a blank slot (or create a new one), and remember the
812          pointer and offset. */
813       for (i = 0; i < itext_size; i++)
814         if (itext_info[i] == NULL)
815           break;
816
817       /* If not found, then add some slots. */
818       if (i == itext_size)
819         {
820           int j;
821
822           itext_info = xrealloc
823             (itext_info, (itext_size += 10) * sizeof (ITEXT *));
824
825           for (j = i; j < itext_size; j++)
826             itext_info[j] = NULL;
827         }
828
829       /* Now add the pointer and the offset. */
830       itext_info[i] = xmalloc (sizeof (ITEXT));
831       itext_info[i]->pointer = pointer;
832       itext_info[i]->offset = offset;
833       itext = itext_info[i];
834     }
835   return itext;
836 }
837
838 /* Forget the input text associated with POINTER. */
839 void
840 forget_itext (char *pointer)
841 {
842   int i;
843
844   for (i = 0; i < itext_size; i++)
845     if (itext_info[i] && (itext_info[i]->pointer == pointer))
846       {
847         free (itext_info[i]);
848         itext_info[i] = NULL;
849         break;
850       }
851 }
852
853 /* Append the text which appeared in input_text from the last offset to
854    the character just before the command that we are currently executing. */
855 void
856 me_append_before_this_command (void)
857 {
858   int i;
859
860   for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
861     ;
862   maybe_write_itext (input_text, i);
863 }
864
865 /* Similar to execute_string, but only takes a single string argument,
866    and remembers the input text location, etc. */
867 void
868 me_execute_string (char *execution_string)
869 {
870   int saved_escape_html = escape_html;
871   int saved_in_paragraph = in_paragraph;
872   escape_html = me_executing_string == 0;
873   in_paragraph = 0;
874   
875   pushfile ();
876   input_text_offset = 0;
877   /* The following xstrdup is so we can relocate input_text at will.  */
878   input_text = xstrdup (execution_string);
879   input_filename = xstrdup (input_filename);
880   input_text_length = strlen (execution_string);
881
882   remember_itext (input_text, 0);
883
884   me_executing_string++;
885   reader_loop ();
886   free (input_text);
887   free (input_filename);
888   popfile ();
889   me_executing_string--;
890
891   in_paragraph = saved_in_paragraph;
892   escape_html = saved_escape_html;
893 }
894
895 /* A wrapper around me_execute_string which saves and restores
896    variables important for output generation.  This is called
897    when we need to produce macro-expanded output for input which
898    leaves no traces in the Info output.  */
899 void
900 me_execute_string_keep_state (char *execution_string, char *append_string)
901 {
902   int op_orig, opcol_orig, popen_orig;
903   int fill_orig, newline_orig, indent_orig, meta_pos_orig;
904
905   remember_itext (input_text, input_text_offset);
906   op_orig = output_paragraph_offset;
907   meta_pos_orig = meta_char_pos;
908   opcol_orig = output_column;
909   popen_orig = paragraph_is_open;
910   fill_orig = filling_enabled;
911   newline_orig = last_char_was_newline;
912   filling_enabled = 0;
913   indent_orig = no_indent;
914   no_indent = 1;
915   me_execute_string (execution_string);
916   if (append_string)
917     write_region_to_macro_output (append_string, 0, strlen (append_string));
918   output_paragraph_offset = op_orig;
919   meta_char_pos = meta_pos_orig;
920   output_column = opcol_orig;
921   paragraph_is_open = popen_orig;
922   filling_enabled = fill_orig;
923   last_char_was_newline = newline_orig;
924   no_indent = indent_orig;
925 }
926
927 /* Append the text which appears in input_text from the last offset to
928    the current OFFSET. */
929 void
930 append_to_expansion_output (int offset)
931 {
932   int i;
933   ITEXT *itext = NULL;
934
935   for (i = 0; i < itext_size; i++)
936     if (itext_info[i] && itext_info[i]->pointer == input_text)
937       {
938         itext = itext_info[i];
939         break;
940       }
941
942   if (!itext)
943     return;
944
945   if (offset > itext->offset)
946     {
947       write_region_to_macro_output (input_text, itext->offset, offset);
948       remember_itext (input_text, offset);
949     }
950 }
951
952 /* Only write this input text iff it appears in our itext list. */
953 void
954 maybe_write_itext (char *pointer, int offset)
955 {
956   int i;
957   ITEXT *itext = NULL;
958
959   for (i = 0; i < itext_size; i++)
960     if (itext_info[i] && (itext_info[i]->pointer == pointer))
961       {
962         itext = itext_info[i];
963         break;
964       }
965
966   if (itext && (itext->offset < offset))
967     {
968       write_region_to_macro_output (itext->pointer, itext->offset, offset);
969       remember_itext (pointer, offset);
970     }
971 }
972
973 void
974 write_region_to_macro_output (char *string, int start, int end)
975 {
976   if (macro_expansion_output_stream)
977     fwrite (string + start, 1, end - start, macro_expansion_output_stream);
978 }
979 \f
980 /* Aliases. */
981
982 typedef struct alias_struct
983 {
984   char *alias;
985   char *mapto;
986   struct alias_struct *next;
987 } alias_type;
988
989 static alias_type *aliases; 
990
991 /* @alias aname = cmdname */
992
993 void
994 cm_alias (void)
995 {
996   alias_type *a = xmalloc (sizeof (alias_type));
997
998   skip_whitespace ();
999   get_until_in_line (0, "=", &(a->alias));
1000   canon_white (a->alias);
1001
1002   discard_until ("=");
1003   skip_whitespace ();
1004   get_until_in_line (0, " ", &(a->mapto));
1005
1006   a->next = aliases;
1007   aliases = a;
1008 }
1009
1010 /* Perform an alias expansion.  Called from read_command.  */
1011 char *
1012 alias_expand (char *tok)
1013 {
1014   alias_type *findit = aliases;
1015
1016   while (findit)
1017     if (strcmp (findit->alias, tok) == 0)
1018       {
1019         free (tok);
1020         return alias_expand (xstrdup (findit->mapto));
1021       }
1022     else
1023       findit = findit->next;
1024
1025   return tok;
1026 }
1027 \f
1028 /* definfoenclose implementation.  */
1029
1030 /* This structure is used to track enclosure macros.  When an enclosure
1031    macro is recognized, a pointer to the enclosure block corresponding 
1032    to its name is saved in the brace element for its argument. */
1033 typedef struct enclose_struct
1034 {
1035   char *enclose;
1036   char *before;
1037   char *after;
1038   struct enclose_struct *next;
1039 } enclosure_type;
1040
1041 static enclosure_type *enclosures; 
1042
1043 typedef struct enclosure_stack_struct
1044 {
1045     enclosure_type *current;
1046     struct enclosure_stack_struct *next;
1047 } enclosure_stack_type;
1048
1049 static enclosure_stack_type *enclosure_stack;
1050
1051 /* @definfoenclose */
1052 void
1053 cm_definfoenclose (void)
1054 {
1055   enclosure_type *e = xmalloc (sizeof (enclosure_type));
1056
1057   skip_whitespace ();
1058   get_until_in_line (1, ",", &(e->enclose));
1059   discard_until (",");
1060   get_until_in_line (0, ",", &(e->before));
1061   discard_until (",");
1062   get_until_in_line (0, "\n", &(e->after));
1063
1064   e->next = enclosures;
1065   enclosures = e;
1066 }
1067
1068 /* If TOK is an enclosure command, push it on the enclosure stack and
1069    return 1.  Else return 0.  */
1070
1071 int
1072 enclosure_command (char *tok)
1073 {
1074   enclosure_type *findit = enclosures;
1075
1076   while (findit)
1077     if (strcmp (findit->enclose, tok) == 0)
1078       {
1079         enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type));
1080         new->current = findit;
1081         new->next = enclosure_stack;
1082         enclosure_stack = new;
1083
1084         return 1;
1085       }
1086     else
1087       findit = findit->next;
1088
1089   return 0;
1090 }
1091
1092 /* actually perform the enclosure expansion */
1093 void
1094 enclosure_expand (int arg, int start, int end)
1095 {
1096   if (arg == START)
1097     add_word (enclosure_stack->current->before);
1098   else
1099     {
1100       enclosure_stack_type *temp;
1101
1102       add_word (enclosure_stack->current->after);
1103
1104       temp = enclosure_stack;
1105       enclosure_stack = enclosure_stack->next;
1106       free (temp);
1107     }
1108 }