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