1126288Smtm/* sectioning.c -- for @chapter, @section, ..., @contents ...
298186Sgordon   $Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp $
378344Sobrien
498186Sgordon   Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
578344Sobrien
678344Sobrien   This program is free software; you can redistribute it and/or modify
778344Sobrien   it under the terms of the GNU General Public License as published by
878344Sobrien   the Free Software Foundation; either version 2, or (at your option)
978344Sobrien   any later version.
1078344Sobrien
1178344Sobrien   This program is distributed in the hope that it will be useful,
1278344Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1378344Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1478344Sobrien   GNU General Public License for more details.
1578344Sobrien
1678344Sobrien   You should have received a copy of the GNU General Public License
1778344Sobrien   along with this program; if not, write to the Free Software
1878344Sobrien   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1978344Sobrien
2078344Sobrien   Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */
2178344Sobrien
2278344Sobrien#include "system.h"
2378344Sobrien#include "cmds.h"
2478344Sobrien#include "macro.h"
2578344Sobrien#include "makeinfo.h"
2678344Sobrien#include "node.h"
2778344Sobrien#include "toc.h"
2878344Sobrien#include "sectioning.h"
2978344Sobrien#include "xml.h"
3078344Sobrien
3178344Sobrien/* See comment in sectioning.h.  */
3278344Sobriensection_alist_type section_alist[] = {
3378344Sobrien  { "unnumberedsubsubsec", 5, ENUM_SECT_NO,  TOC_YES },
3478344Sobrien  { "unnumberedsubsec",    4, ENUM_SECT_NO,  TOC_YES },
3578344Sobrien  { "unnumberedsec",       3, ENUM_SECT_NO,  TOC_YES },
3678344Sobrien  { "unnumbered",          2, ENUM_SECT_NO,  TOC_YES },
3778344Sobrien  { "centerchap",          2, ENUM_SECT_NO,  TOC_YES },
3878344Sobrien
3978344Sobrien  { "appendixsubsubsec",   5, ENUM_SECT_APP, TOC_YES },  /* numbered like A.X.X.X */
4078344Sobrien  { "appendixsubsec",      4, ENUM_SECT_APP, TOC_YES },
4178344Sobrien  { "appendixsec",         3, ENUM_SECT_APP, TOC_YES },
4278344Sobrien  { "appendixsection",     3, ENUM_SECT_APP, TOC_YES },
4398186Sgordon  { "appendix",            2, ENUM_SECT_APP, TOC_YES },
4498186Sgordon
4598186Sgordon  { "subsubsec",           5, ENUM_SECT_YES, TOC_YES },
46131550Scperciva  { "subsubsection",       5, ENUM_SECT_YES, TOC_YES },
47131550Scperciva  { "subsection",          4, ENUM_SECT_YES, TOC_YES },
48131550Scperciva  { "section",             3, ENUM_SECT_YES, TOC_YES },
49131550Scperciva  { "chapter",             2, ENUM_SECT_YES, TOC_YES },
5098186Sgordon
5198186Sgordon  { "subsubheading",       5, ENUM_SECT_NO,  TOC_NO },
5298186Sgordon  { "subheading",          4, ENUM_SECT_NO,  TOC_NO },
53103018Sgordon  { "heading",             3, ENUM_SECT_NO,  TOC_NO },
54124832Smtm  { "chapheading",         2, ENUM_SECT_NO,  TOC_NO },
55124832Smtm  { "majorheading",        2, ENUM_SECT_NO,  TOC_NO },
5698186Sgordon
57103018Sgordon  { "top",                 1, ENUM_SECT_NO,  TOC_YES },
5898186Sgordon  { NULL,                  0, 0, 0 }
5998186Sgordon};
6098186Sgordon
6198186Sgordon/* The argument of @settitle, used for HTML. */
6298186Sgordonchar *title = NULL;
6398186Sgordon
6498186Sgordon
6598186Sgordon#define APPENDIX_MAGIC   1024
6698186Sgordon#define UNNUMBERED_MAGIC 2048
6778344Sobrien
6878344Sobrien/* Number memory for every level @chapter, @section,
6978344Sobrien   @subsection, @subsubsection. */
7078344Sobrienstatic int numbers [] = { 0, 0, 0, 0 };
7198186Sgordon
7298186Sgordon/* enum_marker == APPENDIX_MAGIC then we are counting appendencies
7398186Sgordon   enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area.
7498186Sgordon   Handling situations like this:
7598186Sgordon   @unnumbered ..
7698186Sgordon   @section ...   */
7798186Sgordonstatic int enum_marker = 0;
7898186Sgordon
7998186Sgordon/* Organized by level commands.  That is, "*" == chapter, "=" == section. */
8098186Sgordonstatic char *scoring_characters = "*=-.";
8198186Sgordon
8298186Sgordon/* Amount to offset the name of sectioning commands to levels by. */
8398186Sgordonstatic int section_alist_offset = 0;
8498186Sgordon
8598186Sgordon/* These two variables are for @float, @cindex like commands that need to know
8698186Sgordon   in which section they are used.  */
8798186Sgordon/* Last value returned by get_sectioning_number.  */
88103018Sgordonstatic char *last_sectioning_number = "";
8998186Sgordon/* Last title used by sectioning_underscore, etc.  */
9098186Sgordonstatic char *last_sectioning_title = "";
9198186Sgordon
9298186Sgordon/* num == ENUM_SECT_NO  means unnumbered (should never call this)
9398186Sgordon   num == ENUM_SECT_YES means numbered
9498186Sgordon   num == ENUM_SECT_APP means numbered like A.1 and so on */
9598186Sgordonstatic char *
9698186Sgordonget_sectioning_number (int level, int num)
9798186Sgordon{
9898186Sgordon  static char s[100]; /* should ever be enough for 99.99.99.99
9998186Sgordon                         Appendix A.1 */
10098186Sgordon
10198186Sgordon  char *p;
10298186Sgordon  int i;
10398186Sgordon
10498186Sgordon  s[0] = 0;
10598186Sgordon
10698186Sgordon  /* create enumeration in front of chapter, section, subsection and so on. */
10798186Sgordon  for (i = 0; i < level; i++)
10898186Sgordon    {
10998186Sgordon      p = s + strlen (s);
11098186Sgordon      if ((i == 0) && (enum_marker == APPENDIX_MAGIC))
11198186Sgordon        sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to
11298186Sgordon                                                be more portable */
113146490Sschweikh      else
11498186Sgordon        sprintf (p, "%d.", numbers[i]);
11598186Sgordon    }
11698186Sgordon
11798186Sgordon  /* the last number is never followed by a dot */
11898186Sgordon  p = s + strlen (s);
11998186Sgordon  if ((num == ENUM_SECT_APP)
12098186Sgordon      && (i == 0)
12178344Sobrien      && (enum_marker == APPENDIX_MAGIC))
12278344Sobrien    sprintf (p, _("Appendix %c"), numbers[i] + 64);
12378344Sobrien  else
12478344Sobrien    sprintf (p, "%d", numbers[i]);
12578344Sobrien
12678344Sobrien  /* Poor man's cache :-)  */
12778344Sobrien  if (strlen (last_sectioning_number))
12898186Sgordon    free (last_sectioning_number);
12978344Sobrien  last_sectioning_number = xstrdup (s);
13078344Sobrien
13178344Sobrien  return s;
13278344Sobrien}
13378344Sobrien
13478344Sobrien
13578344Sobrien/* Set the level of @top to LEVEL.  Return the old level of @top. */
13678344Sobrienint
13778344Sobrienset_top_section_level (int level)
13878344Sobrien{
13978344Sobrien  int i, result = -1;
14078344Sobrien
141106643Sgordon  for (i = 0; section_alist[i].name; i++)
14278344Sobrien    if (strcmp (section_alist[i].name, "top") == 0)
14378344Sobrien      {
14478344Sobrien        result = section_alist[i].level;
14578344Sobrien        section_alist[i].level = level;
14678344Sobrien        break;
14798186Sgordon      }
14898186Sgordon  return result;
14978344Sobrien}
15098186Sgordon
15198186Sgordon
15298186Sgordon/* return the index of the given sectioning command in section_alist */
153126286Smtmstatic int
15498186Sgordonsearch_sectioning (char *text)
15598186Sgordon{
15698186Sgordon  int i;
15798186Sgordon  char *t;
15898186Sgordon
15978344Sobrien  /* ignore the optional command prefix */
16098186Sgordon  if (text[0] == COMMAND_PREFIX)
16198186Sgordon    text++;
16298186Sgordon
16398186Sgordon  for (i = 0; (t = section_alist[i].name); i++)
16498186Sgordon    {
16578344Sobrien      if (strcmp (t, text) == 0)
16678344Sobrien        {
16798186Sgordon          return i;
16878344Sobrien        }
16978344Sobrien    }
170126285Smtm  return -1;
17178344Sobrien}
17278344Sobrien
173126285Smtm/* Return an integer which identifies the type of section present in
17478344Sobrien   TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as
17578344Sobrien   specified in section_alist).  We take into account any @lowersections
176126285Smtm   and @raisesections.  If SECNAME is non-NULL, also return the
177126285Smtm   corresponding section name.  */
178126285Smtmint
17978344Sobrienwhat_section (char *text, char **secname)
18078344Sobrien{
18198186Sgordon  int index, j;
18278344Sobrien  char *temp;
18378344Sobrien  int return_val;
18478344Sobrien
18578344Sobrien find_section_command:
18698186Sgordon  for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
18798186Sgordon  if (text[j] != COMMAND_PREFIX)
18878344Sobrien    return -1;
18998186Sgordon
19098186Sgordon  text = text + j + 1;
19178344Sobrien
19278344Sobrien  /* We skip @c, @comment, and @?index commands. */
19378344Sobrien  if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
19478344Sobrien      (text[0] == 'c' && cr_or_whitespace (text[1])) ||
19578344Sobrien      (strcmp (text + 1, "index") == 0))
19698186Sgordon    {
19778344Sobrien      while (*text++ != '\n');
19898186Sgordon      goto find_section_command;
19978344Sobrien    }
20078344Sobrien
201131061Smtm  /* Handle italicized sectioning commands. */
20278344Sobrien  if (*text == 'i')
20378344Sobrien    text++;
20478344Sobrien
20578344Sobrien  for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
206139949Skeramida
20778344Sobrien  temp = xmalloc (1 + j);
20878344Sobrien  strncpy (temp, text, j);
20998186Sgordon  temp[j] = 0;
21078344Sobrien
21178344Sobrien  index = search_sectioning (temp);
21278344Sobrien  free (temp);
21398186Sgordon  if (index >= 0)
21478344Sobrien    {
21598186Sgordon      return_val = section_alist[index].level + section_alist_offset;
21698186Sgordon      if (return_val < 0)
21778344Sobrien        return_val = 0;
21878344Sobrien      else if (return_val > 5)
21978344Sobrien        return_val = 5;
22078344Sobrien
22198186Sgordon      if (secname)
22278344Sobrien        {
22398186Sgordon          int i;
22478344Sobrien          int alist_size = sizeof (section_alist) / sizeof(section_alist_type);
22598186Sgordon          /* Find location of offset sectioning entry, but don't go off
22698186Sgordon             either end of the array.  */
22798186Sgordon          int index_offset = MAX (index - section_alist_offset, 0);
22898186Sgordon          index_offset = MIN (index_offset, alist_size - 1);
22998186Sgordon
23098186Sgordon          /* Also make sure we don't go into the next "group" of
23198186Sgordon             sectioning changes, e.g., change from an @appendix to an
23298186Sgordon             @heading or some such.  */
23398186Sgordon#define SIGN(expr) ((expr) < 0 ? -1 : 1)
23498186Sgordon          for (i = index; i != index_offset; i -= SIGN (section_alist_offset))
23598186Sgordon            {
23698186Sgordon              /* As it happens, each group has unique .num/.toc values.  */
23798186Sgordon              if (section_alist[i].num != section_alist[index_offset].num
23898186Sgordon                  || section_alist[i].toc != section_alist[index_offset].toc)
23998186Sgordon                break;
24098186Sgordon            }
24198186Sgordon          *secname = section_alist[i].name;
24298186Sgordon        }
24398186Sgordon      return return_val;
24498186Sgordon    }
24598186Sgordon  return -1;
24698186Sgordon}
24798186Sgordon
24898186Sgordon/* Returns current top level division (ie. chapter, unnumbered) number.
24998186Sgordon   - For chapters, returns the number.
25098186Sgordon   - For unnumbered sections, returns empty string.
25198186Sgordon   - For appendices, returns A, B, etc. */
25298186Sgordonchar *
25398186Sgordoncurrent_chapter_number (void)
25478344Sobrien{
25598186Sgordon  if (enum_marker == UNNUMBERED_MAGIC)
25698186Sgordon    return xstrdup ("");
25798186Sgordon  else if (enum_marker == APPENDIX_MAGIC)
25898186Sgordon    {
25998186Sgordon      char s[2];
26098186Sgordon      sprintf (s, "%c", numbers[0] + 64);
26178344Sobrien      return xstrdup (s);
26298186Sgordon    }
26398186Sgordon  else
26498186Sgordon    {
26598186Sgordon      char s[11];
26698186Sgordon      sprintf (s, "%d", numbers[0]);
26798186Sgordon      return xstrdup (s);
26898186Sgordon    }
26998186Sgordon}
27098186Sgordon
27198186Sgordon/* Returns number of the last sectioning command used.  */
27298186Sgordonchar *
27398186Sgordoncurrent_sectioning_number (void)
274126556Smtm{
27598186Sgordon  if (enum_marker == UNNUMBERED_MAGIC || !number_sections)
27698186Sgordon    return xstrdup ("");
277146490Sschweikh  else
278146490Sschweikh    return xstrdup (last_sectioning_number);
279146490Sschweikh}
280146490Sschweikh
28198186Sgordon/* Returns arguments of the last sectioning command used.  */
28298186Sgordonchar *
28398186Sgordoncurrent_sectioning_name (void)
28498186Sgordon{
28598186Sgordon  return xstrdup (last_sectioning_title);
286114272Smtm}
28798186Sgordon
28898186Sgordon/* insert_and_underscore, sectioning_underscore and sectioning_html call this.  */
28998186Sgordon
29098186Sgordonstatic char *
29198186Sgordonhandle_enum_increment (int level, int index)
29298186Sgordon{
29398186Sgordon  /* Here is how TeX handles enumeration:
29498186Sgordon     - Anything starting with @unnumbered is not enumerated.
29598186Sgordon     - @majorheading and the like are not enumberated.  */
296126286Smtm  int i;
29798186Sgordon
29898186Sgordon  /* First constraint above.  */
29998186Sgordon  if (enum_marker == UNNUMBERED_MAGIC && level == 0)
30098186Sgordon    return xstrdup ("");
30198186Sgordon
30298186Sgordon  /* Second constraint.  */
30398186Sgordon  if (section_alist[index].num == ENUM_SECT_NO)
30498186Sgordon    return xstrdup ("");
30598186Sgordon
30698186Sgordon  /* reset all counters which are one level deeper */
30798186Sgordon  for (i = level; i < 3; i++)
30898186Sgordon    numbers [i + 1] = 0;
30998186Sgordon
31078344Sobrien  numbers[level]++;
31198186Sgordon  if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC
31298186Sgordon      || !number_sections)
31398186Sgordon    return xstrdup ("");
31498186Sgordon  else
31578344Sobrien    return xstrdup (get_sectioning_number (level, section_alist[index].num));
31698186Sgordon}
31798186Sgordon
31898186Sgordon
31978344Sobrienvoid
32078344Sobriensectioning_underscore (char *cmd)
32178344Sobrien{
32298186Sgordon  char *temp, *secname;
32398186Sgordon  int level;
32498186Sgordon
32598186Sgordon  /* If we're not indenting the first paragraph, we shall make it behave
32698186Sgordon     like @noindent is called directly after the section heading. */
32778344Sobrien  if (! do_first_par_indent)
32898186Sgordon    cm_noindent ();
32998186Sgordon
33078344Sobrien  temp = xmalloc (2 + strlen (cmd));
33198186Sgordon  temp[0] = COMMAND_PREFIX;
33298186Sgordon  strcpy (&temp[1], cmd);
333126303Smtm  level = what_section (temp, &secname);
33478344Sobrien  level -= 2;
33578344Sobrien  if (level < 0)
33678344Sobrien    level = 0;
33798186Sgordon  free (temp);
33898186Sgordon
33978344Sobrien  /* If the argument to @top is empty, we try using the one from @settitle.
34078344Sobrien     Warn if both are unusable.  */
34178344Sobrien  if (STREQ (command, "top"))
34298186Sgordon    {
34378344Sobrien      int save_input_text_offset = input_text_offset;
34478344Sobrien
34578344Sobrien      get_rest_of_line (0, &temp);
34678344Sobrien
34798186Sgordon      /* Due to get_rest_of_line ... */
34898186Sgordon      line_number--;
34998186Sgordon
35078344Sobrien      if (strlen (temp) == 0 && (!title || strlen (title) == 0))
35178344Sobrien        warning ("Must specify a title with least one of @settitle or @top");
35298186Sgordon
35398186Sgordon      input_text_offset = save_input_text_offset;
35498186Sgordon    }
35578344Sobrien
35698186Sgordon  if (xml)
35798186Sgordon    {
35878344Sobrien      /* If the section appears in the toc, it means it's a real section
35978344Sobrien	 unlike majorheading, chapheading etc. */
36078344Sobrien      if (section_alist[search_sectioning (cmd)].toc == TOC_YES)
36178344Sobrien	{
36298186Sgordon	  xml_close_sections (level);
36378344Sobrien	  /* Mark the beginning of the section
36478344Sobrien	     If the next command is printindex, we will remove
36578344Sobrien	     the section and put an Index instead */
36678344Sobrien	  flush_output ();
36778344Sobrien	  xml_last_section_output_position = output_paragraph_offset;
36878344Sobrien
36978344Sobrien	  get_rest_of_line (0, &temp);
37078344Sobrien
37178344Sobrien          /* Use @settitle value if @top parameter is empty.  */
37278344Sobrien          if (STREQ (command, "top") && strlen(temp) == 0)
37378344Sobrien            temp = xstrdup (title ? title : "");
37478344Sobrien
37598186Sgordon          /* Docbook does not support @unnumbered at all.  So we provide numbers
37678344Sobrien             that other formats use.  @appendix seems to be fine though, so we let
37778344Sobrien             Docbook handle that as usual.  */
37898186Sgordon          if (docbook && enum_marker != APPENDIX_MAGIC)
37978344Sobrien            {
38098186Sgordon              if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO
38198186Sgordon                  && section_alist[search_sectioning (cmd)].toc == TOC_YES)
38298186Sgordon                xml_insert_element_with_attribute (xml_element (secname),
38378344Sobrien                    START, "label=\"%s\" xreflabel=\"%s\"",
38498186Sgordon                    handle_enum_increment (level, search_sectioning (cmd)),
38578344Sobrien                    text_expansion (temp));
38678344Sobrien              else
38798186Sgordon                xml_insert_element_with_attribute (xml_element (secname),
38898186Sgordon                    START, "label=\"%s\"",
38998186Sgordon                    handle_enum_increment (level, search_sectioning (cmd)));
39098186Sgordon            }
39178344Sobrien          else
39298186Sgordon            xml_insert_element (xml_element (secname), START);
39378344Sobrien
39498186Sgordon	  xml_insert_element (TITLE, START);
39598186Sgordon	  xml_open_section (level, secname);
39698186Sgordon	  execute_string ("%s", temp);
39798186Sgordon	  xml_insert_element (TITLE, END);
39878344Sobrien
39978344Sobrien	  free (temp);
40078344Sobrien	}
40178344Sobrien      else
40278344Sobrien        {
40378344Sobrien          if (docbook)
40478344Sobrien            {
40578344Sobrien              if (level > 0)
40678344Sobrien                xml_insert_element_with_attribute (xml_element (secname), START,
40778344Sobrien                    "renderas=\"sect%d\"", level);
40878344Sobrien              else
40978344Sobrien                xml_insert_element_with_attribute (xml_element (secname), START,
41098186Sgordon                    "renderas=\"other\"");
41198186Sgordon            }
41278344Sobrien          else
41398186Sgordon            xml_insert_element (xml_element (secname), START);
41498186Sgordon
41578344Sobrien          get_rest_of_line (0, &temp);
41678344Sobrien          execute_string ("%s", temp);
41778344Sobrien          free (temp);
41878344Sobrien
41998186Sgordon          xml_insert_element (xml_element (secname), END);
42078344Sobrien        }
42198186Sgordon    }
42298186Sgordon  else if (html)
42398186Sgordon    sectioning_html (level, secname);
42498186Sgordon  else
42578344Sobrien    insert_and_underscore (level, secname);
42698186Sgordon}
42798186Sgordon
42878344Sobrien
42978344Sobrien/* Insert the text following input_text_offset up to the end of the line
43078344Sobrien   in a new, separate paragraph.  Directly underneath it, insert a
43178344Sobrien   line of WITH_CHAR, the same length of the inserted text. */
43298186Sgordonvoid
43378344Sobrieninsert_and_underscore (int level, char *cmd)
43498186Sgordon{
43598186Sgordon  int i, len;
43698186Sgordon  int index;
43798186Sgordon  int old_no_indent;
43898186Sgordon  unsigned char *starting_pos, *ending_pos;
43998186Sgordon  char *temp;
44098186Sgordon  char with_char = scoring_characters[level];
44198186Sgordon
44298186Sgordon  close_paragraph ();
443126303Smtm  filling_enabled =  indented_fill = 0;
44498186Sgordon  old_no_indent = no_indent;
44598186Sgordon  no_indent = 1;
44698186Sgordon
44798186Sgordon  if (macro_expansion_output_stream && !executing_string)
44898186Sgordon    append_to_expansion_output (input_text_offset + 1);
44998186Sgordon
45098186Sgordon  get_rest_of_line (0, &temp);
45198186Sgordon
45298186Sgordon  /* Use @settitle value if @top parameter is empty.  */
45398186Sgordon  if (STREQ (command, "top") && strlen(temp) == 0)
45498186Sgordon    temp = xstrdup (title ? title : "");
45598186Sgordon
45698186Sgordon  starting_pos = output_paragraph + output_paragraph_offset;
45798186Sgordon
45878344Sobrien  /* Poor man's cache for section title.  */
45978344Sobrien  if (strlen (last_sectioning_title))
460116097Smtm    free (last_sectioning_title);
46198186Sgordon  last_sectioning_title = xstrdup (temp);
46278344Sobrien
46398186Sgordon  index = search_sectioning (cmd);
46478344Sobrien  if (index < 0)
46578344Sobrien    {
466132892Smtm      /* should never happen, but a poor guy, named Murphy ... */
467132892Smtm      warning (_("Internal error (search_sectioning) `%s'!"), cmd);
468132892Smtm      return;
469132892Smtm    }
470132892Smtm
471132892Smtm  /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the
472126303Smtm     Info output and in TOC, but only SECTION-NAME in the macro-expanded
47398186Sgordon     output.  */
47478344Sobrien
47598186Sgordon  /* Step 1: produce "X.Y" and add it to Info output.  */
47698186Sgordon  add_word_args ("%s ", handle_enum_increment (level, index));
47778344Sobrien
478126303Smtm  /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output.  */
47998186Sgordon  if (macro_expansion_output_stream && !executing_string)
480126303Smtm    {
481126303Smtm      char *temp1 = xmalloc (2 + strlen (temp));
48278344Sobrien      sprintf (temp1, "%s\n", temp);
48378344Sobrien      remember_itext (input_text, input_text_offset);
48478344Sobrien      me_execute_string (temp1);
48578344Sobrien      free (temp1);
486126303Smtm    }
487126303Smtm  else
488126303Smtm    execute_string ("%s\n", temp);
489126303Smtm
490126303Smtm  /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and
491126303Smtm     insert it into the TOC.  */
492126303Smtm  ending_pos = output_paragraph + output_paragraph_offset;
49378344Sobrien  if (section_alist[index].toc == TOC_YES)
49478344Sobrien    toc_add_entry (substring (starting_pos, ending_pos - 1),
49598186Sgordon                   level, current_node, NULL);
49698186Sgordon
49798186Sgordon  free (temp);
49898186Sgordon
49998186Sgordon  len = (ending_pos - starting_pos) - 1;
50078344Sobrien  for (i = 0; i < len; i++)
50198186Sgordon    add_char (with_char);
50278344Sobrien  insert ('\n');
50398186Sgordon  close_paragraph ();
50498186Sgordon  filling_enabled = 1;
505131135Smtm  no_indent = old_no_indent;
506131135Smtm}
50778344Sobrien
50898186Sgordon/* Insert the text following input_text_offset up to the end of the
50998186Sgordon   line as an HTML heading element of the appropriate `level' and
51098186Sgordon   tagged as an anchor for the current node.. */
51178344Sobrien
51278344Sobrienvoid
51398186Sgordonsectioning_html (int level, char *cmd)
51478344Sobrien{
51578344Sobrien  static int toc_ref_count = 0;
51678344Sobrien  int index;
51798186Sgordon  int old_no_indent;
51878344Sobrien  unsigned char *starting_pos, *ending_pos;
51978344Sobrien  char *temp, *toc_anchor = NULL;
52078344Sobrien
52178344Sobrien  close_paragraph ();
52298186Sgordon  filling_enabled =  indented_fill = 0;
52378344Sobrien  old_no_indent = no_indent;
52498186Sgordon  no_indent = 1;
52578344Sobrien
52698186Sgordon  /* level 0 (chapter) is <h2>, and we go down from there.  */
52798186Sgordon  add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd);
52898186Sgordon
52978344Sobrien  /* If we are outside of any node, produce an anchor that
53098186Sgordon     the TOC could refer to.  */
531124832Smtm  if (!current_node || !*current_node)
53298186Sgordon    {
53398186Sgordon      static const char a_name[] = "<a name=\"";
53498186Sgordon
53598186Sgordon      starting_pos = output_paragraph + output_paragraph_offset;
53678344Sobrien      add_word_args ("%sTOC%d\">", a_name, toc_ref_count++);
53798186Sgordon      toc_anchor = substring (starting_pos + sizeof (a_name) - 1,
53878344Sobrien                              output_paragraph + output_paragraph_offset);
53978344Sobrien      /* This must be added after toc_anchor is extracted, since
54078344Sobrien         toc_anchor cannot include the closing </a>.  For details,
54198186Sgordon         see toc.c:toc_add_entry and toc.c:contents_update_html.
54278344Sobrien
54378344Sobrien         Also, the anchor close must be output before the section name
54478344Sobrien         in case the name itself contains an anchor. */
54578344Sobrien      add_word ("</a>");
54678344Sobrien    }
54778344Sobrien  starting_pos = output_paragraph + output_paragraph_offset;
54878344Sobrien
54978344Sobrien  if (macro_expansion_output_stream && !executing_string)
55098186Sgordon    append_to_expansion_output (input_text_offset + 1);
55178344Sobrien
55278344Sobrien  get_rest_of_line (0, &temp);
55378344Sobrien
55478344Sobrien  /* Use @settitle value if @top parameter is empty.  */
55578344Sobrien  if (STREQ (command, "top") && strlen(temp) == 0)
55678344Sobrien    temp = xstrdup (title ? title : "");
55798186Sgordon
55898186Sgordon  index = search_sectioning (cmd);
55978344Sobrien  if (index < 0)
56078344Sobrien    {
56178344Sobrien      /* should never happen, but a poor guy, named Murphy ... */
56278344Sobrien      warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
563116097Smtm      return;
564116097Smtm    }
565132892Smtm
566116097Smtm  /* Produce "X.Y" and add it to HTML output.  */
567116097Smtm  {
568116097Smtm    char *title_number = handle_enum_increment (level, index);
56978344Sobrien    if (strlen (title_number) > 0)
57078344Sobrien      add_word_args ("%s ", title_number);
571116097Smtm  }
572116097Smtm
573132892Smtm  /* add the section name to both HTML and macro-expanded output.  */
574116097Smtm  if (macro_expansion_output_stream && !executing_string)
575116097Smtm    {
576116097Smtm      remember_itext (input_text, input_text_offset);
57798186Sgordon      me_execute_string (temp);
578109582Smtm      write_region_to_macro_output ("\n", 0, 1);
579116097Smtm    }
580116097Smtm  else
581132892Smtm    execute_string ("%s", temp);
582116097Smtm
583116097Smtm  ending_pos = output_paragraph + output_paragraph_offset;
584116097Smtm
58578344Sobrien  /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
58678344Sobrien     into the TOC.  */
58798186Sgordon  if (section_alist[index].toc == TOC_YES)
58878344Sobrien    toc_add_entry (substring (starting_pos, ending_pos),
58978344Sobrien                   level, current_node, toc_anchor);
59098186Sgordon
59198186Sgordon  free (temp);
59278344Sobrien
59378344Sobrien  if (outstanding_node)
59478344Sobrien    outstanding_node = 0;
59578344Sobrien
59678344Sobrien  add_word_args ("</h%d>", level + 2);
59778344Sobrien  close_paragraph();
59878344Sobrien  filling_enabled = 1;
599131135Smtm  no_indent = old_no_indent;
60098186Sgordon}
60178344Sobrien
60278344Sobrien
60378344Sobrien/* Shift the meaning of @section to @chapter. */
604126287Smtmvoid
60598186Sgordoncm_raisesections (void)
60678344Sobrien{
60778344Sobrien  discard_until ("\n");
60878344Sobrien  section_alist_offset--;
60978344Sobrien}
61078344Sobrien
61178344Sobrien/* Shift the meaning of @chapter to @section. */
61278344Sobrienvoid
61378344Sobriencm_lowersections (void)
61478344Sobrien{
61598186Sgordon  discard_until ("\n");
61678344Sobrien  section_alist_offset++;
61778344Sobrien}
61878344Sobrien
61978344Sobrien/* The command still works, but prints a warning message in addition. */
62078344Sobrienvoid
62178344Sobriencm_ideprecated (int arg, int start, int end)
62278344Sobrien{
62398186Sgordon  warning (_("%c%s is obsolete; use %c%s instead"),
62478344Sobrien           COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
62578344Sobrien  sectioning_underscore (command + 1);
62678344Sobrien}
62778344Sobrien
62878344Sobrien
62978344Sobrien/* Treat this just like @unnumbered.  The only difference is
63078344Sobrien   in node defaulting. */
63198186Sgordonvoid
63278344Sobriencm_top (void)
63378344Sobrien{
63478344Sobrien  /* It is an error to have more than one @top. */
63578344Sobrien  if (top_node_seen && strcmp (current_node, "Top") != 0)
63678344Sobrien    {
63778344Sobrien      TAG_ENTRY *tag = tag_table;
63878344Sobrien
63978344Sobrien      line_error (_("Node with %ctop as a section already exists"),
640116097Smtm                  COMMAND_PREFIX);
641116097Smtm
642116097Smtm      while (tag)
643116097Smtm        {
644116097Smtm          if (tag->flags & TAG_FLAG_IS_TOP)
645116097Smtm            {
64678344Sobrien              file_line_error (tag->filename, tag->line_no,
64778344Sobrien                               _("Here is the %ctop node"), COMMAND_PREFIX);
64878344Sobrien              return;
64978344Sobrien            }
65078344Sobrien          tag = tag->next_ent;
65178344Sobrien        }
65278344Sobrien    }
65378344Sobrien  else
65478344Sobrien    {
65598186Sgordon      top_node_seen = 1;
65678344Sobrien
65778344Sobrien      /* It is an error to use @top before using @node. */
65878344Sobrien      if (!tag_table)
65978344Sobrien        {
66098186Sgordon          char *top_name;
66198186Sgordon
66298186Sgordon          get_rest_of_line (0, &top_name);
66398186Sgordon          line_error (_("%ctop used before %cnode, defaulting to %s"),
66478344Sobrien                      COMMAND_PREFIX, COMMAND_PREFIX, top_name);
66598186Sgordon          execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
66698186Sgordon          free (top_name);
66798186Sgordon          return;
66898186Sgordon        }
66998186Sgordon
670116097Smtm      cm_unnumbered ();
671116097Smtm
672116097Smtm      /* The most recently defined node is the top node. */
67398186Sgordon      tag_table->flags |= TAG_FLAG_IS_TOP;
67498186Sgordon
67598186Sgordon      /* Now set the logical hierarchical level of the Top node. */
676116097Smtm      {
677116097Smtm        int orig_offset = input_text_offset;
678116097Smtm
679116097Smtm        input_text_offset = search_forward (node_search_string, orig_offset);
68078344Sobrien
68178344Sobrien        if (input_text_offset > 0)
68278344Sobrien          {
68398186Sgordon            int this_section;
684131135Smtm
68578344Sobrien            /* We have encountered a non-top node, so mark that one exists. */
68678344Sobrien            non_top_node_seen = 1;
68778344Sobrien
68878344Sobrien            /* Move to the end of this line, and find out what the
68978344Sobrien               sectioning command is here. */
69078344Sobrien            while (input_text[input_text_offset] != '\n')
69178344Sobrien              input_text_offset++;
69278344Sobrien
69378344Sobrien            if (input_text_offset < input_text_length)
69498186Sgordon              input_text_offset++;
69598186Sgordon
69698186Sgordon            this_section = what_section (input_text + input_text_offset,
697117977Smtm                                         NULL);
698116097Smtm
699116097Smtm            /* If we found a sectioning command, then give the top section
700116097Smtm               a level of this section - 1. */
701116097Smtm            if (this_section != -1)
70278344Sobrien              set_top_section_level (this_section - 1);
70398186Sgordon          }
70498186Sgordon        input_text_offset = orig_offset;
70598186Sgordon      }
70678344Sobrien    }
70798186Sgordon}
70898186Sgordon
70998186Sgordon/* The remainder of the text on this line is a chapter heading. */
71098186Sgordonvoid
71198186Sgordoncm_chapter (void)
71298186Sgordon{
71398186Sgordon  enum_marker = 0;
71498186Sgordon  sectioning_underscore ("chapter");
715116097Smtm}
716116097Smtm
717116097Smtm/* The remainder of the text on this line is a section heading. */
71898186Sgordonvoid
71998186Sgordoncm_section (void)
72098186Sgordon{
72198186Sgordon  sectioning_underscore ("section");
722116097Smtm}
723116097Smtm
724116097Smtm/* The remainder of the text on this line is a subsection heading. */
725116097Smtmvoid
72678344Sobriencm_subsection (void)
72778344Sobrien{
72878344Sobrien  sectioning_underscore ("subsection");
72998186Sgordon}
73078344Sobrien
73178344Sobrien/* The remainder of the text on this line is a subsubsection heading. */
73278344Sobrienvoid
73378344Sobriencm_subsubsection (void)
73478344Sobrien{
73578344Sobrien  sectioning_underscore ("subsubsection");
73678344Sobrien}
73778344Sobrien
73878344Sobrien/* The remainder of the text on this line is an unnumbered heading. */
739116097Smtmvoid
740116097Smtmcm_unnumbered (void)
741116097Smtm{
742116097Smtm  enum_marker = UNNUMBERED_MAGIC;
743116097Smtm  sectioning_underscore ("unnumbered");
74478344Sobrien}
74598186Sgordon
74698186Sgordon/* The remainder of the text on this line is an unnumbered section heading. */
74798186Sgordonvoid
74898186Sgordoncm_unnumberedsec (void)
749116097Smtm{
750116097Smtm  sectioning_underscore ("unnumberedsec");
751116097Smtm}
752116097Smtm
753116097Smtm/* The remainder of the text on this line is an unnumbered
754116097Smtm   subsection heading. */
75598186Sgordonvoid
75678344Sobriencm_unnumberedsubsec (void)
75778344Sobrien{
75878344Sobrien  sectioning_underscore ("unnumberedsubsec");
759116097Smtm}
760132892Smtm
761116097Smtm/* The remainder of the text on this line is an unnumbered
762116097Smtm   subsubsection heading. */
763116097Smtmvoid
76478344Sobriencm_unnumberedsubsubsec (void)
76578344Sobrien{
76678344Sobrien  sectioning_underscore ("unnumberedsubsubsec");
76778344Sobrien}
768126285Smtm
76978344Sobrien/* The remainder of the text on this line is an appendix heading. */
77078344Sobrienvoid
771126285Smtmcm_appendix (void)
77278344Sobrien{
773132892Smtm  /* Reset top level number so we start from Appendix A */
774132892Smtm  if (enum_marker != APPENDIX_MAGIC)
77598186Sgordon    numbers [0] = 0;
776116097Smtm  enum_marker = APPENDIX_MAGIC;
777132892Smtm  sectioning_underscore ("appendix");
778116097Smtm}
779116097Smtm
78078344Sobrien/* The remainder of the text on this line is an appendix section heading. */
78178344Sobrienvoid
78298186Sgordoncm_appendixsec (void)
78398186Sgordon{
78498186Sgordon  sectioning_underscore ("appendixsec");
78598186Sgordon}
78698186Sgordon
78798186Sgordon/* The remainder of the text on this line is an appendix subsection heading. */
78878344Sobrienvoid
78978344Sobriencm_appendixsubsec (void)
79078344Sobrien{
79178344Sobrien  sectioning_underscore ("appendixsubsec");
79278344Sobrien}
79378344Sobrien
79478344Sobrien/* The remainder of the text on this line is an appendix
79578344Sobrien   subsubsection heading. */
79678344Sobrienvoid
79778344Sobriencm_appendixsubsubsec (void)
79878344Sobrien{
79978344Sobrien  sectioning_underscore ("appendixsubsubsec");
80078344Sobrien}
80178344Sobrien
80278344Sobrien/* Compatibility functions substitute for chapter, section, etc. */
80378344Sobrienvoid
804116097Smtmcm_majorheading (void)
80578344Sobrien{
80678344Sobrien  sectioning_underscore ("majorheading");
80798186Sgordon}
80878344Sobrien
80978344Sobrienvoid
81078344Sobriencm_chapheading (void)
81178344Sobrien{
81278344Sobrien  sectioning_underscore ("chapheading");
81378344Sobrien}
81478344Sobrien
81578344Sobrienvoid
81698186Sgordoncm_heading (void)
81798186Sgordon{
81898186Sgordon  sectioning_underscore ("heading");
81978344Sobrien}
82078344Sobrien
82178344Sobrienvoid
82278344Sobriencm_subheading (void)
82378344Sobrien{
82478344Sobrien  sectioning_underscore ("subheading");
82578344Sobrien}
82678344Sobrien
82778344Sobrienvoid
82898186Sgordoncm_subsubheading (void)
82998186Sgordon{
83098186Sgordon  sectioning_underscore ("subsubheading");
83198186Sgordon}
83298186Sgordon