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