1 /* insertion.c -- insertions for Texinfo. 2 $Id: insertion.c,v 1.1.1.1 2000/02/09 01:25:19 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 "defun.h" 23 #include "insertion.h" 24 #include "macro.h" 25 #include "makeinfo.h" 26 27 /* Must match list in insertion.h. */ 28 static char *insertion_type_names[] = 29 { 30 "cartouche", "defcv", "deffn", "defivar", "defmac", "defmethod", 31 "defop", "defopt", "defspec", "deftp", "deftypefn", "deftypefun", 32 "deftypeivar", "deftypemethod", "deftypeop", "deftypevar", 33 "deftypevr", "defun", "defvar", "defvr", "detailmenu", "direntry", 34 "display", "enumerate", "example", "flushleft", "flushright", 35 "format", "ftable", "group", "ifclear", "ifhtml", "ifinfo", 36 "ifnothtml", "ifnotinfo", "ifnottex", "ifset", "iftex", "itemize", 37 "lisp", "menu", "multitable", "quotation", "rawhtml", "rawtex", 38 "smalldisplay", "smallexample", "smallformat", "smalllisp", "table", 39 "tex", "vtable", "bad_type" 40 }; 41 42 /* All nested environments. */ 43 INSERTION_ELT *insertion_stack = NULL; 44 45 /* How deeply we're nested. */ 46 int insertion_level = 0; 47 48 /* Whether to examine menu lines. */ 49 int in_menu = 0; 50 51 /* How to examine menu lines. */ 52 int in_detailmenu = 0; 53 54 /* Set to 1 if we've processed (commentary) text in a @menu that 55 wasn't part of a menu item. */ 56 int had_menu_commentary; 57 58 /* Set to 1 if <p> is written in normal context. 59 Used for menu and itemize. */ 60 int in_paragraph = 0; 61 62 static const char dl_tag[] = "<dl>\n"; 63 64 void 65 init_insertion_stack () 66 { 67 insertion_stack = NULL; 68 } 69 70 /* Return the type of the current insertion. */ 71 static enum insertion_type 72 current_insertion_type () 73 { 74 return insertion_level ? insertion_stack->insertion : bad_type; 75 } 76 77 /* Return the string which is the function to wrap around items, or NULL 78 if we're not in an environment where @item is ok. */ 79 static char * 80 current_item_function () 81 { 82 int done = 0; 83 INSERTION_ELT *elt = insertion_stack; 84 85 /* Skip down through the stack until we find an insertion with an 86 itemize function defined, i.e., skip conditionals, @cartouche, etc. */ 87 while (!done && elt) 88 { 89 switch (elt->insertion) 90 { 91 /* This list should match the one in cm_item. */ 92 case ifclear: 93 case ifhtml: 94 case ifinfo: 95 case ifnothtml: 96 case ifnotinfo: 97 case ifnottex: 98 case ifset: 99 case iftex: 100 case rawhtml: 101 case rawtex: 102 case tex: 103 case cartouche: 104 elt = elt->next; 105 break; 106 107 default: 108 done = 1; 109 } 110 } 111 112 /* item_function usually gets assigned the empty string. */ 113 return done && (*elt->item_function) ? elt->item_function : NULL; 114 } 115 116 /* Parse the item marker function off the input. If result is just "@", 117 change it to "@ ", since "@" by itself is not a command. This makes 118 "@ ", "@\t", and "@\n" all the same, but their default meanings are 119 the same anyway, and let's not worry about supporting redefining them. */ 120 char * 121 get_item_function () 122 { 123 char *item_function; 124 get_rest_of_line (0, &item_function); 125 126 /* If we hit the end of text in get_rest_of_line, backing up 127 input pointer will cause the last character of the last line 128 be pushed back onto the input, which is wrong. */ 129 if (input_text_offset < input_text_length) 130 backup_input_pointer (); 131 132 if (STREQ (item_function, "@")) 133 { 134 free (item_function); 135 item_function = xstrdup ("@ "); 136 } 137 138 return item_function; 139 } 140 141 /* Push the state of the current insertion on the stack. */ 142 void 143 push_insertion (type, item_function) 144 enum insertion_type type; 145 char *item_function; 146 { 147 INSERTION_ELT *new = xmalloc (sizeof (INSERTION_ELT)); 148 149 new->item_function = item_function; 150 new->filling_enabled = filling_enabled; 151 new->indented_fill = indented_fill; 152 new->insertion = type; 153 new->line_number = line_number; 154 new->filename = xstrdup (input_filename); 155 new->inhibited = inhibit_paragraph_indentation; 156 new->in_fixed_width_font = in_fixed_width_font; 157 new->next = insertion_stack; 158 insertion_stack = new; 159 insertion_level++; 160 } 161 162 /* Pop the value on top of the insertion stack into the 163 global variables. */ 164 void 165 pop_insertion () 166 { 167 INSERTION_ELT *temp = insertion_stack; 168 169 if (temp == NULL) 170 return; 171 172 in_fixed_width_font = temp->in_fixed_width_font; 173 inhibit_paragraph_indentation = temp->inhibited; 174 filling_enabled = temp->filling_enabled; 175 indented_fill = temp->indented_fill; 176 free_and_clear (&(temp->item_function)); 177 free_and_clear (&(temp->filename)); 178 insertion_stack = insertion_stack->next; 179 free (temp); 180 insertion_level--; 181 } 182 183 /* Return a pointer to the print name of this 184 enumerated type. */ 185 char * 186 insertion_type_pname (type) 187 enum insertion_type type; 188 { 189 if ((int) type < (int) bad_type) 190 return insertion_type_names[(int) type]; 191 else 192 return _("Broken-Type in insertion_type_pname"); 193 } 194 195 /* Return the insertion_type associated with NAME. 196 If the type is not one of the known ones, return BAD_TYPE. */ 197 enum insertion_type 198 find_type_from_name (name) 199 char *name; 200 { 201 int index = 0; 202 while (index < (int) bad_type) 203 { 204 if (STREQ (name, insertion_type_names[index])) 205 return (enum insertion_type) index; 206 if (index == rawhtml && STREQ (name, "html")) 207 return rawhtml; 208 if (index == rawtex && STREQ (name, "tex")) 209 return rawtex; 210 index++; 211 } 212 return bad_type; 213 } 214 215 int 216 defun_insertion (type) 217 enum insertion_type type; 218 { 219 return 0 220 || (type == defcv) 221 || (type == deffn) 222 || (type == defivar) 223 || (type == defmac) 224 || (type == defmethod) 225 || (type == defop) 226 || (type == defopt) 227 || (type == defspec) 228 || (type == deftp) 229 || (type == deftypefn) 230 || (type == deftypefun) 231 || (type == deftypeivar) 232 || (type == deftypemethod) 233 || (type == deftypeop) 234 || (type == deftypevar) 235 || (type == deftypevr) 236 || (type == defun) 237 || (type == defvar) 238 || (type == defvr) 239 ; 240 } 241 242 /* MAX_NS is the maximum nesting level for enumerations. I picked 100 243 which seemed reasonable. This doesn't control the number of items, 244 just the number of nested lists. */ 245 #define max_stack_depth 100 246 #define ENUM_DIGITS 1 247 #define ENUM_ALPHA 2 248 typedef struct { 249 int enumtype; 250 int enumval; 251 } DIGIT_ALPHA; 252 253 DIGIT_ALPHA enumstack[max_stack_depth]; 254 int enumstack_offset = 0; 255 int current_enumval = 1; 256 int current_enumtype = ENUM_DIGITS; 257 char *enumeration_arg = NULL; 258 259 void 260 start_enumerating (at, type) 261 int at, type; 262 { 263 if ((enumstack_offset + 1) == max_stack_depth) 264 { 265 line_error (_("Enumeration stack overflow")); 266 return; 267 } 268 enumstack[enumstack_offset].enumtype = current_enumtype; 269 enumstack[enumstack_offset].enumval = current_enumval; 270 enumstack_offset++; 271 current_enumval = at; 272 current_enumtype = type; 273 } 274 275 void 276 stop_enumerating () 277 { 278 --enumstack_offset; 279 if (enumstack_offset < 0) 280 enumstack_offset = 0; 281 282 current_enumval = enumstack[enumstack_offset].enumval; 283 current_enumtype = enumstack[enumstack_offset].enumtype; 284 } 285 286 /* Place a letter or digits into the output stream. */ 287 void 288 enumerate_item () 289 { 290 char temp[10]; 291 292 if (current_enumtype == ENUM_ALPHA) 293 { 294 if (current_enumval == ('z' + 1) || current_enumval == ('Z' + 1)) 295 { 296 current_enumval = ((current_enumval - 1) == 'z' ? 'a' : 'A'); 297 warning (_("lettering overflow, restarting at %c"), current_enumval); 298 } 299 sprintf (temp, "%c. ", current_enumval); 300 } 301 else 302 sprintf (temp, "%d. ", current_enumval); 303 304 indent (output_column += (current_indent - strlen (temp))); 305 add_word (temp); 306 current_enumval++; 307 } 308 309 static void 310 enum_html () 311 { 312 char type; 313 int start; 314 315 if (isdigit (*enumeration_arg)) 316 { 317 type = '1'; 318 start = atoi (enumeration_arg); 319 } 320 else if (isupper (*enumeration_arg)) 321 { 322 type = 'A'; 323 start = *enumeration_arg - 'A' + 1; 324 } 325 else 326 { 327 type = 'a'; 328 start = *enumeration_arg - 'a' + 1; 329 } 330 331 add_word_args ("<ol type=%c start=%d>\n", type, start); 332 } 333 334 /* Conditionally parse based on the current command name. */ 335 void 336 command_name_condition () 337 { 338 char *discarder = xmalloc (8 + strlen (command)); 339 340 sprintf (discarder, "\n%cend %s", COMMAND_PREFIX, command); 341 discard_until (discarder); 342 discard_until ("\n"); 343 344 free (discarder); 345 } 346 347 /* This is where the work for all the "insertion" style 348 commands is done. A huge switch statement handles the 349 various setups, and generic code is on both sides. */ 350 void 351 begin_insertion (type) 352 enum insertion_type type; 353 { 354 int no_discard = 0; 355 356 if (defun_insertion (type)) 357 { 358 push_insertion (type, xstrdup ("")); 359 no_discard++; 360 } 361 else 362 push_insertion (type, get_item_function ()); 363 364 switch (type) 365 { 366 case menu: 367 if (!no_headers) 368 close_paragraph (); 369 370 filling_enabled = no_indent = 0; 371 inhibit_paragraph_indentation = 1; 372 373 if (html) 374 { 375 had_menu_commentary = 1; 376 } 377 else if (!no_headers) 378 add_word ("* Menu:\n"); 379 380 in_menu++; 381 in_fixed_width_font++; 382 no_discard++; 383 break; 384 385 case detailmenu: 386 if (!in_menu) 387 { 388 if (!no_headers) 389 close_paragraph (); 390 391 filling_enabled = no_indent = 0; 392 inhibit_paragraph_indentation = 1; 393 394 no_discard++; 395 } 396 397 in_fixed_width_font++; 398 in_detailmenu++; 399 break; 400 401 case direntry: 402 if (html) 403 command_name_condition (); 404 else 405 { 406 close_single_paragraph (); 407 filling_enabled = no_indent = 0; 408 inhibit_paragraph_indentation = 1; 409 insert_string ("START-INFO-DIR-ENTRY\n"); 410 } 411 break; 412 413 case quotation: 414 /* @quotation does filling (@display doesn't). */ 415 if (html) 416 add_word ("<blockquote>\n"); 417 else 418 { 419 close_single_paragraph (); 420 last_char_was_newline = no_indent = 0; 421 indented_fill = filling_enabled = 1; 422 inhibit_paragraph_indentation = 1; 423 } 424 current_indent += default_indentation_increment; 425 break; 426 427 case display: 428 case smalldisplay: 429 case example: 430 case smallexample: 431 case lisp: 432 case smalllisp: 433 /* Like @display but without indentation. */ 434 case smallformat: 435 case format: 436 close_single_paragraph (); 437 inhibit_paragraph_indentation = 1; 438 in_fixed_width_font++; 439 filling_enabled = 0; 440 last_char_was_newline = 0; 441 442 if (html) 443 /* Kludge alert: if <pre> is followed by a newline, IE3 444 renders an extra blank line before the pre-formatted block. 445 Other browsers seem to not mind one way or the other. */ 446 add_word ("<pre>"); 447 448 if (type != format && type != smallformat) 449 current_indent += default_indentation_increment; 450 break; 451 452 case multitable: 453 do_multitable (); 454 break; 455 456 case table: 457 case ftable: 458 case vtable: 459 case itemize: 460 close_single_paragraph (); 461 current_indent += default_indentation_increment; 462 filling_enabled = indented_fill = 1; 463 #if defined (INDENT_PARAGRAPHS_IN_TABLE) 464 inhibit_paragraph_indentation = 0; 465 #else 466 inhibit_paragraph_indentation = 1; 467 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */ 468 469 /* Make things work for losers who forget the itemize syntax. */ 470 if (type == itemize) 471 { 472 if (!(*insertion_stack->item_function)) 473 { 474 free (insertion_stack->item_function); 475 insertion_stack->item_function = xstrdup ("@bullet"); 476 } 477 } 478 479 if (!*insertion_stack->item_function) 480 { 481 line_error (_("%s requires an argument: the formatter for %citem"), 482 insertion_type_pname (type), COMMAND_PREFIX); 483 } 484 485 if (html) 486 { 487 if (type == itemize) 488 { 489 add_word ("<ul>\n"); 490 in_paragraph = 0; 491 } 492 else 493 add_word (dl_tag); 494 } 495 break; 496 497 case enumerate: 498 close_single_paragraph (); 499 no_indent = 0; 500 #if defined (INDENT_PARAGRAPHS_IN_TABLE) 501 inhibit_paragraph_indentation = 0; 502 #else 503 inhibit_paragraph_indentation = 1; 504 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */ 505 506 current_indent += default_indentation_increment; 507 filling_enabled = indented_fill = 1; 508 509 if (html) 510 enum_html (); 511 512 if (isdigit (*enumeration_arg)) 513 start_enumerating (atoi (enumeration_arg), ENUM_DIGITS); 514 else 515 start_enumerating (*enumeration_arg, ENUM_ALPHA); 516 break; 517 518 /* @group does nothing special in makeinfo. */ 519 case group: 520 /* Only close the paragraph if we are not inside of an 521 @example-like environment. */ 522 if (!insertion_stack->next 523 || (insertion_stack->next->insertion != display 524 && insertion_stack->next->insertion != smalldisplay 525 && insertion_stack->next->insertion != example 526 && insertion_stack->next->insertion != smallexample 527 && insertion_stack->next->insertion != lisp 528 && insertion_stack->next->insertion != smalllisp 529 && insertion_stack->next->insertion != format 530 && insertion_stack->next->insertion != smallformat 531 && insertion_stack->next->insertion != flushleft 532 && insertion_stack->next->insertion != flushright)) 533 close_single_paragraph (); 534 break; 535 536 /* Insertions that are no-ops in info, but do something in TeX. */ 537 case cartouche: 538 case ifclear: 539 case ifhtml: 540 case ifinfo: 541 case ifnothtml: 542 case ifnotinfo: 543 case ifnottex: 544 case ifset: 545 case iftex: 546 case rawtex: 547 if (in_menu) 548 no_discard++; 549 break; 550 551 case rawhtml: 552 escape_html = 0; 553 break; 554 555 case defcv: 556 case deffn: 557 case defivar: 558 case defmac: 559 case defmethod: 560 case defop: 561 case defopt: 562 case defspec: 563 case deftp: 564 case deftypefn: 565 case deftypefun: 566 case deftypeivar: 567 case deftypemethod: 568 case deftypeop: 569 case deftypevar: 570 case deftypevr: 571 case defun: 572 case defvar: 573 case defvr: 574 inhibit_paragraph_indentation = 1; 575 filling_enabled = indented_fill = 1; 576 current_indent += default_indentation_increment; 577 no_indent = 0; 578 break; 579 580 case flushleft: 581 close_single_paragraph (); 582 inhibit_paragraph_indentation = 1; 583 filling_enabled = indented_fill = no_indent = 0; 584 break; 585 586 case flushright: 587 close_single_paragraph (); 588 filling_enabled = indented_fill = no_indent = 0; 589 inhibit_paragraph_indentation = 1; 590 force_flush_right++; 591 break; 592 593 default: 594 line_error ("begin_insertion internal error: type=%d", type); 595 596 } 597 598 if (!no_discard) 599 discard_until ("\n"); 600 } 601 602 /* Try to end the insertion with the specified TYPE. With a value of 603 `bad_type', TYPE gets translated to match the value currently on top 604 of the stack. Otherwise, if TYPE doesn't match the top of the 605 insertion stack, give error. */ 606 void 607 end_insertion (type) 608 enum insertion_type type; 609 { 610 enum insertion_type temp_type; 611 612 if (!insertion_level) 613 return; 614 615 temp_type = current_insertion_type (); 616 617 if (type == bad_type) 618 type = temp_type; 619 620 if (type != temp_type) 621 { 622 line_error 623 (_("`@end' expected `%s', but saw `%s'"), 624 insertion_type_pname (temp_type), insertion_type_pname (type)); 625 return; 626 } 627 628 pop_insertion (); 629 630 switch (type) 631 { 632 /* Insertions which have no effect on paragraph formatting. */ 633 case ifclear: 634 case ifhtml: 635 case ifinfo: 636 case ifnothtml: 637 case ifnotinfo: 638 case ifnottex: 639 case ifset: 640 case iftex: 641 case rawtex: 642 break; 643 644 case rawhtml: 645 escape_html = 1; 646 break; 647 648 case direntry: /* Eaten if html. */ 649 insert_string ("END-INFO-DIR-ENTRY\n\n"); 650 close_insertion_paragraph (); 651 break; 652 653 case detailmenu: 654 in_detailmenu--; /* No longer hacking menus. */ 655 if (!in_menu) 656 { 657 if (!no_headers) 658 close_insertion_paragraph (); 659 } 660 break; 661 662 case menu: 663 in_menu--; /* No longer hacking menus. */ 664 if (html) 665 add_word ("</ul>\n"); 666 else if (!no_headers) 667 close_insertion_paragraph (); 668 break; 669 670 case multitable: 671 end_multitable (); 672 break; 673 674 case enumerate: 675 stop_enumerating (); 676 close_insertion_paragraph (); 677 current_indent -= default_indentation_increment; 678 if (html) 679 add_word ("</ol>\n"); 680 break; 681 682 case flushleft: 683 case group: 684 case cartouche: 685 close_insertion_paragraph (); 686 break; 687 688 case format: 689 case smallformat: 690 case display: 691 case smalldisplay: 692 case example: 693 case smallexample: 694 case lisp: 695 case smalllisp: 696 case quotation: 697 /* @format and @smallformat are the only fixed_width insertion 698 without a change in indentation. */ 699 if (type != format && type != smallformat) 700 current_indent -= default_indentation_increment; 701 702 if (html) 703 add_word (type == quotation ? "</blockquote>\n" : "</pre>\n"); 704 705 /* The ending of one of these insertions always marks the 706 start of a new paragraph. */ 707 close_insertion_paragraph (); 708 break; 709 710 case table: 711 case ftable: 712 case vtable: 713 current_indent -= default_indentation_increment; 714 if (html) 715 add_word ("</dl>\n"); 716 break; 717 718 case itemize: 719 current_indent -= default_indentation_increment; 720 if (html) 721 add_word ("</ul>\n"); 722 close_insertion_paragraph (); 723 break; 724 725 case flushright: 726 force_flush_right--; 727 close_insertion_paragraph (); 728 break; 729 730 /* Handle the @defun insertions with this default clause. */ 731 default: 732 { 733 enum insertion_type base_type; 734 735 if (type < defcv || type > defvr) 736 line_error ("end_insertion internal error: type=%d", type); 737 738 base_type = get_base_type (type); 739 switch (base_type) 740 { 741 case deffn: 742 case defvr: 743 case deftp: 744 case deftypefn: 745 case deftypevr: 746 case defcv: 747 case defop: 748 case deftypemethod: 749 case deftypeop: 750 case deftypeivar: 751 if (html) 752 /* close the tables which has been opened in defun.c */ 753 add_word ("</TD></TR>\n</TABLE>\n"); 754 break; 755 } /* switch (base_type)... */ 756 757 current_indent -= default_indentation_increment; 758 close_insertion_paragraph (); 759 } 760 break; 761 762 } 763 764 if (current_indent < 0) 765 line_error ("end_insertion internal error: current indent=%d", 766 current_indent); 767 } 768 769 /* Insertions cannot cross certain boundaries, such as node beginnings. In 770 code that creates such boundaries, you should call `discard_insertions' 771 before doing anything else. It prints the errors for you, and cleans up 772 the insertion stack. 773 774 With nonzero SPECIALS_OK argument, allows unmatched 775 @if... conditionals, otherwise not. This is because conditionals can 776 cross node boundaries. Always happens with the @top node, for example. */ 777 void 778 discard_insertions (specials_ok) 779 int specials_ok; 780 { 781 int real_line_number = line_number; 782 while (insertion_stack) 783 { 784 if (specials_ok 785 && ((ifclear <= insertion_stack->insertion 786 && insertion_stack->insertion <= iftex) 787 || insertion_stack->insertion == rawhtml 788 || insertion_stack->insertion == rawtex)) 789 break; 790 else 791 { 792 char *offender = insertion_type_pname (insertion_stack->insertion); 793 char *current_filename = input_filename; 794 795 input_filename = insertion_stack->filename; 796 line_number = insertion_stack->line_number; 797 line_error (_("No matching `%cend %s'"), COMMAND_PREFIX, offender); 798 input_filename = current_filename; 799 pop_insertion (); 800 } 801 } 802 line_number = real_line_number; 803 } 804 805 /* Insertion (environment) commands. */ 806 807 void 808 cm_quotation () 809 { 810 begin_insertion (quotation); 811 } 812 813 void 814 cm_example () 815 { 816 begin_insertion (example); 817 } 818 819 void 820 cm_smallexample () 821 { 822 begin_insertion (smallexample); 823 } 824 825 void 826 cm_lisp () 827 { 828 begin_insertion (lisp); 829 } 830 831 void 832 cm_smalllisp () 833 { 834 begin_insertion (smalllisp); 835 } 836 837 /* @cartouche/@end cartouche draws box with rounded corners in 838 TeX output. Right now, just a no-op insertion. */ 839 void 840 cm_cartouche () 841 { 842 begin_insertion (cartouche); 843 } 844 845 void 846 cm_format () 847 { 848 begin_insertion (format); 849 } 850 851 void 852 cm_smallformat () 853 { 854 begin_insertion (smallformat); 855 } 856 857 void 858 cm_display () 859 { 860 begin_insertion (display); 861 } 862 863 void 864 cm_smalldisplay () 865 { 866 begin_insertion (smalldisplay); 867 } 868 869 void 870 cm_direntry () 871 { 872 if (no_headers || html) 873 command_name_condition (); 874 else 875 begin_insertion (direntry); 876 } 877 878 void 879 cm_itemize () 880 { 881 begin_insertion (itemize); 882 } 883 884 /* Start an enumeration insertion of type TYPE. If the user supplied 885 no argument on the line, then use DEFAULT_STRING as the initial string. */ 886 static void 887 do_enumeration (type, default_string) 888 int type; 889 char *default_string; 890 { 891 get_until_in_line (0, ".", &enumeration_arg); 892 canon_white (enumeration_arg); 893 894 if (!*enumeration_arg) 895 { 896 free (enumeration_arg); 897 enumeration_arg = xstrdup (default_string); 898 } 899 900 if (!isdigit (*enumeration_arg) && !isletter (*enumeration_arg)) 901 { 902 warning (_("%s requires letter or digit"), insertion_type_pname (type)); 903 904 switch (type) 905 { 906 case enumerate: 907 default_string = "1"; 908 break; 909 } 910 enumeration_arg = xstrdup (default_string); 911 } 912 begin_insertion (type); 913 } 914 915 void 916 cm_enumerate () 917 { 918 do_enumeration (enumerate, "1"); 919 } 920 921 void 922 cm_table () 923 { 924 begin_insertion (table); 925 } 926 927 void 928 cm_multitable () 929 { 930 begin_insertion (multitable); /* @@ */ 931 } 932 933 void 934 cm_ftable () 935 { 936 begin_insertion (ftable); 937 } 938 939 void 940 cm_vtable () 941 { 942 begin_insertion (vtable); 943 } 944 945 void 946 cm_group () 947 { 948 begin_insertion (group); 949 } 950 951 void 952 cm_ifinfo () 953 { 954 if (process_info) 955 begin_insertion (ifinfo); 956 else 957 command_name_condition (); 958 } 959 960 void 961 cm_ifnotinfo () 962 { 963 if (!process_info) 964 begin_insertion (ifnotinfo); 965 else 966 command_name_condition (); 967 } 968 969 970 /* Insert raw HTML (no escaping of `<' etc.). */ 971 void 972 cm_html () 973 { 974 if (process_html) 975 begin_insertion (rawhtml); 976 else 977 command_name_condition (); 978 } 979 980 void 981 cm_ifhtml () 982 { 983 if (process_html) 984 begin_insertion (ifhtml); 985 else 986 command_name_condition (); 987 } 988 989 void 990 cm_ifnothtml () 991 { 992 if (!process_html) 993 begin_insertion (ifnothtml); 994 else 995 command_name_condition (); 996 } 997 998 999 void 1000 cm_tex () 1001 { 1002 if (process_tex) 1003 begin_insertion (rawtex); 1004 else 1005 command_name_condition (); 1006 } 1007 1008 void 1009 cm_iftex () 1010 { 1011 if (process_tex) 1012 begin_insertion (iftex); 1013 else 1014 command_name_condition (); 1015 } 1016 1017 void 1018 cm_ifnottex () 1019 { 1020 if (!process_tex) 1021 begin_insertion (ifnottex); 1022 else 1023 command_name_condition (); 1024 } 1025 1026 /* Begin an insertion where the lines are not filled or indented. */ 1027 void 1028 cm_flushleft () 1029 { 1030 begin_insertion (flushleft); 1031 } 1032 1033 /* Begin an insertion where the lines are not filled, and each line is 1034 forced to the right-hand side of the page. */ 1035 void 1036 cm_flushright () 1037 { 1038 begin_insertion (flushright); 1039 } 1040 1041 void 1042 cm_menu () 1043 { 1044 if (current_node == NULL) 1045 { 1046 warning (_("@menu seen before first @node, creating `Top' node")); 1047 warning (_("perhaps your @top node should be wrapped in @ifnottex rather than @ifinfo?")); 1048 /* Include @top command so we can construct the implicit node tree. */ 1049 execute_string ("@node top\n@top Top\n"); 1050 } 1051 begin_insertion (menu); 1052 } 1053 1054 void 1055 cm_detailmenu () 1056 { 1057 if (current_node == NULL) 1058 { /* Problems anyway, @detailmenu should always be inside @menu. */ 1059 warning (_("@detailmenu seen before first node, creating `Top' node")); 1060 execute_string ("@node top\n@top Top\n"); 1061 } 1062 begin_insertion (detailmenu); 1063 } 1064 1065 /* End existing insertion block. */ 1066 void 1067 cm_end () 1068 { 1069 char *temp; 1070 enum insertion_type type; 1071 1072 if (!insertion_level) 1073 { 1074 line_error (_("Unmatched `%c%s'"), COMMAND_PREFIX, command); 1075 return; 1076 } 1077 1078 get_rest_of_line (0, &temp); 1079 1080 if (temp[0] == 0) 1081 line_error (_("`%c%s' needs something after it"), COMMAND_PREFIX, command); 1082 1083 type = find_type_from_name (temp); 1084 1085 if (type == bad_type) 1086 { 1087 line_error (_("Bad argument to `%s', `%s', using `%s'"), 1088 command, temp, insertion_type_pname (current_insertion_type ())); 1089 } 1090 end_insertion (type); 1091 free (temp); 1092 } 1093 1094 /* @itemx, @item. */ 1095 1096 static int itemx_flag = 0; 1097 1098 /* Return whether CMD takes a brace-delimited {arg}. */ 1099 static int 1100 command_needs_braces (cmd) 1101 char *cmd; 1102 { 1103 int i; 1104 for (i = 0; command_table[i].name; i++) 1105 { 1106 if (STREQ (command_table[i].name, cmd)) 1107 return command_table[i].argument_in_braces == BRACE_ARGS; 1108 } 1109 1110 return 0; /* macro or alias */ 1111 } 1112 1113 1114 void 1115 cm_item () 1116 { 1117 char *rest_of_line, *item_func; 1118 1119 /* Can only hack "@item" while inside of an insertion. */ 1120 if (insertion_level) 1121 { 1122 INSERTION_ELT *stack = insertion_stack; 1123 int original_input_text_offset; 1124 1125 skip_whitespace (); 1126 original_input_text_offset = input_text_offset; 1127 1128 get_rest_of_line (0, &rest_of_line); 1129 item_func = current_item_function (); 1130 1131 /* Do the right thing depending on which insertion function is active. */ 1132 switch_top: 1133 switch (stack->insertion) 1134 { 1135 case multitable: 1136 multitable_item (); 1137 /* Support text directly after the @item. */ 1138 if (*rest_of_line) 1139 { 1140 line_number--; 1141 input_text_offset = original_input_text_offset; 1142 } 1143 break; 1144 1145 case ifclear: 1146 case ifhtml: 1147 case ifinfo: 1148 case ifnothtml: 1149 case ifnotinfo: 1150 case ifnottex: 1151 case ifset: 1152 case iftex: 1153 case rawhtml: 1154 case rawtex: 1155 case tex: 1156 case cartouche: 1157 stack = stack->next; 1158 if (!stack) 1159 goto no_insertion; 1160 else 1161 goto switch_top; 1162 break; 1163 1164 case menu: 1165 case quotation: 1166 case example: 1167 case smallexample: 1168 case lisp: 1169 case smalllisp: 1170 case format: 1171 case smallformat: 1172 case display: 1173 case smalldisplay: 1174 case group: 1175 line_error (_("@%s not meaningful inside `@%s' block"), 1176 command, 1177 insertion_type_pname (current_insertion_type ())); 1178 break; 1179 1180 case itemize: 1181 case enumerate: 1182 if (itemx_flag) 1183 { 1184 line_error (_("@itemx not meaningful inside `%s' block"), 1185 insertion_type_pname (current_insertion_type ())); 1186 } 1187 else 1188 { 1189 if (html) 1190 { 1191 if (in_paragraph) 1192 { 1193 add_word ("</p>"); 1194 in_paragraph = 0; 1195 } 1196 add_word ("<li>"); 1197 } 1198 else 1199 { 1200 start_paragraph (); 1201 kill_self_indent (-1); 1202 filling_enabled = indented_fill = 1; 1203 1204 if (current_item_function ()) 1205 { 1206 output_column = current_indent - 2; 1207 indent (output_column); 1208 1209 /* The item marker can be given with or without 1210 braces -- @bullet and @bullet{} are both ok. 1211 Or it might be something that doesn't take 1212 braces at all, such as "o" or "#" or "@ ". 1213 Thus, only supply braces if the item marker is 1214 a command, they haven't supplied braces 1215 themselves, and we know it needs them. */ 1216 if (item_func && *item_func) 1217 { 1218 if (*item_func == COMMAND_PREFIX 1219 && item_func[strlen (item_func) - 1] != '}' 1220 && command_needs_braces (item_func + 1)) 1221 execute_string ("%s{}", item_func); 1222 else 1223 execute_string ("%s", item_func); 1224 } 1225 insert (' '); 1226 output_column++; 1227 } 1228 else 1229 enumerate_item (); 1230 1231 /* Special hack. This makes `close_paragraph' a no-op until 1232 `start_paragraph' has been called. */ 1233 must_start_paragraph = 1; 1234 } 1235 1236 /* Handle text directly after the @item. */ 1237 if (*rest_of_line) 1238 { 1239 line_number--; 1240 input_text_offset = original_input_text_offset; 1241 } 1242 } 1243 break; 1244 1245 case table: 1246 case ftable: 1247 case vtable: 1248 if (html) 1249 { 1250 static int last_html_output_position = 0; 1251 1252 /* If nothing has been output since the last <dd>, 1253 remove the empty <dd> element. Some browsers render 1254 an extra empty line for <dd><dt>, which makes @itemx 1255 conversion look ugly. */ 1256 if (last_html_output_position == output_position 1257 && strncmp ((char *) output_paragraph, "<dd>", 1258 output_paragraph_offset) == 0) 1259 output_paragraph_offset = 0; 1260 1261 /* Force the browser to render one blank line before 1262 each new @item in a table. But don't do that unless 1263 this is the first <dt> after the <dl>, or if we are 1264 converting @itemx. 1265 1266 Note that there are some browsers which ignore <br> 1267 in this context, but I cannot find any way to force 1268 them all render exactly one blank line. */ 1269 if (!itemx_flag 1270 && strncmp ((char *) output_paragraph 1271 + output_paragraph_offset - sizeof (dl_tag) + 1, 1272 dl_tag, sizeof (dl_tag) - 1) != 0) 1273 add_word ("<br>"); 1274 1275 add_word ("<dt>"); 1276 if (item_func && *item_func) 1277 execute_string ("%s{%s}", item_func, rest_of_line); 1278 else 1279 execute_string ("%s", rest_of_line); 1280 1281 if (current_insertion_type () == ftable) 1282 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line); 1283 1284 if (current_insertion_type () == vtable) 1285 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line); 1286 /* Make sure output_position is updated, so we could 1287 remember it. */ 1288 close_single_paragraph (); 1289 last_html_output_position = output_position; 1290 add_word ("<dd>"); 1291 } 1292 else 1293 { 1294 /* We need this to determine if we have two @item's in a row 1295 (see test just below). */ 1296 static int last_item_output_position = 0; 1297 1298 /* Get rid of extra characters. */ 1299 kill_self_indent (-1); 1300 1301 /* If we have one @item followed directly by another @item, 1302 we need to insert a blank line. This is not true for 1303 @itemx, though. */ 1304 if (!itemx_flag && last_item_output_position == output_position) 1305 insert ('\n'); 1306 1307 /* `close_paragraph' almost does what we want. The problem 1308 is when paragraph_is_open, and last_char_was_newline, and 1309 the last newline has been turned into a space, because 1310 filling_enabled. I handle it here. */ 1311 if (last_char_was_newline && filling_enabled && 1312 paragraph_is_open) 1313 insert ('\n'); 1314 close_paragraph (); 1315 1316 #if defined (INDENT_PARAGRAPHS_IN_TABLE) 1317 /* Indent on a new line, but back up one indentation level. */ 1318 { 1319 int save = inhibit_paragraph_indentation; 1320 inhibit_paragraph_indentation = 1; 1321 /* At this point, inserting any non-whitespace character will 1322 force the existing indentation to be output. */ 1323 add_char ('i'); 1324 inhibit_paragraph_indentation = save; 1325 } 1326 #else /* !INDENT_PARAGRAPHS_IN_TABLE */ 1327 add_char ('i'); 1328 #endif /* !INDENT_PARAGRAPHS_IN_TABLE */ 1329 1330 output_paragraph_offset--; 1331 kill_self_indent (default_indentation_increment + 1); 1332 1333 /* Add item's argument to the line. */ 1334 filling_enabled = 0; 1335 if (item_func && *item_func) 1336 execute_string ("%s{%s}", item_func, rest_of_line); 1337 else 1338 execute_string ("%s", rest_of_line); 1339 1340 if (current_insertion_type () == ftable) 1341 execute_string ("%cfindex %s\n", COMMAND_PREFIX, rest_of_line); 1342 else if (current_insertion_type () == vtable) 1343 execute_string ("%cvindex %s\n", COMMAND_PREFIX, rest_of_line); 1344 1345 /* Start a new line, and let start_paragraph () 1346 do the indenting of it for you. */ 1347 close_single_paragraph (); 1348 indented_fill = filling_enabled = 1; 1349 last_item_output_position = output_position; 1350 } 1351 } 1352 free (rest_of_line); 1353 } 1354 else 1355 { 1356 no_insertion: 1357 line_error (_("%c%s found outside of an insertion block"), 1358 COMMAND_PREFIX, command); 1359 } 1360 } 1361 1362 void 1363 cm_itemx () 1364 { 1365 itemx_flag++; 1366 cm_item (); 1367 itemx_flag--; 1368 } 1369