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