PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/config.c

https://github.com/hanselpc/polipo
C | 869 lines | 772 code | 74 blank | 23 comment | 261 complexity | b538f92adb97f0a0ae8955222600d678 MD5 | raw file
  1. /*
  2. Copyright (c) 2003-2006 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "polipo.h"
  20. ConfigVariablePtr configVariables = NULL;
  21. static ConfigVariablePtr
  22. findConfigVariable(AtomPtr name)
  23. {
  24. ConfigVariablePtr var;
  25. var = configVariables;
  26. while(var != NULL) {
  27. if(var->name == name)
  28. break;
  29. var = var->next;
  30. }
  31. return var;
  32. }
  33. void
  34. declareConfigVariable(AtomPtr name, int type, void *value,
  35. int (*setter)(ConfigVariablePtr, void*), char *help)
  36. {
  37. ConfigVariablePtr var, previous, next;
  38. var = findConfigVariable(name);
  39. if(var) {
  40. do_log(L_ERROR,
  41. "Configuration variable %s declared multiple times.\n",
  42. name->string);
  43. if(var->type != type) {
  44. exit(1);
  45. }
  46. }
  47. var = malloc(sizeof(ConfigVariableRec));
  48. if(var == NULL) {
  49. do_log(L_ERROR, "Couldn't allocate config variable.\n");
  50. exit(1);
  51. }
  52. var->name = retainAtom(name);
  53. var->type = type;
  54. switch(type) {
  55. case CONFIG_INT: case CONFIG_OCTAL: case CONFIG_HEX: case CONFIG_TIME:
  56. case CONFIG_BOOLEAN: case CONFIG_TRISTATE: case CONFIG_TETRASTATE:
  57. case CONFIG_PENTASTATE:
  58. var->value.i = value; break;
  59. case CONFIG_FLOAT: var->value.f = value; break;
  60. case CONFIG_ATOM: case CONFIG_ATOM_LOWER: case CONFIG_PASSWORD:
  61. var->value.a = value; break;
  62. case CONFIG_INT_LIST:
  63. var->value.il = value; break;
  64. case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
  65. var->value.al = value; break;
  66. default: abort();
  67. }
  68. var->setter = setter;
  69. var->help = help;
  70. previous = NULL;
  71. next = configVariables;
  72. while(next && strcmp(next->name->string, var->name->string) < 0) {
  73. previous = next;
  74. next = next->next;
  75. }
  76. if(next && strcmp(next->name->string, var->name->string) == 0) {
  77. do_log(L_ERROR, "Variable %s declared multiple times.\n",
  78. next->name->string);
  79. abort();
  80. }
  81. if(previous == NULL) {
  82. var->next = configVariables;
  83. configVariables = var;
  84. } else {
  85. var->next = next;
  86. previous->next = var;
  87. }
  88. }
  89. static void
  90. printString(FILE *out, char *string, int html)
  91. {
  92. if(html) {
  93. char buf[512];
  94. int i;
  95. i = htmlString(buf, 0, 512, string, strlen(string));
  96. if(i < 0) {
  97. fprintf(out, "(overflow)");
  98. return;
  99. }
  100. fwrite(buf, 1, i, out);
  101. } else {
  102. fprintf(out, "%s", string);
  103. }
  104. }
  105. static void
  106. printVariable(FILE *out, ConfigVariablePtr var, int html, int parseable)
  107. {
  108. int i;
  109. switch(var->type) {
  110. case CONFIG_INT: fprintf(out, "%d", *var->value.i); break;
  111. case CONFIG_OCTAL: fprintf(out, "0%o", *var->value.i); break;
  112. case CONFIG_HEX: fprintf(out, "0x%x", *var->value.i); break;
  113. case CONFIG_TIME:
  114. {
  115. int v = *var->value.i;
  116. if(v == 0) {
  117. fprintf(out, "0s");
  118. } else {
  119. if(v >= 3600 * 24) fprintf(out, "%dd", v/(3600*24));
  120. v = v % (3600 * 24);
  121. if(v >= 3600) fprintf(out, "%dh", v / 3600);
  122. v = v % 3600;
  123. if(v >= 60) fprintf(out, "%dm", v / 60);
  124. v = v % 60;
  125. if(v > 0) fprintf(out, "%ds", v);
  126. }
  127. }
  128. break;
  129. case CONFIG_BOOLEAN:
  130. switch(*var->value.i) {
  131. case 0: fprintf(out, "false"); break;
  132. case 1: fprintf(out, "true"); break;
  133. default: fprintf(out, "???"); break;
  134. }
  135. break;
  136. case CONFIG_TRISTATE:
  137. switch(*var->value.i) {
  138. case 0: fprintf(out, "false"); break;
  139. case 1: fprintf(out, "maybe"); break;
  140. case 2: fprintf(out, "true"); break;
  141. default: fprintf(out, "???"); break;
  142. }
  143. break;
  144. case CONFIG_TETRASTATE:
  145. switch(*var->value.i) {
  146. case 0: fprintf(out, "false"); break;
  147. case 1: fprintf(out, "reluctantly"); break;
  148. case 2: fprintf(out, "happily"); break;
  149. case 3: fprintf(out, "true"); break;
  150. default: fprintf(out, "???"); break;
  151. }
  152. break;
  153. case CONFIG_PENTASTATE:
  154. switch(*var->value.i) {
  155. case 0: fprintf(out, "no"); break;
  156. case 1: fprintf(out, "reluctantly"); break;
  157. case 2: fprintf(out, "maybe"); break;
  158. case 3: fprintf(out, "happily"); break;
  159. case 4: fprintf(out, "true"); break;
  160. default: fprintf(out, "???"); break;
  161. }
  162. break;
  163. case CONFIG_FLOAT: fprintf(out, "%f", *var->value.f); break;
  164. case CONFIG_ATOM: case CONFIG_ATOM_LOWER:
  165. if(*var->value.a) {
  166. if((*var->value.a)->length > 0) {
  167. printString(out, (*var->value.a)->string, html);
  168. } else {
  169. if(!parseable)
  170. fprintf(out, "(empty)");
  171. }
  172. } else {
  173. if(!parseable)
  174. fprintf(out, "(none)");
  175. }
  176. break;
  177. case CONFIG_PASSWORD:
  178. if(!parseable)
  179. fprintf(out, "(hidden)");
  180. break;
  181. case CONFIG_INT_LIST:
  182. if((*var->value.il) == NULL) {
  183. if(!parseable)
  184. fprintf(out, "(not set)");
  185. } else if((*var->value.il)->length == 0) {
  186. if(!parseable)
  187. fprintf(out, "(empty list)");
  188. } else {
  189. for(i = 0; i < (*var->value.il)->length; i++) {
  190. int from = (*var->value.il)->ranges[i].from;
  191. int to = (*var->value.il)->ranges[i].to;
  192. assert(from <= to);
  193. if(from == to)
  194. fprintf(out, "%d", from);
  195. else
  196. fprintf(out, "%d-%d", from, to);
  197. if(i < (*var->value.il)->length - 1)
  198. fprintf(out, ", ");
  199. }
  200. }
  201. break;
  202. case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
  203. if((*var->value.al) == NULL) {
  204. if(!parseable)
  205. fprintf(out, "(not set)");
  206. } else if((*var->value.al)->length == 0) {
  207. if(!parseable)
  208. fprintf(out, "(empty list)");
  209. } else {
  210. for(i = 0; i < (*var->value.al)->length; i++) {
  211. AtomPtr atom = (*var->value.al)->list[i];
  212. if(atom) {
  213. if(atom->length > 0)
  214. printString(out, atom->string, html);
  215. else {
  216. if(!parseable)
  217. fprintf(out, "(empty)");
  218. }
  219. } else {
  220. if(!parseable)
  221. fprintf(out, "(none)");
  222. }
  223. if(i < (*var->value.al)->length - 1)
  224. fprintf(out, ", ");
  225. }
  226. }
  227. break;
  228. default: abort();
  229. }
  230. }
  231. static void
  232. printVariableForm(FILE *out, ConfigVariablePtr var)
  233. {
  234. char *disabled = "";
  235. int i;
  236. if(disableConfiguration || !var->setter) disabled = "disabled=true";
  237. fprintf(out, "<form method=POST action=\"config?\">");
  238. switch(var->type) {
  239. case CONFIG_INT: case CONFIG_OCTAL: case CONFIG_HEX:
  240. case CONFIG_TIME: case CONFIG_FLOAT: case CONFIG_ATOM:
  241. case CONFIG_ATOM_LOWER: case CONFIG_PASSWORD:
  242. case CONFIG_INT_LIST: case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
  243. fprintf(out, "<input value=\"");
  244. printVariable(out, var, 1, 1);
  245. fprintf(out, "\"%s size=14 name=%s %s>\n",
  246. var->type == CONFIG_PASSWORD ? " type=password" : "",
  247. var->name->string, disabled);
  248. break;
  249. case CONFIG_BOOLEAN:
  250. {
  251. static char *states[] = {"false", "true"};
  252. fprintf(out, "<select name=%s %s>", var->name->string, disabled);
  253. for(i=0; i < sizeof(states) / sizeof(states[0]); i++) {
  254. if(*var->value.i == i) {
  255. fprintf(out, "<option selected>%s</option>", states[i]);
  256. } else {
  257. fprintf(out, "<option>%s</option>", states[i]);
  258. }
  259. }
  260. fprintf(out, "</select>");
  261. if(var->setter)
  262. fprintf(out, "<input type=\"submit\" value=\"set\"\n>");
  263. break;
  264. }
  265. case CONFIG_TRISTATE:
  266. {
  267. static char *states[] = {"false", "maybe", "true"};
  268. fprintf(out, "<select name=%s %s>", var->name->string, disabled);
  269. for(i=0; i < sizeof(states) / sizeof(states[0]); i++) {
  270. if(*var->value.i == i) {
  271. fprintf(out, "<option selected>%s</option>", states[i]);
  272. } else {
  273. fprintf(out, "<option>%s</option>", states[i]);
  274. }
  275. }
  276. fprintf(out, "</select>");
  277. if(var->setter)
  278. fprintf(out, "<input type=\"submit\" value=\"set\"\n>");
  279. break;
  280. }
  281. case CONFIG_TETRASTATE:
  282. {
  283. static char *states[] =
  284. {"false", "reluctantly", "happily", "true"};
  285. fprintf(out, "<select name=%s %s>", var->name->string, disabled);
  286. for(i=0; i <sizeof(states) / sizeof(states[0]); i++) {
  287. if(*var->value.i == i) {
  288. fprintf(out, "<option selected>%s</option>", states[i]);
  289. } else {
  290. fprintf(out, "<option>%s</option>", states[i]);
  291. }
  292. }
  293. fprintf(out, "</select>");
  294. if(var->setter)
  295. fprintf(out, "<input type=\"submit\" value=\"set\"\n>");
  296. break;
  297. }
  298. case CONFIG_PENTASTATE:
  299. {
  300. static char *states[] =
  301. {"no", "reluctantly", "maybe", "happily", "true"};
  302. fprintf(out, "<select name=%s %s>", var->name->string, disabled);
  303. for(i=0; i < sizeof(states) / sizeof(states[0]); i++) {
  304. if(*var->value.i == i) {
  305. fprintf(out, "<option selected>%s</option>", states[i]);
  306. } else {
  307. fprintf(out, "<option>%s</option>", states[i]);
  308. }
  309. }
  310. fprintf(out, "</select>");
  311. if(var->setter)
  312. fprintf(out,"<input type=\"submit\" value=\"set\"\n>");
  313. break;
  314. }
  315. default: abort();
  316. }
  317. fprintf(out, "</form>");
  318. }
  319. void
  320. printConfigVariables(FILE *out, int html)
  321. {
  322. ConfigVariablePtr var;
  323. int entryno = 0;
  324. #define PRINT_SEP() \
  325. do {if(html) fprintf(out, "</td><td>"); else fprintf(out, " ");} while(0)
  326. if(html) {
  327. fprintf(out, "<table>\n");
  328. fprintf(out, "<tbody>\n");
  329. }
  330. if(html) {
  331. alternatingHttpStyle(out, "configlist");
  332. fprintf(out,
  333. "<table id=configlist>\n"
  334. "<thead>\n"
  335. "<tr><th>variable name</th>"
  336. "<th>current value</th>"
  337. "<th>new value</th>"
  338. "<th>description</th>\n"
  339. "</thead><tbody>\n"
  340. );
  341. }
  342. /* configFile is not a config variable, for obvious bootstrapping reasons.
  343. CHUNK_SIZE is hardwired for now. */
  344. fprintf(out,
  345. html ?
  346. "<tr class=\"even\"><td>configFile</td><td>%s</td><td></td><td>"
  347. "Configuration file.</td></tr>\n" :
  348. "configFile %s Configuration file.\n",
  349. configFile && configFile->length > 0 ?
  350. configFile->string : "(none)");
  351. fprintf(out,
  352. html ?
  353. "<tr class=\"odd\"><td>CHUNK_SIZE</td><td>%d</td><td></td><td>"
  354. "Unit of chunk memory allocation.</td></tr>\n" :
  355. "CHUNK_SIZE %d Unit of chunk memory allocation.\n", CHUNK_SIZE);
  356. var = configVariables;
  357. while(var != NULL) {
  358. if(html) {
  359. if(entryno % 2)
  360. fprintf(out, "<tr class=odd>");
  361. else
  362. fprintf(out, "<tr class=even>");
  363. fprintf(out, "<td>");
  364. }
  365. fprintf(out, "%s", var->name->string);
  366. fprintf(out, html ? "<br/>" : " ");
  367. fprintf(out, html ? "<i>" : "");
  368. switch(var->type) {
  369. case CONFIG_INT: case CONFIG_OCTAL: case CONFIG_HEX:
  370. fprintf(out, "integer"); break;
  371. case CONFIG_TIME: fprintf(out, "time"); break;
  372. case CONFIG_BOOLEAN: fprintf(out, "boolean"); break;
  373. case CONFIG_TRISTATE: fprintf(out, "tristate"); break;
  374. case CONFIG_TETRASTATE: fprintf(out, "4-state"); break;
  375. case CONFIG_PENTASTATE: fprintf(out, "5-state"); break;
  376. case CONFIG_FLOAT: fprintf(out, "float"); break;
  377. case CONFIG_ATOM: case CONFIG_ATOM_LOWER: case CONFIG_PASSWORD:
  378. fprintf(out, "atom"); break;
  379. case CONFIG_INT_LIST: fprintf(out, "intlist"); break;
  380. case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
  381. fprintf(out, "list"); break;
  382. default: abort();
  383. }
  384. fprintf(out, html ? "</i>" : "");
  385. PRINT_SEP();
  386. printVariable(out, var, html, 0);
  387. PRINT_SEP();
  388. if(html) {
  389. printVariableForm(out, var);
  390. PRINT_SEP();
  391. }
  392. fprintf(out, "%s", var->help?var->help:"");
  393. if(html)
  394. fprintf(out, "</td></tr>\n");
  395. else
  396. fprintf(out, "\n");
  397. entryno++;
  398. var = var->next;
  399. }
  400. if(html) {
  401. fprintf(out, "</tbody>\n");
  402. fprintf(out, "</table>\n");
  403. }
  404. return;
  405. #undef PRINT_SEP
  406. }
  407. static int
  408. skipWhitespace(char *buf, int i)
  409. {
  410. while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\r')
  411. i++;
  412. return i;
  413. }
  414. static int
  415. parseInt(char *buf, int offset, int *value_return)
  416. {
  417. char *p;
  418. int value;
  419. value = strtol(buf + offset, &p, 0);
  420. if(p <= buf + offset)
  421. return -1;
  422. *value_return = value;
  423. return p - buf;
  424. }
  425. static struct config_state { char *name; int value; }
  426. states[] =
  427. { { "false", 0 },
  428. { "no", 0 },
  429. { "reluctantly", 1 },
  430. { "seldom", 1 },
  431. { "rarely", 1 },
  432. { "lazily", 1 },
  433. { "maybe", 2 },
  434. { "perhaps", 2 },
  435. { "happily", 3 },
  436. { "often", 3 },
  437. { "eagerly", 3 },
  438. { "true", 4 },
  439. { "yes", 4 } };
  440. static int
  441. parseState(char *buf, int offset, int kind)
  442. {
  443. int i = offset;
  444. int n;
  445. int state = -1;
  446. while(letter(buf[i]))
  447. i++;
  448. for(n = 0; n < sizeof(states) / sizeof(states[0]); n++) {
  449. if(strlen(states[n].name) == i - offset &&
  450. lwrcmp(buf + offset, states[n].name, i - offset) == 0) {
  451. state = states[n].value;
  452. break;
  453. }
  454. }
  455. if(state < 0)
  456. return -1;
  457. switch(kind) {
  458. case CONFIG_BOOLEAN:
  459. if(state == 0) return 0;
  460. else if(state == 4) return 1;
  461. else return -1;
  462. break;
  463. case CONFIG_TRISTATE:
  464. if(state == 0) return 0;
  465. else if(state == 2) return 1;
  466. else if(state == 4) return 2;
  467. else return -1;
  468. break;
  469. case CONFIG_TETRASTATE:
  470. if(state == 0) return 0;
  471. else if(state == 1) return 1;
  472. else if(state == 3) return 2;
  473. else if(state == 4) return 3;
  474. else return -1;
  475. break;
  476. case CONFIG_PENTASTATE:
  477. return state;
  478. break;
  479. default:
  480. abort();
  481. }
  482. }
  483. static int
  484. parseAtom(char *buf, int offset, AtomPtr *value_return, int insensitive)
  485. {
  486. int y0, i, j, k;
  487. AtomPtr atom;
  488. int escape = 0;
  489. char *s;
  490. i = offset;
  491. if(buf[i] == '\"') {
  492. i++;
  493. y0 = i;
  494. while(buf[i] != '\"' && buf[i] != '\n' && buf[i] != '\0') {
  495. if(buf[i] == '\\' && buf[i + 1] != '\0') {
  496. escape = 1;
  497. i += 2;
  498. } else
  499. i++;
  500. }
  501. if(buf[i] != '\"')
  502. return -1;
  503. j = i + 1;
  504. } else {
  505. y0 = i;
  506. while(letter(buf[i]) || digit(buf[i]) ||
  507. buf[i] == '_' || buf[i] == '-' || buf[i] == '~' ||
  508. buf[i] == '.' || buf[i] == ':' || buf[i] == '/')
  509. i++;
  510. j = i;
  511. }
  512. if(escape) {
  513. s = malloc(i - y0);
  514. if(s == NULL) return -1;
  515. k = 0;
  516. j = y0;
  517. while(j < i) {
  518. if(buf[j] == '\\' && j <= i - 2) {
  519. s[k++] = buf[j + 1];
  520. j += 2;
  521. } else
  522. s[k++] = buf[j++];
  523. }
  524. if(insensitive)
  525. atom = internAtomLowerN(s, k);
  526. else
  527. atom = internAtomN(s, k);
  528. free(s);
  529. j++;
  530. } else {
  531. if(insensitive)
  532. atom = internAtomLowerN(buf + y0, i - y0);
  533. else
  534. atom = internAtomN(buf + y0, i - y0);
  535. }
  536. *value_return = atom;
  537. return j;
  538. }
  539. static int
  540. parseTime(char *line, int i, int *value_return)
  541. {
  542. int v = 0, w;
  543. while(1) {
  544. if(!digit(line[i]))
  545. break;
  546. w = atoi(line + i);
  547. while(digit(line[i])) i++;
  548. switch(line[i]) {
  549. case 'd': v += w * 24 * 3600; i++; break;
  550. case 'h': v += w * 3600; i++; break;
  551. case 'm': v += w * 60; i++; break;
  552. case 's': v += w; i++; break;
  553. default: v += w; goto done;
  554. }
  555. }
  556. done:
  557. *value_return = v;
  558. return i;
  559. }
  560. int
  561. parseConfigLine(char *line, char *filename, int lineno, int set)
  562. {
  563. int x0, x1;
  564. int i, from, to;
  565. AtomPtr name, value;
  566. ConfigVariablePtr var;
  567. int iv;
  568. float fv;
  569. AtomPtr av;
  570. AtomListPtr alv;
  571. IntListPtr ilv;
  572. i = skipWhitespace(line, 0);
  573. if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
  574. return 0;
  575. x0 = i;
  576. while(letter(line[i]) || digit(line[i]))
  577. i++;
  578. x1 = i;
  579. i = skipWhitespace(line, i);
  580. if(line[i] != '=') {
  581. goto syntax;
  582. }
  583. i++;
  584. i = skipWhitespace(line, i);
  585. name = internAtomN(line + x0, x1 - x0);
  586. var = findConfigVariable(name);
  587. releaseAtom(name);
  588. if(set && var->setter == NULL)
  589. return -2;
  590. if(var == NULL) {
  591. if(!set) {
  592. do_log(L_ERROR, "%s:%d: unknown config variable ",
  593. filename, lineno);
  594. do_log_n(L_ERROR, line + x0, x1 - x0);
  595. do_log(L_ERROR, "\n");
  596. }
  597. return -1;
  598. }
  599. i = skipWhitespace(line, i);
  600. switch(var->type) {
  601. case CONFIG_INT: case CONFIG_OCTAL: case CONFIG_HEX:
  602. i = parseInt(line, i, &iv);
  603. if(i < 0) goto syntax;
  604. if(set)
  605. var->setter(var, &iv);
  606. else
  607. *var->value.i = iv;
  608. break;
  609. case CONFIG_TIME:
  610. i = parseTime(line, i, &iv);
  611. if(i < 0) goto syntax;
  612. i = skipWhitespace(line, i);
  613. if(line[i] != '\n' && line[i] != '\0' && line[i] != '#')
  614. goto syntax;
  615. if(set)
  616. var->setter(var, &iv);
  617. else
  618. *var->value.i = iv;
  619. break;
  620. case CONFIG_BOOLEAN:
  621. case CONFIG_TRISTATE:
  622. case CONFIG_TETRASTATE:
  623. case CONFIG_PENTASTATE:
  624. iv = parseState(line, i, var->type);
  625. if(iv < 0)
  626. goto syntax;
  627. if(set)
  628. var->setter(var, &iv);
  629. else
  630. *var->value.i = iv;
  631. break;
  632. case CONFIG_FLOAT:
  633. if(!digit(line[i]) && line[i] != '.')
  634. goto syntax;
  635. fv = atof(line + i);
  636. if(set)
  637. var->setter(var, &fv);
  638. else
  639. *var->value.f = fv;
  640. break;
  641. case CONFIG_ATOM: case CONFIG_ATOM_LOWER: case CONFIG_PASSWORD:
  642. i = parseAtom(line, i, &av, (var->type == CONFIG_ATOM_LOWER));
  643. if(i < 0) goto syntax;
  644. if(!av) {
  645. if(!set)
  646. do_log(L_ERROR, "%s:%d: couldn't allocate atom.\n",
  647. filename, lineno);
  648. return -1;
  649. }
  650. i = skipWhitespace(line, i);
  651. if(line[i] != '\n' && line[i] != '\0' && line[i] != '#') {
  652. releaseAtom(av);
  653. goto syntax;
  654. }
  655. if(set)
  656. var->setter(var, &av);
  657. else {
  658. if(*var->value.a) releaseAtom(*var->value.a);
  659. *var->value.a = av;
  660. }
  661. break;
  662. case CONFIG_INT_LIST:
  663. ilv = makeIntList(0);
  664. if(ilv == NULL) {
  665. if(!set)
  666. do_log(L_ERROR, "%s:%d: couldn't allocate int list.\n",
  667. filename, lineno);
  668. return -1;
  669. }
  670. while(1) {
  671. i = parseInt(line, i, &from);
  672. if(i < 0) goto syntax;
  673. to = from;
  674. i = skipWhitespace(line, i);
  675. if(line[i] == '-') {
  676. i = skipWhitespace(line, i + 1);
  677. i = parseInt(line, i, &to);
  678. if(i < 0) {
  679. destroyIntList(ilv);
  680. goto syntax;
  681. }
  682. i = skipWhitespace(line, i);
  683. }
  684. intListCons(from, to, ilv);
  685. if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
  686. break;
  687. if(line[i] != ',') {
  688. destroyIntList(ilv);
  689. goto syntax;
  690. }
  691. i = skipWhitespace(line, i + 1);
  692. }
  693. if(set)
  694. var->setter(var, &ilv);
  695. else {
  696. if(*var->value.il) destroyIntList(*var->value.il);
  697. *var->value.il = ilv;
  698. }
  699. break;
  700. case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
  701. alv = makeAtomList(NULL, 0);
  702. if(alv == NULL) {
  703. if(!set)
  704. do_log(L_ERROR, "%s:%d: couldn't allocate atom list.\n",
  705. filename, lineno);
  706. return -1;
  707. }
  708. while(1) {
  709. i = parseAtom(line, i, &value,
  710. (var->type == CONFIG_ATOM_LIST_LOWER));
  711. if(i < 0) goto syntax;
  712. if(!value) {
  713. if(!set)
  714. do_log(L_ERROR, "%s:%d: couldn't allocate atom.\n",
  715. filename, lineno);
  716. return -1;
  717. }
  718. atomListCons(value, alv);
  719. i = skipWhitespace(line, i);
  720. if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
  721. break;
  722. if(line[i] != ',') {
  723. destroyAtomList(alv);
  724. goto syntax;
  725. }
  726. i = skipWhitespace(line, i + 1);
  727. }
  728. if(set)
  729. var->setter(var, &alv);
  730. else {
  731. if(*var->value.al) destroyAtomList(*var->value.al);
  732. *var->value.al = alv;
  733. }
  734. break;
  735. default: abort();
  736. }
  737. return 1;
  738. syntax:
  739. if(!set)
  740. do_log(L_ERROR, "%s:%d: parse error.\n", filename, lineno);
  741. return -1;
  742. }
  743. int
  744. parseConfigFile(AtomPtr filename)
  745. {
  746. char buf[512];
  747. int lineno;
  748. FILE *f;
  749. if(!filename || filename->length == 0)
  750. return 0;
  751. f = fopen(filename->string, "r");
  752. if(f == NULL) {
  753. do_log_error(L_ERROR, errno, "Couldn't open config file %s",
  754. filename->string);
  755. return -1;
  756. }
  757. lineno = 1;
  758. while(1) {
  759. char *s;
  760. s = fgets(buf, 512, f);
  761. if(s == NULL) {
  762. fclose(f);
  763. return 1;
  764. }
  765. parseConfigLine(buf, filename->string, lineno, 0);
  766. lineno++;
  767. }
  768. }
  769. int
  770. configIntSetter(ConfigVariablePtr var, void* value)
  771. {
  772. assert(var->type <= CONFIG_PENTASTATE);
  773. *var->value.i = *(int*)value;
  774. return 1;
  775. }
  776. int
  777. configFloatSetter(ConfigVariablePtr var, void* value)
  778. {
  779. assert(var->type == CONFIG_FLOAT);
  780. *var->value.i = *(float*)value;
  781. return 1;
  782. }
  783. int
  784. configAtomSetter(ConfigVariablePtr var, void* value)
  785. {
  786. assert(var->type == CONFIG_ATOM || var->type == CONFIG_ATOM_LOWER ||
  787. var->type == CONFIG_PASSWORD);
  788. if(*var->value.a)
  789. releaseAtom(*var->value.a);
  790. *var->value.a = *(AtomPtr*)value;
  791. return 1;
  792. }