1 //
2 // Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
3 // Creation Date: Sun Apr  5 13:07:18 PDT 1998
4 // Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
5 // Filename:      midifile/src/Options.cpp
6 // Web Address:   http://midifile.sapp.org
7 // Syntax:        C++11
8 // vim:           ts=3 noexpandtab
9 //
10 // Description:   Interface to command-line options.
11 //
12 
13 #include "Options.h"
14 
15 #include <stdlib.h>
16 #include <string>
17 #include <vector>
18 #include <cctype>
19 #include <iostream>
20 #include <algorithm>
21 
22 
23 namespace smf {
24 
25 ///////////////////////////////////////////////////////////////////////////
26 //
27 // Option_register class function definitions.
28 //
29 
30 
31 //////////////////////////////
32 //
33 // Option_register::Option_register -- Constructor.
34 //
35 
Option_register(void)36 Option_register::Option_register(void) {
37    type = 's';
38    modifiedQ = 0;
39 }
40 
41 
Option_register(const std::string & aDefinition,char aType,const std::string & aDefaultOption)42 Option_register::Option_register(const std::string& aDefinition, char aType,
43       const std::string& aDefaultOption) {
44    type = 's';
45    modifiedQ = 0;
46    setType(aType);
47    setDefinition(aDefinition);
48    setDefault(aDefaultOption);
49 }
50 
Option_register(const std::string & aDefinition,char aType,const std::string & aDefaultOption,const std::string & aModifiedOption)51 Option_register::Option_register(const std::string& aDefinition, char aType,
52       const std::string& aDefaultOption, const std::string& aModifiedOption) {
53    type = 's';
54    modifiedQ = 0;
55    setType(aType);
56    setDefinition(aDefinition);
57    setDefault(aDefaultOption);
58    setModified(aModifiedOption);
59 }
60 
61 
62 
63 //////////////////////////////
64 //
65 // Option_register::~Option_register -- Destructor.
66 //
67 
~Option_register()68 Option_register::~Option_register() {
69    // do nothing
70 }
71 
72 
73 
74 //////////////////////////////
75 //
76 // Option_register::clearModified -- Clear any changes in the option value.
77 //
78 
clearModified(void)79 void Option_register::clearModified(void) {
80    modifiedOption.clear();
81    modifiedQ = 0;
82 }
83 
84 
85 
86 //////////////////////////////
87 //
88 // Option_register::getDefinition -- Returns the initial definition.
89 //	string used to define this entry.
90 //
91 
getDefinition(void)92 const std::string& Option_register::getDefinition(void) {
93    return definition;
94 }
95 
96 
97 
98 //////////////////////////////
99 //
100 // Option_register::getDescription -- Return the textual description
101 //      of the entry.
102 //
103 
getDescription(void)104 const std::string& Option_register::getDescription(void) {
105    return description;
106 }
107 
108 
109 
110 //////////////////////////////
111 //
112 // Option_register::getDefault --  Return the default value string.
113 //
114 
getDefault(void)115 const std::string& Option_register::getDefault(void) {
116    return defaultOption;
117 }
118 
119 
120 
121 //////////////////////////////
122 //
123 // Option_register::getModified -- Return the modified option string.
124 //
125 
getModified(void)126 const std::string& Option_register::getModified(void) {
127    return modifiedOption;
128 }
129 
130 
131 
132 //////////////////////////////
133 //
134 // Option_register::isModified -- Return true if option has been
135 //    set on the command-line.
136 //
137 
isModified(void)138 bool Option_register::isModified(void) {
139    return modifiedQ;
140 }
141 
142 
143 
144 //////////////////////////////
145 //
146 // Option_register::getType -- Return the data type of the option.
147 //
148 
getType(void)149 char Option_register::getType(void) {
150    return type;
151 }
152 
153 
154 
155 //////////////////////////////
156 //
157 // Option_register::getOption -- return the modified option
158 //  	or the default option if no modified option.
159 //
160 
getOption(void)161 const std::string& Option_register::getOption(void) {
162    if (isModified()) {
163       return getModified();
164    } else {
165       return getDefault();
166    }
167 }
168 
169 
170 
171 //////////////////////////////
172 //
173 // Option_register::reset -- deallocate space for all
174 //	strings in object.  (but default string is set to "")
175 //
176 
reset(void)177 void Option_register::reset(void) {
178    definition.clear();
179    defaultOption.clear();
180    modifiedOption.clear();
181 }
182 
183 
184 
185 //////////////////////////////
186 //
187 // Option_register::setDefault -- Set the default value.
188 //
189 
setDefault(const std::string & aString)190 void Option_register::setDefault(const std::string& aString) {
191    defaultOption = aString;
192 }
193 
194 
195 
196 //////////////////////////////
197 //
198 // Option_register::setDefinition -- Set the option definition.
199 //
200 
setDefinition(const std::string & aString)201 void Option_register::setDefinition(const std::string& aString) {
202    definition = aString;
203 }
204 
205 
206 
207 //////////////////////////////
208 //
209 // Option_register::setDescription -- Set the textual description.
210 //
211 
setDescription(const std::string & aString)212 void Option_register::setDescription(const std::string& aString) {
213    description = aString;
214 }
215 
216 
217 
218 //////////////////////////////
219 //
220 // Option_register::setModified -- Set the modified value.
221 //
222 
setModified(const std::string & aString)223 void Option_register::setModified(const std::string& aString) {
224    modifiedOption = aString;
225    modifiedQ = 1;
226 }
227 
228 
229 
230 //////////////////////////////
231 //
232 // Option_register::setType -- Set the option type.
233 //
234 
setType(char aType)235 void Option_register::setType(char aType) {
236    type = aType;
237 }
238 
239 
240 
241 //////////////////////////////
242 //
243 // Option_register::print -- Print the state of the option registery entry.
244 //     Useul for debugging.
245 //
246 
print(std::ostream & out)247 std::ostream& Option_register::print(std::ostream& out) {
248    out << "definition:\t"     << definition     << std::endl;
249    out << "description:\t"    << description    << std::endl;
250    out << "defaultOption:\t"  << defaultOption  << std::endl;
251    out << "modifiedOption:\t" << modifiedOption << std::endl;
252    out << "modifiedQ:\t\t"    << modifiedQ      << std::endl;
253    out << "type:\t\t"         << type           << std::endl;
254    return out;
255 };
256 
257 
258 
259 
260 ///////////////////////////////////////////////////////////////////////////
261 //
262 // Options class function definitions.
263 //
264 
265 //////////////////////////////
266 //
267 // Options::Options -- Constructor.
268 //
269 
Options(void)270 Options::Options(void) {
271    m_oargc               = -1;
272    m_suppressQ           =  0;
273    m_processedQ          =  0;
274    m_optionsArgument     =  0;
275    m_options_error_check =  1;
276    m_optionFlag          = '-';
277 
278    m_extraArgv.reserve(100);
279    m_extraArgv_strings.reserve(100);
280 }
281 
282 
Options(int argc,char ** argv)283 Options::Options(int argc, char** argv) {
284    m_oargc               = -1;
285    m_suppressQ           =  0;
286    m_processedQ          =  0;
287    m_optionsArgument     =  0;
288    m_options_error_check =  1;
289    m_optionFlag          = '-';
290 
291    m_extraArgv.reserve(100);
292    m_extraArgv_strings.reserve(100);
293 
294    setOptions(argc, argv);
295 }
296 
297 
298 
299 //////////////////////////////
300 //
301 // Options::~Options -- Destructor.
302 //
303 
~Options()304 Options::~Options() {
305    reset();
306 }
307 
308 
309 
310 //////////////////////////////
311 //
312 // Options::argc -- returns the argument count as input from main().
313 //
314 
argc(void) const315 int Options::argc(void) const {
316    return m_oargc;
317 }
318 
319 
320 
321 //////////////////////////////
322 //
323 // Options::argv -- returns the arguments strings as input from main().
324 //
325 
argv(void) const326 const std::vector<std::string>& Options::argv(void) const {
327    return m_oargv;
328 }
329 
330 
331 
332 //////////////////////////////
333 //
334 // Options::define -- store an option definition in the registry.  Option
335 //     definitions have this sructure:
336 //        option-name|alias-name1|alias-name2=option-type:option-default
337 // option-name :: name of the option (one or more character, not including
338 //      spaces or equal signs.
339 // alias-name  :: equivalent name(s) of the option.
340 // option-type :: single charater indicating the option data type.
341 // option-default :: default value for option if no given on the command-line.
342 //
343 
define(const std::string & aDefinition)344 int Options::define(const std::string& aDefinition) {
345    Option_register* definitionEntry = NULL;
346 
347    // Error if definition string doesn't contain an equals sign
348    auto location = aDefinition.find("=");
349    if (location == std::string::npos) {
350       std::cerr << "Error: no \"=\" in option definition: " << aDefinition << std::endl;
351       exit(1);
352    }
353 
354    std::string aliases = aDefinition.substr(0, location);
355    std::string rest    = aDefinition.substr(location+1);
356    std::string otype   = rest;
357    std::string ovalue  = "";
358 
359    location = rest.find(":");
360    if (location != std::string::npos) {
361       otype  = rest.substr(0, location);
362       ovalue = rest.substr(location+1);
363    }
364 
365    // Remove anyspaces in the option type field
366    otype.erase(remove_if(otype.begin(), otype.end(), ::isspace), otype.end());
367 
368    // Option types are only a single charater (b, i, d, c or s)
369    if (otype.size() != 1) {
370       std::cerr << "Error: option type is invalid: " << otype
371            << " in option definition: " << aDefinition << std::endl;
372       exit(1);
373    }
374 
375    // Check to make sure that the type is known
376    if (otype[0] != OPTION_STRING_TYPE  &&
377        otype[0] != OPTION_INT_TYPE     &&
378        otype[0] != OPTION_FLOAT_TYPE   &&
379        otype[0] != OPTION_DOUBLE_TYPE  &&
380        otype[0] != OPTION_BOOLEAN_TYPE &&
381        otype[0] != OPTION_CHAR_TYPE ) {
382       std::cerr << "Error: unknown option type \'" << otype[0]
383            << "\' in defintion: " << aDefinition << std::endl;
384       exit(1);
385    }
386 
387    // Set up space for a option entry in the registry
388    definitionEntry = new Option_register(aDefinition, otype[0], ovalue);
389 
390    int definitionIndex = (int)m_optionRegister.size();
391 
392    // Store option aliases
393    std::string optionName;
394    unsigned int i;
395    aliases += '|';
396    for (i=0; i<aliases.size(); i++) {
397       if (::isspace(aliases[i])) {
398          continue;
399       } else if (aliases[i] == '|') {
400          if (isDefined(optionName)) {
401             std::cerr << "Option \"" << optionName << "\" from definition:" << std::endl;
402             std::cerr << "\t" << aDefinition << std::endl;
403             std::cerr << "is already defined in: " << std::endl;
404             std::cerr << "\t" << getDefinition(optionName) << std::endl;
405             exit(1);
406          }
407          if (optionName.size() > 0) {
408             m_optionList[optionName] = definitionIndex;
409          }
410          optionName.clear();
411       } else {
412          optionName += aliases[i];
413       }
414    }
415 
416    // Store definition in registry and return its indexed location.
417    // This location will be used to link option aliases to the main
418    // command name.
419    m_optionRegister.push_back(definitionEntry);
420    return definitionIndex;
421 }
422 
423 
define(const std::string & aDefinition,const std::string & aDescription)424 int Options::define(const std::string& aDefinition,
425 		const std::string& aDescription) {
426    int index = define(aDefinition);
427    m_optionRegister[index]->setDescription(aDescription);
428    return index;
429 }
430 
431 
432 
433 //////////////////////////////
434 //
435 // Options::isDefined -- Return true if option is present in registry.
436 //
437 
isDefined(const std::string & name)438 bool Options::isDefined(const std::string& name) {
439    return m_optionList.find(name) == m_optionList.end() ? false : true;
440 }
441 
442 
443 
444 //////////////////////////////
445 //
446 // Options::getArg -- returns the specified argument.
447 //	argurment 0 is the command name.
448 //
449 
getArg(int index)450 const std::string& Options::getArg(int index) {
451    if (index < 0 || index >= (int)m_argument.size()) {
452       std::cerr << "Error: m_argument " << index << " does not exist." << std::endl;
453       exit(1);
454    }
455    return m_argument[index];
456 }
457 
458 // Alias:
459 
getArgument(int index)460 const std::string& Options::getArgument(int index) {
461    return getArg(index);
462 }
463 
464 
465 
466 //////////////////////////////
467 //
468 // Options::getArgCount --  number of arguments on command line.
469 //	does not count the options or the command name.
470 //
471 
getArgCount(void)472 int Options::getArgCount(void) {
473    return ((int)m_argument.size()) - 1;
474 }
475 
476 // Alias:
477 
getArgumentCount(void)478 int Options::getArgumentCount(void) {
479    return getArgCount();
480 }
481 
482 
483 
484 //////////////////////////////
485 //
486 // Options::getArgList -- return a string vector of the arguments
487 //     after the options have been parsed out of it.
488 //
489 
getArgList(void)490 const std::vector<std::string>& Options::getArgList(void) {
491    return m_argument;
492 }
493 
494 // Alias:
495 
getArgumentList(void)496 const std::vector<std::string>& Options::getArgumentList(void) {
497    return getArgList();
498 }
499 
500 
501 
502 //////////////////////////////
503 //
504 // Options::getBoolean --  returns true if the option was
505 //	used on the command line.
506 //
507 
getBoolean(const std::string & optionName)508 bool Options::getBoolean(const std::string& optionName) {
509    int index = getRegIndex(optionName);
510    if (index < 0) {
511       return 0;
512    }
513    return m_optionRegister[index]->isModified();
514 }
515 
516 
517 
518 //////////////////////////////
519 //
520 // Options::getCommand -- returns argv[0] (the first string
521 //     in the original argv list.
522 //
523 
getCommand(void)524 std::string Options::getCommand(void) {
525    if (m_argument.size() == 0) {
526       return "";
527    } else {
528       return m_argument[0];
529    }
530 }
531 
532 
533 
534 //////////////////////////////
535 //
536 // Options::getCommandLine -- returns a string which contains the
537 //     command-line call to the program.  Deal with spaces in arguments...
538 //
539 
getCommandLine(void)540 const std::string& Options::getCommandLine(void) {
541    if (m_commandString.size()) {
542       return m_commandString;
543    }
544 
545    m_commandString = m_oargv[0];
546 
547    int i;
548    for (i=1; i<m_oargc; i++) {
549       m_commandString += " ";
550       m_commandString += m_oargv[i];
551    }
552 
553    return m_commandString;
554 }
555 
556 
557 
558 
559 //////////////////////////////
560 //
561 // Options::getDefinition -- returns the definition for the specified
562 //      option name.  Returns empty string if there is no entry for
563 //      the option name.  spaces count in the input option name.
564 //
565 
getDefinition(const std::string & optionName)566 std::string Options::getDefinition(const std::string& optionName) {
567    auto it = m_optionList.find(optionName);
568    if (it == m_optionList.end()) {
569       return "";
570    } else {
571       return m_optionRegister[it->second]->getDefinition();
572    }
573 }
574 
575 
576 
577 //////////////////////////////
578 //
579 // Options::getDouble -- returns the double float associated
580 //	with the given option.  Returns 0 if there is no
581 //	number associated with the option.
582 //
583 
getDouble(const std::string & optionName)584 double Options::getDouble(const std::string& optionName) {
585    return strtod(getString(optionName).c_str(), (char**)NULL);
586 }
587 
588 
589 
590 //////////////////////////////
591 //
592 // Options::getChar -- Return the first character in the option string;
593 //      If the length is zero, then return '\0'.
594 //
595 
getChar(const std::string & optionName)596 char Options::getChar(const std::string& optionName) {
597    return getString(optionName).c_str()[0];
598 }
599 
600 
601 
602 //////////////////////////////
603 //
604 // Options::getFloat -- Return the floating point number
605 //	associated with the given option.
606 //
607 
getFloat(const std::string & optionName)608 float Options::getFloat(const std::string& optionName) {
609    return (float)getDouble(optionName);
610 }
611 
612 
613 
614 //////////////////////////////
615 //
616 // Options::getInt -- Return the integer argument.  Can handle
617 //	hexadecimal, decimal, and octal written in standard
618 //	C syntax.
619 //
620 
getInt(const std::string & optionName)621 int Options::getInt(const std::string& optionName) {
622    return (int)strtol(getString(optionName).c_str(), (char**)NULL, 0);
623 }
624 
getInteger(const std::string & optionName)625 int Options::getInteger(const std::string& optionName) {
626    return getInt(optionName);
627 }
628 
629 
630 
631 //////////////////////////////
632 //
633 // Options::getString -- Return the option argument string.
634 //
635 
getString(const std::string & optionName)636 std::string Options::getString(const std::string& optionName) {
637    int index = getRegIndex(optionName);
638    if (index < 0) {
639       return "UNKNOWN OPTION";
640    } else {
641       return m_optionRegister[index]->getOption();
642    }
643 }
644 
645 
646 
647 //////////////////////////////
648 //
649 // Options::optionsArg -- Return true if --options is present
650 //    on the command line, otherwise returns false.
651 //
652 
optionsArg(void)653 int Options::optionsArg(void) {
654    return m_optionsArgument;
655 }
656 
657 
658 
659 //////////////////////////////
660 //
661 // Options::print -- Print a list of the defined options.
662 //
663 
print(std::ostream & out)664 std::ostream& Options::print(std::ostream& out) {
665    for (unsigned int i=0; i<m_optionRegister.size(); i++) {
666       out << m_optionRegister[i]->getDefinition() << "\t"
667            << m_optionRegister[i]->getDescription() << std::endl;
668    }
669    return out;
670 }
671 
672 
673 
674 //////////////////////////////
675 //
676 // Options::reset -- Clear all defined options.
677 //
678 
reset(void)679 void Options::reset(void) {
680    unsigned int i;
681    for (i=0; i<m_optionRegister.size(); i++) {
682       delete m_optionRegister[i];
683       m_optionRegister[i] = NULL;
684    }
685    m_optionRegister.clear();
686 
687    m_argument.clear();
688    m_commandString.clear();
689    m_extraArgv.clear();
690    m_extraArgv_strings.clear();
691 
692    m_oargc = -1;
693    m_oargv.clear();
694 }
695 
696 
697 
698 //////////////////////////////
699 //
700 // Options::getFlag -- Set the character which is usually set to a dash.
701 //
702 
getFlag(void)703 char Options::getFlag(void) {
704    return m_optionFlag;
705 }
706 
707 
708 
709 //////////////////////////////
710 //
711 // Options::setFlag -- Set the character used to indicate an
712 //	option.  For unix this is usually '-', in MS-DOS,
713 //	this is usually '/';  But the syntax of the Options
714 //	class is for Unix-style options.
715 //
716 
setFlag(char aFlag)717 void Options::setFlag(char aFlag) {
718    m_optionFlag = aFlag;
719 }
720 
721 
722 
723 //////////////////////////////
724 //
725 // Options::setModified --
726 //
727 
setModified(const std::string & optionName,const std::string & aString)728 void Options::setModified(const std::string& optionName,
729 		const std::string& aString) {
730    int index = getRegIndex(optionName);
731    if (index < 0) {
732       return;
733    }
734 
735    m_optionRegister[getRegIndex(optionName)]->setModified(aString);
736 }
737 
738 
739 
740 
741 //////////////////////////////
742 //
743 // Options::setOptions --  Store the input list of options.
744 //
745 
setOptions(int argc,char ** argv)746 void Options::setOptions(int argc, char** argv) {
747    m_processedQ = 0;
748 
749    m_extraArgv.resize(argc);
750    m_extraArgv_strings.resize(argc);
751    int oldsize = 0;
752 
753    int i;
754    for (i=0; i<argc; i++) {
755       m_extraArgv_strings[i+oldsize] = argv[i];
756       m_extraArgv[i] = m_extraArgv_strings[i];
757    }
758 
759    m_oargc  = (int)m_extraArgv.size();
760    m_oargv  = m_extraArgv;
761 }
762 
763 
764 
765 //////////////////////////////
766 //
767 // Options::appendOptions -- Add argc and argv data to the current
768 //      list residing inside the Options class variable.
769 //
770 
appendOptions(int argc,char ** argv)771 void Options::appendOptions(int argc, char** argv) {
772    m_processedQ = 0;
773 
774    // data used to be stored directly here:
775    //gargc = argc;
776    //gargv = argv;
777    // but now gets interfaced to: m_extraArgv and m_extraArgv_strings:
778 
779    int oldsize = (int)m_extraArgv.size();
780    m_extraArgv.resize(oldsize + argc);
781    m_extraArgv_strings.resize(oldsize + argc);
782 
783    int i;
784    for (i=0; i<argc; i++) {
785       m_extraArgv_strings[i+oldsize] = argv[i];
786       m_extraArgv[i+oldsize] = m_extraArgv_strings[i+oldsize];
787    }
788 
789    m_oargc = (int)m_extraArgv.size();
790    m_oargv = m_extraArgv;
791 }
792 
793 
appendOptions(const std::vector<std::string> & argv)794 void Options::appendOptions(const std::vector<std::string>& argv) {
795    m_processedQ = 0;
796 
797    int oldsize = (int)m_extraArgv.size();
798    m_extraArgv.resize(oldsize + argv.size());
799    m_extraArgv_strings.resize(oldsize + argv.size());
800 
801    unsigned int i;
802    for (i=0; i<argv.size(); i++) {
803       m_extraArgv_strings[i+oldsize] = argv[i];
804       m_extraArgv[i+oldsize] = m_extraArgv_strings[i+oldsize];
805    }
806 
807    m_oargc = (int)m_extraArgv.size();
808    m_oargv = m_extraArgv;
809 }
810 
811 
812 
813 //////////////////////////////
814 //
815 // Options::appendOptions -- parse the string like command-line arguments.
816 //   Either double or single quotes can be used to encapsulate
817 //   a command-line token.  If double quotes are used to encapsulate,
818 //   then you will not have to back quote single quotes inside the
819 //   token string, but you will have to backslash double quotes:
820 //      "-T \"\"" but "-T ''"
821 //   Likewise for single quotes in reverse with double quotes:
822 //      '-T \'\'' is equal to: '-T ""'
823 //
824 
appendOptions(const std::string & strang)825 void Options::appendOptions(const std::string& strang) {
826    int i;
827    int doublequote = 0;
828    int singlequote = 0;
829 
830    std::vector<std::string> tokens;
831    std::vector<std::string> tempargv;
832    std::string tempvalue;
833 
834    tokens.reserve(100);
835    tempargv.reserve(100);
836    tempvalue.reserve(1000);
837 
838    char ch;
839 
840    int length = (int)strang.size();
841    for (i=0; i<length; i++) {
842 
843       if (!singlequote && (strang[i] == '"')) {
844          if ((i>0) && (strang[i-1] != '\\')) {
845             doublequote = !doublequote;
846             if (doublequote == 0) {
847                // finished a doublequoted section of data, so store
848                // even if it is the empty string
849                ch = '\0';
850                tempvalue += (ch);
851                tokens.push_back(tempvalue);
852                tempvalue.clear();
853                continue;
854             } else {
855                // don't store the leading ":
856                continue;
857             }
858          }
859       } else if (!doublequote && (strang[i] == '\'')) {
860          if ((i>0) && (strang[i-1] != '\\')) {
861             singlequote = !singlequote;
862             if (singlequote == 0) {
863                // finished a singlequote section of data, so store
864                // even if it is the empty string
865                ch = '\0';
866                tempvalue += ch;
867                tokens.push_back(tempvalue);
868                tempvalue.clear();
869                continue;
870             } else {
871                // don't store the leading ":
872                continue;
873             }
874          }
875       }
876 
877 
878       if ((!doublequote && !singlequote) && std::isspace(strang[i])) {
879          if (tempvalue.size() > 0) {
880             tempvalue += ch;
881             tokens.push_back(tempvalue);
882             tempvalue.clear();
883          }
884       } else {
885          ch = strang[i];
886          tempvalue += ch;
887       }
888    }
889    if (tempvalue.size() > 0) {
890       tokens.push_back(tempvalue);
891       tempvalue.clear();
892    }
893 
894    // now that the input string has been chopped up into pieces,
895    // assemble the argv structure
896 
897    tempargv.reserve(tokens.size());
898    for (i=0; i<(int)tempargv.size(); i++) {
899       tempargv[i] = tokens[i];
900    }
901 
902    // now store the argv and argc data in opts:
903 
904    // now store the parsed command-line simulated tokens
905    // for actual storage:
906    appendOptions(tempargv);
907 }
908 
909 
910 
911 //////////////////////////////
912 //
913 // Options:getType -- Return the type of the option.
914 //
915 
getType(const std::string & optionName)916 char Options::getType(const std::string& optionName) {
917    int index = getRegIndex(optionName);
918    if (index < 0) {
919       return -1;
920    } else {
921       return m_optionRegister[getRegIndex(optionName)]->getType();
922    }
923 }
924 
925 
926 
927 //////////////////////////////
928 //
929 // Options::process -- Same as xverify.
930 //   	default values: error_check = 1, suppress = 0;
931 //
932 
process(int argc,char ** argv,int error_check,int suppress)933 void Options::process(int argc, char** argv, int error_check, int suppress) {
934    setOptions(argc, argv);
935    xverify(error_check, suppress);
936 }
937 
938 
process(int error_check,int suppress)939 void Options::process(int error_check, int suppress) {
940    xverify(error_check, suppress);
941 }
942 
943 
944 
945 //////////////////////////////
946 //
947 // Options::xverify --
948 //	default value: error_check = 1, suppress = 0;
949 //
950 
xverify(int error_check,int suppress)951 void Options::xverify(int error_check, int suppress) {
952    m_options_error_check = error_check;
953    int gargp = 1;
954    int optionend = 0;
955 
956    if (suppress) {
957       m_suppressQ = 1;
958    } else {
959       m_suppressQ = 0;
960    }
961 
962    // if calling xverify again, must remove previous argument list.
963    if (m_argument.size() != 0) {
964       m_argument.clear();
965    }
966 
967    m_argument.push_back(m_oargv[0]);
968    int oldgargp;
969    int position = 0;
970    int running = 0;
971    while (gargp < m_oargc && optionend == 0) {
972       if (optionQ(m_oargv[gargp], gargp)) {
973          oldgargp = gargp;
974          gargp = storeOption(gargp, position, running);
975          if (gargp != oldgargp) {
976             running = 0;
977             position = 0;
978          }
979       } else {
980          if (m_oargv[gargp].size() == 2 && m_oargv[gargp][0] == getFlag() &&
981             m_oargv[gargp][2] == getFlag() ) {
982                optionend = 1;
983             gargp++;
984             break;
985          } else {                          // this is an argument
986             m_argument.push_back(m_oargv[gargp]);
987             gargp++;
988          }
989       }
990    }
991 
992    while (gargp < m_oargc) {
993       m_argument.push_back(m_oargv[gargp]);
994       gargp++;
995    }
996 
997 }
998 
999 
xverify(int argc,char ** argv,int error_check,int suppress)1000 void Options::xverify(int argc, char** argv, int error_check, int suppress) {
1001    setOptions(argc, argv);
1002    xverify(error_check, suppress);
1003 }
1004 
1005 
1006 
1007 
1008 ///////////////////////////////////////////////////////////////////////////
1009 //
1010 // private functions
1011 //
1012 
1013 
1014 //////////////////////////////
1015 //
1016 // Options::getRegIndex -- returns the index of the option associated
1017 //	with this name.
1018 //
1019 
getRegIndex(const std::string & optionName)1020 int Options::getRegIndex(const std::string& optionName) {
1021    if (m_suppressQ && (optionName == "options")) {
1022          return -1;
1023    }
1024 
1025    if (optionName == "options") {
1026       print(std::cout);
1027       exit(0);
1028    }
1029 
1030 
1031    auto it = m_optionList.find(optionName);
1032    if (it == m_optionList.end()) {
1033       if (m_options_error_check) {
1034          std::cerr << "Error: unknown option \"" << optionName << "\"." << std::endl;
1035          print(std::cout);
1036          exit(1);
1037       } else {
1038          return -1;
1039       }
1040    } else {
1041       return it->second;
1042    }
1043 }
1044 
1045 
1046 
1047 //////////////////////////////
1048 //
1049 // Options::optionQ --  returns true if the string is an option
1050 //	"--" is not an option, also '-' is not an option.
1051 //	aString is assumed to not be NULL.
1052 //
1053 
optionQ(const std::string & aString,int & argp)1054 int Options::optionQ(const std::string& aString, int& argp) {
1055    if (aString[0] == getFlag()) {
1056       if (aString[1] == '\0') {
1057          argp++;
1058          return 0;
1059       } else if (aString[1] == getFlag()) {
1060          if (aString[2] == '\0') {
1061             argp++;
1062             return 0;
1063          } else {
1064             return 1;
1065          }
1066       } else {
1067          return 1;
1068       }
1069    } else {
1070       return 0;
1071    }
1072 }
1073 
1074 
1075 
1076 //////////////////////////////
1077 //
1078 // Options::storeOption --
1079 //
1080 
1081 #define OPTION_FORM_SHORT     0
1082 #define OPTION_FORM_LONG      1
1083 #define OPTION_FORM_CONTINUE  2
1084 
storeOption(int gargp,int & position,int & running)1085 int Options::storeOption(int gargp, int& position, int& running) {
1086    int optionForm;
1087    char tempname[1024];
1088    char optionType = '\0';
1089 
1090    if (running) {
1091       optionForm = OPTION_FORM_CONTINUE;
1092    } else if (m_oargv[gargp][1] == getFlag()) {
1093       optionForm = OPTION_FORM_LONG;
1094    } else {
1095       optionForm = OPTION_FORM_SHORT;
1096    }
1097 
1098    switch (optionForm) {
1099       case OPTION_FORM_CONTINUE:
1100          position++;
1101          tempname[0] = m_oargv[gargp][position];
1102          tempname[1] = '\0';
1103          optionType = getType(tempname);
1104          if (optionType != OPTION_BOOLEAN_TYPE) {
1105             running = 0;
1106             position++;
1107          }
1108          break;
1109       case OPTION_FORM_SHORT:
1110          position = 1;
1111          tempname[0] = m_oargv[gargp][position];
1112          tempname[1] = '\0';
1113          optionType = getType(tempname);
1114          if (optionType != OPTION_BOOLEAN_TYPE) {
1115             position++;
1116          }
1117          break;
1118       case OPTION_FORM_LONG:
1119          position = 2;
1120          while (m_oargv[gargp][position] != '=' &&
1121                m_oargv[gargp][position] != '\0') {
1122             tempname[position-2] = m_oargv[gargp][position];
1123             position++;
1124          }
1125          tempname[position-2] = '\0';
1126          optionType = getType(tempname);
1127          if (optionType == -1) {         // suppressed --options option
1128             m_optionsArgument = 1;
1129             break;
1130          }
1131          if (m_oargv[gargp][position] == '=') {
1132             if (optionType == OPTION_BOOLEAN_TYPE) {
1133                std::cerr << "Error: boolean variable cannot have any options: "
1134                     << tempname << std::endl;
1135                exit(1);
1136             }
1137             position++;
1138          }
1139          break;
1140    }
1141 
1142    if (optionType == -1) {              // suppressed --options option
1143       m_optionsArgument = 1;
1144       gargp++;
1145       position = 0;
1146       return gargp;
1147    }
1148 
1149    if (m_oargv[gargp][position] == '\0' &&
1150          optionType != OPTION_BOOLEAN_TYPE) {
1151       gargp++;
1152       position = 0;
1153    }
1154 
1155    if (optionForm != OPTION_FORM_LONG && optionType == OPTION_BOOLEAN_TYPE &&
1156          m_oargv[gargp][position+1] != '\0') {
1157       running = 1;
1158    } else if (optionType == OPTION_BOOLEAN_TYPE &&
1159          m_oargv[gargp][position+1] == '\0') {
1160       running = 0;
1161    }
1162 
1163    if (gargp >= m_oargc) {
1164       std::cerr << "Error: last option requires a parameter" << std::endl;
1165       exit(1);
1166    }
1167    setModified(tempname, &m_oargv[gargp][position]);
1168 
1169    if (!running) {
1170       gargp++;
1171    }
1172    return gargp;
1173 }
1174 
1175 
1176 
1177 //////////////////////////////
1178 //
1179 // Options::printOptionList --
1180 //
1181 
printOptionList(std::ostream & out)1182 std::ostream& Options::printOptionList(std::ostream& out) {
1183    for (auto it = m_optionList.begin(); it != m_optionList.end(); it++) {
1184       out << it->first << "\t" << it->second << std::endl;
1185    }
1186    return out;
1187 }
1188 
1189 
1190 
1191 //////////////////////////////
1192 //
1193 // Options::printOptionBooleanState --
1194 //
1195 
printOptionListBooleanState(std::ostream & out)1196 std::ostream& Options::printOptionListBooleanState(std::ostream& out) {
1197    for (auto it = m_optionList.begin(); it != m_optionList.end(); it++) {
1198       out << it->first << "\t"
1199           << m_optionRegister[it->second]->isModified() << std::endl;
1200    }
1201    return out;
1202 }
1203 
1204 
1205 
1206 //////////////////////////////
1207 //
1208 // Options::printRegister --
1209 //
1210 
printRegister(std::ostream & out)1211 std::ostream& Options::printRegister(std::ostream& out) {
1212    for (auto it = m_optionRegister.begin(); it != m_optionRegister.end(); it++) {
1213       (*it)->print(out);
1214    }
1215    return out;
1216 }
1217 
1218 
1219 } // end namespace smf
1220 
1221 
1222 
1223