1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158 |
- /*
- This file is part of ezOptionParser. See MIT-LICENSE.
-
- Copyright (C) 2011,2012,2014 Remik Ziemlinski <first d0t surname att gmail>
-
- CHANGELOG
-
- v0.0.0 20110505 rsz Created.
- v0.1.0 20111006 rsz Added validator.
- v0.1.1 20111012 rsz Fixed validation of ulonglong.
- v0.1.2 20111126 rsz Allow flag names start with alphanumeric (previously, flag had to start with alpha).
- v0.1.3 20120108 rsz Created work-around for unique id generation with IDGenerator that avoids retarded c++ translation unit linker errors with single-header static variables. Forced inline on all methods to please retard compiler and avoid multiple def errors.
- v0.1.4 20120629 Enforced MIT license on all files.
- v0.2.0 20121120 Added parseIndex to OptionGroup.
- v0.2.1 20130506 Allow disabling doublespace of OPTIONS usage descriptions.
- v0.2.2 20140504 Jose Santiago added compiler warning fixes.
- Bruce Shankle added a crash fix in description printing.
- */
- #ifndef EZ_OPTION_PARSER_H
- #define EZ_OPTION_PARSER_H
-
- #include <stdlib.h>
- #include <vector>
- #include <list>
- #include <map>
- #include <string>
- #include <iostream>
- #include <fstream>
- #include <algorithm>
- #include <limits>
- #include <sstream>
- #include <cstring>
-
- namespace ez {
- #define DEBUGLINE() printf("%s:%d\n", __FILE__, __LINE__);
-
- /* ################################################################### */
- template<typename T>
- static T fromString(const std::string* s) {
- std::istringstream stream (s->c_str());
- T t;
- stream >> t;
- return t;
- };
- template<typename T>
- static T fromString(const char* s) {
- std::istringstream stream (s);
- T t;
- stream >> t;
- return t;
- };
- /* ################################################################### */
- static inline bool isdigit(const std::string & s, int i=0) {
- int n = s.length();
- for(; i < n; ++i)
- switch(s[i]) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8': case '9': break;
- default: return false;
- }
-
- return true;
- };
- /* ################################################################### */
- static bool isdigit(const std::string * s, int i=0) {
- int n = s->length();
- for(; i < n; ++i)
- switch(s->at(i)) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8': case '9': break;
- default: return false;
- }
-
- return true;
- };
- /* ################################################################### */
- /*
- Compare strings for opts, so short opt flags come before long format flags.
- For example, -d < --dimension < --dmn, and also lower come before upper. The default STL std::string compare doesn't do that.
- */
- static bool CmpOptStringPtr(std::string * s1, std::string * s2) {
- int c1,c2;
- const char *s=s1->c_str();
- for(c1=0; c1 < (long int)s1->size(); ++c1)
- if (isalnum(s[c1])) // locale sensitive.
- break;
-
- s=s2->c_str();
- for(c2=0; c2 < (long int)s2->size(); ++c2)
- if (isalnum(s[c2]))
- break;
-
- // Test which has more symbols before its name.
- if (c1 > c2)
- return false;
- else if (c1 < c2)
- return true;
-
- // Both have same number of symbols, so compare first letter.
- char char1 = s1->at(c1);
- char char2 = s2->at(c2);
- char lo1 = tolower(char1);
- char lo2 = tolower(char2);
-
- if (lo1 != lo2)
- return lo1 < lo2;
-
- // Their case doesn't match, so find which is lower.
- char up1 = isupper(char1);
- char up2 = isupper(char2);
-
- if (up1 && !up2)
- return false;
- else if (!up1 && up2)
- return true;
-
- return (s1->compare(*s2)<0);
- };
- /* ################################################################### */
- /*
- Makes a vector of strings from one string,
- splitting at (and excluding) delimiter "token".
- */
- static void SplitDelim( const std::string& s, const char token, std::vector<std::string*> * result) {
- std::string::const_iterator i = s.begin();
- std::string::const_iterator j = s.begin();
- const std::string::const_iterator e = s.end();
-
- while(i!=e) {
- while(i!=e && *i++!=token);
- std::string *newstr = new std::string(j, i);
- if (newstr->at(newstr->size()-1) == token) newstr->erase(newstr->size()-1);
- result->push_back(newstr);
- j = i;
- }
- };
- /* ################################################################### */
- // Variant that uses deep copies and references instead of pointers (less efficient).
- static void SplitDelim( const std::string& s, const char token, std::vector<std::string> & result) {
- std::string::const_iterator i = s.begin();
- std::string::const_iterator j = s.begin();
- const std::string::const_iterator e = s.end();
-
- while(i!=e) {
- while(i!=e && *i++!=token);
- std::string newstr(j, i);
- if (newstr.at(newstr.size()-1) == token) newstr.erase(newstr.size()-1);
- result.push_back(newstr);
- j = i;
- }
- };
- /* ################################################################### */
- // Variant that uses list instead of vector for efficient insertion, etc.
- static void SplitDelim( const std::string& s, const char token, std::list<std::string*> & result) {
- std::string::const_iterator i = s.begin();
- std::string::const_iterator j = s.begin();
- const std::string::const_iterator e = s.end();
-
- while(i!=e) {
- while(i!=e && *i++!=token);
- std::string *newstr = new std::string(j, i);
- if (newstr->at(newstr->size()-1) == token) newstr->erase(newstr->size()-1);
- result.push_back(newstr);
- j = i;
- }
- };
- /* ################################################################### */
- static void ToU1(std::string ** strings, unsigned char * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (unsigned char)atoi(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToS1(std::string ** strings, char * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (char)atoi(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToU2(std::string ** strings, unsigned short * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (unsigned short)atoi(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToS2(std::string ** strings, short * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (short)atoi(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToS4(std::string ** strings, int * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = atoi(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToU4(std::string ** strings, unsigned int * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (unsigned int)strtoul(strings[i]->c_str(), NULL, 0);
- }
- };
- /* ################################################################### */
- static void ToS8(std::string ** strings, long long * out, int n) {
- for(int i=0; i < n; ++i) {
- std::stringstream ss(strings[i]->c_str());
- ss >> out[i];
- }
- };
- /* ################################################################### */
- static void ToU8(std::string ** strings, unsigned long long * out, int n) {
- for(int i=0; i < n; ++i) {
- std::stringstream ss(strings[i]->c_str());
- ss >> out[i];
- }
- };
- /* ################################################################### */
- static void ToF(std::string ** strings, float * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (float)atof(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void ToD(std::string ** strings, double * out, int n) {
- for(int i=0; i < n; ++i) {
- out[i] = (double)atof(strings[i]->c_str());
- }
- };
- /* ################################################################### */
- static void StringsToInts(std::vector<std::string> & strings, std::vector<int> & out) {
- for(int i=0; i < (long int)strings.size(); ++i) {
- out.push_back(atoi(strings[i].c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToInts(std::vector<std::string*> * strings, std::vector<int> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back(atoi(strings->at(i)->c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToLongs(std::vector<std::string> & strings, std::vector<long> & out) {
- for(int i=0; i < (long int)strings.size(); ++i) {
- out.push_back(atol(strings[i].c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToLongs(std::vector<std::string*> * strings, std::vector<long> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back(atol(strings->at(i)->c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToULongs(std::vector<std::string> & strings, std::vector<unsigned long> & out) {
- for(int i=0; i < (long int)strings.size(); ++i) {
- out.push_back(strtoul(strings[i].c_str(),0,0));
- }
- };
- /* ################################################################### */
- static void StringsToULongs(std::vector<std::string*> * strings, std::vector<unsigned long> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back(strtoul(strings->at(i)->c_str(),0,0));
- }
- };
- /* ################################################################### */
- static void StringsToFloats(std::vector<std::string> & strings, std::vector<float> & out) {
- for(int i=0; i < (long int)strings.size(); ++i) {
- out.push_back(atof(strings[i].c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToFloats(std::vector<std::string*> * strings, std::vector<float> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back(atof(strings->at(i)->c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToDoubles(std::vector<std::string> & strings, std::vector<double> & out) {
- for(int i=0; i < (long int)strings.size(); ++i) {
- out.push_back(atof(strings[i].c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToDoubles(std::vector<std::string*> * strings, std::vector<double> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back(atof(strings->at(i)->c_str()));
- }
- };
- /* ################################################################### */
- static void StringsToStrings(std::vector<std::string*> * strings, std::vector<std::string> * out) {
- for(int i=0; i < (long int)strings->size(); ++i) {
- out->push_back( *strings->at(i) );
- }
- };
- /* ################################################################### */
- static void ToLowerASCII(std::string & s) {
- int n = s.size();
- int i=0;
- char c;
- for(; i < n; ++i) {
- c = s[i];
- if(c<='Z' && c>='A')
- s[i] = c+32;
- }
- }
- /* ################################################################### */
- static char** CommandLineToArgvA(char* CmdLine, int* _argc) {
- char** argv;
- char* _argv;
- unsigned long len;
- unsigned long argc;
- char a;
- unsigned long i, j;
-
- bool in_QM;
- bool in_TEXT;
- bool in_SPACE;
-
- len = strlen(CmdLine);
- i = ((len+2)/2)*sizeof(void*) + sizeof(void*);
-
- argv = (char**)malloc(i + (len+2)*sizeof(char));
-
- _argv = (char*)(((unsigned char*)argv)+i);
-
- argc = 0;
- argv[argc] = _argv;
- in_QM = false;
- in_TEXT = false;
- in_SPACE = true;
- i = 0;
- j = 0;
-
- while( (a = CmdLine[i]) ) {
- if(in_QM) {
- if( (a == '\"') ||
- (a == '\'')) // rsz. Added single quote.
- {
- in_QM = false;
- } else {
- _argv[j] = a;
- j++;
- }
- } else {
- switch(a) {
- case '\"':
- case '\'': // rsz. Added single quote.
- in_QM = true;
- in_TEXT = true;
- if(in_SPACE) {
- argv[argc] = _argv+j;
- argc++;
- }
- in_SPACE = false;
- break;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- if(in_TEXT) {
- _argv[j] = '\0';
- j++;
- }
- in_TEXT = false;
- in_SPACE = true;
- break;
- default:
- in_TEXT = true;
- if(in_SPACE) {
- argv[argc] = _argv+j;
- argc++;
- }
- _argv[j] = a;
- j++;
- in_SPACE = false;
- break;
- }
- }
- i++;
- }
- _argv[j] = '\0';
- argv[argc] = NULL;
-
- (*_argc) = argc;
- return argv;
- };
- /* ################################################################### */
- // Create unique ids with static and still allow single header that avoids multiple definitions linker error.
- class ezOptionParserIDGenerator {
- public:
- static ezOptionParserIDGenerator& instance () { static ezOptionParserIDGenerator Generator; return Generator; }
- short next () { return ++_id; }
- private:
- ezOptionParserIDGenerator() : _id(-1) {}
- short _id;
- };
- /* ################################################################### */
- /* Validate a value by checking:
- - if as string, see if converted value is within datatype's limits,
- - and see if falls within a desired range,
- - or see if within set of given list of values.
-
- If comparing with a range, the values list must contain one or two values. One value is required when comparing with <, <=, >, >=. Use two values when requiring a test such as <x<, <=x<, <x<=, <=x<=.
- A regcomp/regexec based class could be created in the future if a need arises.
- */
- class ezOptionValidator {
- public:
- inline ezOptionValidator(const char* _type, const char* _op=0, const char* list=0, bool _insensitive=false);
- inline ezOptionValidator(char _type);
- inline ezOptionValidator(char _type, char _op, const char* list, int _size);
- inline ezOptionValidator(char _type, char _op, const unsigned char* list, int _size);
- inline ezOptionValidator(char _type, char _op, const short* list, int _size);
- inline ezOptionValidator(char _type, char _op, const unsigned short* list, int _size);
- inline ezOptionValidator(char _type, char _op, const int* list, int _size);
- inline ezOptionValidator(char _type, char _op, const unsigned int* list, int _size);
- inline ezOptionValidator(char _type, char _op, const long long* list, int _size);
- inline ezOptionValidator(char _type, char _op, const unsigned long long* list, int _size=0);
- inline ezOptionValidator(char _type, char _op, const float* list, int _size);
- inline ezOptionValidator(char _type, char _op, const double* list, int _size);
- inline ezOptionValidator(char _type, char _op, const char** list, int _size, bool _insensitive);
- inline ~ezOptionValidator();
-
- inline bool isValid(const std::string * value);
- inline void print();
- inline void reset();
-
- /* If value must be in custom range, use these comparison modes. */
- enum OP { NOOP=0,
- LT, /* value < list[0] */
- LE, /* value <= list[0] */
- GT, /* value > list[0] */
- GE, /* value >= list[0] */
- GTLT, /* list[0] < value < list[1] */
- GELT, /* list[0] <= value < list[1] */
- GELE, /* list[0] <= value <= list[1] */
- GTLE, /* list[0] < value <= list[1] */
- IN /* if value is in list */
- };
-
- enum TYPE { NOTYPE=0, S1, U1, S2, U2, S4, U4, S8, U8, F, D, T };
- enum TYPE2 { NOTYPE2=0, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT, DOUBLE, TEXT };
-
- union {
- unsigned char *u1;
- char *s1;
- unsigned short *u2;
- short *s2;
- unsigned int *u4;
- int *s4;
- unsigned long long *u8;
- long long *s8;
- float *f;
- double *d;
- std::string** t;
- };
-
- char op;
- bool quiet;
- short id;
- char type;
- int size;
- bool insensitive;
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::~ezOptionValidator() {
- reset();
- };
- /* ------------------------------------------------------------------- */
- void ezOptionValidator::reset() {
- #define CLEAR(TYPE,P) case TYPE: if (P) delete [] P; P = 0; break;
- switch(type) {
- CLEAR(S1,s1);
- CLEAR(U1,u1);
- CLEAR(S2,s2);
- CLEAR(U2,u2);
- CLEAR(S4,s4);
- CLEAR(U4,u4);
- CLEAR(S8,s8);
- CLEAR(U8,u8);
- CLEAR(F,f);
- CLEAR(D,d);
- case T:
- for(int i=0; i < size; ++i)
- delete t[i];
-
- delete [] t;
- t = 0;
- break;
- default: break;
- }
-
- size = 0;
- op = NOOP;
- type = NOTYPE;
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type) : s1(0), op(0), quiet(0), type(_type), size(0), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const char* list, int _size) : s1(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- s1 = new char[size];
- memcpy(s1, list, size);
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const unsigned char* list, int _size) : u1(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- u1 = new unsigned char[size];
- memcpy(u1, list, size);
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const short* list, int _size) : s2(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- s2 = new short[size];
- memcpy(s2, list, size*sizeof(short));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const unsigned short* list, int _size) : u2(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- u2 = new unsigned short[size];
- memcpy(u2, list, size*sizeof(unsigned short));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const int* list, int _size) : s4(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- s4 = new int[size];
- memcpy(s4, list, size*sizeof(int));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const unsigned int* list, int _size) : u4(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- u4 = new unsigned int[size];
- memcpy(u4, list, size*sizeof(unsigned int));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const long long* list, int _size) : s8(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- s8 = new long long[size];
- memcpy(s8, list, size*sizeof(long long));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const unsigned long long* list, int _size) : u8(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- u8 = new unsigned long long[size];
- memcpy(u8, list, size*sizeof(unsigned long long));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const float* list, int _size) : f(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- f = new float[size];
- memcpy(f, list, size*sizeof(float));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const double* list, int _size) : d(0), op(_op), quiet(0), type(_type), size(_size), insensitive(0) {
- id = ezOptionParserIDGenerator::instance().next();
- d = new double[size];
- memcpy(d, list, size*sizeof(double));
- };
- /* ------------------------------------------------------------------- */
- ezOptionValidator::ezOptionValidator(char _type, char _op, const char** list, int _size, bool _insensitive) : t(0), op(_op), quiet(0), type(_type), size(_size), insensitive(_insensitive) {
- id = ezOptionParserIDGenerator::instance().next();
- t = new std::string*[size];
- int i=0;
-
- for(; i < size; ++i) {
- t[i] = new std::string(list[i]);
- }
- };
- /* ------------------------------------------------------------------- */
- /* Less efficient but convenient ctor that parses strings to setup validator.
- _type: s1, u1, s2, u2, ..., f, d, t
- _op: lt, gt, ..., in
- _list: comma-delimited string
- */
- ezOptionValidator::ezOptionValidator(const char* _type, const char* _op, const char* _list, bool _insensitive) : t(0), quiet(0), type(0), size(0), insensitive(_insensitive) {
- id = ezOptionParserIDGenerator::instance().next();
-
- switch(_type[0]) {
- case 'u':
- switch(_type[1]) {
- case '1': type = U1; break;
- case '2': type = U2; break;
- case '4': type = U4; break;
- case '8': type = U8; break;
- default: break;
- }
- break;
- case 's':
- switch(_type[1]) {
- case '1': type = S1;
- break;
- case '2': type = S2; break;
- case '4': type = S4; break;
- case '8': type = S8; break;
- default: break;
- }
- break;
- case 'f': type = F; break;
- case 'd': type = D; break;
- case 't': type = T; break;
- default:
- if (!quiet)
- std::cerr << "ERROR: Unknown validator datatype \"" << _type << "\".\n";
- break;
- }
-
- int nop = 0;
- if (_op != 0)
- nop = strlen(_op);
-
- switch(nop) {
- case 0: op = NOOP; break;
- case 2:
- switch(_op[0]) {
- case 'g':
- switch(_op[1]) {
- case 'e': op = GE; break;
- default: op = GT; break;
- }
- break;
- case 'i': op = IN;
- break;
- default:
- switch(_op[1]) {
- case 'e': op = LE; break;
- default: op = LT; break;
- }
- break;
- }
- break;
- case 4:
- switch(_op[1]) {
- case 'e':
- switch(_op[3]) {
- case 'e': op = GELE; break;
- default: op = GELT; break;
- }
- break;
- default:
- switch(_op[3]) {
- case 'e': op = GTLE; break;
- default: op = GTLT; break;
- }
- break;
- }
- break;
- default:
- if (!quiet)
- std::cerr << "ERROR: Unknown validator operation \"" << _op << "\".\n";
- break;
- }
-
- if (_list == 0) return;
- // Create list of strings and then cast to native datatypes.
- std::string unsplit(_list);
- std::list<std::string*> split;
- std::list<std::string*>::iterator it;
- SplitDelim(unsplit, ',', split);
- size = split.size();
- std::string **strings = new std::string*[size];
-
- int i = 0;
- for(it = split.begin(); it != split.end(); ++it)
- strings[i++] = *it;
-
- if (insensitive)
- for(i=0; i < size; ++i)
- ToLowerASCII(*strings[i]);
-
- #define FreeStrings() { \
- for(i=0; i < size; ++i)\
- delete strings[i];\
- delete [] strings;\
- }
-
- #define ToArray(T,P,Y) case T: P = new Y[size]; To##T(strings, P, size); FreeStrings(); break;
- switch(type) {
- ToArray(S1,s1,char);
- ToArray(U1,u1,unsigned char);
- ToArray(S2,s2,short);
- ToArray(U2,u2,unsigned short);
- ToArray(S4,s4,int);
- ToArray(U4,u4,unsigned int);
- ToArray(S8,s8,long long);
- ToArray(U8,u8,unsigned long long);
- ToArray(F,f,float);
- ToArray(D,d,double);
- case T: t = strings; break; /* Don't erase strings array. */
- default: break;
- }
- };
- /* ------------------------------------------------------------------- */
- void ezOptionValidator::print() {
- printf("id=%d, op=%d, type=%d, size=%d, insensitive=%d\n", id, op, type, size, insensitive);
- };
- /* ------------------------------------------------------------------- */
- bool ezOptionValidator::isValid(const std::string * valueAsString) {
- if (valueAsString == 0) return false;
-
- #define CHECKRANGE(E,T) {\
- std::stringstream ss(valueAsString->c_str()); \
- long long E##value; \
- ss >> E##value; \
- long long E##min = static_cast<long long>(std::numeric_limits<T>::min()); \
- if (E##value < E##min) { \
- if (!quiet) \
- std::cerr << "ERROR: Invalid value " << E##value << " is less than datatype min " << E##min << ".\n"; \
- return false; \
- } \
- \
- long long E##max = static_cast<long long>(std::numeric_limits<T>::max()); \
- if (E##value > E##max) { \
- if (!quiet) \
- std::cerr << "ERROR: Invalid value " << E##value << " is greater than datatype max " << E##max << ".\n"; \
- return false; \
- } \
- }
- // Check if within datatype limits.
- if (type != T) {
- switch(type) {
- case S1: CHECKRANGE(S1,char); break;
- case U1: CHECKRANGE(U1,unsigned char); break;
- case S2: CHECKRANGE(S2,short); break;
- case U2: CHECKRANGE(U2,unsigned short); break;
- case S4: CHECKRANGE(S4,int); break;
- case U4: CHECKRANGE(U4,unsigned int); break;
- case S8: {
- if ( (valueAsString->at(0) == '-') &&
- isdigit(valueAsString,1) &&
- (valueAsString->size() > 19) &&
- (valueAsString->compare(1, 19, "9223372036854775808") > 0) ) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << *valueAsString << " is less than datatype min -9223372036854775808.\n";
- return false;
- }
-
- if (isdigit(valueAsString) &&
- (valueAsString->size() > 18) &&
- valueAsString->compare("9223372036854775807") > 0) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << *valueAsString << " is greater than datatype max 9223372036854775807.\n";
- return false;
- }
- } break;
- case U8: {
- if (valueAsString->compare("0") < 0) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << *valueAsString << " is less than datatype min 0.\n";
- return false;
- }
-
- if (isdigit(valueAsString) &&
- (valueAsString->size() > 19) &&
- valueAsString->compare("18446744073709551615") > 0) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << *valueAsString << " is greater than datatype max 18446744073709551615.\n";
- return false;
- }
- } break;
- case F: {
- double dmax = static_cast<double>(std::numeric_limits<float>::max());
- double dvalue = atof(valueAsString->c_str());
- double dmin = -dmax;
- if (dvalue < dmin) {
- if (!quiet) {
- fprintf(stderr, "ERROR: Invalid value %g is less than datatype min %g.\n", dvalue, dmin);
- }
- return false;
- }
-
- if (dvalue > dmax) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << dvalue << " is greater than datatype max " << dmax << ".\n";
- return false;
- }
- } break;
- case D: {
- long double ldmax = static_cast<long double>(std::numeric_limits<double>::max());
- std::stringstream ss(valueAsString->c_str());
- long double ldvalue;
- ss >> ldvalue;
- long double ldmin = -ldmax;
-
- if (ldvalue < ldmin) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << ldvalue << " is less than datatype min " << ldmin << ".\n";
- return false;
- }
-
- if (ldvalue > ldmax) {
- if (!quiet)
- std::cerr << "ERROR: Invalid value " << ldvalue << " is greater than datatype max " << ldmax << ".\n";
- return false;
- }
- } break;
- case NOTYPE: default: break;
- }
- } else {
- if (op == IN) {
- int i=0;
- if (insensitive) {
- std::string valueAsStringLower(*valueAsString);
- ToLowerASCII(valueAsStringLower);
- for(; i < size; ++i) {
- if (valueAsStringLower.compare(t[i]->c_str()) == 0)
- return true;
- }
- } else {
- for(; i < size; ++i) {
- if (valueAsString->compare(t[i]->c_str()) == 0)
- return true;
- }
- }
- return false;
- }
- }
-
- // Only check datatype limits, and return;
- if (op == NOOP) return true;
-
- #define VALIDATE(T, U, LIST) { \
- /* Value string converted to true native type. */ \
- std::stringstream ss(valueAsString->c_str());\
- U v;\
- ss >> v;\
- /* Check if within list. */ \
- if (op == IN) { \
- T * last = LIST + size;\
- return (last != std::find(LIST, last, v)); \
- } \
- \
- /* Check if within user's custom range. */ \
- T v0, v1; \
- if (size > 0) { \
- v0 = LIST[0]; \
- } \
- \
- if (size > 1) { \
- v1 = LIST[1]; \
- } \
- \
- switch (op) {\
- case LT:\
- if (size > 0) {\
- return v < v0;\
- } else {\
- std::cerr << "ERROR: No value given to validate if " << v << " < X.\n";\
- return false;\
- }\
- break;\
- case LE:\
- if (size > 0) {\
- return v <= v0;\
- } else {\
- std::cerr << "ERROR: No value given to validate if " << v << " <= X.\n";\
- return false;\
- }\
- break;\
- case GT:\
- if (size > 0) {\
- return v > v0;\
- } else {\
- std::cerr << "ERROR: No value given to validate if " << v << " > X.\n";\
- return false;\
- }\
- break;\
- case GE:\
- if (size > 0) {\
- return v >= v0;\
- } else {\
- std::cerr << "ERROR: No value given to validate if " << v << " >= X.\n";\
- return false;\
- }\
- break;\
- case GTLT:\
- if (size > 1) {\
- return (v0 < v) && (v < v1);\
- } else {\
- std::cerr << "ERROR: Missing values to validate if X1 < " << v << " < X2.\n";\
- return false;\
- }\
- break;\
- case GELT:\
- if (size > 1) {\
- return (v0 <= v) && (v < v1);\
- } else {\
- std::cerr << "ERROR: Missing values to validate if X1 <= " << v << " < X2.\n";\
- return false;\
- }\
- break;\
- case GELE:\
- if (size > 1) {\
- return (v0 <= v) && (v <= v1);\
- } else {\
- std::cerr << "ERROR: Missing values to validate if X1 <= " << v << " <= X2.\n";\
- return false;\
- }\
- break;\
- case GTLE:\
- if (size > 1) {\
- return (v0 < v) && (v <= v1);\
- } else {\
- std::cerr << "ERROR: Missing values to validate if X1 < " << v << " <= X2.\n";\
- return false;\
- }\
- break;\
- case NOOP: case IN: default: break;\
- } \
- }
-
- switch(type) {
- case U1: VALIDATE(unsigned char, int, u1); break;
- case S1: VALIDATE(char, int, s1); break;
- case U2: VALIDATE(unsigned short, int, u2); break;
- case S2: VALIDATE(short, int, s2); break;
- case U4: VALIDATE(unsigned int, unsigned int, u4); break;
- case S4: VALIDATE(int, int, s4); break;
- case U8: VALIDATE(unsigned long long, unsigned long long, u8); break;
- case S8: VALIDATE(long long, long long, s8); break;
- case F: VALIDATE(float, float, f); break;
- case D: VALIDATE(double, double, d); break;
- default: break;
- }
-
- return true;
- };
- /* ################################################################### */
- class OptionGroup {
- public:
- OptionGroup() : delim(0), expectArgs(0), isRequired(false), isSet(false) { }
-
- ~OptionGroup() {
- int i;
- for(i=0; i < (long int)flags.size(); ++i)
- delete flags[i];
-
- flags.clear();
- parseIndex.clear();
- clearArgs();
- };
-
- inline void clearArgs();
- inline void getInt(int&);
- inline void getLong(long&);
- inline void getLongLong(long long&);
- inline void getULong(unsigned long&);
- inline void getULongLong(unsigned long long&);
- inline void getFloat(float&);
- inline void getDouble(double&);
- inline void getString(std::string&);
- inline void getInts(std::vector<int>&);
- inline void getLongs(std::vector<long>&);
- inline void getULongs(std::vector<unsigned long>&);
- inline void getFloats(std::vector<float>&);
- inline void getDoubles(std::vector<double>&);
- inline void getStrings(std::vector<std::string>&);
- inline void getMultiInts(std::vector< std::vector<int> >&);
- inline void getMultiLongs(std::vector< std::vector<long> >&);
- inline void getMultiULongs(std::vector< std::vector<unsigned long> >&);
- inline void getMultiFloats(std::vector< std::vector<float> >&);
- inline void getMultiDoubles(std::vector< std::vector<double> >&);
- inline void getMultiStrings(std::vector< std::vector<std::string> >&);
-
- // defaults value regardless of being set by user.
- std::string defaults;
- // If expects arguments, this will delimit arg list.
- char delim;
- // If not 0, then number of delimited args. -1 for arbitrary number.
- int expectArgs;
- // Descriptive help message shown in usage instructions for option.
- std::string help;
- // 0 or 1.
- bool isRequired;
- // A list of flags that denote this option, i.e. -d, --dimension.
- std::vector< std::string* > flags;
- // If was set (or found).
- bool isSet;
- // Lists of arguments, per flag instance, after splitting by delimiter.
- std::vector< std::vector< std::string* > * > args;
- // Index where each group was parsed from input stream to track order.
- std::vector<int> parseIndex;
- };
- /* ################################################################### */
- void OptionGroup::clearArgs() {
- int i,j;
- for(i=0; i < (long int)args.size(); ++i) {
- for(j=0; j < (long int)args[i]->size(); ++j)
- delete args[i]->at(j);
-
- delete args[i];
- }
-
- args.clear();
- isSet = false;
- };
- /* ################################################################### */
- void OptionGroup::getInt(int & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0;
- else
- out = atoi(defaults.c_str());
- } else {
- if (args.empty() || args[0]->empty())
- out = 0;
- else {
- out = atoi(args[0]->at(0)->c_str());
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getLong(long & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0;
- else
- out = atoi(defaults.c_str());
- } else {
- if (args.empty() || args[0]->empty())
- out = 0;
- else {
- out = atol(args[0]->at(0)->c_str());
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getLongLong(long long & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0;
- else {
- std::stringstream ss(defaults.c_str());
- ss >> out;
- }
- } else {
- if (args.empty() || args[0]->empty())
- out = 0;
- else {
- std::stringstream ss(args[0]->at(0)->c_str());
- ss >> out;
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getULong(unsigned long & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0;
- else
- out = atoi(defaults.c_str());
- } else {
- if (args.empty() || args[0]->empty())
- out = 0;
- else {
- out = strtoul(args[0]->at(0)->c_str(),0,0);
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getULongLong(unsigned long long & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0;
- else {
- std::stringstream ss(defaults.c_str());
- ss >> out;
- }
- } else {
- if (args.empty() || args[0]->empty())
- out = 0;
- else {
- std::stringstream ss(args[0]->at(0)->c_str());
- ss >> out;
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getFloat(float & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0.0;
- else
- out = (float)atof(defaults.c_str());
- } else {
- if (args.empty() || args[0]->empty())
- out = 0.0;
- else {
- out = (float)atof(args[0]->at(0)->c_str());
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getDouble(double & out) {
- if (!isSet) {
- if (defaults.empty())
- out = 0.0;
- else
- out = atof(defaults.c_str());
- } else {
- if (args.empty() || args[0]->empty())
- out = 0.0;
- else {
- out = atof(args[0]->at(0)->c_str());
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getString(std::string & out) {
- if (!isSet) {
- out = defaults;
- } else {
- if (args.empty() || args[0]->empty())
- out = "";
- else {
- out = *args[0]->at(0);
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getInts(std::vector<int> & out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- StringsToInts(strings, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToInts(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getLongs(std::vector<long> & out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- StringsToLongs(strings, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToLongs(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getULongs(std::vector<unsigned long> & out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- StringsToULongs(strings, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToULongs(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getFloats(std::vector<float> & out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- StringsToFloats(strings, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToFloats(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getDoubles(std::vector<double> & out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- StringsToDoubles(strings, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToDoubles(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getStrings(std::vector<std::string>& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- SplitDelim(defaults, delim, out);
- }
- } else {
- if (!(args.empty() || args[0]->empty()))
- StringsToStrings(args[0], &out);
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiInts(std::vector< std::vector<int> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- StringsToInts(strings, out[0]);
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
- for(int i=0; i < n; ++i) {
- StringsToInts(args[i], &out[i]);
- }
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiLongs(std::vector< std::vector<long> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- StringsToLongs(strings, out[0]);
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
- for(int i=0; i < n; ++i) {
- StringsToLongs(args[i], &out[i]);
- }
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiULongs(std::vector< std::vector<unsigned long> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- StringsToULongs(strings, out[0]);
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
- for(int i=0; i < n; ++i) {
- StringsToULongs(args[i], &out[i]);
- }
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiFloats(std::vector< std::vector<float> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- StringsToFloats(strings, out[0]);
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
- for(int i=0; i < n; ++i) {
- StringsToFloats(args[i], &out[i]);
- }
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiDoubles(std::vector< std::vector<double> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- StringsToDoubles(strings, out[0]);
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
- for(int i=0; i < n; ++i) {
- StringsToDoubles(args[i], &out[i]);
- }
- }
- }
- };
- /* ################################################################### */
- void OptionGroup::getMultiStrings(std::vector< std::vector<std::string> >& out) {
- if (!isSet) {
- if (!defaults.empty()) {
- std::vector< std::string > strings;
- SplitDelim(defaults, delim, strings);
- if (out.size() < 1) out.resize(1);
- out[0] = strings;
- }
- } else {
- if (!args.empty()) {
- int n = args.size();
- if ((long int)out.size() < n) out.resize(n);
-
- for(int i=0; i < n; ++i) {
- for(int j=0; j < (long int)args[i]->size(); ++j)
- out[i].push_back( *args[i]->at(j) );
- }
- }
- }
- };
- /* ################################################################### */
- typedef std::map< int, ezOptionValidator* > ValidatorMap;
-
- class ezOptionParser {
- public:
- // How to layout usage descriptions with the option flags.
- enum Layout { ALIGN, INTERLEAVE, STAGGER };
-
- inline ~ezOptionParser();
-
- inline void add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, ezOptionValidator* validator=0);
- inline void add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, ezOptionValidator* validator=0);
- inline void add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, const char * flag3, ezOptionValidator* validator=0);
- inline void add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, const char * flag3, const char * flag4, ezOptionValidator* validator=0);
- inline bool exportFile(const char * filename, bool all=false);
- inline OptionGroup * get(const char * name);
- inline void getUsage(std::string & usage, int width=80, Layout layout=ALIGN);
- inline void getUsageDescriptions(std::string & usage, int width=80, Layout layout=STAGGER);
- inline bool gotExpected(std::vector<std::string> & badOptions);
- inline bool gotRequired(std::vector<std::string> & badOptions);
- inline bool gotValid(std::vector<std::string> & badOptions, std::vector<std::string> & badArgs);
- inline bool importFile(const char * filename, char comment='#');
- inline int isSet(const char * name);
- inline int isSet(std::string & name);
- inline void parse(int argc, const char * argv[]);
- inline void prettyPrint(std::string & out);
- inline void reset();
- inline void resetArgs();
-
- // Insert extra empty line betwee each option's usage description.
- char doublespace;
- // General description in human language on what the user's tool does.
- // It's the first section to get printed in the full usage message.
- std::string overview;
- // A synopsis of command and options usage to show expected order of input arguments.
- // It's the second section to get printed in the full usage message.
- std::string syntax;
- // Example (third) section in usage message.
- std::string example;
- // Final section printed in usage message. For contact, copyrights, version info.
- std::string footer;
- // Map from an option to an Id of its parent group.
- std::map< std::string, int > optionGroupIds;
- // Unordered collection of the option groups.
- std::vector< OptionGroup* > groups;
- // Store unexpected args in input.
- std::vector< std::string* > unknownArgs;
- // List of args that occur left-most before first option flag.
- std::vector< std::string* > firstArgs;
- // List of args that occur after last right-most option flag and its args.
- std::vector< std::string* > lastArgs;
- // List of validators.
- ValidatorMap validators;
- // Maps group id to a validator index into vector of validators. Validator index is -1 if there is no validator for group.
- std::map< int, int > groupValidators;
- };
- /* ################################################################### */
- ezOptionParser::~ezOptionParser() {
- reset();
- }
- /* ################################################################### */
- void ezOptionParser::reset() {
- this->doublespace = 1;
-
- int i;
- for(i=0; i < (long int)groups.size(); ++i)
- delete groups[i];
- groups.clear();
-
- for(i=0; i < (long int)unknownArgs.size(); ++i)
- delete unknownArgs[i];
- unknownArgs.clear();
-
- for(i=0; i < (long int)firstArgs.size(); ++i)
- delete firstArgs[i];
- firstArgs.clear();
-
- for(i=0; i < (long int)lastArgs.size(); ++i)
- delete lastArgs[i];
- lastArgs.clear();
-
- ValidatorMap::iterator it;
- for(it = validators.begin(); it != validators.end(); ++it)
- delete it->second;
-
- validators.clear();
- optionGroupIds.clear();
- groupValidators.clear();
- };
- /* ################################################################### */
- void ezOptionParser::resetArgs() {
- int i;
- for(i=0; i < (long int)groups.size(); ++i)
- groups[i]->clearArgs();
-
- for(i=0; i < (long int)unknownArgs.size(); ++i)
- delete unknownArgs[i];
- unknownArgs.clear();
-
- for(i=0; i < (long int)firstArgs.size(); ++i)
- delete firstArgs[i];
- firstArgs.clear();
-
- for(i=0; i < (long int)lastArgs.size(); ++i)
- delete lastArgs[i];
- lastArgs.clear();
- };
- /* ################################################################### */
- void ezOptionParser::add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, ezOptionValidator* validator) {
- int id = this->groups.size();
- OptionGroup * g = new OptionGroup;
- g->defaults = defaults;
- g->isRequired = required;
- g->expectArgs = expectArgs;
- g->delim = delim;
- g->isSet = 0;
- g->help = help;
- std::string *f1 = new std::string(flag1);
- g->flags.push_back( f1 );
- this->optionGroupIds[flag1] = id;
- this->groups.push_back(g);
-
- if (validator) {
- int vid = validator->id;
- validators[vid] = validator;
- groupValidators[id] = vid;
- } else {
- groupValidators[id] = -1;
- }
- };
- /* ################################################################### */
- void ezOptionParser::add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, ezOptionValidator* validator) {
- int id = this->groups.size();
- OptionGroup * g = new OptionGroup;
- g->defaults = defaults;
- g->isRequired = required;
- g->expectArgs = expectArgs;
- g->delim = delim;
- g->isSet = 0;
- g->help = help;
- std::string *f1 = new std::string(flag1);
- g->flags.push_back( f1 );
- std::string *f2 = new std::string(flag2);
- g->flags.push_back( f2 );
- this->optionGroupIds[flag1] = id;
- this->optionGroupIds[flag2] = id;
-
- this->groups.push_back(g);
-
- if (validator) {
- int vid = validator->id;
- validators[vid] = validator;
- groupValidators[id] = vid;
- } else {
- groupValidators[id] = -1;
- }
- };
- /* ################################################################### */
- void ezOptionParser::add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, const char * flag3, ezOptionValidator* validator) {
- int id = this->groups.size();
- OptionGroup * g = new OptionGroup;
- g->defaults = defaults;
- g->isRequired = required;
- g->expectArgs = expectArgs;
- g->delim = delim;
- g->isSet = 0;
- g->help = help;
- std::string *f1 = new std::string(flag1);
- g->flags.push_back( f1 );
- std::string *f2 = new std::string(flag2);
- g->flags.push_back( f2 );
- std::string *f3 = new std::string(flag3);
- g->flags.push_back( f3 );
- this->optionGroupIds[flag1] = id;
- this->optionGroupIds[flag2] = id;
- this->optionGroupIds[flag3] = id;
-
- this->groups.push_back(g);
-
- if (validator) {
- int vid = validator->id;
- validators[vid] = validator;
- groupValidators[id] = vid;
- } else {
- groupValidators[id] = -1;
- }
- };
- /* ################################################################### */
- void ezOptionParser::add(const char * defaults, bool required, int expectArgs, char delim, const char * help, const char * flag1, const char * flag2, const char * flag3, const char * flag4, ezOptionValidator* validator) {
- int id = this->groups.size();
- OptionGroup * g = new OptionGroup;
- g->defaults = defaults;
- g->isRequired = required;
- g->expectArgs = expectArgs;
- g->delim = delim;
- g->isSet = 0;
- g->help = help;
- std::string *f1 = new std::string(flag1);
- g->flags.push_back( f1 );
- std::string *f2 = new std::string(flag2);
- g->flags.push_back( f2 );
- std::string *f3 = new std::string(flag3);
- g->flags.push_back( f3 );
- std::string *f4 = new std::string(flag4);
- g->flags.push_back( f4 );
- this->optionGroupIds[flag1] = id;
- this->optionGroupIds[flag2] = id;
- this->optionGroupIds[flag3] = id;
- this->optionGroupIds[flag4] = id;
-
- this->groups.push_back(g);
-
- if (validator) {
- int vid = validator->id;
- validators[vid] = validator;
- groupValidators[id] = vid;
- } else {
- groupValidators[id] = -1;
- }
- };
- /* ################################################################### */
- bool ezOptionParser::exportFile(const char * filename, bool all) {
- int i;
- std::string out;
- bool quote;
-
- // Export the first args, except the program name, so start from 1.
- for(i=1; i < (long int)firstArgs.size(); ++i) {
- quote = ((firstArgs[i]->find_first_of(" \t") != std::string::npos) && (firstArgs[i]->find_first_of("\'\"") == std::string::npos));
-
- if (quote)
- out.append("\"");
-
- out.append(*firstArgs[i]);
- if (quote)
- out.append("\"");
-
- out.append(" ");
- }
-
- if (firstArgs.size() > 1)
- out.append("\n");
-
- std::vector<std::string* > stringPtrs(groups.size());
- int m;
- int n = groups.size();
- for(i=0; i < n; ++i) {
- stringPtrs[i] = groups[i]->flags[0];
- }
-
- OptionGroup *g;
- // Sort first flag of each group with other groups.
- std::sort(stringPtrs.begin(), stringPtrs.end(), CmpOptStringPtr);
- for(i=0; i < n; ++i) {
- g = get(stringPtrs[i]->c_str());
- if (g->isSet || all) {
- if (!g->isSet || g->args.empty()) {
- if (!g->defaults.empty()) {
- out.append(*stringPtrs[i]);
- out.append(" ");
- quote = ((g->defaults.find_first_of(" \t") != std::string::npos) && (g->defaults.find_first_of("\'\"") == std::string::npos));
- if (quote)
- out.append("\"");
-
- out.append(g->defaults);
- if (quote)
- out.append("\"");
-
- out.append("\n");
- }
- } else {
- int n = g->args.size();
- for(int j=0; j < n; ++j) {
- out.append(*stringPtrs[i]);
- out.append(" ");
- m = g->args[j]->size();
-
- for(int k=0; k < m; ++k) {
- quote = ( (*g->args[j]->at(k)).find_first_of(" \t") != std::string::npos );
- if (quote)
- out.append("\"");
-
- out.append(*g->args[j]->at(k));
- if (quote)
- out.append("\"");
-
- if ((g->delim) && ((k+1) != m))
- out.append(1,g->delim);
- }
- out.append("\n");
- }
- }
- }
- }
-
- // Export the last args.
- for(i=0; i < (long int)lastArgs.size(); ++i) {
- quote = ( lastArgs[i]->find_first_of(" \t") != std::string::npos );
- if (quote)
- out.append("\"");
-
- out.append(*lastArgs[i]);
- if (quote)
- out.append("\"");
-
- out.append(" ");
- }
-
- std::ofstream file(filename);
- if (!file.is_open())
- return false;
-
- file << out;
- file.close();
-
- return true;
- };
- /* ################################################################### */
- // Does not overwrite current options.
- // Returns true if file was read successfully.
- // So if this is used before parsing CLI, then option values will reflect
- // this file, but if used after parsing CLI, then values will contain
- // both CLI values and file's values.
- //
- // Comment lines are allowed if prefixed with #.
- // Strings should be quoted as usual.
- bool ezOptionParser::importFile(const char * filename, char comment) {
- std::ifstream file (filename, std::ios::in | std::ios::ate);
- if (!file.is_open())
- return false;
-
- // Read entire file contents.
- std::ifstream::pos_type size = file.tellg();
- char * memblock = new char[(int)size+1]; // Add one for end of string.
- file.seekg (0, std::ios::beg);
- file.read (memblock, size);
- memblock[size] = '\0';
- file.close();
-
- // Find comment lines.
- std::list<std::string*> lines;
- std::string memblockstring(memblock);
- delete[] memblock;
- SplitDelim(memblockstring, '\n', lines);
- int i,j,n;
- std::list<std::string*>::iterator iter;
- std::vector<int> sq, dq; // Single and double quote indices.
- std::vector<int>::iterator lo; // For searching quote indices.
- size_t pos;
- const char *str;
- std::string *line;
- // Find all single and double quotes to correctly handle comment tokens.
- for(iter=lines.begin(); iter != lines.end(); ++iter) {
- line = *iter;
- str = line->c_str();
- n = line->size();
- sq.clear();
- dq.clear();
- if (n) {
- // If first char is comment, then erase line and continue.
- pos = line->find_first_not_of(" \t\r");
- if ((pos==std::string::npos) || (line->at(pos)==comment)) {
- line->erase();
- continue;
- } else {
- // Erase whitespace prefix.
- line->erase(0,pos);
- n = line->size();
- }
-
- if (line->at(0)=='"')
- dq.push_back(0);
-
- if (line->at(0)=='\'')
- sq.push_back(0);
- } else { // Empty line.
- continue;
- }
-
- for(i=1; i < n; ++i) {
- if ( (str[i]=='"') && (str[i-1]!='\\') )
- dq.push_back(i);
- else if ( (str[i]=='\'') && (str[i-1]!='\\') )
- sq.push_back(i);
- }
- // Scan for comments, and when found, check bounds of quotes.
- // Start with second char because already checked first char.
- for(i=1; i < n; ++i) {
- if ( (line->at(i)==comment) && (line->at(i-1)!='\\') ) {
- // If within open/close quote pair, then not real comment.
- if (sq.size()) {
- lo = std::lower_bound(sq.begin(), sq.end(), i);
- // All start of strings will be even indices, closing quotes is odd indices.
- j = (int)(lo-sq.begin());
- if ( (j % 2) == 0) { // Even implies comment char not in quote pair.
- // Erase from comment char to end of line.
- line->erase(i);
- break;
- }
- } else if (dq.size()) {
- // Repeat tests for double quotes.
- lo = std::lower_bound(dq.begin(), dq.end(), i);
- j = (int)(lo-dq.begin());
- if ( (j % 2) == 0) {
- line->erase(i);
- break;
- }
- } else {
- // Not in quotes.
- line->erase(i);
- break;
- }
- }
- }
- }
-
- std::string cmd;
- // Convert list to string without newlines to simulate commandline.
- for(iter=lines.begin(); iter != lines.end(); ++iter) {
- if (! (*iter)->empty()) {
- cmd.append(**iter);
- cmd.append(" ");
- }
- }
-
- // Now parse as if from command line.
- int argc=0;
- char** argv = CommandLineToArgvA((char*)cmd.c_str(), &argc);
-
- // Parse.
- parse(argc, (const char**)argv);
- if (argv) free(argv);
- for(iter=lines.begin(); iter != lines.end(); ++iter)
- delete *iter;
-
- return true;
- };
- /* ################################################################### */
- int ezOptionParser::isSet(const char * name) {
- std::string sname(name);
-
- if (this->optionGroupIds.count(sname)) {
- return this->groups[this->optionGroupIds[sname]]->isSet;
- }
-
- return 0;
- };
- /* ################################################################### */
- int ezOptionParser::isSet(std::string & name) {
- if (this->optionGroupIds.count(name)) {
- return this->groups[this->optionGroupIds[name]]->isSet;
- }
-
- return 0;
- };
- /* ################################################################### */
- OptionGroup * ezOptionParser::get(const char * name) {
- if (optionGroupIds.count(name)) {
- return groups[optionGroupIds[name]];
- }
-
- return 0;
- };
- /* ################################################################### */
- void ezOptionParser::getUsage(std::string & usage, int width, Layout layout) {
-
- usage.append(overview);
- usage.append("\n\n");
- usage.append("USAGE: ");
- usage.append(syntax);
- usage.append("\n\nOPTIONS:\n\n");
- getUsageDescriptions(usage, width, layout);
-
- if (!example.empty()) {
- usage.append("EXAMPLES:\n\n");
- usage.append(example);
- }
-
- if (!footer.empty()) {
- usage.append(footer);
- }
- };
- /* ################################################################### */
- // Creates 2 column formatted help descriptions for each option flag.
- void ezOptionParser::getUsageDescriptions(std::string & usage, int width, Layout layout) {
- // Sort each flag list amongst each group.
- int i;
- // Store index of flag groups before sort for easy lookup later.
- std::map<std::string*, int> stringPtrToIndexMap;
- std::vector<std::string* > stringPtrs(groups.size());
-
- for(i=0; i < (long int)groups.size(); ++i) {
- std::sort(groups[i]->flags.begin(), groups[i]->flags.end(), CmpOptStringPtr);
- stringPtrToIndexMap[groups[i]->flags[0]] = i;
- stringPtrs[i] = groups[i]->flags[0];
- }
-
- size_t j, k;
- std::string opts;
- std::vector<std::string> sortedOpts;
- // Sort first flag of each group with other groups.
- std::sort(stringPtrs.begin(), stringPtrs.end(), CmpOptStringPtr);
- for(i=0; i < (long int)groups.size(); ++i) {
- //printf("DEBUG:%d: %d %d %s\n", __LINE__, i, stringPtrToIndexMap[stringPtrs[i]], stringPtrs[i]->c_str());
- k = stringPtrToIndexMap[stringPtrs[i]];
- opts.clear();
- for(j=0; j < groups[k]->flags.size()-1; ++j) {
- opts.append(*groups[k]->flags[j]);
- opts.append(", ");
-
- if ((long int)opts.size() > width)
- opts.append("\n");
- }
- // The last flag. No need to append comma anymore.
- opts.append( *groups[k]->flags[j] );
-
- if (groups[k]->expectArgs) {
- opts.append(" ARG");
-
- if (groups[k]->delim) {
- opts.append("1[");
- opts.append(1, groups[k]->delim);
- opts.append("ARGn]");
- }
- }
-
- sortedOpts.push_back(opts);
- }
-
- // Each option group will use this to build multiline help description.
- std::list<std::string*> desc;
- // Number of whitespaces from start of line to description (interleave layout) or
- // gap between flag names and description (align, stagger layouts).
- int gutter = 3;
-
- // Find longest opt flag string to set column start for help usage descriptions.
- int maxlen=0;
- if (layout == ALIGN) {
- for(i=0; i < (long int)groups.size(); ++i) {
- if (maxlen < (long int)sortedOpts[i].size())
- maxlen = sortedOpts[i].size();
- }
- }
-
- // The amount of space remaining on a line for help text after flags.
- int helpwidth;
- std::list<std::string*>::iterator cIter, insertionIter;
- size_t pos;
- for(i=0; i < (long int)groups.size(); ++i) {
- k = stringPtrToIndexMap[stringPtrs[i]];
-
- if (layout == STAGGER)
- maxlen = sortedOpts[i].size();
-
- int pad = gutter + maxlen;
- helpwidth = width - pad;
-
- // All the following split-fu could be optimized by just using substring (offset, length) tuples, but just to get it done, we'll do some not-too expensive string copying.
- SplitDelim(groups[k]->help, '\n', desc);
- // Split lines longer than allowable help width.
- for(insertionIter=desc.begin(), cIter=insertionIter++;
- cIter != desc.end();
- cIter=insertionIter++) {
- if ((long int)((*cIter)->size()) > helpwidth) {
- // Get pointer to next string to insert new strings before it.
- std::string *rem = *cIter;
- // Remove this line and add back in pieces.
- desc.erase(cIter);
- // Loop until remaining string is short enough.
- while ((long int)rem->size() > helpwidth) {
- // Find whitespace to split before helpwidth.
- if (rem->at(helpwidth) == ' ') {
- // If word ends exactly at helpwidth, then split after it.
- pos = helpwidth;
- } else {
- // Otherwise, split occurs midword, so find whitespace before this word.
- pos = rem->rfind(" ", helpwidth);
- }
- // Insert split string.
- desc.insert(insertionIter, new std::string(*rem, 0, pos));
- // Now skip any whitespace to start new line.
- pos = rem->find_first_not_of(' ', pos);
- rem->erase(0, pos);
- }
-
- if (rem->size())
- desc.insert(insertionIter, rem);
- else
- delete rem;
- }
- }
-
- usage.append(sortedOpts[i]);
- if (layout != INTERLEAVE)
- // Add whitespace between option names and description.
- usage.append(pad - sortedOpts[i].size(), ' ');
- else {
- usage.append("\n");
- usage.append(gutter, ' ');
- }
-
- if (desc.size() > 0) { // Crash fix by Bruce Shankle.
- // First line already padded above (before calling SplitDelim) after option flag names.
- cIter = desc.begin();
- usage.append(**cIter);
- usage.append("\n");
- // Now inject the pad for each line.
- for(++cIter; cIter != desc.end(); ++cIter) {
- usage.append(pad, ' ');
- usage.append(**cIter);
- usage.append("\n");
- }
-
- if (this->doublespace) usage.append("\n");
-
- for(cIter=desc.begin(); cIter != desc.end(); ++cIter)
- delete *cIter;
-
- desc.clear();
- }
-
- }
- };
- /* ################################################################### */
- bool ezOptionParser::gotExpected(std::vector<std::string> & badOptions) {
- int i,j;
-
- for(i=0; i < (long int)groups.size(); ++i) {
- OptionGroup *g = groups[i];
- // If was set, ensure number of args is correct.
- if (g->isSet) {
- if ((g->expectArgs != 0) && g->args.empty()) {
- badOptions.push_back(*g->flags[0]);
- continue;
- }
-
- for(j=0; j < (long int)g->args.size(); ++j) {
- if ((g->expectArgs != -1) && (g->expectArgs != (long int)g->args[j]->size()))
- badOptions.push_back(*g->flags[0]);
- }
- }
- }
-
- return badOptions.empty();
- };
- /* ################################################################### */
- bool ezOptionParser::gotRequired(std::vector<std::string> & badOptions) {
- int i;
-
- for(i=0; i < (long int)groups.size(); ++i) {
- OptionGroup *g = groups[i];
- // Simple case when required but user never set it.
- if (g->isRequired && (!g->isSet)) {
- badOptions.push_back(*g->flags[0]);
- continue;
- }
- }
-
- return badOptions.empty();
- };
- /* ################################################################### */
- bool ezOptionParser::gotValid(std::vector<std::string> & badOptions, std::vector<std::string> & badArgs) {
- int groupid, validatorid;
- std::map< int, int >::iterator it;
-
- for(it = groupValidators.begin(); it != groupValidators.end(); ++it) {
- groupid = it->first;
- validatorid = it->second;
- if (validatorid < 0) continue;
-
- OptionGroup *g = groups[groupid];
- ezOptionValidator *v = validators[validatorid];
- bool nextgroup = false;
-
- for (int i = 0; i < (long int)g->args.size(); ++i) {
- if (nextgroup) break;
- std::vector< std::string* > * args = g->args[i];
- for (int j = 0; j < (long int)args->size(); ++j) {
- if (!v->isValid(args->at(j))) {
- badOptions.push_back(*g->flags[0]);
- badArgs.push_back(*args->at(j));
- nextgroup = true;
- break;
- }
- }
- }
- }
-
- return badOptions.empty();
- };
- /* ################################################################### */
- void ezOptionParser::parse(int argc, const char * argv[]) {
- if (argc < 1) return;
-
- /*
- std::map<std::string,int>::iterator it;
- for ( it=optionGroupIds.begin() ; it != optionGroupIds.end(); it++ )
- std::cout << (*it).first << " => " << (*it).second << std::endl;
- */
-
- int i, k, firstOptIndex=0, lastOptIndex=0;
- std::string s;
- OptionGroup *g;
-
- for(i=0; i < argc; ++i) {
- s = argv[i];
-
- if (optionGroupIds.count(s))
- break;
- }
-
- firstOptIndex = i;
-
- if (firstOptIndex == argc) {
- // No flags encountered, so set last args.
- this->firstArgs.push_back(new std::string(argv[0]));
-
- for(k=1; k < argc; ++k)
- this->lastArgs.push_back(new std::string(argv[k]));
-
- return;
- }
-
- // Store initial args before opts appear.
- for(k=0; k < i; ++k) {
- this->firstArgs.push_back(new std::string(argv[k]));
- }
-
- for(; i < argc; ++i) {
- s = argv[i];
-
- if (optionGroupIds.count(s)) {
- k = optionGroupIds[s];
- g = groups[k];
- g->isSet = 1;
- g->parseIndex.push_back(i);
-
- if (g->expectArgs) {
- // Read ahead to get args.
- ++i;
- if (i >= argc) return;
- g->args.push_back(new std::vector<std::string*>);
- SplitDelim(argv[i], g->delim, g->args.back());
- }
- lastOptIndex = i;
- }
- }
-
- // Scan for unknown opts/arguments.
- for(i=firstOptIndex; i <= lastOptIndex; ++i) {
- s = argv[i];
-
- if (optionGroupIds.count(s)) {
- k = optionGroupIds[s];
- g = groups[k];
- if (g->expectArgs) {
- // Read ahead for args and skip them.
- ++i;
- }
- } else {
- unknownArgs.push_back(new std::string(argv[i]));
- }
- }
-
- if ( lastOptIndex >= (argc-1) ) return;
-
- // Store final args without flags.
- for(k=lastOptIndex + 1; k < argc; ++k) {
- this->lastArgs.push_back(new std::string(argv[k]));
- }
- };
- /* ################################################################### */
- void ezOptionParser::prettyPrint(std::string & out) {
- char tmp[256];
- int i,j,k;
-
- out += "First Args:\n";
- for(i=0; i < (long int)firstArgs.size(); ++i) {
- sprintf(tmp, "%d: %s\n", i+1, firstArgs[i]->c_str());
- out += tmp;
- }
-
- // Sort the option flag names.
- int n = groups.size();
- std::vector<std::string* > stringPtrs(n);
- for(i=0; i < n; ++i) {
- stringPtrs[i] = groups[i]->flags[0];
- }
-
- // Sort first flag of each group with other groups.
- std::sort(stringPtrs.begin(), stringPtrs.end(), CmpOptStringPtr);
-
- out += "\nOptions:\n";
- OptionGroup *g;
- for(i=0; i < n; ++i) {
- g = get(stringPtrs[i]->c_str());
- out += "\n";
- // The flag names:
- for(j=0; j < (long int)g->flags.size()-1; ++j) {
- sprintf(tmp, "%s, ", g->flags[j]->c_str());
- out += tmp;
- }
- sprintf(tmp, "%s:\n", g->flags.back()->c_str());
- out += tmp;
-
- if (g->isSet) {
- if (g->expectArgs) {
- if (g->args.empty()) {
- sprintf(tmp, "%s (default)\n", g->defaults.c_str());
- out += tmp;
- } else {
- for(k=0; k < (long int)g->args.size(); ++k) {
- for(j=0; j < (long int)g->args[k]->size()-1; ++j) {
- sprintf(tmp, "%s%c", g->args[k]->at(j)->c_str(), g->delim);
- out += tmp;
- }
- sprintf(tmp, "%s\n", g->args[k]->back()->c_str());
- out += tmp;
- }
- }
- } else { // Set but no args expected.
- sprintf(tmp, "Set\n");
- out += tmp;
- }
- } else {
- sprintf(tmp, "Not set\n");
- out += tmp;
- }
- }
-
- out += "\nLast Args:\n";
- for(i=0; i < (long int)lastArgs.size(); ++i) {
- sprintf(tmp, "%d: %s\n", i+1, lastArgs[i]->c_str());
- out += tmp;
- }
-
- out += "\nUnknown Args:\n";
- for(i=0; i < (long int)unknownArgs.size(); ++i) {
- sprintf(tmp, "%d: %s\n", i+1, unknownArgs[i]->c_str());
- out += tmp;
- }
- };
- }
- /* ################################################################### */
- #endif /* EZ_OPTION_PARSER_H */
|