1 /* sectioning.c -- all related stuff @chapter, @section... @contents
2 $Id: sectioning.c,v 1.17 2002/02/09 00:54:51 karl Exp $
4 Copyright (C) 1999, 2001, 02 Free Software Foundation, Inc.
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)
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.
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.
20 Written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
28 #include "sectioning.h"
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 },
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 },
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 },
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 },
56 { "top", 1, ENUM_SECT_NO, TOC_YES },
60 /* The argument of @settitle, used for HTML. */
64 #define APPENDIX_MAGIC 1024
65 #define UNNUMBERED_MAGIC 2048
67 /* Number memory for every level @chapter, @section,
68 @subsection, @subsubsection. */
69 static int numbers [] = { 0, 0, 0, 0 };
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:
76 static int enum_marker = 0;
78 /* Organized by level commands. That is, "*" == chapter, "=" == section. */
79 static char *scoring_characters = "*=-.";
81 /* Amount to offset the name of sectioning commands to levels by. */
82 static int section_alist_offset = 0;
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 */
89 get_sectioning_number (level, num)
93 static char s[100]; /* should ever be enough for 99.99.99.99
101 /* create enumeration in front of chapter, section, subsection and so on. */
102 for (i = 0; i < level; i++)
105 if ((i == 0) && (enum_marker == APPENDIX_MAGIC))
106 sprintf (p, "%c.", numbers[i] + 64); /* Should be changed to
109 sprintf (p, "%d.", numbers[i]);
112 /* the last number is never followed by a dot */
114 if ((num == ENUM_SECT_APP)
116 && (enum_marker == APPENDIX_MAGIC))
117 sprintf (p, _("Appendix %c "), numbers[i] + 64);
119 sprintf (p, "%d ", numbers[i]);
125 /* Set the level of @top to LEVEL. Return the old level of @top. */
127 set_top_section_level (level)
132 for (i = 0; section_alist[i].name; i++)
133 if (strcmp (section_alist[i].name, "top") == 0)
135 result = section_alist[i].level;
136 section_alist[i].level = level;
143 /* return the index of the given sectioning command in section_alist */
145 search_sectioning (text)
151 /* ignore the optional command prefix */
152 if (text[0] == COMMAND_PREFIX)
155 for (i = 0; (t = section_alist[i].name); i++)
157 if (strcmp (t, text) == 0)
165 /* Return an integer which identifies the type section present in TEXT. */
174 find_section_command:
175 for (j = 0; text[j] && cr_or_whitespace (text[j]); j++);
176 if (text[j] != COMMAND_PREFIX)
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))
186 while (*text++ != '\n');
187 goto find_section_command;
190 /* Handle italicized sectioning commands. */
194 for (j = 0; text[j] && !cr_or_whitespace (text[j]); j++);
196 temp = xmalloc (1 + j);
197 strncpy (temp, text, j);
200 index = search_sectioning (temp);
204 return_val = section_alist[index].level + section_alist_offset;
207 else if (return_val > 5)
215 sectioning_underscore (cmd)
222 temp = xmalloc (2 + strlen (cmd));
223 temp[0] = COMMAND_PREFIX;
224 strcpy (&temp[1], cmd);
225 level = what_section (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 */
233 xml_last_section_output_position = output_paragraph_offset;
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);
241 xml_insert_element (TITLE, END);
249 temp = xmalloc (2 + strlen (cmd));
250 temp[0] = COMMAND_PREFIX;
251 strcpy (&temp[1], cmd);
252 level = what_section (temp);
260 sectioning_html (level, cmd);
263 character = scoring_characters[level];
264 insert_and_underscore (level, character, cmd);
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. */
274 handle_enum_increment (level, index)
278 /* special for unnumbered */
279 if (number_sections && section_alist[index].num == ENUM_SECT_NO)
282 && enum_marker != UNNUMBERED_MAGIC)
283 enum_marker = UNNUMBERED_MAGIC;
285 /* enumerate only things which are allowed */
286 if (number_sections && section_alist[index].num)
288 /* reset the marker if we get into enumerated areas */
289 if (section_alist[index].num == ENUM_SECT_YES
291 && enum_marker == UNNUMBERED_MAGIC)
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
298 && enum_marker != APPENDIX_MAGIC)
300 enum_marker = APPENDIX_MAGIC;
301 numbers [0] = 0; /* this means we start with Appendix A */
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
308 if (enum_marker != UNNUMBERED_MAGIC)
312 /* reset all counters which are one level deeper */
313 for (i = level; i < 3; i++)
318 (get_sectioning_number (level, section_alist[index].num));
320 } /* if (number_sections)... */
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. */
330 insert_and_underscore (level, with_char, cmd)
338 unsigned char *starting_pos, *ending_pos;
342 filling_enabled = indented_fill = 0;
343 old_no_indent = no_indent;
346 if (macro_expansion_output_stream && !executing_string)
347 append_to_expansion_output (input_text_offset + 1);
349 get_rest_of_line (0, &temp);
350 starting_pos = output_paragraph + output_paragraph_offset;
352 index = search_sectioning (cmd);
355 /* should never happen, but a poor guy, named Murphy ... */
356 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
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
364 /* Step 1: produce "X.Y" and add it to Info output. */
365 add_word (handle_enum_increment (level, index));
367 /* Step 2: add "SECTION-NAME" to both Info and macro-expanded output. */
368 if (macro_expansion_output_stream && !executing_string)
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);
377 execute_string ("%s\n", temp);
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);
388 len = (ending_pos - starting_pos) - 1;
389 for (i = 0; i < len; i++)
390 add_char (with_char);
394 no_indent = old_no_indent;
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.. */
401 sectioning_html (level, cmd)
405 static int toc_ref_count = 0;
408 unsigned char *starting_pos, *ending_pos;
409 char *temp, *toc_anchor = NULL;
412 filling_enabled = indented_fill = 0;
413 old_no_indent = no_indent;
416 add_word_args ("<h%d>", level + 2); /* level 0 (chapter) is <h2> */
418 /* If we are outside of any node, produce an anchor that
419 the TOC could refer to. */
420 if (!current_node || !*current_node)
422 static const char a_name[] = "<a name=\"";
424 starting_pos = output_paragraph + output_paragraph_offset;
425 add_word_args ("%sTOC%d\">", a_name, toc_ref_count++);
426 toc_anchor = substring (starting_pos + sizeof (a_name) - 1,
427 output_paragraph + output_paragraph_offset);
428 /* This must be added after toc_anchor is extracted, since
429 toc_anchor cannot include the closing </a>. For details,
430 see toc.c:toc_add_entry and toc.c:contents_update_html. */
433 starting_pos = output_paragraph + output_paragraph_offset;
435 if (macro_expansion_output_stream && !executing_string)
436 append_to_expansion_output (input_text_offset + 1);
438 get_rest_of_line (0, &temp);
440 index = search_sectioning (cmd);
443 /* should never happen, but a poor guy, named Murphy ... */
444 warning (_("Internal error (search_sectioning) \"%s\"!"), cmd);
448 /* Produce "X.Y" and add it to HTML output. */
449 add_word (handle_enum_increment (level, index));
451 /* add the section name to both HTML and macro-expanded output. */
452 if (macro_expansion_output_stream && !executing_string)
454 remember_itext (input_text, input_text_offset);
455 me_execute_string (temp);
456 write_region_to_macro_output ("\n", 0, 1);
459 execute_string ("%s", temp);
461 ending_pos = output_paragraph + output_paragraph_offset;
463 /* Pluck ``X.Y SECTION-NAME'' from the output buffer and insert it
465 if (section_alist[index].toc == TOC_YES)
466 toc_add_entry (substring (starting_pos, ending_pos),
467 level, current_node, toc_anchor);
471 if (outstanding_node)
472 outstanding_node = 0;
474 add_word_args ("</h%d>", level + 2);
477 no_indent = old_no_indent;
481 /* Shift the meaning of @section to @chapter. */
485 discard_until ("\n");
486 section_alist_offset--;
489 /* Shift the meaning of @chapter to @section. */
493 discard_until ("\n");
494 section_alist_offset++;
497 /* The command still works, but prints a warning message in addition. */
499 cm_ideprecated (arg, start, end)
502 warning (_("%c%s is obsolete; use %c%s instead"),
503 COMMAND_PREFIX, command, COMMAND_PREFIX, command + 1);
504 sectioning_underscore (command + 1);
508 /* Treat this just like @unnumbered. The only difference is
509 in node defaulting. */
513 /* It is an error to have more than one @top. */
514 if (top_node_seen && strcmp (current_node, "Top") != 0)
516 TAG_ENTRY *tag = tag_table;
518 line_error (_("Node with %ctop as a section already exists"),
523 if (tag->flags & TAG_FLAG_IS_TOP)
525 file_line_error (tag->filename, tag->line_no,
526 _("Here is the %ctop node"), COMMAND_PREFIX);
534 TAG_ENTRY *top_node = find_node ("Top");
537 /* It is an error to use @top before using @node. */
542 get_rest_of_line (0, &top_name);
543 line_error (_("%ctop used before %cnode, defaulting to %s"),
544 COMMAND_PREFIX, COMMAND_PREFIX, top_name);
545 execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name);
552 /* The most recently defined node is the top node. */
553 tag_table->flags |= TAG_FLAG_IS_TOP;
555 /* Now set the logical hierarchical level of the Top node. */
557 int orig_offset = input_text_offset;
559 input_text_offset = search_forward (node_search_string, orig_offset);
561 if (input_text_offset > 0)
565 /* We have encountered a non-top node, so mark that one exists. */
566 non_top_node_seen = 1;
568 /* Move to the end of this line, and find out what the
569 sectioning command is here. */
570 while (input_text[input_text_offset] != '\n')
573 if (input_text_offset < input_text_length)
576 this_section = what_section (input_text + input_text_offset);
578 /* If we found a sectioning command, then give the top section
579 a level of this section - 1. */
580 if (this_section != -1)
581 set_top_section_level (this_section - 1);
583 input_text_offset = orig_offset;
588 /* The remainder of the text on this line is a chapter heading. */
592 sectioning_underscore ("chapter");
595 /* The remainder of the text on this line is a section heading. */
599 sectioning_underscore ("section");
602 /* The remainder of the text on this line is a subsection heading. */
606 sectioning_underscore ("subsection");
609 /* The remainder of the text on this line is a subsubsection heading. */
613 sectioning_underscore ("subsubsection");
616 /* The remainder of the text on this line is an unnumbered heading. */
620 sectioning_underscore ("unnumbered");
623 /* The remainder of the text on this line is an unnumbered section heading. */
627 sectioning_underscore ("unnumberedsec");
630 /* The remainder of the text on this line is an unnumbered
631 subsection heading. */
633 cm_unnumberedsubsec ()
635 sectioning_underscore ("unnumberedsubsec");
638 /* The remainder of the text on this line is an unnumbered
639 subsubsection heading. */
641 cm_unnumberedsubsubsec ()
643 sectioning_underscore ("unnumberedsubsubsec");
646 /* The remainder of the text on this line is an appendix heading. */
650 sectioning_underscore ("appendix");
653 /* The remainder of the text on this line is an appendix section heading. */
657 sectioning_underscore ("appendixsec");
660 /* The remainder of the text on this line is an appendix subsection heading. */
664 sectioning_underscore ("appendixsubsec");
667 /* The remainder of the text on this line is an appendix
668 subsubsection heading. */
670 cm_appendixsubsubsec ()
672 sectioning_underscore ("appendixsubsubsec");
675 /* Compatibility functions substitute for chapter, section, etc. */
679 sectioning_underscore ("majorheading");
685 sectioning_underscore ("chapheading");
691 sectioning_underscore ("heading");
697 sectioning_underscore ("subheading");
703 sectioning_underscore ("subsubheading");