libconfig.c 40 KB

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