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