Coverage Report

Created: 2025-08-24 07:10

/src/glib/glib/gscanner.c
Line
Count
Source (jump to first uncovered 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.1 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, see <http://www.gnu.org/licenses/>.
19
 */
20
21
/*
22
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
23
 * file for a list of people on the GLib Team.  See the ChangeLog
24
 * files for a list of changes.  These files are distributed with
25
 * GLib at ftp://ftp.gtk.org/pub/gtk/.
26
 */
27
28
/*
29
 * MT safe
30
 */
31
32
#include "config.h"
33
34
#include <errno.h>
35
#include <stdlib.h>
36
#include <stdarg.h>
37
#include <string.h>
38
#include <stdio.h>
39
40
#include "gscanner.h"
41
42
#include "gprintfint.h"
43
#include "gstrfuncs.h"
44
#include "gstring.h"
45
#include "gtestutils.h"
46
47
#ifdef G_OS_UNIX
48
#include <unistd.h>
49
#endif
50
#ifdef G_OS_WIN32
51
#include <io.h>
52
#endif
53
54
55
/**
56
 * SECTION:scanner
57
 * @title: Lexical Scanner
58
 * @short_description: a general purpose lexical scanner
59
 *
60
 * The #GScanner and its associated functions provide a
61
 * general purpose lexical scanner.
62
 */
63
64
/**
65
 * GScannerMsgFunc:
66
 * @scanner: a #GScanner
67
 * @message: the message
68
 * @error: %TRUE if the message signals an error,
69
 *     %FALSE if it signals a warning.
70
 *
71
 * Specifies the type of the message handler function.
72
 */
73
74
/**
75
 * G_CSET_a_2_z:
76
 *
77
 * The set of lowercase ASCII alphabet characters.
78
 * Used for specifying valid identifier characters
79
 * in #GScannerConfig.
80
 */
81
82
/**
83
 * G_CSET_A_2_Z:
84
 *
85
 * The set of uppercase ASCII alphabet characters.
86
 * Used for specifying valid identifier characters
87
 * in #GScannerConfig.
88
 */
89
90
/**
91
 * G_CSET_DIGITS:
92
 *
93
 * The set of ASCII digits.
94
 * Used for specifying valid identifier characters
95
 * in #GScannerConfig.
96
 */
97
98
/**
99
 * G_CSET_LATINC:
100
 *
101
 * The set of uppercase ISO 8859-1 alphabet characters
102
 * which are not ASCII characters.
103
 * Used for specifying valid identifier characters
104
 * in #GScannerConfig.
105
 */
106
107
/**
108
 * G_CSET_LATINS:
109
 *
110
 * The set of lowercase ISO 8859-1 alphabet characters
111
 * which are not ASCII characters.
112
 * Used for specifying valid identifier characters
113
 * in #GScannerConfig.
114
 */
115
116
/**
117
 * GTokenType:
118
 * @G_TOKEN_EOF: the end of the file
119
 * @G_TOKEN_LEFT_PAREN: a '(' character
120
 * @G_TOKEN_LEFT_CURLY: a '{' character
121
 * @G_TOKEN_LEFT_BRACE: a '[' character
122
 * @G_TOKEN_RIGHT_CURLY: a '}' character
123
 * @G_TOKEN_RIGHT_PAREN: a ')' character
124
 * @G_TOKEN_RIGHT_BRACE: a ']' character
125
 * @G_TOKEN_EQUAL_SIGN: a '=' character
126
 * @G_TOKEN_COMMA: a ',' character
127
 * @G_TOKEN_NONE: not a token
128
 * @G_TOKEN_ERROR: an error occurred
129
 * @G_TOKEN_CHAR: a character
130
 * @G_TOKEN_BINARY: a binary integer
131
 * @G_TOKEN_OCTAL: an octal integer
132
 * @G_TOKEN_INT: an integer
133
 * @G_TOKEN_HEX: a hex integer
134
 * @G_TOKEN_FLOAT: a floating point number
135
 * @G_TOKEN_STRING: a string
136
 * @G_TOKEN_SYMBOL: a symbol
137
 * @G_TOKEN_IDENTIFIER: an identifier
138
 * @G_TOKEN_IDENTIFIER_NULL: a null identifier
139
 * @G_TOKEN_COMMENT_SINGLE: one line comment
140
 * @G_TOKEN_COMMENT_MULTI: multi line comment
141
 *
142
 * The possible types of token returned from each
143
 * g_scanner_get_next_token() call.
144
 */
145
146
/**
147
 * GTokenValue:
148
 * @v_symbol: token symbol value
149
 * @v_identifier: token identifier value
150
 * @v_binary: token binary integer value
151
 * @v_octal: octal integer value
152
 * @v_int: integer value
153
 * @v_int64: 64-bit integer value
154
 * @v_float: floating point value
155
 * @v_hex: hex integer value
156
 * @v_string: string value
157
 * @v_comment: comment value
158
 * @v_char: character value
159
 * @v_error: error value
160
 *
161
 * A union holding the value of the token.
162
 */
163
164
/**
165
 * GErrorType:
166
 * @G_ERR_UNKNOWN: unknown error
167
 * @G_ERR_UNEXP_EOF: unexpected end of file
168
 * @G_ERR_UNEXP_EOF_IN_STRING: unterminated string constant
169
 * @G_ERR_UNEXP_EOF_IN_COMMENT: unterminated comment
170
 * @G_ERR_NON_DIGIT_IN_CONST: non-digit character in a number
171
 * @G_ERR_DIGIT_RADIX: digit beyond radix in a number
172
 * @G_ERR_FLOAT_RADIX: non-decimal floating point number
173
 * @G_ERR_FLOAT_MALFORMED: malformed floating point number
174
 *
175
 * The possible errors, used in the @v_error field
176
 * of #GTokenValue, when the token is a %G_TOKEN_ERROR.
177
 */
178
179
/**
180
 * GScanner:
181
 * @user_data: unused
182
 * @max_parse_errors: unused
183
 * @parse_errors: g_scanner_error() increments this field
184
 * @input_name: name of input stream, featured by the default message handler
185
 * @qdata: quarked data
186
 * @config: link into the scanner configuration
187
 * @token: token parsed by the last g_scanner_get_next_token()
188
 * @value: value of the last token from g_scanner_get_next_token()
189
 * @line: line number of the last token from g_scanner_get_next_token()
190
 * @position: char number of the last token from g_scanner_get_next_token()
191
 * @next_token: token parsed by the last g_scanner_peek_next_token()
192
 * @next_value: value of the last token from g_scanner_peek_next_token()
193
 * @next_line: line number of the last token from g_scanner_peek_next_token()
194
 * @next_position: char number of the last token from g_scanner_peek_next_token()
195
 * @msg_handler: handler function for _warn and _error
196
 *
197
 * The data structure representing a lexical scanner.
198
 *
199
 * You should set @input_name after creating the scanner, since
200
 * it is used by the default message handler when displaying
201
 * warnings and errors. If you are scanning a file, the filename
202
 * would be a good choice.
203
 *
204
 * The @user_data and @max_parse_errors fields are not used.
205
 * If you need to associate extra data with the scanner you
206
 * can place them here.
207
 *
208
 * If you want to use your own message handler you can set the
209
 * @msg_handler field. The type of the message handler function
210
 * is declared by #GScannerMsgFunc.
211
 */
212
213
/**
214
 * GScannerConfig:
215
 * @cset_skip_characters: specifies which characters should be skipped
216
 *     by the scanner (the default is the whitespace characters: space,
217
 *     tab, carriage-return and line-feed).
218
 * @cset_identifier_first: specifies the characters which can start
219
 *     identifiers (the default is #G_CSET_a_2_z, "_", and #G_CSET_A_2_Z).
220
 * @cset_identifier_nth: specifies the characters which can be used
221
 *     in identifiers, after the first character (the default is
222
 *     #G_CSET_a_2_z, "_0123456789", #G_CSET_A_2_Z, #G_CSET_LATINS,
223
 *     #G_CSET_LATINC).
224
 * @cpair_comment_single: specifies the characters at the start and
225
 *     end of single-line comments. The default is "#\n" which means
226
 *     that single-line comments start with a '#' and continue until
227
 *     a '\n' (end of line).
228
 * @case_sensitive: specifies if symbols are case sensitive (the
229
 *     default is %FALSE).
230
 * @skip_comment_multi: specifies if multi-line comments are skipped
231
 *     and not returned as tokens (the default is %TRUE).
232
 * @skip_comment_single: specifies if single-line comments are skipped
233
 *     and not returned as tokens (the default is %TRUE).
234
 * @scan_comment_multi: specifies if multi-line comments are recognized
235
 *     (the default is %TRUE).
236
 * @scan_identifier: specifies if identifiers are recognized (the
237
 *     default is %TRUE).
238
 * @scan_identifier_1char: specifies if single-character
239
 *     identifiers are recognized (the default is %FALSE).
240
 * @scan_identifier_NULL: specifies if %NULL is reported as
241
 *     %G_TOKEN_IDENTIFIER_NULL (the default is %FALSE).
242
 * @scan_symbols: specifies if symbols are recognized (the default
243
 *     is %TRUE).
244
 * @scan_binary: specifies if binary numbers are recognized (the
245
 *     default is %FALSE).
246
 * @scan_octal: specifies if octal numbers are recognized (the
247
 *     default is %TRUE).
248
 * @scan_float: specifies if floating point numbers are recognized
249
 *     (the default is %TRUE).
250
 * @scan_hex: specifies if hexadecimal numbers are recognized (the
251
 *     default is %TRUE).
252
 * @scan_hex_dollar: specifies if '$' is recognized as a prefix for
253
 *     hexadecimal numbers (the default is %FALSE).
254
 * @scan_string_sq: specifies if strings can be enclosed in single
255
 *     quotes (the default is %TRUE).
256
 * @scan_string_dq: specifies if strings can be enclosed in double
257
 *     quotes (the default is %TRUE).
258
 * @numbers_2_int: specifies if binary, octal and hexadecimal numbers
259
 *     are reported as #G_TOKEN_INT (the default is %TRUE).
260
 * @int_2_float: specifies if all numbers are reported as %G_TOKEN_FLOAT
261
 *     (the default is %FALSE).
262
 * @identifier_2_string: specifies if identifiers are reported as strings
263
 *     (the default is %FALSE).
264
 * @char_2_token: specifies if characters are reported by setting
265
 *     `token = ch` or as %G_TOKEN_CHAR (the default is %TRUE).
266
 * @symbol_2_token: specifies if symbols are reported by setting
267
 *     `token = v_symbol` or as %G_TOKEN_SYMBOL (the default is %FALSE).
268
 * @scope_0_fallback: specifies if a symbol is searched for in the
269
 *     default scope in addition to the current scope (the default is %FALSE).
270
 * @store_int64: use value.v_int64 rather than v_int
271
 *
272
 * Specifies the #GScanner parser configuration. Most settings can
273
 * be changed during the parsing phase and will affect the lexical
274
 * parsing of the next unpeeked token.
275
 */
276
277
/* --- defines --- */
278
0
#define to_lower(c)       ( \
279
0
  (guchar) (              \
280
0
    ( (((guchar)(c))>='A' && ((guchar)(c))<='Z') * ('a'-'A') ) | \
281
0
    ( (((guchar)(c))>=192 && ((guchar)(c))<=214) * (224-192) ) | \
282
0
    ( (((guchar)(c))>=216 && ((guchar)(c))<=222) * (248-216) ) | \
283
0
    ((guchar)(c))             \
284
0
  )               \
285
0
)
286
0
#define READ_BUFFER_SIZE  (4000)
287
288
289
/* --- typedefs --- */
290
typedef struct  _GScannerKey  GScannerKey;
291
292
struct  _GScannerKey
293
{
294
  guint    scope_id;
295
  gchar   *symbol;
296
  gpointer   value;
297
};
298
299
300
/* --- variables --- */
301
static const GScannerConfig g_scanner_config_template =
302
{
303
  (
304
   " \t\r\n"
305
   )      /* cset_skip_characters */,
306
  (
307
   G_CSET_a_2_z
308
   "_"
309
   G_CSET_A_2_Z
310
   )      /* cset_identifier_first */,
311
  (
312
   G_CSET_a_2_z
313
   "_"
314
   G_CSET_A_2_Z
315
   G_CSET_DIGITS
316
   G_CSET_LATINS
317
   G_CSET_LATINC
318
   )      /* cset_identifier_nth */,
319
  ( "#\n" )   /* cpair_comment_single */,
320
  
321
  FALSE     /* case_sensitive */,
322
  
323
  TRUE      /* skip_comment_multi */,
324
  TRUE      /* skip_comment_single */,
325
  TRUE      /* scan_comment_multi */,
326
  TRUE      /* scan_identifier */,
327
  FALSE     /* scan_identifier_1char */,
328
  FALSE     /* scan_identifier_NULL */,
329
  TRUE      /* scan_symbols */,
330
  FALSE     /* scan_binary */,
331
  TRUE      /* scan_octal */,
332
  TRUE      /* scan_float */,
333
  TRUE      /* scan_hex */,
334
  FALSE     /* scan_hex_dollar */,
335
  TRUE      /* scan_string_sq */,
336
  TRUE      /* scan_string_dq */,
337
  TRUE      /* numbers_2_int */,
338
  FALSE     /* int_2_float */,
339
  FALSE     /* identifier_2_string */,
340
  TRUE      /* char_2_token */,
341
  FALSE     /* symbol_2_token */,
342
  FALSE     /* scope_0_fallback */,
343
  FALSE     /* store_int64 */,
344
  0         /* padding_dummy */
345
};
346
347
348
/* --- prototypes --- */
349
static inline
350
GScannerKey*  g_scanner_lookup_internal (GScanner *scanner,
351
             guint   scope_id,
352
             const gchar  *symbol);
