]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/usr.bin/man/man/man.c
This commit was generated by cvs2svn to compensate for changes in r161701,
[FreeBSD/FreeBSD.git] / gnu / usr.bin / man / man / man.c
1 /*
2  * man.c
3  *
4  * Copyright (c) 1990, 1991, John W. Eaton.
5  *
6  * You may distribute under the terms of the GNU General Public
7  * License as specified in the file COPYING that comes with the man
8  * distribution.
9  *
10  * John W. Eaton
11  * jwe@che.utexas.edu
12  * Department of Chemical Engineering
13  * The University of Texas at Austin
14  * Austin, Texas  78712
15  */
16
17 #ifndef lint
18 static const char rcsid[] =
19   "$FreeBSD$";
20 #endif /* not lint */
21
22 #define MAN_MAIN
23
24 #include <sys/file.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
27 #include <sys/utsname.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #ifdef __FreeBSD__
31 #include <locale.h>
32 #include <langinfo.h>
33 #endif
34 #include <stdio.h>
35 #include <string.h>
36 #include <signal.h>
37 #if HAVE_LIBZ > 0
38 #include <zlib.h>
39 #endif
40 #include "config.h"
41 #include "gripes.h"
42 #include "version.h"
43
44 #ifdef POSIX
45 #include <unistd.h>
46 #else
47 #ifndef R_OK
48 #define R_OK 4
49 #endif
50 #endif
51
52 #ifdef STDC_HEADERS
53 #include <stdlib.h>
54 #else
55 extern char *malloc ();
56 extern char *getenv ();
57 extern void free ();
58 extern int system ();
59 extern int strcmp ();
60 extern int strncmp ();
61 extern int exit ();
62 extern int fflush ();
63 extern int printf ();
64 extern int fprintf ();
65 extern FILE *fopen ();
66 extern int fclose ();
67 extern char *sprintf ();
68 #endif
69
70 extern char **glob_filename ();
71 extern int is_newer ();
72 extern int is_directory ();
73 extern int do_system_command ();
74
75 char *prognam;
76 static char *pager;
77 static char *machine_arch;
78 static char *machine;
79 static char *manp;
80 static char *manpathlist[MAXDIRS];
81 static char *shortsec;
82 static char *longsec;
83 static char *colon_sep_section_list;
84 static char **section_list;
85 static char *roff_directive;
86 static int apropos;
87 static int whatis;
88 static int findall;
89 static int print_where;
90
91 #ifdef __FreeBSD__
92 static char *locale, *locale_opts, *locale_nroff, *locale_codeset;
93 static char locale_terr[3], locale_lang[3];
94 static char *man_locale;
95 static int use_man_locale;
96 static int use_original;
97 struct ltable {
98         char *lcode;
99         char *nroff;
100 };
101 static struct ltable ltable[] = {
102         {"KOI8-R", "koi8-r"},
103         {"ISO8859-1", "latin1"},
104         {"ISO8859-15", "latin1"},
105         {NULL}
106 };
107 #endif
108
109 static int troff = 0;
110
111 int debug;
112
113 #ifdef HAS_TROFF
114 #ifdef __FreeBSD__
115 static char args[] = "M:P:S:adfhkm:op:tw?";
116 #else
117 static char args[] = "M:P:S:adfhkm:p:tw?";
118 #endif
119 #else
120 #ifdef __FreeBSD__
121 static char args[] = "M:P:S:adfhkm:op:w?";
122 #else
123 static char args[] = "M:P:S:adfhkm:p:w?";
124 #endif
125 #endif
126
127 #ifdef SETUID
128 uid_t ruid;
129 uid_t euid;
130 #endif
131
132 int
133 main (argc, argv)
134      int argc;
135      char **argv;
136 {
137   int status = 0;
138   char *nextarg;
139   char *tmp;
140   extern char *mkprogname ();
141   char *is_section ();
142   char **get_section_list ();
143   void man_getopt ();
144   void do_apropos ();
145   void do_whatis ();
146   int man ();
147
148   prognam = mkprogname (argv[0]);
149   longsec = NULL;
150
151   unsetenv("IFS");
152 #ifdef __FreeBSD__
153   (void) setlocale(LC_ALL, "");
154 #endif
155   man_getopt (argc, argv);
156
157   if (optind == argc)
158     gripe_no_name ((char *)NULL);
159
160   section_list = get_section_list ();
161
162   if (optind == argc - 1)
163     {
164       tmp = is_section (argv[optind], manp);
165
166       if (tmp != NULL)
167         gripe_no_name (tmp);
168     }
169
170 #ifdef SETUID
171   ruid = getuid();
172   euid = geteuid();
173   seteuid(ruid);
174 #endif
175
176   while (optind < argc)
177     {
178       nextarg = argv[optind++];
179
180       /*
181        * See if this argument is a valid section name.  If not,
182        * is_section returns NULL.
183        */
184       tmp = is_section (nextarg, manp);
185
186       if (tmp != NULL)
187         {
188           shortsec = tmp;
189
190           if (debug)
191             fprintf (stderr, "\nsection: %s\n", shortsec);
192
193           continue;
194         }
195
196       if (apropos) {
197         do_apropos (nextarg);
198         status = (status ? 0 : 1); /* reverts status, see below */
199       }
200       else if (whatis) {
201         do_whatis (nextarg);
202         status = (status ? 0 : 1); /* reverts status, see below */
203       }
204       else
205         {
206           status = man (nextarg);
207
208           if (status == 0)
209             gripe_not_found (nextarg, longsec);
210         }
211     }
212   return (status==0);         /* status==1 --> exit(0),
213                                  status==0 --> exit(1) */
214 }
215
216 void
217 usage ()
218 {
219   static char usage_string[1024] = "%s, version %s\n\n";
220
221 #ifdef HAS_TROFF
222 #ifdef __FreeBSD__
223   static char s1[] =
224     "usage: %s [-adfhkotw] [section] [-M path] [-P pager] [-S list]\n\
225            [-m machine] [-p string] name ...\n\n";
226 #else
227   static char s1[] =
228     "usage: %s [-adfhktw] [section] [-M path] [-P pager] [-S list]\n\
229            [-m machine] [-p string] name ...\n\n";
230 #endif
231 #else
232 #ifdef __FreeBSD__
233   static char s1[] =
234     "usage: %s [-adfhkow] [section] [-M path] [-P pager] [-S list]\n\
235            [-m machine] [-p string] name ...\n\n";
236 #else
237   static char s1[] =
238     "usage: %s [-adfhkw] [section] [-M path] [-P pager] [-S list]\n\
239            [-m machine] [-p string] name ...\n\n";
240 #endif
241 #endif
242
243 static char s2[] = "  a : find all matching entries\n\
244   d : print gobs of debugging information\n\
245   f : same as whatis(1)\n\
246   h : print this help message\n\
247   k : same as apropos(1)\n";
248
249 #ifdef __FreeBSD__
250   static char s3[] = "  o : use original, non-localized manpages\n";
251 #endif
252
253 #ifdef HAS_TROFF
254   static char s4[] = "  t : use troff to format pages for printing\n";
255 #endif
256
257   static char s5[] = "  w : print location of man page(s) that would be displayed\n\n\
258   M path    : set search path for manual pages to `path'\n\
259   P pager   : use program `pager' to display pages\n\
260   S list    : colon separated section list\n\
261   m machine : search for alternate architecture man pages\n";
262
263   static char s6[] = "  p string : string tells which preprocessors to run\n\
264                e - [n]eqn(1)   p - pic(1)    t - tbl(1)\n\
265                g - grap(1)     r - refer(1)  v - vgrind(1)\n";
266
267   strcat (usage_string, s1);
268   strcat (usage_string, s2);
269 #ifdef __FreeBSD__
270   strcat (usage_string, s3);
271 #endif
272
273 #ifdef HAS_TROFF
274   strcat (usage_string, s4);
275 #endif
276
277   strcat (usage_string, s5);
278
279   strcat (usage_string, s6);
280
281   fprintf (stderr, usage_string, prognam, version, prognam);
282   exit(1);
283 }
284
285 char **
286 add_dir_to_mpath_list (mp, p)
287      char **mp;
288      char *p;
289 {
290   int status;
291
292   status = is_directory (p);
293
294   if (status < 0 && debug)
295     {
296       fprintf (stderr, "Warning: couldn't stat file %s!\n", p);
297     }
298   else if (status == 0 && debug)
299     {
300       fprintf (stderr, "Warning: %s isn't a directory!\n", p);
301     }
302   else if (status == 1)
303     {
304       if (debug)
305         fprintf (stderr, "adding %s to manpathlist\n", p);
306
307       *mp++ = strdup (p);
308     }
309   return mp;
310 }
311
312 /*
313  * Get options from the command line and user environment.
314  */
315 void
316 man_getopt (argc, argv)
317      register int argc;
318      register char **argv;
319 {
320   register int c;
321   register char *p;
322   register char *end;
323   register char **mp;
324   extern void downcase ();
325   extern char *manpath ();
326
327   while ((c = getopt (argc, argv, args)) != EOF)
328     {
329       switch (c)
330         {
331         case 'M':
332           manp = strdup (optarg);
333           break;
334         case 'P':
335           pager = strdup (optarg);
336           if (setenv("PAGER", pager, 1) != 0)
337                   (void)fprintf(stderr, "setenv PAGER=%s\n", pager);
338           break;
339         case 'S':
340           colon_sep_section_list = strdup (optarg);
341           break;
342         case 'a':
343           findall++;
344           break;
345         case 'd':
346           debug++;
347           break;
348         case 'f':
349           if (troff)
350             gripe_incompatible ("-f and -t");
351           if (apropos)
352             gripe_incompatible ("-f and -k");
353           if (print_where)
354             gripe_incompatible ("-f and -w");
355           whatis++;
356           break;
357         case 'k':
358           if (troff)
359             gripe_incompatible ("-k and -t");
360           if (whatis)
361             gripe_incompatible ("-k and -f");
362           if (print_where)
363             gripe_incompatible ("-k and -w");
364           apropos++;
365           break;
366         case 'm':
367           machine_arch = optarg;
368           if ((machine = strchr(optarg, ':')) != NULL)
369             *machine++ = '\0';
370           else
371             machine = optarg;
372           break;
373 #ifdef __FreeBSD__
374         case 'o':
375           use_original++;
376           break;
377 #endif
378         case 'p':
379           roff_directive = strdup (optarg);
380           break;
381 #ifdef HAS_TROFF
382         case 't':
383           if (apropos)
384             gripe_incompatible ("-t and -k");
385           if (whatis)
386             gripe_incompatible ("-t and -f");
387           if (print_where)
388             gripe_incompatible ("-t and -w");
389           troff++;
390           break;
391 #endif
392         case 'w':
393           if (apropos)
394             gripe_incompatible ("-w and -k");
395           if (whatis)
396             gripe_incompatible ("-w and -f");
397           if (troff)
398             gripe_incompatible ("-w and -t");
399           print_where++;
400           break;
401         case 'h':
402         case '?':
403         default:
404           usage();
405           break;
406         }
407     }
408
409 #ifdef __FreeBSD__
410   /* "" intentionally used to catch error */
411   if ((locale = setlocale(LC_CTYPE, "")) != NULL)
412         locale_codeset = nl_langinfo(CODESET);
413   if (!use_original && locale != NULL && *locale_codeset != '\0' &&
414       strcmp(locale_codeset, "US-ASCII") != 0
415      ) {
416         char *tmp, *short_locale;
417         struct ltable *pltable;
418
419         *locale_lang = '\0';
420         *locale_terr = '\0';
421
422         if ((short_locale = strdup(locale)) == NULL) {
423                 perror ("ctype locale strdup");
424                 exit (1);
425         }
426         if ((tmp = strchr(short_locale, '.')) != NULL)
427                 *tmp = '\0';
428
429         if (strlen(short_locale) == 2)
430                 strcpy(locale_lang, short_locale);
431         else if ((tmp = strchr(short_locale, '_')) == NULL ||
432                  tmp != short_locale + 2 ||
433                  strlen(tmp + 1) != 2
434                 ) {
435                 errno = EINVAL;
436                 perror ("ctype locale format");
437                 locale = NULL;
438         } else {
439                 strncpy(locale_terr, short_locale + 3, 2);
440                 locale_terr[2] = '\0';
441                 strncpy(locale_lang, short_locale, 2);
442                 locale_lang[2] = '\0';
443         }
444
445         free(short_locale);
446
447         if (locale != NULL) {
448                 for (pltable = ltable; pltable->lcode != NULL; pltable++) {
449                         if (strcmp(pltable->lcode, locale_codeset) == 0) {
450                                 locale_nroff = pltable->nroff;
451                                 break;
452                         }
453                 }
454                 asprintf(&man_locale, "%s.%s", locale_lang, locale_codeset);
455         }
456   } else {
457         if (locale == NULL) {
458                 errno = EINVAL;
459                 perror ("ctype locale");
460         } else {
461                 locale = NULL;
462                 if (*locale_codeset == '\0') {
463                         errno = EINVAL;
464                         perror ("ctype codeset");
465                 }
466         }
467   }
468 #endif /* __FreeBSD__ */
469
470   if (pager == NULL || *pager == '\0')
471     if ((pager = getenv ("PAGER")) == NULL || *pager == '\0')
472       pager = strdup (PAGER);
473
474   if (debug)
475     fprintf (stderr, "\nusing %s as pager\n", pager);
476
477   if (machine_arch == NULL && (machine_arch = getenv ("MACHINE_ARCH")) == NULL)
478     machine_arch = MACHINE_ARCH;
479
480   if (machine == NULL && (machine = getenv ("MACHINE")) == NULL)
481     {
482       static struct utsname utsname;
483
484       if (uname(&utsname) == -1)
485         {
486           perror ("uname");
487           exit (1);
488         }
489       machine = utsname.machine;
490     }
491
492   if (debug)
493     fprintf (stderr, "\nusing %s:%s architecture\n", machine_arch, machine);
494
495   if (manp == NULL)
496     {
497       if ((manp = manpath (0)) == NULL)
498         gripe_manpath ();
499
500       if (debug)
501         fprintf (stderr,
502                  "\nsearch path for pages determined by manpath is\n%s\n\n",
503                  manp);
504     }
505
506   /*
507    * Expand the manpath into a list for easier handling.
508    */
509   mp = manpathlist;
510   for (p = manp; ; p = end+1)
511     {
512       if (mp == manpathlist + MAXDIRS - 1) {
513         fprintf (stderr, "Warning: too many directories in manpath, truncated!\n");
514         break;
515       }
516       if ((end = strchr (p, ':')) != NULL)
517         *end = '\0';
518
519       mp = add_dir_to_mpath_list (mp, p);
520       if (end == NULL)
521         break;
522
523       *end = ':';
524     }
525   *mp = NULL;
526 }
527
528 /*
529  * Check to see if the argument is a valid section number.  If the
530  * first character of name is a numeral, or the name matches one of
531  * the sections listed in section_list, we'll assume that it's a section.
532  * The list of sections in config.h simply allows us to specify oddly
533  * named directories like .../man3f.  Yuk.
534  */
535 char *
536 is_section (name, path)
537      char *name;
538      char *path;
539 {
540   register char **vs;
541   char *temp, *end, *loc;
542   char **plist;
543   int x;
544
545   for (vs = section_list; *vs != NULL; vs++)
546     if ((strcmp (*vs, name) == 0)
547         || (isdigit ((unsigned char)name[0]) && strlen(name) == 1))
548       return (longsec = strdup(name));
549
550   plist = manpathlist;
551   if (isdigit ((unsigned char)name[0]))
552     {
553       while (*plist != NULL)
554         {
555           asprintf (&temp, "%s/man%c/*", *plist, name[0]);
556           plist++;
557
558           x = 0;
559           vs = glob_filename (temp);
560           if (vs == (char **) -1)
561             {
562               free (temp);
563               return NULL;
564             }
565           for ( ; *vs != NULL; vs++)
566             {
567               end = strrchr (*vs, '/');
568               if ((loc = strstr (end, name)) != NULL && loc - end > 2
569                   && *(loc-1) == '.'
570                   && (*(loc+strlen(name)) == '\0' || *(loc+strlen(name)) == '.'))
571                 {
572                   x = 1;
573                   break;
574                 }
575             }
576           free (temp);
577           if (x == 1)
578             {
579               asprintf (&temp, "%c", name[0]);
580               longsec = strdup (name);
581               return (temp);
582             }
583         }
584     }
585   return NULL;
586 }
587
588 /*
589  * Handle the apropos option.  Cheat by using another program.
590  */
591 void
592 do_apropos (name)
593      register char *name;
594 {
595   register int len;
596   register char *command;
597
598   len = strlen (APROPOS) + strlen (name) + 4;
599
600   if ((command = (char *) malloc(len)) == NULL)
601     gripe_alloc (len, "command");
602
603   sprintf (command, "%s \"%s\"", APROPOS, name);
604
605   (void) do_system_command (command);
606
607   free (command);
608 }
609
610 /*
611  * Handle the whatis option.  Cheat by using another program.
612  */
613 void
614 do_whatis (name)
615      register char *name;
616 {
617   register int len;
618   register char *command;
619
620   len = strlen (WHATIS) + strlen (name) + 4;
621
622   if ((command = (char *) malloc(len)) == NULL)
623     gripe_alloc (len, "command");
624
625   sprintf (command, "%s \"%s\"", WHATIS, name);
626
627   (void) do_system_command (command);
628
629   free (command);
630 }
631
632 /*
633  * Change a name of the form ...man/man1/name.1 to ...man/cat1/name.1
634  * or a name of the form ...man/cat1/name.1 to ...man/man1/name.1
635  */
636 char *
637 convert_name (name, to_cat)
638      register char *name;
639      register int to_cat;
640 {
641   register char *to_name;
642   register char *t1;
643   register char *t2 = NULL;
644
645 #ifdef DO_COMPRESS
646   if (to_cat)
647     {
648       int olen = strlen(name);
649       int cextlen = strlen(COMPRESS_EXT);
650       int len = olen + cextlen;
651
652       to_name = malloc (len+1);
653       if (to_name == NULL)
654         gripe_alloc (len+1, "to_name");
655       strcpy (to_name, name);
656       olen -= cextlen;
657       /* Avoid tacking it on twice */
658       if (olen >= 1 && strcmp(name + olen, COMPRESS_EXT) != 0)
659         strcat (to_name, COMPRESS_EXT);
660     }
661   else
662     to_name = strdup (name);
663 #else
664   to_name = strdup (name);
665 #endif
666
667   t1 = strrchr (to_name, '/');
668   if (t1 != NULL)
669     {
670       *t1 = '\0';
671       t2 = strrchr (to_name, '/');
672       *t1 = '/';
673
674       /* Skip architecture part (if present). */
675       if (t2 != NULL && (t1 - t2 < 5 || *(t2 + 1) != 'm' || *(t2 + 3) != 'n'))
676         {
677           t1 = t2;
678           *t1 = '\0';
679           t2 = strrchr (to_name, '/');
680           *t1 = '/';
681         }
682     }
683
684   if (t2 == NULL)
685     gripe_converting_name (name, to_cat);
686
687   if (to_cat)
688     {
689       *(++t2) = 'c';
690       *(t2+2) = 't';
691     }
692   else
693     {
694       *(++t2) = 'm';
695       *(t2+2) = 'n';
696     }
697
698   if (debug)
699     fprintf (stderr, "to_name in convert_name () is: %s\n", to_name);
700
701   return to_name;
702 }
703
704 /*
705  * Try to find the man page corresponding to the given name.  The
706  * reason we do this with globbing is because some systems have man
707  * page directories named man3 which contain files with names like
708  * XtPopup.3Xt.  Rather than requiring that this program know about
709  * all those possible names, we simply try to match things like
710  * .../man[sect]/name[sect]*.  This is *much* easier.
711  *
712  * Note that globbing is only done when the section is unspecified.
713  */
714 char **
715 glob_for_file (path, section, longsec, name, cat)
716      char *path;
717      char *section;
718      char *longsec;
719      char *name;
720      int cat;
721 {
722   char pathname[FILENAME_MAX];
723   char **gf;
724
725   if (longsec == NULL)
726     longsec = section;
727
728   if (cat)
729     snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.%s*", path, section,
730         name, longsec);
731   else
732     snprintf (pathname, sizeof(pathname), "%s/man%s/%s.%s*", path, section,
733         name, longsec);
734
735   if (debug)
736     fprintf (stderr, "globbing %s\n", pathname);
737
738   gf = glob_filename (pathname);
739
740   if ((gf == (char **) -1 || *gf == NULL) && isdigit ((unsigned char)*section)
741       && strlen (longsec) == 1)
742     {
743       if (cat)
744         snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.%c*", path, section, name, *section);
745       else
746         snprintf (pathname, sizeof(pathname), "%s/man%s/%s.%c*", path, section, name, *section);
747
748       gf = glob_filename (pathname);
749     }
750   if ((gf == (char **) -1 || *gf == NULL) && isdigit ((unsigned char)*section)
751       && strlen (longsec) == 1)
752     {
753       if (cat)
754         snprintf (pathname, sizeof(pathname), "%s/cat%s/%s.0*", path, section, name);
755       else
756         snprintf (pathname, sizeof(pathname), "%s/man%s/%s.0*", path, section, name);
757       if (debug)
758         fprintf (stderr, "globbing %s\n", pathname);
759       gf = glob_filename (pathname);
760     }
761   return gf;
762 }
763
764 /*
765  * Return an un-globbed name in the same form as if we were doing
766  * globbing.
767  */
768 char **
769 make_name (path, section, longsec, name, cat)
770      char *path;
771      char *section;
772      char *longsec;
773      char *name;
774      int cat;
775 {
776   register int i = 0;
777   static char *names[3];
778   char buf[FILENAME_MAX];
779
780   if (cat)
781     snprintf (buf, sizeof(buf), "%s/cat%s/%s.%s", path, section, name, longsec);
782   else
783     snprintf (buf, sizeof(buf), "%s/man%s/%s.%s", path, section, name, longsec);
784
785   if (access (buf, R_OK) == 0)
786     names[i++] = strdup (buf);
787
788   /*
789    * If we're given a section that looks like `3f', we may want to try
790    * file names like .../man3/foo.3f as well.  This seems a bit
791    * kludgey to me, but what the hey...
792    */
793   if (section[1] != '\0')
794     {
795       if (cat)
796         snprintf (buf, sizeof(buf), "%s/cat%c/%s.%s", path, section[0], name, section);
797       else
798         snprintf (buf, sizeof(buf), "%s/man%c/%s.%s", path, section[0], name, section);
799
800       if (access (buf, R_OK) == 0)
801         names[i++] = strdup (buf);
802     }
803
804   names[i] = NULL;
805
806   return &names[0];
807 }
808
809 char *
810 get_expander (file)
811      char *file;
812 {
813   char *end = file + (strlen (file) - 1);
814
815   while (end > file && end[-1] != '.')
816     --end;
817   if (end == file)
818     return NULL;
819 #ifdef FCAT
820   if (*end == 'F')
821     return FCAT;
822 #endif  /* FCAT */
823 #ifdef YCAT
824   if (*end == 'Y')
825     return YCAT;
826 #endif  /* YCAT */
827 #ifdef ZCAT
828   if (*end == 'Z' || !strcmp(end, "gz"))
829     return ZCAT;
830 #endif  /* ZCAT */
831   return NULL;
832 }
833
834 /*
835  * Simply display the preformatted page.
836  */
837 int
838 display_cat_file (file)
839      register char *file;
840 {
841   register int found;
842   char command[FILENAME_MAX];
843
844   found = 0;
845
846   if (access (file, R_OK) == 0)
847     {
848       char *expander = get_expander (file);
849
850       if (expander != NULL)
851         snprintf (command, sizeof(command), "%s %s | %s", expander, file, pager);
852       else
853         snprintf (command, sizeof(command), "%s %s", pager, file);
854
855       found = do_system_command (command);
856     }
857   return found;
858 }
859
860 /*
861  * Try to find the ultimate source file.  If the first line of the
862  * current file is not of the form
863  *
864  *      .so man3/printf.3s
865  *
866  * the input file name is returned.
867  */
868 char *
869 ultimate_source (name, path)
870      char *name;
871      char *path;
872 {
873   static  char buf[BUFSIZ];
874   static  char ult[FILENAME_MAX];
875
876   FILE *fp;
877   char *beg;
878   char *end;
879
880   strncpy (ult, name, sizeof(ult)-1);
881   ult[sizeof(ult)-1] = '\0';
882   strncpy (buf, name, sizeof(buf)-1);
883   ult[sizeof(buf)-1] = '\0';
884
885  next:
886
887   if ((fp = fopen (ult, "r")) == NULL)
888     return ult;
889
890   end = fgets (buf, BUFSIZ, fp);
891   fclose(fp);
892
893   if (!end || strlen (buf) < 5)
894     return ult;
895
896   beg = buf;
897   if (*beg++ == '.' && *beg++ == 's' && *beg++ == 'o')
898     {
899       while ((*beg == ' ' || *beg == '\t') && *beg != '\0')
900         beg++;
901
902       end = beg;
903       while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
904         end++;
905
906       *end = '\0';
907
908       snprintf(ult, sizeof(ult), "%s/%s", path, beg);
909       snprintf(buf, sizeof(buf), "%s", ult);
910
911       goto next;
912     }
913
914   if (debug)
915     fprintf (stderr, "found ultimate source file %s\n", ult);
916
917   return ult;
918 }
919
920 void
921 add_directive (first, d, file, buf, bufsize)
922      int *first;
923      char *d;
924      char *file;
925      char *buf;
926      int bufsize;
927 {
928   if (strcmp (d, "") != 0)
929     {
930       if (*first)
931         {
932           *first = 0;
933           snprintf(buf, bufsize, "%s %s", d, file);
934         }
935       else
936         {
937           strncat (buf, " | ", bufsize-strlen(buf)-1);
938           strncat (buf, d, bufsize-strlen(buf)-1);
939         }
940     }
941 }
942
943 int
944 parse_roff_directive (cp, file, buf, bufsize)
945   char *cp;
946   char *file;
947   char *buf;
948   int bufsize;
949 {
950   char c;
951   char *exp;
952   int first = 1;
953   int preproc_found = 0;
954   int use_col = 0;
955
956   if ((exp = get_expander(file)) != NULL)
957         add_directive (&first, exp, file, buf, bufsize);
958
959   while ((c = *cp++) != '\0')
960     {
961       switch (c)
962         {
963         case 'e':
964
965           if (debug)
966             fprintf (stderr, "found eqn(1) directive\n");
967
968           preproc_found++;
969           if (troff)
970             add_directive (&first, EQN, file, buf, bufsize);
971           else {
972 #ifdef __FreeBSD__
973             char lbuf[FILENAME_MAX];
974
975             snprintf(lbuf, sizeof(lbuf), "%s -T%s", NEQN,
976                      locale_opts == NULL ? "ascii" : locale_opts);
977             add_directive (&first, lbuf, file, buf, bufsize);
978 #else
979             add_directive (&first, NEQN, file, buf, bufsize);
980 #endif
981           }
982
983           break;
984
985         case 'g':
986
987           if (debug)
988             fprintf (stderr, "found grap(1) directive\n");
989
990           preproc_found++;
991           add_directive (&first, GRAP, file, buf, bufsize);
992
993           break;
994
995         case 'p':
996
997           if (debug)
998             fprintf (stderr, "found pic(1) directive\n");
999
1000           preproc_found++;
1001           add_directive (&first, PIC, file, buf, bufsize);
1002
1003           break;
1004
1005         case 't':
1006
1007           if (debug)
1008             fprintf (stderr, "found tbl(1) directive\n");
1009
1010           preproc_found++;
1011           use_col++;
1012           add_directive (&first, TBL, file, buf, bufsize);
1013           break;
1014
1015         case 'v':
1016
1017           if (debug)
1018             fprintf (stderr, "found vgrind(1) directive\n");
1019
1020           add_directive (&first, VGRIND, file, buf, bufsize);
1021           break;
1022
1023         case 'r':
1024
1025           if (debug)
1026             fprintf (stderr, "found refer(1) directive\n");
1027
1028           add_directive (&first, REFER, file, buf, bufsize);
1029           break;
1030
1031         case ' ':
1032         case '\t':
1033         case '\n':
1034
1035           goto done;
1036
1037         default:
1038
1039           return -1;
1040         }
1041     }
1042
1043  done:
1044
1045 #ifdef HAS_TROFF
1046   if (troff)
1047     add_directive (&first, TROFF, file, buf, bufsize);
1048   else
1049 #endif
1050     {
1051 #ifdef __FreeBSD__
1052       char lbuf[FILENAME_MAX];
1053
1054       snprintf(lbuf, sizeof(lbuf), "%s -T%s%s%s", NROFF,
1055                locale_opts == NULL ? "ascii" : locale_opts,
1056                use_man_locale ? " -dlocale=" : "",
1057                use_man_locale ? man_locale : "");
1058             add_directive (&first, lbuf, file, buf, bufsize);
1059 #else
1060       add_directive (&first, NROFF " -Tascii", file, buf, bufsize);
1061 #endif
1062     }
1063   if (use_col && !troff)
1064       add_directive (&first, COL, file, buf, bufsize);
1065
1066   if (preproc_found)
1067     return 0;
1068   else
1069     return 1;
1070 }
1071
1072 char *
1073 make_roff_command (file)
1074      char *file;
1075 {
1076 #if HAVE_LIBZ > 0
1077   gzFile fp;
1078 #else
1079   FILE *fp;
1080 #endif
1081   char line [BUFSIZ];
1082   static char buf [BUFSIZ];
1083   int status;
1084   char *cp;
1085
1086   if (roff_directive != NULL)
1087     {
1088       if (debug)
1089         fprintf (stderr, "parsing directive from command line\n");
1090
1091       status = parse_roff_directive (roff_directive, file, buf, sizeof(buf));
1092
1093       if (status == 0)
1094         return buf;
1095
1096       if (status == -1)
1097         gripe_roff_command_from_command_line (file);
1098     }
1099
1100 #if HAVE_LIBZ > 0
1101   if ((fp = gzopen (file, "r")) != NULL)
1102 #else
1103   if ((fp = fopen (file, "r")) != NULL)
1104 #endif
1105     {
1106       cp = line;
1107 #if HAVE_LIBZ > 0
1108       gzgets (fp, line, BUFSIZ);
1109       gzclose(fp);
1110 #else
1111       fgets (line, BUFSIZ, fp);
1112       fclose(fp);
1113 #endif
1114       if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ')
1115         {
1116           if (debug)
1117             fprintf (stderr, "parsing directive from file\n");
1118
1119           status = parse_roff_directive (cp, file, buf, sizeof(buf));
1120
1121           if (status == 0)
1122             return buf;
1123
1124           if (status == -1)
1125             gripe_roff_command_from_file (file);
1126         }
1127     }
1128   else
1129     {
1130       /*
1131        * Is there really any point in continuing to look for
1132        * preprocessor options if we can't even read the man page source?
1133        */
1134       gripe_reading_man_file (file);
1135       return NULL;
1136     }
1137
1138   if ((cp = getenv ("MANROFFSEQ")) != NULL)
1139     {
1140       if (debug)
1141         fprintf (stderr, "parsing directive from environment\n");
1142
1143       status = parse_roff_directive (cp, file, buf, sizeof(buf));
1144
1145       if (status == 0)
1146         return buf;
1147
1148       if (status == -1)
1149         gripe_roff_command_from_env ();
1150     }
1151
1152   if (debug)
1153     fprintf (stderr, "using default preprocessor sequence\n");
1154
1155   status = parse_roff_directive ("t", file, buf, sizeof(buf));
1156   if (status >= 0)
1157     return buf;
1158   else          /* can't happen */
1159     return NULL;
1160 }
1161
1162 sig_t ohup, oint, oquit, oterm;
1163 static char temp[FILENAME_MAX];
1164
1165 void cleantmp()
1166 {
1167         unlink(temp);
1168         exit(1);
1169 }
1170
1171 void
1172 set_sigs()
1173 {
1174   ohup = signal(SIGHUP, cleantmp);
1175   oint = signal(SIGINT, cleantmp);
1176   oquit = signal(SIGQUIT, cleantmp);
1177   oterm = signal(SIGTERM, cleantmp);
1178 }
1179
1180 void
1181 restore_sigs()
1182 {
1183   signal(SIGHUP, ohup);
1184   signal(SIGINT, oint);
1185   signal(SIGQUIT, oquit);
1186   signal(SIGTERM, oterm);
1187 }
1188
1189 /*
1190  * Try to format the man page and create a new formatted file.  Return
1191  * 1 for success and 0 for failure.
1192  */
1193 int
1194 make_cat_file (path, man_file, cat_file, manid)
1195      register char *path;
1196      register char *man_file;
1197      register char *cat_file;
1198 {
1199   int s, f;
1200   FILE *pp;
1201 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1202   gzFile fp;
1203 #else
1204   FILE *fp;
1205 #endif
1206   char *roff_command;
1207   char command[FILENAME_MAX];
1208
1209   roff_command = make_roff_command (man_file);
1210   if (roff_command == NULL)
1211       return 0;
1212
1213   snprintf(temp, sizeof(temp), "%s.tmpXXXXXX", cat_file);
1214   if ((f = mkstemp(temp)) >= 0 && 
1215 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1216       (fp = gzdopen(f, "w")) != NULL)
1217 #else
1218       (fp = fdopen(f, "w")) != NULL)
1219 #endif
1220     {
1221       set_sigs();
1222
1223       if (fchmod (f, CATMODE) < 0) {
1224         perror("fchmod");
1225         unlink(temp);
1226         restore_sigs();
1227         fclose(fp);
1228         return 0;
1229       } else if (debug)
1230         fprintf (stderr, "mode of %s is now %o\n", temp, CATMODE);
1231
1232       snprintf (command, sizeof(command), "(cd %s ; %s)", path,
1233                 roff_command);
1234
1235       fprintf (stderr, "Formatting page, please wait...");
1236       fflush(stderr);
1237
1238       if (debug)
1239         fprintf (stderr, "\ntrying command: %s\n", command);
1240       else {
1241
1242 #ifdef SETUID
1243         if (manid)
1244           seteuid(ruid);
1245 #endif
1246         if ((pp = popen(command, "r")) == NULL) {
1247           s = errno;
1248           fprintf(stderr, "Failed.\n");
1249           errno = s;
1250           perror("popen");
1251 #ifdef SETUID
1252           if (manid)
1253             seteuid(euid);
1254 #endif
1255           unlink(temp);
1256           restore_sigs();
1257 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1258           gzclose(fp);
1259 #else
1260           fclose(fp);
1261 #endif
1262           return 0;
1263         }
1264 #ifdef SETUID
1265         if (manid)
1266           seteuid(euid);
1267 #endif
1268
1269         f = 0;
1270         while ((s = getc(pp)) != EOF) {
1271 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1272           gzputc(fp, s);
1273 #else
1274           putc(s, fp);
1275 #endif
1276           f++;
1277         }
1278
1279         if (!f || ((s = pclose(pp)) == -1)) {
1280           s = errno;
1281           fprintf(stderr, "Failed.\n");
1282           errno = s;
1283           if (f)
1284             perror("pclose");
1285           unlink(temp);
1286           restore_sigs();
1287 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1288           gzclose(fp);
1289 #else
1290           fclose(fp);
1291 #endif
1292           return 0;
1293         }
1294
1295         if (s != 0) {
1296           fprintf(stderr, "Failed.\n");
1297           gripe_system_command(s);
1298           unlink(temp);
1299           restore_sigs();
1300 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1301           gzclose(fp);
1302 #else
1303           fclose(fp);
1304 #endif
1305           return 0;
1306         }
1307       }
1308
1309       if (debug)
1310         unlink(temp);
1311       else if (rename(temp, cat_file) == -1) {
1312         s = errno;
1313         fprintf(stderr,
1314                  "\nHmm!  Can't seem to rename %s to %s, check permissions on man dir!\n",
1315                  temp, cat_file);
1316         errno = s;
1317         perror("rename");
1318         unlink(temp);
1319         restore_sigs();
1320 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1321         gzclose(fp);
1322 #else
1323         fclose(fp);
1324 #endif
1325         return 0;
1326       }
1327       restore_sigs();
1328
1329 #if defined(HAVE_LIBZ) && defined(DO_COMPRESS)
1330       if (gzclose(fp)) {
1331 #else
1332       if (fclose(fp)) {
1333 #endif
1334         s = errno;
1335         if (!debug)
1336           unlink(cat_file);
1337         fprintf(stderr, "Failed.\n");
1338         errno = s;
1339         perror("fclose");
1340         return 0;
1341       }
1342
1343       if (debug) {
1344         fprintf(stderr, "No output, debug mode.\n");
1345         return 0;
1346       }
1347
1348       fprintf(stderr, "Done.\n");
1349
1350       return 1;
1351     }
1352   else
1353     {
1354       if (f >= 0) {
1355         s = errno;
1356         unlink(temp);
1357         errno = s;
1358       }
1359       if (debug) {
1360         s = errno;
1361         fprintf (stderr, "Couldn't open %s for writing.\n", temp);
1362         errno = s;
1363       }
1364       if (f >= 0) {
1365         perror("fdopen");
1366         close(f);
1367       }
1368
1369       return 0;
1370     }
1371 }
1372
1373 /*
1374  * Try to format the man page source and save it, then display it.  If
1375  * that's not possible, try to format the man page source and display
1376  * it directly.
1377  *
1378  * Note that we've already been handed the name of the ultimate source
1379  * file at this point.
1380  */
1381 int
1382 format_and_display (path, man_file, cat_file)
1383      register char *path;
1384      register char *man_file;
1385      register char *cat_file;
1386 {
1387   int status;
1388   register int found;
1389   char *roff_command;
1390   char command[FILENAME_MAX];
1391
1392   found = 0;
1393
1394   if (access (man_file, R_OK) != 0)
1395     return 0;
1396
1397   if (troff)
1398     {
1399       roff_command = make_roff_command (man_file);
1400       if (roff_command == NULL)
1401         return 0;
1402       else
1403         snprintf (command, sizeof(command), "(cd %s ; %s)", path, roff_command);
1404
1405       found = do_system_command (command);
1406     }
1407   else
1408     {
1409       status = is_newer (man_file, cat_file);
1410       if (debug)
1411         fprintf (stderr, "status from is_newer() = %d\n", status);
1412
1413       if (status == 1 || status == -2)
1414         {
1415           /*
1416            * Cat file is out of date.  Try to format and save it.
1417            */
1418           if (print_where)
1419             {
1420               printf ("%s\n", man_file);
1421               found++;
1422             }
1423           else
1424             {
1425
1426 #ifdef SETUID
1427               seteuid(euid);
1428               found = make_cat_file (path, man_file, cat_file, 1);
1429               seteuid(ruid);
1430
1431               if (!found)
1432                 {
1433                   /* Try again as real user - see note below.
1434                      By running with
1435                        effective group (user) ID == real group (user) ID
1436                      except for the call above, I believe the problems
1437                      of reading private man pages is avoided.  */
1438                   found = make_cat_file (path, man_file, cat_file, 0);
1439                 }
1440 #else
1441               found = make_cat_file (path, man_file, cat_file, 0);
1442 #endif
1443               if (found)
1444                 {
1445                   /*
1446                    * Creating the cat file worked.  Now just display it.
1447                    */
1448                   (void) display_cat_file (cat_file);
1449                 }
1450               else
1451                 {
1452                   /*
1453                    * Couldn't create cat file.  Just format it and
1454                    * display it through the pager.
1455                    */
1456                   roff_command = make_roff_command (man_file);
1457                   if (roff_command == NULL)
1458                     return 0;
1459                   else
1460                     snprintf (command, sizeof(command), "(cd %s ; %s | %s)", path,
1461                              roff_command, pager);
1462
1463                   found = do_system_command (command);
1464                 }
1465             }
1466         }
1467       else if (access (cat_file, R_OK) == 0)
1468         {
1469           /*
1470            * Formatting not necessary.  Cat file is newer than source
1471            * file, or source file is not present but cat file is.
1472            */
1473           if (print_where)
1474             {
1475               printf ("%s (source: %s)\n", cat_file, man_file);
1476               found++;
1477             }
1478           else
1479             {
1480               found = display_cat_file (cat_file);
1481             }
1482         }
1483     }
1484   return found;
1485 }
1486
1487 /*
1488  * See if the preformatted man page or the source exists in the given
1489  * section.
1490  */
1491 int
1492 try_section (path, section, longsec, name, glob)
1493      char *path;
1494      char *section;
1495      char *longsec;
1496      char *name;
1497      int glob;
1498 {
1499   register int found = 0;
1500   register int to_cat;
1501   register int cat;
1502   register char **names;
1503   register char **np;
1504   static int arch_search;
1505   char buf[FILENAME_MAX];
1506
1507   if (!arch_search)
1508     {
1509       snprintf(buf, sizeof(buf), "%s/man%s/%s", path, section, machine);
1510       if (is_directory (buf) == 1)
1511         {
1512           snprintf(buf, sizeof(buf), "%s/%s", machine, name);
1513           arch_search++;
1514           found = try_section (path, section, longsec, buf, glob);
1515           arch_search--;
1516           if (found && !findall)   /* only do this architecture... */
1517             return found;
1518         }
1519       if (strcmp(machine_arch, machine) != 0)
1520         {
1521           snprintf(buf, sizeof(buf), "%s/man%s/%s", path, section, machine_arch);
1522           if (is_directory (buf) == 1)
1523             {
1524               snprintf(buf, sizeof(buf), "%s/%s", machine_arch, name);
1525               arch_search++;
1526               found = try_section (path, section, longsec, buf, glob);
1527               arch_search--;
1528               if (found && !findall)   /* only do this architecture... */
1529                 return found;
1530             }
1531         }
1532     }
1533
1534   if (debug)
1535     {
1536       if (glob)
1537         fprintf (stderr, "trying section %s with globbing\n", section);
1538       else
1539         fprintf (stderr, "trying section %s without globbing\n", section);
1540     }
1541
1542 #ifndef NROFF_MISSING
1543   /*
1544    * Look for man page source files.
1545    */
1546   cat = 0;
1547   if (glob)
1548     names = glob_for_file (path, section, longsec, name, cat);
1549   else
1550     names = make_name (path, section, longsec, name, cat);
1551
1552   if (names == (char **) -1 || *names == NULL)
1553     /*
1554      * No files match.  See if there's a preformatted page around that
1555      * we can display.
1556      */
1557 #endif /* NROFF_MISSING */
1558     {
1559       if (!troff)
1560         {
1561           cat = 1;
1562           if (glob)
1563             names = glob_for_file (path, section, longsec, name, cat);
1564           else
1565             names = make_name (path, section, longsec, name, cat);
1566
1567           if (names != (char **) -1 && *names != NULL)
1568             {
1569               for (np = names; *np != NULL; np++)
1570                 {
1571                   if (print_where)
1572                     {
1573                       printf ("%s\n", *np);
1574                       found++;
1575                     }
1576                   else
1577                     {
1578                       found += display_cat_file (*np);
1579                     }
1580                 }
1581             }
1582         }
1583     }
1584 #ifndef NROFF_MISSING
1585   else
1586     {
1587       for (np = names; *np != NULL; np++)
1588         {
1589           register char *cat_file = NULL;
1590           register char *man_file;
1591
1592           man_file = ultimate_source (*np, path);
1593
1594           if (!troff)
1595             {
1596               to_cat = 1;
1597
1598               cat_file = convert_name (man_file, to_cat);
1599
1600               if (debug)
1601                 fprintf (stderr, "will try to write %s if needed\n", cat_file);
1602             }
1603
1604           found += format_and_display (path, man_file, cat_file);
1605         }
1606     }
1607 #endif /* NROFF_MISSING */
1608   return found;
1609 }
1610
1611 /*
1612  * Search for manual pages.
1613  *
1614  * If preformatted manual pages are supported, look for the formatted
1615  * file first, then the man page source file.  If they both exist and
1616  * the man page source file is newer, or only the source file exists,
1617  * try to reformat it and write the results in the cat directory.  If
1618  * it is not possible to write the cat file, simply format and display
1619  * the man file.
1620  *
1621  * If preformatted pages are not supported, or the troff option is
1622  * being used, only look for the man page source file.
1623  *
1624  */
1625 int
1626 man (name)
1627      char *name;
1628 {
1629   register int found;
1630   register int glob;
1631   register char **mp;
1632   register char **sp;
1633 #ifdef __FreeBSD__
1634   int l_found;
1635   char buf[FILENAME_MAX];
1636 #endif
1637
1638   found = 0;
1639
1640   fflush (stdout);
1641   if (shortsec != NULL)
1642     {
1643       for (mp = manpathlist; *mp != NULL; mp++)
1644         {
1645           if (debug)
1646             fprintf (stderr, "\nsearching in %s\n", *mp);
1647
1648           glob = 1;
1649
1650 #ifdef __FreeBSD__
1651           l_found = 0;
1652           if (locale != NULL) {
1653             locale_opts = locale_nroff;
1654             use_man_locale = 1;
1655             if (*locale_lang != '\0' && *locale_terr != '\0') {
1656               snprintf(buf, sizeof(buf), "%s/%s_%s.%s", *mp,
1657                        locale_lang, locale_terr, locale_codeset);
1658               if (is_directory (buf) == 1)
1659                 l_found = try_section (buf, shortsec, longsec, name, glob);
1660             }
1661             if (!l_found) {
1662               if (*locale_lang != '\0') {
1663                 snprintf(buf, sizeof(buf), "%s/%s.%s", *mp,
1664                          locale_lang, locale_codeset);
1665                 if (is_directory (buf) == 1)
1666                   l_found = try_section (buf, shortsec, longsec, name, glob);
1667               }
1668               use_man_locale = 0;
1669               if (!l_found && strcmp(locale_lang, "en") != 0) {
1670                 snprintf(buf, sizeof(buf), "%s/en.%s", *mp,
1671                          locale_codeset);
1672                 if (is_directory (buf) == 1)
1673                   l_found = try_section (buf, shortsec, longsec, name, glob);
1674               }
1675             }
1676             locale_opts = NULL;
1677             use_man_locale = 0;
1678           }
1679           if (!l_found) {
1680 #endif
1681           found += try_section (*mp, shortsec, longsec, name, glob);
1682 #ifdef __FreeBSD__
1683           } else
1684             found += l_found;
1685 #endif
1686
1687           if (found && !findall)   /* i.e. only do this section... */
1688             return found;
1689         }
1690     }
1691   else
1692     {
1693       for (sp = section_list; *sp != NULL; sp++)
1694         {
1695           for (mp = manpathlist; *mp != NULL; mp++)
1696             {
1697               if (debug)
1698                 fprintf (stderr, "\nsearching in %s\n", *mp);
1699
1700               glob = 1;
1701
1702 #ifdef __FreeBSD__
1703               l_found = 0;
1704               if (locale != NULL) {
1705                 locale_opts = locale_nroff;
1706                 use_man_locale = 1;
1707                 if (*locale_lang != '\0' && *locale_terr != '\0') {
1708                   snprintf(buf, sizeof(buf), "%s/%s_%s.%s", *mp,
1709                            locale_lang, locale_terr, locale_codeset);
1710                   if (is_directory (buf) == 1)
1711                     l_found = try_section (buf, *sp, longsec, name, glob);
1712                 }
1713                 if (!l_found) {
1714                   if (*locale_lang != '\0') {
1715                     snprintf(buf, sizeof(buf), "%s/%s.%s", *mp,
1716                              locale_lang, locale_codeset);
1717                     if (is_directory (buf) == 1)
1718                       l_found = try_section (buf, *sp, longsec, name, glob);
1719                   }
1720                   use_man_locale = 0;
1721                   if (!l_found && strcmp(locale_lang, "en") != 0) {
1722                     snprintf(buf, sizeof(buf), "%s/en.%s", *mp,
1723                              locale_codeset);
1724                     if (is_directory (buf) == 1)
1725                       l_found = try_section (buf, *sp, longsec, name, glob);
1726                   }
1727                 }
1728                 locale_opts = NULL;
1729                 use_man_locale = 0;
1730               }
1731               if (!l_found) {
1732 #endif
1733               found += try_section (*mp, *sp, longsec, name, glob);
1734 #ifdef __FreeBSD__
1735               } else
1736                 found += l_found;
1737 #endif
1738
1739               if (found && !findall)   /* i.e. only do this section... */
1740                 return found;
1741             }
1742         }
1743     }
1744   return found;
1745 }
1746
1747 char **
1748 get_section_list ()
1749 {
1750   int i;
1751   char *p;
1752   char *end;
1753 #define TMP_SECTION_LIST_SIZE 100
1754   static char *tmp_section_list[TMP_SECTION_LIST_SIZE];
1755
1756   if (colon_sep_section_list == NULL)
1757     {
1758       if ((p = getenv ("MANSECT")) == NULL)
1759         {
1760           return std_sections;
1761         }
1762       else
1763         {
1764           colon_sep_section_list = strdup (p);
1765         }
1766     }
1767
1768   i = 0;
1769   for (p = colon_sep_section_list; i < TMP_SECTION_LIST_SIZE ; p = end+1) 
1770     {
1771       if ((end = strchr (p, ':')) != NULL)
1772         *end = '\0';
1773
1774       tmp_section_list[i++] = strdup (p);
1775
1776       if (end == NULL)
1777         break;
1778     }
1779
1780   tmp_section_list [i] = NULL;
1781   return tmp_section_list;
1782 }