home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: option.C,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:11 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
-
- #include "sysdefs.h"
- #include "ess.h"
- #include "io.h"
- #include "option.h"
-
- #if !defined(hpux)
-
- #ifdef __cplusplus
- extern "C" {
- extern char* re_comp(const char*);
- extern int re_exec(const char*);
- }
- #else
- extern char* re_comp(char*);
- extern int re_exec(char*);
- #endif
-
- #else /* hpux */
-
- /*
- * hpux does not have re_comp and re_exec. Instead there is
- * regcomp() and regexec().
- */
- # define _INCLUDE_XOPEN_SOURCE
- # include </usr/include/regex.h>
- # include <assert.h>
-
- # define re_comp re_comp_hpux
- # define re_exec re_exec_hpux
-
- static regex_t re_hpux_re;
- static BOOL re_ready = FALSE;
- static char* re_error_str = "Bad regular expression";
-
- char* re_comp_hpux(char* pattern)
- {
- assert(!re_ready);
-
- if (regcomp(&re_hpux_re, pattern, REG_NOSUB) != 0) {
- return re_error_str;
- }
-
- re_ready = TRUE;
- return NULL;
- }
-
- int re_exec_hpux(const char* string)
- {
- int status;
-
- assert(re_ready);
-
- status = regexec(&re_hpux_re, string, (size_t)0, NULL, 0);
- re_ready = FALSE;
- if (status == 0) return 1; // found match
- return 0; // no match
- }
-
- #endif /* !hpux */
-
- OptionInfo::OptionInfo()
- {
- id = -1;
- nameM = NULL;
- possibleValuesM = NULL;
- defaultValueM = NULL;
- requiredM = FALSE;
- setM = FALSE;
- valueM[0] = '\0';
- callBackM = NULL;
- }
-
-
- int OptionInfo::init(int newId, const char* _name, const char* newPoss,
- const char* _defaultValue, const char* _description,
- BOOL _required, OptionCallBackFunc callBack)
- {
- int errorCode = 0;
-
- id = newId;
- nameM = _name;
- possibleValuesM = newPoss;
- defaultValueM = _defaultValue;
- requiredM = _required;
- descriptionM = _description;
- callBackM = callBack;
- if (!requiredM) {
- if (defaultValueM == NULL) {
- return(OPTERR_DefaultNeeded);
- }
- errorCode = setValue(defaultValueM, FALSE);
- }
- setM = FALSE;
- if (errorCode != 0) return errorCode;
-
- return OPTERR_Success;
- }
-
-
- BOOL OptionInfo::match(const char* matchName)
- {
- int i;
- BOOL equal;
-
- i = 0;
- equal = TRUE;
-
- while(equal) {
- if ( (matchName[i] != '\0') && (nameM[i] != '0') ) {
- if (matchName[i] != nameM[i]) {
- equal = FALSE;
- }
- } else {
- if (matchName[i] == '\0') {
- break; // since at end of string
- } else {
- equal = FALSE; // since nameM[i] == '0'
- // matchName must be longer
- }
- }
- i++;
- }
-
- if (i == 0) {
- return FALSE;
- } else {
- return equal;
- }
- }
-
-
- int OptionInfo::setValue(const char* _value, BOOL overRide)
- {
- int errorCode;
-
- if (setM && !overRide) {
- /* option not set */
- return 0;
- }
-
- if (callBackM != NULL) {
- if ( (errorCode = callBackM(this, _value)) != 0) {
- return errorCode; /* call back error */
- }
- }
-
- strncpy(valueM, _value, MaxOptLength);
- valueM[MaxOptLength] = '\0';
- setM = TRUE;
-
-
- return 0; /* option was set successfully */
- }
-
-
- ///////////////////////////////////////////////////////////////////
- // OptionList functions //
- ///////////////////////////////////////////////////////////////////
-
- OptionList::OptionList(int length)
- {
- options = new OptionInfo[length];
- optCount = 0;
- maxOptions = length;
- scanLocation = -1;
- numLevelsM = 0;
- classStringLen = 0;
- classStringName = new char[MaxOptClassLength+1];
-
- if (options == NULL || classStringName == NULL) {
- fprintf(stderr, "not enough memory\n");
- exit(1);
- }
-
- classStringName[0] = '\0';
- }
-
- OptionList::~OptionList()
- {
- delete options;
- delete classStringName;
- }
-
-
- OptionInfo* OptionList::addOpt()
- {
- if (optCount == maxOptions) {
- return NULL;
- }
-
- optCount++;
-
- return options+(optCount-1);
- }
-
-
- int OptionList::addClassLevel(const char* name)
- {
- if (numLevelsM == MaxOptClassification) {
- fprintf(stderr, "OPTERR_TooManyClasses\n");
- return OPTERR_TooManyClasses;
- }
-
- levelNameM[numLevelsM] = name;
- numLevelsM++;
-
- if ((strlen(name)+1) > (MaxOptClassLength-classStringLen) ) {
- return OPTERR_ClassTooLong;
- }
- strncat(classStringName, name, MaxOptClassLength-classStringLen);
- strcat(classStringName, ".");
- classStringLen += strlen(name) + 1;
-
- return OPTERR_Success;
- }
-
- int OptionList::setClassLevel(const char* name, int level)
- {
- int len;
-
- if (level > numLevelsM) {
- return OPTERR_TooManyClasses;
- }
-
- if (level == numLevelsM) {
- return(addClassLevel(name));
- }
-
- if (numLevelsM == MaxOptClassification) {
- fprintf(stderr, "OPTERR_TooManyClasses\n");
- return OPTERR_TooManyClasses;
- }
-
- levelNameM[level] = name;
-
- // rebuild the class level string
- classStringLen = 0;
- classStringName[0] = '\0';
-
- for(int i = 0; i < numLevelsM; i++) {
- len = strlen(levelNameM[i]) + 1;
-
- if (len > (MaxOptClassLength-classStringLen) ) {
- return OPTERR_ClassTooLong;
- }
- strncat(classStringName, levelNameM[i], MaxOptClassLength-classStringLen);
- strcat(classStringName, ".");
- classStringLen += len;
- }
- return OPTERR_Success;
- }
-
-
- int OptionList::lookup(const char* name, OptionInfo*& returnOption)
- {
- int i;
- int e = OPTERR_NoMatch;
-
- returnOption = NULL;
-
- for(i = 0; i < optCount; i++) {
- if (options[i].match(name)) {
- if (returnOption != NULL) {
- returnOption = NULL; // duplicate
- e = OPTERR_Duplicate;
- break;
- } else {
- e = OPTERR_Success;
- }
- returnOption = options+i;
- }
- }
-
- return e;
- }
-
-
- int OptionList::lookupByClass(const char* optClassName, OptionInfo*& returnOption)
- {
- const char* c;
- const char* lastSpecial;
- char newC[MaxOptClassLength+10];
- int lastNewSpecial;
- int errorFound = OPTERR_Success;
- int newClen;
- char* regex = NULL;
- int foundSemi = 0;
- char option[MaxOptLength+1];
- BOOL backSlash = FALSE;
-
- // process the option name and classification suffix
- // Make a regular expression for the option classification
- lastSpecial = optClassName-1;
- lastNewSpecial = 0;
- newC[lastNewSpecial] = '^';
- for (c = optClassName, newClen = 1; *c != '\0'; c++, newClen++) {
- if (!backSlash) {
- switch (*c) {
- case '*':
- newC[newClen] = '.';
- newClen++;
- newC[newClen] = '*';
- lastSpecial = c;
- lastNewSpecial = newClen;
- break;
- case '.':
- newC[newClen] = '\\';
- newClen++;
- newC[newClen] = '.';
- lastSpecial = c;
- lastNewSpecial = newClen;
- break;
- case '?':
- newC[newClen++] = '[';
- newC[newClen++] = '^';
- newC[newClen++] = '.';
- newC[newClen++] = ']';
- newC[newClen] = '*';
- lastSpecial = c;
- lastNewSpecial = newClen;
- break;
- case ':':
- foundSemi = 1;
- newC[newClen] = '\0';
- break;
- case ' ': case '\t':
- errorFound = OPTERR_IllegalClass;
- break;
- case '\\':
- backSlash = TRUE;
- newClen--;
- break;
- default:
- newC[newClen] = *c;
- }
-
- } else {
- newC[newClen] = *c;
- backSlash = FALSE;
- }
-
- if (lastNewSpecial == MaxOptClassLength) {
- errorFound = OPTERR_ClassTooLong;
- }
- }
-
- if (errorFound != OPTERR_Success) return errorFound;
-
- if (!foundSemi) {
- return OPTERR_Syntax;
- } else {
- newC[newClen] = *c;
- }
-
- // See if class name is missing
- if (lastSpecial == (optClassName-1)) {
- return OPTERR_IllegalClass;
- }
-
- newC[lastNewSpecial+1] = '$';
- newC[lastNewSpecial+2] = '\0';
-
- if (newC[1] == '$') {
- strcat(newC, ".*");
- }
-
- regex = re_comp(newC);
- if (regex != NULL) {
- fprintf(stderr, "regular expression error: %s\n", regex);
- errorFound = OPTERR_IllegalClass;
- } else {
- if (re_exec(classStringName) == 1) {
- char* temp;
-
- // see if option name matches
- strncpy(option, lastSpecial+1, MaxOptLength);
- temp = strchr(option, ':');
- if (temp == NULL) {
- errorFound = OPTERR_Syntax;
- } else {
- *temp = '\0';
- return lookup(option, returnOption);
- }
- }
- }
-
- returnOption = NULL;
- return errorFound;
- }
-
-
- void OptionList::printUsage(BOOL longForm, const char* command, FILE* f)
- {
- OptionInfo* current;
- OptionInfo* end;
-
- fprintf(f, "Usage: %s", command);
- if (longForm) fprintf(f, "\n");
- for (current = options, end = options+optCount; current < end; current++) {
-
-
- if (current->required()) {
- fprintf(f, " ");
- } else {
- fprintf(f, " [");
- }
- if (current->possibleValues() == NULL) {
- fprintf(f, "-%s", current->name());
- } else {
- fprintf(f, "-%s <%s>", current->name(), current->possibleValues());
- }
-
- if (!current->required()) fprintf(f, "]");
-
- if (longForm) {
- fprintf(f, "\n\t\t%s\n", current->description());
- if (current->defaultValue() == NULL) {
- fprintf(f, "\t\tdefault value: <none>\n");
- } else {
- fprintf(f, "\t\tdefault value: %s\n", current->defaultValue());
- }
- }
- }
- if (!longForm) fprintf(f, "\n");
-
- return;
- }
-
- void OptionList::printValues(BOOL longForm, FILE* f)
- {
- OptionInfo* current;
- OptionInfo* end;
-
- fprintf(f, "Values for options of class %s: ", classStringName);
- if (longForm) fprintf(f, "\n");
- for (current = options, end = options+optCount; current < end; current++) {
-
- if (current->set()) { // only print option which have a value set
- if (!current->required()) {
- fprintf(f, " [-%s %s", current->name(), current->value());
- } else {
- fprintf(f, " -%s %s", current->name(), current->value());
- }
- if (!current->required()) fprintf(f, "]");
-
- if (longForm) fprintf(f, "\n");
- }
- }
- if (!longForm) fprintf(f, "\n");
-
- return;
- }
-
-
- void OptionList::initScan()
- {
- scanLocation = 0;
- }
-
-
- OptionInfo* OptionList::getNext()
- {
- if (scanLocation == optCount) {
- return NULL;
- }
-
- return &(options[scanLocation++]);
- }
-
-
- ///////////////////////////////////////////////////////////////////
- // OptionFileScan functions //
- ///////////////////////////////////////////////////////////////////
-
- static char ScanErrorString[1000];
-
- OptionFileScan::OptionFileScan(const char* optFile, OptionList* list)
- {
- maxLineLen = 2000;
-
- fileName = optFile;
- optList = list;
-
- line = new char[maxLineLen+1];
- classOption = new char[MaxOptClassLength+1];
-
- if (line == NULL || classOption == NULL) {
- fprintf(stderr, "not enough memory\n");
- exit(1);
- }
-
- lineNum = 0;
- }
-
-
- OptionFileScan::~OptionFileScan()
- {
- delete line;
- delete classOption;
- }
-
-
-
- int OptionFileScan::scan(BOOL overRide, char*& errorString)
- {
- int errorFound = OPTERR_Success;
- OptionInfo* optInfo;
- int optBegin, optEnd, optLength, valBegin, valEnd, valLength;
- int i;
- BOOL backSlash = FALSE;
-
- f = fopen(fileName, "r");
-
- errorString = NULL;
- if (f == NULL) {
- return errno;
- }
-
- while ( !errorFound && (fgets(line, maxLineLen, f) != NULL) ) {
- lineNum++;
-
- //
- // Find the classOption field
- //
- optBegin = -1;
- optEnd = -1;
- for (i = 0; line[i] != '\0'; i++) {
- if (optBegin < 0) {
- /* if whitespace */
- if (isspace(line[i])) {
- continue;
- } else {
- optBegin = i;
- }
- }
- if (line[i] == '\\') {
- backSlash = !backSlash;
- if (backSlash) continue;
- }
- if (line[i] == ':' && !backSlash) {
- optEnd = i;
- break; /* out of for loop */
- }
- backSlash = FALSE;
- }
-
- // check for a comment or blank line and skip it
- if (optBegin < 0 || line[optBegin] == '#' || line[optBegin] == '!') {
- continue;
- }
-
- // check syntax
- if (optEnd < 0) {
- sprintf(ScanErrorString, "syntax error in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_Syntax;
- break;
- }
-
- // check option length
- optLength = optEnd - optBegin + 1;
- if (optLength > MaxOptClassLength) {
- sprintf(ScanErrorString, "option class is too long in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_IllegalClass;
- break;
- }
-
- bcopy(line+optBegin, classOption, optLength);
- classOption[optLength] = '\0';
-
- errorFound = optList->lookupByClass(classOption, optInfo);
- switch (errorFound) {
- case OPTERR_Success:
- break;
- case OPTERR_NoMatch:
- sprintf(ScanErrorString, "unknown option in file %s: line %d", fileName, lineNum);
- break;
- case OPTERR_Duplicate:
- sprintf(ScanErrorString, "option name is not unique in file %s: line %d", fileName, lineNum);
- break;
- case OPTERR_Syntax:
- sprintf(ScanErrorString, "syntax error in file %s: line %d", fileName, lineNum);
- break;
- case OPTERR_IllegalClass:
- sprintf(ScanErrorString, "illegal/missing option class in file %s: line %d", fileName, lineNum);
- break;
- default:
- sprintf(ScanErrorString, "general error in option file %s: line %d", fileName, lineNum);
- break;
- }
-
- if (errorFound != OPTERR_Success) {
- continue;
- }
-
- //
- // Find the option value field
- //
- valBegin = -1;
- valEnd = -1;
- for (i = optEnd+1; line[i] != '\0'; i++) {
- /* if whitespace */
- if (isspace(line[i])) {
- if (valBegin < 0) {
- continue;
- }
- } else {
- if (valBegin < 0) {
- valBegin = i;
- }
- valEnd = i;
- }
- }
-
- if (valBegin < 0) {
- sprintf(ScanErrorString, "syntax error (missing option value) in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_Syntax;
- break;
- }
-
- // remove any quote marks
- if (line[valBegin] == '"') {
- valBegin++;
- if (line[valEnd] != '"') {
- sprintf(ScanErrorString, "syntax error (missing \") in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_Syntax;
- break;
- }
- valEnd--;
- }
- valLength = valEnd - valBegin + 1;
-
- if (valLength < 0) {
- sprintf(ScanErrorString, "syntax error (bad option value) in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_Syntax;
- break;
- }
- if (valLength > MaxOptLength) {
- sprintf(ScanErrorString, "syntax error (option value too long) in file %s: line %d", fileName, lineNum);
- errorFound = OPTERR_Syntax;
- break;
- }
-
- if (errorFound != OPTERR_Success) {
- continue;
- }
-
- // if option was found to set
- if (optInfo != NULL) {
- line[valEnd+1] = '\0';
- errorFound = optInfo->setValue(line+valBegin, overRide);
- if (errorFound) {
- sprintf(ScanErrorString, "Option value error in file %s: line %d", fileName, lineNum);
- break;
- }
- }
-
- }
-
- fclose(f);
-
- if (errorFound) {
- errorString = ScanErrorString;
- }
- return errorFound;
- }
-