| [0b990d] | 1 | /* $Id: GetLongOpt.cc,v 2.2 2003/02/06 01:02:13 cljanss Exp $ */
 | 
|---|
 | 2 | /* S Manoharan. Advanced Computer Research Institute. Lyon. France */
 | 
|---|
 | 3 | 
 | 
|---|
 | 4 | #ifdef __GNUC__
 | 
|---|
 | 5 | #pragma implementation
 | 
|---|
 | 6 | #endif
 | 
|---|
 | 7 | 
 | 
|---|
 | 8 | #include <util/options/GetLongOpt.h>
 | 
|---|
 | 9 | 
 | 
|---|
 | 10 | using namespace std;
 | 
|---|
 | 11 | using namespace sc;
 | 
|---|
 | 12 | 
 | 
|---|
 | 13 | GetLongOpt::GetLongOpt(const char optmark)
 | 
|---|
 | 14 | {
 | 
|---|
 | 15 |    table = last = 0;
 | 
|---|
 | 16 |    ustring = "[valid options and arguments]";
 | 
|---|
 | 17 |    enroll_done = 0;
 | 
|---|
 | 18 |    optmarker = optmark;
 | 
|---|
 | 19 | }
 | 
|---|
 | 20 | 
 | 
|---|
 | 21 | GetLongOpt::~GetLongOpt()
 | 
|---|
 | 22 | {
 | 
|---|
 | 23 |    Cell *t = table;
 | 
|---|
 | 24 | 
 | 
|---|
 | 25 |    while ( t ) {
 | 
|---|
 | 26 |       Cell *tmp = t;
 | 
|---|
 | 27 |       t = t->next;
 | 
|---|
 | 28 |       delete tmp;
 | 
|---|
 | 29 |    }
 | 
|---|
 | 30 | }
 | 
|---|
 | 31 | 
 | 
|---|
 | 32 | char *
 | 
|---|
 | 33 | GetLongOpt::basename(char * const pname) const
 | 
|---|
 | 34 | {
 | 
|---|
 | 35 |    char *s;
 | 
|---|
 | 36 | 
 | 
|---|
 | 37 |    s = strrchr(pname, '/');
 | 
|---|
 | 38 |    if ( s == 0 ) s = pname;
 | 
|---|
 | 39 |    else ++s;
 | 
|---|
 | 40 | 
 | 
|---|
 | 41 |    return s;
 | 
|---|
 | 42 | }
 | 
|---|
 | 43 | 
 | 
|---|
 | 44 | int
 | 
|---|
 | 45 | GetLongOpt::enroll(const char * const opt, const OptType t,
 | 
|---|
 | 46 | const char * const desc, const char * const val)
 | 
|---|
 | 47 | {
 | 
|---|
 | 48 |    if ( enroll_done ) return 0;
 | 
|---|
 | 49 | 
 | 
|---|
 | 50 |    Cell *c = new Cell;
 | 
|---|
 | 51 |    c->option = opt;
 | 
|---|
 | 52 |    c->type = t;
 | 
|---|
 | 53 |    c->description = desc ? desc : "no description available";
 | 
|---|
 | 54 |    c->value = val;
 | 
|---|
 | 55 |    c->next = 0;
 | 
|---|
 | 56 | 
 | 
|---|
 | 57 |    if ( last == 0 ) {
 | 
|---|
 | 58 |       table = last = c;
 | 
|---|
 | 59 |    }
 | 
|---|
 | 60 |    else {
 | 
|---|
 | 61 |       last->next = c;
 | 
|---|
 | 62 |       last = c;
 | 
|---|
 | 63 |    }
 | 
|---|
 | 64 | 
 | 
|---|
 | 65 |    return 1;
 | 
|---|
 | 66 | }
 | 
|---|
 | 67 | 
 | 
|---|
 | 68 | const char *
 | 
|---|
 | 69 | GetLongOpt::retrieve(const char * const opt) const
 | 
|---|
 | 70 | {
 | 
|---|
 | 71 |    Cell *t;
 | 
|---|
 | 72 |    for ( t = table; t != 0; t = t->next ) {
 | 
|---|
 | 73 |       if ( strcmp(opt, t->option) == 0 )
 | 
|---|
 | 74 |          return t->value;
 | 
|---|
 | 75 |    }
 | 
|---|
 | 76 |    cerr << "GetLongOpt::retrieve - unenrolled option ";
 | 
|---|
 | 77 |    cerr << optmarker << opt << "\n";
 | 
|---|
 | 78 |    return 0;
 | 
|---|
 | 79 | }
 | 
