Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / texinfo / makeinfo / macro.c
1 /* macro.c -- user-defined macros for Texinfo.
2    $Id: macro.c,v 1.12 2002/03/02 15:05:21 karl Exp $
3
4    Copyright (C) 1998, 99, 2002 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 \f
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 \f
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 \f
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           file_line_error (input_filename, defining_line,
594                            _("%cend macro not found"), COMMAND_PREFIX);
595           return;
596         }
597
598       get_rest_of_line (0, &line);
599
600       /* Handle commands only meaningful within a macro. */
601       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
602           (strncmp (line + 1, "allow-recursion", 15) == 0) &&
603           (line[16] == 0 || whitespace (line[16])))
604         {
605           for (i = 16; whitespace (line[i]); i++);
606           strcpy (line, line + i);
607           flags |= ME_RECURSE;
608           if (!*line)
609             {
610               free (line);
611               continue;
612             }
613         }
614
615       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
616           (strncmp (line + 1, "quote-arg", 9) == 0) &&
617           (line[10] == 0 || whitespace (line[10])))
618         {
619           for (i = 10; whitespace (line[i]); i++);
620           strcpy (line, line + i);
621
622           if (arglist && arglist[0] && !arglist[1])
623             {
624               flags |= ME_QUOTE_ARG;
625               if (!*line)
626                 {
627                   free (line);
628                   continue;
629                 }
630             }
631           else
632            line_error (_("@quote-arg only useful for single-argument macros"));
633         }
634
635       if (*line == COMMAND_PREFIX
636           && (strncmp (line + 1, "macro ", 6) == 0
637               || strncmp (line + 1, "rmacro ", 7) == 0))
638         depth++;
639
640       /* Incorrect implementation of nesting -- just check that the last
641          @end matches what we started with.  Since nested macros don't
642          work in TeX anyway, this isn't worth the trouble to get right.  */
643       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0)
644         {
645           depth--;
646           last_end = "macro";
647         }
648       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 9) == 0)
649         {
650           depth--;
651           last_end = "rmacro";
652         }
653
654       if (depth)
655         {
656           if ((body_index + strlen (line) + 3) >= body_size)
657             body = xrealloc (body, body_size += 3 + strlen (line));
658           strcpy (body + body_index, line);
659           body_index += strlen (line);
660           body[body_index++] = '\n';
661           body[body_index] = 0;
662         }
663       free (line);
664     }
665
666   /* Check that @end matched the macro command.  */
667   if (!STREQ (last_end, mactype))
668     warning (_("mismatched @end %s with @%s"), last_end, mactype);
669
670   /* If it was an empty macro like
671      @macro foo
672      @end macro
673      create an empty body.  (Otherwise, the macro is not expanded.)  */
674   if (!body)
675     {
676       body = (char *)malloc(1);
677       *body = 0;
678     }
679
680   /* We now have the name, the arglist, and the body.  However, BODY
681      includes the final newline which preceded the `@end macro' text.
682      Delete it. */
683   if (body && strlen (body))
684     body[strlen (body) - 1] = 0;
685
686   if (recursive)
687     flags |= ME_RECURSE;
688     
689   add_macro (name, arglist, body, input_filename, defining_line, flags);
690
691   if (macro_expansion_output_stream && !executing_string)
692     remember_itext (input_text, input_text_offset);
693 }
694
695 void 
696 cm_macro ()
697 {
698   define_macro ("macro", 0);
699 }
700
701 void 
702 cm_rmacro ()
703 {
704   define_macro ("rmacro", 1);
705 }
706 \f
707 /* Delete the macro with name NAME.  The macro is deleted from the list,
708    but it is also returned.  If there was no macro defined, NULL is
709    returned. */
710
711 static MACRO_DEF *
712 delete_macro (name)
713      char *name;
714 {
715   int i;
716   MACRO_DEF *def;
717
718   def = NULL;
719
720   for (i = 0; macro_list && (def = macro_list[i]); i++)
721     if (strcmp (def->name, name) == 0)
722       {
723         memmove (macro_list + i, macro_list + i + 1,
724                ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
725         macro_list_len--;
726         break;
727       }
728   return def;
729 }
730
731 void
732 cm_unmacro ()
733 {
734   int i;
735   char *line, *name;
736   MACRO_DEF *def;
737
738   if (macro_expansion_output_stream && !executing_string)
739     me_append_before_this_command ();
740
741   get_rest_of_line (0, &line);
742
743   for (i = 0; line[i] && !whitespace (line[i]); i++);
744   name = xmalloc (i + 1);
745   memcpy (name, line, i);
746   name[i] = 0;
747
748   def = delete_macro (name);
749
750   if (def)
751     {
752       free (def->source_file);
753       free (def->name);
754       free (def->body);
755
756       if (def->arglist)
757         {
758           int i;
759
760           for (i = 0; def->arglist[i]; i++)
761             free (def->arglist[i]);
762
763           free (def->arglist);
764         }
765
766       free (def);
767     }
768
769   free (line);
770   free (name);
771
772   if (macro_expansion_output_stream && !executing_string)
773     remember_itext (input_text, input_text_offset);
774 }
775 \f
776 /* How to output sections of the input file verbatim. */
777
778 /* Set the value of POINTER's offset to OFFSET. */
779 ITEXT *
780 remember_itext (pointer, offset)
781      char *pointer;
782      int offset;
783 {
784   int i;
785   ITEXT *itext = NULL;
786
787   /* If we have no info, initialize a blank list. */
788   if (!itext_info)
789     {
790       itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
791       for (i = 0; i < itext_size; i++)
792         itext_info[i] = NULL;
793     }
794
795   /* If the pointer is already present in the list, then set the offset. */
796   for (i = 0; i < itext_size; i++)
797     if ((itext_info[i]) &&
798         (itext_info[i]->pointer == pointer))
799       {
800         itext = itext_info[i];
801         itext_info[i]->offset = offset;
802         break;
803       }
804
805   if (i == itext_size)
806     {
807       /* Find a blank slot (or create a new one), and remember the
808          pointer and offset. */
809       for (i = 0; i < itext_size; i++)
810         if (itext_info[i] == NULL)
811           break;
812
813       /* If not found, then add some slots. */
814       if (i == itext_size)
815         {
816           int j;
817
818           itext_info = xrealloc
819             (itext_info, (itext_size += 10) * sizeof (ITEXT *));
820
821           for (j = i; j < itext_size; j++)
822             itext_info[j] = NULL;
823         }
824
825       /* Now add the pointer and the offset. */
826       itext_info[i] = xmalloc (sizeof (ITEXT));
827       itext_info[i]->pointer = pointer;
828       itext_info[i]->offset = offset;
829       itext = itext_info[i];
830     }
831   return itext;
832 }
833
834 /* Forget the input text associated with POINTER. */
835 void
836 forget_itext (pointer)
837      char *pointer;
838 {
839   int i;
840
841   for (i = 0; i < itext_size; i++)
842     if (itext_info[i] && (itext_info[i]->pointer == pointer))
843       {
844         free (itext_info[i]);
845         itext_info[i] = NULL;
846         break;
847       }
848 }
849
850 /* Append the text which appeared in input_text from the last offset to
851    the character just before the command that we are currently executing. */
852 void
853 me_append_before_this_command ()
854 {
855   int i;
856
857   for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
858     ;
859   maybe_write_itext (input_text, i);
860 }
861
862 /* Similar to execute_string, but only takes a single string argument,
863    and remembers the input text location, etc. */
864 void
865 me_execute_string (execution_string)
866      char *execution_string;
867 {
868   int saved_escape_html = escape_html;
869   int saved_in_paragraph = in_paragraph;
870   escape_html = me_executing_string == 0;
871   in_paragraph = 0;
872   
873   pushfile ();
874   input_text_offset = 0;
875   /* The following xstrdup is so we can relocate input_text at will.  */
876   input_text = xstrdup (execution_string);
877   input_filename = xstrdup (input_filename);
878   input_text_length = strlen (execution_string);
879
880   remember_itext (input_text, 0);
881
882   me_executing_string++;
883   reader_loop ();
884   free (input_text);
885   free (input_filename);
886   popfile ();
887   me_executing_string--;
888
889   in_paragraph = saved_in_paragraph;
890   escape_html = saved_escape_html;
891 }
892
893 /* A wrapper around me_execute_string which saves and restores
894    variables important for output generation.  This is called
895    when we need to produce macro-expanded output for input which
896    leaves no traces in the Info output.  */
897 void
898 me_execute_string_keep_state (execution_string, append_string)
899      char *execution_string, *append_string;
900 {
901   int op_orig, opcol_orig, popen_orig;
902   int fill_orig, newline_orig, indent_orig, meta_pos_orig;
903
904   remember_itext (input_text, input_text_offset);
905   op_orig = output_paragraph_offset;
906   meta_pos_orig = meta_char_pos;
907   opcol_orig = output_column;
908   popen_orig = paragraph_is_open;
909   fill_orig = filling_enabled;
910   newline_orig = last_char_was_newline;
911   filling_enabled = 0;
912   indent_orig = no_indent;
913   no_indent = 1;
914   me_execute_string (execution_string);
915   if (append_string)
916     write_region_to_macro_output (append_string, 0, strlen (append_string));
917   output_paragraph_offset = op_orig;
918   meta_char_pos = meta_pos_orig;
919   output_column = opcol_orig;
920   paragraph_is_open = popen_orig;
921   filling_enabled = fill_orig;
922   last_char_was_newline = newline_orig;
923   no_indent = indent_orig;
924 }
925
926 /* Append the text which appears in input_text from the last offset to
927    the current OFFSET. */
928 void
929 append_to_expansion_output (offset)
930      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 (pointer, offset)
955      char *pointer;
956      int offset;
957 {
958   int i;
959   ITEXT *itext = NULL;
960
961   for (i = 0; i < itext_size; i++)
962     if (itext_info[i] && (itext_info[i]->pointer == pointer))
963       {
964         itext = itext_info[i];
965         break;
966       }
967
968   if (itext && (itext->offset < offset))
969     {
970       write_region_to_macro_output (itext->pointer, itext->offset, offset);
971       remember_itext (pointer, offset);
972     }
973 }
974
975 void
976 write_region_to_macro_output (string, start, end)
977      char *string;
978      int start, end;
979 {
980   if (macro_expansion_output_stream)
981     fwrite (string + start, 1, end - start, macro_expansion_output_stream);
982 }
983 \f
984 /* Aliases. */
985
986 typedef struct alias_struct
987 {
988   char *alias;
989   char *mapto;
990   struct alias_struct *next;
991 } alias_type;
992
993 static alias_type *aliases; 
994
995 /* @alias */
996 void
997 cm_alias ()
998 {
999   alias_type *a = xmalloc (sizeof (alias_type));
1000
1001   skip_whitespace ();
1002   get_until_in_line (1, "=", &(a->alias));
1003   canon_white (a->alias);
1004
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 \f
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 }