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.