3 /* toc.c -- table of contents handling.
4 Id: toc.c,v 1.6 2004/04/11 17:56:47 karl Exp
6 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>. */
33 #include "sectioning.h"
37 /* array of toc entries */
38 static TOC_ENTRY_ELT
**toc_entry_alist
= NULL
;
40 /* toc_counter start from 0 ... n for every @chapter, @section ... */
41 static int toc_counter
= 0;
43 /* Routine to add an entry to the table of contents */
45 toc_add_entry (char *tocname
, int level
, char *node_name
, char *anchor
)
47 char *tocname_and_node
, *expanded_node
, *d
;
49 char *filename
= NULL
;
54 /* I assume that xrealloc behaves like xmalloc if toc_entry_alist is
56 toc_entry_alist
= xrealloc (toc_entry_alist
,
57 (toc_counter
+ 1) * sizeof (TOC_ENTRY_ELT
*));
59 toc_entry_alist
[toc_counter
] = xmalloc (sizeof (TOC_ENTRY_ELT
));
63 /* We need to insert the expanded node name into the toc, so
64 that when we eventually output the toc, its <a ref= link will
65 point to the <a name= tag created by cm_node in the navigation
66 bar. We cannot expand the containing_node member, for the
67 reasons explained in the WARNING below. We also cannot wait
68 with the node name expansion until the toc is actually output,
69 since by that time the macro definitions may have been changed.
70 So instead we store in the tocname member the expanded node
71 name and the toc name concatenated together (with the necessary
72 html markup), since that's how they are output. */
74 s
= expanded_node
= expand_node_name (node_name
);
76 expanded_node
= anchor
;
80 filename
= nodename_to_filename (expanded_node
);
82 filename
= filename_part (current_output_filename
);
84 /* Sigh... Need to HTML-escape the expanded node name like
85 add_anchor_name does, except that we are not writing this to
86 the output, so can't use add_anchor_name... */
87 /* The factor 5 in the next allocation is because the maximum
88 expansion of HTML-escaping is for the & character, which is
89 output as "&". 2 is for "> that separates node from tocname. */
90 d
= tocname_and_node
= (char *)xmalloc (2 + 5 * strlen (expanded_node
)
91 + strlen (tocname
) + 1);
96 if (cr_or_whitespace (*s
))
98 else if (! URL_SAFE_CHAR (*s
))
100 sprintf (d
, "_00%x", (unsigned char) *s
);
101 /* do this manually since sprintf returns char * on
102 SunOS 4 and other old systems. */
112 /* Section outside any node, they provided explicit anchor. */
115 free (tocname
); /* it was malloc'ed by substring() */
116 free (expanded_node
);
117 toc_entry_alist
[toc_counter
]->name
= tocname_and_node
;
120 toc_entry_alist
[toc_counter
]->name
= tocname
;
121 /* WARNING! The node name saved in containing_node member must
122 be the node name with _only_ macros expanded (the macros in
123 the node name are expanded by cm_node when it grabs the name
124 from the @node directive). Non-macros, like @value, @@ and
125 other @-commands must NOT be expanded in containing_node,
126 because toc_find_section_of_node looks up the node name where
127 they are also unexpanded. You *have* been warned! */
128 toc_entry_alist
[toc_counter
]->containing_node
= xstrdup (node_name
);
129 toc_entry_alist
[toc_counter
]->level
= level
;
130 toc_entry_alist
[toc_counter
]->number
= toc_counter
;
131 toc_entry_alist
[toc_counter
]->html_file
= filename
;
133 /* have to be done at least */
134 return toc_counter
++;
137 /* Return the name of a chapter/section/subsection etc. that
138 corresponds to the node NODE. If the node isn't found,
141 WARNING! This function relies on NODE being unexpanded
142 except for macros (i.e., @value, @@, and other non-macros
143 should NOT be expanded), because the containing_node member
144 stores unexpanded node names.
146 Note that this function returns the first section whose
147 containing node is NODE. Thus, they will lose if they use
148 more than a single chapter structioning command in a node,
149 or if they have a node without any structuring commands. */
151 toc_find_section_of_node (char *node
)
157 for (i
= 0; i
< toc_counter
; i
++)
158 if (STREQ (node
, toc_entry_alist
[i
]->containing_node
))
159 return toc_entry_alist
[i
]->name
;
164 /* free up memory used by toc entries */
172 for (i
= 0; i
< toc_counter
; i
++)
174 free (toc_entry_alist
[i
]->name
);
175 free (toc_entry_alist
[i
]->containing_node
);
176 free (toc_entry_alist
[i
]);
179 free (toc_entry_alist
);
180 toc_entry_alist
= NULL
; /* to be sure ;-) */
181 toc_counter
= 0; /* to be absolutley sure ;-) */
185 /* Print table of contents in HTML. */
188 contents_update_html (void)
194 /* does exist any toc? */
196 /* no, so return to sender ;-) */
199 add_html_block_elt_args ("\n<div class=\"contents\">\n<h2>%s</h2>\n<ul>\n", _("Table of Contents"));
201 last_level
= toc_entry_alist
[0]->level
;
203 for (i
= 0; i
< toc_counter
; i
++)
205 if (toc_entry_alist
[i
]->level
> last_level
)
207 /* unusual, but it is possible
209 @subsubsection ... ? */
210 for (k
= 0; k
< (toc_entry_alist
[i
]->level
-last_level
); k
++)
211 add_html_block_elt ("<ul>\n");
213 else if (toc_entry_alist
[i
]->level
< last_level
)
215 /* @subsubsection ...
216 @chapter ... this IS usual.*/
217 for (k
= 0; k
< (last_level
-toc_entry_alist
[i
]->level
); k
++)
218 add_word ("</li></ul>\n");
221 /* No double entries in TOC. */
222 if (!(i
&& strcmp (toc_entry_alist
[i
]->name
,
223 toc_entry_alist
[i
-1]->name
) == 0))
225 /* each toc entry is a list item. */
228 /* Insert link -- to an external file if splitting, or
229 within the current document if not splitting. */
231 /* For chapters (only), insert an anchor that the short contents
233 if (toc_entry_alist
[i
]->level
== 0)
235 char *p
= toc_entry_alist
[i
]->name
;
237 /* toc_entry_alist[i]->name has the form `foo">bar',
238 that is, it includes both the node name and anchor
239 text. We need to find where `foo', the node name,
240 ends, and use that in toc_FOO. */
241 while (*p
&& *p
!= '"')
243 add_word_args ("name=\"toc_%.*s\" ",
244 p
- toc_entry_alist
[i
]->name
, toc_entry_alist
[i
]->name
);
246 add_word_args ("href=\"%s#%s</a>\n",
247 splitting
? toc_entry_alist
[i
]->html_file
: "",
248 toc_entry_alist
[i
]->name
);
251 last_level
= toc_entry_alist
[i
]->level
;
254 /* Go back to start level. */
255 if (toc_entry_alist
[0]->level
< last_level
)
256 for (k
= 0; k
< (last_level
-toc_entry_alist
[0]->level
); k
++)
257 add_word ("</li></ul>\n");
259 add_word ("</li></ul>\n</div>\n\n");
262 /* print table of contents in ASCII (--no-headers)
263 May be we should create a new command line switch --ascii ? */
265 contents_update_info (void)
273 insert_string ((char *) _("Table of Contents"));
275 for (i
= 0; i
< strlen (_("Table of Contents")); i
++)
277 insert_string ("\n\n");
279 for (i
= 0; i
< toc_counter
; i
++)
281 if (toc_entry_alist
[i
]->level
== 0)
284 /* indention with two spaces per level, should this
286 for (k
= 0; k
< toc_entry_alist
[i
]->level
; k
++)
289 insert_string (toc_entry_alist
[i
]->name
);
292 insert_string ("\n\n");
295 /* shortcontents in HTML; Should this produce a standalone file? */
297 shortcontents_update_html (char *contents_filename
)
300 char *toc_file
= NULL
;
302 /* does exist any toc? */
306 add_html_block_elt_args ("\n<div class=\"shortcontents\">\n<h2>%s</h2>\n<ul>\n", _("Short Contents"));
308 if (contents_filename
)
309 toc_file
= filename_part (contents_filename
);
311 for (i
= 0; i
< toc_counter
; i
++)
313 char *name
= toc_entry_alist
[i
]->name
;
315 if (toc_entry_alist
[i
]->level
== 0)
317 if (contents_filename
)
318 add_word_args ("<li><a href=\"%s#toc_%s</a></li>\n",
319 splitting
? toc_file
: "", name
);
321 add_word_args ("<a href=\"%s#%s</a>\n",
322 splitting
? toc_entry_alist
[i
]->html_file
: "", name
);
325 add_word ("</ul>\n</div>\n\n");
326 if (contents_filename
)
330 /* short contents in ASCII (--no-headers). */
332 shortcontents_update_info (void)
339 insert_string ((char *) _("Short Contents"));
341 for (i
= 0; i
< strlen (_("Short Contents")); i
++)
343 insert_string ("\n\n");
345 for (i
= 0; i
< toc_counter
; i
++)
347 if (toc_entry_alist
[i
]->level
== 0)
349 insert_string (toc_entry_alist
[i
]->name
);
353 insert_string ("\n\n");
357 cm_contents (int arg
)
359 /* the file where we found the @contents directive */
360 static char *contents_filename
;
362 /* No need to mess with delayed stuff for XML and Docbook. */
367 int elt
= STREQ (command
, "contents") ? CONTENTS
: SHORTCONTENTS
;
368 xml_insert_element (elt
, START
);
369 xml_insert_element (elt
, END
);
372 else if (!handling_delayed_writes
)
374 register_delayed_write (STREQ (command
, "contents")
375 ? "@contents" : "@shortcontents");
377 if (html
&& STREQ (command
, "contents"))
379 if (contents_filename
)
380 free (contents_filename
);
381 contents_filename
= xstrdup (current_output_filename
);
385 STREQ (command
, "contents")
386 ? contents_update_html () : shortcontents_update_html (contents_filename
);
388 STREQ (command
, "contents")
389 ? contents_update_info () : shortcontents_update_info ();