nexmon – Blame information for rev 1

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