Back to index

tetex-bin  3.0
sectioning.c
Go to the documentation of this file.
00001 /* sectioning.c -- for @chapter, @section, ..., @contents ...
00002    $Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp $
00003 
00004    Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 
00020    Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */
00021 
00022 #include "system.h"
00023 #include "cmds.h"
00024 #include "macro.h"
00025 #include "makeinfo.h"
00026 #include "node.h"
00027 #include "toc.h"
00028 #include "sectioning.h"
00029 #include "xml.h"
00030 
00031 /* See comment in sectioning.h.  */
00032 section_alist_type section_alist[] = {
00033   { "unnumberedsubsubsec", 5, ENUM_SECT_NO,  TOC_YES },
00034   { "unnumberedsubsec",    4, ENUM_SECT_NO,  TOC_YES },
00035   { "unnumberedsec",       3, ENUM_SECT_NO,  TOC_YES },
00036   { "unnumbered",          2, ENUM_SECT_NO,  TOC_YES },
00037   { "centerchap",          2, ENUM_SECT_NO,  TOC_YES },
00038 
00039   { "appendixsubsubsec",   5, ENUM_SECT_APP, TOC_YES },  /* numbered like A.X.X.X */
00040   { "appendixsubsec",      4, ENUM_SECT_APP, TOC_YES },
00041   { "appendixsec",         3, ENUM_SECT_APP, TOC_YES },
00042   { "appendixsection",     3, ENUM_SECT_APP, TOC_YES },
00043   { "appendix",            2, ENUM_SECT_APP, TOC_YES },
00044 
00045   { "subsubsec",           5, ENUM_SECT_YES, TOC_YES },
00046   { "subsubsection",       5, ENUM_SECT_YES, TOC_YES },
00047   { "subsection",          4, ENUM_SECT_YES, TOC_YES },
00048   { "section",             3, ENUM_SECT_YES, TOC_YES },
00049   { "chapter",             2, ENUM_SECT_YES, TOC_YES },
00050 
00051   { "subsubheading",       5, ENUM_SECT_NO,  TOC_NO },
00052   { "subheading",          4, ENUM_SECT_NO,  TOC_NO },
00053   { "heading",             3, ENUM_SECT_NO,  TOC_NO },
00054   { "chapheading",         2, ENUM_SECT_NO,  TOC_NO },
00055   { "majorheading",        2, ENUM_SECT_NO,  TOC_NO },
00056 
00057   { "top",                 1, ENUM_SECT_NO,  TOC_YES },
00058   { NULL,                  0, 0, 0 }
00059 };
00060 
00061 /* The argument of @settitle, used for HTML. */
00062 char *title = NULL;
00063 
00064 
00065 #define APPENDIX_MAGIC   1024
00066 #define UNNUMBERED_MAGIC 2048
00067 
00068 /* Number memory for every level @chapter, @section,
00069    @subsection, @subsubsection. */
00070 static int numbers [] = { 0, 0, 0, 0 };
00071 
00072 /* enum_marker == APPENDIX_MAGIC then we are counting appendencies
00073    enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area.
00074    Handling situations like this:
00075    @unnumbered ..
00076    @section ...   */
00077 static int enum_marker = 0;
00078 
00079 /* Organized by level commands.  That is, "*" == chapter, "=" == section. */
00080 static char *scoring_characters = "*=-.";
00081 
00082 /* Amount to offset the name of sectioning commands to levels by. */
00083 static int section_alist_offset = 0;
00084 
00085 /* These two variables are for @float, @cindex like commands that need to know
00086    in which section they are used.  */
00087 /* Last value returned by get_sectioning_number.  */
00088 static char *last_sectioning_number = "";
00089 /* Last title used by sectioning_underscore, etc.  */
00090 static char *last_sectioning_title = "";
00091 
00092 /* num == ENUM_SECT_NO  means unnumbered (should never call this)
00093    num == ENUM_SECT_YES means numbered
00094    num == ENUM_SECT_APP means numbered like A.1 and so on */
00095 static char *
00096 get_sectioning_number (int level, int num)
00097 {
00098   static char s[100]; /* should ever be enough for 99.99.99.99
00099                          Appendix A.1 */
00100 
00101   char *p;
00102   int i;
00103 
00104   s[0] = 0;
00105 
00106   /* create enumeration in front of chapter, section, subsection and so on. */
00107   for (i = 0; i < level; i++)
00108     {
00109       p = s + strlen (s);
00110       if ((i == 0) && (enum_marker == APPENDIX_MAGIC))
00111         sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to
00112                                                 be more portable */
00113       else
00114         sprintf (p, "%d.", numbers[i]);
00115     }
00116 
00117   /* the last number is never followed by a dot */
00118   p = s + strlen (s);
00119   if ((num == ENUM_SECT_APP)
00120       && (i == 0)
00121       && (enum_marker == APPENDIX_MAGIC))
00122     sprintf (p, _("Appendix %c"), numbers[i] + 64);
00123   else
00124     sprintf (p, "%d", numbers[i]);
00125 
00126   /* Poor man's cache :-)  */
00127   if (strlen (last_sectioning_number))
00128     free (last_sectioning_number);
00129   last_sectioning_number = xstrdup (s);
00130 
00131   return s;
00132 }
00133 
00134 
00135 /* Set the level of @top to LEVEL.  Return the old level of @top. */
00136 int
00137 set_top_section_level (int level)
00138 {
00139   int i, result = -1;
00140 
00141   for (i = 0; section_alist[i].name; i++)
00142     if (strcmp (section_alist[i].name, "top") == 0)
00143       {
00144         result = section_alist[i].level;
00145         section_alist[i].level = level;
00146         break;
00147       }
00148   return result;
00149 }
00150 
00151 
00152 /* return the index of the given sectioning command in section_alist */
00153 static int
00154 search_sectioning (char *text)
00155 {
00156   int i;
00157   char *t;
00158 
00159   /* ignore the optional command prefix */
00160   if (text[0] == COMMAND_PREFIX)
00161     text++;
00162 
00163   for (i = 0; (t = section_alist[i].name); i++)
00164     {
00165       if (strcmp (t, text) == 0)
00166         {
00167           return i;
00168         }
00169     }
00170   return -1;
00171 }
00172 
00173 /* Return an integer which identifies the type of section present in
00174    TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as
00175    specified in section_alist).  We take into account any @lowersections
00176    and @raisesections.  If SECNAME is non-NULL, also return the
00177    corresponding section name.  */
00178 int
00179 what_section (char *text, char **secname)
00180 {
00181   int index, j;
00182   char *temp;
00183   int return_val;
00184 
00185  find_section_command:
00186   for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
00187   if (text[j] != COMMAND_PREFIX)
00188     return -1;
00189 
00190   text = text + j + 1;
00191 
00192   /* We skip @c, @comment, and @?index commands. */
00193   if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
00194       (text[0] == 'c' && cr_or_whitespace (text[1])) ||
00195       (strcmp (text + 1, "index") == 0))
00196     {
00197       while (*text++ != '\n');
00198       goto find_section_command;
00199     }
00200 
00201   /* Handle italicized sectioning commands. */
00202   if (*text == 'i')
00203     text++;
00204 
00205   for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
00206 
00207   temp = xmalloc (1 + j);
00208   strncpy (temp, text, j);
00209   temp[j] = 0;
00210 
00211   index = search_sectioning (temp);
00212   free (temp);
00213   if (index >= 0)
00214     {
00215       return_val = section_alist[index].level + section_alist_offset;
00216       if (return_val < 0)
00217         return_val = 0;
00218       else if (return_val > 5)
00219         return_val = 5;
00220 
00221       if (secname)
00222         {
00223           int i;
00224           int alist_size = sizeof (section_alist) / sizeof(section_alist_type);
00225           /* Find location of offset sectioning entry, but don't go off
00226              either end of the array.  */
00227           int index_offset = MAX (index - section_alist_offset, 0);
00228           index_offset = MIN (index_offset, alist_size - 1);
00229 
00230           /* Also make sure we don't go into the next "group" of
00231              sectioning changes, e.g., change from an @appendix to an
00232              @heading or some such.  */
00233 #define SIGN(expr) ((expr) < 0 ? -1 : 1)
00234           for (i = index; i != index_offset; i -= SIGN (section_alist_offset))
00235             {
00236               /* As it happens, each group has unique .num/.toc values.  */
00237               if (section_alist[i].num != section_alist[index_offset].num
00238                   || section_alist[i].toc != section_alist[index_offset].toc)
00239                 break;
00240             }
00241           *secname = section_alist[i].name;
00242         }
00243       return return_val;
00244     }
00245   return -1;
00246 }
00247 
00248 /* Returns current top level division (ie. chapter, unnumbered) number.
00249    - For chapters, returns the number.
00250    - For unnumbered sections, returns empty string.
00251    - For appendices, returns A, B, etc. */
00252 char *
00253 current_chapter_number (void)
00254 {
00255   if (enum_marker == UNNUMBERED_MAGIC)
00256     return xstrdup ("");
00257   else if (enum_marker == APPENDIX_MAGIC)
00258     {
00259       char s[1];
00260       sprintf (s, "%c", numbers[0] + 64);
00261       return xstrdup (s);
00262     }
00263   else
00264     {
00265       char s[5];
00266       sprintf (s, "%d", numbers[0]);
00267       return xstrdup (s);
00268     }
00269 }
00270 
00271 /* Returns number of the last sectioning command used.  */
00272 char *
00273 current_sectioning_number (void)
00274 {
00275   if (enum_marker == UNNUMBERED_MAGIC || !number_sections)
00276     return xstrdup ("");
00277   else
00278     return xstrdup (last_sectioning_number);
00279 }
00280 
00281 /* Returns arguments of the last sectioning command used.  */
00282 char *
00283 current_sectioning_name (void)
00284 {
00285   return xstrdup (last_sectioning_title);
00286 }
00287 
00288 /* insert_and_underscore, sectioning_underscore and sectioning_html call this.  */
00289 
00290 static char *
00291 handle_enum_increment (int level, int index)
00292 {
00293   /* Here is how TeX handles enumeration:
00294      - Anything starting with @unnumbered is not enumerated.
00295      - @majorheading and the like are not enumberated.  */
00296   int i;
00297 
00298   /* First constraint above.  */
00299   if (enum_marker == UNNUMBERED_MAGIC && level == 0)
00300     return xstrdup ("");
00301 
00302   /* Second constraint.  */
00303   if (section_alist[index].num == ENUM_SECT_NO)
00304     return xstrdup ("");
00305 
00306   /* reset all counters which are one level deeper */
00307   for (i = level; i < 3; i++)
00308     numbers [i + 1] = 0;
00309 
00310   numbers[level]++;
00311   if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC
00312       || !number_sections)
00313     return xstrdup ("");
00314   else
00315     return xstrdup (get_sectioning_number (level, section_alist[index].num));
00316 }
00317 
00318 
00319 void
00320 sectioning_underscore (char *cmd)
00321 {
00322   char *temp, *secname;
00323   int level;
00324   
00325   /* If we're not indenting the first paragraph, we shall make it behave
00326      like @noindent is called directly after the section heading. */
00327   if (! do_first_par_indent)
00328     cm_noindent ();
00329 
00330   temp = xmalloc (2 + strlen (cmd));
00331   temp[0] = COMMAND_PREFIX;
00332   strcpy (&temp[1], cmd);
00333   level = what_section (temp, &secname);
00334   level -= 2;
00335   if (level < 0)
00336     level = 0;
00337   free (temp);
00338 
00339   /* If the argument to @top is empty, we try using the one from @settitle.
00340      Warn if both are unusable.  */
00341   if (STREQ (command, "top"))
00342     {
00343       int save_input_text_offset = input_text_offset;
00344 
00345       get_rest_of_line (0, &temp);
00346 
00347       /* Due to get_rest_of_line ... */
00348       line_number--;
00349 
00350       if (strlen (temp) == 0 && (!title || strlen (title) == 0))
00351         warning ("Must specify a title with least one of @settitle or @top");
00352 
00353       input_text_offset = save_input_text_offset;
00354     }
00355 
00356   if (xml)
00357     {
00358       /* If the section appears in the toc, it means it's a real section
00359         unlike majorheading, chapheading etc. */
00360       if (section_alist[search_sectioning (cmd)].toc == TOC_YES)
00361        {
00362          xml_close_sections (level);
00363          /* Mark the beginning of the section
00364             If the next command is printindex, we will remove
00365             the section and put an Index instead */
00366          flush_output ();
00367          xml_last_section_output_position = output_paragraph_offset;
00368 
00369          get_rest_of_line (0, &temp);
00370 
00371           /* Use @settitle value if @top parameter is empty.  */
00372           if (STREQ (command, "top") && strlen(temp) == 0)
00373             temp = xstrdup (title ? title : "");
00374 
00375           /* Docbook does not support @unnumbered at all.  So we provide numbers
00376              that other formats use.  @appendix seems to be fine though, so we let
00377              Docbook handle that as usual.  */
00378           if (docbook && enum_marker != APPENDIX_MAGIC)
00379             {
00380               if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO
00381                   && section_alist[search_sectioning (cmd)].toc == TOC_YES)
00382                 xml_insert_element_with_attribute (xml_element (secname),
00383                     START, "label=\"%s\" xreflabel=\"%s\"",
00384                     handle_enum_increment (level, search_sectioning (cmd)),
00385                     text_expansion (temp));
00386               else
00387                 xml_insert_element_with_attribute (xml_element (secname),
00388                     START, "label=\"%s\"",
00389                     handle_enum_increment (level, search_sectioning (cmd)));
00390             }
00391           else
00392             xml_insert_element (xml_element (secname), START);
00393 
00394          xml_insert_element (TITLE, START);
00395          xml_open_section (level, secname);
00396          execute_string ("%s", temp);
00397          xml_insert_element (TITLE, END);
00398 
00399          free (temp);
00400        }
00401       else
00402         {
00403           if (docbook)
00404             {
00405               if (level > 0)
00406                 xml_insert_element_with_attribute (xml_element (secname), START,
00407                     "renderas=\"sect%d\"", level);
00408               else
00409                 xml_insert_element_with_attribute (xml_element (secname), START,
00410                     "renderas=\"other\"");
00411             }
00412           else
00413             xml_insert_element (xml_element (secname), START);
00414 
00415           get_rest_of_line (0, &temp);
00416           execute_string ("%s", temp);
00417           free (temp);
00418 
00419           xml_insert_element (xml_element (secname), END);
00420         }
00421     }
00422   else if (html)
00423     sectioning_html (level, secname);
00424   else
00425     insert_and_underscore (level, secname);
00426 }
00427 
00428 
00429 /* Insert the text following input_text_offset up to the end of the line
00430    in a new, separate paragraph.  Directly underneath it, insert a
00431    line of WITH_CHAR, the same length of the inserted text. */
00432 void
00433 insert_and_underscore (int level, char *cmd)
00434 {
00435   int i, len;
00436   int index;
00437   int old_no_indent;
00438   unsigned char *starting_pos, *ending_pos;
00439   char *temp;
00440   char with_char = scoring_characters[level];
00441 
00442   close_paragraph ();
00443   filling_enabled =  indented_fill = 0;
00444   old_no_indent = no_indent;
00445   no_indent = 1;
00446 
00447   if (macro_expansion_output_stream && !executing_string)
00448     append_to_expansion_output (input_text_offset + 1);
00449 
00450   get_rest_of_line (0, &temp);
00451 
00452   /* Use @settitle value if @top parameter is empty.  */
00453   if (STREQ (command, "top") && strlen(temp) == 0)
00454     temp = xstrdup (title ? title : "");
00455 
00456   starting_pos = output_paragraph + output_paragraph_offset;
00457 
00458   /* Poor man's cache for section title.  */
00459   if (strlen (last_sectioning_title))
00460     free (last_sectioning_title);
00461   last_sectioning_title = xstrdup (temp);
00462 
00463   index = search_sectioning (cmd);
00464   if (index < 0)
00465     {
00466       /* should never happen, but a poor guy, named Murphy ... */
00467       warning (_("Internal error (search_sectioning) `%s'!"), cmd);
00468       return;
00469     }
00470 
00471   /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the
00472      Info output and in TOC, but only SECTION-NAME in the macro-expanded
00473      output.  */
00474 
00475   /* Step 1: produce "X.Y" and add it to Info output.  */
00476   add_word_args ("%s ", handle_enum_increment (level, index));
00477 
00478   /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output.  */
00479   if (macro_expansion_output_stream && !executing_string)
00480     {
00481       char *temp1 = xmalloc (2 + strlen (temp));
00482       sprintf (temp1, "%s\n", temp);
00483       remember_itext (input_text, input_text_offset);
00484       me_execute_string (temp1);
00485       free (temp1);
00486     }
00487   else
00488     execute_string ("%s\n", temp);
00489 
00490   /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and
00491      insert it into the TOC.  */
00492   ending_pos = output_paragraph + output_paragraph_offset;
00493   if (section_alist[index].toc == TOC_YES)
00494     toc_add_entry (substring (starting_pos, ending_pos - 1),
00495                    level, current_node, NULL);
00496 
00497   free (temp);
00498 
00499   len = (ending_pos - starting_pos) - 1;
00500   for (i = 0; i < len; i++)
00501     add_char (with_char);
00502   insert ('\n');
00503   close_paragraph ();
00504   filling_enabled = 1;
00505   no_indent = old_no_indent;
00506 }
00507 
00508 /* Insert the text following input_text_offset up to the end of the
00509    line as an HTML heading element of the appropriate `level' and
00510    tagged as an anchor for the current node.. */
00511 
00512 void
00513 sectioning_html (int level, char *cmd)
00514 {
00515   static int toc_ref_count = 0;
00516   int index;
00517   int old_no_indent;
00518   unsigned char *starting_pos, *ending_pos;
00519   char *temp, *toc_anchor = NULL;
00520 
00521   close_paragraph ();
00522   filling_enabled =  indented_fill = 0;
00523   old_no_indent = no_indent;
00524   no_indent = 1;
00525 
00526   /* level 0 (chapter) is <h2>, and we go down from there.  */
00527   add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd);
00528 
00529   /* If we are outside of any node, produce an anchor that
00530      the TOC could refer to.  */
00531   if (!current_node || !*current_node)
00532     {
00533       static const char a_name[] = "<a name=\"";
00534 
00535       starting_pos = output_paragraph + output_paragraph_offset;
00536       add_word_args ("%sTOC%d\">", a_name, toc_ref_count++);
00537       toc_anchor = substring (starting_pos + sizeof (a_name) - 1,
00538                               output_paragraph + output_paragraph_offset);
00539       /* This must be added after toc_anchor is extracted, since
00540          toc_anchor cannot include the closing </a>.  For details,
00541          see toc.c:toc_add_entry and toc.c:contents_update_html.
00542 
00543          Also, the anchor close must be output before the section name
00544          in case the name itself contains an anchor. */
00545       add_word ("</a>");
00546     }
00547   starting_pos = output_paragraph + output_paragraph_offset;
00548 
00549   if (macro_expansion_output_stream && !executing_string)
00550     append_to_expansion_output (input_text_offset + 1);
00551 
00552   get_rest_of_line (0, &temp);
00553 
00554   /* Use @settitle value if @top parameter is empty.  */
00555   if (STREQ (command, "top") && strlen(temp) == 0)
00556     temp = xstrdup (title ? title : "");
00557 
00558   index = search_sectioning (cmd);
00559   if (index < 0)
00560     {
00561       /* should never happen, but a poor guy, named Murphy ... */
00562       warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
00563       return;
00564     }
00565 
00566   /* Produce "X.Y" and add it to HTML output.  */
00567   {
00568     char *title_number = handle_enum_increment (level, index);
00569     if (strlen (title_number) > 0)
00570       add_word_args ("%s ", title_number);
00571   }
00572 
00573   /* add the section name to both HTML and macro-expanded output.  */
00574   if (macro_expansion_output_stream && !executing_string)
00575     {
00576       remember_itext (input_text, input_text_offset);
00577       me_execute_string (temp);
00578       write_region_to_macro_output ("\n", 0, 1);
00579     }
00580   else
00581     execute_string ("%s", temp);
00582 
00583   ending_pos = output_paragraph + output_paragraph_offset;
00584 
00585   /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
00586      into the TOC.  */
00587   if (section_alist[index].toc == TOC_YES)
00588     toc_add_entry (substring (starting_pos, ending_pos),
00589                    level, current_node, toc_anchor);
00590 
00591   free (temp);
00592 
00593   if (outstanding_node)
00594     outstanding_node = 0;
00595 
00596   add_word_args ("</h%d>", level + 2);
00597   close_paragraph();
00598   filling_enabled = 1;
00599   no_indent = old_no_indent;
00600 }
00601 
00602 
00603 /* Shift the meaning of @section to @chapter. */
00604 void
00605 cm_raisesections (void)
00606 {
00607   discard_until ("\n");
00608   section_alist_offset--;
00609 }
00610 
00611 /* Shift the meaning of @chapter to @section. */
00612 void
00613 cm_lowersections (void)
00614 {
00615   discard_until ("\n");
00616   section_alist_offset++;
00617 }
00618 
00619 /* The command still works, but prints a warning message in addition. */
00620 void
00621 cm_ideprecated (int arg, int start, int end)
00622 {
00623   warning (_("%c%s is obsolete; use %c%s instead"),
00624            COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
00625   sectioning_underscore (command + 1);
00626 }
00627 
00628 
00629 /* Treat this just like @unnumbered.  The only difference is
00630    in node defaulting. */
00631 void
00632 cm_top (void)
00633 {
00634   /* It is an error to have more than one @top. */
00635   if (top_node_seen && strcmp (current_node, "Top") != 0)
00636     {
00637       TAG_ENTRY *tag = tag_table;
00638 
00639       line_error (_("Node with %ctop as a section already exists"),
00640                   COMMAND_PREFIX);
00641 
00642       while (tag)
00643         {
00644           if (tag->flags & TAG_FLAG_IS_TOP)
00645             {
00646               file_line_error (tag->filename, tag->line_no,
00647                                _("Here is the %ctop node"), COMMAND_PREFIX);
00648               return;
00649             }
00650           tag = tag->next_ent;
00651         }
00652     }
00653   else
00654     {
00655       top_node_seen = 1;
00656 
00657       /* It is an error to use @top before using @node. */
00658       if (!tag_table)
00659         {
00660           char *top_name;
00661 
00662           get_rest_of_line (0, &top_name);
00663           line_error (_("%ctop used before %cnode, defaulting to %s"),
00664                       COMMAND_PREFIX, COMMAND_PREFIX, top_name);
00665           execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
00666           free (top_name);
00667           return;
00668         }
00669 
00670       cm_unnumbered ();
00671 
00672       /* The most recently defined node is the top node. */
00673       tag_table->flags |= TAG_FLAG_IS_TOP;
00674 
00675       /* Now set the logical hierarchical level of the Top node. */
00676       {
00677         int orig_offset = input_text_offset;
00678 
00679         input_text_offset = search_forward (node_search_string, orig_offset);
00680 
00681         if (input_text_offset > 0)
00682           {
00683             int this_section;
00684 
00685             /* We have encountered a non-top node, so mark that one exists. */
00686             non_top_node_seen = 1;
00687 
00688             /* Move to the end of this line, and find out what the
00689                sectioning command is here. */
00690             while (input_text[input_text_offset] != '\n')
00691               input_text_offset++;
00692 
00693             if (input_text_offset < input_text_length)
00694               input_text_offset++;
00695 
00696             this_section = what_section (input_text + input_text_offset,
00697                                          NULL);
00698 
00699             /* If we found a sectioning command, then give the top section
00700                a level of this section - 1. */
00701             if (this_section != -1)
00702               set_top_section_level (this_section - 1);
00703           }
00704         input_text_offset = orig_offset;
00705       }
00706     }
00707 }
00708 
00709 /* The remainder of the text on this line is a chapter heading. */
00710 void
00711 cm_chapter (void)
00712 {
00713   enum_marker = 0;
00714   sectioning_underscore ("chapter");
00715 }
00716 
00717 /* The remainder of the text on this line is a section heading. */
00718 void
00719 cm_section (void)
00720 {
00721   sectioning_underscore ("section");
00722 }
00723 
00724 /* The remainder of the text on this line is a subsection heading. */
00725 void
00726 cm_subsection (void)
00727 {
00728   sectioning_underscore ("subsection");
00729 }
00730 
00731 /* The remainder of the text on this line is a subsubsection heading. */
00732 void
00733 cm_subsubsection (void)
00734 {
00735   sectioning_underscore ("subsubsection");
00736 }
00737 
00738 /* The remainder of the text on this line is an unnumbered heading. */
00739 void
00740 cm_unnumbered (void)
00741 {
00742   enum_marker = UNNUMBERED_MAGIC;
00743   sectioning_underscore ("unnumbered");
00744 }
00745 
00746 /* The remainder of the text on this line is an unnumbered section heading. */
00747 void
00748 cm_unnumberedsec (void)
00749 {
00750   sectioning_underscore ("unnumberedsec");
00751 }
00752 
00753 /* The remainder of the text on this line is an unnumbered
00754    subsection heading. */
00755 void
00756 cm_unnumberedsubsec (void)
00757 {
00758   sectioning_underscore ("unnumberedsubsec");
00759 }
00760 
00761 /* The remainder of the text on this line is an unnumbered
00762    subsubsection heading. */
00763 void
00764 cm_unnumberedsubsubsec (void)
00765 {
00766   sectioning_underscore ("unnumberedsubsubsec");
00767 }
00768 
00769 /* The remainder of the text on this line is an appendix heading. */
00770 void
00771 cm_appendix (void)
00772 {
00773   /* Reset top level number so we start from Appendix A */
00774   if (enum_marker != APPENDIX_MAGIC)
00775     numbers [0] = 0;
00776   enum_marker = APPENDIX_MAGIC;
00777   sectioning_underscore ("appendix");
00778 }
00779 
00780 /* The remainder of the text on this line is an appendix section heading. */
00781 void
00782 cm_appendixsec (void)
00783 {
00784   sectioning_underscore ("appendixsec");
00785 }
00786 
00787 /* The remainder of the text on this line is an appendix subsection heading. */
00788 void
00789 cm_appendixsubsec (void)
00790 {
00791   sectioning_underscore ("appendixsubsec");
00792 }
00793 
00794 /* The remainder of the text on this line is an appendix
00795    subsubsection heading. */
00796 void
00797 cm_appendixsubsubsec (void)
00798 {
00799   sectioning_underscore ("appendixsubsubsec");
00800 }
00801 
00802 /* Compatibility functions substitute for chapter, section, etc. */
00803 void
00804 cm_majorheading (void)
00805 {
00806   sectioning_underscore ("majorheading");
00807 }
00808 
00809 void
00810 cm_chapheading (void)
00811 {
00812   sectioning_underscore ("chapheading");
00813 }
00814 
00815 void
00816 cm_heading (void)
00817 {
00818   sectioning_underscore ("heading");
00819 }
00820 
00821 void
00822 cm_subheading (void)
00823 {
00824   sectioning_underscore ("subheading");
00825 }
00826 
00827 void
00828 cm_subsubheading (void)
00829 {
00830   sectioning_underscore ("subsubheading");
00831 }