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