2 * Lexical scanner for Bacula configuration file
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 extern int debug_level;
42 /* Debug level for this source file */
43 static const int dbglvl = 5000;
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).
50 void scan_to_eol(LEX *lc)
53 Dmsg0(dbglvl, "start scan to eof\n");
54 while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
63 * Get next token, but skip EOL
65 int scan_to_next_not_eol(LEX * lc)
69 token = lex_get_token(lc, T_ALL);
70 } while (token == T_EOL);
75 * Format a scanner error message
77 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
83 va_start(arg_ptr, msg);
84 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
87 if (lc->err_type == 0) { /* M_ERROR_TERM by default */
88 lc->err_type = M_ERROR_TERM;
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);
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);
102 e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
106 void lex_set_default_error_handler(LEX *lf)
108 lf->scan_error = s_err;
112 * Set err_type used in error_handler
113 * return the old value
115 int lex_set_error_handler_error_type(LEX *lf, int err_type)
117 int old = lf->err_type;
118 lf->err_type = err_type;
123 * Free the current file, and retrieve the contents
124 * of the previous packet if any.
126 LEX *lex_close_file(LEX *lf)
131 Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
133 Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
137 Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
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);
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
162 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
167 char *fname = bstrdup(filename);
170 if ((fd = fopen(fname, "rb")) == NULL) {
173 Dmsg1(400, "Open config file: %s\n", fname);
174 nf = (LEX *)malloc(sizeof(LEX));
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 */
181 lf = nf; /* start new packet */
182 memset(lf, 0, sizeof(LEX));
183 lex_set_error_handler_error_type(lf, M_ERROR_TERM);
186 lf->scan_error = scan_error;
188 lex_set_default_error_handler(lf);
192 lf->state = lex_none;
194 Dmsg1(dbglvl, "Return lex=%x\n", lf);
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
204 int lex_get_char(LEX *lf)
206 if (lf->ch == L_EOF) {
207 Emsg0(M_ABORT, 0, _("get_char: called after EOF\n"));
209 if (lf->ch == L_EOL) {
210 if (bfgets(lf->line, MAXSTRING, lf->fd) == NULL) {
219 Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
221 lf->ch = (uint8_t)lf->line[lf->col_no];
227 Dmsg2(dbglvl, "lex_get_char: %c %d\n", lf->ch, lf->ch);
231 void lex_unget_char(LEX *lf)
233 if (lf->ch == L_EOL) {
234 lf->ch = 0; /* End of line, force read of next one */
236 lf->col_no--; /* Backup to re-read char */
243 * Add a character to the current string
245 static void add_str(LEX *lf, int ch)
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);
252 lf->str[lf->str_len++] = ch;
253 lf->str[lf->str_len] = 0;
259 static void begin_str(LEX *lf, int ch)
266 lf->begin_line_no = lf->line_no; /* save start string line no */
270 static const char *lex_state_to_str(int 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 "??????";
286 * Convert a lex token to a string
287 * used for debug/error printing.
289 const char *lex_tok_to_str(int 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 "??????";
311 static uint32_t scan_pint(LEX *lf, char *str)
314 if (!is_a_number(str)) {
315 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
319 val = str_to_int64(str);
320 if (errno != 0 || val < 0) {
321 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
325 return (uint32_t)val;
330 * Get the next token from the input
334 lex_get_token(LEX *lf, int expect)
338 bool esc_next = false;
339 int unicode_count = 0;
341 Dmsg0(dbglvl, "enter lex_get_token\n");
342 while (token == T_NONE) {
343 ch = lex_get_char(lf);
346 Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
350 if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
351 lf->state = lex_string;
353 lf->state = lex_identifier;
359 if (lf->options & LOPT_STRING) {
360 lf->state = lex_string;
362 lf->state = lex_number;
367 Dmsg0(dbglvl, "Enter lex_none switch\n");
371 Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
374 lf->state = lex_comment;
385 lf->state = lex_quoted_string;
397 if (expect != T_SKIP_EOL) {
398 token = T_EOL; /* treat ; like EOL */
402 Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
403 if (expect != T_SKIP_EOL) {
408 lf->state = lex_include;
412 if (lf->line_no != 1 || lf->col_no != 1)
414 lf->state = lex_string;
418 lf->state = lex_unicode_mark;
422 lf->state = lex_string;
428 Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
430 lf->state = lex_none;
431 if (expect != T_SKIP_EOL) {
434 } else if (ch == L_EOF) {
439 Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
444 /* Might want to allow trailing specifications here */
450 /* A valid number can be terminated by the following */
451 if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
453 lf->state = lex_none;
455 lf->state = lex_string;
464 Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
467 Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
472 if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
473 ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
475 token = T_UNQUOTED_STRING;
476 lf->state = lex_none;
482 Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
486 } else if (B_ISSPACE(ch)) {
488 } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
489 ch == '\r' || ch == ';' || ch == ',' || ch == '"' || ch == '#') {
491 token = T_IDENTIFIER;
492 lf->state = lex_none;
494 } else if (ch == L_EOF) {
496 lf->state = lex_none;
500 /* Some non-alpha character => string */
501 lf->state = lex_string;
504 case lex_quoted_string:
505 Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
524 token = T_QUOTED_STRING;
525 lf->state = lex_none;
530 case lex_include: /* scanning a filename */
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. */
540 lf->state = lex_none;
541 lf = lex_open_file(lf, lf->str, lf->scan_error);
544 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
545 lfori->str, be.strerror());
552 case lex_unicode_mark:
558 if (unicode_count == 2) {
563 } else if (unicode_count == 3) {
568 token = T_UNICODE_MARK;
569 lf->state = lex_none;
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);
577 Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
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).
587 lf->pint32_val = scan_pint(lf, lf->str);
588 lf->pint32_val2 = lf->pint32_val;
593 if (token == T_NUMBER) {
594 lf->pint32_val = scan_pint(lf, lf->str);
595 lf->pint32_val2 = lf->pint32_val;
598 char *p = strchr(lf->str, '-');
600 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
601 lex_tok_to_str(token), lf->str);
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;
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);
620 lf->int32_val = (int32_t)str_to_int64(lf->str);
622 scan_err2(lf, _("expected an integer number, got %s: %s"),
623 lex_tok_to_str(token), lf->str);
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);
639 lf->int64_val = str_to_int64(lf->str);
641 scan_err2(lf, _("expected an integer number, got %s: %s"),
642 lex_tok_to_str(token), lf->str);
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);
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);
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);
673 break; /* no expectation given */
675 lf->token = token; /* set possible new token */