| 1 | /* sectioning.c -- for @chapter, @section, ..., @contents ... | 
|---|
| 2 | $Id: sectioning.c,v 1.25 2004/07/05 22:23:23 karl Exp $ | 
|---|
| 3 |  | 
|---|
| 4 | Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. | 
|---|
| 5 |  | 
|---|
| 6 | This program is free software; you can redistribute it and/or modify | 
|---|
| 7 | it under the terms of the GNU General Public License as published by | 
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 9 | any later version. | 
|---|
| 10 |  | 
|---|
| 11 | This program is distributed in the hope that it will be useful, | 
|---|
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 14 | GNU General Public License for more details. | 
|---|
| 15 |  | 
|---|
| 16 | You should have received a copy of the GNU General Public License | 
|---|
| 17 | along with this program; if not, write to the Free Software | 
|---|
| 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 
|---|
| 19 |  | 
|---|
| 20 | Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>.  */ | 
|---|
| 21 |  | 
|---|
| 22 | #include "system.h" | 
|---|
| 23 | #include "cmds.h" | 
|---|
| 24 | #include "macro.h" | 
|---|
| 25 | #include "makeinfo.h" | 
|---|
| 26 | #include "node.h" | 
|---|
| 27 | #include "toc.h" | 
|---|
| 28 | #include "sectioning.h" | 
|---|
| 29 | #include "xml.h" | 
|---|
| 30 |  | 
|---|
| 31 | /* See comment in sectioning.h.  */ | 
|---|
| 32 | section_alist_type section_alist[] = { | 
|---|
| 33 | { "unnumberedsubsubsec", 5, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 34 | { "unnumberedsubsec",    4, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 35 | { "unnumberedsec",       3, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 36 | { "unnumbered",          2, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 37 | { "centerchap",          2, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 38 |  | 
|---|
| 39 | { "appendixsubsubsec",   5, ENUM_SECT_APP, TOC_YES },  /* numbered like A.X.X.X */ | 
|---|
| 40 | { "appendixsubsec",      4, ENUM_SECT_APP, TOC_YES }, | 
|---|
| 41 | { "appendixsec",         3, ENUM_SECT_APP, TOC_YES }, | 
|---|
| 42 | { "appendixsection",     3, ENUM_SECT_APP, TOC_YES }, | 
|---|
| 43 | { "appendix",            2, ENUM_SECT_APP, TOC_YES }, | 
|---|
| 44 |  | 
|---|
| 45 | { "subsubsec",           5, ENUM_SECT_YES, TOC_YES }, | 
|---|
| 46 | { "subsubsection",       5, ENUM_SECT_YES, TOC_YES }, | 
|---|
| 47 | { "subsection",          4, ENUM_SECT_YES, TOC_YES }, | 
|---|
| 48 | { "section",             3, ENUM_SECT_YES, TOC_YES }, | 
|---|
| 49 | { "chapter",             2, ENUM_SECT_YES, TOC_YES }, | 
|---|
| 50 |  | 
|---|
| 51 | { "subsubheading",       5, ENUM_SECT_NO,  TOC_NO }, | 
|---|
| 52 | { "subheading",          4, ENUM_SECT_NO,  TOC_NO }, | 
|---|
| 53 | { "heading",             3, ENUM_SECT_NO,  TOC_NO }, | 
|---|
| 54 | { "chapheading",         2, ENUM_SECT_NO,  TOC_NO }, | 
|---|
| 55 | { "majorheading",        2, ENUM_SECT_NO,  TOC_NO }, | 
|---|
| 56 |  | 
|---|
| 57 | { "top",                 1, ENUM_SECT_NO,  TOC_YES }, | 
|---|
| 58 | { NULL,                  0, 0, 0 } | 
|---|
| 59 | }; | 
|---|
| 60 |  | 
|---|
| 61 |  | 
|---|
| 62 | /* The argument of @settitle, used for HTML. */ | 
|---|
| 63 | char *title = NULL; | 
|---|
| 64 |  | 
|---|
| 65 |  | 
|---|
| 66 | #define APPENDIX_MAGIC   1024 | 
|---|
| 67 | #define UNNUMBERED_MAGIC 2048 | 
|---|
| 68 |  | 
|---|
| 69 | /* Number memory for every level @chapter, @section, | 
|---|
| 70 | @subsection, @subsubsection. */ | 
|---|
| 71 | static int numbers [] = { 0, 0, 0, 0 }; | 
|---|
| 72 |  | 
|---|
| 73 | /* enum_marker == APPENDIX_MAGIC then we are counting appendencies | 
|---|
| 74 | enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area. | 
|---|
| 75 | Handling situations like this: | 
|---|
| 76 | @unnumbered .. | 
|---|
| 77 | @section ...   */ | 
|---|
| 78 | static int enum_marker = 0; | 
|---|
| 79 |  | 
|---|
| 80 | /* Organized by level commands.  That is, "*" == chapter, "=" == section. */ | 
|---|
| 81 | static char *scoring_characters = "*=-."; | 
|---|
| 82 |  | 
|---|
| 83 | /* Amount to offset the name of sectioning commands to levels by. */ | 
|---|
| 84 | static int section_alist_offset = 0; | 
|---|
| 85 |  | 
|---|
| 86 | /* These two variables are for @float, @cindex like commands that need to know | 
|---|
| 87 | in which section they are used.  */ | 
|---|
| 88 | /* Last value returned by get_sectioning_number.  */ | 
|---|
| 89 | static char *last_sectioning_number = ""; | 
|---|
| 90 | /* Last title used by sectioning_underscore, etc.  */ | 
|---|
| 91 | static char *last_sectioning_title = ""; | 
|---|
| 92 |  | 
|---|
| 93 |  | 
|---|
| 94 | /* num == ENUM_SECT_NO  means unnumbered (should never call this) | 
|---|
| 95 | num == ENUM_SECT_YES means numbered | 
|---|
| 96 | num == ENUM_SECT_APP means numbered like A.1 and so on */ | 
|---|
| 97 | static char * | 
|---|
| 98 | get_sectioning_number (int level, int num) | 
|---|
| 99 | { | 
|---|
| 100 | static char s[100]; /* should ever be enough for 99.99.99.99 | 
|---|
| 101 | Appendix A.1 */ | 
|---|
| 102 |  | 
|---|
| 103 | char *p; | 
|---|
| 104 | int i; | 
|---|
| 105 |  | 
|---|
| 106 | s[0] = 0; | 
|---|
| 107 |  | 
|---|
| 108 | /* create enumeration in front of chapter, section, subsection and so on. */ | 
|---|
| 109 | for (i = 0; i < level; i++) | 
|---|
| 110 | { | 
|---|
| 111 | p = s + strlen (s); | 
|---|
| 112 | if ((i == 0) && (enum_marker == APPENDIX_MAGIC)) | 
|---|
| 113 | sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to | 
|---|
| 114 | be more portable */ | 
|---|
| 115 | else | 
|---|
| 116 | sprintf (p, "%d.", numbers[i]); | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | /* the last number is never followed by a dot */ | 
|---|
| 120 | p = s + strlen (s); | 
|---|
| 121 | if ((num == ENUM_SECT_APP) | 
|---|
| 122 | && (i == 0) | 
|---|
| 123 | && (enum_marker == APPENDIX_MAGIC)) | 
|---|
| 124 | sprintf (p, _("Appendix %c"), numbers[i] + 64); | 
|---|
| 125 | else | 
|---|
| 126 | sprintf (p, "%d", numbers[i]); | 
|---|
| 127 |  | 
|---|
| 128 | /* Poor man's cache :-)  */ | 
|---|
| 129 | if (strlen (last_sectioning_number)) | 
|---|
| 130 | free (last_sectioning_number); | 
|---|
| 131 | last_sectioning_number = xstrdup (s); | 
|---|
| 132 |  | 
|---|
| 133 | return s; | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 |  | 
|---|
| 137 | /* Set the level of @top to LEVEL.  Return the old level of @top. */ | 
|---|
| 138 | int | 
|---|
| 139 | set_top_section_level (int level) | 
|---|
| 140 | { | 
|---|
| 141 | int i, result = -1; | 
|---|
| 142 |  | 
|---|
| 143 | for (i = 0; section_alist[i].name; i++) | 
|---|
| 144 | if (strcmp (section_alist[i].name, "top") == 0) | 
|---|
| 145 | { | 
|---|
| 146 | result = section_alist[i].level; | 
|---|
| 147 | section_alist[i].level = level; | 
|---|
| 148 | break; | 
|---|
| 149 | } | 
|---|
| 150 | return result; | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 |  | 
|---|
| 154 | /* return the index of the given sectioning command in section_alist */ | 
|---|
| 155 | static int | 
|---|
| 156 | search_sectioning (char *text) | 
|---|
| 157 | { | 
|---|
| 158 | int i; | 
|---|
| 159 | char *t; | 
|---|
| 160 |  | 
|---|
| 161 | /* ignore the optional command prefix */ | 
|---|
| 162 | if (text[0] == COMMAND_PREFIX) | 
|---|
| 163 | text++; | 
|---|
| 164 |  | 
|---|
| 165 | for (i = 0; (t = section_alist[i].name); i++) | 
|---|
| 166 | { | 
|---|
| 167 | if (strcmp (t, text) == 0) | 
|---|
| 168 | { | 
|---|
| 169 | return i; | 
|---|
| 170 | } | 
|---|
| 171 | } | 
|---|
| 172 | return -1; | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | /* Return an integer which identifies the type of section present in | 
|---|
| 176 | TEXT -- 1 for @top, 2 for chapters, ..., 5 for subsubsections (as | 
|---|
| 177 | specified in section_alist).  We take into account any @lowersections | 
|---|
| 178 | and @raisesections.  If SECNAME is non-NULL, also return the | 
|---|
| 179 | corresponding section name.  */ | 
|---|
| 180 | int | 
|---|
| 181 | what_section (char *text, char **secname) | 
|---|
| 182 | { | 
|---|
| 183 | int index, j; | 
|---|
| 184 | char *temp; | 
|---|
| 185 | int return_val; | 
|---|
| 186 |  | 
|---|
| 187 | find_section_command: | 
|---|
| 188 | for (j = 0; text[j] && cr_or_whitespace (text[j]); j++); | 
|---|
| 189 | if (text[j] != COMMAND_PREFIX) | 
|---|
| 190 | return -1; | 
|---|
| 191 |  | 
|---|
| 192 | text = text + j + 1; | 
|---|
| 193 |  | 
|---|
| 194 | /* We skip @c, @comment, and @?index commands. */ | 
|---|
| 195 | if ((strncmp (text, "comment", strlen ("comment")) == 0) || | 
|---|
| 196 | (text[0] == 'c' && cr_or_whitespace (text[1])) || | 
|---|
| 197 | (strcmp (text + 1, "index") == 0)) | 
|---|
| 198 | { | 
|---|
| 199 | while (*text++ != '\n'); | 
|---|
| 200 | goto find_section_command; | 
|---|
| 201 | } | 
|---|
| 202 |  | 
|---|
| 203 | /* Handle italicized sectioning commands. */ | 
|---|
| 204 | if (*text == 'i') | 
|---|
| 205 | text++; | 
|---|
| 206 |  | 
|---|
| 207 | for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++); | 
|---|
| 208 |  | 
|---|
| 209 | temp = xmalloc (1 + j); | 
|---|
| 210 | strncpy (temp, text, j); | 
|---|
| 211 | temp[j] = 0; | 
|---|
| 212 |  | 
|---|
| 213 | index = search_sectioning (temp); | 
|---|
| 214 | free (temp); | 
|---|
| 215 | if (index >= 0) | 
|---|
| 216 | { | 
|---|
| 217 | return_val = section_alist[index].level + section_alist_offset; | 
|---|
| 218 | if (return_val < 0) | 
|---|
| 219 | return_val = 0; | 
|---|
| 220 | else if (return_val > 5) | 
|---|
| 221 | return_val = 5; | 
|---|
| 222 |  | 
|---|
| 223 | if (secname) | 
|---|
| 224 | { | 
|---|
| 225 | int i; | 
|---|
| 226 | int alist_size = sizeof (section_alist) / sizeof(section_alist_type); | 
|---|
| 227 | /* Find location of offset sectioning entry, but don't go off | 
|---|
| 228 | either end of the array.  */ | 
|---|
| 229 | int index_offset = MAX (index - section_alist_offset, 0); | 
|---|
| 230 | index_offset = MIN (index_offset, alist_size - 1); | 
|---|
| 231 |  | 
|---|
| 232 | /* Also make sure we don't go into the next "group" of | 
|---|
| 233 | sectioning changes, e.g., change from an @appendix to an | 
|---|
| 234 | @heading or some such.  */ | 
|---|
| 235 | #define SIGN(expr) ((expr) < 0 ? -1 : 1) | 
|---|
| 236 | for (i = index; i != index_offset; i -= SIGN (section_alist_offset)) | 
|---|
| 237 | { | 
|---|
| 238 | /* As it happens, each group has unique .num/.toc values.  */ | 
|---|
| 239 | if (section_alist[i].num != section_alist[index_offset].num | 
|---|
| 240 | || section_alist[i].toc != section_alist[index_offset].toc) | 
|---|
| 241 | break; | 
|---|
| 242 | } | 
|---|
| 243 | *secname = section_alist[i].name; | 
|---|
| 244 | } | 
|---|
| 245 | return return_val; | 
|---|
| 246 | } | 
|---|
| 247 | return -1; | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | /* Returns current top level division (ie. chapter, unnumbered) number. | 
|---|
| 251 | - For chapters, returns the number. | 
|---|
| 252 | - For unnumbered sections, returns empty string. | 
|---|
| 253 | - For appendices, returns A, B, etc. */ | 
|---|
| 254 | char * | 
|---|
| 255 | current_chapter_number (void) | 
|---|
| 256 | { | 
|---|
| 257 | if (enum_marker == UNNUMBERED_MAGIC) | 
|---|
| 258 | return xstrdup (""); | 
|---|
| 259 | else if (enum_marker == APPENDIX_MAGIC) | 
|---|
| 260 | { | 
|---|
| 261 | char s[1]; | 
|---|
| 262 | sprintf (s, "%c", numbers[0] + 64); | 
|---|
| 263 | return xstrdup (s); | 
|---|
| 264 | } | 
|---|
| 265 | else | 
|---|
| 266 | { | 
|---|
| 267 | char s[5]; | 
|---|
| 268 | sprintf (s, "%d", numbers[0]); | 
|---|
| 269 | return xstrdup (s); | 
|---|
| 270 | } | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 | /* Returns number of the last sectioning command used.  */ | 
|---|
| 274 | char * | 
|---|
| 275 | current_sectioning_number (void) | 
|---|
| 276 | { | 
|---|
| 277 | if (enum_marker == UNNUMBERED_MAGIC || !number_sections) | 
|---|
| 278 | return xstrdup (""); | 
|---|
| 279 | else | 
|---|
| 280 | return xstrdup (last_sectioning_number); | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | /* Returns arguments of the last sectioning command used.  */ | 
|---|
| 284 | char * | 
|---|
| 285 | current_sectioning_name (void) | 
|---|
| 286 | { | 
|---|
| 287 | return xstrdup (last_sectioning_title); | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | /* insert_and_underscore, sectioning_underscore and sectioning_html call this.  */ | 
|---|
| 291 |  | 
|---|
| 292 | static char * | 
|---|
| 293 | handle_enum_increment (int level, int index) | 
|---|
| 294 | { | 
|---|
| 295 | /* Here is how TeX handles enumeration: | 
|---|
| 296 | - Anything starting with @unnumbered is not enumerated. | 
|---|
| 297 | - @majorheading and the like are not enumberated.  */ | 
|---|
| 298 | int i; | 
|---|
| 299 |  | 
|---|
| 300 | /* First constraint above.  */ | 
|---|
| 301 | if (enum_marker == UNNUMBERED_MAGIC && level == 0) | 
|---|
| 302 | return xstrdup (""); | 
|---|
| 303 |  | 
|---|
| 304 | /* Second constraint.  */ | 
|---|
| 305 | if (section_alist[index].num == ENUM_SECT_NO) | 
|---|
| 306 | return xstrdup (""); | 
|---|
| 307 |  | 
|---|
| 308 | /* reset all counters which are one level deeper */ | 
|---|
| 309 | for (i = level; i < 3; i++) | 
|---|
| 310 | numbers [i + 1] = 0; | 
|---|
| 311 |  | 
|---|
| 312 | numbers[level]++; | 
|---|
| 313 | if (section_alist[index].num == ENUM_SECT_NO || enum_marker == UNNUMBERED_MAGIC | 
|---|
| 314 | || !number_sections) | 
|---|
| 315 | return xstrdup (""); | 
|---|
| 316 | else | 
|---|
| 317 | return xstrdup (get_sectioning_number (level, section_alist[index].num)); | 
|---|
| 318 | } | 
|---|
| 319 |  | 
|---|
| 320 |  | 
|---|
| 321 | void | 
|---|
| 322 | sectioning_underscore (char *cmd) | 
|---|
| 323 | { | 
|---|
| 324 | char *temp, *secname; | 
|---|
| 325 | int level; | 
|---|
| 326 |  | 
|---|
| 327 | /* If we're not indenting the first paragraph, we shall make it behave | 
|---|
| 328 | like @noindent is called directly after the section heading. */ | 
|---|
| 329 | if (! do_first_par_indent) | 
|---|
| 330 | cm_noindent (); | 
|---|
| 331 |  | 
|---|
| 332 | temp = xmalloc (2 + strlen (cmd)); | 
|---|
| 333 | temp[0] = COMMAND_PREFIX; | 
|---|
| 334 | strcpy (&temp[1], cmd); | 
|---|
| 335 | level = what_section (temp, &secname); | 
|---|
| 336 | level -= 2; | 
|---|
| 337 | if (level < 0) | 
|---|
| 338 | level = 0; | 
|---|
| 339 | free (temp); | 
|---|
| 340 |  | 
|---|
| 341 | /* If the argument to @top is empty, we try using the one from @settitle. | 
|---|
| 342 | Warn if both are unusable.  */ | 
|---|
| 343 | if (STREQ (command, "top")) | 
|---|
| 344 | { | 
|---|
| 345 | int save_input_text_offset = input_text_offset; | 
|---|
| 346 |  | 
|---|
| 347 | get_rest_of_line (0, &temp); | 
|---|
| 348 |  | 
|---|
| 349 | /* Due to get_rest_of_line ... */ | 
|---|
| 350 | line_number--; | 
|---|
| 351 |  | 
|---|
| 352 | if (strlen (temp) == 0 && (!title || strlen (title) == 0)) | 
|---|
| 353 | warning ("Must specify a title with least one of @settitle or @top"); | 
|---|
| 354 |  | 
|---|
| 355 | input_text_offset = save_input_text_offset; | 
|---|
| 356 | } | 
|---|
| 357 |  | 
|---|
| 358 | if (xml) | 
|---|
| 359 | { | 
|---|
| 360 | /* If the section appears in the toc, it means it's a real section | 
|---|
| 361 | unlike majorheading, chapheading etc. */ | 
|---|
| 362 | if (section_alist[search_sectioning (cmd)].toc == TOC_YES) | 
|---|
| 363 | { | 
|---|
| 364 | xml_close_sections (level); | 
|---|
| 365 | /* Mark the beginning of the section | 
|---|
| 366 | If the next command is printindex, we will remove | 
|---|
| 367 | the section and put an Index instead */ | 
|---|
| 368 | flush_output (); | 
|---|
| 369 | xml_last_section_output_position = output_paragraph_offset; | 
|---|
| 370 |  | 
|---|
| 371 | get_rest_of_line (0, &temp); | 
|---|
| 372 |  | 
|---|
| 373 | /* Use @settitle value if @top parameter is empty.  */ | 
|---|
| 374 | if (STREQ (command, "top") && strlen(temp) == 0) | 
|---|
| 375 | temp = xstrdup (title ? title : ""); | 
|---|
| 376 |  | 
|---|
| 377 | /* Docbook does not support @unnumbered at all.  So we provide numbers | 
|---|
| 378 | that other formats use.  @appendix seems to be fine though, so we let | 
|---|
| 379 | Docbook handle that as usual.  */ | 
|---|
| 380 | if (docbook && enum_marker != APPENDIX_MAGIC) | 
|---|
| 381 | { | 
|---|
| 382 | if (section_alist[search_sectioning (cmd)].num == ENUM_SECT_NO | 
|---|
| 383 | && section_alist[search_sectioning (cmd)].toc == TOC_YES) | 
|---|
| 384 | xml_insert_element_with_attribute (xml_element (secname), | 
|---|
| 385 | START, "label=\"%s\" xreflabel=\"%s\"", | 
|---|
| 386 | handle_enum_increment (level, search_sectioning (cmd)), | 
|---|
| 387 | text_expansion (temp)); | 
|---|
| 388 | else | 
|---|
| 389 | xml_insert_element_with_attribute (xml_element (secname), | 
|---|
| 390 | START, "label=\"%s\"", | 
|---|
| 391 | handle_enum_increment (level, search_sectioning (cmd))); | 
|---|
| 392 | } | 
|---|
| 393 | else | 
|---|
| 394 | xml_insert_element (xml_element (secname), START); | 
|---|
| 395 |  | 
|---|
| 396 | xml_insert_element (TITLE, START); | 
|---|
| 397 | xml_open_section (level, secname); | 
|---|
| 398 | execute_string ("%s", temp); | 
|---|
| 399 | xml_insert_element (TITLE, END); | 
|---|
| 400 |  | 
|---|
| 401 | free (temp); | 
|---|
| 402 | } | 
|---|
| 403 | else | 
|---|
| 404 | { | 
|---|
| 405 | if (docbook) | 
|---|
| 406 | { | 
|---|
| 407 | if (level > 0) | 
|---|
| 408 | xml_insert_element_with_attribute (xml_element (secname), START, | 
|---|
| 409 | "renderas=\"sect%d\"", level); | 
|---|
| 410 | else | 
|---|
| 411 | xml_insert_element_with_attribute (xml_element (secname), START, | 
|---|
| 412 | "renderas=\"other\""); | 
|---|
| 413 | } | 
|---|
| 414 | else | 
|---|
| 415 | xml_insert_element (xml_element (secname), START); | 
|---|
| 416 |  | 
|---|
| 417 | get_rest_of_line (0, &temp); | 
|---|
| 418 | execute_string ("%s", temp); | 
|---|
| 419 | free (temp); | 
|---|
| 420 |  | 
|---|
| 421 | xml_insert_element (xml_element (secname), END); | 
|---|
| 422 | } | 
|---|
| 423 | } | 
|---|
| 424 | else if (html) | 
|---|
| 425 | sectioning_html (level, secname); | 
|---|
| 426 | else | 
|---|
| 427 | insert_and_underscore (level, secname); | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 |  | 
|---|
| 431 | /* Insert the text following input_text_offset up to the end of the line | 
|---|
| 432 | in a new, separate paragraph.  Directly underneath it, insert a | 
|---|
| 433 | line of WITH_CHAR, the same length of the inserted text. */ | 
|---|
| 434 | void | 
|---|
| 435 | insert_and_underscore (int level, char *cmd) | 
|---|
| 436 | { | 
|---|
| 437 | int i, len; | 
|---|
| 438 | int index; | 
|---|
| 439 | int old_no_indent; | 
|---|
| 440 | unsigned char *starting_pos, *ending_pos; | 
|---|
| 441 | char *temp; | 
|---|
| 442 | char with_char = scoring_characters[level]; | 
|---|
| 443 |  | 
|---|
| 444 | close_paragraph (); | 
|---|
| 445 | filling_enabled =  indented_fill = 0; | 
|---|
| 446 | old_no_indent = no_indent; | 
|---|
| 447 | no_indent = 1; | 
|---|
| 448 |  | 
|---|
| 449 | if (macro_expansion_output_stream && !executing_string) | 
|---|
| 450 | append_to_expansion_output (input_text_offset + 1); | 
|---|
| 451 |  | 
|---|
| 452 | get_rest_of_line (0, &temp); | 
|---|
| 453 |  | 
|---|
| 454 | /* Use @settitle value if @top parameter is empty.  */ | 
|---|
| 455 | if (STREQ (command, "top") && strlen(temp) == 0) | 
|---|
| 456 | temp = xstrdup (title ? title : ""); | 
|---|
| 457 |  | 
|---|
| 458 | starting_pos = output_paragraph + output_paragraph_offset; | 
|---|
| 459 |  | 
|---|
| 460 | /* Poor man's cache for section title.  */ | 
|---|
| 461 | if (strlen (last_sectioning_title)) | 
|---|
| 462 | free (last_sectioning_title); | 
|---|
| 463 | last_sectioning_title = xstrdup (temp); | 
|---|
| 464 |  | 
|---|
| 465 | index = search_sectioning (cmd); | 
|---|
| 466 | if (index < 0) | 
|---|
| 467 | { | 
|---|
| 468 | /* should never happen, but a poor guy, named Murphy ... */ | 
|---|
| 469 | warning (_("Internal error (search_sectioning) `%s'!"), cmd); | 
|---|
| 470 | return; | 
|---|
| 471 | } | 
|---|
| 472 |  | 
|---|
| 473 | /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the | 
|---|
| 474 | Info output and in TOC, but only SECTION-NAME in the macro-expanded | 
|---|
| 475 | output.  */ | 
|---|
| 476 |  | 
|---|
| 477 | /* Step 1: produce "X.Y" and add it to Info output.  */ | 
|---|
| 478 | add_word_args ("%s ", handle_enum_increment (level, index)); | 
|---|
| 479 |  | 
|---|
| 480 | /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output.  */ | 
|---|
| 481 | if (macro_expansion_output_stream && !executing_string) | 
|---|
| 482 | { | 
|---|
| 483 | char *temp1 = xmalloc (2 + strlen (temp)); | 
|---|
| 484 | sprintf (temp1, "%s\n", temp); | 
|---|
| 485 | remember_itext (input_text, input_text_offset); | 
|---|
| 486 | me_execute_string (temp1); | 
|---|
| 487 | free (temp1); | 
|---|
| 488 | } | 
|---|
| 489 | else | 
|---|
| 490 | execute_string ("%s\n", temp); | 
|---|
| 491 |  | 
|---|
| 492 | /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and | 
|---|
| 493 | insert it into the TOC.  */ | 
|---|
| 494 | ending_pos = output_paragraph + output_paragraph_offset; | 
|---|
| 495 | if (section_alist[index].toc == TOC_YES) | 
|---|
| 496 | toc_add_entry (substring (starting_pos, ending_pos - 1), | 
|---|
| 497 | level, current_node, NULL); | 
|---|
| 498 |  | 
|---|
| 499 | free (temp); | 
|---|
| 500 |  | 
|---|
| 501 | len = (ending_pos - starting_pos) - 1; | 
|---|
| 502 | for (i = 0; i < len; i++) | 
|---|
| 503 | add_char (with_char); | 
|---|
| 504 | insert ('\n'); | 
|---|
| 505 | close_paragraph (); | 
|---|
| 506 | filling_enabled = 1; | 
|---|
| 507 | no_indent = old_no_indent; | 
|---|
| 508 | } | 
|---|
| 509 |  | 
|---|
| 510 | /* Insert the text following input_text_offset up to the end of the | 
|---|
| 511 | line as an HTML heading element of the appropriate `level' and | 
|---|
| 512 | tagged as an anchor for the current node.. */ | 
|---|
| 513 |  | 
|---|
| 514 | void | 
|---|
| 515 | sectioning_html (int level, char *cmd) | 
|---|
| 516 | { | 
|---|
| 517 | static int toc_ref_count = 0; | 
|---|
| 518 | int index; | 
|---|
| 519 | int old_no_indent; | 
|---|
| 520 | unsigned char *starting_pos, *ending_pos; | 
|---|
| 521 | char *temp, *toc_anchor = NULL; | 
|---|
| 522 |  | 
|---|
| 523 | close_paragraph (); | 
|---|
| 524 | filling_enabled =  indented_fill = 0; | 
|---|
| 525 | old_no_indent = no_indent; | 
|---|
| 526 | no_indent = 1; | 
|---|
| 527 |  | 
|---|
| 528 | /* level 0 (chapter) is <h2>, and we go down from there.  */ | 
|---|
| 529 | add_html_block_elt_args ("<h%d class=\"%s\">", level + 2, cmd); | 
|---|
| 530 |  | 
|---|
| 531 | /* If we are outside of any node, produce an anchor that | 
|---|
| 532 | the TOC could refer to.  */ | 
|---|
| 533 | if (!current_node || !*current_node) | 
|---|
| 534 | { | 
|---|
| 535 | static const char a_name[] = "<a name=\""; | 
|---|
| 536 |  | 
|---|
| 537 | starting_pos = output_paragraph + output_paragraph_offset; | 
|---|
| 538 | add_word_args ("%sTOC%d\">", a_name, toc_ref_count++); | 
|---|
| 539 | toc_anchor = substring (starting_pos + sizeof (a_name) - 1, | 
|---|
| 540 | output_paragraph + output_paragraph_offset); | 
|---|
| 541 | /* This must be added after toc_anchor is extracted, since | 
|---|
| 542 | toc_anchor cannot include the closing </a>.  For details, | 
|---|
| 543 | see toc.c:toc_add_entry and toc.c:contents_update_html. | 
|---|
| 544 |  | 
|---|
| 545 | Also, the anchor close must be output before the section name | 
|---|
| 546 | in case the name itself contains an anchor. */ | 
|---|
| 547 | add_word ("</a>"); | 
|---|
| 548 | } | 
|---|
| 549 | starting_pos = output_paragraph + output_paragraph_offset; | 
|---|
| 550 |  | 
|---|
| 551 | if (macro_expansion_output_stream && !executing_string) | 
|---|
| 552 | append_to_expansion_output (input_text_offset + 1); | 
|---|
| 553 |  | 
|---|
| 554 | get_rest_of_line (0, &temp); | 
|---|
| 555 |  | 
|---|
| 556 | /* Use @settitle value if @top parameter is empty.  */ | 
|---|
| 557 | if (STREQ (command, "top") && strlen(temp) == 0) | 
|---|
| 558 | temp = xstrdup (title ? title : ""); | 
|---|
| 559 |  | 
|---|
| 560 | index = search_sectioning (cmd); | 
|---|
| 561 | if (index < 0) | 
|---|
| 562 | { | 
|---|
| 563 | /* should never happen, but a poor guy, named Murphy ... */ | 
|---|
| 564 | warning (_("Internal error (search_sectioning) \"%s\"!"), cmd); | 
|---|
| 565 | return; | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | /* Produce "X.Y" and add it to HTML output.  */ | 
|---|
| 569 | { | 
|---|
| 570 | char *title_number = handle_enum_increment (level, index); | 
|---|
| 571 | if (strlen (title_number) > 0) | 
|---|
| 572 | add_word_args ("%s ", title_number); | 
|---|
| 573 | } | 
|---|
| 574 |  | 
|---|
| 575 | /* add the section name to both HTML and macro-expanded output.  */ | 
|---|
| 576 | if (macro_expansion_output_stream && !executing_string) | 
|---|
| 577 | { | 
|---|
| 578 | remember_itext (input_text, input_text_offset); | 
|---|
| 579 | me_execute_string (temp); | 
|---|
| 580 | write_region_to_macro_output ("\n", 0, 1); | 
|---|
| 581 | } | 
|---|
| 582 | else | 
|---|
| 583 | execute_string ("%s", temp); | 
|---|
| 584 |  | 
|---|
| 585 | ending_pos = output_paragraph + output_paragraph_offset; | 
|---|
| 586 |  | 
|---|
| 587 | /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it | 
|---|
| 588 | into the TOC.  */ | 
|---|
| 589 | if (section_alist[index].toc == TOC_YES) | 
|---|
| 590 | toc_add_entry (substring (starting_pos, ending_pos), | 
|---|
| 591 | level, current_node, toc_anchor); | 
|---|
| 592 |  | 
|---|
| 593 | free (temp); | 
|---|
| 594 |  | 
|---|
| 595 | if (outstanding_node) | 
|---|
| 596 | outstanding_node = 0; | 
|---|
| 597 |  | 
|---|
| 598 | add_word_args ("</h%d>", level + 2); | 
|---|
| 599 | close_paragraph(); | 
|---|
| 600 | filling_enabled = 1; | 
|---|
| 601 | no_indent = old_no_indent; | 
|---|
| 602 | } | 
|---|
| 603 |  | 
|---|
| 604 |  | 
|---|
| 605 |  | 
|---|
| 606 | /* Shift the meaning of @section to @chapter. */ | 
|---|
| 607 | void | 
|---|
| 608 | cm_raisesections (void) | 
|---|
| 609 | { | 
|---|
| 610 | discard_until ("\n"); | 
|---|
| 611 | section_alist_offset--; | 
|---|
| 612 | } | 
|---|
| 613 |  | 
|---|
| 614 | /* Shift the meaning of @chapter to @section. */ | 
|---|
| 615 | void | 
|---|
| 616 | cm_lowersections (void) | 
|---|
| 617 | { | 
|---|
| 618 | discard_until ("\n"); | 
|---|
| 619 | section_alist_offset++; | 
|---|
| 620 | } | 
|---|
| 621 |  | 
|---|
| 622 | /* The command still works, but prints a warning message in addition. */ | 
|---|
| 623 | void | 
|---|
| 624 | cm_ideprecated (int arg, int start, int end) | 
|---|
| 625 | { | 
|---|
| 626 | warning (_("%c%s is obsolete; use %c%s instead"), | 
|---|
| 627 | COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1); | 
|---|
| 628 | sectioning_underscore (command + 1); | 
|---|
| 629 | } | 
|---|
| 630 |  | 
|---|
| 631 |  | 
|---|
| 632 |  | 
|---|
| 633 | /* Treat this just like @unnumbered.  The only difference is | 
|---|
| 634 | in node defaulting. */ | 
|---|
| 635 | void | 
|---|
| 636 | cm_top (void) | 
|---|
| 637 | { | 
|---|
| 638 | /* It is an error to have more than one @top. */ | 
|---|
| 639 | if (top_node_seen && strcmp (current_node, "Top") != 0) | 
|---|
| 640 | { | 
|---|
| 641 | TAG_ENTRY *tag = tag_table; | 
|---|
| 642 |  | 
|---|
| 643 | line_error (_("Node with %ctop as a section already exists"), | 
|---|
| 644 | COMMAND_PREFIX); | 
|---|
| 645 |  | 
|---|
| 646 | while (tag) | 
|---|
| 647 | { | 
|---|
| 648 | if (tag->flags & TAG_FLAG_IS_TOP) | 
|---|
| 649 | { | 
|---|
| 650 | file_line_error (tag->filename, tag->line_no, | 
|---|
| 651 | _("Here is the %ctop node"), COMMAND_PREFIX); | 
|---|
| 652 | return; | 
|---|
| 653 | } | 
|---|
| 654 | tag = tag->next_ent; | 
|---|
| 655 | } | 
|---|
| 656 | } | 
|---|
| 657 | else | 
|---|
| 658 | { | 
|---|
| 659 | top_node_seen = 1; | 
|---|
| 660 |  | 
|---|
| 661 | /* It is an error to use @top before using @node. */ | 
|---|
| 662 | if (!tag_table) | 
|---|
| 663 | { | 
|---|
| 664 | char *top_name; | 
|---|
| 665 |  | 
|---|
| 666 | get_rest_of_line (0, &top_name); | 
|---|
| 667 | line_error (_("%ctop used before %cnode, defaulting to %s"), | 
|---|
| 668 | COMMAND_PREFIX, COMMAND_PREFIX, top_name); | 
|---|
| 669 | execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name); | 
|---|
| 670 | free (top_name); | 
|---|
| 671 | return; | 
|---|
| 672 | } | 
|---|
| 673 |  | 
|---|
| 674 | cm_unnumbered (); | 
|---|
| 675 |  | 
|---|
| 676 | /* The most recently defined node is the top node. */ | 
|---|
| 677 | tag_table->flags |= TAG_FLAG_IS_TOP; | 
|---|
| 678 |  | 
|---|
| 679 | /* Now set the logical hierarchical level of the Top node. */ | 
|---|
| 680 | { | 
|---|
| 681 | int orig_offset = input_text_offset; | 
|---|
| 682 |  | 
|---|
| 683 | input_text_offset = search_forward (node_search_string, orig_offset); | 
|---|
| 684 |  | 
|---|
| 685 | if (input_text_offset > 0) | 
|---|
| 686 | { | 
|---|
| 687 | int this_section; | 
|---|
| 688 |  | 
|---|
| 689 | /* We have encountered a non-top node, so mark that one exists. */ | 
|---|
| 690 | non_top_node_seen = 1; | 
|---|
| 691 |  | 
|---|
| 692 | /* Move to the end of this line, and find out what the | 
|---|
| 693 | sectioning command is here. */ | 
|---|
| 694 | while (input_text[input_text_offset] != '\n') | 
|---|
| 695 | input_text_offset++; | 
|---|
| 696 |  | 
|---|
| 697 | if (input_text_offset < input_text_length) | 
|---|
| 698 | input_text_offset++; | 
|---|
| 699 |  | 
|---|
| 700 | this_section = what_section (input_text + input_text_offset, | 
|---|
| 701 | NULL); | 
|---|
| 702 |  | 
|---|
| 703 | /* If we found a sectioning command, then give the top section | 
|---|
| 704 | a level of this section - 1. */ | 
|---|
| 705 | if (this_section != -1) | 
|---|
| 706 | set_top_section_level (this_section - 1); | 
|---|
| 707 | } | 
|---|
| 708 | input_text_offset = orig_offset; | 
|---|
| 709 | } | 
|---|
| 710 | } | 
|---|
| 711 | } | 
|---|
| 712 |  | 
|---|
| 713 | /* The remainder of the text on this line is a chapter heading. */ | 
|---|
| 714 | void | 
|---|
| 715 | cm_chapter (void) | 
|---|
| 716 | { | 
|---|
| 717 | enum_marker = 0; | 
|---|
| 718 | sectioning_underscore ("chapter"); | 
|---|
| 719 | } | 
|---|
| 720 |  | 
|---|
| 721 | /* The remainder of the text on this line is a section heading. */ | 
|---|
| 722 | void | 
|---|
| 723 | cm_section (void) | 
|---|
| 724 | { | 
|---|
| 725 | sectioning_underscore ("section"); | 
|---|
| 726 | } | 
|---|
| 727 |  | 
|---|
| 728 | /* The remainder of the text on this line is a subsection heading. */ | 
|---|
| 729 | void | 
|---|
| 730 | cm_subsection (void) | 
|---|
| 731 | { | 
|---|
| 732 | sectioning_underscore ("subsection"); | 
|---|
| 733 | } | 
|---|
| 734 |  | 
|---|
| 735 | /* The remainder of the text on this line is a subsubsection heading. */ | 
|---|
| 736 | void | 
|---|
| 737 | cm_subsubsection (void) | 
|---|
| 738 | { | 
|---|
| 739 | sectioning_underscore ("subsubsection"); | 
|---|
| 740 | } | 
|---|
| 741 |  | 
|---|
| 742 | /* The remainder of the text on this line is an unnumbered heading. */ | 
|---|
| 743 | void | 
|---|
| 744 | cm_unnumbered (void) | 
|---|
| 745 | { | 
|---|
| 746 | enum_marker = UNNUMBERED_MAGIC; | 
|---|
| 747 | sectioning_underscore ("unnumbered"); | 
|---|
| 748 | } | 
|---|
| 749 |  | 
|---|
| 750 | /* The remainder of the text on this line is an unnumbered section heading. */ | 
|---|
| 751 | void | 
|---|
| 752 | cm_unnumberedsec (void) | 
|---|
| 753 | { | 
|---|
| 754 | sectioning_underscore ("unnumberedsec"); | 
|---|
| 755 | } | 
|---|
| 756 |  | 
|---|
| 757 | /* The remainder of the text on this line is an unnumbered | 
|---|
| 758 | subsection heading. */ | 
|---|
| 759 | void | 
|---|
| 760 | cm_unnumberedsubsec (void) | 
|---|
| 761 | { | 
|---|
| 762 | sectioning_underscore ("unnumberedsubsec"); | 
|---|
| 763 | } | 
|---|
| 764 |  | 
|---|
| 765 | /* The remainder of the text on this line is an unnumbered | 
|---|
| 766 | subsubsection heading. */ | 
|---|
| 767 | void | 
|---|
| 768 | cm_unnumberedsubsubsec (void) | 
|---|
| 769 | { | 
|---|
| 770 | sectioning_underscore ("unnumberedsubsubsec"); | 
|---|
| 771 | } | 
|---|
| 772 |  | 
|---|
| 773 | /* The remainder of the text on this line is an appendix heading. */ | 
|---|
| 774 | void | 
|---|
| 775 | cm_appendix (void) | 
|---|
| 776 | { | 
|---|
| 777 | /* Reset top level number so we start from Appendix A */ | 
|---|
| 778 | if (enum_marker != APPENDIX_MAGIC) | 
|---|
| 779 | numbers [0] = 0; | 
|---|
| 780 | enum_marker = APPENDIX_MAGIC; | 
|---|
| 781 | sectioning_underscore ("appendix"); | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 | /* The remainder of the text on this line is an appendix section heading. */ | 
|---|
| 785 | void | 
|---|
| 786 | cm_appendixsec (void) | 
|---|
| 787 | { | 
|---|
| 788 | sectioning_underscore ("appendixsec"); | 
|---|
| 789 | } | 
|---|
| 790 |  | 
|---|
| 791 | /* The remainder of the text on this line is an appendix subsection heading. */ | 
|---|
| 792 | void | 
|---|
| 793 | cm_appendixsubsec (void) | 
|---|
| 794 | { | 
|---|
| 795 | sectioning_underscore ("appendixsubsec"); | 
|---|
| 796 | } | 
|---|
| 797 |  | 
|---|
| 798 | /* The remainder of the text on this line is an appendix | 
|---|
| 799 | subsubsection heading. */ | 
|---|
| 800 | void | 
|---|
| 801 | cm_appendixsubsubsec (void) | 
|---|
| 802 | { | 
|---|
| 803 | sectioning_underscore ("appendixsubsubsec"); | 
|---|
| 804 | } | 
|---|
| 805 |  | 
|---|
| 806 | /* Compatibility functions substitute for chapter, section, etc. */ | 
|---|
| 807 | void | 
|---|
| 808 | cm_majorheading (void) | 
|---|
| 809 | { | 
|---|
| 810 | sectioning_underscore ("majorheading"); | 
|---|
| 811 | } | 
|---|
| 812 |  | 
|---|
| 813 | void | 
|---|
| 814 | cm_chapheading (void) | 
|---|
| 815 | { | 
|---|
| 816 | sectioning_underscore ("chapheading"); | 
|---|
| 817 | } | 
|---|
| 818 |  | 
|---|
| 819 | void | 
|---|
| 820 | cm_heading (void) | 
|---|
| 821 | { | 
|---|
| 822 | sectioning_underscore ("heading"); | 
|---|
| 823 | } | 
|---|
| 824 |  | 
|---|
| 825 | void | 
|---|
| 826 | cm_subheading (void) | 
|---|
| 827 | { | 
|---|
| 828 | sectioning_underscore ("subheading"); | 
|---|
| 829 | } | 
|---|
| 830 |  | 
|---|
| 831 | void | 
|---|
| 832 | cm_subsubheading (void) | 
|---|
| 833 | { | 
|---|
| 834 | sectioning_underscore ("subsubheading"); | 
|---|
| 835 | } | 
|---|