1178481Sjb/* macro.c -- user-defined macros for Texinfo.
2178481Sjb   $Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp $
3178481Sjb
4178481Sjb   Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
5178481Sjb
6178481Sjb   This program is free software; you can redistribute it and/or modify
7178481Sjb   it under the terms of the GNU General Public License as published by
8178481Sjb   the Free Software Foundation; either version 2, or (at your option)
9178481Sjb   any later version.
10178481Sjb
11178481Sjb   This program is distributed in the hope that it will be useful,
12178481Sjb   but WITHOUT ANY WARRANTY; without even the implied warranty of
13178481Sjb   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14178481Sjb   GNU General Public License for more details.
15178481Sjb
16178481Sjb   You should have received a copy of the GNU General Public License
17178481Sjb   along with this program; if not, write to the Free Software Foundation,
18178481Sjb   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19178481Sjb
20178481Sjb#include "system.h"
21178481Sjb#include "cmds.h"
22210767Srpaulo#include "files.h"
23178481Sjb#include "macro.h"
24178481Sjb#include "makeinfo.h"
25178481Sjb#include "insertion.h"
26178481Sjb
27178481Sjb/* If non-NULL, this is an output stream to write the full macro expansion
28178481Sjb   of the input text to.  The result is another texinfo file, but
29178481Sjb   missing @include, @infoinclude, @macro, and macro invocations.  Instead,
30178481Sjb   all of the text is placed within the file. */
31178481SjbFILE *macro_expansion_output_stream = NULL;
32178481Sjb
33178481Sjb/* Output file for -E.  */
34178481Sjbchar *macro_expansion_filename;
35178481Sjb
36178481Sjb/* Nonzero means a macro string is in execution, as opposed to a file. */
37178481Sjbint me_executing_string = 0;
38178481Sjb
39178481Sjb/* Nonzero means we want only to expand macros and
40178481Sjb   leave everything else intact.  */
41178481Sjbint only_macro_expansion = 0;
42178481Sjb
43178481Sjbstatic ITEXT **itext_info = NULL;
44178481Sjbstatic int itext_size = 0;
45178481Sjb
46178481Sjb/* Return the arglist on the current line.  This can behave in two different
47178481Sjb   ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
48178481Sjbint braces_required_for_macro_args = 0;
49178481Sjb
50178481Sjb/* Array of macros and definitions. */
51178481SjbMACRO_DEF **macro_list = NULL;
52178481Sjb
53178481Sjbint macro_list_len = 0;         /* Number of elements. */
54178481Sjbint macro_list_size = 0;        /* Number of slots in total. */
55178481Sjb
56178481Sjb/* Return the length of the array in ARRAY. */
57178481Sjbint
58178481Sjbarray_len (char **array)
59178481Sjb{
60178481Sjb  int i = 0;
61178481Sjb
62178481Sjb  if (array)
63178481Sjb    for (i = 0; array[i]; i++);
64178481Sjb
65178481Sjb  return i;
66178481Sjb}
67178481Sjb
68178481Sjbvoid
69178481Sjbfree_array (char **array)
70178481Sjb{
71178481Sjb  if (array)
72178481Sjb    {
73178481Sjb      int i;
74178481Sjb      for (i = 0; array[i]; i++)
75178481Sjb        free (array[i]);
76178481Sjb
77178481Sjb      free (array);
78178481Sjb    }
79178481Sjb}
80178481Sjb
81178481Sjb/* Return the macro definition of NAME or NULL if NAME is not defined. */
82178481SjbMACRO_DEF *
83178481Sjbfind_macro (char *name)
84178481Sjb{
85178481Sjb  int i;
86178481Sjb  MACRO_DEF *def;
87210767Srpaulo
88178481Sjb  def = NULL;
89210767Srpaulo  for (i = 0; macro_list && (def = macro_list[i]); i++)
90210767Srpaulo    {
91178481Sjb      if ((!def->inhibited) && (strcmp (def->name, name) == 0))
92178481Sjb        break;
93178481Sjb    }
94178481Sjb  return def;
95178481Sjb}
96178481Sjb
97178481Sjb/* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
98178481Sjb   SOURCE_FILE is the name of the file where this definition can be found,
99178481Sjb   and SOURCE_LINENO is the line number within that file.  If a macro already
100178481Sjb   exists with NAME, then a warning is produced, and that previous
101178481Sjb   definition is overwritten. */
102178481Sjbstatic void
103178481Sjbadd_macro (char *name, char **arglist, char *body, char *source_file,
104178481Sjb    int source_lineno, int flags)
105178481Sjb{
106178481Sjb  MACRO_DEF *def;
107178481Sjb
108178481Sjb  def = find_macro (name);
109178481Sjb
110178481Sjb  if (!def)
111178481Sjb    {
112178481Sjb      if (macro_list_len + 2 >= macro_list_size)
113178481Sjb        macro_list = xrealloc
114178481Sjb          (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
115178481Sjb
116178481Sjb      macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
117178481Sjb      macro_list[macro_list_len + 1] = NULL;
118178481Sjb
119178481Sjb      def = macro_list[macro_list_len];
120178481Sjb      macro_list_len += 1;
121178481Sjb      def->name = name;
122178481Sjb    }
123178481Sjb  else
124178481Sjb    {
125178481Sjb      char *temp_filename = input_filename;
126178481Sjb      int temp_line = line_number;
127178481Sjb
128178481Sjb      warning (_("macro `%s' previously defined"), name);
129178481Sjb
130178481Sjb      input_filename = def->source_file;
131178481Sjb      line_number = def->source_lineno;
132178481Sjb      warning (_("here is the previous definition of `%s'"), name);
133178481Sjb
134178481Sjb      input_filename = temp_filename;
135178481Sjb      line_number = temp_line;
136178481Sjb
137178481Sjb      if (def->arglist)
138178481Sjb        {
139178481Sjb          int i;
140178481Sjb
141178481Sjb          for (i = 0; def->arglist[i]; i++)
142178481Sjb            free (def->arglist[i]);
143178481Sjb
144178481Sjb          free (def->arglist);
145178481Sjb        }
146178481Sjb      free (def->source_file);
147178481Sjb      free (def->body);
148178481Sjb    }
149178481Sjb
150178481Sjb  def->source_file = xstrdup (source_file);
151178481Sjb  def->source_lineno = source_lineno;
152178481Sjb  def->body = body;
153178481Sjb  def->arglist = arglist;
154178481Sjb  def->inhibited = 0;
155178481Sjb  def->flags = flags;
156178481Sjb}
157178481Sjb
158178481Sjb
159178481Sjbchar **
160178481Sjbget_brace_args (int quote_single)
161178481Sjb{
162178481Sjb  char **arglist, *word;
163178481Sjb  int arglist_index, arglist_size;
164178481Sjb  int character, escape_seen, start;
165178481Sjb  int depth = 1;
166178481Sjb
167178481Sjb  /* There is an arglist in braces here, so gather the args inside of it. */
168178481Sjb  skip_whitespace_and_newlines ();
169178481Sjb  input_text_offset++;
170178481Sjb  arglist = NULL;
171178481Sjb  arglist_index = arglist_size = 0;
172178481Sjb
173178481Sjb get_arg:
174178481Sjb  skip_whitespace_and_newlines ();
175178481Sjb  start = input_text_offset;
176178546Sjb  escape_seen = 0;
177178481Sjb
178178546Sjb  while ((character = curchar ()))
179178546Sjb    {
180178481Sjb      if (character == '\\')
181178481Sjb        {
182178481Sjb          input_text_offset += 2;
183178481Sjb          escape_seen = 1;
184178481Sjb        }
185178481Sjb      else if (character == '{')
186178481Sjb        {
187178546Sjb          depth++;
188178481Sjb          input_text_offset++;
189178481Sjb        }
190178481Sjb      else if ((character == ',' && !quote_single) ||
191178481Sjb               ((character == '}') && depth == 1))
192178481Sjb        {
193178481Sjb          int len = input_text_offset - start;
194178481Sjb
195178481Sjb          if (len || (character != '}'))
196178481Sjb            {
197178481Sjb              word = xmalloc (1 + len);
198178481Sjb              memcpy (word, input_text + start, len);
199178481Sjb              word[len] = 0;
200178481Sjb
201178481Sjb              /* Clean up escaped characters. */
202178481Sjb              if (escape_seen)
203178481Sjb                {
204178481Sjb                  int i;
205178481Sjb                  for (i = 0; word[i]; i++)
206178481Sjb                    if (word[i] == '\\')
207178481Sjb                      memmove (word + i, word + i + 1,
208178481Sjb                               1 + strlen (word + i + 1));
209178481Sjb                }
210178481Sjb
211178481Sjb              if (arglist_index + 2 >= arglist_size)
212178481Sjb                arglist = xrealloc
213178481Sjb                  (arglist, (arglist_size += 10) * sizeof (char *));
214178481Sjb
215178481Sjb              arglist[arglist_index++] = word;
216178481Sjb              arglist[arglist_index] = NULL;
217178481Sjb            }
218178481Sjb
219178481Sjb          input_text_offset++;
220178481Sjb          if (character == '}')
221178481Sjb            break;
222178481Sjb          else
223178481Sjb            goto get_arg;
224178481Sjb        }
225178481Sjb      else if (character == '}')
226178481Sjb        {
227178481Sjb          depth--;
228178481Sjb          input_text_offset++;
229178481Sjb        }
230178481Sjb      else
231178481Sjb        {
232178481Sjb          input_text_offset++;
233178481Sjb          if (character == '\n') line_number++;
234178481Sjb        }
235178481Sjb    }
236178481Sjb  return arglist;
237178481Sjb}
238178481Sjb
239178481Sjbstatic char **
240178481Sjbget_macro_args (MACRO_DEF *def)
241178481Sjb{
242178481Sjb  int i;
243178481Sjb  char *word;
244178481Sjb
245178481Sjb  /* Quickly check to see if this macro has been invoked with any arguments.
246178481Sjb     If not, then don't skip any of the following whitespace. */
247178481Sjb  for (i = input_text_offset; i < input_text_length; i++)
248178481Sjb    if (!cr_or_whitespace (input_text[i]))
249178481Sjb      break;
250178481Sjb
251178546Sjb  if (input_text[i] != '{')
252178546Sjb    {
253178481Sjb      if (braces_required_for_macro_args)
254178546Sjb        {
255178481Sjb          return NULL;
256178481Sjb        }
257178481Sjb      else
258178481Sjb        {
259178481Sjb          /* Braces are not required to fill out the macro arguments.  If
260178481Sjb             this macro takes one argument, it is considered to be the
261178546Sjb             remainder of the line, sans whitespace. */
262178481Sjb          if (def->arglist && def->arglist[0] && !def->arglist[1])
263178481Sjb            {
264178481Sjb              char **arglist;
265178481Sjb
266178481Sjb              get_rest_of_line (0, &word);
267178546Sjb              if (input_text[input_text_offset - 1] == '\n')
268178481Sjb                {
269178481Sjb                  input_text_offset--;
270178481Sjb                  line_number--;
271178546Sjb                }
272178481Sjb              /* canon_white (word); */
273178546Sjb              arglist = xmalloc (2 * sizeof (char *));
274178546Sjb              arglist[0] = word;
275178481Sjb              arglist[1] = NULL;
276178481Sjb              return arglist;
277178481Sjb            }
278178481Sjb          else
279178546Sjb            {
280178481Sjb              /* The macro either took no arguments, or took more than
281178481Sjb                 one argument.  In that case, it must be invoked with
282178481Sjb                 arguments surrounded by braces. */
283178481Sjb              return NULL;
284178481Sjb            }
285178481Sjb        }
286178546Sjb    }
287178481Sjb  return get_brace_args (def->flags & ME_QUOTE_ARG);
288178481Sjb}
289178481Sjb
290178481Sjb/* Substitute actual parameters for named parameters in body.
291178481Sjb   The named parameters which appear in BODY must by surrounded
292178481Sjb   reverse slashes, as in \foo\. */
293178481Sjbstatic char *
294178481Sjbapply (char **named, char **actuals, char *body)
295178481Sjb{
296178481Sjb  int i;
297178481Sjb  int new_body_index, new_body_size;
298178481Sjb  char *new_body, *text;
299178481Sjb  int length_of_actuals;
300178481Sjb
301178481Sjb  length_of_actuals = array_len (actuals);
302178481Sjb  new_body_size = strlen (body);
303178481Sjb  new_body = xmalloc (1 + new_body_size);
304178481Sjb
305178481Sjb  /* Copy chars from BODY into NEW_BODY. */
306178481Sjb  i = 0;
307178481Sjb  new_body_index = 0;
308178481Sjb
309178481Sjb  while (body[i])
310178481Sjb    { /* Anything but a \ is easy.  */
311178546Sjb      if (body[i] != '\\')
312178481Sjb        new_body[new_body_index++] = body[i++];
313178546Sjb      else
314178546Sjb        { /* Snarf parameter name, check against named parameters. */
315178481Sjb          char *param;
316178481Sjb          int param_start, len;
317178481Sjb
318178481Sjb          param_start = ++i;
319178481Sjb          while (body[i] && body[i] != '\\')
320178481Sjb            i++;
321178481Sjb
322178481Sjb          len = i - param_start;
323178481Sjb          param = xmalloc (1 + len);
324178481Sjb          memcpy (param, body + param_start, len);
325178481Sjb          param[len] = 0;
326178481Sjb
327178481Sjb          if (body[i]) /* move past \ */
328178481Sjb            i++;
329178481Sjb
330178481Sjb          if (len == 0)
331178481Sjb            { /* \\ always means \, even if macro has no args.  */
332178546Sjb              len++;
333178481Sjb              text = xmalloc (1 + len);
334178481Sjb              sprintf (text, "\\%s", param);
335178481Sjb            }
336178481Sjb          else
337178481Sjb            {
338178481Sjb              int which;
339178481Sjb
340178481Sjb              /* Check against named parameters. */
341178481Sjb              for (which = 0; named && named[which]; which++)
342178481Sjb                if (STREQ (named[which], param))
343178481Sjb                  break;
344178481Sjb
345178481Sjb              if (named && named[which])
346178481Sjb                {
347178481Sjb                  text = which < length_of_actuals ? actuals[which] : NULL;
348178481Sjb                  if (!text)
349178481Sjb                    text = "";
350178481Sjb                  len = strlen (text);
351178481Sjb                  text = xstrdup (text);  /* so we can free it */
352178481Sjb                }
353178481Sjb              else
354178481Sjb                { /* not a parameter, so it's an error.  */
355178481Sjb                  warning (_("\\ in macro expansion followed by `%s' instead of parameter name"),
356178481Sjb                             param);
357178481Sjb                  len++;
358178481Sjb                  text = xmalloc (1 + len);
359178481Sjb                  sprintf (text, "\\%s", param);
360178546Sjb                }
361178481Sjb            }
362178546Sjb
363178481Sjb          if (strlen (param) + 2 < len)
364178481Sjb            {
365178481Sjb              new_body_size += len + 1;
366178481Sjb              new_body = xrealloc (new_body, new_body_size);
367178481Sjb            }
368178481Sjb
369178481Sjb          free (param);
370178481Sjb
371178546Sjb          strcpy (new_body + new_body_index, text);
372178481Sjb          new_body_index += len;
373178481Sjb
374178481Sjb          free (text);
375178481Sjb        }
376178481Sjb    }
377178481Sjb
378178481Sjb  new_body[new_body_index] = 0;
379178481Sjb  return new_body;
380178481Sjb}
381178481Sjb
382178481Sjb/* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
383178481Sjb   return its expansion as a string.  */
384178481Sjbchar *
385178481Sjbexpand_macro (MACRO_DEF *def)
386178481Sjb{
387178481Sjb  char **arglist;
388178481Sjb  int num_args;
389178481Sjb  char *execution_string = NULL;
390178481Sjb  int start_line = line_number;
391178481Sjb
392178481Sjb  /* Find out how many arguments this macro definition takes. */
393178481Sjb  num_args = array_len (def->arglist);
394178481Sjb
395178481Sjb  /* Gather the arguments present on the line if there are any. */
396178481Sjb  arglist = get_macro_args (def);
397178481Sjb
398178481Sjb  if (num_args < array_len (arglist))
399178481Sjb    {
400178481Sjb      free_array (arglist);
401178546Sjb      line_error (_("Macro `%s' called on line %d with too many args"),
402178546Sjb                  def->name, start_line);
403178481Sjb      return execution_string;
404178481Sjb    }
405178481Sjb
406178481Sjb  if (def->body)
407178481Sjb    execution_string = apply (def->arglist, arglist, def->body);
408178481Sjb
409178481Sjb  free_array (arglist);
410178481Sjb  return execution_string;
411178481Sjb}
412178481Sjb
413178481Sjb/* Execute the macro passed in DEF, a pointer to a MACRO_DEF.  */
414178481Sjbvoid
415178481Sjbexecute_macro (MACRO_DEF *def)
416178481Sjb{
417178481Sjb  char *execution_string;
418178546Sjb  int start_line = line_number, end_line;
419178481Sjb
420178481Sjb  if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
421178481Sjb    me_append_before_this_command ();
422178481Sjb
423178481Sjb  execution_string = expand_macro (def);
424178481Sjb  if (!execution_string)
425178481Sjb    return;
426178481Sjb
427178481Sjb  if (def->body)
428178481Sjb    {
429178481Sjb      /* Reset the line number to where the macro arguments began.
430178481Sjb         This makes line numbers reported in error messages correct in
431178481Sjb         case the macro arguments span several lines and the expanded
432178481Sjb         arguments invoke other commands.  */
433178481Sjb      end_line = line_number;
434178481Sjb      line_number = start_line;
435178481Sjb
436178481Sjb      if (macro_expansion_output_stream
437178481Sjb          && !executing_string && !me_inhibit_expansion)
438178481Sjb        {
439178481Sjb          remember_itext (input_text, input_text_offset);
440178481Sjb          me_execute_string (execution_string);
441178481Sjb        }
442178481Sjb      else
443178481Sjb        execute_string ("%s", execution_string);
444178481Sjb
445178481Sjb      free (execution_string);
446178481Sjb      line_number = end_line;
447178481Sjb    }
448178481Sjb}
449178481Sjb
450178481Sjb
451178481Sjb/* Read and remember the definition of a macro.  If RECURSIVE is set,
452178481Sjb   set the ME_RECURSE flag.  MACTYPE is either "macro" or "rmacro", and
453178481Sjb   tells us what the matching @end should be.  */
454178481Sjbstatic void
455178481Sjbdefine_macro (char *mactype, int recursive)
456178481Sjb{
457178481Sjb  int i, start;
458178481Sjb  char *name, *line;
459178481Sjb  char *last_end = NULL;
460178481Sjb  char *body = NULL;
461178481Sjb  char **arglist = NULL;
462178481Sjb  int body_size = 0, body_index = 0;
463178481Sjb  int depth = 1;
464178481Sjb  int flags = 0;
465178481Sjb  int defining_line = line_number;
466178481Sjb
467178481Sjb  if (macro_expansion_output_stream && !executing_string)
468178481Sjb    me_append_before_this_command ();
469178481Sjb
470178481Sjb  skip_whitespace ();
471178481Sjb
472178481Sjb  /* Get the name of the macro.  This is the set of characters which are
473178481Sjb     not whitespace and are not `{' immediately following the @macro. */
474178481Sjb  start = input_text_offset;
475178546Sjb  {
476178481Sjb    int len;
477178481Sjb
478178481Sjb    for (i = start; i < input_text_length && input_text[i] != '{'
479178481Sjb                    && !cr_or_whitespace (input_text[i]);
480178481Sjb         i++) ;
481178481Sjb
482178481Sjb    len = i - start;
483178481Sjb    name = xmalloc (1 + len);
484178481Sjb    memcpy (name, input_text + start, len);
485178481Sjb    name[len] = 0;
486178481Sjb    input_text_offset = i;
487178481Sjb  }
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
702void
703cm_macro (void)
704{
705  define_macro ("macro", 0);
706}
707
708void
709cm_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
718static MACRO_DEF *
719delete_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
737void
738cm_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. */
785ITEXT *
786remember_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. */
839void
840forget_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. */
855void
856me_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. */
867void
868me_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.  */
899void
900me_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. */
929void
930append_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. */
953void
954maybe_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
973void
974write_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
982typedef struct alias_struct
983{
984  char *alias;
985  char *mapto;
986  struct alias_struct *next;
987} alias_type;
988
989static alias_type *aliases;
990
991/* @alias aname = cmdname */
992
993void
994cm_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.  */
1011char *
1012alias_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. */
1033typedef struct enclose_struct
1034{
1035  char *enclose;
1036  char *before;
1037  char *after;
1038  struct enclose_struct *next;
1039} enclosure_type;
1040
1041static enclosure_type *enclosures;
1042
1043typedef struct enclosure_stack_struct
1044{
1045    enclosure_type *current;
1046    struct enclosure_stack_struct *next;
1047} enclosure_stack_type;
1048
1049static enclosure_stack_type *enclosure_stack;
1050
1051/* @definfoenclose */
1052void
1053cm_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
1071int
1072enclosure_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 */
1093void
1094enclosure_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