1/*
2 * man-config.c
3 *
4 * Read the man.conf file
5 *
6 * Input line types:
7 *	MANBIN		/usr/bin/man
8 *	MANPATH         /usr/X386/man	[/var/catman/X386]
9 *	MANPATH_MAP     /usr/bin     /usr/man
10 *      FHS
11 *	FSSTND
12 *  NOAUTOPATH
13 *	NROFF           /usr/bin/groff -Tascii -mandoc
14 *	BROWSER		/usr/bin/lynx
15 *	HTMLPAGER	/usr/bin/lynx -dump
16 *	.gz             /usr/bin/gunzip -c
17 *	# Comment
18 *
19 * Allow globbing in MANPATH elements.
20 * This is useful e.g. for having MANPATH /opt/ * /man
21 * (avoid comment within comment).
22 */
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include "defs.h"
29#include "glob.h"
30#include "man-config.h"
31#include "man.h"
32#include "paths.h"
33#include "gripes.h"
34#include "util.h"
35
36#define BUFSIZE 4096
37
38extern char *rindex (const char *, int);	/* not always in <string.h> */
39
40#define whitespace(x) ((x) == ' ' || (x) == '\t')
41
42/* directories listed in config file */
43struct dirs cfdirlist;          /* linked list, 1st entry unused */
44
45static void
46addval (char *buf) {
47     int i, len;
48     char *bp;
49
50     for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++) {
51	  len = strlen (paths[i].name);
52	  bp = buf + len;
53	  if(!strncmp (buf, paths[i].name, len) && (!*bp || whitespace(*bp))) {
54	       while(whitespace(*bp))
55		    bp++;
56	       paths[i].path = my_strdup(bp);
57	       return;
58	  }
59     }
60     gripe (UNRECOGNIZED_LINE, buf);
61}
62
63const char *
64getval (const char *cmd) {
65     int i;
66
67     for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++)
68	  if (!strcmp (cmd, paths[i].name))
69	       return paths[i].path;	/* never NULL */
70     gripe (GETVAL_ERROR, cmd);
71     return "";				/* impossible */
72}
73
74static void
75adddir (const char *bp, int mandatory) {
76     int i;
77     struct dirs *dlp;
78
79     while (whitespace(*bp))
80	  bp++;
81     if (*bp == 0)
82	  gripe (PARSE_ERROR_IN_CONFIG);
83
84     dlp = &cfdirlist;
85     while (dlp->nxt)
86	  dlp = dlp->nxt;
87     dlp->nxt = (struct dirs *) my_malloc (sizeof(struct dirs));
88     dlp = dlp->nxt;
89     dlp->mandatory = mandatory;
90     dlp->nxt = 0;
91
92     if (!mandatory) {
93	  i = 0;
94	  while (*bp && !whitespace(*bp)) {
95	       if (i < MAXPATHLEN - 1)
96		    dlp->bindir[i++] = *bp;
97	       bp++;
98	  }
99	  dlp->bindir[i] = 0;
100
101	  while (whitespace(*bp))
102	       bp++;
103     } else {
104	  dlp->bindir[0] = 0;
105     }
106
107     i = 0;
108     while (*bp && !whitespace(*bp)) {
109	  if (i < MAXPATHLEN - 1)
110	       dlp->mandir[i++] = *bp;
111	  bp++;
112     }
113     dlp->mandir[i] = 0;
114
115     while (whitespace(*bp))
116	  bp++;
117
118     i = 0;
119     while (*bp && !whitespace(*bp)) {
120	  if (i < MAXPATHLEN - 1)
121	       dlp->catdir[i++] = *bp;
122	  bp++;
123     }
124     dlp->catdir[i] = 0;
125
126     if (debug) {
127	  if (dlp->mandatory)
128	       gripe (FOUND_MANDIR, dlp->mandir);
129	  else
130	       gripe (FOUND_MAP, dlp->bindir, dlp->mandir);
131	  if (dlp->catdir[0])
132	       gripe (FOUND_CATDIR, dlp->catdir);
133     }
134}
135
136static void
137addglobdir (const char *bp, int mandatory) {
138	const char *dir;
139
140	while (whitespace(*bp))
141		bp++;
142
143	dir = bp;
144	if (index(dir, '*') || index(dir, '?') || index(dir, '[')) {
145		char **dp = glob_filename (dir);
146
147		if (dp && dp != (char **) -1) {
148			while (*dp)
149				adddir(*dp++, mandatory);
150			return;
151		}
152	}
153	adddir(dir, mandatory);
154}
155
156static struct xp {
157    char *extension;		/* non-null, including initial . */
158    char *expander;
159    struct xp *nxt;
160} uncompressors;		/* linked list, 1st entry unused */
161
162static void
163addext (char *bp) {
164     char *p, csv;
165     struct xp *xpp;
166
167     xpp = &uncompressors;
168     while (xpp->nxt)
169	  xpp = xpp->nxt;
170     xpp->nxt = (struct xp *) my_malloc (sizeof(struct xp));
171     xpp = xpp->nxt;
172     xpp->nxt = 0;
173
174     p = bp;
175     while(*p && !whitespace(*p))
176	  p++;
177     csv = *p;
178     *p = 0;
179     xpp->extension = my_strdup(bp);
180
181     *p = csv;
182     while(whitespace(*p))
183	  p++;
184     xpp->expander = my_strdup(p);
185}
186
187const char *
188get_expander (const char *file) {
189     struct xp *xp;
190     char *extp = NULL;
191
192     if (dohp) {
193	  /* Some HP systems have both man1 and man1.Z */
194	  /* For man1.Z/file.1 let extp=".Z" */
195	  /* For .1 return NULL */
196	  int len = strlen (dohp);
197	  char *dirname_end = rindex (file, '/');
198	  if (dirname_end && !strncmp (dirname_end-len, dohp, len))
199	      extp = dohp;
200     } else
201	  extp = rindex (file, '.');
202     if (extp != NULL) {
203	  if (uncompressors.nxt) {
204	       for (xp = uncompressors.nxt; xp; xp = xp->nxt)
205	            if (!strcmp (extp, xp->extension))
206		         return (xp->expander);
207	  } else if (!strcmp (extp, getval("COMPRESS_EXT"))) {
208	       return getval("DECOMPRESS");
209	  }
210     }
211     return NULL;
212}
213
214const char *configuration_file = "[no configuration file]";
215
216char *default_config_files[] = {
217     CONFIG_FILE,		/* compiled-in default */
218     "/etc/man.conf", "/etc/man.config",
219     "/usr/lib/man.conf", "/usr/lib/man.config",
220     "/usr/share/misc/man.conf", "/usr/share/misc/man.config"
221};
222
223#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
224
225void
226read_config_file (const char *cf) {
227     char *bp;
228     char *p;
229     char buf[BUFSIZE];
230     FILE *config = NULL;
231
232     if (cf) {
233	  /* User explicitly specified a config file */
234	  if ((config = fopen (cf, "r")) == NULL) {
235	       perror (cf);
236	       gripe (CONFIG_OPEN_ERROR, cf);
237	       return;
238	  }
239     } else {
240	  /* Try some things - unfortunately we cannot lookup
241	     the config file to use in the config file :-). */
242	  int i;
243
244	  for(i=0; i < SIZE(default_config_files); i++) {
245	       cf = default_config_files[i];
246	       if ((config = fopen (cf, "r")) != NULL)
247		    break;
248	  }
249
250	  if (config == NULL) {
251	       gripe (CONFIG_OPEN_ERROR, CONFIG_FILE);
252	       return;
253	  }
254     }
255
256     if (debug)
257	  fprintf(stderr, "Reading config file %s\n", cf);
258     configuration_file = cf;
259
260     while ((bp = fgets (buf, BUFSIZE, config)) != NULL) {
261	  while (whitespace(*bp))
262	       bp++;
263
264	  for (p = bp; *p && *p != '#' && *p != '\n'; p++) ;
265	  if (!*p) {
266	       gripe (LINE_TOO_LONG);
267	       gripe (BAD_CONFIG_FILE, cf);
268	       return;
269	  }
270	  while (p > bp && whitespace(p[-1]))
271	       p--;
272	  *p = 0;
273
274	  if (*bp == 0)
275	       continue;
276
277	  if (!strncmp ("MANPATH_MAP", bp, 11))
278	       adddir (bp+11, 0);
279	  else if (!strncmp ("MANPATH", bp, 7))
280	       addglobdir (bp+7, 1);
281	  else if(!strncmp ("MANDATORY_MANPATH", bp, 17))/* backwards compatible */
282	       adddir (bp+17, 1);
283	  else if (!strncmp ("FHS", bp, 3))
284	       fhs = 1;
285	  else if (!strncmp ("FSSTND", bp, 6))
286	       fsstnd = 1;
287	  else if (!strncmp ("NOAUTOPATH", bp, 10))
288		  noautopath = 1;
289	  else if (!strncmp ("NOCACHE", bp, 7))
290		  nocache = 1;
291	  else if (*bp == '.')
292	       addext (bp);
293	  else
294	       addval (bp);
295     }
296}
297
298