libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmPrefs.c 44KB

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