1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5
6#include "defs.h"
7#include "gripes.h"
8#include "man.h"
9#include "man-config.h"
10#include "man-getopt.h"
11#include "util.h"
12#include "version.h"
13
14int alt_system;
15char *alt_system_name;
16char *opt_manpath;
17int global_apropos = 0;
18
19static void
20print_version (void) {
21     gripe (VERSION, progname, version);
22}
23
24static void
25usage (void) {
26     print_version();
27     gripe (USAGE1, progname);
28
29     gripe (USAGE2);		/* only for alt_systems */
30
31     gripe (USAGE3);
32     gripe (USAGE4);
33     gripe (USAGE5);    /* maybe only if troff found? */
34     gripe (USAGE6);
35
36     gripe (USAGE7);		/* only for alt_systems */
37
38     gripe (USAGE8);
39     exit(1);
40}
41
42static char short_opts[] = "B:C:H:xM:P:S:acdfFhkKm:p:s:tvVwW?Lq";
43
44#ifndef NOGETOPT
45#undef _GNU_SOURCE
46#define _GNU_SOURCE
47#include <getopt.h>
48
49static const struct option long_opts[] = {
50    { "help",       no_argument,            NULL, 'h' },
51    { "version",    no_argument,            NULL, 'v' },
52    { "path",       no_argument,            NULL, 'w' },
53    { "preformat",  no_argument,            NULL, 'F' },
54    { NULL, 0, NULL, 0 }
55};
56#endif
57
58/*
59 * Read options, return count.
60 */
61static int
62get_options_from_argvec(int argc, char **argv, char **config_file,
63			char **manpath) {
64     char *s;
65     int c;
66     int optct = 0;
67
68#ifndef NOGETOPT
69     while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1){
70#else
71     while ((c = getopt (argc, argv, short_opts)) != -1) {
72#endif
73	  switch (c) {
74	  case 'C':
75	       no_privileges ();
76	       if (config_file)
77		       *config_file = my_strdup (optarg);
78	       break;
79	  case'F':
80	       preformat = 1;
81	       break;
82	  case 'M':
83	       if (manpath)
84		       *manpath = my_strdup (optarg);
85	       break;
86	  case 'P':
87	       pager = my_strdup (optarg);
88	       break;
89	  case 'B':
90	       browser = my_strdup (optarg);
91	       break;
92	  case 'H':
93	       htmlpager = my_strdup (optarg);
94	       break;
95	  case 'S':
96	       colon_sep_section_list = my_strdup (optarg);
97	       break;
98	  case 's':
99	       /* undocumented; compatibility with Sun */
100	       s = colon_sep_section_list = my_strdup (optarg);
101	       while (*s) {
102		       if (*s == ',')
103			       *s = ':';
104		       s++;
105	       }
106	       break;
107	  case 'a':
108	       findall++;
109	       break;
110	  case 'c':
111	       nocats++;
112	       break;
113	  case 'd':
114	       debug++;
115	       break;
116	  case 'f':
117	       if (do_troff)
118		    fatal (INCOMPAT, "-f", "-t");
119	       if (apropos)
120		    fatal (INCOMPAT, "-f", "-k");
121	       if (print_where)
122		    fatal (INCOMPAT, "-f", "-w");
123	       whatis++;
124	       break;
125	  case 'k':
126	       if (do_troff)
127		    fatal (INCOMPAT, "-k", "-t");
128	       if (whatis)
129		    fatal (INCOMPAT, "-k", "-f");
130	       if (print_where)
131		    fatal (INCOMPAT, "-k", "-w");
132	       apropos++;
133	       break;
134	  case 'K':
135	       global_apropos++;
136	       break;
137	  case 'm':
138	       alt_system++;
139	       alt_system_name = my_strdup (optarg);
140	       break;
141	       /* or:  gripe (NO_ALTERNATE); exit(1); */
142	  case 'p':
143	       roff_directive = my_strdup (optarg);
144	       break;
145	  case 't':
146	       if (apropos)
147		    fatal (INCOMPAT, "-t", "-k");
148	       if (whatis)
149		    fatal (INCOMPAT, "-t", "-f");
150	       if (print_where)
151		    fatal (INCOMPAT, "-t", "-w");
152	       do_troff++;
153	       break;
154	  case 'v':
155	  case 'V':
156	       print_version();
157	       exit(0);
158	  case 'W':
159	       one_per_line++;
160	       /* fall through */
161	  case 'w':
162	       if (apropos)
163		    fatal (INCOMPAT, "-w", "-k");
164	       if (whatis)
165		    fatal (INCOMPAT, "-w", "-f");
166	       if (do_troff)
167		    fatal (INCOMPAT, "-w", "-t");
168	       print_where++;
169	       break;
170	  /* Silently ignore manpath -q and -L (3825529). */
171	  case 'L':
172	  case 'q':
173	       if (!strncmp(progname, "manpath", 7))
174		    break;
175	  case 'h':
176	  case '?':
177	  default:
178	       usage();
179	       break;
180	  }
181	  optct++;
182     }
183
184     return optct;
185}
186
187static void
188get_options_from_string(const char *s) {
189	char *s0, *ss;
190	int argct;
191	char **argvec;
192	int optindsv;
193
194	if (!s || *s == 0)
195		return;
196
197	/* In order to avoid having a list of options in two places,
198	   massage the string so that it can be fed to getopt() */
199
200	s0 = my_strdup(s);
201
202	/* count arguments */
203	argct = 0;
204	ss = s0;
205	while (*ss) {
206		while (*ss == ' ')
207			ss++;
208		if (*ss) {
209			argct++;
210			while (*ss && *ss != ' ')
211				ss++;
212		}
213	}
214
215	/* allocate argvec */
216	argvec = (char **) my_malloc((argct+2)*sizeof(char *));
217	argct = 0;
218	argvec[argct++] = "dummy";
219	ss = s0;
220	while (*ss) {
221		while (*ss == ' ')
222			*ss++ = 0;
223		if (*ss) {
224			argvec[argct++] = ss;
225			while (*ss && *ss != ' ')
226				ss++;
227		}
228	}
229	argvec[argct] = 0;
230
231	optindsv = optind;
232	optind = 1;
233	get_options_from_argvec(argct, argvec, NULL, NULL);
234	optind = optindsv;
235}
236
237static void
238mysetenv(const char *name, const char *value) {
239#if defined(__sgi__) || defined(__sun__) || defined(sun)
240    int len = strlen(value)+1+strlen(value)+1;
241    char *str = my_malloc(len);
242    sprintf(str, "%s=%s", name, value);
243    putenv(str);
244#else
245    setenv(name, value, 1);
246#endif
247}
248
249/*
250 * Get options from the command line and user environment.
251 * Also reads the configuration file.
252 */
253
254void
255man_getopt (int argc, char **argv) {
256     char *config_file = NULL;
257     char *manp = NULL;
258     int optct = 0;
259
260     optct = get_options_from_argvec(argc, argv, &config_file, &manp);
261
262     read_config_file (config_file);
263
264     /* If no options were given and MANDEFOPTIONS is set, use that */
265     if (optct == 0) {
266	     const char *defopts = getval ("MANDEFOPTIONS");
267	     get_options_from_string(defopts);
268     }
269
270     /* In case an explicit -P option was given, put it in the
271	environment for possible use with -k or -K.
272	Ignore errors (out of memory?) */
273
274     if (pager && (global_apropos || apropos || whatis))
275	     mysetenv("PAGER", pager);
276
277     if (pager == NULL || *pager == '\0')
278	  if ((pager = getenv ("MANPAGER")) == NULL)
279	       if ((pager = getenv ("PAGER")) == NULL)
280		    pager = getval ("PAGER");
281
282     if (debug)
283	  gripe (PAGER_IS, pager);
284
285     /* Ditto for BROWSER and -B */
286     if (browser && (global_apropos || apropos || whatis))
287	 mysetenv("BROWSER", browser);
288
289     if (browser == NULL || *browser == '\0')
290	 if ((browser = getenv ("BROWSER")) == NULL)
291	     browser = getval ("BROWSER");
292
293     if (debug)
294	  gripe (BROWSER_IS, browser);
295
296     /* Ditto for HTMLHTMLPAGER and -D */
297     if (htmlpager && (global_apropos || apropos || whatis))
298	 mysetenv("HTMLPAGER", htmlpager);
299
300     if (htmlpager == NULL || *htmlpager == '\0')
301	 if ((htmlpager = getenv ("HTMLPAGER")) == NULL)
302	     htmlpager = getval ("HTMLPAGER");
303
304     if (debug)
305	  gripe (HTMLPAGER_IS, htmlpager);
306
307     if (do_compress && !*getval ("COMPRESS")) {
308	  if (debug)
309	       gripe (NO_COMPRESS);
310	  do_compress = 0;
311     }
312
313     if (do_troff && !*getval ("TROFF")) {
314	  gripe (NO_TROFF, configuration_file);
315	  exit (1);
316     }
317
318     opt_manpath = manp;		/* do not yet expand manpath -
319					   maybe it is not needed */
320
321     if (alt_system_name == NULL || *alt_system_name == '\0')
322	  if ((alt_system_name = getenv ("SYSTEM")) != NULL)
323	       alt_system_name = my_strdup (alt_system_name);
324
325}
326