353
static gboolean g_scanner_key_equal   (gconstpointer v1,
354
             gconstpointer v2);
355
static guint  g_scanner_key_hash    (gconstpointer v);
356
static void g_scanner_get_token_ll    (GScanner *scanner,
357
             GTokenType *token_p,
358
             GTokenValue  *value_p,
359
             guint  *line_p,
360
             guint  *position_p);
361
static void g_scanner_get_token_i   (GScanner *scanner,
362
             GTokenType *token_p,
363
             GTokenValue  *value_p,
364
             guint  *line_p,
365
             guint  *position_p);
366
367
static guchar g_scanner_peek_next_char  (GScanner *scanner);
368
static guchar g_scanner_get_char    (GScanner *scanner,
369
             guint  *line_p,
370
             guint  *position_p);
371
static void g_scanner_msg_handler   (GScanner *scanner,
372
             gchar  *message,
373
             gboolean  is_error);
374
375
376
/* --- functions --- */
377
static inline gint
378
g_scanner_char_2_num (guchar  c,
379
          guchar  base)
380
0
{
381
0
  if (c >= '0' && c <= '9')
382
0
    c -= '0';
383
0
  else if (c >= 'A' && c <= 'Z')
384
0
    c -= 'A' - 10;
385
0
  else if (c >= 'a' && c <= 'z')
386
0
    c -= 'a' - 10;
387
0
  else
388
0
    return -1;
389
  
390
0
  if (c < base)
391
0
    return c;
392
  
393
0
  return -1;
394
0
}
395
396
/**
397
 * g_scanner_new:
398
 * @config_templ: the initial scanner settings
399
 *
400
 * Creates a new #GScanner.
401
 *
402
 * The @config_templ structure specifies the initial settings
403
 * of the scanner, which are copied into the #GScanner
404
 * @config field. If you pass %NULL then the default settings
405
 * are used.
406
 *
407
 * Returns: the new #GScanner
408
 */
409
GScanner *
410
g_scanner_new (const GScannerConfig *config_templ)
411
0
{
412
0
  GScanner *scanner;
413
  
414
0
  if (!config_templ)
415
0
    config_templ = &g_scanner_config_template;
416
  
417
0
  scanner = g_new0 (GScanner, 1);
418
  
419
0
  scanner->user_data = NULL;
420
0
  scanner->max_parse_errors = 1;
421
0
  scanner->parse_errors = 0;
422
0
  scanner->input_name = NULL;
423
0
  g_datalist_init (&scanner->qdata);
424
  
425
0
  scanner->config = g_new0 (GScannerConfig, 1);
426
  
427
0
  scanner->config->case_sensitive  = config_templ->case_sensitive;
428
0
  scanner->config->cset_skip_characters  = config_templ->cset_skip_characters;
429
0
  if (!scanner->config->cset_skip_characters)
430
0
    scanner->config->cset_skip_characters = "";
431
0
  scanner->config->cset_identifier_first = config_templ->cset_identifier_first;
432
0
  scanner->config->cset_identifier_nth   = config_templ->cset_identifier_nth;
433
0
  scanner->config->cpair_comment_single  = config_templ->cpair_comment_single;
434
0
  scanner->config->skip_comment_multi  = config_templ->skip_comment_multi;
435
0
  scanner->config->skip_comment_single   = config_templ->skip_comment_single;
436
0
  scanner->config->scan_comment_multi  = config_templ->scan_comment_multi;
437
0
  scanner->config->scan_identifier   = config_templ->scan_identifier;
438
0
  scanner->config->scan_identifier_1char = config_templ->scan_identifier_1char;
439
0
  scanner->config->scan_identifier_NULL  = config_templ->scan_identifier_NULL;
440
0
  scanner->config->scan_symbols    = config_templ->scan_symbols;
441
0
  scanner->config->scan_binary     = config_templ->scan_binary;
442
0
  scanner->config->scan_octal    = config_templ->scan_octal;
443
0
  scanner->config->scan_float    = config_templ->scan_float;
444
0
  scanner->config->scan_hex    = config_templ->scan_hex;
445
0
  scanner->config->scan_hex_dollar   = config_templ->scan_hex_dollar;
446
0
  scanner->config->scan_string_sq  = config_templ->scan_string_sq;
447
0
  scanner->config->scan_string_dq  = config_templ->scan_string_dq;
448
0
  scanner->config->numbers_2_int   = config_templ->numbers_2_int;
449
0
  scanner->config->int_2_float     = config_templ->int_2_float;
450
0
  scanner->config->identifier_2_string   = config_templ->identifier_2_string;
451
0
  scanner->config->char_2_token    = config_templ->char_2_token;
452
0
  scanner->config->symbol_2_token  = config_templ->symbol_2_token;
453
0
  scanner->config->scope_0_fallback  = config_templ->scope_0_fallback;
454
0
  scanner->config->store_int64     = config_templ->store_int64;
455
  
456
0
  scanner->token = G_TOKEN_NONE;
457
0
  scanner->value.v_int64 = 0;
458
0
  scanner->line = 1;
459
0
  scanner->position = 0;
460
  
461
0
  scanner->next_token = G_TOKEN_NONE;
462
0
  scanner->next_value.v_int64 = 0;
463
0
  scanner->next_line = 1;
464
0
  scanner->next_position = 0;
465
  
466
0
  scanner->symbol_table = g_hash_table_new (g_scanner_key_hash, g_scanner_key_equal);
467
0
  scanner->input_fd = -1;
468
0
  scanner->text = NULL;
469
0
  scanner->text_end = NULL;
470
0
  scanner->buffer = NULL;
471
0
  scanner->scope_id = 0;
472
  
473
0
  scanner->msg_handler = g_scanner_msg_handler;
474
  
475
0
  return scanner;
476
0
}
477
478
static inline void
479
g_scanner_free_value (GTokenType     *token_p,
480
          GTokenValue     *value_p)
481
0
{
482
0
  switch (*token_p)
483
0
    {
484
0
    case G_TOKEN_STRING:
485
0
    case G_TOKEN_IDENTIFIER:
486
0
    case G_TOKEN_IDENTIFIER_NULL:
487
0
    case G_TOKEN_COMMENT_SINGLE:
488
0
    case G_TOKEN_COMMENT_MULTI:
489
0
      g_free (value_p->v_string);
490
0
      break;
491
      
492
0
    default:
493
0
      break;
494
0
    }
495
  
496
0
  *token_p = G_TOKEN_NONE;
497
0
}
498
499
static void
500
g_scanner_destroy_symbol_table_entry (gpointer _key,
501
              gpointer _value,
502
              gpointer _data)
503
0
{
504
0
  GScannerKey *key = _key;
505
  
506
0
  g_free (key->symbol);
507
0
  g_free (key);
508
0
}
509
510
/**
511
 * g_scanner_destroy:
512
 * @scanner: a #GScanner
513
 *
514
 * Frees all memory used by the #GScanner.
515
 */
516
void
517
g_scanner_destroy (GScanner *scanner)
518
0
{
519
0
  g_return_if_fail (scanner != NULL);
520
  
521
0
  g_datalist_clear (&scanner->qdata);
522
0
  g_hash_table_foreach (scanner->symbol_table, 
523
0
      g_scanner_destroy_symbol_table_entry, NULL);
524
0
  g_hash_table_destroy (scanner->symbol_table);
525
0
  g_scanner_free_value (&scanner->token, &scanner->value);
526
0
  g_scanner_free_value (&scanner->next_token, &scanner->next_value);
527
0
  g_free (scanner->config);
528
0
  g_free (scanner->buffer);
529
0
  g_free (scanner);
530
0
}
531
532
static void
533
g_scanner_msg_handler (GScanner   *scanner,
534
           gchar    *message,
535
           gboolean   is_error)
