1 /*
2 **  Routines for reading in incoming.conf-style config files.
3 */
4 
5 #include "portable/system.h"
6 
7 #include "conffile.h"
8 #include "inn/libinn.h"
9 
10 static int
getconfline(CONFFILE * F,char * buffer,size_t length)11 getconfline(CONFFILE *F, char *buffer, size_t length)
12 {
13     if (F->f) {
14         if (fgets(buffer, (int) length, F->f) == NULL) {
15             return 1;
16         }
17         if (ferror(F->f)) {
18             return 1;
19         }
20     } else if (F->array) {
21         strlcpy(buffer, F->array[F->lineno], F->sbuf);
22     }
23     F->lineno++;
24     if (strlen(F->buf) >= F->sbuf - 1) {
25         return 1; /* Line too long */
26     } else {
27         return 0;
28     }
29 }
30 
31 static int
cfeof(CONFFILE * F)32 cfeof(CONFFILE *F)
33 {
34     if (F->f) {
35         return feof(F->f);
36     } else if (F->array) {
37         return (F->lineno == F->array_len);
38     } else {
39         return 1;
40     }
41 }
42 
43 static char *
CONFgetword(CONFFILE * F)44 CONFgetword(CONFFILE *F)
45 {
46     char *p;
47     char *s;
48     char *t;
49     char *word;
50     bool comment;
51 
52     if (!F)
53         return (NULL); /* No conf file */
54     if (!F->buf || !F->buf[0]) {
55         if (cfeof(F))
56             return (NULL);
57         if (!F->buf) {
58             F->sbuf = BIG_BUFFER;
59             F->buf = xmalloc(F->sbuf);
60         }
61         if (getconfline(F, F->buf, F->sbuf) != 0)
62             return (NULL); /* Line too long */
63     }
64     do {
65         /* Ignore blank and comment lines. */
66         if ((p = strchr(F->buf, '\n')) != NULL)
67             *p = '\0';
68         for (p = F->buf; *p == ' ' || *p == '\t'; p++)
69             ;
70         if ((*p == '\0' || *p == '#') && !cfeof(F)) {
71             if (getconfline(F, F->buf, F->sbuf))
72                 return (NULL); /* Line too long */
73             continue;
74         }
75         break;
76     } while (!cfeof(F));
77 
78     comment = false;
79     if (*p == '"') { /* double quoted string ? */
80         p++;
81         do {
82             for (t = p; (*t != '"' || *(t - 1) == '\\') && *t != '\0'; t++)
83                 ;
84             if (*t == '\0') {
85                 if (strlen(F->buf) >= F->sbuf - 2)
86                     return (NULL); /* Line too long */
87                 *t++ = '\n';
88                 *t = '\0';
89                 if (getconfline(F, t, F->sbuf - strlen(F->buf)))
90                     return (NULL); /* Line too long */
91                 if ((s = strchr(t, '\n')) != NULL)
92                     *s = '\0';
93             } else
94                 break;
95         } while (!cfeof(F));
96         if (*t != '"')
97             return (NULL);
98         *t++ = '\0';
99     } else {
100         for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++)
101             if (*t == '#' && (t == p || *(t - 1) != '\\')) {
102                 comment = true;
103                 break;
104             }
105         if (*t != '\0')
106             *t++ = '\0';
107     }
108     if (*p == '\0' && cfeof(F))
109         return (NULL);
110     word = xstrdup(p);
111     p = F->buf;
112     if (!comment)
113         for (; *t != '\0'; t++)
114             *p++ = *t;
115     *p = '\0';
116 
117     return (word);
118 }
119 
120 CONFFILE *
CONFfopen(const char * filename)121 CONFfopen(const char *filename)
122 {
123     FILE *f;
124     CONFFILE *ret;
125 
126     f = fopen(filename, "r");
127     if (!f)
128         return (0);
129     ret = xmalloc(sizeof(CONFFILE));
130     if (!ret) {
131         fclose(f);
132         return (0);
133     }
134     ret->filename = xstrdup(filename);
135     ret->buf = 0;
136     ret->sbuf = 0;
137     ret->lineno = 0;
138     ret->f = f;
139     ret->array = NULL;
140     return (ret);
141 }
142 
143 void
CONFfclose(CONFFILE * f)144 CONFfclose(CONFFILE *f)
145 {
146     if (!f)
147         return; /* No conf file */
148     fclose(f->f);
149     if (f->buf)
150         free(f->buf);
151     if (f->filename)
152         free(f->filename);
153     free(f);
154 }
155 
156 CONFTOKEN *
CONFgettoken(CONFTOKEN * toklist,CONFFILE * file)157 CONFgettoken(CONFTOKEN *toklist, CONFFILE *file)
158 {
159     char *word;
160     static CONFTOKEN ret = {CONFstring, 0};
161     int i;
162 
163     if (ret.name) {
164         free(ret.name);
165         ret.name = 0;
166     }
167     word = CONFgetword(file);
168     if (!word)
169         return (0);
170     if (toklist) {
171         for (i = 0; toklist[i].type; i++) {
172             if (strcmp(word, toklist[i].name) == 0) {
173                 free(word);
174                 return (&toklist[i]);
175             }
176         }
177     }
178     ret.name = word;
179     return (&ret);
180 }
181