1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpscanner.c
5 * Copyright (C) 2002 Sven Neumann <sven@gimp.org>
6 * Michael Natterer <mitch@gimp.org>
7 *
8 * This library is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 3 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see
20 * <https://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <errno.h>
27
28 #include <cairo.h>
29 #include <gegl.h>
30 #include <gdk-pixbuf/gdk-pixbuf.h>
31
32 #include "libgimpbase/gimpbase.h"
33 #include "libgimpcolor/gimpcolor.h"
34 #include "libgimpmath/gimpmath.h"
35
36 #include "gimpconfig-error.h"
37 #include "gimpscanner.h"
38
39 #include "libgimp/libgimp-intl.h"
40
41
42 /**
43 * SECTION: gimpscanner
44 * @title: GimpScanner
45 * @short_description: A wrapper around #GScanner with some convenience API.
46 *
47 * A wrapper around #GScanner with some convenience API.
48 **/
49
50
51 typedef struct
52 {
53 gchar *name;
54 GMappedFile *mapped;
55 gchar *text;
56 GError **error;
57 } GimpScannerData;
58
59
60 /* local function prototypes */
61
62 static GScanner * gimp_scanner_new (const gchar *name,
63 GMappedFile *mapped,
64 gchar *text,
65 GError **error);
66 static void gimp_scanner_message (GScanner *scanner,
67 gchar *message,
68 gboolean is_error);
69
70
71 /* public functions */
72
73 /**
74 * gimp_scanner_new_file:
75 * @filename:
76 * @error:
77 *
78 * Return value:
79 *
80 * Since: 2.4
81 **/
82 GScanner *
gimp_scanner_new_file(const gchar * filename,GError ** error)83 gimp_scanner_new_file (const gchar *filename,
84 GError **error)
85 {
86 GScanner *scanner;
87 GFile *file;
88
89 g_return_val_if_fail (filename != NULL, NULL);
90 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
91
92 file = g_file_new_for_path (filename);
93 scanner = gimp_scanner_new_gfile (file, error);
94 g_object_unref (file);
95
96 return scanner;
97 }
98
99 /**
100 * gimp_scanner_new_gfile:
101 * @file: a #GFile
102 * @error: return location for #GError, or %NULL
103 *
104 * Return value: The new #GScanner.
105 *
106 * Since: 2.10
107 **/
108 GScanner *
gimp_scanner_new_gfile(GFile * file,GError ** error)109 gimp_scanner_new_gfile (GFile *file,
110 GError **error)
111 {
112 GScanner *scanner;
113 gchar *path;
114
115 g_return_val_if_fail (G_IS_FILE (file), NULL);
116 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
117
118 path = g_file_get_path (file);
119
120 if (path)
121 {
122 GMappedFile *mapped;
123
124 mapped = g_mapped_file_new (path, FALSE, error);
125 g_free (path);
126
127 if (! mapped)
128 {
129 if (error)
130 {
131 (*error)->domain = GIMP_CONFIG_ERROR;
132 (*error)->code = ((*error)->code == G_FILE_ERROR_NOENT ?
133 GIMP_CONFIG_ERROR_OPEN_ENOENT :
134 GIMP_CONFIG_ERROR_OPEN);
135 }
136
137 return NULL;
138 }
139
140 /* gimp_scanner_new() takes a "name" for the scanner, not a filename */
141 scanner = gimp_scanner_new (gimp_file_get_utf8_name (file),
142 mapped, NULL, error);
143
144 g_scanner_input_text (scanner,
145 g_mapped_file_get_contents (mapped),
146 g_mapped_file_get_length (mapped));
147 }
148 else
149 {
150 GInputStream *input;
151
152 input = G_INPUT_STREAM (g_file_read (file, NULL, error));
153
154 if (! input)
155 {
156 if (error)
157 {
158 (*error)->domain = GIMP_CONFIG_ERROR;
159 (*error)->code = ((*error)->code == G_IO_ERROR_NOT_FOUND ?
160 GIMP_CONFIG_ERROR_OPEN_ENOENT :
161 GIMP_CONFIG_ERROR_OPEN);
162 }
163
164 return NULL;
165 }
166
167 g_object_set_data (G_OBJECT (input), "gimp-data", file);
168
169 scanner = gimp_scanner_new_stream (input, error);
170
171 g_object_unref (input);
172 }
173
174 return scanner;
175 }
176
177 /**
178 * gimp_scanner_new_stream:
179 * @input: a #GInputStream
180 * @error: return location for #GError, or %NULL
181 *
182 * Return value: The new #GScanner.
183 *
184 * Since: 2.10
185 **/
186 GScanner *
gimp_scanner_new_stream(GInputStream * input,GError ** error)187 gimp_scanner_new_stream (GInputStream *input,
188 GError **error)
189 {
190 GScanner *scanner;
191 GFile *file;
192 const gchar *path;
193 GString *string;
194 gchar buffer[4096];
195 gsize bytes_read;
196
197 g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
198 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
199
200 file = g_object_get_data (G_OBJECT (input), "gimp-file");
201 if (file)
202 path = gimp_file_get_utf8_name (file);
203 else
204 path = "stream";
205
206 string = g_string_new (NULL);
207
208 do
209 {
210 GError *my_error = NULL;
211 gboolean success;
212
213 success = g_input_stream_read_all (input, buffer, sizeof (buffer),
214 &bytes_read, NULL, &my_error);
215
216 if (bytes_read > 0)
217 g_string_append_len (string, buffer, bytes_read);
218
219 if (! success)
220 {
221 if (string->len > 0)
222 {
223 g_printerr ("%s: read error in '%s', trying to scan "
224 "partial content: %s",
225 G_STRFUNC, path, my_error->message);
226 g_clear_error (&my_error);
227 break;
228 }
229
230 g_string_free (string, TRUE);
231
232 g_propagate_error (error, my_error);
233
234 return NULL;
235 }
236 }
237 while (bytes_read == sizeof (buffer));
238
239 /* gimp_scanner_new() takes a "name" for the scanner, not a filename */
240 scanner = gimp_scanner_new (path, NULL, string->str, error);
241
242 bytes_read = string->len;
243
244 g_scanner_input_text (scanner, g_string_free (string, FALSE), bytes_read);
245
246 return scanner;
247 }
248
249 /**
250 * gimp_scanner_new_string:
251 * @text:
252 * @text_len:
253 * @error:
254 *
255 * Return value:
256 *
257 * Since: 2.4
258 **/
259 GScanner *
gimp_scanner_new_string(const gchar * text,gint text_len,GError ** error)260 gimp_scanner_new_string (const gchar *text,
261 gint text_len,
262 GError **error)
263 {
264 GScanner *scanner;
265
266 g_return_val_if_fail (text != NULL || text_len <= 0, NULL);
267 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
268
269 if (text_len < 0)
270 text_len = text ? strlen (text) : 0;
271
272 scanner = gimp_scanner_new (NULL, NULL, NULL, error);
273
274 g_scanner_input_text (scanner, text, text_len);
275
276 return scanner;
277 }
278
279 static GScanner *
gimp_scanner_new(const gchar * name,GMappedFile * mapped,gchar * text,GError ** error)280 gimp_scanner_new (const gchar *name,
281 GMappedFile *mapped,
282 gchar *text,
283 GError **error)
284 {
285 GScanner *scanner;
286 GimpScannerData *data;
287
288 scanner = g_scanner_new (NULL);
289
290 data = g_slice_new0 (GimpScannerData);
291
292 data->name = g_strdup (name);
293 data->mapped = mapped;
294 data->text = text;
295 data->error = error;
296
297 scanner->user_data = data;
298 scanner->msg_handler = gimp_scanner_message;
299
300 scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z );
301 scanner->config->cset_identifier_nth = ( G_CSET_a_2_z G_CSET_A_2_Z
302 G_CSET_DIGITS "-_" );
303 scanner->config->scan_identifier_1char = TRUE;
304
305 scanner->config->store_int64 = TRUE;
306
307 return scanner;
308 }
309
310 /**
311 * gimp_scanner_destroy:
312 * @scanner: A #GScanner created by gimp_scanner_new_file() or
313 * gimp_scanner_new_string()
314 *
315 * Since: 2.4
316 **/
317 void
gimp_scanner_destroy(GScanner * scanner)318 gimp_scanner_destroy (GScanner *scanner)
319 {
320 GimpScannerData *data;
321
322 g_return_if_fail (scanner != NULL);
323
324 data = scanner->user_data;
325
326 if (data->mapped)
327 g_mapped_file_unref (data->mapped);
328
329 if (data->text)
330 g_free (data->text);
331
332 g_free (data->name);
333 g_slice_free (GimpScannerData, data);
334
335 g_scanner_destroy (scanner);
336 }
337
338 /**
339 * gimp_scanner_parse_token:
340 * @scanner: A #GScanner created by gimp_scanner_new_file() or
341 * gimp_scanner_new_string()
342 * @token: the #GTokenType expected as next token.
343 *
344 * Return value: %TRUE if the next token is @token, %FALSE otherwise.
345 *
346 * Since: 2.4
347 **/
348 gboolean
gimp_scanner_parse_token(GScanner * scanner,GTokenType token)349 gimp_scanner_parse_token (GScanner *scanner,
350 GTokenType token)
351 {
352 if (g_scanner_peek_next_token (scanner) != token)
353 return FALSE;
354
355 g_scanner_get_next_token (scanner);
356
357 return TRUE;
358 }
359
360 /**
361 * gimp_scanner_parse_identifier:
362 * @scanner: A #GScanner created by gimp_scanner_new_file() or
363 * gimp_scanner_new_string()
364 * @identifier: the expected identifier.
365 *
366 * Return value: %TRUE if the next token is an identifier and if its
367 * value matches @identifier.
368 *
369 * Since: 2.4
370 **/
371 gboolean
gimp_scanner_parse_identifier(GScanner * scanner,const gchar * identifier)372 gimp_scanner_parse_identifier (GScanner *scanner,
373 const gchar *identifier)
374 {
375 if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
376 return FALSE;
377
378 g_scanner_get_next_token (scanner);
379
380 if (strcmp (scanner->value.v_identifier, identifier))
381 return FALSE;
382
383 return TRUE;
384 }
385
386 /**
387 * gimp_scanner_parse_string:
388 * @scanner: A #GScanner created by gimp_scanner_new_file() or
389 * gimp_scanner_new_string()
390 * @dest: Return location for the parsed string
391 *
392 * Return value: %TRUE on success
393 *
394 * Since: 2.4
395 **/
396 gboolean
gimp_scanner_parse_string(GScanner * scanner,gchar ** dest)397 gimp_scanner_parse_string (GScanner *scanner,
398 gchar **dest)
399 {
400 if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
401 return FALSE;
402
403 g_scanner_get_next_token (scanner);
404
405 if (*scanner->value.v_string)
406 {
407 if (! g_utf8_validate (scanner->value.v_string, -1, NULL))
408 {
409 g_scanner_warn (scanner, _("invalid UTF-8 string"));
410 return FALSE;
411 }
412
413 *dest = g_strdup (scanner->value.v_string);
414 }
415 else
416 {
417 *dest = NULL;
418 }
419
420 return TRUE;
421 }
422
423 /**
424 * gimp_scanner_parse_string_no_validate:
425 * @scanner: A #GScanner created by gimp_scanner_new_file() or
426 * gimp_scanner_new_string()
427 * @dest: Return location for the parsed string
428 *
429 * Return value: %TRUE on success
430 *
431 * Since: 2.4
432 **/
433 gboolean
gimp_scanner_parse_string_no_validate(GScanner * scanner,gchar ** dest)434 gimp_scanner_parse_string_no_validate (GScanner *scanner,
435 gchar **dest)
436 {
437 if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
438 return FALSE;
439
440 g_scanner_get_next_token (scanner);
441
442 if (*scanner->value.v_string)
443 *dest = g_strdup (scanner->value.v_string);
444 else
445 *dest = NULL;
446
447 return TRUE;
448 }
449
450 /**
451 * gimp_scanner_parse_data:
452 * @scanner: A #GScanner created by gimp_scanner_new_file() or
453 * gimp_scanner_new_string()
454 * @length: Length of the data to parse
455 * @dest: Return location for the parsed data
456 *
457 * Return value: %TRUE on success
458 *
459 * Since: 2.4
460 **/
461 gboolean
gimp_scanner_parse_data(GScanner * scanner,gint length,guint8 ** dest)462 gimp_scanner_parse_data (GScanner *scanner,
463 gint length,
464 guint8 **dest)
465 {
466 if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
467 return FALSE;
468
469 g_scanner_get_next_token (scanner);
470
471 if (scanner->value.v_string)
472 *dest = g_memdup (scanner->value.v_string, length);
473 else
474 *dest = NULL;
475
476 return TRUE;
477 }
478
479 /**
480 * gimp_scanner_parse_int:
481 * @scanner: A #GScanner created by gimp_scanner_new_file() or
482 * gimp_scanner_new_string()
483 * @dest: Return location for the parsed integer
484 *
485 * Return value: %TRUE on success
486 *
487 * Since: 2.4
488 **/
489 gboolean
gimp_scanner_parse_int(GScanner * scanner,gint * dest)490 gimp_scanner_parse_int (GScanner *scanner,
491 gint *dest)
492 {
493 gboolean negate = FALSE;
494
495 if (g_scanner_peek_next_token (scanner) == '-')
496 {
497 negate = TRUE;
498 g_scanner_get_next_token (scanner);
499 }
500
501 if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
502 return FALSE;
503
504 g_scanner_get_next_token (scanner);
505
506 if (negate)
507 *dest = -scanner->value.v_int64;
508 else
509 *dest = scanner->value.v_int64;
510
511 return TRUE;
512 }
513
514 /**
515 * gimp_scanner_parse_int64:
516 * @scanner: A #GScanner created by gimp_scanner_new_file() or
517 * gimp_scanner_new_string()
518 * @dest: Return location for the parsed integer
519 *
520 * Return value: %TRUE on success
521 *
522 * Since: 2.8
523 **/
524 gboolean
gimp_scanner_parse_int64(GScanner * scanner,gint64 * dest)525 gimp_scanner_parse_int64 (GScanner *scanner,
526 gint64 *dest)
527 {
528 gboolean negate = FALSE;
529
530 if (g_scanner_peek_next_token (scanner) == '-')
531 {
532 negate = TRUE;
533 g_scanner_get_next_token (scanner);
534 }
535
536 if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
537 return FALSE;
538
539 g_scanner_get_next_token (scanner);
540
541 if (negate)
542 *dest = -scanner->value.v_int64;
543 else
544 *dest = scanner->value.v_int64;
545
546 return TRUE;
547 }
548
549 /**
550 * gimp_scanner_parse_float:
551 * @scanner: A #GScanner created by gimp_scanner_new_file() or
552 * gimp_scanner_new_string()
553 * @dest: Return location for the parsed float
554 *
555 * Return value: %TRUE on success
556 *
557 * Since: 2.4
558 **/
559 gboolean
gimp_scanner_parse_float(GScanner * scanner,gdouble * dest)560 gimp_scanner_parse_float (GScanner *scanner,
561 gdouble *dest)
562 {
563 gboolean negate = FALSE;
564
565 if (g_scanner_peek_next_token (scanner) == '-')
566 {
567 negate = TRUE;
568 g_scanner_get_next_token (scanner);
569 }
570
571 if (g_scanner_peek_next_token (scanner) == G_TOKEN_FLOAT)
572 {
573 g_scanner_get_next_token (scanner);
574
575 if (negate)
576 *dest = -scanner->value.v_float;
577 else
578 *dest = scanner->value.v_float;
579
580 return TRUE;
581 }
582 else if (g_scanner_peek_next_token (scanner) == G_TOKEN_INT)
583 {
584 g_scanner_get_next_token (scanner);
585
586 if (negate)
587 *dest = -scanner->value.v_int;
588 else
589 *dest = scanner->value.v_int;
590
591 return TRUE;
592 }
593
594 return FALSE;
595 }
596
597 /**
598 * gimp_scanner_parse_boolean:
599 * @scanner: A #GScanner created by gimp_scanner_new_file() or
600 * gimp_scanner_new_string()
601 * @dest: Return location for the parsed boolean
602 *
603 * Return value: %TRUE on success
604 *
605 * Since: 2.4
606 **/
607 gboolean
gimp_scanner_parse_boolean(GScanner * scanner,gboolean * dest)608 gimp_scanner_parse_boolean (GScanner *scanner,
609 gboolean *dest)
610 {
611 if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
612 return FALSE;
613
614 g_scanner_get_next_token (scanner);
615
616 if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
617 ! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
618 {
619 *dest = TRUE;
620 }
621 else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
622 ! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
623 {
624 *dest = FALSE;
625 }
626 else
627 {
628 g_scanner_error
629 (scanner,
630 /* please don't translate 'yes' and 'no' */
631 _("expected 'yes' or 'no' for boolean token, got '%s'"),
632 scanner->value.v_identifier);
633
634 return FALSE;
635 }
636
637 return TRUE;
638 }
639
640 enum
641 {
642 COLOR_RGB = 1,
643 COLOR_RGBA,
644 COLOR_HSV,
645 COLOR_HSVA
646 };
647
648 /**
649 * gimp_scanner_parse_color:
650 * @scanner: A #GScanner created by gimp_scanner_new_file() or
651 * gimp_scanner_new_string()
652 * @dest: Pointer to a color to store the result
653 *
654 * Return value: %TRUE on success
655 *
656 * Since: 2.4
657 **/
658 gboolean
gimp_scanner_parse_color(GScanner * scanner,GimpRGB * dest)659 gimp_scanner_parse_color (GScanner *scanner,
660 GimpRGB *dest)
661 {
662 guint scope_id;
663 guint old_scope_id;
664 GTokenType token;
665 GimpRGB color = { 0.0, 0.0, 0.0, 1.0 };
666
667 scope_id = g_quark_from_static_string ("gimp_scanner_parse_color");
668 old_scope_id = g_scanner_set_scope (scanner, scope_id);
669
670 if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb"))
671 {
672 g_scanner_scope_add_symbol (scanner, scope_id,
673 "color-rgb", GINT_TO_POINTER (COLOR_RGB));
674 g_scanner_scope_add_symbol (scanner, scope_id,
675 "color-rgba", GINT_TO_POINTER (COLOR_RGBA));
676 g_scanner_scope_add_symbol (scanner, scope_id,
677 "color-hsv", GINT_TO_POINTER (COLOR_HSV));
678 g_scanner_scope_add_symbol (scanner, scope_id,
679 "color-hsva", GINT_TO_POINTER (COLOR_HSVA));
680 }
681
682 token = G_TOKEN_LEFT_PAREN;
683
684 while (g_scanner_peek_next_token (scanner) == token)
685 {
686 token = g_scanner_get_next_token (scanner);
687
688 switch (token)
689 {
690 case G_TOKEN_LEFT_PAREN:
691 token = G_TOKEN_SYMBOL;
692 break;
693
694 case G_TOKEN_SYMBOL:
695 {
696 gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 };
697 gint n_channels = 4;
698 gboolean is_hsv = FALSE;
699 gint i;
700
701 switch (GPOINTER_TO_INT (scanner->value.v_symbol))
702 {
703 case COLOR_RGB:
704 n_channels = 3;
705 /* fallthrough */
706 case COLOR_RGBA:
707 break;
708
709 case COLOR_HSV:
710 n_channels = 3;
711 /* fallthrough */
712 case COLOR_HSVA:
713 is_hsv = TRUE;
714 break;
715 }
716
717 token = G_TOKEN_FLOAT;
718
719 for (i = 0; i < n_channels; i++)
720 {
721 if (! gimp_scanner_parse_float (scanner, &col[i]))
722 goto finish;
723 }
724
725 if (is_hsv)
726 {
727 GimpHSV hsv;
728
729 gimp_hsva_set (&hsv, col[0], col[1], col[2], col[3]);
730 gimp_hsv_to_rgb (&hsv, &color);
731 }
732 else
733 {
734 gimp_rgba_set (&color, col[0], col[1], col[2], col[3]);
735 }
736
737 token = G_TOKEN_RIGHT_PAREN;
738 }
739 break;
740
741 case G_TOKEN_RIGHT_PAREN:
742 token = G_TOKEN_NONE; /* indicates success */
743 goto finish;
744
745 default: /* do nothing */
746 break;
747 }
748 }
749
750 finish:
751
752 if (token != G_TOKEN_NONE)
753 {
754 g_scanner_get_next_token (scanner);
755 g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
756 _("fatal parse error"), TRUE);
757 }
758 else
759 {
760 *dest = color;
761 }
762
763 g_scanner_set_scope (scanner, old_scope_id);
764
765 return (token == G_TOKEN_NONE);
766 }
767
768 /**
769 * gimp_scanner_parse_matrix2:
770 * @scanner: A #GScanner created by gimp_scanner_new_file() or
771 * gimp_scanner_new_string()
772 * @dest: Pointer to a matrix to store the result
773 *
774 * Return value: %TRUE on success
775 *
776 * Since: 2.4
777 **/
778 gboolean
gimp_scanner_parse_matrix2(GScanner * scanner,GimpMatrix2 * dest)779 gimp_scanner_parse_matrix2 (GScanner *scanner,
780 GimpMatrix2 *dest)
781 {
782 guint scope_id;
783 guint old_scope_id;
784 GTokenType token;
785 GimpMatrix2 matrix;
786
787 scope_id = g_quark_from_static_string ("gimp_scanner_parse_matrix");
788 old_scope_id = g_scanner_set_scope (scanner, scope_id);
789
790 if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "matrix"))
791 g_scanner_scope_add_symbol (scanner, scope_id,
792 "matrix", GINT_TO_POINTER (0));
793
794 token = G_TOKEN_LEFT_PAREN;
795
796 while (g_scanner_peek_next_token (scanner) == token)
797 {
798 token = g_scanner_get_next_token (scanner);
799
800 switch (token)
801 {
802 case G_TOKEN_LEFT_PAREN:
803 token = G_TOKEN_SYMBOL;
804 break;
805
806 case G_TOKEN_SYMBOL:
807 {
808 token = G_TOKEN_FLOAT;
809
810 if (! gimp_scanner_parse_float (scanner, &matrix.coeff[0][0]))
811 goto finish;
812 if (! gimp_scanner_parse_float (scanner, &matrix.coeff[0][1]))
813 goto finish;
814 if (! gimp_scanner_parse_float (scanner, &matrix.coeff[1][0]))
815 goto finish;
816 if (! gimp_scanner_parse_float (scanner, &matrix.coeff[1][1]))
817 goto finish;
818
819 token = G_TOKEN_RIGHT_PAREN;
820 }
821 break;
822
823 case G_TOKEN_RIGHT_PAREN:
824 token = G_TOKEN_NONE; /* indicates success */
825 goto finish;
826
827 default: /* do nothing */
828 break;
829 }
830 }
831
832 finish:
833
834 if (token != G_TOKEN_NONE)
835 {
836 g_scanner_get_next_token (scanner);
837 g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
838 _("fatal parse error"), TRUE);
839 }
840 else
841 {
842 *dest = matrix;
843 }
844
845 g_scanner_set_scope (scanner, old_scope_id);
846
847 return (token == G_TOKEN_NONE);
848 }
849
850
851 /* private functions */
852
853 static void
gimp_scanner_message(GScanner * scanner,gchar * message,gboolean is_error)854 gimp_scanner_message (GScanner *scanner,
855 gchar *message,
856 gboolean is_error)
857 {
858 GimpScannerData *data = scanner->user_data;
859
860 /* we don't expect warnings */
861 g_return_if_fail (is_error);
862
863 if (data->name)
864 g_set_error (data->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
865 _("Error while parsing '%s' in line %d: %s"),
866 data->name, scanner->line, message);
867 else
868 /* should never happen, thus not marked for translation */
869 g_set_error (data->error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
870 "Error parsing internal buffer: %s", message);
871 }
872