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