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