1 /* man.c: How to read and format man files. */
3 /* This file is part of GNU Info, a program for reading online documentation
6 Copyright (C) 1995 Free Software Foundation, Inc.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 Written by Brian Fox Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
25 #include <sys/ioctl.h>
28 #if defined (HAVE_SYS_TIME_H)
31 #if defined (HAVE_SYS_WAIT_H)
38 #if !defined (SIGCHLD) && defined (SIGCLD)
39 #define SIGCHLD SIGCLD
42 #if !defined (_POSIX_VERSION)
48 # define fd_set_cast(x) (int *)(x)
50 # define fd_set_cast(x) (fd_set *)(x)
54 extern char *getenv ();
56 static char *read_from_fd ();
57 static void clean_manpage ();
58 static NODE
*manpage_node_of_file_buffer ();
59 static char *get_manpage_contents ();
62 make_manpage_node (pagename
)
65 return (info_get_node (MANPAGE_FILE_BUFFER_NAME
, pagename
));
69 get_manpage_node (file_buffer
, pagename
)
70 FILE_BUFFER
*file_buffer
;
75 node
= manpage_node_of_file_buffer (file_buffer
, pagename
);
81 page
= get_manpage_contents (pagename
);
86 long oldsize
, newsize
;
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
);
102 memcpy (file_buffer
->contents
+ oldsize
, 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
);
110 node
= manpage_node_of_file_buffer (file_buffer
, pagename
);
117 create_manpage_file_buffer ()
119 FILE_BUFFER
*file_buffer
;
122 file_buffer
= make_file_buffer ();
123 file_buffer
->filename
= strdup (MANPAGE_FILE_BUFFER_NAME
);
124 file_buffer
->fullpath
= strdup (MANPAGE_FILE_BUFFER_NAME
);
125 file_buffer
->finfo
.st_size
= 0;
126 file_buffer
->filesize
= 0;
127 file_buffer
->contents
= (char *)NULL
;
128 file_buffer
->flags
= (N_IsInternal
| N_CannotGC
| N_IsManPage
);
130 return (file_buffer
);
133 /* Scan the list of directories in PATH looking for FILENAME. If we find
134 one that is an executable file, return it as a new string. Otherwise,
135 return a NULL pointer. */
137 executable_file_in_path (filename
, path
)
138 char *filename
, *path
;
142 int statable
, dirname_index
;
146 while (temp_dirname
= extract_colon_unit (path
, &dirname_index
))
151 /* Expand a leading tilde if one is present. */
152 if (*temp_dirname
== '~')
154 char *expanded_dirname
;
156 expanded_dirname
= tilde_expand_word (temp_dirname
);
158 temp_dirname
= expanded_dirname
;
161 temp
= (char *)xmalloc (30 + strlen (temp_dirname
) + strlen (filename
));
162 strcpy (temp
, temp_dirname
);
163 if (temp
[(strlen (temp
)) - 1] != '/')
165 strcat (temp
, filename
);
169 statable
= (stat (temp
, &finfo
) == 0);
171 /* If we have found a regular executable file, then use it. */
172 if ((statable
) && (S_ISREG (finfo
.st_mode
)) &&
173 (access (temp
, X_OK
) == 0))
178 return ((char *)NULL
);
181 /* Return the full pathname of the system man page formatter. */
183 find_man_formatter ()
185 return (executable_file_in_path ("man", getenv ("PATH")));
188 static char *manpage_pagename
= (char *)NULL
;
189 static char *manpage_section
= (char *)NULL
;
192 get_page_and_section (pagename
)
197 if (manpage_pagename
)
198 free (manpage_pagename
);
201 free (manpage_section
);
203 manpage_pagename
= (char *)NULL
;
204 manpage_section
= (char *)NULL
;
206 for (i
= 0; pagename
[i
] != '\0' && pagename
[i
] != '('; i
++);
208 manpage_pagename
= (char *)xmalloc (1 + i
);
209 strncpy (manpage_pagename
, pagename
, i
);
210 manpage_pagename
[i
] = '\0';
212 if (pagename
[i
] == '(')
218 for (i
= start
; pagename
[i
] != '\0' && pagename
[i
] != ')'; i
++);
220 manpage_section
= (char *)xmalloc (1 + (i
- start
));
221 strncpy (manpage_section
, pagename
+ start
, (i
- start
));
222 manpage_section
[i
- start
] = '\0';
235 get_manpage_contents (pagename
)
238 static char *formatter_args
[4] = { (char *)NULL
};
241 char *formatted_page
= (char *)NULL
;
242 char *section
= (char *)NULL
;
245 if (formatter_args
[0] == (char *)NULL
)
246 formatter_args
[0] = find_man_formatter ();
248 if (formatter_args
[0] == (char *)NULL
)
249 return ((char *)NULL
);
251 get_page_and_section (pagename
);
253 if (manpage_section
!= (char *)NULL
)
254 formatter_args
[arg_index
++] = manpage_section
;
256 formatter_args
[arg_index
++] = manpage_pagename
;
257 formatter_args
[arg_index
] = (char *)NULL
;
259 /* Open a pipe to this program, read the output, and save it away
260 in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
261 writer end is pipes[1]. */
264 signal (SIGCHLD
, reap_children
);
269 return ((char *)NULL
);
273 /* In the parent, close the writing end of the pipe, and read from
276 formatted_page
= read_from_fd (pipes
[0]);
281 /* In the child, close the read end of the pipe, make the write end
282 of the pipe be stdout, and execute the man page formatter. */
284 close (fileno (stderr
));
285 close (fileno (stdin
)); /* Don't print errors. */
286 dup2 (pipes
[1], fileno (stdout
));
288 execv (formatter_args
[0], formatter_args
);
290 /* If we get here, we couldn't exec, so close out the pipe and
296 /* If we have the page, then clean it up. */
298 clean_manpage (formatted_page
);
300 return (formatted_page
);
304 clean_manpage (manpage
)
308 int newline_count
= 0;
311 newpage
= (char *)xmalloc (1 + strlen (manpage
));
313 for (i
= 0, j
= 0; newpage
[j
] = manpage
[i
]; i
++, j
++)
315 if (manpage
[i
] == '\n')
320 if (newline_count
== 3)
326 if (manpage
[i
] == '\b' || manpage
[i
] == '\f')
332 strcpy (manpage
, newpage
);
337 manpage_node_of_file_buffer (file_buffer
, pagename
)
338 FILE_BUFFER
*file_buffer
;
341 NODE
*node
= (NODE
*)NULL
;
342 TAG
*tag
= (TAG
*)NULL
;
344 if (file_buffer
->contents
)
348 for (i
= 0; tag
= file_buffer
->tags
[i
]; i
++)
350 if (strcasecmp (pagename
, tag
->nodename
) == 0)
357 node
= (NODE
*)xmalloc (sizeof (NODE
));
358 node
->filename
= file_buffer
->filename
;
359 node
->nodename
= tag
->nodename
;
360 node
->contents
= file_buffer
->contents
+ tag
->nodestart
;
361 node
->nodelen
= tag
->nodelen
;
363 node
->parent
= (char *)NULL
;
364 node
->flags
= (N_HasTagsTable
| N_IsManPage
);
365 node
->contents
+= skip_node_separator (node
->contents
);
375 struct timeval timeout
;
376 char *buffer
= (char *)NULL
;
387 FD_SET (fd
, &read_fds
);
389 select_result
= select (fd
+ 1, fd_set_cast (&read_fds
), 0, 0, &timeout
);
394 switch (select_result
)
407 while ((bindex
+ 1024) > (bsize
))
408 buffer
= (char *)xrealloc (buffer
, (bsize
+= 1024));
409 buffer
[bindex
] = '\0';
411 amount_read
= read (fd
, buffer
+ bindex
, 1023);
419 bindex
+= amount_read
;
420 buffer
[bindex
] = '\0';
421 if (amount_read
== 0)
428 if ((buffer
!= (char *)NULL
) && (*buffer
== '\0'))
431 buffer
= (char *)NULL
;
437 static char *reference_section_starters
[] =
439 "\nRELATED INFORMATION",
440 "\nRELATED\tINFORMATION",
441 "RELATED INFORMATION\n",
442 "RELATED\tINFORMATION\n",
450 static SEARCH_BINDING frs_binding
;
452 static SEARCH_BINDING
*
453 find_reference_section (node
)
459 frs_binding
.buffer
= node
->contents
;
460 frs_binding
.start
= 0;
461 frs_binding
.end
= node
->nodelen
;
462 frs_binding
.flags
= S_SkipDest
;
464 for (i
= 0; reference_section_starters
[i
] != (char *)NULL
; i
++)
466 position
= search_forward (reference_section_starters
[i
], &frs_binding
);
472 return ((SEARCH_BINDING
*)NULL
);
474 /* We found the start of the reference section, and point is right after
475 the string which starts it. The text from here to the next header
476 (or end of buffer) contains the only references in this manpage. */
477 frs_binding
.start
= position
;
479 for (i
= frs_binding
.start
; i
< frs_binding
.end
- 2; i
++)
481 if ((frs_binding
.buffer
[i
] == '\n') &&
482 (!whitespace (frs_binding
.buffer
[i
+ 1])))
489 return (&frs_binding
);
493 xrefs_of_manpage (node
)
496 SEARCH_BINDING
*reference_section
;
497 REFERENCE
**refs
= (REFERENCE
**)NULL
;
502 reference_section
= find_reference_section (node
);
504 if (reference_section
== (SEARCH_BINDING
*)NULL
)
505 return ((REFERENCE
**)NULL
);
507 /* Grovel the reference section building a list of references found there.
508 A reference is alphabetic characters followed by non-whitespace text
509 within parenthesis. */
510 reference_section
->flags
= 0;
512 while ((position
= search_forward ("(", reference_section
)) != -1)
514 register int start
, end
;
516 for (start
= position
; start
> reference_section
->start
; start
--)
517 if (whitespace (reference_section
->buffer
[start
]))
522 for (end
= position
; end
< reference_section
->end
; end
++)
524 if (whitespace (reference_section
->buffer
[end
]))
530 if (reference_section
->buffer
[end
] == ')')
540 int len
= end
- start
;
542 entry
= (REFERENCE
*)xmalloc (sizeof (REFERENCE
));
543 entry
->label
= (char *)xmalloc (1 + len
);
544 strncpy (entry
->label
, (reference_section
->buffer
) + start
, len
);
545 entry
->label
[len
] = '\0';
546 entry
->filename
= strdup (node
->filename
);
547 entry
->nodename
= strdup (entry
->label
);
548 entry
->start
= start
;
552 (entry
, refs_index
, refs
, refs_slots
, 10, REFERENCE
*);
555 reference_section
->start
= position
+ 1;
562 locate_manpage_xref (node
, start
, dir
)
567 register int i
, count
;
571 refs
= xrefs_of_manpage (node
);
575 register int i
, count
;
578 for (i
= 0; refs
[i
]; i
++);
583 for (i
= 0; entry
= refs
[i
]; i
++)
584 if (entry
->start
> start
)
586 position
= entry
->start
;
592 for (i
= count
- 1; i
> -1; i
--)
596 if (entry
->start
< start
)
598 position
= entry
->start
;
604 info_free_references (refs
);
609 /* This one was a little tricky. The binding buffer that is passed in has
610 a START and END value of 0 -- strlen (window-line-containing-point).
611 The BUFFER is a pointer to the start of that line. */
613 manpage_xrefs_in_binding (node
, binding
)
615 SEARCH_BINDING
*binding
;
618 REFERENCE
**all_refs
= xrefs_of_manpage (node
);
619 REFERENCE
**brefs
= (REFERENCE
**)NULL
;
626 return ((REFERENCE
**)NULL
);
628 start
= binding
->start
+ (binding
->buffer
- node
->contents
);
629 end
= binding
->end
+ (binding
->buffer
- node
->contents
);
631 for (i
= 0; entry
= all_refs
[i
]; i
++)
633 if ((entry
->start
> start
) && (entry
->end
< end
))
636 (entry
, brefs_index
, brefs
, brefs_slots
, 10, REFERENCE
*);
640 maybe_free (entry
->label
);
641 maybe_free (entry
->filename
);
642 maybe_free (entry
->nodename
);