1 /*
2 * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
3 * Copyright (c) 1996-2005 Michael T Pins. All rights reserved.
4 *
5 * Generic option parsing
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include "config.h"
12 #include "global.h"
13 #include "nn.h"
14 #include "options.h"
15 #include "variable.h"
16
17 /* options.c */
18
19 static void dump_options(int type, char *tail);
20 static void error(char *message, char option_letter);
21
22 static char **save_argv, *usage_mesg;
23 static struct option_descr *save_optd;
24
25 extern int no_update;
26
27
28 char *
program_name(char ** av)29 program_name(char **av)
30 {
31 char *cp;
32
33 /* skip "/path/" part of program name */
34 if ((cp = strrchr(*av, '/')))
35 return cp + 1;
36 else
37 return *av;
38 }
39
40 static void
dump_options(int type,char * tail)41 dump_options(int type, char *tail)
42 {
43 register struct option_descr *od;
44 int any = 0;
45
46 for (od = save_optd; od->option_letter; od++) {
47 if (od->option_type != type)
48 continue;
49 fprintf(stderr, any ? "%c" : " -%c", od->option_letter);
50 any++;
51 }
52
53 if (any && tail && tail[0]) {
54 fprintf(stderr, "%s", tail);
55 }
56 }
57
58 static void
error(char * message,char option_letter)59 error(char *message, char option_letter)
60 {
61 char *prog_name = program_name(save_argv);
62
63 fprintf(stderr, "%s: ", prog_name);
64 fprintf(stderr, message, option_letter);
65 fputc('\n', stderr);
66
67 fprintf(stderr, "usage: %s", prog_name);
68
69 dump_options(1, "");
70 dump_options(2, " STR");
71 dump_options(3, " [STR]");
72 dump_options(4, " NUM");
73 dump_options(5, " [NUM]");
74
75 if (usage_mesg)
76 fprintf(stderr, usage_mesg);
77 fputc(NL, stderr);
78
79 nn_exit(9);
80 }
81
82 /* parse variables set on command line seperately from everything
83 * else, very early. This is necessary because open_master is done
84 * so early for nntp; don't alter the arg, so we can skip it later.
85 */
86 void
parseargv_variables(char ** av,int ac)87 parseargv_variables(char **av, int ac)
88 {
89 char *value;
90
91 while (--ac > 0) {
92 if (**++av != '-' && (value = strchr(*av, '='))) {
93 *value++ = NUL;
94 set_variable(*av, 1, value);
95 *--value = '='; /* restore for later parsing to skip it */
96 }
97 }
98 }
99
100 int
parse_options(int ac,char ** av,char * envname,struct option_descr options[],char * usage)101 parse_options(int ac, char **av, char *envname, struct option_descr options[], char *usage)
102 {
103 register char *cp, opt;
104 register struct option_descr *od;
105 int files;
106 char **names;
107 char *envinit;
108
109 save_argv = av;
110 save_optd = options;
111
112 if (options == NULL)
113 return 0;
114
115 usage_mesg = usage;
116
117 --ac;
118 names = ++av;
119 files = 0;
120
121 envinit = envname ? getenv(envname) : NULL;
122 cp = envinit;
123
124 next_option:
125
126 if (envinit) {
127 while (*cp && isspace(*cp))
128 cp++;
129 if (*cp == '-') {
130 cp++;
131 goto next_option;
132 }
133 if (*cp == NUL) {
134 envinit = NULL;
135 goto next_option;
136 }
137 } else if (cp == NULL || *cp == NUL) {
138 if ((cp = *av++) == NULL) {
139 *names = NULL;
140 return files;
141 }
142 ac--;
143
144 if (*cp != '-') {
145 if (!strchr(cp, '=')) {
146 *names++ = cp;
147 cp = NULL;
148 files++;
149 }
150
151 /*
152 * else it's a variable that was handled in parseargv_variables()
153 * earlier, so nothing to do.
154 */
155 cp = NULL;
156 goto next_option;
157 }
158 cp++; /* skip - */
159 }
160 opt = *cp++;
161
162 for (od = options; od->option_letter; od++) {
163 if (od->option_letter != opt)
164 continue;
165
166 switch (od->option_type) {
167
168 case 1: /* BOOL_OPTION */
169
170 *((int *) (od->option_address)) = !*((int *) (od->option_address));
171 goto next_option;
172
173 case 2: /* STRING_OPTION */
174 case 3: /* OPTIONAL_STRING */
175
176 /* -oSTR or -o STR */
177
178 while (*cp && isspace(*cp))
179 cp++;
180
181 if (*cp == NUL) {
182 if (envinit || ac == 0) {
183 if (od->option_type == 3)
184 goto opt_str;
185 error("missing string argumet to -%c", opt);
186 }
187 cp = *av++;
188 ac--;
189 }
190 if (od->option_type == 3 && *cp == '-') {
191 cp++;
192 goto opt_str;
193 }
194 *(od->option_address) = cp;
195
196 if (envinit) {
197 while (*cp && !isspace(*cp))
198 cp++;
199 if (*cp)
200 *cp++ = NUL;
201 } else
202 cp = NULL;
203
204 goto next_option;
205
206 opt_str:
207 *(od->option_address) = od->option_default;
208 goto next_option;
209
210 case 4:
211 case 5:
212
213 /* -oN or -o N */
214
215 while (*cp && isspace(*cp))
216 cp++;
217
218 if (*cp) {
219 if (!isdigit(*cp)) {
220 if (od->option_type == 5)
221 goto opt_int;
222 error("non-numeric argument to -%c", opt);
223 }
224 } else {
225 if (envinit || ac == 0 || !isdigit(**av)) {
226 if (od->option_type == 5)
227 goto opt_int;
228 error("missing argument to -%c", opt);
229 }
230 cp = *av++;
231 ac--;
232 }
233 *((int *) (od->option_address)) = atoi(cp);
234 while (isdigit(*cp))
235 cp++;
236 goto next_option;
237
238 opt_int:
239 *((int *) (od->option_address)) = (int) (od->option_default);
240 goto next_option;
241 }
242 }
243
244 error("unknown option '-%c'", opt);
245 /* NOTREACHED */
246 return 0;
247 }
248