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