| 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 | 
 | 
|---|