sectioning.c revision 1.1.1.1 1 /* $NetBSD: sectioning.c,v 1.1.1.1 2016/01/14 00:11:29 christos 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[1];
264 sprintf (s, "%c", numbers[0] + 64);
265 return xstrdup (s);
266 }
267 else
268 {
269 char s[5];
270 sprintf (s, "%d", numbers[0]);
271 return xstrdup (s);
272 }
273 }
274
275 /* Returns number of the last sectioning command used. */
276 char *
277 current_sectioning_number (void)
278 {
279 if (enum_marker == UNNUMBERED_MAGIC || !number_sections)
280 return xstrdup ("");
281 else
282 return xstrdup (last_sectioning_number);
283 }
284
285 /* Returns arguments of the last sectioning command used. */
286 char *
287 current_sectioning_name (void)
288 {
289 return xstrdup (last_sectioning_title);
290 }
291
292 /* insert_and_underscore, sectioning_underscore and sectioning_html call this. */
293
294 static char *
295 handle_enum_increment (int level, int index)
296 {
297 /* Here is how TeX handles enumeration:
298 - Anything starting with @unnumbered is not enumerated.
299 - @majorheading and the like are not enumberated. */
300 int i;
301
302 /* First constraint above. */
303 if (enum_marker == UNNUMBERED_MAGIC && level == 0)
304 return xstrdup ("");
305
306 /* Second constraint. */
307 if (section_alist[index].num == ENUM_SECT_NO)
308 return xstrdup ("");
309
310 /* reset all counters which are one level deeper */
311 for (i = level; i < 3; i++)
312 numbers [i + 1] = 0;
313
314 numbers[level]++;
315 if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC
316 || !number_sections)
317 return xstrdup ("");
318 else
319 return xstrdup (get_sectioning_number (level, section_alist[index].num));
320 }
321
322
323 void
324 sectioning_underscore (char *cmd)
325 {
326 char *temp, *secname;
327 int level;
328
329 /* If we're not indenting the first paragraph, we shall make it behave
330 like @noindent is called directly after the section heading. */
331 if (! do_first_par_indent)
332 cm_noindent ();
333
334 temp = xmalloc (2 + strlen (cmd));
335 temp[0] = COMMAND_PREFIX;
336 strcpy (&temp[1], cmd);
337 level = what_section (temp, &secname);
338 level -= 2;
339 if (level < 0)
340 level = 0;
341 free (temp);
342
343 /* If the argument to @top is empty, we try using the one from @settitle.
344 Warn if both are unusable. */
345 if (STREQ (command, "top"))
346 {
347 int save_input_text_offset = input_text_offset;
348
349 get_rest_of_line (0, &temp);
350
351 /* Due to get_rest_of_line ... */
352 line_number--;
353
354 if (strlen (temp) == 0 && (!title || strlen (title) == 0))
355 warning ("Must specify a title with least one of @settitle or @top");
356
357 input_text_offset = save_input_text_offset;
358 }
359
360 if (xml)
361 {
362 /* If the section appears in the toc, it means it's a real section
363 unlike majorheading, chapheading etc. */
364 if (section_alist[search_sectioning (cmd)].toc == TOC_YES)
365 {
366 xml_close_sections (level);
367 /* Mark the beginning of the section
368 If the next command is printindex, we will remove
369 the section and put an Index instead */
370 flush_output ();
371 xml_last_section_output_position = output_paragraph_offset;
372
373 get_rest_of_line (0, &temp);
374
375 /* Use @settitle value if @top parameter is empty. */
376 if (STREQ (command, "top") && strlen(temp) == 0)
377 temp = xstrdup (title ? title : "");
378
379 /* Docbook does not support @unnumbered at all. So we provide numbers
380 that other formats use. @appendix seems to be fine though, so we let
381 Docbook handle that as usual. */
382 if (docbook && enum_marker != APPENDIX_MAGIC)
383 {
384 if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO
385 && section_alist[search_sectioning (cmd)].toc == TOC_YES)
386 xml_insert_element_with_attribute (xml_element (secname),
387 START, "label=\"%s\" xreflabel=\"%s\"",
388 handle_enum_increment (level, search_sectioning (cmd)),
389 text_expansion (temp));
390 else
391 xml_insert_element_with_attribute (xml_element (secname),
392 START, "label=\"%s\"",
393 handle_enum_increment (level, search_sectioning (cmd)));
394 }
395 else
396 xml_insert_element (xml_element (secname), START);
397
398 xml_insert_element (TITLE, START);
399 xml_open_section (level, secname);
400 execute_string ("%s", temp);
401 xml_insert_element (TITLE, END);
402
403 free (temp);
404 }
405 else
406 {
407 if (docbook)
408 {
409 if (level > 0)
410 xml_insert_element_with_attribute (xml_element (secname), START,
411 "renderas=\"sect%d\"", level);
412 else
413 xml_insert_element_with_attribute (xml_element (secname), START,
414 "renderas=\"other\"");
415 }
416 else
417 xml_insert_element (xml_element (secname), START);
418
419 get_rest_of_line (0, &temp);
420 execute_string ("%s", temp);
421 free (temp);
422
423 xml_insert_element (xml_element (secname), END);
424 }
425 }
426 else if (html)
427 sectioning_html (level, secname);
428 else
429 insert_and_underscore (level, secname);
430 }
431
432
433 /* Insert the text following input_text_offset up to the end of the line
434 in a new, separate paragraph. Directly underneath it, insert a
435 line of WITH_CHAR, the same length of the inserted text. */
436 void
437 insert_and_underscore (int level, char *cmd)
438 {
439 int i, len;
440 int index;
441 int old_no_indent;
442 unsigned char *starting_pos, *ending_pos;
443 char *temp;
444 char with_char = scoring_characters[level];
445
446 close_paragraph ();
447 filling_enabled = indented_fill = 0;
448 old_no_indent = no_indent;
449 no_indent = 1;
450
451 if (macro_expansion_output_stream && !executing_string)
452 append_to_expansion_output (input_text_offset + 1);
453
454 get_rest_of_line (0, &temp);
455
456 /* Use @settitle value if @top parameter is empty. */
457 if (STREQ (command, "top") && strlen(temp) == 0)
458 temp = xstrdup (title ? title : "");
459
460 starting_pos = output_paragraph + output_paragraph_offset;
461
462 /* Poor man's cache for section title. */
463 if (strlen (last_sectioning_title))
464 free (last_sectioning_title);
465 last_sectioning_title = xstrdup (temp);
466
467 index = search_sectioning (cmd);
468 if (index < 0)
469 {
470 /* should never happen, but a poor guy, named Murphy ... */
471 warning (_("Internal error (search_sectioning) `%s'!"), cmd);
472 return;
473 }
474
475 /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the
476 Info output and in TOC, but only SECTION-NAME in the macro-expanded
477 output. */
478
479 /* Step 1: produce "X.Y" and add it to Info output. */
480 add_word_args ("%s ", handle_enum_increment (level, index));
481
482 /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output. */
483 if (macro_expansion_output_stream && !executing_string)
484 {
485 char *temp1 = xmalloc (2 + strlen (temp));
486 sprintf (temp1, "%s\n", temp);
487 remember_itext (input_text, input_text_offset);
488 me_execute_string (temp1);
489 free (temp1);
490 }
491 else
492 execute_string ("%s\n", temp);
493
494 /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and
495 insert it into the TOC. */
496 ending_pos = output_paragraph + output_paragraph_offset;
497 if (section_alist[index].toc == TOC_YES)
498 toc_add_entry (substring (starting_pos, ending_pos - 1),
499 level, current_node, NULL);
500
501 free (temp);
502
503 len = (ending_pos - starting_pos) - 1;
504 for (i = 0; i < len; i++)
505 add_char (with_char);
506 insert ('\n');
507 close_paragraph ();
508 filling_enabled = 1;
509 no_indent = old_no_indent;
510 }
511
512 /* Insert the text following input_text_offset up to the end of the
513 line as an HTML heading element of the appropriate `level' and
514 tagged as an anchor for the current node.. */
515
516 void
517 sectioning_html (int level, char *cmd)
518 {
519 static int toc_ref_count = 0;
520 int index;
521 int old_no_indent;
522 unsigned char *starting_pos, *ending_pos;
523 char *temp, *toc_anchor = NULL;
524
525 close_paragraph ();
526 filling_enabled = indented_fill = 0;
527 old_no_indent = no_indent;
528 no_indent = 1;
529
530 /* level 0 (chapter) is <h2>, and we go down from there. */
531 add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd);
532
533 /* If we are outside of any node, produce an anchor that
534 the TOC could refer to. */
535 if (!current_node || !*current_node)
536 {
537 static const char a_name[] = "<a name=\"";
538
539 starting_pos = output_paragraph + output_paragraph_offset;
540 add_word_args ("%sTOC%d\">", a_name, toc_ref_count++);
541 toc_anchor = substring (starting_pos + sizeof (a_name) - 1,
542 output_paragraph + output_paragraph_offset);
543 /* This must be added after toc_anchor is extracted, since
544 toc_anchor cannot include the closing </a>. For details,
545 see toc.c:toc_add_entry and toc.c:contents_update_html.
546
547 Also, the anchor close must be output before the section name
548 in case the name itself contains an anchor. */
549 add_word ("</a>");
550 }
551 starting_pos = output_paragraph + output_paragraph_offset;
552
553 if (macro_expansion_output_stream && !executing_string)
554 append_to_expansion_output (input_text_offset + 1);
555
556 get_rest_of_line (0, &temp);
557
558 /* Use @settitle value if @top parameter is empty. */
559 if (STREQ (command, "top") && strlen(temp) == 0)
560 temp = xstrdup (title ? title : "");
561
562 index = search_sectioning (cmd);
563 if (index < 0)
564 {
565 /* should never happen, but a poor guy, named Murphy ... */
566 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
567 return;
568 }
569
570 /* Produce "X.Y" and add it to HTML output. */
571 {
572 char *title_number = handle_enum_increment (level, index);
573 if (strlen (title_number) > 0)
574 add_word_args ("%s ", title_number);
575 }
576
577 /* add the section name to both HTML and macro-expanded output. */
578 if (macro_expansion_output_stream && !executing_string)
579 {
580 remember_itext (input_text, input_text_offset);
581 me_execute_string (temp);
582 write_region_to_macro_output ("\n", 0, 1);
583 }
584 else
585 execute_string ("%s", temp);
586
587 ending_pos = output_paragraph + output_paragraph_offset;
588
589 /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
590 into the TOC. */
591 if (section_alist[index].toc == TOC_YES)
592 toc_add_entry (substring (starting_pos, ending_pos),
593 level, current_node, toc_anchor);
594
595 free (temp);
596
597 if (outstanding_node)
598 outstanding_node = 0;
599
600 add_word_args ("</h%d>", level + 2);
601 close_paragraph();
602 filling_enabled = 1;
603 no_indent = old_no_indent;
604 }
605
606
607 /* Shift the meaning of @section to @chapter. */
609 void
610 cm_raisesections (void)
611 {
612 discard_until ("\n");
613 section_alist_offset--;
614 }
615
616 /* Shift the meaning of @chapter to @section. */
617 void
618 cm_lowersections (void)
619 {
620 discard_until ("\n");
621 section_alist_offset++;
622 }
623
624 /* The command still works, but prints a warning message in addition. */
625 void
626 cm_ideprecated (int arg, int start, int end)
627 {
628 warning (_("%c%s is obsolete; use %c%s instead"),
629 COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
630 sectioning_underscore (command + 1);
631 }
632
633
634 /* Treat this just like @unnumbered. The only difference is
636 in node defaulting. */
637 void
638 cm_top (void)
639 {
640 /* It is an error to have more than one @top. */
641 if (top_node_seen && strcmp (current_node, "Top") != 0)
642 {
643 TAG_ENTRY *tag = tag_table;
644
645 line_error (_("Node with %ctop as a section already exists"),
646 COMMAND_PREFIX);
647
648 while (tag)
649 {
650 if (tag->flags & TAG_FLAG_IS_TOP)
651 {
652 file_line_error (tag->filename, tag->line_no,
653 _("Here is the %ctop node"), COMMAND_PREFIX);
654 return;
655 }
656 tag = tag->next_ent;
657 }
658 }
659 else
660 {
661 top_node_seen = 1;
662
663 /* It is an error to use @top before using @node. */
664 if (!tag_table)
665 {
666 char *top_name;
667
668 get_rest_of_line (0, &top_name);
669 line_error (_("%ctop used before %cnode, defaulting to %s"),
670 COMMAND_PREFIX, COMMAND_PREFIX, top_name);
671 execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
672 free (top_name);
673 return;
674 }
675
676 cm_unnumbered ();
677
678 /* The most recently defined node is the top node. */
679 tag_table->flags |= TAG_FLAG_IS_TOP;
680
681 /* Now set the logical hierarchical level of the Top node. */
682 {
683 int orig_offset = input_text_offset;
684
685 input_text_offset = search_forward (node_search_string, orig_offset);
686
687 if (input_text_offset > 0)
688 {
689 int this_section;
690
691 /* We have encountered a non-top node, so mark that one exists. */
692 non_top_node_seen = 1;
693
694 /* Move to the end of this line, and find out what the
695 sectioning command is here. */
696 while (input_text[input_text_offset] != '\n')
697 input_text_offset++;
698
699 if (input_text_offset < input_text_length)
700 input_text_offset++;
701
702 this_section = what_section (input_text + input_text_offset,
703 NULL);
704
705 /* If we found a sectioning command, then give the top section
706 a level of this section - 1. */
707 if (this_section != -1)
708 set_top_section_level (this_section - 1);
709 }
710 input_text_offset = orig_offset;
711 }
712 }
713 }
714
715 /* The remainder of the text on this line is a chapter heading. */
716 void
717 cm_chapter (void)
718 {
719 enum_marker = 0;
720 sectioning_underscore ("chapter");
721 }
722
723 /* The remainder of the text on this line is a section heading. */
724 void
725 cm_section (void)
726 {
727 sectioning_underscore ("section");
728 }
729
730 /* The remainder of the text on this line is a subsection heading. */
731 void
732 cm_subsection (void)
733 {
734 sectioning_underscore ("subsection");
735 }
736
737 /* The remainder of the text on this line is a subsubsection heading. */
738 void
739 cm_subsubsection (void)
740 {
741 sectioning_underscore ("subsubsection");
742 }
743
744 /* The remainder of the text on this line is an unnumbered heading. */
745 void
746 cm_unnumbered (void)
747 {
748 enum_marker = UNNUMBERED_MAGIC;
749 sectioning_underscore ("unnumbered");
750 }
751
752 /* The remainder of the text on this line is an unnumbered section heading. */
753 void
754 cm_unnumberedsec (void)
755 {
756 sectioning_underscore ("unnumberedsec");
757 }
758
759 /* The remainder of the text on this line is an unnumbered
760 subsection heading. */
761 void
762 cm_unnumberedsubsec (void)
763 {
764 sectioning_underscore ("unnumberedsubsec");
765 }
766
767 /* The remainder of the text on this line is an unnumbered
768 subsubsection heading. */
769 void
770 cm_unnumberedsubsubsec (void)
771 {
772 sectioning_underscore ("unnumberedsubsubsec");
773 }
774
775 /* The remainder of the text on this line is an appendix heading. */
776 void
777 cm_appendix (void)
778 {
779 /* Reset top level number so we start from Appendix A */
780 if (enum_marker != APPENDIX_MAGIC)
781 numbers [0] = 0;
782 enum_marker = APPENDIX_MAGIC;
783 sectioning_underscore ("appendix");
784 }
785
786 /* The remainder of the text on this line is an appendix section heading. */
787 void
788 cm_appendixsec (void)
789 {
790 sectioning_underscore ("appendixsec");
791 }
792
793 /* The remainder of the text on this line is an appendix subsection heading. */
794 void
795 cm_appendixsubsec (void)
796 {
797 sectioning_underscore ("appendixsubsec");
798 }
799
800 /* The remainder of the text on this line is an appendix
801 subsubsection heading. */
802 void
803 cm_appendixsubsubsec (void)
804 {
805 sectioning_underscore ("appendixsubsubsec");
806 }
807
808 /* Compatibility functions substitute for chapter, section, etc. */
809 void
810 cm_majorheading (void)
811 {
812 sectioning_underscore ("majorheading");
813 }
814
815 void
816 cm_chapheading (void)
817 {
818 sectioning_underscore ("chapheading");
819 }
820
821 void
822 cm_heading (void)
823 {
824 sectioning_underscore ("heading");
825 }
826
827 void
828 cm_subheading (void)
829 {
830 sectioning_underscore ("subheading");
831 }
832
833 void
834 cm_subsubheading (void)
835 {
836 sectioning_underscore ("subsubheading");
837 }
838