536
0
{
537
0
  g_return_if_fail (scanner != NULL);
538
  
539
0
  _g_fprintf (stderr, "%s:%d: ",
540
0
        scanner->input_name ? scanner->input_name : "<memory>",
541
0
        scanner->line);
542
0
  if (is_error)
543
0
    _g_fprintf (stderr, "error: ");
544
0
  _g_fprintf (stderr, "%s\n", message);
545
0
}
546
547
/**
548
 * g_scanner_error:
549
 * @scanner: a #GScanner
550
 * @format: the message format. See the printf() documentation
551
 * @...: the parameters to insert into the format string
552
 *
553
 * Outputs an error message, via the #GScanner message handler.
554
 */
555
void
556
g_scanner_error (GScanner *scanner,
557
     const gchar  *format,
558
     ...)
559
0
{
560
0
  g_return_if_fail (scanner != NULL);
561
0
  g_return_if_fail (format != NULL);
562
  
563
0
  scanner->parse_errors++;
564
  
565
0
  if (scanner->msg_handler)
566
0
    {
567
0
      va_list args;
568
0
      gchar *string;
569
      
570
0
      va_start (args, format);
571
0
      string = g_strdup_vprintf (format, args);
572
0
      va_end (args);
573
      
574
0
      scanner->msg_handler (scanner, string, TRUE);
575
      
576
0
      g_free (string);
577
0
    }
578
0
}
579
580
/**
581
 * g_scanner_warn:
582
 * @scanner: a #GScanner
583
 * @format: the message format. See the printf() documentation
584
 * @...: the parameters to insert into the format string
585
 *
586
 * Outputs a warning message, via the #GScanner message handler.
587
 */
588
void
589
g_scanner_warn (GScanner       *scanner,
590
    const gchar    *format,
591
    ...)
592
0
{
593
0
  g_return_if_fail (scanner != NULL);
594
0
  g_return_if_fail (format != NULL);
595
  
596
0
  if (scanner->msg_handler)
597
0
    {
598
0
      va_list args;
599
0
      gchar *string;
600
      
601
0
      va_start (args, format);
602
0
      string = g_strdup_vprintf (format, args);
603
0
      va_end (args);
604
      
605
0
      scanner->msg_handler (scanner, string, FALSE);
606
      
607
0
      g_free (string);
608
0
    }
609
0
}
610
611
static gboolean
612
g_scanner_key_equal (gconstpointer v1,
613
         gconstpointer v2)
614
0
{
615
0
  const GScannerKey *key1 = v1;
616
0
  const GScannerKey *key2 = v2;
617
  
618
0
  return (key1->scope_id == key2->scope_id) && (strcmp (key1->symbol, key2->symbol) == 0);
619
0
}
620
621
static guint
622
g_scanner_key_hash (gconstpointer v)
623
0
{
624
0
  const GScannerKey *key = v;
625
0
  gchar *c;
626
0
  guint h;
627
  
628
0
  h = key->scope_id;
629
0
  for (c = key->symbol; *c; c++)
630
0
    h = (h << 5) - h + *c;
631
  
632
0
  return h;
633
0
}
634
635
static inline GScannerKey*
636
g_scanner_lookup_internal (GScanner *scanner,
637
         guint   scope_id,
638
         const gchar  *symbol)
639
0
{
640
0
  GScannerKey *key_p;
641
0
  GScannerKey key;
642
  
643
0
  key.scope_id = scope_id;
644
  
645
0
  if (!scanner->config->case_sensitive)
646
0
    {
647
0
      gchar *d;
648
0
      const gchar *c;
649
      
650
0
      key.symbol = g_new (gchar, strlen (symbol) + 1);
651
0
      for (d = key.symbol, c = symbol; *c; c++, d++)
652
0
  *d = to_lower (*c);
653
0
      *d = 0;
654
0
      key_p = g_hash_table_lookup (scanner->symbol_table, &key);
655
0
      g_free (key.symbol);
656
0
    }
657
0
  else
658
0
    {
659
0
      key.symbol = (gchar*) symbol;
660
0
      key_p = g_hash_table_lookup (scanner->symbol_table, &key);
661
0
    }
662
  
663
0
  return key_p;
664
0
}
665
666
/**
667
 * g_scanner_add_symbol:
668
 * @scanner: a #GScanner
669
 * @symbol: the symbol to add
670
 * @value: the value of the symbol
671
 *
672
 * Adds a symbol to the default scope.
673
 *
674
 * Deprecated: 2.2: Use g_scanner_scope_add_symbol() instead.
675
 */
676
677
/**
678
 * g_scanner_scope_add_symbol:
679
 * @scanner: a #GScanner
680
 * @scope_id: the scope id
681
 * @symbol: the symbol to add
682
 * @value: the value of the symbol
683
 *
684
 * Adds a symbol to the given scope.
685
 */
686
void
687
g_scanner_scope_add_symbol (GScanner  *scanner,
688
          guint  scope_id,
689
          const gchar *symbol,
690
          gpointer   value)
691
0
{
692
0
  GScannerKey *key;
693
  
694
0
  g_return_if_fail (scanner != NULL);
695
0
  g_return_if_fail (symbol != NULL);
696
  
697
0
  key = g_scanner_lookup_internal (scanner, scope_id, symbol);
698
  
699
0
  if (!key)
700
0
    {
701
0
      key = g_new (GScannerKey, 1);
702
0
      key->scope_id = scope_id;
703
0
      key->symbol = g_strdup (symbol);
704
0
      key->value = value;
705
0
      if (!scanner->config->case_sensitive)
706
0
  {
707
0
    gchar *c;
708
    
709
0
    c = key->symbol;
710
0
    while (*c != 0)
711
0
      {
712
0
        *c = to_lower (*c);
713
0
        c++;
714
0
      }
715
0
  }
716
0
      g_hash_table_add (scanner->symbol_table, key);
717
0
    }
718
0
  else
719
0
    key->value = value;
720
0
}
721
722
/**
723
 * g_scanner_remove_symbol:
724
 * @scanner: a #GScanner
725
 * @symbol: the symbol to remove
726
 *
727
 * Removes a symbol from the default scope.
728
 *
729
 * Deprecated: 2.2: Use g_scanner_scope_remove_symbol() instead.
730
 */
731
732
/**
733
 * g_scanner_scope_remove_symbol:
734
 * @scanner: a #GScanner
735
 * @scope_id: the scope id
736
 * @symbol: the symbol to remove
737
 *
738
 * Removes a symbol from a scope.
739
 */
740
void
741
g_scanner_scope_remove_symbol (GScanner    *scanner,
742
             guint      scope_id,
743
             const gchar *symbol)
744
0
{
745
0
  GScannerKey *key;
746
  
747
0
  g_return_if_fail (scanner != NULL);
748
0
  g_return_if_fail (symbol != NULL);
749
  
750
0
  key = g_scanner_lookup_internal (scanner, scope_id, symbol);
751
  
752
0
  if (key)
753
0
    {
754
0
      g_hash_table_remove (scanner->symbol_table, key);
755
0
      g_free (key->symbol);
756
0
      g_free (key);
757
0
    }
758
0
}
759
760
/**
761
 * g_scanner_freeze_symbol_table:
762
 * @scanner: a #GScanner
763
 *
764
 * There is no reason to use this macro, since it does nothing.
765
 *
766
 * Deprecated: 2.2: This macro does nothing.
767
 */
768
769
/**
770
 * g_scanner_thaw_symbol_table:
771
 * @scanner: a #GScanner
772
 *
773
 * There is no reason to use this macro, since it does nothing.
774
 *
775
 * Deprecated: 2.2: This macro does nothing.
776
 */
777
778
/**
779
 * g_scanner_lookup_symbol:
780
 * @scanner: a #GScanner
781
 * @symbol: the symbol to look up
782
 *
783
 * Looks up a symbol in the current scope and return its value.
784
 * If the symbol is not bound in the current scope, %NULL is
785
 * returned.
786
 *
787
 * Returns: the value of @symbol in the current scope, or %NULL
788
 *     if @symbol is not bound in the current scope
789
 */
790
gpointer
791
g_scanner_lookup_symbol (GScanner *scanner,
792
       const gchar  *symbol)
793
0
{
794
0
  GScannerKey *key;
795
0
  guint scope_id;
796
  
797
0
  g_return_val_if_fail (scanner != NULL, NULL);
798
  
799
0
  if (!symbol)
800
0
    return NULL;
801
  
802
0
  scope_id = scanner->scope_id;
803
0
  key = g_scanner_lookup_internal (scanner, scope_id, symbol);
804
0
  if (!key && scope_id && scanner->config->scope_0_fallback)
805
0
    key = g_scanner_lookup_internal (scanner, 0, symbol);
806
  
807
0
  if (key)
808
0
    return key->value;
809
0
  else
810
0
    return NULL;
811
0
}
812
813
/**
814
 * g_scanner_scope_lookup_symbol:
815
 * @scanner: a #GScanner
816
 * @scope_id: the scope id
817
 * @symbol: the symbol to look up
818
 *
819
 * Looks up a symbol in a scope and return its value. If the
820
 * symbol is not bound in the scope, %NULL is returned.
821
 *
822
 * Returns: the value of @symbol in the given scope, or %NULL
823
 *     if @symbol is not bound in the given scope.
824
 *
825
 */
826
gpointer
827
g_scanner_scope_lookup_symbol (GScanner       *scanner,
828
             guint         scope_id,
829
             const gchar    *symbol)
830
0
{
831
0
  GScannerKey *key;
832
  
833
0
  g_return_val_if_fail (scanner != NULL, NULL);
834
  
835
0
  if (!symbol)
836
0
    return NULL;
837
  
838
0
  key = g_scanner_lookup_internal (scanner, scope_id, symbol);
839
  
840
0
  if (key)
841
0
    return key->value;
842
0
  else
843
0
    return NULL;
844
0
}
845
846
/**
847
 * g_scanner_set_scope:
848
 * @scanner: a #GScanner
849
 * @scope_id: the new scope id
850
 *
851
 * Sets the current scope.
852
 *
853
 * Returns: the old scope id
854
 */
855
guint
856
g_scanner_set_scope (GScanner     *scanner,
857
         guint       scope_id)
858
0
{
859
0
  guint old_scope_id;
860
  
861
0
  g_return_val_if_fail (scanner != NULL, 0);
862
  
863
0
  old_scope_id = scanner->scope_id;
864
0
  scanner->scope_id = scope_id;
865
  
866
0
  return old_scope_id;
867
0
}
868
869
static void
870
g_scanner_foreach_internal (gpointer  _key,
871
          gpointer  _value,
872
          gpointer  _user_data)
