libconfig.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  1. /* ----------------------------------------------------------------------------
  2. libconfig - A library for processing structured configuration files
  3. Copyright (C) 2005-2010 Mark A Lindner
  4. This file is part of libconfig.
  5. This library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this library. If not, see <http://www.gnu.org/licenses/>.
  15. ----------------------------------------------------------------------------
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "ac_config.h"
  19. #endif
  20. #include "libconfig.h"
  21. #include "grammar.h"
  22. #include "scanner.h"
  23. #include "scanctx.h"
  24. #include "parsectx.h"
  25. #include "wincompat.h"
  26. #include <locale.h>
  27. #ifdef HAVE_XLOCALE_H
  28. #include <xlocale.h>
  29. #endif
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #define PATH_TOKENS ":./"
  34. #define CHUNK_SIZE 16
  35. #define FLOAT_PRECISION 10
  36. #define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */
  37. #define _delete(P) free((void *)(P))
  38. /* ------------------------------------------------------------------------- */
  39. #ifndef LIBCONFIG_STATIC
  40. #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
  41. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
  42. {
  43. return(TRUE);
  44. }
  45. #endif /* WIN32 */
  46. #endif /* LIBCONFIG_STATIC */
  47. /* ------------------------------------------------------------------------- */
  48. static const char *__io_error = "file I/O error";
  49. static void __config_list_destroy(config_list_t *list);
  50. static void __config_write_setting(const config_setting_t *setting,
  51. FILE *stream, int depth,
  52. unsigned short tab_width);
  53. extern int libconfig_yyparse(void *scanner, struct parse_context *ctx,
  54. struct scan_context *scan_ctx);
  55. extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx,
  56. yyscan_t *scanner);
  57. /* ------------------------------------------------------------------------- */
  58. static void __config_locale_override(void)
  59. {
  60. #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
  61. && ! defined(__MINGW32__)
  62. _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
  63. setlocale(LC_NUMERIC, "C");
  64. #elif defined(__APPLE__)
  65. locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL);
  66. uselocale(loc);
  67. #elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE))
  68. locale_t loc = newlocale(LC_NUMERIC, "C", NULL);
  69. uselocale(loc);
  70. #else
  71. #warning "No way to modify calling thread's locale!"
  72. #endif
  73. }
  74. /* ------------------------------------------------------------------------- */
  75. static void __config_locale_restore(void)
  76. {
  77. #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
  78. && ! defined(__MINGW32__)
  79. _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
  80. #elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE))
  81. locale_t loc = uselocale(LC_GLOBAL_LOCALE);
  82. freelocale(loc);
  83. #else
  84. #warning "No way to modify calling thread's locale!"
  85. #endif
  86. }
  87. /* ------------------------------------------------------------------------- */
  88. static int __config_name_compare(const char *a, const char *b)
  89. {
  90. const char *p, *q;
  91. for(p = a, q = b; ; p++, q++)
  92. {
  93. int pd = ((! *p) || strchr(PATH_TOKENS, *p));
  94. int qd = ((! *q) || strchr(PATH_TOKENS, *q));
  95. if(pd && qd)
  96. break;
  97. else if(pd)
  98. return(-1);
  99. else if(qd)
  100. return(1);
  101. else if(*p < *q)
  102. return(-1);
  103. else if(*p > *q)
  104. return(1);
  105. }
  106. return(0);
  107. }
  108. /* ------------------------------------------------------------------------- */
  109. static void __config_indent(FILE *stream, int depth, unsigned short w)
  110. {
  111. if(w)
  112. fprintf(stream, "%*s", (depth - 1) * w, " ");
  113. else
  114. {
  115. int i;
  116. for(i = 0; i < (depth - 1); ++i)
  117. fputc('\t', stream);
  118. }
  119. }
  120. /* ------------------------------------------------------------------------- */
  121. static void __config_write_value(const config_value_t *value, int type,
  122. int format, int depth,
  123. unsigned short tab_width, FILE *stream)
  124. {
  125. char fbuf[64];
  126. switch(type)
  127. {
  128. /* boolean */
  129. case CONFIG_TYPE_BOOL:
  130. fputs(value->ival ? "true" : "false", stream);
  131. break;
  132. /* int */
  133. case CONFIG_TYPE_INT:
  134. switch(format)
  135. {
  136. case CONFIG_FORMAT_HEX:
  137. fprintf(stream, "0x%X", value->ival);
  138. break;
  139. case CONFIG_FORMAT_DEFAULT:
  140. default:
  141. fprintf(stream, "%d", value->ival);
  142. break;
  143. }
  144. break;
  145. /* 64-bit int */
  146. case CONFIG_TYPE_INT64:
  147. switch(format)
  148. {
  149. case CONFIG_FORMAT_HEX:
  150. fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval);
  151. break;
  152. case CONFIG_FORMAT_DEFAULT:
  153. default:
  154. fprintf(stream, INT64_FMT "L", value->llval);
  155. break;
  156. }
  157. break;
  158. /* float */
  159. case CONFIG_TYPE_FLOAT:
  160. {
  161. char *q;
  162. snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval);
  163. /* check for exponent */
  164. q = strchr(fbuf, 'e');
  165. if(! q)
  166. {
  167. /* no exponent */
  168. if(! strchr(fbuf, '.')) /* no decimal point */
  169. strcat(fbuf, ".0");
  170. else
  171. {
  172. /* has decimal point */
  173. char *p;
  174. for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p)
  175. {
  176. if(*p != '0')
  177. {
  178. *(++p) = '\0';
  179. break;
  180. }
  181. }
  182. }
  183. }
  184. fputs(fbuf, stream);
  185. break;
  186. }
  187. /* string */
  188. case CONFIG_TYPE_STRING:
  189. {
  190. char *p;
  191. fputc('\"', stream);
  192. if(value->sval)
  193. {
  194. for(p = value->sval; *p; p++)
  195. {
  196. int c = (int)*p & 0xFF;
  197. switch(c)
  198. {
  199. case '\"':
  200. case '\\':
  201. fputc('\\', stream);
  202. fputc(c, stream);
  203. break;
  204. case '\n':
  205. fputs("\\n", stream);
  206. break;
  207. case '\r':
  208. fputs("\\r", stream);
  209. break;
  210. case '\f':
  211. fputs("\\f", stream);
  212. break;
  213. case '\t':
  214. fputs("\\t", stream);
  215. break;
  216. default:
  217. if(c >= ' ')
  218. fputc(c, stream);
  219. else
  220. fprintf(stream, "\\x%02X", c);
  221. }
  222. }
  223. }
  224. fputc('\"', stream);
  225. break;
  226. }
  227. /* list */
  228. case CONFIG_TYPE_LIST:
  229. {
  230. config_list_t *list = value->list;
  231. fprintf(stream, "( ");
  232. if(list)
  233. {
  234. int len = list->length;
  235. config_setting_t **s;
  236. for(s = list->elements; len--; s++)
  237. {
  238. __config_write_value(&((*s)->value), (*s)->type,
  239. config_setting_get_format(*s),
  240. depth + 1, tab_width, stream);
  241. if(len)
  242. fputc(',', stream);
  243. fputc(' ', stream);
  244. }
  245. }
  246. fputc(')', stream);
  247. break;
  248. }
  249. /* array */
  250. case CONFIG_TYPE_ARRAY:
  251. {
  252. config_list_t *list = value->list;
  253. fprintf(stream, "[ ");
  254. if(list)
  255. {
  256. int len = list->length;
  257. config_setting_t **s;
  258. for(s = list->elements; len--; s++)
  259. {
  260. __config_write_value(&((*s)->value), (*s)->type,
  261. config_setting_get_format(*s),
  262. depth + 1, tab_width, stream);
  263. if(len)
  264. fputc(',', stream);
  265. fputc(' ', stream);
  266. }
  267. }
  268. fputc(']', stream);
  269. break;
  270. }
  271. /* group */
  272. case CONFIG_TYPE_GROUP:
  273. {
  274. config_list_t *list = value->list;
  275. if(depth > 0)
  276. {
  277. #ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */
  278. fputc(' ', stream);
  279. #else
  280. fputc('\n', stream);
  281. if(depth > 1)
  282. __config_indent(stream, depth, tab_width);
  283. #endif
  284. fprintf(stream, "{\n");
  285. }
  286. if(list)
  287. {
  288. int len = list->length;
  289. config_setting_t **s;
  290. for(s = list->elements; len--; s++)
  291. __config_write_setting(*s, stream, depth + 1, tab_width);
  292. }
  293. if(depth > 1)
  294. __config_indent(stream, depth, tab_width);
  295. if(depth > 0)
  296. fputc('}', stream);
  297. break;
  298. }
  299. default:
  300. /* this shouldn't happen, but handle it gracefully... */
  301. fputs("???", stream);
  302. break;
  303. }
  304. }
  305. /* ------------------------------------------------------------------------- */
  306. static void __config_list_add(config_list_t *list, config_setting_t *setting)
  307. {
  308. if((list->length % CHUNK_SIZE) == 0)
  309. {
  310. list->elements = (config_setting_t **)realloc(
  311. list->elements,
  312. (list->length + CHUNK_SIZE) * sizeof(config_setting_t *));
  313. }
  314. list->elements[list->length] = setting;
  315. list->length++;
  316. }
  317. /* ------------------------------------------------------------------------- */
  318. static config_setting_t *__config_list_search(config_list_t *list,
  319. const char *name,
  320. unsigned int *idx)
  321. {
  322. config_setting_t **found = NULL;
  323. unsigned int i;
  324. if(! list)
  325. return(NULL);
  326. for(i = 0, found = list->elements; i < list->length; i++, found++)
  327. {
  328. if(! (*found)->name)
  329. continue;
  330. if(! __config_name_compare(name, (*found)->name))
  331. {
  332. if(idx)
  333. *idx = i;
  334. return(*found);
  335. }
  336. }
  337. return(NULL);
  338. }
  339. /* ------------------------------------------------------------------------- */
  340. static config_setting_t *__config_list_remove(config_list_t *list, int idx)
  341. {
  342. config_setting_t *removed = *(list->elements + idx);
  343. int offset = (idx * sizeof(config_setting_t *));
  344. int len = list->length - 1 - idx;
  345. char *base = (char *)list->elements + offset;
  346. memmove(base, base + sizeof(config_setting_t *),
  347. len * sizeof(config_setting_t *));
  348. list->length--;
  349. /* possibly realloc smaller? */
  350. return(removed);
  351. }
  352. /* ------------------------------------------------------------------------- */
  353. static void __config_setting_destroy(config_setting_t *setting)
  354. {
  355. if(setting)
  356. {
  357. if(setting->name)
  358. _delete(setting->name);
  359. if(setting->type == CONFIG_TYPE_STRING)
  360. _delete(setting->value.sval);
  361. else if((setting->type == CONFIG_TYPE_GROUP)
  362. || (setting->type == CONFIG_TYPE_ARRAY)
  363. || (setting->type == CONFIG_TYPE_LIST))
  364. {
  365. if(setting->value.list)
  366. __config_list_destroy(setting->value.list);
  367. }
  368. if(setting->hook && setting->config->destructor)
  369. setting->config->destructor(setting->hook);
  370. _delete(setting);
  371. }
  372. }
  373. /* ------------------------------------------------------------------------- */
  374. static void __config_list_destroy(config_list_t *list)
  375. {
  376. config_setting_t **p;
  377. unsigned int i;
  378. if(! list)
  379. return;
  380. if(list->elements)
  381. {
  382. for(p = list->elements, i = 0; i < list->length; p++, i++)
  383. __config_setting_destroy(*p);
  384. _delete(list->elements);
  385. }
  386. _delete(list);
  387. }
  388. /* ------------------------------------------------------------------------- */
  389. static int __config_vector_checktype(const config_setting_t *vector, int type)
  390. {
  391. /* if the array is empty, then it has no type yet */
  392. if(! vector->value.list)
  393. return(CONFIG_TRUE);
  394. if(vector->value.list->length == 0)
  395. return(CONFIG_TRUE);
  396. /* if it's a list, any type is allowed */
  397. if(vector->type == CONFIG_TYPE_LIST)
  398. return(CONFIG_TRUE);
  399. /* otherwise the first element added determines the type of the array */
  400. return((vector->value.list->elements[0]->type == type)
  401. ? CONFIG_TRUE : CONFIG_FALSE);
  402. }
  403. /* ------------------------------------------------------------------------- */
  404. static int __config_validate_name(const char *name)
  405. {
  406. const char *p = name;
  407. if(*p == '\0')
  408. return(CONFIG_FALSE);
  409. if(! isalpha(*p) && (*p != '*'))
  410. return(CONFIG_FALSE);
  411. for(++p; *p; ++p)
  412. {
  413. if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p)))
  414. return(CONFIG_FALSE);
  415. }
  416. return(CONFIG_TRUE);
  417. }
  418. /* ------------------------------------------------------------------------- */
  419. static int __config_read(config_t *config, FILE *stream, const char *filename,
  420. const char *str)
  421. {
  422. yyscan_t scanner;
  423. struct scan_context scan_ctx;
  424. struct parse_context parse_ctx;
  425. YY_BUFFER_STATE buffer = NULL;
  426. int r;
  427. /* Reinitialize the config */
  428. void (*destructor)(void *) = config->destructor;
  429. const char *include_dir = config->include_dir;
  430. unsigned short tab_width = config->tab_width;
  431. unsigned short flags = config->flags;
  432. config->include_dir = NULL;
  433. config_destroy(config);
  434. config_init(config);
  435. config->destructor = destructor;
  436. config->include_dir = include_dir;
  437. config->tab_width = tab_width;
  438. config->flags = flags;
  439. parsectx_init(&parse_ctx);
  440. parse_ctx.config = config;
  441. parse_ctx.parent = config->root;
  442. parse_ctx.setting = config->root;
  443. __config_locale_override();
  444. scanctx_init(&scan_ctx, filename);
  445. scan_ctx.config = config;
  446. libconfig_yylex_init_extra(&scan_ctx, &scanner);
  447. if(stream)
  448. libconfig_yyrestart(stream, scanner);
  449. else /* read from string */
  450. buffer = libconfig_yy_scan_string(str, scanner);
  451. libconfig_yyset_lineno(1, scanner);
  452. r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx);
  453. if(r != 0)
  454. {
  455. YY_BUFFER_STATE buf;
  456. config->error_file = scanctx_current_filename(&scan_ctx);
  457. config->error_type = CONFIG_ERR_PARSE;
  458. /* Unwind the include stack, freeing the buffers and closing the files. */
  459. while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL)
  460. libconfig_yy_delete_buffer(buf, scanner);
  461. }
  462. libconfig_yylex_destroy(scanner);
  463. config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames));
  464. parsectx_cleanup(&parse_ctx);
  465. __config_locale_restore();
  466. return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE);
  467. }
  468. /* ------------------------------------------------------------------------- */
  469. int config_read(config_t *config, FILE *stream)
  470. {
  471. return(__config_read(config, stream, NULL, NULL));
  472. }
  473. /* ------------------------------------------------------------------------- */
  474. int config_read_string(config_t *config, const char *str)
  475. {
  476. return(__config_read(config, NULL, NULL, str));
  477. }
  478. /* ------------------------------------------------------------------------- */
  479. static void __config_write_setting(const config_setting_t *setting,
  480. FILE *stream, int depth,
  481. unsigned short tab_width)
  482. {
  483. if(depth > 1)
  484. __config_indent(stream, depth, tab_width);
  485. if(setting->name)
  486. {
  487. fputs(setting->name, stream);
  488. fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '='));
  489. }
  490. __config_write_value(&(setting->value), setting->type,
  491. config_setting_get_format(setting),
  492. depth, tab_width, stream);
  493. if(depth > 0)
  494. {
  495. fputc(';', stream);
  496. fputc('\n', stream);
  497. }
  498. }
  499. /* ------------------------------------------------------------------------- */
  500. void config_write(const config_t *config, FILE *stream)
  501. {
  502. __config_locale_override();
  503. __config_write_setting(config->root, stream, 0, config->tab_width);
  504. __config_locale_restore();
  505. }
  506. /* ------------------------------------------------------------------------- */
  507. int config_read_file(config_t *config, const char *filename)
  508. {
  509. int ret;
  510. FILE *stream = fopen(filename, "rt");
  511. if(! stream)
  512. {
  513. config->error_text = __io_error;
  514. config->error_type = CONFIG_ERR_FILE_IO;
  515. return(CONFIG_FALSE);
  516. }
  517. ret = __config_read(config, stream, filename, NULL);
  518. fclose(stream);
  519. return(ret);
  520. }
  521. /* ------------------------------------------------------------------------- */
  522. int config_write_file(config_t *config, const char *filename)
  523. {
  524. FILE *f = fopen(filename, "wt");
  525. if(! f)
  526. {
  527. config->error_text = __io_error;
  528. config->error_type = CONFIG_ERR_FILE_IO;
  529. return(CONFIG_FALSE);
  530. }
  531. config_write(config, f);
  532. fclose(f);
  533. config->error_type = CONFIG_ERR_NONE;
  534. return(CONFIG_TRUE);
  535. }
  536. /* ------------------------------------------------------------------------- */
  537. void config_destroy(config_t *config)
  538. {
  539. unsigned int count = config->num_filenames;
  540. const char **f;
  541. __config_setting_destroy(config->root);
  542. for(f = config->filenames; count > 0; ++f, --count)
  543. _delete(*f);
  544. _delete(config->filenames);
  545. _delete(config->include_dir);
  546. memset((void *)config, 0, sizeof(config_t));
  547. }
  548. /* ------------------------------------------------------------------------- */
  549. void config_init(config_t *config)
  550. {
  551. memset((void *)config, 0, sizeof(config_t));
  552. config->root = _new(config_setting_t);
  553. config->root->type = CONFIG_TYPE_GROUP;
  554. config->root->config = config;
  555. config->tab_width = 2;
  556. }
  557. /* ------------------------------------------------------------------------- */
  558. void config_set_auto_convert(config_t *config, int flag)
  559. {
  560. if(flag)
  561. config->flags |= CONFIG_OPTION_AUTOCONVERT;
  562. else
  563. config->flags &= ~CONFIG_OPTION_AUTOCONVERT;
  564. }
  565. /* ------------------------------------------------------------------------- */
  566. int config_get_auto_convert(const config_t *config)
  567. {
  568. return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0);
  569. }
  570. /* ------------------------------------------------------------------------- */
  571. static config_setting_t *config_setting_create(config_setting_t *parent,
  572. const char *name, int type)
  573. {
  574. config_setting_t *setting;
  575. config_list_t *list;
  576. if((parent->type != CONFIG_TYPE_GROUP)
  577. && (parent->type != CONFIG_TYPE_ARRAY)
  578. && (parent->type != CONFIG_TYPE_LIST))
  579. return(NULL);
  580. setting = _new(config_setting_t);
  581. setting->parent = parent;
  582. setting->name = (name == NULL) ? NULL : strdup(name);
  583. setting->type = type;
  584. setting->config = parent->config;
  585. setting->hook = NULL;
  586. setting->line = 0;
  587. list = parent->value.list;
  588. if(! list)
  589. list = parent->value.list = _new(config_list_t);
  590. __config_list_add(list, setting);
  591. return(setting);
  592. }
  593. /* ------------------------------------------------------------------------- */
  594. static int __config_setting_get_int(const config_setting_t *setting,
  595. int *value)
  596. {
  597. switch(setting->type)
  598. {
  599. case CONFIG_TYPE_INT:
  600. *value = setting->value.ival;
  601. return(CONFIG_TRUE);
  602. case CONFIG_TYPE_INT64:
  603. if((setting->value.llval > INT32_MAX)
  604. || (setting->value.llval < INT32_MIN))
  605. *value = 0;
  606. else
  607. *value = (int)(setting->value.llval);
  608. return(CONFIG_TRUE);
  609. case CONFIG_TYPE_FLOAT:
  610. if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
  611. {
  612. *value = (int)(setting->value.fval);
  613. return(CONFIG_TRUE);
  614. }
  615. else
  616. { /* fall through */ }
  617. default:
  618. return(CONFIG_FALSE);
  619. }
  620. }
  621. /* ------------------------------------------------------------------------- */
  622. int config_setting_get_int(const config_setting_t *setting)
  623. {
  624. int value = 0;
  625. __config_setting_get_int(setting, &value);
  626. return(value);
  627. }
  628. /* ------------------------------------------------------------------------- */
  629. static int __config_setting_get_int64(const config_setting_t *setting,
  630. long long *value)
  631. {
  632. switch(setting->type)
  633. {
  634. case CONFIG_TYPE_INT64:
  635. *value = setting->value.llval;
  636. return(CONFIG_TRUE);
  637. case CONFIG_TYPE_INT:
  638. *value = (long long)(setting->value.ival);
  639. return(CONFIG_TRUE);
  640. case CONFIG_TYPE_FLOAT:
  641. if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
  642. {
  643. *value = (long long)(setting->value.fval);
  644. return(CONFIG_TRUE);
  645. }
  646. else
  647. { /* fall through */ }
  648. default:
  649. return(CONFIG_FALSE);
  650. }
  651. }
  652. /* ------------------------------------------------------------------------- */
  653. long long config_setting_get_int64(const config_setting_t *setting)
  654. {
  655. long long value = 0;
  656. __config_setting_get_int64(setting, &value);
  657. return(value);
  658. }
  659. /* ------------------------------------------------------------------------- */
  660. int config_setting_lookup_int(const config_setting_t *setting,
  661. const char *name, int *value)
  662. {
  663. config_setting_t *member = config_setting_get_member(setting, name);
  664. if(! member)
  665. return(CONFIG_FALSE);
  666. return(__config_setting_get_int(member, value));
  667. }
  668. /* ------------------------------------------------------------------------- */
  669. int config_setting_lookup_int64(const config_setting_t *setting,
  670. const char *name, long long *value)
  671. {
  672. config_setting_t *member = config_setting_get_member(setting, name);
  673. if(! member)
  674. return(CONFIG_FALSE);
  675. return(__config_setting_get_int64(member, value));
  676. }
  677. /* ------------------------------------------------------------------------- */
  678. static int __config_setting_get_float(const config_setting_t *setting,
  679. double *value)
  680. {
  681. switch(setting->type)
  682. {
  683. case CONFIG_TYPE_FLOAT:
  684. *value = setting->value.fval;
  685. return(CONFIG_TRUE);
  686. case CONFIG_TYPE_INT:
  687. if(config_get_auto_convert(setting->config))
  688. {
  689. *value = (double)(setting->value.ival);
  690. return(CONFIG_TRUE);
  691. }
  692. else
  693. return(CONFIG_FALSE);
  694. case CONFIG_TYPE_INT64:
  695. if(config_get_auto_convert(setting->config))
  696. {
  697. *value = (double)(setting->value.llval);
  698. return(CONFIG_TRUE);
  699. }
  700. else
  701. { /* fall through */ }
  702. default:
  703. return(CONFIG_FALSE);
  704. }
  705. }
  706. /* ------------------------------------------------------------------------- */
  707. double config_setting_get_float(const config_setting_t *setting)
  708. {
  709. double value = 0.0;
  710. __config_setting_get_float(setting, &value);
  711. return(value);
  712. }
  713. /* ------------------------------------------------------------------------- */
  714. int config_setting_lookup_float(const config_setting_t *setting,
  715. const char *name, double *value)
  716. {
  717. config_setting_t *member = config_setting_get_member(setting, name);
  718. if(! member)
  719. return(CONFIG_FALSE);
  720. return(__config_setting_get_float(member, value));
  721. }
  722. /* ------------------------------------------------------------------------- */
  723. int config_setting_lookup_string(const config_setting_t *setting,
  724. const char *name, const char **value)
  725. {
  726. config_setting_t *member = config_setting_get_member(setting, name);
  727. if(! member)
  728. return(CONFIG_FALSE);
  729. if(config_setting_type(member) != CONFIG_TYPE_STRING)
  730. return(CONFIG_FALSE);
  731. *value = config_setting_get_string(member);
  732. return(CONFIG_TRUE);
  733. }
  734. /* ------------------------------------------------------------------------- */
  735. int config_setting_lookup_bool(const config_setting_t *setting,
  736. const char *name, int *value)
  737. {
  738. config_setting_t *member = config_setting_get_member(setting, name);
  739. if(! member)
  740. return(CONFIG_FALSE);
  741. if(config_setting_type(member) != CONFIG_TYPE_BOOL)
  742. return(CONFIG_FALSE);
  743. *value = config_setting_get_bool(member);
  744. return(CONFIG_TRUE);
  745. }
  746. /* ------------------------------------------------------------------------- */
  747. int config_setting_set_int(config_setting_t *setting, int value)
  748. {
  749. switch(setting->type)
  750. {
  751. case CONFIG_TYPE_NONE:
  752. setting->type = CONFIG_TYPE_INT;
  753. /* fall through */
  754. case CONFIG_TYPE_INT:
  755. setting->value.ival = value;
  756. return(CONFIG_TRUE);
  757. case CONFIG_TYPE_FLOAT:
  758. if(config_get_auto_convert(setting->config))
  759. {
  760. setting->value.fval = (float)value;
  761. return(CONFIG_TRUE);
  762. }
  763. else
  764. return(CONFIG_FALSE);
  765. default:
  766. return(CONFIG_FALSE);
  767. }
  768. }
  769. /* ------------------------------------------------------------------------- */
  770. int config_setting_set_int64(config_setting_t *setting, long long value)
  771. {
  772. switch(setting->type)
  773. {
  774. case CONFIG_TYPE_NONE:
  775. setting->type = CONFIG_TYPE_INT64;
  776. /* fall through */
  777. case CONFIG_TYPE_INT64:
  778. setting->value.llval = value;
  779. return(CONFIG_TRUE);
  780. case CONFIG_TYPE_INT:
  781. if((value > INT32_MAX) || (value < INT32_MIN))
  782. setting->value.ival = 0;
  783. else
  784. setting->value.ival = (int)value;
  785. return(CONFIG_TRUE);
  786. case CONFIG_TYPE_FLOAT:
  787. if(config_get_auto_convert(setting->config))
  788. {
  789. setting->value.fval = (float)value;
  790. return(CONFIG_TRUE);
  791. }
  792. else
  793. return(CONFIG_FALSE);
  794. default:
  795. return(CONFIG_FALSE);
  796. }
  797. }
  798. /* ------------------------------------------------------------------------- */
  799. int config_setting_set_float(config_setting_t *setting, double value)
  800. {
  801. switch(setting->type)
  802. {
  803. case CONFIG_TYPE_NONE:
  804. setting->type = CONFIG_TYPE_FLOAT;
  805. /* fall through */
  806. case CONFIG_TYPE_FLOAT:
  807. setting->value.fval = value;
  808. return(CONFIG_TRUE);
  809. case CONFIG_TYPE_INT:
  810. if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
  811. {
  812. setting->value.ival = (int)value;
  813. return(CONFIG_TRUE);
  814. }
  815. else
  816. return(CONFIG_FALSE);
  817. case CONFIG_TYPE_INT64:
  818. if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0)
  819. {
  820. setting->value.llval = (long long)value;
  821. return(CONFIG_TRUE);
  822. }
  823. else
  824. return(CONFIG_FALSE);
  825. default:
  826. return(CONFIG_FALSE);
  827. }
  828. }
  829. /* ------------------------------------------------------------------------- */
  830. int config_setting_get_bool(const config_setting_t *setting)
  831. {
  832. return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0);
  833. }
  834. /* ------------------------------------------------------------------------- */
  835. int config_setting_set_bool(config_setting_t *setting, int value)
  836. {
  837. if(setting->type == CONFIG_TYPE_NONE)
  838. setting->type = CONFIG_TYPE_BOOL;
  839. else if(setting->type != CONFIG_TYPE_BOOL)
  840. return(CONFIG_FALSE);
  841. setting->value.ival = value;
  842. return(CONFIG_TRUE);
  843. }
  844. /* ------------------------------------------------------------------------- */
  845. const char *config_setting_get_string(const config_setting_t *setting)
  846. {
  847. return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL);
  848. }
  849. /* ------------------------------------------------------------------------- */
  850. int config_setting_set_string(config_setting_t *setting, const char *value)
  851. {
  852. if(setting->type == CONFIG_TYPE_NONE)
  853. setting->type = CONFIG_TYPE_STRING;
  854. else if(setting->type != CONFIG_TYPE_STRING)
  855. return(CONFIG_FALSE);
  856. if(setting->value.sval)
  857. _delete(setting->value.sval);
  858. setting->value.sval = (value == NULL) ? NULL : strdup(value);
  859. return(CONFIG_TRUE);
  860. }
  861. /* ------------------------------------------------------------------------- */
  862. int config_setting_set_format(config_setting_t *setting, short format)
  863. {
  864. if(((setting->type != CONFIG_TYPE_INT)
  865. && (setting->type != CONFIG_TYPE_INT64))
  866. || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX)))
  867. return(CONFIG_FALSE);
  868. setting->format = format;
  869. return(CONFIG_TRUE);
  870. }
  871. /* ------------------------------------------------------------------------- */
  872. short config_setting_get_format(const config_setting_t *setting)
  873. {
  874. return(setting->format != 0 ? setting->format
  875. : setting->config->default_format);
  876. }
  877. /* ------------------------------------------------------------------------- */
  878. config_setting_t *config_lookup_from(config_setting_t *setting,
  879. const char *path)
  880. {
  881. const char *p = path;
  882. config_setting_t *found;
  883. for(;;)
  884. {
  885. while(*p && strchr(PATH_TOKENS, *p))
  886. p++;
  887. if(! *p)
  888. break;
  889. if(*p == '[')
  890. found = config_setting_get_elem(setting, atoi(++p));
  891. else
  892. found = config_setting_get_member(setting, p);
  893. if(! found)
  894. break;
  895. setting = found;
  896. while(! strchr(PATH_TOKENS, *p))
  897. p++;
  898. }
  899. return(*p ? NULL : setting);
  900. }
  901. /* ------------------------------------------------------------------------- */
  902. config_setting_t *config_lookup(const config_t *config, const char *path)
  903. {
  904. return(config_lookup_from(config->root, path));
  905. }
  906. /* ------------------------------------------------------------------------- */
  907. int config_lookup_string(const config_t *config, const char *path,
  908. const char **value)
  909. {
  910. const config_setting_t *s = config_lookup(config, path);
  911. if(! s)
  912. return(CONFIG_FALSE);
  913. if(config_setting_type(s) != CONFIG_TYPE_STRING)
  914. return(CONFIG_FALSE);
  915. *value = config_setting_get_string(s);
  916. return(CONFIG_TRUE);
  917. }
  918. /* ------------------------------------------------------------------------- */
  919. int config_lookup_int(const config_t *config, const char *path,
  920. int *value)
  921. {
  922. const config_setting_t *s = config_lookup(config, path);
  923. if(! s)
  924. return(CONFIG_FALSE);
  925. return(__config_setting_get_int(s, value));
  926. }
  927. /* ------------------------------------------------------------------------- */
  928. int config_lookup_int64(const config_t *config, const char *path,
  929. long long *value)
  930. {
  931. const config_setting_t *s = config_lookup(config, path);
  932. if(! s)
  933. return(CONFIG_FALSE);
  934. return(__config_setting_get_int64(s, value));
  935. }
  936. /* ------------------------------------------------------------------------- */
  937. int config_lookup_float(const config_t *config, const char *path,
  938. double *value)
  939. {
  940. const config_setting_t *s = config_lookup(config, path);
  941. if(! s)
  942. return(CONFIG_FALSE);
  943. return(__config_setting_get_float(s, value));
  944. }
  945. /* ------------------------------------------------------------------------- */
  946. int config_lookup_bool(const config_t *config, const char *path, int *value)
  947. {
  948. const config_setting_t *s = config_lookup(config, path);
  949. if(! s)
  950. return(CONFIG_FALSE);
  951. if(config_setting_type(s) != CONFIG_TYPE_BOOL)
  952. return(CONFIG_FALSE);
  953. *value = config_setting_get_bool(s);
  954. return(CONFIG_TRUE);
  955. }
  956. /* ------------------------------------------------------------------------- */
  957. int config_setting_get_int_elem(const config_setting_t *vector, int idx)
  958. {
  959. const config_setting_t *element = config_setting_get_elem(vector, idx);
  960. return(element ? config_setting_get_int(element) : 0);
  961. }
  962. /* ------------------------------------------------------------------------- */
  963. config_setting_t *config_setting_set_int_elem(config_setting_t *vector,
  964. int idx, int value)
  965. {
  966. config_setting_t *element = NULL;
  967. if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
  968. return(NULL);
  969. if(idx < 0)
  970. {
  971. if(! __config_vector_checktype(vector, CONFIG_TYPE_INT))
  972. return(NULL);
  973. element = config_setting_create(vector, NULL, CONFIG_TYPE_INT);
  974. }
  975. else
  976. {
  977. element = config_setting_get_elem(vector, idx);
  978. if(! element)
  979. return(NULL);
  980. }
  981. if(! config_setting_set_int(element, value))
  982. return(NULL);
  983. return(element);
  984. }
  985. /* ------------------------------------------------------------------------- */
  986. long long config_setting_get_int64_elem(const config_setting_t *vector,
  987. int idx)
  988. {
  989. const config_setting_t *element = config_setting_get_elem(vector, idx);
  990. return(element ? config_setting_get_int64(element) : 0);
  991. }
  992. /* ------------------------------------------------------------------------- */
  993. config_setting_t *config_setting_set_int64_elem(config_setting_t *vector,
  994. int idx, long long value)
  995. {
  996. config_setting_t *element = NULL;
  997. if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
  998. return(NULL);
  999. if(idx < 0)
  1000. {
  1001. if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64))
  1002. return(NULL);
  1003. element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64);
  1004. }
  1005. else
  1006. {
  1007. element = config_setting_get_elem(vector, idx);
  1008. if(! element)
  1009. return(NULL);
  1010. }
  1011. if(! config_setting_set_int64(element, value))
  1012. return(NULL);
  1013. return(element);
  1014. }
  1015. /* ------------------------------------------------------------------------- */
  1016. double config_setting_get_float_elem(const config_setting_t *vector, int idx)
  1017. {
  1018. config_setting_t *element = config_setting_get_elem(vector, idx);
  1019. return(element ? config_setting_get_float(element) : 0.0);
  1020. }
  1021. /* ------------------------------------------------------------------------- */
  1022. config_setting_t *config_setting_set_float_elem(config_setting_t *vector,
  1023. int idx, double value)
  1024. {
  1025. config_setting_t *element = NULL;
  1026. if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
  1027. return(NULL);
  1028. if(idx < 0)
  1029. {
  1030. if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT))
  1031. return(NULL);
  1032. element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT);
  1033. }
  1034. else
  1035. element = config_setting_get_elem(vector, idx);
  1036. if(! element)
  1037. return(NULL);
  1038. if(! config_setting_set_float(element, value))
  1039. return(NULL);
  1040. return(element);
  1041. }
  1042. /* ------------------------------------------------------------------------- */
  1043. int config_setting_get_bool_elem(const config_setting_t *vector, int idx)
  1044. {
  1045. config_setting_t *element = config_setting_get_elem(vector, idx);
  1046. if(! element)
  1047. return(CONFIG_FALSE);
  1048. if(element->type != CONFIG_TYPE_BOOL)
  1049. return(CONFIG_FALSE);
  1050. return(element->value.ival);
  1051. }
  1052. /* ------------------------------------------------------------------------- */
  1053. config_setting_t *config_setting_set_bool_elem(config_setting_t *vector,
  1054. int idx, int value)
  1055. {
  1056. config_setting_t *element = NULL;
  1057. if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
  1058. return(NULL);
  1059. if(idx < 0)
  1060. {
  1061. if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL))
  1062. return(NULL);
  1063. element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL);
  1064. }
  1065. else
  1066. element = config_setting_get_elem(vector, idx);
  1067. if(! element)
  1068. return(NULL);
  1069. if(! config_setting_set_bool(element, value))
  1070. return(NULL);
  1071. return(element);
  1072. }
  1073. /* ------------------------------------------------------------------------- */
  1074. const char *config_setting_get_string_elem(const config_setting_t *vector,
  1075. int idx)
  1076. {
  1077. config_setting_t *element = config_setting_get_elem(vector, idx);
  1078. if(! element)
  1079. return(NULL);
  1080. if(element->type != CONFIG_TYPE_STRING)
  1081. return(NULL);
  1082. return(element->value.sval);
  1083. }
  1084. /* ------------------------------------------------------------------------- */
  1085. config_setting_t *config_setting_set_string_elem(config_setting_t *vector,
  1086. int idx, const char *value)
  1087. {
  1088. config_setting_t *element = NULL;
  1089. if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST))
  1090. return(NULL);
  1091. if(idx < 0)
  1092. {
  1093. if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING))
  1094. return(NULL);
  1095. element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING);
  1096. }
  1097. else
  1098. element = config_setting_get_elem(vector, idx);
  1099. if(! element)
  1100. return(NULL);
  1101. if(! config_setting_set_string(element, value))
  1102. return(NULL);
  1103. return(element);
  1104. }
  1105. /* ------------------------------------------------------------------------- */
  1106. config_setting_t *config_setting_get_elem(const config_setting_t *vector,
  1107. unsigned int idx)
  1108. {
  1109. config_list_t *list = vector->value.list;
  1110. if(((vector->type != CONFIG_TYPE_ARRAY)
  1111. && (vector->type != CONFIG_TYPE_LIST)
  1112. && (vector->type != CONFIG_TYPE_GROUP)) || ! list)
  1113. return(NULL);
  1114. if(idx >= list->length)
  1115. return(NULL);
  1116. return(list->elements[idx]);
  1117. }
  1118. /* ------------------------------------------------------------------------- */
  1119. config_setting_t *config_setting_get_member(const config_setting_t *setting,
  1120. const char *name)
  1121. {
  1122. if(setting->type != CONFIG_TYPE_GROUP)
  1123. return(NULL);
  1124. return(__config_list_search(setting->value.list, name, NULL));
  1125. }
  1126. /* ------------------------------------------------------------------------- */
  1127. void config_set_destructor(config_t *config, void (*destructor)(void *))
  1128. {
  1129. config->destructor = destructor;
  1130. }
  1131. /* ------------------------------------------------------------------------- */
  1132. void config_set_include_dir(config_t *config, const char *include_dir)
  1133. {
  1134. _delete(config->include_dir);
  1135. config->include_dir = strdup(include_dir);
  1136. }
  1137. /* ------------------------------------------------------------------------- */
  1138. int config_setting_length(const config_setting_t *setting)
  1139. {
  1140. if((setting->type != CONFIG_TYPE_GROUP)
  1141. && (setting->type != CONFIG_TYPE_ARRAY)
  1142. && (setting->type != CONFIG_TYPE_LIST))
  1143. return(0);
  1144. if(! setting->value.list)
  1145. return(0);
  1146. return(setting->value.list->length);
  1147. }
  1148. /* ------------------------------------------------------------------------- */
  1149. void config_setting_set_hook(config_setting_t *setting, void *hook)
  1150. {
  1151. setting->hook = hook;
  1152. }
  1153. /* ------------------------------------------------------------------------- */
  1154. config_setting_t *config_setting_add(config_setting_t *parent,
  1155. const char *name, int type)
  1156. {
  1157. if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST))
  1158. return(NULL);
  1159. if(! parent)
  1160. return(NULL);
  1161. if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST))
  1162. name = NULL;
  1163. if(name)
  1164. {
  1165. if(! __config_validate_name(name))
  1166. return(NULL);
  1167. }
  1168. if(config_setting_get_member(parent, name) != NULL)
  1169. return(NULL); /* already exists */
  1170. return(config_setting_create(parent, name, type));
  1171. }
  1172. /* ------------------------------------------------------------------------- */
  1173. int config_setting_remove(config_setting_t *parent, const char *name)
  1174. {
  1175. unsigned int idx;
  1176. config_setting_t *setting;
  1177. if(! parent)
  1178. return(CONFIG_FALSE);
  1179. if(parent->type != CONFIG_TYPE_GROUP)
  1180. return(CONFIG_FALSE);
  1181. if(! (setting = __config_list_search(parent->value.list, name, &idx)))
  1182. return(CONFIG_FALSE);
  1183. __config_list_remove(parent->value.list, idx);
  1184. __config_setting_destroy(setting);
  1185. return(CONFIG_TRUE);
  1186. }
  1187. /* ------------------------------------------------------------------------- */
  1188. int config_setting_remove_elem(config_setting_t *parent, unsigned int idx)
  1189. {
  1190. config_list_t *list;
  1191. config_setting_t *removed = NULL;
  1192. if(! parent)
  1193. return(CONFIG_FALSE);
  1194. list = parent->value.list;
  1195. if(((parent->type != CONFIG_TYPE_ARRAY)
  1196. && (parent->type != CONFIG_TYPE_LIST)
  1197. && (parent->type != CONFIG_TYPE_GROUP)) || ! list)
  1198. return(CONFIG_FALSE);
  1199. if(idx >= list->length)
  1200. return(CONFIG_FALSE);
  1201. removed = __config_list_remove(list, idx);
  1202. __config_setting_destroy(removed);
  1203. return(CONFIG_TRUE);
  1204. }
  1205. /* ------------------------------------------------------------------------- */
  1206. int config_setting_index(const config_setting_t *setting)
  1207. {
  1208. config_setting_t **found = NULL;
  1209. config_list_t *list;
  1210. int i;
  1211. if(! setting->parent)
  1212. return(-1);
  1213. list = setting->parent->value.list;
  1214. for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found)
  1215. {
  1216. if(*found == setting)
  1217. return(i);
  1218. }
  1219. return(-1);
  1220. }
  1221. /* ------------------------------------------------------------------------- */
  1222. /* eof */