home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / common / options / option.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  14.8 KB  |  703 lines

  1. /*
  2.  *   $RCSfile: option.C,v $
  3.  *   $Revision: 1.1.1.1 $
  4.  *   $Date: 1996/05/04 21:55:11 $
  5.  */
  6. /**********************************************************************
  7. * EXODUS Database Toolkit Software
  8. * Copyright (c) 1991 Computer Sciences Department, University of
  9. *                    Wisconsin -- Madison
  10. * All Rights Reserved.
  11. *
  12. * Permission to use, copy, modify and distribute this software and its
  13. * documentation is hereby granted, provided that both the copyright
  14. * notice and this permission notice appear in all copies of the
  15. * software, derivative works or modified versions, and any portions
  16. * thereof, and that both notices appear in supporting documentation.
  17. *
  18. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  19. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
  20. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  21. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  22. *
  23. * The EXODUS Project Group requests users of this software to return
  24. * any improvements or extensions that they make to:
  25. *
  26. *   EXODUS Project Group
  27. *     c/o David J. DeWitt and Michael J. Carey
  28. *   Computer Sciences Department
  29. *   University of Wisconsin -- Madison
  30. *   Madison, WI 53706
  31. *
  32. *    or exodus@cs.wisc.edu
  33. *
  34. * In addition, the EXODUS Project Group requests that users grant the
  35. * Computer Sciences Department rights to redistribute these changes.
  36. **********************************************************************/
  37.  
  38. #include "sysdefs.h"
  39. #include "ess.h"
  40. #include "io.h"
  41. #include "option.h"
  42.  
  43. #if !defined(hpux)
  44.  
  45. #ifdef __cplusplus
  46.     extern "C" {
  47.         extern char* re_comp(const char*);
  48.         extern int re_exec(const char*);
  49.     }
  50. #else
  51.     extern char* re_comp(char*);
  52.     extern int re_exec(char*);
  53. #endif
  54.  
  55. #else /* hpux */
  56.  
  57.     /*
  58.      * hpux does not have re_comp and re_exec.  Instead there is
  59.      * regcomp() and regexec().
  60.      */
  61. #    define _INCLUDE_XOPEN_SOURCE
  62. #    include </usr/include/regex.h>
  63. #    include <assert.h>
  64.  
  65. #    define re_comp re_comp_hpux
  66. #    define re_exec re_exec_hpux
  67.  
  68.     static regex_t     re_hpux_re;
  69.     static BOOL     re_ready = FALSE;
  70.     static char*    re_error_str = "Bad regular expression";
  71.  
  72.     char* re_comp_hpux(char* pattern)
  73.     {
  74.         assert(!re_ready);
  75.  
  76.         if (regcomp(&re_hpux_re, pattern, REG_NOSUB) != 0) {
  77.             return re_error_str;
  78.         }
  79.  
  80.         re_ready = TRUE;
  81.         return NULL;
  82.     }
  83.  
  84.     int    re_exec_hpux(const char* string)
  85.     {
  86.         int status;
  87.  
  88.         assert(re_ready);
  89.  
  90.         status = regexec(&re_hpux_re, string, (size_t)0, NULL, 0);
  91.         re_ready = FALSE;
  92.         if (status == 0) return 1; // found match
  93.         return 0; // no match
  94.     }
  95.  
  96. #endif /* !hpux */
  97.  
  98. OptionInfo::OptionInfo()
  99. {
  100.     id = -1;
  101.     nameM = NULL;
  102.     possibleValuesM = NULL;
  103.     defaultValueM = NULL;
  104.     requiredM = FALSE;
  105.     setM = FALSE;
  106.     valueM[0] = '\0'; 
  107.     callBackM = NULL;
  108. }
  109.  
  110.  
  111. int    OptionInfo::init(int newId, const char* _name, const char* newPoss,
  112.                      const char* _defaultValue, const char* _description,
  113.                      BOOL _required, OptionCallBackFunc callBack) 
  114. {
  115.     int errorCode = 0;
  116.  
  117.     id = newId;
  118.     nameM = _name;
  119.     possibleValuesM = newPoss;
  120.     defaultValueM = _defaultValue;
  121.     requiredM = _required;
  122.     descriptionM = _description;
  123.     callBackM = callBack;
  124.     if (!requiredM) {
  125.         if (defaultValueM == NULL) {
  126.             return(OPTERR_DefaultNeeded);
  127.         }
  128.         errorCode = setValue(defaultValueM, FALSE);
  129.     }
  130.     setM = FALSE;
  131.     if (errorCode != 0) return errorCode;
  132.  
  133.     return OPTERR_Success;
  134. }
  135.  
  136.  
  137. BOOL OptionInfo::match(const char* matchName)
  138. {
  139.     int i;
  140.     BOOL equal;
  141.  
  142.     i = 0;
  143.     equal = TRUE;
  144.  
  145.     while(equal) {
  146.         if ( (matchName[i] != '\0') && (nameM[i] != '0') ) {
  147.             if (matchName[i] != nameM[i]) {
  148.                 equal = FALSE;
  149.             } 
  150.         } else {
  151.             if (matchName[i] == '\0') {
  152.                 break; // since at end of string
  153.             } else {
  154.                 equal = FALSE;     // since nameM[i] == '0' 
  155.                                 // matchName must be longer
  156.             }
  157.         }
  158.         i++;
  159.     }
  160.  
  161.     if (i == 0) {
  162.         return FALSE;
  163.     } else {
  164.         return equal;
  165.     }
  166. }
  167.  
  168.  
  169. int OptionInfo::setValue(const char* _value, BOOL overRide)
  170. {
  171.     int    errorCode;
  172.  
  173.     if (setM && !overRide) {
  174.         /* option not set */
  175.         return 0;
  176.     }
  177.  
  178.     if (callBackM != NULL) {
  179.         if ( (errorCode = callBackM(this, _value)) != 0) {
  180.             return errorCode;  /* call back error */
  181.         }
  182.     }
  183.  
  184.     strncpy(valueM, _value, MaxOptLength);
  185.     valueM[MaxOptLength] = '\0';
  186.     setM = TRUE;
  187.  
  188.  
  189.     return 0; /* option was set successfully */
  190. }
  191.  
  192.  
  193. ///////////////////////////////////////////////////////////////////
  194. //        OptionList functions                                     //
  195. ///////////////////////////////////////////////////////////////////
  196.  
  197. OptionList::OptionList(int length)
  198. {
  199.     options = new OptionInfo[length];
  200.     optCount = 0;
  201.     maxOptions = length;
  202.     scanLocation = -1;
  203.     numLevelsM = 0;
  204.     classStringLen = 0;
  205.     classStringName = new char[MaxOptClassLength+1];
  206.  
  207.     if (options == NULL || classStringName == NULL) {
  208.         fprintf(stderr, "not enough memory\n");
  209.         exit(1);
  210.     }
  211.  
  212.     classStringName[0] = '\0';
  213. }
  214.  
  215. OptionList::~OptionList()
  216. {
  217.     delete options;
  218.     delete classStringName;
  219. }
  220.  
  221.  
  222. OptionInfo* OptionList::addOpt()
  223. {
  224.     if (optCount == maxOptions) {
  225.         return NULL;
  226.     }
  227.  
  228.     optCount++;
  229.  
  230.     return options+(optCount-1);
  231. }
  232.  
  233.  
  234. int OptionList::addClassLevel(const char* name)
  235. {
  236.     if (numLevelsM == MaxOptClassification) {
  237.         fprintf(stderr, "OPTERR_TooManyClasses\n");
  238.         return OPTERR_TooManyClasses;
  239.     }
  240.  
  241.     levelNameM[numLevelsM] = name;
  242.     numLevelsM++;
  243.  
  244.     if ((strlen(name)+1) > (MaxOptClassLength-classStringLen) ) {
  245.         return OPTERR_ClassTooLong;
  246.     }
  247.     strncat(classStringName, name, MaxOptClassLength-classStringLen);
  248.     strcat(classStringName, ".");
  249.     classStringLen += strlen(name) + 1;
  250.  
  251.     return OPTERR_Success;
  252. }
  253.  
  254. int OptionList::setClassLevel(const char* name, int level)
  255. {
  256.     int        len;
  257.  
  258.     if (level > numLevelsM) {
  259.         return OPTERR_TooManyClasses;
  260.     }
  261.  
  262.     if (level == numLevelsM) {
  263.         return(addClassLevel(name));
  264.     }
  265.  
  266.     if (numLevelsM == MaxOptClassification) {
  267.         fprintf(stderr, "OPTERR_TooManyClasses\n");
  268.         return OPTERR_TooManyClasses;
  269.     }
  270.  
  271.     levelNameM[level] = name;
  272.  
  273.     // rebuild the class level string
  274.     classStringLen = 0;
  275.     classStringName[0] = '\0';
  276.  
  277.     for(int i = 0; i < numLevelsM; i++) {
  278.         len = strlen(levelNameM[i]) + 1;
  279.  
  280.         if (len > (MaxOptClassLength-classStringLen) ) {
  281.             return OPTERR_ClassTooLong;
  282.         }
  283.         strncat(classStringName, levelNameM[i], MaxOptClassLength-classStringLen);
  284.         strcat(classStringName, ".");
  285.         classStringLen += len;
  286.     }
  287.     return OPTERR_Success;
  288. }
  289.  
  290.  
  291. int OptionList::lookup(const char* name, OptionInfo*& returnOption)
  292. {
  293.     int i;
  294.     int e = OPTERR_NoMatch;
  295.  
  296.     returnOption = NULL;
  297.  
  298.     for(i = 0; i < optCount; i++) {
  299.          if (options[i].match(name)) {
  300.             if (returnOption != NULL) {
  301.                 returnOption = NULL;    // duplicate
  302.                 e = OPTERR_Duplicate;
  303.                 break;
  304.             } else {
  305.                 e = OPTERR_Success;
  306.             }
  307.             returnOption = options+i;
  308.         }
  309.     }
  310.  
  311.     return e;
  312. }
  313.  
  314.  
  315. int OptionList::lookupByClass(const char* optClassName, OptionInfo*& returnOption)
  316. {
  317.     const char*        c;
  318.     const char*        lastSpecial;
  319.     char            newC[MaxOptClassLength+10];
  320.     int                lastNewSpecial;
  321.     int                errorFound = OPTERR_Success;
  322.     int                newClen;
  323.     char*            regex = NULL;
  324.     int                foundSemi = 0;
  325.     char            option[MaxOptLength+1];
  326.     BOOL            backSlash = FALSE;
  327.  
  328.     // process the option name and classification suffix
  329.     // Make a regular expression for the option classification
  330.     lastSpecial = optClassName-1;
  331.     lastNewSpecial = 0;
  332.     newC[lastNewSpecial] = '^';
  333.     for (c = optClassName, newClen = 1; *c != '\0'; c++, newClen++) {
  334.         if (!backSlash) {
  335.             switch (*c) {
  336.             case '*':
  337.                 newC[newClen] = '.';
  338.                 newClen++;
  339.                 newC[newClen] = '*';
  340.                 lastSpecial = c;
  341.                 lastNewSpecial = newClen;
  342.                 break;
  343.             case '.':
  344.                 newC[newClen] = '\\';
  345.                 newClen++;
  346.                 newC[newClen] = '.';
  347.                 lastSpecial = c;
  348.                 lastNewSpecial = newClen;
  349.                 break;
  350.             case '?':
  351.                 newC[newClen++] = '[';
  352.                 newC[newClen++] = '^';
  353.                 newC[newClen++] = '.';
  354.                 newC[newClen++] = ']';
  355.                 newC[newClen] = '*';
  356.                 lastSpecial = c;
  357.                 lastNewSpecial = newClen;
  358.                 break;
  359.             case ':':
  360.                 foundSemi = 1;
  361.                 newC[newClen] = '\0';
  362.                 break;
  363.             case ' ': case '\t':    
  364.                 errorFound = OPTERR_IllegalClass;
  365.                 break;
  366.             case '\\':
  367.                 backSlash = TRUE;
  368.                 newClen--;
  369.                 break;
  370.             default:
  371.                 newC[newClen] = *c;
  372.             }
  373.  
  374.         } else {
  375.             newC[newClen] = *c;
  376.             backSlash = FALSE;
  377.         }
  378.  
  379.         if (lastNewSpecial == MaxOptClassLength) {
  380.             errorFound = OPTERR_ClassTooLong;
  381.         }
  382.     }
  383.  
  384.     if (errorFound != OPTERR_Success) return errorFound;
  385.  
  386.     if (!foundSemi) {
  387.         return OPTERR_Syntax;
  388.     } else {
  389.         newC[newClen] = *c;
  390.     }
  391.  
  392.     //    See if class name is missing
  393.     if (lastSpecial == (optClassName-1)) {
  394.         return OPTERR_IllegalClass;
  395.     }
  396.  
  397.     newC[lastNewSpecial+1] = '$';
  398.     newC[lastNewSpecial+2] = '\0';
  399.  
  400.     if (newC[1] == '$') {
  401.         strcat(newC, ".*");
  402.     }
  403.  
  404.     regex = re_comp(newC);
  405.     if (regex != NULL) {
  406.             fprintf(stderr, "regular expression error: %s\n", regex);
  407.             errorFound = OPTERR_IllegalClass;
  408.     } else {
  409.         if (re_exec(classStringName) == 1) {
  410.             char* temp;
  411.  
  412.              // see if option name matches
  413.             strncpy(option, lastSpecial+1, MaxOptLength);
  414.             temp = strchr(option, ':');
  415.             if (temp == NULL) {
  416.                 errorFound = OPTERR_Syntax;
  417.             } else {
  418.                 *temp = '\0';
  419.                 return lookup(option, returnOption);
  420.             }
  421.         }
  422.     }
  423.  
  424.     returnOption = NULL;    
  425.     return errorFound; 
  426. }
  427.  
  428.  
  429. void OptionList::printUsage(BOOL longForm, const char* command, FILE* f)
  430. {
  431.     OptionInfo*    current;
  432.     OptionInfo*    end;
  433.  
  434.     fprintf(f, "Usage: %s", command);
  435.     if (longForm) fprintf(f, "\n");
  436.     for (current = options, end = options+optCount; current < end; current++) {
  437.  
  438.  
  439.         if (current->required()) {
  440.             fprintf(f, " ");
  441.         } else {
  442.             fprintf(f, " [");
  443.         }
  444.         if (current->possibleValues() == NULL) {
  445.             fprintf(f, "-%s", current->name());
  446.         } else {
  447.             fprintf(f, "-%s <%s>", current->name(), current->possibleValues());
  448.         }
  449.  
  450.         if (!current->required()) fprintf(f, "]");
  451.  
  452.         if (longForm) {
  453.             fprintf(f, "\n\t\t%s\n", current->description());
  454.             if (current->defaultValue() == NULL) {
  455.                 fprintf(f, "\t\tdefault value: <none>\n");
  456.             } else {
  457.                 fprintf(f, "\t\tdefault value: %s\n", current->defaultValue());
  458.             }
  459.         }
  460.     }
  461.     if (!longForm) fprintf(f, "\n");
  462.  
  463.     return;
  464. }
  465.  
  466. void OptionList::printValues(BOOL longForm, FILE* f)
  467. {
  468.     OptionInfo*    current;
  469.     OptionInfo*    end;
  470.  
  471.     fprintf(f, "Values for options of class %s: ", classStringName);
  472.     if (longForm) fprintf(f, "\n");
  473.     for (current = options, end = options+optCount; current < end; current++) {
  474.  
  475.         if (current->set()) { // only print option which have a value set
  476.             if (!current->required()) {
  477.                 fprintf(f, " [-%s %s", current->name(), current->value());
  478.             } else {
  479.                 fprintf(f, " -%s %s", current->name(), current->value());
  480.             }
  481.             if (!current->required()) fprintf(f, "]");
  482.  
  483.             if (longForm) fprintf(f, "\n");
  484.         }
  485.     }
  486.     if (!longForm) fprintf(f, "\n");
  487.  
  488.     return;
  489. }
  490.  
  491.  
  492. void OptionList::initScan()
  493. {
  494.     scanLocation = 0;
  495. }
  496.  
  497.  
  498. OptionInfo* OptionList::getNext()
  499. {
  500.     if (scanLocation == optCount) {
  501.         return NULL;
  502.     } 
  503.  
  504.     return &(options[scanLocation++]);
  505. }
  506.  
  507.  
  508. ///////////////////////////////////////////////////////////////////
  509. //        OptionFileScan functions                                 //
  510. ///////////////////////////////////////////////////////////////////
  511.  
  512. static    char    ScanErrorString[1000];
  513.  
  514. OptionFileScan::OptionFileScan(const char* optFile, OptionList* list)
  515. {
  516.     maxLineLen = 2000;
  517.  
  518.     fileName = optFile;
  519.     optList = list;
  520.  
  521.     line = new char[maxLineLen+1];    
  522.     classOption = new char[MaxOptClassLength+1];
  523.  
  524.     if (line == NULL || classOption == NULL) {
  525.         fprintf(stderr, "not enough memory\n");
  526.         exit(1);
  527.     }
  528.  
  529.     lineNum = 0;
  530. }
  531.  
  532.  
  533. OptionFileScan::~OptionFileScan()
  534. {
  535.     delete line;
  536.     delete classOption;
  537. }
  538.  
  539.  
  540.  
  541. int OptionFileScan::scan(BOOL overRide, char*& errorString)
  542. {
  543.     int            errorFound = OPTERR_Success;
  544.     OptionInfo*    optInfo;
  545.     int            optBegin, optEnd, optLength, valBegin, valEnd, valLength;
  546.     int         i;
  547.     BOOL        backSlash = FALSE;
  548.  
  549.     f = fopen(fileName, "r");
  550.  
  551.     errorString = NULL;
  552.     if (f == NULL) {
  553.         return errno;
  554.     }
  555.  
  556.     while ( !errorFound && (fgets(line, maxLineLen, f) != NULL) ) {
  557.         lineNum++;
  558.  
  559.         // 
  560.         //    Find the classOption field
  561.         //
  562.         optBegin = -1;
  563.         optEnd = -1;
  564.         for (i = 0; line[i] != '\0'; i++) {
  565.             if (optBegin < 0) {
  566.                 /* if whitespace */
  567.                 if (isspace(line[i])) {
  568.                     continue; 
  569.                 } else {
  570.                     optBegin = i;
  571.                 }
  572.             }
  573.             if (line[i] == '\\') {
  574.                 backSlash = !backSlash;
  575.                 if (backSlash) continue;
  576.             }
  577.             if (line[i] == ':' && !backSlash) {
  578.                 optEnd = i;    
  579.                 break; /* out of for loop */
  580.             } 
  581.             backSlash = FALSE;
  582.         }
  583.  
  584.         // check for a comment or blank line and skip it
  585.         if (optBegin < 0 || line[optBegin] == '#' || line[optBegin] == '!') {
  586.             continue;    
  587.         }
  588.  
  589.         // check syntax
  590.         if (optEnd < 0) {
  591.             sprintf(ScanErrorString, "syntax error in file %s: line %d", fileName, lineNum);
  592.             errorFound = OPTERR_Syntax;
  593.             break;
  594.         }
  595.  
  596.         // check option length 
  597.         optLength = optEnd - optBegin + 1;
  598.         if (optLength > MaxOptClassLength) {
  599.             sprintf(ScanErrorString, "option class is too long in file %s: line %d", fileName, lineNum);
  600.             errorFound = OPTERR_IllegalClass;
  601.             break;
  602.         }
  603.  
  604.         bcopy(line+optBegin, classOption, optLength);
  605.         classOption[optLength] = '\0';
  606.  
  607.         errorFound = optList->lookupByClass(classOption, optInfo);
  608.         switch (errorFound) {
  609.         case OPTERR_Success:
  610.             break;
  611.         case OPTERR_NoMatch:
  612.             sprintf(ScanErrorString, "unknown option in file %s: line %d", fileName, lineNum);
  613.             break;
  614.         case OPTERR_Duplicate:
  615.             sprintf(ScanErrorString, "option name is not unique in file %s: line %d", fileName, lineNum);
  616.             break;
  617.         case OPTERR_Syntax:
  618.             sprintf(ScanErrorString, "syntax error in file %s: line %d", fileName, lineNum);
  619.             break;
  620.         case OPTERR_IllegalClass:
  621.             sprintf(ScanErrorString, "illegal/missing option class in file %s: line %d", fileName, lineNum);
  622.             break;
  623.         default:
  624.             sprintf(ScanErrorString, "general error in option file %s: line %d", fileName, lineNum);
  625.             break;    
  626.         }
  627.  
  628.         if (errorFound != OPTERR_Success) {
  629.             continue;
  630.         }
  631.  
  632.         // 
  633.         //    Find the option value field
  634.         //
  635.         valBegin = -1;
  636.         valEnd = -1;
  637.         for (i = optEnd+1; line[i] != '\0'; i++) {
  638.             /* if whitespace */
  639.             if (isspace(line[i])) {
  640.                 if (valBegin < 0) {
  641.                     continue; 
  642.                 }    
  643.             } else {
  644.                 if (valBegin < 0) {
  645.                     valBegin = i;
  646.                 }    
  647.                 valEnd = i;
  648.             }
  649.         }
  650.  
  651.         if (valBegin < 0) {
  652.             sprintf(ScanErrorString, "syntax error (missing option value) in file %s: line %d", fileName, lineNum);
  653.             errorFound = OPTERR_Syntax;
  654.             break;
  655.         }
  656.  
  657.         // remove any quote marks
  658.         if (line[valBegin] == '"') {
  659.             valBegin++;
  660.             if (line[valEnd] != '"') {
  661.                 sprintf(ScanErrorString, "syntax error (missing \") in file %s: line %d", fileName, lineNum);
  662.                 errorFound = OPTERR_Syntax;
  663.                 break;
  664.             }
  665.             valEnd--;
  666.         }
  667.         valLength = valEnd - valBegin + 1;
  668.  
  669.         if (valLength < 0) {
  670.             sprintf(ScanErrorString, "syntax error (bad option value) in file %s: line %d", fileName, lineNum);
  671.             errorFound = OPTERR_Syntax;
  672.             break;
  673.         }
  674.         if (valLength > MaxOptLength) {
  675.             sprintf(ScanErrorString, "syntax error (option value too long) in file %s: line %d", fileName, lineNum);
  676.             errorFound = OPTERR_Syntax;
  677.             break;
  678.         }
  679.  
  680.         if (errorFound != OPTERR_Success) {
  681.             continue;
  682.         }
  683.  
  684.         // if option was found to set 
  685.         if (optInfo != NULL) {
  686.             line[valEnd+1] = '\0';
  687.             errorFound = optInfo->setValue(line+valBegin, overRide);
  688.             if (errorFound) {
  689.                 sprintf(ScanErrorString, "Option value error in file %s: line %d", fileName, lineNum);
  690.                 break;
  691.             }
  692.         }
  693.     
  694.     }
  695.  
  696.     fclose(f);
  697.  
  698.     if (errorFound) {
  699.         errorString = ScanErrorString;
  700.     }
  701.     return errorFound; 
  702. }
  703.