873
0
{
874
0
  GScannerKey *key;
875
0
  gpointer *d;
876
0
  GHFunc func;
877
0
  gpointer user_data;
878
0
  guint *scope_id;
879
  
880
0
  d = _user_data;
881
0
  func = (GHFunc) d[0];
882
0
  user_data = d[1];
883
0
  scope_id = d[2];
884
0
  key = _value;
885
  
886
0
  if (key->scope_id == *scope_id)
887
0
    func (key->symbol, key->value, user_data);
888
0
}
889
890
/**
891
 * g_scanner_foreach_symbol:
892
 * @scanner: a #GScanner
893
 * @func: the function to call with each symbol
894
 * @data: data to pass to the function
895
 *
896
 * Calls a function for each symbol in the default scope.
897
 *
898
 * Deprecated: 2.2: Use g_scanner_scope_foreach_symbol() instead.
899
 */
900
901
/**
902
 * g_scanner_scope_foreach_symbol:
903
 * @scanner: a #GScanner
904
 * @scope_id: the scope id
905
 * @func: the function to call for each symbol/value pair
906
 * @user_data: user data to pass to the function
907
 *
908
 * Calls the given function for each of the symbol/value pairs
909
 * in the given scope of the #GScanner. The function is passed
910
 * the symbol and value of each pair, and the given @user_data
911
 * parameter.
912
 */
913
void
914
g_scanner_scope_foreach_symbol (GScanner       *scanner,
915
        guint   scope_id,
916
        GHFunc    func,
917
        gpointer  user_data)
918
0
{
919
0
  gpointer d[3];
920
  
921
0
  g_return_if_fail (scanner != NULL);
922
  
923
0
  d[0] = (gpointer) func;
924
0
  d[1] = user_data;
925
0
  d[2] = &scope_id;
926
  
927
0
  g_hash_table_foreach (scanner->symbol_table, g_scanner_foreach_internal, d);
928
0
}
929
930
/**
931
 * g_scanner_peek_next_token:
932
 * @scanner: a #GScanner
933
 *
934
 * Parses the next token, without removing it from the input stream.
935
 * The token data is placed in the @next_token, @next_value, @next_line,
936
 * and @next_position fields of the #GScanner structure.
937
 *
938
 * Note that, while the token is not removed from the input stream
939
 * (i.e. the next call to g_scanner_get_next_token() will return the
940
 * same token), it will not be reevaluated. This can lead to surprising
941
 * results when changing scope or the scanner configuration after peeking
942
 * the next token. Getting the next token after switching the scope or
943
 * configuration will return whatever was peeked before, regardless of
944
 * any symbols that may have been added or removed in the new scope.
945
 *
946
 * Returns: the type of the token
947
 */
948
GTokenType
949
g_scanner_peek_next_token (GScanner *scanner)
950
0
{
951
0
  g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
952
  
953
0
  if (scanner->next_token == G_TOKEN_NONE)
954
0
    {
955
0
      scanner->next_line = scanner->line;
956
0
      scanner->next_position = scanner->position;
957
0
      g_scanner_get_token_i (scanner,
958
0
           &scanner->next_token,
959
0
           &scanner->next_value,
960
0
           &scanner->next_line,
961
0
           &scanner->next_position);
962
0
    }
963
  
964
0
  return scanner->next_token;
965
0
}
966
967
/**
968
 * g_scanner_get_next_token:
969
 * @scanner: a #GScanner
970
 *
971
 * Parses the next token just like g_scanner_peek_next_token()
972
 * and also removes it from the input stream. The token data is
973
 * placed in the @token, @value, @line, and @position fields of
974
 * the #GScanner structure.
975
 *
976
 * Returns: the type of the token
977
 */
978
GTokenType
979
g_scanner_get_next_token (GScanner  *scanner)
980
0
{
981
0
  g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
982
  
983
0
  if (scanner->next_token != G_TOKEN_NONE)
984
0
    {
985
0
      g_scanner_free_value (&scanner->token, &scanner->value);
986
      
987
0
      scanner->token = scanner->next_token;
988
0
      scanner->value = scanner->next_value;
989
0
      scanner->line = scanner->next_line;
990
0
      scanner->position = scanner->next_position;
991
0
      scanner->next_token = G_TOKEN_NONE;
992
0
    }
993
0
  else
994
0
    g_scanner_get_token_i (scanner,
995
0
         &scanner->token,
996
0
         &scanner->value,
997
0
         &scanner->line,
998
0
         &scanner->position);
999
  
1000
0
  return scanner->token;
1001
0
}
1002
1003
/**
1004
 * g_scanner_cur_token:
1005
 * @scanner: a #GScanner
1006
 *
1007
 * Gets the current token type. This is simply the @token
1008
 * field in the #GScanner structure.
1009
 *
1010
 * Returns: the current token type
1011
 */
1012
GTokenType
1013
g_scanner_cur_token (GScanner *scanner)
1014
0
{
1015
0
  g_return_val_if_fail (scanner != NULL, G_TOKEN_EOF);
1016
  
1017
0
  return scanner->token;
1018
0
}
1019
1020
/**
1021
 * g_scanner_cur_value:
1022
 * @scanner: a #GScanner
1023
 *
1024
 * Gets the current token value. This is simply the @value
1025
 * field in the #GScanner structure.
1026
 *
1027
 * Returns: the current token value
1028
 */
1029
GTokenValue
1030
g_scanner_cur_value (GScanner *scanner)
1031
0
{
1032
0
  GTokenValue v;
1033
  
1034
0
  v.v_int64 = 0;
1035
  
1036
0
  g_return_val_if_fail (scanner != NULL, v);
1037
1038
  /* MSC isn't capable of handling return scanner->value; ? */
1039
1040
0
  v = scanner->value;
1041
1042
0
  return v;
1043
0
}
1044
1045
/**
1046
 * g_scanner_cur_line:
1047
 * @scanner: a #GScanner
1048
 *
1049
 * Returns the current line in the input stream (counting
1050
 * from 1). This is the line of the last token parsed via
1051
 * g_scanner_get_next_token().
1052
 *
1053
 * Returns: the current line
1054
 */
1055
guint
1056
g_scanner_cur_line (GScanner *scanner)
1057
0
{
1058
0
  g_return_val_if_fail (scanner != NULL, 0);
1059
  
1060
0
  return scanner->line;
1061
0
}
1062
1063
/**
1064
 * g_scanner_cur_position:
1065
 * @scanner: a #GScanner
1066
 *
1067
 * Returns the current position in the current line (counting
1068
 * from 0). This is the position of the last token parsed via
1069
 * g_scanner_get_next_token().
1070
 *
1071
 * Returns: the current position on the line
1072
 */
1073
guint
1074
g_scanner_cur_position (GScanner *scanner)
1075
0
{
1076
0
  g_return_val_if_fail (scanner != NULL, 0);
1077
  
1078
0
  return scanner->position;
1079
0
}
1080
1081
/**
1082
 * g_scanner_eof:
1083
 * @scanner: a #GScanner
1084
 *
1085
 * Returns %TRUE if the scanner has reached the end of
1086
 * the file or text buffer.
1087
 *
1088
 * Returns: %TRUE if the scanner has reached the end of
1089
 *     the file or text buffer
1090
 */
1091
gboolean
1092
g_scanner_eof (GScanner *scanner)
1093
0
{
1094
0
  g_return_val_if_fail (scanner != NULL, TRUE);
1095
  
1096
0
  return scanner->token == G_TOKEN_EOF || scanner->token == G_TOKEN_ERROR;
1097
0
}
1098
1099
/**
1100
 * g_scanner_input_file:
1101
 * @scanner: a #GScanner
1102
 * @input_fd: a file descriptor
1103
 *
1104
 * Prepares to scan a file.
1105
 */
1106
void
1107
g_scanner_input_file (GScanner *scanner,
1108
          gint  input_fd)
1109
0
{
1110
0
  g_return_if_fail (scanner != NULL);
1111
0
  g_return_if_fail (input_fd >= 0);
1112
1113
0
  if (scanner->input_fd >= 0)
1114
0
    g_scanner_sync_file_offset (scanner);
1115
1116
0
  scanner->token = G_TOKEN_NONE;
1117
0
  scanner->value.v_int64 = 0;
1118
0
  scanner->line = 1;
1119
0
  scanner->position = 0;
1120
0
  scanner->next_token = G_TOKEN_NONE;
1121
1122
0
  scanner->input_fd = input_fd;
1123
0
  scanner->text = NULL;
1124
0
  scanner->text_end = NULL;
1125
1126
0
  if (!scanner->buffer)
1127
0
    scanner->buffer = g_new (gchar, READ_BUFFER_SIZE + 1);
1128
0
}
1129
1130
/**
1131
 * g_scanner_input_text:
1132
 * @scanner: a #GScanner
1133
 * @text: the text buffer to scan
1134
 * @text_len: the length of the text buffer
1135
 *
1136
 * Prepares to scan a text buffer.
1137
 */
1138
void
1139
g_scanner_input_text (GScanner    *scanner,
1140
          const gchar *text,
1141
          guint    text_len)
1142
0
{
1143
0
  g_return_if_fail (scanner != NULL);
1144
0
  if (text_len)
1145
0
    g_return_if_fail (text != NULL);
1146
0
  else
1147
0
    text = NULL;
1148
1149
0
  if (scanner->input_fd >= 0)
1150
0
    g_scanner_sync_file_offset (scanner);
1151
1152
0
  scanner->token = G_TOKEN_NONE;
1153
0
  scanner->value.v_int64 = 0;
1154
0
  scanner->line = 1;
1155
0
  scanner->position = 0;
1156
0
  scanner->next_token = G_TOKEN_NONE;
1157
1158
0
  scanner->input_fd = -1;
1159
0
  scanner->text = text;
1160
0
  scanner->text_end = text + text_len;
1161
1162
0
  if (scanner->buffer)
1163
0
    {
1164
0
      g_free (scanner->buffer);
1165
0
      scanner->buffer = NULL;
1166
0
    }
1167
0
}
1168
1169
static guchar
1170
g_scanner_peek_next_char (GScanner *scanner)
1171
0
{
1172
0
  if (scanner->text < scanner->text_end)
1173
0
    {
1174
0
      return *scanner->text;
1175
0
    }
1176
0
  else if (scanner->input_fd >= 0)
1177
0
    {
1178
0
      gint count;
1179
0
      gchar *buffer;
1180
1181
0
      buffer = scanner->buffer;
1182
0
      do
1183
0
  {
1184
0
    count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE);
1185
0
  }
1186
0
      while (count == -1 && (errno == EINTR || errno == EAGAIN));
1187
1188
0
      if (count < 1)
1189
0
  {
1190
0
    scanner->input_fd = -1;
1191
1192
0
    return 0;
1193
0
  }
1194
0
      else
1195
0
  {
1196
0
    scanner->text = buffer;
1197
0
    scanner->text_end = buffer + count;
1198
1199
0
    return *buffer;
1200
0
  }
1201
0
    }
1202
0
  else
1203
0
    return 0;
