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