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