macro.c revision 116525
1189251Ssam/* macro.c -- user-defined macros for Texinfo. 2189251Ssam $Id: macro.c,v 1.2 2003/06/01 23:41:23 karl Exp $ 3189251Ssam 4189251Ssam Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc. 5252726Srpaulo 6252726Srpaulo This program is free software; you can redistribute it and/or modify 7189251Ssam it under the terms of the GNU General Public License as published by 8189251Ssam the Free Software Foundation; either version 2, or (at your option) 9189251Ssam any later version. 10189251Ssam 11189251Ssam This program is distributed in the hope that it will be useful, 12189251Ssam but WITHOUT ANY WARRANTY; without even the implied warranty of 13214734Srpaulo MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14189251Ssam GNU General Public License for more details. 15189251Ssam 16189251Ssam You should have received a copy of the GNU General Public License 17189251Ssam along with this program; if not, write to the Free Software Foundation, 18189251Ssam Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19214734Srpaulo 20189251Ssam#include "system.h" 21189251Ssam#include "cmds.h" 22189251Ssam#include "macro.h" 23189251Ssam#include "makeinfo.h" 24189251Ssam#include "insertion.h" 25189251Ssam 26189251Ssam/* If non-NULL, this is an output stream to write the full macro expansion 27189251Ssam of the input text to. The result is another texinfo file, but 28189251Ssam 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, 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 if (len == 0) 340 { /* \\ always means \, even if macro has no args. */ 341 len++; 342 text = xmalloc (1 + len); 343 sprintf (text, "\\%s", param); 344 } 345 else 346 { 347 int which; 348 349 /* Check against named parameters. */ 350 for (which = 0; named && named[which]; which++) 351 if (STREQ (named[which], param)) 352 break; 353 354 if (named && named[which]) 355 { 356 text = which < length_of_actuals ? actuals[which] : NULL; 357 if (!text) 358 text = ""; 359 len = strlen (text); 360 text = xstrdup (text); /* so we can free it */ 361 } 362 else 363 { /* not a parameter, so it's an error. */ 364 warning (_("\\ in macro expansion followed by `%s' instead of parameter name"), 365 param); 366 len++; 367 text = xmalloc (1 + len); 368 sprintf (text, "\\%s", param); 369 } 370 } 371 372 if (strlen (param) + 2 < len) 373 { 374 new_body_size += len + 1; 375 new_body = xrealloc (new_body, new_body_size); 376 } 377 378 free (param); 379 380 strcpy (new_body + new_body_index, text); 381 new_body_index += len; 382 383 free (text); 384 } 385 } 386 387 new_body[new_body_index] = 0; 388 return new_body; 389} 390 391/* Expand macro passed in DEF, a pointer to a MACRO_DEF, and 392 return its expansion as a string. */ 393char * 394expand_macro (def) 395 MACRO_DEF *def; 396{ 397 char **arglist; 398 int num_args; 399 char *execution_string = NULL; 400 int start_line = line_number; 401 402 /* Find out how many arguments this macro definition takes. */ 403 num_args = array_len (def->arglist); 404 405 /* Gather the arguments present on the line if there are any. */ 406 arglist = get_macro_args (def); 407 408 if (num_args < array_len (arglist)) 409 { 410 free_array (arglist); 411 line_error (_("Macro `%s' called on line %d with too many args"), 412 def->name, start_line); 413 return execution_string; 414 } 415 416 if (def->body) 417 execution_string = apply (def->arglist, arglist, def->body); 418 419 free_array (arglist); 420 return execution_string; 421} 422 423/* Execute the macro passed in DEF, a pointer to a MACRO_DEF. */ 424void 425execute_macro (def) 426 MACRO_DEF *def; 427{ 428 char *execution_string; 429 int start_line = line_number, end_line; 430 431 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion) 432 me_append_before_this_command (); 433 434 execution_string = expand_macro (def); 435 if (!execution_string) 436 return; 437 438 if (def->body) 439 { 440 /* Reset the line number to where the macro arguments began. 441 This makes line numbers reported in error messages correct in 442 case the macro arguments span several lines and the expanded 443 arguments invoke other commands. */ 444 end_line = line_number; 445 line_number = start_line; 446 447 if (macro_expansion_output_stream && !executing_string && !me_inhibit_expansion) 448 { 449 remember_itext (input_text, input_text_offset); 450 me_execute_string (execution_string); 451 } 452 else 453 execute_string ("%s", execution_string); 454 455 free (execution_string); 456 line_number = end_line; 457 } 458} 459 460 461/* Read and remember the definition of a macro. If RECURSIVE is set, 462 set the ME_RECURSE flag. MACTYPE is either "macro" or "rmacro", and 463 tells us what the matching @end should be. */ 464static void 465define_macro (mactype, recursive) 466 char *mactype; 467 int recursive; 468{ 469 int i; 470 char *name, **arglist, *body, *line, *last_end; 471 int body_size, body_index; 472 int depth = 1; 473 int defining_line = line_number; 474 int flags = 0; 475 476 arglist = NULL; 477 body = NULL; 478 body_size = 0; 479 body_index = 0; 480 481 if (macro_expansion_output_stream && !executing_string) 482 me_append_before_this_command (); 483 484 skip_whitespace (); 485 486 /* Get the name of the macro. This is the set of characters which are 487 not whitespace and are not `{' immediately following the @macro. */ 488 { 489 int start = input_text_offset; 490 int len; 491 492 for (i = start; 493 (i < input_text_length) && 494 (input_text[i] != '{') && 495 (!cr_or_whitespace (input_text[i])); 496 i++); 497 498 len = i - start; 499 name = xmalloc (1 + len); 500 memcpy (name, input_text + start, len); 501 name[len] = 0; 502 input_text_offset = i; 503 } 504 505 skip_whitespace (); 506 507 /* It is not required that the definition of a macro includes an arglist. 508 If not, don't try to get the named parameters, just use a null list. */ 509 if (curchar () == '{') 510 { 511 int character; 512 int arglist_index = 0, arglist_size = 0; 513 int gathering_words = 1; 514 char *word = NULL; 515 516 /* Read the words inside of the braces which determine the arglist. 517 These words will be replaced within the body of the macro at 518 execution time. */ 519 520 input_text_offset++; 521 skip_whitespace_and_newlines (); 522 523 while (gathering_words) 524 { 525 int len; 526 527 for (i = input_text_offset; 528 (character = input_text[i]); 529 i++) 530 { 531 switch (character) 532 { 533 case '\n': 534 line_number++; 535 case ' ': 536 case '\t': 537 case ',': 538 case '}': 539 /* Found the end of the current arglist word. Save it. */ 540 len = i - input_text_offset; 541 word = xmalloc (1 + len); 542 memcpy (word, input_text + input_text_offset, len); 543 word[len] = 0; 544 input_text_offset = i; 545 546 /* Advance to the comma or close-brace that signified 547 the end of the argument. */ 548 while ((character = curchar ()) 549 && character != ',' 550 && character != '}') 551 { 552 input_text_offset++; 553 if (character == '\n') 554 line_number++; 555 } 556 557 /* Add the word to our list of words. */ 558 if (arglist_index + 2 >= arglist_size) 559 { 560 arglist_size += 10; 561 arglist = xrealloc (arglist, 562 arglist_size * sizeof (char *)); 563 } 564 565 arglist[arglist_index++] = word; 566 arglist[arglist_index] = NULL; 567 break; 568 } 569 570 if (character == '}') 571 { 572 input_text_offset++; 573 gathering_words = 0; 574 break; 575 } 576 577 if (character == ',') 578 { 579 input_text_offset++; 580 skip_whitespace_and_newlines (); 581 i = input_text_offset - 1; 582 } 583 } 584 } 585 586 /* If we have exactly one argument, do @quote-arg implicitly. Not 587 only does this match TeX's behavior (which can't feasibly be 588 changed), but it's a good idea. */ 589 if (arglist_index == 1) 590 flags |= ME_QUOTE_ARG; 591 } 592 593 /* Read the text carefully until we find an "@end macro" which 594 matches this one. The text in between is the body of the macro. */ 595 skip_whitespace_and_newlines (); 596 597 while (depth) 598 { 599 if ((input_text_offset + 9) > input_text_length) 600 { 601 file_line_error (input_filename, defining_line, 602 _("%cend macro not found"), COMMAND_PREFIX); 603 return; 604 } 605 606 get_rest_of_line (0, &line); 607 608 /* Handle commands only meaningful within a macro. */ 609 if ((*line == COMMAND_PREFIX) && (depth == 1) && 610 (strncmp (line + 1, "allow-recursion", 15) == 0) && 611 (line[16] == 0 || whitespace (line[16]))) 612 { 613 for (i = 16; whitespace (line[i]); i++); 614 strcpy (line, line + i); 615 flags |= ME_RECURSE; 616 if (!*line) 617 { 618 free (line); 619 continue; 620 } 621 } 622 623 if ((*line == COMMAND_PREFIX) && (depth == 1) && 624 (strncmp (line + 1, "quote-arg", 9) == 0) && 625 (line[10] == 0 || whitespace (line[10]))) 626 { 627 for (i = 10; whitespace (line[i]); i++); 628 strcpy (line, line + i); 629 630 if (arglist && arglist[0] && !arglist[1]) 631 { 632 flags |= ME_QUOTE_ARG; 633 if (!*line) 634 { 635 free (line); 636 continue; 637 } 638 } 639 else 640 line_error (_("@quote-arg only useful for single-argument macros")); 641 } 642 643 if (*line == COMMAND_PREFIX 644 && (strncmp (line + 1, "macro ", 6) == 0 645 || strncmp (line + 1, "rmacro ", 7) == 0)) 646 depth++; 647 648 /* Incorrect implementation of nesting -- just check that the last 649 @end matches what we started with. Since nested macros don't 650 work in TeX anyway, this isn't worth the trouble to get right. */ 651 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end macro", 9) == 0) 652 { 653 depth--; 654 last_end = "macro"; 655 } 656 if (*line == COMMAND_PREFIX && strncmp (line + 1, "end rmacro", 9) == 0) 657 { 658 depth--; 659 last_end = "rmacro"; 660 } 661 662 if (depth) 663 { 664 if ((body_index + strlen (line) + 3) >= body_size) 665 body = xrealloc (body, body_size += 3 + strlen (line)); 666 strcpy (body + body_index, line); 667 body_index += strlen (line); 668 body[body_index++] = '\n'; 669 body[body_index] = 0; 670 } 671 free (line); 672 } 673 674 /* Check that @end matched the macro command. */ 675 if (!STREQ (last_end, mactype)) 676 warning (_("mismatched @end %s with @%s"), last_end, mactype); 677 678 /* If it was an empty macro like 679 @macro foo 680 @end macro 681 create an empty body. (Otherwise, the macro is not expanded.) */ 682 if (!body) 683 { 684 body = (char *)malloc(1); 685 *body = 0; 686 } 687 688 /* We now have the name, the arglist, and the body. However, BODY 689 includes the final newline which preceded the `@end macro' text. 690 Delete it. */ 691 if (body && strlen (body)) 692 body[strlen (body) - 1] = 0; 693 694 if (recursive) 695 flags |= ME_RECURSE; 696 697 add_macro (name, arglist, body, input_filename, defining_line, flags); 698 699 if (macro_expansion_output_stream && !executing_string) 700 remember_itext (input_text, input_text_offset); 701} 702 703void 704cm_macro () 705{ 706 define_macro ("macro", 0); 707} 708 709void 710cm_rmacro () 711{ 712 define_macro ("rmacro", 1); 713} 714 715/* Delete the macro with name NAME. The macro is deleted from the list, 716 but it is also returned. If there was no macro defined, NULL is 717 returned. */ 718 719static MACRO_DEF * 720delete_macro (name) 721 char *name; 722{ 723 int i; 724 MACRO_DEF *def; 725 726 def = NULL; 727 728 for (i = 0; macro_list && (def = macro_list[i]); i++) 729 if (strcmp (def->name, name) == 0) 730 { 731 memmove (macro_list + i, macro_list + i + 1, 732 ((macro_list_len + 1) - i) * sizeof (MACRO_DEF *)); 733 macro_list_len--; 734 break; 735 } 736 return def; 737} 738 739void 740cm_unmacro () 741{ 742 int i; 743 char *line, *name; 744 MACRO_DEF *def; 745 746 if (macro_expansion_output_stream && !executing_string) 747 me_append_before_this_command (); 748 749 get_rest_of_line (0, &line); 750 751 for (i = 0; line[i] && !whitespace (line[i]); i++); 752 name = xmalloc (i + 1); 753 memcpy (name, line, i); 754 name[i] = 0; 755 756 def = delete_macro (name); 757 758 if (def) 759 { 760 free (def->source_file); 761 free (def->name); 762 free (def->body); 763 764 if (def->arglist) 765 { 766 int i; 767 768 for (i = 0; def->arglist[i]; i++) 769 free (def->arglist[i]); 770 771 free (def->arglist); 772 } 773 774 free (def); 775 } 776 777 free (line); 778 free (name); 779 780 if (macro_expansion_output_stream && !executing_string) 781 remember_itext (input_text, input_text_offset); 782} 783 784/* How to output sections of the input file verbatim. */ 785 786/* Set the value of POINTER's offset to OFFSET. */ 787ITEXT * 788remember_itext (pointer, offset) 789 char *pointer; 790 int offset; 791{ 792 int i; 793 ITEXT *itext = NULL; 794 795 /* If we have no info, initialize a blank list. */ 796 if (!itext_info) 797 { 798 itext_info = xmalloc ((itext_size = 10) * sizeof (ITEXT *)); 799 for (i = 0; i < itext_size; i++) 800 itext_info[i] = NULL; 801 } 802 803 /* If the pointer is already present in the list, then set the offset. */ 804 for (i = 0; i < itext_size; i++) 805 if ((itext_info[i]) && 806 (itext_info[i]->pointer == pointer)) 807 { 808 itext = itext_info[i]; 809 itext_info[i]->offset = offset; 810 break; 811 } 812 813 if (i == itext_size) 814 { 815 /* Find a blank slot (or create a new one), and remember the 816 pointer and offset. */ 817 for (i = 0; i < itext_size; i++) 818 if (itext_info[i] == NULL) 819 break; 820 821 /* If not found, then add some slots. */ 822 if (i == itext_size) 823 { 824 int j; 825 826 itext_info = xrealloc 827 (itext_info, (itext_size += 10) * sizeof (ITEXT *)); 828 829 for (j = i; j < itext_size; j++) 830 itext_info[j] = NULL; 831 } 832 833 /* Now add the pointer and the offset. */ 834 itext_info[i] = xmalloc (sizeof (ITEXT)); 835 itext_info[i]->pointer = pointer; 836 itext_info[i]->offset = offset; 837 itext = itext_info[i]; 838 } 839 return itext; 840} 841 842/* Forget the input text associated with POINTER. */ 843void 844forget_itext (pointer) 845 char *pointer; 846{ 847 int i; 848 849 for (i = 0; i < itext_size; i++) 850 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 851 { 852 free (itext_info[i]); 853 itext_info[i] = NULL; 854 break; 855 } 856} 857 858/* Append the text which appeared in input_text from the last offset to 859 the character just before the command that we are currently executing. */ 860void 861me_append_before_this_command () 862{ 863 int i; 864 865 for (i = input_text_offset; i && (input_text[i] != COMMAND_PREFIX); i--) 866 ; 867 maybe_write_itext (input_text, i); 868} 869 870/* Similar to execute_string, but only takes a single string argument, 871 and remembers the input text location, etc. */ 872void 873me_execute_string (execution_string) 874 char *execution_string; 875{ 876 int saved_escape_html = escape_html; 877 int saved_in_paragraph = in_paragraph; 878 escape_html = me_executing_string == 0; 879 in_paragraph = 0; 880 881 pushfile (); 882 input_text_offset = 0; 883 /* The following xstrdup is so we can relocate input_text at will. */ 884 input_text = xstrdup (execution_string); 885 input_filename = xstrdup (input_filename); 886 input_text_length = strlen (execution_string); 887 888 remember_itext (input_text, 0); 889 890 me_executing_string++; 891 reader_loop (); 892 free (input_text); 893 free (input_filename); 894 popfile (); 895 me_executing_string--; 896 897 in_paragraph = saved_in_paragraph; 898 escape_html = saved_escape_html; 899} 900 901/* A wrapper around me_execute_string which saves and restores 902 variables important for output generation. This is called 903 when we need to produce macro-expanded output for input which 904 leaves no traces in the Info output. */ 905void 906me_execute_string_keep_state (execution_string, append_string) 907 char *execution_string, *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. */ 936void 937append_to_expansion_output (offset) 938 int offset; 939{ 940 int i; 941 ITEXT *itext = NULL; 942 943 for (i = 0; i < itext_size; i++) 944 if (itext_info[i] && itext_info[i]->pointer == input_text) 945 { 946 itext = itext_info[i]; 947 break; 948 } 949 950 if (!itext) 951 return; 952 953 if (offset > itext->offset) 954 { 955 write_region_to_macro_output (input_text, itext->offset, offset); 956 remember_itext (input_text, offset); 957 } 958} 959 960/* Only write this input text iff it appears in our itext list. */ 961void 962maybe_write_itext (pointer, offset) 963 char *pointer; 964 int offset; 965{ 966 int i; 967 ITEXT *itext = NULL; 968 969 for (i = 0; i < itext_size; i++) 970 if (itext_info[i] && (itext_info[i]->pointer == pointer)) 971 { 972 itext = itext_info[i]; 973 break; 974 } 975 976 if (itext && (itext->offset < offset)) 977 { 978 write_region_to_macro_output (itext->pointer, itext->offset, offset); 979 remember_itext (pointer, offset); 980 } 981} 982 983void 984write_region_to_macro_output (string, start, end) 985 char *string; 986 int start, end; 987{ 988 if (macro_expansion_output_stream) 989 fwrite (string + start, 1, end - start, macro_expansion_output_stream); 990} 991 992/* Aliases. */ 993 994typedef struct alias_struct 995{ 996 char *alias; 997 char *mapto; 998 struct alias_struct *next; 999} alias_type; 1000 1001static alias_type *aliases; 1002 1003/* @alias */ 1004void 1005cm_alias () 1006{ 1007 alias_type *a = xmalloc (sizeof (alias_type)); 1008 1009 skip_whitespace (); 1010 get_until_in_line (1, "=", &(a->alias)); 1011 canon_white (a->alias); 1012 1013 discard_until ("="); 1014 skip_whitespace (); 1015 get_until_in_line (0, " ", &(a->mapto)); 1016 1017 a->next = aliases; 1018 aliases = a; 1019} 1020 1021/* Perform an alias expansion. Called from read_command. */ 1022char * 1023alias_expand (tok) 1024 char *tok; 1025{ 1026 alias_type *findit = aliases; 1027 1028 while (findit) 1029 if (strcmp (findit->alias, tok) == 0) 1030 { 1031 free (tok); 1032 return alias_expand (xstrdup (findit->mapto)); 1033 } 1034 else 1035 findit = findit->next; 1036 1037 return tok; 1038} 1039 1040/* definfoenclose implementation. */ 1041 1042/* This structure is used to track enclosure macros. When an enclosure 1043 macro is recognized, a pointer to the enclosure block corresponding 1044 to its name is saved in the brace element for its argument. */ 1045typedef struct enclose_struct 1046{ 1047 char *enclose; 1048 char *before; 1049 char *after; 1050 struct enclose_struct *next; 1051} enclosure_type; 1052 1053static enclosure_type *enclosures; 1054 1055typedef struct enclosure_stack_struct 1056{ 1057 enclosure_type *current; 1058 struct enclosure_stack_struct *next; 1059} enclosure_stack_type; 1060 1061static enclosure_stack_type *enclosure_stack; 1062 1063/* @definfoenclose */ 1064void 1065cm_definfoenclose () 1066{ 1067 enclosure_type *e = xmalloc (sizeof (enclosure_type)); 1068 1069 skip_whitespace (); 1070 get_until_in_line (1, ",", &(e->enclose)); 1071 discard_until (","); 1072 get_until_in_line (0, ",", &(e->before)); 1073 discard_until (","); 1074 get_until_in_line (0, "\n", &(e->after)); 1075 1076 e->next = enclosures; 1077 enclosures = e; 1078} 1079 1080/* If TOK is an enclosure command, push it on the enclosure stack and 1081 return 1. Else return 0. */ 1082 1083int 1084enclosure_command (tok) 1085 char *tok; 1086{ 1087 enclosure_type *findit = enclosures; 1088 1089 while (findit) 1090 if (strcmp (findit->enclose, tok) == 0) 1091 { 1092 enclosure_stack_type *new = xmalloc (sizeof (enclosure_stack_type)); 1093 new->current = findit; 1094 new->next = enclosure_stack; 1095 enclosure_stack = new; 1096 1097 return 1; 1098 } 1099 else 1100 findit = findit->next; 1101 1102 return 0; 1103} 1104 1105/* actually perform the enclosure expansion */ 1106void 1107enclosure_expand (arg, start, end) 1108 int arg, start, end; 1109{ 1110 if (arg == START) 1111 add_word (enclosure_stack->current->before); 1112 else 1113 { 1114 enclosure_stack_type *temp; 1115 1116 add_word (enclosure_stack->current->after); 1117 1118 temp = enclosure_stack; 1119 enclosure_stack = enclosure_stack->next; 1120 free (temp); 1121 } 1122} 1123