]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
Make bfgets handle very long lines
[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 /*
263  * Add a character to the current string
264  */
265 static void add_str(LEX *lf, int ch)
266 {
267    if (lf->str_len >= MAXSTRING-3) {
268       Emsg3(M_ERROR_TERM, 0, _(
269            _("Config token too long, file: %s, line %d, begins at line %d\n")),
270              lf->fname, lf->line_no, lf->begin_line_no);
271    }
272    lf->str[lf->str_len++] = ch;
273    lf->str[lf->str_len] = 0;
274 }
275
276 /*
277  * Begin the string
278  */
279 static void begin_str(LEX *lf, int ch)
280 {
281    lf->str_len = 0;
282    lf->str[0] = 0;
283    if (ch != 0) {
284       add_str(lf, ch);
285    }
286    lf->begin_line_no = lf->line_no;   /* save start string line no */
287 }
288
289 #ifdef DEBUG
290 static const char *lex_state_to_str(int state)
291 {
292    switch (state) {
293    case lex_none:          return _("none");
294    case lex_comment:       return _("comment");
295    case lex_number:        return _("number");
296    case lex_ip_addr:       return _("ip_addr");
297    case lex_identifier:    return _("identifier");
298    case lex_string:        return _("string");
299    case lex_quoted_string: return _("quoted_string");
300    case lex_include:       return _("include");
301    case lex_include_quoted_string: return _("include_quoted_string");
302    case lex_utf8_bom:      return _("UTF-8 Byte Order Mark");
303    case lex_utf16_le_bom:  return _("UTF-16le Byte Order Mark");
304    default:                return "??????";
305    }
306 }
307 #endif
308
309 /*
310  * Convert a lex token to a string
311  * used for debug/error printing.
312  */
313 const char *lex_tok_to_str(int token)
314 {
315    switch(token) {
316    case L_EOF:             return "L_EOF";
317    case L_EOL:             return "L_EOL";
318    case T_NONE:            return "T_NONE";
319    case T_NUMBER:          return "T_NUMBER";
320    case T_IPADDR:          return "T_IPADDR";
321    case T_IDENTIFIER:      return "T_IDENTIFIER";
322    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
323    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
324    case T_BOB:             return "T_BOB";
325    case T_EOB:             return "T_EOB";
326    case T_EQUALS:          return "T_EQUALS";
327    case T_ERROR:           return "T_ERROR";
328    case T_EOF:             return "T_EOF";
329    case T_COMMA:           return "T_COMMA";
330    case T_EOL:             return "T_EOL";
331    case T_UTF8_BOM:        return "T_UTF8_BOM";
332    case T_UTF16_BOM:       return "T_UTF16_BOM";
333    default:                return "??????";
334    }
335 }
336
337 static uint32_t scan_pint(LEX *lf, char *str)
338 {
339    int64_t val = 0;
340    if (!is_a_number(str)) {
341       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
342       /* NOT REACHED */
343    } else {
344       errno = 0;
345       val = str_to_int64(str);
346       if (errno != 0 || val < 0) {
347          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
348          /* NOT REACHED */
349       }
350    }
351    return (uint32_t)val;
352 }
353
354 static uint64_t scan_pint64(LEX *lf, char *str)
355 {
356    uint64_t val = 0;
357    if (!is_a_number(str)) {
358       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
359       /* NOT REACHED */
360    } else {
361       errno = 0;
362       val = str_to_uint64(str);
363       if (errno != 0) {
364          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
365          /* NOT REACHED */
366       }
367    }
368    return val;
369 }
370
371 /*
372  *
373  * Get the next token from the input
374  *
375  */
376 int
377 lex_get_token(LEX *lf, int expect)
378 {
379    int ch;
380    int token = T_NONE;
381    bool esc_next = false;
382    /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
383       to indicate which transmission format the file is in. The codepoint for
384       this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
385       and as FF-FE in UTF-16le(little endian) and  FE-FF in UTF-16(big endian).
386       We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
387       to tell which byte we are expecting. */
388    int bom_bytes_seen = 0;
389
390    Dmsg0(dbglvl, "enter lex_get_token\n");
391    while (token == T_NONE) {
392       ch = lex_get_char(lf);
393       switch (lf->state) {
394       case lex_none:
395          Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
396          if (B_ISSPACE(ch))
397             break;
398          if (B_ISALPHA(ch)) {
399             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
400                lf->state = lex_string;
401             } else {
402                lf->state = lex_identifier;
403             }
404             begin_str(lf, ch);
405             break;
406          }
407          if (B_ISDIGIT(ch)) {
408             if (lf->options & LOPT_STRING) {
409                lf->state = lex_string;
410             } else {
411                lf->state = lex_number;
412             }
413             begin_str(lf, ch);
414             break;
415          }
416          Dmsg0(dbglvl, "Enter lex_none switch\n");
417          switch (ch) {
418          case L_EOF:
419             token = T_EOF;
420             Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
421             break;
422          case '#':
423             lf->state = lex_comment;
424             break;
425          case '{':
426             token = T_BOB;
427             begin_str(lf, ch);
428             break;
429          case '}':
430             token = T_EOB;
431             begin_str(lf, ch);
432             break;
433          case '"':
434             lf->state = lex_quoted_string;
435             begin_str(lf, 0);
436             break;
437          case '=':
438             token = T_EQUALS;
439             begin_str(lf, ch);
440             break;
441          case ',':
442             token = T_COMMA;
443             begin_str(lf, ch);
444             break;
445          case ';':
446             if (expect != T_SKIP_EOL) {
447                token = T_EOL;      /* treat ; like EOL */
448             }
449             break;
450          case L_EOL:
451             Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
452             if (expect != T_SKIP_EOL) {
453                token = T_EOL;
454             }
455             break;
456          case '@':
457             /* In NO_EXTERN mode, @ is part of a string */
458             if (lf->options & LOPT_NO_EXTERN) {
459                lf->state = lex_string;
460                begin_str(lf, ch);
461             } else {
462                lf->state = lex_include;
463                begin_str(lf, 0);
464             }
465             break;
466          case 0xEF: /* probably a UTF-8 BOM */
467          case 0xFF: /* probably a UTF-16le BOM */
468          case 0xFE: /* probably a UTF-16be BOM (error)*/
469             if (lf->line_no != 1 || lf->col_no != 1)
470             {
471                lf->state = lex_string;
472                begin_str(lf, ch);
473             } else {
474                bom_bytes_seen = 1;
475                if (ch == 0xEF) {
476                   lf->state = lex_utf8_bom;
477                } else if (ch == 0xFF) {
478                   lf->state = lex_utf16_le_bom;
479                } else {
480                   scan_err0(lf, _("This config file appears to be in an "
481                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
482                   return T_ERROR;
483                }
484             }
485             break;
486          default:
487             lf->state = lex_string;
488             begin_str(lf, ch);
489             break;
490          }
491          break;
492       case lex_comment:
493          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
494          if (ch == L_EOL) {
495             lf->state = lex_none;
496             if (expect != T_SKIP_EOL) {
497                token = T_EOL;
498             }
499          } else if (ch == L_EOF) {
500             token = T_ERROR;
501          }
502          break;
503       case lex_number:
504          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
505          if (ch == L_EOF) {
506             token = T_ERROR;
507             break;
508          }
509          /* Might want to allow trailing specifications here */
510          if (B_ISDIGIT(ch)) {
511             add_str(lf, ch);
512             break;
513          }
514
515          /* A valid number can be terminated by the following */
516          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
517             token = T_NUMBER;
518             lf->state = lex_none;
519          } else {
520             lf->state = lex_string;
521          }
522          lex_unget_char(lf);
523          break;
524       case lex_ip_addr:
525          if (ch == L_EOF) {
526             token = T_ERROR;
527             break;
528          }
529          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
530          break;
531       case lex_string:
532          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
533          if (ch == L_EOF) {
534             token = T_ERROR;
535             break;
536          }
537          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
538              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
539             lex_unget_char(lf);
540             token = T_UNQUOTED_STRING;
541             lf->state = lex_none;
542             break;
543          }
544          add_str(lf, ch);
545          break;
546       case lex_identifier:
547          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
548          if (B_ISALPHA(ch)) {
549             add_str(lf, ch);
550             break;
551          } else if (B_ISSPACE(ch)) {
552             break;
553          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
554                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
555             lex_unget_char(lf);
556             token = T_IDENTIFIER;
557             lf->state = lex_none;
558             break;
559          } else if (ch == L_EOF) {
560             token = T_ERROR;
561             lf->state = lex_none;
562             begin_str(lf, ch);
563             break;
564          }
565          /* Some non-alpha character => string */
566          lf->state = lex_string;
567          add_str(lf, ch);
568          break;
569       case lex_quoted_string:
570          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
571          if (ch == L_EOF) {
572             token = T_ERROR;
573             break;
574          }
575          if (ch == L_EOL) {
576             esc_next = false;
577             break;
578          }
579          if (esc_next) {
580             add_str(lf, ch);
581             esc_next = false;
582             break;
583          }
584          if (ch == '\\') {
585             esc_next = true;
586             break;
587          }
588          if (ch == '"') {
589             token = T_QUOTED_STRING;
590             lf->state = lex_none;
591             break;
592          }
593          add_str(lf, ch);
594          break;
595       case lex_include_quoted_string:
596          if (ch == L_EOF) {
597             token = T_ERROR;
598             break;
599          }
600          if (esc_next) {
601             add_str(lf, ch);
602             esc_next = false;
603             break;
604          }
605          if (ch == '\\') {
606             esc_next = true;
607             break;
608          }
609          if (ch == '"') {
610             /* Keep the original LEX so we can print an error if the included file can't be opened. */
611             LEX* lfori = lf;
612             /* Skip the double quote when restarting parsing */
613             lex_get_char(lf);
614
615             lf->state = lex_none;
616             lf = lex_open_file(lf, lf->str, lf->scan_error);
617             if (lf == NULL) {
618                berrno be;
619                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
620                   lfori->str, be.bstrerror());
621                return T_ERROR;
622             }
623             break;
624          }
625          add_str(lf, ch);
626          break;
627       case lex_include:            /* scanning a filename */
628          if (ch == L_EOF) {
629             token = T_ERROR;
630             break;
631          }
632          if (ch == '"') {
633             lf->state = lex_include_quoted_string;
634             break;
635          }
636
637
638          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
639              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
640             /* Keep the original LEX so we can print an error if the included file can't be opened. */
641             LEX* lfori = lf;
642
643             lf->state = lex_none;
644             lf = lex_open_file(lf, lf->str, lf->scan_error);
645             if (lf == NULL) {
646                berrno be;
647                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
648                   lfori->str, be.bstrerror());
649                return T_ERROR;
650             }
651             break;
652          }
653          add_str(lf, ch);
654          break;
655       case lex_utf8_bom:
656          /* we only end up in this state if we have read an 0xEF 
657             as the first byte of the file, indicating we are probably
658             reading a UTF-8 file */
659          if (ch == 0xBB && bom_bytes_seen == 1) {
660             bom_bytes_seen++;
661          } else if (ch == 0xBF && bom_bytes_seen == 2) {
662             token = T_UTF8_BOM;
663             lf->state = lex_none;
664          } else {
665             token = T_ERROR;
666          }
667          break;
668       case lex_utf16_le_bom:
669          /* we only end up in this state if we have read an 0xFF 
670             as the first byte of the file -- indicating that we are
671             probably dealing with an Intel based (little endian) UTF-16 file*/
672          if (ch == 0xFE) {
673             token = T_UTF16_BOM;
674             lf->state = lex_none;
675          } else {
676             token = T_ERROR;
677          }
678          break;
679       }
680       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
681         lex_tok_to_str(token), ch);
682    }
683    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
684    lf->token = token;
685
686    /*
687     * Here is where we check to see if the user has set certain
688     *  expectations (e.g. 32 bit integer). If so, we do type checking
689     *  and possible additional scanning (e.g. for range).
690     */
691    switch (expect) {
692    case T_PINT32:
693       lf->pint32_val = scan_pint(lf, lf->str);
694       lf->pint32_val2 = lf->pint32_val;
695       token = T_PINT32;
696       break;
697
698    case T_PINT32_RANGE:
699       if (token == T_NUMBER) {
700          lf->pint32_val = scan_pint(lf, lf->str);
701          lf->pint32_val2 = lf->pint32_val;
702          token = T_PINT32;
703       } else {
704          char *p = strchr(lf->str, '-');
705          if (!p) {
706             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
707                lex_tok_to_str(token), lf->str);
708             token = T_ERROR;
709             break;
710          }
711          *p++ = 0;                       /* terminate first half of range */
712          lf->pint32_val  = scan_pint(lf, lf->str);
713          lf->pint32_val2 = scan_pint(lf, p);
714          token = T_PINT32_RANGE;
715       }
716       break;
717
718    case T_INT32:
719       if (token != T_NUMBER || !is_a_number(lf->str)) {
720          scan_err2(lf, _("expected an integer number, got %s: %s"),
721                lex_tok_to_str(token), lf->str);
722          token = T_ERROR;
723          break;
724       }
725       errno = 0;
726       lf->int32_val = (int32_t)str_to_int64(lf->str);
727       if (errno != 0) {
728          scan_err2(lf, _("expected an integer number, got %s: %s"),
729                lex_tok_to_str(token), lf->str);
730          token = T_ERROR;
731       } else {
732          token = T_INT32;
733       }
734       break;
735
736    case T_INT64:
737       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
738       if (token != T_NUMBER || !is_a_number(lf->str)) {
739          scan_err2(lf, _("expected an integer number, got %s: %s"),
740                lex_tok_to_str(token), lf->str);
741          token = T_ERROR;
742          break;
743       }
744       errno = 0;
745       lf->int64_val = str_to_int64(lf->str);
746       if (errno != 0) {
747          scan_err2(lf, _("expected an integer number, got %s: %s"),
748                lex_tok_to_str(token), lf->str);
749          token = T_ERROR;
750       } else {
751          token = T_INT64;
752       }
753       break;
754
755    case T_PINT64_RANGE:
756       if (token == T_NUMBER) {
757          lf->pint64_val = scan_pint64(lf, lf->str);
758          lf->pint64_val2 = lf->pint64_val;
759          token = T_PINT64;
760       } else {
761          char *p = strchr(lf->str, '-');
762          if (!p) {
763             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
764                lex_tok_to_str(token), lf->str);
765             token = T_ERROR;
766             break;
767          }
768          *p++ = 0;                       /* terminate first half of range */
769          lf->pint64_val  = scan_pint64(lf, lf->str);
770          lf->pint64_val2 = scan_pint64(lf, p);
771          token = T_PINT64_RANGE;
772       }
773       break;
774
775    case T_NAME:
776       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
777          scan_err2(lf, _("expected a name, got %s: %s"),
778                lex_tok_to_str(token), lf->str);
779          token = T_ERROR;
780       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
781          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
782             lf->str_len, MAX_RES_NAME_LENGTH);
783          token = T_ERROR;
784       }
785       break;
786
787    case T_STRING:
788       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
789          scan_err2(lf, _("expected a string, got %s: %s"),
790                lex_tok_to_str(token), lf->str);
791          token = T_ERROR;
792       } else {
793          token = T_STRING;
794       }
795       break;
796
797
798    default:
799       break;                          /* no expectation given */
800    }
801    lf->token = token;                 /* set possible new token */
802    return token;
803 }