1 /* $NetBSD: macro.c,v 1.4 2025/12/31 22:18:50 oster Exp $ */ 2 3 /* macro.c -- user-defined macros for Texinfo. 4 Id: macro.c,v 1.6 2004/04/11 17:56:47 karl Exp 5 6 Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2, or (at your option) 11 any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software Foundation, 20 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 21 22 #include "system.h" 23 #include "cmds.h" 24 #include "files.h" 25 #include "macro.h" 26 #include "makeinfo.h" 27 #include "insertion.h" 28 29 /* If non-NULL, this is an output stream to write the full macro expansion 30 of the input text to. The result is another texinfo file, but 31 missing @include, @infoinclude, @macro, and macro invocations. Instead, 32 all of the text is placed within the file. */ 33 FILE *macro_expansion_output_stream = NULL; 34 35 /* Output file for -E. */ 36 char *macro_expansion_filename; 37 38 /* Nonzero means a macro string is in execution, as opposed to a file. */ 39 int me_executing_string = 0; 40 41 /* Nonzero means we want only to expand macros and 42 leave everything else intact. */ 43 int only_macro_expansion = 0; 44 45 static ITEXT **itext_info = NULL; 46 static int itext_size = 0; 47 48 /* Return the arglist on the current line. This can behave in two different 49 ways, depending on the variable BRACES_REQUIRED_FOR_MACRO_ARGS. */ 50 int braces_required_for_macro_args = 0; 51 52 /* Array of macros and definitions. */ 53 MACRO_DEF **macro_list = NULL; 54 55 int macro_list_len = 0; /* Number of elements. */ 56 int macro_list_size = 0; /* Number of slots in total. */ 57 58 /* Return the length of the array in ARRAY. */ 60 int 61 array_len (char **array) 62 { 63 int i = 0; 64 65 if (array) 66 for (i = 0; array[i]; i++); 67 68 return i; 69 } 70 71 void 72 free_array (char **array) 73 { 74 if (array) 75 { 76 int i; 77 for (i = 0; array[i]; i++) 78 free (array[i]); 79 80 free (array); 81 } 82 } 83 84 /* Return the macro definition of NAME or NULL if NAME is not defined. */ 86 MACRO_DEF * 87 find_macro (char *name) 88 { 89 int i; 90 MACRO_DEF *def; 91 92 def = NULL; 93 for (i = 0; macro_list && (def = macro_list[i]); i++) 94 { 95 if ((!def->inhibited) && (strcmp (def->name, name) == 0)) 96 break; 97 } 98 return def; 99 } 100 101 /* Add the macro NAME with ARGLIST and BODY to the list of defined macros. 102 SOURCE_FILE is the name of the file where this definition can be found, 103 and SOURCE_LINENO is the line number within that file. If a macro already 104 exists with NAME, then a warning is produced, and that previous 105 definition is overwritten. */ 106 static void 107 add_macro (char *name, char **arglist, char *body, char *source_file, 108 int source_lineno, int flags) 109 { 110 MACRO_DEF *def; 111 112 def = find_macro (name); 113 114 if (!def) 115 { 116 if (macro_list_len + 2 >= macro_list_size) 117 macro_list = xrealloc 118 (macro_list, ((macro_list_size += 10) * sizeof (MACRO_DEF *))); 119 120 macro_list[macro_list_len] = xmalloc (sizeof (MACRO_DEF)); 121 macro_list[macro_list_len + 1] = NULL; 122 123 def = macro_list[macro_list_len]; 124 macro_list_len += 1; 125 def->name = name; 126 } 127 else 128 { 129 char *temp_filename = input_filename; 130 int temp_line = line_number; 131 132 warning (_("macro `%s' previously defined"), name); 133 134 input_filename = def->source_file; 135 line_number = def->source_lineno; 136 warning (_("here is the previous definition of `%s'"), name); 137 138 input_filename = temp_filename; 139 line_number = temp_line; 140 141 if (def->arglist) 142 { 143 int i; 144 145 for (i = 0; def->arglist[i]; i++) 146 free (def->arglist[i]); 147 148 free (def->arglist); 149 } 150 free (def->source_file); 151 free (def->body); 152 } 153 154 def->source_file = xstrdup (source_file); 155 def->source_lineno = source_lineno; 156 def->body = body; 157 def->arglist = arglist; 158 def->inhibited = 0; 159 def->flags = flags; 160 } 161 162 163 char ** 164 get_brace_args (int quote_single) 165 { 166 char **arglist, *word; 167 int arglist_index, arglist_size; 168 int character, escape_seen, start; 169 int depth = 1; 170 171 /* There is an arglist in braces here, so gather the args inside of it. */ 172 skip_whitespace_and_newlines (); 173 input_text_offset++; 174 arglist = NULL; 175 arglist_index = arglist_size = 0; 176 177 get_arg: 178 skip_whitespace_and_newlines (); 179 start = input_text_offset; 180 escape_seen = 0; 181 182 while ((character = curchar ())) 183 { 184 if (character == '\\') 185 { 186 input_text_offset += 2; 187 escape_seen = 1; 188 } 189 else if (character == '{') 190 { 191 depth++; 192 input_text_offset++; 193 } 194 else if ((character == ',' && !quote_single) || 195 ((character == '}') && depth == 1)) 196 { 197 int len = input_text_offset - start; 198 199 if (len || (character != '}')) 200 { 201 word = xmalloc (1 + len); 202 memcpy (word, input_text + start, len); 203 word[len] = 0; 204 205 /* Clean up escaped characters. */ 206 if (escape_seen) 207 { 208 int i; 209 for (i = 0; word[i]; i++) 210 if (word[i] == '\\') 211 memmove (word + i, word + i + 1, 212 1 + strlen (word + i + 1)); 213 } 214 215 if (arglist_index + 2 >= arglist_size) 216 arglist = xrealloc 217 (arglist, (arglist_size += 10) * sizeof (char *)); 218 219 arglist[arglist_index++] = word; 220 arglist[arglist_index] = NULL; 221 } 222 223 input_text_offset++; 224 if (character == '}') 225 break; 226 else 227 goto get_arg; 228 } 229 else if (character == '}') 230 { 231 depth--; 232 input_text_offset++; 233 } 234 else 235 { 236 input_text_offset++; 237 if (character == '\n') line_number++; 238 } 239 } 240 return arglist; 241 } 242 243 static char ** 244 get_macro_args (MACRO_DEF *def) 245 { 246 int i; 247 char *word; 248 249 /* Quickly check to see if this macro has been invoked with any arguments. 250 If not, then don't skip any of the following whitespace. */ 251 for (i = input_text_offset; i < input_text_length; i++) 252 if (!cr_or_whitespace (input_text[i])) 253 break; 254 255 if (input_text[i] != '{') 256 { 257 if (braces_required_for_macro_args) 258 { 259 return NULL; 260 } 261 else 262 { 263 /* Braces are not required to fill out the macro arguments. If 264 this macro takes one argument, it is considered to be the 265 remainder of the line, sans whitespace. */ 266 if (def->arglist && def->arglist[0] && !def->arglist[1]) 267 { 268 char **arglist; 269 270 get_rest_of_line (0, &word); 271 if (input_text[input_text_offset - 1] == '\n') 272 { 273 input_text_offset--; 274 line_number--; 275 } 276 /* canon_white (word); */ 277 arglist = xmalloc (2 * sizeof (char *)); 278 arglist[0] = word; 279 arglist[1] = NULL; 280 return arglist; 281 } 282 else 283 { 284 /* The macro either took no arguments, or took more than 285 one argument. In that case, it must be invoked with 286 arguments surrounded by braces. */ 287 return NULL; 288 } 289 } 290 } 291 return get_brace_args (def->flags & ME_QUOTE_ARG); 292 } 293 294 /* Substitute actual parameters for named parameters in body. 295 The named parameters which appear in BODY must by surrounded 296 reverse slashes, as in \foo\. */ 297 static char * 298 apply (char **named, char **actuals, char *body) 299 { 300 int i; 301 int new_body_index, new_body_size; 302 char *new_body, *text; 303 int length_of_actuals; 304 305 length_of_actuals = array_len (actuals); 306 new_body_size = strlen (body); 307 new_body = xmalloc (1 + new_body_size); 308 309 /* Copy chars from BODY into NEW_BODY. */ 310 i = 0; 311 new_body_index = 0; 312 313 while (body[i]) 314 { /* Anything but a \ is easy. */ 315 if (body[i] != '\\') 316 new_body[new_body_index++] = body[i++]; 317 else 318 { /* Snarf parameter name, check against named parameters. */ 319 char *param; 320 int param_start, len; 321 322 param_start = ++i; 323 while (body[i] && body[i] != '\\') 324 i++; 325 326 len = i - param_start; 327 param = xmalloc (1 + len); 328 memcpy (param, body + param_start, len); 329 param[len] = 0; 330 331 if (body[i]) /* move past \ */ 332 i++; 333 334 if (len == 0) 335 { /* \\ always means \, even if macro has no args. */ 336 len++; 337 text = xmalloc (1 + len); 338 sprintf (text, "\\%s", param); 339 } 340 else 341 { 342 int which; 343 344 /* Check against named parameters. */ 345 for (which = 0; named && named[which]; which++) 346 if (STREQ (named[which], param)) 347 break; 348 349 if (named && named[which]) 350 { 351 text = which < length_of_actuals ? actuals[which] : NULL; 352 if (!text) 353 text = ""; 354 len = strlen (text); 355 text = xstrdup (text); /* so we can free it */ 356 } 357 else 358 { /* not a parameter, so it's an error. */ 359 warning (_("\\ in macro expansion followed by `%s' instead of parameter name"), 360 param); 361 len++; 362 text = xmalloc (1 + len); 363 sprintf (text, "\\%s", param); 364 } 365 } 366 367 if (strlen (param) + 2 < len) 368 { 369 new_body_size += len + 1; 370 new_body = xrealloc (new_body, new_body_size); 371 } 372 373 free (param); 374 375 strcpy (new_body + new_body_index, text); 376 new_body_index += len; 377 378 free (text); 379 } 380 } 381 382 new_body[new_body_index] = 0; 383 return new_body; 384 } 385 386 /* Expand macro passed in DEF, a pointer to a MACRO_DEF, and 387 return its expansion as a string. */ 388 char * 389 expand_macro (MACRO_DEF *def) 390 { 391 char **arglist; 392 int num_args; 393 char *execution_string = NULL; 394 int start_line = line_number; 395 396 /* Find out how many arguments this macro definition takes. */ 397 num_args = array_len (def->arglist); 398 399 /* Gather the arguments present on the line if there are any. */ 400 arglist = get_macro_args (def); 401 402 if (num_args < array_len (arglist)) 403 { 404 free_array (arglist); 405 line_error (_("Macro `%s' called on line %d with too many args"), 406 def->name, start_line); 407 return execution_string; 408 } 409 410 if (def->body) 411 execution_string = apply (def->arglist, arglist, def->body); 412 413 free_array (arglist); 414 return execution_string; 415 } 416 417 /* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */ 418 void 419 execute_macro (MACRO_DEF *def) 420 { 421 char *execution_string; 422 int start_line = line_number, end_line; 423 424 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion) 425 me_append_before_this_command (); 426 427 execution_string = expand_macro (def); 428 if (!execution_string) 429 return; 430 431 if (def->body) 432 { 433 /* Reset the line number to where the macro arguments began. 434 This makes line numbers reported in error messages correct in 435 case the macro arguments span several lines and the expanded 436 arguments invoke other commands. */ 437 end_line = line_number; 438 line_number = start_line; 439 440 if (macro_expansion_output_stream 441 && !executing_string && !me_inhibit_expansion) 442 { 443 remember_itext (input_text, input_text_offset); 444 me_execute_string (execution_string); 445 } 446 else 447 execute_string ("%s", execution_string); 448 449 free (execution_string); 450 line_number = end_line; 451 } 452 } 453 454 455 /* Read and remember the definition of a macro. If RECURSIVE is set, 457 set the ME_RECURSE flag. MACTYPE is either "macro" or "rmacro", and 458 tells us what the matching @end should be. */ 459 static void 460 define_macro (char *mactype, int recursive) 461 { 462 int i, start; 463 char *name, *line; 464 char *last_end = NULL; 465 char *body = NULL; 466 char **arglist = NULL; 467 int body_size = 0, body_index = 0; 468 int depth = 1; 469 int flags = 0; 470 int defining_line = line_number; 471 472 if (macro_expansion_output_stream && !executing_string) 473 me_append_before_this_command (); 474 475 skip_whitespace (); 476 477 /* Get the name of the macro. This is the set of characters which are 478 not whitespace and are not `{' immediately following the @macro. */ 479 start = input_text_offset; 480 { 481 int len; 482 483 for (i = start; i < input_text_length && input_text[i] != '{' 484 && !cr_or_whitespace (input_text[i]); 485 i++) ; 486 487 len = i - start; 488 name = xmalloc (1 + len); 489 memcpy (name, input_text + start, len); 490 name[len] = 0; 491 input_text_offset = i; 492 } 493 494 skip_whitespace (); 495 496 /* It is not required that the definition of a macro includes an arglist. 497 If not, don't try to get the named parameters, just use a null list. */ 498 if (curchar () == '{') 499 { 500 int character; 501 int arglist_index = 0, arglist_size = 0; 502 int gathering_words = 1; 503 char *word = NULL; 504 505 /* Read the words inside of the braces which determine the arglist. 506 These words will be replaced within the body of the macro at 507 execution time. */ 508 509 input_text_offset++; 510 skip_whitespace_and_newlines (); 511 512 while (gathering_words) 513 { 514 int len; 515 516 for (i = input_text_offset; 517 (character = input_text[i]); 518 i++) 519 { 520 switch (character) 521 { 522 case '\n': 523 line_number++; 524 case ' ': 525 case '\t': 526 case ',': 527 case '}': 528 /* Found the end of the current arglist word. Save it. */ 529 len = i - input_text_offset; 530 word = xmalloc (1 + len); 531 memcpy (word, input_text + input_text_offset, len); 532 word[len] = 0; 533 input_text_offset = i; 534 535 /* Advance to the comma or close-brace that signified 536 the end of the argument. */ 537 while ((character = curchar ()) 538 && character != ',' 539 && character != '}') 540 { 541 input_text_offset++; 542 if (character == '\n') 543 line_number++; 544 } 545 546 /* Add the word to our list of words. */ 547 if (arglist_index + 2 >= arglist_size) 548 { 549 arglist_size += 10; 550 arglist = xrealloc (arglist, 551 arglist_size * sizeof (char *)); 552 } 553 554 arglist[arglist_index++] = word; 555 arglist[arglist_index] = NULL; 556 break; 557 } 558 559 if (character == '}') 560 { 561 input_text_offset++; 562 gathering_words = 0; 563 break; 564 } 565 566 if (character == ',') 567 { 568 input_text_offset++; 569 skip_whitespace_and_newlines (); 570 i = input_text_offset - 1; 571 } 572 } 573 } 574 575 /* If we have exactly one argument, do @quote-arg implicitly. Not 576 only does this match TeX's behavior (which can't feasibly be 577 changed), but it's a good idea. */ 578 if (arglist_index == 1) 579 flags |= ME_QUOTE_ARG; 580 } 581 582 /* Read the text carefully until we find an "@end macro" which 583 matches this one. The text in between is the body of the macro. */ 584 skip_whitespace_and_newlines (); 585 586 while (depth) 587 { 588 if ((input_text_offset + 9) > input_text_length) 589 { 590 file_line_error (input_filename, defining_line, 591 _("%cend macro not found"), COMMAND_PREFIX); 592 return; 593 } 594 595 get_rest_of_line (0, &line); 596 597 /* Handle commands only meaningful within a macro. */ 598 if ((*line == COMMAND_PREFIX) && (depth == 1) && 599 (strncmp (line + 1, "allow-recursion", 15) == 0) && 600 (line[16] == 0 || whitespace (line[16]))) 601 { 602 for (i = 16; whitespace (line[i]); i++); 603 strcpy (line, line + i); 604 flags |= ME_RECURSE; 605 if (!*line) 606 { 607 free (line); 608 continue; 609 } 610 } 611 612 if ((*line == COMMAND_PREFIX) && (depth == 1) && 613 (strncmp (line + 1, "quote-arg", 9) == 0) && 614 (line[10] == 0 || whitespace (line[10]))) 615 { 616 for (i = 10; whitespace (line[i]); i++); 617 strcpy (line, line + i); 618 619 if (arglist && arglist[0] && !arglist[1]) 620 { 621 flags |= ME_QUOTE_ARG; 622 if (!*line) 623 { 624 free (line); 625 continue; 626 } 627 } 628 else 629 line_error (_("@quote-arg only useful for single-argument macros")); 630 } 631 632 if (*line == COMMAND_PREFIX 633 && (strncmp (line + 1, "macro ", 6) == 0 634 || strncmp (line + 1, "rmacro ", 7) == 0)) 635 depth++; 636 637 /* Incorrect implementation of nesting -- just check that the last 638 @end matches what we started with. Since nested macros don't 639 work in TeX anyway, this isn't worth the trouble to get right. */ 640 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0) 641 { 642 depth--; 643 last_end = "macro"; 644 } 645 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 10) == 0) 646 { 647 depth--; 648 last_end = "rmacro"; 649 } 650 651 if (depth) 652 { 653 if ((body_index + strlen (line) + 3) >= body_size) 654 body = xrealloc (body, body_size += 3 + strlen (line)); 655 strcpy (body + body_index, line); 656 body_index += strlen (line); 657 body[body_index++] = '\n'; 658 body[body_index] = 0; 659 } 660 free (line); 661 } 662 663 /* Check that @end matched the macro command. */ 664 if (!STREQ (last_end, mactype)) 665 warning (_("mismatched @end %s with @%s"), last_end, mactype); 666 667 /* If it was an empty macro like 668 @macro foo 669 @end macro 670 create an empty body. (Otherwise, the macro is not expanded.) */ 671 if (!body) 672 { 673 body = (char *)malloc(1); 674 *body = 0; 675 } 676 677 /* We now have the name, the arglist, and the body. However, BODY 678 includes the final newline which preceded the `@end macro' text. 679 Delete it. */ 680 if (body && strlen (body)) 681 body[strlen (body) - 1] = 0; 682 683 if (recursive) 684 flags |= ME_RECURSE; 685 686 add_macro (name, arglist, body, input_filename, defining_line, flags); 687 688 if (macro_expansion_output_stream && !executing_string) 689 { 690 /* Remember text for future expansions. */ 691 remember_itext (input_text, input_text_offset); 692 693 /* Bizarrely, output the @macro itself. This is so texinfo.tex 694 will have a chance to read it when texi2dvi calls makeinfo -E. 695 The problem is that we don't really expand macros in all 696 contexts; a @table's @item is one. And a fix is not obvious to 697 me, since it appears virtually identical to any other internal 698 expansion. Just setting a variable in cm_item caused other 699 strange expansion problems. */ 700 write_region_to_macro_output ("@", 0, 1); 701 write_region_to_macro_output (mactype, 0, strlen (mactype)); 702 write_region_to_macro_output (" ", 0, 1); 703 write_region_to_macro_output (input_text, start, input_text_offset); 704 } 705 } 706 707 void 708 cm_macro (int arg, int arg2, int arg3) 709 { 710 define_macro ("macro", 0); 711 } 712 713 void 714 cm_rmacro (int arg, int arg2, int arg3) 715 { 716 define_macro ("rmacro", 1); 717 } 718 719 /* Delete the macro with name NAME. The macro is deleted from the list, 721 but it is also returned. If there was no macro defined, NULL is 722 returned. */ 723 724 static MACRO_DEF * 725 delete_macro (char *name) 726 { 727 int i; 728 MACRO_DEF *def; 729 730 def = NULL; 731 732 for (i = 0; macro_list && (def = macro_list[i]); i++) 733 if (strcmp (def->name, name) == 0) 734 { 735 memmove (macro_list + i, macro_list + i + 1, 736 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *)); 737 macro_list_len--; 738 break; 739 } 740 return def; 741 } 742 743 void 744 cm_unmacro (int arg, int arg2, int arg3) 745 { 746 int i; 747 char *line, *name; 748 MACRO_DEF *def; 749 750 if (macro_expansion_output_stream && !executing_string) 751 me_append_before_this_command (); 752 753 get_rest_of_line (0, &line); 754 755 for (i = 0; line[i] && !whitespace (line[i]); i++); 756 name = xmalloc (i + 1); 757 memcpy (name, line, i); 758 name[i] = 0; 759 760 def = delete_macro (name); 761 762 if (def) 763 { 764 free (def->source_file); 765 free (def->name); 766 free (def->body); 767 768 if (def->arglist) 769 { 770 int i; 771 772 for (i = 0; def->arglist[i]; i++) 773 free (def->arglist[i]); 774 775 free (def->arglist); 776 } 777 778 free (def); 779 } 780 781 free (line); 782 free (name); 783 784 if (macro_expansion_output_stream && !executing_string) 785 remember_itext (input_text, input_text_offset); 786 } 787 788 /* How to output sections of the input file verbatim. */ 790 791 /* Set the value of POINTER's offset to OFFSET. */ 792 ITEXT * 793 remember_itext (char *pointer, int offset) 794 { 795 int i; 796 ITEXT *itext = NULL; 797 798 /* If we have no info, initialize a blank list. */ 799 if (!itext_info) 800 { 801 itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *)); 802 for (i = 0; i < itext_size; i++) 803 itext_info[i] = NULL; 804 } 805 806 /* If the pointer is already present in the list, then set the offset. */ 807 for (i = 0; i < itext_size; i++) 808 if ((itext_info[i]) && 809 (itext_info[i]->pointer == pointer)) 810 { 811 itext = itext_info[i]; 812 itext_info[i]->offset = offset; 813 break; 814 } 815 816 if (i == itext_size) 817 { 818 /* Find a blank slot (or create a new one), and remember the 819 pointer and offset. */ 820 for (i = 0; i < itext_size; i++) 821 if (itext_info[i] == NULL) 822 break; 823 824 /* If not found, then add some slots. */ 825 if (i == itext_size) 826 { 827 int j; 828 829 itext_info = xrealloc 830 (itext_info, (itext_size += 10) * sizeof (ITEXT *)); 831 832 for (j = i; j < itext_size; j++) 833 itext_info[j] = NULL; 834 } 835 836 /* Now add the pointer and the offset. */ 837 itext_info[i] = xmalloc (sizeof (ITEXT)); 838 itext_info[i]->pointer = pointer; 839 itext_info[i]->offset = offset; 840 itext = itext_info[i]; 841 } 842 return itext; 843 } 844 845 /* Forget the input text associated with POINTER. */ 846 void 847 forget_itext (char *pointer) 848 { 849 int i; 850 851 for (i = 0; i < itext_size; i++) 852 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 853 { 854 free (itext_info[i]); 855 itext_info[i] = NULL; 856 break; 857 } 858 } 859 860 /* Append the text which appeared in input_text from the last offset to 861 the character just before the command that we are currently executing. */ 862 void 863 me_append_before_this_command (void) 864 { 865 int i; 866 867 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--) 868 ; 869 maybe_write_itext (input_text, i); 870 } 871 872 /* Similar to execute_string, but only takes a single string argument, 873 and remembers the input text location, etc. */ 874 void 875 me_execute_string (char *execution_string) 876 { 877 int saved_escape_html = escape_html; 878 int saved_in_paragraph = in_paragraph; 879 escape_html = me_executing_string == 0; 880 in_paragraph = 0; 881 882 pushfile (); 883 input_text_offset = 0; 884 /* The following xstrdup is so we can relocate input_text at will. */ 885 input_text = xstrdup (execution_string); 886 input_filename = xstrdup (input_filename); 887 input_text_length = strlen (execution_string); 888 889 remember_itext (input_text, 0); 890 891 me_executing_string++; 892 reader_loop (); 893 free (input_text); 894 free (input_filename); 895 popfile (); 896 me_executing_string--; 897 898 in_paragraph = saved_in_paragraph; 899 escape_html = saved_escape_html; 900 } 901 902 /* A wrapper around me_execute_string which saves and restores 903 variables important for output generation. This is called 904 when we need to produce macro-expanded output for input which 905 leaves no traces in the Info output. */ 906 void 907 me_execute_string_keep_state (char *execution_string, char *append_string) 908 { 909 int op_orig, opcol_orig, popen_orig; 910 int fill_orig, newline_orig, indent_orig, meta_pos_orig; 911 912 remember_itext (input_text, input_text_offset); 913 op_orig = output_paragraph_offset; 914 meta_pos_orig = meta_char_pos; 915 opcol_orig = output_column; 916 popen_orig = paragraph_is_open; 917 fill_orig = filling_enabled; 918 newline_orig = last_char_was_newline; 919 filling_enabled = 0; 920 indent_orig = no_indent; 921 no_indent = 1; 922 me_execute_string (execution_string); 923 if (append_string) 924 write_region_to_macro_output (append_string, 0, strlen (append_string)); 925 output_paragraph_offset = op_orig; 926 meta_char_pos = meta_pos_orig; 927 output_column = opcol_orig; 928 paragraph_is_open = popen_orig; 929 filling_enabled = fill_orig; 930 last_char_was_newline = newline_orig; 931 no_indent = indent_orig; 932 } 933 934 /* Append the text which appears in input_text from the last offset to 935 the current OFFSET. */ 936 void 937 append_to_expansion_output (int offset) 938 { 939 int i; 940 ITEXT *itext = NULL; 941 942 for (i = 0; i < itext_size; i++) 943 if (itext_info[i] && itext_info[i]->pointer == input_text) 944 { 945 itext = itext_info[i]; 946 break; 947 } 948 949 if (!itext) 950 return; 951 952 if (offset > itext->offset) 953 { 954 write_region_to_macro_output (input_text, itext->offset, offset); 955 remember_itext (input_text, offset); 956 } 957 } 958 959 /* Only write this input text iff it appears in our itext list. */ 960 void 961 maybe_write_itext (char *pointer, int offset) 962 { 963 int i; 964 ITEXT *itext = NULL; 965 966 for (i = 0; i < itext_size; i++) 967 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 968 { 969 itext = itext_info[i]; 970 break; 971 } 972 973 if (itext && (itext->offset < offset)) 974 { 975 write_region_to_macro_output (itext->pointer, itext->offset, offset); 976 remember_itext (pointer, offset); 977 } 978 } 979 980 void 981 write_region_to_macro_output (char *string, int start, int end) 982 { 983 if (macro_expansion_output_stream) 984 fwrite (string + start, 1, end - start, macro_expansion_output_stream); 985 } 986 987 /* Aliases. */ 989 990 typedef struct alias_struct 991 { 992 char *alias; 993 char *mapto; 994 struct alias_struct *next; 995 } alias_type; 996 997 static alias_type *aliases; 998 999 /* @alias aname = cmdname */ 1000 1001 void 1002 cm_alias (int arg, int arg2, int arg3) 1003 { 1004 alias_type *a = xmalloc (sizeof (alias_type)); 1005 1006 skip_whitespace (); 1007 get_until_in_line (0, "=", &(a->alias)); 1008 canon_white (a->alias); 1009 1010 discard_until ("="); 1011 skip_whitespace (); 1012 get_until_in_line (0, " ", &(a->mapto)); 1013 1014 a->next = aliases; 1015 aliases = a; 1016 } 1017 1018 /* Perform an alias expansion. Called from read_command. */ 1019 char * 1020 alias_expand (char *tok) 1021 { 1022 alias_type *findit = aliases; 1023 1024 while (findit) 1025 if (strcmp (findit->alias, tok) == 0) 1026 { 1027 free (tok); 1028 return alias_expand (xstrdup (findit->mapto)); 1029 } 1030 else 1031 findit = findit->next; 1032 1033 return tok; 1034 } 1035 1036 /* definfoenclose implementation. */ 1038 1039 /* This structure is used to track enclosure macros. When an enclosure 1040 macro is recognized, a pointer to the enclosure block corresponding 1041 to its name is saved in the brace element for its argument. */ 1042 typedef struct enclose_struct 1043 { 1044 char *enclose; 1045 char *before; 1046 char *after; 1047 struct enclose_struct *next; 1048 } enclosure_type; 1049 1050 static enclosure_type *enclosures; 1051 1052 typedef struct enclosure_stack_struct 1053 { 1054 enclosure_type *current; 1055 struct enclosure_stack_struct *next; 1056 } enclosure_stack_type; 1057 1058 static enclosure_stack_type *enclosure_stack; 1059 1060 /* @definfoenclose */ 1061 void 1062 cm_definfoenclose (int arg, int arg2, int arg3) 1063 { 1064 enclosure_type *e = xmalloc (sizeof (enclosure_type)); 1065 1066 skip_whitespace (); 1067 get_until_in_line (1, ",", &(e->enclose)); 1068 discard_until (","); 1069 get_until_in_line (0, ",", &(e->before)); 1070 discard_until (","); 1071 get_until_in_line (0, "\n", &(e->after)); 1072 1073 e->next = enclosures; 1074 enclosures = e; 1075 } 1076 1077 /* If TOK is an enclosure command, push it on the enclosure stack and 1078 return 1. Else return 0. */ 1079 1080 int 1081 enclosure_command (char *tok) 1082 { 1083 enclosure_type *findit = enclosures; 1084 1085 while (findit) 1086 if (strcmp (findit->enclose, tok) == 0) 1087 { 1088 enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type)); 1089 new->current = findit; 1090 new->next = enclosure_stack; 1091 enclosure_stack = new; 1092 1093 return 1; 1094 } 1095 else 1096 findit = findit->next; 1097 1098 return 0; 1099 } 1100 1101 /* actually perform the enclosure expansion */ 1102 void 1103 enclosure_expand (int arg, int start, int end) 1104 { 1105 if (arg == START) 1106 add_word (enclosure_stack->current->before); 1107 else 1108 { 1109 enclosure_stack_type *temp; 1110 1111 add_word (enclosure_stack->current->after); 1112 1113 temp = enclosure_stack; 1114 enclosure_stack = enclosure_stack->next; 1115 free (temp); 1116 } 1117 } 1118