libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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. }