|---|
 | 80 | 
 | 
|---|
 | 81 | int
 | 
|---|
 | 82 | GetLongOpt::parse(int argc, char * const *argv)
 | 
|---|
 | 83 | {
 | 
|---|
 | 84 |    int optind = 1;
 | 
|---|
 | 85 | 
 | 
|---|
 | 86 |    pname = basename(*argv);
 | 
|---|
 | 87 |    enroll_done = 1;
 | 
|---|
 | 88 |    if ( argc-- <= 1 ) return optind;
 | 
|---|
 | 89 | 
 | 
|---|
 | 90 |    while ( argc >= 1 ) {
 | 
|---|
 | 91 |       char *token = *++argv; --argc;
 | 
|---|
 | 92 | 
 | 
|---|
 | 93 |       if ( token[0] != optmarker || token[1] == optmarker )
 | 
|---|
 | 94 |          break; /* end of options */
 | 
|---|
 | 95 | 
 | 
|---|
 | 96 |       ++optind;
 | 
|---|
 | 97 |       char *tmptoken = ++token;
 | 
|---|
 | 98 |       while ( *tmptoken && *tmptoken != '=' )
 | 
|---|
 | 99 |          ++tmptoken;
 | 
|---|
 | 100 |       /* (tmptoken - token) is now equal to the command line option
 | 
|---|
 | 101 |          length. */
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 |       Cell *t;
 | 
|---|
 | 104 |       enum { NoMatch, ExactMatch, PartialMatch } matchStatus = NoMatch;
 | 
|---|
 | 105 |       Cell *pc = 0;     // pointer to the partially-matched cell
 | 
|---|
 | 106 |       for ( t = table; t != 0; t = t->next ) {
 | 
|---|
 | 107 |          if ( strncmp(t->option, token, (tmptoken - token)) == 0 ) {
 | 
|---|
 | 108 |             if ( strlen(t->option) == (tmptoken - token) ) {
 | 
|---|
 | 109 |                /* an exact match found */
 | 
|---|
 | 110 |                int stat = setcell(t, tmptoken, *(argv+1), pname);
 | 
|---|
 | 111 |                if ( stat == -1 ) return -1;
 | 
|---|
 | 112 |                else if ( stat == 1 ) {
 | 
|---|
 | 113 |                   ++argv; --argc; ++optind;
 | 
|---|
 | 114 |                }
 | 
|---|
 | 115 |                matchStatus = ExactMatch;
 | 
|---|
 | 116 |                break;
 | 
|---|
 | 117 |             }
 | 
|---|
 | 118 |             else {
 | 
|---|
 | 119 |                /* partial match found */
 | 
|---|
 | 120 |                matchStatus = PartialMatch;
 | 
|---|
 | 121 |                pc = t;
 | 
|---|
 | 122 |             }
 | 
|---|
 | 123 |          } /* end if */
 | 
|---|
 | 124 |       } /* end for */
 | 
|---|
 | 125 | 
 | 
|---|
 | 126 |       if ( matchStatus == PartialMatch ) {
 | 
|---|
 | 127 |          int stat = setcell(pc, tmptoken, *(argv+1), pname);
 | 
|---|
 | 128 |          if ( stat == -1 ) return -1;
 | 
|---|
 | 129 |          else if ( stat == 1 ) {
 | 
|---|
 | 130 |             ++argv; --argc; ++optind;
 | 
|---|
 | 131 |          }
 | 
|---|
 | 132 |       }
 | 
|---|
 | 133 |       else if ( matchStatus == NoMatch ) {
 | 
|---|
 | 134 |          cerr << pname << ": unrecognized option ";
 | 
|---|
 | 135 |          cerr << optmarker << strtok(token,"= ") << "\n";
 | 
|---|
 | 136 |          return -1;             /* no match */
 | 
|---|
 | 137 |       }
 | 
|---|
 | 138 | 
 | 
|---|
 | 139 |    } /* end while */
 | 
|---|
 | 140 | 
 | 
|---|
 | 141 |    return optind;
 | 
|---|
 | 142 | }
 | 
|---|
 | 143 | 
 | 
