xref: /netbsd-src/external/gpl2/texinfo/dist/makeinfo/sectioning.c (revision d3737e9cfd8cdb680cae0994d1d5f26b365d6d47)
1*d3737e9cSchristos /*	$NetBSD: sectioning.c,v 1.2 2016/01/14 00:34:53 christos Exp $	*/
229619d2aSchristos 
329619d2aSchristos /* sectioning.c -- for @chapter, @section, ..., @contents ...
429619d2aSchristos    Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp
529619d2aSchristos 
629619d2aSchristos    Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
729619d2aSchristos 
829619d2aSchristos    This program is free software; you can redistribute it and/or modify
929619d2aSchristos    it under the terms of the GNU General Public License as published by
1029619d2aSchristos    the Free Software Foundation; either version 2, or (at your option)
1129619d2aSchristos    any later version.
1229619d2aSchristos 
1329619d2aSchristos    This program is distributed in the hope that it will be useful,
1429619d2aSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1529619d2aSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1629619d2aSchristos    GNU General Public License for more details.
1729619d2aSchristos 
1829619d2aSchristos    You should have received a copy of the GNU General Public License
1929619d2aSchristos    along with this program; if not, write to the Free Software
2029619d2aSchristos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2129619d2aSchristos 
2229619d2aSchristos    Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */
2329619d2aSchristos 
2429619d2aSchristos #include "system.h"
2529619d2aSchristos #include "cmds.h"
2629619d2aSchristos #include "macro.h"
2729619d2aSchristos #include "makeinfo.h"
2829619d2aSchristos #include "node.h"
2929619d2aSchristos #include "toc.h"
3029619d2aSchristos #include "sectioning.h"
3129619d2aSchristos #include "xml.h"
3229619d2aSchristos 
3329619d2aSchristos /* See comment in sectioning.h.  */
3429619d2aSchristos section_alist_type section_alist[] = {
3529619d2aSchristos   { "unnumberedsubsubsec", 5, ENUM_SECT_NO,  TOC_YES },
3629619d2aSchristos   { "unnumberedsubsec",    4, ENUM_SECT_NO,  TOC_YES },
3729619d2aSchristos   { "unnumberedsec",       3, ENUM_SECT_NO,  TOC_YES },
3829619d2aSchristos   { "unnumbered",          2, ENUM_SECT_NO,  TOC_YES },
3929619d2aSchristos   { "centerchap",          2, ENUM_SECT_NO,  TOC_YES },
4029619d2aSchristos 
4129619d2aSchristos   { "appendixsubsubsec",   5, ENUM_SECT_APP, TOC_YES },  /* numbered like A.X.X.X */
4229619d2aSchristos   { "appendixsubsec",      4, ENUM_SECT_APP, TOC_YES },
4329619d2aSchristos   { "appendixsec",         3, ENUM_SECT_APP, TOC_YES },
4429619d2aSchristos   { "appendixsection",     3, ENUM_SECT_APP, TOC_YES },
4529619d2aSchristos   { "appendix",            2, ENUM_SECT_APP, TOC_YES },
4629619d2aSchristos 
4729619d2aSchristos   { "subsubsec",           5, ENUM_SECT_YES, TOC_YES },
4829619d2aSchristos   { "subsubsection",       5, ENUM_SECT_YES, TOC_YES },
4929619d2aSchristos   { "subsection",          4, ENUM_SECT_YES, TOC_YES },
5029619d2aSchristos   { "section",             3, ENUM_SECT_YES, TOC_YES },
5129619d2aSchristos   { "chapter",             2, ENUM_SECT_YES, TOC_YES },
5229619d2aSchristos 
5329619d2aSchristos   { "subsubheading",       5, ENUM_SECT_NO,  TOC_NO },
5429619d2aSchristos   { "subheading",          4, ENUM_SECT_NO,  TOC_NO },
5529619d2aSchristos   { "heading",             3, ENUM_SECT_NO,  TOC_NO },
5629619d2aSchristos   { "chapheading",         2, ENUM_SECT_NO,  TOC_NO },
5729619d2aSchristos   { "majorheading",        2, ENUM_SECT_NO,  TOC_NO },
5829619d2aSchristos 
5929619d2aSchristos   { "top",                 1, ENUM_SECT_NO,  TOC_YES },
6029619d2aSchristos   { NULL,                  0, 0, 0 }
6129619d2aSchristos };
6229619d2aSchristos 
6329619d2aSchristos /* The argument of @settitle, used for HTML. */
6429619d2aSchristos char *title = NULL;
6529619d2aSchristos 
6629619d2aSchristos 
6729619d2aSchristos #define APPENDIX_MAGIC   1024
6829619d2aSchristos #define UNNUMBERED_MAGIC 2048
6929619d2aSchristos 
7029619d2aSchristos /* Number memory for every level @chapter, @section,
7129619d2aSchristos    @subsection, @subsubsection. */
7229619d2aSchristos static int numbers [] = { 0, 0, 0, 0 };
7329619d2aSchristos 
7429619d2aSchristos /* enum_marker == APPENDIX_MAGIC then we are counting appendencies
7529619d2aSchristos    enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area.
7629619d2aSchristos    Handling situations like this:
7729619d2aSchristos    @unnumbered ..
7829619d2aSchristos    @section ...   */
7929619d2aSchristos static int enum_marker = 0;
8029619d2aSchristos 
8129619d2aSchristos /* Organized by level commands.  That is, "*" == chapter, "=" == section. */
8229619d2aSchristos static char *scoring_characters = "*=-.";
8329619d2aSchristos 
8429619d2aSchristos /* Amount to offset the name of sectioning commands to levels by. */
8529619d2aSchristos static int section_alist_offset = 0;
8629619d2aSchristos 
8729619d2aSchristos /* These two variables are for @float, @cindex like commands that need to know
8829619d2aSchristos    in which section they are used.  */
8929619d2aSchristos /* Last value returned by get_sectioning_number.  */
9029619d2aSchristos static char *last_sectioning_number = "";
9129619d2aSchristos /* Last title used by sectioning_underscore, etc.  */
9229619d2aSchristos static char *last_sectioning_title = "";
9329619d2aSchristos 
9429619d2aSchristos /* num == ENUM_SECT_NO  means unnumbered (should never call this)
9529619d2aSchristos    num == ENUM_SECT_YES means numbered
9629619d2aSchristos    num == ENUM_SECT_APP means numbered like A.1 and so on */
9729619d2aSchristos static char *
get_sectioning_number(int level,int num)9829619d2aSchristos get_sectioning_number (int level, int num)
9929619d2aSchristos {
10029619d2aSchristos   static char s[100]; /* should ever be enough for 99.99.99.99
10129619d2aSchristos                          Appendix A.1 */
10229619d2aSchristos 
10329619d2aSchristos   char *p;
10429619d2aSchristos   int i;
10529619d2aSchristos 
10629619d2aSchristos   s[0] = 0;
10729619d2aSchristos 
10829619d2aSchristos   /* create enumeration in front of chapter, section, subsection and so on. */
10929619d2aSchristos   for (i = 0; i < level; i++)
11029619d2aSchristos     {
11129619d2aSchristos       p = s + strlen (s);
11229619d2aSchristos       if ((i == 0) && (enum_marker == APPENDIX_MAGIC))
11329619d2aSchristos         sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to
11429619d2aSchristos                                                 be more portable */
11529619d2aSchristos       else
11629619d2aSchristos         sprintf (p, "%d.", numbers[i]);
11729619d2aSchristos     }
11829619d2aSchristos 
11929619d2aSchristos   /* the last number is never followed by a dot */
12029619d2aSchristos   p = s + strlen (s);
12129619d2aSchristos   if ((num == ENUM_SECT_APP)
12229619d2aSchristos       && (i == 0)
12329619d2aSchristos       && (enum_marker == APPENDIX_MAGIC))
12429619d2aSchristos     sprintf (p, _("Appendix %c"), numbers[i] + 64);
12529619d2aSchristos   else
12629619d2aSchristos     sprintf (p, "%d", numbers[i]);
12729619d2aSchristos 
12829619d2aSchristos   /* Poor man's cache :-)  */
12929619d2aSchristos   if (strlen (last_sectioning_number))
13029619d2aSchristos     free (last_sectioning_number);
13129619d2aSchristos   last_sectioning_number = xstrdup (s);
13229619d2aSchristos 
13329619d2aSchristos   return s;
13429619d2aSchristos }
13529619d2aSchristos 
13629619d2aSchristos 
13729619d2aSchristos /* Set the level of @top to LEVEL.  Return the old level of @top. */
13829619d2aSchristos int
set_top_section_level(int level)13929619d2aSchristos set_top_section_level (int level)
14029619d2aSchristos {
14129619d2aSchristos   int i, result = -1;
14229619d2aSchristos 
14329619d2aSchristos   for (i = 0; section_alist[i].name; i++)
14429619d2aSchristos     if (strcmp (section_alist[i].name, "top") == 0)
14529619d2aSchristos       {
14629619d2aSchristos         result = section_alist[i].level;
14729619d2aSchristos         section_alist[i].level = level;
14829619d2aSchristos         break;
14929619d2aSchristos       }
15029619d2aSchristos   return result;
15129619d2aSchristos }
15229619d2aSchristos 
15329619d2aSchristos 
15429619d2aSchristos /* return the index of the given sectioning command in section_alist */
15529619d2aSchristos static int
search_sectioning(char * text)15629619d2aSchristos search_sectioning (char *text)
15729619d2aSchristos {
15829619d2aSchristos   int i;
15929619d2aSchristos   char *t;
16029619d2aSchristos 
16129619d2aSchristos   /* ignore the optional command prefix */
16229619d2aSchristos   if (text[0] == COMMAND_PREFIX)
16329619d2aSchristos     text++;
16429619d2aSchristos 
16529619d2aSchristos   for (i = 0; (t = section_alist[i].name); i++)
16629619d2aSchristos     {
16729619d2aSchristos       if (strcmp (t, text) == 0)
16829619d2aSchristos         {
16929619d2aSchristos           return i;
17029619d2aSchristos         }
17129619d2aSchristos     }
17229619d2aSchristos   return -1;
17329619d2aSchristos }
17429619d2aSchristos 
17529619d2aSchristos /* Return an integer which identifies the type of section present in
17629619d2aSchristos    TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as
17729619d2aSchristos    specified in section_alist).  We take into account any @lowersections
17829619d2aSchristos    and @raisesections.  If SECNAME is non-NULL, also return the
17929619d2aSchristos    corresponding section name.  */
18029619d2aSchristos int
what_section(char * text,char ** secname)18129619d2aSchristos what_section (char *text, char **secname)
18229619d2aSchristos {
18329619d2aSchristos   int index, j;
18429619d2aSchristos   char *temp;
18529619d2aSchristos   int return_val;
18629619d2aSchristos 
18729619d2aSchristos  find_section_command:
18829619d2aSchristos   for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
18929619d2aSchristos   if (text[j] != COMMAND_PREFIX)
19029619d2aSchristos     return -1;
19129619d2aSchristos 
19229619d2aSchristos   text = text + j + 1;
19329619d2aSchristos 
19429619d2aSchristos   /* We skip @c, @comment, and @?index commands. */
19529619d2aSchristos   if ((strncmp (text, "comment", strlen ("comment")) == 0) ||
19629619d2aSchristos       (text[0] == 'c' && cr_or_whitespace (text[1])) ||
19729619d2aSchristos       (strcmp (text + 1, "index") == 0))
19829619d2aSchristos     {
19929619d2aSchristos       while (*text++ != '\n');
20029619d2aSchristos       goto find_section_command;
20129619d2aSchristos     }
20229619d2aSchristos 
20329619d2aSchristos   /* Handle italicized sectioning commands. */
20429619d2aSchristos   if (*text == 'i')
20529619d2aSchristos     text++;
20629619d2aSchristos 
20729619d2aSchristos   for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
20829619d2aSchristos 
20929619d2aSchristos   temp = xmalloc (1 + j);
21029619d2aSchristos   strncpy (temp, text, j);
21129619d2aSchristos   temp[j] = 0;
21229619d2aSchristos 
21329619d2aSchristos   index = search_sectioning (temp);
21429619d2aSchristos   free (temp);
21529619d2aSchristos   if (index >= 0)
21629619d2aSchristos     {
21729619d2aSchristos       return_val = section_alist[index].level + section_alist_offset;
21829619d2aSchristos       if (return_val < 0)
21929619d2aSchristos         return_val = 0;
22029619d2aSchristos       else if (return_val > 5)
22129619d2aSchristos         return_val = 5;
22229619d2aSchristos 
22329619d2aSchristos       if (secname)
22429619d2aSchristos         {
22529619d2aSchristos           int i;
22629619d2aSchristos           int alist_size = sizeof (section_alist) / sizeof(section_alist_type);
22729619d2aSchristos           /* Find location of offset sectioning entry, but don't go off
22829619d2aSchristos              either end of the array.  */
22929619d2aSchristos           int index_offset = MAX (index - section_alist_offset, 0);
23029619d2aSchristos           index_offset = MIN (index_offset, alist_size - 1);
23129619d2aSchristos 
23229619d2aSchristos           /* Also make sure we don't go into the next "group" of
23329619d2aSchristos              sectioning changes, e.g., change from an @appendix to an
23429619d2aSchristos              @heading or some such.  */
23529619d2aSchristos #define SIGN(expr) ((expr) < 0 ? -1 : 1)
23629619d2aSchristos           for (i = index; i != index_offset; i -= SIGN (section_alist_offset))
23729619d2aSchristos             {
23829619d2aSchristos               /* As it happens, each group has unique .num/.toc values.  */
23929619d2aSchristos               if (section_alist[i].num != section_alist[index_offset].num
24029619d2aSchristos                   || section_alist[i].toc != section_alist[index_offset].toc)
24129619d2aSchristos                 break;
24229619d2aSchristos             }
24329619d2aSchristos           *secname = section_alist[i].name;
24429619d2aSchristos         }
24529619d2aSchristos       return return_val;
24629619d2aSchristos     }
24729619d2aSchristos   return -1;
24829619d2aSchristos }
24929619d2aSchristos 
25029619d2aSchristos /* Returns current top level division (ie. chapter, unnumbered) number.
25129619d2aSchristos    - For chapters, returns the number.
25229619d2aSchristos    - For unnumbered sections, returns empty string.
25329619d2aSchristos    - For appendices, returns A, B, etc. */
25429619d2aSchristos char *
current_chapter_number(void)25529619d2aSchristos current_chapter_number (void)
25629619d2aSchristos {
25729619d2aSchristos   if (enum_marker == UNNUMBERED_MAGIC)
25829619d2aSchristos     return xstrdup ("");
25929619d2aSchristos   else if (enum_marker == APPENDIX_MAGIC)
26029619d2aSchristos     {
261*d3737e9cSchristos       char s[2] = { numbers[0] + 64, '\0' };
26229619d2aSchristos       return xstrdup (s);
26329619d2aSchristos     }
26429619d2aSchristos   else
26529619d2aSchristos     {
266*d3737e9cSchristos       char s[11];
267*d3737e9cSchristos       snprintf (s, sizeof(s), "%d", numbers[0]);
26829619d2aSchristos       return xstrdup (s);
26929619d2aSchristos     }
27029619d2aSchristos }
27129619d2aSchristos 
27229619d2aSchristos /* Returns number of the last sectioning command used.  */
27329619d2aSchristos char *
current_sectioning_number(void)27429619d2aSchristos current_sectioning_number (void)
27529619d2aSchristos {
27629619d2aSchristos   if (enum_marker == UNNUMBERED_MAGIC || !number_sections)
27729619d2aSchristos     return xstrdup ("");
27829619d2aSchristos   else
27929619d2aSchristos     return xstrdup (last_sectioning_number);
28029619d2aSchristos }
28129619d2aSchristos 
28229619d2aSchristos /* Returns arguments of the last sectioning command used.  */
28329619d2aSchristos char *
current_sectioning_name(void)28429619d2aSchristos current_sectioning_name (void)
28529619d2aSchristos {
28629619d2aSchristos   return xstrdup (last_sectioning_title);
28729619d2aSchristos }
28829619d2aSchristos 
28929619d2aSchristos /* insert_and_underscore, sectioning_underscore and sectioning_html call this.  */
29029619d2aSchristos 
29129619d2aSchristos static char *
handle_enum_increment(int level,int index)29229619d2aSchristos handle_enum_increment (int level, int index)
29329619d2aSchristos {
29429619d2aSchristos   /* Here is how TeX handles enumeration:
29529619d2aSchristos      - Anything starting with @unnumbered is not enumerated.
29629619d2aSchristos      - @majorheading and the like are not enumberated.  */
29729619d2aSchristos   int i;
29829619d2aSchristos 
29929619d2aSchristos   /* First constraint above.  */
30029619d2aSchristos   if (enum_marker == UNNUMBERED_MAGIC && level == 0)
30129619d2aSchristos     return xstrdup ("");
30229619d2aSchristos 
30329619d2aSchristos   /* Second constraint.  */
30429619d2aSchristos   if (section_alist[index].num == ENUM_SECT_NO)
30529619d2aSchristos     return xstrdup ("");
30629619d2aSchristos 
30729619d2aSchristos   /* reset all counters which are one level deeper */
30829619d2aSchristos   for (i = level; i < 3; i++)
30929619d2aSchristos     numbers [i + 1] = 0;
31029619d2aSchristos 
31129619d2aSchristos   numbers[level]++;
31229619d2aSchristos   if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC
31329619d2aSchristos       || !number_sections)
31429619d2aSchristos     return xstrdup ("");
31529619d2aSchristos   else
31629619d2aSchristos     return xstrdup (get_sectioning_number (level, section_alist[index].num));
31729619d2aSchristos }
31829619d2aSchristos 
31929619d2aSchristos 
32029619d2aSchristos void
sectioning_underscore(char * cmd)32129619d2aSchristos sectioning_underscore (char *cmd)
32229619d2aSchristos {
32329619d2aSchristos   char *temp, *secname;
32429619d2aSchristos   int level;
32529619d2aSchristos 
32629619d2aSchristos   /* If we're not indenting the first paragraph, we shall make it behave
32729619d2aSchristos      like @noindent is called directly after the section heading. */
32829619d2aSchristos   if (! do_first_par_indent)
32929619d2aSchristos     cm_noindent ();
33029619d2aSchristos 
33129619d2aSchristos   temp = xmalloc (2 + strlen (cmd));
33229619d2aSchristos   temp[0] = COMMAND_PREFIX;
33329619d2aSchristos   strcpy (&temp[1], cmd);
33429619d2aSchristos   level = what_section (temp, &secname);
33529619d2aSchristos   level -= 2;
33629619d2aSchristos   if (level < 0)
33729619d2aSchristos     level = 0;
33829619d2aSchristos   free (temp);
33929619d2aSchristos 
34029619d2aSchristos   /* If the argument to @top is empty, we try using the one from @settitle.
34129619d2aSchristos      Warn if both are unusable.  */
34229619d2aSchristos   if (STREQ (command, "top"))
34329619d2aSchristos     {
34429619d2aSchristos       int save_input_text_offset = input_text_offset;
34529619d2aSchristos 
34629619d2aSchristos       get_rest_of_line (0, &temp);
34729619d2aSchristos 
34829619d2aSchristos       /* Due to get_rest_of_line ... */
34929619d2aSchristos       line_number--;
35029619d2aSchristos 
35129619d2aSchristos       if (strlen (temp) == 0 && (!title || strlen (title) == 0))
35229619d2aSchristos         warning ("Must specify a title with least one of @settitle or @top");
35329619d2aSchristos 
35429619d2aSchristos       input_text_offset = save_input_text_offset;
35529619d2aSchristos     }
35629619d2aSchristos 
35729619d2aSchristos   if (xml)
35829619d2aSchristos     {
35929619d2aSchristos       /* If the section appears in the toc, it means it's a real section
36029619d2aSchristos 	 unlike majorheading, chapheading etc. */
36129619d2aSchristos       if (section_alist[search_sectioning (cmd)].toc == TOC_YES)
36229619d2aSchristos 	{
36329619d2aSchristos 	  xml_close_sections (level);
36429619d2aSchristos 	  /* Mark the beginning of the section
36529619d2aSchristos 	     If the next command is printindex, we will remove
36629619d2aSchristos 	     the section and put an Index instead */
36729619d2aSchristos 	  flush_output ();
36829619d2aSchristos 	  xml_last_section_output_position = output_paragraph_offset;
36929619d2aSchristos 
37029619d2aSchristos 	  get_rest_of_line (0, &temp);
37129619d2aSchristos 
37229619d2aSchristos           /* Use @settitle value if @top parameter is empty.  */
37329619d2aSchristos           if (STREQ (command, "top") && strlen(temp) == 0)
37429619d2aSchristos             temp = xstrdup (title ? title : "");
37529619d2aSchristos 
37629619d2aSchristos           /* Docbook does not support @unnumbered at all.  So we provide numbers
37729619d2aSchristos              that other formats use.  @appendix seems to be fine though, so we let
37829619d2aSchristos              Docbook handle that as usual.  */
37929619d2aSchristos           if (docbook && enum_marker != APPENDIX_MAGIC)
38029619d2aSchristos             {
38129619d2aSchristos               if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO
38229619d2aSchristos                   && section_alist[search_sectioning (cmd)].toc == TOC_YES)
38329619d2aSchristos                 xml_insert_element_with_attribute (xml_element (secname),
38429619d2aSchristos                     START, "label=\"%s\" xreflabel=\"%s\"",
38529619d2aSchristos                     handle_enum_increment (level, search_sectioning (cmd)),
38629619d2aSchristos                     text_expansion (temp));
38729619d2aSchristos               else
38829619d2aSchristos                 xml_insert_element_with_attribute (xml_element (secname),
38929619d2aSchristos                     START, "label=\"%s\"",
39029619d2aSchristos                     handle_enum_increment (level, search_sectioning (cmd)));
39129619d2aSchristos             }
39229619d2aSchristos           else
39329619d2aSchristos             xml_insert_element (xml_element (secname), START);
39429619d2aSchristos 
39529619d2aSchristos 	  xml_insert_element (TITLE, START);
39629619d2aSchristos 	  xml_open_section (level, secname);
39729619d2aSchristos 	  execute_string ("%s", temp);
39829619d2aSchristos 	  xml_insert_element (TITLE, END);
39929619d2aSchristos 
40029619d2aSchristos 	  free (temp);
40129619d2aSchristos 	}
40229619d2aSchristos       else
40329619d2aSchristos         {
40429619d2aSchristos           if (docbook)
40529619d2aSchristos             {
40629619d2aSchristos               if (level > 0)
40729619d2aSchristos                 xml_insert_element_with_attribute (xml_element (secname), START,
40829619d2aSchristos                     "renderas=\"sect%d\"", level);
40929619d2aSchristos               else
41029619d2aSchristos                 xml_insert_element_with_attribute (xml_element (secname), START,
41129619d2aSchristos                     "renderas=\"other\"");
41229619d2aSchristos             }
41329619d2aSchristos           else
41429619d2aSchristos             xml_insert_element (xml_element (secname), START);
41529619d2aSchristos 
41629619d2aSchristos           get_rest_of_line (0, &temp);
41729619d2aSchristos           execute_string ("%s", temp);
41829619d2aSchristos           free (temp);
41929619d2aSchristos 
42029619d2aSchristos           xml_insert_element (xml_element (secname), END);
42129619d2aSchristos         }
42229619d2aSchristos     }
42329619d2aSchristos   else if (html)
42429619d2aSchristos     sectioning_html (level, secname);
42529619d2aSchristos   else
42629619d2aSchristos     insert_and_underscore (level, secname);
42729619d2aSchristos }
42829619d2aSchristos 
42929619d2aSchristos 
43029619d2aSchristos /* Insert the text following input_text_offset up to the end of the line
43129619d2aSchristos    in a new, separate paragraph.  Directly underneath it, insert a
43229619d2aSchristos    line of WITH_CHAR, the same length of the inserted text. */
43329619d2aSchristos void
insert_and_underscore(int level,char * cmd)43429619d2aSchristos insert_and_underscore (int level, char *cmd)
43529619d2aSchristos {
43629619d2aSchristos   int i, len;
43729619d2aSchristos   int index;
43829619d2aSchristos   int old_no_indent;
43929619d2aSchristos   unsigned char *starting_pos, *ending_pos;
44029619d2aSchristos   char *temp;
44129619d2aSchristos   char with_char = scoring_characters[level];
44229619d2aSchristos 
44329619d2aSchristos   close_paragraph ();
44429619d2aSchristos   filling_enabled =  indented_fill = 0;
44529619d2aSchristos   old_no_indent = no_indent;
44629619d2aSchristos   no_indent = 1;
44729619d2aSchristos 
44829619d2aSchristos   if (macro_expansion_output_stream && !executing_string)
44929619d2aSchristos     append_to_expansion_output (input_text_offset + 1);
45029619d2aSchristos 
45129619d2aSchristos   get_rest_of_line (0, &temp);
45229619d2aSchristos 
45329619d2aSchristos   /* Use @settitle value if @top parameter is empty.  */
45429619d2aSchristos   if (STREQ (command, "top") && strlen(temp) == 0)
45529619d2aSchristos     temp = xstrdup (title ? title : "");
45629619d2aSchristos 
45729619d2aSchristos   starting_pos = output_paragraph + output_paragraph_offset;
45829619d2aSchristos 
45929619d2aSchristos   /* Poor man's cache for section title.  */
46029619d2aSchristos   if (strlen (last_sectioning_title))
46129619d2aSchristos     free (last_sectioning_title);
46229619d2aSchristos   last_sectioning_title = xstrdup (temp);
46329619d2aSchristos 
46429619d2aSchristos   index = search_sectioning (cmd);
46529619d2aSchristos   if (index < 0)
46629619d2aSchristos     {
46729619d2aSchristos       /* should never happen, but a poor guy, named Murphy ... */
46829619d2aSchristos       warning (_("Internal error (search_sectioning) `%s'!"), cmd);
46929619d2aSchristos       return;
47029619d2aSchristos     }
47129619d2aSchristos 
47229619d2aSchristos   /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the
47329619d2aSchristos      Info output and in TOC, but only SECTION-NAME in the macro-expanded
47429619d2aSchristos      output.  */
47529619d2aSchristos 
47629619d2aSchristos   /* Step 1: produce "X.Y" and add it to Info output.  */
47729619d2aSchristos   add_word_args ("%s ", handle_enum_increment (level, index));
47829619d2aSchristos 
47929619d2aSchristos   /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output.  */
48029619d2aSchristos   if (macro_expansion_output_stream && !executing_string)
48129619d2aSchristos     {
48229619d2aSchristos       char *temp1 = xmalloc (2 + strlen (temp));
48329619d2aSchristos       sprintf (temp1, "%s\n", temp);
48429619d2aSchristos       remember_itext (input_text, input_text_offset);
48529619d2aSchristos       me_execute_string (temp1);
48629619d2aSchristos       free (temp1);
48729619d2aSchristos     }
48829619d2aSchristos   else
48929619d2aSchristos     execute_string ("%s\n", temp);
49029619d2aSchristos 
49129619d2aSchristos   /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and
49229619d2aSchristos      insert it into the TOC.  */
49329619d2aSchristos   ending_pos = output_paragraph + output_paragraph_offset;
49429619d2aSchristos   if (section_alist[index].toc == TOC_YES)
49529619d2aSchristos     toc_add_entry (substring (starting_pos, ending_pos - 1),
49629619d2aSchristos                    level, current_node, NULL);
49729619d2aSchristos 
49829619d2aSchristos   free (temp);
49929619d2aSchristos 
50029619d2aSchristos   len = (ending_pos - starting_pos) - 1;
50129619d2aSchristos   for (i = 0; i < len; i++)
50229619d2aSchristos     add_char (with_char);
50329619d2aSchristos   insert ('\n');
50429619d2aSchristos   close_paragraph ();
50529619d2aSchristos   filling_enabled = 1;
50629619d2aSchristos   no_indent = old_no_indent;
50729619d2aSchristos }
50829619d2aSchristos 
50929619d2aSchristos /* Insert the text following input_text_offset up to the end of the
51029619d2aSchristos    line as an HTML heading element of the appropriate `level' and
51129619d2aSchristos    tagged as an anchor for the current node.. */
51229619d2aSchristos 
51329619d2aSchristos void
sectioning_html(int level,char * cmd)51429619d2aSchristos sectioning_html (int level, char *cmd)
51529619d2aSchristos {
51629619d2aSchristos   static int toc_ref_count = 0;
51729619d2aSchristos   int index;
51829619d2aSchristos   int old_no_indent;
51929619d2aSchristos   unsigned char *starting_pos, *ending_pos;
52029619d2aSchristos   char *temp, *toc_anchor = NULL;
52129619d2aSchristos 
52229619d2aSchristos   close_paragraph ();
52329619d2aSchristos   filling_enabled =  indented_fill = 0;
52429619d2aSchristos   old_no_indent = no_indent;
52529619d2aSchristos   no_indent = 1;
52629619d2aSchristos 
52729619d2aSchristos   /* level 0 (chapter) is <h2>, and we go down from there.  */
52829619d2aSchristos   add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd);
52929619d2aSchristos 
53029619d2aSchristos   /* If we are outside of any node, produce an anchor that
53129619d2aSchristos      the TOC could refer to.  */
53229619d2aSchristos   if (!current_node || !*current_node)
53329619d2aSchristos     {
53429619d2aSchristos       static const char a_name[] = "<a name=\"";
53529619d2aSchristos 
53629619d2aSchristos       starting_pos = output_paragraph + output_paragraph_offset;
53729619d2aSchristos       add_word_args ("%sTOC%d\">", a_name, toc_ref_count++);
53829619d2aSchristos       toc_anchor = substring (starting_pos + sizeof (a_name) - 1,
53929619d2aSchristos                               output_paragraph + output_paragraph_offset);
54029619d2aSchristos       /* This must be added after toc_anchor is extracted, since
54129619d2aSchristos          toc_anchor cannot include the closing </a>.  For details,
54229619d2aSchristos          see toc.c:toc_add_entry and toc.c:contents_update_html.
54329619d2aSchristos 
54429619d2aSchristos          Also, the anchor close must be output before the section name
54529619d2aSchristos          in case the name itself contains an anchor. */
54629619d2aSchristos       add_word ("</a>");
54729619d2aSchristos     }
54829619d2aSchristos   starting_pos = output_paragraph + output_paragraph_offset;
54929619d2aSchristos 
55029619d2aSchristos   if (macro_expansion_output_stream && !executing_string)
55129619d2aSchristos     append_to_expansion_output (input_text_offset + 1);
55229619d2aSchristos 
55329619d2aSchristos   get_rest_of_line (0, &temp);
55429619d2aSchristos 
55529619d2aSchristos   /* Use @settitle value if @top parameter is empty.  */
55629619d2aSchristos   if (STREQ (command, "top") && strlen(temp) == 0)
55729619d2aSchristos     temp = xstrdup (title ? title : "");
55829619d2aSchristos 
55929619d2aSchristos   index = search_sectioning (cmd);
56029619d2aSchristos   if (index < 0)
56129619d2aSchristos     {
56229619d2aSchristos       /* should never happen, but a poor guy, named Murphy ... */
56329619d2aSchristos       warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
56429619d2aSchristos       return;
56529619d2aSchristos     }
56629619d2aSchristos 
56729619d2aSchristos   /* Produce "X.Y" and add it to HTML output.  */
56829619d2aSchristos   {
56929619d2aSchristos     char *title_number = handle_enum_increment (level, index);
57029619d2aSchristos     if (strlen (title_number) > 0)
57129619d2aSchristos       add_word_args ("%s ", title_number);
57229619d2aSchristos   }
57329619d2aSchristos 
57429619d2aSchristos   /* add the section name to both HTML and macro-expanded output.  */
57529619d2aSchristos   if (macro_expansion_output_stream && !executing_string)
57629619d2aSchristos     {
57729619d2aSchristos       remember_itext (input_text, input_text_offset);
57829619d2aSchristos       me_execute_string (temp);
57929619d2aSchristos       write_region_to_macro_output ("\n", 0, 1);
58029619d2aSchristos     }
58129619d2aSchristos   else
58229619d2aSchristos     execute_string ("%s", temp);
58329619d2aSchristos 
58429619d2aSchristos   ending_pos = output_paragraph + output_paragraph_offset;
58529619d2aSchristos 
58629619d2aSchristos   /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
58729619d2aSchristos      into the TOC.  */
58829619d2aSchristos   if (section_alist[index].toc == TOC_YES)
58929619d2aSchristos     toc_add_entry (substring (starting_pos, ending_pos),
59029619d2aSchristos                    level, current_node, toc_anchor);
59129619d2aSchristos 
59229619d2aSchristos   free (temp);
59329619d2aSchristos 
59429619d2aSchristos   if (outstanding_node)
59529619d2aSchristos     outstanding_node = 0;
59629619d2aSchristos 
59729619d2aSchristos   add_word_args ("</h%d>", level + 2);
59829619d2aSchristos   close_paragraph();
59929619d2aSchristos   filling_enabled = 1;
60029619d2aSchristos   no_indent = old_no_indent;
60129619d2aSchristos }
60229619d2aSchristos 
60329619d2aSchristos 
60429619d2aSchristos /* Shift the meaning of @section to @chapter. */
60529619d2aSchristos void
cm_raisesections(void)60629619d2aSchristos cm_raisesections (void)
60729619d2aSchristos {
60829619d2aSchristos   discard_until ("\n");
60929619d2aSchristos   section_alist_offset--;
61029619d2aSchristos }
61129619d2aSchristos 
61229619d2aSchristos /* Shift the meaning of @chapter to @section. */
61329619d2aSchristos void
cm_lowersections(void)61429619d2aSchristos cm_lowersections (void)
61529619d2aSchristos {
61629619d2aSchristos   discard_until ("\n");
61729619d2aSchristos   section_alist_offset++;
61829619d2aSchristos }
61929619d2aSchristos 
62029619d2aSchristos /* The command still works, but prints a warning message in addition. */
62129619d2aSchristos void
cm_ideprecated(int arg,int start,int end)62229619d2aSchristos cm_ideprecated (int arg, int start, int end)
62329619d2aSchristos {
62429619d2aSchristos   warning (_("%c%s is obsolete; use %c%s instead"),
62529619d2aSchristos            COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
62629619d2aSchristos   sectioning_underscore (command + 1);
62729619d2aSchristos }
62829619d2aSchristos 
62929619d2aSchristos 
63029619d2aSchristos /* Treat this just like @unnumbered.  The only difference is
63129619d2aSchristos    in node defaulting. */
63229619d2aSchristos void
cm_top(void)63329619d2aSchristos cm_top (void)
63429619d2aSchristos {
63529619d2aSchristos   /* It is an error to have more than one @top. */
63629619d2aSchristos   if (top_node_seen && strcmp (current_node, "Top") != 0)
63729619d2aSchristos     {
63829619d2aSchristos       TAG_ENTRY *tag = tag_table;
63929619d2aSchristos 
64029619d2aSchristos       line_error (_("Node with %ctop as a section already exists"),
64129619d2aSchristos                   COMMAND_PREFIX);
64229619d2aSchristos 
64329619d2aSchristos       while (tag)
64429619d2aSchristos         {
64529619d2aSchristos           if (tag->flags & TAG_FLAG_IS_TOP)
64629619d2aSchristos             {
64729619d2aSchristos               file_line_error (tag->filename, tag->line_no,
64829619d2aSchristos                                _("Here is the %ctop node"), COMMAND_PREFIX);
64929619d2aSchristos               return;
65029619d2aSchristos             }
65129619d2aSchristos           tag = tag->next_ent;
65229619d2aSchristos         }
65329619d2aSchristos     }
65429619d2aSchristos   else
65529619d2aSchristos     {
65629619d2aSchristos       top_node_seen = 1;
65729619d2aSchristos 
65829619d2aSchristos       /* It is an error to use @top before using @node. */
65929619d2aSchristos       if (!tag_table)
66029619d2aSchristos         {
66129619d2aSchristos           char *top_name;
66229619d2aSchristos 
66329619d2aSchristos           get_rest_of_line (0, &top_name);
66429619d2aSchristos           line_error (_("%ctop used before %cnode, defaulting to %s"),
66529619d2aSchristos                       COMMAND_PREFIX, COMMAND_PREFIX, top_name);
66629619d2aSchristos           execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
66729619d2aSchristos           free (top_name);
66829619d2aSchristos           return;
66929619d2aSchristos         }
67029619d2aSchristos 
67129619d2aSchristos       cm_unnumbered ();
67229619d2aSchristos 
67329619d2aSchristos       /* The most recently defined node is the top node. */
67429619d2aSchristos       tag_table->flags |= TAG_FLAG_IS_TOP;
67529619d2aSchristos 
67629619d2aSchristos       /* Now set the logical hierarchical level of the Top node. */
67729619d2aSchristos       {
67829619d2aSchristos         int orig_offset = input_text_offset;
67929619d2aSchristos 
68029619d2aSchristos         input_text_offset = search_forward (node_search_string, orig_offset);
68129619d2aSchristos 
68229619d2aSchristos         if (input_text_offset > 0)
68329619d2aSchristos           {
68429619d2aSchristos             int this_section;
68529619d2aSchristos 
68629619d2aSchristos             /* We have encountered a non-top node, so mark that one exists. */
68729619d2aSchristos             non_top_node_seen = 1;
68829619d2aSchristos 
68929619d2aSchristos             /* Move to the end of this line, and find out what the
69029619d2aSchristos                sectioning command is here. */
69129619d2aSchristos             while (input_text[input_text_offset] != '\n')
69229619d2aSchristos               input_text_offset++;
69329619d2aSchristos 
69429619d2aSchristos             if (input_text_offset < input_text_length)
69529619d2aSchristos               input_text_offset++;
69629619d2aSchristos 
69729619d2aSchristos             this_section = what_section (input_text + input_text_offset,
69829619d2aSchristos                                          NULL);
69929619d2aSchristos 
70029619d2aSchristos             /* If we found a sectioning command, then give the top section
70129619d2aSchristos                a level of this section - 1. */
70229619d2aSchristos             if (this_section != -1)
70329619d2aSchristos               set_top_section_level (this_section - 1);
70429619d2aSchristos           }
70529619d2aSchristos         input_text_offset = orig_offset;
70629619d2aSchristos       }
70729619d2aSchristos     }
70829619d2aSchristos }
70929619d2aSchristos 
71029619d2aSchristos /* The remainder of the text on this line is a chapter heading. */
71129619d2aSchristos void
cm_chapter(void)71229619d2aSchristos cm_chapter (void)
71329619d2aSchristos {
71429619d2aSchristos   enum_marker = 0;
71529619d2aSchristos   sectioning_underscore ("chapter");
71629619d2aSchristos }
71729619d2aSchristos 
71829619d2aSchristos /* The remainder of the text on this line is a section heading. */
71929619d2aSchristos void
cm_section(void)72029619d2aSchristos cm_section (void)
72129619d2aSchristos {
72229619d2aSchristos   sectioning_underscore ("section");
72329619d2aSchristos }
72429619d2aSchristos 
72529619d2aSchristos /* The remainder of the text on this line is a subsection heading. */
72629619d2aSchristos void
cm_subsection(void)72729619d2aSchristos cm_subsection (void)
72829619d2aSchristos {
72929619d2aSchristos   sectioning_underscore ("subsection");
73029619d2aSchristos }
73129619d2aSchristos 
73229619d2aSchristos /* The remainder of the text on this line is a subsubsection heading. */
73329619d2aSchristos void
cm_subsubsection(void)73429619d2aSchristos cm_subsubsection (void)
73529619d2aSchristos {
73629619d2aSchristos   sectioning_underscore ("subsubsection");
73729619d2aSchristos }
73829619d2aSchristos 
73929619d2aSchristos /* The remainder of the text on this line is an unnumbered heading. */
74029619d2aSchristos void
cm_unnumbered(void)74129619d2aSchristos cm_unnumbered (void)
74229619d2aSchristos {
74329619d2aSchristos   enum_marker = UNNUMBERED_MAGIC;
74429619d2aSchristos   sectioning_underscore ("unnumbered");
74529619d2aSchristos }
74629619d2aSchristos 
74729619d2aSchristos /* The remainder of the text on this line is an unnumbered section heading. */
74829619d2aSchristos void
cm_unnumberedsec(void)74929619d2aSchristos cm_unnumberedsec (void)
75029619d2aSchristos {
75129619d2aSchristos   sectioning_underscore ("unnumberedsec");
75229619d2aSchristos }
75329619d2aSchristos 
75429619d2aSchristos /* The remainder of the text on this line is an unnumbered
75529619d2aSchristos    subsection heading. */
75629619d2aSchristos void
cm_unnumberedsubsec(void)75729619d2aSchristos cm_unnumberedsubsec (void)
75829619d2aSchristos {
75929619d2aSchristos   sectioning_underscore ("unnumberedsubsec");
76029619d2aSchristos }
76129619d2aSchristos 
76229619d2aSchristos /* The remainder of the text on this line is an unnumbered
76329619d2aSchristos    subsubsection heading. */
76429619d2aSchristos void
cm_unnumberedsubsubsec(void)76529619d2aSchristos cm_unnumberedsubsubsec (void)
76629619d2aSchristos {
76729619d2aSchristos   sectioning_underscore ("unnumberedsubsubsec");
76829619d2aSchristos }
76929619d2aSchristos 
77029619d2aSchristos /* The remainder of the text on this line is an appendix heading. */
77129619d2aSchristos void
cm_appendix(void)77229619d2aSchristos cm_appendix (void)
77329619d2aSchristos {
77429619d2aSchristos   /* Reset top level number so we start from Appendix A */
77529619d2aSchristos   if (enum_marker != APPENDIX_MAGIC)
77629619d2aSchristos     numbers [0] = 0;
77729619d2aSchristos   enum_marker = APPENDIX_MAGIC;
77829619d2aSchristos   sectioning_underscore ("appendix");
77929619d2aSchristos }
78029619d2aSchristos 
78129619d2aSchristos /* The remainder of the text on this line is an appendix section heading. */
78229619d2aSchristos void
cm_appendixsec(void)78329619d2aSchristos cm_appendixsec (void)
78429619d2aSchristos {
78529619d2aSchristos   sectioning_underscore ("appendixsec");
78629619d2aSchristos }
78729619d2aSchristos 
78829619d2aSchristos /* The remainder of the text on this line is an appendix subsection heading. */
78929619d2aSchristos void
cm_appendixsubsec(void)79029619d2aSchristos cm_appendixsubsec (void)
79129619d2aSchristos {
79229619d2aSchristos   sectioning_underscore ("appendixsubsec");
79329619d2aSchristos }
79429619d2aSchristos 
79529619d2aSchristos /* The remainder of the text on this line is an appendix
79629619d2aSchristos    subsubsection heading. */
79729619d2aSchristos void
cm_appendixsubsubsec(void)79829619d2aSchristos cm_appendixsubsubsec (void)
79929619d2aSchristos {
80029619d2aSchristos   sectioning_underscore ("appendixsubsubsec");
80129619d2aSchristos }
80229619d2aSchristos 
80329619d2aSchristos /* Compatibility functions substitute for chapter, section, etc. */
80429619d2aSchristos void
cm_majorheading(void)80529619d2aSchristos cm_majorheading (void)
80629619d2aSchristos {
80729619d2aSchristos   sectioning_underscore ("majorheading");
80829619d2aSchristos }
80929619d2aSchristos 
81029619d2aSchristos void
cm_chapheading(void)81129619d2aSchristos cm_chapheading (void)
81229619d2aSchristos {
81329619d2aSchristos   sectioning_underscore ("chapheading");
81429619d2aSchristos }
81529619d2aSchristos 
81629619d2aSchristos void
cm_heading(void)81729619d2aSchristos cm_heading (void)
81829619d2aSchristos {
81929619d2aSchristos   sectioning_underscore ("heading");
82029619d2aSchristos }
82129619d2aSchristos 
82229619d2aSchristos void
cm_subheading(void)82329619d2aSchristos cm_subheading (void)
82429619d2aSchristos {
82529619d2aSchristos   sectioning_underscore ("subheading");
82629619d2aSchristos }
82729619d2aSchristos 
82829619d2aSchristos void
cm_subsubheading(void)82929619d2aSchristos cm_subsubheading (void)
83029619d2aSchristos {
83129619d2aSchristos   sectioning_underscore ("subsubheading");
83229619d2aSchristos }
833