1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
3 *
4 * gimpunit.c
5 * Copyright (C) 1999-2000 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 /* This file contains functions to load & save the file containing the
22 * user-defined size units, when the application starts/finished.
23 */
24
25 #include "config.h"
26
27 #include <gio/gio.h>
28
29 #include "libgimpbase/gimpbase.h"
30 #include "libgimpbase/gimpbase-private.h"
31 #include "libgimpconfig/gimpconfig.h"
32
33 #include "core-types.h"
34
35 #include "gimp.h"
36 #include "gimp-units.h"
37 #include "gimpunit.h"
38
39 #include "config/gimpconfig-file.h"
40
41 #include "gimp-intl.h"
42
43
44 /*
45 * All deserialize functions return G_TOKEN_LEFT_PAREN on success,
46 * or the GTokenType they would have expected but didn't get.
47 */
48
49 static GTokenType gimp_unitrc_unit_info_deserialize (GScanner *scanner,
50 Gimp *gimp);
51
52
53 static Gimp *the_unit_gimp = NULL;
54
55
56 static gint
gimp_units_get_number_of_units(void)57 gimp_units_get_number_of_units (void)
58 {
59 return _gimp_unit_get_number_of_units (the_unit_gimp);
60 }
61
62 static gint
gimp_units_get_number_of_built_in_units(void)63 gimp_units_get_number_of_built_in_units (void)
64 {
65 return GIMP_UNIT_END;
66 }
67
68 static GimpUnit
gimp_units_unit_new(gchar * identifier,gdouble factor,gint digits,gchar * symbol,gchar * abbreviation,gchar * singular,gchar * plural)69 gimp_units_unit_new (gchar *identifier,
70 gdouble factor,
71 gint digits,
72 gchar *symbol,
73 gchar *abbreviation,
74 gchar *singular,
75 gchar *plural)
76 {
77 return _gimp_unit_new (the_unit_gimp,
78 identifier,
79 factor,
80 digits,
81 symbol,
82 abbreviation,
83 singular,
84 plural);
85 }
86
87 static gboolean
gimp_units_unit_get_deletion_flag(GimpUnit unit)88 gimp_units_unit_get_deletion_flag (GimpUnit unit)
89 {
90 return _gimp_unit_get_deletion_flag (the_unit_gimp, unit);
91 }
92
93 static void
gimp_units_unit_set_deletion_flag(GimpUnit unit,gboolean deletion_flag)94 gimp_units_unit_set_deletion_flag (GimpUnit unit,
95 gboolean deletion_flag)
96 {
97 _gimp_unit_set_deletion_flag (the_unit_gimp, unit, deletion_flag);
98 }
99
100 static gdouble
gimp_units_unit_get_factor(GimpUnit unit)101 gimp_units_unit_get_factor (GimpUnit unit)
102 {
103 return _gimp_unit_get_factor (the_unit_gimp, unit);
104 }
105
106 static gint
gimp_units_unit_get_digits(GimpUnit unit)107 gimp_units_unit_get_digits (GimpUnit unit)
108 {
109 return _gimp_unit_get_digits (the_unit_gimp, unit);
110 }
111
112 static const gchar *
gimp_units_unit_get_identifier(GimpUnit unit)113 gimp_units_unit_get_identifier (GimpUnit unit)
114 {
115 return _gimp_unit_get_identifier (the_unit_gimp, unit);
116 }
117
118 static const gchar *
gimp_units_unit_get_symbol(GimpUnit unit)119 gimp_units_unit_get_symbol (GimpUnit unit)
120 {
121 return _gimp_unit_get_symbol (the_unit_gimp, unit);
122 }
123
124 static const gchar *
gimp_units_unit_get_abbreviation(GimpUnit unit)125 gimp_units_unit_get_abbreviation (GimpUnit unit)
126 {
127 return _gimp_unit_get_abbreviation (the_unit_gimp, unit);
128 }
129
130 static const gchar *
gimp_units_unit_get_singular(GimpUnit unit)131 gimp_units_unit_get_singular (GimpUnit unit)
132 {
133 return _gimp_unit_get_singular (the_unit_gimp, unit);
134 }
135
136 static const gchar *
gimp_units_unit_get_plural(GimpUnit unit)137 gimp_units_unit_get_plural (GimpUnit unit)
138 {
139 return _gimp_unit_get_plural (the_unit_gimp, unit);
140 }
141
142 void
gimp_units_init(Gimp * gimp)143 gimp_units_init (Gimp *gimp)
144 {
145 GimpUnitVtable vtable;
146
147 g_return_if_fail (GIMP_IS_GIMP (gimp));
148 g_return_if_fail (the_unit_gimp == NULL);
149
150 the_unit_gimp = gimp;
151
152 vtable.unit_get_number_of_units = gimp_units_get_number_of_units;
153 vtable.unit_get_number_of_built_in_units = gimp_units_get_number_of_built_in_units;
154 vtable.unit_new = gimp_units_unit_new;
155 vtable.unit_get_deletion_flag = gimp_units_unit_get_deletion_flag;
156 vtable.unit_set_deletion_flag = gimp_units_unit_set_deletion_flag;
157 vtable.unit_get_factor = gimp_units_unit_get_factor;
158 vtable.unit_get_digits = gimp_units_unit_get_digits;
159 vtable.unit_get_identifier = gimp_units_unit_get_identifier;
160 vtable.unit_get_symbol = gimp_units_unit_get_symbol;
161 vtable.unit_get_abbreviation = gimp_units_unit_get_abbreviation;
162 vtable.unit_get_singular = gimp_units_unit_get_singular;
163 vtable.unit_get_plural = gimp_units_unit_get_plural;
164
165 gimp_base_init (&vtable);
166
167 gimp->user_units = NULL;
168 gimp->n_user_units = 0;
169 }
170
171 void
gimp_units_exit(Gimp * gimp)172 gimp_units_exit (Gimp *gimp)
173 {
174 g_return_if_fail (GIMP_IS_GIMP (gimp));
175
176 gimp_user_units_free (gimp);
177 }
178
179
180 /* unitrc functions **********/
181
182 enum
183 {
184 UNIT_INFO = 1,
185 UNIT_FACTOR,
186 UNIT_DIGITS,
187 UNIT_SYMBOL,
188 UNIT_ABBREV,
189 UNIT_SINGULAR,
190 UNIT_PLURAL
191 };
192
193 void
gimp_unitrc_load(Gimp * gimp)194 gimp_unitrc_load (Gimp *gimp)
195 {
196 GFile *file;
197 GScanner *scanner;
198 GTokenType token;
199 GError *error = NULL;
200
201 g_return_if_fail (GIMP_IS_GIMP (gimp));
202
203 file = gimp_directory_file ("unitrc", NULL);
204
205 if (gimp->be_verbose)
206 g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file));
207
208 scanner = gimp_scanner_new_gfile (file, &error);
209
210 if (! scanner && error->code == GIMP_CONFIG_ERROR_OPEN_ENOENT)
211 {
212 g_clear_error (&error);
213 g_object_unref (file);
214
215 file = gimp_sysconf_directory_file ("unitrc", NULL);
216
217 scanner = gimp_scanner_new_gfile (file, NULL);
218 }
219
220 if (! scanner)
221 {
222 g_clear_error (&error);
223 g_object_unref (file);
224 return;
225 }
226
227 g_scanner_scope_add_symbol (scanner, 0,
228 "unit-info", GINT_TO_POINTER (UNIT_INFO));
229 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
230 "factor", GINT_TO_POINTER (UNIT_FACTOR));
231 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
232 "digits", GINT_TO_POINTER (UNIT_DIGITS));
233 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
234 "symbol", GINT_TO_POINTER (UNIT_SYMBOL));
235 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
236 "abbreviation", GINT_TO_POINTER (UNIT_ABBREV));
237 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
238 "singular", GINT_TO_POINTER (UNIT_SINGULAR));
239 g_scanner_scope_add_symbol (scanner, UNIT_INFO,
240 "plural", GINT_TO_POINTER (UNIT_PLURAL));
241
242 token = G_TOKEN_LEFT_PAREN;
243
244 while (g_scanner_peek_next_token (scanner) == token)
245 {
246 token = g_scanner_get_next_token (scanner);
247
248 switch (token)
249 {
250 case G_TOKEN_LEFT_PAREN:
251 token = G_TOKEN_SYMBOL;
252 break;
253
254 case G_TOKEN_SYMBOL:
255 if (scanner->value.v_symbol == GINT_TO_POINTER (UNIT_INFO))
256 {
257 g_scanner_set_scope (scanner, UNIT_INFO);
258 token = gimp_unitrc_unit_info_deserialize (scanner, gimp);
259
260 if (token == G_TOKEN_RIGHT_PAREN)
261 g_scanner_set_scope (scanner, 0);
262 }
263 break;
264
265 case G_TOKEN_RIGHT_PAREN:
266 token = G_TOKEN_LEFT_PAREN;
267 break;
268
269 default: /* do nothing */
270 break;
271 }
272 }
273
274 if (token != G_TOKEN_LEFT_PAREN)
275 {
276 g_scanner_get_next_token (scanner);
277 g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
278 _("fatal parse error"), TRUE);
279
280 gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
281 g_clear_error (&error);
282
283 gimp_config_file_backup_on_error (file, "unitrc", NULL);
284 }
285
286 gimp_scanner_destroy (scanner);
287 g_object_unref (file);
288 }
289
290 void
gimp_unitrc_save(Gimp * gimp)291 gimp_unitrc_save (Gimp *gimp)
292 {
293 GimpConfigWriter *writer;
294 GFile *file;
295 gint i;
296 GError *error = NULL;
297
298 g_return_if_fail (GIMP_IS_GIMP (gimp));
299
300 file = gimp_directory_file ("unitrc", NULL);
301
302 if (gimp->be_verbose)
303 g_print ("Writing '%s'\n", gimp_file_get_utf8_name (file));
304
305 writer =
306 gimp_config_writer_new_gfile (file,
307 TRUE,
308 "GIMP units\n\n"
309 "This file contains the user unit database. "
310 "You can edit this list with the unit "
311 "editor. You are not supposed to edit it "
312 "manually, but of course you can do.\n"
313 "This file will be entirely rewritten each "
314 "time you exit.",
315 NULL);
316
317 g_object_unref (file);
318
319 if (!writer)
320 return;
321
322 /* save user defined units */
323 for (i = _gimp_unit_get_number_of_built_in_units (gimp);
324 i < _gimp_unit_get_number_of_units (gimp);
325 i++)
326 {
327 if (_gimp_unit_get_deletion_flag (gimp, i) == FALSE)
328 {
329 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
330
331 gimp_config_writer_open (writer, "unit-info");
332 gimp_config_writer_string (writer,
333 _gimp_unit_get_identifier (gimp, i));
334
335 gimp_config_writer_open (writer, "factor");
336 gimp_config_writer_print (writer,
337 g_ascii_dtostr (buf, sizeof (buf),
338 _gimp_unit_get_factor (gimp, i)),
339 -1);
340 gimp_config_writer_close (writer);
341
342 gimp_config_writer_open (writer, "digits");
343 gimp_config_writer_printf (writer,
344 "%d", _gimp_unit_get_digits (gimp, i));
345 gimp_config_writer_close (writer);
346
347 gimp_config_writer_open (writer, "symbol");
348 gimp_config_writer_string (writer,
349 _gimp_unit_get_symbol (gimp, i));
350 gimp_config_writer_close (writer);
351
352 gimp_config_writer_open (writer, "abbreviation");
353 gimp_config_writer_string (writer,
354 _gimp_unit_get_abbreviation (gimp, i));
355 gimp_config_writer_close (writer);
356
357 gimp_config_writer_open (writer, "singular");
358 gimp_config_writer_string (writer,
359 _gimp_unit_get_singular (gimp, i));
360 gimp_config_writer_close (writer);
361
362 gimp_config_writer_open (writer, "plural");
363 gimp_config_writer_string (writer,
364 _gimp_unit_get_plural (gimp, i));
365 gimp_config_writer_close (writer);
366
367 gimp_config_writer_close (writer);
368 }
369 }
370
371 if (! gimp_config_writer_finish (writer, "end of units", &error))
372 {
373 gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
374 g_clear_error (&error);
375 }
376 }
377
378
379 /* private functions */
380
381 static GTokenType
gimp_unitrc_unit_info_deserialize(GScanner * scanner,Gimp * gimp)382 gimp_unitrc_unit_info_deserialize (GScanner *scanner,
383 Gimp *gimp)
384 {
385 gchar *identifier = NULL;
386 gdouble factor = 1.0;
387 gint digits = 2.0;
388 gchar *symbol = NULL;
389 gchar *abbreviation = NULL;
390 gchar *singular = NULL;
391 gchar *plural = NULL;
392 GTokenType token;
393
394 if (! gimp_scanner_parse_string (scanner, &identifier))
395 return G_TOKEN_STRING;
396
397 token = G_TOKEN_LEFT_PAREN;
398
399 while (g_scanner_peek_next_token (scanner) == token)
400 {
401 token = g_scanner_get_next_token (scanner);
402
403 switch (token)
404 {
405 case G_TOKEN_LEFT_PAREN:
406 token = G_TOKEN_SYMBOL;
407 break;
408
409 case G_TOKEN_SYMBOL:
410 switch (GPOINTER_TO_INT (scanner->value.v_symbol))
411 {
412 case UNIT_FACTOR:
413 token = G_TOKEN_FLOAT;
414 if (! gimp_scanner_parse_float (scanner, &factor))
415 goto cleanup;
416 break;
417
418 case UNIT_DIGITS:
419 token = G_TOKEN_INT;
420 if (! gimp_scanner_parse_int (scanner, &digits))
421 goto cleanup;
422 break;
423
424 case UNIT_SYMBOL:
425 token = G_TOKEN_STRING;
426 if (! gimp_scanner_parse_string (scanner, &symbol))
427 goto cleanup;
428 break;
429
430 case UNIT_ABBREV:
431 token = G_TOKEN_STRING;
432 if (! gimp_scanner_parse_string (scanner, &abbreviation))
433 goto cleanup;
434 break;
435
436 case UNIT_SINGULAR:
437 token = G_TOKEN_STRING;
438 if (! gimp_scanner_parse_string (scanner, &singular))
439 goto cleanup;
440 break;
441
442 case UNIT_PLURAL:
443 token = G_TOKEN_STRING;
444 if (! gimp_scanner_parse_string (scanner, &plural))
445 goto cleanup;
446 break;
447
448 default:
449 break;
450 }
451 token = G_TOKEN_RIGHT_PAREN;
452 break;
453
454 case G_TOKEN_RIGHT_PAREN:
455 token = G_TOKEN_LEFT_PAREN;
456 break;
457
458 default:
459 break;
460 }
461 }
462
463 if (token == G_TOKEN_LEFT_PAREN)
464 {
465 token = G_TOKEN_RIGHT_PAREN;
466
467 if (g_scanner_peek_next_token (scanner) == token)
468 {
469 GimpUnit unit = _gimp_unit_new (gimp,
470 identifier, factor, digits,
471 symbol, abbreviation,
472 singular, plural);
473
474 /* make the unit definition persistent */
475 _gimp_unit_set_deletion_flag (gimp, unit, FALSE);
476 }
477 }
478
479 cleanup:
480
481 g_free (identifier);
482 g_free (symbol);
483 g_free (abbreviation);
484 g_free (singular);
485 g_free (plural);
486
487 return token;
488 }
489