macro.c revision 93139
1/* macro.c -- user-defined macros for Texinfo. 2 $Id: macro.c,v 1.12 2002/03/02 15:05:21 karl Exp $ 3 4 Copyright (C) 1998, 99, 2002 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. */ 30FILE *macro_expansion_output_stream = NULL; 31 32/* Output file for -E. */ 33char *macro_expansion_filename; 34 35/* Nonzero means a macro string is in execution, as opposed to a file. */ 36int me_executing_string = 0; 37 38/* Nonzero means we want only to expand macros and 39 leave everything else intact. */ 40int only_macro_expansion = 0; 41 42static ITEXT **itext_info = NULL; 43static 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. */ 47int braces_required_for_macro_args = 0; 48 49/* Array of macros and definitions. */ 50MACRO_DEF **macro_list = NULL; 51 52int macro_list_len = 0; /* Number of elements. */ 53int macro_list_size = 0; /* Number of slots in total. */ 54 55/* Return the length of the array in ARRAY. */ 56int 57array_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 68void 69free_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. */ 83MACRO_DEF * 84find_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. */ 104void 105add_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 165char ** 166get_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 246char ** 247get_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\. */ 301char * 302apply (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. */ 385char * 386expand_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. */ 416void 417execute_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. */ 456static void 457define_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 file_line_error (input_filename, defining_line, 594 _("%cend macro not found"), COMMAND_PREFIX); 595 return; 596 } 597 598 get_rest_of_line (0, &line); 599 600 /* Handle commands only meaningful within a macro. */ 601 if ((*line == COMMAND_PREFIX) && (depth == 1) && 602 (strncmp (line + 1, "allow-recursion", 15) == 0) && 603 (line[16] == 0 || whitespace (line[16]))) 604 { 605 for (i = 16; whitespace (line[i]); i++); 606 strcpy (line, line + i); 607 flags |= ME_RECURSE; 608 if (!*line) 609 { 610 free (line); 611 continue; 612 } 613 } 614 615 if ((*line == COMMAND_PREFIX) && (depth == 1) && 616 (strncmp (line + 1, "quote-arg", 9) == 0) && 617 (line[10] == 0 || whitespace (line[10]))) 618 { 619 for (i = 10; whitespace (line[i]); i++); 620 strcpy (line, line + i); 621 622 if (arglist && arglist[0] && !arglist[1]) 623 { 624 flags |= ME_QUOTE_ARG; 625 if (!*line) 626 { 627 free (line); 628 continue; 629 } 630 } 631 else 632 line_error (_("@quote-arg only useful for single-argument macros")); 633 } 634 635 if (*line == COMMAND_PREFIX 636 && (strncmp (line + 1, "macro ", 6) == 0 637 || strncmp (line + 1, "rmacro ", 7) == 0)) 638 depth++; 639 640 /* Incorrect implementation of nesting -- just check that the last 641 @end matches what we started with. Since nested macros don't 642 work in TeX anyway, this isn't worth the trouble to get right. */ 643 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0) 644 { 645 depth--; 646 last_end = "macro"; 647 } 648 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 9) == 0) 649 { 650 depth--; 651 last_end = "rmacro"; 652 } 653 654 if (depth) 655 { 656 if ((body_index + strlen (line) + 3) >= body_size) 657 body = xrealloc (body, body_size += 3 + strlen (line)); 658 strcpy (body + body_index, line); 659 body_index += strlen (line); 660 body[body_index++] = '\n'; 661 body[body_index] = 0; 662 } 663 free (line); 664 } 665 666 /* Check that @end matched the macro command. */ 667 if (!STREQ (last_end, mactype)) 668 warning (_("mismatched @end %s with @%s"), last_end, mactype); 669 670 /* If it was an empty macro like 671 @macro foo 672 @end macro 673 create an empty body. (Otherwise, the macro is not expanded.) */ 674 if (!body) 675 { 676 body = (char *)malloc(1); 677 *body = 0; 678 } 679 680 /* We now have the name, the arglist, and the body. However, BODY 681 includes the final newline which preceded the `@end macro' text. 682 Delete it. */ 683 if (body && strlen (body)) 684 body[strlen (body) - 1] = 0; 685 686 if (recursive) 687 flags |= ME_RECURSE; 688 689 add_macro (name, arglist, body, input_filename, defining_line, flags); 690 691 if (macro_expansion_output_stream && !executing_string) 692 remember_itext (input_text, input_text_offset); 693} 694 695void 696cm_macro () 697{ 698 define_macro ("macro", 0); 699} 700 701void 702cm_rmacro () 703{ 704 define_macro ("rmacro", 1); 705} 706 707/* Delete the macro with name NAME. The macro is deleted from the list, 708 but it is also returned. If there was no macro defined, NULL is 709 returned. */ 710 711static MACRO_DEF * 712delete_macro (name) 713 char *name; 714{ 715 int i; 716 MACRO_DEF *def; 717 718 def = NULL; 719 720 for (i = 0; macro_list && (def = macro_list[i]); i++) 721 if (strcmp (def->name, name) == 0) 722 { 723 memmove (macro_list + i, macro_list + i + 1, 724 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *)); 725 macro_list_len--; 726 break; 727 } 728 return def; 729} 730 731void 732cm_unmacro () 733{ 734 int i; 735 char *line, *name; 736 MACRO_DEF *def; 737 738 if (macro_expansion_output_stream && !executing_string) 739 me_append_before_this_command (); 740 741 get_rest_of_line (0, &line); 742 743 for (i = 0; line[i] && !whitespace (line[i]); i++); 744 name = xmalloc (i + 1); 745 memcpy (name, line, i); 746 name[i] = 0; 747 748 def = delete_macro (name); 749 750 if (def) 751 { 752 free (def->source_file); 753 free (def->name); 754 free (def->body); 755 756 if (def->arglist) 757 { 758 int i; 759 760 for (i = 0; def->arglist[i]; i++) 761 free (def->arglist[i]); 762 763 free (def->arglist); 764 } 765 766 free (def); 767 } 768 769 free (line); 770 free (name); 771 772 if (macro_expansion_output_stream && !executing_string) 773 remember_itext (input_text, input_text_offset); 774} 775 776/* How to output sections of the input file verbatim. */ 777 778/* Set the value of POINTER's offset to OFFSET. */ 779ITEXT * 780remember_itext (pointer, offset) 781 char *pointer; 782 int offset; 783{ 784 int i; 785 ITEXT *itext = NULL; 786 787 /* If we have no info, initialize a blank list. */ 788 if (!itext_info) 789 { 790 itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *)); 791 for (i = 0; i < itext_size; i++) 792 itext_info[i] = NULL; 793 } 794 795 /* If the pointer is already present in the list, then set the offset. */ 796 for (i = 0; i < itext_size; i++) 797 if ((itext_info[i]) && 798 (itext_info[i]->pointer == pointer)) 799 { 800 itext = itext_info[i]; 801 itext_info[i]->offset = offset; 802 break; 803 } 804 805 if (i == itext_size) 806 { 807 /* Find a blank slot (or create a new one), and remember the 808 pointer and offset. */ 809 for (i = 0; i < itext_size; i++) 810 if (itext_info[i] == NULL) 811 break; 812 813 /* If not found, then add some slots. */ 814 if (i == itext_size) 815 { 816 int j; 817 818 itext_info = xrealloc 819 (itext_info, (itext_size += 10) * sizeof (ITEXT *)); 820 821 for (j = i; j < itext_size; j++) 822 itext_info[j] = NULL; 823 } 824 825 /* Now add the pointer and the offset. */ 826 itext_info[i] = xmalloc (sizeof (ITEXT)); 827 itext_info[i]->pointer = pointer; 828 itext_info[i]->offset = offset; 829 itext = itext_info[i]; 830 } 831 return itext; 832} 833 834/* Forget the input text associated with POINTER. */ 835void 836forget_itext (pointer) 837 char *pointer; 838{ 839 int i; 840 841 for (i = 0; i < itext_size; i++) 842 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 843 { 844 free (itext_info[i]); 845 itext_info[i] = NULL; 846 break; 847 } 848} 849 850/* Append the text which appeared in input_text from the last offset to 851 the character just before the command that we are currently executing. */ 852void 853me_append_before_this_command () 854{ 855 int i; 856 857 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--) 858 ; 859 maybe_write_itext (input_text, i); 860} 861 862/* Similar to execute_string, but only takes a single string argument, 863 and remembers the input text location, etc. */ 864void 865me_execute_string (execution_string) 866 char *execution_string; 867{ 868 int saved_escape_html = escape_html; 869 int saved_in_paragraph = in_paragraph; 870 escape_html = me_executing_string == 0; 871 in_paragraph = 0; 872 873 pushfile (); 874 input_text_offset = 0; 875 /* The following xstrdup is so we can relocate input_text at will. */ 876 input_text = xstrdup (execution_string); 877 input_filename = xstrdup (input_filename); 878 input_text_length = strlen (execution_string); 879 880 remember_itext (input_text, 0); 881 882 me_executing_string++; 883 reader_loop (); 884 free (input_text); 885 free (input_filename); 886 popfile (); 887 me_executing_string--; 888 889 in_paragraph = saved_in_paragraph; 890 escape_html = saved_escape_html; 891} 892 893/* A wrapper around me_execute_string which saves and restores 894 variables important for output generation. This is called 895 when we need to produce macro-expanded output for input which 896 leaves no traces in the Info output. */ 897void 898me_execute_string_keep_state (execution_string, append_string) 899 char *execution_string, *append_string; 900{ 901 int op_orig, opcol_orig, popen_orig; 902 int fill_orig, newline_orig, indent_orig, meta_pos_orig; 903 904 remember_itext (input_text, input_text_offset); 905 op_orig = output_paragraph_offset; 906 meta_pos_orig = meta_char_pos; 907 opcol_orig = output_column; 908 popen_orig = paragraph_is_open; 909 fill_orig = filling_enabled; 910 newline_orig = last_char_was_newline; 911 filling_enabled = 0; 912 indent_orig = no_indent; 913 no_indent = 1; 914 me_execute_string (execution_string); 915 if (append_string) 916 write_region_to_macro_output (append_string, 0, strlen (append_string)); 917 output_paragraph_offset = op_orig; 918 meta_char_pos = meta_pos_orig; 919 output_column = opcol_orig; 920 paragraph_is_open = popen_orig; 921 filling_enabled = fill_orig; 922 last_char_was_newline = newline_orig; 923 no_indent = indent_orig; 924} 925 926/* Append the text which appears in input_text from the last offset to 927 the current OFFSET. */ 928void 929append_to_expansion_output (offset) 930 int offset; 931{ 932 int i; 933 ITEXT *itext = NULL; 934 935 for (i = 0; i < itext_size; i++) 936 if (itext_info[i] && itext_info[i]->pointer == input_text) 937 { 938 itext = itext_info[i]; 939 break; 940 } 941 942 if (!itext) 943 return; 944 945 if (offset > itext->offset) 946 { 947 write_region_to_macro_output (input_text, itext->offset, offset); 948 remember_itext (input_text, offset); 949 } 950} 951 952/* Only write this input text iff it appears in our itext list. */ 953void 954maybe_write_itext (pointer, offset) 955 char *pointer; 956 int offset; 957{ 958 int i; 959 ITEXT *itext = NULL; 960 961 for (i = 0; i < itext_size; i++) 962 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 963 { 964 itext = itext_info[i]; 965 break; 966 } 967 968 if (itext && (itext->offset < offset)) 969 { 970 write_region_to_macro_output (itext->pointer, itext->offset, offset); 971 remember_itext (pointer, offset); 972 } 973} 974 975void 976write_region_to_macro_output (string, start, end) 977 char *string; 978 int start, end; 979{ 980 if (macro_expansion_output_stream) 981 fwrite (string + start, 1, end - start, macro_expansion_output_stream); 982} 983 984/* Aliases. */ 985 986typedef struct alias_struct 987{ 988 char *alias; 989 char *mapto; 990 struct alias_struct *next; 991} alias_type; 992 993static alias_type *aliases; 994 995/* @alias */ 996void 997cm_alias () 998{ 999 alias_type *a = xmalloc (sizeof (alias_type)); 1000 1001 skip_whitespace (); 1002 get_until_in_line (1, "=", &(a->alias)); 1003 canon_white (a->alias); 1004 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. */ 1014char * 1015alias_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. */ 1037typedef struct enclose_struct 1038{ 1039 char *enclose; 1040 char *before; 1041 char *after; 1042 struct enclose_struct *next; 1043} enclosure_type; 1044 1045static enclosure_type *enclosures; 1046 1047typedef struct enclosure_stack_struct 1048{ 1049 enclosure_type *current; 1050 struct enclosure_stack_struct *next; 1051} enclosure_stack_type; 1052 1053static enclosure_stack_type *enclosure_stack; 1054 1055/* @definfoenclose */ 1056void 1057cm_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 1075int 1076enclosure_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 */ 1098void 1099enclosure_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