]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
wx-console: Improve error handling when reading configuration file.
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2  * Lexical scanner for Bacula configuration file
3  *
4  *   Kern Sibbald, 2000
5  *
6  *   Version $Id$
7  *
8  */
9
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "lex.h"
32
33 extern int debug_level;
34
35 /*
36  * Scan to "logical" end of line. I.e. end of line,
37  *   or semicolon, but stop on T_EOB (same as end of
38  *   line except it is not eaten).
39  */
40 void scan_to_eol(LEX *lc)
41 {
42    int token;
43    Dmsg0(2000, "start scan to eof\n");
44    while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
45       if (token == T_EOB) {
46          lex_unget_char(lc);
47          return;
48       }
49    }
50 }
51
52 /*
53  * Get next token, but skip EOL
54  */
55 int scan_to_next_not_eol(LEX * lc)
56 {
57    int token;
58    do {
59       token = lex_get_token(lc, T_ALL);
60    } while (token == T_EOL);
61    return token;
62 }
63
64
65 /*
66  * Format a scanner error message
67  */
68 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
69 {
70    va_list arg_ptr;
71    char buf[MAXSTRING];
72    char more[MAXSTRING];
73
74    va_start(arg_ptr, msg);
75    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
76    va_end(arg_ptr);
77
78    if (lc->line_no > lc->begin_line_no) {
79       bsnprintf(more, sizeof(more),
80                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
81    } else {
82       more[0] = 0;
83    }
84    e_msg(file, line, M_ERROR_TERM, 0, _("Config error: %s\n"
85 "            : line %d, col %d of file %s\n%s\n%s"),
86       buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
87 }
88
89
90 /*
91  * Free the current file, and retrieve the contents
92  * of the previous packet if any.
93  */
94 LEX *lex_close_file(LEX *lf)
95 {
96    LEX *of;
97
98    Dmsg1(2000, "Close lex file: %s\n", lf->fname);
99    if (lf == NULL) {
100       Emsg0(M_ABORT, 0, "Close of NULL file\n");
101    }
102    of = lf->next;
103    fclose(lf->fd);
104    Dmsg1(2000, "Close cfg file %s\n", lf->fname);
105    free(lf->fname);
106    if (of) {
107       of->options = lf->options;      /* preserve options */
108       memcpy(lf, of, sizeof(LEX));
109       Dmsg1(2000, "Restart scan of cfg file %s\n", of->fname);
110    } else {
111       of = lf;
112       lf = NULL;
113    }
114    free(of);
115    return lf;
116 }
117
118 /*
119  * Open a new configuration file. We push the
120  * state of the current file (lf) so that we
121  * can do includes.  This is a bit of a hammer.
122  * Instead of passing back the pointer to the
123  * new packet, I simply replace the contents
124  * of the caller's packet with the new packet,
125  * and link the contents of the old packet into
126  * the next field.
127  *
128  */
129 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
130
131 {
132    LEX *nf;
133    FILE *fd;
134    char *fname = bstrdup(filename);
135
136
137    if ((fd = fopen(fname, "r")) == NULL) {
138       return NULL;
139    }
140    Dmsg1(2000, "Open config file: %s\n", fname);
141    nf = (LEX *)malloc(sizeof(LEX));
142    if (lf) {
143       memcpy(nf, lf, sizeof(LEX));
144       memset(lf, 0, sizeof(LEX));
145       lf->next = nf;                  /* if have lf, push it behind new one */
146       lf->options = nf->options;      /* preserve user options */
147    } else {
148       lf = nf;                        /* start new packet */
149       memset(lf, 0, sizeof(LEX));
150    }
151    lf->fd = fd;
152    lf->fname = fname;
153    lf->state = lex_none;
154    lf->ch = L_EOL;
155    if (scan_error) {
156       lf->scan_error = scan_error;
157    } else {
158       lf->scan_error = s_err;
159    }
160    Dmsg1(2000, "Return lex=%x\n", lf);
161    return lf;
162 }
163
164 /*
165  * Get the next character from the input.
166  *  Returns the character or
167  *    L_EOF if end of file
168  *    L_EOL if end of line
169  */
170 int lex_get_char(LEX *lf)
171 {
172    if (lf->ch == L_EOF) {
173       Emsg0(M_ABORT, 0, "get_char: called after EOF\n");
174    }
175    if (lf->ch == L_EOL) {
176       if (bfgets(lf->line, MAXSTRING, lf->fd) == NULL) {
177          lf->ch = L_EOF;
178          if (lf->next) {
179             lex_close_file(lf);
180          }
181          return lf->ch;
182       }
183       lf->line_no++;
184       lf->col_no = 0;
185    }
186    lf->ch = lf->line[lf->col_no];
187    if (lf->ch == 0) {
188       lf->ch = L_EOL;
189    } else {
190       lf->col_no++;
191    }
192    Dmsg2(2000, "lex_get_char: %c %d\n", lf->ch, lf->ch);
193    return lf->ch;
194 }
195
196 void lex_unget_char(LEX *lf)
197 {
198    lf->col_no--;
199    if (lf->ch == L_EOL)
200       lf->ch = 0;
201 }
202
203
204 /*
205  * Add a character to the current string
206  */
207 static void add_str(LEX *lf, int ch)
208 {
209    if (lf->str_len >= MAXSTRING-3) {
210       Emsg3(M_ERROR_TERM, 0, _(
211            _("Config token too long, file: %s, line %d, begins at line %d\n")),
212              lf->fname, lf->line_no, lf->begin_line_no);
213    }
214    lf->str[lf->str_len++] = ch;
215    lf->str[lf->str_len] = 0;
216 }
217
218 /*
219  * Begin the string
220  */
221 static void begin_str(LEX *lf, int ch)
222 {
223    lf->str_len = 0;
224    lf->str[0] = 0;
225    if (ch != 0) {
226       add_str(lf, ch);
227    }
228    lf->begin_line_no = lf->line_no;   /* save start string line no */
229 }
230
231 #ifdef DEBUG
232 static const char *lex_state_to_str(int state)
233 {
234    switch (state) {
235    case lex_none:          return "none";
236    case lex_comment:       return "comment";
237    case lex_number:        return "number";
238    case lex_ip_addr:       return "ip_addr";
239    case lex_identifier:    return "identifier";
240    case lex_string:        return "string";
241    case lex_quoted_string: return "quoted_string";
242    default:                return "??????";
243    }
244 }
245 #endif
246
247 /*
248  * Convert a lex token to a string
249  * used for debug/error printing.
250  */
251 const char *lex_tok_to_str(int token)
252 {
253    switch(token) {
254    case L_EOF:             return "L_EOF";
255    case L_EOL:             return "L_EOL";
256    case T_NONE:            return "T_NONE";
257    case T_NUMBER:          return "T_NUMBER";
258    case T_IPADDR:          return "T_IPADDR";
259    case T_IDENTIFIER:      return "T_IDENTIFIER";
260    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
261    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
262    case T_BOB:             return "T_BOB";
263    case T_EOB:             return "T_EOB";
264    case T_EQUALS:          return "T_EQUALS";
265    case T_ERROR:           return "T_ERROR";
266    case T_EOF:             return "T_EOF";
267    case T_COMMA:           return "T_COMMA";
268    case T_EOL:             return "T_EOL";
269    default:                return "??????";
270    }
271 }
272
273 static uint32_t scan_pint(LEX *lf, char *str)
274 {
275    int64_t val = 0;
276    if (!is_a_number(str)) {
277       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
278       /* NOT REACHED */
279    } else {
280       errno = 0;
281       val = str_to_int64(str);
282       if (errno != 0 || val < 0) {
283          scan_err1(lf, _("expected a postive integer number, got: %s"), str);
284          /* NOT REACHED */
285       }
286    }
287    return (uint32_t)val;
288 }
289
290 /*
291  *
292  * Get the next token from the input
293  *
294  */
295 int
296 lex_get_token(LEX *lf, int expect)
297 {
298    int ch;
299    int token = T_NONE;
300    bool esc_next = false;
301
302    Dmsg0(2000, "enter lex_get_token\n");
303    while (token == T_NONE) {
304       ch = lex_get_char(lf);
305       switch (lf->state) {
306       case lex_none:
307          Dmsg2(2000, "Lex state lex_none ch=%d,%x\n", ch, ch);
308          if (B_ISSPACE(ch))
309             break;
310          if (B_ISALPHA(ch)) {
311             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
312                lf->state = lex_string;
313             } else {
314                lf->state = lex_identifier;
315             }
316             begin_str(lf, ch);
317             break;
318          }
319          if (B_ISDIGIT(ch)) {
320             if (lf->options & LOPT_STRING) {
321                lf->state = lex_string;
322             } else {
323                lf->state = lex_number;
324             }
325             begin_str(lf, ch);
326             break;
327          }
328          Dmsg0(2000, "Enter lex_none switch\n");
329          switch (ch) {
330          case L_EOF:
331             token = T_EOF;
332             Dmsg0(2000, "got L_EOF set token=T_EOF\n");
333             break;
334          case '#':
335             lf->state = lex_comment;
336             break;
337          case '{':
338             token = T_BOB;
339             begin_str(lf, ch);
340             break;
341          case '}':
342             token = T_EOB;
343             begin_str(lf, ch);
344             break;
345          case '"':
346             lf->state = lex_quoted_string;
347             begin_str(lf, 0);
348             break;
349          case '=':
350             token = T_EQUALS;
351             begin_str(lf, ch);
352             break;
353          case ',':
354             token = T_COMMA;
355             begin_str(lf, ch);
356             break;
357          case ';':
358             if (expect != T_SKIP_EOL) {
359                token = T_EOL;      /* treat ; like EOL */
360             }
361             break;
362          case L_EOL:
363             Dmsg0(2000, "got L_EOL set token=T_EOL\n");
364             if (expect != T_SKIP_EOL) {
365                token = T_EOL;
366             }
367             break;
368          case '@':
369             lf->state = lex_include;
370             begin_str(lf, 0);
371             break;
372          default:
373             lf->state = lex_string;
374             begin_str(lf, ch);
375             break;
376          }
377          break;
378       case lex_comment:
379          Dmsg1(2000, "Lex state lex_comment ch=%x\n", ch);
380          if (ch == L_EOL) {
381             lf->state = lex_none;
382             if (expect != T_SKIP_EOL) {
383                token = T_EOL;
384             }
385          } else if (ch == L_EOF) {
386             token = T_ERROR;
387          }
388          break;
389       case lex_number:
390          Dmsg2(2000, "Lex state lex_number ch=%x %c\n", ch, ch);
391          if (ch == L_EOF) {
392             token = T_ERROR;
393             break;
394          }
395          /* Might want to allow trailing specifications here */
396          if (B_ISDIGIT(ch)) {
397             add_str(lf, ch);
398             break;
399          }
400
401          /* A valid number can be terminated by the following */
402          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
403             token = T_NUMBER;
404             lf->state = lex_none;
405          } else {
406             lf->state = lex_string;
407          }
408          lex_unget_char(lf);
409          break;
410       case lex_ip_addr:
411          if (ch == L_EOF) {
412             token = T_ERROR;
413             break;
414          }
415          Dmsg1(2000, "Lex state lex_ip_addr ch=%x\n", ch);
416          break;
417       case lex_string:
418          Dmsg1(2000, "Lex state lex_string ch=%x\n", ch);
419          if (ch == L_EOF) {
420             token = T_ERROR;
421             break;
422          }
423          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
424              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
425             lex_unget_char(lf);
426             token = T_UNQUOTED_STRING;
427             lf->state = lex_none;
428             break;
429          }
430          add_str(lf, ch);
431          break;
432       case lex_identifier:
433          Dmsg2(2000, "Lex state lex_identifier ch=%x %c\n", ch, ch);
434          if (B_ISALPHA(ch)) {
435             add_str(lf, ch);
436             break;
437          } else if (B_ISSPACE(ch)) {
438             break;
439          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
440                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
441             lex_unget_char(lf);
442             token = T_IDENTIFIER;
443             lf->state = lex_none;
444             break;
445          } else if (ch == L_EOF) {
446             token = T_ERROR;
447             lf->state = lex_none;
448             begin_str(lf, ch);
449             break;
450          }
451          /* Some non-alpha character => string */
452          lf->state = lex_string;
453          add_str(lf, ch);
454          break;
455       case lex_quoted_string:
456          Dmsg2(2000, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
457          if (ch == L_EOF) {
458             token = T_ERROR;
459             break;
460          }
461          if (ch == L_EOL) {
462             esc_next = false;
463             break;
464          }
465          if (esc_next) {
466             add_str(lf, ch);
467             esc_next = false;
468             break;
469          }
470          if (ch == '\\') {
471             esc_next = true;
472             break;
473          }
474          if (ch == '"') {
475             token = T_QUOTED_STRING;
476             lf->state = lex_none;
477             break;
478          }
479          add_str(lf, ch);
480          break;
481       case lex_include:            /* scanning a filename */
482          if (ch == L_EOF) {
483             token = T_ERROR;
484             break;
485          }
486          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
487              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
488             /* Keep the original LEX so we can print an error if the included file can't be opened. */
489             LEX* lfori = lf;
490             
491             lf->state = lex_none;
492             lf = lex_open_file(lf, lf->str, NULL);
493             if (lf == NULL) {
494                berrno be;
495                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
496                   lfori->str, be.strerror());
497                return T_ERROR;
498             }
499             break;
500          }
501          add_str(lf, ch);
502          break;
503       }
504       Dmsg4(2000, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
505         lex_tok_to_str(token), ch);
506    }
507    Dmsg2(2000, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
508    lf->token = token;
509
510    /*
511     * Here is where we check to see if the user has set certain
512     *  expectations (e.g. 32 bit integer). If so, we do type checking
513     *  and possible additional scanning (e.g. for range).
514     */
515    switch (expect) {
516    case T_PINT32:
517       lf->pint32_val = scan_pint(lf, lf->str);
518       lf->pint32_val2 = lf->pint32_val;
519       token = T_PINT32;
520       break;
521
522    case T_PINT32_RANGE:
523       if (token == T_NUMBER) {
524          lf->pint32_val = scan_pint(lf, lf->str);
525          lf->pint32_val2 = lf->pint32_val;
526          token = T_PINT32;
527       } else {
528          char *p = strchr(lf->str, '-');
529          if (!p) {
530             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
531                lex_tok_to_str(token), lf->str);
532             token = T_ERROR;
533             break;
534          }
535          *p++ = 0;                       /* terminate first half of range */
536          lf->pint32_val  = scan_pint(lf, lf->str);
537          lf->pint32_val2 = scan_pint(lf, p);
538          token = T_PINT32_RANGE;
539       }
540       break;
541
542    case T_INT32:
543       if (token != T_NUMBER || !is_a_number(lf->str)) {
544          scan_err2(lf, _("expected an integer number, got %s: %s"),
545                lex_tok_to_str(token), lf->str);
546          token = T_ERROR;
547          break;
548       }
549       errno = 0;
550       lf->int32_val = (int32_t)str_to_int64(lf->str);
551       if (errno != 0) {
552          scan_err2(lf, _("expected an integer number, got %s: %s"),
553                lex_tok_to_str(token), lf->str);
554          token = T_ERROR;
555       } else {
556          token = T_INT32;
557       }
558       break;
559
560    case T_INT64:
561       Dmsg2(2000, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
562       if (token != T_NUMBER || !is_a_number(lf->str)) {
563          scan_err2(lf, _("expected an integer number, got %s: %s"),
564                lex_tok_to_str(token), lf->str);
565          token = T_ERROR;
566          break;
567       }
568       errno = 0;
569       lf->int64_val = str_to_int64(lf->str);
570       if (errno != 0) {
571          scan_err2(lf, _("expected an integer number, got %s: %s"),
572                lex_tok_to_str(token), lf->str);
573          token = T_ERROR;
574       } else {
575          token = T_INT64;
576       }
577       break;
578
579    case T_NAME:
580       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
581          scan_err2(lf, _("expected a name, got %s: %s"),
582                lex_tok_to_str(token), lf->str);
583          token = T_ERROR;
584       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
585          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
586             lf->str_len, MAX_RES_NAME_LENGTH);
587          token = T_ERROR;
588       }
589       break;
590
591    case T_STRING:
592       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
593          scan_err2(lf, _("expected a string, got %s: %s"),
594                lex_tok_to_str(token), lf->str);
595          token = T_ERROR;
596       } else {
597          token = T_STRING;
598       }
599       break;
600
601
602    default:
603       break;                          /* no expectation given */
604    }
605    lf->token = token;                 /* set possible new token */
606    return token;
607 }