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