Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
[multipath-tools/.git] / libmultipath / parser.c
1 /*
2  * Part:        Configuration file parser/reader. Place into the dynamic
3  *              data structure representation the conf file
4  *
5  * Version:     $Id: parser.c,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
6  *
7  * Author:      Alexandre Cassen, <acassen@linux-vs.org>
8  *
9  *              This program is distributed in the hope that it will be useful,
10  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *              See the GNU General Public License for more details.
13  *
14  *              This program is free software; you can redistribute it and/or
15  *              modify it under the terms of the GNU General Public License
16  *              as published by the Free Software Foundation; either version
17  *              2 of the License, or (at your option) any later version.
18  */
19
20 #include <syslog.h>
21
22 #include "parser.h"
23 #include "memory.h"
24
25 /* local vars */
26 static int sublevel = 0;
27 vector keywords = NULL;
28 vector *keywords_addr = NULL;
29
30 void set_current_keywords (vector *k)
31 {
32         keywords_addr = k;
33         keywords = NULL;
34 }
35
36 int
37 keyword_alloc(vector keywords, char *string, int (*handler) (vector),
38                 int (*print) (char *, int, void *))
39 {
40         struct keyword *keyword;
41
42         keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
43
44         if (!keyword)
45                 return 1;
46
47         if (!vector_alloc_slot(keywords)) {
48                 FREE(keyword);
49                 return 1;
50         }
51         keyword->string = string;
52         keyword->handler = handler;
53         keyword->print = print;
54
55         vector_set_slot(keywords, keyword);
56
57         return 0;
58 }
59
60 int
61 install_keyword_root(char *string, int (*handler) (vector))
62 {
63         int r = keyword_alloc(keywords, string, handler, NULL);
64         if (!r)
65                 *keywords_addr = keywords;
66         return r;
67 }
68
69 void
70 install_sublevel(void)
71 {
72         sublevel++;
73 }
74
75 void
76 install_sublevel_end(void)
77 {
78         sublevel--;
79 }
80
81 int
82 install_keyword(char *string, int (*handler) (vector),
83                 int (*print) (char *, int, void *))
84 {
85         int i = 0;
86         struct keyword *keyword;
87
88         /* fetch last keyword */
89         keyword = VECTOR_SLOT(keywords, VECTOR_SIZE(keywords) - 1);
90
91         /* position to last sub level */
92         for (i = 0; i < sublevel; i++)
93                 keyword =
94                     VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1);
95
96         /* First sub level allocation */
97         if (!keyword->sub)
98                 keyword->sub = vector_alloc();
99
100         if (!keyword->sub)
101                 return 1;
102
103         /* add new sub keyword */
104         return keyword_alloc(keyword->sub, string, handler, print);
105 }
106
107 void
108 free_keywords(vector keywords)
109 {
110         struct keyword *keyword;
111         int i;
112
113         if (!keywords)
114                 return;
115
116         for (i = 0; i < VECTOR_SIZE(keywords); i++) {
117                 keyword = VECTOR_SLOT(keywords, i);
118                 if (keyword->sub)
119                         free_keywords(keyword->sub);
120                 FREE(keyword);
121         }
122         vector_free(keywords);
123 }
124
125 struct keyword *
126 find_keyword(vector v, char * name)
127 {
128         struct keyword *keyword;
129         int i;
130         int len;
131
132         if (!name || !keywords)
133                 return NULL;
134
135         if (!v)
136                 v = keywords;
137
138         len = strlen(name);
139
140         for (i = 0; i < VECTOR_SIZE(v); i++) {
141                 keyword = VECTOR_SLOT(v, i);
142                 if ((strlen(keyword->string) == len) &&
143                     !strcmp(keyword->string, name))
144                         return keyword;
145                 if (keyword->sub) {
146                         keyword = find_keyword(keyword->sub, name);
147                         if (keyword)
148                                 return keyword;
149                 }
150         }
151         return NULL;
152 }
153
154 int
155 snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
156 {
157         int r;
158         int fwd = 0;
159         char *f = fmt;
160
161         if (!kw || !kw->print)
162                 return 0;
163
164         do {
165                 if (fwd == len || *f == '\0')
166                         break;
167                 if (*f != '%') {
168                         *(buff + fwd) = *f;
169                         fwd++;
170                         continue;
171                 }
172                 f++;
173                 switch(*f) {
174                 case 'k':
175                         fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
176                         break;
177                 case 'v':
178                         r = kw->print(buff + fwd, len - fwd, data);
179                         if (!r) { /* no output if no value */
180                                 buff = '\0';
181                                 return 0;
182                         }
183                         fwd += r;
184                         break;
185                 }
186                 if (fwd > len)
187                         fwd = len;
188         } while (*f++);
189         return fwd;
190 }
191
192 vector
193 alloc_strvec(char *string)
194 {
195         char *cp, *start, *token;
196         int strlen;
197         int in_string;
198         vector strvec;
199
200         if (!string)
201                 return NULL;
202
203         cp = string;
204
205         /* Skip white spaces */
206         while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
207                 cp++;
208
209         /* Return if there is only white spaces */
210         if (*cp == '\0')
211                 return NULL;
212
213         /* Return if string begin with a comment */
214         if (*cp == '!' || *cp == '#')
215                 return NULL;
216
217         /* Create a vector and alloc each command piece */
218         strvec = vector_alloc();
219
220         if (!strvec)
221                 return NULL;
222
223         in_string = 0;
224         while (1) {
225                 if (!vector_alloc_slot(strvec))
226                         goto out;
227
228                 start = cp;
229                 if (*cp == '"') {
230                         cp++;
231                         token = MALLOC(2);
232
233                         if (!token)
234                                 goto out;
235
236                         *(token) = '"';
237                         *(token + 1) = '\0';
238                         if (in_string)
239                                 in_string = 0;
240                         else
241                                 in_string = 1;
242                 } else if (!in_string && (*cp == '{' || *cp == '}')) {
243                         token = MALLOC(2);
244
245                         if (!token)
246                                 goto out;
247
248                         *(token) = *cp;
249                         *(token + 1) = '\0';
250                         cp++;
251                 } else {
252                         while ((in_string ||
253                                 (!isspace((int) *cp) && isascii((int) *cp) &&
254                                  *cp != '!' && *cp != '#' && *cp != '{' &&
255                                  *cp != '}')) && *cp != '\0' && *cp != '"')
256                                 cp++;
257                         strlen = cp - start;
258                         token = MALLOC(strlen + 1);
259
260                         if (!token)
261                                 goto out;
262
263                         memcpy(token, start, strlen);
264                         *(token + strlen) = '\0';
265                 }
266                 vector_set_slot(strvec, token);
267
268                 while ((isspace((int) *cp) || !isascii((int) *cp))
269                        && *cp != '\0')
270                         cp++;
271                 if (*cp == '\0' || *cp == '!' || *cp == '#')
272                         return strvec;
273         }
274 out:
275         vector_free(strvec);
276         return NULL;
277 }
278
279 int
280 read_line(char *buf, int size)
281 {
282         int ch;
283         int count = 0;
284
285         while ((ch = fgetc(stream)) != EOF && (int) ch != '\n'
286                && (int) ch != '\r') {
287                 if (count < size)
288                         buf[count] = (int) ch;
289                 else
290                         break;
291                 count++;
292         }
293         return (ch == EOF) ? 0 : 1;
294 }
295
296 vector
297 read_value_block(void)
298 {
299         char *buf;
300         int i;
301         char *str = NULL;
302         char *dup;
303         vector vec = NULL;
304         vector elements = vector_alloc();
305
306         if (!elements)
307                 return NULL;
308
309         buf = (char *) MALLOC(MAXBUF);
310
311         if (!buf)
312                 return NULL;
313
314         while (read_line(buf, MAXBUF)) {
315                 vec = alloc_strvec(buf);
316                 if (vec) {
317                         str = VECTOR_SLOT(vec, 0);
318                         if (!strcmp(str, EOB)) {
319                                 free_strvec(vec);
320                                 break;
321                         }
322
323                         if (VECTOR_SIZE(vec))
324                                 for (i = 0; i < VECTOR_SIZE(vec); i++) {
325                                         str = VECTOR_SLOT(vec, i);
326                                         dup = (char *) MALLOC(strlen(str) + 1);
327                                         if (!dup)
328                                                 goto out;
329                                         memcpy(dup, str, strlen(str));
330
331                                         if (!vector_alloc_slot(elements)) {
332                                                 free_strvec(vec);
333                                                 goto out1;
334                                         }
335
336                                         vector_set_slot(elements, dup);
337                                 }
338                         free_strvec(vec);
339                 }
340                 memset(buf, 0, MAXBUF);
341         }
342         FREE(buf);
343         return elements;
344 out1:
345         FREE(dup);
346 out:
347         FREE(buf);
348         return NULL;
349 }
350
351 int
352 alloc_value_block(vector strvec, void (*alloc_func) (vector))
353 {
354         char *buf;
355         char *str = NULL;
356         vector vec = NULL;
357
358         buf = (char *) MALLOC(MAXBUF);
359
360         if (!buf)
361                 return 1;
362
363         while (read_line(buf, MAXBUF)) {
364                 vec = alloc_strvec(buf);
365                 if (vec) {
366                         str = VECTOR_SLOT(vec, 0);
367                         if (!strcmp(str, EOB)) {
368                                 free_strvec(vec);
369                                 break;
370                         }
371
372                         if (VECTOR_SIZE(vec))
373                                 (*alloc_func) (vec);
374
375                         free_strvec(vec);
376                 }
377                 memset(buf, 0, MAXBUF);
378         }
379         FREE(buf);
380         return 0;
381 }
382
383 void *
384 set_value(vector strvec)
385 {
386         char *str = VECTOR_SLOT(strvec, 1);
387         int size = strlen(str);
388         int i = 0;
389         int len = 0;
390         char *alloc = NULL;
391         char *tmp;
392
393         if (*str == '"') {
394                 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
395                         str = VECTOR_SLOT(strvec, i);
396                         len += strlen(str);
397                         if (!alloc)
398                                 alloc =
399                                     (char *) MALLOC(sizeof (char *) *
400                                                     (len + 1));
401                         else {
402                                 alloc =
403                                     REALLOC(alloc, sizeof (char *) * (len + 1));
404                                 tmp = VECTOR_SLOT(strvec, i-1);
405                                 if (alloc && *str != '"' && *tmp != '"')
406                                         strncat(alloc, " ", 1);
407                         }
408
409                         if (alloc && i != VECTOR_SIZE(strvec)-1)
410                                 strncat(alloc, str, strlen(str));
411                 }
412         } else {
413                 alloc = MALLOC(sizeof (char *) * (size + 1));
414                 if (alloc)
415                         memcpy(alloc, str, size);
416         }
417         return alloc;
418 }
419
420 /* non-recursive configuration stream handler */
421 static int kw_level = 0;
422 int
423 process_stream(vector keywords)
424 {
425         int i;
426         int r = 0;
427         struct keyword *keyword;
428         char *str;
429         char *buf;
430         vector strvec;
431
432         buf = MALLOC(MAXBUF);
433
434         if (!buf)
435                 return 1;
436
437         while (read_line(buf, MAXBUF)) {
438                 strvec = alloc_strvec(buf);
439                 memset(buf,0, MAXBUF);
440
441                 if (!strvec)
442                         continue;
443
444                 str = VECTOR_SLOT(strvec, 0);
445
446                 if (!strcmp(str, EOB) && kw_level > 0) {
447                         free_strvec(strvec);
448                         break;
449                 }
450
451                 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
452                         keyword = VECTOR_SLOT(keywords, i);
453
454                         if (!strcmp(keyword->string, str)) {
455                                 if (keyword->handler)
456                                         r += (*keyword->handler) (strvec);
457
458                                 if (keyword->sub) {
459                                         kw_level++;
460                                         r += process_stream(keyword->sub);
461                                         kw_level--;
462                                 }
463                                 break;
464                         }
465                 }
466
467                 free_strvec(strvec);
468         }
469
470         FREE(buf);
471         return r;
472 }
473
474 /* Data initialization */
475 int
476 init_data(char *conf_file, void (*init_keywords) (void))
477 {
478         int r;
479
480         if (!keywords)
481                 keywords = vector_alloc();
482         if (!keywords)
483                 return 1;
484         stream = fopen(conf_file, "r");
485         if (!stream) {
486                 syslog(LOG_WARNING, "Configuration file open problem");
487                 return 1;
488         }
489
490         /* Init Keywords structure */
491         (*init_keywords) ();
492
493 /* Dump configuration *
494   vector_dump(keywords);
495   dump_keywords(keywords, 0);
496 */
497
498         /* Stream handling */
499         r = process_stream(keywords);
500         fclose(stream);
501         //free_keywords(keywords);
502
503         return r;
504 }