429 lines
12 KiB
C
429 lines
12 KiB
C
/****************************************************************************
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* 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);
|
|
}
|