Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:25:46 dillon 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?")) != EOF)
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
417   tmppath = strdup (path);
418
419   for (p = tmppath; ; p = end+1)
420     {
421       if ((end = strchr(p, ':')) != NULL)
422         *end = '\0';
423
424       if (debug)
425         fprintf (stderr, "\npath directory %s ", p);
426
427       if (*p != '/')
428         {
429           if (debug)
430             fprintf (stderr, "is not an absolute pathname\n");
431
432           goto found;   /* skip. */
433         }
434
435       /*
436        * The directory we're working on is in the config file.
437        * If we haven't added it to the list yet, do.
438        */
439       for (dlp = list; dlp->mandir[0] != '\0'; dlp++)
440         if (dlp->bin[0] != '\0' && !strcmp (p, dlp->bin))
441           {
442             if (debug)
443               fprintf (stderr, "is in the config file\n");
444
445             add_dir_to_list (tmplist, dlp->mandir, perrs);
446             goto found;
447           }
448
449       /*
450        * The directory we're working on isn't in the config file.  See
451        * if it has man or MAN subdirectories.  If so, and it hasn't
452        * been added to the list, do.
453        */
454       if (debug)
455         fprintf (stderr, "is not in the config file\n");
456
457       t = has_subdirs (p);
458       if (t != NULL)
459         {
460           if (debug)
461             fprintf (stderr, "but it does have a man or MAN subdirectory\n");
462
463           add_dir_to_list (tmplist, t, perrs);
464           free (t);
465         }
466       else
467         {
468           if (debug)
469             fprintf (stderr, "and doesn't have man or MAN subdirectories\n");
470         }
471
472     found:
473
474       if (!end)
475         break;
476     }
477
478   if (debug)
479     fprintf (stderr, "\nadding mandatory man directories\n\n");
480
481   dlp = list;
482   while (dlp->type != MANPATH_NONE) {
483     if (dlp->type == MANPATH_MANDATORY || dlp->type == MANPATH_OPTIONAL)
484       add_dir_to_list (tmplist, dlp->mandir,
485         dlp->type == MANPATH_MANDATORY? perrs: 0);
486     dlp++;
487   }
488
489   len = 0;
490   lp = tmplist;
491   while (*lp != NULL)
492     {
493       len += strlen (*lp) + 1;
494       lp++;
495     }
496
497   if (!len)
498     return strdup("");
499
500   manpathlist = (char *) malloc (len);
501   if (manpathlist == NULL)
502     gripe_alloc (len, "manpathlist");
503
504   *manpathlist = '\0';
505
506   lp = tmplist;
507   p = manpathlist;
508   while (*lp != NULL)
509     {
510       len = strlen (*lp);
511       memcpy (p, *lp, len);
512       p += len;
513       *p++ = ':';
514       lp++;
515     }
516
517   p[-1] = '\0';
518
519   return manpathlist;
520 }
521
522 /*
523  * Add a directory to the manpath list if it isn't already there.
524  */
525 void
526 add_dir_to_list (lp, dir, perrs)
527      char **lp;
528      char *dir;
529      int perrs;
530 {
531   extern char *strdup ();
532   int status;
533
534   while (*lp != NULL)
535     {
536       if (!strcmp (*lp, dir))
537         {
538           if (debug)
539             fprintf (stderr, "%s is already in the manpath\n", dir);
540           return;
541         }
542       lp++;
543     }
544   /*
545    * Not found -- add it.
546    */
547   status = is_directory(dir);
548
549   if (status < 0 && perrs)
550     {
551       fprintf (stderr, "Warning: couldn't stat file %s!\n", dir);
552     }
553   else if (status == 0 && perrs)
554     {
555       fprintf (stderr, "Warning: %s isn't a directory!\n", dir);
556     }
557   else if (status == 1)
558     {
559       if (debug)
560         fprintf (stderr, "adding %s to manpath\n", dir);
561
562       *lp = strdup (dir);
563     }
564 }
565
566 /*
567  * Check to see if the current directory has man or MAN
568  * subdirectories.
569  */
570 char *
571 has_subdirs (p)
572      register char *p;
573 {
574   int len;
575   register char *t;
576
577   len = strlen (p);
578
579   t = (char *) malloc ((unsigned) len + 5);
580   if (t == NULL)
581     gripe_alloc (len+5, "p\n");
582
583   memcpy (t, p, len);
584   strcpy (t + len, "/man");
585
586   if (is_directory (t) == 1)
587     return t;
588
589   strcpy (t + len, "/MAN");
590
591   if (is_directory (t) == 1)
592     return t;
593
594   /* If the path ends in `bin' then replace with `man' and see if that works. */
595   if (len > 3 && strncmp(t+len-4, "/bin", 4) == 0) {
596     strcpy(t+len-4, "/man");
597
598     if (is_directory(t) == 1) 
599        return t;
600   }
601
602   return NULL;
603 }