1 /* man.c: How to read and format man files.
2 $Id: man.c,v 1.13 1999/07/05 20:43:23 karl Exp $
4 Copyright (C) 1995, 97, 98, 99 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
23 #include <sys/ioctl.h>
25 #if defined (HAVE_SYS_TIME_H)
28 #if defined (HAVE_SYS_WAIT_H)
35 #if !defined (_POSIX_VERSION)
41 # define fd_set_cast(x) (int *)(x)
43 # define fd_set_cast(x) (fd_set *)(x)
48 static char const * const exec_extensions[] = {
49 ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
52 static char const * const exec_extensions[] = { "", NULL };
55 static char *read_from_fd ();
56 static void clean_manpage ();
57 static NODE *manpage_node_of_file_buffer ();
58 static char *get_manpage_contents ();
61 make_manpage_node (pagename)
64 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
68 get_manpage_node (file_buffer, pagename)
69 FILE_BUFFER *file_buffer;
74 node = manpage_node_of_file_buffer (file_buffer, pagename);
80 page = get_manpage_contents (pagename);
85 long oldsize, newsize;
87 char *old_contents = file_buffer->contents;
89 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
91 INFO_FILE_LABEL, file_buffer->filename,
92 INFO_NODE_LABEL, pagename,
94 oldsize = file_buffer->filesize;
95 hlen = strlen (header);
97 newsize = (oldsize + hlen + plen);
98 file_buffer->contents =
99 (char *)xrealloc (file_buffer->contents, 1 + newsize);
100 memcpy (file_buffer->contents + oldsize, header, hlen);
101 memcpy (file_buffer->contents + oldsize + hlen, page, plen);
102 file_buffer->contents[newsize] = '\0';
103 file_buffer->filesize = newsize;
104 file_buffer->finfo.st_size = newsize;
105 build_tags_and_nodes (file_buffer);
107 /* We have just relocated file_buffer->contents from under
108 the feet of info_windows[] array. Therefore, all the
109 nodes on that list which are showing man pages have their
110 contents member pointing into the blue. Undo that harm. */
111 if (old_contents && oldsize && old_contents != file_buffer->contents)
114 INFO_WINDOW *info_win;
115 char *old_contents_end = old_contents + oldsize;
117 for (iw = 0; (info_win = info_windows[iw]); iw++)
121 for (in = 0; in < info_win->nodes_index; in++)
123 NODE *node = info_win->nodes[in];
125 /* It really only suffices to see that node->filename
126 is "*manpages*". But after several hours of
127 debugging this, would you blame me for being a bit
129 if (node && node->filename && node->contents &&
130 strcmp (node->filename,
131 MANPAGE_FILE_BUFFER_NAME) == 0 &&
132 node->contents >= old_contents &&
133 node->contents + node->nodelen <= old_contents_end)
135 info_win->nodes[in] =
136 manpage_node_of_file_buffer (file_buffer,
138 free (node->nodename);
146 node = manpage_node_of_file_buffer (file_buffer, pagename);
153 create_manpage_file_buffer ()
155 FILE_BUFFER *file_buffer = make_file_buffer ();
156 file_buffer->filename = xstrdup (MANPAGE_FILE_BUFFER_NAME);
157 file_buffer->fullpath = xstrdup (MANPAGE_FILE_BUFFER_NAME);
158 file_buffer->finfo.st_size = 0;
159 file_buffer->filesize = 0;
160 file_buffer->contents = (char *)NULL;
161 file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
163 return (file_buffer);
166 /* Scan the list of directories in PATH looking for FILENAME. If we find
167 one that is an executable file, return it as a new string. Otherwise,
168 return a NULL pointer. */
170 executable_file_in_path (filename, path)
171 char *filename, *path;
175 int statable, dirname_index;
179 while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
185 /* Expand a leading tilde if one is present. */
186 if (*temp_dirname == '~')
188 char *expanded_dirname;
190 expanded_dirname = tilde_expand_word (temp_dirname);
192 temp_dirname = expanded_dirname;
195 temp = (char *)xmalloc (34 + strlen (temp_dirname) + strlen (filename));
196 strcpy (temp, temp_dirname);
197 if (!IS_SLASH (temp[(strlen (temp)) - 1]))
199 strcat (temp, filename);
200 temp_end = temp + strlen (temp);
204 /* Look for FILENAME, possibly with any of the extensions
205 in EXEC_EXTENSIONS[]. */
206 for (i = 0; exec_extensions[i]; i++)
208 if (exec_extensions[i][0])
209 strcpy (temp_end, exec_extensions[i]);
210 statable = (stat (temp, &finfo) == 0);
212 /* If we have found a regular executable file, then use it. */
213 if ((statable) && (S_ISREG (finfo.st_mode)) &&
214 (access (temp, X_OK) == 0))
220 return ((char *)NULL);
223 /* Return the full pathname of the system man page formatter. */
225 find_man_formatter ()
227 return (executable_file_in_path ("man", (char *)getenv ("PATH")));
230 static char *manpage_pagename = (char *)NULL;
231 static char *manpage_section = (char *)NULL;
234 get_page_and_section (pagename)
239 if (manpage_pagename)
240 free (manpage_pagename);
243 free (manpage_section);
245 manpage_pagename = (char *)NULL;
246 manpage_section = (char *)NULL;
248 for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
250 manpage_pagename = (char *)xmalloc (1 + i);
251 strncpy (manpage_pagename, pagename, i);
252 manpage_pagename[i] = '\0';
254 if (pagename[i] == '(')
260 for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
262 manpage_section = (char *)xmalloc (1 + (i - start));
263 strncpy (manpage_section, pagename + start, (i - start));
264 manpage_section[i - start] = '\0';
278 get_manpage_contents (pagename)
281 static char *formatter_args[4] = { (char *)NULL };
284 RETSIGTYPE (*sigsave) ();
285 char *formatted_page = NULL;
288 if (formatter_args[0] == (char *)NULL)
289 formatter_args[0] = find_man_formatter ();
291 if (formatter_args[0] == (char *)NULL)
292 return ((char *)NULL);
294 get_page_and_section (pagename);
296 if (manpage_section != (char *)NULL)
297 formatter_args[arg_index++] = manpage_section;
299 formatter_args[arg_index++] = manpage_pagename;
300 formatter_args[arg_index] = (char *)NULL;
302 /* Open a pipe to this program, read the output, and save it away
303 in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
304 writer end is pipes[1]. */
308 sigsave = signal (SIGCHLD, reap_children);
312 return ((char *)NULL);
316 /* In the parent, close the writing end of the pipe, and read from
319 formatted_page = read_from_fd (pipes[0]);
321 signal (SIGCHLD, sigsave);
324 { /* In the child, close the read end of the pipe, make the write end
325 of the pipe be stdout, and execute the man page formatter. */
327 freopen (NULL_DEVICE, "w", stderr);
328 freopen (NULL_DEVICE, "r", stdin);
329 dup2 (pipes[1], fileno (stdout));
331 execv (formatter_args[0], formatter_args);
333 /* If we get here, we couldn't exec, so close out the pipe and
338 #else /* !PIPE_USE_FORK */
339 /* Cannot fork/exec, but can popen/pclose. */
342 char *cmdline = xmalloc (strlen (formatter_args[0])
343 + strlen (manpage_pagename)
344 + (arg_index > 2 ? strlen (manpage_section) : 0)
346 int save_stderr = dup (fileno (stderr));
347 int fd_err = open (NULL_DEVICE, O_WRONLY, 0666);
350 dup2 (fd_err, fileno (stderr)); /* Don't print errors. */
351 sprintf (cmdline, "%s %s %s", formatter_args[0], manpage_pagename,
352 arg_index > 2 ? manpage_section : "");
353 fpipe = popen (cmdline, "r");
357 dup2 (save_stderr, fileno (stderr));
359 return ((char *)NULL);
360 formatted_page = read_from_fd (fileno (fpipe));
361 if (pclose (fpipe) == -1)
364 free (formatted_page);
365 return ((char *)NULL);
368 #endif /* !PIPE_USE_FORK */
370 /* If we have the page, then clean it up. */
372 clean_manpage (formatted_page);
374 return (formatted_page);
378 clean_manpage (manpage)
382 int newline_count = 0;
385 newpage = (char *)xmalloc (1 + strlen (manpage));
387 for (i = 0, j = 0; (newpage[j] = manpage[i]); i++, j++)
389 if (manpage[i] == '\n')
394 if (newline_count == 3)
400 if (manpage[i] == '\b' || manpage[i] == '\f')
406 strcpy (manpage, newpage);
411 manpage_node_of_file_buffer (file_buffer, pagename)
412 FILE_BUFFER *file_buffer;
415 NODE *node = (NODE *)NULL;
416 TAG *tag = (TAG *)NULL;
418 if (file_buffer->contents)
422 for (i = 0; (tag = file_buffer->tags[i]); i++)
424 if (strcasecmp (pagename, tag->nodename) == 0)
431 node = (NODE *)xmalloc (sizeof (NODE));
432 node->filename = file_buffer->filename;
433 node->nodename = xstrdup (tag->nodename);
434 node->contents = file_buffer->contents + tag->nodestart;
435 node->nodelen = tag->nodelen;
437 node->display_pos = 0;
438 node->parent = (char *)NULL;
439 node->flags = (N_HasTagsTable | N_IsManPage);
440 node->contents += skip_node_separator (node->contents);
450 struct timeval timeout;
451 char *buffer = (char *)NULL;
462 FD_SET (fd, &read_fds);
464 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
469 switch (select_result)
482 while ((bindex + 1024) > (bsize))
483 buffer = (char *)xrealloc (buffer, (bsize += 1024));
484 buffer[bindex] = '\0';
486 amount_read = read (fd, buffer + bindex, 1023);
494 bindex += amount_read;
495 buffer[bindex] = '\0';
496 if (amount_read == 0)
503 if ((buffer != (char *)NULL) && (*buffer == '\0'))
506 buffer = (char *)NULL;
512 static char *reference_section_starters[] =
514 "\nRELATED INFORMATION",
515 "\nRELATED\tINFORMATION",
516 "RELATED INFORMATION\n",
517 "RELATED\tINFORMATION\n",
525 static SEARCH_BINDING frs_binding;
527 static SEARCH_BINDING *
528 find_reference_section (node)
534 frs_binding.buffer = node->contents;
535 frs_binding.start = 0;
536 frs_binding.end = node->nodelen;
537 frs_binding.flags = S_SkipDest;
539 for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
541 position = search_forward (reference_section_starters[i], &frs_binding);
547 return ((SEARCH_BINDING *)NULL);
549 /* We found the start of the reference section, and point is right after
550 the string which starts it. The text from here to the next header
551 (or end of buffer) contains the only references in this manpage. */
552 frs_binding.start = position;
554 for (i = frs_binding.start; i < frs_binding.end - 2; i++)
556 if ((frs_binding.buffer[i] == '\n') &&
557 (!whitespace (frs_binding.buffer[i + 1])))
564 return (&frs_binding);
568 xrefs_of_manpage (node)
571 SEARCH_BINDING *reference_section;
572 REFERENCE **refs = (REFERENCE **)NULL;
577 reference_section = find_reference_section (node);
579 if (reference_section == (SEARCH_BINDING *)NULL)
580 return ((REFERENCE **)NULL);
582 /* Grovel the reference section building a list of references found there.
583 A reference is alphabetic characters followed by non-whitespace text
584 within parenthesis. */
585 reference_section->flags = 0;
587 while ((position = search_forward ("(", reference_section)) != -1)
589 register int start, end;
591 for (start = position; start > reference_section->start; start--)
592 if (whitespace (reference_section->buffer[start]))
597 for (end = position; end < reference_section->end; end++)
599 if (whitespace (reference_section->buffer[end]))
605 if (reference_section->buffer[end] == ')')
615 int len = end - start;
617 entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
618 entry->label = (char *)xmalloc (1 + len);
619 strncpy (entry->label, (reference_section->buffer) + start, len);
620 entry->label[len] = '\0';
621 entry->filename = xstrdup (node->filename);
622 entry->nodename = xstrdup (entry->label);
623 entry->start = start;
627 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
630 reference_section->start = position + 1;
637 locate_manpage_xref (node, start, dir)
645 refs = xrefs_of_manpage (node);
649 register int i, count;
652 for (i = 0; refs[i]; i++);
657 for (i = 0; (entry = refs[i]); i++)
658 if (entry->start > start)
660 position = entry->start;
666 for (i = count - 1; i > -1; i--)
670 if (entry->start < start)
672 position = entry->start;
678 info_free_references (refs);
683 /* This one was a little tricky. The binding buffer that is passed in has
684 a START and END value of 0 -- strlen (window-line-containing-point).
685 The BUFFER is a pointer to the start of that line. */
687 manpage_xrefs_in_binding (node, binding)
689 SEARCH_BINDING *binding;
692 REFERENCE **all_refs = xrefs_of_manpage (node);
693 REFERENCE **brefs = (REFERENCE **)NULL;
700 return ((REFERENCE **)NULL);
702 start = binding->start + (binding->buffer - node->contents);
703 end = binding->end + (binding->buffer - node->contents);
705 for (i = 0; (entry = all_refs[i]); i++)
707 if ((entry->start > start) && (entry->end < end))
710 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
714 maybe_free (entry->label);
715 maybe_free (entry->filename);
716 maybe_free (entry->nodename);