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