156160Sru/* macro.c -- user-defined macros for Texinfo. 2146515Sru $Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp $ 356160Sru 4116525Sru Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc. 556160Sru 656160Sru This program is free software; you can redistribute it and/or modify 756160Sru it under the terms of the GNU General Public License as published by 856160Sru the Free Software Foundation; either version 2, or (at your option) 956160Sru any later version. 1056160Sru 1156160Sru This program is distributed in the hope that it will be useful, 1256160Sru but WITHOUT ANY WARRANTY; without even the implied warranty of 1356160Sru MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1456160Sru GNU General Public License for more details. 1556160Sru 1656160Sru You should have received a copy of the GNU General Public License 1756160Sru along with this program; if not, write to the Free Software Foundation, 1856160Sru Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 1956160Sru 2056160Sru#include "system.h" 2156160Sru#include "cmds.h" 22146515Sru#include "files.h" 2356160Sru#include "macro.h" 2456160Sru#include "makeinfo.h" 2556160Sru#include "insertion.h" 2656160Sru 2756160Sru/* If non-NULL, this is an output stream to write the full macro expansion 2856160Sru of the input text to. The result is another texinfo file, but 2956160Sru missing @include, @infoinclude, @macro, and macro invocations. Instead, 3056160Sru all of the text is placed within the file. */ 3156160SruFILE *macro_expansion_output_stream = NULL; 3256160Sru 3356160Sru/* Output file for -E. */ 3456160Sruchar *macro_expansion_filename; 3556160Sru 3656160Sru/* Nonzero means a macro string is in execution, as opposed to a file. */ 3756160Sruint me_executing_string = 0; 3856160Sru 3956160Sru/* Nonzero means we want only to expand macros and 4056160Sru leave everything else intact. */ 4156160Sruint only_macro_expansion = 0; 4256160Sru 4356160Srustatic ITEXT **itext_info = NULL; 4456160Srustatic int itext_size = 0; 4556160Sru 4656160Sru/* Return the arglist on the current line. This can behave in two different 4756160Sru ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */ 4856160Sruint braces_required_for_macro_args = 0; 4956160Sru 5056160Sru/* Array of macros and definitions. */ 5156160SruMACRO_DEF **macro_list = NULL; 5256160Sru 5356160Sruint macro_list_len = 0; /* Number of elements. */ 5456160Sruint macro_list_size = 0; /* Number of slots in total. */ 5556160Sru 5656160Sru/* Return the length of the array in ARRAY. */ 5756160Sruint 58146515Sruarray_len (char **array) 5956160Sru{ 6056160Sru int i = 0; 6156160Sru 6256160Sru if (array) 6356160Sru for (i = 0; array[i]; i++); 6456160Sru 6556160Sru return i; 6656160Sru} 6756160Sru 6856160Sruvoid 69146515Srufree_array (char **array) 7056160Sru{ 7156160Sru if (array) 7256160Sru { 7356160Sru int i; 7456160Sru for (i = 0; array[i]; i++) 7556160Sru free (array[i]); 7656160Sru 7756160Sru free (array); 7856160Sru } 7956160Sru} 8056160Sru 8156160Sru/* Return the macro definition of NAME or NULL if NAME is not defined. */ 8256160SruMACRO_DEF * 83146515Srufind_macro (char *name) 8456160Sru{ 8556160Sru int i; 8656160Sru MACRO_DEF *def; 8756160Sru 8856160Sru def = NULL; 8956160Sru for (i = 0; macro_list && (def = macro_list[i]); i++) 9056160Sru { 9156160Sru if ((!def->inhibited) && (strcmp (def->name, name) == 0)) 9256160Sru break; 9356160Sru } 9456160Sru return def; 9556160Sru} 9656160Sru 9756160Sru/* Add the macro NAME with ARGLIST and BODY to the list of defined macros. 9856160Sru SOURCE_FILE is the name of the file where this definition can be found, 9956160Sru and SOURCE_LINENO is the line number within that file. If a macro already 10056160Sru exists with NAME, then a warning is produced, and that previous 10156160Sru definition is overwritten. */ 102146515Srustatic void 103146515Sruadd_macro (char *name, char **arglist, char *body, char *source_file, 104146515Sru int source_lineno, int flags) 10556160Sru{ 10656160Sru MACRO_DEF *def; 10756160Sru 10856160Sru def = find_macro (name); 10956160Sru 11056160Sru if (!def) 11156160Sru { 11256160Sru if (macro_list_len + 2 >= macro_list_size) 11356160Sru macro_list = xrealloc 11456160Sru (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *))); 11556160Sru 11656160Sru macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF)); 11756160Sru macro_list[macro_list_len + 1] = NULL; 11856160Sru 11956160Sru def = macro_list[macro_list_len]; 12056160Sru macro_list_len += 1; 12156160Sru def->name = name; 12256160Sru } 12356160Sru else 12456160Sru { 12556160Sru char *temp_filename = input_filename; 12656160Sru int temp_line = line_number; 12756160Sru 12856160Sru warning (_("macro `%s' previously defined"), name); 12956160Sru 13056160Sru input_filename = def->source_file; 13156160Sru line_number = def->source_lineno; 13256160Sru warning (_("here is the previous definition of `%s'"), name); 13356160Sru 13456160Sru input_filename = temp_filename; 13556160Sru line_number = temp_line; 13656160Sru 13756160Sru if (def->arglist) 13856160Sru { 13956160Sru int i; 14056160Sru 14156160Sru for (i = 0; def->arglist[i]; i++) 14256160Sru free (def->arglist[i]); 14356160Sru 14456160Sru free (def->arglist); 14556160Sru } 14656160Sru free (def->source_file); 14756160Sru free (def->body); 14856160Sru } 14956160Sru 15056160Sru def->source_file = xstrdup (source_file); 15156160Sru def->source_lineno = source_lineno; 15256160Sru def->body = body; 15356160Sru def->arglist = arglist; 15456160Sru def->inhibited = 0; 15556160Sru def->flags = flags; 15656160Sru} 15756160Sru 15856160Sru 15956160Sruchar ** 160146515Sruget_brace_args (int quote_single) 16156160Sru{ 16256160Sru char **arglist, *word; 16356160Sru int arglist_index, arglist_size; 16456160Sru int character, escape_seen, start; 16556160Sru int depth = 1; 16656160Sru 16756160Sru /* There is an arglist in braces here, so gather the args inside of it. */ 16856160Sru skip_whitespace_and_newlines (); 16956160Sru input_text_offset++; 17056160Sru arglist = NULL; 17156160Sru arglist_index = arglist_size = 0; 17256160Sru 17356160Sru get_arg: 17456160Sru skip_whitespace_and_newlines (); 17556160Sru start = input_text_offset; 17656160Sru escape_seen = 0; 17756160Sru 17856160Sru while ((character = curchar ())) 17956160Sru { 18056160Sru if (character == '\\') 18156160Sru { 18256160Sru input_text_offset += 2; 18356160Sru escape_seen = 1; 18456160Sru } 18556160Sru else if (character == '{') 18656160Sru { 18756160Sru depth++; 18856160Sru input_text_offset++; 18956160Sru } 19056160Sru else if ((character == ',' && !quote_single) || 19156160Sru ((character == '}') && depth == 1)) 19256160Sru { 19356160Sru int len = input_text_offset - start; 19456160Sru 19556160Sru if (len || (character != '}')) 19656160Sru { 19756160Sru word = xmalloc (1 + len); 19856160Sru memcpy (word, input_text + start, len); 19956160Sru word[len] = 0; 20056160Sru 20156160Sru /* Clean up escaped characters. */ 20256160Sru if (escape_seen) 20356160Sru { 20456160Sru int i; 20556160Sru for (i = 0; word[i]; i++) 20656160Sru if (word[i] == '\\') 20756160Sru memmove (word + i, word + i + 1, 20856160Sru 1 + strlen (word + i + 1)); 20956160Sru } 21056160Sru 21156160Sru if (arglist_index + 2 >= arglist_size) 21256160Sru arglist = xrealloc 21356160Sru (arglist, (arglist_size += 10) * sizeof (char *)); 21456160Sru 21556160Sru arglist[arglist_index++] = word; 21656160Sru arglist[arglist_index] = NULL; 21756160Sru } 21856160Sru 21956160Sru input_text_offset++; 22056160Sru if (character == '}') 22156160Sru break; 22256160Sru else 22356160Sru goto get_arg; 22456160Sru } 22556160Sru else if (character == '}') 22656160Sru { 22756160Sru depth--; 22856160Sru input_text_offset++; 22956160Sru } 23056160Sru else 23156160Sru { 23256160Sru input_text_offset++; 23356160Sru if (character == '\n') line_number++; 23456160Sru } 23556160Sru } 23656160Sru return arglist; 23756160Sru} 23856160Sru 239146515Srustatic char ** 240146515Sruget_macro_args (MACRO_DEF *def) 24156160Sru{ 24256160Sru int i; 24356160Sru char *word; 24456160Sru 24556160Sru /* Quickly check to see if this macro has been invoked with any arguments. 24656160Sru If not, then don't skip any of the following whitespace. */ 24756160Sru for (i = input_text_offset; i < input_text_length; i++) 24856160Sru if (!cr_or_whitespace (input_text[i])) 24956160Sru break; 25056160Sru 25156160Sru if (input_text[i] != '{') 25256160Sru { 25356160Sru if (braces_required_for_macro_args) 25456160Sru { 25556160Sru return NULL; 25656160Sru } 25756160Sru else 25856160Sru { 25956160Sru /* Braces are not required to fill out the macro arguments. If 26056160Sru this macro takes one argument, it is considered to be the 26156160Sru remainder of the line, sans whitespace. */ 26256160Sru if (def->arglist && def->arglist[0] && !def->arglist[1]) 26356160Sru { 26456160Sru char **arglist; 26556160Sru 26656160Sru get_rest_of_line (0, &word); 26756160Sru if (input_text[input_text_offset - 1] == '\n') 26856160Sru { 26956160Sru input_text_offset--; 27056160Sru line_number--; 27156160Sru } 27256160Sru /* canon_white (word); */ 27356160Sru arglist = xmalloc (2 * sizeof (char *)); 27456160Sru arglist[0] = word; 27556160Sru arglist[1] = NULL; 27656160Sru return arglist; 27756160Sru } 27856160Sru else 27956160Sru { 28056160Sru /* The macro either took no arguments, or took more than 28156160Sru one argument. In that case, it must be invoked with 28256160Sru arguments surrounded by braces. */ 28356160Sru return NULL; 28456160Sru } 28556160Sru } 28656160Sru } 28756160Sru return get_brace_args (def->flags & ME_QUOTE_ARG); 28856160Sru} 28956160Sru 29056160Sru/* Substitute actual parameters for named parameters in body. 29156160Sru The named parameters which appear in BODY must by surrounded 29256160Sru reverse slashes, as in \foo\. */ 293146515Srustatic char * 294146515Sruapply (char **named, char **actuals, char *body) 29556160Sru{ 29656160Sru int i; 29756160Sru int new_body_index, new_body_size; 29856160Sru char *new_body, *text; 29956160Sru int length_of_actuals; 30056160Sru 30156160Sru length_of_actuals = array_len (actuals); 30256160Sru new_body_size = strlen (body); 30356160Sru new_body = xmalloc (1 + new_body_size); 30456160Sru 30556160Sru /* Copy chars from BODY into NEW_BODY. */ 30656160Sru i = 0; 30756160Sru new_body_index = 0; 30856160Sru 30956160Sru while (body[i]) 31056160Sru { /* Anything but a \ is easy. */ 31156160Sru if (body[i] != '\\') 31256160Sru new_body[new_body_index++] = body[i++]; 31356160Sru else 31456160Sru { /* Snarf parameter name, check against named parameters. */ 31556160Sru char *param; 316116525Sru int param_start, len; 31756160Sru 31856160Sru param_start = ++i; 31956160Sru while (body[i] && body[i] != '\\') 32056160Sru i++; 32156160Sru 32256160Sru len = i - param_start; 32356160Sru param = xmalloc (1 + len); 32456160Sru memcpy (param, body + param_start, len); 32556160Sru param[len] = 0; 32656160Sru 32756160Sru if (body[i]) /* move past \ */ 32856160Sru i++; 32956160Sru 330116525Sru if (len == 0) 331116525Sru { /* \\ always means \, even if macro has no args. */ 33256160Sru len++; 33356160Sru text = xmalloc (1 + len); 33456160Sru sprintf (text, "\\%s", param); 33556160Sru } 336116525Sru else 337116525Sru { 338116525Sru int which; 339116525Sru 340116525Sru /* Check against named parameters. */ 341116525Sru for (which = 0; named && named[which]; which++) 342116525Sru if (STREQ (named[which], param)) 343116525Sru break; 34456160Sru 345116525Sru if (named && named[which]) 346116525Sru { 347116525Sru text = which < length_of_actuals ? actuals[which] : NULL; 348116525Sru if (!text) 349116525Sru text = ""; 350116525Sru len = strlen (text); 351116525Sru text = xstrdup (text); /* so we can free it */ 352116525Sru } 353116525Sru else 354116525Sru { /* not a parameter, so it's an error. */ 355116525Sru warning (_("\\ in macro expansion followed by `%s' instead of parameter name"), 356116525Sru param); 357116525Sru len++; 358116525Sru text = xmalloc (1 + len); 359116525Sru sprintf (text, "\\%s", param); 360116525Sru } 361116525Sru } 362116525Sru 36356160Sru if (strlen (param) + 2 < len) 36456160Sru { 36556160Sru new_body_size += len + 1; 36656160Sru new_body = xrealloc (new_body, new_body_size); 36756160Sru } 36856160Sru 36956160Sru free (param); 37056160Sru 37156160Sru strcpy (new_body + new_body_index, text); 37256160Sru new_body_index += len; 37356160Sru 374116525Sru free (text); 37556160Sru } 37656160Sru } 37756160Sru 37856160Sru new_body[new_body_index] = 0; 37956160Sru return new_body; 38056160Sru} 38156160Sru 38256160Sru/* Expand macro passed in DEF, a pointer to a MACRO_DEF, and 38356160Sru return its expansion as a string. */ 38456160Sruchar * 385146515Sruexpand_macro (MACRO_DEF *def) 38656160Sru{ 38756160Sru char **arglist; 38856160Sru int num_args; 38956160Sru char *execution_string = NULL; 39056160Sru int start_line = line_number; 39156160Sru 39256160Sru /* Find out how many arguments this macro definition takes. */ 39356160Sru num_args = array_len (def->arglist); 39456160Sru 39556160Sru /* Gather the arguments present on the line if there are any. */ 39656160Sru arglist = get_macro_args (def); 39756160Sru 39856160Sru if (num_args < array_len (arglist)) 39956160Sru { 40056160Sru free_array (arglist); 40156160Sru line_error (_("Macro `%s' called on line %d with too many args"), 40256160Sru def->name, start_line); 40356160Sru return execution_string; 40456160Sru } 40556160Sru 40656160Sru if (def->body) 40756160Sru execution_string = apply (def->arglist, arglist, def->body); 40856160Sru 40956160Sru free_array (arglist); 41056160Sru return execution_string; 41156160Sru} 41256160Sru 41356160Sru/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */ 41456160Sruvoid 415146515Sruexecute_macro (MACRO_DEF *def) 41656160Sru{ 41756160Sru char *execution_string; 41856160Sru int start_line = line_number, end_line; 41956160Sru 42056160Sru if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion) 42156160Sru me_append_before_this_command (); 42256160Sru 42356160Sru execution_string = expand_macro (def); 42456160Sru if (!execution_string) 42556160Sru return; 42656160Sru 42756160Sru if (def->body) 42856160Sru { 42956160Sru /* Reset the line number to where the macro arguments began. 43056160Sru This makes line numbers reported in error messages correct in 43156160Sru case the macro arguments span several lines and the expanded 43256160Sru arguments invoke other commands. */ 43356160Sru end_line = line_number; 43456160Sru line_number = start_line; 43556160Sru 436146515Sru if (macro_expansion_output_stream 437146515Sru && !executing_string && !me_inhibit_expansion) 43856160Sru { 43956160Sru remember_itext (input_text, input_text_offset); 44056160Sru me_execute_string (execution_string); 44156160Sru } 44256160Sru else 44356160Sru execute_string ("%s", execution_string); 44456160Sru 44556160Sru free (execution_string); 44656160Sru line_number = end_line; 44756160Sru } 44856160Sru} 44956160Sru 45056160Sru 45156160Sru/* Read and remember the definition of a macro. If RECURSIVE is set, 45256160Sru set the ME_RECURSE flag. MACTYPE is either "macro" or "rmacro", and 45356160Sru tells us what the matching @end should be. */ 45456160Srustatic void 455146515Srudefine_macro (char *mactype, int recursive) 45656160Sru{ 457146515Sru int i, start; 458146515Sru char *name, *line; 459146515Sru char *last_end = NULL; 460146515Sru char *body = NULL; 461146515Sru char **arglist = NULL; 462146515Sru int body_size = 0, body_index = 0; 46356160Sru int depth = 1; 464146515Sru int flags = 0; 46556160Sru int defining_line = line_number; 46656160Sru 46756160Sru if (macro_expansion_output_stream && !executing_string) 46856160Sru me_append_before_this_command (); 46956160Sru 47056160Sru skip_whitespace (); 47156160Sru 47256160Sru /* Get the name of the macro. This is the set of characters which are 47356160Sru not whitespace and are not `{' immediately following the @macro. */ 474146515Sru start = input_text_offset; 47556160Sru { 47656160Sru int len; 47756160Sru 478146515Sru for (i = start; i < input_text_length && input_text[i] != '{' 479146515Sru && !cr_or_whitespace (input_text[i]); 480146515Sru i++) ; 48156160Sru 48256160Sru len = i - start; 48356160Sru name = xmalloc (1 + len); 48456160Sru memcpy (name, input_text + start, len); 48556160Sru name[len] = 0; 48656160Sru input_text_offset = i; 48756160Sru } 48856160Sru 48956160Sru skip_whitespace (); 49056160Sru 49156160Sru /* It is not required that the definition of a macro includes an arglist. 49256160Sru If not, don't try to get the named parameters, just use a null list. */ 49356160Sru if (curchar () == '{') 49456160Sru { 49556160Sru int character; 49656160Sru int arglist_index = 0, arglist_size = 0; 49756160Sru int gathering_words = 1; 49856160Sru char *word = NULL; 49956160Sru 50056160Sru /* Read the words inside of the braces which determine the arglist. 50156160Sru These words will be replaced within the body of the macro at 50256160Sru execution time. */ 50356160Sru 50456160Sru input_text_offset++; 50556160Sru skip_whitespace_and_newlines (); 50656160Sru 50756160Sru while (gathering_words) 50856160Sru { 50956160Sru int len; 51056160Sru 51156160Sru for (i = input_text_offset; 51256160Sru (character = input_text[i]); 51356160Sru i++) 51456160Sru { 51556160Sru switch (character) 51656160Sru { 51756160Sru case '\n': 51856160Sru line_number++; 51956160Sru case ' ': 52056160Sru case '\t': 52156160Sru case ',': 52256160Sru case '}': 52356160Sru /* Found the end of the current arglist word. Save it. */ 52456160Sru len = i - input_text_offset; 52556160Sru word = xmalloc (1 + len); 52656160Sru memcpy (word, input_text + input_text_offset, len); 52756160Sru word[len] = 0; 52856160Sru input_text_offset = i; 52956160Sru 53056160Sru /* Advance to the comma or close-brace that signified 53156160Sru the end of the argument. */ 53256160Sru while ((character = curchar ()) 53356160Sru && character != ',' 53456160Sru && character != '}') 53556160Sru { 53656160Sru input_text_offset++; 53756160Sru if (character == '\n') 53856160Sru line_number++; 53956160Sru } 54056160Sru 54156160Sru /* Add the word to our list of words. */ 54256160Sru if (arglist_index + 2 >= arglist_size) 54356160Sru { 54456160Sru arglist_size += 10; 54556160Sru arglist = xrealloc (arglist, 54656160Sru arglist_size * sizeof (char *)); 54756160Sru } 54856160Sru 54956160Sru arglist[arglist_index++] = word; 55056160Sru arglist[arglist_index] = NULL; 55156160Sru break; 55256160Sru } 55356160Sru 55456160Sru if (character == '}') 55556160Sru { 55656160Sru input_text_offset++; 55756160Sru gathering_words = 0; 55856160Sru break; 55956160Sru } 56056160Sru 56156160Sru if (character == ',') 56256160Sru { 56356160Sru input_text_offset++; 56456160Sru skip_whitespace_and_newlines (); 56556160Sru i = input_text_offset - 1; 56656160Sru } 56756160Sru } 56856160Sru } 56956160Sru 57056160Sru /* If we have exactly one argument, do @quote-arg implicitly. Not 57156160Sru only does this match TeX's behavior (which can't feasibly be 57256160Sru changed), but it's a good idea. */ 57356160Sru if (arglist_index == 1) 57456160Sru flags |= ME_QUOTE_ARG; 57556160Sru } 57656160Sru 57756160Sru /* Read the text carefully until we find an "@end macro" which 57856160Sru matches this one. The text in between is the body of the macro. */ 57956160Sru skip_whitespace_and_newlines (); 58056160Sru 58156160Sru while (depth) 58256160Sru { 58356160Sru if ((input_text_offset + 9) > input_text_length) 58456160Sru { 58593139Sru file_line_error (input_filename, defining_line, 58693139Sru _("%cend macro not found"), COMMAND_PREFIX); 58756160Sru return; 58856160Sru } 58956160Sru 59056160Sru get_rest_of_line (0, &line); 59156160Sru 59256160Sru /* Handle commands only meaningful within a macro. */ 59356160Sru if ((*line == COMMAND_PREFIX) && (depth == 1) && 59456160Sru (strncmp (line + 1, "allow-recursion", 15) == 0) && 59556160Sru (line[16] == 0 || whitespace (line[16]))) 59656160Sru { 59756160Sru for (i = 16; whitespace (line[i]); i++); 59856160Sru strcpy (line, line + i); 59956160Sru flags |= ME_RECURSE; 60056160Sru if (!*line) 60156160Sru { 60256160Sru free (line); 60356160Sru continue; 60456160Sru } 60556160Sru } 60656160Sru 60756160Sru if ((*line == COMMAND_PREFIX) && (depth == 1) && 60856160Sru (strncmp (line + 1, "quote-arg", 9) == 0) && 60956160Sru (line[10] == 0 || whitespace (line[10]))) 61056160Sru { 61156160Sru for (i = 10; whitespace (line[i]); i++); 61256160Sru strcpy (line, line + i); 61356160Sru 61456160Sru if (arglist && arglist[0] && !arglist[1]) 61556160Sru { 61656160Sru flags |= ME_QUOTE_ARG; 61756160Sru if (!*line) 61856160Sru { 61956160Sru free (line); 62056160Sru continue; 62156160Sru } 62256160Sru } 62356160Sru else 62456160Sru line_error (_("@quote-arg only useful for single-argument macros")); 62556160Sru } 62656160Sru 62756160Sru if (*line == COMMAND_PREFIX 62856160Sru && (strncmp (line + 1, "macro ", 6) == 0 62956160Sru || strncmp (line + 1, "rmacro ", 7) == 0)) 63056160Sru depth++; 63156160Sru 63256160Sru /* Incorrect implementation of nesting -- just check that the last 63356160Sru @end matches what we started with. Since nested macros don't 63456160Sru work in TeX anyway, this isn't worth the trouble to get right. */ 63556160Sru if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0) 63656160Sru { 63756160Sru depth--; 63856160Sru last_end = "macro"; 63956160Sru } 640146515Sru if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0) 64156160Sru { 64256160Sru depth--; 64356160Sru last_end = "rmacro"; 64456160Sru } 64556160Sru 64656160Sru if (depth) 64756160Sru { 64856160Sru if ((body_index + strlen (line) + 3) >= body_size) 64956160Sru body = xrealloc (body, body_size += 3 + strlen (line)); 65056160Sru strcpy (body + body_index, line); 65156160Sru body_index += strlen (line); 65256160Sru body[body_index++] = '\n'; 65356160Sru body[body_index] = 0; 65456160Sru } 65556160Sru free (line); 65656160Sru } 65756160Sru 65856160Sru /* Check that @end matched the macro command. */ 65956160Sru if (!STREQ (last_end, mactype)) 66056160Sru warning (_("mismatched @end %s with @%s"), last_end, mactype); 66156160Sru 66256160Sru /* If it was an empty macro like 66356160Sru @macro foo 66456160Sru @end macro 66556160Sru create an empty body. (Otherwise, the macro is not expanded.) */ 66656160Sru if (!body) 66756160Sru { 66856160Sru body = (char *)malloc(1); 66956160Sru *body = 0; 67056160Sru } 67156160Sru 67256160Sru /* We now have the name, the arglist, and the body. However, BODY 67356160Sru includes the final newline which preceded the `@end macro' text. 67456160Sru Delete it. */ 67556160Sru if (body && strlen (body)) 67656160Sru body[strlen (body) - 1] = 0; 67756160Sru 67856160Sru if (recursive) 67956160Sru flags |= ME_RECURSE; 68056160Sru 68156160Sru add_macro (name, arglist, body, input_filename, defining_line, flags); 68256160Sru 68356160Sru if (macro_expansion_output_stream && !executing_string) 684146515Sru { 685146515Sru /* Remember text for future expansions. */ 686146515Sru remember_itext (input_text, input_text_offset); 687146515Sru 688146515Sru /* Bizarrely, output the @macro itself. This is so texinfo.tex 689146515Sru will have a chance to read it when texi2dvi calls makeinfo -E. 690146515Sru The problem is that we don't really expand macros in all 691146515Sru contexts; a @table's @item is one. And a fix is not obvious to 692146515Sru me, since it appears virtually identical to any other internal 693146515Sru expansion. Just setting a variable in cm_item caused other 694146515Sru strange expansion problems. */ 695146515Sru write_region_to_macro_output ("@", 0, 1); 696146515Sru write_region_to_macro_output (mactype, 0, strlen (mactype)); 697146515Sru write_region_to_macro_output (" ", 0, 1); 698146515Sru write_region_to_macro_output (input_text, start, input_text_offset); 699146515Sru } 70056160Sru} 70156160Sru 70256160Sruvoid 703146515Srucm_macro (void) 70456160Sru{ 70556160Sru define_macro ("macro", 0); 70656160Sru} 70756160Sru 70856160Sruvoid 709146515Srucm_rmacro (void) 71056160Sru{ 71156160Sru define_macro ("rmacro", 1); 71256160Sru} 71356160Sru 71456160Sru/* Delete the macro with name NAME. The macro is deleted from the list, 71556160Sru but it is also returned. If there was no macro defined, NULL is 71656160Sru returned. */ 71756160Sru 71856160Srustatic MACRO_DEF * 719146515Srudelete_macro (char *name) 72056160Sru{ 72156160Sru int i; 72256160Sru MACRO_DEF *def; 72356160Sru 72456160Sru def = NULL; 72556160Sru 72656160Sru for (i = 0; macro_list && (def = macro_list[i]); i++) 72756160Sru if (strcmp (def->name, name) == 0) 72856160Sru { 72956160Sru memmove (macro_list + i, macro_list + i + 1, 73056160Sru ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *)); 73156160Sru macro_list_len--; 73256160Sru break; 73356160Sru } 73456160Sru return def; 73556160Sru} 73656160Sru 73756160Sruvoid 738146515Srucm_unmacro (void) 73956160Sru{ 74056160Sru int i; 74156160Sru char *line, *name; 74256160Sru MACRO_DEF *def; 74356160Sru 74456160Sru if (macro_expansion_output_stream && !executing_string) 74556160Sru me_append_before_this_command (); 74656160Sru 74756160Sru get_rest_of_line (0, &line); 74856160Sru 74956160Sru for (i = 0; line[i] && !whitespace (line[i]); i++); 75056160Sru name = xmalloc (i + 1); 75156160Sru memcpy (name, line, i); 75256160Sru name[i] = 0; 75356160Sru 75456160Sru def = delete_macro (name); 75556160Sru 75656160Sru if (def) 75756160Sru { 75856160Sru free (def->source_file); 75956160Sru free (def->name); 76056160Sru free (def->body); 76156160Sru 76256160Sru if (def->arglist) 76356160Sru { 76456160Sru int i; 76556160Sru 76656160Sru for (i = 0; def->arglist[i]; i++) 76756160Sru free (def->arglist[i]); 76856160Sru 76956160Sru free (def->arglist); 77056160Sru } 77156160Sru 77256160Sru free (def); 77356160Sru } 77456160Sru 77556160Sru free (line); 77656160Sru free (name); 77756160Sru 77856160Sru if (macro_expansion_output_stream && !executing_string) 77956160Sru remember_itext (input_text, input_text_offset); 78056160Sru} 78156160Sru 78256160Sru/* How to output sections of the input file verbatim. */ 78356160Sru 78456160Sru/* Set the value of POINTER's offset to OFFSET. */ 78556160SruITEXT * 786146515Sruremember_itext (char *pointer, int offset) 78756160Sru{ 78856160Sru int i; 78956160Sru ITEXT *itext = NULL; 79056160Sru 79156160Sru /* If we have no info, initialize a blank list. */ 79256160Sru if (!itext_info) 79356160Sru { 79456160Sru itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *)); 79556160Sru for (i = 0; i < itext_size; i++) 79656160Sru itext_info[i] = NULL; 79756160Sru } 79856160Sru 79956160Sru /* If the pointer is already present in the list, then set the offset. */ 80056160Sru for (i = 0; i < itext_size; i++) 80156160Sru if ((itext_info[i]) && 80256160Sru (itext_info[i]->pointer == pointer)) 80356160Sru { 80456160Sru itext = itext_info[i]; 80556160Sru itext_info[i]->offset = offset; 80656160Sru break; 80756160Sru } 80856160Sru 80956160Sru if (i == itext_size) 81056160Sru { 81156160Sru /* Find a blank slot (or create a new one), and remember the 81256160Sru pointer and offset. */ 81356160Sru for (i = 0; i < itext_size; i++) 81456160Sru if (itext_info[i] == NULL) 81556160Sru break; 81656160Sru 81756160Sru /* If not found, then add some slots. */ 81856160Sru if (i == itext_size) 81956160Sru { 82056160Sru int j; 82156160Sru 82256160Sru itext_info = xrealloc 82356160Sru (itext_info, (itext_size += 10) * sizeof (ITEXT *)); 82456160Sru 82556160Sru for (j = i; j < itext_size; j++) 82656160Sru itext_info[j] = NULL; 82756160Sru } 82856160Sru 82956160Sru /* Now add the pointer and the offset. */ 83056160Sru itext_info[i] = xmalloc (sizeof (ITEXT)); 83156160Sru itext_info[i]->pointer = pointer; 83256160Sru itext_info[i]->offset = offset; 83356160Sru itext = itext_info[i]; 83456160Sru } 83556160Sru return itext; 83656160Sru} 83756160Sru 83856160Sru/* Forget the input text associated with POINTER. */ 83956160Sruvoid 840146515Sruforget_itext (char *pointer) 84156160Sru{ 84256160Sru int i; 84356160Sru 84456160Sru for (i = 0; i < itext_size; i++) 84556160Sru if (itext_info[i] && (itext_info[i]->pointer == pointer)) 84656160Sru { 84756160Sru free (itext_info[i]); 84856160Sru itext_info[i] = NULL; 84956160Sru break; 85056160Sru } 85156160Sru} 85256160Sru 85356160Sru/* Append the text which appeared in input_text from the last offset to 85456160Sru the character just before the command that we are currently executing. */ 85556160Sruvoid 856146515Srume_append_before_this_command (void) 85756160Sru{ 85856160Sru int i; 85956160Sru 86056160Sru for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--) 86156160Sru ; 86256160Sru maybe_write_itext (input_text, i); 86356160Sru} 86456160Sru 86556160Sru/* Similar to execute_string, but only takes a single string argument, 86656160Sru and remembers the input text location, etc. */ 86756160Sruvoid 868146515Srume_execute_string (char *execution_string) 86956160Sru{ 87056160Sru int saved_escape_html = escape_html; 87156160Sru int saved_in_paragraph = in_paragraph; 87256160Sru escape_html = me_executing_string == 0; 87356160Sru in_paragraph = 0; 87456160Sru 87556160Sru pushfile (); 87656160Sru input_text_offset = 0; 87756160Sru /* The following xstrdup is so we can relocate input_text at will. */ 87856160Sru input_text = xstrdup (execution_string); 87956160Sru input_filename = xstrdup (input_filename); 88056160Sru input_text_length = strlen (execution_string); 88156160Sru 88256160Sru remember_itext (input_text, 0); 88356160Sru 88456160Sru me_executing_string++; 88556160Sru reader_loop (); 88656160Sru free (input_text); 88756160Sru free (input_filename); 88856160Sru popfile (); 88956160Sru me_executing_string--; 89056160Sru 89156160Sru in_paragraph = saved_in_paragraph; 89256160Sru escape_html = saved_escape_html; 89356160Sru} 89456160Sru 89556160Sru/* A wrapper around me_execute_string which saves and restores 89656160Sru variables important for output generation. This is called 89756160Sru when we need to produce macro-expanded output for input which 89856160Sru leaves no traces in the Info output. */ 89956160Sruvoid 900146515Srume_execute_string_keep_state (char *execution_string, char *append_string) 90156160Sru{ 90256160Sru int op_orig, opcol_orig, popen_orig; 90356160Sru int fill_orig, newline_orig, indent_orig, meta_pos_orig; 90456160Sru 90556160Sru remember_itext (input_text, input_text_offset); 90656160Sru op_orig = output_paragraph_offset; 90756160Sru meta_pos_orig = meta_char_pos; 90856160Sru opcol_orig = output_column; 90956160Sru popen_orig = paragraph_is_open; 91056160Sru fill_orig = filling_enabled; 91156160Sru newline_orig = last_char_was_newline; 91256160Sru filling_enabled = 0; 91356160Sru indent_orig = no_indent; 91456160Sru no_indent = 1; 91556160Sru me_execute_string (execution_string); 91656160Sru if (append_string) 91756160Sru write_region_to_macro_output (append_string, 0, strlen (append_string)); 91856160Sru output_paragraph_offset = op_orig; 91956160Sru meta_char_pos = meta_pos_orig; 92056160Sru output_column = opcol_orig; 92156160Sru paragraph_is_open = popen_orig; 92256160Sru filling_enabled = fill_orig; 92356160Sru last_char_was_newline = newline_orig; 92456160Sru no_indent = indent_orig; 92556160Sru} 92656160Sru 92756160Sru/* Append the text which appears in input_text from the last offset to 92856160Sru the current OFFSET. */ 92956160Sruvoid 930146515Sruappend_to_expansion_output (int offset) 93156160Sru{ 93256160Sru int i; 93356160Sru ITEXT *itext = NULL; 93456160Sru 93556160Sru for (i = 0; i < itext_size; i++) 93656160Sru if (itext_info[i] && itext_info[i]->pointer == input_text) 93756160Sru { 93856160Sru itext = itext_info[i]; 93956160Sru break; 94056160Sru } 94156160Sru 94256160Sru if (!itext) 94356160Sru return; 94456160Sru 94556160Sru if (offset > itext->offset) 94656160Sru { 94756160Sru write_region_to_macro_output (input_text, itext->offset, offset); 94856160Sru remember_itext (input_text, offset); 94956160Sru } 95056160Sru} 95156160Sru 95256160Sru/* Only write this input text iff it appears in our itext list. */ 95356160Sruvoid 954146515Srumaybe_write_itext (char *pointer, int offset) 95556160Sru{ 95656160Sru int i; 95756160Sru ITEXT *itext = NULL; 95856160Sru 95956160Sru for (i = 0; i < itext_size; i++) 96056160Sru if (itext_info[i] && (itext_info[i]->pointer == pointer)) 96156160Sru { 96256160Sru itext = itext_info[i]; 96356160Sru break; 96456160Sru } 96556160Sru 96656160Sru if (itext && (itext->offset < offset)) 96756160Sru { 96856160Sru write_region_to_macro_output (itext->pointer, itext->offset, offset); 96956160Sru remember_itext (pointer, offset); 97056160Sru } 97156160Sru} 97256160Sru 97356160Sruvoid 974146515Sruwrite_region_to_macro_output (char *string, int start, int end) 97556160Sru{ 97656160Sru if (macro_expansion_output_stream) 97756160Sru fwrite (string + start, 1, end - start, macro_expansion_output_stream); 97856160Sru} 97956160Sru 98056160Sru/* Aliases. */ 98156160Sru 98256160Srutypedef struct alias_struct 98356160Sru{ 98456160Sru char *alias; 98556160Sru char *mapto; 98656160Sru struct alias_struct *next; 98756160Sru} alias_type; 98856160Sru 98956160Srustatic alias_type *aliases; 99056160Sru 991146515Sru/* @alias aname = cmdname */ 992146515Sru 99356160Sruvoid 994146515Srucm_alias (void) 99556160Sru{ 99656160Sru alias_type *a = xmalloc (sizeof (alias_type)); 99756160Sru 99856160Sru skip_whitespace (); 999146515Sru get_until_in_line (0, "=", &(a->alias)); 100093139Sru canon_white (a->alias); 100193139Sru 100256160Sru discard_until ("="); 100356160Sru skip_whitespace (); 100456160Sru get_until_in_line (0, " ", &(a->mapto)); 100556160Sru 100656160Sru a->next = aliases; 100756160Sru aliases = a; 100856160Sru} 100956160Sru 101056160Sru/* Perform an alias expansion. Called from read_command. */ 101156160Sruchar * 1012146515Srualias_expand (char *tok) 101356160Sru{ 101456160Sru alias_type *findit = aliases; 101556160Sru 101656160Sru while (findit) 101756160Sru if (strcmp (findit->alias, tok) == 0) 101856160Sru { 101956160Sru free (tok); 102056160Sru return alias_expand (xstrdup (findit->mapto)); 102156160Sru } 102256160Sru else 102356160Sru findit = findit->next; 102456160Sru 102556160Sru return tok; 102656160Sru} 102756160Sru 102856160Sru/* definfoenclose implementation. */ 102956160Sru 103056160Sru/* This structure is used to track enclosure macros. When an enclosure 103156160Sru macro is recognized, a pointer to the enclosure block corresponding 103256160Sru to its name is saved in the brace element for its argument. */ 103356160Srutypedef struct enclose_struct 103456160Sru{ 103556160Sru char *enclose; 103656160Sru char *before; 103756160Sru char *after; 103856160Sru struct enclose_struct *next; 103956160Sru} enclosure_type; 104056160Sru 104156160Srustatic enclosure_type *enclosures; 104256160Sru 104356160Srutypedef struct enclosure_stack_struct 104456160Sru{ 104556160Sru enclosure_type *current; 104656160Sru struct enclosure_stack_struct *next; 104756160Sru} enclosure_stack_type; 104856160Sru 104956160Srustatic enclosure_stack_type *enclosure_stack; 105056160Sru 105156160Sru/* @definfoenclose */ 105256160Sruvoid 1053146515Srucm_definfoenclose (void) 105456160Sru{ 105556160Sru enclosure_type *e = xmalloc (sizeof (enclosure_type)); 105656160Sru 105756160Sru skip_whitespace (); 105856160Sru get_until_in_line (1, ",", &(e->enclose)); 105956160Sru discard_until (","); 106056160Sru get_until_in_line (0, ",", &(e->before)); 106156160Sru discard_until (","); 106256160Sru get_until_in_line (0, "\n", &(e->after)); 106356160Sru 106456160Sru e->next = enclosures; 106556160Sru enclosures = e; 106656160Sru} 106756160Sru 106856160Sru/* If TOK is an enclosure command, push it on the enclosure stack and 106956160Sru return 1. Else return 0. */ 107056160Sru 107156160Sruint 1072146515Sruenclosure_command (char *tok) 107356160Sru{ 107456160Sru enclosure_type *findit = enclosures; 107556160Sru 107656160Sru while (findit) 107756160Sru if (strcmp (findit->enclose, tok) == 0) 107856160Sru { 107956160Sru enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type)); 108056160Sru new->current = findit; 108156160Sru new->next = enclosure_stack; 108256160Sru enclosure_stack = new; 108356160Sru 108456160Sru return 1; 108556160Sru } 108656160Sru else 108756160Sru findit = findit->next; 108856160Sru 108956160Sru return 0; 109056160Sru} 109156160Sru 109256160Sru/* actually perform the enclosure expansion */ 109356160Sruvoid 1094146515Sruenclosure_expand (int arg, int start, int end) 109556160Sru{ 109656160Sru if (arg == START) 109756160Sru add_word (enclosure_stack->current->before); 109856160Sru else 109956160Sru { 110056160Sru enclosure_stack_type *temp; 110156160Sru 110256160Sru add_word (enclosure_stack->current->after); 110356160Sru 110456160Sru temp = enclosure_stack; 110556160Sru enclosure_stack = enclosure_stack->next; 110656160Sru free (temp); 110756160Sru } 110856160Sru} 1109