1 | /****************************************************************************/ |
---|
2 | /* GETPARAM.C: command-line processing functions. */ |
---|
3 | /* Copyright (c) 2001 by Joshua E. Barnes, Honolulu, Hawai`i. */ |
---|
4 | /****************************************************************************/ |
---|
5 | |
---|
6 | #include "stdinc.h" |
---|
7 | #include "getparam.h" |
---|
8 | #include <string.h> |
---|
9 | |
---|
10 | /* |
---|
11 | * PARAM: structure encoding parameter name and value. |
---|
12 | */ |
---|
13 | |
---|
14 | typedef struct { |
---|
15 | string name; /* name of parameter */ |
---|
16 | string value; /* value of parameter */ |
---|
17 | string comment; /* documentation string */ |
---|
18 | int flags; /* for various options */ |
---|
19 | } param; |
---|
20 | |
---|
21 | /* |
---|
22 | * Local routines and definitions. |
---|
23 | */ |
---|
24 | |
---|
25 | local int countdefaults(string *); /* number of defaults */ |
---|
26 | local void setprogram(param *, string); /* set 0th parameter */ |
---|
27 | local void copydefaults(param *, string *); /* set default parameters */ |
---|
28 | local void checkhelp(param *, string); /* help processing */ |
---|
29 | local void printitem(string, string); /* print param and comment */ |
---|
30 | local void setarguments(param *, string *); /* set command parameters */ |
---|
31 | local void reqarguments(param *); /* check manditory args */ |
---|
32 | local param *findparam(string, param *); /* look up parameter value */ |
---|
33 | local string parname(string); /* extract param name */ |
---|
34 | local string parvalue(string); /* extract param value */ |
---|
35 | |
---|
36 | local param *paramvec = NULL; /* vector of parameters */ |
---|
37 | |
---|
38 | local string progname = NULL; /* program name, for errors */ |
---|
39 | |
---|
40 | /* |
---|
41 | * INITPARAM: initalize parameter lists and handle special requests. |
---|
42 | */ |
---|
43 | |
---|
44 | void initparam(string *argv, string *defv) |
---|
45 | { |
---|
46 | int nparam; |
---|
47 | param *pvec; |
---|
48 | |
---|
49 | progname = argv[0]; /* initialize program name */ |
---|
50 | nparam = 1 + countdefaults(defv); /* include argv0 in count */ |
---|
51 | pvec = (param *) allocate(sizeof(param) * (nparam + 1)); |
---|
52 | setprogram(pvec, argv[0]); /* install 0th argument */ |
---|
53 | copydefaults(pvec, defv); /* set up default values */ |
---|
54 | checkhelp(pvec, argv[1]); /* give help if requested */ |
---|
55 | setarguments(pvec, argv); /* args override defaults */ |
---|
56 | reqarguments(pvec); /* complain if args missing */ |
---|
57 | paramvec = pvec; /* install parameter vector */ |
---|
58 | } |
---|
59 | |
---|
60 | /* |
---|
61 | * COUNTDEFAULTS: count number of default parameters. |
---|
62 | */ |
---|
63 | |
---|
64 | local int countdefaults(string *defv) |
---|
65 | { |
---|
66 | int ndefault; |
---|
67 | string *dp; |
---|
68 | |
---|
69 | ndefault = 0; |
---|
70 | for (dp = defv; *dp != NULL; dp++) /* loop over all defaults */ |
---|
71 | if (**dp != ';') /* if not a comment */ |
---|
72 | ndefault++; /* then count one more */ |
---|
73 | return (ndefault); |
---|
74 | } |
---|
75 | |
---|
76 | /* |
---|
77 | * SETPROGRAM: initialize the program name as parameter "argv0". |
---|
78 | */ |
---|
79 | |
---|
80 | local void setprogram(param *pvec, string argv0) |
---|
81 | { |
---|
82 | pvec->name = "argv0"; /* install 0th parameter */ |
---|
83 | pvec->value = argv0; /* set name from argv[0] */ |
---|
84 | pvec->comment = NULL; /* no comment for now */ |
---|
85 | pvec->flags = ARGPARAM; /* so user can't reset it */ |
---|
86 | } |
---|
87 | |
---|
88 | /* |
---|
89 | * COPYDEFAULTS: install default parameters and comments. |
---|
90 | */ |
---|
91 | |
---|
92 | local void copydefaults(param *pvec, string *defv) |
---|
93 | { |
---|
94 | param *pp; |
---|
95 | string *dp, name, value; |
---|
96 | |
---|
97 | pp = pvec; /* start with 0th param */ |
---|
98 | for (dp = defv; *dp != NULL; dp++) /* loop over the defaults */ |
---|
99 | if (**dp == ';') { /* is this is a comment? */ |
---|
100 | if (pp->comment != NULL) /* already have a comment? */ |
---|
101 | error("copydefaults: cant append comments\n"); |
---|
102 | pp->comment = strdup(*dp + 1); /* store comment in field */ |
---|
103 | } else { /* else its not a comment */ |
---|
104 | pp++; /* so move onto new param */ |
---|
105 | name = parname(*dp); /* extract parameter name */ |
---|
106 | value = parvalue(*dp); /* and parameter value */ |
---|
107 | if (name == NULL || value == NULL) /* is either one missing? */ |
---|
108 | error("copydefaults: bad parameter %s\n", *dp); |
---|
109 | pp->name = strdup(name); /* assign parameter name */ |
---|
110 | pp->value = strdup(value); /* and parameter value */ |
---|
111 | pp->comment = NULL; /* clear comment field */ |
---|
112 | pp->flags = DEFPARAM; /* set source to default */ |
---|
113 | if (streq(pp->value, "???")) /* is this param required? */ |
---|
114 | pp->flags |= REQPARAM; /* set the required flag */ |
---|
115 | if (**dp == '<') /* an input parameter? */ |
---|
116 | pp->flags |= INPARAM; /* set the input flag */ |
---|
117 | else if (**dp == '>') /* or an output parameter? */ |
---|
118 | pp->flags |= OUTPARAM; /* set the output flag */ |
---|
119 | if (name[0] == '.') /* a hidden parameter? */ |
---|
120 | pp->flags |= HIDPARAM; /* set the hidden flag */ |
---|
121 | } |
---|
122 | pp++; /* past last real param */ |
---|
123 | pp->name = NULL; /* end list of parameters */ |
---|
124 | } |
---|
125 | |
---|
126 | /* |
---|
127 | * CHECKHELP: if requested, print out help mesaages and exit. |
---|
128 | */ |
---|
129 | |
---|
130 | local void checkhelp(param *pvec, string argv1) |
---|
131 | { |
---|
132 | param *pp; |
---|
133 | char buf[128]; |
---|
134 | |
---|
135 | if (argv1 != NULL && streq(argv1, "-clue")) { |
---|
136 | /* print brief help message */ |
---|
137 | printf("%s", pvec->value); |
---|
138 | for (pp = pvec+1; pp->name != NULL; pp++) |
---|
139 | printf(" %s=%s", pp->name, pp->value); |
---|
140 | printf("\n"); |
---|
141 | exit(0); |
---|
142 | } |
---|
143 | if (argv1 != NULL && streq(argv1, "-help")) { |
---|
144 | /* print full help message */ |
---|
145 | printitem(pvec->value, pvec->comment); |
---|
146 | for (pp = pvec+1; pp->name != NULL; pp++) { |
---|
147 | sprintf(buf, " %s=%s", pp->name, pp->value); |
---|
148 | printitem(buf, pp->comment); |
---|
149 | } |
---|
150 | exit(0); |
---|
151 | } |
---|
152 | } |
---|
153 | |
---|
154 | local void printitem(string item, string comment) |
---|
155 | { |
---|
156 | if (comment == NULL) |
---|
157 | printf("%s\n", item); |
---|
158 | else |
---|
159 | if (strlen(item) < 32) |
---|
160 | printf("%-32s %s\n", item, comment); |
---|
161 | else |
---|
162 | printf("%s\n\t\t\t\t %s\n", item, comment); |
---|
163 | } |
---|
164 | |
---|
165 | /* |
---|
166 | * SETARGUMENTS: override defaults with commandline arguments. |
---|
167 | */ |
---|
168 | |
---|
169 | local void setarguments(param *pvec, string *argv) |
---|
170 | { |
---|
171 | bool scanpos; |
---|
172 | param *pp; |
---|
173 | string *ap, name; |
---|
174 | |
---|
175 | scanpos = TRUE; /* start scan by position */ |
---|
176 | pp = pvec; /* start at 0th param */ |
---|
177 | for (ap = argv + 1; *ap != NULL; ap++) { /* loop over command args */ |
---|
178 | name = parname(*ap); /* get param name, if any */ |
---|
179 | scanpos = scanpos && (name == NULL); /* see how to match args */ |
---|
180 | if (scanpos) { /* matching by position? */ |
---|
181 | pp++; /* then move to next param */ |
---|
182 | if (pp->name == NULL) /* make sure it exists */ |
---|
183 | error("%s: too many arguments\n", progname); |
---|
184 | pp->value = strdup(*ap); /* OK, set new param value */ |
---|
185 | } else { /* else matching by name? */ |
---|
186 | if (name == NULL) /* make sure name was given */ |
---|
187 | error("%s: nameless arg %s\n", progname, *ap); |
---|
188 | pp = findparam(name, pvec); /* look for named param */ |
---|
189 | if (pp == NULL) /* make sure param exists */ |
---|
190 | error("%s: parameter %s unknown\n", progname, name); |
---|
191 | if (pp->flags & ARGPARAM) /* must not already be set */ |
---|
192 | error("%s: parameter %s duplicated\n", progname, name); |
---|
193 | pp->value = strdup(parvalue(*ap)); /* OK, set new param value */ |
---|
194 | } |
---|
195 | pp->flags = (pp->flags & ~DEFPARAM) | ARGPARAM; |
---|
196 | /* switch source flag */ |
---|
197 | } |
---|
198 | } |
---|
199 | |
---|
200 | /* |
---|
201 | * REQARGUMENTS: print out short message on use. |
---|
202 | */ |
---|
203 | |
---|
204 | local void reqarguments(param *pvec) |
---|
205 | { |
---|
206 | bool needarg; |
---|
207 | param *pp; |
---|
208 | |
---|
209 | needarg = FALSE; /* see if any args left out */ |
---|
210 | for (pp = pvec+1; pp->name != NULL; pp++) /* scan list of parameters */ |
---|
211 | if ((pp->flags & REQPARAM) && /* a required parameter? */ |
---|
212 | (pp->flags & DEFPARAM)) /* and still defaulted? */ |
---|
213 | needarg = TRUE; /* note missing args exist */ |
---|
214 | if (needarg) { /* list required arguments */ |
---|
215 | eprintf("Usage: %s", progname); |
---|
216 | for (pp = pvec+1; pp->name != NULL; pp++) |
---|
217 | if ((pp->flags & REQPARAM)) |
---|
218 | eprintf(" %s=???", pp->name); |
---|
219 | error("%s: required arguments missing\n", progname); |
---|
220 | } |
---|
221 | } |
---|
222 | |
---|
223 | /* |
---|
224 | * GETPARAM: return value of parameter. As a special case, requests for |
---|
225 | * "argv0" can be handled before paramvec has been set, to allow error |
---|
226 | * handling during the initialization process. |
---|
227 | */ |
---|
228 | |
---|
229 | string getparam(string name) |
---|
230 | { |
---|
231 | param *par; |
---|
232 | |
---|
233 | if (paramvec == NULL) |
---|
234 | if (streq(name, "argv0") && progname != NULL) |
---|
235 | return (progname); |
---|
236 | else |
---|
237 | error("getparam: called before initparam\n"); |
---|
238 | par = findparam(name, paramvec); |
---|
239 | if (par == NULL) |
---|
240 | error("getparam in %s: parameter %s unknown\n", progname, name); |
---|
241 | return (par->value); |
---|
242 | } |
---|
243 | |
---|
244 | /* |
---|
245 | * GETPARAMSTAT: return parameter flags, or zero if no such parameter |
---|
246 | * (note that all defined parameters have at least one bit set). |
---|
247 | */ |
---|
248 | |
---|
249 | int getparamstat(string name) |
---|
250 | { |
---|
251 | param *par; |
---|
252 | |
---|
253 | par = findparam(name, paramvec); |
---|
254 | return (par != NULL ? par->flags : 0); |
---|
255 | } |
---|
256 | |
---|
257 | /* |
---|
258 | * GETIPARAM, GETDPARAM, GETBPARAM: get int, double, or bool parameter. |
---|
259 | */ |
---|
260 | |
---|
261 | int getiparam(string name) |
---|
262 | { |
---|
263 | int val; |
---|
264 | string end; |
---|
265 | |
---|
266 | val = strtol(getparam(name), &end, 0); |
---|
267 | if (*end == 'k' || *end == 'K') |
---|
268 | return (1024 * val); |
---|
269 | if (*end == 'm' || *end == 'M') |
---|
270 | return (1024 * 1024 * val); |
---|
271 | return (val); |
---|
272 | } |
---|
273 | |
---|
274 | double getdparam(string name) |
---|
275 | { |
---|
276 | return (atof(getparam(name))); /* convert value to double */ |
---|
277 | } |
---|
278 | |
---|
279 | bool getbparam(string name) |
---|
280 | { |
---|
281 | char *val; |
---|
282 | |
---|
283 | val = getparam(name); /* obtain value of param */ |
---|
284 | if (strchr("tTyY1", *val) != NULL) /* is value true? */ |
---|
285 | return (TRUE); |
---|
286 | if (strchr("fFnN0", *val) != NULL) /* is value false? */ |
---|
287 | return (FALSE); |
---|
288 | error("getbparam: %s=%s not bool\n", name, val); |
---|
289 | return (FALSE); /* keep compiler happy... */ |
---|
290 | } |
---|
291 | |
---|
292 | /* |
---|
293 | * FINDPARAM: look for named parameter in list of parameters. |
---|
294 | */ |
---|
295 | |
---|
296 | local param *findparam(string name, param *pvec) |
---|
297 | { |
---|
298 | param *pp; |
---|
299 | |
---|
300 | for (pp = pvec; pp->name != NULL; pp++) |
---|
301 | if (streq(name, pp->name)) |
---|
302 | return (pp); |
---|
303 | return (NULL); |
---|
304 | } |
---|
305 | |
---|
306 | /* |
---|
307 | * PARNAME: extract name from name=value string. |
---|
308 | * W A R N I N G : returns ptr to static storage. |
---|
309 | */ |
---|
310 | |
---|
311 | local string parname(string arg) |
---|
312 | { |
---|
313 | char *ap, *ep; |
---|
314 | static char namebuf[64]; |
---|
315 | |
---|
316 | ap = (char *) arg; |
---|
317 | if (*ap == '<' || *ap == '>') |
---|
318 | ap++; |
---|
319 | strncpy(namebuf, ap, 63); |
---|
320 | namebuf[63] = NULL; |
---|
321 | ep = strchr(namebuf, '='); |
---|
322 | if (ep == NULL) /* not of form name=value? */ |
---|
323 | return (NULL); |
---|
324 | *ep = NULL; |
---|
325 | return (namebuf); |
---|
326 | } |
---|
327 | |
---|
328 | /* |
---|
329 | * PARVALUE: extract value from name=value string. |
---|
330 | */ |
---|
331 | |
---|
332 | local string parvalue(string arg) |
---|
333 | { |
---|
334 | char *ep; |
---|
335 | |
---|
336 | ep = strchr(arg, '='); |
---|
337 | if (ep == NULL) |
---|
338 | return (NULL); |
---|
339 | return (ep + 1); |
---|
340 | } |
---|