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. */
33FILE *macro_expansion_output_stream = NULL;
34
35/* Output file for -E.  */
36char *macro_expansion_filename;
37
38/* Nonzero means a macro string is in execution, as opposed to a file. */
39int me_executing_string = 0;
40
41/* Nonzero means we want only to expand macros and
42   leave everything else intact.  */
43int only_macro_expansion = 0;
44
45static ITEXT **itext_info = NULL;
46static 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. */
50int braces_required_for_macro_args = 0;
51
52/* Array of macros and definitions. */
53MACRO_DEF **macro_list = NULL;
54
55int macro_list_len = 0;         /* Number of elements. */
56int macro_list_size = 0;        /* Number of slots in total. */
57
58/* Return the length of the array in ARRAY. */
59int
60array_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
70void
71free_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. */
84MACRO_DEF *
85find_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. */
104static void
105add_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
161char **
162get_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
241static char **
242get_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\. */
295static char *
296apply (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.  */
386char *
387expand_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.  */
416void
417execute_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.  */
456static void
457define_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
704void
705cm_macro (void)
706{
707  define_macro ("macro", 0);
708}
709
710void
711cm_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
720static MACRO_DEF *
721delete_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
739void
740cm_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. */
787ITEXT *
788remember_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. */
841void
842forget_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. */
857void
858me_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. */
869void
870me_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.  */
901void
902me_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. */
931void
932append_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. */
955void
956maybe_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
975void
976write_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
984typedef struct alias_struct
985{
986  char *alias;
987  char *mapto;
988  struct alias_struct *next;
989} alias_type;
990
991static alias_type *aliases;
992
993/* @alias aname = cmdname */
994
995void
996cm_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.  */
1013char *
1014alias_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. */
1035typedef struct enclose_struct
1036{
1037  char *enclose;
1038  char *before;
1039  char *after;
1040  struct enclose_struct *next;
1041} enclosure_type;
1042
1043static enclosure_type *enclosures;
1044
1045typedef struct enclosure_stack_struct
1046{
1047    enclosure_type *current;
1048    struct enclosure_stack_struct *next;
1049} enclosure_stack_type;
1050
1051static enclosure_stack_type *enclosure_stack;
1052
1053/* @definfoenclose */
1054void
1055cm_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
1073int
1074enclosure_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 */
1095void
1096enclosure_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