2 * Lexical scanner for Bacula configuration file
10 Copyright (C) 2000-2006 Kern Sibbald
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.
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.
28 extern int debug_level;
30 /* Debug level for this source file */
31 static const int dbglvl = 5000;
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).
38 void scan_to_eol(LEX *lc)
41 Dmsg0(dbglvl, "start scan to eof\n");
42 while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
51 * Get next token, but skip EOL
53 int scan_to_next_not_eol(LEX * lc)
57 token = lex_get_token(lc, T_ALL);
58 } while (token == T_EOL);
63 * Format a scanner error message
65 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
71 va_start(arg_ptr, msg);
72 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
75 if (lc->err_type == 0) { /* M_ERROR_TERM by default */
76 lc->err_type = M_ERROR_TERM;
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);
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);
90 e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
94 void lex_set_default_error_handler(LEX *lf)
96 lf->scan_error = s_err;
100 * Set err_type used in error_handler
101 * return the old value
103 int lex_set_error_handler_error_type(LEX *lf, int err_type)
105 int old = lf->err_type;
106 lf->err_type = err_type;
111 * Free the current file, and retrieve the contents
112 * of the previous packet if any.
114 LEX *lex_close_file(LEX *lf)
119 Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
121 Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
125 Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
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);
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
150 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
155 char *fname = bstrdup(filename);
158 if ((fd = fopen(fname, "rb")) == NULL) {
161 Dmsg1(400, "Open config file: %s\n", fname);
162 nf = (LEX *)malloc(sizeof(LEX));
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 */
169 lf = nf; /* start new packet */
170 memset(lf, 0, sizeof(LEX));
171 lex_set_error_handler_error_type(lf, M_ERROR_TERM);
174 lf->scan_error = scan_error;
176 lex_set_default_error_handler(lf);
180 lf->state = lex_none;
182 Dmsg1(dbglvl, "Return lex=%x\n", lf);
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
192 int lex_get_char(LEX *lf)
194 if (lf->ch == L_EOF) {
195 Emsg0(M_ABORT, 0, _("get_char: called after EOF\n"));
197 if (lf->ch == L_EOL) {
198 if (bfgets(lf->line, MAXSTRING, lf->fd) == NULL) {
207 Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
209 lf->ch = (uint8_t)lf->line[lf->col_no];
215 Dmsg2(dbglvl, "lex_get_char: %c %d\n", lf->ch, lf->ch);
219 void lex_unget_char(LEX *lf)
221 if (lf->ch == L_EOL) {
222 lf->ch = 0; /* End of line, force read of next one */
224 lf->col_no--; /* Backup to re-read char */
231 * Add a character to the current string
233 static void add_str(LEX *lf, int ch)
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);
240 lf->str[lf->str_len++] = ch;
241 lf->str[lf->str_len] = 0;
247 static void begin_str(LEX *lf, int ch)
254 lf->begin_line_no = lf->line_no; /* save start string line no */
258 static const char *lex_state_to_str(int 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 "??????";
274 * Convert a lex token to a string
275 * used for debug/error printing.
277 const char *lex_tok_to_str(int 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 "??????";
299 static uint32_t scan_pint(LEX *lf, char *str)
302 if (!is_a_number(str)) {
303 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
307 val = str_to_int64(str);
308 if (errno != 0 || val < 0) {
309 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
313 return (uint32_t)val;
318 * Get the next token from the input
322 lex_get_token(LEX *lf, int expect)
326 bool esc_next = false;
327 int unicode_count = 0;
329 Dmsg0(dbglvl, "enter lex_get_token\n");
330 while (token == T_NONE) {
331 ch = lex_get_char(lf);
334 Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
338 if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
339 lf->state = lex_string;
341 lf->state = lex_identifier;
347 if (lf->options & LOPT_STRING) {
348 lf->state = lex_string;
350 lf->state = lex_number;
355 Dmsg0(dbglvl, "Enter lex_none switch\n");
359 Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
362 lf->state = lex_comment;
373 lf->state = lex_quoted_string;
385 if (expect != T_SKIP_EOL) {
386 token = T_EOL; /* treat ; like EOL */
390 Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
391 if (expect != T_SKIP_EOL) {
396 lf->state = lex_include;
400 if (lf->line_no != 1 || lf->col_no != 1)
402 lf->state = lex_string;
406 lf->state = lex_unicode_mark;
410 lf->state = lex_string;
416 Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
418 lf->state = lex_none;
419 if (expect != T_SKIP_EOL) {
422 } else if (ch == L_EOF) {
427 Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
432 /* Might want to allow trailing specifications here */
438 /* A valid number can be terminated by the following */
439 if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
441 lf->state = lex_none;
443 lf->state = lex_string;
452 Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
455 Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
460 if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
461 ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
463 token = T_UNQUOTED_STRING;
464 lf->state = lex_none;
470 Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
474 } else if (B_ISSPACE(ch)) {
476 } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
477 ch == '\r' || ch == ';' || ch == ',' || ch == '"' || ch == '#') {
479 token = T_IDENTIFIER;
480 lf->state = lex_none;
482 } else if (ch == L_EOF) {
484 lf->state = lex_none;
488 /* Some non-alpha character => string */
489 lf->state = lex_string;
492 case lex_quoted_string:
493 Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
512 token = T_QUOTED_STRING;
513 lf->state = lex_none;
518 case lex_include: /* scanning a filename */
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. */
528 lf->state = lex_none;
529 lf = lex_open_file(lf, lf->str, lf->scan_error);
532 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
533 lfori->str, be.strerror());
540 case lex_unicode_mark:
546 if (unicode_count == 2) {
551 } else if (unicode_count == 3) {
556 token = T_UNICODE_MARK;
557 lf->state = lex_none;
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);
565 Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
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).
575 lf->pint32_val = scan_pint(lf, lf->str);
576 lf->pint32_val2 = lf->pint32_val;
581 if (token == T_NUMBER) {
582 lf->pint32_val = scan_pint(lf, lf->str);
583 lf->pint32_val2 = lf->pint32_val;
586 char *p = strchr(lf->str, '-');
588 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
589 lex_tok_to_str(token), lf->str);
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;
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);
608 lf->int32_val = (int32_t)str_to_int64(lf->str);
610 scan_err2(lf, _("expected an integer number, got %s: %s"),
611 lex_tok_to_str(token), lf->str);
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);
627 lf->int64_val = str_to_int64(lf->str);
629 scan_err2(lf, _("expected an integer number, got %s: %s"),
630 lex_tok_to_str(token), lf->str);
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);
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);
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);
661 break; /* no expectation given */
663 lf->token = token; /* set possible new token */