source: trunk/third/glib2/glib/gscanner.c @ 20721

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