sectioning.c revision 114472
1/* sectioning.c -- for @chapter, @section, ..., @contents ... 2 $Id: sectioning.c,v 1.6 2002/11/08 02:21:07 karl Exp $ 3 4 Copyright (C) 1999, 2001, 2002 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. */ 32section_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 38 { "appendixsubsubsec", 5, ENUM_SECT_APP, TOC_YES }, /* numbered like A.X.X.X */ 39 { "appendixsubsec", 4, ENUM_SECT_APP, TOC_YES }, 40 { "appendixsec", 3, ENUM_SECT_APP, TOC_YES }, 41 { "appendixsection", 3, ENUM_SECT_APP, TOC_YES }, 42 { "appendix", 2, ENUM_SECT_APP, TOC_YES }, 43 44 { "subsubsec", 5, ENUM_SECT_YES, TOC_YES }, 45 { "subsubsection", 5, ENUM_SECT_YES, TOC_YES }, 46 { "subsection", 4, ENUM_SECT_YES, TOC_YES }, 47 { "section", 3, ENUM_SECT_YES, TOC_YES }, 48 { "chapter", 2, ENUM_SECT_YES, TOC_YES }, 49 50 { "subsubheading", 5, ENUM_SECT_NO, TOC_NO }, 51 { "subheading", 4, ENUM_SECT_NO, TOC_NO }, 52 { "heading", 3, ENUM_SECT_NO, TOC_NO }, 53 { "chapheading", 2, ENUM_SECT_NO, TOC_NO }, 54 { "majorheading", 2, ENUM_SECT_NO, TOC_NO }, 55 56 { "top", 1, ENUM_SECT_NO, TOC_YES }, 57 { NULL, 0, 0, 0 } 58}; 59 60/* The argument of @settitle, used for HTML. */ 61char *title = NULL; 62 63 64#define APPENDIX_MAGIC 1024 65#define UNNUMBERED_MAGIC 2048 66 67/* Number memory for every level @chapter, @section, 68 @subsection, @subsubsection. */ 69static int numbers [] = { 0, 0, 0, 0 }; 70 71/* enum_marker == APPENDIX_MAGIC then we are counting appendencies 72 enum_marker == UNNUMBERED_MAGIC then we are within unnumbered area. 73 Handling situations like this: 74 @unnumbered .. 75 @section ... */ 76static int enum_marker = 0; 77 78/* Organized by level commands. That is, "*" == chapter, "=" == section. */ 79static char *scoring_characters = "*=-."; 80 81/* Amount to offset the name of sectioning commands to levels by. */ 82static int section_alist_offset = 0; 83 84 85/* num == ENUM_SECT_NO means unnumbered (should never call this) 86 num == ENUM_SECT_YES means numbered 87 num == ENUM_SECT_APP means numbered like A.1 and so on */ 88char * 89get_sectioning_number (level, num) 90 int level; 91 int num; 92{ 93 static char s[100]; /* should ever be enough for 99.99.99.99 94 Appendix A.1 */ 95 96 char *p; 97 int i; 98 99 s[0] = 0; 100 101 /* create enumeration in front of chapter, section, subsection and so on. */ 102 for (i = 0; i < level; i++) 103 { 104 p = s + strlen (s); 105 if ((i == 0) && (enum_marker == APPENDIX_MAGIC)) 106 sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to 107 be more portable */ 108 else 109 sprintf (p, "%d.", numbers[i]); 110 } 111 112 /* the last number is never followed by a dot */ 113 p = s + strlen (s); 114 if ((num == ENUM_SECT_APP) 115 && (i == 0) 116 && (enum_marker == APPENDIX_MAGIC)) 117 sprintf (p, _("Appendix %c "), numbers[i] + 64); 118 else 119 sprintf (p, "%d ", numbers[i]); 120 121 return s; 122} 123 124 125/* Set the level of @top to LEVEL. Return the old level of @top. */ 126int 127set_top_section_level (level) 128 int level; 129{ 130 int i, result = -1; 131 132 for (i = 0; section_alist[i].name; i++) 133 if (strcmp (section_alist[i].name, "top") == 0) 134 { 135 result = section_alist[i].level; 136 section_alist[i].level = level; 137 break; 138 } 139 return result; 140} 141 142 143/* return the index of the given sectioning command in section_alist */ 144int 145search_sectioning (text) 146 char *text; 147{ 148 int i; 149 char *t; 150 151 /* ignore the optional command prefix */ 152 if (text[0] == COMMAND_PREFIX) 153 text++; 154 155 for (i = 0; (t = section_alist[i].name); i++) 156 { 157 if (strcmp (t, text) == 0) 158 { 159 return i; 160 } 161 } 162 return -1; 163} 164 165/* Return an integer which identifies the type section present in TEXT. */ 166int 167what_section (text) 168 char *text; 169{ 170 int index, j; 171 char *temp; 172 int return_val; 173 174 find_section_command: 175 for (j = 0; text[j] && cr_or_whitespace (text[j]); j++); 176 if (text[j] != COMMAND_PREFIX) 177 return -1; 178 179 text = text + j + 1; 180 181 /* We skip @c, @comment, and @?index commands. */ 182 if ((strncmp (text, "comment", strlen ("comment")) == 0) || 183 (text[0] == 'c' && cr_or_whitespace (text[1])) || 184 (strcmp (text + 1, "index") == 0)) 185 { 186 while (*text++ != '\n'); 187 goto find_section_command; 188 } 189 190 /* Handle italicized sectioning commands. */ 191 if (*text == 'i') 192 text++; 193 194 for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++); 195 196 temp = xmalloc (1 + j); 197 strncpy (temp, text, j); 198 temp[j] = 0; 199 200 index = search_sectioning (temp); 201 free (temp); 202 if (index >= 0) 203 { 204 return_val = section_alist[index].level + section_alist_offset; 205 if (return_val < 0) 206 return_val = 0; 207 else if (return_val > 5) 208 return_val = 5; 209 return return_val; 210 } 211 return -1; 212} 213 214void 215sectioning_underscore (cmd) 216 char *cmd; 217{ 218 if (xml) 219 { 220 char *temp; 221 int level; 222 temp = xmalloc (2 + strlen (cmd)); 223 temp[0] = COMMAND_PREFIX; 224 strcpy (&temp[1], cmd); 225 level = what_section (temp); 226 level -= 2; 227 free (temp); 228 xml_close_sections (level); 229 /* Mark the beginning of the section 230 If the next command is printindex, we will remove 231 the section and put an Index instead */ 232 flush_output (); 233 xml_last_section_output_position = output_paragraph_offset; 234 235 xml_insert_element (xml_element (cmd), START); 236 xml_insert_element (TITLE, START); 237 xml_open_section (level, cmd); 238 get_rest_of_line (0, &temp); 239 execute_string ("%s\n", temp); 240 free (temp); 241 xml_insert_element (TITLE, END); 242 } 243 else 244 { 245 char character; 246 char *temp; 247 int level; 248 249 temp = xmalloc (2 + strlen (cmd)); 250 temp[0] = COMMAND_PREFIX; 251 strcpy (&temp[1], cmd); 252 level = what_section (temp); 253 free (temp); 254 level -= 2; 255 256 if (level < 0) 257 level = 0; 258 259 if (html) 260 sectioning_html (level, cmd); 261 else 262 { 263 character = scoring_characters[level]; 264 insert_and_underscore (level, character, cmd); 265 } 266 } 267} 268 269/* insert_and_underscore and sectioning_html are the 270 only functions which call this. 271 I have created this, because it was exactly the same 272 code in both functions. */ 273static char * 274handle_enum_increment (level, index) 275 int level; 276 int index; 277{ 278 /* special for unnumbered */ 279 if (number_sections && section_alist[index].num == ENUM_SECT_NO) 280 { 281 if (level == 0 282 && enum_marker != UNNUMBERED_MAGIC) 283 enum_marker = UNNUMBERED_MAGIC; 284 } 285 /* enumerate only things which are allowed */ 286 if (number_sections && section_alist[index].num) 287 { 288 /* reset the marker if we get into enumerated areas */ 289 if (section_alist[index].num == ENUM_SECT_YES 290 && level == 0 291 && enum_marker == UNNUMBERED_MAGIC) 292 enum_marker = 0; 293 /* This is special for appendix; if we got the first 294 time an appendix command then we are entering appendix. 295 Thats the point we have to start countint with A, B and so on. */ 296 if (section_alist[index].num == ENUM_SECT_APP 297 && level == 0 298 && enum_marker != APPENDIX_MAGIC) 299 { 300 enum_marker = APPENDIX_MAGIC; 301 numbers [0] = 0; /* this means we start with Appendix A */ 302 } 303 304 /* only increment counters if we are not in unnumbered 305 area. This handles situations like this: 306 @unnumbered .... This sets enum_marker to UNNUMBERED_MAGIC 307 @section .... */ 308 if (enum_marker != UNNUMBERED_MAGIC) 309 { 310 int i; 311 312 /* reset all counters which are one level deeper */ 313 for (i = level; i < 3; i++) 314 numbers [i + 1] = 0; 315 316 numbers[level]++; 317 return xstrdup 318 (get_sectioning_number (level, section_alist[index].num)); 319 } 320 } /* if (number_sections)... */ 321 322 return xstrdup (""); 323} 324 325 326/* Insert the text following input_text_offset up to the end of the line 327 in a new, separate paragraph. Directly underneath it, insert a 328 line of WITH_CHAR, the same length of the inserted text. */ 329void 330insert_and_underscore (level, with_char, cmd) 331 int level; 332 int with_char; 333 char *cmd; 334{ 335 int i, len; 336 int index; 337 int old_no_indent; 338 unsigned char *starting_pos, *ending_pos; 339 char *temp; 340 341 close_paragraph (); 342 filling_enabled = indented_fill = 0; 343 old_no_indent = no_indent; 344 no_indent = 1; 345 346 if (macro_expansion_output_stream && !executing_string) 347 append_to_expansion_output (input_text_offset + 1); 348 349 get_rest_of_line (0, &temp); 350 starting_pos = output_paragraph + output_paragraph_offset; 351 352 index = search_sectioning (cmd); 353 if (index < 0) 354 { 355 /* should never happen, but a poor guy, named Murphy ... */ 356 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd); 357 return; 358 } 359 360 /* This is a bit tricky: we must produce "X.Y SECTION-NAME" in the 361 Info output and in TOC, but only SECTION-NAME in the macro-expanded 362 output. */ 363 364 /* Step 1: produce "X.Y" and add it to Info output. */ 365 add_word (handle_enum_increment (level, index)); 366 367 /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output. */ 368 if (macro_expansion_output_stream && !executing_string) 369 { 370 char *temp1 = xmalloc (2 + strlen (temp)); 371 sprintf (temp1, "%s\n", temp); 372 remember_itext (input_text, input_text_offset); 373 me_execute_string (temp1); 374 free (temp1); 375 } 376 else 377 execute_string ("%s\n", temp); 378 379 /* Step 3: pluck "X.Y SECTION-NAME" from the output buffer and 380 insert it into the TOC. */ 381 ending_pos = output_paragraph + output_paragraph_offset; 382 if (section_alist[index].toc == TOC_YES) 383 toc_add_entry (substring (starting_pos, ending_pos - 1), 384 level, current_node, NULL); 385 386 free (temp); 387 388 len = (ending_pos - starting_pos) - 1; 389 for (i = 0; i < len; i++) 390 add_char (with_char); 391 insert ('\n'); 392 close_paragraph (); 393 filling_enabled = 1; 394 no_indent = old_no_indent; 395} 396 397/* Insert the text following input_text_offset up to the end of the 398 line as an HTML heading element of the appropriate `level' and 399 tagged as an anchor for the current node.. */ 400void 401sectioning_html (level, cmd) 402 int level; 403 char *cmd; 404{ 405 static int toc_ref_count = 0; 406 int index; 407 int old_no_indent; 408 unsigned char *starting_pos, *ending_pos; 409 char *temp, *toc_anchor = NULL; 410 411 close_paragraph (); 412 filling_enabled = indented_fill = 0; 413 old_no_indent = no_indent; 414 no_indent = 1; 415 416 /* level 0 (chapter) is <h2> */ 417 add_word_args ("<h%d class=\"%s\">", level + 2, cmd); 418 419 /* If we are outside of any node, produce an anchor that 420 the TOC could refer to. */ 421 if (!current_node || !*current_node) 422 { 423 static const char a_name[] = "<a name=\""; 424 425 starting_pos = output_paragraph + output_paragraph_offset; 426 add_word_args ("%sTOC%d\">", a_name, toc_ref_count++); 427 toc_anchor = substring (starting_pos + sizeof (a_name) - 1, 428 output_paragraph + output_paragraph_offset); 429 /* This must be added after toc_anchor is extracted, since 430 toc_anchor cannot include the closing </a>. For details, 431 see toc.c:toc_add_entry and toc.c:contents_update_html. 432 433 Also, the anchor close must be output before the section name 434 in case the name itself contains an anchor. */ 435 add_word ("</a>"); 436 } 437 starting_pos = output_paragraph + output_paragraph_offset; 438 439 if (macro_expansion_output_stream && !executing_string) 440 append_to_expansion_output (input_text_offset + 1); 441 442 get_rest_of_line (0, &temp); 443 444 index = search_sectioning (cmd); 445 if (index < 0) 446 { 447 /* should never happen, but a poor guy, named Murphy ... */ 448 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd); 449 return; 450 } 451 452 /* Produce "X.Y" and add it to HTML output. */ 453 add_word (handle_enum_increment (level, index)); 454 455 /* add the section name to both HTML and macro-expanded output. */ 456 if (macro_expansion_output_stream && !executing_string) 457 { 458 remember_itext (input_text, input_text_offset); 459 me_execute_string (temp); 460 write_region_to_macro_output ("\n", 0, 1); 461 } 462 else 463 execute_string ("%s", temp); 464 465 ending_pos = output_paragraph + output_paragraph_offset; 466 467 /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it 468 into the TOC. */ 469 if (section_alist[index].toc == TOC_YES) 470 toc_add_entry (substring (starting_pos, ending_pos), 471 level, current_node, toc_anchor); 472 473 free (temp); 474 475 if (outstanding_node) 476 outstanding_node = 0; 477 478 add_word_args ("</h%d>", level + 2); 479 close_paragraph(); 480 filling_enabled = 1; 481 no_indent = old_no_indent; 482} 483 484 485/* Shift the meaning of @section to @chapter. */ 486void 487cm_raisesections () 488{ 489 discard_until ("\n"); 490 section_alist_offset--; 491} 492 493/* Shift the meaning of @chapter to @section. */ 494void 495cm_lowersections () 496{ 497 discard_until ("\n"); 498 section_alist_offset++; 499} 500 501/* The command still works, but prints a warning message in addition. */ 502void 503cm_ideprecated (arg, start, end) 504 int arg, start, end; 505{ 506 warning (_("%c%s is obsolete; use %c%s instead"), 507 COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1); 508 sectioning_underscore (command + 1); 509} 510 511 512/* Treat this just like @unnumbered. The only difference is 513 in node defaulting. */ 514void 515cm_top () 516{ 517 /* It is an error to have more than one @top. */ 518 if (top_node_seen && strcmp (current_node, "Top") != 0) 519 { 520 TAG_ENTRY *tag = tag_table; 521 522 line_error (_("Node with %ctop as a section already exists"), 523 COMMAND_PREFIX); 524 525 while (tag) 526 { 527 if (tag->flags & TAG_FLAG_IS_TOP) 528 { 529 file_line_error (tag->filename, tag->line_no, 530 _("Here is the %ctop node"), COMMAND_PREFIX); 531 return; 532 } 533 tag = tag->next_ent; 534 } 535 } 536 else 537 { 538 TAG_ENTRY *top_node = find_node ("Top"); 539 top_node_seen = 1; 540 541 /* It is an error to use @top before using @node. */ 542 if (!tag_table) 543 { 544 char *top_name; 545 546 get_rest_of_line (0, &top_name); 547 line_error (_("%ctop used before %cnode, defaulting to %s"), 548 COMMAND_PREFIX, COMMAND_PREFIX, top_name); 549 execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name); 550 free (top_name); 551 return; 552 } 553 554 cm_unnumbered (); 555 556 /* The most recently defined node is the top node. */ 557 tag_table->flags |= TAG_FLAG_IS_TOP; 558 559 /* Now set the logical hierarchical level of the Top node. */ 560 { 561 int orig_offset = input_text_offset; 562 563 input_text_offset = search_forward (node_search_string, orig_offset); 564 565 if (input_text_offset > 0) 566 { 567 int this_section; 568 569 /* We have encountered a non-top node, so mark that one exists. */ 570 non_top_node_seen = 1; 571 572 /* Move to the end of this line, and find out what the 573 sectioning command is here. */ 574 while (input_text[input_text_offset] != '\n') 575 input_text_offset++; 576 577 if (input_text_offset < input_text_length) 578 input_text_offset++; 579 580 this_section = what_section (input_text + input_text_offset); 581 582 /* If we found a sectioning command, then give the top section 583 a level of this section - 1. */ 584 if (this_section != -1) 585 set_top_section_level (this_section - 1); 586 } 587 input_text_offset = orig_offset; 588 } 589 } 590} 591 592/* The remainder of the text on this line is a chapter heading. */ 593void 594cm_chapter () 595{ 596 sectioning_underscore ("chapter"); 597} 598 599/* The remainder of the text on this line is a section heading. */ 600void 601cm_section () 602{ 603 sectioning_underscore ("section"); 604} 605 606/* The remainder of the text on this line is a subsection heading. */ 607void 608cm_subsection () 609{ 610 sectioning_underscore ("subsection"); 611} 612 613/* The remainder of the text on this line is a subsubsection heading. */ 614void 615cm_subsubsection () 616{ 617 sectioning_underscore ("subsubsection"); 618} 619 620/* The remainder of the text on this line is an unnumbered heading. */ 621void 622cm_unnumbered () 623{ 624 sectioning_underscore ("unnumbered"); 625} 626 627/* The remainder of the text on this line is an unnumbered section heading. */ 628void 629cm_unnumberedsec () 630{ 631 sectioning_underscore ("unnumberedsec"); 632} 633 634/* The remainder of the text on this line is an unnumbered 635 subsection heading. */ 636void 637cm_unnumberedsubsec () 638{ 639 sectioning_underscore ("unnumberedsubsec"); 640} 641 642/* The remainder of the text on this line is an unnumbered 643 subsubsection heading. */ 644void 645cm_unnumberedsubsubsec () 646{ 647 sectioning_underscore ("unnumberedsubsubsec"); 648} 649 650/* The remainder of the text on this line is an appendix heading. */ 651void 652cm_appendix () 653{ 654 sectioning_underscore ("appendix"); 655} 656 657/* The remainder of the text on this line is an appendix section heading. */ 658void 659cm_appendixsec () 660{ 661 sectioning_underscore ("appendixsec"); 662} 663 664/* The remainder of the text on this line is an appendix subsection heading. */ 665void 666cm_appendixsubsec () 667{ 668 sectioning_underscore ("appendixsubsec"); 669} 670 671/* The remainder of the text on this line is an appendix 672 subsubsection heading. */ 673void 674cm_appendixsubsubsec () 675{ 676 sectioning_underscore ("appendixsubsubsec"); 677} 678 679/* Compatibility functions substitute for chapter, section, etc. */ 680void 681cm_majorheading () 682{ 683 sectioning_underscore ("majorheading"); 684} 685 686void 687cm_chapheading () 688{ 689 sectioning_underscore ("chapheading"); 690} 691 692void 693cm_heading () 694{ 695 sectioning_underscore ("heading"); 696} 697 698void 699cm_subheading () 700{ 701 sectioning_underscore ("subheading"); 702} 703 704void 705cm_subsubheading () 706{ 707 sectioning_underscore ("subsubheading"); 708} 709