96d2b88a73b52e11188369f7aea4fb2a47f30c55
[dragonfly.git] / gnu / usr.bin / man / manpath / manpath.c
1 /*
2  * manpath.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  * $FreeBSD: src/gnu/usr.bin/man/manpath/manpath.c,v 1.11.2.2 2003/02/15 05:33:06 kris Exp $
17  * $DragonFly: src/gnu/usr.bin/man/manpath/manpath.c,v 1.5 2008/07/10 18:29:51 swildner Exp $
18  */
19
20 #define MANPATH_MAIN
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include "config.h"
27 #include "manpath.h"
28 #include "gripes.h"
29
30 #ifdef STDC_HEADERS
31 #include <stdlib.h>
32 #else
33 extern int fprintf ();
34 extern int strcmp ();
35 extern int strncmp ();
36 extern char *memcpy ();
37 extern char *getenv();
38 extern char *malloc();
39 extern void free ();
40 extern int exit ();
41 #endif
42
43 extern char *strdup ();
44 extern int is_directory ();
45
46 #ifndef MAIN
47 extern int debug;
48 #endif
49
50 #ifdef MAIN
51
52 #ifndef STDC_HEADERS
53 extern char *strcpy ();
54 extern int fflush ();
55 #endif
56
57 char *prognam;
58 int debug;
59 int locale;
60 char *man_locales;
61
62 /*
63  * Examine user's PATH and print a reasonable MANPATH.
64  */
65 int
66 main(argc, argv)
67      int argc;
68      char **argv;
69 {
70   int c;
71   int quiet;
72   char *mp;
73   extern int getopt ();
74   extern char *mkprogname ();
75   void usage ();
76   char *manpath ();
77
78   quiet = 1;
79
80   prognam = mkprogname (argv[0]);
81
82   while ((c = getopt (argc, argv, "dhLq?")) != -1)
83     {
84       switch (c)
85         {
86         case 'd':
87           debug++;
88           break;
89         case 'L':
90           locale++;
91           break;
92         case 'q':
93           quiet = 0;
94           break;
95         case '?':
96         case 'h':
97         default:
98           usage();
99           break;
100         }
101     }
102
103   mp = manpath (quiet);
104
105   fprintf (stdout, "%s\n", mp);
106   fflush (stdout);
107
108   return 0;
109 }
110
111 void
112 usage ()
113 {
114   fprintf (stderr, "usage: %s [-dLq]\n", prognam);
115   exit (1);
116 }
117 #endif /* MAIN */
118
119 /*
120  * If the environment variable MANPATH is set, return it.
121  * If the environment variable PATH is set and has a nonzero length,
122  * try to determine the corresponding manpath, otherwise, return the
123  * default manpath.
124  *
125  * The manpath.config file is used to map system wide /bin directories
126  * to top level man page directories.
127  *
128  * For directories which are in the user's path but not in the
129  * manpath.config file, see if there is a subdirectory `man' or `MAN'.
130  * If so, add that directory to the path.  Example:  user has
131  * $HOME/bin in his path and the directory $HOME/bin/man exists -- the
132  * directory $HOME/bin/man will be added to the manpath.
133  *
134  * Also search for a `man' directory next to the directory on the path.
135  * Example: $HOME/bin will look for $HOME/man
136  */
137 char *
138 manpath (perrs)
139      register int perrs;
140 {
141   register int len;
142   register char *manpathlist;
143   register char *path;
144   int  get_dirlist ();
145   char *def_path ();
146   char *get_manpath ();
147
148   if (get_dirlist ())
149       gripe_reading_mp_config (config_file);
150
151 #ifdef MAIN
152   if (locale)
153     {
154       if ((manpathlist = getenv ("MANLOCALES")) != NULL)
155         /*
156          * This must be it.
157          */
158         {
159           if (perrs)
160             fprintf (stderr, "(Warning: MANLOCALES environment variable set)\n");
161           return strdup (manpathlist);
162         }
163       return (man_locales ? man_locales : "");
164     }
165 #endif /* MAIN */
166
167   if ((manpathlist = getenv ("MANPATH")) != NULL)
168     /*
169      * This must be it.
170      */
171     {
172       if (perrs)
173         fprintf (stderr, "(Warning: MANPATH environment variable set)\n");
174       return strdup (manpathlist);
175     }
176   else if ((path = getenv ("PATH")) == NULL)
177     /*
178      * Things aren't going to work well, but hey...
179      */
180     {
181       if (perrs)
182         fprintf (stderr, "Warning: path not set\n");
183       return def_path (perrs);
184     }
185   else
186     {
187       if ((len = strlen (path)) == 0)
188         /*
189          * Things aren't going to work well here either...
190          */
191         {
192           if (perrs)
193             fprintf (stderr, "Warning: path set but has zero length\n");
194           return def_path (perrs);
195         }
196       return get_manpath (perrs, path);
197     }
198 }
199
200 /*
201  * Get the list of bin directories and the corresponding man
202  * directories from the manpath.config file.
203  *
204  * This is ugly.
205  */
206 int
207 get_dirlist ()
208 {
209   int i;
210   char *bp;
211   char *p;
212   char buf[BUFSIZ];
213   DIRLIST *dlp = list;
214   FILE *config;
215
216   if ((config = fopen (config_file, "r")) == NULL)
217     gripe_getting_mp_config (config_file);
218
219   while ((bp = fgets (buf, BUFSIZ, config)) != NULL)
220     {
221       while (*bp && (*bp == ' ' || *bp == '\t'))
222         bp++;
223
224       if (*bp == '#' || *bp == '\n')
225         continue;
226
227       if (!strncmp ("MANDATORY_MANPATH", bp, 17) ||
228           !strncmp ("OPTIONAL_MANPATH", bp, 16))
229         {
230           if ((p = strchr (bp, ' ')) == NULL &&
231               (p = strchr (bp, '\t')) == NULL) {
232             fclose(config);
233             return -1;
234           }
235
236           dlp->type = *bp == 'M'? MANPATH_MANDATORY: MANPATH_OPTIONAL;
237
238           bp = p;
239
240           while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
241             bp++;
242
243           i = 0;
244           while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
245             dlp->mandir[i++] = *bp++;
246           dlp->mandir[i] = '\0';
247
248           if (debug)
249             fprintf (stderr, "found %s man directory %s\n",
250                      dlp->type == MANPATH_MANDATORY? "mandatory": "optional",
251                      dlp->mandir);
252         }
253       else if (!strncmp ("MANPATH_MAP", bp, 11))
254         {
255           if ((p = strchr (bp, ' ')) == NULL &&
256               (p = strchr (bp, '\t')) == NULL) {
257             fclose(config);
258             return -1;
259           }
260
261           bp = p;
262
263           dlp->type = MANPATH_MAP;
264
265           while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
266             bp++;
267
268           i = 0;
269           while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
270             dlp->bin[i++] = *bp++;
271           dlp->bin[i] = '\0';
272
273           while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
274             bp++;
275
276           i = 0;
277           while (*bp && *bp != '\n' && *bp != ' ' && *bp != '\t')
278             dlp->mandir[i++] = *bp++;
279           dlp->mandir[i] = '\0';
280
281           if (debug)
282             fprintf (stderr, "found manpath map %s --> %s\n",
283                      dlp->bin, dlp->mandir);
284         }
285       else if (!strncmp ("MANLOCALES", bp, 10))
286         {
287           if ((p = strchr (bp, ' ')) == NULL &&
288               (p = strchr (bp, '\t')) == NULL) {
289             fclose(config);
290             return -1;
291           }
292
293           bp = p;
294
295           while (*bp && *bp != '\n' && (*bp == ' ' || *bp == '\t'))
296             bp++;
297
298           for (p = bp; *p && *p != '\n'; p++)
299                 ;
300           do {
301                 *p-- = '\0';
302           } while (p >= bp && (*p == ' ' || *p == '\t'));
303
304 #ifdef MAIN
305           if (man_locales != NULL)
306                 free (man_locales);
307
308           if ((man_locales = strdup (bp)) == NULL) {
309                 fclose(config);
310                 return -1;
311           }
312 #endif  /* MAIN */
313
314           if (debug)
315             fprintf (stderr, "found man locales: %s\n", bp);
316         }
317       else
318         {
319           gripe_reading_mp_config (config_file);
320         }
321       dlp++;
322     }
323
324   fclose(config);
325   dlp->bin[0] = '\0';
326   dlp->mandir[0] = '\0';
327   dlp->type = MANPATH_NONE;
328
329   return 0;
330 }
331
332 /*
333  * Construct the default manpath.  This picks up mandatory
334  * and optional (if they exist) manpaths only.
335  */
336 char *
337 def_path (perrs)
338      int perrs;
339 {
340   register int len;
341   register char *manpathlist, *p;
342   register DIRLIST *dlp;
343
344   len = 0;
345   dlp = list;
346   while (dlp->type != MANPATH_NONE) {
347     if (dlp->type == MANPATH_MANDATORY || dlp->type == MANPATH_OPTIONAL)
348       len += strlen (dlp->mandir) + 1;
349     dlp++;
350   }
351
352   manpathlist = (char *) malloc (len);
353   if (manpathlist == NULL)
354     gripe_alloc (len, "manpathlist");
355
356   *manpathlist = '\0';
357
358   dlp = list;
359   p = manpathlist;
360   while (dlp->type != MANPATH_NONE) {
361     if (dlp->type == MANPATH_MANDATORY || dlp->type == MANPATH_OPTIONAL) {
362       int status;
363       char *path = dlp->mandir;
364
365       status = is_directory(path);
366
367       if (status < 0 && perrs && dlp->type == MANPATH_MANDATORY)
368         {
369           fprintf (stderr, "Warning: couldn't stat file %s!\n", path);
370         }
371       else if (status == 0 && perrs)
372         {
373           fprintf (stderr, "Warning: %s isn't a directory!\n", path);
374         }
375       else if (status == 1)
376         {
377           len = strlen (path);
378           memcpy (p, path, len);
379           p += len;
380           *p++ = ':';
381         }
382     }
383     dlp++;
384   }
385
386   p[-1] = '\0';
387
388   return manpathlist;
389 }
390
391 /*
392  * For each directory in the user's path, see if it is one of the
393  * directories listed in the manpath.config file.  If so, and it is
394  * not already in the manpath, add it.  If the directory is not listed
395  * in the manpath.config file, see if there is a subdirectory `man' or
396  * `MAN'.  If so, and it is not already in the manpath, add it.
397  * Example:  user has $HOME/bin in his path and the directory
398  * $HOME/bin/man exists -- the directory $HOME/bin/man will be added
399  * to the manpath.
400  */
401 char *
402 get_manpath (perrs, path)
403      register int perrs;
404      register char *path;
405 {
406   register int len;
407   register char *tmppath;
408   register char *t;
409   register char *p;
410   register char **lp;
411   register char *end;
412   register char *manpathlist;
413   register DIRLIST *dlp;
414   void add_dir_to_list ();
415   char *has_subdirs ();
416   int fnd = 0;
417
418   tmppath = strdup (path);
419
420   for (p = tmppath; ; p = end+1)
421     {
422       if ((end = strchr(p, ':')) != NULL)
423         *end = '\0';
424
425       if (debug)
426         fprintf (stderr, "\npath directory %s ", p);
427
428       if (*p != '/')
429         {
430           if (debug)
431             fprintf (stderr, "is not an absolute pathname\n");
432
433           goto found;   /* skip. */
434         }
435
436       /*
437        * The directory we're working on is in the config file.
438        * If we haven't added it to the list yet, do.
439        */
440       for (dlp = list; dlp->mandir[0] != '\0'; dlp++)
441         if (dlp->bin[0] != '\0' && !strcmp (p, dlp->bin))
442           {
443             if (debug && !fnd)
444               fprintf (stderr, "is in the config file\n");
445
446             add_dir_to_list (tmplist, dlp->mandir, perrs);
447             fnd++;
448           }
449       if (fnd)
450         {
451           fnd = 0;
452           goto found;
453         }
454
455       /*
456        * The directory we're working on isn't in the config file.  See
457        * if it has man or MAN subdirectories.  If so, and it hasn't
458        * been added to the list, do.
459        */
460       if (debug)
461         fprintf (stderr, "is not in the config file\n");
462
463       t = has_subdirs (p);
464       if (t != NULL)
465         {
466           if (debug)
467             fprintf (stderr, "but it does have a man or MAN subdirectory\n");
468
469           add_dir_to_list (tmplist, t, perrs);
470           free (t);
471         }
472       else
473         {
474           if (debug)
475             fprintf (stderr, "and doesn't have man or MAN subdirectories\n");
476         }
477
478     found:
479
480       if (!end)
481         break;
482     }
483
484   if (debug)
485     fprintf (stderr, "\nadding mandatory man directories\n\n");
486
487   dlp = list;
488   while (dlp->type != MANPATH_NONE) {
489     if (dlp->type == MANPATH_MANDATORY || dlp->type == MANPATH_OPTIONAL)
490       add_dir_to_list (tmplist, dlp->mandir,
491         dlp->type == MANPATH_MANDATORY? perrs: 0);
492     dlp++;
493   }
494
495   len = 0;
496   lp = tmplist;
497   while (*lp != NULL)
498     {
499       len += strlen (*lp) + 1;
500       lp++;
501     }
502
503   if (!len)
504     return strdup("");
505
506   manpathlist = (char *) malloc (len);
507   if (manpathlist == NULL)
508     gripe_alloc (len, "manpathlist");
509
510   *manpathlist = '\0';
511
512   lp = tmplist;
513   p = manpathlist;
514   while (*lp != NULL)
515     {
516       len = strlen (*lp);
517       memcpy (p, *lp, len);
518       p += len;
519       *p++ = ':';
520       lp++;
521     }
522
523   p[-1] = '\0';
524
525   return manpathlist;
526 }
527
528 /*
529  * Add a directory to the manpath list if it isn't already there.
530  */
531 void
532 add_dir_to_list (lp, dir, perrs)
533      char **lp;
534      char *dir;
535      int perrs;
536 {
537   extern char *strdup ();
538   int status;
539
540   while (*lp != NULL)
541     {
542       if (!strcmp (*lp, dir))
543         {
544           if (debug)
545             fprintf (stderr, "%s is already in the manpath\n", dir);
546           return;
547         }
548       lp++;
549     }
550   /*
551    * Not found -- add it.
552    */
553   status = is_directory(dir);
554
555   if (status < 0 && perrs)
556     {
557       fprintf (stderr, "Warning: couldn't stat file %s!\n", dir);
558     }
559   else if (status == 0 && perrs)
560     {
561       fprintf (stderr, "Warning: %s isn't a directory!\n", dir);
562     }
563   else if (status == 1)
564     {
565       if (debug)
566         fprintf (stderr, "adding %s to manpath\n", dir);
567
568       *lp = strdup (dir);
569     }
570 }
571
572 /*
573  * Check to see if the current directory has man or MAN
574  * subdirectories.
575  */
576 char *
577 has_subdirs (p)
578      register char *p;
579 {
580   int len;
581   register char *t;
582
583   len = strlen (p);
584
585   t = (char *) malloc ((unsigned) len + 5);
586   if (t == NULL)
587     gripe_alloc (len+5, "p\n");
588
589   memcpy (t, p, len);
590   strcpy (t + len, "/man");
591
592   if (is_directory (t) == 1)
593     return t;
594
595   strcpy (t + len, "/MAN");
596
597   if (is_directory (t) == 1)
598     return t;
599
600   /* If the path ends in `bin' then replace with `man' and see if that works. */
601   if (len > 3 && strncmp(t+len-4, "/bin", 4) == 0) {
602     strcpy(t+len-4, "/man");
603
604     if (is_directory(t) == 1) 
605        return t;
606   }
607
608   return NULL;
609 }