libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmPgmOpts.c 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. #include "cmGlobal.h"
  2. #include "cmRpt.h"
  3. #include "cmErr.h"
  4. #include "cmCtx.h"
  5. #include "cmMem.h"
  6. #include "cmMallocDebug.h"
  7. #include "cmLinkedHeap.h"
  8. #include "cmPgmOpts.h"
  9. #include "config.h"
  10. cmPgmOptH_t cmPgmOptNullHandle = cmSTATIC_NULL_HANDLE;
  11. struct _cmPoArg_str;
  12. typedef union
  13. {
  14. bool b;
  15. char c;
  16. int i;
  17. unsigned u;
  18. double d;
  19. const cmChar_t* s;
  20. } _cmPoValue_t;
  21. typedef union
  22. {
  23. bool* b;
  24. char* c;
  25. int* i;
  26. unsigned* u;
  27. double* d;
  28. const cmChar_t** s;
  29. } _cmPoValPtr_t;
  30. // opt records describe the a given parameters configuration
  31. typedef struct _cmPoOpt_str
  32. {
  33. unsigned numId; //
  34. cmChar_t charId; //
  35. cmChar_t* wordId; //
  36. unsigned flags; //
  37. unsigned enumId; //
  38. struct _cmPoOpt_str* enumPtr; // pointer to mast enum recd
  39. unsigned maxInstCnt; //
  40. _cmPoValue_t dfltVal; // default value for this parm
  41. _cmPoValPtr_t retVal; // client supplied variable which recieves the value of the last arg. parsed for this parm.
  42. cmChar_t* helpStr; //
  43. struct _cmPoOpt_str* link; // link used by the _cmPo_t.list linked list
  44. struct _cmPoArg_str* inst; // arg's belonging to this opt record formed by _cmPoArg_t.inst links
  45. } _cmPoOpt_t;
  46. // arg records describe an instance of a given parameter.
  47. // (there may be multiple instances of a given parameter)
  48. typedef struct _cmPoArg_str
  49. {
  50. const _cmPoOpt_t* opt; // the opt record associated with this arg. instance
  51. struct _cmPoArg_str* link; // link used by the _cmPo_t.args list
  52. struct _cmPoArg_str* inst; // link used by the _cmPoOpt_t* inst list
  53. const cmChar_t* valStr; // string value for this arg.
  54. _cmPoValue_t u; // parsed value for this arg.
  55. } _cmPoArg_t;
  56. typedef struct
  57. {
  58. cmErr_t err;
  59. cmLHeapH_t lH;
  60. cmChar_t* helpBegStr;
  61. cmChar_t* helpEndStr;
  62. _cmPoOpt_t* list; // list of control records formed by _cmPoOpt_t.link links
  63. _cmPoArg_t* args; // list of arg. records formed by _cmPoArg_t.link links
  64. bool execFl; // set to false in cmPgmOptParse() if only built-in options were selected
  65. } _cmPo_t;
  66. _cmPo_t* _cmPoHandleToPtr( cmPgmOptH_t h )
  67. {
  68. _cmPo_t* p = (_cmPo_t*)h.h;
  69. assert(p != NULL );
  70. return p;
  71. }
  72. cmPoRC_t _cmPgmOptFinalize( _cmPo_t* p )
  73. {
  74. cmPoRC_t rc = kOkPoRC;
  75. cmLHeapDestroy(&p->lH);
  76. cmMemPtrFree(&p);
  77. return rc;
  78. }
  79. bool cmPgmOptIsValid( cmPgmOptH_t h )
  80. { return h.h != NULL; }
  81. cmPoRC_t cmPgmOptInitialize(cmCtx_t* c, cmPgmOptH_t* hp, const cmChar_t* helpBegStr, const cmChar_t* helpEndStr )
  82. {
  83. cmPoRC_t rc;
  84. if((rc = cmPgmOptFinalize(hp)) != kOkPoRC )
  85. return rc;
  86. _cmPo_t* p = cmMemAllocZ(_cmPo_t,1);
  87. cmErrSetup(&p->err,&c->rpt,"Program Options");
  88. p->lH = cmLHeapCreate(2048,c);
  89. p->helpBegStr = helpBegStr==NULL ? NULL : cmLhAllocStr( p->lH, helpBegStr );
  90. p->helpEndStr = helpEndStr==NULL ? NULL : cmLhAllocStr( p->lH, helpEndStr );
  91. hp->h = p;
  92. cmPgmOptInstallBool(*hp, kPrintHelpPoId, 'h', "help", 0, false, NULL,0,"Print this usage information." );
  93. cmPgmOptInstallBool(*hp, kVersionPoId, 'v', "version", 0, false, NULL,0,"Print version information." );
  94. cmPgmOptInstallBool(*hp, kPrintParmsPoId,'p', "parms", 0, false, NULL,0,"Print the parameter information.");
  95. return cmErrLastRC(&p->err);
  96. }
  97. cmPoRC_t cmPgmOptFinalize( cmPgmOptH_t* hp )
  98. {
  99. cmPoRC_t rc = kOkPoRC;
  100. if( hp == NULL || cmPgmOptIsValid(*hp) == false )
  101. return kOkPoRC;
  102. _cmPo_t* p = _cmPoHandleToPtr(*hp);
  103. if((rc = _cmPgmOptFinalize(p)) != kOkPoRC )
  104. return rc;
  105. hp->h = NULL;
  106. return rc;
  107. }
  108. _cmPoOpt_t* _cmPgmOptNumIdToOptRecd( _cmPo_t* p, unsigned numId )
  109. {
  110. _cmPoOpt_t* r = p->list;
  111. while( r != NULL )
  112. {
  113. if( r->numId == numId )
  114. {
  115. if( cmIsFlag(r->flags,kEnumPoFl) && r->enumPtr!=NULL )
  116. r = r->enumPtr;
  117. return r;
  118. }
  119. r = r->link;
  120. }
  121. return NULL;
  122. }
  123. _cmPoOpt_t* _cmPgmOptEnumIdToOptRecd( _cmPo_t* p, unsigned numId, unsigned enumId )
  124. {
  125. _cmPoOpt_t* r = p->list;
  126. while( r != NULL )
  127. {
  128. if( r->numId == numId && r->enumId == enumId )
  129. return r;
  130. r = r->link;
  131. }
  132. return NULL;
  133. }
  134. _cmPoOpt_t* _cmPgmOptCharIdToOptRecd( _cmPo_t* p, cmChar_t charId )
  135. {
  136. _cmPoOpt_t* r = p->list;
  137. while( r != NULL )
  138. {
  139. if( r->charId == charId )
  140. return r;
  141. r = r->link;
  142. }
  143. return NULL;
  144. }
  145. _cmPoOpt_t* _cmPgmOptWordIdToOptRecd( _cmPo_t* p, const cmChar_t* wordId )
  146. {
  147. _cmPoOpt_t* r = p->list;
  148. while( r != NULL )
  149. {
  150. if( strcmp(wordId,r->wordId) == 0 )
  151. return r;
  152. r = r->link;
  153. }
  154. return NULL;
  155. }
  156. cmPoRC_t _cmPgmOptInstall( _cmPo_t* p, unsigned numId, const cmChar_t charId, const cmChar_t* wordId, unsigned flags, unsigned enumId, unsigned cnt, const cmChar_t* helpStr, _cmPoOpt_t** rpp )
  157. {
  158. // validate the num. id
  159. if( enumId==0 && _cmPgmOptNumIdToOptRecd(p,numId) != NULL )
  160. return cmErrMsg(&p->err,kDuplicateIdPoRC,"The numeric id '%i' was already used by another parameter.",numId);
  161. // validate the char. id
  162. if( _cmPgmOptCharIdToOptRecd(p,charId) != NULL )
  163. return cmErrMsg(&p->err,kDuplicateIdPoRC,"The character id -'%c' was already used by another parameter.",charId);
  164. // validate the word. id
  165. if( _cmPgmOptWordIdToOptRecd(p,wordId) != NULL )
  166. return cmErrMsg(&p->err,kDuplicateIdPoRC,"The word id --'%s' was already used by another parameter.",wordId);
  167. // allocate the new parm recd
  168. _cmPoOpt_t* r = cmLhAllocZ( p->lH, _cmPoOpt_t, 1 );
  169. // if enumId != 0 then this is automatically an enum type.
  170. if( enumId != 0 )
  171. {
  172. flags = cmClrFlag(flags,kTypeMaskPoFl) | kEnumPoFl;
  173. // set the master recd for this enum ptr
  174. _cmPoOpt_t* erp;
  175. if((erp = _cmPgmOptNumIdToOptRecd(p,numId)) != NULL )
  176. {
  177. r->enumPtr = erp->enumPtr==NULL ? erp : erp->enumPtr;
  178. // if this child enum has it's required flags set
  179. if( cmIsFlag(flags,kReqPoFl) )
  180. {
  181. // then set the required flag in the parent and clear it in the child
  182. // (this way both the parent and child will not be required (which would be impossible for an enum))
  183. r->enumPtr->flags = cmSetFlag(r->enumPtr->flags,kReqPoFl);
  184. flags = cmClrFlag(flags,kReqPoFl);
  185. }
  186. }
  187. }
  188. r->flags = flags;
  189. r->numId = numId;
  190. r->charId = charId;
  191. r->wordId = cmLhAllocStr( p->lH, wordId );
  192. r->enumId = enumId;
  193. r->maxInstCnt = cnt;
  194. r->helpStr = helpStr==NULL ? NULL : cmLhAllocStr( p->lH, helpStr );
  195. r->link = p->list;
  196. p->list = r;
  197. *rpp = r;
  198. return kOkPoRC;
  199. }
  200. cmPoRC_t cmPgmOptInstallChar(cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, cmChar_t dfltVal, cmChar_t* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  201. {
  202. cmPoRC_t rc;
  203. _cmPoOpt_t* r = NULL;
  204. _cmPo_t* p = _cmPoHandleToPtr(h);
  205. flags = cmClrFlag(flags,kTypeMaskPoFl) | kCharPoFl;
  206. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  207. return rc;
  208. r->dfltVal.c = dfltVal;
  209. if( retValPtr != NULL )
  210. {
  211. r->retVal.c = retValPtr;
  212. *r->retVal.c = dfltVal;
  213. }
  214. return rc;
  215. }
  216. cmPoRC_t cmPgmOptInstallBool(cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, bool dfltVal, bool* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  217. {
  218. cmPoRC_t rc;
  219. _cmPoOpt_t* r = NULL;
  220. _cmPo_t* p = _cmPoHandleToPtr(h);
  221. flags = cmClrFlag(flags,kTypeMaskPoFl) | kBoolPoFl;
  222. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  223. return rc;
  224. r->dfltVal.b = dfltVal;
  225. if( retValPtr != NULL )
  226. {
  227. r->retVal.b = retValPtr;
  228. *r->retVal.b = dfltVal;
  229. }
  230. return rc;
  231. }
  232. cmPoRC_t cmPgmOptInstallInt( cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, int dfltVal, int* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  233. {
  234. cmPoRC_t rc;
  235. _cmPoOpt_t* r = NULL;
  236. _cmPo_t* p = _cmPoHandleToPtr(h);
  237. flags = cmClrFlag(flags,kTypeMaskPoFl) | kIntPoFl;
  238. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  239. return rc;
  240. r->dfltVal.i = dfltVal;
  241. if( retValPtr != NULL )
  242. {
  243. r->retVal.i = retValPtr;
  244. *r->retVal.i = dfltVal;
  245. }
  246. return rc;
  247. }
  248. cmPoRC_t cmPgmOptInstallUInt(cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, unsigned dfltVal, unsigned* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  249. {
  250. cmPoRC_t rc;
  251. _cmPoOpt_t* r = NULL;
  252. _cmPo_t* p = _cmPoHandleToPtr(h);
  253. flags = cmClrFlag(flags,kTypeMaskPoFl) | kUIntPoFl;
  254. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  255. return rc;
  256. r->dfltVal.u = dfltVal;
  257. if( retValPtr != NULL )
  258. {
  259. r->retVal.u = retValPtr;
  260. *r->retVal.u = dfltVal;
  261. }
  262. return rc;
  263. }
  264. cmPoRC_t cmPgmOptInstallDbl( cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, double dfltVal, double* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  265. {
  266. cmPoRC_t rc;
  267. _cmPoOpt_t* r = NULL;
  268. _cmPo_t* p = _cmPoHandleToPtr(h);
  269. flags = cmClrFlag(flags,kTypeMaskPoFl) | kDblPoFl;
  270. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  271. return rc;
  272. r->dfltVal.d = dfltVal;
  273. if( retValPtr != NULL )
  274. {
  275. r->retVal.d = retValPtr;
  276. *r->retVal.d = dfltVal;
  277. }
  278. return rc;
  279. }
  280. cmPoRC_t cmPgmOptInstallStr( cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, const cmChar_t* dfltVal, const cmChar_t** retValPtr, unsigned cnt, const cmChar_t* helpStr )
  281. {
  282. cmPoRC_t rc;
  283. _cmPoOpt_t* r = NULL;
  284. _cmPo_t* p = _cmPoHandleToPtr(h);
  285. flags = cmClrFlag(flags,kTypeMaskPoFl) | kStrPoFl;
  286. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, 0, cnt, helpStr, &r )) != kOkPoRC )
  287. return rc;
  288. r->dfltVal.s = dfltVal;
  289. if( retValPtr != NULL )
  290. {
  291. r->retVal.s = retValPtr;
  292. *r->retVal.s = dfltVal;
  293. }
  294. return rc;
  295. }
  296. cmPoRC_t cmPgmOptInstallEnum(cmPgmOptH_t h, unsigned numId, cmChar_t charId, const cmChar_t* wordId, unsigned flags, unsigned enumId, unsigned dfltVal, unsigned* retValPtr, unsigned cnt, const cmChar_t* helpStr )
  297. {
  298. cmPoRC_t rc;
  299. _cmPoOpt_t* r = NULL;
  300. _cmPo_t* p = _cmPoHandleToPtr(h);
  301. flags = cmClrFlag(flags,kTypeMaskPoFl) | kEnumPoFl;
  302. if((rc= _cmPgmOptInstall(p, numId, charId, wordId, flags, enumId, cnt, helpStr, &r )) != kOkPoRC )
  303. return rc;
  304. r->dfltVal.u = dfltVal;
  305. if( retValPtr != NULL )
  306. {
  307. r->retVal.u = retValPtr;
  308. *r->retVal.u = dfltVal;
  309. }
  310. return rc;
  311. }
  312. _cmPoArg_t* _cmPgmOptInsertArg( _cmPo_t* p, _cmPoOpt_t* r )
  313. {
  314. _cmPoArg_t* a = cmLhAllocZ(p->lH, _cmPoArg_t, 1);
  315. // if this is an enumerated type then switch to the master enum recd
  316. unsigned enumId = r->enumId;
  317. _cmPoOpt_t* e = r;
  318. if( r->enumPtr != NULL )
  319. r = r->enumPtr;
  320. a->opt = r;
  321. a->valStr = NULL;
  322. a->link = p->args; // link into master arg list
  323. p->args = a;
  324. a->inst = r->inst; // link into opt recd list
  325. r->inst = a;
  326. // if no parm. type flag was given then the arg is implicitely a bool and the value is true.
  327. //if( (r->flags & kTypeMaskPoFl) == 0 )
  328. // a->u.b = true;
  329. // if this is an enumerated type
  330. if( cmIsFlag(r->flags,kEnumPoFl) )
  331. {
  332. a->u.u = enumId;
  333. if( r->retVal.u != NULL )
  334. *r->retVal.u = enumId;
  335. if( e->retVal.u != NULL )
  336. *e->retVal.u = enumId;
  337. }
  338. return a;
  339. }
  340. cmPoRC_t _cmPgmOptParseBool(_cmPo_t* p, const cmChar_t* valStr, bool* retValPtr )
  341. {
  342. cmPoRC_t rc = kOkPoRC;
  343. unsigned n = strlen("false");
  344. char val[n+1];
  345. int i;
  346. for(i=0; i<n && valStr[i]; ++i)
  347. val[i] = tolower(valStr[i]);
  348. val[i] = 0;
  349. if( !strcmp(val,"0") || !strcmp(val,"false") || !strcmp(val,"f") )
  350. *retValPtr = false;
  351. else
  352. if( !strcmp(val,"1") || !strcmp(val,"true") || !strcmp(val,"t") )
  353. *retValPtr = true;
  354. else
  355. rc = cmErrMsg(&p->err,kParseFailPoRC,"The argument '%s' could not be parsed into a bool. Legal bool values are 0,F,FALSE,1,T,TRUE (case insensitive).",valStr);
  356. return rc;
  357. }
  358. cmPoRC_t _cmPgmOptParseValue( _cmPo_t* p, _cmPoOpt_t* r, _cmPoArg_t* a, const cmChar_t* valStr )
  359. {
  360. cmPoRC_t rc = kOkPoRC;
  361. assert(a != NULL && valStr != NULL);
  362. a->valStr = valStr;
  363. errno = 0;
  364. switch( r->flags & kTypeMaskPoFl )
  365. {
  366. case kBoolPoFl:
  367. //rc = _cmPgmOptParseBool(p,valStr,&a->u.b);
  368. a->u.b = true;
  369. if( r->retVal.b != NULL )
  370. *r->retVal.b = a->u.b;
  371. break;
  372. case kCharPoFl:
  373. a->u.c = valStr[0];
  374. if( r->retVal.c != NULL )
  375. *r->retVal.c = a->u.c;
  376. break;
  377. case kIntPoFl:
  378. a->u.i = strtol(valStr,NULL,10);
  379. if( r->retVal.i != NULL )
  380. *r->retVal.i = a->u.i;
  381. break;
  382. case kUIntPoFl:
  383. a->u.u = strtol(valStr,NULL,10);
  384. if( r->retVal.u != NULL )
  385. *r->retVal.u = a->u.u;
  386. break;
  387. // case kEnumPoFl:
  388. // enum values get set in _cmPgmOptInsertArg()
  389. case kHexPoFl:
  390. a->u.u = strtol(valStr,NULL,16);
  391. if( r->retVal.u != NULL )
  392. *r->retVal.u = a->u.u;
  393. break;
  394. case kDblPoFl:
  395. a->u.d = strtod(valStr,NULL);
  396. if( r->retVal.d != NULL )
  397. *r->retVal.d = a->u.d;
  398. break;
  399. case kStrPoFl:
  400. a->u.s = valStr;
  401. if( r->retVal.s != NULL )
  402. *r->retVal.s = a->u.s;
  403. break;
  404. }
  405. if( errno != 0 )
  406. rc = cmErrMsg(&p->err,kParseFailPoRC,"The value '%s' for option '%s' could not be parsed.",valStr,r->wordId);
  407. return rc;
  408. }
  409. unsigned _cmPgmOptInstCount( const _cmPoOpt_t* r )
  410. {
  411. const _cmPoArg_t* a = r->inst;
  412. unsigned n = 0;
  413. while( a != NULL )
  414. {
  415. ++n;
  416. a = a->inst;
  417. }
  418. return n;
  419. }
  420. // check if any non-built-in options were provided
  421. // If only built in options were selected then no execution is assumed
  422. // and required arg's are not checked.
  423. bool _cmPgmOptCheckNoExec( _cmPo_t* p )
  424. {
  425. _cmPoArg_t* a = p->args;
  426. while( a != NULL )
  427. {
  428. if( a->opt->numId >= kBasePoId )
  429. return true;
  430. a = a->link;
  431. }
  432. return false;
  433. }
  434. // check that all required arg.s were actually given and that the actual
  435. // number of instances does not exceed the defined limit
  436. cmPoRC_t _cmPgmOptCheckReqArgs( _cmPo_t* p )
  437. {
  438. cmPoRC_t rc = kOkPoRC;
  439. _cmPoOpt_t* r = p->list;
  440. while( r != NULL )
  441. {
  442. if( cmIsFlag(r->flags, kReqPoFl ) )
  443. {
  444. _cmPoArg_t* a = p->args;
  445. while( a != NULL )
  446. {
  447. if( a->opt == r )
  448. break;
  449. a = a->link;
  450. }
  451. if( a == NULL )
  452. rc = cmErrMsg(&p->err,kNoReqArgPoRC,"No argument was supplied for the required parameter '%s'.",r->wordId);
  453. }
  454. unsigned cnt;
  455. if( r->maxInstCnt > 0 && r->maxInstCnt < (cnt=_cmPgmOptInstCount(r)) )
  456. rc = cmErrMsg(&p->err,kArgCntErrPoRC,"The parameter '%s' has %i instances which exceeds the defined limit of %i instances.",r->wordId,cnt,r->maxInstCnt);
  457. r = r->link;
  458. }
  459. return rc;
  460. }
  461. cmPoRC_t cmPgmOptParse( cmPgmOptH_t h, unsigned argCnt, char* argArray[] )
  462. {
  463. enum { kDash, kCharId, kWordId, kArgVal };
  464. cmPoRC_t rc = kOkPoRC;
  465. _cmPo_t* p = _cmPoHandleToPtr(h);
  466. unsigned state = kDash;
  467. _cmPoOpt_t* r = NULL;
  468. _cmPoArg_t* a = NULL;
  469. int i = 0; // arg index
  470. int j = 0; // arg label character index
  471. while(i<argCnt)
  472. {
  473. const cmChar_t* valStr = NULL;
  474. switch(state)
  475. {
  476. case kDash:
  477. // this token must begin with a '-' character
  478. if( argArray[i][0] != '-')
  479. return cmErrMsg(&p->err,kSyntaxErrPoRC,"Syntax error. Expecting a '-'.");
  480. // if the second char. is also a '-' then this is a wordId
  481. if( argArray[i][1] == '-' )
  482. {
  483. state = kWordId;
  484. j = 2; // word id's always begin on the third token char
  485. }
  486. else // otherwise it is a charId
  487. {
  488. state = kCharId;
  489. j = 1; // char id's always begin on the second token char
  490. }
  491. r = NULL;
  492. break;
  493. case kCharId:
  494. // we complete our parsing of charId's only when we encounter a '\0'
  495. if( argArray[i][j] == '\0' )
  496. {
  497. ++i;
  498. state = kDash;
  499. r = NULL;
  500. a = NULL;
  501. }
  502. else
  503. {
  504. // get the opt recd assoc'd with the jth character in this charId
  505. if((r = _cmPgmOptCharIdToOptRecd(p,argArray[i][j])) == NULL )
  506. return cmErrMsg(&p->err,kSyntaxErrPoRC,"The program option selector char '%c' is not valid.",argArray[i][j]);
  507. // if this charId is not a bool or enum then it must be followed by a value.
  508. if( cmIsFlag(r->flags,kBoolPoFl)==false && cmIsFlag(r->flags,kEnumPoFl)==false )
  509. ++i;
  510. else // otherwise process the next char id in this charId token
  511. ++j;
  512. }
  513. break;
  514. case kWordId:
  515. // get the wordId
  516. if((r = _cmPgmOptWordIdToOptRecd(p,argArray[i]+j)) == NULL )
  517. return cmErrMsg(&p->err,kSyntaxErrPoRC,"The program option selector word '%s' is not valid.",cmStringNullGuard(argArray[i]+j));
  518. ++i; // advance to the next token
  519. break;
  520. case kArgVal:
  521. assert(r != NULL );
  522. valStr = argArray[i];
  523. ++i;
  524. break;
  525. }
  526. // if a valid opt recd has been selected
  527. if( r != NULL )
  528. {
  529. // if the cur token reprsents a value ...
  530. if( state == kArgVal )
  531. {
  532. // ... then parse the value string
  533. if((rc = _cmPgmOptParseValue(p,r,a,valStr)) != kOkPoRC )
  534. goto errLabel;
  535. r = NULL;
  536. a = NULL;
  537. state = kDash; // value strings are always followed by char or word id's
  538. }
  539. else
  540. {
  541. // create an arg record for the cur char or word id.
  542. a = _cmPgmOptInsertArg(p, r );
  543. // and the value type is not 'bool' or 'enum'
  544. if( cmIsFlag(r->flags,kBoolPoFl)== false && cmIsFlag(r->flags,kEnumPoFl)==false )
  545. state = kArgVal;
  546. switch(state)
  547. {
  548. case kDash: assert(i==argCnt); break;
  549. case kCharId: break;
  550. case kWordId: state = kDash; break;
  551. case kArgVal: break;
  552. default: assert(0); break;
  553. }
  554. }
  555. }
  556. }
  557. errLabel:
  558. // if no errors have occurred then check for missing parameters.
  559. if( rc == kOkPoRC )
  560. {
  561. if((p->execFl = _cmPgmOptCheckNoExec(p)) == true )
  562. rc = _cmPgmOptCheckReqArgs(p);
  563. }
  564. return rc;
  565. }
  566. unsigned cmPgmOptArgCount( cmPgmOptH_t h)
  567. {
  568. _cmPo_t* p = _cmPoHandleToPtr(h);
  569. const _cmPoArg_t* a = p->args;
  570. unsigned n = 0;
  571. while( a != NULL )
  572. {
  573. ++n;
  574. a = a->link;
  575. }
  576. return n;
  577. }
  578. cmPoRC_t _cmPgmOptIndexToPtr( _cmPo_t* p, unsigned idx, const _cmPoArg_t** app )
  579. {
  580. unsigned n = 0;
  581. const _cmPoArg_t* a = p->args;
  582. while( a != NULL && idx < n )
  583. {
  584. ++n;
  585. a = a->link;
  586. }
  587. if( n!=idx || a==NULL)
  588. return cmErrMsg(&p->err,kInvalidIdxPoRC,"The option index '%i' is not valid.",idx);
  589. *app = a;
  590. return kOkPoRC;
  591. }
  592. unsigned cmPgmOptSelId( cmPgmOptH_t h, unsigned argIdx )
  593. {
  594. const _cmPoArg_t* a;
  595. cmPoRC_t rc;
  596. if((rc = _cmPgmOptIndexToPtr(_cmPoHandleToPtr(h),argIdx,&a)) != kOkPoRC )
  597. return cmInvalidId;
  598. return a->opt->numId;
  599. }
  600. cmPoRC_t _cmPgmOptArgPtr( _cmPo_t* p, unsigned argIdx, const _cmPoArg_t** app )
  601. {
  602. cmPoRC_t rc;
  603. if((rc = _cmPgmOptIndexToPtr(p,argIdx,app)) != kOkPoRC )
  604. {
  605. if( (*app)->valStr == NULL )
  606. return cmErrMsg(&p->err,kParseFailPoRC,"The parameter at index '%i' is not a value.",argIdx);
  607. }
  608. return rc;
  609. }
  610. char cmPgmOptParseArgChar( cmPgmOptH_t h, unsigned argIdx )
  611. {
  612. cmPoRC_t rc;
  613. const _cmPoArg_t* a;
  614. _cmPo_t* p = _cmPoHandleToPtr(h);
  615. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  616. return 0;
  617. return a->valStr==NULL ? 0 : a->valStr[0];
  618. }
  619. bool cmPgmOptParseArgBool( cmPgmOptH_t h, unsigned argIdx )
  620. {
  621. cmPoRC_t rc;
  622. const _cmPoArg_t* a;
  623. _cmPo_t* p = _cmPoHandleToPtr(h);
  624. bool val = false;
  625. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  626. return false;
  627. if( a->valStr != NULL )
  628. _cmPgmOptParseBool(p,a->valStr,&val);
  629. return val;
  630. }
  631. int cmPgmOptParseArgInt( cmPgmOptH_t h, unsigned argIdx )
  632. {
  633. cmPoRC_t rc;
  634. const _cmPoArg_t* a;
  635. _cmPo_t* p = _cmPoHandleToPtr(h);
  636. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  637. return rc;
  638. errno = 0;
  639. int v = strtol(a->valStr,NULL,10);
  640. if( errno != 0 )
  641. cmErrMsg(&p->err,kParseFailPoRC,"The parameter '%s' could not be converted to an 'int'.",a->valStr);
  642. return v;
  643. }
  644. unsigned cmPgmOptParseArgUInt( cmPgmOptH_t h, unsigned argIdx )
  645. {
  646. cmPoRC_t rc;
  647. const _cmPoArg_t* a;
  648. _cmPo_t* p = _cmPoHandleToPtr(h);
  649. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  650. return rc;
  651. errno = 0;
  652. unsigned v = strtol(a->valStr,NULL,10);
  653. if( errno != 0 )
  654. cmErrMsg(&p->err,kParseFailPoRC,"The parameter '%s' could not be converted to an 'unsigned int'.",a->valStr);
  655. return v;
  656. }
  657. double cmPgmOptParseArgDbl( cmPgmOptH_t h, unsigned argIdx )
  658. {
  659. cmPoRC_t rc;
  660. const _cmPoArg_t* a;
  661. _cmPo_t* p = _cmPoHandleToPtr(h);
  662. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  663. return rc;
  664. errno = 0;
  665. double v = strtod(a->valStr,NULL);
  666. if( errno != 0 )
  667. cmErrMsg(&p->err,kParseFailPoRC,"The parameter '%s' could not be converted to a 'double'.",a->valStr);
  668. return v;
  669. }
  670. const char* cmPgmOptParseArgStr( cmPgmOptH_t h, unsigned argIdx )
  671. {
  672. cmPoRC_t rc;
  673. const _cmPoArg_t* a;
  674. _cmPo_t* p = _cmPoHandleToPtr(h);
  675. if((rc = _cmPgmOptArgPtr(p,argIdx,&a)) != kOkPoRC )
  676. return NULL;
  677. return a->valStr;
  678. }
  679. unsigned cmPgmOptParmArgCount( cmPgmOptH_t h, unsigned numId )
  680. {
  681. const _cmPoOpt_t* r;
  682. _cmPo_t* p = _cmPoHandleToPtr(h);
  683. unsigned n = 0;
  684. if((r = _cmPgmOptNumIdToOptRecd(p,numId)) == NULL )
  685. cmErrMsg(&p->err,kParmNotFoundPoRC,"No parameter definition was found for numeric id %i.",numId);
  686. else
  687. n = _cmPgmOptInstCount(r);
  688. return n;
  689. }
  690. cmPoRC_t _cmPgmOptInstPtr( _cmPo_t* p, unsigned numId, unsigned instIdx, const _cmPoOpt_t** rpp, const _cmPoValue_t** vpp )
  691. {
  692. *rpp = NULL;
  693. *vpp = NULL;
  694. // locate the opt recd
  695. if((*rpp = _cmPgmOptNumIdToOptRecd(p,numId)) == NULL )
  696. return cmErrMsg(&p->err,kParmNotFoundPoRC,"No parameter definition was found for the numeric id %i.",numId);
  697. const _cmPoArg_t* a = (*rpp)->inst;
  698. unsigned i;
  699. // locate the instance recd
  700. for(i=0; i<instIdx && a != NULL; ++i)
  701. a = a->inst;
  702. // if the instance recd was not found
  703. if( i != instIdx || a == NULL )
  704. {
  705. // if the instance index is 0 then and no instance recd exists then
  706. // we will return the default value.
  707. if( instIdx == 0 )
  708. {
  709. *vpp = &((*rpp)->dfltVal);
  710. return kOkPoRC;
  711. }
  712. // otherwise signal an error
  713. return cmErrMsg(&p->err,kInstNotFoundPoRC,"The instance index %i is not valid for parameter %s instance count %i.",instIdx,(*rpp)->wordId,i);
  714. }
  715. *vpp = &a->u;
  716. return kOkPoRC;
  717. }
  718. char cmPgmOptArgChar( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  719. {
  720. const _cmPoOpt_t* rp = NULL;
  721. const _cmPoValue_t* vp = NULL;
  722. _cmPo_t* p = _cmPoHandleToPtr(h);
  723. if(_cmPgmOptInstPtr(p,numId,instIdx,&rp,&vp) != kOkPoRC )
  724. return 0;
  725. if( cmIsFlag(rp->flags,kCharPoFl) )
  726. {
  727. cmErrMsg(&p->err,kTypeErrPoRC,"The parameter '%s' is not a 'char'.",rp->wordId);
  728. return 0;
  729. }
  730. return vp->c;
  731. }
  732. bool cmPgmOptArgBool( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  733. {
  734. const _cmPoOpt_t* rp = NULL;
  735. const _cmPoValue_t* vp = NULL;
  736. _cmPo_t* p = _cmPoHandleToPtr(h);
  737. if(_cmPgmOptInstPtr(p,numId,instIdx,&rp,&vp) != kOkPoRC )
  738. return 0;
  739. // all types have a meaning in terms of bool
  740. return vp->b;
  741. }
  742. int cmPgmOptArgInt( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  743. {
  744. cmPoRC_t rc;
  745. const _cmPoOpt_t* rp = NULL;
  746. const _cmPoValue_t* vp = NULL;
  747. _cmPo_t* p = _cmPoHandleToPtr(h);
  748. int v = 0;
  749. if((rc = _cmPgmOptInstPtr(p,numId,instIdx,&rp,&vp)) != kOkPoRC )
  750. return rc;
  751. switch( rp->flags & kTypeMaskPoFl )
  752. {
  753. case kBoolPoFl: v = vp->b; break;
  754. case kCharPoFl: v = vp->c; break;
  755. case kIntPoFl:
  756. case kEnumPoFl: v = vp->i; break;
  757. case kUIntPoFl:
  758. case kHexPoFl: v = vp->u; break;
  759. case kDblPoFl: v = roundl(vp->d); break;
  760. case kStrPoFl:
  761. cmErrMsg(&p->err,kTypeErrPoRC,"The string parameter '%s' cannot be converted to an integer.",rp->wordId);
  762. break;
  763. default:
  764. assert(0);
  765. break;
  766. }
  767. return v;
  768. }
  769. unsigned cmPgmOptArgUInt( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  770. { return cmPgmOptArgInt(h,numId,instIdx); }
  771. double cmPgmOptArgDbl( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  772. {
  773. cmPoRC_t rc;
  774. const _cmPoOpt_t* rp = NULL;
  775. const _cmPoValue_t* vp = NULL;
  776. _cmPo_t* p = _cmPoHandleToPtr(h);
  777. double v = 0;
  778. if((rc = _cmPgmOptInstPtr(p,numId,instIdx,&rp,&vp)) != kOkPoRC )
  779. return rc;
  780. switch( rp->flags & kTypeMaskPoFl )
  781. {
  782. case kBoolPoFl: v = vp->b; break;
  783. case kCharPoFl: v = vp->c; break;
  784. case kEnumPoFl:
  785. case kIntPoFl: v = vp->i; break;
  786. case kHexPoFl:
  787. case kUIntPoFl: v = vp->u; break;
  788. case kDblPoFl: v = vp->d; break;
  789. case kStrPoFl:
  790. cmErrMsg(&p->err,kTypeErrPoRC,"The string parameter '%s' cannot be converted to a double.",rp->wordId);
  791. break;
  792. default:
  793. assert(0);
  794. break;
  795. }
  796. return v;
  797. }
  798. const char* cmPgmOptArgStr( cmPgmOptH_t h, unsigned numId, unsigned instIdx )
  799. {
  800. cmPoRC_t rc;
  801. const _cmPoOpt_t* rp = NULL;
  802. const _cmPoValue_t* vp = NULL;
  803. _cmPo_t* p = _cmPoHandleToPtr(h);
  804. if((rc = _cmPgmOptInstPtr(p,numId,instIdx,&rp,&vp)) != kOkPoRC )
  805. return NULL;
  806. // if the requested param is a defined as a string
  807. if( cmIsFlag(rp->flags,kStrPoFl) )
  808. return vp->s;
  809. // otherwise the requested param is not defined as a string - so try to return the instance string value
  810. const _cmPoArg_t* a = rp->inst;
  811. unsigned i;
  812. for(i=0; i<instIdx && a != NULL; ++i)
  813. a = a->inst;
  814. // if the index is not valid
  815. if( i != instIdx )
  816. {
  817. cmErrMsg(&p->err,kInstNotFoundPoRC,"The instance index %i is not valid for parameter %s instance count %i.",instIdx,rp->wordId,i);
  818. return NULL;
  819. }
  820. // otherwise return the instance string
  821. return a->valStr;
  822. }
  823. cmPoRC_t cmPgmOptRC( cmPgmOptH_t h, cmPoRC_t rc )
  824. {
  825. _cmPo_t* p = _cmPoHandleToPtr(h);
  826. return cmErrSetRC(&p->err,rc);
  827. }
  828. bool cmPgmOptHandleBuiltInActions( cmPgmOptH_t h, cmRpt_t* rpt )
  829. {
  830. _cmPo_t* p = _cmPoHandleToPtr(h);
  831. _cmPoArg_t* a = p->args;
  832. while( a != NULL )
  833. {
  834. switch( a->opt->numId )
  835. {
  836. case kPrintHelpPoId:
  837. cmPgmOptPrintHelp(h,rpt);
  838. break;
  839. case kVersionPoId:
  840. cmPgmOptPrintVersion(h,rpt);
  841. break;
  842. case kPrintParmsPoId:
  843. cmPgmOptPrintParms(h,rpt);
  844. break;
  845. }
  846. a = a->link;
  847. }
  848. return p->execFl;
  849. }
  850. void cmPgmOptPrintHelp( cmPgmOptH_t h, cmRpt_t* rpt )
  851. {
  852. _cmPo_t* p = _cmPoHandleToPtr(h);
  853. const _cmPoOpt_t* r = p->list;
  854. if( p->helpBegStr != NULL )
  855. cmRptPrintf(rpt,"%s\n",p->helpBegStr);
  856. while( r != NULL )
  857. {
  858. cmRptPrintf(rpt,"-%c --%-20s ",r->charId,r->wordId);
  859. if( r->helpStr != NULL )
  860. cmRptPrintf(rpt," %s\n",r->helpStr);
  861. r = r->link;
  862. }
  863. if( p->helpEndStr != NULL )
  864. cmRptPrintf(rpt,"\n%s\n",p->helpEndStr);
  865. }
  866. void cmPgmOptPrintVersion( cmPgmOptH_t h, cmRpt_t* rpt )
  867. {
  868. cmRptPrintf(rpt,"%s\n",PACKAGE_STRING); // PACKAGE_STRING is defined in config.h
  869. }
  870. bool _cmPgmOptPrint( _cmPo_t* p, cmRpt_t* rpt, const _cmPoOpt_t* r, const _cmPoValue_t* v, const cmChar_t* valStr )
  871. {
  872. const _cmPoOpt_t* e = r;
  873. if( cmIsFlag(r->flags,kEnumPoFl) )
  874. {
  875. if( r->enumPtr != NULL )
  876. return false;
  877. if((e = _cmPgmOptEnumIdToOptRecd(p,r->numId,v->u)) == NULL )
  878. {
  879. cmErrMsg(&p->err,kParmNotFoundPoRC,"The parm. defn. could not be found for numId=%i enumId=%i.",r->numId,v->u);
  880. return false;
  881. }
  882. }
  883. cmRptPrintf(rpt,"-%c --%-20s %i ",e->charId,e->wordId, _cmPgmOptInstCount(r));
  884. switch(r->flags & kTypeMaskPoFl)
  885. {
  886. case kBoolPoFl: cmRptPrintf(rpt,"%c ", v->b ? 'T' : 'F'); break;
  887. case kCharPoFl: cmRptPrintf(rpt,"%c ", v->c); break;
  888. case kIntPoFl: cmRptPrintf(rpt,"%i ", v->i); break;
  889. case kUIntPoFl: cmRptPrintf(rpt,"%u ", v->u); break;
  890. case kHexPoFl: cmRptPrintf(rpt,"0x%x ",v->u); break;
  891. case kDblPoFl: cmRptPrintf(rpt,"%f ", v->d); break;
  892. case kStrPoFl: cmRptPrintf(rpt,"%s ", v->s); break;
  893. case kEnumPoFl: cmRptPrintf(rpt,"%i ", v->u); break;
  894. default:
  895. cmRptPrintf(rpt,"%s ",cmStringNullGuard(valStr)); break;
  896. }
  897. return true;
  898. }
  899. void cmPgmOptPrintParms( cmPgmOptH_t h, cmRpt_t* rpt )
  900. {
  901. _cmPo_t* p = _cmPoHandleToPtr(h);
  902. _cmPoArg_t* a = p->args;
  903. // print the given arguments
  904. while( a != NULL )
  905. {
  906. if(_cmPgmOptPrint(p, rpt, a->opt,&a->u,a->valStr))
  907. cmRptPrintf(rpt,"\n");
  908. a = a->link;
  909. }
  910. // print the default values
  911. _cmPoOpt_t* r = p->list;
  912. while( r != NULL )
  913. {
  914. if( r->inst == NULL )
  915. {
  916. if(_cmPgmOptPrint(p,rpt,r,&r->dfltVal,NULL))
  917. cmRptPrintf(rpt,"\n");
  918. }
  919. r = r->link;
  920. }
  921. }