diff options
Diffstat (limited to 'src/midiio/src/Options.cpp')
-rw-r--r-- | src/midiio/src/Options.cpp | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/src/midiio/src/Options.cpp b/src/midiio/src/Options.cpp new file mode 100644 index 0000000..0341fe3 --- /dev/null +++ b/src/midiio/src/Options.cpp @@ -0,0 +1,887 @@ +// +// Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sat Mar 27 18:17:06 PST 1999 +// Last Modified: Thu Apr 13 14:02:52 PDT 2000 (added 2nd define function) +// Last Modified: Fri May 5 17:52:01 PDT 2000 (added --options suppression) +// Last Modified: Tue May 1 01:25:58 PDT 2001 (fixed getArgumentCount()) +// Filename: ...sig/maint/code/sigBase/Options.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Options.cpp +// Documentation: http://sig.sapp.org/doc/classes/Options +// Syntax: C++ +// +// Description: Handles command-line options in a graceful manner. +// + +int optionListCompare(const void* a, const void* b); + +#include "Options.h" +#include "Options_private.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <iostream> + + +////////////////////////////// +// +// Options::Options -- +// + +Options::Options(void) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; +} + + +Options::Options(int argc, char** argv) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; + + setOptions(argc, argv); +} + + + +////////////////////////////// +// +// Options::~Options -- +// + +Options::~Options() { + reset(); +} + + + +////////////////////////////// +// +// Options::argc -- returns the argument count as from main(). +// + +int Options::argc(void) const { + return gargc; +} + + + +////////////////////////////// +// +// Options::argv -- returns the arguments strings as from main(). +// + +char** Options::argv(void) const { + return gargv; +} + + + +////////////////////////////// +// +// Options::define -- define an option entry in the option register +// + +void Options::define(const char* aDefinition) { + sortedQ = 0; // have to sort option list later + option_register* definitionEntry; + option_list* optionListEntry; + + + // error if the definition string doesn't contain an equals sign. + if (strchr(aDefinition, '=') == NULL) { + std::cout << "Error: no \"=\" in option definition: " << aDefinition << std::endl; + exit(1); + } + + // get the length of the definition string + int len = strlen(aDefinition); + + // put space before and after the equals sign so that strtok works + char* definitionString; + definitionString = new char[len + 3]; + int i = 0; + while (aDefinition[i] != '=' && i < len) { + definitionString[i] = aDefinition[i]; + i++; + } + definitionString[i] = ' '; + i++; + definitionString[i] = '='; + i++; + definitionString[i] = ' '; + for (int k=i; k<len+2; k++) { + definitionString[k+1] = aDefinition[k-1]; + } + len += 2; + + // determine the registry index for the definition + int definitionIndex = optionRegister.getSize(); + + + // set up space for a definition entry + definitionEntry = new option_register(aDefinition, OPTION_UNKNOWN_TYPE, + "", NULL); + + + char *tempstr; // temporary storage for strtok use on defaultString + tempstr = new char[len + 1]; + strncpy(tempstr, definitionString, len); + + char *optionName; // option name to add to list + + // get the first option name + optionName = strtok(tempstr, " \t\n|"); + if (optionName[0] == '=') { + std::cout << "Error: must specify an option name in definition: " + << aDefinition << std::endl; + exit(1); + } + // store an entry for each option name alias + const char* tempsearch; + while (optionName != NULL && optionName[0] != '=') { + tempsearch = getDefinition(optionName); + if (tempsearch != NULL) { + std::cerr << "option name \"" << optionName + << "\" from definition: " << aDefinition << std::endl; + std::cerr << "is already defined in definition: " + << tempsearch << std::endl; + exit(1); + } + optionListEntry = new option_list(optionName, definitionIndex); + optionList.append(optionListEntry); + optionName = strtok(NULL, " \t\n|"); + } + if (optionName == NULL) { + std::cout << "Error: unknown error in definition: " << aDefinition << std::endl; + exit(1); + } + + // now process the option type and any default value. + i = 0; + + // find the equals sign + while (definitionString[i] != '=' && i < len) { + i++; + } + i++; + // skip over any white space + while (isspace(definitionString[i]) && i < len) { + i++; + } + + // this character must be the option type + char optionType = (char)tolower(definitionString[i]); + definitionEntry->setType(optionType); + i++; + + + // check to make sure that the type is correct. + if (optionType != OPTION_STRING_TYPE && + optionType != OPTION_INT_TYPE && + optionType != OPTION_FLOAT_TYPE && + optionType != OPTION_DOUBLE_TYPE && + optionType != OPTION_BOOLEAN_TYPE && + optionType != OPTION_CHAR_TYPE ) { + std::cout << "Error: unknown option type \'" << optionType + << "\' in defintion: " << aDefinition << std::endl; + exit(1); + } + + // skip any white space after option type. + while (isspace(definitionString[i]) && i < len) { + i++; + } + + + // there can only be two characters now: '\0' or ':' + if (i >= len || definitionString[i] == '\0') { + goto option_finish; + } else if (i<len && definitionString[i] == ':') { + i++; + } else { + std::cout << "Unknown error in definition: " << aDefinition << std::endl; + exit(1); + } + + + // now proces the default string. store it in a temp storage for copying + + // skip any white space after option type. + while (i < len && isspace(definitionString[i])) { + i++; + } + if (i >= len || definitionString[i] == '\0') { + goto option_finish; + } + + + // now at beginnng of default option string which continues + // until the end of the definition string. + definitionEntry->setDefault(&definitionString[i]); + +option_finish: + + optionRegister.append(definitionEntry); + + + delete [] definitionString; + delete [] tempstr; + +} + + +void Options::define(const char* aDefinition, const char* description) { + define(aDefinition); + + // now find some place to store the description... +} + + + +////////////////////////////// +// +// Options::getArg -- returns the specified argument. +// argurment 0 is the command name. +// + +char* Options::getArg(int index) { + if (index < 0 || index >= argument.getSize()) { + std::cout << "Error: argument " << index << " does not exist." << std::endl; + exit(1); + } + return argument[index]; +} + + + +////////////////////////////// +// +// Options::getArgument -- same as getArg +// + +char* Options::getArgument(int index) { + return getArg(index); +} + + + +////////////////////////////// +// +// Options::getArgCount -- number of arguments on command line. +// does not count the options or the command name. +// + +int Options::getArgCount(void) { + return argument.getSize() - 1; +} + + + +////////////////////////////// +// +// Options::getArgumentCount -- Same as getArgCount(). +// + +int Options::getArgumentCount(void) { + return getArgCount(); +} + + + +////////////////////////////// +// +// Options::getBoolean -- returns true if the option was +// used on the command line. +// + +int Options::getBoolean(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return 0; + } + if (optionRegister[index]->getModifiedQ() == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Options::getCommand -- returns argv[0] +// + +const char* Options::getCommand(void) { + if (argument.getSize() == 0) { + return ""; + } else { + return argument[0]; + } +} + + + +////////////////////////////// +// +// Options::getCommandLine -- returns a string which contains the +// command-line call to the program. +// + +const char* Options::getCommandLine(void) { + if (commandString != NULL) { + return commandString; + } + + int length = 0; + int i; + for (i=0; i<gargc; i++) { + length += strlen(gargv[i]) + 1; + } + length--; // remove the last space + commandString = new char[length + 1]; + strcpy(commandString, gargv[0]); + for (i=1; i<gargc; i++) { + strcat(commandString, " "); + strcat(commandString, gargv[i]); + } + + return commandString; +} + + + + +////////////////////////////// +// +// Options::getDefinition -- returns the definition +// for the specified option name. Returns NULL +// if there is no entry for the option name. +// It is assumed that the option list is unsorted. +// spaces count in the input option name. +// + +const char* Options::getDefinition(const char* optionName) { + int i; + for (i=0; i<optionList.getSize(); i++) { + if (strcmp(optionName, optionList[i]->getName()) == 0) { + return optionRegister[optionList[i]->getIndex()]->getDefinition(); + } + } + return (const char*)NULL; +} + + + +////////////////////////////// +// +// Options::getDouble -- returns the double float associated +// with the given option. Returns 0 if there is no +// number associated with the option. +// + +double Options::getDouble(const char* optionName) { + return strtod(getString(optionName), (char**)NULL); +} + + + +////////////////////////////// +// +// Options::getFlag -- +// + +char Options::getFlag(void) { + return optionFlag; +} + + + +////////////////////////////// +// +// Options::getFloat -- returns the floating point number +// associated with the given option. +// + +float Options::getFloat(const char* optionName) { + return (float)getDouble(optionName); +} + + + +////////////////////////////// +// +// Options::getInt -- returns the integer argument. Can handle +// hexadecimal, decimal, and octal written in standard +// C syntax. +// + +int Options::getInt(const char* optionName) { + return (int)strtol(getString(optionName), (char**)NULL, 0); +} + +int Options::getInteger(const char* optionName) { + return getInt(optionName); +} + + + +////////////////////////////// +// +// Options::getString -- +// + +const char* Options::getString(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return "UNKNOWN OPTION"; + } else { + return optionRegister[index]->getOption(); + } +} + + + +////////////////////////////// +// +// Options::optionsArg -- returns true if the --options is present +// on the command line, otherwise returns false. +// + +int Options::optionsArg(void) { + return optionsArgument; +} + + + +////////////////////////////// +// +// Options::print -- +// + +void Options::print(void) { + for (int i=0; i<optionRegister.getSize(); i++) { + std::cout << optionRegister[i]->getDefinition() << std::endl; + } +} + + + +////////////////////////////// +// +// Options::reset -- +// + +void Options::reset(void) { + int i; + for (i=0; i<optionRegister.getSize(); i++) { + delete optionRegister[i]; + } + optionRegister.setSize(0); + for (i=0; i<optionList.getSize(); i++) { + delete optionList[i]; + } + optionList.setSize(0); + for (i=0; i<argument.getSize(); i++) { + delete [] argument[i]; + } + argument.setSize(0); + + if (commandString != NULL) { + delete [] commandString; + } +} + + + +////////////////////////////// +// +// Options::setFlag -- set the character used to indicate an +// option. For unix this is usually '-', in MS-DOS, +// this is usually '/'; But the syntax of the Options +// class is for Unix-style options. +// + +void Options::setFlag(char aFlag) { + optionFlag = aFlag; +} + + + + +////////////////////////////// +// +// setModified -- +// + +void Options::setModified(const char* optionName, const char* aString) { + int index = getRegIndex(optionName); + if (index < 0) { + return; + } + + optionRegister[getRegIndex(optionName)]->setModified(aString); +} + + + + +////////////////////////////// +// +// setOptions -- +// + +void Options::setOptions(int argc, char** argv) { + processedQ = 0; + + gargc = argc; + gargv = argv; +} + + + +////////////////////////////// +// +// Options:getType -- returns the type of the option +// + +char Options::getType(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return -1; + } else { + return optionRegister[getRegIndex(optionName)]->getType(); + } +} + + + +////////////////////////////// +// +// Options::process -- same as verify +// default values: error_check = 1, suppress = 0; +// + +void Options::process(int argc, char** argv, int error_check, int suppress) { + setOptions(argc, argv); + verify(error_check, suppress); +} + + +void Options::process(int error_check, int suppress) { + verify(error_check, suppress); +} + + + +////////////////////////////// +// +// Options::verify -- +// default value: error_check = 1, suppress = 0; +// + +void Options::verify(int error_check, int suppress) { + options_error_check = error_check; + int gargp = 1; + int optionend = 0; + + if (suppress) { + suppressQ = 1; + } else { + suppressQ = 0; + } + + // if calling verify again, must remove previous argument list. + if (argument.getSize() != 0) { + for (int j=0; j<argument.getSize(); j++) { + delete argument[j]; + } + argument.setSize(0); + } + + char* tempargument; + tempargument = new char[strlen(gargv[0])+1]; + strcpy(tempargument, gargv[0]); + argument.append(tempargument); + + int oldgargp; + int position = 0; + int running = 0; + while (gargp < gargc && optionend == 0) { + if (optionQ(gargv[gargp], gargp)) { + oldgargp = gargp; + gargp = storeOption(gargp, position, running); + if (gargp != oldgargp) { + running = 0; + position = 0; + } + } else { + if ( strlen(gargv[gargp]) == 2 && gargv[gargp][0] == getFlag() && + gargv[gargp][2] == getFlag() ) { + optionend = 1; + gargp++; + break; + } else { // this is an argument + tempargument = new char[strlen(gargv[gargp])+1]; + strcpy(tempargument, gargv[gargp]); + argument.append(tempargument); + gargp++; + } + } + } + + while (gargp < gargc) { + tempargument = new char[strlen(gargv[gargp])+1]; + strcpy(tempargument, gargv[gargp]); + argument.append(tempargument); + gargp++; + } + +} + + +void Options::verify(int argc, char** argv, int error_check, int suppress) { + setOptions(argc, argv); + verify(error_check, suppress); +} + + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// getRegIndex -- returns the index of the option associated +// with this name. +// + +int Options::getRegIndex(const char* optionName) { + if (suppressQ && strcmp("options", optionName) == 0) { + return -1; + } + + if (sortedQ == 0) { + sortOptionNames(); + } + option_list key(optionName, -1); + option_list* keyp = &key; + void* searchresult; + searchresult = bsearch(&keyp, optionList.getBase(), + optionList.getSize(), sizeof(option_list*), optionListCompare); + if (searchresult != NULL) { + return (*((option_list**)searchresult))->getIndex(); + } else if (strcmp("options", optionName) == 0) { + print(); + exit(1); + } + + if (options_error_check) { + std::cout << "Error: unknown option \"" << optionName << "\"." << std::endl; + print(); + exit(1); + } + + return -1; +} + + + +////////////////////////////// +// +// optionQ -- returns true if the string is an option +// "--" is not an option, also '-' is not an option. +// aString is assumed to not be NULL. +// + +int Options::optionQ(const char* aString, int& argp) { + if (aString[0] == getFlag()) { + if (aString[1] == '\0') { + argp++; + return 0; + } else if (aString[1] == getFlag()) { + if (aString[2] == '\0') { + argp++; + return 0; + } else { + return 1; + } + } else { + return 1; + } + } else { + return 0; + } +} + + + + +////////////////////////////// +// +// sortOptionNames -- +// + +void Options::sortOptionNames(void) { + qsort(optionList.getBase(), optionList.getSize(), + sizeof(option_list*), optionListCompare); + sortedQ = 1; +} + + + +////////////////////////////// +// +// storeOption -- +// + +#define OPTION_FORM_SHORT 0 +#define OPTION_FORM_LONG 1 +#define OPTION_FORM_CONTINUE 2 + +int Options::storeOption(int gargp, int& position, int& running) { + int optionForm; + char tempname[1024]; + char optionType = '\0'; + + if (running) { + optionForm = OPTION_FORM_CONTINUE; + } else if (gargv[gargp][1] == getFlag()) { + optionForm = OPTION_FORM_LONG; + } else { + optionForm = OPTION_FORM_SHORT; + } + + switch (optionForm) { + case OPTION_FORM_CONTINUE: + position++; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + running = 0; + position++; + } + break; + case OPTION_FORM_SHORT: + position = 1; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + position++; + } + break; + case OPTION_FORM_LONG: + position = 2; + while (gargv[gargp][position] != '=' && + gargv[gargp][position] != '\0') { + tempname[position-2] = gargv[gargp][position]; + position++; + } + tempname[position-2] = '\0'; + optionType = getType(tempname); + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + break; + } + if (gargv[gargp][position] == '=') { + if (optionType == OPTION_BOOLEAN_TYPE) { + std::cout << "Error: boolean variable cannot have any options: " + << tempname << std::endl; + exit(1); + } + position++; + } + break; + } + + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + gargp++; + position = 0; + return gargp; + } + + if (gargv[gargp][position] == '\0' && + optionType != OPTION_BOOLEAN_TYPE) { + gargp++; + position = 0; + } + + if (optionForm != OPTION_FORM_LONG && optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] != '\0') { + running = 1; + } else if (optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] == '\0') { + running = 0; + } + + if (gargp >= gargc) { + std::cout << "Error: last option requires a parameter" << std::endl; + exit(1); + } + setModified(tempname, &gargv[gargp][position]); + + if (!running) { + gargp++; + } + return gargp; +} + + +/////////////////////////////////////////////////////////////////////////// +// +// helping function +// + +////////////////////////////// +// +// optionListCompare -- for sorting the option list +// + +int optionListCompare(const void* a, const void* b) { +//cerr << " comparing: " << (*((option_list**)a))->getName() +// << " i=" << (*((option_list**)a))->getIndex() +// << " :to: " +// << (*((option_list**)b))->getName() +// << " i=" << (*((option_list**)b))->getIndex() << std::endl; + return strcmp((*((option_list**)a))->getName(), + (*((option_list**)b))->getName()); +} + + + +// md5sum: 63584ffabc92170fdb9ef5caedb5a3f6 - Options.cpp =css= 20030102 |