sectioning.c revision 221386
1/* sectioning.c -- for @chapter, @section, ..., @contents ... 2 $Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp $ 3 4 Copyright (C) 1999, 2001, 2002, 2003, 2004 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 18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 20 Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>. */ 21 22#include "system.h" 23#include "cmds.h" 24#include "macro.h" 25#include "makeinfo.h" 26#include "node.h" 27#include "toc.h" 28#include "sectioning.h" 29#include "xml.h" 30 31/* See comment in sectioning.h. */ 32section_alist_type section_alist[] = { 33 { "unnumberedsubsubsec", 5, ENUM_SECT_NO, TOC_YES }, 34 { "unnumberedsubsec", 4, ENUM_SECT_NO, TOC_YES }, 35 { "unnumberedsec", 3, ENUM_SECT_NO, TOC_YES }, 36 { "unnumbered", 2, ENUM_SECT_NO, TOC_YES }, 37 { "centerchap", 2, ENUM_SECT_NO, TOC_YES }, 38 39 { "appendixsubsubsec", 5, ENUM_SECT_APP, TOC_YES }, /* numbered like A.X.X.X */ 40 { "appendixsubsec", 4, ENUM_SECT_APP, TOC_YES }, 41 { "appendixsec", 3, ENUM_SECT_APP, TOC_YES }, 42 { "appendixsection", 3, ENUM_SECT_APP, TOC_YES }, 43 { "appendix", 2, ENUM_SECT_APP, TOC_YES }, 44 45 { "subsubsec", 5, ENUM_SECT_YES, TOC_YES }, 46 { "subsubsection", 5, ENUM_SECT_YES, TOC_YES }, 47 { "subsection", 4, ENUM_SECT_YES, TOC_YES }, 48 { "section", 3, ENUM_SECT_YES, TOC_YES }, 49 { "chapter", 2, ENUM_SECT_YES, TOC_YES }, 50 51 { "subsubheading", 5, ENUM_SECT_NO, TOC_NO }, 52 { "subheading", 4, ENUM_SECT_NO, TOC_NO }, 53 { "heading", 3, ENUM_SECT_NO, TOC_NO }, 54 { "chapheading", 2, ENUM_SECT_NO, TOC_NO }, 55 { "majorheading", 2, ENUM_SECT_NO, TOC_NO }, 56 57 { "top", 1, ENUM_SECT_NO, TOC_YES }, 58 { NULL, 0, 0, 0 } 59}; 60 61/* The argument of @settitle, used for HTML. */ 62char *title = NULL; 63 64 65#define APPENDIX_MAGIC 1024 66#define UNNUMBERED_MAGIC 2048 67 68/* Number memory for every level @chapter, @section, 69 @subsection, @subsubsection. */ 70static int numbers [] = { 0, 0, 0, 0 }; 71 72/* enum_marker == APPENDIX_MAGIC then we are counting appendencies 73 enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area. 74 Handling situations like this: 75 @unnumbered .. 76 @section ... */ 77static int enum_marker = 0; 78 79/* Organized by level commands. That is, "*" == chapter, "=" == section. */ 80static char *scoring_characters = "*=-."; 81 82/* Amount to offset the name of sectioning commands to levels by. */ 83static int section_alist_offset = 0; 84 85/* These two variables are for @float, @cindex like commands that need to know 86 in which section they are used. */ 87/* Last value returned by get_sectioning_number. */ 88static char *last_sectioning_number = ""; 89/* Last title used by sectioning_underscore, etc. */ 90static char *last_sectioning_title = ""; 91 92/* num == ENUM_SECT_NO means unnumbered (should never call this) 93 num == ENUM_SECT_YES means numbered 94 num == ENUM_SECT_APP means numbered like A.1 and so on */ 95static char * 96get_sectioning_number (int level, int num) 97{ 98 static char s[100]; /* should ever be enough for 99.99.99.99 99 Appendix A.1 */ 100 101 char *p; 102 int i; 103 104 s[0] = 0; 105 106 /* create enumeration in front of chapter, section, subsection and so on. */ 107 for (i = 0; i < level; i++) 108 { 109 p = s + strlen (s); 110 if ((i == 0) && (enum_marker == APPENDIX_MAGIC)) 111 sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to 112 be more portable */ 113 else 114 sprintf (p, "%d.", numbers[i]); 115 } 116 117 /* the last number is never followed by a dot */ 118 p = s + strlen (s); 119 if ((num == ENUM_SECT_APP) 120 && (i == 0) 121 && (enum_marker == APPENDIX_MAGIC)) 122 sprintf (p, _("Appendix %c"), numbers[i] + 64); 123 else 124 sprintf (p, "%d", numbers[i]); 125 126 /* Poor man's cache :-) */ 127 if (strlen (last_sectioning_number)) 128 free (last_sectioning_number); 129 last_sectioning_number = xstrdup (s); 130 131 return s; 132} 133 134 135/* Set the level of @top to LEVEL. Return the old level of @top. */ 136int 137set_top_section_level (int level) 138{ 139 int i, result = -1; 140 141 for (i = 0; section_alist[i].name; i++) 142 if (strcmp (section_alist[i].name, "top") == 0) 143 { 144 result = section_alist[i].level; 145 section_alist[i].level = level; 146 break; 147 } 148 return result; 149} 150 151 152/* return the index of the given sectioning command in section_alist */ 153static int 154search_sectioning (char *text) 155{ 156 int i; 157 char *t; 158 159 /* ignore the optional command prefix */ 160 if (text[0] == COMMAND_PREFIX) 161 text++; 162 163 for (i = 0; (t = section_alist[i].name); i++) 164 { 165 if (strcmp (t, text) == 0) 166 { 167 return i; 168 } 169 } 170 return -1; 171} 172 173/* Return an integer which identifies the type of section present in 174 TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as 175 specified in section_alist). We take into account any @lowersections 176 and @raisesections. If SECNAME is non-NULL, also return the 177 corresponding section name. */ 178int 179what_section (char *text, char **secname) 180{ 181 int index, j; 182 char *temp; 183 int return_val; 184 185 find_section_command: 186 for (j = 0; text[j] && cr_or_whitespace (text[j]); j++); 187 if (text[j] != COMMAND_PREFIX) 188 return -1; 189 190 text = text + j + 1; 191 192 /* We skip @c, @comment, and @?index commands. */ 193 if ((strncmp (text, "comment", strlen ("comment")) == 0) || 194 (text[0] == 'c' && cr_or_whitespace (text[1])) || 195 (strcmp (text + 1, "index") == 0)) 196 { 197 while (*text++ != '\n'); 198 goto find_section_command; 199 } 200 201 /* Handle italicized sectioning commands. */ 202 if (*text == 'i') 203 text++; 204 205 for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++); 206 207 temp = xmalloc (1 + j); 208 strncpy (temp, text, j); 209 temp[j] = 0; 210 211 index = search_sectioning (temp); 212 free (temp); 213 if (index >= 0) 214 { 215 return_val = section_alist[index].level + section_alist_offset; 216 if (return_val < 0) 217 return_val = 0; 218 else if (return_val > 5) 219 return_val = 5; 220 221 if (secname) 222 { 223 int i; 224 int alist_size = sizeof (section_alist) / sizeof(section_alist_type); 225 /* Find location of offset sectioning entry, but don't go off 226 either end of the array. */ 227 int index_offset = MAX (index - section_alist_offset, 0); 228 index_offset = MIN (index_offset, alist_size - 1); 229 230 /* Also make sure we don't go into the next "group" of 231 sectioning changes, e.g., change from an @appendix to an 232 @heading or some such. */ 233#define SIGN(expr) ((expr) < 0 ? -1 : 1) 234 for (i = index; i != index_offset; i -= SIGN (section_alist_offset)) 235 { 236 /* As it happens, each group has unique .num/.toc values. */ 237 if (section_alist[i].num != section_alist[index_offset].num 238 || section_alist[i].toc != section_alist[index_offset].toc) 239 break; 240 } 241 *secname = section_alist[i].name; 242 } 243 return return_val; 244 } 245 return -1; 246} 247 248/* Returns current top level division (ie. chapter, unnumbered) number. 249 - For chapters, returns the number. 250 - For unnumbered sections, returns empty string. 251 - For appendices, returns A, B, etc. */ 252char * 253current_chapter_number (void) 254{ 255 if (enum_marker == UNNUMBERED_MAGIC) 256 return xstrdup (""); 257 else if (enum_marker == APPENDIX_MAGIC) 258 { 259 char s[2]; 260 sprintf (s, "%c", numbers[0] + 64); 261 return xstrdup (s); 262 } 263 else 264 { 265 char s[11]; 266 sprintf (s, "%d", numbers[0]); 267 return xstrdup (s); 268 } 269} 270 271/* Returns number of the last sectioning command used. */ 272char * 273current_sectioning_number (void) 274{ 275 if (enum_marker == UNNUMBERED_MAGIC || !number_sections) 276 return xstrdup (""); 277 else 278 return xstrdup (last_sectioning_number); 279} 280 281/* Returns arguments of the last sectioning command used. */ 282char * 283current_sectioning_name (void) 284{ 285 return xstrdup (last_sectioning_title); 286} 287 288/* insert_and_underscore, sectioning_underscore and sectioning_html call this. */ 289 290static char * 291handle_enum_increment (int level, int index) 292{ 293 /* Here is how TeX handles enumeration: 294 - Anything starting with @unnumbered is not enumerated. 295 - @majorheading and the like are not enumberated. */ 296 int i; 297 298 /* First constraint above. */ 299 if (enum_marker == UNNUMBERED_MAGIC && level == 0) 300 return xstrdup (""); 301 302 /* Second constraint. */ 303 if (section_alist[index].num == ENUM_SECT_NO) 304 return xstrdup (""); 305 306 /* reset all counters which are one level deeper */ 307 for (i = level; i < 3; i++) 308 numbers [i + 1] = 0; 309 310 numbers[level]++; 311 if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC 312 || !number_sections) 313 return xstrdup (""); 314 else 315 return xstrdup (get_sectioning_number (level, section_alist[index].num)); 316} 317 318 319void 320sectioning_underscore (char *cmd) 321{ 322 char *temp, *secname; 323 int level; 324 325 /* If we're not indenting the first paragraph, we shall make it behave 326 like @noindent is called directly after the section heading. */ 327 if (! do_first_par_indent) 328 cm_noindent (); 329 330 temp = xmalloc (2 + strlen (cmd)); 331 temp[0] = COMMAND_PREFIX; 332 strcpy (&temp[1], cmd); 333 level = what_section (temp, &secname); 334 level -= 2; 335 if (level < 0) 336 level = 0; 337 free (temp); 338 339 /* If the argument to @top is empty, we try using the one from @settitle. 340 Warn if both are unusable. */ 341 if (STREQ (command, "top")) 342 { 343 int save_input_text_offset = input_text_offset; 344 345 get_rest_of_line (0, &temp); 346 347 /* Due to get_rest_of_line ... */ 348 line_number--; 349 350 if (strlen (temp) == 0 && (!title || strlen (title) == 0)) 351 warning ("Must specify a title with least one of @settitle or @top"); 352 353 input_text_offset = save_input_text_offset; 354 } 355 356 if (xml) 357 { 358 /* If the section appears in the toc, it means it's a real section 359 unlike majorheading, chapheading etc. */ 360 if (section_alist[search_sectioning (cmd)].toc == TOC_YES) 361 { 362 xml_close_sections (level); 363 /* Mark the beginning of the section 364 If the next command is printindex, we will remove 365 the section and put an Index instead */ 366 flush_output (); 367 xml_last_section_output_position = output_paragraph_offset; 368 369 get_rest_of_line (0, &temp); 370 371 /* Use @settitle value if @top parameter is empty. */ 372 if (STREQ (command, "top") && strlen(temp) == 0) 373 temp = xstrdup (title ? title : ""); 374 375 /* Docbook does not support @unnumbered at all. So we provide numbers 376 that other formats use. @appendix seems to be fine though, so we let 377 Docbook handle that as usual. */ 378 if (docbook && enum_marker != APPENDIX_MAGIC) 379 { 380 if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO 381 && section_alist[search_sectioning (cmd)].toc == TOC_YES) 382 xml_insert_element_with_attribute (xml_element (secname), 383 START, "label=\"%s\" xreflabel=\"%s\"", 384 handle_enum_increment (level, search_sectioning (cmd)), 385 text_expansion (temp)); 386 else 387 xml_insert_element_with_attribute (xml_element (secname), 388 START, "label=\"%s\"", 389 handle_enum_increment (level, search_sectioning (cmd))); 390 } 391 else 392 xml_insert_element (xml_element (secname), START); 393 394 xml_insert_element (TITLE, START); 395 xml_open_section (level, secname); 396 execute_string ("%s", temp); 397 xml_insert_element (TITLE, END); 398 399 free (temp); 400 } 401 else 402 { 403 if (docbook) 404 { 405 if (level > 0) 406 xml_insert_element_with_attribute (xml_element (secname), START, 407 "renderas=\"sect%d\"", level); 408 else 409 xml_insert_element_with_attribute (xml_element (secname), START, 410 "renderas=\"other\""); 411 } 412 else 413 xml_insert_element (xml_element (secname), START); 414 415 get_rest_of_line (0, &temp); 416 execute_string ("%s", temp); 417 free (temp); 418 419 xml_insert_element (xml_element (secname), END); 420 } 421 } 422 else if (html) 423 sectioning_html (level, secname); 424 else 425 insert_and_underscore (level, secname); 426} 427 428 429/* Insert the text following input_text_offset up to the end of the line 430 in a new, separate paragraph. Directly underneath it, insert a 431 line of WITH_CHAR, the same length of the inserted text. */ 432void 433insert_and_underscore (int level, char *cmd) 434{ 435 int i, len; 436 int index; 437 int old_no_indent; 438 unsigned char *starting_pos, *ending_pos; 439 char *temp; 440 char with_char = scoring_characters[level]; 441 442 close_paragraph (); 443 filling_enabled = indented_fill = 0; 444 old_no_indent = no_indent; 445 no_indent = 1; 446 447 if (macro_expansion_output_stream && !executing_string) 448 append_to_expansion_output (input_text_offset + 1); 449 450 get_rest_of_line (0, &temp); 451 452 /* Use @settitle value if @top parameter is empty. */ 453 if (STREQ (command, "top") && strlen(temp) == 0) 454 temp = xstrdup (title ? title : ""); 455 456 starting_pos = output_paragraph + output_paragraph_offset; 457 458 /* Poor man's cache for section title. */ 459 if (strlen (last_sectioning_title)) 460 free (last_sectioning_title); 461 last_sectioning_title = xstrdup (temp); 462 463 index = search_sectioning (cmd); 464 if (index < 0) 465 { 466 /* should never happen, but a poor guy, named Murphy ... */ 467 warning (_("Internal error (search_sectioning) `%s'!"), cmd); 468 return; 469 } 470 471 /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the 472 Info output and in TOC, but only SECTION-NAME in the macro-expanded 473 output. */ 474 475 /* Step 1: produce "X.Y" and add it to Info output. */ 476 add_word_args ("%s ", handle_enum_increment (level, index)); 477 478 /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output. */ 479 if (macro_expansion_output_stream && !executing_string) 480 { 481 char *temp1 = xmalloc (2 + strlen (temp)); 482 sprintf (temp1, "%s\n", temp); 483 remember_itext (input_text, input_text_offset); 484 me_execute_string (temp1); 485 free (temp1); 486 } 487 else 488 execute_string ("%s\n", temp); 489 490 /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and 491 insert it into the TOC. */ 492 ending_pos = output_paragraph + output_paragraph_offset; 493 if (section_alist[index].toc == TOC_YES) 494 toc_add_entry (substring (starting_pos, ending_pos - 1), 495 level, current_node, NULL); 496 497 free (temp); 498 499 len = (ending_pos - starting_pos) - 1; 500 for (i = 0; i < len; i++) 501 add_char (with_char); 502 insert ('\n'); 503 close_paragraph (); 504 filling_enabled = 1; 505 no_indent = old_no_indent; 506} 507 508/* Insert the text following input_text_offset up to the end of the 509 line as an HTML heading element of the appropriate `level' and 510 tagged as an anchor for the current node.. */ 511 512void 513sectioning_html (int level, char *cmd) 514{ 515 static int toc_ref_count = 0; 516 int index; 517 int old_no_indent; 518 unsigned char *starting_pos, *ending_pos; 519 char *temp, *toc_anchor = NULL; 520 521 close_paragraph (); 522 filling_enabled = indented_fill = 0; 523 old_no_indent = no_indent; 524 no_indent = 1; 525 526 /* level 0 (chapter) is <h2>, and we go down from there. */ 527 add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd); 528 529 /* If we are outside of any node, produce an anchor that 530 the TOC could refer to. */ 531 if (!current_node || !*current_node) 532 { 533 static const char a_name[] = "<a name=\""; 534 535 starting_pos = output_paragraph + output_paragraph_offset; 536 add_word_args ("%sTOC%d\">", a_name, toc_ref_count++); 537 toc_anchor = substring (starting_pos + sizeof (a_name) - 1, 538 output_paragraph + output_paragraph_offset); 539 /* This must be added after toc_anchor is extracted, since 540 toc_anchor cannot include the closing </a>. For details, 541 see toc.c:toc_add_entry and toc.c:contents_update_html. 542 543 Also, the anchor close must be output before the section name 544 in case the name itself contains an anchor. */ 545 add_word ("</a>"); 546 } 547 starting_pos = output_paragraph + output_paragraph_offset; 548 549 if (macro_expansion_output_stream && !executing_string) 550 append_to_expansion_output (input_text_offset + 1); 551 552 get_rest_of_line (0, &temp); 553 554 /* Use @settitle value if @top parameter is empty. */ 555 if (STREQ (command, "top") && strlen(temp) == 0) 556 temp = xstrdup (title ? title : ""); 557 558 index = search_sectioning (cmd); 559 if (index < 0) 560 { 561 /* should never happen, but a poor guy, named Murphy ... */ 562 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd); 563 return; 564 } 565 566 /* Produce "X.Y" and add it to HTML output. */ 567 { 568 char *title_number = handle_enum_increment (level, index); 569 if (strlen (title_number) > 0) 570 add_word_args ("%s ", title_number); 571 } 572 573 /* add the section name to both HTML and macro-expanded output. */ 574 if (macro_expansion_output_stream && !executing_string) 575 { 576 remember_itext (input_text, input_text_offset); 577 me_execute_string (temp); 578 write_region_to_macro_output ("\n", 0, 1); 579 } 580 else 581 execute_string ("%s", temp); 582 583 ending_pos = output_paragraph + output_paragraph_offset; 584 585 /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it 586 into the TOC. */ 587 if (section_alist[index].toc == TOC_YES) 588 toc_add_entry (substring (starting_pos, ending_pos), 589 level, current_node, toc_anchor); 590 591 free (temp); 592 593 if (outstanding_node) 594 outstanding_node = 0; 595 596 add_word_args ("</h%d>", level + 2); 597 close_paragraph(); 598 filling_enabled = 1; 599 no_indent = old_no_indent; 600} 601 602 603/* Shift the meaning of @section to @chapter. */ 604void 605cm_raisesections (void) 606{ 607 discard_until ("\n"); 608 section_alist_offset--; 609} 610 611/* Shift the meaning of @chapter to @section. */ 612void 613cm_lowersections (void) 614{ 615 discard_until ("\n"); 616 section_alist_offset++; 617} 618 619/* The command still works, but prints a warning message in addition. */ 620void 621cm_ideprecated (int arg, int start, int end) 622{ 623 warning (_("%c%s is obsolete; use %c%s instead"), 624 COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1); 625 sectioning_underscore (command + 1); 626} 627 628 629/* Treat this just like @unnumbered. The only difference is 630 in node defaulting. */ 631void 632cm_top (void) 633{ 634 /* It is an error to have more than one @top. */ 635 if (top_node_seen && strcmp (current_node, "Top") != 0) 636 { 637 TAG_ENTRY *tag = tag_table; 638 639 line_error (_("Node with %ctop as a section already exists"), 640 COMMAND_PREFIX); 641 642 while (tag) 643 { 644 if (tag->flags & TAG_FLAG_IS_TOP) 645 { 646 file_line_error (tag->filename, tag->line_no, 647 _("Here is the %ctop node"), COMMAND_PREFIX); 648 return; 649 } 650 tag = tag->next_ent; 651 } 652 } 653 else 654 { 655 top_node_seen = 1; 656 657 /* It is an error to use @top before using @node. */ 658 if (!tag_table) 659 { 660 char *top_name; 661 662 get_rest_of_line (0, &top_name); 663 line_error (_("%ctop used before %cnode, defaulting to %s"), 664 COMMAND_PREFIX, COMMAND_PREFIX, top_name); 665 execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name); 666 free (top_name); 667 return; 668 } 669 670 cm_unnumbered (); 671 672 /* The most recently defined node is the top node. */ 673 tag_table->flags |= TAG_FLAG_IS_TOP; 674 675 /* Now set the logical hierarchical level of the Top node. */ 676 { 677 int orig_offset = input_text_offset; 678 679 input_text_offset = search_forward (node_search_string, orig_offset); 680 681 if (input_text_offset > 0) 682 { 683 int this_section; 684 685 /* We have encountered a non-top node, so mark that one exists. */ 686 non_top_node_seen = 1; 687 688 /* Move to the end of this line, and find out what the 689 sectioning command is here. */ 690 while (input_text[input_text_offset] != '\n') 691 input_text_offset++; 692 693 if (input_text_offset < input_text_length) 694 input_text_offset++; 695 696 this_section = what_section (input_text + input_text_offset, 697 NULL); 698 699 /* If we found a sectioning command, then give the top section 700 a level of this section - 1. */ 701 if (this_section != -1) 702 set_top_section_level (this_section - 1); 703 } 704 input_text_offset = orig_offset; 705 } 706 } 707} 708 709/* The remainder of the text on this line is a chapter heading. */ 710void 711cm_chapter (void) 712{ 713 enum_marker = 0; 714 sectioning_underscore ("chapter"); 715} 716 717/* The remainder of the text on this line is a section heading. */ 718void 719cm_section (void) 720{ 721 sectioning_underscore ("section"); 722} 723 724/* The remainder of the text on this line is a subsection heading. */ 725void 726cm_subsection (void) 727{ 728 sectioning_underscore ("subsection"); 729} 730 731/* The remainder of the text on this line is a subsubsection heading. */ 732void 733cm_subsubsection (void) 734{ 735 sectioning_underscore ("subsubsection"); 736} 737 738/* The remainder of the text on this line is an unnumbered heading. */ 739void 740cm_unnumbered (void) 741{ 742 enum_marker = UNNUMBERED_MAGIC; 743 sectioning_underscore ("unnumbered"); 744} 745 746/* The remainder of the text on this line is an unnumbered section heading. */ 747void 748cm_unnumberedsec (void) 749{ 750 sectioning_underscore ("unnumberedsec"); 751} 752 753/* The remainder of the text on this line is an unnumbered 754 subsection heading. */ 755void 756cm_unnumberedsubsec (void) 757{ 758 sectioning_underscore ("unnumberedsubsec"); 759} 760 761/* The remainder of the text on this line is an unnumbered 762 subsubsection heading. */ 763void 764cm_unnumberedsubsubsec (void) 765{ 766 sectioning_underscore ("unnumberedsubsubsec"); 767} 768 769/* The remainder of the text on this line is an appendix heading. */ 770void 771cm_appendix (void) 772{ 773 /* Reset top level number so we start from Appendix A */ 774 if (enum_marker != APPENDIX_MAGIC) 775 numbers [0] = 0; 776 enum_marker = APPENDIX_MAGIC; 777 sectioning_underscore ("appendix"); 778} 779 780/* The remainder of the text on this line is an appendix section heading. */ 781void 782cm_appendixsec (void) 783{ 784 sectioning_underscore ("appendixsec"); 785} 786 787/* The remainder of the text on this line is an appendix subsection heading. */ 788void 789cm_appendixsubsec (void) 790{ 791 sectioning_underscore ("appendixsubsec"); 792} 793 794/* The remainder of the text on this line is an appendix 795 subsubsection heading. */ 796void 797cm_appendixsubsubsec (void) 798{ 799 sectioning_underscore ("appendixsubsubsec"); 800} 801 802/* Compatibility functions substitute for chapter, section, etc. */ 803void 804cm_majorheading (void) 805{ 806 sectioning_underscore ("majorheading"); 807} 808 809void 810cm_chapheading (void) 811{ 812 sectioning_underscore ("chapheading"); 813} 814 815void 816cm_heading (void) 817{ 818 sectioning_underscore ("heading"); 819} 820 821void 822cm_subheading (void) 823{ 824 sectioning_underscore ("subheading"); 825} 826 827void 828cm_subsubheading (void) 829{ 830 sectioning_underscore ("subsubheading"); 831} 832