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