source: trunk/third/glib/gscanner.c @ 14807

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