File: footnotes.c

package info (click to toggle)
texinfo 7.2-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 113,148 kB
  • sloc: perl: 1,281,149; ansic: 135,801; sh: 12,218; xml: 9,069; makefile: 4,016; javascript: 1,923; awk: 1,889; sed: 78; pascal: 65
file content (274 lines) | stat: -rw-r--r-- 8,668 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* footnotes.c -- Some functions for manipulating footnotes.

   Copyright 1993-2024 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. */

#include "info.h"
#include "session.h"
#include "scan.h"
#include "util.h"
#include "footnotes.h"

/* Nonzero means attempt to show footnotes when displaying a new window. */
int auto_footnotes_p = 0;

static char *footnote_nodename = "*Footnotes*";

/* 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 = 0, *footnotes_node = NULL, *result = NULL;
  long fn_start;
  char *fnptr;

  /* Make the initial assumption that the footnotes appear as simple
     text within this windows node. */
  /* See if this node contains the magic footnote label. */
    {
      char saved = node->contents[node->nodelen];
      node->contents[node->nodelen] = '\0';
      fnptr = strstr (node->contents, FOOTNOTE_LABEL);
      node->contents[node->nodelen] = saved;
    }
  if (fnptr)
    {
      fn_node = node;
      fn_start = fnptr - node->contents;
    }
  /* If it doesn't, check to see if it has an associated footnotes node. */
  else
    {
      REFERENCE **refs;

      refs = node->references;

      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]->type == REFERENCE_XREF
                && (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 ((unsigned char) refs[i]->nodename[reflen]))))
              {
                footnotes_node = info_get_node (node->fullpath, refname);
                if (footnotes_node)
                  {
                    fn_node = footnotes_node;
                    fn_start = 0;
                  }
                break;
              }

          free (refname);
        }
    }

  /* Quit if we never found the node associated to the footnote. */
  if (fn_node == 0)
    return NULL;

  /* Make the new node. */
  result = info_create_node ();

  /* Get the size of the footnotes appearing within this node. */
  {
    char *header;
    long text_start = fn_start;

    xasprintf (&header,
              "*** Footnotes appearing in the node '%s' ***\n",
              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);
    result->contents[strlen (header) + fn_node->nodelen - text_start] = '\0';

   /* Copy and adjust references that appear in footnotes section. */
    {
      REFERENCE **ref = fn_node->references;

      for (; *ref; ref++)
        {
          if ((*ref)->start > text_start)
            break;
        }

      result->references = info_copy_references (ref);

      for (ref = result->references; *ref; ref++)
        {
          (*ref)->start -= text_start - strlen (header);
          (*ref)->end -= text_start - strlen (header);
        }
    }

    result->nodename = xstrdup (footnote_nodename);
    result->flags |= N_IsInternal | N_WasRewritten;

    /* Needed in case the user follows a reference in the footnotes window. */
    result->fullpath = fn_node->fullpath;
    result->subfile = fn_node->subfile;

    free (header);
  }

  free_history_node (footnotes_node);
  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 = 0;

  fn_win = find_footnotes_window ();

  /* If we are in the footnotes window, change nothing. */
  if (fn_win == window)
    return FN_FOUND;

  /* Don't display footnotes for the "*" node (entire contents of file) or
     for nodes without a name like completion windows. */
  if (window->node->nodename && strcmp ("*", window->node->nodename))
    /* Try to find footnotes for this window's node. */
    new_footnotes = make_footnotes_node (window->node);

  if (!new_footnotes)
    {
      /* If there was a window showing footnotes, and there are no footnotes
         for the current window, delete the old footnote window. */
      if (fn_win && windows->next)
        info_delete_window_internal (fn_win);
      return FN_UNFOUND;
    }

  /* If there is no window around showing footnotes, try
     to make a new window. */
  if (!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 ();
      active_window = old_active;

      /* If we are hacking automatic footnotes, and there are footnotes
         but we couldn't display them, print a message to that effect. */
      if (!fn_win)
        {
          if (auto_footnotes_p)
            info_error (_("Footnotes could not be displayed"));
          return FN_UNABLE;
        }
    }

  /* Note that info_set_node_of_window calls this function
     (info_get_or_remove_footnotes), but we do not recurse indefinitely
     because we check if we are in the footnote window above. */
  info_set_node_of_window (fn_win, new_footnotes);
  fn_win->flags |= W_TempWindow;

  /* Make the height be the number of lines appearing in the footnotes. */
  if (new_footnotes)
    window_change_window_height (fn_win, fn_win->line_count - fn_win->height);

  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"))
{
  /* Make the window go away if it is already showing. */
    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);
        return;
      }


    switch (info_get_or_remove_footnotes (window))
      {
      case FN_UNFOUND:
        info_error ("%s", msg_no_foot_node);
        break;

      case FN_UNABLE:
        info_error ("%s", msg_win_too_small);
        break;
      }
}