No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / texinfo / info / man.c
blob92d02b5e0e351a9f94996303aee5ad96e798d03a
1 /* $NetBSD$ */
3 /* man.c: How to read and format man files.
4 Id: man.c,v 1.4 2004/04/11 17:56:46 karl Exp
6 Copyright (C) 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free Software
7 Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Written by Brian Fox Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
25 #include "info.h"
26 #include <sys/ioctl.h>
27 #include "signals.h"
28 #if defined (HAVE_SYS_TIME_H)
29 #include <sys/time.h>
30 #endif
31 #if defined (HAVE_SYS_WAIT_H)
32 #include <sys/wait.h>
33 #endif
35 #include "tilde.h"
36 #include "man.h"
38 #if !defined (_POSIX_VERSION)
39 #define pid_t int
40 #endif
42 #if defined (FD_SET)
43 # if defined (hpux)
44 # define fd_set_cast(x) (int *)(x)
45 # else
46 # define fd_set_cast(x) (fd_set *)(x)
47 # endif /* !hpux */
48 #endif /* FD_SET */
50 #if STRIP_DOT_EXE
51 static char const * const exec_extensions[] = {
52 ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
54 #else
55 static char const * const exec_extensions[] = { "", NULL };
56 #endif
58 static char *read_from_fd (int fd);
59 static void clean_manpage (char *manpage);
60 static NODE *manpage_node_of_file_buffer (FILE_BUFFER *file_buffer,
61 char *pagename);
62 static char *get_manpage_contents (char *pagename);
64 NODE *
65 make_manpage_node (char *pagename)
67 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
70 NODE *
71 get_manpage_node (FILE_BUFFER *file_buffer, char *pagename)
73 NODE *node;
75 node = manpage_node_of_file_buffer (file_buffer, pagename);
77 if (!node)
79 char *page;
81 page = get_manpage_contents (pagename);
83 if (page)
85 char header[1024];
86 long oldsize, newsize;
87 int hlen, plen;
88 char *old_contents = file_buffer->contents;
90 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
91 INFO_COOKIE,
92 INFO_FILE_LABEL, file_buffer->filename,
93 INFO_NODE_LABEL, pagename,
94 INFO_UP_LABEL);
95 oldsize = file_buffer->filesize;
96 hlen = strlen (header);
97 plen = strlen (page);
98 newsize = (oldsize + hlen + plen);
99 file_buffer->contents =
100 (char *)xrealloc (file_buffer->contents, 1 + newsize);
101 memcpy (file_buffer->contents + oldsize, header, hlen);
102 memcpy (file_buffer->contents + oldsize + hlen, page, plen);
103 file_buffer->contents[newsize] = '\0';
104 file_buffer->filesize = newsize;
105 file_buffer->finfo.st_size = newsize;
106 build_tags_and_nodes (file_buffer);
107 free (page);
108 /* We have just relocated file_buffer->contents from under
109 the feet of info_windows[] array. Therefore, all the
110 nodes on that list which are showing man pages have their
111 contents member pointing into the blue. Undo that harm. */
112 if (old_contents && oldsize && old_contents != file_buffer->contents)
114 int iw;
115 INFO_WINDOW *info_win;
116 char *old_contents_end = old_contents + oldsize;
118 for (iw = 0; (info_win = info_windows[iw]); iw++)
120 int in;
122 for (in = 0; in < info_win->nodes_index; in++)
124 NODE *tmp_node = info_win->nodes[in];
126 /* It really only suffices to see that node->filename
127 is "*manpages*". But after several hours of
128 debugging this, would you blame me for being a bit
129 paranoid? */
130 if (tmp_node && tmp_node->filename
131 && tmp_node->contents
132 && strcmp (tmp_node->filename,
133 MANPAGE_FILE_BUFFER_NAME) == 0
134 && tmp_node->contents >= old_contents
135 && tmp_node->contents + tmp_node->nodelen
136 <= old_contents_end)
138 info_win->nodes[in] =
139 manpage_node_of_file_buffer (file_buffer,
140 tmp_node->nodename);
141 free (tmp_node->nodename);
142 free (tmp_node);
149 node = manpage_node_of_file_buffer (file_buffer, pagename);
152 return (node);
155 FILE_BUFFER *
156 create_manpage_file_buffer (void)
158 FILE_BUFFER *file_buffer = make_file_buffer ();
159 file_buffer->filename = xstrdup (MANPAGE_FILE_BUFFER_NAME);
160 file_buffer->fullpath = xstrdup (MANPAGE_FILE_BUFFER_NAME);
161 file_buffer->finfo.st_size = 0;
162 file_buffer->filesize = 0;
163 file_buffer->contents = (char *)NULL;
164 file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
166 return (file_buffer);
169 /* Scan the list of directories in PATH looking for FILENAME. If we find
170 one that is an executable file, return it as a new string. Otherwise,
171 return a NULL pointer. */
172 static char *
173 executable_file_in_path (char *filename, char *path)
175 struct stat finfo;
176 char *temp_dirname;
177 int statable, dirname_index;
179 dirname_index = 0;
181 while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
183 char *temp;
184 char *temp_end;
185 int i;
187 /* Expand a leading tilde if one is present. */
188 if (*temp_dirname == '~')
190 char *expanded_dirname;
192 expanded_dirname = tilde_expand_word (temp_dirname);
193 free (temp_dirname);
194 temp_dirname = expanded_dirname;
197 temp = (char *)xmalloc (34 + strlen (temp_dirname) + strlen (filename));
198 strcpy (temp, temp_dirname);
199 if (!IS_SLASH (temp[(strlen (temp)) - 1]))
200 strcat (temp, "/");
201 strcat (temp, filename);
202 temp_end = temp + strlen (temp);
204 free (temp_dirname);
206 /* Look for FILENAME, possibly with any of the extensions
207 in EXEC_EXTENSIONS[]. */
208 for (i = 0; exec_extensions[i]; i++)
210 if (exec_extensions[i][0])
211 strcpy (temp_end, exec_extensions[i]);
212 statable = (stat (temp, &finfo) == 0);
214 /* If we have found a regular executable file, then use it. */
215 if ((statable) && (S_ISREG (finfo.st_mode)) &&
216 (access (temp, X_OK) == 0))
217 return (temp);
220 free (temp);
222 return ((char *)NULL);
225 /* Return the full pathname of the system man page formatter. */
226 static char *
227 find_man_formatter (void)
229 return (executable_file_in_path ("man", (char *)getenv ("PATH")));
232 static char *manpage_pagename = (char *)NULL;
233 static char *manpage_section = (char *)NULL;
235 static void
236 get_page_and_section (char *pagename)
238 register int i;
240 if (manpage_pagename)
241 free (manpage_pagename);
243 if (manpage_section)
244 free (manpage_section);
246 manpage_pagename = (char *)NULL;
247 manpage_section = (char *)NULL;
249 for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
251 manpage_pagename = (char *)xmalloc (1 + i);
252 strncpy (manpage_pagename, pagename, i);
253 manpage_pagename[i] = '\0';
255 if (pagename[i] == '(')
257 int start;
259 start = i + 1;
261 for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
263 manpage_section = (char *)xmalloc (1 + (i - start));
264 strncpy (manpage_section, pagename + start, (i - start));
265 manpage_section[i - start] = '\0';
269 #if PIPE_USE_FORK
270 static void
271 reap_children (int sig)
273 wait (NULL);
275 #endif
277 static char *
278 get_manpage_contents (char *pagename)
280 static char *formatter_args[4] = { (char *)NULL };
281 int pipes[2];
282 pid_t child;
283 RETSIGTYPE (*sigsave) (int signum);
284 char *formatted_page = NULL;
285 int arg_index = 1;
287 if (formatter_args[0] == (char *)NULL)
288 formatter_args[0] = find_man_formatter ();
290 if (formatter_args[0] == (char *)NULL)
291 return ((char *)NULL);
293 get_page_and_section (pagename);
295 if (manpage_section != (char *)NULL)
296 formatter_args[arg_index++] = manpage_section;
298 formatter_args[arg_index++] = manpage_pagename;
299 formatter_args[arg_index] = (char *)NULL;
301 /* Open a pipe to this program, read the output, and save it away
302 in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
303 writer end is pipes[1]. */
304 #if PIPE_USE_FORK
305 pipe (pipes);
307 sigsave = signal (SIGCHLD, reap_children);
309 child = fork ();
310 if (child == -1)
311 return ((char *)NULL);
313 if (child != 0)
315 /* In the parent, close the writing end of the pipe, and read from
316 the exec'd child. */
317 close (pipes[1]);
318 formatted_page = read_from_fd (pipes[0]);
319 close (pipes[0]);
320 signal (SIGCHLD, sigsave);
322 else
323 { /* In the child, close the read end of the pipe, make the write end
324 of the pipe be stdout, and execute the man page formatter. */
325 close (pipes[0]);
326 freopen (NULL_DEVICE, "w", stderr);
327 freopen (NULL_DEVICE, "r", stdin);
328 dup2 (pipes[1], fileno (stdout));
330 execv (formatter_args[0], formatter_args);
332 /* If we get here, we couldn't exec, so close out the pipe and
333 exit. */
334 close (pipes[1]);
335 xexit (0);
337 #else /* !PIPE_USE_FORK */
338 /* Cannot fork/exec, but can popen/pclose. */
340 FILE *fpipe;
341 char *cmdline = xmalloc (strlen (formatter_args[0])
342 + strlen (manpage_pagename)
343 + (arg_index > 2 ? strlen (manpage_section) : 0)
344 + 3);
345 int save_stderr = dup (fileno (stderr));
346 int fd_err = open (NULL_DEVICE, O_WRONLY, 0666);
348 if (fd_err > 2)
349 dup2 (fd_err, fileno (stderr)); /* Don't print errors. */
350 sprintf (cmdline, "%s %s %s", formatter_args[0], manpage_pagename,
351 arg_index > 2 ? manpage_section : "");
352 fpipe = popen (cmdline, "r");
353 free (cmdline);
354 if (fd_err > 2)
355 close (fd_err);
356 dup2 (save_stderr, fileno (stderr));
357 if (fpipe == 0)
358 return ((char *)NULL);
359 formatted_page = read_from_fd (fileno (fpipe));
360 if (pclose (fpipe) == -1)
362 if (formatted_page)
363 free (formatted_page);
364 return ((char *)NULL);
367 #endif /* !PIPE_USE_FORK */
369 /* If we have the page, then clean it up. */
370 if (formatted_page)
371 clean_manpage (formatted_page);
373 return (formatted_page);
376 static void
377 clean_manpage (char *manpage)
379 register int i, j;
380 int newline_count = 0;
381 char *newpage;
383 newpage = (char *)xmalloc (1 + strlen (manpage));
385 for (i = 0, j = 0; (newpage[j] = manpage[i]); i++, j++)
387 if (manpage[i] == '\n')
388 newline_count++;
389 else
390 newline_count = 0;
392 if (newline_count == 3)
394 j--;
395 newline_count--;
398 /* A malformed man page could have a \b as its first character,
399 in which case decrementing j by 2 will cause us to write into
400 newpage[-1], smashing the hidden info stored there by malloc. */
401 if (manpage[i] == '\b' || (manpage[i] == '\f' && j > 0))
402 j -= 2;
403 else if (!raw_escapes_p)
405 /* Remove the ANSI escape sequences for color, boldface,
406 underlining, and italics, generated by some versions of
407 Groff. */
408 if (manpage[i] == '\033' && manpage[i + 1] == '['
409 && isdigit (manpage[i + 2]))
411 if (isdigit (manpage[i + 3]) && manpage[i + 4] == 'm')
413 i += 4;
414 j--;
416 else if (manpage[i + 3] == 'm')
418 i += 3;
419 j--;
421 /* Else do nothing: it's some unknown escape sequence,
422 so let's leave it alone. */
427 newpage[j++] = 0;
429 strcpy (manpage, newpage);
430 free (newpage);
433 static NODE *
434 manpage_node_of_file_buffer (FILE_BUFFER *file_buffer, char *pagename)
436 NODE *node = (NODE *)NULL;
437 TAG *tag = (TAG *)NULL;
439 if (file_buffer->contents)
441 register int i;
443 for (i = 0; (tag = file_buffer->tags[i]); i++)
445 if (strcasecmp (pagename, tag->nodename) == 0)
446 break;
450 if (tag)
452 node = (NODE *)xmalloc (sizeof (NODE));
453 node->filename = file_buffer->filename;
454 node->nodename = xstrdup (tag->nodename);
455 node->contents = file_buffer->contents + tag->nodestart;
456 node->nodelen = tag->nodelen;
457 node->flags = 0;
458 node->display_pos = 0;
459 node->parent = (char *)NULL;
460 node->flags = (N_HasTagsTable | N_IsManPage);
461 node->contents += skip_node_separator (node->contents);
464 return (node);
467 static char *
468 read_from_fd (int fd)
470 struct timeval timeout;
471 char *buffer = (char *)NULL;
472 int bsize = 0;
473 int bindex = 0;
474 int select_result;
475 #if defined (FD_SET)
476 fd_set read_fds;
478 timeout.tv_sec = 15;
479 timeout.tv_usec = 0;
481 FD_ZERO (&read_fds);
482 FD_SET (fd, &read_fds);
484 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
485 #else /* !FD_SET */
486 select_result = 1;
487 #endif /* !FD_SET */
489 switch (select_result)
491 case 0:
492 case -1:
493 break;
495 default:
497 int amount_read;
498 int done = 0;
500 while (!done)
502 while ((bindex + 1024) > (bsize))
503 buffer = (char *)xrealloc (buffer, (bsize += 1024));
504 buffer[bindex] = '\0';
506 amount_read = read (fd, buffer + bindex, 1023);
508 if (amount_read < 0)
510 done = 1;
512 else
514 bindex += amount_read;
515 buffer[bindex] = '\0';
516 if (amount_read == 0)
517 done = 1;
523 if ((buffer != (char *)NULL) && (*buffer == '\0'))
525 free (buffer);
526 buffer = (char *)NULL;
529 return (buffer);
532 static char *reference_section_starters[] =
534 "\nRELATED INFORMATION",
535 "\nRELATED\tINFORMATION",
536 "RELATED INFORMATION\n",
537 "RELATED\tINFORMATION\n",
538 "\nSEE ALSO",
539 "\nSEE\tALSO",
540 "SEE ALSO\n",
541 "SEE\tALSO\n",
542 (char *)NULL
545 static SEARCH_BINDING frs_binding;
547 static SEARCH_BINDING *
548 find_reference_section (NODE *node)
550 register int i;
551 long position = -1;
553 frs_binding.buffer = node->contents;
554 frs_binding.start = 0;
555 frs_binding.end = node->nodelen;
556 frs_binding.flags = S_SkipDest;
558 for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
560 position = search_forward (reference_section_starters[i], &frs_binding);
561 if (position != -1)
562 break;
565 if (position == -1)
566 return ((SEARCH_BINDING *)NULL);
568 /* We found the start of the reference section, and point is right after
569 the string which starts it. The text from here to the next header
570 (or end of buffer) contains the only references in this manpage. */
571 frs_binding.start = position;
573 for (i = frs_binding.start; i < frs_binding.end - 2; i++)
575 if ((frs_binding.buffer[i] == '\n') &&
576 (!whitespace (frs_binding.buffer[i + 1])))
578 frs_binding.end = i;
579 break;
583 return (&frs_binding);
586 REFERENCE **
587 xrefs_of_manpage (NODE *node)
589 SEARCH_BINDING *reference_section;
590 REFERENCE **refs = (REFERENCE **)NULL;
591 int refs_index = 0;
592 int refs_slots = 0;
593 long position;
595 reference_section = find_reference_section (node);
597 if (reference_section == (SEARCH_BINDING *)NULL)
598 return ((REFERENCE **)NULL);
600 /* Grovel the reference section building a list of references found there.
601 A reference is alphabetic characters followed by non-whitespace text
602 within parenthesis. */
603 reference_section->flags = 0;
605 while ((position = search_forward ("(", reference_section)) != -1)
607 register int start, end;
609 for (start = position; start > reference_section->start; start--)
610 if (whitespace (reference_section->buffer[start]))
611 break;
613 start++;
615 for (end = position; end < reference_section->end; end++)
617 if (whitespace (reference_section->buffer[end]))
619 end = start;
620 break;
623 if (reference_section->buffer[end] == ')')
625 end++;
626 break;
630 if (end != start)
632 REFERENCE *entry;
633 int len = end - start;
635 entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
636 entry->label = (char *)xmalloc (1 + len);
637 strncpy (entry->label, (reference_section->buffer) + start, len);
638 entry->label[len] = '\0';
639 entry->filename = xstrdup (node->filename);
640 entry->nodename = xstrdup (entry->label);
641 entry->start = start;
642 entry->end = end;
644 add_pointer_to_array
645 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
648 reference_section->start = position + 1;
651 return (refs);
654 long
655 locate_manpage_xref (NODE *node, long int start, int dir)
657 REFERENCE **refs;
658 long position = -1;
660 refs = xrefs_of_manpage (node);
662 if (refs)
664 register int i, count;
665 REFERENCE *entry;
667 for (i = 0; refs[i]; i++);
668 count = i;
670 if (dir > 0)
672 for (i = 0; (entry = refs[i]); i++)
673 if (entry->start > start)
675 position = entry->start;
676 break;
679 else
681 for (i = count - 1; i > -1; i--)
683 entry = refs[i];
685 if (entry->start < start)
687 position = entry->start;
688 break;
693 info_free_references (refs);
695 return (position);
698 /* This one was a little tricky. The binding buffer that is passed in has
699 a START and END value of 0 -- strlen (window-line-containing-point).
700 The BUFFER is a pointer to the start of that line. */
701 REFERENCE **
702 manpage_xrefs_in_binding (NODE *node, SEARCH_BINDING *binding)
704 register int i;
705 REFERENCE **all_refs = xrefs_of_manpage (node);
706 REFERENCE **brefs = (REFERENCE **)NULL;
707 REFERENCE *entry;
708 int brefs_index = 0;
709 int brefs_slots = 0;
710 int start, end;
712 if (!all_refs)
713 return ((REFERENCE **)NULL);
715 start = binding->start + (binding->buffer - node->contents);
716 end = binding->end + (binding->buffer - node->contents);
718 for (i = 0; (entry = all_refs[i]); i++)
720 if ((entry->start > start) && (entry->end < end))
722 add_pointer_to_array
723 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
725 else
727 maybe_free (entry->label);
728 maybe_free (entry->filename);
729 maybe_free (entry->nodename);
730 free (entry);
734 free (all_refs);
735 return (brefs);