config.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Configuration File Parser
  5. *
  6. * Copyright (C) 1999, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <time.h>
  19. #include <asterisk/config.h>
  20. #include <asterisk/options.h>
  21. #include <asterisk/logger.h>
  22. #include "asterisk.h"
  23. #include "astconf.h"
  24. #define MAX_INCLUDE_LEVEL 10
  25. struct ast_category {
  26. char name[80];
  27. struct ast_variable *root;
  28. struct ast_category *next;
  29. #ifdef PRESERVE_COMMENTS
  30. struct ast_comment *precomments;
  31. struct ast_comment *sameline;
  32. #endif
  33. };
  34. struct ast_config {
  35. /* Maybe this structure isn't necessary but we'll keep it
  36. for now */
  37. struct ast_category *root;
  38. struct ast_category *prev;
  39. #ifdef PRESERVE_COMMENTS
  40. struct ast_comment *trailingcomments;
  41. #endif
  42. };
  43. #ifdef PRESERVE_COMMENTS
  44. struct ast_comment_struct
  45. {
  46. struct ast_comment *root;
  47. struct ast_comment *prev;
  48. };
  49. #endif
  50. static char *strip(char *buf)
  51. {
  52. char *start;
  53. /* Strip off trailing whitespace, returns, etc */
  54. while(strlen(buf) && (buf[strlen(buf)-1]<33))
  55. buf[strlen(buf)-1] = '\0';
  56. start = buf;
  57. /* Strip off leading whitespace, returns, etc */
  58. while(*start && (*start < 33))
  59. *start++ = '\0';
  60. return start;
  61. }
  62. #ifdef PRESERVE_COMMENTS
  63. static void free_comments(struct ast_comment *com)
  64. {
  65. struct ast_comment *l;
  66. while (com) {
  67. l = com;
  68. com = com->next;
  69. free(l);
  70. }
  71. }
  72. #endif
  73. void ast_destroy(struct ast_config *ast)
  74. {
  75. struct ast_category *cat, *catn;
  76. struct ast_variable *v, *vn;
  77. if (!ast)
  78. return;
  79. cat = ast->root;
  80. while(cat) {
  81. v = cat->root;
  82. while(v) {
  83. vn = v;
  84. free(v->name);
  85. free(v->value);
  86. #ifdef PRESERVE_COMMENTS
  87. free_comments(v->precomments);
  88. free_comments(v->sameline);
  89. #endif
  90. v = v->next;
  91. free(vn);
  92. }
  93. catn = cat;
  94. #ifdef PRESERVE_COMMENTS
  95. free_comments(cat->precomments);
  96. free_comments(cat->sameline);
  97. #endif
  98. cat = cat->next;
  99. free(catn);
  100. }
  101. #ifdef PRESERVE_COMMENTS
  102. free_comments(ast->trailingcomments);
  103. #endif
  104. free(ast);
  105. }
  106. int ast_true(char *s)
  107. {
  108. if (!s)
  109. return 0;
  110. /* Determine if this is a true value */
  111. if (!strcasecmp(s, "yes") ||
  112. !strcasecmp(s, "true") ||
  113. !strcasecmp(s, "y") ||
  114. !strcasecmp(s, "t") ||
  115. !strcasecmp(s, "1"))
  116. return -1;
  117. return 0;
  118. }
  119. int ast_false(char *s)
  120. {
  121. if (!s)
  122. return 0;
  123. /* Determine if this is a false value */
  124. if (!strcasecmp(s, "no") ||
  125. !strcasecmp(s, "false") ||
  126. !strcasecmp(s, "n") ||
  127. !strcasecmp(s, "f") ||
  128. !strcasecmp(s, "0"))
  129. return -1;
  130. return 0;
  131. }
  132. struct ast_variable *ast_variable_browse(struct ast_config *config, char *category)
  133. {
  134. struct ast_category *cat;
  135. cat = config->root;
  136. while(cat) {
  137. if (cat->name == category)
  138. return cat->root;
  139. cat = cat->next;
  140. }
  141. cat = config->root;
  142. while(cat) {
  143. if (!strcasecmp(cat->name, category))
  144. return cat->root;
  145. cat = cat->next;
  146. }
  147. return NULL;
  148. }
  149. char *ast_variable_retrieve(struct ast_config *config, char *category, char *value)
  150. {
  151. struct ast_variable *v;
  152. if (category) {
  153. v = ast_variable_browse(config, category);
  154. while (v) {
  155. if (value == v->name)
  156. return v->value;
  157. v=v->next;
  158. }
  159. v = ast_variable_browse(config, category);
  160. while (v) {
  161. if (!strcasecmp(value, v->name))
  162. return v->value;
  163. v=v->next;
  164. }
  165. } else {
  166. struct ast_category *cat;
  167. cat = config->root;
  168. while(cat) {
  169. v = cat->root;
  170. while (v) {
  171. if (!strcasecmp(value, v->name))
  172. return v->value;
  173. v=v->next;
  174. }
  175. cat = cat->next;
  176. }
  177. }
  178. return NULL;
  179. }
  180. #ifdef PRESERVE_COMMENTS
  181. int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value)
  182. {
  183. struct ast_variable *v, *pv, *bv, *bpv;
  184. struct ast_category *cat;
  185. cat = cfg->root;
  186. while(cat) {
  187. if (cat->name == category) {
  188. break;
  189. }
  190. cat = cat->next;
  191. }
  192. if (!cat) {
  193. cat = cfg->root;
  194. while(cat) {
  195. if (!strcasecmp(cat->name, category)) {
  196. break;
  197. }
  198. cat = cat->next;
  199. }
  200. }
  201. if (!cat)
  202. return -1;
  203. v = cat->root;
  204. pv = NULL;
  205. while (v) {
  206. if ((variable == v->name) && (!value || !strcmp(v->value, value)))
  207. break;
  208. pv = v;
  209. v=v->next;
  210. }
  211. if (!v) {
  212. /* Get the last one that looks like it */
  213. bv = NULL;
  214. bpv = NULL;
  215. v = cat->root;
  216. pv = NULL;
  217. while (v) {
  218. if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) {
  219. bv = v;
  220. bpv = pv;
  221. }
  222. pv = v;
  223. v=v->next;
  224. }
  225. v = bv;
  226. }
  227. if (v) {
  228. /* Unlink from original position */
  229. if (pv)
  230. pv->next = v->next;
  231. else
  232. cat->root = v->next;
  233. v->next = NULL;
  234. free(v->name);
  235. if (v->value)
  236. free(v->value);
  237. free_comments(v->sameline);
  238. free_comments(v->precomments);
  239. return 0;
  240. }
  241. return -1;
  242. }
  243. int ast_category_delete(struct ast_config *cfg, char *category)
  244. {
  245. struct ast_variable *v, *pv;
  246. struct ast_category *cat, *cprev;
  247. cat = cfg->root;
  248. cprev = NULL;
  249. while(cat) {
  250. if (cat->name == category) {
  251. break;
  252. }
  253. cprev = cat;
  254. cat = cat->next;
  255. }
  256. if (!cat) {
  257. cat = cfg->root;
  258. cprev = NULL;
  259. while(cat) {
  260. if (!strcasecmp(cat->name, category)) {
  261. break;
  262. }
  263. cprev = cat;
  264. cat = cat->next;
  265. }
  266. }
  267. if (!cat)
  268. return -1;
  269. /* Unlink it */
  270. if (cprev)
  271. cprev->next = cat->next;
  272. else
  273. cfg->root = cat->next;
  274. v = cat->root;
  275. while (v) {
  276. pv = v;
  277. v=v->next;
  278. if (pv->value)
  279. free(pv->value);
  280. if (pv->name)
  281. free(pv->name);
  282. free_comments(pv->sameline);
  283. free_comments(pv->precomments);
  284. free(pv);
  285. }
  286. free_comments(cat->sameline);
  287. free_comments(cat->precomments);
  288. free(cat);
  289. return 0;
  290. }
  291. struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move)
  292. {
  293. struct ast_variable *v, *pv=NULL, *bv, *bpv;
  294. struct ast_category *cat, *pcat;
  295. cat = config->root;
  296. if (!newcat) {
  297. while(cat) {
  298. if (cat->name == category) {
  299. break;
  300. }
  301. cat = cat->next;
  302. }
  303. if (!cat) {
  304. cat = config->root;
  305. while(cat) {
  306. if (!strcasecmp(cat->name, category)) {
  307. break;
  308. }
  309. cat = cat->next;
  310. }
  311. }
  312. }
  313. if (!cat) {
  314. cat = malloc(sizeof(struct ast_category));
  315. if (!cat)
  316. return NULL;
  317. memset(cat, 0, sizeof(struct ast_category));
  318. strncpy(cat->name, category, sizeof(cat->name));
  319. if (config->root) {
  320. /* Put us at the end */
  321. pcat = config->root;
  322. while(pcat->next)
  323. pcat = pcat->next;
  324. pcat->next = cat;
  325. } else {
  326. /* We're the first one */
  327. config->root = cat;
  328. }
  329. }
  330. if (!newvar) {
  331. v = cat->root;
  332. pv = NULL;
  333. while (v) {
  334. if (variable == v->name)
  335. break;
  336. pv = v;
  337. v=v->next;
  338. }
  339. if (!v) {
  340. /* Get the last one that looks like it */
  341. bv = NULL;
  342. bpv = NULL;
  343. v = cat->root;
  344. pv = NULL;
  345. while (v) {
  346. if (!strcasecmp(variable, v->name)) {
  347. bv = v;
  348. bpv = pv;
  349. }
  350. pv = v;
  351. v=v->next;
  352. }
  353. v = bv;
  354. }
  355. } else v = NULL;
  356. if (v && move) {
  357. /* Unlink from original position */
  358. if (pv)
  359. pv->next = v->next;
  360. else
  361. cat->root = v->next;
  362. v->next = NULL;
  363. }
  364. if (!v) {
  365. v = malloc(sizeof(struct ast_variable));
  366. if (!v)
  367. return NULL;
  368. memset(v, 0, sizeof(struct ast_variable));
  369. v->name = strdup(variable);
  370. move = 1;
  371. }
  372. if (v->value)
  373. free(v->value);
  374. if (value)
  375. v->value = strdup(value);
  376. else
  377. v->value = strdup("");
  378. if (move) {
  379. if (cat->root) {
  380. pv = cat->root;
  381. while (pv->next)
  382. pv = pv->next;
  383. pv->next = v;
  384. } else {
  385. cat->root = v;
  386. }
  387. }
  388. return v;
  389. }
  390. #endif
  391. int ast_category_exist(struct ast_config *config, char *category_name)
  392. {
  393. struct ast_category *category = NULL;
  394. category = config->root;
  395. while(category) {
  396. if (!strcasecmp(category->name,category_name))
  397. return 1;
  398. category = category->next;
  399. }
  400. return 0;
  401. }
  402. #ifdef PRESERVE_COMMENTS
  403. static struct ast_comment *build_comment(char *cmt)
  404. {
  405. struct ast_comment *c;
  406. int len = strlen(cmt) + 1;
  407. c = malloc(sizeof(struct ast_comment) + len);
  408. if (c) {
  409. /* Memset the header */
  410. memset(c, 0, sizeof(struct ast_comment));
  411. /* Copy the rest */
  412. strcpy(c->cmt, cmt);
  413. }
  414. return c;
  415. }
  416. #endif
  417. static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
  418. #ifdef PRESERVE_COMMENTS
  419. , struct ast_comment_struct *acs
  420. #endif
  421. );
  422. static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel
  423. #ifdef PRESERVE_COMMENTS
  424. ,struct ast_comment_struct *acs
  425. #endif
  426. )
  427. {
  428. char *c;
  429. char *cur;
  430. struct ast_variable *v;
  431. #ifdef PRESERVE_COMMENTS
  432. struct ast_comment *com = NULL;
  433. #endif
  434. int object;
  435. /* Strip off lines using ; as comment */
  436. c = strchr(buf, ';');
  437. if (c) {
  438. *c = '\0';
  439. #ifdef PRESERVE_COMMENTS
  440. c++;
  441. if (*c != '!')
  442. com = build_comment(c);
  443. #endif
  444. }
  445. cur = strip(buf);
  446. if (strlen(cur)) {
  447. /* Actually parse the entry */
  448. if (cur[0] == '[') {
  449. /* A category header */
  450. c = strchr(cur, ']');
  451. if (c) {
  452. *c = 0;
  453. *_tmpc = malloc(sizeof(struct ast_category));
  454. if (!*_tmpc) {
  455. ast_destroy(tmp);
  456. ast_log(LOG_WARNING,
  457. "Out of memory, line %d\n", lineno);
  458. return -1;
  459. }
  460. memset(*_tmpc, 0, sizeof(struct ast_category));
  461. strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
  462. (*_tmpc)->root = NULL;
  463. #ifdef PRESERVE_COMMENTS
  464. (*_tmpc)->precomments = acs->root;
  465. (*_tmpc)->sameline = com;
  466. #endif
  467. if (!tmp->prev)
  468. tmp->root = *_tmpc;
  469. else
  470. tmp->prev->next = *_tmpc;
  471. tmp->prev = *_tmpc;
  472. #ifdef PRESERVE_COMMENTS
  473. acs->root = NULL;
  474. acs->prev = NULL;
  475. #endif
  476. *_last = NULL;
  477. } else {
  478. ast_log(LOG_WARNING,
  479. "parse error: no closing ']', line %d of %s\n", lineno, configfile);
  480. }
  481. } else if (cur[0] == '#') {
  482. /* A directive */
  483. cur++;
  484. c = cur;
  485. while(*c && (*c > 32)) c++;
  486. if (*c) {
  487. *c = '\0';
  488. c++;
  489. /* Find real argument */
  490. while(*c && (*c < 33)) c++;
  491. if (!*c)
  492. c = NULL;
  493. } else
  494. c = NULL;
  495. if (!strcasecmp(cur, "include")) {
  496. /* A #include */
  497. if (c) {
  498. while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
  499. /* Get rid of leading mess */
  500. cur = c;
  501. while(strlen(cur)) {
  502. c = cur + strlen(cur) - 1;
  503. if ((*c == '>') || (*c == '<') || (*c == '\"'))
  504. *c = '\0';
  505. else
  506. break;
  507. }
  508. if (includelevel < MAX_INCLUDE_LEVEL) {
  509. __ast_load(cur, tmp, _tmpc, _last, includelevel + 1
  510. #ifdef PRESERVE_COMMENTS
  511. ,acs
  512. #endif
  513. );
  514. } else
  515. ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel);
  516. } else
  517. ast_log(LOG_WARNING, "Directive '#include' needs an argument (filename) at line %d of %s\n", lineno, configfile);
  518. /* Strip off leading and trailing "'s and <>'s */
  519. } else
  520. ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
  521. } else {
  522. /* Just a line (variable = value) */
  523. if (!*_tmpc) {
  524. ast_log(LOG_WARNING,
  525. "parse error: No category context for line %d of %s\n", lineno, configfile);
  526. ast_destroy(tmp);
  527. return -1;
  528. }
  529. c = strchr(cur, '=');
  530. if (c) {
  531. *c = 0;
  532. c++;
  533. /* Ignore > in => */
  534. if (*c== '>') {
  535. object = 1;
  536. c++;
  537. } else
  538. object = 0;
  539. v = malloc(sizeof(struct ast_variable));
  540. if (v) {
  541. memset(v, 0, sizeof(struct ast_variable));
  542. v->next = NULL;
  543. v->name = strdup(strip(cur));
  544. v->value = strdup(strip(c));
  545. v->lineno = lineno;
  546. v->object = object;
  547. /* Put and reset comments */
  548. #ifdef PRESERVE_COMMENTS
  549. v->precomments = acs->root;
  550. v->sameline = com;
  551. acs->prev = NULL;
  552. acs->root = NULL;
  553. #endif
  554. v->blanklines = 0;
  555. if (*_last)
  556. (*_last)->next = v;
  557. else
  558. (*_tmpc)->root = v;
  559. *_last = v;
  560. } else {
  561. ast_destroy(tmp);
  562. ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno);
  563. return -1;
  564. }
  565. } else {
  566. ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
  567. }
  568. }
  569. } else {
  570. /* store any comments if there are any */
  571. #ifdef PRESERVE_COMMENTS
  572. if (com) {
  573. if (acs->prev)
  574. acs->prev->next = com;
  575. else
  576. acs->root = com;
  577. acs->prev = com;
  578. } else {
  579. if (*_last)
  580. (*_last)->blanklines++;
  581. }
  582. #endif
  583. }
  584. return 0;
  585. }
  586. #ifdef PRESERVE_COMMENTS
  587. static void dump_comments(FILE *f, struct ast_comment *comment)
  588. {
  589. while (comment) {
  590. fprintf(f, ";%s", comment->cmt);
  591. comment = comment->next;
  592. }
  593. }
  594. #endif
  595. int ast_save(char *configfile, struct ast_config *cfg, char *generator)
  596. {
  597. FILE *f;
  598. char fn[256];
  599. char date[256];
  600. time_t t;
  601. struct ast_variable *var;
  602. struct ast_category *cat;
  603. int blanklines = 0;
  604. if (configfile[0] == '/') {
  605. strncpy(fn, configfile, sizeof(fn)-1);
  606. } else {
  607. snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
  608. }
  609. time(&t);
  610. strncpy(date, ctime(&t), sizeof(date));
  611. if ((f = fopen(fn, "w"))) {
  612. if ((option_verbose > 1) && !option_debug)
  613. ast_verbose( VERBOSE_PREFIX_2 "Saving '%s': ", fn);
  614. fprintf(f, ";!\n");
  615. fprintf(f, ";! Automatically generated configuration file\n");
  616. fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
  617. fprintf(f, ";! Generator: %s\n", generator);
  618. fprintf(f, ";! Creation Date: %s", date);
  619. fprintf(f, ";!\n");
  620. cat = cfg->root;
  621. while(cat) {
  622. #ifdef PRESERVE_COMMENTS
  623. /* Dump any precomments */
  624. dump_comments(f, cat->precomments);
  625. #endif
  626. /* Dump section with any appropriate comment */
  627. #ifdef PRESERVE_COMMENTS
  628. if (cat->sameline)
  629. fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->cmt);
  630. else
  631. #endif
  632. fprintf(f, "[%s]\n", cat->name);
  633. var = cat->root;
  634. while(var) {
  635. #ifdef PRESERVE_COMMENTS
  636. dump_comments(f, var->precomments);
  637. #endif
  638. if (var->sameline)
  639. fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
  640. else
  641. fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
  642. if (var->blanklines) {
  643. blanklines = var->blanklines;
  644. while (blanklines) {
  645. fprintf(f, "\n");
  646. blanklines--;
  647. }
  648. }
  649. var = var->next;
  650. }
  651. #if 0
  652. /* Put an empty line */
  653. fprintf(f, "\n");
  654. #endif
  655. cat = cat->next;
  656. }
  657. #ifdef PRESERVE_COMMENTS
  658. dump_comments(f, cfg->trailingcomments);
  659. #endif
  660. } else {
  661. if (option_debug)
  662. printf("Unable to open for writing: %s\n", fn);
  663. else if (option_verbose > 1)
  664. printf( "Unable to write (%s)", strerror(errno));
  665. return -1;
  666. }
  667. fclose(f);
  668. return 0;
  669. }
  670. static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
  671. #ifdef PRESERVE_COMMENTS
  672. , struct ast_comment_struct *acs
  673. #endif
  674. )
  675. {
  676. char fn[256];
  677. char buf[512];
  678. FILE *f;
  679. int lineno=0;
  680. int master=0;
  681. if (configfile[0] == '/') {
  682. strncpy(fn, configfile, sizeof(fn)-1);
  683. } else {
  684. snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, configfile);
  685. }
  686. if ((option_verbose > 1) && !option_debug) {
  687. ast_verbose( VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
  688. fflush(stdout);
  689. }
  690. if ((f = fopen(fn, "r"))) {
  691. if (option_debug)
  692. ast_log(LOG_DEBUG, "Parsing %s\n", fn);
  693. else if (option_verbose > 1)
  694. ast_verbose( "Found\n");
  695. if (!tmp) {
  696. tmp = malloc(sizeof(struct ast_config));
  697. if (tmp)
  698. memset(tmp, 0, sizeof(struct ast_config));
  699. master = 1;
  700. }
  701. if (!tmp) {
  702. ast_log(LOG_WARNING, "Out of memory\n");
  703. fclose(f);
  704. return NULL;
  705. }
  706. while(!feof(f)) {
  707. fgets(buf, sizeof(buf), f);
  708. lineno++;
  709. if (!feof(f)) {
  710. if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel
  711. #ifdef PRESERVE_COMMENTS
  712. , acs
  713. #endif
  714. )) {
  715. fclose(f);
  716. return NULL;
  717. }
  718. }
  719. }
  720. fclose(f);
  721. } else {
  722. if (option_debug)
  723. ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
  724. else if (option_verbose > 1)
  725. ast_verbose( "Not found (%s)\n", strerror(errno));
  726. }
  727. #ifdef PRESERVE_COMMENTS
  728. if (master) {
  729. /* Keep trailing comments */
  730. tmp->trailingcomments = acs->root;
  731. acs->root = NULL;
  732. acs->prev = NULL;
  733. }
  734. #endif
  735. return tmp;
  736. }
  737. struct ast_config *ast_load(char *configfile)
  738. {
  739. struct ast_category *tmpc=NULL;
  740. struct ast_variable *last = NULL;
  741. #ifdef PRESERVE_COMMENTS
  742. struct ast_comment_struct acs = { NULL, NULL };
  743. #endif
  744. return __ast_load(configfile, NULL, &tmpc, &last, 0
  745. #ifdef PRESERVE_COMMENTS
  746. ,&acs
  747. #endif
  748. );
  749. }
  750. char *ast_category_browse(struct ast_config *config, char *prev)
  751. {
  752. struct ast_category *cat;
  753. if (!prev) {
  754. if (config->root)
  755. return config->root->name;
  756. else
  757. return NULL;
  758. }
  759. cat = config->root;
  760. while(cat) {
  761. if (cat->name == prev) {
  762. if (cat->next)
  763. return cat->next->name;
  764. else
  765. return NULL;
  766. }
  767. cat = cat->next;
  768. }
  769. cat = config->root;
  770. while(cat) {
  771. if (!strcasecmp(cat->name, prev)) {
  772. if (cat->next)
  773. return cat->next->name;
  774. else
  775. return NULL;
  776. }
  777. cat = cat->next;
  778. }
  779. return NULL;
  780. }