* class.c (create_vtable_ptr): Put the vtable at the beginning of
[official-gcc.git] / texinfo / info / man.c
blobf200d12e3c7a830cc011489711e9a4e936734c11
1 /* man.c: How to read and format man files.
2 $Id: man.c,v 1.5 1998/03/22 22:35:19 law Exp $
4 Copyright (C) 1995, 97 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox Thu May 4 09:17:52 1995 (bfox@ai.mit.edu). */
22 #include "info.h"
23 #include <sys/ioctl.h>
24 #include "signals.h"
25 #if defined (HAVE_SYS_TIME_H)
26 #include <sys/time.h>
27 #endif
28 #if defined (HAVE_SYS_WAIT_H)
29 #include <sys/wait.h>
30 #endif
32 #include "tilde.h"
33 #include "man.h"
35 #if !defined (_POSIX_VERSION)
36 #define pid_t int
37 #endif
39 #if defined (FD_SET)
40 # if defined (hpux)
41 # define fd_set_cast(x) (int *)(x)
42 # else
43 # define fd_set_cast(x) (fd_set *)(x)
44 # endif /* !hpux */
45 #endif /* FD_SET */
47 static char *read_from_fd ();
48 static void clean_manpage ();
49 static NODE *manpage_node_of_file_buffer ();
50 static char *get_manpage_contents ();
52 NODE *
53 make_manpage_node (pagename)
54 char *pagename;
56 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
59 NODE *
60 get_manpage_node (file_buffer, pagename)
61 FILE_BUFFER *file_buffer;
62 char *pagename;
64 NODE *node;
66 node = manpage_node_of_file_buffer (file_buffer, pagename);
68 if (!node)
70 char *page;
72 page = get_manpage_contents (pagename);
74 if (page)
76 char header[1024];
77 long oldsize, newsize;
78 int hlen, plen;
80 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
81 INFO_COOKIE,
82 INFO_FILE_LABEL, file_buffer->filename,
83 INFO_NODE_LABEL, pagename,
84 INFO_UP_LABEL);
85 oldsize = file_buffer->filesize;
86 hlen = strlen (header);
87 plen = strlen (page);
88 newsize = (oldsize + hlen + plen);
89 file_buffer->contents =
90 (char *)xrealloc (file_buffer->contents, 1 + newsize);
91 memcpy (file_buffer->contents + oldsize, header, hlen);
92 oldsize += hlen;
93 memcpy (file_buffer->contents + oldsize, page, plen);
94 file_buffer->contents[newsize] = '\0';
95 file_buffer->filesize = newsize;
96 file_buffer->finfo.st_size = newsize;
97 build_tags_and_nodes (file_buffer);
98 free (page);
101 node = manpage_node_of_file_buffer (file_buffer, pagename);
104 return (node);
107 FILE_BUFFER *
108 create_manpage_file_buffer ()
110 FILE_BUFFER *file_buffer = make_file_buffer ();
111 file_buffer->filename = xstrdup (MANPAGE_FILE_BUFFER_NAME);
112 file_buffer->fullpath = xstrdup (MANPAGE_FILE_BUFFER_NAME);
113 file_buffer->finfo.st_size = 0;
114 file_buffer->filesize = 0;
115 file_buffer->contents = (char *)NULL;
116 file_buffer->flags = (N_IsInternal | N_CannotGC | N_IsManPage);
118 return (file_buffer);
121 /* Scan the list of directories in PATH looking for FILENAME. If we find
122 one that is an executable file, return it as a new string. Otherwise,
123 return a NULL pointer. */
124 static char *
125 executable_file_in_path (filename, path)
126 char *filename, *path;
128 struct stat finfo;
129 char *temp_dirname;
130 int statable, dirname_index;
132 dirname_index = 0;
134 while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
136 char *temp;
138 /* Expand a leading tilde if one is present. */
139 if (*temp_dirname == '~')
141 char *expanded_dirname;
143 expanded_dirname = tilde_expand_word (temp_dirname);
144 free (temp_dirname);
145 temp_dirname = expanded_dirname;
148 temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
149 strcpy (temp, temp_dirname);
150 if (temp[(strlen (temp)) - 1] != '/')
151 strcat (temp, "/");
152 strcat (temp, filename);
154 free (temp_dirname);
156 statable = (stat (temp, &finfo) == 0);
158 /* If we have found a regular executable file, then use it. */
159 if ((statable) && (S_ISREG (finfo.st_mode)) &&
160 (access (temp, X_OK) == 0))
161 return (temp);
162 else
163 free (temp);
165 return ((char *)NULL);
168 /* Return the full pathname of the system man page formatter. */
169 static char *
170 find_man_formatter ()
172 return (executable_file_in_path ("man", (char *)getenv ("PATH")));
175 static char *manpage_pagename = (char *)NULL;
176 static char *manpage_section = (char *)NULL;
178 static void
179 get_page_and_section (pagename)
180 char *pagename;
182 register int i;
184 if (manpage_pagename)
185 free (manpage_pagename);
187 if (manpage_section)
188 free (manpage_section);
190 manpage_pagename = (char *)NULL;
191 manpage_section = (char *)NULL;
193 for (i = 0; pagename[i] != '\0' && pagename[i] != '('; i++);
195 manpage_pagename = (char *)xmalloc (1 + i);
196 strncpy (manpage_pagename, pagename, i);
197 manpage_pagename[i] = '\0';
199 if (pagename[i] == '(')
201 int start;
203 start = i + 1;
205 for (i = start; pagename[i] != '\0' && pagename[i] != ')'; i++);
207 manpage_section = (char *)xmalloc (1 + (i - start));
208 strncpy (manpage_section, pagename + start, (i - start));
209 manpage_section[i - start] = '\0';
213 static void
214 reap_children (sig)
215 int sig;
217 int status;
218 wait (&status);
221 static char *
222 get_manpage_contents (pagename)
223 char *pagename;
225 static char *formatter_args[4] = { (char *)NULL };
226 int pipes[2];
227 pid_t child;
228 char *formatted_page = (char *)NULL;
229 int arg_index = 1;
231 if (formatter_args[0] == (char *)NULL)
232 formatter_args[0] = find_man_formatter ();
234 if (formatter_args[0] == (char *)NULL)
235 return ((char *)NULL);
237 get_page_and_section (pagename);
239 if (manpage_section != (char *)NULL)
240 formatter_args[arg_index++] = manpage_section;
242 formatter_args[arg_index++] = manpage_pagename;
243 formatter_args[arg_index] = (char *)NULL;
245 /* Open a pipe to this program, read the output, and save it away
246 in FORMATTED_PAGE. The reader end of the pipe is pipes[0]; the
247 writer end is pipes[1]. */
248 pipe (pipes);
250 signal (SIGCHLD, reap_children);
252 child = fork ();
254 if (child == -1)
255 return ((char *)NULL);
257 if (child != 0)
259 /* In the parent, close the writing end of the pipe, and read from
260 the exec'd child. */
261 close (pipes[1]);
262 formatted_page = read_from_fd (pipes[0]);
263 close (pipes[0]);
265 else
267 /* In the child, close the read end of the pipe, make the write end
268 of the pipe be stdout, and execute the man page formatter. */
269 close (pipes[0]);
270 close (fileno (stderr));
271 close (fileno (stdin)); /* Don't print errors. */
272 dup2 (pipes[1], fileno (stdout));
274 execv (formatter_args[0], formatter_args);
276 /* If we get here, we couldn't exec, so close out the pipe and
277 exit. */
278 close (pipes[1]);
279 exit (0);
282 /* If we have the page, then clean it up. */
283 if (formatted_page)
284 clean_manpage (formatted_page);
286 return (formatted_page);
289 static void
290 clean_manpage (manpage)
291 char *manpage;
293 register int i, j;
294 int newline_count = 0;
295 char *newpage;
297 newpage = (char *)xmalloc (1 + strlen (manpage));
299 for (i = 0, j = 0; (newpage[j] = manpage[i]); i++, j++)
301 if (manpage[i] == '\n')
302 newline_count++;
303 else
304 newline_count = 0;
306 if (newline_count == 3)
308 j--;
309 newline_count--;
312 if (manpage[i] == '\b' || manpage[i] == '\f')
313 j -= 2;
316 newpage[j++] = '\0';
318 strcpy (manpage, newpage);
319 free (newpage);
322 static NODE *
323 manpage_node_of_file_buffer (file_buffer, pagename)
324 FILE_BUFFER *file_buffer;
325 char *pagename;
327 NODE *node = (NODE *)NULL;
328 TAG *tag = (TAG *)NULL;
330 if (file_buffer->contents)
332 register int i;
334 for (i = 0; (tag = file_buffer->tags[i]); i++)
336 if (strcasecmp (pagename, tag->nodename) == 0)
337 break;
341 if (tag)
343 node = (NODE *)xmalloc (sizeof (NODE));
344 node->filename = file_buffer->filename;
345 node->nodename = tag->nodename;
346 node->contents = file_buffer->contents + tag->nodestart;
347 node->nodelen = tag->nodelen;
348 node->flags = 0;
349 node->parent = (char *)NULL;
350 node->flags = (N_HasTagsTable | N_IsManPage);
351 node->contents += skip_node_separator (node->contents);
354 return (node);
357 static char *
358 read_from_fd (fd)
359 int fd;
361 struct timeval timeout;
362 char *buffer = (char *)NULL;
363 int bsize = 0;
364 int bindex = 0;
365 int select_result;
366 #if defined (FD_SET)
367 fd_set read_fds;
369 timeout.tv_sec = 15;
370 timeout.tv_usec = 0;
372 FD_ZERO (&read_fds);
373 FD_SET (fd, &read_fds);
375 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
376 #else /* !FD_SET */
377 select_result = 1;
378 #endif /* !FD_SET */
380 switch (select_result)
382 case 0:
383 case -1:
384 break;
386 default:
388 int amount_read;
389 int done = 0;
391 while (!done)
393 while ((bindex + 1024) > (bsize))
394 buffer = (char *)xrealloc (buffer, (bsize += 1024));
395 buffer[bindex] = '\0';
397 amount_read = read (fd, buffer + bindex, 1023);
399 if (amount_read < 0)
401 done = 1;
403 else
405 bindex += amount_read;
406 buffer[bindex] = '\0';
407 if (amount_read == 0)
408 done = 1;
414 if ((buffer != (char *)NULL) && (*buffer == '\0'))
416 free (buffer);
417 buffer = (char *)NULL;
420 return (buffer);
423 static char *reference_section_starters[] =
425 "\nRELATED INFORMATION",
426 "\nRELATED\tINFORMATION",
427 "RELATED INFORMATION\n",
428 "RELATED\tINFORMATION\n",
429 "\nSEE ALSO",
430 "\nSEE\tALSO",
431 "SEE ALSO\n",
432 "SEE\tALSO\n",
433 (char *)NULL
436 static SEARCH_BINDING frs_binding;
438 static SEARCH_BINDING *
439 find_reference_section (node)
440 NODE *node;
442 register int i;
443 long position = -1;
445 frs_binding.buffer = node->contents;
446 frs_binding.start = 0;
447 frs_binding.end = node->nodelen;
448 frs_binding.flags = S_SkipDest;
450 for (i = 0; reference_section_starters[i] != (char *)NULL; i++)
452 position = search_forward (reference_section_starters[i], &frs_binding);
453 if (position != -1)
454 break;
457 if (position == -1)
458 return ((SEARCH_BINDING *)NULL);
460 /* We found the start of the reference section, and point is right after
461 the string which starts it. The text from here to the next header
462 (or end of buffer) contains the only references in this manpage. */
463 frs_binding.start = position;
465 for (i = frs_binding.start; i < frs_binding.end - 2; i++)
467 if ((frs_binding.buffer[i] == '\n') &&
468 (!whitespace (frs_binding.buffer[i + 1])))
470 frs_binding.end = i;
471 break;
475 return (&frs_binding);
478 REFERENCE **
479 xrefs_of_manpage (node)
480 NODE *node;
482 SEARCH_BINDING *reference_section;
483 REFERENCE **refs = (REFERENCE **)NULL;
484 int refs_index = 0;
485 int refs_slots = 0;
486 long position;
488 reference_section = find_reference_section (node);
490 if (reference_section == (SEARCH_BINDING *)NULL)
491 return ((REFERENCE **)NULL);
493 /* Grovel the reference section building a list of references found there.
494 A reference is alphabetic characters followed by non-whitespace text
495 within parenthesis. */
496 reference_section->flags = 0;
498 while ((position = search_forward ("(", reference_section)) != -1)
500 register int start, end;
502 for (start = position; start > reference_section->start; start--)
503 if (whitespace (reference_section->buffer[start]))
504 break;
506 start++;
508 for (end = position; end < reference_section->end; end++)
510 if (whitespace (reference_section->buffer[end]))
512 end = start;
513 break;
516 if (reference_section->buffer[end] == ')')
518 end++;
519 break;
523 if (end != start)
525 REFERENCE *entry;
526 int len = end - start;
528 entry = (REFERENCE *)xmalloc (sizeof (REFERENCE));
529 entry->label = (char *)xmalloc (1 + len);
530 strncpy (entry->label, (reference_section->buffer) + start, len);
531 entry->label[len] = '\0';
532 entry->filename = xstrdup (node->filename);
533 entry->nodename = xstrdup (entry->label);
534 entry->start = start;
535 entry->end = end;
537 add_pointer_to_array
538 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
541 reference_section->start = position + 1;
544 return (refs);
547 long
548 locate_manpage_xref (node, start, dir)
549 NODE *node;
550 long start;
551 int dir;
553 REFERENCE **refs;
554 long position = -1;
556 refs = xrefs_of_manpage (node);
558 if (refs)
560 register int i, count;
561 REFERENCE *entry;
563 for (i = 0; refs[i]; i++);
564 count = i;
566 if (dir > 0)
568 for (i = 0; (entry = refs[i]); i++)
569 if (entry->start > start)
571 position = entry->start;
572 break;
575 else
577 for (i = count - 1; i > -1; i--)
579 entry = refs[i];
581 if (entry->start < start)
583 position = entry->start;
584 break;
589 info_free_references (refs);
591 return (position);
594 /* This one was a little tricky. The binding buffer that is passed in has
595 a START and END value of 0 -- strlen (window-line-containing-point).
596 The BUFFER is a pointer to the start of that line. */
597 REFERENCE **
598 manpage_xrefs_in_binding (node, binding)
599 NODE *node;
600 SEARCH_BINDING *binding;
602 register int i;
603 REFERENCE **all_refs = xrefs_of_manpage (node);
604 REFERENCE **brefs = (REFERENCE **)NULL;
605 REFERENCE *entry;
606 int brefs_index = 0;
607 int brefs_slots = 0;
608 int start, end;
610 if (!all_refs)
611 return ((REFERENCE **)NULL);
613 start = binding->start + (binding->buffer - node->contents);
614 end = binding->end + (binding->buffer - node->contents);
616 for (i = 0; (entry = all_refs[i]); i++)
618 if ((entry->start > start) && (entry->end < end))
620 add_pointer_to_array
621 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
623 else
625 maybe_free (entry->label);
626 maybe_free (entry->filename);
627 maybe_free (entry->nodename);
628 free (entry);
632 free (all_refs);
633 return (brefs);