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