summaryrefslogtreecommitdiff
path: root/info/footnotes.c
diff options
context:
space:
mode:
Diffstat (limited to 'info/footnotes.c')
-rw-r--r--info/footnotes.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/info/footnotes.c b/info/footnotes.c
new file mode 100644
index 0000000..552ae2a
--- /dev/null
+++ b/info/footnotes.c
@@ -0,0 +1,267 @@
+/* footnotes.c -- Some functions for manipulating footnotes.
+ $Id: footnotes.c,v 1.9 2008/06/11 09:55:42 gray Exp $
+
+ Copyright (C) 1993, 1997, 1998, 1999, 2002, 2004, 2007,
+ 2008 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+ Originally written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+
+/* Nonzero means attempt to show footnotes when displaying a new window. */
+int auto_footnotes_p = 0;
+
+static char *footnote_nodename = "*Footnotes*";
+
+NODE * make_footnotes_node (NODE *node);
+
+#define FOOTNOTE_HEADER_FORMAT \
+ "*** Footnotes appearing in the node `%s' ***\n"
+
+/* Find the window currently showing footnotes. */
+static WINDOW *
+find_footnotes_window (void)
+{
+ WINDOW *win;
+
+ /* Try to find an existing window first. */
+ for (win = windows; win; win = win->next)
+ if (internal_info_node_p (win->node) &&
+ (strcmp (win->node->nodename, footnote_nodename) == 0))
+ break;
+
+ return win;
+}
+
+/* Manufacture a node containing the footnotes of this node, and
+ return the manufactured node. If NODE has no footnotes, return a
+ NULL pointer. */
+NODE *
+make_footnotes_node (NODE *node)
+{
+ NODE *fn_node, *result = NULL;
+ long fn_start;
+
+ /* Make the initial assumption that the footnotes appear as simple
+ text within this windows node. */
+ fn_node = node;
+
+ /* See if this node contains the magic footnote label. */
+ fn_start =
+ info_search_in_node (FOOTNOTE_LABEL, node, 0, NULL, 1, 0);
+
+ /* If it doesn't, check to see if it has an associated footnotes node. */
+ if (fn_start == -1)
+ {
+ REFERENCE **refs;
+
+ refs = info_xrefs_of_node (node);
+
+ if (refs)
+ {
+ register int i;
+ char *refname;
+ int reflen = strlen ("-Footnotes") + strlen (node->nodename);
+
+ refname = xmalloc (reflen + 1);
+
+ strcpy (refname, node->nodename);
+ strcat (refname, "-Footnotes");
+
+ for (i = 0; refs[i]; i++)
+ if ((refs[i]->nodename != NULL) &&
+ /* Support both the older "foo-Footnotes" and the new
+ style "foo-Footnote-NN" references. */
+ (strcmp (refs[i]->nodename, refname) == 0 ||
+ (strncmp (refs[i]->nodename, refname, reflen - 1) == 0 &&
+ refs[i]->nodename[reflen - 1] == '-' &&
+ isdigit (refs[i]->nodename[reflen]))))
+ {
+ char *filename;
+
+ filename = node->parent;
+ if (!filename)
+ filename = node->filename;
+
+ fn_node = info_get_node (filename, refname);
+
+ if (fn_node)
+ fn_start = 0;
+
+ break;
+ }
+
+ free (refname);
+ info_free_references (refs);
+ }
+ }
+
+ /* If we never found the start of a footnotes area, quit now. */
+ if (fn_start == -1)
+ return NULL;
+
+ /* Make the new node. */
+ result = xmalloc (sizeof (NODE));
+ result->flags = 0;
+ result->display_pos = 0;
+
+ /* Get the size of the footnotes appearing within this node. */
+ {
+ char *header;
+ long text_start = fn_start;
+
+ header = xmalloc
+ (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT));
+ sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename);
+
+ /* Move the start of the displayed text to right after the first line.
+ This effectively skips either "---- footno...", or "File: foo...". */
+ while (text_start < fn_node->nodelen)
+ if (fn_node->contents[text_start++] == '\n')
+ break;
+
+ result->nodelen = strlen (header) + fn_node->nodelen - text_start;
+
+ /* Set the contents of this node. */
+ result->contents = xmalloc (1 + result->nodelen);
+ sprintf (result->contents, "%s", header);
+ memcpy (result->contents + strlen (header),
+ fn_node->contents + text_start, fn_node->nodelen - text_start);
+
+ name_internal_node (result, footnote_nodename);
+ free (header);
+ }
+
+#if defined (NOTDEF)
+ /* If the footnotes were gleaned from the node that we were called with,
+ shorten the calling node's display length. */
+ if (fn_node == node)
+ narrow_node (node, 0, fn_start);
+#endif /* NOTDEF */
+
+ return result;
+}
+
+/* Create or delete the footnotes window depending on whether footnotes
+ exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found
+ and displayed. Returns FN_UNFOUND if there were no footnotes found
+ in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the
+ window to show them couldn't be made. */
+int
+info_get_or_remove_footnotes (WINDOW *window)
+{
+ WINDOW *fn_win;
+ NODE *new_footnotes;
+
+ fn_win = find_footnotes_window ();
+
+ /* If we are in the footnotes window, change nothing. */
+ if (fn_win == window)
+ return FN_FOUND;
+
+ /* Try to find footnotes for this window's node. */
+ new_footnotes = make_footnotes_node (window->node);
+
+ /* If there was a window showing footnotes, and there are no footnotes
+ for the current window, delete the old footnote window. */
+ if (fn_win && !new_footnotes)
+ {
+ if (windows->next)
+ info_delete_window_internal (fn_win);
+ }
+
+ /* If there are footnotes for this window's node, but no window around
+ showing footnotes, try to make a new window. */
+ if (new_footnotes && !fn_win)
+ {
+ WINDOW *old_active;
+ WINDOW *last, *win;
+
+ /* Always make this window be the last one appearing in the list. Find
+ the last window in the chain. */
+ for (win = windows, last = windows; win; last = win, win = win->next);
+
+ /* Try to split this window, and make the split window the one to
+ contain the footnotes. */
+ old_active = active_window;
+ active_window = last;
+ fn_win = window_make_window (new_footnotes);
+ active_window = old_active;
+
+ if (!fn_win)
+ {
+ free (new_footnotes->contents);
+ free (new_footnotes);
+
+ /* If we are hacking automatic footnotes, and there are footnotes
+ but we couldn't display them, print a message to that effect. */
+ if (auto_footnotes_p)
+ inform_in_echo_area (_("Footnotes could not be displayed"));
+ return FN_UNABLE;
+ }
+ }
+
+ /* If there are footnotes, and there is a window to display them,
+ make that window be the number of lines appearing in the footnotes. */
+ if (new_footnotes && fn_win)
+ {
+ window_set_node_of_window (fn_win, new_footnotes);
+
+ window_change_window_height
+ (fn_win, fn_win->line_count - fn_win->height);
+
+ remember_window_and_node (fn_win, new_footnotes);
+ add_gcable_pointer (new_footnotes->contents);
+ }
+
+ if (!new_footnotes)
+ return FN_UNFOUND;
+ else
+ return FN_FOUND;
+}
+
+/* Show the footnotes associated with this node in another window. */
+DECLARE_INFO_COMMAND (info_show_footnotes,
+ _("Show the footnotes associated with this node in another window"))
+{
+ /* A negative argument means just make the window go away. */
+ if (count < 0)
+ {
+ WINDOW *fn_win = find_footnotes_window ();
+
+ /* If there is an old footnotes window, and it isn't the only window
+ on the screen, delete it. */
+ if (fn_win && windows->next)
+ info_delete_window_internal (fn_win);
+ }
+ else
+ {
+ int result;
+
+ result = info_get_or_remove_footnotes (window);
+
+ switch (result)
+ {
+ case FN_UNFOUND:
+ info_error (msg_no_foot_node, NULL, NULL);
+ break;
+
+ case FN_UNABLE:
+ info_error (msg_win_too_small, NULL, NULL);
+ break;
+ }
+ }
+}