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