1204
0
}
1205
1206
/**
1207
 * g_scanner_sync_file_offset:
1208
 * @scanner: a #GScanner
1209
 *
1210
 * Rewinds the filedescriptor to the current buffer position
1211
 * and blows the file read ahead buffer. This is useful for
1212
 * third party uses of the scanners filedescriptor, which hooks
1213
 * onto the current scanning position.
1214
 */
1215
void
1216
g_scanner_sync_file_offset (GScanner *scanner)
1217
0
{
1218
0
  g_return_if_fail (scanner != NULL);
1219
1220
  /* for file input, rewind the filedescriptor to the current
1221
   * buffer position and blow the file read ahead buffer. useful
1222
   * for third party uses of our file descriptor, which hooks 
1223
   * onto the current scanning position.
1224
   */
1225
1226
0
  if (scanner->input_fd >= 0 && scanner->text_end > scanner->text)
1227
0
    {
1228
0
      gint buffered;
1229
1230
0
      buffered = scanner->text_end - scanner->text;
1231
0
      if (lseek (scanner->input_fd, - buffered, SEEK_CUR) >= 0)
1232
0
  {
1233
    /* we succeeded, blow our buffer's contents now */
1234
0
    scanner->text = NULL;
1235
0
    scanner->text_end = NULL;
1236
0
  }
1237
0
      else
1238
0
  errno = 0;
1239
0
    }
1240
0
}
1241
1242
static guchar
1243
g_scanner_get_char (GScanner  *scanner,
1244
        guint *line_p,
1245
        guint *position_p)
1246
0
{
1247
0
  guchar fchar;
1248
1249
0
  if (scanner->text < scanner->text_end)
1250
0
    fchar = *(scanner->text++);
1251
0
  else if (scanner->input_fd >= 0)
1252
0
    {
1253
0
      gint count;
1254
0
      gchar *buffer;
1255
1256
0
      buffer = scanner->buffer;
1257
0
      do
1258
0
  {
1259
0
    count = read (scanner->input_fd, buffer, READ_BUFFER_SIZE);
1260
0
  }
1261
0
      while (count == -1 && (errno == EINTR || errno == EAGAIN));
1262
1263
0
      if (count < 1)
1264
0
  {
1265
0
    scanner->input_fd = -1;
1266
0
    fchar = 0;
1267
0
  }
1268
0
      else
1269
0
  {
1270
0
    scanner->text = buffer + 1;
1271
0
    scanner->text_end = buffer + count;
1272
0
    fchar = *buffer;
1273
0
    if (!fchar)
1274
0
      {
1275
0
        g_scanner_sync_file_offset (scanner);
1276
0
        scanner->text_end = scanner->text;
1277
0
        scanner->input_fd = -1;
1278
0
      }
1279
0
  }
1280
0
    }
1281
0
  else
1282
0
    fchar = 0;
1283
  
1284
0
  if (fchar == '\n')
1285
0
    {
1286
0
      (*position_p) = 0;
1287
0
      (*line_p)++;
1288
0
    }
1289
0
  else if (fchar)
1290
0
    {
1291
0
      (*position_p)++;
1292
0
    }
1293
  
1294
0
  return fchar;
1295
0
}
1296
1297
/**
1298
 * g_scanner_unexp_token:
1299
 * @scanner: a #GScanner
1300
 * @expected_token: the expected token
1301
 * @identifier_spec: a string describing how the scanner's user
1302
 *     refers to identifiers (%NULL defaults to "identifier").
1303
 *     This is used if @expected_token is %G_TOKEN_IDENTIFIER or
1304
 *     %G_TOKEN_IDENTIFIER_NULL.
1305
 * @symbol_spec: a string describing how the scanner's user refers
1306
 *     to symbols (%NULL defaults to "symbol"). This is used if
1307
 *     @expected_token is %G_TOKEN_SYMBOL or any token value greater
1308
 *     than %G_TOKEN_LAST.
1309
 * @symbol_name: the name of the symbol, if the scanner's current
1310
 *     token is a symbol.
1311
 * @message: a message string to output at the end of the
1312
 *     warning/error, or %NULL.
1313
 * @is_error: if %TRUE it is output as an error. If %FALSE it is
1314
 *     output as a warning.
1315
 *
1316
 * Outputs a message through the scanner's msg_handler,
1317
 * resulting from an unexpected token in the input stream.
1318
 * Note that you should not call g_scanner_peek_next_token()
1319
 * followed by g_scanner_unexp_token() without an intermediate
1320
 * call to g_scanner_get_next_token(), as g_scanner_unexp_token()
1321
 * evaluates the scanner's current token (not the peeked token)
1322
 * to construct part of the message.
1323
 */
1324
void
1325
g_scanner_unexp_token (GScanner   *scanner,
1326
           GTokenType  expected_token,
1327
           const gchar  *identifier_spec,
1328
           const gchar  *symbol_spec,
1329
           const gchar  *symbol_name,
1330
           const gchar  *message,
1331
           gint    is_error)
1332
0
{
1333
0
  gchar *token_string;
1334
0
  guint token_string_len;
1335
0
  gchar *expected_string;
1336
0
  guint expected_string_len;
1337
0
  gchar *message_prefix;
1338
0
  gboolean print_unexp;
1339
0
  void (*msg_handler) (GScanner*, const gchar*, ...);
1340
  
1341
0
  g_return_if_fail (scanner != NULL);
1342
  
1343
0
  if (is_error)
1344
0
    msg_handler = g_scanner_error;
1345
0
  else
1346
0
    msg_handler = g_scanner_warn;
1347
  
1348
0
  if (!identifier_spec)
1349
0
    identifier_spec = "identifier";
1350
0
  if (!symbol_spec)
1351
0
    symbol_spec = "symbol";
1352
  
1353
0
  token_string_len = 56;
1354
0
  token_string = g_new (gchar, token_string_len + 1);
1355
0
  expected_string_len = 64;
1356
0
  expected_string = g_new (gchar, expected_string_len + 1);
1357
0
  print_unexp = TRUE;
1358
  
1359
0
  switch (scanner->token)
1360
0
    {
1361
0
    case G_TOKEN_EOF:
1362
0
      _g_snprintf (token_string, token_string_len, "end of file");
1363
0
      break;
1364
      
1365
0
    default:
1366
0
      if (scanner->token >= 1 && scanner->token <= 255)
1367
0
  {
1368
0
    if ((scanner->token >= ' ' && scanner->token <= '~') ||
1369
0
        strchr (scanner->config->cset_identifier_first, scanner->token) ||
1370
0
        strchr (scanner->config->cset_identifier_nth, scanner->token))
1371
0
      _g_snprintf (token_string, token_string_len, "character '%c'", scanner->token);
1372
0
    else
1373
0
      _g_snprintf (token_string, token_string_len, "character '\\%o'", scanner->token);
1374
0
    break;
1375
0
  }
1376
0
      else if (!scanner->config->symbol_2_token)
1377
0
  {
1378
0
    _g_snprintf (token_string, token_string_len, "(unknown) token <%d>", scanner->token);
1379
0
    break;
1380
0
  }
1381
0
      G_GNUC_FALLTHROUGH;
1382
0
    case G_TOKEN_SYMBOL:
1383
0
      if (expected_token == G_TOKEN_SYMBOL ||
1384
0
    (scanner->config->symbol_2_token &&
1385
0
     expected_token > G_TOKEN_LAST))
1386
0
  print_unexp = FALSE;
1387
0
      if (symbol_name)
1388
0
  _g_snprintf (token_string,
1389
0
         token_string_len,
1390
0
         "%s%s '%s'",
1391
0
         print_unexp ? "" : "invalid ",
1392
0
         symbol_spec,
1393
0
         symbol_name);
1394
0
      else
1395
0
  _g_snprintf (token_string,
1396
0
         token_string_len,
1397
0
         "%s%s",
1398
0
         print_unexp ? "" : "invalid ",
1399
0
         symbol_spec);
1400
0
      break;
1401
      
1402
0
    case G_TOKEN_ERROR:
1403
0
      print_unexp = FALSE;
1404
0
      expected_token = G_TOKEN_NONE;
1405
0
      switch (scanner->value.v_error)
1406
0
  {
1407
0
  case G_ERR_UNEXP_EOF:
1408
0
    _g_snprintf (token_string, token_string_len, "scanner: unexpected end of file");
1409
0
    break;
1410
    
1411
0
  case G_ERR_UNEXP_EOF_IN_STRING:
1412
0
    _g_snprintf (token_string, token_string_len, "scanner: unterminated string constant");
1413
0
    break;
1414
    
1415
0
  case G_ERR_UNEXP_EOF_IN_COMMENT:
1416
0
    _g_snprintf (token_string, token_string_len, "scanner: unterminated comment");
1417
0
    break;
1418
    
1419
0
  case G_ERR_NON_DIGIT_IN_CONST:
1420
0
    _g_snprintf (token_string, token_string_len, "scanner: non digit in constant");
1421
0
    break;
1422
    
1423
0
  case G_ERR_FLOAT_RADIX:
1424
0
    _g_snprintf (token_string, token_string_len, "scanner: invalid radix for floating constant");
1425
0
    break;
1426
    
1427
0
  case G_ERR_FLOAT_MALFORMED:
1428
0
    _g_snprintf (token_string, token_string_len, "scanner: malformed floating constant");
1429
0
    break;
1430
    
1431
0
  case G_ERR_DIGIT_RADIX:
1432
0
    _g_snprintf (token_string, token_string_len, "scanner: digit is beyond radix");
1433
0
    break;
1434
    
1435
0
  case G_ERR_UNKNOWN:
1436
0
  default:
1437
0
    _g_snprintf (token_string, token_string_len, "scanner: unknown error");
1438
0
    break;
1439
0
  }
1440
0
      break;
1441
      
1442
0
    case G_TOKEN_CHAR:
1443
0
      _g_snprintf (token_string, token_string_len, "character '%c'", scanner->value.v_char);
1444
0
      break;
1445
      
1446
0
    case G_TOKEN_IDENTIFIER:
1447
0
    case G_TOKEN_IDENTIFIER_NULL:
1448
0
      if (expected_token == G_TOKEN_IDENTIFIER ||
1449
0
    expected_token == G_TOKEN_IDENTIFIER_NULL)
1450
0
  print_unexp = FALSE;
1451
0
      _g_snprintf (token_string,
1452
0
      token_string_len,
1453
0
      "%s%s '%s'",
1454
0
      print_unexp ? "" : "invalid ",
1455
0
      identifier_spec,
1456
0
      scanner->token == G_TOKEN_IDENTIFIER ? scanner->value.v_string : "null");
1457
0
      break;
1458
      
1459
0
    case G_TOKEN_BINARY:
1460
0
    case G_TOKEN_OCTAL:
1461
0
    case G_TOKEN_INT:
1462
0
    case G_TOKEN_HEX:
1463
0
      if (scanner->config->store_int64)
1464
0
  _g_snprintf (token_string, token_string_len, "number '%" G_GUINT64_FORMAT "'", scanner->value.v_int64);
1465
0
      else
1466
0
  _g_snprintf (token_string, token_string_len, "number '%lu'", scanner->value.v_int);
1467
0
      break;
1468
      
1469
0
    case G_TOKEN_FLOAT:
1470
0
      _g_snprintf (token_string, token_string_len, "number '%.3f'", scanner->value.v_float);
1471
0
      break;
1472
      
1473
0
    case G_TOKEN_STRING:
1474
0
      if (expected_token == G_TOKEN_STRING)
1475
0
  print_unexp = FALSE;
1476
0
      _g_snprintf (token_string,
1477
0
       token_string_len,
1478
0
       "%s%sstring constant \"%s\"",
1479
0
       print_unexp ? "" : "invalid ",
1480
0
       scanner->value.v_string[0] == 0 ? "empty " : "",
1481
0
       scanner->value.v_string);
1482
0
      token_string[token_string_len - 2] = '"';
1483
0
      token_string[token_string_len - 1] = 0;
1484
0
      break;
1485
      
1486
0
    case G_TOKEN_COMMENT_SINGLE:
1487
0
    case G_TOKEN_COMMENT_MULTI:
1488
0
      _g_snprintf (token_string, token_string_len, "comment");
1489
0
      break;
1490
      
1491
0
    case G_TOKEN_NONE:
1492
      /* somehow the user's parsing code is screwed, there isn't much
1493
       * we can do about it.
1494
       * Note, a common case to trigger this is
1495
       * g_scanner_peek_next_token(); g_scanner_unexp_token();
1496
       * without an intermediate g_scanner_get_next_token().
1497
       */
1498
0
      g_assert_not_reached ();
1499
0
      break;
1500
0
    }
1501
  
1502
  
1503
0
  switch (expected_token)
1504
0
    {
1505
0
      gboolean need_valid;
1506
0
      gchar *tstring;
1507
0
    case G_TOKEN_EOF:
1508
0
      _g_snprintf (expected_string, expected_string_len, "end of file");
1509
0
      break;
1510
0
    default:
1511
0
      if (expected_token >= 1 && expected_token <= 255)
1512
0
  {
1513
0
    if ((expected_token >= ' ' && expected_token <= '~') ||
1514
0
        strchr (scanner->config->cset_identifier_first, expected_token) ||
1515
0
        strchr (scanner->config->cset_identifier_nth, expected_token))
1516
0
      _g_snprintf (expected_string, expected_string_len, "character '%c'", expected_token);
1517
0
    else
1518
0
      _g_snprintf (expected_string, expected_string_len, "character '\\%o'", expected_token);
1519
0
    break;
1520
0
  }
1521
0
      else if (!scanner->config->symbol_2_token)
1522
0
  {
1523
0
    _g_snprintf (expected_string, expected_string_len, "(unknown) token <%d>", expected_token);
1524
0
    break;
1525
0
  }
1526
0
      G_GNUC_FALLTHROUGH;
1527
0
    case G_TOKEN_SYMBOL:
1528
0
      need_valid = (scanner->token == G_TOKEN_SYMBOL ||
1529
0
        (scanner->config->symbol_2_token &&
1530
0
         scanner->token > G_TOKEN_LAST));
1531
0
      _g_snprintf (expected_string,
1532
0
       expected_string_len,
1533
0
       "%s%s",
1534
0
       need_valid ? "valid " : "",
1535
0
       symbol_spec);
1536
      /* FIXME: should we attempt to look up the symbol_name for symbol_2_token? */
1537
0
      break;
1538
0
    case G_TOKEN_CHAR:
1539
0
      _g_snprintf (expected_string, expected_string_len, "%scharacter",
1540
0
       scanner->token == G_TOKEN_CHAR ? "valid " : "");
1541
0
      break;
1542
0
    case G_TOKEN_BINARY:
1543
0
      tstring = "binary";
1544
0
      _g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
1545
0
       scanner->token == expected_token ? "valid " : "", tstring);
1546
0
      break;
1547
0
    case G_TOKEN_OCTAL:
1548
0
      tstring = "octal";
1549
0
      _g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
1550
0
       scanner->token == expected_token ? "valid " : "", tstring);
