Home | History | Annotate | Line # | Download | only in makeinfo
sectioning.c revision 1.2.18.1
      1 /*	$NetBSD: sectioning.c,v 1.2.18.1 2026/01/22 19:02:27 martin 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