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