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