1551
0
      break;
1552
0
    case G_TOKEN_INT:
1553
0
      tstring = "integer";
1554
0
      _g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
1555
0
       scanner->token == expected_token ? "valid " : "", tstring);
1556
0
      break;
1557
0
    case G_TOKEN_HEX:
1558
0
      tstring = "hexadecimal";
1559
0
      _g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
1560
0
       scanner->token == expected_token ? "valid " : "", tstring);
1561
0
      break;
1562
0
    case G_TOKEN_FLOAT:
1563
0
      tstring = "float";
1564
0
      _g_snprintf (expected_string, expected_string_len, "%snumber (%s)",
1565
0
       scanner->token == expected_token ? "valid " : "", tstring);
1566
0
      break;
1567
0
    case G_TOKEN_STRING:
1568
0
      _g_snprintf (expected_string,
1569
0
       expected_string_len,
1570
0
       "%sstring constant",
1571
0
       scanner->token == G_TOKEN_STRING ? "valid " : "");
1572
0
      break;
1573
0
    case G_TOKEN_IDENTIFIER:
1574
0
    case G_TOKEN_IDENTIFIER_NULL:
1575
0
      need_valid = (scanner->token == G_TOKEN_IDENTIFIER_NULL ||
1576
0
        scanner->token == G_TOKEN_IDENTIFIER);
1577
0
      _g_snprintf (expected_string,
1578
0
       expected_string_len,
1579
0
       "%s%s",
1580
0
       need_valid ? "valid " : "",
1581
0
       identifier_spec);
1582
0
      break;
1583
0
    case G_TOKEN_COMMENT_SINGLE:
1584
0
      tstring = "single-line";
1585
0
      _g_snprintf (expected_string, expected_string_len, "%scomment (%s)",
1586
0
       scanner->token == expected_token ? "valid " : "", tstring);
1587
0
      break;
1588
0
    case G_TOKEN_COMMENT_MULTI:
1589
0
      tstring = "multi-line";
1590
0
      _g_snprintf (expected_string, expected_string_len, "%scomment (%s)",
1591
0
       scanner->token == expected_token ? "valid " : "", tstring);
1592
0
      break;
1593
0
    case G_TOKEN_NONE:
1594
0
    case G_TOKEN_ERROR:
1595
      /* this is handled upon printout */
1596
0
      break;
1597
0
    }
1598
  
1599
0
  if (message && message[0] != 0)
1600
0
    message_prefix = " - ";
1601
0
  else
1602
0
    {
1603
0
      message_prefix = "";
1604
0
      message = "";
1605
0
    }
1606
0
  if (expected_token == G_TOKEN_ERROR)
1607
0
    {
1608
0
      msg_handler (scanner,
1609
0
       "failure around %s%s%s",
1610
0
       token_string,
1611
0
       message_prefix,
1612
0
       message);
1613
0
    }
1614
0
  else if (expected_token == G_TOKEN_NONE)
1615
0
    {
1616
0
      if (print_unexp)
1617
0
  msg_handler (scanner,
1618
0
         "unexpected %s%s%s",
1619
0
         token_string,
1620
0
         message_prefix,
1621
0
         message);
1622
0
      else
1623
0
  msg_handler (scanner,
1624
0
         "%s%s%s",
1625
0
         token_string,
1626
0
         message_prefix,
1627
0
         message);
1628
0
    }
1629
0
  else
1630
0
    {
1631
0
      if (print_unexp)
1632
0
  msg_handler (scanner,
1633
0
         "unexpected %s, expected %s%s%s",
1634
0
         token_string,
1635
0
         expected_string,
1636
0
         message_prefix,
1637
0
         message);
1638
0
      else
1639
0
  msg_handler (scanner,
1640
0
         "%s, expected %s%s%s",
1641
0
         token_string,
1642
0
         expected_string,
1643
0
         message_prefix,
1644
0
         message);
1645
0
    }
1646
  
1647
0
  g_free (token_string);
1648
0
  g_free (expected_string);
1649
0
}
1650
1651
static void
1652
g_scanner_get_token_i (GScanner *scanner,
1653
           GTokenType *token_p,
1654
           GTokenValue  *value_p,
1655
           guint    *line_p,
1656
           guint    *position_p)
1657
0
{
1658
0
  do
1659
0
    {
1660
0
      g_scanner_free_value (token_p, value_p);
1661
0
      g_scanner_get_token_ll (scanner, token_p, value_p, line_p, position_p);
1662
0
    }
1663
0
  while (((*token_p > 0 && *token_p < 256) &&
1664
0
    strchr (scanner->config->cset_skip_characters, *token_p)) ||
1665
0
   (*token_p == G_TOKEN_CHAR &&
1666
0
    strchr (scanner->config->cset_skip_characters, value_p->v_char)) ||
1667
0
   (*token_p == G_TOKEN_COMMENT_MULTI &&
1668
0
    scanner->config->skip_comment_multi) ||
1669
0
   (*token_p == G_TOKEN_COMMENT_SINGLE &&
1670
0
    scanner->config->skip_comment_single));
1671
  
1672
0
  switch (*token_p)
1673
0
    {
1674
0
    case G_TOKEN_IDENTIFIER:
1675
0
      if (scanner->config->identifier_2_string)
1676
0
  *token_p = G_TOKEN_STRING;
1677
0
      break;
1678
      
1679
0
    case G_TOKEN_SYMBOL:
1680
0
      if (scanner->config->symbol_2_token)
1681
0
  *token_p = (GTokenType) value_p->v_symbol;
1682
0
      break;
1683
      
1684
0
    case G_TOKEN_BINARY:
1685
0
    case G_TOKEN_OCTAL:
1686
0
    case G_TOKEN_HEX:
1687
0
      if (scanner->config->numbers_2_int)
1688
0
  *token_p = G_TOKEN_INT;
1689
0
      break;
1690
      
1691
0
    default:
1692
0
      break;
1693
0
    }
1694
  
1695
0
  if (*token_p == G_TOKEN_INT &&
1696
0
      scanner->config->int_2_float)
1697
0
    {
1698
0
      *token_p = G_TOKEN_FLOAT;
1699
1700
      /* Have to assign through a temporary variable to avoid undefined behaviour
1701
       * by copying between potentially-overlapping union members. */
1702
0
      if (scanner->config->store_int64)
1703
0
        {
1704
0
          gint64 temp = value_p->v_int64;
1705
0
          value_p->v_float = temp;
1706
0
        }
1707
0
      else
1708
0
        {
1709
0
          gint temp = value_p->v_int;
1710
0
          value_p->v_float = temp;
1711
0
        }
1712
0
    }
1713
  
1714
0
  errno = 0;
1715
0
}
1716
1717
static void
1718
g_scanner_get_token_ll  (GScanner *scanner,
1719
       GTokenType *token_p,
1720
       GTokenValue  *value_p,
1721
       guint    *line_p,
1722
       guint    *position_p)
