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