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