1723
0
{
1724
0
  GScannerConfig *config;
1725
0
  GTokenType     token;
1726
0
  gboolean     in_comment_multi;
1727
0
  gboolean     in_comment_single;
1728
0
  gboolean     in_string_sq;
1729
0
  gboolean     in_string_dq;
1730
0
  GString   *gstring;
1731
0
  GTokenValue    value;
1732
0
  guchar     ch;
1733
  
1734
0
  config = scanner->config;
1735
0
  (*value_p).v_int64 = 0;
1736
  
1737
0
  if ((scanner->text >= scanner->text_end && scanner->input_fd < 0) ||
1738
0
      scanner->token == G_TOKEN_EOF)
1739
0
    {
1740
0
      *token_p = G_TOKEN_EOF;
1741
0
      return;
1742
0
    }
1743
  
1744
0
  in_comment_multi = FALSE;
1745
0
  in_comment_single = FALSE;
1746
0
  in_string_sq = FALSE;
1747
0
  in_string_dq = FALSE;
1748
0
  gstring = NULL;
1749
  
1750
0
  do /* while (ch != 0) */
1751
0
    {
1752
0
      gboolean dotted_float = FALSE;
1753
      
1754
0
      ch = g_scanner_get_char (scanner, line_p, position_p);
1755
      
1756
0
      value.v_int64 = 0;
1757
0
      token = G_TOKEN_NONE;
1758
      
1759
      /* this is *evil*, but needed ;(
1760
       * we first check for identifier first character, because  it
1761
       * might interfere with other key chars like slashes or numbers
1762
       */
1763
0
      if (config->scan_identifier &&
1764
0
    ch && strchr (config->cset_identifier_first, ch))
1765
0
  goto identifier_precedence;
1766
      
1767
0
      switch (ch)
1768
0
  {
1769
0
  case 0:
1770
0
    token = G_TOKEN_EOF;
1771
0
    (*position_p)++;
1772
    /* ch = 0; */
1773
0
    break;
1774
    
1775
0
  case '/':
1776
0
    if (!config->scan_comment_multi ||
1777
0
        g_scanner_peek_next_char (scanner) != '*')
1778
0
      goto default_case;
1779
0
    g_scanner_get_char (scanner, line_p, position_p);
1780
0
    token = G_TOKEN_COMMENT_MULTI;
1781
0
    in_comment_multi = TRUE;
1782
0
    gstring = g_string_new (NULL);
1783
0
    while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1784
0
      {
1785
0
        if (ch == '*' && g_scanner_peek_next_char (scanner) == '/')
1786
0
    {
1787
0
      g_scanner_get_char (scanner, line_p, position_p);
1788
0
      in_comment_multi = FALSE;
1789
0
      break;
1790
0
    }
1791
0
        else
1792
0
    gstring = g_string_append_c (gstring, ch);
1793
0
      }
1794
0
    ch = 0;
1795
0
    break;
1796
    
1797
0
  case '\'':
1798
0
    if (!config->scan_string_sq)
1799
0
      goto default_case;
1800
0
    token = G_TOKEN_STRING;
1801
0
    in_string_sq = TRUE;
1802
0
    gstring = g_string_new (NULL);
1803
0
    while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1804
0
      {
1805
0
        if (ch == '\'')
1806
0
    {
1807
0
      in_string_sq = FALSE;
1808
0
      break;
1809
0
    }
1810
0
        else
1811
0
    gstring = g_string_append_c (gstring, ch);
1812
0
      }
1813
0
    ch = 0;
1814
0
    break;
1815
    
1816
0
  case '"':
1817
0
    if (!config->scan_string_dq)
1818
0
      goto default_case;
1819
0
    token = G_TOKEN_STRING;
1820
0
    in_string_dq = TRUE;
1821
0
    gstring = g_string_new (NULL);
1822
0
    while ((ch = g_scanner_get_char (scanner, line_p, position_p)) != 0)
1823
0
      {
1824
0
        if (ch == '"')
1825
0
    {
1826
0
      in_string_dq = FALSE;
1827
0
      break;
1828
0
    }
1829
0
        else
1830
0
    {
1831
0
      if (ch == '\\')
1832
0
        {
1833
0
          ch = g_scanner_get_char (scanner, line_p, position_p);
1834
0
          switch (ch)
1835
0
      {
1836
0
        guint i;
1837
0
        guint fchar;
1838
        
1839
0
      case 0:
1840
0
        break;
1841
        
1842
0
      case '\\':
1843
0
        gstring = g_string_append_c (gstring, '\\');
1844
0
        break;
1845
        
1846
0
      case 'n':
1847
0
        gstring = g_string_append_c (gstring, '\n');
1848
0
        break;
1849
        
1850
0
      case 't':
1851
0
        gstring = g_string_append_c (gstring, '\t');
1852
0
        break;
1853
        
1854
0
      case 'r':
1855
0
        gstring = g_string_append_c (gstring, '\r');
1856
0
        break;
1857
        
1858
0
      case 'b':
1859
0
        gstring = g_string_append_c (gstring, '\b');
1860
0
        break;
1861
        
1862
0
      case 'f':
1863
0
        gstring = g_string_append_c (gstring, '\f');
1864
0
        break;
1865
        
1866
0
      case '0':
1867
0
      case '1':
1868
0
      case '2':
1869
0
      case '3':
1870
0
      case '4':
1871
0
      case '5':
1872
0
      case '6':
1873
0
      case '7':
1874
0
        i = ch - '0';
1875
0
        fchar = g_scanner_peek_next_char (scanner);
1876
0
        if (fchar >= '0' && fchar <= '7')
1877
0
          {
1878
0
            ch = g_scanner_get_char (scanner, line_p, position_p);
1879
0
            i = i * 8 + ch - '0';
1880
0
            fchar = g_scanner_peek_next_char (scanner);
1881
0
            if (fchar >= '0' && fchar <= '7')
1882
0
        {
1883
0
          ch = g_scanner_get_char (scanner, line_p, position_p);
1884
0
          i = i * 8 + ch - '0';
1885
0
        }
1886
0
          }
1887
0
        gstring = g_string_append_c (gstring, i);
1888
0
        break;
1889
        
1890
0
      default:
1891
0
        gstring = g_string_append_c (gstring, ch);
1892
0
        break;
1893
0
      }
1894
0
        }
1895
0
      else
1896
0
        gstring = g_string_append_c (gstring, ch);
1897
0
    }
1898
0
      }
1899
0
    ch = 0;
1900
0
    break;
1901
    
1902
0
  case '.':
1903
0
    if (!config->scan_float)
1904
0
      goto default_case;
1905
0
    token = G_TOKEN_FLOAT;
1906
0
    dotted_float = TRUE;
1907
0
    ch = g_scanner_get_char (scanner, line_p, position_p);
1908
0
    goto number_parsing;
1909
    
1910
0
  case '$':
1911
0
    if (!config->scan_hex_dollar)
1912
0
      goto default_case;
1913
0
    token = G_TOKEN_HEX;
1914
0
    ch = g_scanner_get_char (scanner, line_p, position_p);
1915
0
    goto number_parsing;
1916
    
1917
0
  case '0':
1918
0
    if (config->scan_octal)
1919
0
      token = G_TOKEN_OCTAL;
1920
0
    else
1921
0
      token = G_TOKEN_INT;
1922
0
    ch = g_scanner_peek_next_char (scanner);
1923
0
    if (config->scan_hex && (ch == 'x' || ch == 'X'))
1924
0
      {
1925
0
        token = G_TOKEN_HEX;
1926
0
        g_scanner_get_char (scanner, line_p, position_p);
1927
0
        ch = g_scanner_get_char (scanner, line_p, position_p);
1928
0
        if (ch == 0)
1929
0
    {
1930
0
      token = G_TOKEN_ERROR;
1931
0
      value.v_error = G_ERR_UNEXP_EOF;
1932
0
      (*position_p)++;
1933
0
      break;
1934
0
    }
1935
0
        if (g_scanner_char_2_num (ch, 16) < 0)
1936
0
    {
1937
0
      token = G_TOKEN_ERROR;
1938
0
      value.v_error = G_ERR_DIGIT_RADIX;
1939
0
      ch = 0;
1940
0
      break;
1941
0
    }
1942
0
      }
1943
0
    else if (config->scan_binary && (ch == 'b' || ch == 'B'))
1944
0
      {
1945
0
        token = G_TOKEN_BINARY;
1946
0
        g_scanner_get_char (scanner, line_p, position_p);
1947
0
        ch = g_scanner_get_char (scanner, line_p, position_p);
1948
0
        if (ch == 0)
1949
0
    {
1950
0
      token = G_TOKEN_ERROR;
1951
0
      value.v_error = G_ERR_UNEXP_EOF;
1952
0
      (*position_p)++;
1953
0
      break;
1954
0
    }
1955
0
        if (g_scanner_char_2_num (ch, 10) < 0)
1956
0
    {
1957
0
      token = G_TOKEN_ERROR;
1958
0
      value.v_error = G_ERR_NON_DIGIT_IN_CONST;
1959
0
      ch = 0;
1960
0
      break;
1961
0
    }
1962
0
      }
1963
0
    else
1964
0
      ch = '0';
1965
0
          G_GNUC_FALLTHROUGH;
1966
0
  case '1':
1967
0
  case '2':
1968
0
  case '3':
1969
0
  case '4':
1970
0
  case '5':
1971
0
  case '6':
1972
0
  case '7':
1973
0
  case '8':
1974
0
  case '9':
1975
0
  number_parsing:
1976
0
  {
1977
0
          gboolean in_number = TRUE;
1978
0
    gchar *endptr;
1979
    
1980
0
    if (token == G_TOKEN_NONE)
1981
0
      token = G_TOKEN_INT;
1982
    
1983
0
    gstring = g_string_new (dotted_float ? "0." : "");
1984
0
    gstring = g_string_append_c (gstring, ch);
1985
    
1986
0
    do /* while (in_number) */
1987
0
      {
1988
0
        gboolean is_E;
1989
        
1990
0
        is_E = token == G_TOKEN_FLOAT && (ch == 'e' || ch == 'E');
1991
        
1992
0
        ch = g_scanner_peek_next_char (scanner);
1993
        
1994
0
        if (g_scanner_char_2_num (ch, 36) >= 0 ||
1995
0
      (config->scan_float && ch == '.') ||
1996
0
      (is_E && (ch == '+' || ch == '-')))
1997
0
    {
1998
0
      ch = g_scanner_get_char (scanner, line_p, position_p);
1999
      
2000
0
      switch (ch)
2001
0
        {
2002
0
        case '.':
2003
0
          if (token != G_TOKEN_INT && token != G_TOKEN_OCTAL)
2004
0
      {
2005
0
        value.v_error = token == G_TOKEN_FLOAT ? G_ERR_FLOAT_MALFORMED : G_ERR_FLOAT_RADIX;
2006
0
        token = G_TOKEN_ERROR;
2007
0
        in_number = FALSE;
2008
0
      }
2009
0
          else
2010
0
      {
2011
0
        token = G_TOKEN_FLOAT;
2012
0
        gstring = g_string_append_c (gstring, ch);
2013
0
      }
2014
0
          break;
2015
          
2016
0
        case '0':
2017
0
        case '1':
2018
0
        case '2':
2019
0
        case '3':
2020
0
        case '4':
2021
0
        case '5':
2022
0
        case '6':
2023
0
        case '7':
2024
0
        case '8':
2025
0
        case '9':
2026
0
          gstring = g_string_append_c (gstring, ch);
2027
0
          break;
2028
          
2029
0
        case '-':
2030
0
        case '+':
2031
0
          if (token != G_TOKEN_FLOAT)
2032
0
      {
2033
0
        token = G_TOKEN_ERROR;
2034
0
        value.v_error = G_ERR_NON_DIGIT_IN_CONST;
2035
0
        in_number = FALSE;
2036
0
      }
2037
0
          else
2038
0
      gstring = g_string_append_c (gstring, ch);
2039
0
          break;
2040
          
2041
0
        case 'e':
2042
0
        case 'E':
2043
0
          if ((token != G_TOKEN_HEX && !config->scan_float) ||
2044
0
        (token != G_TOKEN_HEX &&
2045
0
         token != G_TOKEN_OCTAL &&
2046
0
         token != G_TOKEN_FLOAT &&
2047
0
         token != G_TOKEN_INT))
2048
0
      {
2049
0
        token = G_TOKEN_ERROR;
2050
0
        value.v_error = G_ERR_NON_DIGIT_IN_CONST;
2051
0
        in_number = FALSE;
2052
0
      }
2053
0
          else
2054
0
      {
2055
0
        if (token != G_TOKEN_HEX)
2056
0
          token = G_TOKEN_FLOAT;
2057
0
        gstring = g_string_append_c (gstring, ch);
2058
0
      }
2059
0
          break;
2060
          
2061
0
        default:
2062
0
          if (token != G_TOKEN_HEX)
2063
0
      {
2064
0
        token = G_TOKEN_ERROR;
2065
0
        value.v_error = G_ERR_NON_DIGIT_IN_CONST;
2066
0
        in_number = FALSE;
2067
0
      }
2068
0
          else
2069
0
      gstring = g_string_append_c (gstring, ch);
2070
0
          break;
2071
0
        }
2072
0
    }
2073
0
        else
2074
0
    in_number = FALSE;
2075
0
      }
2076
0
    while (in_number);
2077
    
2078
0
    endptr = NULL;
2079
0
    if (token == G_TOKEN_FLOAT)
2080
0
      value.v_float = g_strtod (gstring->str, &endptr);
2081
0
    else
2082
0
      {
2083
0
        guint64 ui64 = 0;
2084
0
        switch (token)
2085
0
    {
2086
0
    case G_TOKEN_BINARY:
2087
0
      ui64 = g_ascii_strtoull (gstring->str, &endptr, 2);
2088
0
      break;
2089
0
    case G_TOKEN_OCTAL:
2090
0
      ui64 = g_ascii_strtoull (gstring->str, &endptr, 8);
2091
0
      break;
2092
0
    case G_TOKEN_INT:
2093
0
      ui64 = g_ascii_strtoull (gstring->str, &endptr, 10);
2094
0
      break;
2095
0
    case G_TOKEN_HEX:
2096
0
      ui64 = g_ascii_strtoull (gstring->str, &endptr, 16);
2097
0
      break;
2098
0
    default: ;
2099
0
    }
2100
0
        if (scanner->config->store_int64)
2101
0
    value.v_int64 = ui64;
2102
0
        else
2103
0
    value.v_int = ui64;
2104
0
      }
2105
0
    if (endptr && *endptr)
2106
0
      {
2107
0
        token = G_TOKEN_ERROR;
2108
0
        if (*endptr == 'e' || *endptr == 'E')
2109
0
    value.v_error = G_ERR_NON_DIGIT_IN_CONST;
2110
0
        else
2111
0
    value.v_error = G_ERR_DIGIT_RADIX;
2112
0
      }
2113
0
    g_string_free (gstring, TRUE);
2114
0
    gstring = NULL;
2115
0
    ch = 0;
2116
0
  } /* number_parsing:... */
2117
0
  break;
2118
  
2119
0
  default:
2120
0
  default_case:
2121
0
  {
2122
0
    if (config->cpair_comment_single &&
2123
0
        ch == config->cpair_comment_single[0])
2124
0
      {
2125
0
        token = G_TOKEN_COMMENT_SINGLE;
2126
0
        in_comment_single = TRUE;
2127
0
        gstring = g_string_new (NULL);
2128
0
        ch = g_scanner_get_char (scanner, line_p, position_p);
2129
0
        while (ch != 0)
2130
0
    {
2131
0
      if (ch == config->cpair_comment_single[1])
2132
0
        {
2133
0
          in_comment_single = FALSE;
2134
0
          ch = 0;
2135
0
          break;
2136
0
        }
2137
      
2138
0
      gstring = g_string_append_c (gstring, ch);
2139
0
      ch = g_scanner_get_char (scanner, line_p, position_p);
2140
0
    }
2141
        /* ignore a missing newline at EOF for single line comments */
2142
0
        if (in_comment_single &&
2143
0
      config->cpair_comment_single[1] == '\n')
2144
0
    in_comment_single = FALSE;
2145
0
      }
2146
0
    else if (config->scan_identifier && ch &&
2147
0
       strchr (config->cset_identifier_first, ch))
2148
0
      {
2149
0
      identifier_precedence:
2150
        
2151
0
        if (config->cset_identifier_nth && ch &&
2152
0
      strchr (config->cset_identifier_nth,
2153
0
        g_scanner_peek_next_char (scanner)))
2154
0
    {
2155
0
      token = G_TOKEN_IDENTIFIER;
2156
0
      gstring = g_string_new (NULL);
2157
0
      gstring = g_string_append_c (gstring, ch);
2158
0
      do
2159
0
        {
2160
0
          ch = g_scanner_get_char (scanner, line_p, position_p);
2161
0
          gstring = g_string_append_c (gstring, ch);
2162
0
          ch = g_scanner_peek_next_char (scanner);
2163
0
        }
2164
0
      while (ch && strchr (config->cset_identifier_nth, ch));
2165
0
      ch = 0;
2166
0
    }
2167
0
        else if (config->scan_identifier_1char)
2168
0
    {
2169
0
      token = G_TOKEN_IDENTIFIER;
2170
0
      value.v_identifier = g_new0 (gchar, 2);
2171
0
      value.v_identifier[0] = ch;
2172
0
      ch = 0;
2173
0
    }
2174
0
      }
2175
0
    if (ch)
2176
0
      {
2177
0
        if (config->char_2_token)
2178
0
    token = ch;
2179
0
        else
2180
0
    {
2181
0
      token = G_TOKEN_CHAR;
2182
0
      value.v_char = ch;
2183
0
    }
2184
0
        ch = 0;
2185
0
      }
2186
0
  } /* default_case:... */
2187
0
  break;
2188
0
  }
2189
0
      g_assert (ch == 0 && token != G_TOKEN_NONE); /* paranoid */
2190
0
    }
2191
0
  while (ch != 0);
2192
  
2193
0
  if (in_comment_multi || in_comment_single ||
2194
0
      in_string_sq || in_string_dq)
2195
0
    {
2196
0
      token = G_TOKEN_ERROR;
2197
0
      if (gstring)
2198
0
  {
2199
0
    g_string_free (gstring, TRUE);
2200
0
    gstring = NULL;
2201
0
  }
2202
0
      (*position_p)++;
2203
0
      if (in_comment_multi || in_comment_single)
2204
0
  value.v_error = G_ERR_UNEXP_EOF_IN_COMMENT;
2205
0
      else /* (in_string_sq || in_string_dq) */
2206
0
  value.v_error = G_ERR_UNEXP_EOF_IN_STRING;
2207
0
    }
2208
  
2209
0
  if (gstring)
2210
0
    {
2211
0
      value.v_string = g_string_free (gstring, FALSE);
2212
0
      gstring = NULL;
2213
0
    }
2214
  
2215
0
  if (token == G_TOKEN_IDENTIFIER)
2216
0
    {
2217
0
      if (config->scan_symbols)
2218
0
  {
2219
0
    GScannerKey *key;
2220
0
    guint scope_id;
2221
    
2222
0
    scope_id = scanner->scope_id;
2223
0
    key = g_scanner_lookup_internal (scanner, scope_id, value.v_identifier);
2224
0
    if (!key && scope_id && scanner->config->scope_0_fallback)
2225
0
      key = g_scanner_lookup_internal (scanner, 0, value.v_identifier);
2226
    
2227
0
    if (key)
2228
0
      {
2229
0
        g_free (value.v_identifier);
2230
0
        token = G_TOKEN_SYMBOL;
2231
0
        value.v_symbol = key->value;
2232
0
      }
2233
0
  }
2234
      
2235
0
      if (token == G_TOKEN_IDENTIFIER &&
2236
0
    config->scan_identifier_NULL &&
2237
0
    strlen (value.v_identifier) == 4)
2238
0
  {
2239
0
    gchar *null_upper = "NULL";
2240
0
    gchar *null_lower = "null";
2241
    
2242
0
    if (scanner->config->case_sensitive)
2243
0
      {
2244
0
        if (value.v_identifier[0] == null_upper[0] &&
2245
0
      value.v_identifier[1] == null_upper[1] &&
2246
0
      value.v_identifier[2] == null_upper[2] &&
2247
0
      value.v_identifier[3] == null_upper[3])
2248
0
    token = G_TOKEN_IDENTIFIER_NULL;
2249
0
      }
2250
0
    else
2251
0
      {
2252
0
        if ((value.v_identifier[0] == null_upper[0] ||
2253
0
       value.v_identifier[0] == null_lower[0]) &&
2254
0
      (value.v_identifier[1] == null_upper[1] ||
2255
0
       value.v_identifier[1] == null_lower[1]) &&
2256
0
      (value.v_identifier[2] == null_upper[2] ||
2257
0
       value.v_identifier[2] == null_lower[2]) &&
2258
0
      (value.v_identifier[3] == null_upper[3] ||
2259
0
       value.v_identifier[3] == null_lower[3]))
2260
0
    token = G_TOKEN_IDENTIFIER_NULL;
2261
0
      }
2262
0
  }
2263
0
    }
2264
  
2265
0
  *token_p = token;
2266
0
  *value_p = value;
2267
0
}