aa023955417efc30036e6dbd70b56dc75127a638
[platform/upstream/glib.git] / glib / gscanner.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GScanner: Flexible lexical scanner for general purpose.
5  * Copyright (C) 1997, 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #define         __gscanner_c__
23
24 #include        <stdlib.h>
25 #include        <stdarg.h>
26 #include        <string.h>
27 #include        <stdio.h>
28 #include        <unistd.h>
29 #include        <errno.h>
30 #include        <sys/types.h>   /* needed for sys/stat.h */
31 #include        <sys/stat.h>
32 #include        "glib.h"
33
34
35
36 /* --- defines --- */
37 #define to_lower(c)                             ( \
38         (guchar) (                                                      \
39           ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) |  \
40           ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) |  \
41           ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) |  \
42           ((guchar)(c))                                                 \
43         )                                                               \
44 )
45
46
47 /* --- typedefs --- */
48 typedef struct  _GScannerKey    GScannerKey;
49
50 struct  _GScannerKey
51 {
52   guint          scope_id;
53   gchar         *symbol;
54   gpointer       value;
55 };
56
57
58
59 /* --- variables --- */
60 static  GScannerConfig  g_scanner_config_template =
61 {
62   (
63    " \t\n"
64    )                    /* cset_skip_characters */,
65   (
66    G_CSET_a_2_z
67    "_"
68    G_CSET_A_2_Z
69    )                    /* cset_identifier_first */,
70   (
71    G_CSET_a_2_z
72    "_0123456789"
73    G_CSET_A_2_Z
74    G_CSET_LATINS
75    G_CSET_LATINC
76    )                    /* cset_identifier_nth */,
77   ( "#\n" )             /* cpair_comment_single */,
78   
79   FALSE                 /* case_sensitive */,
80   
81   TRUE                  /* skip_comment_multi */,
82   TRUE                  /* skip_comment_single */,
83   TRUE                  /* scan_comment_multi */,
84   TRUE                  /* scan_identifier */,
85   FALSE                 /* scan_identifier_1char */,
86   FALSE                 /* scan_identifier_NULL */,
87   TRUE                  /* scan_symbols */,
88   FALSE                 /* scan_binary */,
89   TRUE                  /* scan_octal */,
90   TRUE                  /* scan_float */,
91   TRUE                  /* scan_hex */,
92   FALSE                 /* scan_hex_dollar */,
93   TRUE                  /* scan_string_sq */,
94   TRUE                  /* scan_string_dq */,
95   TRUE                  /* numbers_2_int */,
96   FALSE                 /* int_2_float */,
97   FALSE                 /* identifier_2_string */,
98   TRUE                  /* char_2_token */,
99   FALSE                 /* symbol_2_token */,
100   FALSE                 /* scope_0_fallback */,
101 };
102
103
104 /* --- prototypes --- */
105 extern char* g_vsprintf (gchar *fmt, va_list *args, va_list *args2);
106 static inline
107 gint            g_scanner_char_2_num      (guchar        c,
108                                            guchar        base);
109 static inline
110 GScannerKey*    g_scanner_lookup_internal (GScanner     *scanner,
111                                            guint         scope_id,
112                                            const gchar  *symbol);
113 static gint     g_scanner_key_equal       (gconstpointer v1,
114                                            gconstpointer v2);
115 static guint    g_scanner_key_hash        (gconstpointer v);
116 static void     g_scanner_get_token_ll    (GScanner     *scanner,
117                                            GTokenType   *token_p,
118                                            GValue       *value_p,
119                                            guint        *line_p,
120                                            guint        *position_p);
121 static void     g_scanner_get_token_i     (GScanner     *scanner,
122                                            GTokenType   *token_p,
123                                            GValue       *value_p,
124                                            guint        *line_p,
125                                            guint        *position_p);
126 static void     g_scanner_free_value      (GTokenType   *token_p,
127                                            GValue       *value_p);
128
129 static guchar   g_scanner_peek_next_char  (GScanner     *scanner);
130 static guchar   g_scanner_get_char        (GScanner     *scanner,
131                                            guint        *line_p,
132                                            guint        *position_p);
133 static void     g_scanner_msg_handler     (GScanner     *scanner,
134                                            gchar        *message,
135                                            gint          is_error);
136
137
138 /* --- functions --- */
139 static gint
140 g_scanner_char_2_num (guchar    c,
141                       guchar    base)
142 {
143   if (c >= '0' && c <= '9')
144     c -= '0';
145   else if (c >= 'A' && c <= 'Z')
146     c -= 'A' - 10;
147   else if (c >= 'a' && c <= 'z')
148     c -= 'a' - 10;
149   else
150     return -1;
151   
152   if (c < base)
153     return c;
154   
155   return -1;
156 }
157
158 GScanner*
159 g_scanner_new (GScannerConfig   *config_templ)
160 {
161   register GScanner     *scanner;
162   
163   if (!config_templ)
164     config_templ = &g_scanner_config_template;
165   
166   scanner = g_new0 (GScanner, 1);
167   
168   scanner->user_data = NULL;
169   scanner->max_parse_errors = 0;
170   scanner->parse_errors = 0;
171   scanner->input_name = NULL;
172   scanner->derived_data = NULL;
173   
174   scanner->config = g_new0 (GScannerConfig, 1);
175   
176   scanner->config->case_sensitive       = config_templ->case_sensitive;
177   scanner->config->cset_skip_characters = config_templ->cset_skip_characters;
178   scanner->config->cset_identifier_first= config_templ->cset_identifier_first;
179   scanner->config->cset_identifier_nth  = config_templ->cset_identifier_nth;
180   scanner->config->cpair_comment_single = config_templ->cpair_comment_single;
181   scanner->config->skip_comment_multi   = config_templ->skip_comment_multi;
182   scanner->config->skip_comment_single  = config_templ->skip_comment_single;
183   scanner->config->scan_comment_multi   = config_templ->scan_comment_multi;
184   scanner->config->scan_identifier      = config_templ->scan_identifier;
185   scanner->config->scan_identifier_1char= config_templ->scan_identifier_1char;
186   scanner->config->scan_identifier_NULL = config_templ->scan_identifier_NULL;
187   scanner->config->scan_symbols         = config_templ->scan_symbols;
188   scanner->config->scan_binary          = config_templ->scan_binary;
189   scanner->config->scan_octal           = config_templ->scan_octal;
190   scanner->config->scan_float           = config_templ->scan_float;
191   scanner->config->scan_hex             = config_templ->scan_hex;
192   scanner->config->scan_hex_dollar      = config_templ->scan_hex_dollar;
193   scanner->config->scan_string_sq       = config_templ->scan_string_sq;
194   scanner->config->scan_string_dq       = config_templ->scan_string_dq;
195   scanner->config->numbers_2_int        = config_templ->numbers_2_int;
196   scanner->config->int_2_float          = config_templ->int_2_float;
197   scanner->config->identifier_2_string  = config_templ->identifier_2_string;
198   scanner->config->char_2_token         = config_templ->char_2_token;
199   scanner->config->symbol_2_token       = config_templ->symbol_2_token;
200   scanner->config->scope_0_fallback     = config_templ->scope_0_fallback;
201   
202   scanner->token = G_TOKEN_NONE;
203   scanner->value.v_int = 0;
204   scanner->line = 1;
205   scanner->position = 0;
206   
207   scanner->next_token = G_TOKEN_NONE;
208   scanner->next_value.v_int = 0;
209   scanner->next_line = 1;
210   scanner->next_position = 0;
211   
212   scanner->symbol_table = g_hash_table_new (g_scanner_key_hash, g_scanner_key_equal);
213   scanner->text = NULL;
214   scanner->text_len = 0;
215   scanner->input_fd = -1;
216   scanner->peeked_char = -1;
217   scanner->scope_id = 0;
218   
219   scanner->msg_handler = g_scanner_msg_handler;
220   
221   return scanner;
222 }
223
224 static void
225 g_scanner_destroy_symbol_table_entry (gpointer _key,
226                                       gpointer _value,
227                                       gpointer _data)
228 {
229   GScannerKey *key = _key;
230   
231   g_free (key->symbol);
232   g_free (key);
233 }
234
235 void
236 g_scanner_destroy (GScanner     *scanner)
237 {
238   g_return_if_fail (scanner != NULL);
239   
240   g_hash_table_foreach (scanner->symbol_table, 
241                         g_scanner_destroy_symbol_table_entry, NULL);
242   g_hash_table_destroy (scanner->symbol_table);
243   g_scanner_free_value (&scanner->token, &scanner->value);
244   g_scanner_free_value (&scanner->next_token, &scanner->next_value);
245   g_free (scanner->config);
246   g_free (scanner);
247 }
248
249 static void
250 g_scanner_msg_handler (GScanner         *scanner,
251                        gchar            *message,
252                        gint              is_error)
253 {
254   g_return_if_fail (scanner != NULL);
255   
256   fprintf (stdout, "%s:%d: ", scanner->input_name, scanner->line);
257   if (is_error)
258     fprintf (stdout, "error: ");
259   fprintf (stdout, "%s\n", message);
260 }
261
262 void
263 g_scanner_error (GScanner       *scanner,
264                  const gchar    *format,
265                  ...)
266 {
267   g_return_if_fail (scanner != NULL);
268   g_return_if_fail (format != NULL);
269   
270   scanner->parse_errors++;
271   
272   if (scanner->msg_handler)
273     {
274       va_list args, args2;
275       gchar *string;
276       
277       va_start (args, format);
278       va_start (args2, format);
279       string = g_vsprintf ((gchar*) format, &args, &args2);
280       va_end (args);
281       va_end (args2);
282       
283       string = g_strdup (string);
284       
285       scanner->msg_handler (scanner, string, TRUE);
286       
287       g_free (string);
288     }
289 }
290
291 void
292 g_scanner_warn (GScanner       *scanner,
293                 const gchar    *format,
294                 ...)
295 {
296   g_return_if_fail (scanner != NULL);
297   g_return_if_fail (format != NULL);
298   
299   if (scanner->msg_handler)
300     {
301       va_list args, args2;
302       gchar *string;
303       
304       va_start (args, format);
305       va_start (args2, format);
306       string = g_vsprintf ((gchar*) format, &args, &args2);
307       va_end (args);
308       va_end (args2);
309       
310       string = g_strdup (string);
311       
312       scanner->msg_handler (scanner, string, FALSE);
313       
314       g_free (string);
315     }
316 }
317
318 void
319 g_scanner_input_file (GScanner  *scanner,
320                       gint      input_fd)
321 {
322   g_return_if_fail (input_fd >= 0);
323   
324   scanner->token = G_TOKEN_NONE;
325   scanner->value.v_int = 0;
326   scanner->line = 1;
327   scanner->position = 0;
328   scanner->next_token = G_TOKEN_NONE;
329   
330   scanner->text = NULL;
331   scanner->text_len = 0;
332   scanner->input_fd = input_fd;
333   scanner->peeked_char = -1;
334 }
335
336 void
337 g_scanner_input_text (GScanner       *scanner,
338                       const  gchar   *text,
339                       guint           text_len)
340 {
341   g_return_if_fail (text != NULL);
342   
343   scanner->token = G_TOKEN_NONE;
344   scanner->value.v_int = 0;
345   scanner->line = 1;
346   scanner->position = 0;
347   scanner->next_token = G_TOKEN_NONE;
348   
349   scanner->text = text;
350   scanner->text_len = text_len;
351   scanner->input_fd = -1;
352   scanner->peeked_char = -1;
353 }
354
355 static gint
356 g_scanner_key_equal (gconstpointer v1,
357                      gconstpointer v2)
358 {
359   register const GScannerKey *key1 = v1;
360   register const GScannerKey *key2 = v2;
361   
362   return (key1->scope_id == key2->scope_id) && (strcmp (key1->symbol, key2->symbol) == 0);
363 }
364
365 static guint
366 g_scanner_key_hash (gconstpointer v)
367 {
368   register const GScannerKey *key = v;
369   register gchar *c;
370   register guint h;
371   
372   h = key->scope_id;
373   for (c = key->symbol; *c; c++)
374     {
375       register guint g;
376       
377       h = (h << 4) + *c;
378       g = h & 0xf0000000;
379       if (g)
380         {
381           h = h ^ (g >> 24);
382           h = h ^ g;
383         }
384     }
385   
386   return h;
387 }
388
389 static inline GScannerKey*
390 g_scanner_lookup_internal (GScanner     *scanner,
391                            guint         scope_id,
392                            const gchar  *symbol)
393 {
394   register GScannerKey  *key_p;
395   GScannerKey key;
396   
397   key.scope_id = scope_id;
398   
399   if (!scanner->config->case_sensitive)
400     {
401       register gchar *d;
402       register const gchar *c;
403       
404       key.symbol = g_new (gchar, strlen (symbol) + 1);
405       for (d = key.symbol, c = symbol; *c; c++, d++)
406         *d = to_lower (*c);
407       *d = 0;
408       key_p = g_hash_table_lookup (scanner->symbol_table, &key);
409       g_free (key.symbol);
410     }
411   else
412     {
413       key.symbol = (gchar*) symbol;
414       key_p = g_hash_table_lookup (scanner->symbol_table, &key);
415     }
416   
417   return key_p;
418 }
419
420 void
421 g_scanner_scope_add_symbol (GScanner    *scanner,
422                             guint        scope_id,
423                             const gchar *symbol,
424                             gpointer     value)
425 {
426   register GScannerKey  *key;
427   
428   g_return_if_fail (scanner != NULL);
429   g_return_if_fail (symbol != NULL);
430   
431   key = g_scanner_lookup_internal (scanner, scope_id, symbol);
432   
433   if (!key)
434     {
435       key = g_new (GScannerKey, 1);
436       key->scope_id = scope_id;
437       key->symbol = g_strdup (symbol);
438       key->value = value;
439       if (!scanner->config->case_sensitive)
440         {
441           register gchar *c;
442           
443           c = key->symbol;
444           while (*c != 0)
445             {
446               *c = to_lower (*c);
447               c++;
448             }
449         }
450       g_hash_table_insert (scanner->symbol_table, key, key);
451     }
452   else
453     key->value = value;
454 }
455
456 void
457 g_scanner_scope_remove_symbol (GScanner    *scanner,
458                                guint        scope_id,
459                                const gchar *symbol)
460 {
461   register GScannerKey  *key;
462   
463   g_return_if_fail (scanner != NULL);
464   g_return_if_fail (symbol != NULL);
465   
466   key = g_scanner_lookup_internal (scanner, scope_id, symbol);
467   
468   if (key)
469     {
470       g_hash_table_remove (scanner->symbol_table, key);
471       g_free (key->symbol);
472       g_free (key);
473     }
474 }
475
476 gpointer
477 g_scanner_lookup_symbol (GScanner       *scanner,
478                          const gchar    *symbol)
479 {
480   register GScannerKey  *key;
481   register guint scope_id;
482   
483   g_return_val_if_fail (scanner != NULL, NULL);
484   
485   if (!symbol)
486     return NULL;
487   
488   scope_id = scanner->scope_id;
489   key = g_scanner_lookup_internal (scanner, scope_id, symbol);
490   if (!key && scope_id && scanner->config->scope_0_fallback)
491     key = g_scanner_lookup_internal (scanner, 0, symbol);
492   
493   if (key)
494     return key->value;
495   else
496     return NULL;
497 }
498
499 gpointer
500 g_scanner_scope_lookup_symbol (GScanner       *scanner,
501                                guint           scope_id,
502                                const gchar    *symbol)
503 {
504   register GScannerKey  *key;
505   
506   g_return_val_if_fail (scanner != NULL, NULL);
507   
508   if (!symbol)
509     return NULL;
510   
511   key = g_scanner_lookup_internal (scanner, scope_id, symbol);
512   
513   if (key)
514     return key->value;
515   else
516     return NULL;
517 }
518
519 guint
520 g_scanner_set_scope (GScanner       *scanner,
521                      guint           scope_id)
522 {
523   register guint old_scope_id;
524   
525   g_return_val_if_fail (scanner != NULL, 0);
526   
527   old_scope_id = scanner->scope_id;
528   scanner->scope_id = scope_id;
529   
530   return old_scope_id;
531 }
532
533 static void
534 g_scanner_foreach_internal (gpointer  _key,
535                             gpointer  _value,
536                             gpointer  _user_data)
537 {
538   register GScannerKey *key;
539   register gpointer *d;
540   register GHFunc func;
541   register gpointer func_data;
542   register guint *scope_id;
543   
544   d = _user_data;
545   func = (GHFunc) d[0];
546   func_data = d[1];
547   scope_id = d[2];
548   key = _value;
549   
550   if (key->scope_id == *scope_id)
551     func (key->symbol, key->value, func_data);
552 }
553
554 void
555 g_scanner_scope_foreach_symbol (GScanner       *scanner,
556                                 guint           scope_id,
557                                 GHFunc          func,
558                                 gpointer        func_data)
559 {
560   gpointer d[3];
561   
562   g_return_if_fail (scanner != NULL);
563   
564   d[0] = (gpointer) func;
565   d[1] = func_data;
566   d[2] = &scope_id;
567   
568   g_hash_table_foreach (scanner->symbol_table, g_scanner_foreach_internal, d);
569 }
570
571 void
572 g_scanner_freeze_symbol_table (GScanner *scanner)
573 {
574   g_return_if_fail (scanner != NULL);
575   
576   g_hash_table_freeze (scanner->symbol_table);
577 }
578
579 void
580 g_scanner_thaw_symbol_table (GScanner *scanner)
581 {
582   g_return_if_fail (scanner != NULL);
583   
584   g_hash_table_thaw (scanner->symbol_table);
585 }
586
587 GTokenType
588 g_scanner_peek_next_token (GScanner     *scanner)
589 {
590   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
591   
592   if (scanner->next_token == G_TOKEN_NONE)
593     {
594       scanner->next_line = scanner->line;
595       scanner->next_position = scanner->position;
596       g_scanner_get_token_i (scanner,
597                              &scanner->next_token,
598                              &scanner->next_value,
599                              &scanner->next_line,
600                              &scanner->next_position);
601     }
602   
603   return scanner->next_token;
604 }
605
606 GTokenType
607 g_scanner_get_next_token (GScanner      *scanner)
608 {
609   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
610   
611   if (scanner->next_token != G_TOKEN_NONE)
612     {
613       g_scanner_free_value (&scanner->token, &scanner->value);
614       
615       scanner->token = scanner->next_token;
616       scanner->value = scanner->next_value;
617       scanner->line = scanner->next_line;
618       scanner->position = scanner->next_position;
619       scanner->next_token = G_TOKEN_NONE;
620     }
621   else
622     g_scanner_get_token_i (scanner,
623                            &scanner->token,
624                            &scanner->value,
625                            &scanner->line,
626                            &scanner->position);
627   
628   return scanner->token;
629 }
630
631 GTokenType
632 g_scanner_cur_token (GScanner *scanner)
633 {
634   g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
635   
636   return scanner->token;
637 }
638
639 GValue
640 g_scanner_cur_value (GScanner *scanner)
641 {
642   register GValue v;
643   
644   v.v_int = 0;
645   g_return_val_if_fail (scanner != NULL, v);
646   
647   return scanner->value;
648 }
649
650 guint
651 g_scanner_cur_line (GScanner *scanner)
652 {
653   g_return_val_if_fail (scanner != NULL, 0);
654   
655   return scanner->line;
656 }
657
658 guint
659 g_scanner_cur_position (GScanner *scanner)
660 {
661   g_return_val_if_fail (scanner != NULL, 0);
662   
663   return scanner->position;
664 }
665
666 gboolean
667 g_scanner_eof (GScanner *scanner)
668 {
669   g_return_val_if_fail (scanner != NULL, TRUE);
670   
671   return scanner->token == G_TOKEN_EOF;
672 }
673
674 static guchar
675 g_scanner_peek_next_char (GScanner *scanner)
676 {
677   guchar fchar;
678   
679   if (scanner->text_len)
680     {
681       fchar = scanner->text[0];
682     }
683   else if (scanner->input_fd >= 0)
684     {
685       if (scanner->peeked_char < 0)
686         {
687           register gint count;
688           
689           do
690             {
691               count = read (scanner->input_fd, &fchar, 1);
692             }
693           while (count == -1 &&
694                  (errno == EINTR ||
695                   errno == EAGAIN));
696           
697           if (count != 1)
698             fchar = 0;
699           
700           scanner->peeked_char = fchar;
701         }
702       else
703         fchar = scanner->peeked_char;
704     }
705   else
706     fchar = 0;
707   
708   return fchar;
709 }
710
711 static guchar
712 g_scanner_get_char (GScanner    *scanner,
713                     guint       *line_p,
714                     guint       *position_p)
715 {
716   guchar fchar;
717   
718   if (scanner->text_len)
719     {
720       fchar = *(scanner->text++);
721       scanner->text_len--;
722     }
723   else if (scanner->input_fd >= 0)
724     {
725       if (scanner->peeked_char < 0)
726         {
727           register gint count;
728           
729           do
730             {
731               count = read (scanner->input_fd, &fchar, 1);
732             }
733           while (count == -1 &&
734                  (errno == EINTR ||
735                   errno == EAGAIN));
736           if (count != 1 || fchar == 0)
737             {
738               fchar = 0;
739               scanner->peeked_char = 0;
740             }
741         }
742       else
743         {
744           fchar = scanner->peeked_char;
745           if (fchar)
746             scanner->peeked_char = -1;
747         }
748     }
749   else
750     fchar = 0;
751   
752   if (fchar == '\n')
753     {
754       (*position_p) = 0;
755       (*line_p)++;
756     }
757   else if (fchar)
758     {
759       (*position_p)++;
760     }
761   
762   return fchar;
763 }
764
765 void
766 g_scanner_unexp_token (GScanner         *scanner,
767                        GTokenType        expected_token,
768                        const gchar      *identifier_spec,
769                        const gchar      *symbol_spec,
770                        const gchar      *symbol_name,
771                        const gchar      *message,
772                        gint              is_error)
773 {
774   register gchar        *token_string;
775   register guint        token_string_len;
776   register gchar        *expected_string;
777   register guint        expected_string_len;
778   register gchar        *message_prefix;
779   register gboolean     print_unexp;
780   void (*msg_handler)   (GScanner*, const gchar*, ...);
781   
782   g_return_if_fail (scanner != NULL);
783   
784   if (is_error)
785     msg_handler = g_scanner_error;
786   else
787     msg_handler = g_scanner_warn;
788   
789   if (!identifier_spec)
790     identifier_spec = "identifier";
791   if (!symbol_spec)
792     symbol_spec = "symbol";
793   
794   token_string_len = 56;
795   token_string = g_new (gchar, token_string_len + 1);
796   expected_string_len = 64;
797   expected_string = g_new (gchar, expected_string_len + 1);
798   print_unexp = TRUE;
799   
800   switch (scanner->token)
801     {
802     case  G_TOKEN_EOF:
803       g_snprintf (token_string, token_string_len, "end of file");
804       break;
805       
806     default:
807       if (scanner->token >= 1 && scanner->token <= 255)
808         {
809           if ((scanner->token >= ' ' && scanner->token <= '~') ||
810               strchr (scanner->config->cset_identifier_first, scanner->token) ||
811               strchr (scanner->config->cset_identifier_nth, scanner->token))
812             g_snprintf (token_string, expected_string_len, "character `%c'", scanner->token);
813           else
814             g_snprintf (token_string, expected_string_len, "character `\\%o'", scanner->token);
815           break;
816         }
817       else if (!scanner->config->symbol_2_token)
818         {
819           g_snprintf (token_string, token_string_len, "(unknown) token <%d>", scanner->token);
820           break;
821         }
822       /* fall through */
823     case  G_TOKEN_SYMBOL:
824       if (expected_token == G_TOKEN_SYMBOL ||
825           (scanner->config->symbol_2_token &&
826            expected_token > G_TOKEN_LAST))
827         print_unexp = FALSE;
828       if (symbol_name)
829         g_snprintf (token_string,
830                     token_string_len,
831                     "%s%s `%s'",
832                     print_unexp ? "" : "invalid ",
833                     symbol_spec,
834                     symbol_name);
835       else
836         g_snprintf (token_string,
837                     token_string_len,
838                     "%s%s",
839                     print_unexp ? "" : "invalid ",
840                     symbol_spec);
841       break;
842       
843     case  G_TOKEN_ERROR:
844       print_unexp = FALSE;
845       expected_token = G_TOKEN_NONE;
846       switch (scanner->value.v_error)
847         {
848         case  G_ERR_UNEXP_EOF:
849           g_snprintf (token_string, token_string_len, "scanner: unexpected end of file");
850           break;
851           
852         case  G_ERR_UNEXP_EOF_IN_STRING:
853           g_snprintf (token_string, token_string_len, "scanner: unterminated string constant");
854           break;
855           
856         case  G_ERR_UNEXP_EOF_IN_COMMENT:
857           g_snprintf (token_string, token_string_len, "scanner: unterminated comment");
858           break;
859           
860         case  G_ERR_NON_DIGIT_IN_CONST:
861           g_snprintf (token_string, token_string_len, "scanner: non digit in constant");
862           break;
863           
864         case  G_ERR_FLOAT_RADIX:
865           g_snprintf (token_string, token_string_len, "scanner: invalid radix for floating constant");
866           break;
867           
868         case  G_ERR_FLOAT_MALFORMED:
869           g_snprintf (token_string, token_string_len, "scanner: malformed floating constant");
870           break;
871           
872         case  G_ERR_DIGIT_RADIX:
873           g_snprintf (token_string, token_string_len, "scanner: digit is beyond radix");
874           break;
875           
876         case  G_ERR_UNKNOWN:
877         default:
878           g_snprintf (token_string, token_string_len, "scanner: unknown error");
879           break;
880         }
881       break;
882       
883     case  G_TOKEN_CHAR:
884       g_snprintf (token_string, token_string_len, "character `%c'", scanner->value.v_char);
885       break;
886       
887     case  G_TOKEN_IDENTIFIER:
888       if (expected_token == G_TOKEN_IDENTIFIER)
889         print_unexp = FALSE;
890       g_snprintf (token_string,
891                   token_string_len,
892                   "%s%s `%s'",
893                   print_unexp ? "" : "invalid ",
894                   identifier_spec,
895                   scanner->value.v_string);
896       break;
897       
898     case  G_TOKEN_BINARY:
899     case  G_TOKEN_OCTAL:
900     case  G_TOKEN_INT:
901     case  G_TOKEN_HEX:
902       g_snprintf (token_string, token_string_len, "number `%ld'", scanner->value.v_int);
903       break;
904       
905     case  G_TOKEN_FLOAT:
906       g_snprintf (token_string, token_string_len, "number `%.3f'", scanner->value.v_float);
907       break;
908       
909     case  G_TOKEN_STRING:
910       if (expected_token == G_TOKEN_STRING)
911         print_unexp = FALSE;
912       g_snprintf (token_string,
913                   token_string_len,
914                   "%s%sstring constant \"%s\"",
915                   print_unexp ? "" : "invalid ",
916                   scanner->value.v_string[0] == 0 ? "empty " : "",
917                   scanner->value.v_string);
918       token_string[token_string_len - 2] = '"';
919       token_string[token_string_len - 1] = 0;
920       break;
921       
922     case  G_TOKEN_COMMENT_SINGLE:
923     case  G_TOKEN_COMMENT_MULTI:
924       g_snprintf (token_string, token_string_len, "comment");
925       break;
926       
927     case  G_TOKEN_NONE:
928       /* somehow the user's parsing code is screwed, there isn't much
929        * we can do about it.
930        * Note, a common case to trigger this is
931        * g_scanner_peek_next_token(); g_scanner_unexp_token();
932        * without an intermediate g_scanner_get_next_token().
933        */
934       g_assert_not_reached ();
935       break;
936     }
937   
938   
939   switch (expected_token)
940     {
941       gboolean need_valid;
942       
943     default:
944       if (expected_token >= 1 && expected_token <= 255)
945         {
946           if ((expected_token >= ' ' && expected_token <= '~') ||
947               strchr (scanner->config->cset_identifier_first, expected_token) ||
948               strchr (scanner->config->cset_identifier_nth, expected_token))
949             g_snprintf (expected_string, expected_string_len, "character `%c'", expected_token);
950           else
951             g_snprintf (expected_string, expected_string_len, "character `\\%o'", expected_token);
952           break;
953         }
954       else if (!scanner->config->symbol_2_token)
955         {
956           g_snprintf (expected_string, expected_string_len, "(unknown) token <%d>", expected_token);
957           break;
958         }
959       /* fall through */
960     case  G_TOKEN_SYMBOL:
961       need_valid = (scanner->token == G_TOKEN_SYMBOL ||
962                     (scanner->config->symbol_2_token &&
963                      scanner->token > G_TOKEN_LAST));
964       g_snprintf (expected_string,
965                   expected_string_len,
966                   "%s%s",
967                   need_valid ? "valid " : "",
968                   symbol_spec);
969       /* FIXME: should we attempt to lookup the symbol_name for symbol_2_token? */
970       break;
971       
972     case  G_TOKEN_INT:
973       g_snprintf (expected_string, expected_string_len, "number (integer)");
974       break;
975       
976     case  G_TOKEN_FLOAT:
977       g_snprintf (expected_string, expected_string_len, "number (float)");
978       break;
979       
980     case  G_TOKEN_STRING:
981       g_snprintf (expected_string,
982                   expected_string_len,
983                   "%sstring constant",
984                   scanner->token == G_TOKEN_STRING ? "valid " : "");
985       break;
986       
987     case  G_TOKEN_IDENTIFIER:
988       g_snprintf (expected_string,
989                   expected_string_len,
990                   "%s%s",
991                   scanner->token == G_TOKEN_IDENTIFIER ? "valid " : "",
992                   identifier_spec);
993       break;
994       
995     case  G_TOKEN_NONE:
996       break;
997     }
998   
999   if (message && message[0] != 0)
1000     message_prefix = " - ";
1001   else
1002     {
1003       message_prefix = "";
1004       message = "";
1005     }
1006   
1007   if (expected_token != G_TOKEN_NONE)
1008     {
1009       if (print_unexp)
1010         msg_handler (scanner,
1011                      "unexpected %s, expected %s%s%s",
1012                      token_string,
1013                      expected_string,
1014                      message_prefix,
1015                      message);
1016       else
1017         msg_handler (scanner,
1018                      "%s, expected %s%s%s",
1019                      token_string,
1020                      expected_string,
1021                      message_prefix,
1022                      message);
1023     }
1024   else
1025     {
1026       if (print_unexp)
1027         msg_handler (scanner,
1028                      "unexpected %s%s%s",
1029                      token_string,
1030                      message_prefix,
1031                      message);
1032       else
1033         msg_handler (scanner,
1034                      "%s%s%s",
1035                      token_string,
1036                      message_prefix,
1037                      message);
1038     }
1039   
1040   g_free (token_string);
1041   g_free (expected_string);
1042 }
1043
1044 gint
1045 g_scanner_stat_mode (const gchar *filename)
1046 {
1047   struct stat  *stat_buf;
1048   gint          st_mode;
1049   
1050   stat_buf = g_new0 (struct stat, 1);
1051   
1052   lstat (filename, stat_buf);
1053   
1054   st_mode = stat_buf->st_mode;
1055   
1056   g_free (stat_buf);
1057   
1058   return st_mode;
1059 }
1060
1061 static void
1062 g_scanner_free_value (GTokenType     *token_p,
1063                       GValue         *value_p)
1064 {
1065   switch (*token_p)
1066     {
1067     case  G_TOKEN_STRING:
1068     case  G_TOKEN_IDENTIFIER:
1069     case  G_TOKEN_IDENTIFIER_NULL:
1070     case  G_TOKEN_COMMENT_SINGLE:
1071     case  G_TOKEN_COMMENT_MULTI:
1072       g_free (value_p->v_string);
1073       break;
1074       
1075     default:
1076       break;
1077     }
1078   
1079   *token_p = G_TOKEN_NONE;
1080 }
1081
1082 static void
1083 g_scanner_get_token_i (GScanner *scanner,
1084                        GTokenType       *token_p,
1085                        GValue           *value_p,
1086                        guint            *line_p,
1087                        guint            *position_p)
1088 {
1089   do
1090     {
1091       g_scanner_free_value (token_p, value_p);
1092       g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p);
1093     }
1094   while (((*token_p > 0 && *token_p < 256) &&
1095           strchr (scanner->config->cset_skip_characters, *token_p)) ||
1096          (*token_p == G_TOKEN_CHAR &&
1097           strchr (scanner->config->cset_skip_characters, value_p->v_char)) ||
1098          (*token_p == G_TOKEN_COMMENT_MULTI &&
1099           scanner->config->skip_comment_multi) ||
1100          (*token_p == G_TOKEN_COMMENT_SINGLE &&
1101           scanner->config->skip_comment_single));
1102   
1103   switch (*token_p)
1104     {
1105     case G_TOKEN_IDENTIFIER:
1106       if (scanner->config->identifier_2_string)
1107         *token_p = G_TOKEN_STRING;
1108       break;
1109       
1110     case G_TOKEN_SYMBOL:
1111       if (scanner->config->symbol_2_token)
1112         *token_p = (GTokenType) value_p->v_symbol;
1113       break;
1114       
1115     case G_TOKEN_BINARY:
1116     case G_TOKEN_OCTAL:
1117     case G_TOKEN_HEX:
1118       if (scanner->config->numbers_2_int)
1119         *token_p = G_TOKEN_INT;
1120       break;
1121       
1122     default:
1123       break;
1124     }
1125   
1126   if (*token_p == G_TOKEN_INT &&
1127       scanner->config->int_2_float)
1128     {
1129       *token_p = G_TOKEN_FLOAT;
1130       value_p->v_float = value_p->v_int;
1131     }
1132   
1133   errno = 0;
1134 }
1135
1136 static void
1137 g_scanner_get_token_ll  (GScanner       *scanner,
1138                          GTokenType     *token_p,
1139                          GValue         *value_p,
1140                          guint          *line_p,
1141                          guint          *position_p)
1142 {
1143   register GScannerConfig       *config;
1144   register gboolean             in_comment_multi;
1145   register gboolean             in_comment_single;
1146   register gboolean             in_string_sq;
1147   register gboolean             in_string_dq;
1148   static   guchar               ch;
1149   register GTokenType           token;
1150   register GValue               value;
1151   register GString              *gstring;
1152   
1153   config = scanner->config;
1154   (*value_p).v_int = 0;
1155   
1156   if (scanner->token == G_TOKEN_EOF ||
1157       (!scanner->text_len &&
1158        (scanner->input_fd < 0 ||
1159         scanner->peeked_char == 0)))
1160     {
1161       *token_p = G_TOKEN_EOF;
1162       return;
1163     }
1164   
1165   in_comment_multi = FALSE;
1166   in_comment_single = FALSE;
1167   in_string_sq = FALSE;
1168   in_string_dq = FALSE;
1169   gstring = NULL;
1170   
1171   do
1172     {
1173       register gboolean         dotted_float = FALSE;
1174       
1175       ch = g_scanner_get_char (scanner, line_p, position_p);
1176       
1177       value.v_int = 0;
1178       token = G_TOKEN_NONE;
1179       
1180       /* this is *evil*, but needed ;(
1181        * we first check for identifier first character, because  it
1182        * might interfere with other key chars like slashes or numbers
1183        */
1184       if (config->scan_identifier &&
1185           ch && strchr (config->cset_identifier_first, ch))
1186         goto identifier_precedence;
1187       
1188       switch (ch)
1189         {
1190           register gboolean     in_number;
1191           static         gchar          *endptr;
1192           
1193         case  0:
1194           token = G_TOKEN_EOF;
1195           (*position_p)++;
1196           ch = 0;
1197           break;
1198           
1199         case  '/':
1200           if (!config->scan_comment_multi ||
1201               g_scanner_peek_next_char (scanner) != '*')
1202             goto default_case;
1203           g_scanner_get_char (scanner, line_p, position_p);
1204           token = G_TOKEN_COMMENT_MULTI;
1205           in_comment_multi = TRUE;
1206           gstring = g_string_new ("");
1207           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1208             {
1209               if (ch == '*' && g_scanner_peek_next_char (scanner) == '/')
1210                 {
1211                   g_scanner_get_char (scanner, line_p, position_p);
1212                   in_comment_multi = FALSE;
1213                   break;
1214                 }
1215               else
1216                 gstring = g_string_append_c (gstring, ch);
1217             }
1218           ch = 0;
1219           break;
1220           
1221         case  '\'':
1222           if (!config->scan_string_sq)
1223             goto default_case;
1224           token = G_TOKEN_STRING;
1225           in_string_sq = TRUE;
1226           gstring = g_string_new ("");
1227           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1228             {
1229               if (ch == '\'')
1230                 {
1231                   in_string_sq = FALSE;
1232                   break;
1233                 }
1234               else
1235                 gstring = g_string_append_c (gstring, ch);
1236             }
1237           ch = 0;
1238           break;
1239           
1240         case  '"':
1241           if (!config->scan_string_dq)
1242             goto default_case;
1243           token = G_TOKEN_STRING;
1244           in_string_dq = TRUE;
1245           gstring = g_string_new ("");
1246           while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1247             {
1248               if (ch == '"')
1249                 {
1250                   in_string_dq = FALSE;
1251                   break;
1252                 }
1253               else
1254                 {
1255                   if (ch == '\\')
1256                     {
1257                       ch = g_scanner_get_char (scanner, line_p, position_p);
1258                       switch (ch)
1259                         {
1260                           register guint        i;
1261                           register guint        fchar;
1262                           
1263                         case  0:
1264                           break;
1265                           
1266                         case  '\\':
1267                           gstring = g_string_append_c (gstring, '\\');
1268                           break;
1269                           
1270                         case  'n':
1271                           gstring = g_string_append_c (gstring, '\n');
1272                           break;
1273                           
1274                         case  't':
1275                           gstring = g_string_append_c (gstring, '\t');
1276                           break;
1277                           
1278                         case  'r':
1279                           gstring = g_string_append_c (gstring, '\r');
1280                           break;
1281                           
1282                         case  'b':
1283                           gstring = g_string_append_c (gstring, '\b');
1284                           break;
1285                           
1286                         case  'f':
1287                           gstring = g_string_append_c (gstring, '\f');
1288                           break;
1289                           
1290                         case  '0':
1291                         case  '1':
1292                         case  '2':
1293                         case  '3':
1294                         case  '4':
1295                         case  '5':
1296                         case  '6':
1297                         case  '7':
1298                           i = ch - '0';
1299                           fchar = g_scanner_peek_next_char (scanner);
1300                           if (fchar >= '0' && fchar <= '7')
1301                             {
1302                               ch = g_scanner_get_char (scanner, line_p, position_p);
1303                               i= i * 8 + ch - '0';
1304                               fchar = g_scanner_peek_next_char (scanner);
1305                               if (fchar >= '0' && fchar <= '7')
1306                                 {
1307                                   ch = g_scanner_get_char (scanner, line_p, position_p);
1308                                   i = i * 8 + ch - '0';
1309                                 }
1310                             }
1311                           gstring = g_string_append_c (gstring, i);
1312                           break;
1313                           
1314                         default:
1315                           gstring = g_string_append_c (gstring, ch);
1316                           break;
1317                         }
1318                     }
1319                   else
1320                     gstring = g_string_append_c (gstring, ch);
1321                 }
1322             }
1323           ch = 0;
1324           break;
1325           
1326         case  '.':
1327           if (!config->scan_float)
1328             goto default_case;
1329           token = G_TOKEN_FLOAT;
1330           dotted_float = TRUE;
1331           ch = g_scanner_get_char (scanner, line_p, position_p);
1332           goto number_parsing;
1333           
1334         case  '$':
1335           if (!config->scan_hex_dollar)
1336             goto default_case;
1337           token = G_TOKEN_HEX;
1338           ch = g_scanner_get_char (scanner, line_p, position_p);
1339           goto number_parsing;
1340           
1341         case  '0':
1342           if (config->scan_octal)
1343             token = G_TOKEN_OCTAL;
1344           else
1345             token = G_TOKEN_INT;
1346           ch = g_scanner_peek_next_char (scanner);
1347           if (config->scan_hex && (ch == 'x' || ch == 'X'))
1348             {
1349               token = G_TOKEN_HEX;
1350               g_scanner_get_char (scanner, line_p, position_p);
1351               ch = g_scanner_get_char (scanner, line_p, position_p);
1352               if (ch == 0)
1353                 {
1354                   token = G_TOKEN_ERROR;
1355                   value.v_error = G_ERR_UNEXP_EOF;
1356                   (*position_p)++;
1357                   break;
1358                 }
1359               if (g_scanner_char_2_num (ch, 16) < 0)
1360                 {
1361                   token = G_TOKEN_ERROR;
1362                   value.v_error = G_ERR_DIGIT_RADIX;
1363                   ch = 0;
1364                   break;
1365                 }
1366             }
1367           else if (config->scan_binary && (ch == 'b' || ch == 'B'))
1368             {
1369               token = G_TOKEN_BINARY;
1370               g_scanner_get_char (scanner, line_p, position_p);
1371               ch = g_scanner_get_char (scanner, line_p, position_p);
1372               if (ch == 0)
1373                 {
1374                   token = G_TOKEN_ERROR;
1375                   value.v_error = G_ERR_UNEXP_EOF;
1376                   (*position_p)++;
1377                   break;
1378                 }
1379               if (g_scanner_char_2_num (ch, 10) < 0)
1380                 {
1381                   token = G_TOKEN_ERROR;
1382                   value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1383                   ch = 0;
1384                   break;
1385                 }
1386             }
1387           else
1388             ch = '0';
1389           /* fall through */
1390         case  '1':
1391         case  '2':
1392         case  '3':
1393         case  '4':
1394         case  '5':
1395         case  '6':
1396         case  '7':
1397         case  '8':
1398         case  '9':
1399         number_parsing:
1400         if (token == G_TOKEN_NONE)
1401           token = G_TOKEN_INT;
1402         
1403         gstring = g_string_new (dotted_float ? "0." : "");
1404         gstring = g_string_append_c (gstring, ch);
1405         in_number = TRUE;
1406         while (in_number)
1407           {
1408             register gboolean is_E;
1409             
1410             is_E = (ch == 'e' || ch == 'E') && token == G_TOKEN_FLOAT;
1411             ch = g_scanner_peek_next_char (scanner);
1412             
1413             if (g_scanner_char_2_num (ch, 36) >= 0 ||
1414                 (config->scan_float && ch == '.') ||
1415                 (is_E && ch == '+') ||
1416                 (is_E && ch == '-') )
1417               ch = g_scanner_get_char (scanner, line_p, position_p);
1418             else
1419               in_number = FALSE;
1420             
1421             if (in_number)
1422               switch (ch)
1423                 {
1424                 case  '.':
1425                   if (token != G_TOKEN_INT &&
1426                       token != G_TOKEN_OCTAL)
1427                     {
1428                       token = G_TOKEN_ERROR;
1429                       if (token == G_TOKEN_FLOAT)
1430                         value.v_error = G_ERR_FLOAT_MALFORMED;
1431                       else
1432                         value.v_error = G_ERR_FLOAT_RADIX;
1433                       in_number = FALSE;
1434                     }
1435                   else
1436                     {
1437                       token = G_TOKEN_FLOAT;
1438                       gstring = g_string_append_c (gstring, ch);
1439                     }
1440                   break;
1441                   
1442                 case    '0':
1443                 case  '1':
1444                 case  '2':
1445                 case  '3':
1446                 case  '4':
1447                 case  '5':
1448                 case  '6':
1449                 case  '7':
1450                 case  '8':
1451                 case  '9':
1452                   gstring = g_string_append_c (gstring, ch);
1453                   break;
1454                   
1455                 case    '-':
1456                 case    '+':
1457                   if (token != G_TOKEN_FLOAT)
1458                     {
1459                       token = G_TOKEN_ERROR;
1460                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1461                       in_number = FALSE;
1462                     }
1463                   else
1464                     gstring = g_string_append_c (gstring, ch);
1465                   break;
1466                   
1467                 case    'e':
1468                 case    'E':
1469                   if ((token != G_TOKEN_HEX && !config->scan_float) ||
1470                       (token != G_TOKEN_HEX &&
1471                        token != G_TOKEN_OCTAL &&
1472                        token != G_TOKEN_FLOAT &&
1473                        token != G_TOKEN_INT))
1474                     {
1475                       token = G_TOKEN_ERROR;
1476                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1477                       in_number = FALSE;
1478                     }
1479                   else
1480                     {
1481                       if (token != G_TOKEN_HEX)
1482                         token = G_TOKEN_FLOAT;
1483                       gstring = g_string_append_c (gstring, ch);
1484                     }
1485                   break;
1486                   
1487                 default:
1488                   if (token != G_TOKEN_HEX)
1489                     {
1490                       token = G_TOKEN_ERROR;
1491                       value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1492                       in_number = FALSE;
1493                     }
1494                   else
1495                     gstring = g_string_append_c (gstring, ch);
1496                   break;
1497                 }
1498           }
1499         endptr = NULL;
1500         switch (token)
1501           {
1502           case  G_TOKEN_BINARY:
1503             value.v_binary = strtol (gstring->str, &endptr, 2);
1504             break;
1505             
1506           case  G_TOKEN_OCTAL:
1507             value.v_octal = strtol (gstring->str, &endptr, 8);
1508             break;
1509             
1510           case  G_TOKEN_INT:
1511             value.v_int = strtol (gstring->str, &endptr, 10);
1512             break;
1513             
1514           case  G_TOKEN_FLOAT:
1515             value.v_float = g_strtod (gstring->str, &endptr);
1516             break;
1517             
1518           case  G_TOKEN_HEX:
1519             value.v_hex = strtol (gstring->str, &endptr, 16);
1520             break;
1521             
1522           default:
1523             break;
1524           }
1525         if (endptr && *endptr)
1526           {
1527             token = G_TOKEN_ERROR;
1528             if (*endptr == 'e' || *endptr == 'E')
1529               value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1530             else
1531               value.v_error = G_ERR_DIGIT_RADIX;
1532           }
1533         g_string_free (gstring, TRUE);
1534         gstring = NULL;
1535         ch = 0;
1536         break;
1537         
1538         default:
1539         default_case:
1540         if (config->cpair_comment_single &&
1541             ch == config->cpair_comment_single[0])
1542           {
1543             token = G_TOKEN_COMMENT_SINGLE;
1544             in_comment_single = TRUE;
1545             gstring = g_string_new ("");
1546             while ((ch = g_scanner_get_char (scanner,
1547                                              line_p,
1548                                              position_p)) != 0)
1549               {
1550                 if (ch == config->cpair_comment_single[1])
1551                   {
1552                     in_comment_single = FALSE;
1553                     ch = 0;
1554                     break;
1555                   }
1556                 
1557                 gstring = g_string_append_c (gstring, ch);
1558                 ch = 0;
1559               }
1560           }
1561         else if (config->scan_identifier && ch &&
1562                  strchr (config->cset_identifier_first, ch))
1563           {
1564           identifier_precedence:
1565             
1566             if (config->cset_identifier_nth && ch &&
1567                 strchr (config->cset_identifier_nth,
1568                         g_scanner_peek_next_char (scanner)))
1569               {
1570                 token = G_TOKEN_IDENTIFIER;
1571                 gstring = g_string_new ("");
1572                 gstring = g_string_append_c (gstring, ch);
1573                 do
1574                   {
1575                     ch = g_scanner_get_char (scanner, line_p, position_p);
1576                     gstring = g_string_append_c (gstring, ch);
1577                     ch = g_scanner_peek_next_char (scanner);
1578                   }
1579                 while (ch && strchr (config->cset_identifier_nth, ch));
1580                 ch = 0;
1581               }
1582             else if (config->scan_identifier_1char)
1583               {
1584                 token = G_TOKEN_IDENTIFIER;
1585                 value.v_identifier = g_new0 (gchar, 2);
1586                 value.v_identifier[0] = ch;
1587                 ch = 0;
1588               }
1589           }
1590         if (ch)
1591           {
1592             if (config->char_2_token)
1593               token = ch;
1594             else
1595               {
1596                 token = G_TOKEN_CHAR;
1597                 value.v_char = ch;
1598               }
1599             ch = 0;
1600           }
1601         break;
1602         }
1603       g_assert (ch == 0 && token != G_TOKEN_NONE);
1604     }
1605   while (ch != 0);
1606   
1607   if (in_comment_multi ||
1608       in_comment_single ||
1609       in_string_sq ||
1610       in_string_dq)
1611     {
1612       token = G_TOKEN_ERROR;
1613       if (gstring)
1614         {
1615           g_string_free (gstring, TRUE);
1616           gstring = NULL;
1617         }
1618       (*position_p)++;
1619       if (in_comment_multi || in_comment_single)
1620         value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT;
1621       else if (in_string_sq || in_string_dq)
1622         value.v_error = G_ERR_UNEXP_EOF_IN_STRING;
1623     }
1624   
1625   if (gstring)
1626     {
1627       value.v_string = gstring->str;
1628       g_string_free (gstring, FALSE);
1629       gstring = NULL;
1630     }
1631   
1632   if (token == G_TOKEN_IDENTIFIER &&
1633       config->scan_symbols)
1634     {
1635       register GScannerKey      *key;
1636       register guint scope_id;
1637       
1638       scope_id = scanner->scope_id;
1639       key = g_scanner_lookup_internal (scanner, scope_id, value.v_identifier);
1640       if (!key && scope_id && scanner->config->scope_0_fallback)
1641         key = g_scanner_lookup_internal (scanner, 0, value.v_identifier);
1642       
1643       if (key)
1644         {
1645           g_free (value.v_identifier);
1646           token = G_TOKEN_SYMBOL;
1647           value.v_symbol = key->value;
1648         }
1649     }
1650   
1651   if (token == G_TOKEN_IDENTIFIER &&
1652       config->scan_identifier_NULL &&
1653       strlen (value.v_identifier) == 4)
1654     {
1655       gchar *null_upper = "NULL";
1656       gchar *null_lower = "null";
1657       
1658       if (scanner->config->case_sensitive)
1659         {
1660           if (value.v_identifier[0] == null_upper[0] &&
1661               value.v_identifier[1] == null_upper[1] &&
1662               value.v_identifier[2] == null_upper[2] &&
1663               value.v_identifier[3] == null_upper[3])
1664             token = G_TOKEN_IDENTIFIER_NULL;
1665         }
1666       else
1667         {
1668           if ((value.v_identifier[0] == null_upper[0] ||
1669                value.v_identifier[0] == null_lower[0]) &&
1670               (value.v_identifier[1] == null_upper[1] ||
1671                value.v_identifier[1] == null_lower[1]) &&
1672               (value.v_identifier[2] == null_upper[2] ||
1673                value.v_identifier[2] == null_lower[2]) &&
1674               (value.v_identifier[3] == null_upper[3] ||
1675                value.v_identifier[3] == null_lower[3]))
1676             token = G_TOKEN_IDENTIFIER_NULL;
1677         }
1678     }
1679   
1680   *token_p = token;
1681   *value_p = value;
1682 }