| 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 | }
|
|---|