diff options
Diffstat (limited to 'Build/source/utils/texinfo/makeinfo/toc.c')
-rw-r--r-- | Build/source/utils/texinfo/makeinfo/toc.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/Build/source/utils/texinfo/makeinfo/toc.c b/Build/source/utils/texinfo/makeinfo/toc.c new file mode 100644 index 00000000000..fa3d8e07382 --- /dev/null +++ b/Build/source/utils/texinfo/makeinfo/toc.c @@ -0,0 +1,388 @@ +/* toc.c -- table of contents handling. + $Id: toc.c,v 1.6 2004/04/11 17:56:47 karl Exp $ + + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Originally written by Karl Heinz Marbaise <kama@hippo.fido.de>. */ + +#include "system.h" +#include "makeinfo.h" +#include "cmds.h" +#include "files.h" +#include "macro.h" +#include "node.h" +#include "html.h" +#include "lang.h" +#include "makeinfo.h" +#include "sectioning.h" +#include "toc.h" +#include "xml.h" + +/* array of toc entries */ +static TOC_ENTRY_ELT **toc_entry_alist = NULL; + +/* toc_counter start from 0 ... n for every @chapter, @section ... */ +static int toc_counter = 0; + +/* Routine to add an entry to the table of contents */ +int +toc_add_entry (char *tocname, int level, char *node_name, char *anchor) +{ + char *tocname_and_node, *expanded_node, *d; + char *s = NULL; + char *filename = NULL; + + if (!node_name) + node_name = ""; + + /* I assume that xrealloc behaves like xmalloc if toc_entry_alist is + NULL */ + toc_entry_alist = xrealloc (toc_entry_alist, + (toc_counter + 1) * sizeof (TOC_ENTRY_ELT *)); + + toc_entry_alist[toc_counter] = xmalloc (sizeof (TOC_ENTRY_ELT)); + + if (html) + { + /* We need to insert the expanded node name into the toc, so + that when we eventually output the toc, its <a ref= link will + point to the <a name= tag created by cm_node in the navigation + bar. We cannot expand the containing_node member, for the + reasons explained in the WARNING below. We also cannot wait + with the node name expansion until the toc is actually output, + since by that time the macro definitions may have been changed. + So instead we store in the tocname member the expanded node + name and the toc name concatenated together (with the necessary + html markup), since that's how they are output. */ + if (!anchor) + s = expanded_node = expand_node_name (node_name); + else + expanded_node = anchor; + if (splitting) + { + if (!anchor) + filename = nodename_to_filename (expanded_node); + else + filename = filename_part (current_output_filename); + } + /* Sigh... Need to HTML-escape the expanded node name like + add_anchor_name does, except that we are not writing this to + the output, so can't use add_anchor_name... */ + /* The factor 5 in the next allocation is because the maximum + expansion of HTML-escaping is for the & character, which is + output as "&". 2 is for "> that separates node from tocname. */ + d = tocname_and_node = (char *)xmalloc (2 + 5 * strlen (expanded_node) + + strlen (tocname) + 1); + if (!anchor) + { + for (; *s; s++) + { + if (cr_or_whitespace (*s)) + *d++ = '-'; + else if (! URL_SAFE_CHAR (*s)) + { + sprintf (d, "_00%x", (unsigned char) *s); + /* do this manually since sprintf returns char * on + SunOS 4 and other old systems. */ + while (*d) + d++; + } + else + *d++ = *s; + } + strcpy (d, "\">"); + } + else + /* Section outside any node, they provided explicit anchor. */ + strcpy (d, anchor); + strcat (d, tocname); + free (tocname); /* it was malloc'ed by substring() */ + free (expanded_node); + toc_entry_alist[toc_counter]->name = tocname_and_node; + } + else + toc_entry_alist[toc_counter]->name = tocname; + /* WARNING! The node name saved in containing_node member must + be the node name with _only_ macros expanded (the macros in + the node name are expanded by cm_node when it grabs the name + from the @node directive). Non-macros, like @value, @@ and + other @-commands must NOT be expanded in containing_node, + because toc_find_section_of_node looks up the node name where + they are also unexpanded. You *have* been warned! */ + toc_entry_alist[toc_counter]->containing_node = xstrdup (node_name); + toc_entry_alist[toc_counter]->level = level; + toc_entry_alist[toc_counter]->number = toc_counter; + toc_entry_alist[toc_counter]->html_file = filename; + + /* have to be done at least */ + return toc_counter++; +} + +/* Return the name of a chapter/section/subsection etc. that + corresponds to the node NODE. If the node isn't found, + return NULL. + + WARNING! This function relies on NODE being unexpanded + except for macros (i.e., @value, @@, and other non-macros + should NOT be expanded), because the containing_node member + stores unexpanded node names. + + Note that this function returns the first section whose + containing node is NODE. Thus, they will lose if they use + more than a single chapter structioning command in a node, + or if they have a node without any structuring commands. */ +char * +toc_find_section_of_node (char *node) +{ + int i; + + if (!node) + node = ""; + for (i = 0; i < toc_counter; i++) + if (STREQ (node, toc_entry_alist[i]->containing_node)) + return toc_entry_alist[i]->name; + + return NULL; +} + +/* free up memory used by toc entries */ +void +toc_free (void) +{ + int i; + + if (toc_counter) + { + for (i = 0; i < toc_counter; i++) + { + free (toc_entry_alist[i]->name); + free (toc_entry_alist[i]->containing_node); + free (toc_entry_alist[i]); + } + + free (toc_entry_alist); + toc_entry_alist = NULL; /* to be sure ;-) */ + toc_counter = 0; /* to be absolutley sure ;-) */ + } +} + +/* Print table of contents in HTML. */ + +static void +contents_update_html (void) +{ + int i; + int k; + int last_level; + + /* does exist any toc? */ + if (!toc_counter) + /* no, so return to sender ;-) */ + return; + + add_html_block_elt_args ("\n<div class=\"contents\">\n<h2>%s</h2>\n<ul>\n", _("Table of Contents")); + + last_level = toc_entry_alist[0]->level; + + for (i = 0; i < toc_counter; i++) + { + if (toc_entry_alist[i]->level > last_level) + { + /* unusual, but it is possible + @chapter ... + @subsubsection ... ? */ + for (k = 0; k < (toc_entry_alist[i]->level-last_level); k++) + add_html_block_elt ("<ul>\n"); + } + else if (toc_entry_alist[i]->level < last_level) + { + /* @subsubsection ... + @chapter ... this IS usual.*/ + for (k = 0; k < (last_level-toc_entry_alist[i]->level); k++) + add_word ("</li></ul>\n"); + } + + /* No double entries in TOC. */ + if (!(i && strcmp (toc_entry_alist[i]->name, + toc_entry_alist[i-1]->name) == 0)) + { + /* each toc entry is a list item. */ + add_word ("<li>"); + + /* Insert link -- to an external file if splitting, or + within the current document if not splitting. */ + add_word ("<a "); + /* For chapters (only), insert an anchor that the short contents + will link to. */ + if (toc_entry_alist[i]->level == 0) + { + char *p = toc_entry_alist[i]->name; + + /* toc_entry_alist[i]->name has the form `foo">bar', + that is, it includes both the node name and anchor + text. We need to find where `foo', the node name, + ends, and use that in toc_FOO. */ + while (*p && *p != '"') + p++; + add_word_args ("name=\"toc_%.*s\" ", + p - toc_entry_alist[i]->name, toc_entry_alist[i]->name); + } + add_word_args ("href=\"%s#%s</a>\n", + splitting ? toc_entry_alist[i]->html_file : "", + toc_entry_alist[i]->name); + } + + last_level = toc_entry_alist[i]->level; + } + + /* Go back to start level. */ + if (toc_entry_alist[0]->level < last_level) + for (k = 0; k < (last_level-toc_entry_alist[0]->level); k++) + add_word ("</li></ul>\n"); + + add_word ("</li></ul>\n</div>\n\n"); +} + +/* print table of contents in ASCII (--no-headers) + May be we should create a new command line switch --ascii ? */ +static void +contents_update_info (void) +{ + int i; + int k; + + if (!toc_counter) + return; + + insert_string ((char *) _("Table of Contents")); + insert ('\n'); + for (i = 0; i < strlen (_("Table of Contents")); i++) + insert ('*'); + insert_string ("\n\n"); + + for (i = 0; i < toc_counter; i++) + { + if (toc_entry_alist[i]->level == 0) + add_char ('\n'); + + /* indention with two spaces per level, should this + changed? */ + for (k = 0; k < toc_entry_alist[i]->level; k++) + insert_string (" "); + + insert_string (toc_entry_alist[i]->name); + insert ('\n'); + } + insert_string ("\n\n"); +} + +/* shortcontents in HTML; Should this produce a standalone file? */ +static void +shortcontents_update_html (char *contents_filename) +{ + int i; + char *toc_file = NULL; + + /* does exist any toc? */ + if (!toc_counter) + return; + + add_html_block_elt_args ("\n<div class=\"shortcontents\">\n<h2>%s</h2>\n<ul>\n", _("Short Contents")); + + if (contents_filename) + toc_file = filename_part (contents_filename); + + for (i = 0; i < toc_counter; i++) + { + char *name = toc_entry_alist[i]->name; + + if (toc_entry_alist[i]->level == 0) + { + if (contents_filename) + add_word_args ("<li><a href=\"%s#toc_%s</a></li>\n", + splitting ? toc_file : "", name); + else + add_word_args ("<a href=\"%s#%s</a>\n", + splitting ? toc_entry_alist[i]->html_file : "", name); + } + } + add_word ("</ul>\n</div>\n\n"); + if (contents_filename) + free (toc_file); +} + +/* short contents in ASCII (--no-headers). */ +static void +shortcontents_update_info (void) +{ + int i; + + if (!toc_counter) + return; + + insert_string ((char *) _("Short Contents")); + insert ('\n'); + for (i = 0; i < strlen (_("Short Contents")); i++) + insert ('*'); + insert_string ("\n\n"); + + for (i = 0; i < toc_counter; i++) + { + if (toc_entry_alist[i]->level == 0) + { + insert_string (toc_entry_alist[i]->name); + insert ('\n'); + } + } + insert_string ("\n\n"); +} + +void +cm_contents (int arg) +{ + /* the file where we found the @contents directive */ + static char *contents_filename; + + /* No need to mess with delayed stuff for XML and Docbook. */ + if (xml) + { + if (arg == START) + { + int elt = STREQ (command, "contents") ? CONTENTS : SHORTCONTENTS; + xml_insert_element (elt, START); + xml_insert_element (elt, END); + } + } + else if (!handling_delayed_writes) + { + register_delayed_write (STREQ (command, "contents") + ? "@contents" : "@shortcontents"); + + if (html && STREQ (command, "contents")) + { + if (contents_filename) + free (contents_filename); + contents_filename = xstrdup (current_output_filename); + } + } + else if (html) + STREQ (command, "contents") + ? contents_update_html () : shortcontents_update_html (contents_filename); + else if (no_headers) + STREQ (command, "contents") + ? contents_update_info () : shortcontents_update_info (); +} |