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