libconfig.c 40 KB

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