1 bob 1.2 //BEGIN_LICENSE
2 //
3 // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 // DEALINGS IN THE SOFTWARE.
19 //
20 //END_LICENSE
21 //BEGIN_HISTORY
22 bob 1.2 //
23 // Author: Bob Blair bblair@bmc.com
24 //
25 // $Log:
26 //
27 //
28 //END_HISTORY
|
29 bob 1.1 //
30 // implementation of getoopt
31
32 #include "getoopt.h"
33 #include <string.h>
34
35 using namespace std;
36
37 //-----------------------------------------------------------------------
38 // Implementation of class Optarg
39 // An Optarg is created for each parameter on the command line.
40 //-----------------------------------------------------------------------
41
42 // Constructors
43 // Default Constructor
44 Optarg::Optarg() : _name(""), _opttype(REGULAR), _value("") {
45 }
46
47 // All-in-one
48 Optarg::Optarg(const string &name, opttype type, const string &value) :
49 _name(name), _opttype(type), _value(value) {
50 bob 1.1 }
51
52 // Destructor
53 Optarg::~Optarg() {};
54
55 //-----------------------------------------------------------------------
56 // Set the class members
57 //-----------------------------------------------------------------------
58
59 // Set the _name member
60 void
61 Optarg::setName(const string &name) {
62 _name = name;
63 }
64
65 // Set the _opttype member
66 void
67 Optarg::setType(opttype type) {
68 _opttype = type;
69 }
70
71 bob 1.1 // Set the _value member
72 void
73 Optarg::setValue(const string &value) {
74 _value = value;
75 }
76
77 //-----------------------------------------------------------------------
78 // Retrieve class members
79 //-----------------------------------------------------------------------
80
81 // Get the _name member
82 const string &
83 Optarg::getName() const { return _name; }
84
85 // Get the _name member using getopt() terminology
86 const string &
87 Optarg::getopt() const { return _name; }
88
89 // Get the _type member
90 Optarg::opttype
91 Optarg::getType() const { return _opttype; }
92 bob 1.1
93 //-------------------------------------------------------------------
94 // Ways to get the _value member
95 //-------------------------------------------------------------------
96
97 // Return _value as const string ref
98 const string &
99 Optarg::Value() const { return _value; }
100
101 // Same thing as Value(), but using getopt() terminology
102 const string &
103 Optarg::optarg() const { return _value; }
104
105 // Fill in a caller-provided string
106 void
107 Optarg::Value(string &s) const { s = _value; }
108
109 // Fill in a caller-provided int with the integer conversion of the value.
110 void
111 Optarg::Value(int &i) const { i = (int)atoi(_value.c_str()); }
112
113 bob 1.1 // Fill in a caller-provided unsigned int
114 void
115 Optarg::Value(unsigned int &i) const {
116 i = (unsigned int)atoi(_value.c_str());
117 }
118
119 // Fill in a call-provided unsigned int
120 void
121 Optarg::Value(long &l) const {
122 l = (long)atoi(_value.c_str());
123 }
124
125 // Fill in a caller-provided long
126 void
127 Optarg::Value(unsigned long &l) const {
128 l = (unsigned long)atoi(_value.c_str());
129 }
130
131 // Ditto unsigned long
132 void
133 Optarg::Value(double &d) const {
134 bob 1.1 d = (double)atof(_value.c_str());
135 }
136
137 //--------------------------------------------------------------------
138 // Provide information about the flag, if any
139 //--------------------------------------------------------------------
140
141 // Is the option value is bound to a flag?
142 bool
143 Optarg::isFlag() const { return (_opttype == FLAG || _opttype == LONGFLAG); }
144
145 // Is it bound to a long-named flag?
146 bool
147 Optarg::isLongFlag() const { return (_opttype == LONGFLAG); }
148
149 //-----------------------------------------------------------------------
150 // print the members as a formatted string
151 //-----------------------------------------------------------------------
152 ostream &
153 Optarg::print(ostream &os) const {
154 os << "{name:(" << getName();
155 bob 1.1 os << ") type:(";
156 switch (getType()) {
157 case FLAG: os << "FLAG"; break;
158 case LONGFLAG: os << "LONGFLAG"; break;
159 case REGULAR: os << "REGULAR"; break;
160 }
161 os << ") value:(" << Value() << ")}";
162 return os;
163 }
164
165
166
167 //---------------------------------------------------------------------
168 // Implementation of class getoopt
169 //---------------------------------------------------------------------
170
171 // Constructors and destructor
172
173 // Default constructor. The optional string is in the format of
174 // a getopt() optstring
175 getoopt::getoopt(const char *optstring)
176 bob 1.1 {
177 if (optstring) {
178 addFlagspec(optstring);
179 }
180 }
181
182 getoopt::~getoopt() {;}
183
184 //----------------------------------------------------------------------
185 // methods to register program-defined flags and their characteristics
186 // The flags are encapsulated in the struct flagspec, an array of which
187 // is a member of this class.
188 // There are also methods to deregister flags. This is done by resetting
189 // a flagspec's active flag.
190 //----------------------------------------------------------------------
191
192 // Parse through a getopt() optstring and create flagspecs from each
193 // short flag.
194 bool
195 getoopt::addFlagspec(const string &opt) {
196 unsigned int size = opt.size();
197 bob 1.1 if (size == 0)
198 return false;
199 for (unsigned int i = 0; i < size; i++) {
200 char c = opt[i];
201 if ( ((i + 1) < size) && (opt[i+1] == ':') ) {
202 if (!(addFlagspec(c, true))) {
203 return false;
204 }
205 ++i;
206 } else {
207 if (!(addFlagspec(c, false)))
208 return false;
209 }
210 }
211 return true;
212 }
213
214 // Create a filespec from a single short flag and push it onto the array
215 bool
216 getoopt::addFlagspec(char flag, bool hasarg) {
217 if (flag == '*') {
218 bob 1.1 addError("You can't have a flag named '*'");
219 return false;
220 }
221 flagspec fs;
222 char c[2];
223 c[0] = flag;
224 c[1] = 0;
225 fs.name = c;
226 fs.argtype = hasarg ? 1 : 0;
227 fs.islong = false;
228 fs.active = true;
229 _flagspecs.push_back(fs);
230 return true;
231 }
232
233 // Create a flagspec from a single long flag and push it onto the array
234 bool
235 getoopt::addLongFlagspec(const string &name, argtype type) {
236 flagspec fs;
237 fs.name = name;
238 fs.argtype = type;
239 bob 1.1 fs.islong = true;
240 fs.active = true;
241 _flagspecs.push_back(fs);
242 return true;
243 }
244
245 // Unregister a flagspec
246 bool
247 getoopt::removeFlagspec(char opt) {
248 flagspec *fs = getFlagspecForUpdate(opt);
249 if (fs) {
250 fs->active = false;
251 return true;
252 }
253 return false;
254 }
255
256 //--------------------------------------------------------------------
257 // Routines for parsing the command line
258 //--------------------------------------------------------------------
259
260 bob 1.1 //------------------------
261 // Static functions
262 //------------------------
263
264 // Parse out the flagname and the value from a long flag option that
265 // may be in the form
266 // --longflag=value
267 static void
268 partsFromLongOpt (const string &s, string &name, string &value) {
269 for (unsigned int i = 0; i < s.size(); i++) {
270 if (s[i] == '=') {
271 name = s.substr(0, i);
272 value = s.substr(i+1);
273 return;
274 }
275 }
276 name = s;
277 value = "";
278 }
279
280 // Create an Optarg instance from a long flag string like
281 bob 1.1 // --longflag=value
282 // (The =value is optional).
283 static void
284 optargFromLongOpt(Optarg &o, const string &arg) {
285 string name;
286 string value;
287 partsFromLongOpt(arg, name, value);
288 o.setName(name);
289 o.setType(Optarg::LONGFLAG);
290 o.setValue(value);
291 }
292
293 // Create an Optarg instance from a short flag string like
294 // -fValue
295 // (The Value part is optional)
296 static void
297 optargFromShortOpt(Optarg &o, const char *arg) {
298 char name[2];
299 name[0] = arg[0];
300 name[1] = 0;
301 o.setName(name);
302 bob 1.1 o.setType(Optarg::FLAG);
303 const char *p = arg + 1;
304 o.setValue(p);
305 }
306
307 // Look at a command line option and determine whether it is a
308 // long flag, a short flag or an unflagged option.
309 static int
310 catagorize(const char *s) {
311 if (s[0] != '-')
312 return 0;
313 else
314 if (s[1] == '-')
315 return 2;
316 return 1;
317 }
318
319 // Push an Optarg onto our array
320 static void
321 addarg(getoopt::Arg_List&list, const Optarg &o) {
322 //o.print(cout);
323 bob 1.1 list.push_back(o);
324 }
325
326 // Create an Optarg from its members and push it onto the array
327 static void
328 addarg(getoopt::Arg_List&list, const string &name, Optarg::opttype type,
329 const string &value) {
330 Optarg *o = new Optarg(name, type, value);
331 addarg(list, *o);
332 delete o;
333 }
334
335 // Take an array of arguments and append it to another
336 static void
337 copyargs(getoopt::Arg_List &out, const getoopt::Arg_List &in) {
338 for (getoopt::Arg_List::const_iterator it = in.begin();
339 it != in.end();
340 it++) {
341 addarg(out, *it);
342 }
343 }
344 bob 1.1
345 //------------------------------------
346 // The parse method: Way too long.
347 // Note that flag args are pushed
348 // onto the stack, then the regular
349 // args are appended, sorting them
350 // to the rear the way getopt() does.
351 //------------------------------------
352 bool
353 getoopt::parse(int argc, char **argv) {
354 Optarg o;
355 int cat;
356 const flagspec *fs;
357 Arg_List nonflagargs;
358 enum states {START, ARGEXPECTED};
359 states state = START;
360 for (unsigned int i = 1; i < (unsigned int)argc; i++) {
361 unsigned int endsize = strlen(argv[i]);
362 switch (state) {
363 case START:
364 cat = catagorize(argv[i]);
365 bob 1.1 switch (cat) {
366 case 0: // non-flag command line argument
367 addarg(nonflagargs, "", Optarg::REGULAR, argv[i]);
368 break;
369 case 1: // short (1-character) flag
370 {
371 unsigned int argpos = 1;
372 while (argpos < endsize) {
373 char c = argv[i][argpos];
374 fs = getFlagspec(c); // Short flag
375 string temp = argv[i];
376 string name = temp.substr(argpos, 1);
377 if (!fs) { // See if we recognize it
378 addError("Unknown flag -" + name);
379 argpos++;
380 } else {
381 if (fs->argtype == NOARG) { // Should this flag be bound
382 addarg(_args, name, Optarg::FLAG, ""); // NO
383 argpos++;
384 } else { // YES -- the value is here or in the next arg
385 optargFromShortOpt(o, &argv[i][argpos]);
386 bob 1.1 if (o.Value() == "") { // No value yet
387 state = ARGEXPECTED;
388 } else {
389 addarg(_args, o);
390 }
391 argpos = endsize;
392 }
393 }
394 }
395 } // end subcase 1
396 break;
397 case 2: // long (--xyz) flag
398 {
399 string arg = &(argv[i][2]);
400 optargFromLongOpt(o, arg);
401 fs = getFlagspec(o.getName());
402 if (!fs) { // see if we recognize this flag
403 string temp = "Unknown flag ";
404 addError(temp + o.getName());
405 } else {
406 // this is a long flag we know about
407 bob 1.1 if (o.optarg() != "" || fs->argtype != MUSTHAVE) {
408 addarg(_args, o);
409 state = START; // we have a completed long flag
410 } else { // no value yet, and we expect one
411 if (fs->argtype == MUSTHAVE) {
412 state = ARGEXPECTED;
413 }
414 }
415 }
416 break;
417 } // end subcase 2
418 } // end switch catagorize()
419 break; // end of case START
420
421 case ARGEXPECTED:
422 if (argv[i][0] == '-') {
423 addError("Missing required value for flag " + o.getopt());
424 i--;
425 } else {
426 o.setValue(argv[i]);
427 }
428 bob 1.1 addarg(_args, o);
429 state = START;
430 break;
431 } // end switch
432 } // end for
433 if (state != START) {
434 addError("Missing required value for flag " + o.getName());
435 }
436 copyargs(_args, nonflagargs);
437 return !_errorStrings.size();
438 }
439
440 //----------------------------------------------------------------------
441 // Methods to retrieve the command line arguments
442 //----------------------------------------------------------------------
443
444 //----------------------------------------------
445 // Access the command line arguments by index
446 //----------------------------------------------
447
448 // Index operator
449 bob 1.1 const Optarg &
450 getoopt::operator[](unsigned int n) {
451 unsigned int lim = _args.size();
452 if (n < lim)
453 return _args[n];
454 else
455 return _emptyopt;
456 }
457
458 // Return first index
459 unsigned int
460 getoopt::first() const { return 0; }
461
462 // Return one past last index
463 unsigned int
464 getoopt::last() const { return _args.size(); }
465
466 //-----------------------------------------------
467 // Access the command line arguments using
468 // getoopt::const_iterator
469 //-----------------------------------------------
470 bob 1.1
471 Optarg *
472 getoopt::begin() {
473 return _args.begin();
474 }
475
476 Optarg *
477 getoopt::end() {
478 return _args.end();
479 }
480
481 //-----------------------------------------------
482 // Access the command line arguments ad-hoc
483 //-----------------------------------------------
484
485 // Return the number of times a short flag is set
486 // on the command line
487 unsigned int
488 getoopt::isSet(char c) const {
489 unsigned int cnt = 0;
490 for (unsigned int i = 0; i < _args.size(); i++) {
491 bob 1.1 const Optarg &o = _args[i];
492 if (o.getType() == Optarg::FLAG) {
493 const string &s = o.getopt();
494 if (s[0] == c) {
495 cnt++;
496 }
497 }
498 }
499 return cnt;
500 }
501
502 // Return the number of times any flag is set
503 // on the command line
504 unsigned int
505 getoopt::isSet(const string &s) const {
506 unsigned int cnt = 0;
507 for (unsigned int i = 0; i < _args.size(); i++) {
508 const Optarg &o = _args[i];
509 if (o.optarg() == s) {
510 cnt++;
511 }
512 bob 1.1 }
513 return cnt;
514 }
515
516 // Return the string value of the nth instance of
517 // a particular short flag on the command line
518 const string &
519 getoopt::value(char opt, unsigned int idx) const {
520 unsigned int cnt = 0;
521 for (unsigned int i = 0; i < _args.size(); i++) {
522 const Optarg &o = _args[i];
523 if (o.getType() == Optarg::FLAG) {
524 const string &s = o.getopt();
525 if (s[0] == opt) {
526 if (cnt == idx) {
527 return o.optarg();
528 } else {
529 cnt++;
530 }
531 }
532 }
533 bob 1.1 }
534 return(emptystring);
535 }
536
537 // Return the nth instance of any flag on the command line
538 const string &
539 getoopt::value(const string &opt, unsigned int idx) const {
540 unsigned int cnt = 0;
541 for (unsigned int i = 0; i < _args.size(); i++) {
542 const Optarg &o = _args[i];
543 if (o.optarg() == opt) {
544 if (cnt == idx) {
545 return o.getopt();
546 } else {
547 cnt++;
548 }
549 }
550 }
551 return(emptystring);
552 }
553
554 bob 1.1 // Of the command line arguments, how many are flags?
555 unsigned int
556 getoopt::flagcnt() const {
557 unsigned int cnt = 0;
558 for (Arg_List::const_iterator it = _args.begin();
559 it != _args.end();
560 it++) {
561 if (it->getType() != Optarg::REGULAR)
562 cnt++;
563 }
564 return cnt;
565 }
566
567 // How many command line arguments were there?
568 unsigned int
569 getoopt::size() const {
570 return _args.size();
571 }
572
573 // Return the list of command line arguments for use by
574 // the program.
575 bob 1.1 const getoopt::Arg_List &
576 getoopt::getArgs() const { return _args; }
577
578
579 //-----------------------------------------------------------
580 // Routines dealing with errors during parsing
581 // FIXME: This needs to be reworked so that the error text
582 // is hidden and provided by the caller
583 //----------------------------------------------------------
584
585 // Add an error into the list
586 void
587 getoopt::addError(const string &s)
588 {
589 _errorStrings.push_back(s);
590 }
591
592 // Return a list of the errors
593 const getoopt::Error_List &
594 getoopt::getErrorStrings() const {
595 return _errorStrings;
596 bob 1.1 }
597
598 // Did any errors occur?
599 bool
600 getoopt::hasErrors() const {
601 return _errorStrings.size() ? true : false;
602 }
603
604
605
606 flagspec *
607 getoopt::getFlagspecForUpdate(const string &s) {
608 for (unsigned int i = 0; i < _flagspecs.size(); i++) {
609 flagspec &o = _flagspecs[i];
610 if (o.islong && s == o.name)
611 return &_flagspecs[i];
612 }
613 return 0;
614 }
615
616 const flagspec *
617 bob 1.1 getoopt::getFlagspec(const string &s) {
618 return (const flagspec *)getFlagspecForUpdate(s);
619 }
620
621 ostream &
622 getoopt::printErrors(ostream &os) const {
623 for (Error_List::const_iterator it = _errorStrings.begin();
624 it != _errorStrings.end();
625 it++) {
626 os << "> " << *it << endl;
627 }
628 return os;
629 }
630
631 //---------------------------------------------------------------
632 // Private methods
633 //---------------------------------------------------------------
634 flagspec *
635 getoopt::getFlagspecForUpdate(char c) {
636 for (unsigned int i = 0; i < _flagspecs.size(); i++) {
637 flagspec &o = _flagspecs[i];
638 bob 1.1 if (!o.islong && c == o.name[0])
639 return &_flagspecs[i];
640 }
641 return 0;
642 }
643
644 const flagspec *
645 getoopt::getFlagspec(char c) {
646 return (const flagspec *)getFlagspecForUpdate(c);
647 }
|