]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
Switch from GPLv2 to AGPLv3
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "lex.h"
39
40 extern int debug_level;
41
42 /* Debug level for this source file */
43 static const int dbglvl = 5000;
44
45 /*
46  * Scan to "logical" end of line. I.e. end of line,
47  *   or semicolon, but stop on T_EOB (same as end of
48  *   line except it is not eaten).
49  */
50 void scan_to_eol(LEX *lc)
51 {
52    int token;
53    Dmsg0(dbglvl, "start scan to eof\n");
54    while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
55       if (token == T_EOB) {
56          lex_unget_char(lc);
57          return;
58       }
59    }
60 }
61
62 /*
63  * Get next token, but skip EOL
64  */
65 int scan_to_next_not_eol(LEX * lc)
66 {
67    int token;
68    do {
69       token = lex_get_token(lc, T_ALL);
70    } while (token == T_EOL);
71    return token;
72 }
73
74 /*
75  * Format a scanner error message
76  */
77 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
78 {
79    va_list arg_ptr;
80    char buf[MAXSTRING];
81    char more[MAXSTRING];
82
83    va_start(arg_ptr, msg);
84    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
85    va_end(arg_ptr);
86
87    if (lc->err_type == 0) {     /* M_ERROR_TERM by default */
88       lc->err_type = M_ERROR_TERM;
89    }
90
91    if (lc->line_no > lc->begin_line_no) {
92       bsnprintf(more, sizeof(more),
93                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
94    } else {
95       more[0] = 0;
96    }  
97    if (lc->line_no > 0) {
98       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
99 "            : line %d, col %d of file %s\n%s\n%s"),
100          buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
101    } else {
102       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
103    }
104 }
105
106 void lex_set_default_error_handler(LEX *lf)
107 {
108    lf->scan_error = s_err;
109 }
110
111 /*
112  * Set err_type used in error_handler
113  * return the old value
114  */
115 int lex_set_error_handler_error_type(LEX *lf, int err_type)
116 {
117    int old = lf->err_type;
118    lf->err_type = err_type;
119    return old;
120 }
121
122 /*
123  * Free the current file, and retrieve the contents
124  * of the previous packet if any.
125  */
126 LEX *lex_close_file(LEX *lf)
127 {
128    LEX *of;
129
130    if (lf == NULL) {
131       Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
132    }
133    Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
134
135    of = lf->next;
136    if (lf->bpipe) {
137       close_bpipe(lf->bpipe);
138       lf->bpipe = NULL;
139    } else {
140       fclose(lf->fd);
141    }
142    Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
143    free(lf->fname);
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
176    if (fname[0] == '|') {
177       if ((bpipe = open_bpipe(fname+1, 0, "rb")) == NULL) {
178          free(fname);
179          return NULL;
180       }
181       fd = bpipe->rfd;
182    } else if ((fd = fopen(fname, "rb")) == NULL) {
183       free(fname);
184       return NULL;
185    }
186    Dmsg1(400, "Open config file: %s\n", fname);
187    nf = (LEX *)malloc(sizeof(LEX));
188    if (lf) {
189       memcpy(nf, lf, sizeof(LEX));
190       memset(lf, 0, sizeof(LEX));
191       lf->next = nf;                  /* if have lf, push it behind new one */
192       lf->options = nf->options;      /* preserve user options */
193       /*
194        * preserve err_type to prevent bacula exiting on 'reload' 
195        * if config is invalid. Fixes bug #877         
196        */
197       lf->err_type = nf->err_type;    
198    } else {
199       lf = nf;                        /* start new packet */
200       memset(lf, 0, sizeof(LEX));
201       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
202    }
203    if (scan_error) {
204       lf->scan_error = scan_error;
205    } else {
206       lex_set_default_error_handler(lf);
207    }
208    lf->fd = fd;
209    lf->bpipe = bpipe;
210    lf->fname = fname;
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, MAXSTRING, 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             lf->state = lex_include;
458             begin_str(lf, 0);
459             break;
460          case 0xEF: /* probably a UTF-8 BOM */
461          case 0xFF: /* probably a UTF-16le BOM */
462          case 0xFE: /* probably a UTF-16be BOM (error)*/
463             if (lf->line_no != 1 || lf->col_no != 1)
464             {
465                lf->state = lex_string;
466                begin_str(lf, ch);
467             } else {
468                bom_bytes_seen = 1;
469                if (ch == 0xEF) {
470                   lf->state = lex_utf8_bom;
471                } else if (ch == 0xFF) {
472                   lf->state = lex_utf16_le_bom;
473                } else {
474                   scan_err0(lf, _("This config file appears to be in an "
475                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
476                   return T_ERROR;
477                }
478             }
479             break;
480          default:
481             lf->state = lex_string;
482             begin_str(lf, ch);
483             break;
484          }
485          break;
486       case lex_comment:
487          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
488          if (ch == L_EOL) {
489             lf->state = lex_none;
490             if (expect != T_SKIP_EOL) {
491                token = T_EOL;
492             }
493          } else if (ch == L_EOF) {
494             token = T_ERROR;
495          }
496          break;
497       case lex_number:
498          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
499          if (ch == L_EOF) {
500             token = T_ERROR;
501             break;
502          }
503          /* Might want to allow trailing specifications here */
504          if (B_ISDIGIT(ch)) {
505             add_str(lf, ch);
506             break;
507          }
508
509          /* A valid number can be terminated by the following */
510          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
511             token = T_NUMBER;
512             lf->state = lex_none;
513          } else {
514             lf->state = lex_string;
515          }
516          lex_unget_char(lf);
517          break;
518       case lex_ip_addr:
519          if (ch == L_EOF) {
520             token = T_ERROR;
521             break;
522          }
523          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
524          break;
525       case lex_string:
526          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
527          if (ch == L_EOF) {
528             token = T_ERROR;
529             break;
530          }
531          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
532              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
533             lex_unget_char(lf);
534             token = T_UNQUOTED_STRING;
535             lf->state = lex_none;
536             break;
537          }
538          add_str(lf, ch);
539          break;
540       case lex_identifier:
541          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
542          if (B_ISALPHA(ch)) {
543             add_str(lf, ch);
544             break;
545          } else if (B_ISSPACE(ch)) {
546             break;
547          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
548                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
549             lex_unget_char(lf);
550             token = T_IDENTIFIER;
551             lf->state = lex_none;
552             break;
553          } else if (ch == L_EOF) {
554             token = T_ERROR;
555             lf->state = lex_none;
556             begin_str(lf, ch);
557             break;
558          }
559          /* Some non-alpha character => string */
560          lf->state = lex_string;
561          add_str(lf, ch);
562          break;
563       case lex_quoted_string:
564          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
565          if (ch == L_EOF) {
566             token = T_ERROR;
567             break;
568          }
569          if (ch == L_EOL) {
570             esc_next = false;
571             break;
572          }
573          if (esc_next) {
574             add_str(lf, ch);
575             esc_next = false;
576             break;
577          }
578          if (ch == '\\') {
579             esc_next = true;
580             break;
581          }
582          if (ch == '"') {
583             token = T_QUOTED_STRING;
584             lf->state = lex_none;
585             break;
586          }
587          add_str(lf, ch);
588          break;
589       case lex_include_quoted_string:
590          if (ch == L_EOF) {
591             token = T_ERROR;
592             break;
593          }
594          if (esc_next) {
595             add_str(lf, ch);
596             esc_next = false;
597             break;
598          }
599          if (ch == '\\') {
600             esc_next = true;
601             break;
602          }
603          if (ch == '"') {
604             /* Keep the original LEX so we can print an error if the included file can't be opened. */
605             LEX* lfori = lf;
606             /* Skip the double quote when restarting parsing */
607             lex_get_char(lf);
608
609             lf->state = lex_none;
610             lf = lex_open_file(lf, lf->str, lf->scan_error);
611             if (lf == NULL) {
612                berrno be;
613                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
614                   lfori->str, be.bstrerror());
615                return T_ERROR;
616             }
617             break;
618          }
619          add_str(lf, ch);
620          break;
621       case lex_include:            /* scanning a filename */
622          if (ch == L_EOF) {
623             token = T_ERROR;
624             break;
625          }
626          if (ch == '"') {
627             lf->state = lex_include_quoted_string;
628             break;
629          }
630
631
632          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
633              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
634             /* Keep the original LEX so we can print an error if the included file can't be opened. */
635             LEX* lfori = lf;
636
637             lf->state = lex_none;
638             lf = lex_open_file(lf, lf->str, lf->scan_error);
639             if (lf == NULL) {
640                berrno be;
641                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
642                   lfori->str, be.bstrerror());
643                return T_ERROR;
644             }
645             break;
646          }
647          add_str(lf, ch);
648          break;
649       case lex_utf8_bom:
650          /* we only end up in this state if we have read an 0xEF 
651             as the first byte of the file, indicating we are probably
652             reading a UTF-8 file */
653          if (ch == 0xBB && bom_bytes_seen == 1) {
654             bom_bytes_seen++;
655          } else if (ch == 0xBF && bom_bytes_seen == 2) {
656             token = T_UTF8_BOM;
657             lf->state = lex_none;
658          } else {
659             token = T_ERROR;
660          }
661          break;
662       case lex_utf16_le_bom:
663          /* we only end up in this state if we have read an 0xFF 
664             as the first byte of the file -- indicating that we are
665             probably dealing with an Intel based (little endian) UTF-16 file*/
666          if (ch == 0xFE) {
667             token = T_UTF16_BOM;
668             lf->state = lex_none;
669          } else {
670             token = T_ERROR;
671          }
672          break;
673       }
674       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
675         lex_tok_to_str(token), ch);
676    }
677    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
678    lf->token = token;
679
680    /*
681     * Here is where we check to see if the user has set certain
682     *  expectations (e.g. 32 bit integer). If so, we do type checking
683     *  and possible additional scanning (e.g. for range).
684     */
685    switch (expect) {
686    case T_PINT32:
687       lf->pint32_val = scan_pint(lf, lf->str);
688       lf->pint32_val2 = lf->pint32_val;
689       token = T_PINT32;
690       break;
691
692    case T_PINT32_RANGE:
693       if (token == T_NUMBER) {
694          lf->pint32_val = scan_pint(lf, lf->str);
695          lf->pint32_val2 = lf->pint32_val;
696          token = T_PINT32;
697       } else {
698          char *p = strchr(lf->str, '-');
699          if (!p) {
700             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
701                lex_tok_to_str(token), lf->str);
702             token = T_ERROR;
703             break;
704          }
705          *p++ = 0;                       /* terminate first half of range */
706          lf->pint32_val  = scan_pint(lf, lf->str);
707          lf->pint32_val2 = scan_pint(lf, p);
708          token = T_PINT32_RANGE;
709       }
710       break;
711
712    case T_INT32:
713       if (token != T_NUMBER || !is_a_number(lf->str)) {
714          scan_err2(lf, _("expected an integer number, got %s: %s"),
715                lex_tok_to_str(token), lf->str);
716          token = T_ERROR;
717          break;
718       }
719       errno = 0;
720       lf->int32_val = (int32_t)str_to_int64(lf->str);
721       if (errno != 0) {
722          scan_err2(lf, _("expected an integer number, got %s: %s"),
723                lex_tok_to_str(token), lf->str);
724          token = T_ERROR;
725       } else {
726          token = T_INT32;
727       }
728       break;
729
730    case T_INT64:
731       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
732       if (token != T_NUMBER || !is_a_number(lf->str)) {
733          scan_err2(lf, _("expected an integer number, got %s: %s"),
734                lex_tok_to_str(token), lf->str);
735          token = T_ERROR;
736          break;
737       }
738       errno = 0;
739       lf->int64_val = str_to_int64(lf->str);
740       if (errno != 0) {
741          scan_err2(lf, _("expected an integer number, got %s: %s"),
742                lex_tok_to_str(token), lf->str);
743          token = T_ERROR;
744       } else {
745          token = T_INT64;
746       }
747       break;
748
749    case T_PINT64_RANGE:
750       if (token == T_NUMBER) {
751          lf->pint64_val = scan_pint64(lf, lf->str);
752          lf->pint64_val2 = lf->pint64_val;
753          token = T_PINT64;
754       } else {
755          char *p = strchr(lf->str, '-');
756          if (!p) {
757             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
758                lex_tok_to_str(token), lf->str);
759             token = T_ERROR;
760             break;
761          }
762          *p++ = 0;                       /* terminate first half of range */
763          lf->pint64_val  = scan_pint64(lf, lf->str);
764          lf->pint64_val2 = scan_pint64(lf, p);
765          token = T_PINT64_RANGE;
766       }
767       break;
768
769    case T_NAME:
770       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
771          scan_err2(lf, _("expected a name, got %s: %s"),
772                lex_tok_to_str(token), lf->str);
773          token = T_ERROR;
774       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
775          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
776             lf->str_len, MAX_RES_NAME_LENGTH);
777          token = T_ERROR;
778       }
779       break;
780
781    case T_STRING:
782       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
783          scan_err2(lf, _("expected a string, got %s: %s"),
784                lex_tok_to_str(token), lf->str);
785          token = T_ERROR;
786       } else {
787          token = T_STRING;
788       }
789       break;
790
791
792    default:
793       break;                          /* no expectation given */
794    }
795    lf->token = token;                 /* set possible new token */
796    return token;
797 }