Fix incomplete stack traces by gdb.
[dragonfly.git] / contrib / texinfo-4 / info / man.c
blob33fd6d4be0bb73c5d1a556219a2cf10bc57b0550
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
5 Foundation, Inc.
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)
10 any later version.
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). */
23 #include "info.h"
24 #include <sys/ioctl.h>
25 #include "signals.h"
26 #if defined (HAVE_SYS_TIME_H)
27 #include <sys/time.h>
28 #endif
29 #if defined (HAVE_SYS_WAIT_H)
30 #include <sys/wait.h>
31 #endif
33 #include "tilde.h"
34 #include "man.h"
36 #if !defined (_POSIX_VERSION)
37 #define pid_t int
38 #endif
40 #if defined (FD_SET)
41 # if defined (hpux)
42 # define fd_set_cast(x) (int *)(x)
43 # else
44 # define fd_set_cast(x) (fd_set *)(x)
45 # endif /* !hpux */
46 #endif /* FD_SET */
48 #if STRIP_DOT_EXE
49 static char const * const exec_extensions[] = {
50 ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
52 #else
53 static char const * const exec_extensions[] = { "", NULL };
54 #endif
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,
59 char *pagename);
60 static char *get_manpage_contents (char *pagename);
62 NODE *
63 make_manpage_node (char *pagename)
65 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
68 NODE *
69 get_manpage_node (FILE_BUFFER *file_buffer, char *pagename)
71 NODE *node;
73 node = manpage_node_of_file_buffer (file_buffer, pagename);
75 if (!node)
77 char *page;
79 page = get_manpage_contents (pagename);
81 if (page)
83 char header[1024];
84 long oldsize, newsize;
85 int hlen, plen;
86 char *old_contents = file_buffer->contents;
88 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
89 INFO_COOKIE,
90 INFO_FILE_LABEL, file_buffer->filename,
91 INFO_NODE_LABEL, pagename,
92 INFO_UP_LABEL);
93 oldsize = file_buffer->filesize;
94 hlen = strlen (header);
95 plen = strlen (page);
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);
105 free (page);
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)
112 int iw;
113 INFO_WINDOW *info_win;
114 char *old_contents_end = old_contents + oldsize;
116 for (iw = 0; (info_win = info_windows[iw]); iw++)
118 int in;
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
127 paranoid? */
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
134 <= old_contents_end)
136 info_win->nodes[in] =
137 manpage_node_of_file_buffer (file_buffer,
138 tmp_node->nodename);
139 free (tmp_node->nodename);
140 free (tmp_node);
147 node = manpage_node_of_file_buffer (file_buffer, pagename);
150 return (node);
153 FILE_BUFFER *
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. */
170 static char *
171 executable_file_in_path (char *filename, char *path)
173 struct stat finfo;
174 char *temp_dirname;
175 int statable, dirname_index;
177 dirname_index = 0;
179 while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
181 char *temp;
182 char *temp_end;
183 int i;
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);
191 free (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]))
198 strcat (temp, "/");
199 strcat (temp, filename);
200 temp_end = temp + strlen (temp);
202 free (temp_dirname);
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))
215 return (temp);
218 free (temp);
220 return ((char *)NULL);
223 /* Return the full pathname of the system man page formatter. */
224 static char *
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;
233 static void
234 get_page_and_section (char *pagename)
236 register int i;
238 if (manpage_pagename)
239 free (manpage_pagename);
241 if (manpage_section)
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] == '(')
255 int start;
257 start = i + 1;
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';
267 #if PIPE_USE_FORK
268 static void
269 reap_children (int sig)
271 wait (NULL);
273 #endif
275 static char *
276 get_manpage_contents (char *pagename)
278 static char *formatter_args[4] = { (char *)NULL };
279 int pipes[2];
280 pid_t child;
281 RETSIGTYPE (*sigsave) (int signum);
282 char *formatted_page = NULL;
283 int arg_index = 1;
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]. */
302 #if PIPE_USE_FORK
303 pipe (pipes);
305 sigsave = signal (SIGCHLD, reap_children);
307 child = fork ();
308 if (child == -1)
309 return ((char *)NULL);
311 if (child != 0)
313 /* In the parent, close the writing end of the pipe, and read from
314 the exec'd child. */
315 close (pipes[1]);
316 formatted_page = read_from_fd (pipes[0]);
317 close (pipes[0]);
318 signal (SIGCHLD, sigsave);
320 else
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. */
323 close (pipes[0]);
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
331 exit. */
332 close (pipes[1]);
333 xexit (0);
335 #else /* !PIPE_USE_FORK */
336 /* Cannot fork/exec, but can popen/pclose. */
338 FILE *fpipe;
339 char *cmdline = xmalloc (strlen (formatter_args[0])
340 + strlen (manpage_pagename)
341 + (arg_index > 2 ? strlen (manpage_section) : 0)
342 + 3);
343 int save_stderr = dup (fileno (stderr));
344 int fd_err = open (NULL_DEVICE, O_WRONLY, 0666);
346 if (fd_err > 2)
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");
351 free (cmdline);
352 if (fd_err > 2)
353 close (fd_err);
354 dup2 (save_stderr, fileno (stderr));
355 if (fpipe == 0)
356 return ((char *)NULL);
357 formatted_page = read_from_fd (fileno (fpipe));
358 if (pclose (fpipe) == -1)
360 if (formatted_page)
361 free (formatted_page);
362 return ((char *)NULL);
365 #endif /* !PIPE_USE_FORK */
367 /* If we have the page, then clean it up. */
368 if (formatted_page)
369 clean_manpage (formatted_page);
371 return (formatted_page);
374 static void
375 clean_manpage (char *manpage)
377 register int i, j;
378 int newline_count = 0;
379 char *newpage;
381 newpage = (char *)xmalloc (1 + strlen (manpage));
383 for (i = 0, j = 0; (newpage[j] = manpage[i]); i++, j++)
385 if (manpage[i] == '\n')
386 newline_count++;
387 else
388 newline_count = 0;
390 if (newline_count == 3)
392 j--;
393 newline_count--;
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))
400 j -= 2;
401 else if (!raw_escapes_p)
403 /* Remove the ANSI escape sequences for color, boldface,
404 underlining, and italics, generated by some versions of
405 Groff. */
406 if (manpage[i] == '\033' && manpage[i + 1] == '['
407 && isdigit (manpage[i + 2]))
409 if (isdigit (manpage[i + 3]) && manpage[i + 4] == 'm')
411 i += 4;
412 j--;
414 else if (manpage[i + 3] == 'm')
416 i += 3;
417 j--;
419 /* Else do nothing: it's some unknown escape sequence,
420 so let's leave it alone. */
425 newpage[j++] = 0;
427 strcpy (manpage, newpage);
428 free (newpage);
431 static NODE *
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)
439 register int i;
441 for (i = 0; (tag = file_buffer->tags[i]); i++)
443 if (strcasecmp (pagename, tag->nodename) == 0)
444 break;
448 if (tag)
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;
455 node->flags = 0;
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);
462 return (node);
465 static char *
466 read_from_fd (int fd)
468 struct timeval timeout;
469 char *buffer = (char *)NULL;
470 int bsize = 0;
471 int bindex = 0;
472 int select_result;
473 #if defined (FD_SET)
474 fd_set read_fds;
476 timeout.tv_sec = 15;
477 timeout.tv_usec = 0;
479 FD_ZERO (&read_fds);
480 FD_SET (fd, &read_fds);
482 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
483 #else /* !FD_SET */
484 select_result = 1;
485 #endif /* !FD_SET */
487 switch (select_result)
489 case 0:
490 case -1:
491 break;
493 default:
495 int amount_read;
496 int done = 0;
498 while (!done)
500 while ((bindex + 1024) > (bsize))
501 buffer = (char *)xrealloc (buffer, (bsize += 1024));
502 buffer[bindex] = '\0';
504 amount_read = read (fd, buffer + bindex, 1023);
506 if (amount_read < 0)
508 done = 1;
510 else
512 bindex += amount_read;
513 buffer[bindex] = '\0';
514 if (amount_read == 0)
515 done = 1;
521 if ((buffer != (char *)NULL) && (*buffer == '\0'))
523 free (buffer);
524 buffer = (char *)NULL;
527 return (buffer);
530 static char *reference_section_starters[] =
532 "\nRELATED INFORMATION",
533 "\nRELATED\tINFORMATION",
534 "RELATED INFORMATION\n",
535 "RELATED\tINFORMATION\n",
536 "\nSEE ALSO",
537 "\nSEE\tALSO",
538 "SEE ALSO\n",
539 "SEE\tALSO\n",
540 (char *)NULL
543 static SEARCH_BINDING frs_binding;
545 static SEARCH_BINDING *
546 find_reference_section (NODE *node)
548 register int i;
549 long position = -1;
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);
559 if (position != -1)
560 break;
563 if (position == -1)
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])))
576 frs_binding.end = i;
577 break;
581 return (&frs_binding);
584 REFERENCE **
585 xrefs_of_manpage (NODE *node)
587 SEARCH_BINDING *reference_section;
588 REFERENCE **refs = (REFERENCE **)NULL;
589 int refs_index = 0;
590 int refs_slots = 0;
591 long position;
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]))
609 break;
611 start++;
613 for (end = position; end < reference_section->end; end++)
615 if (whitespace (reference_section->buffer[end]))
617 end = start;
618 break;
621 if (reference_section->buffer[end] == ')')
623 end++;
624 break;
628 if (end != start)
630 REFERENCE *entry;
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;
640 entry->end = end;
642 add_pointer_to_array
643 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
646 reference_section->start = position + 1;
649 return (refs);
652 long
653 locate_manpage_xref (NODE *node, long int start, int dir)
655 REFERENCE **refs;
656 long position = -1;
658 refs = xrefs_of_manpage (node);
660 if (refs)
662 register int i, count;
663 REFERENCE *entry;
665 for (i = 0; refs[i]; i++);
666 count = i;
668 if (dir > 0)
670 for (i = 0; (entry = refs[i]); i++)
671 if (entry->start > start)
673 position = entry->start;
674 break;
677 else
679 for (i = count - 1; i > -1; i--)
681 entry = refs[i];
683 if (entry->start < start)
685 position = entry->start;
686 break;
691 info_free_references (refs);
693 return (position);
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. */
699 REFERENCE **
700 manpage_xrefs_in_binding (NODE *node, SEARCH_BINDING *binding)
702 register int i;
703 REFERENCE **all_refs = xrefs_of_manpage (node);
704 REFERENCE **brefs = (REFERENCE **)NULL;
705 REFERENCE *entry;
706 int brefs_index = 0;
707 int brefs_slots = 0;
708 int start, end;
710 if (!all_refs)
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))
720 add_pointer_to_array
721 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
723 else
725 maybe_free (entry->label);
726 maybe_free (entry->filename);
727 maybe_free (entry->nodename);
728 free (entry);
732 free (all_refs);
733 return (brefs);