|---|
 | 144 | int
 | 
|---|
 | 145 | GetLongOpt::parse(char * const str, char * const p)
 | 
|---|
 | 146 | {
 | 
|---|
 | 147 |    enroll_done = 1;
 | 
|---|
 | 148 |    char *token = strtok(str, " \t");
 | 
|---|
 | 149 |    const char *name = p ? p : "GetLongOpt";
 | 
|---|
 | 150 | 
 | 
|---|
 | 151 |    while ( token ) {
 | 
|---|
 | 152 |       if ( token[0] != optmarker || token[1] == optmarker ) {
 | 
|---|
 | 153 |          cerr << name << ": nonoptions not allowed\n";
 | 
|---|
 | 154 |          return -1;     /* end of options */
 | 
|---|
 | 155 |       }
 | 
|---|
 | 156 | 
 | 
|---|
 | 157 |       char *ladtoken = 0;       /* lookahead token */
 | 
|---|
 | 158 |       char *tmptoken = ++token;
 | 
|---|
 | 159 |       while ( *tmptoken && *tmptoken != '=' )
 | 
|---|
 | 160 |          ++tmptoken;
 | 
|---|
 | 161 |       /* (tmptoken - token) is now equal to the command line option
 | 
|---|
 | 162 |          length. */
 | 
|---|
 | 163 | 
 | 
|---|
 | 164 |       Cell *t;
 | 
|---|
 | 165 |       enum { NoMatch, ExactMatch, PartialMatch } matchStatus = NoMatch;
 | 
|---|
 | 166 |       Cell *pc =0;      // pointer to the partially-matched cell
 | 
|---|
 | 167 |       for ( t = table; t != 0; t = t->next ) {
 | 
|---|
 | 168 |          if ( strncmp(t->option, token, (tmptoken - token)) == 0 ) {
 | 
|---|
 | 169 |             if ( strlen(t->option) == (tmptoken - token) ) {
 | 
|---|
 | 170 |                /* an exact match found */
 | 
|---|
 | 171 |                ladtoken = strtok(0, " \t");
 | 
|---|
 | 172 |                int stat = setcell(t, tmptoken, ladtoken, name);
 | 
|---|
 | 173 |                if ( stat == -1 ) return -1;
 | 
|---|
 | 174 |                else if ( stat == 1 ) {
 | 
|---|
 | 175 |                   ladtoken = 0;
 | 
|---|
 | 176 |                }
 | 
|---|
 | 177 |                matchStatus = ExactMatch;
 | 
|---|
 | 178 |                break;
 | 
|---|
 | 179 |             }
 | 
|---|
 | 180 |             else {
 | 
|---|
 | 181 |                /* partial match found */
 | 
|---|
 | 182 |                matchStatus = PartialMatch;
 | 
|---|
 | 183 |                pc = t;
 | 
|---|
 | 184 |             }
 | 
|---|
 | 185 |          } /* end if */
 | 
|---|
 | 186 |       } /* end for */
 | 
|---|
 | 187 | 
 | 
|---|
 | 188 |       if ( matchStatus == PartialMatch ) {
 | 
|---|
 | 189 |          ladtoken = strtok(0, " \t");
 | 
|---|
 | 190 |          int stat = setcell(pc, tmptoken, ladtoken, name);
 | 
|---|
 | 191 |          if ( stat == -1 ) return -1;
 | 
|---|
 | 192 |          else if ( stat == 1 ) {
 | 
|---|
 | 193 |             ladtoken = 0;
 | 
|---|
 | 194 |          }
 | 
|---|
 | 195 |       }
 | 
|---|
 | 196 |       else if ( matchStatus == NoMatch ) {
 | 
|---|
 | 197 |          cerr << name << ": unrecognized option ";
 | 
|---|
 | 198 |          cerr << optmarker << strtok(token,"= ") << "\n";
 | 
|---|
 | 199 |          return -1;             /* no match */
 | 
|---|
 | 200 |       }
 | 
|---|
 | 201 | 
 | 
|---|
 | 202 |       token = ladtoken ? ladtoken : strtok(0, " \t");
 | 
|---|
 | 203 |    } /* end while */
 | 
|---|
 | 204 | 
 | 
|---|
 | 205 |    return 1;
 | 
|---|
 | 206 | }
 | 
|---|
 | 207 | 
 | 
