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