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