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 43KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  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 cmPrefsInit( cmCtx_t* ctx, cmPrH_t* prefsH, const cmChar_t* fnName, const cmChar_t* fnExt, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr )
  201. {
  202. cmPrRC_t rc = kOkPrRC;
  203. const cmChar_t* prefsDir = cmFsPrefsDir();
  204. const cmChar_t* prefsFn = NULL;
  205. if( fnName == NULL )
  206. fnName = cmFsAppName();
  207. if( fnExt == NULL )
  208. fnExt = ".js";
  209. // if the prefs directory does not exist then create it
  210. if( cmFsIsDir(prefsDir) == false )
  211. {
  212. if( cmFsMkDir(prefsDir) != kOkFsRC )
  213. {
  214. rc = cmErrMsg(&ctx->err,kFileSysFailPrRC,"The preference directory '%s' could not be created.",prefsDir);
  215. goto errLabel;
  216. }
  217. }
  218. // create the preference file name
  219. if((prefsFn = cmFsMakeFn( prefsDir, fnName, fnExt, NULL )) == NULL )
  220. {
  221. rc = cmErrMsg(&ctx->err,kFileSysFailPrRC,"The preference file name could not be formed.");
  222. goto errLabel;
  223. }
  224. // initialize the preference manager
  225. rc = cmPrefsInitialize(ctx,prefsH,prefsFn,cbFunc,cbDataPtr);
  226. errLabel:
  227. return rc;
  228. }
  229. cmPrRC_t cmPrefsInitialize( cmCtx_t* ctx, cmPrH_t* hp, const cmChar_t* fn, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr )
  230. {
  231. cmPrRC_t rc = kOkPrRC;
  232. if((rc = cmPrefsFinalize(hp)) != kOkPrRC)
  233. return rc;
  234. cmPr_t* p = cmMemAllocZ( cmPr_t, 1 );
  235. cmErrSetup(&p->err,&ctx->rpt,"Preferences");
  236. // initialize a linked heap
  237. if( cmLHeapIsValid(p->lhH = cmLHeapCreate(1024,ctx))==false )
  238. {
  239. rc = cmErrMsg(&p->err,kLHeapFailPrRC,"Linked heap initialization failed.");
  240. goto errLabel;
  241. }
  242. // if the preference file exists
  243. if( cmFsIsFile(fn) )
  244. {
  245. // initialize the JSON tree from the preferences file
  246. if( cmJsonInitializeFromFile( &p->jsH, fn, ctx ) != kOkJsRC )
  247. {
  248. rc = cmErrMsg(&p->err,kJsonFailPrRC,"Preferences initialization failed on JSON initialization.");
  249. goto errLabel;
  250. }
  251. // build the id list
  252. _cmPrefsBuildIdList(p, cmJsonRoot(p->jsH), NULL );
  253. }
  254. else // otherwise create an empty JSON tree
  255. {
  256. if( cmJsonInitialize( &p->jsH, ctx ) != kOkJsRC )
  257. {
  258. rc = cmErrMsg(&p->err,kJsonFailPrRC,"An empty JSON tree could not be created.");
  259. goto errLabel;
  260. }
  261. if( cmJsonCreateObject( p->jsH, NULL ) == NULL )
  262. {
  263. rc = cmErrMsg(&p->err,kJsonFailPrRC,"The JSON root object could not be created.");
  264. goto errLabel;
  265. }
  266. }
  267. // install the callback function
  268. if( cbFunc != NULL )
  269. _cmPrefsInstallCallback(p,cbFunc,cbDataPtr);
  270. // store the file name
  271. p->fn = cmLHeapAllocZ( p->lhH, strlen(fn)+1 );
  272. strcpy(p->fn,fn);
  273. p->id = kMaxVarPrId;
  274. hp->h = p;
  275. errLabel:
  276. if( rc != kOkPrRC )
  277. {
  278. _cmPrefsFinalize(p);
  279. hp-> h = NULL;
  280. }
  281. return rc;
  282. }
  283. cmPrRC_t cmPrefsFinalize( cmPrH_t* hp )
  284. {
  285. cmPrRC_t rc = kOkPrRC;
  286. if( hp==NULL || hp->h == NULL )
  287. return kOkPrRC;
  288. if((rc = _cmPrefsFinalize( _cmPrefsHandleToPtr(*hp))) == kOkPrRC )
  289. return rc;
  290. hp->h = NULL;
  291. return rc;
  292. }
  293. bool cmPrefsIsValid( cmPrH_t h )
  294. { return h.h != NULL; }
  295. const cmChar_t* cmPrefsFileName( cmPrH_t h )
  296. {
  297. cmPr_t* p = _cmPrefsHandleToPtr(h);
  298. return p->fn;
  299. }
  300. cmPrRC_t cmPrefsRC( cmPrH_t h)
  301. { return cmErrLastRC(&_cmPrefsHandleToPtr(h)->err); }
  302. cmPrRC_t cmPrefsSetRC( cmPrH_t h, cmPrRC_t rc )
  303. { return cmErrSetRC(&_cmPrefsHandleToPtr(h)->err,rc); }
  304. cmPrRC_t cmPrefsInstallCallback( cmPrH_t h, cmPrefsOnChangeFunc_t cbFunc, void* cbDataPtr )
  305. {
  306. cmPr_t* p = _cmPrefsHandleToPtr(h);
  307. _cmPrefsInstallCallback(p,cbFunc,cbDataPtr);
  308. return kOkPrRC;
  309. }
  310. cmPrRC_t cmPrefsRemoveCallback( cmPrH_t h, cmPrefsOnChangeFunc_t cbFunc )
  311. {
  312. cmPr_t* p = _cmPrefsHandleToPtr(h);
  313. cmPrCb_t* cc = p->cbChainPtr;
  314. cmPrCb_t* pc = NULL;
  315. while( cc == NULL )
  316. {
  317. if( cc->cbFunc == cbFunc )
  318. {
  319. if( pc == NULL )
  320. p->cbChainPtr = cc->linkPtr;
  321. else
  322. pc->linkPtr = cc->linkPtr;
  323. break;
  324. }
  325. pc = cc;
  326. cc = cc->linkPtr;
  327. }
  328. if( cc == NULL )
  329. return cmErrMsg(&p->err,kCbNotFoundPrRC,"The callback function %p could not be found.",cbFunc);
  330. return kOkPrRC;
  331. }
  332. unsigned cmPrefsId( cmPrH_t h, const cmChar_t* pathStr, bool reportErrFl )
  333. {
  334. cmPr_t* p = _cmPrefsHandleToPtr(h);
  335. return _cmPrefsId(p,pathStr,reportErrFl);
  336. }
  337. unsigned cmPrefsEleCount( cmPrH_t h, unsigned id )
  338. {
  339. cmPr_t* p = _cmPrefsHandleToPtr(h);
  340. cmPrNode_t* np = _cmPrefsIdToNodePtr(p,id,true);
  341. if( np == NULL )
  342. return -1;
  343. if( cmJsonIsArray(np->nodePtr) )
  344. return cmJsonChildCount(np->nodePtr);
  345. return 1;
  346. }
  347. void _cmPrefsFormPath( cmPr_t* p, const cmPrNode_t* np )
  348. {
  349. cmPrPath_t* pp = np->pathPtr;
  350. int n = 0;
  351. for(; pp!=NULL; pp=pp->parentPtr)
  352. ++n;
  353. const char* pathArray[n];
  354. unsigned i = n-1;
  355. for(pp = np->pathPtr; pp!=NULL; pp=pp->parentPtr,--i)
  356. pathArray[i] = pp->label;
  357. cmMemPtrFree(&p->pathBuf);
  358. for(i=0; i<n; ++i)
  359. {
  360. if( i > 0 )
  361. p->pathBuf = cmTextAppendSS(p->pathBuf,"/");
  362. p->pathBuf = cmTextAppendSS(p->pathBuf,pathArray[i]);
  363. }
  364. }
  365. 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 )
  366. {
  367. cmJsRC_t jsRC = kOkJsRC;
  368. const char* typeLabel = NULL;
  369. // verify that adequate return space was provided
  370. if( retEleCnt < 1 )
  371. {
  372. _cmPrefsFormPath(p,np);
  373. return cmErrMsg(&p->err,kBufTooSmallPrRC,"No return space was provided for the preference variable '%s' (id:%i).",p->pathBuf,np->id);
  374. }
  375. if( bvp != NULL )
  376. {
  377. jsRC = cmJsonBoolValue(jnp,bvp);
  378. typeLabel = "bool";
  379. }
  380. else
  381. if( ivp != NULL )
  382. {
  383. jsRC = cmJsonIntValue(jnp,ivp);
  384. typeLabel = "int";
  385. }
  386. else
  387. if( rvp != NULL )
  388. {
  389. jsRC = cmJsonRealValue(jnp,rvp);
  390. typeLabel = "real";
  391. }
  392. else
  393. if( svp != NULL )
  394. {
  395. jsRC = cmJsonStringValue(jnp,svp);
  396. typeLabel = "string";
  397. }
  398. else
  399. {
  400. assert(0);
  401. }
  402. if( jsRC != kOkJsRC )
  403. {
  404. _cmPrefsFormPath(p,np);
  405. return cmErrMsg(&p->err,kCvtErrPrRC,"The perferences variable '%s' (id:%i) could not be converted to type '%s'.",p->pathBuf,np->id,typeLabel);
  406. }
  407. return kOkPrRC;
  408. }
  409. cmPrRC_t _cmPrefsGetValue( cmPrH_t h, unsigned id, bool* bvp, int* ivp, double* rvp, const cmChar_t** svp, unsigned* eleCntPtr, unsigned eleIdx )
  410. {
  411. cmPrRC_t rc = kOkPrRC;
  412. cmPr_t* p = _cmPrefsHandleToPtr(h);
  413. cmPrNode_t* np = NULL;
  414. // if no return buffer was given - do nothing
  415. if( *eleCntPtr == 0 )
  416. return kOkPrRC;
  417. // locate the pref node from 'id'
  418. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  419. {
  420. rc = cmErrMsg(&p->err,kVarNotFoundPrRC,"No preference variable was found for id:%i.",id);
  421. goto errLabel;
  422. }
  423. // if the requested pref. var is a scalar
  424. if( cmJsonIsArray(np->nodePtr) == false )
  425. {
  426. if((rc = _cmPrefsValue(p,np,np->nodePtr,bvp,ivp,rvp,svp,*eleCntPtr)) == kOkPrRC )
  427. *eleCntPtr = 1;
  428. }
  429. else // the request pref. var. is an array
  430. {
  431. unsigned i = 0;
  432. unsigned n = cmJsonChildCount(np->nodePtr);
  433. // if the entire array was requestedd
  434. if( eleIdx == cmInvalidIdx )
  435. {
  436. // if the return buffer is too small to hold all of the values.
  437. if( *eleCntPtr < n )
  438. {
  439. *eleCntPtr = 0;
  440. _cmPrefsFormPath(p,np);
  441. 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);
  442. goto errLabel;
  443. }
  444. // read each element
  445. for(i=0; i<n; ++i)
  446. {
  447. const cmJsonNode_t* cnp = cmJsonArrayElement(np->nodePtr,i);
  448. 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 )
  449. goto errLabel;
  450. }
  451. *eleCntPtr = n;
  452. }
  453. else // a single ele of the array was requested
  454. {
  455. // validate the index
  456. if( eleIdx >= n )
  457. {
  458. _cmPrefsFormPath(p,np);
  459. rc = cmErrMsg(&p->err,kInvalidIndexPrRC,"The index %i is invalid for the variable '%s' of length %i.",eleIdx,p->pathBuf,n);
  460. goto errLabel;
  461. }
  462. // get the json element at array index 'eleIdx'
  463. const cmJsonNode_t* cnp = cmJsonArrayElement(np->nodePtr,eleIdx);
  464. assert(cnp != NULL );
  465. // read the element from the array
  466. if((rc = _cmPrefsValue(p,np,cnp,bvp,ivp,rvp,svp,*eleCntPtr)) == kOkPrRC )
  467. *eleCntPtr = 1;
  468. }
  469. }
  470. errLabel:
  471. if( rc != kOkPrRC )
  472. *eleCntPtr = 0;
  473. return rc;
  474. }
  475. cmPrRC_t cmPrefsGetBool( cmPrH_t h, unsigned id, bool* vp, unsigned* eleCntPtr )
  476. { return _cmPrefsGetValue(h, id, vp, NULL, NULL, NULL, eleCntPtr, cmInvalidIdx ); }
  477. cmPrRC_t cmPrefsGetInt( cmPrH_t h, unsigned id, int* vp, unsigned* eleCntPtr )
  478. { return _cmPrefsGetValue(h, id, NULL, vp, NULL, NULL, eleCntPtr, cmInvalidIdx ); }
  479. cmPrRC_t cmPrefsGetReal( cmPrH_t h, unsigned id, double* vp, unsigned* eleCntPtr )
  480. { return _cmPrefsGetValue(h, id, NULL, NULL, vp, NULL, eleCntPtr, cmInvalidIdx ); }
  481. cmPrRC_t cmPrefsGetString( cmPrH_t h, unsigned id, const cmChar_t** vp, unsigned* eleCntPtr )
  482. { return _cmPrefsGetValue(h, id, NULL, NULL, NULL, vp, eleCntPtr, cmInvalidIdx ); }
  483. bool cmPrefsBool( cmPrH_t h, unsigned id )
  484. {
  485. bool v = false;
  486. unsigned n = 1;
  487. cmPrefsGetBool(h,id,&v,&n);
  488. return v;
  489. }
  490. unsigned cmPrefsUInt( cmPrH_t h, unsigned id )
  491. {
  492. int v = 0;
  493. unsigned n = 1;
  494. cmPrefsGetInt(h,id,&v,&n);
  495. return (unsigned)v;
  496. }
  497. int cmPrefsInt( cmPrH_t h, unsigned id )
  498. {
  499. int v = 0;
  500. unsigned n = 1;
  501. cmPrefsGetInt(h,id,&v,&n);
  502. return v;
  503. }
  504. float cmPrefsFloat( cmPrH_t h, unsigned id )
  505. {
  506. double v = 0;
  507. unsigned n = 1;
  508. cmPrefsGetReal(h,id,&v,&n);
  509. return (float)v;
  510. }
  511. double cmPrefsReal( cmPrH_t h, unsigned id )
  512. {
  513. double v = 0;
  514. unsigned n = 1;
  515. cmPrefsGetReal(h,id,&v,&n);
  516. return v;
  517. }
  518. const cmChar_t* cmPrefsString( cmPrH_t h, unsigned id )
  519. {
  520. const cmChar_t* v = NULL;
  521. unsigned n = 1;
  522. if( cmPrefsGetString(h,id,&v,&n) == kOkPrRC )
  523. return v==NULL ? "" : v;
  524. return "";
  525. }
  526. bool cmPrefsBoolDef( cmPrH_t h, const cmChar_t* pathStr, bool dfltVal )
  527. {
  528. unsigned id;
  529. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  530. return dfltVal;
  531. return cmPrefsBool(h,id);
  532. }
  533. unsigned cmPrefsUIntDef( cmPrH_t h, const cmChar_t* pathStr, unsigned dfltVal )
  534. {
  535. unsigned id;
  536. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  537. return dfltVal;
  538. return cmPrefsUInt(h,id);
  539. }
  540. int cmPrefsIntDef( cmPrH_t h, const cmChar_t* pathStr, int dfltVal )
  541. {
  542. unsigned id;
  543. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  544. return dfltVal;
  545. return cmPrefsInt(h,id);
  546. }
  547. float cmPrefsFloatDef( cmPrH_t h, const cmChar_t* pathStr, float dfltVal )
  548. {
  549. unsigned id;
  550. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  551. return dfltVal;
  552. return cmPrefsFloat(h,id);
  553. }
  554. double cmPrefsRealDef( cmPrH_t h, const cmChar_t* pathStr, double dfltVal )
  555. {
  556. unsigned id;
  557. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  558. return dfltVal;
  559. return cmPrefsReal(h,id);
  560. }
  561. const cmChar_t* cmPrefsStringDef( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t* dfltVal )
  562. {
  563. unsigned id;
  564. if( cmPrefsIsValid(h)==false || (id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  565. return dfltVal;
  566. const cmChar_t* v = cmPrefsString(h,id);
  567. return v==NULL || strlen(v)==0 ? dfltVal : v;
  568. }
  569. cmPrRC_t cmPrefsBoolRc( cmPrH_t h, const cmChar_t* pathStr, bool* retValPtr )
  570. {
  571. unsigned id;
  572. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  573. return kVarNotFoundPrRC;
  574. unsigned n = 1;
  575. return cmPrefsGetBool(h,id,retValPtr,&n);
  576. }
  577. cmPrRC_t cmPrefsUIntRc( cmPrH_t h, const cmChar_t* pathStr, unsigned* retValPtr )
  578. {
  579. unsigned id;
  580. unsigned n = 1;
  581. int v;
  582. cmPrRC_t rc;
  583. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  584. return kVarNotFoundPrRC;
  585. if((rc =cmPrefsGetInt(h,id,&v,&n)) == kOkPrRC )
  586. *retValPtr = v;
  587. return rc;
  588. }
  589. cmPrRC_t cmPrefsIntRc( cmPrH_t h, const cmChar_t* pathStr, int* retValPtr )
  590. {
  591. unsigned id;
  592. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  593. return kVarNotFoundPrRC;
  594. unsigned n = 1;
  595. return cmPrefsGetInt(h,id,retValPtr,&n);
  596. }
  597. cmPrRC_t cmPrefsFloatRc( cmPrH_t h, const cmChar_t* pathStr, float* retValPtr )
  598. {
  599. unsigned id;
  600. unsigned n = 1;
  601. double v;
  602. cmPrRC_t rc;
  603. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  604. return kVarNotFoundPrRC;
  605. if((rc =cmPrefsGetReal(h,id,&v,&n)) == kOkPrRC )
  606. *retValPtr = v;
  607. return rc;
  608. }
  609. cmPrRC_t cmPrefsRealRc( cmPrH_t h, const cmChar_t* pathStr, double* retValPtr )
  610. {
  611. unsigned id;
  612. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  613. return kVarNotFoundPrRC;
  614. unsigned n = 1;
  615. return cmPrefsGetReal(h,id,retValPtr,&n);
  616. }
  617. cmPrRC_t cmPrefsStringRc( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t** retValPtr )
  618. {
  619. unsigned id;
  620. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  621. return kVarNotFoundPrRC;
  622. unsigned n = 1;
  623. return cmPrefsGetString(h,id,retValPtr,&n);
  624. }
  625. unsigned cmPrefsArrayElementCount( cmPrH_t h, unsigned id )
  626. {
  627. cmPrNode_t* np;
  628. cmPr_t* p = _cmPrefsHandleToPtr(h);
  629. // locate the pref node from 'id'
  630. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  631. {
  632. cmErrMsg(&p->err,kVarNotFoundPrRC,"No preference variable was found for id:%i.",id);
  633. return cmInvalidCnt;
  634. }
  635. // if the requested pref. var is a scalar
  636. if( cmJsonIsArray(np->nodePtr) )
  637. return cmJsonChildCount(np->nodePtr);
  638. return 0;
  639. }
  640. bool cmPrefsBoolEle( cmPrH_t h, unsigned id, unsigned idx )
  641. {
  642. bool v = false;;
  643. unsigned n = 1;
  644. _cmPrefsGetValue(h,id, &v, NULL, NULL, NULL, &n, idx );
  645. return v;
  646. }
  647. unsigned cmPrefsUIntEle( cmPrH_t h, unsigned id, unsigned idx )
  648. {
  649. int v = 0;
  650. unsigned n = 1;
  651. _cmPrefsGetValue(h,id, NULL, &v, NULL, NULL, &n, idx );
  652. return (unsigned)v;
  653. }
  654. int cmPrefsIntEle( cmPrH_t h, unsigned id, unsigned idx )
  655. {
  656. int v = 0;
  657. unsigned n = 1;
  658. _cmPrefsGetValue(h,id, NULL, &v, NULL, NULL, &n, idx );
  659. return v;
  660. }
  661. float cmPrefsFloatEle( cmPrH_t h, unsigned id, unsigned idx )
  662. {
  663. double v = 0;
  664. unsigned n = 1;
  665. _cmPrefsGetValue(h,id, NULL, NULL, &v, NULL, &n, idx );
  666. return (float)v;
  667. }
  668. double cmPrefsRealEle( cmPrH_t h, unsigned id, unsigned idx )
  669. {
  670. double v = 0;
  671. unsigned n = 1;
  672. _cmPrefsGetValue(h,id, NULL, NULL, &v, NULL, &n, idx );
  673. return v;
  674. }
  675. const cmChar_t* cmPrefsStringEle( cmPrH_t h, unsigned id, unsigned idx )
  676. {
  677. const cmChar_t* v = "";
  678. unsigned n = 1;
  679. if( _cmPrefsGetValue(h,id, NULL, NULL, NULL, &v, &n, idx ) == kOkPrRC )
  680. return v;
  681. return "";
  682. }
  683. 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 )
  684. {
  685. cmJsRC_t jsRC = kOkJsRC;
  686. //const cmChar_t* typeLabel;
  687. if( bvp != NULL )
  688. {
  689. bool v;
  690. if((jsRC = cmJsonBoolValue(jnp,&v)) == kOkJsRC )
  691. if( (*deltaFlPtr = (v != *bvp)) )
  692. jsRC = cmJsonSetBool(p->jsH,jnp,*bvp);
  693. //typeLabel = "bool";
  694. }
  695. else
  696. if( ivp != NULL )
  697. {
  698. int v;
  699. if((jsRC = cmJsonIntValue(jnp,&v)) == kOkJsRC )
  700. if( (*deltaFlPtr = (v != *ivp)) )
  701. jsRC = cmJsonSetInt(p->jsH,jnp,*ivp);
  702. //typeLabel = "int";
  703. }
  704. else
  705. if( rvp != NULL )
  706. {
  707. double v;
  708. if((jsRC = cmJsonRealValue(jnp,&v)) == kOkJsRC )
  709. if( (*deltaFlPtr = (v != *rvp)) )
  710. jsRC = cmJsonSetReal(p->jsH,jnp,*rvp);
  711. //typeLabel = "real";
  712. }
  713. else
  714. if( svp != NULL )
  715. {
  716. const cmChar_t* v;
  717. if((jsRC = cmJsonStringValue(jnp,&v)) == kOkJsRC )
  718. {
  719. const cmChar_t* s0 = v ==NULL ? "" : v;
  720. const cmChar_t* s1 = *svp==NULL ? "" : *svp;
  721. if( (*deltaFlPtr = (strcmp(s0,s1)!=0)) )
  722. jsRC = cmJsonSetString(p->jsH,jnp,s1);
  723. }
  724. //typeLabel = "string";
  725. }
  726. else
  727. {
  728. assert(0);
  729. }
  730. if( jsRC != kOkJsRC )
  731. {
  732. _cmPrefsFormPath(p,np);
  733. return cmErrMsg(&p->err,kCvtErrPrRC,"The perferences variable '%s' (id:%i) could not be set.",p->pathBuf,np->id);
  734. }
  735. return kOkPrRC;
  736. }
  737. void _cmPrefsCallback( cmPr_t* p, unsigned id )
  738. {
  739. // notify any listeners that a node has changed values
  740. cmPrCb_t* cbNodePtr = p->cbChainPtr;
  741. for(; cbNodePtr!=NULL; cbNodePtr=cbNodePtr->linkPtr)
  742. {
  743. cmPrH_t h;
  744. h.h = p;
  745. cbNodePtr->cbFunc(h,cbNodePtr->cbDataPtr,id);
  746. }
  747. }
  748. 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 )
  749. {
  750. cmPrRC_t rc = kOkPrRC;
  751. bool deltaFl = false; // set to true if the value of the pref. var. identified by 'id' actually changes.
  752. // a scalar has been passed in and the existing json node is also a scalar
  753. if( cmJsonIsArray(np->nodePtr)== false && *eleCntPtr==1 )
  754. {
  755. rc = _cmPrefsSetValue(p,np,np->nodePtr,bvp,ivp,rvp,svp,&deltaFl);
  756. goto errLabel;
  757. }
  758. // the pref. variable is an array
  759. if( cmJsonIsArray(np->nodePtr) )
  760. {
  761. unsigned i;
  762. unsigned curArrCnt = cmJsonChildCount(np->nodePtr);
  763. unsigned n = cmMin(*eleCntPtr,curArrCnt);
  764. for(i=0; i<n; ++i)
  765. {
  766. cmJsonNode_t* jnp = cmJsonArrayElement(np->nodePtr,i);
  767. bool dfl = false;
  768. 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 )
  769. return rc;
  770. if( dfl )
  771. deltaFl = true;
  772. }
  773. // if elements should be removed
  774. if( curArrCnt > *eleCntPtr )
  775. {
  776. deltaFl = true; // ele's are being removed so the variable value is changing
  777. for(i=*eleCntPtr; i<curArrCnt; ++i)
  778. {
  779. cmJsonNode_t* jnp = cmJsonArrayElement(np->nodePtr,*eleCntPtr);
  780. assert(jnp!=NULL);
  781. cmJsonRemoveNode(p->jsH,jnp,true);
  782. }
  783. }
  784. // if elements should be added
  785. if( *eleCntPtr > curArrCnt )
  786. {
  787. unsigned typeId = cmInvalidId;
  788. cmJsonNode_t* jnp = NULL;
  789. cmJsonNode_t* snp = curArrCnt==0 ? NULL : cmJsonArrayElement(np->nodePtr,curArrCnt-1);
  790. assert(snp->ownerPtr==np->nodePtr && snp->siblingPtr==NULL);
  791. deltaFl = true; // ele's are being added so the variable value is changing
  792. if( ivp != NULL )
  793. typeId = kIntTId;
  794. else
  795. if( rvp != NULL )
  796. typeId = kRealTId;
  797. else
  798. if( svp != NULL )
  799. typeId = kStringTId;
  800. // for each new array element
  801. for(; i<*eleCntPtr; ++i)
  802. {
  803. if( bvp != NULL )
  804. typeId = bvp[i];
  805. // create the new array element node - the new node is automatically added to the end of the array
  806. if( cmJsonCreate(p->jsH, np->nodePtr, typeId, svp==NULL?NULL:svp[i], ivp==NULL?0:ivp[i], rvp==NULL?0:rvp[i], &jnp ) != kOkJsRC )
  807. {
  808. _cmPrefsFormPath(p,np);
  809. return cmErrMsg(&p->err,kJsonFailPrRC,"Unable to create a value node for '%s' (id=%i).",p->pathBuf,np->id);
  810. }
  811. }
  812. }
  813. errLabel:
  814. if( (rc == kOkPrRC) && deltaFl )
  815. {
  816. _cmPrefsCallback(p, np->id );
  817. // update the global delta flag
  818. p->dirtyFl = true;
  819. }
  820. return rc;
  821. }
  822. _cmPrefsFormPath(p,np);
  823. 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);
  824. }
  825. cmPrRC_t _cmPrefsSetValues( cmPrH_t h, unsigned id, const bool* bvp, const int* ivp, const double* rvp, const cmChar_t** svp, const unsigned* eleCntPtr )
  826. {
  827. cmPr_t* p = _cmPrefsHandleToPtr(h);
  828. cmPrNode_t* np;
  829. // locate the pref node
  830. if((np = _cmPrefsIdToNodePtr(p,id,true)) == NULL )
  831. return cmErrMsg(&p->err,kVarNotFoundPrRC,"The variable with id=%i was not found.",id);
  832. return _cmPrefsSetValues2( p, np, bvp, ivp, rvp, svp, eleCntPtr );
  833. }
  834. cmPrRC_t cmPrefsSetBoolArray( cmPrH_t h, unsigned id, const bool* vp, const unsigned* eleCntPtr )
  835. { return _cmPrefsSetValues(h, id, vp, NULL, NULL, NULL, eleCntPtr ); }
  836. cmPrRC_t cmPrefsSetIntArray( cmPrH_t h, unsigned id, const int* vp, const unsigned* eleCntPtr )
  837. { return _cmPrefsSetValues(h, id, NULL, vp, NULL, NULL, eleCntPtr ); }
  838. cmPrRC_t cmPrefsSetRealArray( cmPrH_t h, unsigned id, const double* vp, const unsigned* eleCntPtr )
  839. { return _cmPrefsSetValues(h, id, NULL, NULL, vp, NULL, eleCntPtr ); }
  840. cmPrRC_t cmPrefsSetStringArray( cmPrH_t h, unsigned id, const cmChar_t** vp, const unsigned* eleCntPtr )
  841. { return _cmPrefsSetValues(h, id, NULL, NULL, NULL, vp, eleCntPtr ); }
  842. cmPrRC_t cmPrefsSetBool( cmPrH_t h, unsigned id, bool val )
  843. {
  844. unsigned n = 1;
  845. return cmPrefsSetBoolArray(h,id,&val,&n);
  846. }
  847. cmPrRC_t cmPrefsSetUInt( cmPrH_t h, unsigned id, unsigned val )
  848. {
  849. unsigned n = 1;
  850. int ival = (int)val;
  851. return cmPrefsSetIntArray(h,id,&ival,&n);
  852. }
  853. cmPrRC_t cmPrefsSetInt( cmPrH_t h, unsigned id, int val )
  854. {
  855. unsigned n = 1;
  856. return cmPrefsSetIntArray(h,id,&val,&n);
  857. }
  858. cmPrRC_t cmPrefsSetFloat( cmPrH_t h, unsigned id, float val )
  859. {
  860. unsigned n = 1;
  861. double dval = val;
  862. return cmPrefsSetRealArray(h,id,&dval,&n);
  863. }
  864. cmPrRC_t cmPrefsSetReal( cmPrH_t h, unsigned id, double val )
  865. {
  866. unsigned n = 1;
  867. return cmPrefsSetRealArray(h,id,&val,&n);
  868. }
  869. cmPrRC_t cmPrefsSetString( cmPrH_t h, unsigned id, const cmChar_t* val )
  870. {
  871. unsigned n = 1;
  872. return cmPrefsSetStringArray(h,id,&val,&n);
  873. }
  874. cmPrRC_t cmPrefsPathSetBool( cmPrH_t h, const cmChar_t* pathStr, bool val )
  875. {
  876. unsigned id;
  877. unsigned n = 1;
  878. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  879. return kVarNotFoundPrRC;
  880. return cmPrefsSetBoolArray(h,id,&val,&n);
  881. }
  882. cmPrRC_t cmPrefsPathSetUInt( cmPrH_t h, const cmChar_t* pathStr, unsigned val )
  883. {
  884. unsigned id;
  885. unsigned n = 1;
  886. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  887. return kVarNotFoundPrRC;
  888. int ival = (int)val;
  889. return cmPrefsSetIntArray(h,id,&ival,&n);
  890. }
  891. cmPrRC_t cmPrefsPathSetInt( cmPrH_t h, const cmChar_t* pathStr, int val )
  892. {
  893. unsigned id;
  894. unsigned n = 1;
  895. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  896. return kVarNotFoundPrRC;
  897. return cmPrefsSetIntArray(h,id,&val,&n);
  898. }
  899. cmPrRC_t cmPrefsPathSetFloat( cmPrH_t h, const cmChar_t* pathStr, float val )
  900. {
  901. unsigned id;
  902. unsigned n = 1;
  903. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  904. return kVarNotFoundPrRC;
  905. double dval = val;
  906. return cmPrefsSetRealArray(h,id,&dval,&n);
  907. }
  908. cmPrRC_t cmPrefsPathSetReal( cmPrH_t h, const cmChar_t* pathStr, double val )
  909. {
  910. unsigned id;
  911. unsigned n = 1;
  912. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  913. return kVarNotFoundPrRC;
  914. return cmPrefsSetRealArray(h,id,&val,&n);
  915. }
  916. cmPrRC_t cmPrefsPathSetString( cmPrH_t h, const cmChar_t* pathStr, const cmChar_t* val )
  917. {
  918. unsigned id;
  919. unsigned n = 1;
  920. if((id = cmPrefsId(h,pathStr,true)) == cmInvalidId )
  921. return kVarNotFoundPrRC;
  922. return cmPrefsSetStringArray(h,id,&val,&n);
  923. }
  924. bool _cmPrefsValidateNodeType( cmJsonNode_t* np, unsigned jsTypeId, unsigned valCnt )
  925. {
  926. // if we are looking for a scalar node then the type must be jsTypeId
  927. if( valCnt == 1 )
  928. return np->typeId == jsTypeId;
  929. // if we are looking for an array node then the type must be kArrayTId ...
  930. if( np->typeId != kArrayTId )
  931. return false;
  932. unsigned n = cmJsonChildCount(np);
  933. unsigned i = 0;
  934. // ... and all of the array elements must be of type jsTypeId
  935. for(; i<n; ++i)
  936. {
  937. const cmJsonNode_t* cnp = cmJsonArrayElementC(np,i);
  938. assert( cnp != NULL );
  939. if( cnp->typeId != jsTypeId )
  940. return false;
  941. }
  942. return true;
  943. }
  944. //
  945. cmPrRC_t _cmPrefsCreateJsonNode(
  946. cmPr_t* p,
  947. unsigned id, // new variable id
  948. const cmChar_t* pathString, // new variable name
  949. unsigned jsTypeId, // type of new variable
  950. const cmChar_t** strVal, // value of new variable
  951. const double* realVal, //
  952. const int* intVal, //
  953. const bool* boolVal, //
  954. unsigned valCnt, // length of xxxVal[]
  955. bool setFlag ) // true== if same named variable already exists then set the value to xxxVal
  956. {
  957. cmPrRC_t rc = kOkPrRC;
  958. int pathCnt = 0;
  959. cmChar_t* pathStr = _cmPrefsCreatePathStr(pathString,&pathCnt);
  960. const cmChar_t* pathEleStr = pathStr;
  961. cmJsonNode_t* jsnp = cmJsonRoot(p->jsH);
  962. cmJsonNode_t* jsPairNodePtr = NULL;
  963. cmPrNode_t* pnp = NULL; // current pref node pointer
  964. bool existsFl = false; // set if variable already exists
  965. int i;
  966. assert( pathCnt >= 1 );
  967. if( id != cmInvalidId && id >= kMaxVarPrId )
  968. return cmErrMsg(&p->err,kNodeCreateFailPrRC,"User supplied id's must be less than 0x%x.",kMaxVarPrId);
  969. // for each path element
  970. for(i=0; i<pathCnt; ++i)
  971. {
  972. cmJsonNode_t* tnp = NULL;
  973. // find the child pair node of jsnp named 'pathEleStr'.
  974. if( (tnp = cmJsonNodeMemberValue(jsnp, pathEleStr )) == NULL )
  975. break;
  976. // the located json node must be an object (i<pathCnt-1) or the same type as jsTypeId (i=pathCnt-1)
  977. // This check guarantees that all nodes up to the leaf node are objects and the leaf node matches the created type.
  978. if( !(((i<pathCnt-1) && cmJsonIsObject(tnp)) || ((i==pathCnt-1) && _cmPrefsValidateNodeType(tnp,jsTypeId,valCnt))) )
  979. {
  980. 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);
  981. goto errLabel;
  982. }
  983. // assert that the json nodes we are finding form a tree
  984. assert( (tnp->ownerPtr==NULL && jsnp==NULL) || (tnp->ownerPtr!=NULL && tnp->ownerPtr->ownerPtr==jsnp));
  985. jsnp = tnp;
  986. // find the pref node which refers to the located json node
  987. // (we need to track the pnp->pathPtr)
  988. pnp = p->idChainPtr;
  989. for(; pnp != NULL; pnp=pnp->linkPtr)
  990. if( pnp->nodePtr == jsnp )
  991. break;
  992. assert(pnp->pathPtr != NULL);
  993. // advance to the next path segment
  994. pathEleStr += strlen(pathEleStr) + 1;
  995. }
  996. // if i<pathCnt then json nodes must be created to
  997. // if i==pathCnt then a matching variable already exists
  998. if( i==pathCnt )
  999. {
  1000. // the reference variable already exists and assignment was requested (setFlag==true).
  1001. // but the assignment cannot be made until the 'id' is updated.
  1002. existsFl = true;
  1003. }
  1004. // we have followed 'pathString' to the last node which already
  1005. // exists in the JSON tree - now we must create new JSON nodes to reflect
  1006. // the remaining path elements
  1007. for(; i<pathCnt; ++i)
  1008. {
  1009. // if this is the last element in the path - then it is a pair
  1010. if( i==pathCnt-1 )
  1011. {
  1012. // create a scalar value pair node
  1013. if( valCnt == 1 )
  1014. {
  1015. const char* sv = strVal==NULL ? NULL : *strVal;
  1016. double rv = realVal==NULL ? 0.0 : *realVal;
  1017. int iv = intVal ==NULL ? 0 : *intVal;
  1018. if( boolVal != NULL )
  1019. jsTypeId = *boolVal ? kTrueTId : kFalseTId;
  1020. if((jsnp = cmJsonInsertPair( p->jsH, jsnp, pathEleStr,jsTypeId, sv, iv, rv )) == NULL )
  1021. {
  1022. rc = cmErrMsg(&p->err,kInvalidIdPrRC,"Preference node create failed for '%s'",cmStringNullGuard(pathString));
  1023. goto errLabel;
  1024. }
  1025. }
  1026. else // create a vector value pair node
  1027. {
  1028. switch( jsTypeId )
  1029. {
  1030. case kStringTId: jsnp = cmJsonInsertPairStringArray2(p->jsH, jsnp, pathEleStr, valCnt, strVal); break;
  1031. case kRealTId: jsnp = cmJsonInsertPairRealArray2( p->jsH, jsnp, pathEleStr, valCnt, realVal);break;
  1032. case kIntTId: jsnp = cmJsonInsertPairIntArray2( p->jsH, jsnp, pathEleStr, valCnt, intVal); break;
  1033. case kBoolTId: jsnp = cmJsonInsertPairBoolArray2( p->jsH, jsnp, pathEleStr, valCnt, boolVal ); break;
  1034. default:
  1035. {
  1036. rc = cmErrMsg(&p->err,kInvalidIdPrRC,"Preference node insert failed on '%s' due to invalid type id '%i'.",cmStringNullGuard(pathString),jsTypeId);
  1037. goto errLabel;
  1038. }
  1039. }
  1040. }
  1041. assert( jsnp != NULL );
  1042. jsPairNodePtr = jsnp;
  1043. }
  1044. else // this is not the last element in the path - create an object node
  1045. {
  1046. // create the object associated with this new level
  1047. if((jsnp = cmJsonInsertPairObject( p->jsH, jsnp, pathEleStr )) == NULL )
  1048. {
  1049. rc = cmErrMsg(&p->err,kJsonFailPrRC,"Preference node create failed because JSON node create failed on '%s'.",cmStringNullGuard(pathString));
  1050. goto errLabel;
  1051. }
  1052. jsPairNodePtr = jsnp->ownerPtr;
  1053. }
  1054. unsigned nxtId = p->id;
  1055. // create a pref node to associate with this new level
  1056. if((pnp = _cmPrefsCreateNode(p, jsPairNodePtr, pnp==NULL ? NULL : pnp->pathPtr )) == NULL )
  1057. {
  1058. rc = cmErrMsg(&p->err,kNodeCreateFailPrRC,"Creation failed for the '%s' element of the preference node '%s'.",cmStringNullGuard(pathEleStr),cmStringNullGuard(pathString));
  1059. goto errLabel;
  1060. }
  1061. // always leave internal nodes with id=cmInvalidId, leaf node id's will be set below
  1062. p->id = nxtId;
  1063. pnp->id = cmInvalidId;
  1064. pathEleStr += strlen(pathEleStr) + 1;
  1065. }
  1066. assert( pnp != NULL );
  1067. // if an preference variable 'id' was given then set it here
  1068. if( id == cmInvalidId )
  1069. pnp->id = _cmPrefsCalcNextAvailId(p);
  1070. else
  1071. {
  1072. if( _cmPrefsIdToNodePtr(p, id, false ) != NULL )
  1073. cmErrWarnMsg(&p->err,kDuplicateIdPrRC,"The preference variable id '%i' is used by multiple preference variables including '%s'.",id,cmStringNullGuard(pathString));
  1074. pnp->id = id;
  1075. }
  1076. // if the variable already existed and setFlag==true then update the variable value here
  1077. // (note that this cannot occur earlier because the 'id' has not yet been updated
  1078. // which might result in the incorrect id being set with the callback function)
  1079. if( existsFl && setFlag )
  1080. if((rc = _cmPrefsSetValues2(p, pnp, boolVal, intVal, realVal, strVal, &valCnt )) != kOkPrRC )
  1081. goto errLabel;
  1082. // if a new variable was created then notify the application of the new value
  1083. if(existsFl==false)
  1084. {
  1085. assert(pnp!=NULL);
  1086. _cmPrefsCallback(p,pnp->id);
  1087. }
  1088. errLabel:
  1089. cmMemFree(pathStr);
  1090. return rc;
  1091. }
  1092. cmPrRC_t cmPrefsCreateBool( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, bool val )
  1093. {
  1094. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1095. bool v = val;
  1096. return _cmPrefsCreateJsonNode(p, id, pathStr, kBoolTId, NULL, NULL, NULL, &v, 1, cmIsFlag(flags, kForceValuePrFl) );
  1097. }
  1098. cmPrRC_t cmPrefsCreateUInt( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, unsigned val )
  1099. {
  1100. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1101. int v = val;
  1102. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, &v, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1103. }
  1104. cmPrRC_t cmPrefsCreateInt( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, int val )
  1105. {
  1106. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1107. int v = val;
  1108. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, &v, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1109. }
  1110. cmPrRC_t cmPrefsCreateFloat( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, float val )
  1111. {
  1112. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1113. double v = val;
  1114. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, &v, NULL, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1115. }
  1116. cmPrRC_t cmPrefsCreateReal( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, double val )
  1117. {
  1118. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1119. double v = val;
  1120. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, &v,NULL, NULL, 1, cmIsFlag(flags, kForceValuePrFl) );
  1121. }
  1122. cmPrRC_t cmPrefsCreateString( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const cmChar_t* val )
  1123. {
  1124. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1125. const cmChar_t* v = val;
  1126. return _cmPrefsCreateJsonNode(p, id, pathStr, kStringTId, &v, NULL, NULL, NULL, 1, cmIsFlag(flags,kForceValuePrFl) );
  1127. }
  1128. cmPrRC_t cmPrefsCreateBoolArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const bool* val, unsigned eleCnt )
  1129. {
  1130. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1131. return _cmPrefsCreateJsonNode(p, id, pathStr, kBoolTId, NULL, NULL, NULL, val, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1132. }
  1133. cmPrRC_t cmPrefsCreateUIntArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const unsigned* val, unsigned eleCnt )
  1134. {
  1135. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1136. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, (int*)val, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1137. }
  1138. cmPrRC_t cmPrefsCreateIntArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const int* val, unsigned eleCnt )
  1139. {
  1140. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1141. return _cmPrefsCreateJsonNode(p, id, pathStr, kIntTId, NULL, NULL, val, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1142. }
  1143. cmPrRC_t cmPrefsCreateFloatArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const float* val, unsigned eleCnt )
  1144. {
  1145. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1146. double* a = cmMemAlloc(double,eleCnt);
  1147. unsigned i;
  1148. for(i=0; i<eleCnt; ++i)
  1149. a[i] = val[i];
  1150. cmPrRC_t rc = _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, a, NULL, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1151. cmMemFree(a);
  1152. return rc;
  1153. }
  1154. cmPrRC_t cmPrefsCreateRealArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const double* val, unsigned eleCnt )
  1155. {
  1156. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1157. return _cmPrefsCreateJsonNode(p, id, pathStr, kRealTId, NULL, val, NULL, NULL, eleCnt, cmIsFlag(flags, kForceValuePrFl) );
  1158. }
  1159. cmPrRC_t cmPrefsCreateStringArray( cmPrH_t h, unsigned id, const cmChar_t* pathStr, unsigned flags, const cmChar_t** val, unsigned eleCnt )
  1160. {
  1161. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1162. return _cmPrefsCreateJsonNode(p, id, pathStr, kStringTId, val, NULL, NULL, NULL, eleCnt, cmIsFlag(flags,kForceValuePrFl) );
  1163. }
  1164. bool cmPrefsIsDirty( cmPrH_t h )
  1165. {
  1166. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1167. return p->dirtyFl;
  1168. }
  1169. cmPrRC_t cmPrefsWrite( cmPrH_t h, const cmChar_t* fn )
  1170. {
  1171. cmPrRC_t rc = kOkPrRC;
  1172. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1173. if( fn == NULL )
  1174. fn = p->fn;
  1175. if( cmJsonWrite( p->jsH, cmJsonRoot(p->jsH), fn) != kOkJsRC )
  1176. return cmErrMsg(&p->err,kWriteFileFailPrRC,"Preference writing failed.");
  1177. p->dirtyFl = false;
  1178. return rc;
  1179. }
  1180. void cmPrefsReport( cmPrH_t h )
  1181. {
  1182. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1183. cmJsonReport(p->jsH);
  1184. }
  1185. //=============================================================================================
  1186. // cmPrefsTest()
  1187. //
  1188. void _cmPrintNode( const cmPrNode_t* np )
  1189. {
  1190. const cmPrPath_t* pp = np->pathPtr;
  1191. const cmJsonNode_t* jnp = np->nodePtr;
  1192. const cmJsonNode_t* jpp = jnp->ownerPtr;
  1193. printf("id:%i type:0x%x parent:0x%x ",np->id,jnp->typeId,jpp==NULL?0:jpp->typeId);
  1194. while( pp != NULL )
  1195. {
  1196. printf("%s ",pp->label);
  1197. pp = pp->parentPtr;
  1198. }
  1199. printf("\n");
  1200. }
  1201. void _cmPrintNodes( const cmPrNode_t* np )
  1202. {
  1203. if( np == NULL )
  1204. return;
  1205. _cmPrintNode(np);
  1206. _cmPrintNodes(np->linkPtr);
  1207. }
  1208. /* example preferences file
  1209. {
  1210. "cfg" :
  1211. {
  1212. "inAudDevIdx" : 0
  1213. "outAudDevIdx" : 0
  1214. "syncInputFl" : false
  1215. "midiPortBufByteCnt" : 8192
  1216. "msgQueueByteCnt" : 64768
  1217. "devFramesPerCycle" : 128
  1218. "dspFramesPerCycle" : 64
  1219. "audioBufCnt" : 3
  1220. "srate" : 44100.000000
  1221. "chNames" :
  1222. {
  1223. "left" : 0
  1224. "right" : 1
  1225. "array" :
  1226. [
  1227. 0 ,
  1228. 1 ,
  1229. 2
  1230. ]
  1231. }
  1232. }
  1233. }
  1234. */
  1235. void cmPrefsTest( cmCtx_t* ctx, const char* ifn, const char* ofn )
  1236. {
  1237. cmPrH_t h = cmPrNullHandle;
  1238. if( cmPrefsInitialize(ctx,&h,ifn,NULL,NULL) != kOkPrRC )
  1239. return;
  1240. cmPr_t* p = _cmPrefsHandleToPtr(h);
  1241. _cmPrintNodes(p->idChainPtr);
  1242. unsigned id;
  1243. id = cmPrefsId(h, "cfg/audioBufCnt", true );
  1244. printf("id:%i\n",id);
  1245. //id = cmPrefsId(h, "cfg/audioBuf", true );
  1246. //printf("id:%i\n",id);
  1247. int sr;
  1248. unsigned n=1;
  1249. cmPrefsGetInt(h, cmPrefsId(h,"cfg/srate",true), &sr, &n );
  1250. printf("sr:%i %i\n",sr,n);
  1251. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), &sr, &n );
  1252. printf("sr:%i %i\n",sr,n);
  1253. int arr[4];
  1254. n = 4;
  1255. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), arr, &n );
  1256. printf("array:%i %i %i n=%i\n",arr[0],arr[1],arr[2],n);
  1257. sr = 44100;
  1258. n = 1;
  1259. cmPrefsSetIntArray(h, cmPrefsId(h,"cfg/srate",true), &sr, &n);
  1260. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), &sr, &n );
  1261. printf("sr:%i %i\n",sr,n);
  1262. int sarr[] = {10,11,12,13 };
  1263. n = sizeof(sarr)/sizeof(sarr[0]);
  1264. cmPrefsSetIntArray(h, cmPrefsId(h,"cfg/chNames/array",true), sarr, &n);
  1265. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), sarr, &n );
  1266. printf("array:%i %i %i %i n=%i\n",sarr[0],sarr[1],sarr[2],sarr[3],n);
  1267. int tarr[] = {20,21 };
  1268. n = sizeof(tarr)/sizeof(tarr[0]);
  1269. cmPrefsSetIntArray(h, cmPrefsId(h,"cfg/chNames/array",true), tarr, &n);
  1270. cmPrefsGetInt(h, cmPrefsId(h,"cfg/chNames/array",true), tarr, &n );
  1271. printf("array:%i %i n=%i\n",tarr[0],tarr[1],n);
  1272. cmPrefsCreateBool(h, cmInvalidId, "cfg/flags/flag0", 0, true );
  1273. bool bv = cmPrefsBool(h, cmPrefsId(h,"cfg/flags/flag0",true));
  1274. printf("bool:%i\n",bv);
  1275. cmPrefsCreateString(h,cmInvalidId, "cfg/audioBufCnt",0,"hey");
  1276. const cmChar_t* strArray[] =
  1277. {
  1278. "snap", "crackle", "pop"
  1279. };
  1280. cmPrefsCreateStringArray(h, cmInvalidId, "cfg/chNames/strList",0,strArray,3);
  1281. cmPrefsWrite(h,ofn);
  1282. cmPrefsFinalize(&h);
  1283. }