xref: /openbsd/gnu/usr.bin/texinfo/makeinfo/macro.c (revision a1acfa9b)
1 /* macro.c -- user-defined macros for Texinfo.
2    $Id: macro.c,v 1.1.1.3 2006/07/17 16:03:47 espie 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 
56 /* Return the length of the array in ARRAY. */
57 int
array_len(char ** array)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
free_array(char ** array)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 
81 /* Return the macro definition of NAME or NULL if NAME is not defined. */
82 MACRO_DEF *
find_macro(char * name)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
add_macro(char * name,char ** arglist,char * body,char * source_file,int source_lineno,int flags)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 **
get_brace_args(int quote_single)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 **
get_macro_args(MACRO_DEF * def)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 *
apply(char ** named,char ** actuals,char * body)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 *
expand_macro(MACRO_DEF * def)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
execute_macro(MACRO_DEF * def)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 
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
define_macro(char * mactype,int recursive)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
cm_macro(void)703 cm_macro (void)
704 {
705   define_macro ("macro", 0);
706 }
707 
708 void
cm_rmacro(void)709 cm_rmacro (void)
710 {
711   define_macro ("rmacro", 1);
712 }
713 
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 *
delete_macro(char * name)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
cm_unmacro(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 
782 /* How to output sections of the input file verbatim. */
783 
784 /* Set the value of POINTER's offset to OFFSET. */
785 ITEXT *
remember_itext(char * pointer,int offset)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
forget_itext(char * pointer)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
me_append_before_this_command(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
me_execute_string(char * execution_string)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
me_execute_string_keep_state(char * execution_string,char * append_string)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
append_to_expansion_output(int offset)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
maybe_write_itext(char * pointer,int offset)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
write_region_to_macro_output(char * string,int start,int end)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 
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
cm_alias(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 *
alias_expand(char * tok)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 
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
cm_definfoenclose(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
enclosure_command(char * tok)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
enclosure_expand(int arg,int start,int end)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 }
1109