/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis * * pikaunit.c * Copyright (C) 1999-2000 Michael Natterer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* This file contains functions to load & save the file containing the * user-defined size units, when the application starts/finished. */ #include "config.h" #include #include "libpikabase/pikabase.h" #include "libpikabase/pikabase-private.h" #include "libpikaconfig/pikaconfig.h" #include "core-types.h" #include "pika.h" #include "pika-units.h" #include "pikaunit.h" #include "config/pikaconfig-file.h" #include "pika-intl.h" /* * All deserialize functions return G_TOKEN_LEFT_PAREN on success, * or the GTokenType they would have expected but didn't get. */ static GTokenType pika_unitrc_unit_info_deserialize (GScanner *scanner, Pika *pika); static Pika *the_unit_pika = NULL; static gint pika_units_get_number_of_units (void) { return _pika_unit_get_number_of_units (the_unit_pika); } static gint pika_units_get_number_of_built_in_units (void) { return PIKA_UNIT_END; } static PikaUnit pika_units_unit_new (gchar *identifier, gdouble factor, gint digits, gchar *symbol, gchar *abbreviation, gchar *singular, gchar *plural) { return _pika_unit_new (the_unit_pika, identifier, factor, digits, symbol, abbreviation, singular, plural); } static gboolean pika_units_unit_get_deletion_flag (PikaUnit unit) { return _pika_unit_get_deletion_flag (the_unit_pika, unit); } static void pika_units_unit_set_deletion_flag (PikaUnit unit, gboolean deletion_flag) { _pika_unit_set_deletion_flag (the_unit_pika, unit, deletion_flag); } static gdouble pika_units_unit_get_factor (PikaUnit unit) { return _pika_unit_get_factor (the_unit_pika, unit); } static gint pika_units_unit_get_digits (PikaUnit unit) { return _pika_unit_get_digits (the_unit_pika, unit); } static const gchar * pika_units_unit_get_identifier (PikaUnit unit) { return _pika_unit_get_identifier (the_unit_pika, unit); } static const gchar * pika_units_unit_get_symbol (PikaUnit unit) { return _pika_unit_get_symbol (the_unit_pika, unit); } static const gchar * pika_units_unit_get_abbreviation (PikaUnit unit) { return _pika_unit_get_abbreviation (the_unit_pika, unit); } static const gchar * pika_units_unit_get_singular (PikaUnit unit) { return _pika_unit_get_singular (the_unit_pika, unit); } static const gchar * pika_units_unit_get_plural (PikaUnit unit) { return _pika_unit_get_plural (the_unit_pika, unit); } void pika_units_init (Pika *pika) { PikaUnitVtable vtable; g_return_if_fail (PIKA_IS_PIKA (pika)); g_return_if_fail (the_unit_pika == NULL); the_unit_pika = pika; vtable.unit_get_number_of_units = pika_units_get_number_of_units; vtable.unit_get_number_of_built_in_units = pika_units_get_number_of_built_in_units; vtable.unit_new = pika_units_unit_new; vtable.unit_get_deletion_flag = pika_units_unit_get_deletion_flag; vtable.unit_set_deletion_flag = pika_units_unit_set_deletion_flag; vtable.unit_get_factor = pika_units_unit_get_factor; vtable.unit_get_digits = pika_units_unit_get_digits; vtable.unit_get_identifier = pika_units_unit_get_identifier; vtable.unit_get_symbol = pika_units_unit_get_symbol; vtable.unit_get_abbreviation = pika_units_unit_get_abbreviation; vtable.unit_get_singular = pika_units_unit_get_singular; vtable.unit_get_plural = pika_units_unit_get_plural; pika_base_init (&vtable); pika->user_units = NULL; pika->n_user_units = 0; } void pika_units_exit (Pika *pika) { g_return_if_fail (PIKA_IS_PIKA (pika)); pika_user_units_free (pika); } /* unitrc functions **********/ enum { UNIT_INFO = 1, UNIT_FACTOR, UNIT_DIGITS, UNIT_SYMBOL, UNIT_ABBREV, UNIT_SINGULAR, UNIT_PLURAL }; void pika_unitrc_load (Pika *pika) { GFile *file; GScanner *scanner; GTokenType token; GError *error = NULL; g_return_if_fail (PIKA_IS_PIKA (pika)); file = pika_directory_file ("unitrc", NULL); if (pika->be_verbose) g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file)); scanner = pika_scanner_new_file (file, &error); if (! scanner && error->code == PIKA_CONFIG_ERROR_OPEN_ENOENT) { g_clear_error (&error); g_object_unref (file); file = pika_sysconf_directory_file ("unitrc", NULL); scanner = pika_scanner_new_file (file, NULL); } if (! scanner) { g_clear_error (&error); g_object_unref (file); return; } g_scanner_scope_add_symbol (scanner, 0, "unit-info", GINT_TO_POINTER (UNIT_INFO)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "factor", GINT_TO_POINTER (UNIT_FACTOR)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "digits", GINT_TO_POINTER (UNIT_DIGITS)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "symbol", GINT_TO_POINTER (UNIT_SYMBOL)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "abbreviation", GINT_TO_POINTER (UNIT_ABBREV)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "singular", GINT_TO_POINTER (UNIT_SINGULAR)); g_scanner_scope_add_symbol (scanner, UNIT_INFO, "plural", GINT_TO_POINTER (UNIT_PLURAL)); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: if (scanner->value.v_symbol == GINT_TO_POINTER (UNIT_INFO)) { g_scanner_set_scope (scanner, UNIT_INFO); token = pika_unitrc_unit_info_deserialize (scanner, pika); if (token == G_TOKEN_RIGHT_PAREN) g_scanner_set_scope (scanner, 0); } break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: /* do nothing */ break; } } if (token != G_TOKEN_LEFT_PAREN) { g_scanner_get_next_token (scanner); g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, _("fatal parse error"), TRUE); pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message); g_clear_error (&error); pika_config_file_backup_on_error (file, "unitrc", NULL); } pika_scanner_unref (scanner); g_object_unref (file); } void pika_unitrc_save (Pika *pika) { PikaConfigWriter *writer; GFile *file; gint i; GError *error = NULL; g_return_if_fail (PIKA_IS_PIKA (pika)); file = pika_directory_file ("unitrc", NULL); if (pika->be_verbose) g_print ("Writing '%s'\n", pika_file_get_utf8_name (file)); writer = pika_config_writer_new_from_file (file, TRUE, "PIKA units\n\n" "This file contains the user unit database. " "You can edit this list with the unit " "editor. You are not supposed to edit it " "manually, but of course you can do.\n" "This file will be entirely rewritten each " "time you exit.", NULL); g_object_unref (file); if (!writer) return; /* save user defined units */ for (i = _pika_unit_get_number_of_built_in_units (pika); i < _pika_unit_get_number_of_units (pika); i++) { if (_pika_unit_get_deletion_flag (pika, i) == FALSE) { gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; pika_config_writer_open (writer, "unit-info"); pika_config_writer_string (writer, _pika_unit_get_identifier (pika, i)); pika_config_writer_open (writer, "factor"); pika_config_writer_print (writer, g_ascii_dtostr (buf, sizeof (buf), _pika_unit_get_factor (pika, i)), -1); pika_config_writer_close (writer); pika_config_writer_open (writer, "digits"); pika_config_writer_printf (writer, "%d", _pika_unit_get_digits (pika, i)); pika_config_writer_close (writer); pika_config_writer_open (writer, "symbol"); pika_config_writer_string (writer, _pika_unit_get_symbol (pika, i)); pika_config_writer_close (writer); pika_config_writer_open (writer, "abbreviation"); pika_config_writer_string (writer, _pika_unit_get_abbreviation (pika, i)); pika_config_writer_close (writer); pika_config_writer_open (writer, "singular"); pika_config_writer_string (writer, _pika_unit_get_singular (pika, i)); pika_config_writer_close (writer); pika_config_writer_open (writer, "plural"); pika_config_writer_string (writer, _pika_unit_get_plural (pika, i)); pika_config_writer_close (writer); pika_config_writer_close (writer); } } if (! pika_config_writer_finish (writer, "end of units", &error)) { pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message); g_clear_error (&error); } } /* private functions */ static GTokenType pika_unitrc_unit_info_deserialize (GScanner *scanner, Pika *pika) { gchar *identifier = NULL; gdouble factor = 1.0; gint digits = 2.0; gchar *symbol = NULL; gchar *abbreviation = NULL; gchar *singular = NULL; gchar *plural = NULL; GTokenType token; if (! pika_scanner_parse_string (scanner, &identifier)) return G_TOKEN_STRING; token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: switch (GPOINTER_TO_INT (scanner->value.v_symbol)) { case UNIT_FACTOR: token = G_TOKEN_FLOAT; if (! pika_scanner_parse_float (scanner, &factor)) goto cleanup; break; case UNIT_DIGITS: token = G_TOKEN_INT; if (! pika_scanner_parse_int (scanner, &digits)) goto cleanup; break; case UNIT_SYMBOL: token = G_TOKEN_STRING; if (! pika_scanner_parse_string (scanner, &symbol)) goto cleanup; break; case UNIT_ABBREV: token = G_TOKEN_STRING; if (! pika_scanner_parse_string (scanner, &abbreviation)) goto cleanup; break; case UNIT_SINGULAR: token = G_TOKEN_STRING; if (! pika_scanner_parse_string (scanner, &singular)) goto cleanup; break; case UNIT_PLURAL: token = G_TOKEN_STRING; if (! pika_scanner_parse_string (scanner, &plural)) goto cleanup; break; default: break; } token = G_TOKEN_RIGHT_PAREN; break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: break; } } if (token == G_TOKEN_LEFT_PAREN) { token = G_TOKEN_RIGHT_PAREN; if (g_scanner_peek_next_token (scanner) == token) { PikaUnit unit = _pika_unit_new (pika, identifier, factor, digits, symbol, abbreviation, singular, plural); /* make the unit definition persistent */ _pika_unit_set_deletion_flag (pika, unit, FALSE); } } cleanup: g_free (identifier); g_free (symbol); g_free (abbreviation); g_free (singular); g_free (plural); return token; }