|---|
 | 208 | /* ----------------------------------------------------------------
 | 
|---|
 | 209 | GetLongOpt::setcell returns
 | 
|---|
 | 210 |    -1   if there was an error
 | 
|---|
 | 211 |     0   if the nexttoken was not consumed
 | 
|---|
 | 212 |     1   if the nexttoken was consumed
 | 
|---|
 | 213 | ------------------------------------------------------------------- */
 | 
|---|
 | 214 | 
 | 
|---|
 | 215 | int
 | 
|---|
 | 216 | GetLongOpt::setcell(Cell *c, const char *valtoken, const char *nexttoken, const char *name)
 | 
|---|
 | 217 | {
 | 
|---|
 | 218 |    if ( c == 0 ) return -1;
 | 
|---|
 | 219 | 
 | 
|---|
 | 220 |    switch ( c->type ) {
 | 
|---|
 | 221 |    case GetLongOpt::NoValue :
 | 
|---|
 | 222 |       if ( *valtoken == '=' ) {
 | 
|---|
 | 223 |          cerr << name << ": unsolicited value for flag ";
 | 
|---|
 | 224 |          cerr << optmarker << c->option << "\n";
 | 
|---|
 | 225 |          return -1;     /* unsolicited value specification */
 | 
|---|
 | 226 |       }
 | 
|---|
 | 227 |       c->value = (char*)1;
 | 
|---|
 | 228 |       return 0;
 | 
|---|
 | 229 |    case GetLongOpt::OptionalValue :
 | 
|---|
 | 230 |       if ( *valtoken == '=' ) {
 | 
|---|
 | 231 |          c->value = ++valtoken;
 | 
|---|
 | 232 |       }
 | 
|---|
 | 233 |       else if ( nexttoken != 0 && nexttoken[0] != optmarker ) {
 | 
|---|
 | 234 |           c->value = nexttoken;
 | 
|---|
 | 235 |           return 1;
 | 
|---|
 | 236 |       }
 | 
|---|
 | 237 |       return 0;
 | 
|---|
 | 238 |    case GetLongOpt::MandatoryValue :
 | 
|---|
 | 239 |       if ( *valtoken == '=' ) {
 | 
|---|
 | 240 |          c->value = ++valtoken;
 | 
|---|
 | 241 |          return 0;
 | 
|---|
 | 242 |       }
 | 
|---|
 | 243 |       else if ( nexttoken != 0 && nexttoken[0] != optmarker ) {
 | 
|---|
 | 244 |          c->value = nexttoken;
 | 
|---|
 | 245 |          return 1;
 | 
|---|
 | 246 |       }
 | 
|---|
 | 247 | 
 | 
|---|
 | 248 |       cerr << name << ": mandatory value for ";
 | 
|---|
 | 249 |       cerr << optmarker << c->option << " not specified\n";
 | 
|---|
 | 250 |       return -1;        /* mandatory value not specified */
 | 
|---|
 | 251 |    default :
 | 
|---|
 | 252 |       break;
 | 
|---|
 | 253 |    }
 | 
|---|
 | 254 |    return -1;
 | 
|---|
 | 255 | }
 | 
|---|
 | 256 | 
 | 
|---|
 | 257 | void
 | 
|---|
 | 258 | GetLongOpt::usage(ostream &outfile) const
 | 
|---|
 | 259 | {
 | 
|---|
 | 260 |    Cell *t;
 | 
|---|
 | 261 | 
 | 
|---|
 | 262 |    outfile << "usage: " << pname << " " << ustring << "\n";
 | 
|---|
 | 263 |    for ( t = table; t != 0; t = t->next ) {
 | 
|---|
 | 264 |       outfile << "\t" << optmarker << t->option;
 | 
|---|
 | 265 |       if ( t->type == GetLongOpt::MandatoryValue )
 | 
|---|
 | 266 |          outfile << " <$val>";
 | 
|---|
 | 267 |       else if ( t->type == GetLongOpt::OptionalValue )
 | 
|---|
 | 268 |          outfile << " [$val]";
 | 
|---|
 | 269 |       outfile << " (" << t->description << ")\n";
 | 
|---|
 | 270 |    }
 | 
|---|
 | 271 |    outfile.flush();
 | 
|---|
 | 272 | }
 | 
|---|
 | 273 | 
 | 
|---|