]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
- Correct EOF with no \n lex.c problem.
[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, "r")) == 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
328    Dmsg0(dbglvl, "enter lex_get_token\n");
329    while (token == T_NONE) {
330       ch = lex_get_char(lf);
331       switch (lf->state) {
332       case lex_none:
333          Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
334          if (B_ISSPACE(ch))
335             break;
336          if (B_ISALPHA(ch)) {
337             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
338                lf->state = lex_string;
339             } else {
340                lf->state = lex_identifier;
341             }
342             begin_str(lf, ch);
343             break;
344          }
345          if (B_ISDIGIT(ch)) {
346             if (lf->options & LOPT_STRING) {
347                lf->state = lex_string;
348             } else {
349                lf->state = lex_number;
350             }
351             begin_str(lf, ch);
352             break;
353          }
354          Dmsg0(dbglvl, "Enter lex_none switch\n");
355          switch (ch) {
356          case L_EOF:
357             token = T_EOF;
358             Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
359             break;
360          case '#':
361             lf->state = lex_comment;
362             break;
363          case '{':
364             token = T_BOB;
365             begin_str(lf, ch);
366             break;
367          case '}':
368             token = T_EOB;
369             begin_str(lf, ch);
370             break;
371          case '"':
372             lf->state = lex_quoted_string;
373             begin_str(lf, 0);
374             break;
375          case '=':
376             token = T_EQUALS;
377             begin_str(lf, ch);
378             break;
379          case ',':
380             token = T_COMMA;
381             begin_str(lf, ch);
382             break;
383          case ';':
384             if (expect != T_SKIP_EOL) {
385                token = T_EOL;      /* treat ; like EOL */
386             }
387             break;
388          case L_EOL:
389             Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
390             if (expect != T_SKIP_EOL) {
391                token = T_EOL;
392             }
393             break;
394          case '@':
395             lf->state = lex_include;
396             begin_str(lf, 0);
397             break;
398          default:
399             lf->state = lex_string;
400             begin_str(lf, ch);
401             break;
402          }
403          break;
404       case lex_comment:
405          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
406          if (ch == L_EOL) {
407             lf->state = lex_none;
408             if (expect != T_SKIP_EOL) {
409                token = T_EOL;
410             }
411          } else if (ch == L_EOF) {
412             token = T_ERROR;
413          }
414          break;
415       case lex_number:
416          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
417          if (ch == L_EOF) {
418             token = T_ERROR;
419             break;
420          }
421          /* Might want to allow trailing specifications here */
422          if (B_ISDIGIT(ch)) {
423             add_str(lf, ch);
424             break;
425          }
426
427          /* A valid number can be terminated by the following */
428          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
429             token = T_NUMBER;
430             lf->state = lex_none;
431          } else {
432             lf->state = lex_string;
433          }
434          lex_unget_char(lf);
435          break;
436       case lex_ip_addr:
437          if (ch == L_EOF) {
438             token = T_ERROR;
439             break;
440          }
441          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
442          break;
443       case lex_string:
444          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
445          if (ch == L_EOF) {
446             token = T_ERROR;
447             break;
448          }
449          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
450              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
451             lex_unget_char(lf);
452             token = T_UNQUOTED_STRING;
453             lf->state = lex_none;
454             break;
455          }
456          add_str(lf, ch);
457          break;
458       case lex_identifier:
459          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
460          if (B_ISALPHA(ch)) {
461             add_str(lf, ch);
462             break;
463          } else if (B_ISSPACE(ch)) {
464             break;
465          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
466                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
467             lex_unget_char(lf);
468             token = T_IDENTIFIER;
469             lf->state = lex_none;
470             break;
471          } else if (ch == L_EOF) {
472             token = T_ERROR;
473             lf->state = lex_none;
474             begin_str(lf, ch);
475             break;
476          }
477          /* Some non-alpha character => string */
478          lf->state = lex_string;
479          add_str(lf, ch);
480          break;
481       case lex_quoted_string:
482          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
483          if (ch == L_EOF) {
484             token = T_ERROR;
485             break;
486          }
487          if (ch == L_EOL) {
488             esc_next = false;
489             break;
490          }
491          if (esc_next) {
492             add_str(lf, ch);
493             esc_next = false;
494             break;
495          }
496          if (ch == '\\') {
497             esc_next = true;
498             break;
499          }
500          if (ch == '"') {
501             token = T_QUOTED_STRING;
502             lf->state = lex_none;
503             break;
504          }
505          add_str(lf, ch);
506          break;
507       case lex_include:            /* scanning a filename */
508          if (ch == L_EOF) {
509             token = T_ERROR;
510             break;
511          }
512          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
513              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
514             /* Keep the original LEX so we can print an error if the included file can't be opened. */
515             LEX* lfori = lf;
516             
517             lf->state = lex_none;
518             lf = lex_open_file(lf, lf->str, lf->scan_error);
519             if (lf == NULL) {
520                berrno be;
521                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
522                   lfori->str, be.strerror());
523                return T_ERROR;
524             }
525             break;
526          }
527          add_str(lf, ch);
528          break;
529       }
530       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
531         lex_tok_to_str(token), ch);
532    }
533    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
534    lf->token = token;
535
536    /*
537     * Here is where we check to see if the user has set certain
538     *  expectations (e.g. 32 bit integer). If so, we do type checking
539     *  and possible additional scanning (e.g. for range).
540     */
541    switch (expect) {
542    case T_PINT32:
543       lf->pint32_val = scan_pint(lf, lf->str);
544       lf->pint32_val2 = lf->pint32_val;
545       token = T_PINT32;
546       break;
547
548    case T_PINT32_RANGE:
549       if (token == T_NUMBER) {
550          lf->pint32_val = scan_pint(lf, lf->str);
551          lf->pint32_val2 = lf->pint32_val;
552          token = T_PINT32;
553       } else {
554          char *p = strchr(lf->str, '-');
555          if (!p) {
556             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
557                lex_tok_to_str(token), lf->str);
558             token = T_ERROR;
559             break;
560          }
561          *p++ = 0;                       /* terminate first half of range */
562          lf->pint32_val  = scan_pint(lf, lf->str);
563          lf->pint32_val2 = scan_pint(lf, p);
564          token = T_PINT32_RANGE;
565       }
566       break;
567
568    case T_INT32:
569       if (token != T_NUMBER || !is_a_number(lf->str)) {
570          scan_err2(lf, _("expected an integer number, got %s: %s"),
571                lex_tok_to_str(token), lf->str);
572          token = T_ERROR;
573          break;
574       }
575       errno = 0;
576       lf->int32_val = (int32_t)str_to_int64(lf->str);
577       if (errno != 0) {
578          scan_err2(lf, _("expected an integer number, got %s: %s"),
579                lex_tok_to_str(token), lf->str);
580          token = T_ERROR;
581       } else {
582          token = T_INT32;
583       }
584       break;
585
586    case T_INT64:
587       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
588       if (token != T_NUMBER || !is_a_number(lf->str)) {
589          scan_err2(lf, _("expected an integer number, got %s: %s"),
590                lex_tok_to_str(token), lf->str);
591          token = T_ERROR;
592          break;
593       }
594       errno = 0;
595       lf->int64_val = str_to_int64(lf->str);
596       if (errno != 0) {
597          scan_err2(lf, _("expected an integer number, got %s: %s"),
598                lex_tok_to_str(token), lf->str);
599          token = T_ERROR;
600       } else {
601          token = T_INT64;
602       }
603       break;
604
605    case T_NAME:
606       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
607          scan_err2(lf, _("expected a name, got %s: %s"),
608                lex_tok_to_str(token), lf->str);
609          token = T_ERROR;
610       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
611          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
612             lf->str_len, MAX_RES_NAME_LENGTH);
613          token = T_ERROR;
614       }
615       break;
616
617    case T_STRING:
618       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
619          scan_err2(lf, _("expected a string, got %s: %s"),
620                lex_tok_to_str(token), lf->str);
621          token = T_ERROR;
622       } else {
623          token = T_STRING;
624       }
625       break;
626
627
628    default:
629       break;                          /* no expectation given */
630    }
631    lf->token = token;                 /* set possible new token */
632    return token;
633 }