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