1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
|
/****************************************************************************
*
* ========================================================================
*
* The contents of this file are subject to the SciTech MGL Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.scitechsoft.com/mgl-license.txt
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
*
* The Initial Developer of the Original Code is SciTech Software, Inc.
* All Rights Reserved.
*
* ========================================================================
*
* Language: ANSI C
* Environment: any
*
* Description: This module contains code to parse the command line,
* extracting options and parameters in standard System V
* style.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "cmdline.h"
/*------------------------- Global variables ------------------------------*/
int nextargv = 1; /* Index into argv array */
char *nextchar = NULL; /* Pointer to next character */
/*-------------------------- Implementation -------------------------------*/
#define IS_SWITCH_CHAR(c) ((c) == '-')
#define IS_NOT_SWITCH_CHAR(c) ((c) != '-')
/****************************************************************************
DESCRIPTION:
Parse the command line for specific options
HEADER:
cmdline.h
PARAMETERS:
argc - Value passed to program through argc variable
argv - Pointer to the argv array passed to the program
format - A string representing the expected format of the command line
argument - Pointer to optional argument on command line
RETURNS:
Character code representing the next option parsed from the command line by
getcmdopt. Returns ALLDONE (-1) when there are no more parameters to be parsed
on the command line, PARAMETER (-2) when the argument being parsed is a
parameter and not an option switch and lastly INVALID (-3) if an error
occured while parsing the command line.
REMARKS:
Function to parse the command line option switches in UNIX System V style.
When getcmdopt is called, it returns the character code of the next valid
option that is parsed from the command line as specified by the Format
string. The format string should be in the following form:
"abcd:e:f:"
where a,b and c represent single switch style options and the character
code returned by getcmdopt is the only value returned. Also d, e and f
represent options that expect arguments immediately after them on the
command line. The argument that follows the option on the command line is
returned via a reference in the pointer argument. Thus a valid command line
for this format string might be:
myprogram -adlines -b -f format infile outfile
where a and b will be returned as single character options with no argument,
while d is returned with the argument lines and f is returned with the
argument format.
When getcmdopt returns with PARAMETER (we attempted to parse a paramter, not
an option), the global variable NextArgv will hold an index in the argv
array to the argument on the command line AFTER the options, ie in the
above example the string 'infile'. If the parameter is successfully used,
NextArgv should be incremented and getcmdopt can be called again to parse any
more options. Thus you can also have options interspersed throught the
command line. eg:
myprogram -adlines infile -b outfile -f format
can be made to be a valid form of the above command line.
****************************************************************************/
int getcmdopt(
int argc,
char **argv,
char *format,
char **argument)
{
char ch;
char *formatchar;
if (argc > nextargv) {
if (nextchar == NULL) {
nextchar = argv[nextargv]; /* Index next argument */
if (nextchar == NULL) {
nextargv++;
return ALLDONE; /* No more options */
}
if (IS_NOT_SWITCH_CHAR(*nextchar)) {
nextchar = NULL;
return PARAMETER; /* We have a parameter */
}
nextchar++; /* Move past switch operator */
if (IS_SWITCH_CHAR(*nextchar)) {
nextchar = NULL;
return INVALID; /* Ignore rest of line */
}
}
if ((ch = *(nextchar++)) == 0) {
nextchar = NULL;
return INVALID; /* No options on line */
}
if (ch == ':' || (formatchar = strchr(format, ch)) == NULL)
return INVALID;
if (*(++formatchar) == ':') { /* Expect an argument after option */
nextargv++;
if (*nextchar == 0) {
if (argc <= nextargv)
return INVALID;
nextchar = argv[nextargv++];
}
*argument = nextchar;
nextchar = NULL;
}
else { /* We have a switch style option */
if (*nextchar == 0) {
nextargv++;
nextchar = NULL;
}
*argument = NULL;
}
return ch; /* return the option specifier */
}
nextchar = NULL;
nextargv++;
return ALLDONE; /* no arguments on command line */
}
/****************************************************************************
PARAMETERS:
optarr - Description for the option we are parsing
argument - String to parse
RETURNS:
INVALID on error, ALLDONE on success.
REMARKS:
Parses the argument string depending on the type of argument that is
expected, filling in the argument for that option. Note that to parse a
string, we simply return a pointer to argument.
****************************************************************************/
static int parse_option(
Option *optarr,
char *argument)
{
int num_read;
switch ((int)(optarr->type)) {
case OPT_INTEGER:
num_read = sscanf(argument,"%d",(int*)optarr->arg);
break;
case OPT_HEX:
num_read = sscanf(argument,"%x",(int*)optarr->arg);
break;
case OPT_OCTAL:
num_read = sscanf(argument,"%o",(int*)optarr->arg);
break;
case OPT_UNSIGNED:
num_read = sscanf(argument,"%u",(uint*)optarr->arg);
break;
case OPT_LINTEGER:
num_read = sscanf(argument,"%ld",(long*)optarr->arg);
break;
case OPT_LHEX:
num_read = sscanf(argument,"%lx",(long*)optarr->arg);
break;
case OPT_LOCTAL:
num_read = sscanf(argument,"%lo",(long*)optarr->arg);
break;
case OPT_LUNSIGNED:
num_read = sscanf(argument,"%lu",(ulong*)optarr->arg);
break;
case OPT_FLOAT:
num_read = sscanf(argument,"%f",(float*)optarr->arg);
break;
case OPT_DOUBLE:
num_read = sscanf(argument,"%lf",(double*)optarr->arg);
break;
case OPT_LDOUBLE:
num_read = sscanf(argument,"%Lf",(long double*)optarr->arg);
break;
case OPT_STRING:
num_read = 1; /* This always works */
*((char**)optarr->arg) = argument;
break;
default:
return INVALID;
}
if (num_read == 0)
return INVALID;
else
return ALLDONE;
}
/****************************************************************************
HEADER:
cmdline.h
PARAMETERS:
argc - Number of arguments on command line
argv - Array of command line arguments
num_opt - Number of options in option array
optarr - Array to specify how to parse the command line
do_param - Routine to handle a command line parameter
RETURNS:
ALLDONE, INVALID or HELP
REMARKS:
Function to parse the command line according to a table of options. This
routine calls getcmdopt above to parse each individual option and attempts
to parse each option into a variable of the specified type. The routine
can parse integers and long integers in either decimal, octal, hexadecimal
notation, unsigned integers and unsigned longs, strings and option switches.
Option switches are simply boolean variables that get turned on if the
switch was parsed.
Parameters are extracted from the command line by calling a user supplied
routine do_param() to handle each parameter as it is encountered. The
routine do_param() should accept a pointer to the parameter on the command
line and an integer representing how many parameters have been encountered
(ie: 1 if this is the first parameter, 10 if it is the 10th etc), and return
ALLDONE upon successfully parsing it or INVALID if the parameter was invalid.
We return either ALLDONE if all the options were successfully parsed,
INVALID if an invalid option was encountered or HELP if any of -h, -H or
-? were present on the command line.
****************************************************************************/
int getargs(
int argc,
char *argv[],
int num_opt,
Option optarr[],
int (*do_param)(
char *param,
int num))
{
int i,opt;
char *argument;
int param_num = 1;
char cmdstr[MAXARG*2 + 4];
/* Build the command string from the array of options */
strcpy(cmdstr,"hH?");
for (i = 0,opt = 3; i < num_opt; i++,opt++) {
cmdstr[opt] = optarr[i].opt;
if (optarr[i].type != OPT_SWITCH) {
cmdstr[++opt] = ':';
}
}
cmdstr[opt] = '\0';
for (;;) {
opt = getcmdopt(argc,argv,cmdstr,&argument);
switch (opt) {
case 'H':
case 'h':
case '?':
return HELP;
case ALLDONE:
return ALLDONE;
case INVALID:
return INVALID;
case PARAMETER:
if (do_param == NULL)
return INVALID;
if (do_param(argv[nextargv],param_num) == INVALID)
return INVALID;
nextargv++;
param_num++;
break;
default:
/* Search for the option in the option array. We are
* guaranteed to find it.
*/
for (i = 0; i < num_opt; i++) {
if (optarr[i].opt == opt)
break;
}
if (optarr[i].type == OPT_SWITCH)
*((ibool*)optarr[i].arg) = true;
else {
if (parse_option(&optarr[i],argument) == INVALID)
return INVALID;
}
break;
}
}
}
/****************************************************************************
HEADER:
cmdline.h
PARAMETERS:
num_opt - Number of options in the table
optarr - Table of option descriptions
REMARKS:
Prints the description of each option in a standard format to the standard
output device. The description for each option is obtained from the table
of options.
****************************************************************************/
void print_desc(
int num_opt,
Option optarr[])
{
int i;
for (i = 0; i < num_opt; i++) {
if (optarr[i].type == OPT_SWITCH)
printf(" -%c %s\n",optarr[i].opt,optarr[i].desc);
else
printf(" -%c<arg> %s\n",optarr[i].opt,optarr[i].desc);
}
}
/****************************************************************************
HEADER:
cmdline.h
PARAMETERS:
moduleName - Module name for program
cmdLine - Command line to parse
pargc - Pointer to 'argc' parameter
pargv - Pointer to 'argv' parameter
maxArgc - Maximum argv array index
REMARKS:
Parses a command line from a single string into the C style 'argc' and
'argv' format. Most useful for Windows programs where the command line
is passed in verbatim.
****************************************************************************/
int parse_commandline(
char *moduleName,
char *cmdLine,
int *pargc,
char *argv[],
int maxArgv)
{
static char str[512];
static char filename[260];
char *prevWord = NULL;
ibool inQuote = FALSE;
ibool noStrip = FALSE;
int argc;
argc = 0;
strcpy(filename,moduleName);
argv[argc++] = filename;
cmdLine = strncpy(str, cmdLine, sizeof(str)-1);
while (*cmdLine) {
switch (*cmdLine) {
case '"' :
if (prevWord != NULL) {
if (inQuote) {
if (!noStrip)
*cmdLine = '\0';
argv [argc++] = prevWord;
prevWord = NULL;
}
else
noStrip = TRUE;
}
inQuote = !inQuote;
break;
case ' ' :
case '\t' :
if (!inQuote) {
if (prevWord != NULL) {
*cmdLine = '\0';
argv [argc++] = prevWord;
prevWord = NULL;
noStrip = FALSE;
}
}
break;
default :
if (prevWord == NULL)
prevWord = cmdLine;
break;
}
if (argc >= maxArgv - 1)
break;
cmdLine++;
}
if ((prevWord != NULL || (inQuote && prevWord != NULL)) && argc < maxArgv - 1) {
*cmdLine = '\0';
argv [argc++] = prevWord;
}
argv[argc] = NULL;
/* Return updated parameters */
return (*pargc = argc);
}
|