]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
update version
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2011 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             lf->state = lex_include;
456             begin_str(lf, 0);
457             break;
458          case 0xEF: /* probably a UTF-8 BOM */
459          case 0xFF: /* probably a UTF-16le BOM */
460          case 0xFE: /* probably a UTF-16be BOM (error)*/
461             if (lf->line_no != 1 || lf->col_no != 1)
462             {
463                lf->state = lex_string;
464                begin_str(lf, ch);
465             } else {
466                bom_bytes_seen = 1;
467                if (ch == 0xEF) {
468                   lf->state = lex_utf8_bom;
469                } else if (ch == 0xFF) {
470                   lf->state = lex_utf16_le_bom;
471                } else {
472                   scan_err0(lf, _("This config file appears to be in an "
473                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
474                   return T_ERROR;
475                }
476             }
477             break;
478          default:
479             lf->state = lex_string;
480             begin_str(lf, ch);
481             break;
482          }
483          break;
484       case lex_comment:
485          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
486          if (ch == L_EOL) {
487             lf->state = lex_none;
488             if (expect != T_SKIP_EOL) {
489                token = T_EOL;
490             }
491          } else if (ch == L_EOF) {
492             token = T_ERROR;
493          }
494          break;
495       case lex_number:
496          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
497          if (ch == L_EOF) {
498             token = T_ERROR;
499             break;
500          }
501          /* Might want to allow trailing specifications here */
502          if (B_ISDIGIT(ch)) {
503             add_str(lf, ch);
504             break;
505          }
506
507          /* A valid number can be terminated by the following */
508          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
509             token = T_NUMBER;
510             lf->state = lex_none;
511          } else {
512             lf->state = lex_string;
513          }
514          lex_unget_char(lf);
515          break;
516       case lex_ip_addr:
517          if (ch == L_EOF) {
518             token = T_ERROR;
519             break;
520          }
521          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
522          break;
523       case lex_string:
524          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
525          if (ch == L_EOF) {
526             token = T_ERROR;
527             break;
528          }
529          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
530              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
531             lex_unget_char(lf);
532             token = T_UNQUOTED_STRING;
533             lf->state = lex_none;
534             break;
535          }
536          add_str(lf, ch);
537          break;
538       case lex_identifier:
539          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
540          if (B_ISALPHA(ch)) {
541             add_str(lf, ch);
542             break;
543          } else if (B_ISSPACE(ch)) {
544             break;
545          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
546                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
547             lex_unget_char(lf);
548             token = T_IDENTIFIER;
549             lf->state = lex_none;
550             break;
551          } else if (ch == L_EOF) {
552             token = T_ERROR;
553             lf->state = lex_none;
554             begin_str(lf, ch);
555             break;
556          }
557          /* Some non-alpha character => string */
558          lf->state = lex_string;
559          add_str(lf, ch);
560          break;
561       case lex_quoted_string:
562          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
563          if (ch == L_EOF) {
564             token = T_ERROR;
565             break;
566          }
567          if (ch == L_EOL) {
568             esc_next = false;
569             break;
570          }
571          if (esc_next) {
572             add_str(lf, ch);
573             esc_next = false;
574             break;
575          }
576          if (ch == '\\') {
577             esc_next = true;
578             break;
579          }
580          if (ch == '"') {
581             token = T_QUOTED_STRING;
582             lf->state = lex_none;
583             break;
584          }
585          add_str(lf, ch);
586          break;
587       case lex_include_quoted_string:
588          if (ch == L_EOF) {
589             token = T_ERROR;
590             break;
591          }
592          if (esc_next) {
593             add_str(lf, ch);
594             esc_next = false;
595             break;
596          }
597          if (ch == '\\') {
598             esc_next = true;
599             break;
600          }
601          if (ch == '"') {
602             /* Keep the original LEX so we can print an error if the included file can't be opened. */
603             LEX* lfori = lf;
604             /* Skip the double quote when restarting parsing */
605             lex_get_char(lf);
606
607             lf->state = lex_none;
608             lf = lex_open_file(lf, lf->str, lf->scan_error);
609             if (lf == NULL) {
610                berrno be;
611                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
612                   lfori->str, be.bstrerror());
613                return T_ERROR;
614             }
615             break;
616          }
617          add_str(lf, ch);
618          break;
619       case lex_include:            /* scanning a filename */
620          if (ch == L_EOF) {
621             token = T_ERROR;
622             break;
623          }
624          if (ch == '"') {
625             lf->state = lex_include_quoted_string;
626             break;
627          }
628
629
630          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
631              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
632             /* Keep the original LEX so we can print an error if the included file can't be opened. */
633             LEX* lfori = lf;
634
635             lf->state = lex_none;
636             lf = lex_open_file(lf, lf->str, lf->scan_error);
637             if (lf == NULL) {
638                berrno be;
639                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
640                   lfori->str, be.bstrerror());
641                return T_ERROR;
642             }
643             break;
644          }
645          add_str(lf, ch);
646          break;
647       case lex_utf8_bom:
648          /* we only end up in this state if we have read an 0xEF 
649             as the first byte of the file, indicating we are probably
650             reading a UTF-8 file */
651          if (ch == 0xBB && bom_bytes_seen == 1) {
652             bom_bytes_seen++;
653          } else if (ch == 0xBF && bom_bytes_seen == 2) {
654             token = T_UTF8_BOM;
655             lf->state = lex_none;
656          } else {
657             token = T_ERROR;
658          }
659          break;
660       case lex_utf16_le_bom:
661          /* we only end up in this state if we have read an 0xFF 
662             as the first byte of the file -- indicating that we are
663             probably dealing with an Intel based (little endian) UTF-16 file*/
664          if (ch == 0xFE) {
665             token = T_UTF16_BOM;
666             lf->state = lex_none;
667          } else {
668             token = T_ERROR;
669          }
670          break;
671       }
672       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
673         lex_tok_to_str(token), ch);
674    }
675    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
676    lf->token = token;
677
678    /*
679     * Here is where we check to see if the user has set certain
680     *  expectations (e.g. 32 bit integer). If so, we do type checking
681     *  and possible additional scanning (e.g. for range).
682     */
683    switch (expect) {
684    case T_PINT32:
685       lf->pint32_val = scan_pint(lf, lf->str);
686       lf->pint32_val2 = lf->pint32_val;
687       token = T_PINT32;
688       break;
689
690    case T_PINT32_RANGE:
691       if (token == T_NUMBER) {
692          lf->pint32_val = scan_pint(lf, lf->str);
693          lf->pint32_val2 = lf->pint32_val;
694          token = T_PINT32;
695       } else {
696          char *p = strchr(lf->str, '-');
697          if (!p) {
698             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
699                lex_tok_to_str(token), lf->str);
700             token = T_ERROR;
701             break;
702          }
703          *p++ = 0;                       /* terminate first half of range */
704          lf->pint32_val  = scan_pint(lf, lf->str);
705          lf->pint32_val2 = scan_pint(lf, p);
706          token = T_PINT32_RANGE;
707       }
708       break;
709
710    case T_INT32:
711       if (token != T_NUMBER || !is_a_number(lf->str)) {
712          scan_err2(lf, _("expected an integer number, got %s: %s"),
713                lex_tok_to_str(token), lf->str);
714          token = T_ERROR;
715          break;
716       }
717       errno = 0;
718       lf->int32_val = (int32_t)str_to_int64(lf->str);
719       if (errno != 0) {
720          scan_err2(lf, _("expected an integer number, got %s: %s"),
721                lex_tok_to_str(token), lf->str);
722          token = T_ERROR;
723       } else {
724          token = T_INT32;
725       }
726       break;
727
728    case T_INT64:
729       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
730       if (token != T_NUMBER || !is_a_number(lf->str)) {
731          scan_err2(lf, _("expected an integer number, got %s: %s"),
732                lex_tok_to_str(token), lf->str);
733          token = T_ERROR;
734          break;
735       }
736       errno = 0;
737       lf->int64_val = str_to_int64(lf->str);
738       if (errno != 0) {
739          scan_err2(lf, _("expected an integer number, got %s: %s"),
740                lex_tok_to_str(token), lf->str);
741          token = T_ERROR;
742       } else {
743          token = T_INT64;
744       }
745       break;
746
747    case T_PINT64_RANGE:
748       if (token == T_NUMBER) {
749          lf->pint64_val = scan_pint64(lf, lf->str);
750          lf->pint64_val2 = lf->pint64_val;
751          token = T_PINT64;
752       } else {
753          char *p = strchr(lf->str, '-');
754          if (!p) {
755             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
756                lex_tok_to_str(token), lf->str);
757             token = T_ERROR;
758             break;
759          }
760          *p++ = 0;                       /* terminate first half of range */
761          lf->pint64_val  = scan_pint64(lf, lf->str);
762          lf->pint64_val2 = scan_pint64(lf, p);
763          token = T_PINT64_RANGE;
764       }
765       break;
766
767    case T_NAME:
768       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
769          scan_err2(lf, _("expected a name, got %s: %s"),
770                lex_tok_to_str(token), lf->str);
771          token = T_ERROR;
772       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
773          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
774             lf->str_len, MAX_RES_NAME_LENGTH);
775          token = T_ERROR;
776       }
777       break;
778
779    case T_STRING:
780       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
781          scan_err2(lf, _("expected a string, got %s: %s"),
782                lex_tok_to_str(token), lf->str);
783          token = T_ERROR;
784       } else {
785          token = T_STRING;
786       }
787       break;
788
789
790    default:
791       break;                          /* no expectation given */
792    }
793    lf->token = token;                 /* set possible new token */
794    return token;
795 }