* fixincludes: Tweak fix for struct exception in math.h
[official-gcc.git] / texinfo / info / man.c
blob603325886b489fbf68fd7ce7b89ccb29d597057e
1 /* man.c: How to read and format man files. */
3 /* This file is part of GNU Info, a program for reading online documentation
4 stored in Info format.
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)
11 any later version.
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). */
24 #include "info.h"
25 #include <sys/ioctl.h>
26 #include <sys/file.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
34 #include "tilde.h"
36 #include "man.h"
38 #if !defined (SIGCHLD) && defined (SIGCLD)
39 #define SIGCHLD SIGCLD
40 #endif
42 #if !defined (_POSIX_VERSION)
43 #define pid_t int
44 #endif
46 #if defined (FD_SET)
47 # if defined (hpux)
48 # define fd_set_cast(x) (int *)(x)
49 # else
50 # define fd_set_cast(x) (fd_set *)(x)
51 # endif /* !hpux */
52 #endif /* FD_SET */
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 ();
61 NODE *
62 make_manpage_node (pagename)
63 char *pagename;
65 return (info_get_node (MANPAGE_FILE_BUFFER_NAME, pagename));
68 NODE *
69 get_manpage_node (file_buffer, pagename)
70 FILE_BUFFER *file_buffer;
71 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;
89 sprintf (header, "\n\n%c\n%s %s, %s %s, %s (dir)\n\n",
90 INFO_COOKIE,
91 INFO_FILE_LABEL, file_buffer->filename,
92 INFO_NODE_LABEL, pagename,
93 INFO_UP_LABEL);
94 oldsize = file_buffer->filesize;
95 hlen = strlen (header);
96 plen = strlen (page);
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);
101 oldsize += 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);
107 free (page);
110 node = manpage_node_of_file_buffer (file_buffer, pagename);
113 return (node);
116 FILE_BUFFER *
117 create_manpage_file_buffer ()
119 FILE_BUFFER *file_buffer;
120 struct stat *finfo;
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. */
136 static char *
137 executable_file_in_path (filename, path)
138 char *filename, *path;
140 struct stat finfo;
141 char *temp_dirname;
142 int statable, dirname_index;
144 dirname_index = 0;
146 while (temp_dirname = extract_colon_unit (path, &dirname_index))
148 register int i;
149 char *temp;
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);
157 free (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] != '/')
164 strcat (temp, "/");
165 strcat (temp, filename);
167 free (temp_dirname);
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))
174 return (temp);
175 else
176 free (temp);
178 return ((char *)NULL);
181 /* Return the full pathname of the system man page formatter. */
182 static char *
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;
191 static void
192 get_page_and_section (pagename)
193 char *pagename;
195 register int i;
197 if (manpage_pagename)
198 free (manpage_pagename);
200 if (manpage_section)
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] == '(')
214 int start;
216 start = i + 1;
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';
226 static void
227 reap_children (sig)
228 int sig;
230 unsigned int status;
231 wait (&status);
234 static char *
235 get_manpage_contents (pagename)
236 char *pagename;
238 static char *formatter_args[4] = { (char *)NULL };
239 int pipes[2];
240 pid_t child;
241 char *formatted_page = (char *)NULL;
242 char *section = (char *)NULL;
243 int arg_index = 1;
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]. */
262 pipe (pipes);
264 signal (SIGCHLD, reap_children);
266 child = fork ();
268 if (child == -1)
269 return ((char *)NULL);
271 if (child != 0)
273 /* In the parent, close the writing end of the pipe, and read from
274 the exec'd child. */
275 close (pipes[1]);
276 formatted_page = read_from_fd (pipes[0]);
277 close (pipes[0]);
279 else
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. */
283 close (pipes[0]);
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
291 exit. */
292 close (pipes[1]);
293 exit (0);
296 /* If we have the page, then clean it up. */
297 if (formatted_page)
298 clean_manpage (formatted_page);
300 return (formatted_page);
303 static void
304 clean_manpage (manpage)
305 char *manpage;
307 register int i, j;
308 int newline_count = 0;
309 char *newpage;
311 newpage = (char *)xmalloc (1 + strlen (manpage));
313 for (i = 0, j = 0; newpage[j] = manpage[i]; i++, j++)
315 if (manpage[i] == '\n')
316 newline_count++;
317 else
318 newline_count = 0;
320 if (newline_count == 3)
322 j--;
323 newline_count--;
326 if (manpage[i] == '\b' || manpage[i] == '\f')
327 j -= 2;
330 newpage[j++] = '\0';
332 strcpy (manpage, newpage);
333 free (newpage);
336 static NODE *
337 manpage_node_of_file_buffer (file_buffer, pagename)
338 FILE_BUFFER *file_buffer;
339 char *pagename;
341 NODE *node = (NODE *)NULL;
342 TAG *tag = (TAG *)NULL;
344 if (file_buffer->contents)
346 register int i;
348 for (i = 0; tag = file_buffer->tags[i]; i++)
350 if (strcasecmp (pagename, tag->nodename) == 0)
351 break;
355 if (tag)
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;
362 node->flags = 0;
363 node->parent = (char *)NULL;
364 node->flags = (N_HasTagsTable | N_IsManPage);
365 node->contents += skip_node_separator (node->contents);
368 return (node);
371 static char *
372 read_from_fd (fd)
373 int fd;
375 struct timeval timeout;
376 char *buffer = (char *)NULL;
377 int bsize = 0;
378 int bindex = 0;
379 int select_result;
380 #if defined (FD_SET)
381 fd_set read_fds;
383 timeout.tv_sec = 15;
384 timeout.tv_usec = 0;
386 FD_ZERO (&read_fds);
387 FD_SET (fd, &read_fds);
389 select_result = select (fd + 1, fd_set_cast (&read_fds), 0, 0, &timeout);
390 #else /* !FD_SET */
391 select_result = 1;
392 #endif /* !FD_SET */
394 switch (select_result)
396 case 0:
397 case -1:
398 break;
400 default:
402 int amount_read;
403 int done = 0;
405 while (!done)
407 while ((bindex + 1024) > (bsize))
408 buffer = (char *)xrealloc (buffer, (bsize += 1024));
409 buffer[bindex] = '\0';
411 amount_read = read (fd, buffer + bindex, 1023);
413 if (amount_read < 0)
415 done = 1;
417 else
419 bindex += amount_read;
420 buffer[bindex] = '\0';
421 if (amount_read == 0)
422 done = 1;
428 if ((buffer != (char *)NULL) && (*buffer == '\0'))
430 free (buffer);
431 buffer = (char *)NULL;
434 return (buffer);
437 static char *reference_section_starters[] =
439 "\nRELATED INFORMATION",
440 "\nRELATED\tINFORMATION",
441 "RELATED INFORMATION\n",
442 "RELATED\tINFORMATION\n",
443 "\nSEE ALSO",
444 "\nSEE\tALSO",
445 "SEE ALSO\n",
446 "SEE\tALSO\n",
447 (char *)NULL
450 static SEARCH_BINDING frs_binding;
452 static SEARCH_BINDING *
453 find_reference_section (node)
454 NODE *node;
456 register int i;
457 long position = -1;
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);
467 if (position != -1)
468 break;
471 if (position == -1)
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])))
484 frs_binding.end = i;
485 break;
489 return (&frs_binding);
492 REFERENCE **
493 xrefs_of_manpage (node)
494 NODE *node;
496 SEARCH_BINDING *reference_section;
497 REFERENCE **refs = (REFERENCE **)NULL;
498 int refs_index = 0;
499 int refs_slots = 0;
500 long position;
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]))
518 break;
520 start++;
522 for (end = position; end < reference_section->end; end++)
524 if (whitespace (reference_section->buffer[end]))
526 end = start;
527 break;
530 if (reference_section->buffer[end] == ')')
532 end++;
533 break;
537 if (end != start)
539 REFERENCE *entry;
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;
549 entry->end = end;
551 add_pointer_to_array
552 (entry, refs_index, refs, refs_slots, 10, REFERENCE *);
555 reference_section->start = position + 1;
558 return (refs);
561 long
562 locate_manpage_xref (node, start, dir)
563 NODE *node;
564 long start;
565 int dir;
567 register int i, count;
568 REFERENCE **refs;
569 long position = -1;
571 refs = xrefs_of_manpage (node);
573 if (refs)
575 register int i, count;
576 REFERENCE *entry;
578 for (i = 0; refs[i]; i++);
579 count = i;
581 if (dir > 0)
583 for (i = 0; entry = refs[i]; i++)
584 if (entry->start > start)
586 position = entry->start;
587 break;
590 else
592 for (i = count - 1; i > -1; i--)
594 entry = refs[i];
596 if (entry->start < start)
598 position = entry->start;
599 break;
604 info_free_references (refs);
606 return (position);
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. */
612 REFERENCE **
613 manpage_xrefs_in_binding (node, binding)
614 NODE *node;
615 SEARCH_BINDING *binding;
617 register int i;
618 REFERENCE **all_refs = xrefs_of_manpage (node);
619 REFERENCE **brefs = (REFERENCE **)NULL;
620 REFERENCE *entry;
621 int brefs_index = 0;
622 int brefs_slots = 0;
623 int start, end;
625 if (!all_refs)
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))
635 add_pointer_to_array
636 (entry, brefs_index, brefs, brefs_slots, 10, REFERENCE *);
638 else
640 maybe_free (entry->label);
641 maybe_free (entry->filename);
642 maybe_free (entry->nodename);
643 free (entry);
647 free (all_refs);
648 return (brefs);