1/* footnotes.c -- Some functions for manipulating footnotes. 2 $Id: footnotes.c,v 1.1 2004/10/28 18:14:09 zooey Exp $ 3 4 Copyright (C) 1993, 97 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 20 Written by Brian Fox (bfox@ai.mit.edu). */ 21 22#include "info.h" 23 24/* Non-zero means attempt to show footnotes when displaying a new window. */ 25int auto_footnotes_p = 1; 26 27static char *footnote_nodename = "*Footnotes*"; 28 29#define FOOTNOTE_HEADER_FORMAT \ 30 "*** Footnotes appearing in the node \"%s\" ***\n" 31 32/* Find the window currently showing footnotes. */ 33static WINDOW * 34find_footnotes_window () 35{ 36 WINDOW *win; 37 38 /* Try to find an existing window first. */ 39 for (win = windows; win; win = win->next) 40 if (internal_info_node_p (win->node) && 41 (strcmp (win->node->nodename, footnote_nodename) == 0)) 42 break; 43 44 return (win); 45} 46 47/* Manufacture a node containing the footnotes of this node, and 48 return the manufactured node. If NODE has no footnotes, return a 49 NULL pointer. */ 50NODE * 51make_footnotes_node (node) 52 NODE *node; 53{ 54 NODE *fn_node, *result = (NODE *)NULL; 55 long fn_start; 56 57 /* Make the initial assumption that the footnotes appear as simple 58 text within this windows node. */ 59 fn_node = node; 60 61 /* See if this node contains the magic footnote label. */ 62 fn_start = 63 info_search_in_node (FOOTNOTE_LABEL, node, 0, (WINDOW *)NULL, 1); 64 65 /* If it doesn't, check to see if it has an associated footnotes node. */ 66 if (fn_start == -1) 67 { 68 REFERENCE **refs; 69 70 refs = info_xrefs_of_node (node); 71 72 if (refs) 73 { 74 register int i; 75 char *refname; 76 77 refname = (char *)xmalloc 78 (1 + strlen ("-Footnotes") + strlen (node->nodename)); 79 80 strcpy (refname, node->nodename); 81 strcat (refname, "-Footnotes"); 82 83 for (i = 0; refs[i]; i++) 84 if ((refs[i]->nodename != (char *)NULL) && 85 (strcmp (refs[i]->nodename, refname) == 0)) 86 { 87 char *filename; 88 89 filename = node->parent; 90 if (!filename) 91 filename = node->filename; 92 93 fn_node = info_get_node (filename, refname); 94 95 if (fn_node) 96 fn_start = 0; 97 98 break; 99 } 100 101 free (refname); 102 info_free_references (refs); 103 } 104 } 105 106 /* If we never found the start of a footnotes area, quit now. */ 107 if (fn_start == -1) 108 return ((NODE *)NULL); 109 110 /* Make the new node. */ 111 result = (NODE *)xmalloc (sizeof (NODE)); 112 result->flags = 0; 113 114 /* Get the size of the footnotes appearing within this node. */ 115 { 116 char *header; 117 long text_start = fn_start; 118 119 header = (char *)xmalloc 120 (1 + strlen (node->nodename) + strlen (FOOTNOTE_HEADER_FORMAT)); 121 sprintf (header, FOOTNOTE_HEADER_FORMAT, node->nodename); 122 123 /* Move the start of the displayed text to right after the first line. 124 This effectively skips either "---- footno...", or "File: foo...". */ 125 while (text_start < fn_node->nodelen) 126 if (fn_node->contents[text_start++] == '\n') 127 break; 128 129 result->nodelen = strlen (header) + fn_node->nodelen - text_start; 130 131 /* Set the contents of this node. */ 132 result->contents = (char *)xmalloc (1 + result->nodelen); 133 sprintf (result->contents, "%s", header); 134 memcpy (result->contents + strlen (header), 135 fn_node->contents + text_start, fn_node->nodelen - text_start); 136 137 name_internal_node (result, footnote_nodename); 138 free (header); 139 } 140 141#if defined (NOTDEF) 142 /* If the footnotes were gleaned from the node that we were called with, 143 shorten the calling node's display length. */ 144 if (fn_node == node) 145 narrow_node (node, 0, fn_start); 146#endif /* NOTDEF */ 147 148 return (result); 149} 150 151/* Create or delete the footnotes window depending on whether footnotes 152 exist in WINDOW's node or not. Returns FN_FOUND if footnotes were found 153 and displayed. Returns FN_UNFOUND if there were no footnotes found 154 in WINDOW's node. Returns FN_UNABLE if there were footnotes, but the 155 window to show them couldn't be made. */ 156int 157info_get_or_remove_footnotes (window) 158 WINDOW *window; 159{ 160 WINDOW *fn_win; 161 NODE *new_footnotes; 162 163 fn_win = find_footnotes_window (); 164 165 /* If we are in the footnotes window, change nothing. */ 166 if (fn_win == window) 167 return (FN_FOUND); 168 169 /* Try to find footnotes for this window's node. */ 170 new_footnotes = make_footnotes_node (window->node); 171 172 /* If there was a window showing footnotes, and there are no footnotes 173 for the current window, delete the old footnote window. */ 174 if (fn_win && !new_footnotes) 175 { 176 if (windows->next) 177 info_delete_window_internal (fn_win); 178 } 179 180 /* If there are footnotes for this window's node, but no window around 181 showing footnotes, try to make a new window. */ 182 if (new_footnotes && !fn_win) 183 { 184 WINDOW *old_active; 185 WINDOW *last, *win; 186 187 /* Always make this window be the last one appearing in the list. Find 188 the last window in the chain. */ 189 for (win = windows, last = windows; win; last = win, win = win->next); 190 191 /* Try to split this window, and make the split window the one to 192 contain the footnotes. */ 193 old_active = active_window; 194 active_window = last; 195 fn_win = window_make_window (new_footnotes); 196 active_window = old_active; 197 198 if (!fn_win) 199 { 200 free (new_footnotes->contents); 201 free (new_footnotes); 202 203 /* If we are hacking automatic footnotes, and there are footnotes 204 but we couldn't display them, print a message to that effect. */ 205 if (auto_footnotes_p) 206 inform_in_echo_area (_("Footnotes could not be displayed")); 207 return (FN_UNABLE); 208 } 209 } 210 211 /* If there are footnotes, and there is a window to display them, 212 make that window be the number of lines appearing in the footnotes. */ 213 if (new_footnotes && fn_win) 214 { 215 window_set_node_of_window (fn_win, new_footnotes); 216 217 window_change_window_height 218 (fn_win, fn_win->line_count - fn_win->height); 219 220 remember_window_and_node (fn_win, new_footnotes); 221 add_gcable_pointer (new_footnotes->contents); 222 } 223 224 if (!new_footnotes) 225 return (FN_UNFOUND); 226 else 227 return (FN_FOUND); 228} 229 230/* Show the footnotes associated with this node in another window. */ 231DECLARE_INFO_COMMAND (info_show_footnotes, 232 _("Show the footnotes associated with this node in another window")) 233{ 234 /* A negative argument means just make the window go away. */ 235 if (count < 0) 236 { 237 WINDOW *fn_win = find_footnotes_window (); 238 239 /* If there is an old footnotes window, and it isn't the only window 240 on the screen, delete it. */ 241 if (fn_win && windows->next) 242 info_delete_window_internal (fn_win); 243 } 244 else 245 { 246 int result; 247 248 result = info_get_or_remove_footnotes (window); 249 250 switch (result) 251 { 252 case FN_UNFOUND: 253 info_error (NO_FOOT_NODE); 254 break; 255 256 case FN_UNABLE: 257 info_error (WIN_TOO_SMALL); 258 break; 259 } 260 } 261} 262