xref: /openbsd/gnu/usr.bin/texinfo/makeinfo/macro.c (revision a1acfa9b)
11cc83814Sespie /* macro.c -- user-defined macros for Texinfo.
2*a1acfa9bSespie    $Id: macro.c,v 1.1.1.3 2006/07/17 16:03:47 espie Exp $
31cc83814Sespie 
4*a1acfa9bSespie    Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
51cc83814Sespie 
61cc83814Sespie    This program is free software; you can redistribute it and/or modify
71cc83814Sespie    it under the terms of the GNU General Public License as published by
81cc83814Sespie    the Free Software Foundation; either version 2, or (at your option)
91cc83814Sespie    any later version.
101cc83814Sespie 
111cc83814Sespie    This program is distributed in the hope that it will be useful,
121cc83814Sespie    but WITHOUT ANY WARRANTY; without even the implied warranty of
131cc83814Sespie    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141cc83814Sespie    GNU General Public License for more details.
151cc83814Sespie 
161cc83814Sespie    You should have received a copy of the GNU General Public License
171cc83814Sespie    along with this program; if not, write to the Free Software Foundation,
181cc83814Sespie    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
191cc83814Sespie 
201cc83814Sespie #include "system.h"
211cc83814Sespie #include "cmds.h"
22*a1acfa9bSespie #include "files.h"
231cc83814Sespie #include "macro.h"
241cc83814Sespie #include "makeinfo.h"
251cc83814Sespie #include "insertion.h"
261cc83814Sespie 
271cc83814Sespie /* If non-NULL, this is an output stream to write the full macro expansion
281cc83814Sespie    of the input text to.  The result is another texinfo file, but
291cc83814Sespie    missing @include, @infoinclude, @macro, and macro invocations.  Instead,
301cc83814Sespie    all of the text is placed within the file. */
311cc83814Sespie FILE *macro_expansion_output_stream = NULL;
321cc83814Sespie 
331cc83814Sespie /* Output file for -E.  */
341cc83814Sespie char *macro_expansion_filename;
351cc83814Sespie 
361cc83814Sespie /* Nonzero means a macro string is in execution, as opposed to a file. */
371cc83814Sespie int me_executing_string = 0;
381cc83814Sespie 
391cc83814Sespie /* Nonzero means we want only to expand macros and
401cc83814Sespie    leave everything else intact.  */
411cc83814Sespie int only_macro_expansion = 0;
421cc83814Sespie 
431cc83814Sespie static ITEXT **itext_info = NULL;
441cc83814Sespie static int itext_size = 0;
451cc83814Sespie 
461cc83814Sespie /* Return the arglist on the current line.  This can behave in two different
471cc83814Sespie    ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */
481cc83814Sespie int braces_required_for_macro_args = 0;
491cc83814Sespie 
501cc83814Sespie /* Array of macros and definitions. */
511cc83814Sespie MACRO_DEF **macro_list = NULL;
521cc83814Sespie 
531cc83814Sespie int macro_list_len = 0;         /* Number of elements. */
541cc83814Sespie int macro_list_size = 0;        /* Number of slots in total. */
551cc83814Sespie 
561cc83814Sespie /* Return the length of the array in ARRAY. */
571cc83814Sespie int
array_len(char ** array)58*a1acfa9bSespie array_len (char **array)
591cc83814Sespie {
601cc83814Sespie   int i = 0;
611cc83814Sespie 
621cc83814Sespie   if (array)
631cc83814Sespie     for (i = 0; array[i]; i++);
641cc83814Sespie 
651cc83814Sespie   return i;
661cc83814Sespie }
671cc83814Sespie 
681cc83814Sespie void
free_array(char ** array)69*a1acfa9bSespie free_array (char **array)
701cc83814Sespie {
711cc83814Sespie   if (array)
721cc83814Sespie     {
731cc83814Sespie       int i;
741cc83814Sespie       for (i = 0; array[i]; i++)
751cc83814Sespie         free (array[i]);
761cc83814Sespie 
771cc83814Sespie       free (array);
781cc83814Sespie     }
791cc83814Sespie }
801cc83814Sespie 
811cc83814Sespie /* Return the macro definition of NAME or NULL if NAME is not defined. */
821cc83814Sespie MACRO_DEF *
find_macro(char * name)83*a1acfa9bSespie find_macro (char *name)
841cc83814Sespie {
851cc83814Sespie   int i;
861cc83814Sespie   MACRO_DEF *def;
871cc83814Sespie 
881cc83814Sespie   def = NULL;
891cc83814Sespie   for (i = 0; macro_list && (def = macro_list[i]); i++)
901cc83814Sespie     {
911cc83814Sespie       if ((!def->inhibited) && (strcmp (def->name, name) == 0))
921cc83814Sespie         break;
931cc83814Sespie     }
941cc83814Sespie   return def;
951cc83814Sespie }
961cc83814Sespie 
971cc83814Sespie /* Add the macro NAME with ARGLIST and BODY to the list of defined macros.
981cc83814Sespie    SOURCE_FILE is the name of the file where this definition can be found,
991cc83814Sespie    and SOURCE_LINENO is the line number within that file.  If a macro already
1001cc83814Sespie    exists with NAME, then a warning is produced, and that previous
1011cc83814Sespie    definition is overwritten. */
102*a1acfa9bSespie static void
add_macro(char * name,char ** arglist,char * body,char * source_file,int source_lineno,int flags)103*a1acfa9bSespie add_macro (char *name, char **arglist, char *body, char *source_file,
104*a1acfa9bSespie     int source_lineno, int flags)
1051cc83814Sespie {
1061cc83814Sespie   MACRO_DEF *def;
1071cc83814Sespie 
1081cc83814Sespie   def = find_macro (name);
1091cc83814Sespie 
1101cc83814Sespie   if (!def)
1111cc83814Sespie     {
1121cc83814Sespie       if (macro_list_len + 2 >= macro_list_size)
1131cc83814Sespie         macro_list = xrealloc
1141cc83814Sespie           (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *)));
1151cc83814Sespie 
1161cc83814Sespie       macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF));
1171cc83814Sespie       macro_list[macro_list_len + 1] = NULL;
1181cc83814Sespie 
1191cc83814Sespie       def = macro_list[macro_list_len];
1201cc83814Sespie       macro_list_len += 1;
1211cc83814Sespie       def->name = name;
1221cc83814Sespie     }
1231cc83814Sespie   else
1241cc83814Sespie     {
1251cc83814Sespie       char *temp_filename = input_filename;
1261cc83814Sespie       int temp_line = line_number;
1271cc83814Sespie 
1281cc83814Sespie       warning (_("macro `%s' previously defined"), name);
1291cc83814Sespie 
1301cc83814Sespie       input_filename = def->source_file;
1311cc83814Sespie       line_number = def->source_lineno;
1321cc83814Sespie       warning (_("here is the previous definition of `%s'"), name);
1331cc83814Sespie 
1341cc83814Sespie       input_filename = temp_filename;
1351cc83814Sespie       line_number = temp_line;
1361cc83814Sespie 
1371cc83814Sespie       if (def->arglist)
1381cc83814Sespie         {
1391cc83814Sespie           int i;
1401cc83814Sespie 
1411cc83814Sespie           for (i = 0; def->arglist[i]; i++)
1421cc83814Sespie             free (def->arglist[i]);
1431cc83814Sespie 
1441cc83814Sespie           free (def->arglist);
1451cc83814Sespie         }
1461cc83814Sespie       free (def->source_file);
1471cc83814Sespie       free (def->body);
1481cc83814Sespie     }
1491cc83814Sespie 
1501cc83814Sespie   def->source_file = xstrdup (source_file);
1511cc83814Sespie   def->source_lineno = source_lineno;
1521cc83814Sespie   def->body = body;
1531cc83814Sespie   def->arglist = arglist;
1541cc83814Sespie   def->inhibited = 0;
1551cc83814Sespie   def->flags = flags;
1561cc83814Sespie }
1571cc83814Sespie 
1581cc83814Sespie 
1591cc83814Sespie char **
get_brace_args(int quote_single)160*a1acfa9bSespie get_brace_args (int quote_single)
1611cc83814Sespie {
1621cc83814Sespie   char **arglist, *word;
1631cc83814Sespie   int arglist_index, arglist_size;
1641cc83814Sespie   int character, escape_seen, start;
1651cc83814Sespie   int depth = 1;
1661cc83814Sespie 
1671cc83814Sespie   /* There is an arglist in braces here, so gather the args inside of it. */
1681cc83814Sespie   skip_whitespace_and_newlines ();
1691cc83814Sespie   input_text_offset++;
1701cc83814Sespie   arglist = NULL;
1711cc83814Sespie   arglist_index = arglist_size = 0;
1721cc83814Sespie 
1731cc83814Sespie  get_arg:
1741cc83814Sespie   skip_whitespace_and_newlines ();
1751cc83814Sespie   start = input_text_offset;
1761cc83814Sespie   escape_seen = 0;
1771cc83814Sespie 
1781cc83814Sespie   while ((character = curchar ()))
1791cc83814Sespie     {
1801cc83814Sespie       if (character == '\\')
1811cc83814Sespie         {
1821cc83814Sespie           input_text_offset += 2;
1831cc83814Sespie           escape_seen = 1;
1841cc83814Sespie         }
1851cc83814Sespie       else if (character == '{')
1861cc83814Sespie         {
1871cc83814Sespie           depth++;
1881cc83814Sespie           input_text_offset++;
1891cc83814Sespie         }
1901cc83814Sespie       else if ((character == ',' && !quote_single) ||
1911cc83814Sespie                ((character == '}') && depth == 1))
1921cc83814Sespie         {
1931cc83814Sespie           int len = input_text_offset - start;
1941cc83814Sespie 
1951cc83814Sespie           if (len || (character != '}'))
1961cc83814Sespie             {
1971cc83814Sespie               word = xmalloc (1 + len);
1981cc83814Sespie               memcpy (word, input_text + start, len);
1991cc83814Sespie               word[len] = 0;
2001cc83814Sespie 
2011cc83814Sespie               /* Clean up escaped characters. */
2021cc83814Sespie               if (escape_seen)
2031cc83814Sespie                 {
2041cc83814Sespie                   int i;
2051cc83814Sespie                   for (i = 0; word[i]; i++)
2061cc83814Sespie                     if (word[i] == '\\')
2071cc83814Sespie                       memmove (word + i, word + i + 1,
2081cc83814Sespie                                1 + strlen (word + i + 1));
2091cc83814Sespie                 }
2101cc83814Sespie 
2111cc83814Sespie               if (arglist_index + 2 >= arglist_size)
2121cc83814Sespie                 arglist = xrealloc
2131cc83814Sespie                   (arglist, (arglist_size += 10) * sizeof (char *));
2141cc83814Sespie 
2151cc83814Sespie               arglist[arglist_index++] = word;
2161cc83814Sespie               arglist[arglist_index] = NULL;
2171cc83814Sespie             }
2181cc83814Sespie 
2191cc83814Sespie           input_text_offset++;
2201cc83814Sespie           if (character == '}')
2211cc83814Sespie             break;
2221cc83814Sespie           else
2231cc83814Sespie             goto get_arg;
2241cc83814Sespie         }
2251cc83814Sespie       else if (character == '}')
2261cc83814Sespie         {
2271cc83814Sespie           depth--;
2281cc83814Sespie           input_text_offset++;
2291cc83814Sespie         }
2301cc83814Sespie       else
2311cc83814Sespie         {
2321cc83814Sespie           input_text_offset++;
2331cc83814Sespie           if (character == '\n') line_number++;
2341cc83814Sespie         }
2351cc83814Sespie     }
2361cc83814Sespie   return arglist;
2371cc83814Sespie }
2381cc83814Sespie 
239*a1acfa9bSespie static char **
get_macro_args(MACRO_DEF * def)240*a1acfa9bSespie get_macro_args (MACRO_DEF *def)
2411cc83814Sespie {
2421cc83814Sespie   int i;
2431cc83814Sespie   char *word;
2441cc83814Sespie 
2451cc83814Sespie   /* Quickly check to see if this macro has been invoked with any arguments.
2461cc83814Sespie      If not, then don't skip any of the following whitespace. */
2471cc83814Sespie   for (i = input_text_offset; i < input_text_length; i++)
2481cc83814Sespie     if (!cr_or_whitespace (input_text[i]))
2491cc83814Sespie       break;
2501cc83814Sespie 
2511cc83814Sespie   if (input_text[i] != '{')
2521cc83814Sespie     {
2531cc83814Sespie       if (braces_required_for_macro_args)
2541cc83814Sespie         {
2551cc83814Sespie           return NULL;
2561cc83814Sespie         }
2571cc83814Sespie       else
2581cc83814Sespie         {
2591cc83814Sespie           /* Braces are not required to fill out the macro arguments.  If
2601cc83814Sespie              this macro takes one argument, it is considered to be the
2611cc83814Sespie              remainder of the line, sans whitespace. */
2621cc83814Sespie           if (def->arglist && def->arglist[0] && !def->arglist[1])
2631cc83814Sespie             {
2641cc83814Sespie               char **arglist;
2651cc83814Sespie 
2661cc83814Sespie               get_rest_of_line (0, &word);
2671cc83814Sespie               if (input_text[input_text_offset - 1] == '\n')
2681cc83814Sespie                 {
2691cc83814Sespie                   input_text_offset--;
2701cc83814Sespie                   line_number--;
2711cc83814Sespie                 }
2721cc83814Sespie               /* canon_white (word); */
2731cc83814Sespie               arglist = xmalloc (2 * sizeof (char *));
2741cc83814Sespie               arglist[0] = word;
2751cc83814Sespie               arglist[1] = NULL;
2761cc83814Sespie               return arglist;
2771cc83814Sespie             }
2781cc83814Sespie           else
2791cc83814Sespie             {
2801cc83814Sespie               /* The macro either took no arguments, or took more than
2811cc83814Sespie                  one argument.  In that case, it must be invoked with
2821cc83814Sespie                  arguments surrounded by braces. */
2831cc83814Sespie               return NULL;
2841cc83814Sespie             }
2851cc83814Sespie         }
2861cc83814Sespie     }
2871cc83814Sespie   return get_brace_args (def->flags & ME_QUOTE_ARG);
2881cc83814Sespie }
2891cc83814Sespie 
2901cc83814Sespie /* Substitute actual parameters for named parameters in body.
2911cc83814Sespie    The named parameters which appear in BODY must by surrounded
2921cc83814Sespie    reverse slashes, as in \foo\. */
293*a1acfa9bSespie static char *
apply(char ** named,char ** actuals,char * body)294*a1acfa9bSespie apply (char **named, char **actuals, char *body)
2951cc83814Sespie {
2961cc83814Sespie   int i;
2971cc83814Sespie   int new_body_index, new_body_size;
2981cc83814Sespie   char *new_body, *text;
2991cc83814Sespie   int length_of_actuals;
3001cc83814Sespie 
3011cc83814Sespie   length_of_actuals = array_len (actuals);
3021cc83814Sespie   new_body_size = strlen (body);
3031cc83814Sespie   new_body = xmalloc (1 + new_body_size);
3041cc83814Sespie 
3051cc83814Sespie   /* Copy chars from BODY into NEW_BODY. */
3061cc83814Sespie   i = 0;
3071cc83814Sespie   new_body_index = 0;
3081cc83814Sespie 
3091cc83814Sespie   while (body[i])
3101cc83814Sespie     { /* Anything but a \ is easy.  */
3111cc83814Sespie       if (body[i] != '\\')
3121cc83814Sespie         new_body[new_body_index++] = body[i++];
3131cc83814Sespie       else
3141cc83814Sespie         { /* Snarf parameter name, check against named parameters. */
3151cc83814Sespie           char *param;
316*a1acfa9bSespie           int param_start, len;
3171cc83814Sespie 
3181cc83814Sespie           param_start = ++i;
3191cc83814Sespie           while (body[i] && body[i] != '\\')
3201cc83814Sespie             i++;
3211cc83814Sespie 
3221cc83814Sespie           len = i - param_start;
3231cc83814Sespie           param = xmalloc (1 + len);
3241cc83814Sespie           memcpy (param, body + param_start, len);
3251cc83814Sespie           param[len] = 0;
3261cc83814Sespie 
3271cc83814Sespie           if (body[i]) /* move past \ */
3281cc83814Sespie             i++;
3291cc83814Sespie 
330*a1acfa9bSespie           if (len == 0)
331*a1acfa9bSespie             { /* \\ always means \, even if macro has no args.  */
332*a1acfa9bSespie               len++;
333*a1acfa9bSespie               text = xmalloc (1 + len);
334*a1acfa9bSespie               sprintf (text, "\\%s", param);
335*a1acfa9bSespie             }
336*a1acfa9bSespie           else
337*a1acfa9bSespie             {
338*a1acfa9bSespie               int which;
339*a1acfa9bSespie 
340*a1acfa9bSespie               /* Check against named parameters. */
3411cc83814Sespie               for (which = 0; named && named[which]; which++)
3421cc83814Sespie                 if (STREQ (named[which], param))
3431cc83814Sespie                   break;
3441cc83814Sespie 
3451cc83814Sespie               if (named && named[which])
3461cc83814Sespie                 {
3471cc83814Sespie                   text = which < length_of_actuals ? actuals[which] : NULL;
3481cc83814Sespie                   if (!text)
3491cc83814Sespie                     text = "";
3501cc83814Sespie                   len = strlen (text);
351*a1acfa9bSespie                   text = xstrdup (text);  /* so we can free it */
3521cc83814Sespie                 }
3531cc83814Sespie               else
354*a1acfa9bSespie                 { /* not a parameter, so it's an error.  */
355*a1acfa9bSespie                   warning (_("\\ in macro expansion followed by `%s' instead of parameter name"),
3561cc83814Sespie                              param);
3571cc83814Sespie                   len++;
3581cc83814Sespie                   text = xmalloc (1 + len);
3591cc83814Sespie                   sprintf (text, "\\%s", param);
3601cc83814Sespie                 }
361*a1acfa9bSespie             }
3621cc83814Sespie 
3631cc83814Sespie           if (strlen (param) + 2 < len)
3641cc83814Sespie             {
3651cc83814Sespie               new_body_size += len + 1;
3661cc83814Sespie               new_body = xrealloc (new_body, new_body_size);
3671cc83814Sespie             }
3681cc83814Sespie 
3691cc83814Sespie           free (param);
3701cc83814Sespie 
3711cc83814Sespie           strcpy (new_body + new_body_index, text);
3721cc83814Sespie           new_body_index += len;
3731cc83814Sespie 
3741cc83814Sespie           free (text);
3751cc83814Sespie         }
3761cc83814Sespie     }
3771cc83814Sespie 
3781cc83814Sespie   new_body[new_body_index] = 0;
3791cc83814Sespie   return new_body;
3801cc83814Sespie }
3811cc83814Sespie 
3821cc83814Sespie /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and
3831cc83814Sespie    return its expansion as a string.  */
3841cc83814Sespie char *
expand_macro(MACRO_DEF * def)385*a1acfa9bSespie expand_macro (MACRO_DEF *def)
3861cc83814Sespie {
3871cc83814Sespie   char **arglist;
3881cc83814Sespie   int num_args;
3891cc83814Sespie   char *execution_string = NULL;
3901cc83814Sespie   int start_line = line_number;
3911cc83814Sespie 
3921cc83814Sespie   /* Find out how many arguments this macro definition takes. */
3931cc83814Sespie   num_args = array_len (def->arglist);
3941cc83814Sespie 
3951cc83814Sespie   /* Gather the arguments present on the line if there are any. */
3961cc83814Sespie   arglist = get_macro_args (def);
3971cc83814Sespie 
3981cc83814Sespie   if (num_args < array_len (arglist))
3991cc83814Sespie     {
4001cc83814Sespie       free_array (arglist);
4011cc83814Sespie       line_error (_("Macro `%s' called on line %d with too many args"),
4021cc83814Sespie                   def->name, start_line);
4031cc83814Sespie       return execution_string;
4041cc83814Sespie     }
4051cc83814Sespie 
4061cc83814Sespie   if (def->body)
4071cc83814Sespie     execution_string = apply (def->arglist, arglist, def->body);
4081cc83814Sespie 
4091cc83814Sespie   free_array (arglist);
4101cc83814Sespie   return execution_string;
4111cc83814Sespie }
4121cc83814Sespie 
4131cc83814Sespie /* Execute the macro passed in DEF, a pointer to a MACRO_DEF.  */
4141cc83814Sespie void
execute_macro(MACRO_DEF * def)415*a1acfa9bSespie execute_macro (MACRO_DEF *def)
4161cc83814Sespie {
4171cc83814Sespie   char *execution_string;
4181cc83814Sespie   int start_line = line_number, end_line;
4191cc83814Sespie 
4201cc83814Sespie   if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion)
4211cc83814Sespie     me_append_before_this_command ();
4221cc83814Sespie 
4231cc83814Sespie   execution_string = expand_macro (def);
4241cc83814Sespie   if (!execution_string)
4251cc83814Sespie     return;
4261cc83814Sespie 
4271cc83814Sespie   if (def->body)
4281cc83814Sespie     {
4291cc83814Sespie       /* Reset the line number to where the macro arguments began.
4301cc83814Sespie          This makes line numbers reported in error messages correct in
4311cc83814Sespie          case the macro arguments span several lines and the expanded
4321cc83814Sespie          arguments invoke other commands.  */
4331cc83814Sespie       end_line = line_number;
4341cc83814Sespie       line_number = start_line;
4351cc83814Sespie 
436*a1acfa9bSespie       if (macro_expansion_output_stream
437*a1acfa9bSespie           && !executing_string && !me_inhibit_expansion)
4381cc83814Sespie         {
4391cc83814Sespie           remember_itext (input_text, input_text_offset);
4401cc83814Sespie           me_execute_string (execution_string);
4411cc83814Sespie         }
4421cc83814Sespie       else
4431cc83814Sespie         execute_string ("%s", execution_string);
4441cc83814Sespie 
4451cc83814Sespie       free (execution_string);
4461cc83814Sespie       line_number = end_line;
4471cc83814Sespie     }
4481cc83814Sespie }
4491cc83814Sespie 
4501cc83814Sespie 
4511cc83814Sespie /* Read and remember the definition of a macro.  If RECURSIVE is set,
4521cc83814Sespie    set the ME_RECURSE flag.  MACTYPE is either "macro" or "rmacro", and
4531cc83814Sespie    tells us what the matching @end should be.  */
4541cc83814Sespie static void
define_macro(char * mactype,int recursive)455*a1acfa9bSespie define_macro (char *mactype, int recursive)
4561cc83814Sespie {
457*a1acfa9bSespie   int i, start;
458*a1acfa9bSespie   char *name, *line;
459*a1acfa9bSespie   char *last_end = NULL;
460*a1acfa9bSespie   char *body = NULL;
461*a1acfa9bSespie   char **arglist = NULL;
462*a1acfa9bSespie   int body_size = 0, body_index = 0;
4631cc83814Sespie   int depth = 1;
4641cc83814Sespie   int flags = 0;
465*a1acfa9bSespie   int defining_line = line_number;
4661cc83814Sespie 
4671cc83814Sespie   if (macro_expansion_output_stream && !executing_string)
4681cc83814Sespie     me_append_before_this_command ();
4691cc83814Sespie 
4701cc83814Sespie   skip_whitespace ();
4711cc83814Sespie 
4721cc83814Sespie   /* Get the name of the macro.  This is the set of characters which are
4731cc83814Sespie      not whitespace and are not `{' immediately following the @macro. */
474*a1acfa9bSespie   start = input_text_offset;
4751cc83814Sespie   {
4761cc83814Sespie     int len;
4771cc83814Sespie 
478*a1acfa9bSespie     for (i = start; i < input_text_length && input_text[i] != '{'
479*a1acfa9bSespie                     && !cr_or_whitespace (input_text[i]);
4801cc83814Sespie          i++) ;
4811cc83814Sespie 
4821cc83814Sespie     len = i - start;
4831cc83814Sespie     name = xmalloc (1 + len);
4841cc83814Sespie     memcpy (name, input_text + start, len);
4851cc83814Sespie     name[len] = 0;
4861cc83814Sespie     input_text_offset = i;
4871cc83814Sespie   }
4881cc83814Sespie 
4891cc83814Sespie   skip_whitespace ();
4901cc83814Sespie 
4911cc83814Sespie   /* It is not required that the definition of a macro includes an arglist.
4921cc83814Sespie      If not, don't try to get the named parameters, just use a null list. */
4931cc83814Sespie   if (curchar () == '{')
4941cc83814Sespie     {
4951cc83814Sespie       int character;
4961cc83814Sespie       int arglist_index = 0, arglist_size = 0;
4971cc83814Sespie       int gathering_words = 1;
4981cc83814Sespie       char *word = NULL;
4991cc83814Sespie 
5001cc83814Sespie       /* Read the words inside of the braces which determine the arglist.
5011cc83814Sespie          These words will be replaced within the body of the macro at
5021cc83814Sespie          execution time. */
5031cc83814Sespie 
5041cc83814Sespie       input_text_offset++;
5051cc83814Sespie       skip_whitespace_and_newlines ();
5061cc83814Sespie 
5071cc83814Sespie       while (gathering_words)
5081cc83814Sespie         {
5091cc83814Sespie           int len;
5101cc83814Sespie 
5111cc83814Sespie           for (i = input_text_offset;
5121cc83814Sespie                (character = input_text[i]);
5131cc83814Sespie                i++)
5141cc83814Sespie             {
5151cc83814Sespie               switch (character)
5161cc83814Sespie                 {
5171cc83814Sespie                 case '\n':
5181cc83814Sespie                   line_number++;
5191cc83814Sespie                 case ' ':
5201cc83814Sespie                 case '\t':
5211cc83814Sespie                 case ',':
5221cc83814Sespie                 case '}':
5231cc83814Sespie                   /* Found the end of the current arglist word.  Save it. */
5241cc83814Sespie                   len = i - input_text_offset;
5251cc83814Sespie                   word = xmalloc (1 + len);
5261cc83814Sespie                   memcpy (word, input_text + input_text_offset, len);
5271cc83814Sespie                   word[len] = 0;
5281cc83814Sespie                   input_text_offset = i;
5291cc83814Sespie 
5301cc83814Sespie                   /* Advance to the comma or close-brace that signified
5311cc83814Sespie                      the end of the argument. */
5321cc83814Sespie                   while ((character = curchar ())
5331cc83814Sespie                          && character != ','
5341cc83814Sespie                          && character != '}')
5351cc83814Sespie                     {
5361cc83814Sespie                       input_text_offset++;
5371cc83814Sespie                       if (character == '\n')
5381cc83814Sespie                         line_number++;
5391cc83814Sespie                     }
5401cc83814Sespie 
5411cc83814Sespie                   /* Add the word to our list of words. */
5421cc83814Sespie                   if (arglist_index + 2 >= arglist_size)
5431cc83814Sespie                     {
5441cc83814Sespie                       arglist_size += 10;
5451cc83814Sespie                       arglist = xrealloc (arglist,
5461cc83814Sespie                                           arglist_size * sizeof (char *));
5471cc83814Sespie                     }
5481cc83814Sespie 
5491cc83814Sespie                   arglist[arglist_index++] = word;
5501cc83814Sespie                   arglist[arglist_index] = NULL;
5511cc83814Sespie                   break;
5521cc83814Sespie                 }
5531cc83814Sespie 
5541cc83814Sespie               if (character == '}')
5551cc83814Sespie                 {
5561cc83814Sespie                   input_text_offset++;
5571cc83814Sespie                   gathering_words = 0;
5581cc83814Sespie                   break;
5591cc83814Sespie                 }
5601cc83814Sespie 
5611cc83814Sespie               if (character == ',')
5621cc83814Sespie                 {
5631cc83814Sespie                   input_text_offset++;
5641cc83814Sespie                   skip_whitespace_and_newlines ();
5651cc83814Sespie                   i = input_text_offset - 1;
5661cc83814Sespie                 }
5671cc83814Sespie             }
5681cc83814Sespie         }
5691cc83814Sespie 
5701cc83814Sespie       /* If we have exactly one argument, do @quote-arg implicitly.  Not
5711cc83814Sespie          only does this match TeX's behavior (which can't feasibly be
5721cc83814Sespie          changed), but it's a good idea.  */
5731cc83814Sespie       if (arglist_index == 1)
5741cc83814Sespie         flags |= ME_QUOTE_ARG;
5751cc83814Sespie     }
5761cc83814Sespie 
5771cc83814Sespie   /* Read the text carefully until we find an "@end macro" which
5781cc83814Sespie      matches this one.  The text in between is the body of the macro. */
5791cc83814Sespie   skip_whitespace_and_newlines ();
5801cc83814Sespie 
5811cc83814Sespie   while (depth)
5821cc83814Sespie     {
5831cc83814Sespie       if ((input_text_offset + 9) > input_text_length)
5841cc83814Sespie         {
5853fb98d4aSespie           file_line_error (input_filename, defining_line,
5863fb98d4aSespie 			   _("%cend macro not found"), COMMAND_PREFIX);
5871cc83814Sespie           return;
5881cc83814Sespie         }
5891cc83814Sespie 
5901cc83814Sespie       get_rest_of_line (0, &line);
5911cc83814Sespie 
5921cc83814Sespie       /* Handle commands only meaningful within a macro. */
5931cc83814Sespie       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
5941cc83814Sespie           (strncmp (line + 1, "allow-recursion", 15) == 0) &&
5951cc83814Sespie           (line[16] == 0 || whitespace (line[16])))
5961cc83814Sespie         {
5971cc83814Sespie           for (i = 16; whitespace (line[i]); i++);
5981cc83814Sespie           strcpy (line, line + i);
5991cc83814Sespie           flags |= ME_RECURSE;
6001cc83814Sespie           if (!*line)
6011cc83814Sespie             {
6021cc83814Sespie               free (line);
6031cc83814Sespie               continue;
6041cc83814Sespie             }
6051cc83814Sespie         }
6061cc83814Sespie 
6071cc83814Sespie       if ((*line == COMMAND_PREFIX) && (depth == 1) &&
6081cc83814Sespie           (strncmp (line + 1, "quote-arg", 9) == 0) &&
6091cc83814Sespie           (line[10] == 0 || whitespace (line[10])))
6101cc83814Sespie         {
6111cc83814Sespie           for (i = 10; whitespace (line[i]); i++);
6121cc83814Sespie           strcpy (line, line + i);
6131cc83814Sespie 
6141cc83814Sespie           if (arglist && arglist[0] && !arglist[1])
6151cc83814Sespie             {
6161cc83814Sespie               flags |= ME_QUOTE_ARG;
6171cc83814Sespie               if (!*line)
6181cc83814Sespie                 {
6191cc83814Sespie                   free (line);
6201cc83814Sespie                   continue;
6211cc83814Sespie                 }
6221cc83814Sespie             }
6231cc83814Sespie           else
6241cc83814Sespie            line_error (_("@quote-arg only useful for single-argument macros"));
6251cc83814Sespie         }
6261cc83814Sespie 
6271cc83814Sespie       if (*line == COMMAND_PREFIX
6281cc83814Sespie           && (strncmp (line + 1, "macro ", 6) == 0
6291cc83814Sespie               || strncmp (line + 1, "rmacro ", 7) == 0))
6301cc83814Sespie         depth++;
6311cc83814Sespie 
6321cc83814Sespie       /* Incorrect implementation of nesting -- just check that the last
6331cc83814Sespie          @end matches what we started with.  Since nested macros don't
6341cc83814Sespie          work in TeX anyway, this isn't worth the trouble to get right.  */
6351cc83814Sespie       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0)
6361cc83814Sespie         {
6371cc83814Sespie           depth--;
6381cc83814Sespie           last_end = "macro";
6391cc83814Sespie         }
640*a1acfa9bSespie       if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0)
6411cc83814Sespie         {
6421cc83814Sespie           depth--;
6431cc83814Sespie           last_end = "rmacro";
6441cc83814Sespie         }
6451cc83814Sespie 
6461cc83814Sespie       if (depth)
6471cc83814Sespie         {
6481cc83814Sespie           if ((body_index + strlen (line) + 3) >= body_size)
6491cc83814Sespie             body = xrealloc (body, body_size += 3 + strlen (line));
6501cc83814Sespie           strcpy (body + body_index, line);
6511cc83814Sespie           body_index += strlen (line);
6521cc83814Sespie           body[body_index++] = '\n';
6531cc83814Sespie           body[body_index] = 0;
6541cc83814Sespie         }
6551cc83814Sespie       free (line);
6561cc83814Sespie     }
6571cc83814Sespie 
6581cc83814Sespie   /* Check that @end matched the macro command.  */
6591cc83814Sespie   if (!STREQ (last_end, mactype))
6601cc83814Sespie     warning (_("mismatched @end %s with @%s"), last_end, mactype);
6611cc83814Sespie 
6621cc83814Sespie   /* If it was an empty macro like
6631cc83814Sespie      @macro foo
6641cc83814Sespie      @end macro
6651cc83814Sespie      create an empty body.  (Otherwise, the macro is not expanded.)  */
6661cc83814Sespie   if (!body)
6671cc83814Sespie     {
6681cc83814Sespie       body = (char *)malloc(1);
6691cc83814Sespie       *body = 0;
6701cc83814Sespie     }
6711cc83814Sespie 
6721cc83814Sespie   /* We now have the name, the arglist, and the body.  However, BODY
6731cc83814Sespie      includes the final newline which preceded the `@end macro' text.
6741cc83814Sespie      Delete it. */
6751cc83814Sespie   if (body && strlen (body))
6761cc83814Sespie     body[strlen (body) - 1] = 0;
6771cc83814Sespie 
6781cc83814Sespie   if (recursive)
6791cc83814Sespie     flags |= ME_RECURSE;
6801cc83814Sespie 
6811cc83814Sespie   add_macro (name, arglist, body, input_filename, defining_line, flags);
6821cc83814Sespie 
6831cc83814Sespie   if (macro_expansion_output_stream && !executing_string)
684*a1acfa9bSespie     {
685*a1acfa9bSespie       /* Remember text for future expansions.  */
6861cc83814Sespie       remember_itext (input_text, input_text_offset);
687*a1acfa9bSespie 
688*a1acfa9bSespie       /* Bizarrely, output the @macro itself.  This is so texinfo.tex
689*a1acfa9bSespie          will have a chance to read it when texi2dvi calls makeinfo -E.
690*a1acfa9bSespie          The problem is that we don't really expand macros in all
691*a1acfa9bSespie          contexts; a @table's @item is one.  And a fix is not obvious to
692*a1acfa9bSespie          me, since it appears virtually identical to any other internal
693*a1acfa9bSespie          expansion.  Just setting a variable in cm_item caused other
694*a1acfa9bSespie          strange expansion problems.  */
695*a1acfa9bSespie       write_region_to_macro_output ("@", 0, 1);
696*a1acfa9bSespie       write_region_to_macro_output (mactype, 0, strlen (mactype));
697*a1acfa9bSespie       write_region_to_macro_output (" ", 0, 1);
698*a1acfa9bSespie       write_region_to_macro_output (input_text, start, input_text_offset);
699*a1acfa9bSespie     }
7001cc83814Sespie }
7011cc83814Sespie 
7021cc83814Sespie void
cm_macro(void)703*a1acfa9bSespie cm_macro (void)
7041cc83814Sespie {
7051cc83814Sespie   define_macro ("macro", 0);
7061cc83814Sespie }
7071cc83814Sespie 
7081cc83814Sespie void
cm_rmacro(void)709*a1acfa9bSespie cm_rmacro (void)
7101cc83814Sespie {
7111cc83814Sespie   define_macro ("rmacro", 1);
7121cc83814Sespie }
7131cc83814Sespie 
7141cc83814Sespie /* Delete the macro with name NAME.  The macro is deleted from the list,
7151cc83814Sespie    but it is also returned.  If there was no macro defined, NULL is
7161cc83814Sespie    returned. */
7171cc83814Sespie 
7181cc83814Sespie static MACRO_DEF *
delete_macro(char * name)719*a1acfa9bSespie delete_macro (char *name)
7201cc83814Sespie {
7211cc83814Sespie   int i;
7221cc83814Sespie   MACRO_DEF *def;
7231cc83814Sespie 
7241cc83814Sespie   def = NULL;
7251cc83814Sespie 
7261cc83814Sespie   for (i = 0; macro_list && (def = macro_list[i]); i++)
7271cc83814Sespie     if (strcmp (def->name, name) == 0)
7281cc83814Sespie       {
7291cc83814Sespie         memmove (macro_list + i, macro_list + i + 1,
7301cc83814Sespie                ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *));
7311cc83814Sespie         macro_list_len--;
7321cc83814Sespie         break;
7331cc83814Sespie       }
7341cc83814Sespie   return def;
7351cc83814Sespie }
7361cc83814Sespie 
7371cc83814Sespie void
cm_unmacro(void)738*a1acfa9bSespie cm_unmacro (void)
7391cc83814Sespie {
7401cc83814Sespie   int i;
7411cc83814Sespie   char *line, *name;
7421cc83814Sespie   MACRO_DEF *def;
7431cc83814Sespie 
7441cc83814Sespie   if (macro_expansion_output_stream && !executing_string)
7451cc83814Sespie     me_append_before_this_command ();
7461cc83814Sespie 
7471cc83814Sespie   get_rest_of_line (0, &line);
7481cc83814Sespie 
7491cc83814Sespie   for (i = 0; line[i] && !whitespace (line[i]); i++);
7501cc83814Sespie   name = xmalloc (i + 1);
7511cc83814Sespie   memcpy (name, line, i);
7521cc83814Sespie   name[i] = 0;
7531cc83814Sespie 
7541cc83814Sespie   def = delete_macro (name);
7551cc83814Sespie 
7561cc83814Sespie   if (def)
7571cc83814Sespie     {
7581cc83814Sespie       free (def->source_file);
7591cc83814Sespie       free (def->name);
7601cc83814Sespie       free (def->body);
7611cc83814Sespie 
7621cc83814Sespie       if (def->arglist)
7631cc83814Sespie         {
7641cc83814Sespie           int i;
7651cc83814Sespie 
7661cc83814Sespie           for (i = 0; def->arglist[i]; i++)
7671cc83814Sespie             free (def->arglist[i]);
7681cc83814Sespie 
7691cc83814Sespie           free (def->arglist);
7701cc83814Sespie         }
7711cc83814Sespie 
7721cc83814Sespie       free (def);
7731cc83814Sespie     }
7741cc83814Sespie 
7751cc83814Sespie   free (line);
7761cc83814Sespie   free (name);
7771cc83814Sespie 
7781cc83814Sespie   if (macro_expansion_output_stream && !executing_string)
7791cc83814Sespie     remember_itext (input_text, input_text_offset);
7801cc83814Sespie }
7811cc83814Sespie 
7821cc83814Sespie /* How to output sections of the input file verbatim. */
7831cc83814Sespie 
7841cc83814Sespie /* Set the value of POINTER's offset to OFFSET. */
7851cc83814Sespie ITEXT *
remember_itext(char * pointer,int offset)786*a1acfa9bSespie remember_itext (char *pointer, int offset)
7871cc83814Sespie {
7881cc83814Sespie   int i;
7891cc83814Sespie   ITEXT *itext = NULL;
7901cc83814Sespie 
7911cc83814Sespie   /* If we have no info, initialize a blank list. */
7921cc83814Sespie   if (!itext_info)
7931cc83814Sespie     {
7941cc83814Sespie       itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *));
7951cc83814Sespie       for (i = 0; i < itext_size; i++)
7961cc83814Sespie         itext_info[i] = NULL;
7971cc83814Sespie     }
7981cc83814Sespie 
7991cc83814Sespie   /* If the pointer is already present in the list, then set the offset. */
8001cc83814Sespie   for (i = 0; i < itext_size; i++)
8011cc83814Sespie     if ((itext_info[i]) &&
8021cc83814Sespie         (itext_info[i]->pointer == pointer))
8031cc83814Sespie       {
8041cc83814Sespie         itext = itext_info[i];
8051cc83814Sespie         itext_info[i]->offset = offset;
8061cc83814Sespie         break;
8071cc83814Sespie       }
8081cc83814Sespie 
8091cc83814Sespie   if (i == itext_size)
8101cc83814Sespie     {
8111cc83814Sespie       /* Find a blank slot (or create a new one), and remember the
8121cc83814Sespie          pointer and offset. */
8131cc83814Sespie       for (i = 0; i < itext_size; i++)
8141cc83814Sespie         if (itext_info[i] == NULL)
8151cc83814Sespie           break;
8161cc83814Sespie 
8171cc83814Sespie       /* If not found, then add some slots. */
8181cc83814Sespie       if (i == itext_size)
8191cc83814Sespie         {
8201cc83814Sespie           int j;
8211cc83814Sespie 
8221cc83814Sespie           itext_info = xrealloc
8231cc83814Sespie             (itext_info, (itext_size += 10) * sizeof (ITEXT *));
8241cc83814Sespie 
8251cc83814Sespie           for (j = i; j < itext_size; j++)
8261cc83814Sespie             itext_info[j] = NULL;
8271cc83814Sespie         }
8281cc83814Sespie 
8291cc83814Sespie       /* Now add the pointer and the offset. */
8301cc83814Sespie       itext_info[i] = xmalloc (sizeof (ITEXT));
8311cc83814Sespie       itext_info[i]->pointer = pointer;
8321cc83814Sespie       itext_info[i]->offset = offset;
8331cc83814Sespie       itext = itext_info[i];
8341cc83814Sespie     }
8351cc83814Sespie   return itext;
8361cc83814Sespie }
8371cc83814Sespie 
8381cc83814Sespie /* Forget the input text associated with POINTER. */
8391cc83814Sespie void
forget_itext(char * pointer)840*a1acfa9bSespie forget_itext (char *pointer)
8411cc83814Sespie {
8421cc83814Sespie   int i;
8431cc83814Sespie 
8441cc83814Sespie   for (i = 0; i < itext_size; i++)
8451cc83814Sespie     if (itext_info[i] && (itext_info[i]->pointer == pointer))
8461cc83814Sespie       {
8471cc83814Sespie         free (itext_info[i]);
8481cc83814Sespie         itext_info[i] = NULL;
8491cc83814Sespie         break;
8501cc83814Sespie       }
8511cc83814Sespie }
8521cc83814Sespie 
8531cc83814Sespie /* Append the text which appeared in input_text from the last offset to
8541cc83814Sespie    the character just before the command that we are currently executing. */
8551cc83814Sespie void
me_append_before_this_command(void)856*a1acfa9bSespie me_append_before_this_command (void)
8571cc83814Sespie {
8581cc83814Sespie   int i;
8591cc83814Sespie 
8601cc83814Sespie   for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--)
8611cc83814Sespie     ;
8621cc83814Sespie   maybe_write_itext (input_text, i);
8631cc83814Sespie }
8641cc83814Sespie 
8651cc83814Sespie /* Similar to execute_string, but only takes a single string argument,
8661cc83814Sespie    and remembers the input text location, etc. */
8671cc83814Sespie void
me_execute_string(char * execution_string)868*a1acfa9bSespie me_execute_string (char *execution_string)
8691cc83814Sespie {
8701cc83814Sespie   int saved_escape_html = escape_html;
8711cc83814Sespie   int saved_in_paragraph = in_paragraph;
8721cc83814Sespie   escape_html = me_executing_string == 0;
8731cc83814Sespie   in_paragraph = 0;
8741cc83814Sespie 
8751cc83814Sespie   pushfile ();
8761cc83814Sespie   input_text_offset = 0;
8771cc83814Sespie   /* The following xstrdup is so we can relocate input_text at will.  */
8781cc83814Sespie   input_text = xstrdup (execution_string);
8791cc83814Sespie   input_filename = xstrdup (input_filename);
8801cc83814Sespie   input_text_length = strlen (execution_string);
8811cc83814Sespie 
8821cc83814Sespie   remember_itext (input_text, 0);
8831cc83814Sespie 
8841cc83814Sespie   me_executing_string++;
8851cc83814Sespie   reader_loop ();
8861cc83814Sespie   free (input_text);
8871cc83814Sespie   free (input_filename);
8881cc83814Sespie   popfile ();
8891cc83814Sespie   me_executing_string--;
8901cc83814Sespie 
8911cc83814Sespie   in_paragraph = saved_in_paragraph;
8921cc83814Sespie   escape_html = saved_escape_html;
8931cc83814Sespie }
8941cc83814Sespie 
8951cc83814Sespie /* A wrapper around me_execute_string which saves and restores
8961cc83814Sespie    variables important for output generation.  This is called
8971cc83814Sespie    when we need to produce macro-expanded output for input which
8981cc83814Sespie    leaves no traces in the Info output.  */
8991cc83814Sespie void
me_execute_string_keep_state(char * execution_string,char * append_string)900*a1acfa9bSespie me_execute_string_keep_state (char *execution_string, char *append_string)
9011cc83814Sespie {
9021cc83814Sespie   int op_orig, opcol_orig, popen_orig;
9031cc83814Sespie   int fill_orig, newline_orig, indent_orig, meta_pos_orig;
9041cc83814Sespie 
9051cc83814Sespie   remember_itext (input_text, input_text_offset);
9061cc83814Sespie   op_orig = output_paragraph_offset;
9071cc83814Sespie   meta_pos_orig = meta_char_pos;
9081cc83814Sespie   opcol_orig = output_column;
9091cc83814Sespie   popen_orig = paragraph_is_open;
9101cc83814Sespie   fill_orig = filling_enabled;
9111cc83814Sespie   newline_orig = last_char_was_newline;
9121cc83814Sespie   filling_enabled = 0;
9131cc83814Sespie   indent_orig = no_indent;
9141cc83814Sespie   no_indent = 1;
9151cc83814Sespie   me_execute_string (execution_string);
9161cc83814Sespie   if (append_string)
9171cc83814Sespie     write_region_to_macro_output (append_string, 0, strlen (append_string));
9181cc83814Sespie   output_paragraph_offset = op_orig;
9191cc83814Sespie   meta_char_pos = meta_pos_orig;
9201cc83814Sespie   output_column = opcol_orig;
9211cc83814Sespie   paragraph_is_open = popen_orig;
9221cc83814Sespie   filling_enabled = fill_orig;
9231cc83814Sespie   last_char_was_newline = newline_orig;
9241cc83814Sespie   no_indent = indent_orig;
9251cc83814Sespie }
9261cc83814Sespie 
9271cc83814Sespie /* Append the text which appears in input_text from the last offset to
9281cc83814Sespie    the current OFFSET. */
9291cc83814Sespie void
append_to_expansion_output(int offset)930*a1acfa9bSespie append_to_expansion_output (int offset)
9311cc83814Sespie {
9321cc83814Sespie   int i;
9331cc83814Sespie   ITEXT *itext = NULL;
9341cc83814Sespie 
9351cc83814Sespie   for (i = 0; i < itext_size; i++)
9361cc83814Sespie     if (itext_info[i] && itext_info[i]->pointer == input_text)
9371cc83814Sespie       {
9381cc83814Sespie         itext = itext_info[i];
9391cc83814Sespie         break;
9401cc83814Sespie       }
9411cc83814Sespie 
9421cc83814Sespie   if (!itext)
9431cc83814Sespie     return;
9441cc83814Sespie 
9451cc83814Sespie   if (offset > itext->offset)
9461cc83814Sespie     {
9471cc83814Sespie       write_region_to_macro_output (input_text, itext->offset, offset);
9481cc83814Sespie       remember_itext (input_text, offset);
9491cc83814Sespie     }
9501cc83814Sespie }
9511cc83814Sespie 
9521cc83814Sespie /* Only write this input text iff it appears in our itext list. */
9531cc83814Sespie void
maybe_write_itext(char * pointer,int offset)954*a1acfa9bSespie maybe_write_itext (char *pointer, int offset)
9551cc83814Sespie {
9561cc83814Sespie   int i;
9571cc83814Sespie   ITEXT *itext = NULL;
9581cc83814Sespie 
9591cc83814Sespie   for (i = 0; i < itext_size; i++)
9601cc83814Sespie     if (itext_info[i] && (itext_info[i]->pointer == pointer))
9611cc83814Sespie       {
9621cc83814Sespie         itext = itext_info[i];
9631cc83814Sespie         break;
9641cc83814Sespie       }
9651cc83814Sespie 
9661cc83814Sespie   if (itext && (itext->offset < offset))
9671cc83814Sespie     {
9681cc83814Sespie       write_region_to_macro_output (itext->pointer, itext->offset, offset);
9691cc83814Sespie       remember_itext (pointer, offset);
9701cc83814Sespie     }
9711cc83814Sespie }
9721cc83814Sespie 
9731cc83814Sespie void
write_region_to_macro_output(char * string,int start,int end)974*a1acfa9bSespie write_region_to_macro_output (char *string, int start, int end)
9751cc83814Sespie {
9761cc83814Sespie   if (macro_expansion_output_stream)
9771cc83814Sespie     fwrite (string + start, 1, end - start, macro_expansion_output_stream);
9781cc83814Sespie }
9791cc83814Sespie 
9801cc83814Sespie /* Aliases. */
9811cc83814Sespie 
9821cc83814Sespie typedef struct alias_struct
9831cc83814Sespie {
9841cc83814Sespie   char *alias;
9851cc83814Sespie   char *mapto;
9861cc83814Sespie   struct alias_struct *next;
9871cc83814Sespie } alias_type;
9881cc83814Sespie 
9891cc83814Sespie static alias_type *aliases;
9901cc83814Sespie 
991*a1acfa9bSespie /* @alias aname = cmdname */
992*a1acfa9bSespie 
9931cc83814Sespie void
cm_alias(void)994*a1acfa9bSespie cm_alias (void)
9951cc83814Sespie {
9961cc83814Sespie   alias_type *a = xmalloc (sizeof (alias_type));
9971cc83814Sespie 
9981cc83814Sespie   skip_whitespace ();
999*a1acfa9bSespie   get_until_in_line (0, "=", &(a->alias));
10003fb98d4aSespie   canon_white (a->alias);
10013fb98d4aSespie 
10021cc83814Sespie   discard_until ("=");
10031cc83814Sespie   skip_whitespace ();
10041cc83814Sespie   get_until_in_line (0, " ", &(a->mapto));
10051cc83814Sespie 
10061cc83814Sespie   a->next = aliases;
10071cc83814Sespie   aliases = a;
10081cc83814Sespie }
10091cc83814Sespie 
10101cc83814Sespie /* Perform an alias expansion.  Called from read_command.  */
10111cc83814Sespie char *
alias_expand(char * tok)1012*a1acfa9bSespie alias_expand (char *tok)
10131cc83814Sespie {
10141cc83814Sespie   alias_type *findit = aliases;
10151cc83814Sespie 
10161cc83814Sespie   while (findit)
10171cc83814Sespie     if (strcmp (findit->alias, tok) == 0)
10181cc83814Sespie       {
10191cc83814Sespie 	free (tok);
10201cc83814Sespie 	return alias_expand (xstrdup (findit->mapto));
10211cc83814Sespie       }
10221cc83814Sespie     else
10231cc83814Sespie       findit = findit->next;
10241cc83814Sespie 
10251cc83814Sespie   return tok;
10261cc83814Sespie }
10271cc83814Sespie 
10281cc83814Sespie /* definfoenclose implementation.  */
10291cc83814Sespie 
10301cc83814Sespie /* This structure is used to track enclosure macros.  When an enclosure
10311cc83814Sespie    macro is recognized, a pointer to the enclosure block corresponding
10321cc83814Sespie    to its name is saved in the brace element for its argument. */
10331cc83814Sespie typedef struct enclose_struct
10341cc83814Sespie {
10351cc83814Sespie   char *enclose;
10361cc83814Sespie   char *before;
10371cc83814Sespie   char *after;
10381cc83814Sespie   struct enclose_struct *next;
10391cc83814Sespie } enclosure_type;
10401cc83814Sespie 
10411cc83814Sespie static enclosure_type *enclosures;
10421cc83814Sespie 
10431cc83814Sespie typedef struct enclosure_stack_struct
10441cc83814Sespie {
10451cc83814Sespie     enclosure_type *current;
10461cc83814Sespie     struct enclosure_stack_struct *next;
10471cc83814Sespie } enclosure_stack_type;
10481cc83814Sespie 
10491cc83814Sespie static enclosure_stack_type *enclosure_stack;
10501cc83814Sespie 
10511cc83814Sespie /* @definfoenclose */
10521cc83814Sespie void
cm_definfoenclose(void)1053*a1acfa9bSespie cm_definfoenclose (void)
10541cc83814Sespie {
10551cc83814Sespie   enclosure_type *e = xmalloc (sizeof (enclosure_type));
10561cc83814Sespie 
10571cc83814Sespie   skip_whitespace ();
10581cc83814Sespie   get_until_in_line (1, ",", &(e->enclose));
10591cc83814Sespie   discard_until (",");
10601cc83814Sespie   get_until_in_line (0, ",", &(e->before));
10611cc83814Sespie   discard_until (",");
10621cc83814Sespie   get_until_in_line (0, "\n", &(e->after));
10631cc83814Sespie 
10641cc83814Sespie   e->next = enclosures;
10651cc83814Sespie   enclosures = e;
10661cc83814Sespie }
10671cc83814Sespie 
10681cc83814Sespie /* If TOK is an enclosure command, push it on the enclosure stack and
10691cc83814Sespie    return 1.  Else return 0.  */
10701cc83814Sespie 
10711cc83814Sespie int
enclosure_command(char * tok)1072*a1acfa9bSespie enclosure_command (char *tok)
10731cc83814Sespie {
10741cc83814Sespie   enclosure_type *findit = enclosures;
10751cc83814Sespie 
10761cc83814Sespie   while (findit)
10771cc83814Sespie     if (strcmp (findit->enclose, tok) == 0)
10781cc83814Sespie       {
10791cc83814Sespie         enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type));
10801cc83814Sespie         new->current = findit;
10811cc83814Sespie         new->next = enclosure_stack;
10821cc83814Sespie         enclosure_stack = new;
10831cc83814Sespie 
10841cc83814Sespie         return 1;
10851cc83814Sespie       }
10861cc83814Sespie     else
10871cc83814Sespie       findit = findit->next;
10881cc83814Sespie 
10891cc83814Sespie   return 0;
10901cc83814Sespie }
10911cc83814Sespie 
10921cc83814Sespie /* actually perform the enclosure expansion */
10931cc83814Sespie void
enclosure_expand(int arg,int start,int end)1094*a1acfa9bSespie enclosure_expand (int arg, int start, int end)
10951cc83814Sespie {
10961cc83814Sespie   if (arg == START)
10971cc83814Sespie     add_word (enclosure_stack->current->before);
10981cc83814Sespie   else
10991cc83814Sespie     {
11001cc83814Sespie       enclosure_stack_type *temp;
11011cc83814Sespie 
11021cc83814Sespie       add_word (enclosure_stack->current->after);
11031cc83814Sespie 
11041cc83814Sespie       temp = enclosure_stack;
11051cc83814Sespie       enclosure_stack = enclosure_stack->next;
11061cc83814Sespie       free (temp);
11071cc83814Sespie     }
11081cc83814Sespie }
1109