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