1 /* man.c: How to read and format man files.
2 $Id: man.c,v 1.4 2004/04/11 17:56:46 karl Exp $
4 Copyright (C) 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free Software
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 Written by Brian Fox Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
24 #include <sys/ioctl.h>
26 #if defined (HAVE_SYS_TIME_H)
29 #if defined (HAVE_SYS_WAIT_H)
36 #if !defined (_POSIX_VERSION)
42 # define fd_set_cast(x) (int *)(x)
44 # define fd_set_cast(x) (fd_set *)(x)
49 static char const * const exec_extensions[] = {
50 ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
53 static char const * const exec_extensions[] = { "", NULL };
56 static char *read_from_fd (int fd);
57 static void clean_manpage (char *manpage);
58 static NODE *manpage_node_of_file_buffer (FILE_BUFFER *file_buffer,
60 static char *get_manpage_contents (char *pagename);
63 make_manpage_node (char *pagename)
65 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
69 get_manpage_node (FILE_BUFFER *file_buffer, char *pagename)
73 node = manpage_node_of_file_buffer (file_buffer, pagename);
79 page = get_manpage_contents (pagename);
84 long oldsize, newsize;
86 char *old_contents = file_buffer->contents;
88 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
90 INFO_FILE_LABEL, file_buffer->filename,
91 INFO_NODE_LABEL, pagename,
93 oldsize = file_buffer->filesize;
94 hlen = strlen (header);
96 newsize = (oldsize + hlen + plen);
97 file_buffer->contents =
98 (char *)xrealloc (file_buffer->contents, 1 + newsize);
99 memcpy (file_buffer->contents + oldsize, header, hlen);
100 memcpy (file_buffer->contents + oldsize + hlen, page, plen);
101 file_buffer->contents[newsize] = '\0';
102 file_buffer->filesize = newsize;
103 file_buffer->finfo.st_size = newsize;
104 build_tags_and_nodes (file_buffer);
106 /* We have just relocated file_buffer->contents from under
107 the feet of info_windows[] array. Therefore, all the
108 nodes on that list which are showing man pages have their
109 contents member pointing into the blue. Undo that harm. */
110 if (old_contents && oldsize && old_contents != file_buffer->contents)
113 INFO_WINDOW *info_win;
114 char *old_contents_end = old_contents + oldsize;
116 for (iw = 0; (info_win = info_windows[iw]); iw++)
120 for (in = 0; in < info_win->nodes_index; in++)
122 NODE *tmp_node = info_win->nodes[in];
124 /* It really only suffices to see that node->filename
125 is "*manpages*". But after several hours of
126 debugging this, would you blame me for being a bit
128 if (tmp_node && tmp_node->filename
129 && tmp_node->contents
130 && strcmp (tmp_node->filename,
131 MANPAGE_FILE_BUFFER_NAME) == 0
132 && tmp_node->contents >= old_contents
133 && tmp_node->contents + tmp_node->nodelen
136 info_win->nodes[in] =
137 manpage_node_of_file_buffer (file_buffer,
139 free (tmp_node->nodename);
147 node = manpage_node_of_file_buffer (file_buffer, pagename);
154 create_manpage_file_buffer (void)
156 FILE_BUFFER *file_buffer = make_file_buffer ();
157 file_buffer->filename = xstrdup (MANPAGE_FILE_BUFFER_NAME);
158 file_buffer->fullpath = xstrdup (MANPAGE_FILE_BUFFER_NAME);
159 file_buffer->finfo.st_size = 0;
160 file_buffer->filesize = 0;
161 file_buffer->contents = (char *)NULL;
162 file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
164 return (file_buffer);
167 /* Scan the list of directories in PATH looking for FILENAME. If we find
168 one that is an executable file, return it as a new string. Otherwise,
169 return a NULL pointer. */
171 executable_file_in_path (char *filename, char *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 (void)
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 (char *pagename)
238 if (manpage_pagename)
239 free (manpage_pagename);
242 free (manpage_section);
244 manpage_pagename = (char *)NULL;
245 manpage_section = (char *)NULL;
247 for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
249 manpage_pagename = (char *)xmalloc (1 + i);
250 strncpy (manpage_pagename, pagename, i);
251 manpage_pagename[i] = '\0';
253 if (pagename[i] == '(')
259 for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
261 manpage_section = (char *)xmalloc (1 + (i - start));
262 strncpy (manpage_section, pagename + start, (i - start));
263 manpage_section[i - start] = '\0';
269 reap_children (int sig)
276 get_manpage_contents (char *pagename)
278 static char *formatter_args[4] = { (char *)NULL };
281 RETSIGTYPE (*sigsave) (int signum);
282 char *formatted_page = NULL;
285 if (formatter_args[0] == (char *)NULL)
286 formatter_args[0] = find_man_formatter ();
288 if (formatter_args[0] == (char *)NULL)
289 return ((char *)NULL);
291 get_page_and_section (pagename);
293 if (manpage_section != (char *)NULL)
294 formatter_args[arg_index++] = manpage_section;
296 formatter_args[arg_index++] = manpage_pagename;
297 formatter_args[arg_index] = (char *)NULL;
299 /* Open a pipe to this program, read the output, and save it away
300 in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
301 writer end is pipes[1]. */
305 sigsave = signal (SIGCHLD, reap_children);
309 return ((char *)NULL);
313 /* In the parent, close the writing end of the pipe, and read from
316 formatted_page = read_from_fd (pipes[0]);
318 signal (SIGCHLD, sigsave);
321 { /* In the child, close the read end of the pipe, make the write end
322 of the pipe be stdout, and execute the man page formatter. */
324 freopen (NULL_DEVICE, "w", stderr);
325 freopen (NULL_DEVICE, "r", stdin);
326 dup2 (pipes[1], fileno (stdout));
328 execv (formatter_args[0], formatter_args);
330 /* If we get here, we couldn't exec, so close out the pipe and
335 #else /* !PIPE_USE_FORK */
336 /* Cannot fork/exec, but can popen/pclose. */
339 char *cmdline = xmalloc (strlen (formatter_args[0])
340 + strlen (manpage_pagename)
341 + (arg_index > 2 ? strlen (manpage_section) : 0)
343 int save_stderr = dup (fileno (stderr));
344 int fd_err = open (NULL_DEVICE, O_WRONLY, 0666);
347 dup2 (fd_err, fileno (stderr)); /* Don't print errors. */
348 sprintf (cmdline, "%s %s %s", formatter_args[0], manpage_pagename,
349 arg_index > 2 ? manpage_section : "");
350 fpipe = popen (cmdline, "r");
354 dup2 (save_stderr, fileno (stderr));
356 return ((char *)NULL);
357 formatted_page = read_from_fd (fileno (fpipe));
358 if (pclose (fpipe) == -1)
361 free (formatted_page);
362 return ((char *)NULL);
365 #endif /* !PIPE_USE_FORK */
367 /* If we have the page, then clean it up. */
369 clean_manpage (formatted_page);
371 return (formatted_page);
375 clean_manpage (char *manpage)
378 int newline_count = 0;
381 newpage = (char *)xmalloc (1 + strlen (manpage));
383 for (i = 0, j = 0; (newpage[j] = manpage[i]); i++, j++)
385 if (manpage[i] == '\n')
390 if (newline_count == 3)
396 /* A malformed man page could have a \b as its first character,
397 in which case decrementing j by 2 will cause us to write into
398 newpage[-1], smashing the hidden info stored there by malloc. */
399 if (manpage[i] == '\b' || (manpage[i] == '\f' && j > 0))
401 else if (!raw_escapes_p)
403 /* Remove the ANSI escape sequences for color, boldface,
404 underlining, and italics, generated by some versions of
406 if (manpage[i] == '\033' && manpage[i + 1] == '['
407 && isdigit (manpage[i + 2]))
409 if (isdigit (manpage[i + 3]) && manpage[i + 4] == 'm')
414 else if (manpage[i + 3] == 'm')
419 /* Else do nothing: it's some unknown escape sequence,
420 so let's leave it alone. */
427 strcpy (manpage, newpage);
432 manpage_node_of_file_buffer (FILE_BUFFER *file_buffer, char *pagename)
434 NODE *node = (NODE *)NULL;
435 TAG *tag = (TAG *)NULL;
437 if (file_buffer->contents)
441 for (i = 0; (tag = file_buffer->tags[i]); i++)
443 if (strcasecmp (pagename, tag->nodename) == 0)
450 node = (NODE *)xmalloc (sizeof (NODE));
451 node->filename = file_buffer->filename;
452 node->nodename = xstrdup (tag->nodename);
453 node->contents = file_buffer->contents + tag->nodestart;
454 node->nodelen = tag->nodelen;
456 node->display_pos = 0;
457 node->parent = (char *)NULL;
458 node->flags = (N_HasTagsTable | N_IsManPage);
459 node->contents += skip_node_separator (node->contents);
466 read_from_fd (int fd)
468 struct timeval timeout;
469 char *buffer = (char *)NULL;
480 FD_SET (fd, &read_fds);
482 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
487 switch (select_result)
500 while ((bindex + 1024) > (bsize))
501 buffer = (char *)xrealloc (buffer, (bsize += 1024));
502 buffer[bindex] = '\0';
504 amount_read = read (fd, buffer + bindex, 1023);
512 bindex += amount_read;
513 buffer[bindex] = '\0';
514 if (amount_read == 0)
521 if ((buffer != (char *)NULL) && (*buffer == '\0'))
524 buffer = (char *)NULL;
530 static char *reference_section_starters[] =
532 "\nRELATED INFORMATION",
533 "\nRELATED\tINFORMATION",
534 "RELATED INFORMATION\n",
535 "RELATED\tINFORMATION\n",
543 static SEARCH_BINDING frs_binding;
545 static SEARCH_BINDING *
546 find_reference_section (NODE *node)
551 frs_binding.buffer = node->contents;
552 frs_binding.start = 0;
553 frs_binding.end = node->nodelen;
554 frs_binding.flags = S_SkipDest;
556 for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
558 position = search_forward (reference_section_starters[i], &frs_binding);
564 return ((SEARCH_BINDING *)NULL);
566 /* We found the start of the reference section, and point is right after
567 the string which starts it. The text from here to the next header
568 (or end of buffer) contains the only references in this manpage. */
569 frs_binding.start = position;
571 for (i = frs_binding.start; i < frs_binding.end - 2; i++)
573 if ((frs_binding.buffer[i] == '\n') &&
574 (!whitespace (frs_binding.buffer[i + 1])))
581 return (&frs_binding);
585 xrefs_of_manpage (NODE *node)
587 SEARCH_BINDING *reference_section;
588 REFERENCE **refs = (REFERENCE **)NULL;
593 reference_section = find_reference_section (node);
595 if (reference_section == (SEARCH_BINDING *)NULL)
596 return ((REFERENCE **)NULL);
598 /* Grovel the reference section building a list of references found there.
599 A reference is alphabetic characters followed by non-whitespace text
600 within parenthesis. */
601 reference_section->flags = 0;
603 while ((position = search_forward ("(", reference_section)) != -1)
605 register int start, end;
607 for (start = position; start > reference_section->start; start--)
608 if (whitespace (reference_section->buffer[start]))
613 for (end = position; end < reference_section->end; end++)
615 if (whitespace (reference_section->buffer[end]))
621 if (reference_section->buffer[end] == ')')
631 int len = end - start;
633 entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
634 entry->label = (char *)xmalloc (1 + len);
635 strncpy (entry->label, (reference_section->buffer) + start, len);
636 entry->label[len] = '\0';
637 entry->filename = xstrdup (node->filename);
638 entry->nodename = xstrdup (entry->label);
639 entry->start = start;
643 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
646 reference_section->start = position + 1;
653 locate_manpage_xref (NODE *node, long int start, int dir)
658 refs = xrefs_of_manpage (node);
662 register int i, count;
665 for (i = 0; refs[i]; i++);
670 for (i = 0; (entry = refs[i]); i++)
671 if (entry->start > start)
673 position = entry->start;
679 for (i = count - 1; i > -1; i--)
683 if (entry->start < start)
685 position = entry->start;
691 info_free_references (refs);
696 /* This one was a little tricky. The binding buffer that is passed in has
697 a START and END value of 0 -- strlen (window-line-containing-point).
698 The BUFFER is a pointer to the start of that line. */
700 manpage_xrefs_in_binding (NODE *node, SEARCH_BINDING *binding)
703 REFERENCE **all_refs = xrefs_of_manpage (node);
704 REFERENCE **brefs = (REFERENCE **)NULL;
711 return ((REFERENCE **)NULL);
713 start = binding->start + (binding->buffer - node->contents);
714 end = binding->end + (binding->buffer - node->contents);
716 for (i = 0; (entry = all_refs[i]); i++)
718 if ((entry->start > start) && (entry->end < end))
721 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
725 maybe_free (entry->label);
726 maybe_free (entry->filename);
727 maybe_free (entry->nodename);