142660Smarkm/* footnotes.c -- Some functions for manipulating footnotes. 2146515Sru $Id: footnotes.c,v 1.4 2004/04/11 17:56:45 karl Exp $ 321495Sjmacd 4146515Sru Copyright (C) 1993, 1997, 1998, 1999, 2002, 2004 Free Software 5146515Sru Foundation, Inc. 621495Sjmacd 721495Sjmacd This program is free software; you can redistribute it and/or modify 821495Sjmacd it under the terms of the GNU General Public License as published by 921495Sjmacd the Free Software Foundation; either version 2, or (at your option) 1021495Sjmacd any later version. 1121495Sjmacd 1221495Sjmacd This program is distributed in the hope that it will be useful, 1321495Sjmacd but WITHOUT ANY WARRANTY; without even the implied warranty of 1421495Sjmacd MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1521495Sjmacd GNU General Public License for more details. 1621495Sjmacd 1721495Sjmacd You should have received a copy of the GNU General Public License 1821495Sjmacd along with this program; if not, write to the Free Software 1921495Sjmacd Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2021495Sjmacd 21146515Sru Originally written by Brian Fox (bfox@ai.mit.edu). */ 2221495Sjmacd 2321495Sjmacd#include "info.h" 2421495Sjmacd 25114472Sru/* Nonzero means attempt to show footnotes when displaying a new window. */ 26114472Sruint auto_footnotes_p = 0; 2721495Sjmacd 2821495Sjmacdstatic char *footnote_nodename = "*Footnotes*"; 2921495Sjmacd 30146515SruNODE * make_footnotes_node (NODE *node); 31146515Sru 3221495Sjmacd#define FOOTNOTE_HEADER_FORMAT \ 33146515Sru "*** Footnotes appearing in the node `%s' ***\n" 3421495Sjmacd 3521495Sjmacd/* Find the window currently showing footnotes. */ 3621495Sjmacdstatic WINDOW * 37146515Srufind_footnotes_window (void) 3821495Sjmacd{ 3921495Sjmacd WINDOW *win; 4021495Sjmacd 4121495Sjmacd /* Try to find an existing window first. */ 4221495Sjmacd for (win = windows; win; win = win->next) 4321495Sjmacd if (internal_info_node_p (win->node) && 4442660Smarkm (strcmp (win->node->nodename, footnote_nodename) == 0)) 4521495Sjmacd break; 4621495Sjmacd 4721495Sjmacd return (win); 4821495Sjmacd} 4921495Sjmacd 5021495Sjmacd/* Manufacture a node containing the footnotes of this node, and 5121495Sjmacd return the manufactured node. If NODE has no footnotes, return a 5221495Sjmacd NULL pointer. */ 5321495SjmacdNODE * 54146515Srumake_footnotes_node (NODE *node) 5521495Sjmacd{ 5621495Sjmacd NODE *fn_node, *result = (NODE *)NULL; 5721495Sjmacd long fn_start; 5821495Sjmacd 5921495Sjmacd /* Make the initial assumption that the footnotes appear as simple 6021495Sjmacd text within this windows node. */ 6121495Sjmacd fn_node = node; 6221495Sjmacd 6321495Sjmacd /* See if this node contains the magic footnote label. */ 6421495Sjmacd fn_start = 6556160Sru info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1, 0); 6621495Sjmacd 6721495Sjmacd /* If it doesn't, check to see if it has an associated footnotes node. */ 6821495Sjmacd if (fn_start == -1) 6921495Sjmacd { 7021495Sjmacd REFERENCE **refs; 7121495Sjmacd 7221495Sjmacd refs = info_xrefs_of_node (node); 7321495Sjmacd 7421495Sjmacd if (refs) 7542660Smarkm { 7642660Smarkm register int i; 7742660Smarkm char *refname; 7856160Sru int reflen = strlen ("-Footnotes") + strlen (node->nodename); 7921495Sjmacd 8056160Sru refname = (char *)xmalloc (reflen + 1); 8121495Sjmacd 8242660Smarkm strcpy (refname, node->nodename); 8342660Smarkm strcat (refname, "-Footnotes"); 8421495Sjmacd 8542660Smarkm for (i = 0; refs[i]; i++) 8642660Smarkm if ((refs[i]->nodename != (char *)NULL) && 8756160Sru /* Support both the older "foo-Footnotes" and the new 8856160Sru style "foo-Footnote-NN" references. */ 8956160Sru (strcmp (refs[i]->nodename, refname) == 0 || 9056160Sru (strncmp (refs[i]->nodename, refname, reflen - 1) == 0 && 9156160Sru refs[i]->nodename[reflen - 1] == '-' && 9256160Sru isdigit (refs[i]->nodename[reflen])))) 9342660Smarkm { 9442660Smarkm char *filename; 9521495Sjmacd 9642660Smarkm filename = node->parent; 9742660Smarkm if (!filename) 9842660Smarkm filename = node->filename; 9921495Sjmacd 10042660Smarkm fn_node = info_get_node (filename, refname); 10121495Sjmacd 10242660Smarkm if (fn_node) 10342660Smarkm fn_start = 0; 10421495Sjmacd 10542660Smarkm break; 10642660Smarkm } 10721495Sjmacd 10842660Smarkm free (refname); 10942660Smarkm info_free_references (refs); 11042660Smarkm } 11121495Sjmacd } 11221495Sjmacd 11321495Sjmacd /* If we never found the start of a footnotes area, quit now. */ 11421495Sjmacd if (fn_start == -1) 11521495Sjmacd return ((NODE *)NULL); 11621495Sjmacd 11721495Sjmacd /* Make the new node. */ 11821495Sjmacd result = (NODE *)xmalloc (sizeof (NODE)); 11921495Sjmacd result->flags = 0; 12056160Sru result->display_pos = 0; 12121495Sjmacd 12221495Sjmacd /* Get the size of the footnotes appearing within this node. */ 12321495Sjmacd { 12421495Sjmacd char *header; 12521495Sjmacd long text_start = fn_start; 12621495Sjmacd 12721495Sjmacd header = (char *)xmalloc 12821495Sjmacd (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT)); 12921495Sjmacd sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename); 13021495Sjmacd 13121495Sjmacd /* Move the start of the displayed text to right after the first line. 13221495Sjmacd This effectively skips either "---- footno...", or "File: foo...". */ 13321495Sjmacd while (text_start < fn_node->nodelen) 13421495Sjmacd if (fn_node->contents[text_start++] == '\n') 13542660Smarkm break; 13621495Sjmacd 13721495Sjmacd result->nodelen = strlen (header) + fn_node->nodelen - text_start; 13821495Sjmacd 13921495Sjmacd /* Set the contents of this node. */ 14021495Sjmacd result->contents = (char *)xmalloc (1 + result->nodelen); 14121495Sjmacd sprintf (result->contents, "%s", header); 14221495Sjmacd memcpy (result->contents + strlen (header), 14342660Smarkm fn_node->contents + text_start, fn_node->nodelen - text_start); 14421495Sjmacd 14521495Sjmacd name_internal_node (result, footnote_nodename); 14621495Sjmacd free (header); 14721495Sjmacd } 14821495Sjmacd 14921495Sjmacd#if defined (NOTDEF) 15021495Sjmacd /* If the footnotes were gleaned from the node that we were called with, 15121495Sjmacd shorten the calling node's display length. */ 15221495Sjmacd if (fn_node == node) 15321495Sjmacd narrow_node (node, 0, fn_start); 15421495Sjmacd#endif /* NOTDEF */ 15521495Sjmacd 15621495Sjmacd return (result); 15721495Sjmacd} 15821495Sjmacd 15921495Sjmacd/* Create or delete the footnotes window depending on whether footnotes 16021495Sjmacd exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found 16121495Sjmacd and displayed. Returns FN_UNFOUND if there were no footnotes found 16221495Sjmacd in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the 16321495Sjmacd window to show them couldn't be made. */ 16421495Sjmacdint 165146515Sruinfo_get_or_remove_footnotes (WINDOW *window) 16621495Sjmacd{ 16721495Sjmacd WINDOW *fn_win; 16821495Sjmacd NODE *new_footnotes; 16921495Sjmacd 17021495Sjmacd fn_win = find_footnotes_window (); 17121495Sjmacd 17221495Sjmacd /* If we are in the footnotes window, change nothing. */ 17321495Sjmacd if (fn_win == window) 17421495Sjmacd return (FN_FOUND); 17521495Sjmacd 17621495Sjmacd /* Try to find footnotes for this window's node. */ 17721495Sjmacd new_footnotes = make_footnotes_node (window->node); 17821495Sjmacd 17921495Sjmacd /* If there was a window showing footnotes, and there are no footnotes 18021495Sjmacd for the current window, delete the old footnote window. */ 18121495Sjmacd if (fn_win && !new_footnotes) 18221495Sjmacd { 18321495Sjmacd if (windows->next) 18442660Smarkm info_delete_window_internal (fn_win); 18521495Sjmacd } 18621495Sjmacd 18721495Sjmacd /* If there are footnotes for this window's node, but no window around 18821495Sjmacd showing footnotes, try to make a new window. */ 18921495Sjmacd if (new_footnotes && !fn_win) 19021495Sjmacd { 19121495Sjmacd WINDOW *old_active; 19221495Sjmacd WINDOW *last, *win; 19321495Sjmacd 19421495Sjmacd /* Always make this window be the last one appearing in the list. Find 19542660Smarkm the last window in the chain. */ 19621495Sjmacd for (win = windows, last = windows; win; last = win, win = win->next); 19721495Sjmacd 19821495Sjmacd /* Try to split this window, and make the split window the one to 19942660Smarkm contain the footnotes. */ 20021495Sjmacd old_active = active_window; 20121495Sjmacd active_window = last; 20221495Sjmacd fn_win = window_make_window (new_footnotes); 20321495Sjmacd active_window = old_active; 20421495Sjmacd 20521495Sjmacd if (!fn_win) 20642660Smarkm { 20742660Smarkm free (new_footnotes->contents); 20842660Smarkm free (new_footnotes); 20921495Sjmacd 21042660Smarkm /* If we are hacking automatic footnotes, and there are footnotes 21142660Smarkm but we couldn't display them, print a message to that effect. */ 21242660Smarkm if (auto_footnotes_p) 213146515Sru inform_in_echo_area ((char *) _("Footnotes could not be displayed")); 21442660Smarkm return (FN_UNABLE); 21542660Smarkm } 21621495Sjmacd } 21721495Sjmacd 21821495Sjmacd /* If there are footnotes, and there is a window to display them, 21921495Sjmacd make that window be the number of lines appearing in the footnotes. */ 22021495Sjmacd if (new_footnotes && fn_win) 22121495Sjmacd { 22221495Sjmacd window_set_node_of_window (fn_win, new_footnotes); 22321495Sjmacd 22421495Sjmacd window_change_window_height 22542660Smarkm (fn_win, fn_win->line_count - fn_win->height); 22621495Sjmacd 22721495Sjmacd remember_window_and_node (fn_win, new_footnotes); 22821495Sjmacd add_gcable_pointer (new_footnotes->contents); 22921495Sjmacd } 23021495Sjmacd 23121495Sjmacd if (!new_footnotes) 23221495Sjmacd return (FN_UNFOUND); 23321495Sjmacd else 23421495Sjmacd return (FN_FOUND); 23521495Sjmacd} 23621495Sjmacd 23721495Sjmacd/* Show the footnotes associated with this node in another window. */ 23821495SjmacdDECLARE_INFO_COMMAND (info_show_footnotes, 23942660Smarkm _("Show the footnotes associated with this node in another window")) 24021495Sjmacd{ 24121495Sjmacd /* A negative argument means just make the window go away. */ 24221495Sjmacd if (count < 0) 24321495Sjmacd { 24421495Sjmacd WINDOW *fn_win = find_footnotes_window (); 24521495Sjmacd 24621495Sjmacd /* If there is an old footnotes window, and it isn't the only window 24742660Smarkm on the screen, delete it. */ 24821495Sjmacd if (fn_win && windows->next) 24942660Smarkm info_delete_window_internal (fn_win); 25021495Sjmacd } 25121495Sjmacd else 25221495Sjmacd { 25321495Sjmacd int result; 25421495Sjmacd 25521495Sjmacd result = info_get_or_remove_footnotes (window); 25621495Sjmacd 25721495Sjmacd switch (result) 25842660Smarkm { 25942660Smarkm case FN_UNFOUND: 260146515Sru info_error ((char *) msg_no_foot_node, NULL, NULL); 26142660Smarkm break; 26221495Sjmacd 26342660Smarkm case FN_UNABLE: 264146515Sru info_error ((char *) msg_win_too_small, NULL, NULL); 26542660Smarkm break; 26642660Smarkm } 26721495Sjmacd } 26821495Sjmacd} 269