man.c revision 21495
121495Sjmacd/*  man.c: How to read and format man files. */
221495Sjmacd
321495Sjmacd/* This file is part of GNU Info, a program for reading online documentation
421495Sjmacd   stored in Info format.
521495Sjmacd
621495Sjmacd   Copyright (C) 1995 Free Software Foundation, Inc.
721495Sjmacd
821495Sjmacd   This program is free software; you can redistribute it and/or modify
921495Sjmacd   it under the terms of the GNU General Public License as published by
1021495Sjmacd   the Free Software Foundation; either version 2, or (at your option)
1121495Sjmacd   any later version.
1221495Sjmacd
1321495Sjmacd   This program is distributed in the hope that it will be useful,
1421495Sjmacd   but WITHOUT ANY WARRANTY; without even the implied warranty of
1521495Sjmacd   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1621495Sjmacd   GNU General Public License for more details.
1721495Sjmacd
1821495Sjmacd   You should have received a copy of the GNU General Public License
1921495Sjmacd   along with this program; if not, write to the Free Software
2021495Sjmacd   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2121495Sjmacd
2221495Sjmacd   Written by Brian Fox Thu May  4 09:17:52 1995 (bfox@ai.mit.edu). */
2321495Sjmacd
2421495Sjmacd#include "info.h"
2521495Sjmacd#include <sys/ioctl.h>
2621495Sjmacd#include <sys/file.h>
2721495Sjmacd#include "signals.h"
2821495Sjmacd#if defined (HAVE_SYS_TIME_H)
2921495Sjmacd#include <sys/time.h>
3021495Sjmacd#endif
3121495Sjmacd#if defined (HAVE_SYS_WAIT_H)
3221495Sjmacd#include <sys/wait.h>
3321495Sjmacd#endif
3421495Sjmacd#include "tilde.h"
3521495Sjmacd
3621495Sjmacd#include "man.h"
3721495Sjmacd
3821495Sjmacd#if !defined (_POSIX_VERSION)
3921495Sjmacd#define pid_t int
4021495Sjmacd#endif
4121495Sjmacd
4221495Sjmacd#if defined (FD_SET)
4321495Sjmacd#  if defined (hpux)
4421495Sjmacd#    define fd_set_cast(x) (int *)(x)
4521495Sjmacd#  else
4621495Sjmacd#    define fd_set_cast(x) (fd_set *)(x)
4721495Sjmacd#  endif /* !hpux */
4821495Sjmacd#endif /* FD_SET */
4921495Sjmacd
5021495Sjmacdstatic char *read_from_fd ();
5121495Sjmacdstatic void clean_manpage ();
5221495Sjmacdstatic NODE *manpage_node_of_file_buffer ();
5321495Sjmacdstatic char *get_manpage_contents ();
5421495Sjmacd
5521495SjmacdNODE *
5621495Sjmacdmake_manpage_node (pagename)
5721495Sjmacd     char *pagename;
5821495Sjmacd{
5921495Sjmacd  return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
6021495Sjmacd}
6121495Sjmacd
6221495SjmacdNODE *
6321495Sjmacdget_manpage_node (file_buffer, pagename)
6421495Sjmacd     FILE_BUFFER *file_buffer;
6521495Sjmacd     char *pagename;
6621495Sjmacd{
6721495Sjmacd  NODE *node;
6821495Sjmacd
6921495Sjmacd  node = manpage_node_of_file_buffer (file_buffer, pagename);
7021495Sjmacd
7121495Sjmacd  if (!node)
7221495Sjmacd    {
7321495Sjmacd      char *page;
7421495Sjmacd
7521495Sjmacd      page = get_manpage_contents (pagename);
7621495Sjmacd
7721495Sjmacd      if (page)
7821495Sjmacd	{
7921495Sjmacd	  char header[1024];
8021495Sjmacd	  long oldsize, newsize;
8121495Sjmacd	  int hlen, plen;
8221495Sjmacd
8321495Sjmacd	  sprintf (header, "\n\n%c\n%s %s,  %s %s,  %s (dir)\n\n",
8421495Sjmacd		   INFO_COOKIE,
8521495Sjmacd		   INFO_FILE_LABEL, file_buffer->filename,
8621495Sjmacd		   INFO_NODE_LABEL, pagename,
8721495Sjmacd		   INFO_UP_LABEL);
8821495Sjmacd	  oldsize = file_buffer->filesize;
8921495Sjmacd	  hlen = strlen (header);
9021495Sjmacd	  plen = strlen (page);
9121495Sjmacd	  newsize = (oldsize + hlen + plen);
9221495Sjmacd	  file_buffer->contents =
9321495Sjmacd	    (char *)xrealloc (file_buffer->contents, 1 + newsize);
9421495Sjmacd	  memcpy (file_buffer->contents + oldsize, header, hlen);
9521495Sjmacd	  oldsize += hlen;
9621495Sjmacd	  memcpy (file_buffer->contents + oldsize, page, plen);
9721495Sjmacd	  file_buffer->contents[newsize] = '\0';
9821495Sjmacd	  file_buffer->filesize = newsize;
9921495Sjmacd	  file_buffer->finfo.st_size = newsize;
10021495Sjmacd	  build_tags_and_nodes (file_buffer);
10121495Sjmacd	  free (page);
10221495Sjmacd	}
10321495Sjmacd
10421495Sjmacd      node = manpage_node_of_file_buffer (file_buffer, pagename);
10521495Sjmacd    }
10621495Sjmacd
10721495Sjmacd  return (node);
10821495Sjmacd}
10921495Sjmacd
11021495SjmacdFILE_BUFFER *
11121495Sjmacdcreate_manpage_file_buffer ()
11221495Sjmacd{
11321495Sjmacd  FILE_BUFFER *file_buffer;
11421495Sjmacd  struct stat *finfo;
11521495Sjmacd
11621495Sjmacd  file_buffer = make_file_buffer ();
11721495Sjmacd  file_buffer->filename = strdup (MANPAGE_FILE_BUFFER_NAME);
11821495Sjmacd  file_buffer->fullpath = strdup (MANPAGE_FILE_BUFFER_NAME);
11921495Sjmacd  file_buffer->finfo.st_size = 0;
12021495Sjmacd  file_buffer->filesize = 0;
12121495Sjmacd  file_buffer->contents = (char *)NULL;
12221495Sjmacd  file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
12321495Sjmacd
12421495Sjmacd  return (file_buffer);
12521495Sjmacd}
12621495Sjmacd
12721495Sjmacd/* Scan the list of directories in PATH looking for FILENAME.  If we find
12821495Sjmacd   one that is an executable file, return it as a new string.  Otherwise,
12921495Sjmacd   return a NULL pointer. */
13021495Sjmacdstatic char *
13121495Sjmacdexecutable_file_in_path (filename, path)
13221495Sjmacd     char *filename, *path;
13321495Sjmacd{
13421495Sjmacd  struct stat finfo;
13521495Sjmacd  char *temp_dirname;
13621495Sjmacd  int statable, dirname_index;
13721495Sjmacd
13821495Sjmacd  dirname_index = 0;
13921495Sjmacd
14021495Sjmacd  while (temp_dirname = extract_colon_unit (path, &dirname_index))
14121495Sjmacd    {
14221495Sjmacd      register int i;
14321495Sjmacd      char *temp;
14421495Sjmacd
14521495Sjmacd      /* Expand a leading tilde if one is present. */
14621495Sjmacd      if (*temp_dirname == '~')
14721495Sjmacd	{
14821495Sjmacd	  char *expanded_dirname;
14921495Sjmacd
15021495Sjmacd	  expanded_dirname = tilde_expand_word (temp_dirname);
15121495Sjmacd	  free (temp_dirname);
15221495Sjmacd	  temp_dirname = expanded_dirname;
15321495Sjmacd	}
15421495Sjmacd
15521495Sjmacd      temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
15621495Sjmacd      strcpy (temp, temp_dirname);
15721495Sjmacd      if (temp[(strlen (temp)) - 1] != '/')
15821495Sjmacd	strcat (temp, "/");
15921495Sjmacd      strcat (temp, filename);
16021495Sjmacd
16121495Sjmacd      free (temp_dirname);
16221495Sjmacd
16321495Sjmacd      statable = (stat (temp, &finfo) == 0);
16421495Sjmacd
16521495Sjmacd      /* If we have found a regular executable file, then use it. */
16621495Sjmacd      if ((statable) && (S_ISREG (finfo.st_mode)) &&
16721495Sjmacd	  (access (temp, X_OK) == 0))
16821495Sjmacd	return (temp);
16921495Sjmacd      else
17021495Sjmacd	free (temp);
17121495Sjmacd    }
17221495Sjmacd  return ((char *)NULL);
17321495Sjmacd}
17421495Sjmacd
17521495Sjmacd/* Return the full pathname of the system man page formatter. */
17621495Sjmacdstatic char *
17721495Sjmacdfind_man_formatter ()
17821495Sjmacd{
17921495Sjmacd  return (executable_file_in_path ("man", (char *)getenv ("PATH")));
18021495Sjmacd}
18121495Sjmacd
18221495Sjmacdstatic char *manpage_pagename = (char *)NULL;
18321495Sjmacdstatic char *manpage_section  = (char *)NULL;
18421495Sjmacd
18521495Sjmacdstatic void
18621495Sjmacdget_page_and_section (pagename)
18721495Sjmacd     char *pagename;
18821495Sjmacd{
18921495Sjmacd  register int i;
19021495Sjmacd
19121495Sjmacd  if (manpage_pagename)
19221495Sjmacd    free (manpage_pagename);
19321495Sjmacd
19421495Sjmacd  if (manpage_section)
19521495Sjmacd    free (manpage_section);
19621495Sjmacd
19721495Sjmacd  manpage_pagename = (char *)NULL;
19821495Sjmacd  manpage_section  = (char *)NULL;
19921495Sjmacd
20021495Sjmacd  for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
20121495Sjmacd
20221495Sjmacd  manpage_pagename = (char *)xmalloc (1 + i);
20321495Sjmacd  strncpy (manpage_pagename, pagename, i);
20421495Sjmacd  manpage_pagename[i] = '\0';
20521495Sjmacd
20621495Sjmacd  if (pagename[i] == '(')
20721495Sjmacd    {
20821495Sjmacd      int start;
20921495Sjmacd
21021495Sjmacd      start = i + 1;
21121495Sjmacd
21221495Sjmacd      for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
21321495Sjmacd
21421495Sjmacd      manpage_section = (char *)xmalloc (1 + (i - start));
21521495Sjmacd      strncpy (manpage_section, pagename + start, (i - start));
21621495Sjmacd      manpage_section[i - start] = '\0';
21721495Sjmacd    }
21821495Sjmacd}
21921495Sjmacd
22021495Sjmacdstatic void
22121495Sjmacdreap_children (sig)
22221495Sjmacd     int sig;
22321495Sjmacd{
22421495Sjmacd  unsigned int status;
22521495Sjmacd  wait (&status);
22621495Sjmacd}
22721495Sjmacd
22821495Sjmacdstatic char *
22921495Sjmacdget_manpage_contents (pagename)
23021495Sjmacd     char *pagename;
23121495Sjmacd{
23221495Sjmacd  static char *formatter_args[4] = { (char *)NULL };
23321495Sjmacd  int pipes[2];
23421495Sjmacd  pid_t child;
23521495Sjmacd  char *formatted_page = (char *)NULL;
23621495Sjmacd  char *section = (char *)NULL;
23721495Sjmacd  int arg_index = 1;
23821495Sjmacd
23921495Sjmacd  if (formatter_args[0] == (char *)NULL)
24021495Sjmacd    formatter_args[0] = find_man_formatter ();
24121495Sjmacd
24221495Sjmacd  if (formatter_args[0] == (char *)NULL)
24321495Sjmacd    return ((char *)NULL);
24421495Sjmacd
24521495Sjmacd  get_page_and_section (pagename);
24621495Sjmacd
24721495Sjmacd  if (manpage_section != (char *)NULL)
24821495Sjmacd    formatter_args[arg_index++] = manpage_section;
24921495Sjmacd
25021495Sjmacd  formatter_args[arg_index++] = manpage_pagename;
25121495Sjmacd  formatter_args[arg_index] = (char *)NULL;
25221495Sjmacd
25321495Sjmacd  /* Open a pipe to this program, read the output, and save it away
25421495Sjmacd     in FORMATTED_PAGE.  The reader end of the pipe is pipes[0]; the
25521495Sjmacd     writer end is pipes[1]. */
25621495Sjmacd  pipe (pipes);
25721495Sjmacd
25821495Sjmacd  signal (SIGCHLD, reap_children);
25921495Sjmacd
26021495Sjmacd  child = fork ();
26121495Sjmacd
26221495Sjmacd  if (child == -1)
26321495Sjmacd    return ((char *)NULL);
26421495Sjmacd
26521495Sjmacd  if (child != 0)
26621495Sjmacd    {
26721495Sjmacd      /* In the parent, close the writing end of the pipe, and read from
26821495Sjmacd	 the exec'd child. */
26921495Sjmacd      close (pipes[1]);
27021495Sjmacd      formatted_page = read_from_fd (pipes[0]);
27121495Sjmacd      close (pipes[0]);
27221495Sjmacd    }
27321495Sjmacd  else
27421495Sjmacd    {
27521495Sjmacd      /* In the child, close the read end of the pipe, make the write end
27621495Sjmacd	 of the pipe be stdout, and execute the man page formatter. */
27721495Sjmacd      close (pipes[0]);
27821495Sjmacd      close (fileno (stderr));
27921495Sjmacd      close (fileno (stdin));	/* Don't print errors. */
28021495Sjmacd      dup2 (pipes[1], fileno (stdout));
28121495Sjmacd
28221495Sjmacd      execv (formatter_args[0], formatter_args);
28321495Sjmacd
28421495Sjmacd      /* If we get here, we couldn't exec, so close out the pipe and
28521495Sjmacd	 exit. */
28621495Sjmacd      close (pipes[1]);
28721495Sjmacd      exit (0);
28821495Sjmacd    }
28921495Sjmacd
29021495Sjmacd  /* If we have the page, then clean it up. */
29121495Sjmacd  if (formatted_page)
29221495Sjmacd    clean_manpage (formatted_page);
29321495Sjmacd
29421495Sjmacd  return (formatted_page);
29521495Sjmacd}
29621495Sjmacd
29721495Sjmacdstatic void
29821495Sjmacdclean_manpage (manpage)
29921495Sjmacd     char *manpage;
30021495Sjmacd{
30121495Sjmacd  register int i, j;
30221495Sjmacd  int newline_count = 0;
30321495Sjmacd  char *newpage;
30421495Sjmacd
30521495Sjmacd  newpage = (char *)xmalloc (1 + strlen (manpage));
30621495Sjmacd
30721495Sjmacd  for (i = 0, j = 0; newpage[j] = manpage[i]; i++, j++)
30821495Sjmacd    {
30921495Sjmacd      if (manpage[i] == '\n')
31021495Sjmacd	newline_count++;
31121495Sjmacd      else
31221495Sjmacd	newline_count = 0;
31321495Sjmacd
31421495Sjmacd      if (newline_count == 3)
31521495Sjmacd	{
31621495Sjmacd	  j--;
31721495Sjmacd	  newline_count--;
31821495Sjmacd	}
31921495Sjmacd
32021495Sjmacd      if (manpage[i] == '\b' || manpage[i] == '\f')
32121495Sjmacd	j -= 2;
32221495Sjmacd    }
32321495Sjmacd
32421495Sjmacd  newpage[j++] = '\0';
32521495Sjmacd
32621495Sjmacd  strcpy (manpage, newpage);
32721495Sjmacd  free (newpage);
32821495Sjmacd}
32921495Sjmacd
33021495Sjmacdstatic NODE *
33121495Sjmacdmanpage_node_of_file_buffer (file_buffer, pagename)
33221495Sjmacd     FILE_BUFFER *file_buffer;
33321495Sjmacd     char *pagename;
33421495Sjmacd{
33521495Sjmacd  NODE *node = (NODE *)NULL;
33621495Sjmacd  TAG *tag = (TAG *)NULL;
33721495Sjmacd
33821495Sjmacd  if (file_buffer->contents)
33921495Sjmacd    {
34021495Sjmacd      register int i;
34121495Sjmacd
34221495Sjmacd      for (i = 0; tag = file_buffer->tags[i]; i++)
34321495Sjmacd	{
34421495Sjmacd	  if (strcasecmp (pagename, tag->nodename) == 0)
34521495Sjmacd	    break;
34621495Sjmacd	}
34721495Sjmacd    }
34821495Sjmacd
34921495Sjmacd  if (tag)
35021495Sjmacd    {
35121495Sjmacd      node = (NODE *)xmalloc (sizeof (NODE));
35221495Sjmacd      node->filename = file_buffer->filename;
35321495Sjmacd      node->nodename = tag->nodename;
35421495Sjmacd      node->contents = file_buffer->contents + tag->nodestart;
35521495Sjmacd      node->nodelen = tag->nodelen;
35621495Sjmacd      node->flags    = 0;
35721495Sjmacd      node->parent   = (char *)NULL;
35821495Sjmacd      node->flags = (N_HasTagsTable | N_IsManPage);
35921495Sjmacd      node->contents += skip_node_separator (node->contents);
36021495Sjmacd    }
36121495Sjmacd
36221495Sjmacd  return (node);
36321495Sjmacd}
36421495Sjmacd
36521495Sjmacdstatic char *
36621495Sjmacdread_from_fd (fd)
36721495Sjmacd     int fd;
36821495Sjmacd{
36921495Sjmacd  struct timeval timeout;
37021495Sjmacd  char *buffer = (char *)NULL;
37121495Sjmacd  int bsize = 0;
37221495Sjmacd  int bindex = 0;
37321495Sjmacd  int select_result;
37421495Sjmacd#if defined (FD_SET)
37521495Sjmacd  fd_set read_fds;
37621495Sjmacd
37721495Sjmacd  timeout.tv_sec = 15;
37821495Sjmacd  timeout.tv_usec = 0;
37921495Sjmacd
38021495Sjmacd  FD_ZERO (&read_fds);
38121495Sjmacd  FD_SET (fd, &read_fds);
38221495Sjmacd
38321495Sjmacd  select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
38421495Sjmacd#else /* !FD_SET */
38521495Sjmacd  select_result = 1;
38621495Sjmacd#endif /* !FD_SET */
38721495Sjmacd
38821495Sjmacd  switch (select_result)
38921495Sjmacd    {
39021495Sjmacd    case 0:
39121495Sjmacd    case -1:
39221495Sjmacd      break;
39321495Sjmacd
39421495Sjmacd    default:
39521495Sjmacd      {
39621495Sjmacd        int amount_read;
39721495Sjmacd        int done = 0;
39821495Sjmacd
39921495Sjmacd        while (!done)
40021495Sjmacd          {
40121495Sjmacd            while ((bindex + 1024) > (bsize))
40221495Sjmacd              buffer = (char *)xrealloc (buffer, (bsize += 1024));
40321495Sjmacd            buffer[bindex] = '\0';
40421495Sjmacd
40521495Sjmacd            amount_read = read (fd, buffer + bindex, 1023);
40621495Sjmacd
40721495Sjmacd            if (amount_read < 0)
40821495Sjmacd              {
40921495Sjmacd                done = 1;
41021495Sjmacd              }
41121495Sjmacd            else
41221495Sjmacd              {
41321495Sjmacd                bindex += amount_read;
41421495Sjmacd                buffer[bindex] = '\0';
41521495Sjmacd                if (amount_read == 0)
41621495Sjmacd                  done = 1;
41721495Sjmacd              }
41821495Sjmacd          }
41921495Sjmacd      }
42021495Sjmacd    }
42121495Sjmacd
42221495Sjmacd  if ((buffer != (char *)NULL) && (*buffer == '\0'))
42321495Sjmacd    {
42421495Sjmacd      free (buffer);
42521495Sjmacd      buffer = (char *)NULL;
42621495Sjmacd    }
42721495Sjmacd
42821495Sjmacd  return (buffer);
42921495Sjmacd}
43021495Sjmacd
43121495Sjmacdstatic char *reference_section_starters[] =
43221495Sjmacd{
43321495Sjmacd  "\nRELATED INFORMATION",
43421495Sjmacd  "\nRELATED\tINFORMATION",
43521495Sjmacd  "RELATED INFORMATION\n",
43621495Sjmacd  "RELATED\tINFORMATION\n",
43721495Sjmacd  "\nSEE ALSO",
43821495Sjmacd  "\nSEE\tALSO",
43921495Sjmacd  "SEE ALSO\n",
44021495Sjmacd  "SEE\tALSO\n",
44121495Sjmacd  (char *)NULL
44221495Sjmacd};
44321495Sjmacd
44421495Sjmacdstatic SEARCH_BINDING frs_binding;
44521495Sjmacd
44621495Sjmacdstatic SEARCH_BINDING *
44721495Sjmacdfind_reference_section (node)
44821495Sjmacd     NODE *node;
44921495Sjmacd{
45021495Sjmacd  register int i;
45121495Sjmacd  long position = -1;
45221495Sjmacd
45321495Sjmacd  frs_binding.buffer = node->contents;
45421495Sjmacd  frs_binding.start = 0;
45521495Sjmacd  frs_binding.end = node->nodelen;
45621495Sjmacd  frs_binding.flags = S_SkipDest;
45721495Sjmacd
45821495Sjmacd  for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
45921495Sjmacd    {
46021495Sjmacd      position = search_forward (reference_section_starters[i], &frs_binding);
46121495Sjmacd      if (position != -1)
46221495Sjmacd	break;
46321495Sjmacd    }
46421495Sjmacd
46521495Sjmacd  if (position == -1)
46621495Sjmacd    return ((SEARCH_BINDING *)NULL);
46721495Sjmacd
46821495Sjmacd  /* We found the start of the reference section, and point is right after
46921495Sjmacd     the string which starts it.  The text from here to the next header
47021495Sjmacd     (or end of buffer) contains the only references in this manpage. */
47121495Sjmacd  frs_binding.start = position;
47221495Sjmacd
47321495Sjmacd  for (i = frs_binding.start; i < frs_binding.end - 2; i++)
47421495Sjmacd    {
47521495Sjmacd      if ((frs_binding.buffer[i] == '\n') &&
47621495Sjmacd	  (!whitespace (frs_binding.buffer[i + 1])))
47721495Sjmacd	{
47821495Sjmacd	  frs_binding.end = i;
47921495Sjmacd	  break;
48021495Sjmacd	}
48121495Sjmacd    }
48221495Sjmacd
48321495Sjmacd  return (&frs_binding);
48421495Sjmacd}
48521495Sjmacd
48621495SjmacdREFERENCE **
48721495Sjmacdxrefs_of_manpage (node)
48821495Sjmacd     NODE *node;
48921495Sjmacd{
49021495Sjmacd  SEARCH_BINDING *reference_section;
49121495Sjmacd  REFERENCE **refs = (REFERENCE **)NULL;
49221495Sjmacd  int refs_index = 0;
49321495Sjmacd  int refs_slots = 0;
49421495Sjmacd  long position;
49521495Sjmacd
49621495Sjmacd  reference_section = find_reference_section (node);
49721495Sjmacd
49821495Sjmacd  if (reference_section == (SEARCH_BINDING *)NULL)
49921495Sjmacd    return ((REFERENCE **)NULL);
50021495Sjmacd
50121495Sjmacd  /* Grovel the reference section building a list of references found there.
50221495Sjmacd     A reference is alphabetic characters followed by non-whitespace text
50321495Sjmacd     within parenthesis. */
50421495Sjmacd  reference_section->flags = 0;
50521495Sjmacd
50621495Sjmacd  while ((position = search_forward ("(", reference_section)) != -1)
50721495Sjmacd    {
50821495Sjmacd      register int start, end;
50921495Sjmacd
51021495Sjmacd      for (start = position; start > reference_section->start; start--)
51121495Sjmacd	if (whitespace (reference_section->buffer[start]))
51221495Sjmacd	  break;
51321495Sjmacd
51421495Sjmacd      start++;
51521495Sjmacd
51621495Sjmacd      for (end = position; end < reference_section->end; end++)
51721495Sjmacd	{
51821495Sjmacd	  if (whitespace (reference_section->buffer[end]))
51921495Sjmacd	    {
52021495Sjmacd	      end = start;
52121495Sjmacd	      break;
52221495Sjmacd	    }
52321495Sjmacd
52421495Sjmacd	  if (reference_section->buffer[end] == ')')
52521495Sjmacd	    {
52621495Sjmacd	      end++;
52721495Sjmacd	      break;
52821495Sjmacd	    }
52921495Sjmacd	}
53021495Sjmacd
53121495Sjmacd      if (end != start)
53221495Sjmacd	{
53321495Sjmacd	  REFERENCE *entry;
53421495Sjmacd	  int len = end - start;
53521495Sjmacd
53621495Sjmacd	  entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
53721495Sjmacd	  entry->label = (char *)xmalloc (1 + len);
53821495Sjmacd	  strncpy (entry->label, (reference_section->buffer) + start, len);
53921495Sjmacd	  entry->label[len] = '\0';
54021495Sjmacd	  entry->filename = strdup (node->filename);
54121495Sjmacd	  entry->nodename = strdup (entry->label);
54221495Sjmacd	  entry->start = start;
54321495Sjmacd	  entry->end = end;
54421495Sjmacd
54521495Sjmacd	  add_pointer_to_array
54621495Sjmacd	    (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
54721495Sjmacd	}
54821495Sjmacd
54921495Sjmacd      reference_section->start = position + 1;
55021495Sjmacd    }
55121495Sjmacd
55221495Sjmacd  return (refs);
55321495Sjmacd}
55421495Sjmacd
55521495Sjmacdlong
55621495Sjmacdlocate_manpage_xref (node, start, dir)
55721495Sjmacd     NODE *node;
55821495Sjmacd     long start;
55921495Sjmacd     int dir;
56021495Sjmacd{
56121495Sjmacd  register int i, count;
56221495Sjmacd  REFERENCE **refs;
56321495Sjmacd  long position = -1;
56421495Sjmacd
56521495Sjmacd  refs = xrefs_of_manpage (node);
56621495Sjmacd
56721495Sjmacd  if (refs)
56821495Sjmacd    {
56921495Sjmacd      register int i, count;
57021495Sjmacd      REFERENCE *entry;
57121495Sjmacd
57221495Sjmacd      for (i = 0; refs[i]; i++);
57321495Sjmacd      count = i;
57421495Sjmacd
57521495Sjmacd      if (dir > 0)
57621495Sjmacd	{
57721495Sjmacd	  for (i = 0; entry = refs[i]; i++)
57821495Sjmacd	    if (entry->start > start)
57921495Sjmacd	      {
58021495Sjmacd		position = entry->start;
58121495Sjmacd		break;
58221495Sjmacd	      }
58321495Sjmacd	}
58421495Sjmacd      else
58521495Sjmacd	{
58621495Sjmacd	  for (i = count - 1; i > -1; i--)
58721495Sjmacd	    {
58821495Sjmacd	      entry = refs[i];
58921495Sjmacd
59021495Sjmacd	      if (entry->start < start)
59121495Sjmacd		{
59221495Sjmacd		  position = entry->start;
59321495Sjmacd		  break;
59421495Sjmacd		}
59521495Sjmacd	    }
59621495Sjmacd	}
59721495Sjmacd
59821495Sjmacd      info_free_references (refs);
59921495Sjmacd    }
60021495Sjmacd  return (position);
60121495Sjmacd}
60221495Sjmacd
60321495Sjmacd/* This one was a little tricky.  The binding buffer that is passed in has
60421495Sjmacd   a START and END value of 0 -- strlen (window-line-containing-point).
60521495Sjmacd   The BUFFER is a pointer to the start of that line. */
60621495SjmacdREFERENCE **
60721495Sjmacdmanpage_xrefs_in_binding (node, binding)
60821495Sjmacd     NODE *node;
60921495Sjmacd     SEARCH_BINDING *binding;
61021495Sjmacd{
61121495Sjmacd  register int i;
61221495Sjmacd  REFERENCE **all_refs = xrefs_of_manpage (node);
61321495Sjmacd  REFERENCE **brefs = (REFERENCE **)NULL;
61421495Sjmacd  REFERENCE *entry;
61521495Sjmacd  int brefs_index = 0;
61621495Sjmacd  int brefs_slots = 0;
61721495Sjmacd  int start, end;
61821495Sjmacd
61921495Sjmacd  if (!all_refs)
62021495Sjmacd    return ((REFERENCE **)NULL);
62121495Sjmacd
62221495Sjmacd  start = binding->start + (binding->buffer - node->contents);
62321495Sjmacd  end = binding->end + (binding->buffer - node->contents);
62421495Sjmacd
62521495Sjmacd  for (i = 0; entry = all_refs[i]; i++)
62621495Sjmacd    {
62721495Sjmacd      if ((entry->start > start) && (entry->end < end))
62821495Sjmacd	{
62921495Sjmacd	  add_pointer_to_array
63021495Sjmacd	    (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
63121495Sjmacd	}
63221495Sjmacd      else
63321495Sjmacd	{
63421495Sjmacd	  maybe_free (entry->label);
63521495Sjmacd	  maybe_free (entry->filename);
63621495Sjmacd	  maybe_free (entry->nodename);
63721495Sjmacd	  free (entry);
63821495Sjmacd	}
63921495Sjmacd    }
64021495Sjmacd
64121495Sjmacd  free (all_refs);
64221495Sjmacd  return (brefs);
64321495Sjmacd}
644