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