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