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