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