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