This is cmdarg.c in view mode; [Download] [Up]
//------------------------------------------------------------------------
// ^FILE: cmdarg.c - implement a CmdArg
//
// ^DESCRIPTION:
// This file implements the CmdArg class which is the base
// class for all command-arguments.
//
// ^HISTORY:
// 03/25/92 Brad Appleton <brad@ssd.csd.harris.com> Created
//
// 03/01/93 Brad Appleton <brad@ssd.csd.harris.com>
// - Added arg_sequence field to CmdArg
//-^^---------------------------------------------------------------------
#include <stdlib.h>
#include <iostream.h>
#include <string.h>
#include <ctype.h>
#include "cmdline.h"
//---------------------------------------------------------------------- CmdArg
int CmdArg::is_dummy(void) { return 0; }
// Copy-Constructor
CmdArg::CmdArg(const CmdArg & cp)
: alloc_value_name(cp.alloc_value_name),
arg_flags(cp.arg_flags),
arg_syntax(cp.arg_syntax),
arg_sequence(cp.arg_sequence),
arg_char_name(cp.arg_char_name),
arg_keyword_name(cp.arg_keyword_name),
arg_value_name(cp.arg_value_name),
arg_description(cp.arg_description)
{
if (alloc_value_name) {
char * val_name = new char[::strlen(cp.arg_value_name) + 1] ;
::strcpy((char *)val_name, cp.arg_value_name);
arg_value_name = val_name;
}
}
// Constructors
CmdArg::CmdArg(char optchar,
const char * keyword,
const char * value,
const char * description,
unsigned syntax_flags)
: alloc_value_name(0),
arg_flags(0),
arg_syntax(syntax_flags),
arg_sequence(0),
arg_char_name(optchar),
arg_keyword_name(keyword),
arg_value_name(value),
arg_description(description)
{
parse_description();
parse_value();
adjust_syntax();
}
CmdArg::CmdArg(char optchar,
const char * keyword,
const char * description,
unsigned syntax_flags)
: alloc_value_name(0),
arg_flags(0),
arg_syntax(syntax_flags),
arg_sequence(0),
arg_char_name(optchar),
arg_keyword_name(keyword),
arg_value_name(NULL),
arg_description(description)
{
parse_description();
adjust_syntax();
}
CmdArg::CmdArg(const char * value,
const char * description,
unsigned syntax_flags)
: alloc_value_name(0),
arg_flags(0),
arg_syntax(syntax_flags),
arg_sequence(0),
arg_char_name(0),
arg_keyword_name(NULL),
arg_value_name(value),
arg_description(description)
{
parse_description();
parse_value();
adjust_syntax();
}
// Destructor
CmdArg::~CmdArg(void)
{
if (alloc_value_name) delete [] (char *)arg_value_name;
}
//-------------------
// ^FUNCTION: adjust_syntax - adjust command argument syntax
//
// ^SYNOPSIS:
// CmdArg::adjust_syntax(void)
//
// ^PARAMETERS:
// None.
//
// ^DESCRIPTION:
// This routine tries to "iron out" any inconsistencies (such as
// conflicting syntax flags) in the way a command-argument is specified
// and makes its best guess at what the user eally intended.
//
// ^REQUIREMENTS:
// parse_value() and parse_description() must already have been called.
//
// ^SIDE-EFFECTS:
// Modifies the argument syntax flags.
// Modifies is keyword and value names if they are ""
//
// ^RETURN-VALUE:
// None.
//
// ^ALGORITHM:
// Follow along in the code ...
//-^^----------------
void
CmdArg::adjust_syntax(void)
{
static const char default_value_name[] = "value" ;
// If the value is specified as both OPTIONAL and REQUIRED
// then assume it is required.
//
if ((arg_syntax & isVALREQ) && (arg_syntax & isVALOPT)) {
arg_syntax &= ~isVALOPT ;
}
// If they said the argument was both STICKY and SEPARATE then
// I dont know what to think just just ignore both of them.
//
if ((arg_syntax & isVALSTICKY) && (arg_syntax & isVALSEP)) {
arg_syntax &= ~(isVALSTICKY | isVALSEP);
}
// If a non-NULL, non-empty value-name was given but we werent
// told that the argument takes a value, then assume that it
// does take a value and that the value is required.
//
if (arg_value_name && *arg_value_name && (! (arg_syntax & isVALTAKEN))) {
arg_syntax |= isVALREQ;
}
// If a value is taken and the argument is positional, then
// we need to make isREQ and isOPT consistent with isVALREQ
// and isVALOPT
//
if ((arg_syntax & isVALTAKEN) && (arg_syntax & isPOS)) {
arg_syntax &= ~(isREQ | isOPT);
if (arg_syntax & isVALREQ) arg_syntax |= isREQ;
if (arg_syntax & isVALOPT) arg_syntax |= isOPT;
}
// If the keyword name is empty then just use NULL
if (arg_keyword_name && (! *arg_keyword_name)) {
arg_keyword_name = NULL;
}
// If the value name is empty then just use NULL
if (arg_value_name && (! *arg_value_name)) {
arg_value_name = NULL;
}
// If a value is taken but no value name was given,
// then default the value name.
//
if ((arg_syntax & isVALTAKEN) && (! arg_value_name)) {
arg_value_name = default_value_name;
}
// If no keyword name or character name was given, then the
// argument had better take a value and it must be positional
//
if ((! arg_char_name) && (arg_keyword_name == NULL) &&
(! (arg_syntax & isPOS))) {
if (arg_syntax & isVALTAKEN) {
arg_syntax |= isPOS;
} else {
cerr << "*** Error: non-positional CmdArg "
<< "has no character or keyword name!\n"
<< "\t(error occurred in CmdArg constructor)" << endl ;
}
}
}
//-------------------
// ^FUNCTION: parse_description - parse the argument description string
//
// ^SYNOPSIS:
// CmdLine::parse_description(void)
//
// ^PARAMETERS:
// None.
//
// ^DESCRIPTION:
// All we have to do is see if the first non-white character of
// the description is string is ';'. If it is, then the argument
// is a "hidden" argument and the description starts with the
// next non-white character.
//
// ^REQUIREMENTS:
// None.
//
// ^SIDE-EFFECTS:
// Modifies arg_description
//
// ^RETURN-VALUE:
// None.
//
// ^ALGORITHM:
// Trivial.
//-^^----------------
enum { c_HIDDEN = ';', c_OPEN = '[', c_CLOSE = ']', c_LIST = '.' } ;
void
CmdArg::parse_description(void)
{
if (arg_description == NULL) return;
while (isspace(*arg_description)) ++arg_description;
if (*arg_description == c_HIDDEN) {
arg_syntax |= isHIDDEN ;
++arg_description;
while (isspace(*arg_description)) ++arg_description;
}
}
//-------------------
// ^FUNCTION: parse_value - parse the argument value name
//
// ^SYNOPSIS:
// CmdLine::parse_value(void)
//
// ^PARAMETERS:
// None.
//
// ^DESCRIPTION:
// This routine parses the argument value string. If the value name is
// is enclosed between '[' and ']', then the value is optional (not
// required) and we need to modify the arg_syntax flags. Also, if the
// value name is suffixed by "..." then it means the value is a LIST
// of values and we need to modify the arg_syntax flags.
//
// ^REQUIREMENTS:
// This routine must be called BEFORE, adjust_syntax() is called/
//
// ^SIDE-EFFECTS:
// Modifies the arg_value_name and the arg_syntax flags.
//
// ^RETURN-VALUE:
// None.
//
// ^ALGORITHM:
// Its kind of hairy so follow along.
//-^^----------------
void
CmdArg::parse_value(void)
{
const char * save_value = arg_value_name;
int brace = 0;
int errors = 0;
// Skip whitespace as necessary and look for a '['
while (isspace(*arg_value_name)) ++arg_value_name;
if (*arg_value_name == c_OPEN) {
++brace;
++arg_value_name;
while (isspace(*arg_value_name)) ++arg_value_name;
arg_syntax &= ~isVALREQ;
arg_syntax |= isVALOPT;
}
// Now that arg_value_name points to the beginning of the value,
// lets find the end of it.
//
const char * ptr = arg_value_name;
while ((*ptr) && (! isspace(*ptr)) &&
(*ptr != c_LIST) && (*ptr != c_CLOSE)) {
++ptr;
}
// See if we dont need to allocate a new string
if ((! *ptr) && (save_value == arg_value_name)) return;
// Copy the value name
alloc_value_name = 1;
int len = (int) (ptr - arg_value_name);
char * copied_value = new char[len + 1];
(void) ::strncpy(copied_value, arg_value_name, len);
copied_value[len] = '\0';
arg_value_name = copied_value;
// Did we end on a ']' ?
if (*ptr == c_CLOSE) {
if (! brace) {
cerr << "Error: unmatched '" << char(c_CLOSE) << "'." << endl ;
++errors;
arg_syntax &= ~isVALREQ;
arg_syntax |= isVALOPT;
}
brace = 0;
++ptr;
}
// Skip whitespace and see if we are finished.
while (isspace(*ptr)) ++ptr;
if (! *ptr) {
// Was there an unmatched ']'
if (brace) {
cerr << "Error: unmatched '" << char(c_OPEN) << "'." << endl ;
++errors;
}
if (errors) {
cerr << "*** Syntax error in value \"" << save_value << "\".\n"
<< "\t(error occurred in CmdArg constructor)" << endl ;
}
return;
}
// Not done - we had better see a "..."
if (::strncmp(ptr, "...", 3) != 0) {
cerr << "Error: unexpected token \"" << ptr << "\"." << endl ;
++errors;
} else {
arg_syntax |= isLIST;
ptr += 3;
while (isspace(*ptr)) ++ptr;
if (brace && (*ptr != c_CLOSE)) {
cerr << "Error: unmatched '" << char(c_OPEN) << "'." << endl ;
++errors;
} else {
// If theres anything left (except ']') it's an error
if (brace && (*ptr == c_CLOSE)) ++ptr;
while (isspace(*ptr)) ++ptr;
if (*ptr) {
cerr << "Error: unexpected token \"" << ptr << "\"." << endl ;
++errors;
}
}
}
// Were there any errors?
if (errors) {
cerr << "*** Syntax error in value \"" << save_value << "\".\n"
<< "\t(error occurred in CmdArg constructor)" << endl ;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.