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
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)
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). */
26 #include <sys/ioctl.h>
28 #if defined (HAVE_SYS_TIME_H)
31 #if defined (HAVE_SYS_WAIT_H)
38 #if !defined (_POSIX_VERSION)
44 # define fd_set_cast(x) (int *)(x)
46 # define fd_set_cast(x) (fd_set *)(x)
51 static char const * const exec_extensions
[] = {
52 ".exe", ".com", ".bat", ".btm", ".sh", ".ksh", ".pl", ".sed", "", NULL
55 static char const * const exec_extensions
[] = { "", NULL
};
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
,
62 static char *get_manpage_contents (char *pagename
);
65 make_manpage_node (char *pagename
)
67 return (info_get_node (MANPAGE_FILE_BUFFER_NAME
, pagename
));
71 get_manpage_node (FILE_BUFFER
*file_buffer
, char *pagename
)
75 node
= manpage_node_of_file_buffer (file_buffer
, pagename
);
81 page
= get_manpage_contents (pagename
);
86 long oldsize
, newsize
;
88 char *old_contents
= file_buffer
->contents
;
90 sprintf (header
, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
92 INFO_FILE_LABEL
, file_buffer
->filename
,
93 INFO_NODE_LABEL
, pagename
,
95 oldsize
= file_buffer
->filesize
;
96 hlen
= strlen (header
);
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
);
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
)
115 INFO_WINDOW
*info_win
;
116 char *old_contents_end
= old_contents
+ oldsize
;
118 for (iw
= 0; (info_win
= info_windows
[iw
]); iw
++)
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
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
138 info_win
->nodes
[in
] =
139 manpage_node_of_file_buffer (file_buffer
,
141 free (tmp_node
->nodename
);
149 node
= manpage_node_of_file_buffer (file_buffer
, pagename
);
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. */
173 executable_file_in_path (char *filename
, char *path
)
177 int statable
, dirname_index
;
181 while ((temp_dirname
= extract_colon_unit (path
, &dirname_index
)))
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
);
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]))
201 strcat (temp
, filename
);
202 temp_end
= temp
+ strlen (temp
);
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))
222 return ((char *)NULL
);
225 /* Return the full pathname of the system man page formatter. */
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
;
236 get_page_and_section (char *pagename
)
240 if (manpage_pagename
)
241 free (manpage_pagename
);
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
] == '(')
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';
271 reap_children (int sig
)
278 get_manpage_contents (char *pagename
)
280 static char *formatter_args
[4] = { (char *)NULL
};
283 RETSIGTYPE (*sigsave
) (int signum
);
284 char *formatted_page
= NULL
;
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]. */
307 sigsave
= signal (SIGCHLD
, reap_children
);
311 return ((char *)NULL
);
315 /* In the parent, close the writing end of the pipe, and read from
318 formatted_page
= read_from_fd (pipes
[0]);
320 signal (SIGCHLD
, sigsave
);
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. */
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
337 #else /* !PIPE_USE_FORK */
338 /* Cannot fork/exec, but can popen/pclose. */
341 char *cmdline
= xmalloc (strlen (formatter_args
[0])
342 + strlen (manpage_pagename
)
343 + (arg_index
> 2 ? strlen (manpage_section
) : 0)
345 int save_stderr
= dup (fileno (stderr
));
346 int fd_err
= open (NULL_DEVICE
, O_WRONLY
, 0666);
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");
356 dup2 (save_stderr
, fileno (stderr
));
358 return ((char *)NULL
);
359 formatted_page
= read_from_fd (fileno (fpipe
));
360 if (pclose (fpipe
) == -1)
363 free (formatted_page
);
364 return ((char *)NULL
);
367 #endif /* !PIPE_USE_FORK */
369 /* If we have the page, then clean it up. */
371 clean_manpage (formatted_page
);
373 return (formatted_page
);
377 clean_manpage (char *manpage
)
380 int newline_count
= 0;
383 newpage
= (char *)xmalloc (1 + strlen (manpage
));
385 for (i
= 0, j
= 0; (newpage
[j
] = manpage
[i
]); i
++, j
++)
387 if (manpage
[i
] == '\n')
392 if (newline_count
== 3)
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))
403 else if (!raw_escapes_p
)
405 /* Remove the ANSI escape sequences for color, boldface,
406 underlining, and italics, generated by some versions of
408 if (manpage
[i
] == '\033' && manpage
[i
+ 1] == '['
409 && isdigit (manpage
[i
+ 2]))
411 if (isdigit (manpage
[i
+ 3]) && manpage
[i
+ 4] == 'm')
416 else if (manpage
[i
+ 3] == 'm')
421 /* Else do nothing: it's some unknown escape sequence,
422 so let's leave it alone. */
429 strcpy (manpage
, newpage
);
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
)
443 for (i
= 0; (tag
= file_buffer
->tags
[i
]); i
++)
445 if (strcasecmp (pagename
, tag
->nodename
) == 0)
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
;
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
);
468 read_from_fd (int fd
)
470 struct timeval timeout
;
471 char *buffer
= (char *)NULL
;
482 FD_SET (fd
, &read_fds
);
484 select_result
= select (fd
+ 1, fd_set_cast (&read_fds
), 0, 0, &timeout
);
489 switch (select_result
)
502 while ((bindex
+ 1024) > (bsize
))
503 buffer
= (char *)xrealloc (buffer
, (bsize
+= 1024));
504 buffer
[bindex
] = '\0';
506 amount_read
= read (fd
, buffer
+ bindex
, 1023);
514 bindex
+= amount_read
;
515 buffer
[bindex
] = '\0';
516 if (amount_read
== 0)
523 if ((buffer
!= (char *)NULL
) && (*buffer
== '\0'))
526 buffer
= (char *)NULL
;
532 static char *reference_section_starters
[] =
534 "\nRELATED INFORMATION",
535 "\nRELATED\tINFORMATION",
536 "RELATED INFORMATION\n",
537 "RELATED\tINFORMATION\n",
545 static SEARCH_BINDING frs_binding
;
547 static SEARCH_BINDING
*
548 find_reference_section (NODE
*node
)
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
);
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])))
583 return (&frs_binding
);
587 xrefs_of_manpage (NODE
*node
)
589 SEARCH_BINDING
*reference_section
;
590 REFERENCE
**refs
= (REFERENCE
**)NULL
;
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
]))
615 for (end
= position
; end
< reference_section
->end
; end
++)
617 if (whitespace (reference_section
->buffer
[end
]))
623 if (reference_section
->buffer
[end
] == ')')
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
;
645 (entry
, refs_index
, refs
, refs_slots
, 10, REFERENCE
*);
648 reference_section
->start
= position
+ 1;
655 locate_manpage_xref (NODE
*node
, long int start
, int dir
)
660 refs
= xrefs_of_manpage (node
);
664 register int i
, count
;
667 for (i
= 0; refs
[i
]; i
++);
672 for (i
= 0; (entry
= refs
[i
]); i
++)
673 if (entry
->start
> start
)
675 position
= entry
->start
;
681 for (i
= count
- 1; i
> -1; i
--)
685 if (entry
->start
< start
)
687 position
= entry
->start
;
693 info_free_references (refs
);
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. */
702 manpage_xrefs_in_binding (NODE
*node
, SEARCH_BINDING
*binding
)
705 REFERENCE
**all_refs
= xrefs_of_manpage (node
);
706 REFERENCE
**brefs
= (REFERENCE
**)NULL
;
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
))
723 (entry
, brefs_index
, brefs
, brefs_slots
, 10, REFERENCE
*);
727 maybe_free (entry
->label
);
728 maybe_free (entry
->filename
);
729 maybe_free (entry
->nodename
);