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.

cmPrefs.c 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFileSys.h"
  10. #include "cmText.h"
  11. #include "cmJson.h"
  12. #include "cmPrefs.h"
  13. cmPrH_t cmPrNullHandle = cmSTATIC_NULL_HANDLE;
  14. typedef struct cmPrCb_str
  15. {
  16. cmPrefsOnChangeFunc_t cbFunc;
  17. void* cbDataPtr;
  18. struct cmPrCb_str* linkPtr;
  19. } cmPrCb_t;
  20. // Link record used by cmPrNode_t to form the
  21. // path labels for each pref. node.
  22. typedef struct cmPrPath_str
  23. {
  24. const cmChar_t* label;
  25. struct cmPrPath_str* parentPtr;
  26. } cmPrPath_t;
  27. // Every pair in the prefs JSON tree is given a unique id.
  28. // The 'path' chain forms a path of pair labels which names the variable.
  29. typedef struct cmPrNode_str
  30. {
  31. unsigned id; // unique id assigned to this pref node
  32. cmJsonNode_t* nodePtr; // pointer to the JSON value for this pref node
  33. cmPrPath_t* pathPtr; // pointer to the path label chain for this node
  34. struct cmPrNode_str* linkPtr; // link used to form the pref. node chain
  35. } cmPrNode_t;
  36. typedef struct
  37. {
  38. cmErr_t err; //
  39. cmJsonH_t jsH; // json tree
  40. cmLHeapH_t lhH; // linked heap handle
  41. cmChar_t* fn; // default filename
  42. bool dirtyFl; //
  43. cmPrCb_t* cbChainPtr; // callback record linked list
  44. cmPrNode_t* idChainPtr; //
  45. unsigned id; // next JSON node id
  46. cmChar_t* pathBuf;
  47. } cmPr_t;
  48. cmPr_t* _cmPrefsHandleToPtr( cmPrH_t h )
  49. {
  50. assert(h.h != NULL);
  51. return (cmPr_t*)h.h;
  52. }
  53. cmPrNode_t* _cmPrefsIdToNodePtr( cmPr_t* p, unsigned id, bool reportErrFl )
  54. {
  55. if( id == cmInvalidId )
  56. {
  57. cmErrMsg(&p->err,kInvalidIdPrRC,"No preference variables can use the id:%i.",id);
  58. return NULL;
  59. }
  60. cmPrNode_t* np = p->idChainPtr;
  61. for(; np!=NULL; np=np->linkPtr)
  62. if( np->id == id )
  63. return np;
  64. if( reportErrFl )
  65. cmErrMsg(&p->err,kVarNotFoundPrRC,"The preference variable associated with id:%i does not exist.",id);
  66. return NULL;
  67. }
  68. unsigned _cmPrefsCalcNextAvailId( cmPr_t* p )
  69. {
  70. while( _cmPrefsIdToNodePtr( p, p->id, false) != NULL )
  71. ++p->id;
  72. return p->id;
  73. }
  74. cmPrNode_t* _cmPrefsCreateNode( cmPr_t* p, const cmJsonNode_t* jsPairNodePtr, cmPrPath_t* parentPathPtr )
  75. {
  76. assert( jsPairNodePtr->typeId == kPairTId );
  77. cmPrNode_t* np = cmLHeapAllocZ( p->lhH, sizeof(cmPrNode_t) );
  78. np->id = cmInvalidId;
  79. np->pathPtr = cmLHeapAllocZ( p->lhH, sizeof(cmPrPath_t) );
  80. np->pathPtr->label = jsPairNodePtr->u.childPtr->u.stringVal;
  81. np->pathPtr->parentPtr = parentPathPtr;
  82. np->nodePtr = jsPairNodePtr->u.childPtr->siblingPtr;
  83. np->linkPtr = p->idChainPtr;
  84. p->idChainPtr = np;
  85. // object and pair nodes cannot be returned as pref values - so do not give them id's
  86. if( cmJsonIsObject(np->nodePtr)==false && cmJsonIsPair(np->nodePtr)==false )
  87. np->id = _cmPrefsCalcNextAvailId(p);
  88. return np;
  89. }
  90. void _cmPrefsBuildIdList( cmPr_t* p, const cmJsonNode_t* jsnPtr, cmPrPath_t* parentPathPtr )
  91. {
  92. assert( jsnPtr != NULL );
  93. if( jsnPtr->typeId == kPairTId )
  94. {
  95. cmPrNode_t* np = _cmPrefsCreateNode(p,jsnPtr,parentPathPtr);
  96. _cmPrefsBuildIdList( p, jsnPtr->u.childPtr->siblingPtr, np->pathPtr );
  97. }
  98. else
  99. if( cmJsonChildCount(jsnPtr) )
  100. {
  101. const cmJsonNode_t* np = jsnPtr->u.childPtr;
  102. for(; np != NULL; np = np->siblingPtr )
  103. _cmPrefsBuildIdList(p,np,parentPathPtr);
  104. }
  105. }
  106. void _cmPrefsInstallCallback( cmPr_t* p, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr )
  107. {
  108. cmPrCb_t* nrp = cmLHeapAllocZ( p->lhH, sizeof(cmPrCb_t));
  109. nrp->cbFunc = cbFunc;
  110. nrp->cbDataPtr = cbDataPtr;
  111. cmPrCb_t* cp = p->cbChainPtr;
  112. // if the cb chain is empty ...
  113. if(cp == NULL)
  114. p->cbChainPtr = nrp;// ... make the new cb the first on the chain
  115. else
  116. {
  117. // ... otherwise add the new cb to the end of the cb chain
  118. while( cp->linkPtr != NULL )
  119. cp = cp->linkPtr;
  120. cp->linkPtr = nrp;
  121. }
  122. }
  123. cmPrRC_t _cmPrefsFinalize( cmPr_t* p )
  124. {
  125. cmPrRC_t rc = kOkPrRC;
  126. if( cmLHeapIsValid(p->lhH) )
  127. cmLHeapDestroy(&p->lhH);
  128. if( cmJsonIsValid(p->jsH) )
  129. if( cmJsonFinalize(&p->jsH) != kOkJsRC )
  130. rc = cmErrMsg(&p->err,kJsonFailPrRC,"JSON finalization failed.");
  131. cmMemPtrFree(&p->pathBuf);
  132. cmMemFree(p);
  133. return rc;
  134. }
  135. // Convert 'pathString' to a sequence of zero terminated sub-strings.
  136. // The character string returned from this function must be released with a
  137. // call to cmMemFree()
  138. cmChar_t* _cmPrefsCreatePathStr( const cmChar_t* pathString, int* cnt )
  139. {
  140. assert( pathString != NULL );
  141. // duplicate the path string
  142. cmChar_t* pathStr = cmMemAllocStr(pathString);
  143. int i = 0;
  144. int n = 1;
  145. for(i=0; pathStr[i]; ++i)
  146. if( pathStr[i]=='/' )
  147. {
  148. pathStr[i] = 0;
  149. ++n;
  150. }
  151. *cnt = n;
  152. return pathStr;
  153. }
  154. unsigned _cmPrefsId( cmPr_t* p, const cmChar_t* pathStr, bool reportErrFl )
  155. {
  156. int n = 1;
  157. int i;
  158. unsigned retId = cmInvalidId;
  159. cmChar_t* path = _cmPrefsCreatePathStr(pathStr, &n );
  160. const cmChar_t* pathArray[n];
  161. const cmChar_t* cp = path;
  162. // store path parts in reverse order - because this
  163. // is the way the node sees the path
  164. for(i=n-1; i>=0; --i)
  165. {
  166. pathArray[i] = cp;
  167. cp += strlen(cp) + 1;
  168. }
  169. const cmPrNode_t* np = p->idChainPtr;
  170. // go down the id chain
  171. for(; retId==cmInvalidId && np != NULL; np=np->linkPtr)
  172. {
  173. unsigned i = 0;
  174. const cmPrPath_t* pp = np->pathPtr;
  175. // go down the path chain from leaf to root
  176. while( strcmp(pp->label,pathArray[i]) == 0 )
  177. {
  178. ++i;
  179. pp = pp->parentPtr;
  180. // if the match is complete
  181. if( i==n && pp==NULL)
  182. {
  183. retId = np->id;
  184. break;
  185. }
  186. }
  187. }
  188. if( retId==cmInvalidId && reportErrFl )
  189. cmErrMsg(&p->err,kVarNotFoundPrRC,"The preference variable '%s' was not found.",pathStr);
  190. cmMemFree(path);
  191. return retId;
  192. }
  193. cmPrNode_t* _cmPrefsPathToNodePtr( cmPr_t* p, const cmChar_t* pathStr, bool reportErrFl )
  194. {
  195. unsigned id;
  196. if((id = _cmPrefsId(p,pathStr,reportErrFl)) == cmInvalidId )
  197. return NULL;
  198. return _cmPrefsIdToNodePtr(p,id, reportErrFl);
  199. }
  200. cmPrRC_t cmPrefsInitialize( cmPrH_t* hp, const cmChar_t* fn, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr, cmCtx_t* ctx )
  201. {
  202. cmPrRC_t rc = kOkPrRC;
  203. if((rc = cmPrefsFinalize(hp)) != kOkPrRC)
  204. return rc;
  205. cmPr_t* p = cmMemAllocZ( cmPr_t, 1 );
  206. cmErrSetup(&p->err,&ctx->rpt,"Preferences");
  207. // initialize a linked heap
  208. if( cmLHeapIsValid(p->lhH = cmLHeapCreate(1024,ctx))==false )
  209. {
  210. rc = cmErrMsg(&p->err,kLHeapFailPrRC,"Linked heap initialization failed.");
  211. goto errLabel;
  212. }
  213. // if the preference file exists
  214. if( cmFsIsFile(fn) )
  215. {
  216. // initialize the JSON tree from the preferences file
  217. if( cmJsonInitializeFromFile( &p->jsH, fn, ctx ) != kOkJsRC )
  218. {
  219. rc = cmErrMsg(&p->err,kJsonFailPrRC,"Preferences initialization failed on JSON initialization.");
  220. goto errLabel;
  221. }
  222. // build the id list
  223. _cmPrefsBuildIdList(p, cmJsonRoot(p->jsH), NULL );
  224. }
  225. else // otherwise create an empty JSON tree
  226. {
  227. if( cmJsonInitialize( &p->jsH, ctx ) != kOkJsRC )
  228. {
  229. rc = cmErrMsg(&p->err,kJsonFailPrRC,"An empty JSON tree could not be created.");
  230. goto errLabel;
  231. }
  232. if( cmJsonCreateObject( p->jsH, NULL ) != kOkJsRC )
  233. {
  234. rc = cmErrMsg(&p->err,kJsonFailPrRC,"The JSON root object could not be created.");
  235. goto errLabel;
  236. }
  237. }
  238. // install the callback function
  239. if( cbFunc != NULL )
  240. _cmPrefsInstallCallback(p,cbFunc,cbDataPtr);
  241. // store the file name
  242. p->fn = cmLHeapAllocZ( p->lhH, strlen(fn)+1 );
  243. strcpy(p->fn,fn);
  244. hp->h = p;
  245. errLabel:
  246. if( rc != kOkPrRC )
  247. {
  248. _cmPrefsFinalize(p);
  249. hp-> h = NULL;
  250. }
  251. return rc;
  252. }
  253. cmPrRC_t cmPrefsFinalize( cmPrH_t* hp )
  254. {
  255. cmPrRC_t rc = kOkPrRC;
  256. if( hp==NULL || hp->h == NULL )
  257. return kOkPrRC;
  258. if((rc = _cmPrefsFinalize( _cmPrefsHandleToPtr(*hp))) == kOkPrRC )
  259. return rc;
  260. hp->h = NULL;
  261. return rc;
  262. }
  263. bool cmPrefsIsValid( cmPrH_t h )
  264. { return h.h != NULL; }
  265. cmPrRC_t cmPrefsRC( cmPrH_t h)
  266. { return cmErrLastRC(&_cmPrefsHandleToPtr(h)->err); }
  267. cmPrRC_t cmPrefsSetRC( cmPrH_t h, cmPrRC_t rc )
  268. { return cmErrSetRC(&_cmPrefsHandleToPtr(h)->err,rc); }
  269. cmPrRC_t cmPrefsInstallCallback( cmPrH_t h, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr )
  270. {
  271. cmPr_t* p = _cmPrefsHandleToPtr(h);
  272. _cmPrefsInstallCallback(p,cbFunc,cbDataPtr);
  273. return kOkPrRC;
  274. }
  275. cmPrRC_t cmPrefsRemoveCallback( cmPrH_t h, cmPrefsOnChangeFunc_t cbFunc )
  276. {
  277. cmPr_t* p = _cmPrefsHandleToPtr(h);
  278. cmPrCb_t* cc = p->cbChainPtr;
  279. cmPrCb_t* pc = NULL;
  280. while( cc == NULL )
  281. {
  282. if( cc->cbFunc == cbFunc )
  283. {
  284. if( pc == NULL )
  285. p->cbChainPtr = cc->linkPtr;
  286. else
  287. pc->linkPtr = cc->linkPtr;
  288. break;
  289. }
  290. pc = cc;
  291. cc = cc->linkPtr;
  292. }
  293. if( cc == NULL )
  294. return cmErrMsg(&p->err,kCbNotFoundPrRC,"The callback function %p could not be found.",cbFunc);
  295. return kOkPrRC;
  296. }
  297. unsigned cmPrefsId( cmPrH_t h, const cmChar_t* pathStr, bool reportErrFl )
  298. {
  299. cmPr_t* p = _cmPrefsHandleToPtr(h);
  300. return _cmPrefsId(p,pathStr,reportErrFl);
  301. }
  302. unsigned cmPrefsEleCount( cmPrH_t h, unsigned id )
  303. {
  304. cmPr_t* p = _cmPrefsHandleToPtr(h);
  305. cmPrNode_t* np = _cmPrefsIdToNodePtr(p,id,true);
  306. if( np == NULL )
  307. return -1;
  308. if( cmJsonIsArray(np->nodePtr) )
  309. return cmJsonChildCount(np->nodePtr);
  310. return 1;
  311. }
  312. void _cmPrefsFormPath( cmPr_t* p, const cmPrNode_t* np )
  313. {
  314. cmPrPath_t* pp = np->pathPtr;
  315. int n = 0;
  316. for(; pp!=NULL; pp=pp->parentPtr)
  317. ++n;
  318. const char* pathArray[n];
  319. unsigned i = n-1;
  320. for(pp = np->pathPtr; pp!=NULL; pp=pp->parentPtr,--i)
  321. pathArray[i] = pp->label;
  322. cmMemPtrFree(&p->pathBuf);
  323. for(i=0; i<n; ++i)
  324. {
  325. if( i > 0 )
  326. p->pathBuf = cmTextAppendSS(p->pathBuf,"/");
  327. p->pathBuf = cmTextAppendSS(p->pathBuf,pathArray[i]);
  328. }
  329. }
  330. cmPrRC_t _cmPrefsValue( cmPr_t* p, const cmPrNode_t* np, const cmJsonNode_t* jnp, bool* bvp, int* ivp, double* rvp, const cmChar_t** svp, unsigned retEleCnt )
  331. {
  332. cmJsRC_t jsRC = kOkJsRC;
  333. const char* typeLabel = NULL;
  334. // verify that adequate return space was provided
  335. if( retEleCnt < 1 )
  336. {
  337. _cmPrefsFormPath(p,np);
  338. return cmErrMsg(&p->err,kBufTooSmallPrRC,"No return space was provided for the preference variable '%s' (id:%i).",p->pathBuf,np->id);
  339. }
  340. if( bvp != NULL )
  341. {
  342. jsRC = cmJsonBoolValue(jnp,bvp);
  343. typeLabel = "bool";
  344. }
  345. else
  346. if( ivp != NULL )
  347. {
  348. jsRC = cmJsonIntValue(jnp,ivp);
  349. typeLabel = "int";
  350. }
  351. else
  352. if( rvp != NULL )
  353. {
  354. jsRC = cmJsonRealValue(jnp,rvp);
  355. typeLabel = "real";
  356. }
  357. else
  358. if( svp != NULL )
  359. {
  360. jsRC = cmJsonStringValue(jnp,svp);
  361. typeLabel = "string";
  362. }
  363. else
  364. {
  365. assert(0);
  366. }
  367. if( jsRC != kOkJsRC )
  368. {
  369. _cmPrefsFormPath(p,np);
  370. return cmErrMsg(&p->err,kCvtErrPrRC,"The perferences variable '%s' (id:%i) could not be converted to type '%s'.",p->pathBuf,np->id,typeLabel);
  371. }
  372. return kOkPrRC;
  373. }
  374. cmPrRC_t _cmPrefsGetValue( cmPrH_t h, unsigned id, bool* bvp, int* ivp, double* rvp, const cmChar_t** svp, unsigned* eleCntPtr, unsigned eleIdx )
  375. {
  376. cmPrRC_t rc = kOkPrRC;
  377. cmPr_t* p = _cmPrefsHandleToPtr(h);
  378. cmPrNode_t* np = NULL;
  379. // if no return buffer was given - do nothing
  380. if( *eleCntPtr == 0 )
  381. return kOkPrRC;
  382. // locate the pref node from 'id'
  383. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  384. {
  385. rc = cmErrMsg(&p->err,kVarNotFoundPrRC,"No preference variable was found for id:%i.",id);
  386. goto errLabel;
  387. }
  388. // if the requested pref. var is a scalar
  389. if( cmJsonIsArray(np->nodePtr) == false )
  390. {
  391. if((rc = _cmPrefsValue(p,np,np->nodePtr,bvp,ivp,rvp,svp,*eleCntPtr)) == kOkPrRC )
  392. *eleCntPtr = 1;
  393. }
  394. else // the request pref. var. is an array
  395. {
  396. unsigned i = 0;
  397. unsigned n = cmJsonChildCount(np->nodePtr);
  398. // if the entire array was requestedd
  399. if( eleIdx == cmInvalidIdx )
  400. {
  401. // if the return buffer is too small to hold all of the values.
  402. if( *eleCntPtr < n )
  403. {
  404. *eleCntPtr = 0;
  405. _cmPrefsFormPath(p,np);
  406. rc = cmErrMsg(&p->err,kBufTooSmallPrRC,"The return array for the preference variable '%s' (id:%i) is too small to hold '%i elements",p->pathBuf,np->id,n);
  407. goto errLabel;
  408. }
  409. // read each element
  410. for(i=0; i<n; ++i)
  411. {
  412. const cmJsonNode_t* cnp = cmJsonArrayElement(np->nodePtr,i);
  413. if((rc= _cmPrefsValue(p,np,cnp,bvp==NULL?NULL:bvp+i,ivp==NULL?NULL:ivp+i,rvp==NULL?NULL:rvp+i,svp==NULL?NULL:svp+i,1)) != kOkPrRC )
  414. goto errLabel;
  415. }
  416. *eleCntPtr = n;
  417. }
  418. else // a single ele of the array was requested
  419. {
  420. // validate the index
  421. if( eleIdx >= n )
  422. {
  423. _cmPrefsFormPath(p,np);
  424. rc = cmErrMsg(&p->err,kInvalidIndexPrRC,"The index %i is invalid for the variable '%s' of length %i.",eleIdx,p->pathBuf,n);
  425. goto errLabel;
  426. }
  427. // get the json element at array index 'eleIdx'
  428. const cmJsonNode_t* cnp = cmJsonArrayElement(np->nodePtr,eleIdx);
  429. assert(cnp != NULL );
  430. // read the element from the array
  431. if((rc = _cmPrefsValue(p,np,cnp,bvp,ivp,rvp,svp,*eleCntPtr)) == kOkPrRC )
  432. *eleCntPtr = 1;
  433. }
  434. }
  435. errLabel:
  436. if( rc != kOkPrRC )
  437. *eleCntPtr = 0;
  438. return rc;
  439. }
  440. cmPrRC_t cmPrefsGetBool( cmPrH_t h, unsigned id, bool* vp, unsigned* eleCntPtr )
  441. { return _cmPrefsGetValue(h, id, vp, NULL, NULL, NULL, eleCntPtr, cmInvalidIdx ); }
  442. cmPrRC_t cmPrefsGetInt( cmPrH_t h, unsigned id, int* vp, unsigned* eleCntPtr )
  443. { return _cmPrefsGetValue(h, id, NULL, vp, NULL, NULL, eleCntPtr, cmInvalidIdx ); }
  444. cmPrRC_t cmPrefsGetReal( cmPrH_t h, unsigned id, double* vp, unsigned* eleCntPtr )
  445. { return _cmPrefsGetValue(h, id, NULL, NULL, vp, NULL, eleCntPtr, cmInvalidIdx ); }
  446. cmPrRC_t cmPrefsGetString( cmPrH_t h, unsigned id, const cmChar_t** vp, unsigned* eleCntPtr )
  447. { return _cmPrefsGetValue(h, id, NULL, NULL, NULL, vp, eleCntPtr, cmInvalidIdx ); }
  448. bool cmPrefsBool( cmPrH_t h, unsigned id )
  449. {
  450. bool v = false;
  451. unsigned n = 1;
  452. cmPrefsGetBool(h,id,&v,&n);
  453. return v;
  454. }
  455. unsigned cmPrefsUInt( cmPrH_t h, unsigned id )
  456. {
  457. int v = 0;
  458. unsigned n = 1;
  459. cmPrefsGetInt(h,id,&v,&n);
  460. return (unsigned)v;
  461. }
  462. int cmPrefsInt( cmPrH_t h, unsigned id )
  463. {
  464. int v = 0;
  465. unsigned n = 1;
  466. cmPrefsGetInt(h,id,&v,&n);
  467. return v;
  468. }
  469. float cmPrefsFloat( cmPrH_t h, unsigned id )
  470. {
  471. double v = 0;
  472. unsigned n = 1;
  473. cmPrefsGetReal(h,id,&v,&n);
  474. return (float)v;
  475. }
  476. double cmPrefsReal( cmPrH_t h, unsigned id )
  477. {
  478. double v = 0;
  479. unsigned n = 1;
  480. cmPrefsGetReal(h,id,&v,&n);
  481. return v;
  482. }
  483. const cmChar_t* cmPrefsString( cmPrH_t h, unsigned id )
  484. {
  485. const cmChar_t* v = NULL;
  486. unsigned n = 1;
  487. if( cmPrefsGetString(h,id,&v,&n) == kOkPrRC )
  488. return v==NULL ? "" : v;
  489. return "";
  490. }
  491. bool cmPrefsBoolDef( cmPrH_t h, const cmChar_t* pathStr, bool dfltVal )
  492. {
  493. unsigned id;
  494. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  495. return dfltVal;
  496. return cmPrefsBool(h,id);
  497. }
  498. unsigned cmPrefsUIntDef( cmPrH_t h, const cmChar_t* pathStr, unsigned dfltVal )
  499. {
  500. unsigned id;
  501. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  502. return dfltVal;
  503. return cmPrefsUInt(h,id);
  504. }
  505. int cmPrefsIntDef( cmPrH_t h, const cmChar_t* pathStr, int dfltVal )
  506. {
  507. unsigned id;
  508. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  509. return dfltVal;
  510. return cmPrefsInt(h,id);
  511. }
  512. float cmPrefsFloatDef( cmPrH_t h, const cmChar_t* pathStr, float dfltVal )
  513. {
  514. unsigned id;
  515. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  516. return dfltVal;
  517. return cmPrefsFloat(h,id);
  518. }
  519. double cmPrefsRealDef( cmPrH_t h, const cmChar_t* pathStr, double dfltVal )
  520. {
  521. unsigned id;
  522. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  523. return dfltVal;
  524. return cmPrefsReal(h,id);
  525. }
  526. const cmChar_t* cmPrefsStringDef( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t* dfltVal )
  527. {
  528. unsigned id;
  529. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  530. return dfltVal;
  531. const cmChar_t* v = cmPrefsString(h,id);
  532. return v==NULL || strlen(v)==0 ? dfltVal : v;
  533. }
  534. cmPrRC_t cmPrefsScalarBool( cmPrH_t h, const cmChar_t* pathStr, bool* retValPtr )
  535. {
  536. unsigned id;
  537. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  538. return kVarNotFoundPrRC;
  539. unsigned n = 1;
  540. return cmPrefsGetBool(h,id,retValPtr,&n);
  541. }
  542. cmPrRC_t cmPrefsScalarUInt( cmPrH_t h, const cmChar_t* pathStr, unsigned* retValPtr )
  543. {
  544. unsigned id;
  545. unsigned n = 1;
  546. int v;
  547. cmPrRC_t rc;
  548. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  549. return kVarNotFoundPrRC;
  550. if((rc =cmPrefsGetInt(h,id,&v,&n)) == kOkPrRC )
  551. *retValPtr = v;
  552. return rc;
  553. }
  554. cmPrRC_t cmPrefsScalarInt( cmPrH_t h, const cmChar_t* pathStr, int* retValPtr )
  555. {
  556. unsigned id;
  557. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  558. return kVarNotFoundPrRC;
  559. unsigned n = 1;
  560. return cmPrefsGetInt(h,id,retValPtr,&n);
  561. }
  562. cmPrRC_t cmPrefsScalarFloat( cmPrH_t h, const cmChar_t* pathStr, float* retValPtr )
  563. {
  564. unsigned id;
  565. unsigned n = 1;
  566. double v;
  567. cmPrRC_t rc;
  568. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  569. return kVarNotFoundPrRC;
  570. if((rc =cmPrefsGetReal(h,id,&v,&n)) == kOkPrRC )
  571. *retValPtr = v;
  572. return rc;
  573. }
  574. cmPrRC_t cmPrefsScalarReal( cmPrH_t h, const cmChar_t* pathStr, double* retValPtr )
  575. {
  576. unsigned id;
  577. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  578. return kVarNotFoundPrRC;
  579. unsigned n = 1;
  580. return cmPrefsGetReal(h,id,retValPtr,&n);
  581. }
  582. cmPrRC_t cmPrefsScalarString( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t** retValPtr )
  583. {
  584. unsigned id;
  585. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  586. return kVarNotFoundPrRC;
  587. unsigned n = 1;
  588. return cmPrefsGetString(h,id,retValPtr,&n);
  589. }
  590. unsigned cmPrefsArrayElementCount( cmPrH_t h, unsigned id )
  591. {
  592. cmPrNode_t* np;
  593. cmPr_t* p = _cmPrefsHandleToPtr(h);
  594. // locate the pref node from 'id'
  595. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  596. {
  597. cmErrMsg(&p->err,kVarNotFoundPrRC,"No preference variable was found for id:%i.",id);
  598. return cmInvalidCnt;
  599. }
  600. // if the requested pref. var is a scalar
  601. if( cmJsonIsArray(np->nodePtr) )
  602. return cmJsonChildCount(np->nodePtr);
  603. return 0;
  604. }
  605. bool cmPrefsBoolEle( cmPrH_t h, unsigned id, unsigned idx )
  606. {
  607. bool v = false;;
  608. unsigned n = 1;
  609. _cmPrefsGetValue(h,id, &v, NULL, NULL, NULL, &n, idx );
  610. return v;
  611. }
  612. unsigned cmPrefsUIntEle( cmPrH_t h, unsigned id, unsigned idx )
  613. {
  614. int v = 0;
  615. unsigned n = 1;
  616. _cmPrefsGetValue(h,id, NULL, &v, NULL, NULL, &n, idx );
  617. return (unsigned)v;
  618. }
  619. int cmPrefsIntEle( cmPrH_t h, unsigned id, unsigned idx )
  620. {
  621. int v = 0;
  622. unsigned n = 1;
  623. _cmPrefsGetValue(h,id, NULL, &v, NULL, NULL, &n, idx );
  624. return v;
  625. }
  626. float cmPrefsFloatEle( cmPrH_t h, unsigned id, unsigned idx )
  627. {
  628. double v = 0;
  629. unsigned n = 1;
  630. _cmPrefsGetValue(h,id, NULL, NULL, &v, NULL, &n, idx );
  631. return (float)v;
  632. }
  633. double cmPrefsRealEle( cmPrH_t h, unsigned id, unsigned idx )
  634. {
  635. double v = 0;
  636. unsigned n = 1;
  637. _cmPrefsGetValue(h,id, NULL, NULL, &v, NULL, &n, idx );
  638. return v;
  639. }
  640. const cmChar_t* cmPrefsStringEle( cmPrH_t h, unsigned id, unsigned idx )
  641. {
  642. const cmChar_t* v = "";
  643. unsigned n = 1;
  644. if( _cmPrefsGetValue(h,id, NULL, NULL, NULL, &v, &n, idx ) == kOkPrRC )
  645. return v;
  646. return "";
  647. }
  648. cmPrRC_t _cmPrefsSetValue( cmPr_t* p, cmPrNode_t* np, cmJsonNode_t* jnp,const bool* bvp, const int* ivp, const double* rvp, const cmChar_t** svp, bool* deltaFlPtr )
  649. {
  650. cmJsRC_t jsRC = kOkJsRC;
  651. //const cmChar_t* typeLabel;
  652. if( bvp != NULL )
  653. {
  654. bool v;
  655. if((jsRC = cmJsonBoolValue(jnp,&v)) == kOkJsRC )
  656. if( (*deltaFlPtr = (v != *bvp)) )
  657. jsRC = cmJsonSetBool(p->jsH,jnp,*bvp);
  658. //typeLabel = "bool";
  659. }
  660. else
  661. if( ivp != NULL )
  662. {
  663. int v;
  664. if((jsRC = cmJsonIntValue(jnp,&v)) == kOkJsRC )
  665. if( (*deltaFlPtr = (v != *ivp)) )
  666. jsRC = cmJsonSetInt(p->jsH,jnp,*ivp);
  667. //typeLabel = "int";
  668. }
  669. else
  670. if( rvp != NULL )
  671. {
  672. double v;
  673. if((jsRC = cmJsonRealValue(jnp,&v)) == kOkJsRC )
  674. if( (*deltaFlPtr = (v != *rvp)) )
  675. jsRC = cmJsonSetReal(p->jsH,jnp,*rvp);
  676. //typeLabel = "real";
  677. }
  678. else
  679. if( svp != NULL )
  680. {
  681. const cmChar_t* v;
  682. if((jsRC = cmJsonStringValue(jnp,&v)) == kOkJsRC )
  683. {
  684. const cmChar_t* s0 = v ==NULL ? "" : v;
  685. const cmChar_t* s1 = *svp==NULL ? "" : *svp;
  686. if( (*deltaFlPtr = (strcmp(s0,s1)!=0)) )
  687. jsRC = cmJsonSetString(p->jsH,jnp,s1);
  688. }
  689. //typeLabel = "string";
  690. }
  691. else
  692. {
  693. assert(0);
  694. }
  695. if( jsRC != kOkJsRC )
  696. {
  697. _cmPrefsFormPath(p,np);
  698. return cmErrMsg(&p->err,kCvtErrPrRC,"The perferences variable '%s' (id:%i) could not be set.",p->pathBuf,np->id);
  699. }
  700. return kOkPrRC;
  701. }
  702. void _cmPrefsCallback( cmPr_t* p, unsigned id )
  703. {
  704. // notify any listeners that a node has changed values
  705. cmPrCb_t* cbNodePtr = p->cbChainPtr;
  706. for(; cbNodePtr!=NULL; cbNodePtr=cbNodePtr->linkPtr)
  707. {
  708. cmPrH_t h;
  709. h.h = p;
  710. cbNodePtr->cbFunc(h,cbNodePtr->cbDataPtr,id);
  711. }
  712. }
  713. cmPrRC_t _cmPrefsSetValues2( cmPr_t* p, cmPrNode_t* np, const bool* bvp, const int* ivp, const double* rvp, const cmChar_t** svp, const unsigned* eleCntPtr )
  714. {
  715. cmPrRC_t rc = kOkPrRC;
  716. bool deltaFl = false; // set to true if the value of the pref. var. identified by 'id' actually changes.
  717. // a scalar has been passed in and the existing json node is also a scalar
  718. if( cmJsonIsArray(np->nodePtr)== false && *eleCntPtr==1 )
  719. {
  720. rc = _cmPrefsSetValue(p,np,np->nodePtr,bvp,ivp,rvp,svp,&deltaFl);
  721. goto errLabel;
  722. }
  723. // the pref. variable is an array
  724. if( cmJsonIsArray(np->nodePtr) )
  725. {
  726. unsigned i;
  727. unsigned curArrCnt = cmJsonChildCount(np->nodePtr);
  728. unsigned n = cmMin(*eleCntPtr,curArrCnt);
  729. for(i=0; i<n; ++i)
  730. {
  731. cmJsonNode_t* jnp = cmJsonArrayElement(np->nodePtr,i);
  732. bool dfl = false;
  733. if((rc = _cmPrefsSetValue(p,np,jnp,bvp==NULL?NULL:bvp+i,ivp==NULL?NULL:ivp+i,rvp==NULL?NULL:rvp+i,svp==NULL?NULL:svp+i,&dfl)) != kOkPrRC )
  734. return rc;
  735. if( dfl )
  736. deltaFl = true;
  737. }
  738. // if elements should be removed
  739. if( curArrCnt > *eleCntPtr )
  740. {
  741. deltaFl = true; // ele's are being removed so the variable value is changing
  742. for(i=*eleCntPtr; i<curArrCnt; ++i)
  743. {
  744. cmJsonNode_t* jnp = cmJsonArrayElement(np->nodePtr,*eleCntPtr);
  745. assert(jnp!=NULL);
  746. cmJsonRemoveNode(p->jsH,jnp,true);
  747. }
  748. }
  749. // if elements should be added
  750. if( *eleCntPtr > curArrCnt )
  751. {
  752. unsigned typeId = cmInvalidId;
  753. cmJsonNode_t* jnp = NULL;
  754. cmJsonNode_t* snp = curArrCnt==0 ? NULL : cmJsonArrayElement(np->nodePtr,curArrCnt-1);
  755. assert(snp->ownerPtr==np->nodePtr && snp->siblingPtr==NULL);
  756. deltaFl = true; // ele's are being added so the variable value is changing
  757. if( ivp != NULL )
  758. typeId = kIntTId;
  759. else
  760. if( rvp != NULL )
  761. typeId = kRealTId;
  762. else
  763. if( svp != NULL )
  764. typeId = kStringTId;
  765. // for each new array element
  766. for(; i<*eleCntPtr; ++i)
  767. {
  768. if( bvp != NULL )
  769. typeId = bvp[i];
  770. // create the new array element node - the new node is automatically added to the end of the array
  771. if( cmJsonCreate(p->jsH, np->nodePtr, typeId, svp==NULL?NULL:svp[i], ivp==NULL?0:ivp[i], rvp==NULL?0:rvp[i], &jnp ) != kOkJsRC )
  772. {
  773. _cmPrefsFormPath(p,np);
  774. return cmErrMsg(&p->err,kJsonFailPrRC,"Unable to create a value node for '%s' (id=%i).",p->pathBuf,np->id);
  775. }
  776. }
  777. }
  778. errLabel:
  779. if( (rc == kOkPrRC) && deltaFl )
  780. {
  781. _cmPrefsCallback(p, np->id );
  782. // update the global delta flag
  783. p->dirtyFl = true;
  784. }
  785. return rc;
  786. }
  787. _cmPrefsFormPath(p,np);
  788. return cmErrMsg(&p->err,kCvtErrPrRC,"The new preference value could not be converted to the existing preference variable type for '%s' (id=%i).",p->pathBuf,np->id);
  789. }
  790. cmPrRC_t _cmPrefsSetValues( cmPrH_t h, unsigned id, const bool* bvp, const int* ivp, const double* rvp, const cmChar_t** svp, const unsigned* eleCntPtr )
  791. {
  792. cmPr_t* p = _cmPrefsHandleToPtr(h);
  793. cmPrNode_t* np;
  794. // locate the pref node
  795. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  796. return cmErrMsg(&p->err,kVarNotFoundPrRC,"The variable with id=%i was not found.",id);
  797. return _cmPrefsSetValues2( p, np, bvp, ivp, rvp, svp, eleCntPtr );
  798. }
  799. cmPrRC_t cmPrefsSetBool( cmPrH_t h, unsigned id, const bool* vp, const unsigned* eleCntPtr )
  800. { return _cmPrefsSetValues(h, id, vp, NULL, NULL, NULL, eleCntPtr ); }
  801. cmPrRC_t cmPrefsSetInt( cmPrH_t h, unsigned id, const int* vp, const unsigned* eleCntPtr )
  802. { return _cmPrefsSetValues(h, id, NULL, vp, NULL, NULL, eleCntPtr ); }
  803. cmPrRC_t cmPrefsSetReal( cmPrH_t h, unsigned id, const double* vp, const unsigned* eleCntPtr )
  804. { return _cmPrefsSetValues(h, id, NULL, NULL, vp, NULL, eleCntPtr ); }
  805. cmPrRC_t cmPrefsSetString( cmPrH_t h, unsigned id, const cmChar_t** vp, const unsigned* eleCntPtr )
  806. { return _cmPrefsSetValues(h, id, NULL, NULL, NULL, vp, eleCntPtr ); }
  807. cmPrRC_t cmPrefsSetScalarBool( cmPrH_t h, const cmChar_t* pathStr, bool val )
  808. {
  809. unsigned id;
  810. unsigned n = 1;
  811. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  812. return kVarNotFoundPrRC;
  813. return cmPrefsSetBool(h,id,&val,&n);
  814. }
  815. cmPrRC_t cmPrefsSetScalarUInt( cmPrH_t h, const cmChar_t* pathStr, unsigned val )
  816. {
  817. unsigned id;
  818. unsigned n = 1;
  819. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  820. return kVarNotFoundPrRC;
  821. int ival = (int)val;
  822. return cmPrefsSetInt(h,id,&ival,&n);
  823. }
  824. cmPrRC_t cmPrefsSetScalarInt( cmPrH_t h, const cmChar_t* pathStr, int val )
  825. {
  826. unsigned id;
  827. unsigned n = 1;
  828. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  829. return kVarNotFoundPrRC;
  830. return cmPrefsSetInt(h,id,&val,&n);
  831. }
  832. cmPrRC_t cmPrefsSetScalarFloat( cmPrH_t h, const cmChar_t* pathStr, float val )
  833. {
  834. unsigned id;
  835. unsigned n = 1;
  836. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  837. return kVarNotFoundPrRC;
  838. double dval = val;
  839. return cmPrefsSetReal(h,id,&dval,&n);
  840. }
  841. cmPrRC_t cmPrefsSetScalarReal( cmPrH_t h, const cmChar_t* pathStr, double val )
  842. {
  843. unsigned id;
  844. unsigned n = 1;
  845. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  846. return kVarNotFoundPrRC;
  847. return cmPrefsSetReal(h,id,&val,&n);
  848. }
  849. cmPrRC_t cmPrefsSetScalarString( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t* val )
  850. {
  851. unsigned id;
  852. unsigned n = 1;
  853. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  854. return kVarNotFoundPrRC;
  855. return cmPrefsSetString(h,id,&val,&n);
  856. }
  857. bool _cmPrefsValidateNodeType( cmJsonNode_t* np, unsigned jsTypeId, unsigned valCnt )
  858. {
  859. // if we are looking for a scalar node then the type must be jsTypeId
  860. if( valCnt == 1 )
  861. return np->typeId == jsTypeId;
  862. // if we are looking for an array node then the type must be kArrayTId ...
  863. if( np->typeId != kArrayTId )
  864. return false;
  865. unsigned n = cmJsonChildCount(np);
  866. unsigned i = 0;
  867. // ... and all of the array elements must be of type jsTypeId
  868. for(; i<n; ++i)
  869. {
  870. const cmJsonNode_t* cnp = cmJsonArrayElementC(np,i);
  871. assert( cnp != NULL );
  872. if( cnp->typeId != jsTypeId )
  873. return false;
  874. }
  875. return true;
  876. }
  877. //
  878. cmPrRC_t _cmPrefsCreateJsonNode(
  879. cmPr_t* p,
  880. unsigned id, // new variable id
  881. const cmChar_t* pathString, // new variable name
  882. unsigned jsTypeId, // type of new variable
  883. const cmChar_t** strVal, // value of new variable
  884. const double* realVal, //
  885. const int* intVal, //
  886. const bool* boolVal, //
  887. unsigned valCnt, // length of xxxVal[]
  888. bool setFlag ) // true== if same named variable already exists then set the value to xxxVal
  889. {
  890. cmPrRC_t rc = kOkPrRC;
  891. int pathCnt = 0;
  892. cmChar_t* pathStr = _cmPrefsCreatePathStr(pathString,&pathCnt);
  893. const cmChar_t* pathEleStr = pathStr;
  894. cmJsonNode_t* jsnp = cmJsonRoot(p->jsH);
  895. cmJsonNode_t* jsPairNodePtr = NULL;
  896. cmPrNode_t* pnp = NULL; // current pref node pointer
  897. bool existsFl = false; // set if variable already exists
  898. int i;
  899. assert( pathCnt >= 1 );
  900. // for each path element
  901. for(i=0; i<pathCnt; ++i)
  902. {
  903. cmJsonNode_t* tnp = NULL;
  904. // find the child pair node of jsnp named 'pathEleStr'.
  905. if( (tnp = cmJsonNodeMemberValue(jsnp, pathEleStr )) == NULL )
  906. break;
  907. // the located json node must be an object (i<pathCnt-1) or the same type as jsTypeId (i=pathCnt-1)
  908. // This check guarantees that all nodes up to the leaf node are objects and the leaf node matches the created type.
  909. if( !(((i<pathCnt-1) && cmJsonIsObject(tnp)) || ((i==pathCnt-1) && _cmPrefsValidateNodeType(tnp,jsTypeId,valCnt))) )
  910. {
  911. rc = cmErrMsg(&p->err,kNodeCreateFailPrRC,"Node creation for '%s' failed because an existing node with the same name but different type (%i) was found.",pathString,tnp->typeId);
  912. goto errLabel;
  913. }
  914. // assert that the json nodes we are finding form a tree
  915. assert( (tnp->ownerPtr==NULL && jsnp==NULL) || (tnp->ownerPtr!=NULL && tnp->ownerPtr->ownerPtr==jsnp));
  916. jsnp = tnp;
  917. // find the pref node which refers to the located json node
  918. // (we need to track the pnp->pathPtr)
  919. pnp = p->idChainPtr;
  920. for(; pnp != NULL; pnp=pnp->linkPtr)
  921. if( pnp->nodePtr == jsnp )
  922. break;
  923. assert(pnp->pathPtr != NULL);
  924. // advance to the next path segment
  925. pathEleStr += strlen(pathEleStr) + 1;
  926. }
  927. // if i<pathCnt then json nodes must be created to
  928. // if i==pathCnt then a matching variable already exists
  929. if( i==pathCnt )
  930. {
  931. // the reference variable already exists and assignment was requested (setFlag==true).
  932. // but the assignment cannot be made until the 'id' is updated.
  933. existsFl = true;
  934. }
  935. // we have followed 'pathString' to the last node which already
  936. // exists in the JSON tree - now we must new JSON nodes to reflect
  937. // the remaining path elements
  938. for(; i<pathCnt; ++i)
  939. {
  940. // if this is the last element in the path - then it is a pair
  941. if( i==pathCnt-1 )
  942. {
  943. // create a scalar value pair node
  944. if( valCnt == 1 )
  945. {
  946. const char* sv = strVal==NULL ? NULL : *strVal;
  947. double rv = realVal==NULL ? 0.0 : *realVal;
  948. int iv = intVal ==NULL ? 0 : *intVal;
  949. if( boolVal != NULL )
  950. jsTypeId = *boolVal ? kTrueTId : kFalseTId;
  951. if((jsnp = cmJsonInsertPair( p->jsH, jsnp, pathEleStr,jsTypeId, sv, rv, iv )) == NULL )
  952. {
  953. rc = cmErrMsg(&p->err,kInvalidIdPrRC,"Preference node create failed for '%s'",cmStringNullGuard(pathString));
  954. goto errLabel;
  955. }
  956. }
  957. else // create a vector value pair node
  958. {
  959. switch( jsTypeId )
  960. {
  961. case kStringTId: jsnp = cmJsonInsertPairStringArray2(p->jsH, jsnp, pathEleStr, valCnt, strVal); break;
  962. case kRealTId: jsnp = cmJsonInsertPairRealArray2( p->jsH, jsnp, pathEleStr, valCnt, realVal);break;
  963. case kIntTId: jsnp = cmJsonInsertPairIntArray2( p->jsH, jsnp, pathEleStr, valCnt, intVal); break;
  964. case kBoolTId: jsnp = cmJsonInsertPairBoolArray2( p->jsH, jsnp, pathEleStr, valCnt, boolVal ); break;
  965. default:
  966. {
  967. rc = cmErrMsg(&p->err,kInvalidIdPrRC,"Preference node insert failed on '%s' due to invalid type id '%i'.",cmStringNullGuard(pathString),jsTypeId);
  968. goto errLabel;
  969. }
  970. }
  971. }
  972. assert( jsnp != NULL );
  973. jsPairNodePtr = jsnp;
  974. }
  975. else // this is not the last element in the path - create an object node
  976. {
  977. // create the object associated with this new level
  978. if((jsnp = cmJsonInsertPairObject( p->jsH, jsnp, pathEleStr )) == NULL )
  979. {
  980. rc = cmErrMsg(&p->err,kJsonFailPrRC,"Preference node create failed because JSON node create failed on '%s'.",cmStringNullGuard(pathString));
  981. goto errLabel;
  982. }
  983. jsPairNodePtr = jsnp->ownerPtr;
  984. }
  985. // create a pref node to associate with this new level
  986. if((pnp = _cmPrefsCreateNode(p, jsPairNodePtr, pnp->pathPtr )) == NULL )
  987. {
  988. rc = cmErrMsg(&p->err,kNodeCreateFailPrRC,"Creation failed for the '%s' element of the preference node '%s'.",cmStringNullGuard(pathEleStr),cmStringNullGuard(pathString));
  989. goto errLabel;
  990. }
  991. pathEleStr += strlen(pathEleStr) + 1;
  992. }
  993. assert( pnp != NULL );
  994. // if an preference variable 'id' was given then set it here
  995. if( id != cmInvalidId )
  996. {
  997. if( _cmPrefsIdToNodePtr(p, id, false ) != NULL )
  998. cmErrWarnMsg(&p->err,kDuplicateIdPrRC,"The preference variable id '%i' is used by multiple preference variables including '%s'.",cmStringNullGuard(pathString));
  999. pnp->id = id;
  1000. }
  1001. // if the variable already existed and setFlag==true then update the variable value here
  1002. // (note that this cannot occur earlier because the 'id' has not yet been updated
  1003. // which might result in the incorrect id being set with the callback function)
  1004. if( existsFl && setFlag )
  1005. if((rc = _cmPrefsSetValues2(p, pnp, boolVal, intVal, realVal, strVal, &valCnt )) != kOkPrRC )
  1006. goto errLabel;
  1007. // if a new variable was created then notify the application of the new value
  1008. if(existsFl==false)
  1009. {
  1010. assert(pnp!=NULL);
  1011. _cmPrefsCallback(p,pnp->id);
  1012. }
  1013. errLabel:
  1014. cmMemFree(pathStr);
  1015. return rc;
  1016. }
  1017. cmPrRC_t cmPrefsCreateBool( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, bool val )
  1018. {
  1019. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1020. bool v = val;
  1021. return _cmPrefsCreateJsonNode(p, id, pathStr, kBoolTId, NULL, NULL, NULL, &v, 1, cmIsFlag(flags, kForceValuePrFl) );
  1022. }
  1023. cmPrRC_t cmPrefsCreateUInt( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, unsigned val )
  1024. {
  1025. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1026. int v = val;
  1027. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, &v, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1028. }
  1029. cmPrRC_t cmPrefsCreateInt( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, int val )
  1030. {
  1031. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1032. int v = val;
  1033. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, &v, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1034. }
  1035. cmPrRC_t cmPrefsCreateFloat( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, float val )
  1036. {
  1037. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1038. double v = val;
  1039. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, &v, NULL, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1040. }
  1041. cmPrRC_t cmPrefsCreateReal( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, double val )
  1042. {
  1043. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1044. double v = val;
  1045. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, &v,NULL, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1046. }
  1047. cmPrRC_t cmPrefsCreateString( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const cmChar_t* val )
  1048. {
  1049. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1050. const cmChar_t* v = val;
  1051. return _cmPrefsCreateJsonNode(p, id, pathStr, kStringTId, &v, NULL, NULL, NULL, 1, cmIsFlag(flags,kForceValuePrFl) );
  1052. }
  1053. cmPrRC_t cmPrefsCreateBoolArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const bool* val, unsigned eleCnt )
  1054. {
  1055. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1056. return _cmPrefsCreateJsonNode(p, id, pathStr, kBoolTId, NULL, NULL, NULL, val, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1057. }
  1058. cmPrRC_t cmPrefsCreateUIntArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const unsigned* val, unsigned eleCnt )
  1059. {
  1060. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1061. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, (int*)val, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1062. }
  1063. cmPrRC_t cmPrefsCreateIntArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const int* val, unsigned eleCnt )
  1064. {
  1065. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1066. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, val, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1067. }
  1068. cmPrRC_t cmPrefsCreateFloatArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const float* val, unsigned eleCnt )
  1069. {
  1070. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1071. double* a = cmMemAlloc(double,eleCnt);
  1072. unsigned i;
  1073. for(i=0; i<eleCnt; ++i)
  1074. a[i] = val[i];
  1075. cmPrRC_t rc = _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, a, NULL, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1076. cmMemFree(a);
  1077. return rc;
  1078. }
  1079. cmPrRC_t cmPrefsCreateRealArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const double* val, unsigned eleCnt )
  1080. {
  1081. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1082. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, val, NULL, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1083. }
  1084. cmPrRC_t cmPrefsCreateStringArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const cmChar_t** val, unsigned eleCnt )
  1085. {
  1086. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1087. return _cmPrefsCreateJsonNode(p, id, pathStr, kStringTId, val, NULL, NULL, NULL, eleCnt, cmIsFlag(flags,kForceValuePrFl) );
  1088. }
  1089. bool cmPrefsIsDirty( cmPrH_t h )
  1090. {
  1091. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1092. return p->dirtyFl;
  1093. }
  1094. cmPrRC_t cmPrefsWrite( cmPrH_t h, const cmChar_t* fn )
  1095. {
  1096. cmPrRC_t rc = kOkPrRC;
  1097. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1098. if( fn == NULL )
  1099. fn = p->fn;
  1100. if( cmJsonWrite( p->jsH, cmJsonRoot(p->jsH), fn) != kOkJsRC )
  1101. return cmErrMsg(&p->err,kWriteFileFailPrRC,"Preference writing failed.");
  1102. p->dirtyFl = false;
  1103. return rc;
  1104. }
  1105. //=============================================================================================
  1106. // cmPrefsTest()
  1107. //
  1108. void _cmPrintNode( const cmPrNode_t* np )
  1109. {
  1110. const cmPrPath_t* pp = np->pathPtr;
  1111. const cmJsonNode_t* jnp = np->nodePtr;
  1112. const cmJsonNode_t* jpp = jnp->ownerPtr;
  1113. printf("id:%i type:0x%x parent:0x%x ",np->id,jnp->typeId,jpp==NULL?0:jpp->typeId);
  1114. while( pp != NULL )
  1115. {
  1116. printf("%s ",pp->label);
  1117. pp = pp->parentPtr;
  1118. }
  1119. printf("\n");
  1120. }
  1121. void _cmPrintNodes( const cmPrNode_t* np )
  1122. {
  1123. if( np == NULL )
  1124. return;
  1125. _cmPrintNode(np);
  1126. _cmPrintNodes(np->linkPtr);
  1127. }
  1128. /* example preferences file
  1129. {
  1130. "cfg" :
  1131. {
  1132. "inAudDevIdx" : 0
  1133. "outAudDevIdx" : 0
  1134. "syncInputFl" : false
  1135. "midiPortBufByteCnt" : 8192
  1136. "msgQueueByteCnt" : 64768
  1137. "devFramesPerCycle" : 128
  1138. "dspFramesPerCycle" : 64
  1139. "audioBufCnt" : 3
  1140. "srate" : 44100.000000
  1141. "chNames" :
  1142. {
  1143. "left" : 0
  1144. "right" : 1
  1145. "array" :
  1146. [
  1147. 0 ,
  1148. 1 ,
  1149. 2
  1150. ]
  1151. }
  1152. }
  1153. }
  1154. */
  1155. void cmPrefsTest( cmCtx_t* ctx, const char* ifn, const char* ofn )
  1156. {
  1157. cmPrH_t h = cmPrNullHandle;
  1158. if( cmPrefsInitialize(&h,ifn,NULL,NULL,ctx) != kOkPrRC )
  1159. return;
  1160. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1161. _cmPrintNodes(p->idChainPtr);
  1162. unsigned id;
  1163. id = cmPrefsId(h, "cfg/audioBufCnt", true );
  1164. printf("id:%i\n",id);
  1165. //id = cmPrefsId(h, "cfg/audioBuf", true );
  1166. //printf("id:%i\n",id);
  1167. int sr;
  1168. unsigned n=1;
  1169. cmPrefsGetInt(h, cmPrefsId(h,"cfg/srate",true), &sr, &n );
  1170. printf("sr:%i %i\n",sr,n);
  1171. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), &sr, &n );
  1172. printf("sr:%i %i\n",sr,n);
  1173. int arr[4];
  1174. n = 4;
  1175. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), arr, &n );
  1176. printf("array:%i %i %i n=%i\n",arr[0],arr[1],arr[2],n);
  1177. sr = 44100;
  1178. n = 1;
  1179. cmPrefsSetInt(h, cmPrefsId(h,"cfg/srate",true), &sr, &n);
  1180. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), &sr, &n );
  1181. printf("sr:%i %i\n",sr,n);
  1182. int sarr[] = {10,11,12,13 };
  1183. n = sizeof(sarr)/sizeof(sarr[0]);
  1184. cmPrefsSetInt(h, cmPrefsId(h,"cfg/chNames/array",true), sarr, &n);
  1185. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), sarr, &n );
  1186. printf("array:%i %i %i %i n=%i\n",sarr[0],sarr[1],sarr[2],sarr[3],n);
  1187. int tarr[] = {20,21 };
  1188. n = sizeof(tarr)/sizeof(tarr[0]);
  1189. cmPrefsSetInt(h, cmPrefsId(h,"cfg/chNames/array",true), tarr, &n);
  1190. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), tarr, &n );
  1191. printf("array:%i %i n=%i\n",tarr[0],tarr[1],n);
  1192. cmPrefsCreateBool(h, cmInvalidId, "cfg/flags/flag0", 0, true );
  1193. bool bv = cmPrefsBool(h, cmPrefsId(h,"cfg/flags/flag0",true));
  1194. printf("bool:%i\n",bv);
  1195. cmPrefsCreateString(h,cmInvalidId, "cfg/audioBufCnt",0,"hey");
  1196. const cmChar_t* strArray[] =
  1197. {
  1198. "snap", "crackle", "pop"
  1199. };
  1200. cmPrefsCreateStringArray(h, cmInvalidId, "cfg/chNames/strList",0,strArray,3);
  1201. cmPrefsWrite(h,ofn);
  1202. cmPrefsFinalize(&h);
  1203. }