diff options
Diffstat (limited to 'info/footnotes.c')
-rw-r--r-- | info/footnotes.c | 267 |
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; + } + } +} |