]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /*
21  * Lexical scanner for Bacula configuration file
22  *
23  *   Kern Sibbald, 2000
24  *
25  */
26
27 #include "bacula.h"
28 #include "lex.h"
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 eol\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       if (token == T_EOF) {
48          return;
49       }
50    }
51 }
52
53 /*
54  * Get next token, but skip EOL
55  */
56 int scan_to_next_not_eol(LEX * lc)
57 {
58    int token;
59    do {
60       token = lex_get_token(lc, T_ALL);
61    } while (token == T_EOL);
62    return token;
63 }
64
65 /*
66  * Format a scanner error message
67  */
68 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
69 {
70    va_list arg_ptr;
71    char buf[MAXSTRING];
72    char more[MAXSTRING];
73
74    va_start(arg_ptr, msg);
75    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
76    va_end(arg_ptr);
77
78    if (lc->err_type == 0) {     /* M_ERROR_TERM by default */
79       lc->err_type = M_ERROR_TERM;
80    }
81
82    if (lc->line_no > lc->begin_line_no) {
83       bsnprintf(more, sizeof(more),
84                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
85    } else {
86       more[0] = 0;
87    }
88    if (lc->line_no > 0) {
89       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
90 "            : line %d, col %d of file %s\n%s\n%s"),
91          buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
92    } else {
93       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
94    }
95 }
96
97 void lex_set_default_error_handler(LEX *lf)
98 {
99    lf->scan_error = s_err;
100 }
101
102 /*
103  * Set err_type used in error_handler
104  * return the old value
105  */
106 int lex_set_error_handler_error_type(LEX *lf, int err_type)
107 {
108    int old = lf->err_type;
109    lf->err_type = err_type;
110    return old;
111 }
112
113 /*
114  * Free the current file, and retrieve the contents
115  * of the previous packet if any.
116  */
117 LEX *lex_close_file(LEX *lf)
118 {
119    LEX *of;
120
121    if (lf == NULL) {
122       Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
123    }
124    Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
125
126    of = lf->next;
127    if (lf->bpipe) {
128       close_bpipe(lf->bpipe);
129       lf->bpipe = NULL;
130    } else if (lf->fd) {
131       fclose(lf->fd);
132    }
133    Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
134    if (lf->fname) {
135       free(lf->fname);
136    }
137    free_memory(lf->line);
138    lf->line = NULL;
139    free_memory(lf->str);
140    lf->str = NULL;
141    if (of) {
142       of->options = lf->options;      /* preserve options */
143       memcpy(lf, of, sizeof(LEX));
144       Dmsg1(dbglvl, "Restart scan of cfg file %s\n", of->fname);
145    } else {
146       of = lf;
147       lf = NULL;
148    }
149    if (of) {
150       free(of);
151    }
152    return lf;
153 }
154
155 /*
156  * Open a configuration in memory buffer. We push the
157  * state of the current file (lf) so that we
158  * can do includes.  This is a bit of a hammer.
159  * Instead of passing back the pointer to the
160  * new packet, I simply replace the contents
161  * of the caller's packet with the new packet,
162  * and link the contents of the old packet into
163  * the next field.
164  *
165  */
166 LEX *lex_open_buf(LEX *lf, const char *buffer, LEX_ERROR_HANDLER *scan_error)
167
168 {
169    LEX *nf;
170
171    Dmsg0(400, "Open config buffer\n");
172    nf = (LEX *)malloc(sizeof(LEX));
173    if (lf) {
174       memcpy(nf, lf, sizeof(LEX));
175       memset(lf, 0, sizeof(LEX));
176       lf->next = nf;                  /* if have lf, push it behind new one */
177       lf->options = nf->options;      /* preserve user options */
178       /*
179        * preserve err_type to prevent bacula exiting on 'reload'
180        * if config is invalid. Fixes bug #877
181        */
182       lf->err_type = nf->err_type;
183    } else {
184       lf = nf;                        /* start new packet */
185       memset(lf, 0, sizeof(LEX));
186       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
187    }
188    if (scan_error) {
189       lf->scan_error = scan_error;
190    } else {
191       lex_set_default_error_handler(lf);
192    }
193    lf->fd = NULL;
194    lf->bpipe = NULL;
195    lf->fname = NULL;
196    lf->line = get_memory(5000);
197    pm_strcpy(lf->line, buffer);
198    pm_strcat(lf->line, "");
199    lf->state = lex_none;
200    lf->ch = 0;
201    lf->str = get_memory(5000);
202    return lf;
203 }
204
205 /*
206  * Open a new configuration file. We push the
207  * state of the current file (lf) so that we
208  * can do includes.  This is a bit of a hammer.
209  * Instead of passing back the pointer to the
210  * new packet, I simply replace the contents
211  * of the caller's packet with the new packet,
212  * and link the contents of the old packet into
213  * the next field.
214  *
215  */
216 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
217
218 {
219    LEX *nf;
220    FILE *fd;
221    BPIPE *bpipe = NULL;
222    char *fname = bstrdup(filename);
223
224    if (fname[0] == '|') {
225       if ((bpipe = open_bpipe(fname+1, 0, "rb")) == NULL) {
226          free(fname);
227          return NULL;
228       }
229       fd = bpipe->rfd;
230    } else if ((fd = fopen(fname, "rb")) == NULL) {
231       free(fname);
232       return NULL;
233    }
234    Dmsg1(400, "Open config file: %s\n", fname);
235    nf = (LEX *)malloc(sizeof(LEX));
236    if (lf) {
237       memcpy(nf, lf, sizeof(LEX));
238       memset(lf, 0, sizeof(LEX));
239       lf->next = nf;                  /* if have lf, push it behind new one */
240       lf->options = nf->options;      /* preserve user options */
241       /*
242        * preserve err_type to prevent bacula exiting on 'reload'
243        * if config is invalid. Fixes bug #877
244        */
245       lf->err_type = nf->err_type;
246    } else {
247       lf = nf;                        /* start new packet */
248       memset(lf, 0, sizeof(LEX));
249       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
250    }
251    if (scan_error) {
252       lf->scan_error = scan_error;
253    } else {
254       lex_set_default_error_handler(lf);
255    }
256    lf->fd = fd;
257    lf->bpipe = bpipe;
258    lf->fname = fname;
259    lf->line = get_memory(5000);
260    lf->state = lex_none;
261    lf->ch = L_EOL;
262    lf->str = get_memory(5000);
263    Dmsg1(dbglvl, "Return lex=%x\n", lf);
264    return lf;
265 }
266
267 /*
268  * Get the next character from the input.
269  *  Returns the character or
270  *    L_EOF if end of file
271  *    L_EOL if end of line
272  */
273 int lex_get_char(LEX *lf)
274 {
275    if (lf->ch == L_EOF) {
276       Emsg0(M_ABORT, 0, _("get_char: called after EOF."
277          " You may have a open double quote without the closing double quote.\n"));
278    }
279    if (lf->fd && lf->ch == L_EOL) {
280       if (bfgets(lf->line, lf->fd) == NULL) {
281          lf->ch = L_EOF;
282          if (lf->next) {
283             lex_close_file(lf);
284          }
285          return lf->ch;
286       }
287       lf->line_no++;
288       lf->col_no = 0;
289       Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
290    } else if (lf->ch == L_EOL) {
291       lf->line_no++;
292       lf->col_no++;
293    }
294    lf->ch = (uint8_t)lf->line[lf->col_no];
295    if (lf->fd) {
296       if (lf->ch == 0) {
297          lf->ch = L_EOL;           /* reached end of line, force bfgets */
298       } else {
299          lf->col_no++;
300       }
301    } else {
302       if (lf->ch == 0) {           /* End of buffer, stop scan */
303          lf->ch = L_EOF;
304          if (lf->next) {
305             lex_close_file(lf);
306          }
307          return lf->ch;
308       } else if (lf->ch == '\n') {  /* End of line */
309          Dmsg0(dbglvl, "Found newline return L_EOL\n");
310          lf->ch = L_EOL;
311       } else {
312          lf->col_no++;
313       }
314    }
315    Dmsg3(dbglvl, "lex_get_char: %c %d col=%d\n", lf->ch, lf->ch, lf->col_no);
316    return lf->ch;
317 }
318
319 void lex_unget_char(LEX *lf)
320 {
321    if (lf->ch == L_EOL) {
322       lf->ch = 0;                     /* End of line, force read of next one */
323    } else {
324       lf->col_no--;                   /* Backup to re-read char */
325    }
326 }
327
328
329 /*
330  * Add a character to the current string
331  */
332 static void add_str(LEX *lf, int ch)
333 {
334    if (lf->str_len >= sizeof_pool_memory(lf->str)) {
335       Emsg3(M_ERROR_TERM, 0, _(
336            _("Config token too long, file: %s, line %d, begins at line %d\n")),
337              lf->fname, lf->line_no, lf->begin_line_no);
338    }
339    lf->str[lf->str_len++] = ch;
340    lf->str[lf->str_len] = 0;
341 }
342
343 /*
344  * Begin the string
345  */
346 static void begin_str(LEX *lf, int ch)
347 {
348    lf->str_len = 0;
349    lf->str[0] = 0;
350    if (ch != 0) {
351       add_str(lf, ch);
352    }
353    lf->begin_line_no = lf->line_no;   /* save start string line no */
354 }
355
356 #ifdef DEBUG
357 static const char *lex_state_to_str(int state)
358 {
359    switch (state) {
360    case lex_none:          return _("none");
361    case lex_comment:       return _("comment");
362    case lex_number:        return _("number");
363    case lex_ip_addr:       return _("ip_addr");
364    case lex_identifier:    return _("identifier");
365    case lex_string:        return _("string");
366    case lex_quoted_string: return _("quoted_string");
367    case lex_include:       return _("include");
368    case lex_include_quoted_string: return _("include_quoted_string");
369    case lex_utf8_bom:      return _("UTF-8 Byte Order Mark");
370    case lex_utf16_le_bom:  return _("UTF-16le Byte Order Mark");
371    default:                return "??????";
372    }
373 }
374 #endif
375
376 /*
377  * Convert a lex token to a string
378  * used for debug/error printing.
379  */
380 const char *lex_tok_to_str(int token)
381 {
382    switch(token) {
383    case L_EOF:             return "L_EOF";
384    case L_EOL:             return "L_EOL";
385    case T_NONE:            return "T_NONE";
386    case T_NUMBER:          return "T_NUMBER";
387    case T_IPADDR:          return "T_IPADDR";
388    case T_IDENTIFIER:      return "T_IDENTIFIER";
389    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
390    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
391    case T_BOB:             return "T_BOB";
392    case T_EOB:             return "T_EOB";
393    case T_EQUALS:          return "T_EQUALS";
394    case T_ERROR:           return "T_ERROR";
395    case T_EOF:             return "T_EOF";
396    case T_COMMA:           return "T_COMMA";
397    case T_EOL:             return "T_EOL";
398    case T_UTF8_BOM:        return "T_UTF8_BOM";
399    case T_UTF16_BOM:       return "T_UTF16_BOM";
400    default:                return "??????";
401    }
402 }
403
404 static uint32_t scan_pint(LEX *lf, char *str)
405 {
406    int64_t val = 0;
407    if (!is_a_number(str)) {
408       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
409       /* NOT REACHED */
410    } else {
411       errno = 0;
412       val = str_to_int64(str);
413       if (errno != 0 || val < 0) {
414          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
415          /* NOT REACHED */
416       }
417    }
418    return (uint32_t)val;
419 }
420
421 static uint64_t scan_pint64(LEX *lf, char *str)
422 {
423    uint64_t val = 0;
424    if (!is_a_number(str)) {
425       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
426       /* NOT REACHED */
427    } else {
428       errno = 0;
429       val = str_to_uint64(str);
430       if (errno != 0) {
431          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
432          /* NOT REACHED */
433       }
434    }
435    return val;
436 }
437
438 /*
439  *
440  * Get the next token from the input
441  *
442  */
443 int
444 lex_get_token(LEX *lf, int expect)
445 {
446    int ch;
447    int token = T_NONE;
448    bool esc_next = false;
449    /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
450       to indicate which transmission format the file is in. The codepoint for
451       this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
452       and as FF-FE in UTF-16le(little endian) and  FE-FF in UTF-16(big endian).
453       We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
454       to tell which byte we are expecting. */
455    int bom_bytes_seen = 0;
456
457    Dmsg1(dbglvl, "enter lex_get_token state=%s\n", lex_state_to_str(lf->state));
458    while (token == T_NONE) {
459       ch = lex_get_char(lf);
460       switch (lf->state) {
461       case lex_none:
462          Dmsg2(dbglvl, "Lex state lex_none ch=%c,%d\n", ch, ch);
463          if (B_ISSPACE(ch))
464             break;
465          if (B_ISALPHA(ch)) {
466             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
467                lf->state = lex_string;
468             } else {
469                lf->state = lex_identifier;
470             }
471             begin_str(lf, ch);
472             break;
473          }
474          if (B_ISDIGIT(ch)) {
475             if (lf->options & LOPT_STRING) {
476                lf->state = lex_string;
477             } else {
478                lf->state = lex_number;
479             }
480             begin_str(lf, ch);
481             break;
482          }
483          Dmsg0(dbglvl, "Enter lex_none switch\n");
484          switch (ch) {
485          case L_EOF:
486             token = T_EOF;
487             Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
488             break;
489          case '#':
490             lf->state = lex_comment;
491             break;
492          case '{':
493             token = T_BOB;
494             begin_str(lf, ch);
495             break;
496          case '}':
497             token = T_EOB;
498             begin_str(lf, ch);
499             break;
500          case '"':
501             lf->state = lex_quoted_string;
502             begin_str(lf, 0);
503             break;
504          case '=':
505             token = T_EQUALS;
506             begin_str(lf, ch);
507             break;
508          case ',':
509             token = T_COMMA;
510             begin_str(lf, ch);
511             break;
512          case ';':
513             if (expect != T_SKIP_EOL) {
514                token = T_EOL;      /* treat ; like EOL */
515             }
516             break;
517          case L_EOL:
518             Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
519             if (expect != T_SKIP_EOL) {
520                token = T_EOL;
521             }
522             break;
523          case '@':
524             /* In NO_EXTERN mode, @ is part of a string */
525             if (lf->options & LOPT_NO_EXTERN) {
526                lf->state = lex_string;
527                begin_str(lf, ch);
528             } else {
529                lf->state = lex_include;
530                begin_str(lf, 0);
531             }
532             break;
533          case 0xEF: /* probably a UTF-8 BOM */
534          case 0xFF: /* probably a UTF-16le BOM */
535          case 0xFE: /* probably a UTF-16be BOM (error)*/
536             if (lf->line_no != 1 || lf->col_no != 1)
537             {
538                lf->state = lex_string;
539                begin_str(lf, ch);
540             } else {
541                bom_bytes_seen = 1;
542                if (ch == 0xEF) {
543                   lf->state = lex_utf8_bom;
544                } else if (ch == 0xFF) {
545                   lf->state = lex_utf16_le_bom;
546                } else {
547                   scan_err0(lf, _("This config file appears to be in an "
548                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
549                   return T_ERROR;
550                }
551             }
552             break;
553          default:
554             lf->state = lex_string;
555             begin_str(lf, ch);
556             break;
557          }
558          break;
559       case lex_comment:
560          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
561          if (ch == L_EOL) {
562             lf->state = lex_none;
563             if (expect != T_SKIP_EOL) {
564                token = T_EOL;
565             }
566          } else if (ch == L_EOF) {
567             token = T_ERROR;
568          }
569          break;
570       case lex_number:
571          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
572          if (ch == L_EOF) {
573             token = T_ERROR;
574             break;
575          }
576          /* Might want to allow trailing specifications here */
577          if (B_ISDIGIT(ch)) {
578             add_str(lf, ch);
579             break;
580          }
581
582          /* A valid number can be terminated by the following */
583          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
584             token = T_NUMBER;
585             lf->state = lex_none;
586          } else {
587             lf->state = lex_string;
588          }
589          lex_unget_char(lf);
590          break;
591       case lex_ip_addr:
592          if (ch == L_EOF) {
593             token = T_ERROR;
594             break;
595          }
596          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
597          break;
598       case lex_string:
599          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
600          if (ch == L_EOF) {
601             token = T_ERROR;
602             break;
603          }
604          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
605              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
606             lex_unget_char(lf);
607             token = T_UNQUOTED_STRING;
608             lf->state = lex_none;
609             break;
610          }
611          add_str(lf, ch);
612          break;
613       case lex_identifier:
614          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
615          if (B_ISALPHA(ch)) {
616             add_str(lf, ch);
617             break;
618          } else if (B_ISSPACE(ch)) {
619             break;
620          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
621                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
622             lex_unget_char(lf);
623             token = T_IDENTIFIER;
624             lf->state = lex_none;
625             break;
626          } else if (ch == L_EOF) {
627             token = T_ERROR;
628             lf->state = lex_none;
629             begin_str(lf, ch);
630             break;
631          }
632          /* Some non-alpha character => string */
633          lf->state = lex_string;
634          add_str(lf, ch);
635          break;
636       case lex_quoted_string:
637          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
638          if (ch == L_EOF) {
639             token = T_ERROR;
640             break;
641          }
642          if (ch == L_EOL) {
643             esc_next = false;
644             break;
645          }
646          if (esc_next) {
647             add_str(lf, ch);
648             esc_next = false;
649             break;
650          }
651          if (ch == '\\') {
652             esc_next = true;
653             break;
654          }
655          if (ch == '"') {
656             token = T_QUOTED_STRING;
657             /*
658              * Since we may be scanning a quoted list of names,
659              *  we get the next character (a comma indicates another
660              *  one), then we put it back for rescanning.
661              */
662             lex_get_char(lf);
663             lex_unget_char(lf);
664             lf->state = lex_none;
665             break;
666          }
667          add_str(lf, ch);
668          break;
669       case lex_include_quoted_string:
670          if (ch == L_EOF) {
671             token = T_ERROR;
672             break;
673          }
674          if (esc_next) {
675             add_str(lf, ch);
676             esc_next = false;
677             break;
678          }
679          if (ch == '\\') {
680             esc_next = true;
681             break;
682          }
683          if (ch == '"') {
684             /* Keep the original LEX so we can print an error if the included file can't be opened. */
685             LEX* lfori = lf;
686             /* Skip the double quote when restarting parsing */
687             lex_get_char(lf);
688
689             lf->state = lex_none;
690             lf = lex_open_file(lf, lf->str, lf->scan_error);
691             if (lf == NULL) {
692                berrno be;
693                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
694                   lfori->str, be.bstrerror());
695                return T_ERROR;
696             }
697             break;
698          }
699          add_str(lf, ch);
700          break;
701       case lex_include:            /* scanning a filename */
702          if (ch == L_EOF) {
703             token = T_ERROR;
704             break;
705          }
706          if (ch == '"') {
707             lf->state = lex_include_quoted_string;
708             break;
709          }
710
711
712          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
713              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
714             /* Keep the original LEX so we can print an error if the included file can't be opened. */
715             LEX* lfori = lf;
716
717             lf->state = lex_none;
718             lf = lex_open_file(lf, lf->str, lf->scan_error);
719             if (lf == NULL) {
720                berrno be;
721                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
722                   lfori->str, be.bstrerror());
723                return T_ERROR;
724             }
725             break;
726          }
727          add_str(lf, ch);
728          break;
729       case lex_utf8_bom:
730          /* we only end up in this state if we have read an 0xEF
731             as the first byte of the file, indicating we are probably
732             reading a UTF-8 file */
733          if (ch == 0xBB && bom_bytes_seen == 1) {
734             bom_bytes_seen++;
735          } else if (ch == 0xBF && bom_bytes_seen == 2) {
736             token = T_UTF8_BOM;
737             lf->state = lex_none;
738          } else {
739             token = T_ERROR;
740          }
741          break;
742       case lex_utf16_le_bom:
743          /* we only end up in this state if we have read an 0xFF
744             as the first byte of the file -- indicating that we are
745             probably dealing with an Intel based (little endian) UTF-16 file*/
746          if (ch == 0xFE) {
747             token = T_UTF16_BOM;
748             lf->state = lex_none;
749          } else {
750             token = T_ERROR;
751          }
752          break;
753       }
754       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
755         lex_tok_to_str(token), ch);
756    }
757    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
758    lf->token = token;
759
760    /*
761     * Here is where we check to see if the user has set certain
762     *  expectations (e.g. 32 bit integer). If so, we do type checking
763     *  and possible additional scanning (e.g. for range).
764     */
765    switch (expect) {
766    case T_PINT32:
767       lf->pint32_val = scan_pint(lf, lf->str);
768       lf->pint32_val2 = lf->pint32_val;
769       token = T_PINT32;
770       break;
771
772    case T_PINT32_RANGE:
773       if (token == T_NUMBER) {
774          lf->pint32_val = scan_pint(lf, lf->str);
775          lf->pint32_val2 = lf->pint32_val;
776          token = T_PINT32;
777       } else {
778          char *p = strchr(lf->str, '-');
779          if (!p) {
780             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
781                lex_tok_to_str(token), lf->str);
782             token = T_ERROR;
783             break;
784          }
785          *p++ = 0;                       /* terminate first half of range */
786          lf->pint32_val  = scan_pint(lf, lf->str);
787          lf->pint32_val2 = scan_pint(lf, p);
788          token = T_PINT32_RANGE;
789       }
790       break;
791
792    case T_INT32:
793       if (token != T_NUMBER || !is_a_number(lf->str)) {
794          scan_err2(lf, _("expected an integer number, got %s: %s"),
795                lex_tok_to_str(token), lf->str);
796          token = T_ERROR;
797          break;
798       }
799       errno = 0;
800       lf->int32_val = (int32_t)str_to_int64(lf->str);
801       if (errno != 0) {
802          scan_err2(lf, _("expected an integer number, got %s: %s"),
803                lex_tok_to_str(token), lf->str);
804          token = T_ERROR;
805       } else {
806          token = T_INT32;
807       }
808       break;
809
810    case T_INT64:
811       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
812       if (token != T_NUMBER || !is_a_number(lf->str)) {
813          scan_err2(lf, _("expected an integer number, got %s: %s"),
814                lex_tok_to_str(token), lf->str);
815          token = T_ERROR;
816          break;
817       }
818       errno = 0;
819       lf->int64_val = str_to_int64(lf->str);
820       if (errno != 0) {
821          scan_err2(lf, _("expected an integer number, got %s: %s"),
822                lex_tok_to_str(token), lf->str);
823          token = T_ERROR;
824       } else {
825          token = T_INT64;
826       }
827       break;
828
829    case T_PINT64_RANGE:
830       if (token == T_NUMBER) {
831          lf->pint64_val = scan_pint64(lf, lf->str);
832          lf->pint64_val2 = lf->pint64_val;
833          token = T_PINT64;
834       } else {
835          char *p = strchr(lf->str, '-');
836          if (!p) {
837             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
838                lex_tok_to_str(token), lf->str);
839             token = T_ERROR;
840             break;
841          }
842          *p++ = 0;                       /* terminate first half of range */
843          lf->pint64_val  = scan_pint64(lf, lf->str);
844          lf->pint64_val2 = scan_pint64(lf, p);
845          token = T_PINT64_RANGE;
846       }
847       break;
848
849    case T_NAME:
850       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
851          scan_err2(lf, _("expected a name, got %s: %s"),
852                lex_tok_to_str(token), lf->str);
853          token = T_ERROR;
854       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
855          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
856             lf->str_len, MAX_RES_NAME_LENGTH);
857          token = T_ERROR;
858       }
859       break;
860
861    case T_STRING:
862       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
863          scan_err2(lf, _("expected a string, got %s: %s"),
864                lex_tok_to_str(token), lf->str);
865          token = T_ERROR;
866       } else {
867          token = T_STRING;
868       }
869       break;
870
871
872    default:
873       break;                          /* no expectation given */
874    }
875    lf->token = token;                 /* set possible new token */
876    return token;
877 }