Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

32
libpikaconfig/Makefile.gi Normal file
View File

@ -0,0 +1,32 @@
# Introspectable sources for libpikaconfig
libpikaconfig_introspectable_headers = \
../libpikaconfig/pikaconfigenums.h \
../libpikaconfig/pikaconfigtypes.h \
../libpikaconfig/pikaconfig-array.h \
../libpikaconfig/pikaconfig-iface.h \
../libpikaconfig/pikaconfig-deserialize.h \
../libpikaconfig/pikaconfig-error.h \
../libpikaconfig/pikaconfig-params.h \
../libpikaconfig/pikaconfig-path.h \
../libpikaconfig/pikaconfig-register.h \
../libpikaconfig/pikaconfig-serialize.h \
../libpikaconfig/pikaconfig-utils.h \
../libpikaconfig/pikaconfigwriter.h \
../libpikaconfig/pikascanner.h \
../libpikaconfig/pikacolorconfig.h
libpikaconfig_introspectable = \
../libpikaconfig/pikaconfig-array.c \
../libpikaconfig/pikaconfig-iface.c \
../libpikaconfig/pikaconfig-deserialize.c \
../libpikaconfig/pikaconfig-error.c \
../libpikaconfig/pikaconfig-path.c \
../libpikaconfig/pikaconfig-params.c \
../libpikaconfig/pikaconfig-register.c \
../libpikaconfig/pikaconfig-serialize.c \
../libpikaconfig/pikaconfig-utils.c \
../libpikaconfig/pikaconfigwriter.c \
../libpikaconfig/pikascanner.c \
../libpikaconfig/pikacolorconfig.c \
$(libpikaconfig_introspectable_headers)

91
libpikaconfig/meson.build Normal file
View File

@ -0,0 +1,91 @@
stamp_config_enums = custom_target('stamp-pikaconfigenums.h',
input : [
files(
'pikaconfigenums.h'
),
],
output: [ 'stamp-pikaconfigenums.h', ],
command: [
mkenums_wrap, perl,
meson.project_source_root(), meson.current_source_dir(),
meson.current_build_dir(),
'pikaconfig',
'#include <gio/gio.h>\n' +
'#include "libpikabase/pikabase.h"\n',
'#include "libpika/libpika-intl.h"',
libpika_mkenums_dtails
],
build_by_default: true
)
libpikaconfig_sources_introspectable = files(
'pikacolorconfig.c',
'pikaconfig-array.c',
'pikaconfig-deserialize.c',
'pikaconfig-error.c',
'pikaconfig-iface.c',
'pikaconfig-params.c',
'pikaconfig-path.c',
'pikaconfig-register.c',
'pikaconfig-serialize.c',
'pikaconfig-utils.c',
'pikaconfigwriter.c',
'pikascanner.c',
)
libpikaconfig_sources = [
libpikaconfig_sources_introspectable,
'pikaconfigenums.c',
stamp_config_enums
]
libpikaconfig_headers_introspectable = files(
'pikacolorconfig.h',
'pikaconfig-array.h',
'pikaconfig-deserialize.h',
'pikaconfig-error.h',
'pikaconfig-iface.h',
'pikaconfig-params.h',
'pikaconfig-path.h',
'pikaconfig-register.h',
'pikaconfig-serialize.h',
'pikaconfig-utils.h',
'pikaconfigenums.h',
'pikaconfigtypes.h',
'pikaconfigwriter.h',
'pikascanner.h',
)
libpikaconfig_headers = [
libpikaconfig_headers_introspectable,
'pikaconfig.h',
]
libpikaconfig_introspectable = [
libpikaconfig_headers_introspectable,
libpikaconfig_sources_introspectable,
]
libpikaconfig = library('pikaconfig-' + pika_api_version,
libpikaconfig_sources,
include_directories: rootInclude,
dependencies: [
cairo, gdk_pixbuf, gegl, gio, gio_specific,
],
c_args: [ '-DG_LOG_DOMAIN="LibPikaConfig"', '-DPIKA_CONFIG_COMPILATION', ],
link_with: [
libpikabase,
libpikacolor,
libpikamath,
],
vs_module_defs: 'pikaconfig.def',
install: true,
version: so_version,
)
install_headers(
libpikaconfig_headers,
subdir: pika_api_name / 'libpikaconfig',
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* PikaColorConfig class
* Copyright (C) 2004 Stefan Döhla <stefan@doehla.de>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_CONFIG_H__
#define __PIKA_COLOR_CONFIG_H__
#define PIKA_TYPE_COLOR_CONFIG (pika_color_config_get_type ())
#define PIKA_COLOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_CONFIG, PikaColorConfig))
#define PIKA_COLOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_CONFIG, PikaColorConfigClass))
#define PIKA_IS_COLOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_CONFIG))
#define PIKA_IS_COLOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_CONFIG))
typedef struct _PikaColorConfigPrivate PikaColorConfigPrivate;
typedef struct _PikaColorConfigClass PikaColorConfigClass;
struct _PikaColorConfig
{
GObject parent_instance;
PikaColorConfigPrivate *priv;
};
struct _PikaColorConfigClass
{
GObjectClass parent_class;
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_config_get_type (void) G_GNUC_CONST;
PikaColorManagementMode
pika_color_config_get_mode (PikaColorConfig *config);
PikaColorRenderingIntent
pika_color_config_get_display_intent (PikaColorConfig *config);
gboolean pika_color_config_get_display_bpc (PikaColorConfig *config);
gboolean pika_color_config_get_display_optimize (PikaColorConfig *config);
gboolean pika_color_config_get_display_profile_from_gdk (PikaColorConfig *config);
PikaColorRenderingIntent
pika_color_config_get_simulation_intent (PikaColorConfig *config);
gboolean pika_color_config_get_simulation_bpc (PikaColorConfig *config);
gboolean pika_color_config_get_simulation_optimize (PikaColorConfig *config);
gboolean pika_color_config_get_simulation_gamut_check (PikaColorConfig *config);
void pika_color_config_get_out_of_gamut_color (PikaColorConfig *config,
PikaRGB *color);
PikaColorProfile * pika_color_config_get_rgb_color_profile (PikaColorConfig *config,
GError **error);
PikaColorProfile * pika_color_config_get_gray_color_profile (PikaColorConfig *config,
GError **error);
PikaColorProfile * pika_color_config_get_cmyk_color_profile (PikaColorConfig *config,
GError **error);
PikaColorProfile * pika_color_config_get_display_color_profile (PikaColorConfig *config,
GError **error);
PikaColorProfile * pika_color_config_get_simulation_color_profile (PikaColorConfig *config,
GError **error);
#endif /* PIKA_COLOR_CONFIG_H__ */

View File

@ -0,0 +1,155 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "pikaconfigtypes.h"
#include "pikaconfig-utils.h"
#include "pikaconfig-array.h"
#include "pikascanner.h"
/* GStrv i.e. char** i.e. null terminated array of strings. */
/**
* pika_config_serialize_strv:
* @value: source #GValue holding a #GStrv
* @str: destination string
*
* Appends a string repr of the #GStrv value of #GValue to @str.
* Repr is an integer literal greater than or equal to zero,
* followed by a possibly empty sequence
* of quoted and escaped string literals.
*
* Returns: %TRUE always
*
* Since: 3.0
**/
gboolean
pika_config_serialize_strv (const GValue *value,
GString *str)
{
GStrv gstrv;
gstrv = g_value_get_boxed (value);
if (gstrv)
{
gint length = g_strv_length (gstrv);
/* Write length */
g_string_append_printf (str, "%d", length);
for (gint i = 0; i < length; i++)
{
g_string_append (str, " "); /* separator */
pika_config_string_append_escaped (str, gstrv[i]);
}
}
else
{
/* GValue has NULL value. Not quite the same as an empty GStrv.
* But handle it quietly as an empty GStrv: write a length of zero.
*/
g_string_append (str, "0");
}
return TRUE;
}
/**
* pika_config_deserialize_strv:
* @value: destination #GValue to hold a #GStrv
* @scanner: #GScanner positioned in serialization stream
*
* Sets @value to new #GStrv.
* Scans i.e. consumes serialization to fill the GStrv.
*
* Requires @value to be initialized to hold type #G_TYPE_BOXED.
*
* Returns:
* G_TOKEN_RIGHT_PAREN on success.
* G_TOKEN_INT on failure to scan length.
* G_TOKEN_STRING on failure to scan enough quoted strings.
*
* On failure, the value in @value is not touched and could be NULL.
*
* Since: 3.0
**/
GTokenType
pika_config_deserialize_strv (GValue *value,
GScanner *scanner)
{
gint n_values;
GTokenType result_token = G_TOKEN_RIGHT_PAREN;
GStrvBuilder *builder;
/* Scan length of array. */
if (! pika_scanner_parse_int (scanner, &n_values))
return G_TOKEN_INT;
builder = g_strv_builder_new ();
for (gint i = 0; i < n_values; i++)
{
gchar *scanned_string;
if (! pika_scanner_parse_string (scanner, &scanned_string))
{
/* Error, missing a string. */
result_token = G_TOKEN_STRING;
break;
}
/* Not an error for scanned string to be empty.*/
/* Adding string to builder DOES not transfer ownership,
* the builder will copy the string.
*/
g_strv_builder_add (builder, scanned_string);
g_free (scanned_string);
}
/* assert result_token is G_TOKEN_RIGHT_PAREN OR G_TOKEN_STRING */
if (result_token == G_TOKEN_RIGHT_PAREN)
{
GStrv gstrv;
/* Allocate new GStrv. */
gstrv = g_strv_builder_end (builder);
/* Transfer ownership of the array and all strings it points to. */
g_value_take_boxed (value, gstrv);
}
else
{
/* No GStrv to unref. */
g_scanner_error (scanner, "Missing string.");
}
g_strv_builder_unref (builder);
return result_token;
}

View File

@ -0,0 +1,47 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikaconfig-array.h
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_ARRAY_H__
#define __PIKA_CONFIG_ARRAY_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/* Functions to ser/des arrays. */
/* FIXME: move pika_config_serialize_value_array here.
* FIXME: implement other arrays for which plugins can declare args e.g. int32 array.
* FIXME: doesn't need to be introspected, these are internal
*/
gboolean pika_config_serialize_strv (const GValue *value,
GString *str);
GTokenType pika_config_deserialize_strv (GValue *value,
GScanner *scanner);
G_END_DECLS
#endif /* __PIKA_CONFIG_ARRAY_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Object properties deserialization routines
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_DESERIALIZE_H__
#define __PIKA_CONFIG_DESERIALIZE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
gboolean pika_config_deserialize_properties (PikaConfig *config,
GScanner *scanner,
gint nest_level);
GTokenType pika_config_deserialize_property (PikaConfig *config,
GScanner *scanner,
gint nest_level);
G_END_DECLS
#endif /* __PIKA_CONFIG_DESERIALIZE_H__ */

View File

@ -0,0 +1,51 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Config file serialization and deserialization interface
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#include "pikaconfig-error.h"
/**
* SECTION: pikaconfig-error
* @title: PikaConfig-error
* @short_description: Error utils for libpikaconfig.
*
* Error utils for libpikaconfig.
**/
/**
* pika_config_error_quark:
*
* This function is never called directly. Use PIKA_CONFIG_ERROR() instead.
*
* Returns: the #GQuark that defines the PikaConfig error domain.
*
* Since: 2.4
**/
GQuark
pika_config_error_quark (void)
{
return g_quark_from_static_string ("pika-config-error-quark");
}

View File

@ -0,0 +1,59 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Copyright (C) 2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_ERROR_H__
#define __PIKA_CONFIG_ERROR_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/**
* PikaConfigError:
* @PIKA_CONFIG_ERROR_OPEN: open failed
* @PIKA_CONFIG_ERROR_OPEN_ENOENT: file does not exist
* @PIKA_CONFIG_ERROR_WRITE: write failed
* @PIKA_CONFIG_ERROR_PARSE: parser error
* @PIKA_CONFIG_ERROR_VERSION: parser failed due to version mismatch
*
* The possible values of a #GError thrown by libpikaconfig.
**/
typedef enum
{
PIKA_CONFIG_ERROR_OPEN,
PIKA_CONFIG_ERROR_OPEN_ENOENT,
PIKA_CONFIG_ERROR_WRITE,
PIKA_CONFIG_ERROR_PARSE,
PIKA_CONFIG_ERROR_VERSION
} PikaConfigError;
#define PIKA_CONFIG_ERROR (pika_config_error_quark ())
GQuark pika_config_error_quark (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __PIKA_CONFIG_ERROR_H__ */

View File

@ -0,0 +1,839 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Config file serialization and deserialization interface
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "pikaconfigtypes.h"
#include "pikaconfigwriter.h"
#include "pikaconfig-iface.h"
#include "pikaconfig-deserialize.h"
#include "pikaconfig-serialize.h"
#include "pikaconfig-params.h"
#include "pikaconfig-utils.h"
#include "pikascanner.h"
#include "libpika/libpika-intl.h"
/*
* PikaConfigIface:
*
* The [struct@Config] serialization and deserialization interface.
*/
/* local function prototypes */
static void pika_config_iface_default_init (PikaConfigInterface *iface);
static void pika_config_iface_base_init (PikaConfigInterface *iface);
static gboolean pika_config_iface_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data);
static gboolean pika_config_iface_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data);
static PikaConfig * pika_config_iface_duplicate (PikaConfig *config);
static gboolean pika_config_iface_equal (PikaConfig *a,
PikaConfig *b);
static void pika_config_iface_reset (PikaConfig *config);
static gboolean pika_config_iface_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags);
/* private functions */
GType
pika_config_get_type (void)
{
static GType config_iface_type = 0;
if (! config_iface_type)
{
const GTypeInfo config_iface_info =
{
sizeof (PikaConfigInterface),
(GBaseInitFunc) pika_config_iface_base_init,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) pika_config_iface_default_init,
(GClassFinalizeFunc) NULL,
};
config_iface_type = g_type_register_static (G_TYPE_INTERFACE,
"PikaConfigInterface",
&config_iface_info,
0);
g_type_interface_add_prerequisite (config_iface_type, G_TYPE_OBJECT);
}
return config_iface_type;
}
static void
pika_config_iface_default_init (PikaConfigInterface *iface)
{
iface->serialize = pika_config_iface_serialize;
iface->deserialize = pika_config_iface_deserialize;
iface->duplicate = pika_config_iface_duplicate;
iface->equal = pika_config_iface_equal;
iface->reset = pika_config_iface_reset;
iface->copy = pika_config_iface_copy;
}
static void
pika_config_iface_base_init (PikaConfigInterface *iface)
{
/* always set these to NULL since we don't want to inherit them
* from parent classes
*/
iface->serialize_property = NULL;
iface->deserialize_property = NULL;
}
static gboolean
pika_config_iface_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data)
{
return pika_config_serialize_properties (config, writer);
}
static gboolean
pika_config_iface_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data)
{
return pika_config_deserialize_properties (config, scanner, nest_level);
}
static PikaConfig *
pika_config_iface_duplicate (PikaConfig *config)
{
GObject *object = G_OBJECT (config);
GObjectClass *klass = G_OBJECT_GET_CLASS (object);
GParamSpec **property_specs;
guint n_property_specs;
gint n_construct_properties = 0;
const gchar **construct_names = NULL;
GValue *construct_values = NULL;
guint i;
GObject *dup;
property_specs = g_object_class_list_properties (klass, &n_property_specs);
construct_names = g_new0 (const gchar *, n_property_specs);
construct_values = g_new0 (GValue, n_property_specs);
for (i = 0; i < n_property_specs; i++)
{
GParamSpec *prop_spec = property_specs[i];
if ((prop_spec->flags & G_PARAM_READABLE) &&
(prop_spec->flags & G_PARAM_WRITABLE) &&
(prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
{
construct_names[n_construct_properties] = prop_spec->name;
g_value_init (&construct_values[n_construct_properties],
prop_spec->value_type);
g_object_get_property (object, prop_spec->name,
&construct_values[n_construct_properties]);
n_construct_properties++;
}
}
g_free (property_specs);
dup = g_object_new_with_properties (G_TYPE_FROM_INSTANCE (object),
n_construct_properties,
(const gchar **) construct_names,
(const GValue *) construct_values);
for (i = 0; i < n_construct_properties; i++)
g_value_unset (&construct_values[i]);
g_free (construct_names);
g_free (construct_values);
pika_config_copy (config, PIKA_CONFIG (dup), 0);
return PIKA_CONFIG (dup);
}
static gboolean
pika_config_iface_equal (PikaConfig *a,
PikaConfig *b)
{
GObjectClass *klass;
GParamSpec **property_specs;
guint n_property_specs;
guint i;
gboolean equal = TRUE;
klass = G_OBJECT_GET_CLASS (a);
property_specs = g_object_class_list_properties (klass, &n_property_specs);
for (i = 0; equal && i < n_property_specs; i++)
{
GParamSpec *prop_spec;
GValue a_value = G_VALUE_INIT;
GValue b_value = G_VALUE_INIT;
prop_spec = property_specs[i];
if (! (prop_spec->flags & G_PARAM_READABLE) ||
(prop_spec->flags & PIKA_CONFIG_PARAM_DONT_COMPARE))
{
continue;
}
g_value_init (&a_value, prop_spec->value_type);
g_value_init (&b_value, prop_spec->value_type);
g_object_get_property (G_OBJECT (a), prop_spec->name, &a_value);
g_object_get_property (G_OBJECT (b), prop_spec->name, &b_value);
if (g_param_values_cmp (prop_spec, &a_value, &b_value))
{
if ((prop_spec->flags & PIKA_CONFIG_PARAM_AGGREGATE) &&
G_IS_PARAM_SPEC_OBJECT (prop_spec) &&
g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
PIKA_TYPE_CONFIG))
{
if (! pika_config_is_equal_to (g_value_get_object (&a_value),
g_value_get_object (&b_value)))
{
equal = FALSE;
}
}
else
{
equal = FALSE;
}
}
g_value_unset (&a_value);
g_value_unset (&b_value);
}
g_free (property_specs);
return equal;
}
static void
pika_config_iface_reset (PikaConfig *config)
{
pika_config_reset_properties (G_OBJECT (config));
}
static gboolean
pika_config_iface_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags)
{
return pika_config_sync (G_OBJECT (src), G_OBJECT (dest), flags);
}
/* public functions */
/**
* pika_config_serialize_to_file:
* @config: an object that implements [iface@ConfigInterface].
* @file: the file to write the configuration to.
* @header: (nullable): optional file header (must be ASCII only)
* @footer: (nullable): optional file footer (must be ASCII only)
* @data: user data passed to the serialize implementation.
* @error: return location for a possible error
*
* Serializes the object properties of @config to the file specified
* by @file. If a file with that name already exists, it is
* overwritten. Basically this function opens @file for you and calls
* the serialize function of the @config's [iface@ConfigInterface].
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise.
*
* Since: 2.10
**/
gboolean
pika_config_serialize_to_file (PikaConfig *config,
GFile *file,
const gchar *header,
const gchar *footer,
gpointer data,
GError **error)
{
PikaConfigWriter *writer;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
writer = pika_config_writer_new_from_file (file, TRUE, header, error);
if (!writer)
return FALSE;
PIKA_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
return pika_config_writer_finish (writer, footer, error);
}
/**
* pika_config_serialize_to_stream:
* @config: an object that implements [iface@ConfigInterface].
* @output: the #GOutputStream to write the configuration to.
* @header: (nullable): optional file header (must be ASCII only)
* @footer: (nullable): optional file footer (must be ASCII only)
* @data: user data passed to the serialize implementation.
* @error: return location for a possible error
*
* Serializes the object properties of @config to the stream specified
* by @output.
*
* Returns: Whether serialization succeeded.
*
* Since: 2.10
**/
gboolean
pika_config_serialize_to_stream (PikaConfig *config,
GOutputStream *output,
const gchar *header,
const gchar *footer,
gpointer data,
GError **error)
{
PikaConfigWriter *writer;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
writer = pika_config_writer_new_from_stream (output, header, error);
if (!writer)
return FALSE;
PIKA_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
return pika_config_writer_finish (writer, footer, error);
}
/**
* pika_config_serialize_to_fd:
* @config: an object that implements [iface@ConfigInterface].
* @fd: a file descriptor, opened for writing
* @data: user data passed to the serialize implementation.
*
* Serializes the object properties of @config to the given file
* descriptor.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise.
*
* Since: 2.4
**/
gboolean
pika_config_serialize_to_fd (PikaConfig *config,
gint fd,
gpointer data)
{
PikaConfigWriter *writer;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (fd > 0, FALSE);
writer = pika_config_writer_new_from_fd (fd);
if (!writer)
return FALSE;
PIKA_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
return pika_config_writer_finish (writer, NULL, NULL);
}
/**
* pika_config_serialize_to_string:
* @config: an object that implements the [iface@ConfigInterface].
* @data: user data passed to the serialize implementation.
*
* Serializes the object properties of @config to a string.
*
* Returns: a newly allocated NUL-terminated string.
*
* Since: 2.4
**/
gchar *
pika_config_serialize_to_string (PikaConfig *config,
gpointer data)
{
PikaConfigWriter *writer;
GString *str;
g_return_val_if_fail (PIKA_IS_CONFIG (config), NULL);
str = g_string_new (NULL);
writer = pika_config_writer_new_from_string (str);
PIKA_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
pika_config_writer_finish (writer, NULL, NULL);
return g_string_free (str, FALSE);
}
/**
* pika_config_serialize_to_parasite:
* @config: an object that implements the [iface@ConfigInterface].
* @parasite_name: the new parasite's name
* @parasite_flags: the new parasite's flags
* @data: user data passed to the serialize implementation.
*
* Serializes the object properties of @config to a [struct@Parasite].
*
* Returns: (transfer full): the newly allocated parasite.
*
* Since: 3.0
**/
PikaParasite *
pika_config_serialize_to_parasite (PikaConfig *config,
const gchar *parasite_name,
guint parasite_flags,
gpointer data)
{
PikaParasite *parasite;
gchar *str;
g_return_val_if_fail (PIKA_IS_CONFIG (config), NULL);
g_return_val_if_fail (parasite_name != NULL, NULL);
str = pika_config_serialize_to_string (config, data);
if (! str)
return NULL;
parasite = pika_parasite_new (parasite_name,
parasite_flags,
0, NULL);
parasite->size = strlen (str) + 1;
parasite->data = str;
return parasite;
}
/**
* pika_config_deserialize_file:
* @config: an object that implements the #PikaConfigInterface.
* @file: the file to read configuration from.
* @data: user data passed to the deserialize implementation.
* @error: return location for a possible error
*
* Opens the file specified by @file, reads configuration data from it
* and configures @config accordingly. Basically this function creates
* a properly configured [struct@GLib.Scanner] for you and calls the deserialize
* function of the @config's [iface@ConfigInterface].
*
* Returns: Whether deserialization succeeded.
*
* Since: 2.10
**/
gboolean
pika_config_deserialize_file (PikaConfig *config,
GFile *file,
gpointer data,
GError **error)
{
GScanner *scanner;
gboolean success;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
scanner = pika_scanner_new_file (file, error);
if (! scanner)
return FALSE;
g_object_freeze_notify (G_OBJECT (config));
success = PIKA_CONFIG_GET_IFACE (config)->deserialize (config,
scanner, 0, data);
g_object_thaw_notify (G_OBJECT (config));
pika_scanner_unref (scanner);
if (! success)
/* If we get this assert, it means we have a bug in one of the
* deserialize() implementations. Any failure case should report the
* error condition with g_scanner_error() which will populate the
* error object passed in pika_scanner_new*().
*/
g_assert (error == NULL || *error != NULL);
return success;
}
/**
* pika_config_deserialize_stream:
* @config: an object that implements the #PikaConfigInterface.
* @input: the input stream to read configuration from.
* @data: user data passed to the deserialize implementation.
* @error: return location for a possible error
*
* Reads configuration data from @input and configures @config
* accordingly. Basically this function creates a properly configured
* #GScanner for you and calls the deserialize function of the
* @config's #PikaConfigInterface.
*
* Returns: Whether deserialization succeeded.
*
* Since: 2.10
**/
gboolean
pika_config_deserialize_stream (PikaConfig *config,
GInputStream *input,
gpointer data,
GError **error)
{
GScanner *scanner;
gboolean success;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
scanner = pika_scanner_new_stream (input, error);
if (! scanner)
return FALSE;
g_object_freeze_notify (G_OBJECT (config));
success = PIKA_CONFIG_GET_IFACE (config)->deserialize (config,
scanner, 0, data);
g_object_thaw_notify (G_OBJECT (config));
pika_scanner_unref (scanner);
if (! success)
g_assert (error == NULL || *error != NULL);
return success;
}
/**
* pika_config_deserialize_string:
* @config: a #GObject that implements the #PikaConfigInterface.
* @text: (array length=text_len): string to deserialize (in UTF-8 encoding)
* @text_len: length of @text in bytes or -1
* @data: client data
* @error: return location for a possible error
*
* Configures @config from @text. Basically this function creates a
* properly configured #GScanner for you and calls the deserialize
* function of the @config's #PikaConfigInterface.
*
* Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
*
* Since: 2.4
**/
gboolean
pika_config_deserialize_string (PikaConfig *config,
const gchar *text,
gint text_len,
gpointer data,
GError **error)
{
GScanner *scanner;
gboolean success;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (text != NULL || text_len == 0, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
scanner = pika_scanner_new_string (text, text_len, error);
g_object_freeze_notify (G_OBJECT (config));
success = PIKA_CONFIG_GET_IFACE (config)->deserialize (config,
scanner, 0, data);
g_object_thaw_notify (G_OBJECT (config));
pika_scanner_unref (scanner);
if (! success)
g_assert (error == NULL || *error != NULL);
return success;
}
/**
* pika_config_deserialize_parasite:
* @config: a #GObject that implements the #PikaConfigInterface.
* @parasite: parasite containing a serialized config string
* @data: client data
* @error: return location for a possible error
*
* Configures @config from @parasite. Basically this function creates
* a properly configured #GScanner for you and calls the deserialize
* function of the @config's #PikaConfigInterface.
*
* Returns: %TRUE if deserialization succeeded, %FALSE otherwise.
*
* Since: 3.0
**/
gboolean
pika_config_deserialize_parasite (PikaConfig *config,
const PikaParasite *parasite,
gpointer data,
GError **error)
{
const gchar *parasite_data;
guint32 parasite_size;
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
g_return_val_if_fail (parasite != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
parasite_data = pika_parasite_get_data (parasite, &parasite_size);
if (! parasite_data)
return TRUE;
return pika_config_deserialize_string (config, parasite_data, parasite_size,
data, error);
}
/**
* pika_config_deserialize_return:
* @scanner: a #GScanner
* @expected_token: the expected token
* @nest_level: the nest level
*
* Returns:
*
* Since: 2.4
**/
gboolean
pika_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level)
{
GTokenType next_token;
g_return_val_if_fail (scanner != NULL, FALSE);
next_token = g_scanner_peek_next_token (scanner);
if (expected_token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
return FALSE;
}
else
{
if (nest_level > 0 && next_token == G_TOKEN_RIGHT_PAREN)
{
return TRUE;
}
else if (next_token != G_TOKEN_EOF)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
return FALSE;
}
}
return TRUE;
}
/**
* pika_config_serialize:
* @config: an object that implements the #PikaConfigInterface.
* @writer: the #PikaConfigWriter to use.
* @data: client data
*
* Serialize the #PikaConfig object.
*
* Returns: Whether serialization succeeded.
*
* Since: 2.8
**/
gboolean
pika_config_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data)
{
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
return PIKA_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
}
/**
* pika_config_deserialize:
* @config: a #GObject that implements the #PikaConfigInterface.
* @scanner: the #GScanner to use.
* @nest_level: the nest level.
* @data: client data.
*
* Deserialize the #PikaConfig object.
*
* Returns: Whether serialization succeeded.
*
* Since: 2.8
**/
gboolean
pika_config_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data)
{
g_return_val_if_fail (PIKA_IS_CONFIG (config), FALSE);
return PIKA_CONFIG_GET_IFACE (config)->deserialize (config,
scanner,
nest_level,
data);
}
/**
* pika_config_duplicate:
* @config: a #GObject that implements the #PikaConfigInterface.
*
* Creates a copy of the passed object by copying all object
* properties. The default implementation of the #PikaConfigInterface
* only works for objects that are completely defined by their
* properties.
*
* Returns: the duplicated #PikaConfig object
*
* Since: 2.4
**/
gpointer
pika_config_duplicate (PikaConfig *config)
{
g_return_val_if_fail (PIKA_IS_CONFIG (config), NULL);
return PIKA_CONFIG_GET_IFACE (config)->duplicate (config);
}
/**
* pika_config_is_equal_to:
* @a: a #GObject that implements the #PikaConfigInterface.
* @b: another #GObject of the same type as @a.
*
* Compares the two objects. The default implementation of the
* #PikaConfigInterface compares the object properties and thus only
* works for objects that are completely defined by their
* properties.
*
* Returns: %TRUE if the two objects are equal.
*
* Since: 2.4
**/
gboolean
pika_config_is_equal_to (PikaConfig *a,
PikaConfig *b)
{
g_return_val_if_fail (PIKA_IS_CONFIG (a), FALSE);
g_return_val_if_fail (PIKA_IS_CONFIG (b), FALSE);
g_return_val_if_fail (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b),
FALSE);
return PIKA_CONFIG_GET_IFACE (a)->equal (a, b);
}
/**
* pika_config_reset:
* @config: a #GObject that implements the #PikaConfigInterface.
*
* Resets the object to its default state. The default implementation of the
* #PikaConfigInterface only works for objects that are completely defined by
* their properties.
*
* Since: 2.4
**/
void
pika_config_reset (PikaConfig *config)
{
g_return_if_fail (PIKA_IS_CONFIG (config));
g_object_freeze_notify (G_OBJECT (config));
PIKA_CONFIG_GET_IFACE (config)->reset (config);
g_object_thaw_notify (G_OBJECT (config));
}
/**
* pika_config_copy:
* @src: a #GObject that implements the #PikaConfigInterface.
* @dest: another #GObject of the same type as @a.
* @flags: a mask of GParamFlags
*
* Compares all read- and write-able properties from @src and @dest
* that have all @flags set. Differing values are then copied from
* @src to @dest. If @flags is 0, all differing read/write properties.
*
* Properties marked as "construct-only" are not touched.
*
* Returns: %TRUE if @dest was modified, %FALSE otherwise
*
* Since: 2.6
**/
gboolean
pika_config_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags)
{
gboolean changed;
g_return_val_if_fail (PIKA_IS_CONFIG (src), FALSE);
g_return_val_if_fail (PIKA_IS_CONFIG (dest), FALSE);
g_return_val_if_fail (G_TYPE_FROM_INSTANCE (src) == G_TYPE_FROM_INSTANCE (dest),
FALSE);
g_object_freeze_notify (G_OBJECT (dest));
changed = PIKA_CONFIG_GET_IFACE (src)->copy (src, dest, flags);
g_object_thaw_notify (G_OBJECT (dest));
return changed;
}

View File

@ -0,0 +1,135 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Config file serialization and deserialization interface
* Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_IFACE_H__
#define __PIKA_CONFIG_IFACE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_CONFIG (pika_config_get_type ())
G_DECLARE_INTERFACE (PikaConfig, pika_config, PIKA, CONFIG, GObject)
struct _PikaConfigInterface
{
GTypeInterface base_iface;
gboolean (* serialize) (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data);
gboolean (* deserialize) (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data);
PikaConfig * (* deserialize_create) (GType type,
GScanner *scanner,
gint nest_level,
gpointer data);
gboolean (* serialize_property) (PikaConfig *config,
guint property_id,
const GValue *value,
GParamSpec *pspec,
PikaConfigWriter *writer);
gboolean (* deserialize_property) (PikaConfig *config,
guint property_id,
GValue *value,
GParamSpec *pspec,
GScanner *scanner,
GTokenType *expected);
PikaConfig * (* duplicate) (PikaConfig *config);
gboolean (* equal) (PikaConfig *a,
PikaConfig *b);
void (* reset) (PikaConfig *config);
gboolean (* copy) (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags);
};
gboolean pika_config_serialize_to_file (PikaConfig *config,
GFile *file,
const gchar *header,
const gchar *footer,
gpointer data,
GError **error);
gboolean pika_config_serialize_to_stream (PikaConfig *config,
GOutputStream *output,
const gchar *header,
const gchar *footer,
gpointer data,
GError **error);
gboolean pika_config_serialize_to_fd (PikaConfig *config,
gint fd,
gpointer data);
gchar * pika_config_serialize_to_string (PikaConfig *config,
gpointer data);
PikaParasite *
pika_config_serialize_to_parasite (PikaConfig *config,
const gchar *parasite_name,
guint parasite_flags,
gpointer data);
gboolean pika_config_deserialize_file (PikaConfig *config,
GFile *file,
gpointer data,
GError **error);
gboolean pika_config_deserialize_stream (PikaConfig *config,
GInputStream *input,
gpointer data,
GError **error);
gboolean pika_config_deserialize_string (PikaConfig *config,
const gchar *text,
gint text_len,
gpointer data,
GError **error);
gboolean pika_config_deserialize_parasite (PikaConfig *config,
const PikaParasite *parasite,
gpointer data,
GError **error);
gboolean pika_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level);
gboolean pika_config_serialize (PikaConfig *config,
PikaConfigWriter *writer,
gpointer data);
gboolean pika_config_deserialize (PikaConfig *config,
GScanner *scanner,
gint nest_level,
gpointer data);
gpointer pika_config_duplicate (PikaConfig *config);
gboolean pika_config_is_equal_to (PikaConfig *a,
PikaConfig *b);
void pika_config_reset (PikaConfig *config);
gboolean pika_config_copy (PikaConfig *src,
PikaConfig *dest,
GParamFlags flags);
G_END_DECLS
#endif /* __PIKA_CONFIG_IFACE_H__ */

View File

@ -0,0 +1,388 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
*
* pikaconfig-params.c
* Copyright (C) 2008-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gegl-paramspecs.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikaconfig.h"
/**
* SECTION: pikaconfig-params
* @title: PikaConfig-params
* @short_description: Macros and defines to install config properties.
*
* Macros and defines to install config properties.
**/
static gboolean
pika_gegl_param_spec_has_key (GParamSpec *pspec,
const gchar *key,
const gchar *value)
{
const gchar *v = gegl_param_spec_get_property_key (pspec, key);
if (v && ! strcmp (v, value))
return TRUE;
return FALSE;
}
/**
* pika_config_param_spec_duplicate:
* @pspec: the #GParamSpec to duplicate
*
* Creates an exact copy of @pspec, with all its properties, returns
* %NULL if @pspec is of an unknown type that can't be duplicated.
*
* Return: (transfer full): The new #GParamSpec, or %NULL.
*
* Since: 3.0
**/
GParamSpec *
pika_config_param_spec_duplicate (GParamSpec *pspec)
{
GParamSpec *copy = NULL;
const gchar *name;
const gchar *nick;
const gchar *blurb;
GParamFlags flags;
g_return_val_if_fail (pspec != NULL, NULL);
name = pspec->name;
nick = g_param_spec_get_nick (pspec);
blurb = g_param_spec_get_blurb (pspec);
flags = pspec->flags;
/* this special case exists for the GEGL tool, we don't want this
* property serialized
*/
if (! pika_gegl_param_spec_has_key (pspec, "role", "output-extent"))
flags |= PIKA_CONFIG_PARAM_SERIALIZE;
if (G_IS_PARAM_SPEC_STRING (pspec))
{
GParamSpecString *spec = G_PARAM_SPEC_STRING (pspec);
if (GEGL_IS_PARAM_SPEC_FILE_PATH (pspec))
{
copy = pika_param_spec_config_path (name, nick, blurb,
PIKA_CONFIG_PATH_FILE,
spec->default_value,
flags);
}
else if (PIKA_IS_PARAM_SPEC_CONFIG_PATH (pspec))
{
copy = pika_param_spec_config_path (name, nick, blurb,
pika_param_spec_config_path_type (pspec),
spec->default_value,
flags);
}
else
{
copy = g_param_spec_string (name, nick, blurb,
spec->default_value,
flags);
}
}
else if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
{
GParamSpecBoolean *spec = G_PARAM_SPEC_BOOLEAN (pspec);
copy = g_param_spec_boolean (name, nick, blurb,
spec->default_value,
flags);
}
else if (G_IS_PARAM_SPEC_ENUM (pspec))
{
GParamSpecEnum *spec = G_PARAM_SPEC_ENUM (pspec);
copy = g_param_spec_enum (name, nick, blurb,
G_TYPE_FROM_CLASS (spec->enum_class),
spec->default_value,
flags);
}
else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
{
GParamSpecDouble *spec = G_PARAM_SPEC_DOUBLE (pspec);
if (GEGL_IS_PARAM_SPEC_DOUBLE (pspec))
{
GeglParamSpecDouble *gspec = GEGL_PARAM_SPEC_DOUBLE (pspec);
copy = gegl_param_spec_double (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
gspec->ui_minimum,
gspec->ui_maximum,
gspec->ui_gamma,
flags);
gegl_param_spec_double_set_steps (GEGL_PARAM_SPEC_DOUBLE (copy),
gspec->ui_step_small,
gspec->ui_step_big);
gegl_param_spec_double_set_digits (GEGL_PARAM_SPEC_DOUBLE (copy),
gspec->ui_digits);
}
else
{
copy = g_param_spec_double (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
flags);
}
}
else if (G_IS_PARAM_SPEC_FLOAT (pspec))
{
GParamSpecFloat *spec = G_PARAM_SPEC_FLOAT (pspec);
copy = g_param_spec_float (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
flags);
}
else if (G_IS_PARAM_SPEC_INT (pspec))
{
GParamSpecInt *spec = G_PARAM_SPEC_INT (pspec);
if (GEGL_IS_PARAM_SPEC_INT (pspec))
{
GeglParamSpecInt *gspec = GEGL_PARAM_SPEC_INT (pspec);
copy = gegl_param_spec_int (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
gspec->ui_minimum,
gspec->ui_maximum,
gspec->ui_gamma,
flags);
gegl_param_spec_int_set_steps (GEGL_PARAM_SPEC_INT (copy),
gspec->ui_step_small,
gspec->ui_step_big);
}
else if (PIKA_IS_PARAM_SPEC_UNIT (pspec))
{
PikaParamSpecUnit *spec = PIKA_PARAM_SPEC_UNIT (pspec);
GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec);
copy = pika_param_spec_unit (name, nick, blurb,
ispec->minimum == PIKA_UNIT_PIXEL,
spec->allow_percent,
ispec->default_value,
flags);
}
else
{
copy = g_param_spec_int (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
flags);
}
}
else if (G_IS_PARAM_SPEC_UINT (pspec))
{
GParamSpecUInt *spec = G_PARAM_SPEC_UINT (pspec);
if (GEGL_IS_PARAM_SPEC_SEED (pspec))
{
GeglParamSpecSeed *gspec = GEGL_PARAM_SPEC_SEED (pspec);
copy = gegl_param_spec_seed (name, nick, blurb,
flags);
G_PARAM_SPEC_UINT (copy)->minimum = spec->minimum;
G_PARAM_SPEC_UINT (copy)->maximum = spec->maximum;
G_PARAM_SPEC_UINT (copy)->default_value = spec->default_value;
GEGL_PARAM_SPEC_SEED (copy)->ui_minimum = gspec->ui_minimum;
GEGL_PARAM_SPEC_SEED (copy)->ui_maximum = gspec->ui_maximum;
}
else
{
copy = g_param_spec_uint (name, nick, blurb,
spec->minimum,
spec->maximum,
spec->default_value,
flags);
}
}
else if (PIKA_IS_PARAM_SPEC_RGB (pspec))
{
PikaRGB color;
pika_param_spec_rgb_get_default (pspec, &color);
copy = pika_param_spec_rgb (name, nick, blurb,
pika_param_spec_rgb_has_alpha (pspec),
&color,
flags);
}
/* In some cases, such as some GIR bindings, creating a PikaRGB
* argument is impossible (or at least I have not found how, at least
* in the Python binding which is doing some weird shortcuts when
* handling GValue and param specs. So instead, the parameter appears
* as a Boxed param with a PikaRGB value type.
*/
else if (G_IS_PARAM_SPEC_BOXED (pspec) &&
G_PARAM_SPEC_VALUE_TYPE (pspec) == PIKA_TYPE_RGB)
{
GValue *value;
PikaRGB color;
value = (GValue *) g_param_spec_get_default_value (pspec);
pika_value_get_rgb (value, &color);
copy = pika_param_spec_rgb (name, nick, blurb,
TRUE, &color, flags);
}
else if (GEGL_IS_PARAM_SPEC_COLOR (pspec))
{
GeglColor *gegl_color;
PikaRGB pika_color;
gdouble r = 0.0;
gdouble g = 0.0;
gdouble b = 0.0;
gdouble a = 1.0;
GValue value = G_VALUE_INIT;
g_value_init (&value, GEGL_TYPE_COLOR);
g_param_value_set_default (pspec, &value);
gegl_color = g_value_get_object (&value);
if (gegl_color)
gegl_color_get_rgba (gegl_color, &r, &g, &b, &a);
pika_rgba_set (&pika_color, r, g, b, a);
g_value_unset (&value);
copy = pika_param_spec_rgb (name, nick, blurb,
TRUE,
&pika_color,
flags);
}
else if (G_IS_PARAM_SPEC_PARAM (pspec))
{
copy = g_param_spec_param (name, nick, blurb,
G_PARAM_SPEC_VALUE_TYPE (pspec),
flags);
}
else if (PIKA_IS_PARAM_SPEC_PARASITE (pspec))
{
copy = pika_param_spec_parasite (name, nick, blurb,
flags);
}
else if (PIKA_IS_PARAM_SPEC_ARRAY (pspec))
{
if (PIKA_IS_PARAM_SPEC_INT32_ARRAY (pspec))
{
copy = pika_param_spec_int32_array (name, nick, blurb,
flags);
}
else if (PIKA_IS_PARAM_SPEC_FLOAT_ARRAY (pspec))
{
copy = pika_param_spec_float_array (name, nick, blurb,
flags);
}
else if (PIKA_IS_PARAM_SPEC_RGB_ARRAY (pspec))
{
copy = pika_param_spec_rgb_array (name, nick, blurb,
flags);
}
}
else if (PIKA_IS_PARAM_SPEC_OBJECT_ARRAY (pspec))
{
PikaParamSpecObjectArray *spec = PIKA_PARAM_SPEC_OBJECT_ARRAY (pspec);
copy = pika_param_spec_object_array (name, nick, blurb,
spec->object_type,
flags);
}
else if (G_IS_PARAM_SPEC_OBJECT (pspec))
{
GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
const gchar *type_name = g_type_name (value_type);
if (value_type == G_TYPE_FILE ||
/* These types are not visibile in libpikaconfig so we compare
* with type names instead.
*/
g_strcmp0 (type_name, "PikaImage") == 0 ||
g_strcmp0 (type_name, "PikaDrawable") == 0 ||
g_strcmp0 (type_name, "PikaLayer") == 0 ||
g_strcmp0 (type_name, "PikaChannel") == 0 ||
g_strcmp0 (type_name, "PikaSelection") == 0 ||
g_strcmp0 (type_name, "PikaBrush") == 0 ||
g_strcmp0 (type_name, "PikaFont") == 0 ||
g_strcmp0 (type_name, "PikaGradient") == 0 ||
g_strcmp0 (type_name, "PikaPalette") == 0 ||
g_strcmp0 (type_name, "PikaPattern") == 0 ||
g_strcmp0 (type_name, "PikaVectors") == 0)
{
copy = g_param_spec_object (name, nick, blurb,
value_type,
flags);
}
}
else if (G_IS_PARAM_SPEC_BOXED (pspec))
{
GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
if (value_type == G_TYPE_BYTES ||
value_type == G_TYPE_STRV)
{
copy = g_param_spec_boxed (name, nick, blurb, value_type, flags);
}
}
if (copy)
{
GQuark quark = 0;
GHashTable *keys;
if (G_UNLIKELY (! quark))
quark = g_quark_from_static_string ("gegl-property-keys");
keys = g_param_spec_get_qdata (pspec, quark);
if (keys)
g_param_spec_set_qdata_full (copy, quark, g_hash_table_ref (keys),
(GDestroyNotify) g_hash_table_unref);
}
return copy;
}

View File

@ -0,0 +1,224 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* ParamSpecs for config objects
* Copyright (C) 2001 Sven Neumann <sven@gimp.org>
* 2001-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_PARAMS_H__
#define __PIKA_CONFIG_PARAMS_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/**
* PIKA_CONFIG_PARAM_SERIALIZE:
*
* A property that can and should be serialized and deserialized.
**/
#define PIKA_CONFIG_PARAM_SERIALIZE (1 << (0 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_AGGREGATE:
*
* The object property is to be treated as part of the parent object.
**/
#define PIKA_CONFIG_PARAM_AGGREGATE (1 << (1 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_RESTART:
*
* Changes to this property take effect only after a restart.
**/
#define PIKA_CONFIG_PARAM_RESTART (1 << (2 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_CONFIRM:
*
* Changes to this property should be confirmed by the user before
* being applied.
**/
#define PIKA_CONFIG_PARAM_CONFIRM (1 << (3 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_DEFAULTS:
*
* Don't serialize this property if it has the default value.
**/
#define PIKA_CONFIG_PARAM_DEFAULTS (1 << (4 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_IGNORE:
*
* This property exists for obscure reasons or is needed for backward
* compatibility. Ignore the value read and don't serialize it.
**/
#define PIKA_CONFIG_PARAM_IGNORE (1 << (5 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_DONT_COMPARE:
*
* Ignore this property when comparing objects.
**/
#define PIKA_CONFIG_PARAM_DONT_COMPARE (1 << (6 + G_PARAM_USER_SHIFT))
/**
* PIKA_CONFIG_PARAM_FLAGS:
*
* The default flags that should be used for serializable #PikaConfig
* properties.
**/
#define PIKA_CONFIG_PARAM_FLAGS (G_PARAM_READWRITE | \
G_PARAM_CONSTRUCT | \
G_PARAM_STATIC_STRINGS | \
PIKA_CONFIG_PARAM_SERIALIZE)
/* some convenience macros to install object properties */
#define PIKA_CONFIG_PROP_BOOLEAN(class, id, name, nick, blurb, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_boolean (name, nick, blurb,\
default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_INT(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_int (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_UINT(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_uint (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_INT64(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_int64 (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_UINT64(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_uint64 (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_UNIT(class, id, name, nick, blurb, pixels, percent, default, flags) \
g_object_class_install_property (class, id,\
pika_param_spec_unit (name, nick, blurb,\
pixels, percent, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_MEMSIZE(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
pika_param_spec_memsize (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_DOUBLE(class, id, name, nick, blurb, min, max, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_double (name, nick, blurb,\
min, max, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_RESOLUTION(class, id, name, nick, blurb, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_double (name, nick, blurb,\
PIKA_MIN_RESOLUTION, PIKA_MAX_RESOLUTION, \
default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_ENUM(class, id, name, nick, blurb, enum_type, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_enum (name, nick, blurb,\
enum_type, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_STRING(class, id, name, nick, blurb, default, flags) \
g_object_class_install_property (class, id,\
g_param_spec_string (name, nick, blurb,\
default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_PATH(class, id, name, nick, blurb, path_type, default, flags) \
g_object_class_install_property (class, id,\
pika_param_spec_config_path (name, nick, blurb,\
path_type, default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_RGB(class, id, name, nick, blurb, has_alpha, default, flags) \
g_object_class_install_property (class, id,\
pika_param_spec_rgb (name, nick, blurb,\
has_alpha, default, \
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_MATRIX2(class, id, name, nick, blurb, default, flags) \
g_object_class_install_property (class, id,\
pika_param_spec_matrix2 (name, nick, blurb,\
default,\
flags | PIKA_CONFIG_PARAM_FLAGS))
#define PIKA_CONFIG_PROP_FONT(class, id, name, nick, blurb, flags) \
g_object_class_install_property (class, id,\
g_param_spec_object (name, nick, blurb,\
PIKA_TYPE_FONT,\
flags | PIKA_CONFIG_PARAM_FLAGS))
/* object, boxed and pointer properties are _not_ G_PARAM_CONSTRUCT */
#define PIKA_CONFIG_PROP_OBJECT(class, id, name, nick, blurb, object_type, flags) \
g_object_class_install_property (class, id,\
g_param_spec_object (name, nick, blurb,\
object_type,\
flags |\
G_PARAM_READWRITE |\
PIKA_CONFIG_PARAM_SERIALIZE))
#define PIKA_CONFIG_PROP_BOXED(class, id, name, nick, blurb, boxed_type, flags) \
g_object_class_install_property (class, id,\
g_param_spec_boxed (name, nick, blurb,\
boxed_type,\
flags |\
G_PARAM_READWRITE |\
PIKA_CONFIG_PARAM_SERIALIZE))
#define PIKA_CONFIG_PROP_POINTER(class, id, name, nick, blurb, flags) \
g_object_class_install_property (class, id,\
g_param_spec_pointer (name, nick, blurb,\
flags |\
G_PARAM_READWRITE |\
PIKA_CONFIG_PARAM_SERIALIZE))
/* create a copy of a GParamSpec */
GParamSpec * pika_config_param_spec_duplicate (GParamSpec *pspec);
G_END_DECLS
#endif /* __PIKA_CONFIG_PARAMS_H__ */

View File

@ -0,0 +1,743 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* pikaconfig-path.c
* Copyright (C) 2001 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "pikaconfig-error.h"
#include "pikaconfig-path.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikaconfig-path
* @title: PikaConfig-path
* @short_description: File path utilities for libpikaconfig.
*
* File path utilities for libpikaconfig.
**/
/**
* pika_config_path_get_type:
*
* Reveals the object type
*
* Returns: the #GType for a PikaConfigPath string property
*
* Since: 2.4
**/
GType
pika_config_path_get_type (void)
{
static GType path_type = 0;
if (! path_type)
{
const GTypeInfo type_info = { 0, };
path_type = g_type_register_static (G_TYPE_STRING, "PikaConfigPath",
&type_info, 0);
}
return path_type;
}
/*
* PIKA_TYPE_PARAM_CONFIG_PATH
*/
#define PIKA_PARAM_SPEC_CONFIG_PATH(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), PIKA_TYPE_PARAM_CONFIG_PATH, PikaParamSpecConfigPath))
typedef struct _PikaParamSpecConfigPath PikaParamSpecConfigPath;
struct _PikaParamSpecConfigPath
{
GParamSpecString parent_instance;
PikaConfigPathType type;
};
static void pika_param_config_path_class_init (GParamSpecClass *class);
/**
* pika_param_config_path_get_type:
*
* Reveals the object type
*
* Returns: the #GType for a directory path object
*
* Since: 2.4
**/
GType
pika_param_config_path_get_type (void)
{
static GType spec_type = 0;
if (! spec_type)
{
const GTypeInfo type_info =
{
sizeof (GParamSpecClass),
NULL, NULL,
(GClassInitFunc) pika_param_config_path_class_init,
NULL, NULL,
sizeof (PikaParamSpecConfigPath),
0, NULL, NULL
};
spec_type = g_type_register_static (G_TYPE_PARAM_STRING,
"PikaParamConfigPath",
&type_info, 0);
}
return spec_type;
}
static void
pika_param_config_path_class_init (GParamSpecClass *class)
{
class->value_type = PIKA_TYPE_CONFIG_PATH;
}
/**
* pika_param_spec_config_path:
* @name: Canonical name of the param
* @nick: Nickname of the param
* @blurb: Brief description of param.
* @type: a #PikaConfigPathType value.
* @default_value: Value to use if none is assigned.
* @flags: a combination of #GParamFlags
*
* Creates a param spec to hold a filename, dir name,
* or list of file or dir names.
* See g_param_spec_internal() for more information.
*
* Returns: (transfer full): a newly allocated #GParamSpec instance
*
* Since: 2.4
**/
GParamSpec *
pika_param_spec_config_path (const gchar *name,
const gchar *nick,
const gchar *blurb,
PikaConfigPathType type,
const gchar *default_value,
GParamFlags flags)
{
GParamSpecString *pspec;
pspec = g_param_spec_internal (PIKA_TYPE_PARAM_CONFIG_PATH,
name, nick, blurb, flags);
pspec->default_value = g_strdup (default_value);
PIKA_PARAM_SPEC_CONFIG_PATH (pspec)->type = type;
return G_PARAM_SPEC (pspec);
}
/**
* pika_param_spec_config_path_type:
* @pspec: A #GParamSpec for a path param
*
* Tells whether the path param encodes a filename,
* dir name, or list of file or dir names.
*
* Returns: a #PikaConfigPathType value
*
* Since: 2.4
**/
PikaConfigPathType
pika_param_spec_config_path_type (GParamSpec *pspec)
{
g_return_val_if_fail (PIKA_IS_PARAM_SPEC_CONFIG_PATH (pspec), 0);
return PIKA_PARAM_SPEC_CONFIG_PATH (pspec)->type;
}
/*
* PikaConfig path utilities
*/
static gchar * pika_config_path_expand_only (const gchar *path,
GError **error) G_GNUC_MALLOC;
static inline gchar * pika_config_path_extract_token (const gchar **str);
static gchar * pika_config_path_unexpand_only (const gchar *path) G_GNUC_MALLOC;
/**
* pika_config_build_data_path:
* @name: directory name (in UTF-8 encoding)
*
* Creates a search path as it is used in the pikarc file. The path
* returned by pika_config_build_data_path() includes a directory
* below the user's pika directory and one in the system-wide data
* directory.
*
* Note that you cannot use this path directly with pika_path_parse().
* As it is in the pikarc notation, you first need to expand and
* recode it using pika_config_path_expand().
*
* Returns: a newly allocated string
*
* Since: 2.4
**/
gchar *
pika_config_build_data_path (const gchar *name)
{
return g_strconcat ("${pika_dir}", G_DIR_SEPARATOR_S, name,
G_SEARCHPATH_SEPARATOR_S,
"${pika_data_dir}", G_DIR_SEPARATOR_S, name,
NULL);
}
/**
* pika_config_build_plug_in_path:
* @name: directory name (in UTF-8 encoding)
*
* Creates a search path as it is used in the pikarc file. The path
* returned by pika_config_build_plug_in_path() includes a directory
* below the user's pika directory and one in the system-wide plug-in
* directory.
*
* Note that you cannot use this path directly with pika_path_parse().
* As it is in the pikarc notation, you first need to expand and
* recode it using pika_config_path_expand().
*
* Returns: a newly allocated string
*
* Since: 2.4
**/
gchar *
pika_config_build_plug_in_path (const gchar *name)
{
return g_strconcat ("${pika_dir}", G_DIR_SEPARATOR_S, name,
G_SEARCHPATH_SEPARATOR_S,
"${pika_plug_in_dir}", G_DIR_SEPARATOR_S, name,
NULL);
}
/**
* pika_config_build_writable_path:
* @name: directory name (in UTF-8 encoding)
*
* Creates a search path as it is used in the pikarc file. The path
* returned by pika_config_build_writable_path() is just the writable
* parts of the search path constructed by pika_config_build_data_path().
*
* Note that you cannot use this path directly with pika_path_parse().
* As it is in the pikarc notation, you first need to expand and
* recode it using pika_config_path_expand().
*
* Returns: a newly allocated string
*
* Since: 2.4
**/
gchar *
pika_config_build_writable_path (const gchar *name)
{
return g_strconcat ("${pika_dir}", G_DIR_SEPARATOR_S, name, NULL);
}
/**
* pika_config_build_system_path:
* @name: directory name (in UTF-8 encoding)
*
* Creates a search path as it is used in the pikarc file. The path
* returned by pika_config_build_system_path() is just the read-only
* parts of the search path constructed by pika_config_build_plug_in_path().
*
* Note that you cannot use this path directly with pika_path_parse().
* As it is in the pikarc notation, you first need to expand and
* recode it using pika_config_path_expand().
*
* Returns: a newly allocated string
*
* Since: 2.10.6
**/
gchar *
pika_config_build_system_path (const gchar *name)
{
return g_strconcat ("${pika_plug_in_dir}", G_DIR_SEPARATOR_S, name, NULL);
}
/**
* pika_config_path_expand:
* @path: a NUL-terminated string in UTF-8 encoding
* @recode: whether to convert to the filesystem's encoding
* @error: return location for errors
*
* Paths as stored in pikarc and other config files have to be treated
* special. The string may contain special identifiers such as for
* example ${pika_dir} that have to be substituted before use. Also
* the user's filesystem may be in a different encoding than UTF-8
* (which is what is used for the pikarc). This function does the
* variable substitution for you and can also attempt to convert to
* the filesystem encoding.
*
* To reverse the expansion, use pika_config_path_unexpand().
*
* Returns: a newly allocated NUL-terminated string
*
* Since: 2.4
**/
gchar *
pika_config_path_expand (const gchar *path,
gboolean recode,
GError **error)
{
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (recode)
{
gchar *retval;
gchar *expanded = pika_config_path_expand_only (path, error);
if (! expanded)
return NULL;
retval = g_filename_from_utf8 (expanded, -1, NULL, NULL, error);
g_free (expanded);
return retval;
}
return pika_config_path_expand_only (path, error);
}
/**
* pika_config_path_expand_to_files:
* @path: a NUL-terminated string in UTF-8 encoding
* @error: return location for errors
*
* Paths as stored in the pikarc have to be treated special. The
* string may contain special identifiers such as for example
* ${pika_dir} that have to be substituted before use. Also the user's
* filesystem may be in a different encoding than UTF-8 (which is what
* is used for the pikarc).
*
* This function runs @path through pika_config_path_expand() and
* pika_path_parse(), then turns the filenames returned by
* pika_path_parse() into GFile using g_file_new_for_path().
*
* Returns: (element-type GFile) (transfer full):
a #GList of newly allocated #GFile objects.
*
* Since: 2.10
**/
GList *
pika_config_path_expand_to_files (const gchar *path,
GError **error)
{
GList *files;
GList *list;
gchar *expanded;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
expanded = pika_config_path_expand (path, TRUE, error);
if (! expanded)
return NULL;
files = pika_path_parse (expanded, 256, FALSE, NULL);
g_free (expanded);
for (list = files; list; list = g_list_next (list))
{
gchar *dir = list->data;
list->data = g_file_new_for_path (dir);
g_free (dir);
}
return files;
}
/**
* pika_config_path_unexpand:
* @path: a NUL-terminated string
* @recode: whether @path is in filesystem encoding or UTF-8
* @error: return location for errors
*
* The inverse operation of pika_config_path_expand()
*
* This function takes a @path and tries to substitute the first
* elements by well-known special identifiers such as for example
* ${pika_dir}. The unexpanded path can then be stored in pikarc and
* other config files.
*
* If @recode is %TRUE then @path is in local filesystem encoding,
* if @recode is %FALSE then @path is assumed to be UTF-8.
*
* Returns: a newly allocated NUL-terminated UTF-8 string
*
* Since: 2.10
**/
gchar *
pika_config_path_unexpand (const gchar *path,
gboolean recode,
GError **error)
{
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (recode)
{
gchar *retval;
gchar *utf8 = g_filename_to_utf8 (path, -1, NULL, NULL, error);
if (! utf8)
return NULL;
retval = pika_config_path_unexpand_only (utf8);
g_free (utf8);
return retval;
}
return pika_config_path_unexpand_only (path);
}
/**
* pika_file_new_for_config_path:
* @path: a NUL-terminated string in UTF-8 encoding
* @error: return location for errors
*
* Expands @path using pika_config_path_expand() and returns a #GFile
* for the expanded path.
*
* To reverse the expansion, use pika_file_get_config_path().
*
* Returns: (nullable) (transfer full): a newly allocated #GFile,
* or %NULL if the expansion failed.
*
* Since: 2.10
**/
GFile *
pika_file_new_for_config_path (const gchar *path,
GError **error)
{
GFile *file = NULL;
gchar *expanded;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
expanded = pika_config_path_expand (path, TRUE, error);
if (expanded)
{
file = g_file_new_for_path (expanded);
g_free (expanded);
}
return file;
}
/**
* pika_file_get_config_path:
* @file: a #GFile
* @error: return location for errors
*
* Unexpands @file's path using pika_config_path_unexpand() and
* returns the unexpanded path.
*
* The inverse operation of pika_file_new_for_config_path().
*
* Returns: a newly allocated NUL-terminated UTF-8 string, or %NULL if
* unexpanding failed.
*
* Since: 2.10
**/
gchar *
pika_file_get_config_path (GFile *file,
GError **error)
{
gchar *unexpanded = NULL;
gchar *path;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
path = g_file_get_path (file);
if (path)
{
unexpanded = pika_config_path_unexpand (path, TRUE, error);
g_free (path);
}
else
{
g_set_error_literal (error, 0, 0,
_("File has no path representation"));
}
return unexpanded;
}
/* private functions */
#define SUBSTS_ALLOC 4
static gchar *
pika_config_path_expand_only (const gchar *path,
GError **error)
{
const gchar *home;
const gchar *p;
const gchar *s;
gchar *n;
gchar *token;
gchar *filename = NULL;
gchar *expanded = NULL;
gchar **substs = NULL;
guint n_substs = 0;
gint length = 0;
guint i;
home = g_get_home_dir ();
if (home)
home = pika_filename_to_utf8 (home);
p = path;
while (*p)
{
if (*p == '~' && home)
{
length += strlen (home);
p += 1;
}
else if ((token = pika_config_path_extract_token (&p)) != NULL)
{
for (i = 0; i < n_substs; i++)
if (strcmp (substs[2*i], token) == 0)
break;
if (i < n_substs)
{
s = substs[2*i+1];
}
else
{
s = NULL;
if (strcmp (token, "pika_dir") == 0)
s = pika_directory ();
else if (strcmp (token, "pika_data_dir") == 0)
s = pika_data_directory ();
else if (strcmp (token, "pika_plug_in_dir") == 0 ||
strcmp (token, "pika_plugin_dir") == 0)
s = pika_plug_in_directory ();
else if (strcmp (token, "pika_sysconf_dir") == 0)
s = pika_sysconf_directory ();
else if (strcmp (token, "pika_installation_dir") == 0)
s = pika_installation_directory ();
else if (strcmp (token, "pika_cache_dir") == 0)
s = pika_cache_directory ();
else if (strcmp (token, "pika_temp_dir") == 0)
s = pika_temp_directory ();
if (!s)
s = g_getenv (token);
#ifdef G_OS_WIN32
/* The default user pikarc on Windows references
* ${TEMP}, but not all Windows installations have that
* environment variable, even if it should be kinda
* standard. So special-case it.
*/
if (!s && strcmp (token, "TEMP") == 0)
s = g_get_tmp_dir ();
#endif /* G_OS_WIN32 */
}
if (!s)
{
g_set_error (error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
_("Cannot expand ${%s}"), token);
g_free (token);
goto cleanup;
}
if (n_substs % SUBSTS_ALLOC == 0)
substs = g_renew (gchar *, substs, 2 * (n_substs + SUBSTS_ALLOC));
substs[2*n_substs] = token;
substs[2*n_substs + 1] = (gchar *) pika_filename_to_utf8 (s);
length += strlen (substs[2*n_substs + 1]);
n_substs++;
}
else
{
length += g_utf8_skip[(const guchar) *p];
p = g_utf8_next_char (p);
}
}
if (n_substs == 0)
return g_strdup (path);
expanded = g_new (gchar, length + 1);
p = path;
n = expanded;
while (*p)
{
if (*p == '~' && home)
{
*n = '\0';
strcat (n, home);
n += strlen (home);
p += 1;
}
else if ((token = pika_config_path_extract_token (&p)) != NULL)
{
for (i = 0; i < n_substs; i++)
{
if (strcmp (substs[2*i], token) == 0)
{
s = substs[2*i+1];
*n = '\0';
strcat (n, s);
n += strlen (s);
break;
}
}
g_free (token);
}
else
{
*n++ = *p++;
}
}
*n = '\0';
cleanup:
for (i = 0; i < n_substs; i++)
g_free (substs[2*i]);
g_free (substs);
g_free (filename);
return expanded;
}
static inline gchar *
pika_config_path_extract_token (const gchar **str)
{
const gchar *p;
gchar *token;
if (strncmp (*str, "${", 2))
return NULL;
p = *str + 2;
while (*p && (*p != '}'))
p = g_utf8_next_char (p);
if (! *p)
return NULL;
token = g_strndup (*str + 2, g_utf8_pointer_to_offset (*str + 2, p));
*str = p + 1; /* after the closing bracket */
return token;
}
static gchar *
pika_config_path_unexpand_only (const gchar *path)
{
const struct
{
const gchar *id;
const gchar *prefix;
}
identifiers[] =
{
{ "${pika_plug_in_dir}", pika_plug_in_directory () },
{ "${pika_data_dir}", pika_data_directory () },
{ "${pika_sysconf_dir}", pika_sysconf_directory () },
{ "${pika_installation_dir}", pika_installation_directory () },
{ "${pika_cache_dir}", pika_cache_directory () },
{ "${pika_temp_dir}", pika_temp_directory () },
{ "${pika_dir}", pika_directory () }
};
GList *files;
GList *list;
gchar *unexpanded;
files = pika_path_parse (path, 256, FALSE, NULL);
for (list = files; list; list = g_list_next (list))
{
gchar *dir = list->data;
gint i;
for (i = 0; i < G_N_ELEMENTS (identifiers); i++)
{
if (g_str_has_prefix (dir, identifiers[i].prefix))
{
gchar *tmp = g_strconcat (identifiers[i].id,
dir + strlen (identifiers[i].prefix),
NULL);
g_free (dir);
list->data = tmp;
break;
}
}
}
unexpanded = pika_path_to_str (files);
pika_path_free (files);
return unexpanded;
}

View File

@ -0,0 +1,109 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikaconfig-path.h
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_PATH_H__
#define __PIKA_CONFIG_PATH_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/*
* PIKA_TYPE_CONFIG_PATH
*/
#define PIKA_TYPE_CONFIG_PATH (pika_config_path_get_type ())
#define PIKA_VALUE_HOLDS_CONFIG_PATH(value) (G_TYPE_CHECK_VALUE_TYPE ((value), PIKA_TYPE_CONFIG_PATH))
GType pika_config_path_get_type (void) G_GNUC_CONST;
/*
* PIKA_TYPE_PARAM_CONFIG_PATH
*/
/**
* PikaConfigPathType:
* @PIKA_CONFIG_PATH_FILE: A single file
* @PIKA_CONFIG_PATH_FILE_LIST: A list of files
* @PIKA_CONFIG_PATH_DIR: A single folder
* @PIKA_CONFIG_PATH_DIR_LIST: A list of folders
*
* Types of config paths.
**/
typedef enum
{
PIKA_CONFIG_PATH_FILE,
PIKA_CONFIG_PATH_FILE_LIST,
PIKA_CONFIG_PATH_DIR,
PIKA_CONFIG_PATH_DIR_LIST
} PikaConfigPathType;
#define PIKA_TYPE_PARAM_CONFIG_PATH (pika_param_config_path_get_type ())
#define PIKA_IS_PARAM_SPEC_CONFIG_PATH(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), PIKA_TYPE_PARAM_CONFIG_PATH))
GType pika_param_config_path_get_type (void) G_GNUC_CONST;
GParamSpec * pika_param_spec_config_path (const gchar *name,
const gchar *nick,
const gchar *blurb,
PikaConfigPathType type,
const gchar *default_value,
GParamFlags flags);
PikaConfigPathType pika_param_spec_config_path_type (GParamSpec *pspec);
/*
* PikaConfigPath utilities
*/
gchar * pika_config_path_expand (const gchar *path,
gboolean recode,
GError **error) G_GNUC_MALLOC;
GList * pika_config_path_expand_to_files (const gchar *path,
GError **error) G_GNUC_MALLOC;
gchar * pika_config_path_unexpand (const gchar *path,
gboolean recode,
GError **error) G_GNUC_MALLOC;
GFile * pika_file_new_for_config_path (const gchar *path,
GError **error) G_GNUC_MALLOC;
gchar * pika_file_get_config_path (GFile *file,
GError **error) G_GNUC_MALLOC;
gchar * pika_config_build_data_path (const gchar *name) G_GNUC_MALLOC;
gchar * pika_config_build_writable_path (const gchar *name) G_GNUC_MALLOC;
gchar * pika_config_build_plug_in_path (const gchar *name) G_GNUC_MALLOC;
gchar * pika_config_build_system_path (const gchar *name) G_GNUC_MALLOC;
G_END_DECLS
#endif /* __PIKA_CONFIG_PATH_H__ */

View File

@ -0,0 +1,244 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
*
* pikaconfig-register.c
* Copyright (C) 2008-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl-paramspecs.h>
#include "libpikabase/pikabase.h"
#include "pikaconfig.h"
/* local function prototypes */
static void pika_config_class_init (GObjectClass *klass,
GParamSpec **pspecs);
static void pika_config_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_config_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GValue * pika_config_value_get (GObject *object,
GParamSpec *pspec);
static GValue * pika_config_value_new (GParamSpec *pspec);
static void pika_config_value_free (GValue *value);
/* public functions */
/**
* pika_config_type_register:
* @parent_type: type from which this type will be derived
* @type_name: string used as the name of the new type
* @pspecs: (array length=n_pspecs): array of #GParamSpec to install as properties on the new type
* @n_pspecs: the number of param specs in @pspecs
*
* This function is a fancy wrapper around g_type_register_static().
* It creates a new object type as subclass of @parent_type, installs
* @pspecs on it and makes the new type implement the #PikaConfig
* interface.
*
* Returns: the newly registered #GType
*
* Since: 3.0
**/
GType
pika_config_type_register (GType parent_type,
const gchar *type_name,
GParamSpec **pspecs,
gint n_pspecs)
{
GParamSpec **terminated_pspecs;
GTypeQuery query;
GType config_type;
g_return_val_if_fail (g_type_is_a (parent_type, G_TYPE_OBJECT), G_TYPE_NONE);
g_return_val_if_fail (type_name != NULL, G_TYPE_NONE);
g_return_val_if_fail (pspecs != NULL || n_pspecs == 0, G_TYPE_NONE);
terminated_pspecs = g_new0 (GParamSpec *, n_pspecs + 1);
memcpy (terminated_pspecs, pspecs, sizeof (GParamSpec *) * n_pspecs);
g_type_query (parent_type, &query);
{
GTypeInfo info =
{
query.class_size,
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) pika_config_class_init,
NULL, /* class_finalize */
terminated_pspecs,
query.instance_size,
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
config_type = g_type_register_static (parent_type, type_name,
&info, 0);
if (! g_type_is_a (parent_type, PIKA_TYPE_CONFIG))
{
const GInterfaceInfo config_info =
{
NULL, /* interface_init */
NULL, /* interface_finalize */
NULL /* interface_data */
};
g_type_add_interface_static (config_type, PIKA_TYPE_CONFIG,
&config_info);
}
}
return config_type;
}
/* private functions */
static void
pika_config_class_init (GObjectClass *klass,
GParamSpec **pspecs)
{
gint i;
klass->set_property = pika_config_set_property;
klass->get_property = pika_config_get_property;
for (i = 0; pspecs[i] != NULL; i++)
{
GParamSpec *pspec = pspecs[i];
GParamSpec *copy = pika_config_param_spec_duplicate (pspec);
if (copy)
{
g_object_class_install_property (klass, i + 1, copy);
}
else
{
GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
const gchar *type_name = g_type_name (value_type);
/* There are some properties that we don't care to copy because they
* are not serializable anyway (or we don't want them to be).
* PikaContext properties are one such property type. We can find them
* e.g. in some custom GEGL ops, such as "pika:offset". So we silently
* ignore these.
* We might add more types of properties to the list as we discover
* more cases. We keep warnings for all the other types which we
* explicitly don't support.
*/
if (g_strcmp0 (type_name, "PikaContext") != 0 &&
/* Format specs are a GParamSpecPointer. There might be other
* pointer specs we might be able to serialize, but BablFormat are
* not one of these (there might be easy serializable formats, but
* many are not and anyway it's probably not a data which ops or
* plug-ins want to remember across run).
*/
! GEGL_IS_PARAM_SPEC_FORMAT (pspec))
g_warning ("%s: not supported: %s (%s | %s)\n", G_STRFUNC,
g_type_name (G_TYPE_FROM_INSTANCE (pspec)), pspec->name, type_name);
}
}
}
static void
pika_config_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GValue *val = pika_config_value_get (object, pspec);
g_value_copy (value, val);
}
static void
pika_config_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GValue *val = pika_config_value_get (object, pspec);
g_value_copy (val, value);
}
static GValue *
pika_config_value_get (GObject *object,
GParamSpec *pspec)
{
GHashTable *properties;
GValue *value;
properties = g_object_get_data (object, "pika-config-properties");
if (! properties)
{
properties =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) pika_config_value_free);
g_object_set_data_full (object, "pika-config-properties", properties,
(GDestroyNotify) g_hash_table_unref);
}
value = g_hash_table_lookup (properties, pspec->name);
if (! value)
{
value = pika_config_value_new (pspec);
g_hash_table_insert (properties, g_strdup (pspec->name), value);
}
return value;
}
static GValue *
pika_config_value_new (GParamSpec *pspec)
{
GValue *value = g_slice_new0 (GValue);
g_value_init (value, pspec->value_type);
g_param_value_set_default (pspec, value);
return value;
}
static void
pika_config_value_free (GValue *value)
{
g_value_unset (value);
g_slice_free (GValue, value);
}

View File

@ -0,0 +1,42 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
*
* pikaconfig-register.c
* Copyright (C) 2008-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_REGISTER_H__
#define __PIKA_CONFIG_REGISTER_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
GType pika_config_type_register (GType parent_type,
const gchar *type_name,
GParamSpec **pspecs,
gint n_pspecs);
G_END_DECLS
#endif /* __PIKA_CONFIG_REGISTER_H__ */

View File

@ -0,0 +1,618 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Object properties serialization routines
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikacolor/pikacolor.h"
#include "pikaconfigtypes.h"
#include "pikaconfigwriter.h"
#include "pikaconfig-array.h"
#include "pikaconfig-iface.h"
#include "pikaconfig-params.h"
#include "pikaconfig-path.h"
#include "pikaconfig-serialize.h"
#include "pikaconfig-utils.h"
/**
* SECTION: pikaconfig-serialize
* @title: PikaConfig-serialize
* @short_description: Serializing for libpikaconfig.
*
* Serializing interface for libpikaconfig.
**/
static gboolean pika_config_serialize_rgb (const GValue *value,
GString *str,
gboolean has_alpha);
/**
* pika_config_serialize_properties:
* @config: a #PikaConfig.
* @writer: a #PikaConfigWriter.
*
* This function writes all object properties to the @writer.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise
*
* Since: 2.4
**/
gboolean
pika_config_serialize_properties (PikaConfig *config,
PikaConfigWriter *writer)
{
GObjectClass *klass;
GParamSpec **property_specs;
guint n_property_specs;
guint i;
gboolean success = TRUE;
g_return_val_if_fail (G_IS_OBJECT (config), FALSE);
klass = G_OBJECT_GET_CLASS (config);
property_specs = g_object_class_list_properties (klass, &n_property_specs);
if (! property_specs)
return success;
for (i = 0; i < n_property_specs; i++)
{
GParamSpec *prop_spec = property_specs[i];
if (! (prop_spec->flags & PIKA_CONFIG_PARAM_SERIALIZE))
continue;
/* Some properties may fail writing, which shouldn't break serializing
* more properties, yet final result would be a (partial) failure.
*/
if (! pika_config_serialize_property (config, prop_spec, writer))
success = FALSE;
}
g_free (property_specs);
return success;
}
/**
* pika_config_serialize_changed_properties:
* @config: a #PikaConfig.
* @writer: a #PikaConfigWriter.
*
* This function writes all object properties that have been changed from
* their default values to the @writer.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise
*
* Since: 2.4
**/
gboolean
pika_config_serialize_changed_properties (PikaConfig *config,
PikaConfigWriter *writer)
{
GObjectClass *klass;
GParamSpec **property_specs;
guint n_property_specs;
guint i;
GValue value = G_VALUE_INIT;
gboolean success = TRUE;
g_return_val_if_fail (G_IS_OBJECT (config), FALSE);
klass = G_OBJECT_GET_CLASS (config);
property_specs = g_object_class_list_properties (klass, &n_property_specs);
if (! property_specs)
return success;
for (i = 0; i < n_property_specs; i++)
{
GParamSpec *prop_spec = property_specs[i];
if (! (prop_spec->flags & PIKA_CONFIG_PARAM_SERIALIZE))
continue;
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (config), prop_spec->name, &value);
if (! g_param_value_defaults (prop_spec, &value))
{
/* Some properties may fail writing, which shouldn't break serializing
* more properties, yet final result would be a (partial) failure.
*/
if (! pika_config_serialize_property (config, prop_spec, writer))
success = FALSE;
}
g_value_unset (&value);
}
g_free (property_specs);
return success;
}
/**
* pika_config_serialize_property:
* @config: a #PikaConfig.
* @param_spec: a #GParamSpec.
* @writer: a #PikaConfigWriter.
*
* This function serializes a single object property to the @writer.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise
*
* Since: 2.4
**/
gboolean
pika_config_serialize_property (PikaConfig *config,
GParamSpec *param_spec,
PikaConfigWriter *writer)
{
PikaConfigInterface *config_iface = NULL;
PikaConfigInterface *parent_iface = NULL;
GValue value = G_VALUE_INIT;
gboolean success = FALSE;
if (! (param_spec->flags & PIKA_CONFIG_PARAM_SERIALIZE))
return FALSE;
if (param_spec->flags & PIKA_CONFIG_PARAM_IGNORE)
return TRUE;
g_value_init (&value, param_spec->value_type);
g_object_get_property (G_OBJECT (config), param_spec->name, &value);
if (param_spec->flags & PIKA_CONFIG_PARAM_DEFAULTS &&
g_param_value_defaults (param_spec, &value))
{
g_value_unset (&value);
return TRUE;
}
if (G_TYPE_IS_OBJECT (param_spec->owner_type))
{
GTypeClass *owner_class = g_type_class_peek (param_spec->owner_type);
config_iface = g_type_interface_peek (owner_class, PIKA_TYPE_CONFIG);
/* We must call serialize_property() *only* if the *exact* class
* which implements it is param_spec->owner_type's class.
*
* Therefore, we ask param_spec->owner_type's immediate parent class
* for it's PikaConfigInterface and check if we get a different
* pointer.
*
* (if the pointers are the same, param_spec->owner_type's
* PikaConfigInterface is inherited from one of it's parent classes
* and thus not able to handle param_spec->owner_type's properties).
*/
if (config_iface)
{
GTypeClass *owner_parent_class;
owner_parent_class = g_type_class_peek_parent (owner_class);
parent_iface = g_type_interface_peek (owner_parent_class,
PIKA_TYPE_CONFIG);
}
}
if (config_iface &&
config_iface != parent_iface && /* see comment above */
config_iface->serialize_property &&
config_iface->serialize_property (config,
param_spec->param_id,
(const GValue *) &value,
param_spec,
writer))
{
success = TRUE;
}
/* If there is no serialize_property() method *or* if it returned
* FALSE, continue with the default implementation
*/
if (! success)
{
if (G_VALUE_TYPE (&value) == PIKA_TYPE_PARASITE)
{
PikaParasite *parasite = g_value_get_boxed (&value);
pika_config_writer_open (writer, param_spec->name);
if (parasite)
{
const gchar *name;
gconstpointer data;
guint32 data_length;
gulong flags;
name = pika_parasite_get_name (parasite);
pika_config_writer_string (writer, name);
flags = pika_parasite_get_flags (parasite);
data = pika_parasite_get_data (parasite, &data_length);
pika_config_writer_printf (writer, "%lu %u", flags, data_length);
pika_config_writer_data (writer, data_length, data);
success = TRUE;
}
if (success)
pika_config_writer_close (writer);
else
pika_config_writer_revert (writer);
}
else if (G_VALUE_HOLDS_OBJECT (&value) &&
G_VALUE_TYPE (&value) != G_TYPE_FILE)
{
PikaConfigInterface *config_iface = NULL;
PikaConfig *prop_object;
prop_object = g_value_get_object (&value);
if (prop_object)
config_iface = PIKA_CONFIG_GET_IFACE (prop_object);
else
success = TRUE;
if (config_iface)
{
pika_config_writer_open (writer, param_spec->name);
/* if the object property is not PIKA_CONFIG_PARAM_AGGREGATE,
* deserializing will need to know the exact type
* in order to create the object
*/
if (! (param_spec->flags & PIKA_CONFIG_PARAM_AGGREGATE))
{
GType object_type = G_TYPE_FROM_INSTANCE (prop_object);
pika_config_writer_string (writer, g_type_name (object_type));
}
success = config_iface->serialize (prop_object, writer, NULL);
if (success)
pika_config_writer_close (writer);
else
pika_config_writer_revert (writer);
}
}
else
{
GString *str = g_string_new (NULL);
if (PIKA_VALUE_HOLDS_RGB (&value))
{
gboolean has_alpha = pika_param_spec_rgb_has_alpha (param_spec);
success = pika_config_serialize_rgb (&value, str, has_alpha);
}
else if (G_VALUE_TYPE (&value) == G_TYPE_STRV)
{
success = pika_config_serialize_strv (&value, str);
}
else
{
success = pika_config_serialize_value (&value, str, TRUE);
}
if (success)
{
pika_config_writer_open (writer, param_spec->name);
pika_config_writer_print (writer, str->str, str->len);
pika_config_writer_close (writer);
}
g_string_free (str, TRUE);
}
if (! success)
{
/* don't warn for empty string properties */
if (G_VALUE_HOLDS_STRING (&value))
{
success = TRUE;
}
else
{
g_warning ("couldn't serialize property %s::%s of type %s",
g_type_name (G_TYPE_FROM_INSTANCE (config)),
param_spec->name,
g_type_name (param_spec->value_type));
}
}
}
g_value_unset (&value);
return success;
}
/**
* pika_config_serialize_property_by_name:
* @config: a #PikaConfig.
* @prop_name: the property's name.
* @writer: a #PikaConfigWriter.
*
* This function serializes a single object property to the @writer.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise
*
* Since: 2.6
**/
gboolean
pika_config_serialize_property_by_name (PikaConfig *config,
const gchar *prop_name,
PikaConfigWriter *writer)
{
GParamSpec *pspec;
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
prop_name);
if (! pspec)
return FALSE;
return pika_config_serialize_property (config, pspec, writer);
}
/**
* pika_config_serialize_value:
* @value: a #GValue.
* @str: a #GString.
* @escaped: whether to escape string values.
*
* This utility function appends a string representation of #GValue to @str.
*
* Returns: %TRUE if serialization succeeded, %FALSE otherwise.
*
* Since: 2.4
**/
gboolean
pika_config_serialize_value (const GValue *value,
GString *str,
gboolean escaped)
{
if (G_VALUE_HOLDS_BOOLEAN (value))
{
gboolean bool;
bool = g_value_get_boolean (value);
g_string_append (str, bool ? "yes" : "no");
return TRUE;
}
if (G_VALUE_HOLDS_ENUM (value))
{
GEnumClass *enum_class = g_type_class_peek (G_VALUE_TYPE (value));
GEnumValue *enum_value = g_enum_get_value (enum_class,
g_value_get_enum (value));
if (enum_value && enum_value->value_nick)
{
g_string_append (str, enum_value->value_nick);
return TRUE;
}
else
{
g_warning ("Couldn't get nick for enum_value of %s",
G_ENUM_CLASS_TYPE_NAME (enum_class));
return FALSE;
}
}
if (G_VALUE_HOLDS_STRING (value))
{
const gchar *cstr = g_value_get_string (value);
if (!cstr)
return FALSE;
if (escaped)
pika_config_string_append_escaped (str, cstr);
else
g_string_append (str, cstr);
return TRUE;
}
if (G_VALUE_HOLDS_DOUBLE (value) || G_VALUE_HOLDS_FLOAT (value))
{
gdouble v_double;
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
if (G_VALUE_HOLDS_DOUBLE (value))
v_double = g_value_get_double (value);
else
v_double = (gdouble) g_value_get_float (value);
g_ascii_dtostr (buf, sizeof (buf), v_double);
g_string_append (str, buf);
return TRUE;
}
if (PIKA_VALUE_HOLDS_RGB (value))
{
return pika_config_serialize_rgb (value, str, TRUE);
}
if (PIKA_VALUE_HOLDS_MATRIX2 (value))
{
PikaMatrix2 *trafo;
trafo = g_value_get_boxed (value);
if (trafo)
{
gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE];
gint i, j, k;
for (i = 0, k = 0; i < 2; i++)
for (j = 0; j < 2; j++, k++)
g_ascii_dtostr (buf[k], G_ASCII_DTOSTR_BUF_SIZE,
trafo->coeff[i][j]);
g_string_append_printf (str, "(matrix %s %s %s %s)",
buf[0], buf[1], buf[2], buf[3]);
}
else
{
g_string_append (str, "(matrix 1.0 1.0 1.0 1.0)");
}
return TRUE;
}
if (G_VALUE_TYPE (value) == PIKA_TYPE_VALUE_ARRAY)
{
PikaValueArray *array;
array = g_value_get_boxed (value);
if (array)
{
gint length = pika_value_array_length (array);
gint i;
g_string_append_printf (str, "%d", length);
for (i = 0; i < length; i++)
{
g_string_append (str, " ");
if (! pika_config_serialize_value (pika_value_array_index (array,
i),
str, TRUE))
return FALSE;
}
}
else
{
g_string_append (str, "0");
}
return TRUE;
}
if (G_VALUE_TYPE (value) == G_TYPE_FILE)
{
GFile *file = g_value_get_object (value);
if (file)
{
gchar *path = g_file_get_path (file);
gchar *unexpand = NULL;
if (path)
{
unexpand = pika_config_path_unexpand (path, TRUE, NULL);
g_free (path);
}
if (unexpand)
{
if (escaped)
pika_config_string_append_escaped (str, unexpand);
else
g_string_append (str, unexpand);
g_free (unexpand);
}
else
{
g_string_append (str, "NULL");
}
}
else
{
g_string_append (str, "NULL");
}
return TRUE;
}
if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING))
{
GValue tmp_value = G_VALUE_INIT;
g_value_init (&tmp_value, G_TYPE_STRING);
g_value_transform (value, &tmp_value);
g_string_append (str, g_value_get_string (&tmp_value));
g_value_unset (&tmp_value);
return TRUE;
}
return FALSE;
}
static gboolean
pika_config_serialize_rgb (const GValue *value,
GString *str,
gboolean has_alpha)
{
PikaRGB *rgb;
rgb = g_value_get_boxed (value);
if (rgb)
{
gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_dtostr (buf[0], G_ASCII_DTOSTR_BUF_SIZE, rgb->r);
g_ascii_dtostr (buf[1], G_ASCII_DTOSTR_BUF_SIZE, rgb->g);
g_ascii_dtostr (buf[2], G_ASCII_DTOSTR_BUF_SIZE, rgb->b);
if (has_alpha)
{
g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, rgb->a);
g_string_append_printf (str, "(color-rgba %s %s %s %s)",
buf[0], buf[1], buf[2], buf[3]);
}
else
{
g_string_append_printf (str, "(color-rgb %s %s %s)",
buf[0], buf[1], buf[2]);
}
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,52 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* Object properties serialization routines
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_SERIALIZE_H__
#define __PIKA_CONFIG_SERIALIZE_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
gboolean pika_config_serialize_properties (PikaConfig *config,
PikaConfigWriter *writer);
gboolean pika_config_serialize_changed_properties (PikaConfig *config,
PikaConfigWriter *writer);
gboolean pika_config_serialize_property (PikaConfig *config,
GParamSpec *param_spec,
PikaConfigWriter *writer);
gboolean pika_config_serialize_property_by_name (PikaConfig *config,
const gchar *prop_name,
PikaConfigWriter *writer);
gboolean pika_config_serialize_value (const GValue *value,
GString *str,
gboolean escaped);
G_END_DECLS
#endif /* __PIKA_CONFIG_SERIALIZE_H__ */

View File

@ -0,0 +1,482 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Utility functions for PikaConfig.
* Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "pikaconfigtypes.h"
#include "pikaconfigwriter.h"
#include "pikaconfig-iface.h"
#include "pikaconfig-params.h"
#include "pikaconfig-utils.h"
/**
* SECTION: pikaconfig-utils
* @title: PikaConfig-utils
* @short_description: Miscellaneous utility functions for libpikaconfig.
*
* Miscellaneous utility functions for libpikaconfig.
**/
static gboolean
pika_config_diff_property (GObject *a,
GObject *b,
GParamSpec *prop_spec)
{
GValue a_value = G_VALUE_INIT;
GValue b_value = G_VALUE_INIT;
gboolean retval = FALSE;
g_value_init (&a_value, prop_spec->value_type);
g_value_init (&b_value, prop_spec->value_type);
g_object_get_property (a, prop_spec->name, &a_value);
g_object_get_property (b, prop_spec->name, &b_value);
if (g_param_values_cmp (prop_spec, &a_value, &b_value))
{
if ((prop_spec->flags & PIKA_CONFIG_PARAM_AGGREGATE) &&
G_IS_PARAM_SPEC_OBJECT (prop_spec) &&
g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
PIKA_TYPE_CONFIG))
{
if (! pika_config_is_equal_to (g_value_get_object (&a_value),
g_value_get_object (&b_value)))
{
retval = TRUE;
}
}
else
{
retval = TRUE;
}
}
g_value_unset (&a_value);
g_value_unset (&b_value);
return retval;
}
static GList *
pika_config_diff_same (GObject *a,
GObject *b,
GParamFlags flags)
{
GParamSpec **param_specs;
guint n_param_specs;
guint i;
GList *list = NULL;
param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
&n_param_specs);
for (i = 0; i < n_param_specs; i++)
{
GParamSpec *prop_spec = param_specs[i];
if (! flags || ((prop_spec->flags & flags) == flags))
{
if (pika_config_diff_property (a, b, prop_spec))
list = g_list_prepend (list, prop_spec);
}
}
g_free (param_specs);
return list;
}
static GList *
pika_config_diff_other (GObject *a,
GObject *b,
GParamFlags flags)
{
GParamSpec **param_specs;
guint n_param_specs;
guint i;
GList *list = NULL;
param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
&n_param_specs);
for (i = 0; i < n_param_specs; i++)
{
GParamSpec *a_spec = param_specs[i];
GParamSpec *b_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (b),
a_spec->name);
if (b_spec &&
(a_spec->value_type == b_spec->value_type) &&
(! flags || (a_spec->flags & b_spec->flags & flags) == flags))
{
if (pika_config_diff_property (a, b, b_spec))
list = g_list_prepend (list, b_spec);
}
}
g_free (param_specs);
return list;
}
/**
* pika_config_diff:
* @a: a #GObject
* @b: another #GObject object
* @flags: a mask of GParamFlags
*
* Compares all properties of @a and @b that have all @flags set. If
* @flags is 0, all properties are compared.
*
* If the two objects are not of the same type, only properties that
* exist in both object classes and are of the same value_type are
* compared.
*
* Returns: (transfer container) (element-type GParamSpec): a GList of differing GParamSpecs.
*
* Since: 2.4
**/
GList *
pika_config_diff (GObject *a,
GObject *b,
GParamFlags flags)
{
GList *diff;
g_return_val_if_fail (G_IS_OBJECT (a), NULL);
g_return_val_if_fail (G_IS_OBJECT (b), NULL);
if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b))
diff = pika_config_diff_same (a, b, flags);
else
diff = pika_config_diff_other (a, b, flags);
return g_list_reverse (diff);
}
/**
* pika_config_sync:
* @src: a #GObject
* @dest: another #GObject
* @flags: a mask of GParamFlags
*
* Compares all read- and write-able properties from @src and @dest
* that have all @flags set. Differing values are then copied from
* @src to @dest. If @flags is 0, all differing read/write properties.
*
* Properties marked as "construct-only" are not touched.
*
* If the two objects are not of the same type, only properties that
* exist in both object classes and are of the same value_type are
* synchronized
*
* Returns: %TRUE if @dest was modified, %FALSE otherwise
*
* Since: 2.4
**/
gboolean
pika_config_sync (GObject *src,
GObject *dest,
GParamFlags flags)
{
GList *diff;
GList *list;
g_return_val_if_fail (G_IS_OBJECT (src), FALSE);
g_return_val_if_fail (G_IS_OBJECT (dest), FALSE);
/* we use the internal versions here for a number of reasons:
* - it saves a g_list_reverse()
* - it avoids duplicated parameter checks
*/
if (G_TYPE_FROM_INSTANCE (src) == G_TYPE_FROM_INSTANCE (dest))
diff = pika_config_diff_same (src, dest, (flags | G_PARAM_READWRITE));
else
diff = pika_config_diff_other (src, dest, flags);
if (!diff)
return FALSE;
g_object_freeze_notify (G_OBJECT (dest));
for (list = diff; list; list = list->next)
{
GParamSpec *prop_spec = list->data;
if (! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
{
GValue value = G_VALUE_INIT;
g_value_init (&value, prop_spec->value_type);
g_object_get_property (src, prop_spec->name, &value);
g_object_set_property (dest, prop_spec->name, &value);
g_value_unset (&value);
}
}
g_object_thaw_notify (G_OBJECT (dest));
g_list_free (diff);
return TRUE;
}
/**
* pika_config_reset_properties:
* @object: a #GObject
*
* Resets all writable properties of @object to the default values as
* defined in their #GParamSpec. Properties marked as "construct-only"
* are not touched.
*
* If you want to reset a #PikaConfig object, please use pika_config_reset().
*
* Since: 2.4
**/
void
pika_config_reset_properties (GObject *object)
{
GObjectClass *klass;
GParamSpec **property_specs;
guint n_property_specs;
guint i;
g_return_if_fail (G_IS_OBJECT (object));
klass = G_OBJECT_GET_CLASS (object);
property_specs = g_object_class_list_properties (klass, &n_property_specs);
if (!property_specs)
return;
g_object_freeze_notify (object);
for (i = 0; i < n_property_specs; i++)
{
GParamSpec *prop_spec;
GValue value = G_VALUE_INIT;
prop_spec = property_specs[i];
if ((prop_spec->flags & G_PARAM_WRITABLE) &&
! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
{
if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
{
if ((prop_spec->flags & PIKA_CONFIG_PARAM_SERIALIZE) &&
(prop_spec->flags & PIKA_CONFIG_PARAM_AGGREGATE) &&
g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
PIKA_TYPE_CONFIG))
{
g_value_init (&value, prop_spec->value_type);
g_object_get_property (object, prop_spec->name, &value);
pika_config_reset (g_value_get_object (&value));
g_value_unset (&value);
}
}
else
{
GValue default_value = G_VALUE_INIT;
g_value_init (&default_value, prop_spec->value_type);
g_value_init (&value, prop_spec->value_type);
g_param_value_set_default (prop_spec, &default_value);
g_object_get_property (object, prop_spec->name, &value);
if (g_param_values_cmp (prop_spec, &default_value, &value))
{
g_object_set_property (object, prop_spec->name,
&default_value);
}
g_value_unset (&value);
g_value_unset (&default_value);
}
}
}
g_object_thaw_notify (object);
g_free (property_specs);
}
/**
* pika_config_reset_property:
* @object: a #GObject
* @property_name: name of the property to reset
*
* Resets the property named @property_name to its default value. The
* property must be writable and must not be marked as "construct-only".
*
* Since: 2.4
**/
void
pika_config_reset_property (GObject *object,
const gchar *property_name)
{
GObjectClass *klass;
GParamSpec *prop_spec;
g_return_if_fail (G_IS_OBJECT (object));
g_return_if_fail (property_name != NULL);
klass = G_OBJECT_GET_CLASS (object);
prop_spec = g_object_class_find_property (klass, property_name);
if (!prop_spec)
return;
if ((prop_spec->flags & G_PARAM_WRITABLE) &&
! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
{
GValue value = G_VALUE_INIT;
if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
{
if ((prop_spec->flags & PIKA_CONFIG_PARAM_SERIALIZE) &&
(prop_spec->flags & PIKA_CONFIG_PARAM_AGGREGATE) &&
g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
PIKA_TYPE_CONFIG))
{
g_value_init (&value, prop_spec->value_type);
g_object_get_property (object, prop_spec->name, &value);
pika_config_reset (g_value_get_object (&value));
g_value_unset (&value);
}
}
else
{
g_value_init (&value, prop_spec->value_type);
g_param_value_set_default (prop_spec, &value);
g_object_set_property (object, prop_spec->name, &value);
g_value_unset (&value);
}
}
}
/*
* PikaConfig string utilities
*/
/**
* pika_config_string_append_escaped:
* @string: pointer to a #GString
* @val: a string to append or %NULL
*
* Escapes and quotes @val and appends it to @string. The escape
* algorithm is different from the one used by g_strescape() since it
* leaves non-ASCII characters intact and thus preserves UTF-8
* strings. Only control characters and quotes are being escaped.
*
* Since: 2.4
**/
void
pika_config_string_append_escaped (GString *string,
const gchar *val)
{
g_return_if_fail (string != NULL);
if (val)
{
const guchar *p;
gchar buf[4] = { '\\', 0, 0, 0 };
gint len;
g_string_append_c (string, '\"');
for (p = (const guchar *) val, len = 0; *p; p++)
{
if (*p < ' ' || *p == '\\' || *p == '\"')
{
g_string_append_len (string, val, len);
len = 2;
switch (*p)
{
case '\b':
buf[1] = 'b';
break;
case '\f':
buf[1] = 'f';
break;
case '\n':
buf[1] = 'n';
break;
case '\r':
buf[1] = 'r';
break;
case '\t':
buf[1] = 't';
break;
case '\\':
case '"':
buf[1] = *p;
break;
default:
len = 4;
buf[1] = '0' + (((*p) >> 6) & 07);
buf[2] = '0' + (((*p) >> 3) & 07);
buf[3] = '0' + ((*p) & 07);
break;
}
g_string_append_len (string, buf, len);
val = (const gchar *) p + 1;
len = 0;
}
else
{
len++;
}
}
g_string_append_len (string, val, len);
g_string_append_c (string, '\"');
}
else
{
g_string_append_len (string, "\"\"", 2);
}
}

View File

@ -0,0 +1,52 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Utility functions for PikaConfig.
* Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_UTILS_H__
#define __PIKA_CONFIG_UTILS_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
GList * pika_config_diff (GObject *a,
GObject *b,
GParamFlags flags);
gboolean pika_config_sync (GObject *src,
GObject *dest,
GParamFlags flags);
void pika_config_reset_properties (GObject *object);
void pika_config_reset_property (GObject *object,
const gchar *property_name);
void pika_config_string_append_escaped (GString *string,
const gchar *val);
G_END_DECLS
#endif /* __PIKA_CONFIG_UTILS_H__ */

View File

@ -0,0 +1,102 @@
EXPORTS
pika_color_config_get_cmyk_color_profile
pika_color_config_get_display_bpc
pika_color_config_get_display_color_profile
pika_color_config_get_display_intent
pika_color_config_get_display_optimize
pika_color_config_get_display_profile_from_gdk
pika_color_config_get_gray_color_profile
pika_color_config_get_mode
pika_color_config_get_out_of_gamut_color
pika_color_config_get_rgb_color_profile
pika_color_config_get_simulation_bpc
pika_color_config_get_simulation_color_profile
pika_color_config_get_simulation_gamut_check
pika_color_config_get_simulation_intent
pika_color_config_get_simulation_optimize
pika_color_config_get_type
pika_color_management_mode_get_type
pika_color_rendering_intent_get_type
pika_config_build_data_path
pika_config_build_plug_in_path
pika_config_build_system_path
pika_config_build_writable_path
pika_config_copy
pika_config_deserialize
pika_config_deserialize_file
pika_config_deserialize_parasite
pika_config_deserialize_properties
pika_config_deserialize_property
pika_config_deserialize_return
pika_config_deserialize_stream
pika_config_deserialize_string
pika_config_deserialize_strv
pika_config_diff
pika_config_duplicate
pika_config_error_quark
pika_config_get_type
pika_config_is_equal_to
pika_config_param_spec_duplicate
pika_config_path_expand
pika_config_path_expand_to_files
pika_config_path_get_type
pika_config_path_unexpand
pika_config_reset
pika_config_reset_properties
pika_config_reset_property
pika_config_serialize
pika_config_serialize_changed_properties
pika_config_serialize_properties
pika_config_serialize_property
pika_config_serialize_property_by_name
pika_config_serialize_strv
pika_config_serialize_to_fd
pika_config_serialize_to_file
pika_config_serialize_to_parasite
pika_config_serialize_to_stream
pika_config_serialize_to_string
pika_config_serialize_value
pika_config_string_append_escaped
pika_config_sync
pika_config_type_register
pika_config_writer_close
pika_config_writer_comment
pika_config_writer_comment_mode
pika_config_writer_data
pika_config_writer_finish
pika_config_writer_get_type
pika_config_writer_identifier
pika_config_writer_linefeed
pika_config_writer_new_from_fd
pika_config_writer_new_from_file
pika_config_writer_new_from_stream
pika_config_writer_new_from_string
pika_config_writer_open
pika_config_writer_print
pika_config_writer_printf
pika_config_writer_ref
pika_config_writer_revert
pika_config_writer_string
pika_config_writer_unref
pika_file_get_config_path
pika_file_new_for_config_path
pika_param_config_path_get_type
pika_param_spec_config_path
pika_param_spec_config_path_type
pika_scanner_get_type
pika_scanner_new_file
pika_scanner_new_stream
pika_scanner_new_string
pika_scanner_parse_boolean
pika_scanner_parse_color
pika_scanner_parse_data
pika_scanner_parse_float
pika_scanner_parse_identifier
pika_scanner_parse_int
pika_scanner_parse_int64
pika_scanner_parse_matrix2
pika_scanner_parse_string
pika_scanner_parse_string_no_validate
pika_scanner_parse_token
pika_scanner_ref
pika_scanner_unref

View File

@ -0,0 +1,41 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CONFIG_H__
#define __PIKA_CONFIG_H__
#define __PIKA_CONFIG_H_INSIDE__
#include <libpikaconfig/pikaconfigtypes.h>
#include <libpikaconfig/pikaconfig-deserialize.h>
#include <libpikaconfig/pikaconfig-error.h>
#include <libpikaconfig/pikaconfig-iface.h>
#include <libpikaconfig/pikaconfig-params.h>
#include <libpikaconfig/pikaconfig-path.h>
#include <libpikaconfig/pikaconfig-register.h>
#include <libpikaconfig/pikaconfig-serialize.h>
#include <libpikaconfig/pikaconfig-utils.h>
#include <libpikaconfig/pikaconfigwriter.h>
#include <libpikaconfig/pikascanner.h>
#include <libpikaconfig/pikacolorconfig.h>
#undef __PIKA_CONFIG_H_INSIDE__
#endif /* __PIKA_CONFIG_H__ */

View File

@ -0,0 +1,80 @@
/* Generated data (by pika-mkenums) */
#include "stamp-pikaconfigenums.h"
#include "config.h"
#include <gio/gio.h>
#include "libpikabase/pikabase.h"
#include "pikaconfigenums.h"
#include "libpika/libpika-intl.h"
/* enumerations from "pikaconfigenums.h" */
GType
pika_color_management_mode_get_type (void)
{
static const GEnumValue values[] =
{
{ PIKA_COLOR_MANAGEMENT_OFF, "PIKA_COLOR_MANAGEMENT_OFF", "off" },
{ PIKA_COLOR_MANAGEMENT_DISPLAY, "PIKA_COLOR_MANAGEMENT_DISPLAY", "display" },
{ PIKA_COLOR_MANAGEMENT_SOFTPROOF, "PIKA_COLOR_MANAGEMENT_SOFTPROOF", "softproof" },
{ 0, NULL, NULL }
};
static const PikaEnumDesc descs[] =
{
{ PIKA_COLOR_MANAGEMENT_OFF, NC_("color-management-mode", "No color management"), NULL },
{ PIKA_COLOR_MANAGEMENT_DISPLAY, NC_("color-management-mode", "Color-managed display"), NULL },
{ PIKA_COLOR_MANAGEMENT_SOFTPROOF, NC_("color-management-mode", "Soft-proofing"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("PikaColorManagementMode", values);
pika_type_set_translation_domain (type, GETTEXT_PACKAGE "-libpika");
pika_type_set_translation_context (type, "color-management-mode");
pika_enum_set_value_descriptions (type, descs);
}
return type;
}
GType
pika_color_rendering_intent_get_type (void)
{
static const GEnumValue values[] =
{
{ PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL, "PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL", "perceptual" },
{ PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, "PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC", "relative-colorimetric" },
{ PIKA_COLOR_RENDERING_INTENT_SATURATION, "PIKA_COLOR_RENDERING_INTENT_SATURATION", "saturation" },
{ PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC, "PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC", "absolute-colorimetric" },
{ 0, NULL, NULL }
};
static const PikaEnumDesc descs[] =
{
{ PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL, NC_("color-rendering-intent", "Perceptual"), NULL },
{ PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, NC_("color-rendering-intent", "Relative colorimetric"), NULL },
{ PIKA_COLOR_RENDERING_INTENT_SATURATION, NC_("color-rendering-intent", "Saturation"), NULL },
{ PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC, NC_("color-rendering-intent", "Absolute colorimetric"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("PikaColorRenderingIntent", values);
pika_type_set_translation_domain (type, GETTEXT_PACKAGE "-libpika");
pika_type_set_translation_context (type, "color-rendering-intent");
pika_enum_set_value_descriptions (type, descs);
}
return type;
}
/* Generated data ends here */

View File

@ -0,0 +1,68 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikaconfigenums.h
* Copyright (C) 2004 Stefan Döhla <stefan@doehla.de>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CONFIG_ENUMS_H__
#define __PIKA_CONFIG_ENUMS_H__
#define PIKA_TYPE_COLOR_MANAGEMENT_MODE (pika_color_management_mode_get_type ())
GType pika_color_management_mode_get_type (void) G_GNUC_CONST;
/**
* PikaColorManagementMode:
* @PIKA_COLOR_MANAGEMENT_OFF: Color management is off
* @PIKA_COLOR_MANAGEMENT_DISPLAY: Color managed display
* @PIKA_COLOR_MANAGEMENT_SOFTPROOF: Soft-proofing
*
* Modes of color management.
**/
typedef enum
{
PIKA_COLOR_MANAGEMENT_OFF, /*< desc="No color management" >*/
PIKA_COLOR_MANAGEMENT_DISPLAY, /*< desc="Color-managed display" >*/
PIKA_COLOR_MANAGEMENT_SOFTPROOF /*< desc="Soft-proofing" >*/
} PikaColorManagementMode;
#define PIKA_TYPE_COLOR_RENDERING_INTENT (pika_color_rendering_intent_get_type ())
GType pika_color_rendering_intent_get_type (void) G_GNUC_CONST;
/**
* PikaColorRenderingIntent:
* @PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL: Perceptual
* @PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC: Relative colorimetric
* @PIKA_COLOR_RENDERING_INTENT_SATURATION: Saturation
* @PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC: Absolute colorimetric
*
* Intents for color management.
**/
typedef enum
{
PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL, /*< desc="Perceptual" >*/
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, /*< desc="Relative colorimetric" >*/
PIKA_COLOR_RENDERING_INTENT_SATURATION, /*< desc="Saturation" >*/
PIKA_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC /*< desc="Absolute colorimetric" >*/
} PikaColorRenderingIntent;
#endif /* __PIKA_CONFIG_ENUMS_H__ */

View File

@ -0,0 +1,39 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* Config file serialization and deserialization interface
* Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_CONFIG_TYPES_H__
#define __PIKA_CONFIG_TYPES_H__
#include <libpikabase/pikabasetypes.h>
typedef struct _PikaConfig PikaConfig; /* dummy typedef */
typedef struct _PikaConfigWriter PikaConfigWriter;
typedef gchar * PikaConfigPath; /* to satisfy docs */
typedef struct _GScanner PikaScanner;
typedef struct _PikaColorConfig PikaColorConfig;
#include <libpikaconfig/pikaconfigenums.h>
#endif /* __PIKA_CONFIG_TYPES_H__ */

View File

@ -0,0 +1,849 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* PikaConfigWriter
* Copyright (C) 2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gio/gio.h>
#ifdef G_OS_WIN32
#include <gio/gwin32outputstream.h>
#else
#include <gio/gunixoutputstream.h>
#endif
#include "libpikabase/pikabase.h"
#include "pikaconfigtypes.h"
#include "pikaconfigwriter.h"
#include "pikaconfig-iface.h"
#include "pikaconfig-error.h"
#include "pikaconfig-serialize.h"
#include "pikaconfig-utils.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikaconfigwriter
* @title: PikaConfigWriter
* @short_description: Functions for writing config info to a file for
* libpikaconfig.
*
* Functions for writing config info to a file for libpikaconfig.
**/
struct _PikaConfigWriter
{
gint ref_count;
gboolean finished;
GOutputStream *output;
GFile *file;
GError *error;
GString *buffer;
gboolean comment;
gint depth;
gint marker;
};
G_DEFINE_BOXED_TYPE (PikaConfigWriter, pika_config_writer,
pika_config_writer_ref, pika_config_writer_unref)
static inline void pika_config_writer_flush (PikaConfigWriter *writer);
static inline void pika_config_writer_newline (PikaConfigWriter *writer);
static gboolean pika_config_writer_close_output (PikaConfigWriter *writer,
GError **error);
static inline void
pika_config_writer_flush (PikaConfigWriter *writer)
{
GError *error = NULL;
if (! writer->output)
return;
if (! g_output_stream_write_all (writer->output,
writer->buffer->str,
writer->buffer->len,
NULL, NULL, &error))
{
g_set_error (&writer->error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_WRITE,
_("Error writing to '%s': %s"),
writer->file ?
pika_file_get_utf8_name (writer->file) : "output stream",
error->message);
g_clear_error (&error);
}
g_string_truncate (writer->buffer, 0);
}
static inline void
pika_config_writer_newline (PikaConfigWriter *writer)
{
gint i;
g_string_append_c (writer->buffer, '\n');
if (writer->comment)
g_string_append_len (writer->buffer, "# ", 2);
for (i = 0; i < writer->depth; i++)
g_string_append_len (writer->buffer, " ", 4);
}
/**
* pika_config_writer_new_from_file:
* @file: a #GFile
* @atomic: if %TRUE the file is written atomically
* @header: text to include as comment at the top of the file
* @error: return location for errors
*
* Creates a new #PikaConfigWriter and sets it up to write to
* @file. If @atomic is %TRUE, a temporary file is used to avoid
* possible race conditions. The temporary file is then moved to @file
* when the writer is closed.
*
* Returns: (nullable): a new #PikaConfigWriter or %NULL in case of an error
*
* Since: 2.10
**/
PikaConfigWriter *
pika_config_writer_new_from_file (GFile *file,
gboolean atomic,
const gchar *header,
GError **error)
{
PikaConfigWriter *writer;
GOutputStream *output;
GFile *dir;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
dir = g_file_get_parent (file);
if (dir && ! g_file_query_exists (dir, NULL))
{
if (! g_file_make_directory_with_parents (dir, NULL, error))
g_prefix_error (error,
_("Could not create directory '%s' for '%s': "),
pika_file_get_utf8_name (dir),
pika_file_get_utf8_name (file));
}
g_object_unref (dir);
if (error && *error)
return NULL;
if (atomic)
{
output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE, G_FILE_CREATE_NONE,
NULL, error));
if (! output)
g_prefix_error (error,
_("Could not create temporary file for '%s': "),
pika_file_get_utf8_name (file));
}
else
{
output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE,
G_FILE_CREATE_REPLACE_DESTINATION,
NULL, error));
}
if (! output)
return NULL;
writer = g_slice_new0 (PikaConfigWriter);
writer->ref_count = 1;
writer->output = output;
writer->file = g_object_ref (file);
writer->buffer = g_string_new (NULL);
if (header)
{
pika_config_writer_comment (writer, header);
pika_config_writer_linefeed (writer);
}
return writer;
}
/**
* pika_config_writer_new_from_stream:
* @output: a #GOutputStream
* @header: text to include as comment at the top of the file
* @error: return location for errors
*
* Creates a new #PikaConfigWriter and sets it up to write to
* @output.
*
* Returns: (nullable): a new #PikaConfigWriter or %NULL in case of an error
*
* Since: 2.10
**/
PikaConfigWriter *
pika_config_writer_new_from_stream (GOutputStream *output,
const gchar *header,
GError **error)
{
PikaConfigWriter *writer;
g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
writer = g_slice_new0 (PikaConfigWriter);
writer->ref_count = 1;
writer->output = g_object_ref (output);
writer->buffer = g_string_new (NULL);
if (header)
{
pika_config_writer_comment (writer, header);
pika_config_writer_linefeed (writer);
}
return writer;
}
/**
* pika_config_writer_new_from_fd:
* @fd:
*
* Returns: (nullable): a new #PikaConfigWriter or %NULL in case of an error
*
* Since: 2.4
**/
PikaConfigWriter *
pika_config_writer_new_from_fd (gint fd)
{
PikaConfigWriter *writer;
g_return_val_if_fail (fd > 0, NULL);
writer = g_slice_new0 (PikaConfigWriter);
writer->ref_count = 1;
#ifdef G_OS_WIN32
writer->output = g_win32_output_stream_new ((gpointer) fd, FALSE);
#else
writer->output = g_unix_output_stream_new (fd, FALSE);
#endif
writer->buffer = g_string_new (NULL);
return writer;
}
/**
* pika_config_writer_new_from_string:
* @string:
*
* Returns: (nullable): a new #PikaConfigWriter or %NULL in case of an error
*
* Since: 2.4
**/
PikaConfigWriter *
pika_config_writer_new_from_string (GString *string)
{
PikaConfigWriter *writer;
g_return_val_if_fail (string != NULL, NULL);
writer = g_slice_new0 (PikaConfigWriter);
writer->ref_count = 1;
writer->buffer = string;
return writer;
}
/**
* pika_config_writer_ref:
* @writer: #PikaConfigWriter to ref
*
* Adds a reference to a #PikaConfigWriter.
*
* Returns: the same @writer.
*
* Since: 3.0
*/
PikaConfigWriter *
pika_config_writer_ref (PikaConfigWriter *writer)
{
g_return_val_if_fail (writer != NULL, NULL);
writer->ref_count++;
return writer;
}
/**
* pika_config_writer_unref:
* @writer: #PikaConfigWriter to unref
*
* Unref a #PikaConfigWriter. If the reference count drops to zero, the
* writer is freed.
*
* Note that at least one of the references has to be dropped using
* pika_config_writer_finish().
*
* Since: 3.0
*/
void
pika_config_writer_unref (PikaConfigWriter *writer)
{
g_return_if_fail (writer != NULL);
writer->ref_count--;
if (writer->ref_count < 1)
{
if (! writer->finished)
{
GError *error = NULL;
g_printerr ("%s: dropping last reference via unref(), you should "
"call pika_config_writer_finish()\n", G_STRFUNC);
if (! pika_config_writer_finish (writer, NULL, &error))
{
g_printerr ("%s: error on finishing writer: %s\n",
G_STRFUNC, error->message);
}
}
else
{
g_slice_free (PikaConfigWriter, writer);
}
}
}
/**
* pika_config_writer_comment_mode:
* @writer: a #PikaConfigWriter
* @enable: %TRUE to enable comment mode, %FALSE to disable it
*
* This function toggles whether the @writer should create commented
* or uncommented output. This feature is used to generate the
* system-wide installed pikarc that documents the default settings.
*
* Since comments have to start at the beginning of a line, this
* function will insert a newline if necessary.
*
* Since: 2.4
**/
void
pika_config_writer_comment_mode (PikaConfigWriter *writer,
gboolean enable)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
enable = (enable ? TRUE : FALSE);
if (writer->comment == enable)
return;
writer->comment = enable;
if (enable)
{
if (writer->buffer->len == 0)
g_string_append_len (writer->buffer, "# ", 2);
else
pika_config_writer_newline (writer);
}
}
/**
* pika_config_writer_open:
* @writer: a #PikaConfigWriter
* @name: name of the element to open
*
* This function writes the opening parenthesis followed by @name.
* It also increases the indentation level and sets a mark that
* can be used by pika_config_writer_revert().
*
* Since: 2.4
**/
void
pika_config_writer_open (PikaConfigWriter *writer,
const gchar *name)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
g_return_if_fail (name != NULL);
if (writer->error)
return;
/* store the current buffer length so we can revert to this state */
writer->marker = writer->buffer->len;
if (writer->depth > 0)
pika_config_writer_newline (writer);
writer->depth++;
g_string_append_printf (writer->buffer, "(%s", name);
}
/**
* pika_config_writer_print:
* @writer: a #PikaConfigWriter
* @string: a string to write
* @len: number of bytes from @string or -1 if @string is NUL-terminated.
*
* Appends a space followed by @string to the @writer. Note that string
* must not contain any special characters that might need to be escaped.
*
* Since: 2.4
**/
void
pika_config_writer_print (PikaConfigWriter *writer,
const gchar *string,
gint len)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
g_return_if_fail (len == 0 || string != NULL);
if (writer->error)
return;
if (len < 0)
len = strlen (string);
if (len)
{
g_string_append_c (writer->buffer, ' ');
g_string_append_len (writer->buffer, string, len);
}
}
/**
* pika_config_writer_printf: (skip)
* @writer: a #PikaConfigWriter
* @format: a format string as described for g_strdup_printf().
* @...: list of arguments according to @format
*
* A printf-like function for #PikaConfigWriter.
*
* Since: 2.4
**/
void
pika_config_writer_printf (PikaConfigWriter *writer,
const gchar *format,
...)
{
gchar *buffer;
va_list args;
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
g_return_if_fail (format != NULL);
if (writer->error)
return;
va_start (args, format);
buffer = g_strdup_vprintf (format, args);
va_end (args);
g_string_append_c (writer->buffer, ' ');
g_string_append (writer->buffer, buffer);
g_free (buffer);
}
/**
* pika_config_writer_string:
* @writer: a #PikaConfigWriter
* @string: a NUL-terminated string
*
* Writes a string value to @writer. The @string is quoted and special
* characters are escaped.
*
* Since: 2.4
**/
void
pika_config_writer_string (PikaConfigWriter *writer,
const gchar *string)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
g_string_append_c (writer->buffer, ' ');
pika_config_string_append_escaped (writer->buffer, string);
}
/**
* pika_config_writer_identifier:
* @writer: a #PikaConfigWriter
* @identifier: a NUL-terminated string
*
* Writes an identifier to @writer. The @string is *not* quoted and special
* characters are *not* escaped.
*
* Since: 2.4
**/
void
pika_config_writer_identifier (PikaConfigWriter *writer,
const gchar *identifier)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
g_return_if_fail (identifier != NULL);
if (writer->error)
return;
g_string_append_printf (writer->buffer, " %s", identifier);
}
/**
* pika_config_writer_data:
* @writer: a #PikaConfigWriter
* @length:
* @data:
*
* Since: 2.4
**/
void
pika_config_writer_data (PikaConfigWriter *writer,
gint length,
const guint8 *data)
{
gint i;
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
g_return_if_fail (length >= 0);
g_return_if_fail (data != NULL || length == 0);
if (writer->error)
return;
g_string_append (writer->buffer, " \"");
for (i = 0; i < length; i++)
{
if (g_ascii_isalpha (data[i]))
g_string_append_c (writer->buffer, data[i]);
else
g_string_append_printf (writer->buffer, "\\%o", data[i]);
}
g_string_append (writer->buffer, "\"");
}
/**
* pika_config_writer_revert:
* @writer: a #PikaConfigWriter
*
* Reverts all changes to @writer that were done since the last call
* to pika_config_writer_open(). This can only work if you didn't call
* pika_config_writer_close() yet.
*
* Since: 2.4
**/
void
pika_config_writer_revert (PikaConfigWriter *writer)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
g_return_if_fail (writer->depth > 0);
g_return_if_fail (writer->marker != -1);
g_string_truncate (writer->buffer, writer->marker);
writer->depth--;
writer->marker = -1;
}
/**
* pika_config_writer_close:
* @writer: a #PikaConfigWriter
*
* Closes an element opened with pika_config_writer_open().
*
* Since: 2.4
**/
void
pika_config_writer_close (PikaConfigWriter *writer)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
g_return_if_fail (writer->depth > 0);
g_string_append_c (writer->buffer, ')');
if (--writer->depth == 0)
{
g_string_append_c (writer->buffer, '\n');
pika_config_writer_flush (writer);
}
}
/**
* pika_config_writer_finish:
* @writer: a #PikaConfigWriter
* @footer: text to include as comment at the bottom of the file
* @error: return location for possible errors
*
* This function finishes the work of @writer and unrefs it
* afterwards. It closes all open elements, appends an optional
* comment and releases all resources allocated by @writer.
*
* Using any function except pika_config_writer_ref() or
* pika_config_writer_unref() after this function is forbidden
* and will trigger warnings.
*
* Returns: %TRUE if everything could be successfully written,
* %FALSE otherwise
*
* Since: 2.4
**/
gboolean
pika_config_writer_finish (PikaConfigWriter *writer,
const gchar *footer,
GError **error)
{
gboolean success = TRUE;
g_return_val_if_fail (writer != NULL, FALSE);
g_return_val_if_fail (writer->finished == FALSE, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (writer->depth < 0)
{
g_warning ("pika_config_writer_finish: depth < 0 !!");
}
else
{
while (writer->depth)
pika_config_writer_close (writer);
}
if (footer)
{
pika_config_writer_linefeed (writer);
pika_config_writer_comment (writer, footer);
}
if (writer->output)
{
success = pika_config_writer_close_output (writer, error);
g_clear_object (&writer->file);
g_string_free (writer->buffer, TRUE);
writer->buffer = NULL;
}
if (writer->error)
{
if (error && *error == NULL)
g_propagate_error (error, writer->error);
else
g_clear_error (&writer->error);
success = FALSE;
}
writer->finished = TRUE;
pika_config_writer_unref (writer);
return success;
}
void
pika_config_writer_linefeed (PikaConfigWriter *writer)
{
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
if (writer->output && writer->buffer->len == 0 && !writer->comment)
{
GError *error = NULL;
if (! g_output_stream_write_all (writer->output, "\n", 1,
NULL, NULL, &error))
{
g_set_error (&writer->error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_WRITE,
_("Error writing to '%s': %s"),
writer->file ?
pika_file_get_utf8_name (writer->file) : "output stream",
error->message);
g_clear_error (&error);
}
}
else
{
pika_config_writer_newline (writer);
}
}
/**
* pika_config_writer_comment:
* @writer: a #PikaConfigWriter
* @comment: the comment to write (ASCII only)
*
* Appends the @comment to @str and inserts linebreaks and hash-marks to
* format it as a comment. Note that this function does not handle non-ASCII
* characters.
*
* Since: 2.4
**/
void
pika_config_writer_comment (PikaConfigWriter *writer,
const gchar *comment)
{
const gchar *s;
gboolean comment_mode;
gint i, len, space;
#define LINE_LENGTH 75
g_return_if_fail (writer != NULL);
g_return_if_fail (writer->finished == FALSE);
if (writer->error)
return;
g_return_if_fail (writer->depth == 0);
if (!comment)
return;
comment_mode = writer->comment;
pika_config_writer_comment_mode (writer, TRUE);
len = strlen (comment);
while (len > 0)
{
for (s = comment, i = 0, space = 0;
*s != '\n' && (i <= LINE_LENGTH || space == 0) && i < len;
s++, i++)
{
if (g_ascii_isspace (*s))
space = i;
}
if (i > LINE_LENGTH && space && *s != '\n')
i = space;
g_string_append_len (writer->buffer, comment, i);
i++;
comment += i;
len -= i;
if (len > 0)
pika_config_writer_newline (writer);
}
pika_config_writer_comment_mode (writer, comment_mode);
pika_config_writer_newline (writer);
if (writer->depth == 0)
pika_config_writer_flush (writer);
#undef LINE_LENGTH
}
static gboolean
pika_config_writer_close_output (PikaConfigWriter *writer,
GError **error)
{
g_return_val_if_fail (writer->output != NULL, FALSE);
if (writer->error)
{
GCancellable *cancellable = g_cancellable_new ();
/* Cancel the overwrite initiated by g_file_replace(). */
g_cancellable_cancel (cancellable);
g_output_stream_close (writer->output, cancellable, NULL);
g_object_unref (cancellable);
g_clear_object (&writer->output);
return FALSE;
}
if (writer->file)
{
GError *my_error = NULL;
if (! g_output_stream_close (writer->output, NULL, &my_error))
{
g_set_error (error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_WRITE,
_("Error writing '%s': %s"),
pika_file_get_utf8_name (writer->file),
my_error->message);
g_clear_error (&my_error);
g_clear_object (&writer->output);
return FALSE;
}
}
g_clear_object (&writer->output);
return TRUE;
}

View File

@ -0,0 +1,86 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* PikaConfigWriter
* Copyright (C) 2003 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_CONFIG_WRITER_H__
#define __PIKA_CONFIG_WRITER_H__
/**
* PIKA_TYPE_CONFIG_WRITER:
*
* The type ID of the "PikaConfigWriter" type which is a boxed type,
* used to write config files.
*
* Since: 3.0
*/
#define PIKA_TYPE_CONFIG_WRITER (pika_config_writer_get_type ())
GType pika_config_writer_get_type (void) G_GNUC_CONST;
PikaConfigWriter * pika_config_writer_new_from_file (GFile *file,
gboolean atomic,
const gchar *header,
GError **error);
PikaConfigWriter * pika_config_writer_new_from_stream (GOutputStream *output,
const gchar *header,
GError **error);
PikaConfigWriter * pika_config_writer_new_from_fd (gint fd);
PikaConfigWriter * pika_config_writer_new_from_string (GString *string);
PikaConfigWriter * pika_config_writer_ref (PikaConfigWriter *writer);
void pika_config_writer_unref (PikaConfigWriter *writer);
void pika_config_writer_open (PikaConfigWriter *writer,
const gchar *name);
void pika_config_writer_comment_mode (PikaConfigWriter *writer,
gboolean enable);
void pika_config_writer_print (PikaConfigWriter *writer,
const gchar *string,
gint len);
void pika_config_writer_printf (PikaConfigWriter *writer,
const gchar *format,
...) G_GNUC_PRINTF (2, 3);
void pika_config_writer_identifier (PikaConfigWriter *writer,
const gchar *identifier);
void pika_config_writer_string (PikaConfigWriter *writer,
const gchar *string);
void pika_config_writer_data (PikaConfigWriter *writer,
gint length,
const guint8 *data);
void pika_config_writer_comment (PikaConfigWriter *writer,
const gchar *comment);
void pika_config_writer_linefeed (PikaConfigWriter *writer);
void pika_config_writer_revert (PikaConfigWriter *writer);
void pika_config_writer_close (PikaConfigWriter *writer);
gboolean pika_config_writer_finish (PikaConfigWriter *writer,
const gchar *footer,
GError **error);
#endif /* __PIKA_CONFIG_WRITER_H__ */

889
libpikaconfig/pikascanner.c Normal file
View File

@ -0,0 +1,889 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikascanner.c
* Copyright (C) 2002 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "pikaconfig-error.h"
#include "pikascanner.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikascanner
* @title: PikaScanner
* @short_description: A wrapper around #GScanner with some convenience API.
*
* A wrapper around #GScanner with some convenience API.
**/
typedef struct
{
gint ref_count;
gchar *name;
GMappedFile *mapped;
gchar *text;
GError **error;
} PikaScannerData;
G_DEFINE_BOXED_TYPE (PikaScanner, pika_scanner,
pika_scanner_ref, pika_scanner_unref)
/* local function prototypes */
static PikaScanner * pika_scanner_new (const gchar *name,
GMappedFile *mapped,
gchar *text,
GError **error);
static void pika_scanner_message (PikaScanner *scanner,
gchar *message,
gboolean is_error);
/* public functions */
/**
* pika_scanner_new_file:
* @file: a #GFile
* @error: return location for #GError, or %NULL
*
* Returns: (transfer full): The new #PikaScanner.
*
* Since: 2.10
**/
PikaScanner *
pika_scanner_new_file (GFile *file,
GError **error)
{
PikaScanner *scanner;
gchar *path;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
path = g_file_get_path (file);
if (path)
{
GMappedFile *mapped;
mapped = g_mapped_file_new (path, FALSE, error);
g_free (path);
if (! mapped)
{
if (error)
{
(*error)->domain = PIKA_CONFIG_ERROR;
(*error)->code = ((*error)->code == G_FILE_ERROR_NOENT ?
PIKA_CONFIG_ERROR_OPEN_ENOENT :
PIKA_CONFIG_ERROR_OPEN);
}
return NULL;
}
/* pika_scanner_new() takes a "name" for the scanner, not a filename */
scanner = pika_scanner_new (pika_file_get_utf8_name (file),
mapped, NULL, error);
g_scanner_input_text (scanner,
g_mapped_file_get_contents (mapped),
g_mapped_file_get_length (mapped));
}
else
{
GInputStream *input;
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (! input)
{
if (error)
{
(*error)->domain = PIKA_CONFIG_ERROR;
(*error)->code = ((*error)->code == G_IO_ERROR_NOT_FOUND ?
PIKA_CONFIG_ERROR_OPEN_ENOENT :
PIKA_CONFIG_ERROR_OPEN);
}
return NULL;
}
g_object_set_data (G_OBJECT (input), "pika-data", file);
scanner = pika_scanner_new_stream (input, error);
g_object_unref (input);
}
return scanner;
}
/**
* pika_scanner_new_stream:
* @input: a #GInputStream
* @error: return location for #GError, or %NULL
*
* Returns: (transfer full): The new #PikaScanner.
*
* Since: 2.10
**/
PikaScanner *
pika_scanner_new_stream (GInputStream *input,
GError **error)
{
PikaScanner *scanner;
GFile *file;
const gchar *path;
GString *string;
gchar buffer[4096];
gsize bytes_read;
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
file = g_object_get_data (G_OBJECT (input), "pika-file");
if (file)
path = pika_file_get_utf8_name (file);
else
path = "stream";
string = g_string_new (NULL);
do
{
GError *my_error = NULL;
gboolean success;
success = g_input_stream_read_all (input, buffer, sizeof (buffer),
&bytes_read, NULL, &my_error);
if (bytes_read > 0)
g_string_append_len (string, buffer, bytes_read);
if (! success)
{
if (string->len > 0)
{
g_printerr ("%s: read error in '%s', trying to scan "
"partial content: %s",
G_STRFUNC, path, my_error->message);
g_clear_error (&my_error);
break;
}
g_string_free (string, TRUE);
g_propagate_error (error, my_error);
return NULL;
}
}
while (bytes_read == sizeof (buffer));
/* pika_scanner_new() takes a "name" for the scanner, not a filename */
scanner = pika_scanner_new (path, NULL, string->str, error);
bytes_read = string->len;
g_scanner_input_text (scanner, g_string_free (string, FALSE), bytes_read);
return scanner;
}
/**
* pika_scanner_new_string:
* @text: (array length=text_len):
* @text_len: The length of @text, or -1 if NULL-terminated
* @error: return location for #GError, or %NULL
*
* Returns: (transfer full): The new #PikaScanner.
*
* Since: 2.4
**/
PikaScanner *
pika_scanner_new_string (const gchar *text,
gint text_len,
GError **error)
{
PikaScanner *scanner;
g_return_val_if_fail (text != NULL || text_len <= 0, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (text_len < 0)
text_len = text ? strlen (text) : 0;
scanner = pika_scanner_new (NULL, NULL, NULL, error);
g_scanner_input_text (scanner, text, text_len);
return scanner;
}
static PikaScanner *
pika_scanner_new (const gchar *name,
GMappedFile *mapped,
gchar *text,
GError **error)
{
PikaScanner *scanner;
PikaScannerData *data;
scanner = g_scanner_new (NULL);
data = g_slice_new0 (PikaScannerData);
data->ref_count = 1;
data->name = g_strdup (name);
data->mapped = mapped;
data->text = text;
data->error = error;
scanner->user_data = data;
scanner->msg_handler = pika_scanner_message;
scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z );
scanner->config->cset_identifier_nth = ( G_CSET_a_2_z G_CSET_A_2_Z
G_CSET_DIGITS "-_" );
scanner->config->scan_identifier_1char = TRUE;
scanner->config->store_int64 = TRUE;
return scanner;
}
/**
* pika_scanner_ref:
* @scanner: #PikaScanner to ref
*
* Adds a reference to a #PikaScanner.
*
* Returns: the same @scanner.
*
* Since: 3.0
*/
PikaScanner *
pika_scanner_ref (PikaScanner *scanner)
{
PikaScannerData *data;
g_return_val_if_fail (scanner != NULL, NULL);
data = scanner->user_data;
data->ref_count++;
return scanner;
}
/**
* pika_scanner_unref:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
*
* Unref a #PikaScanner. If the reference count drops to zero, the
* scanner is freed.
*
* Since: 3.0
**/
void
pika_scanner_unref (PikaScanner *scanner)
{
PikaScannerData *data;
g_return_if_fail (scanner != NULL);
data = scanner->user_data;
data->ref_count--;
if (data->ref_count < 1)
{
if (data->mapped)
g_mapped_file_unref (data->mapped);
if (data->text)
g_free (data->text);
g_free (data->name);
g_slice_free (PikaScannerData, data);
g_scanner_destroy (scanner);
}
}
/**
* pika_scanner_parse_token:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @token: the #GTokenType expected as next token.
*
* Returns: %TRUE if the next token is @token, %FALSE otherwise.
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_token (PikaScanner *scanner,
GTokenType token)
{
if (g_scanner_peek_next_token (scanner) != token)
return FALSE;
g_scanner_get_next_token (scanner);
return TRUE;
}
/**
* pika_scanner_parse_identifier:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @identifier: (out): the expected identifier.
*
* Returns: %TRUE if the next token is an identifier and if its
* value matches @identifier.
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_identifier (PikaScanner *scanner,
const gchar *identifier)
{
if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
return FALSE;
g_scanner_get_next_token (scanner);
if (strcmp (scanner->value.v_identifier, identifier))
return FALSE;
return TRUE;
}
/**
* pika_scanner_parse_string:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed string
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_string (PikaScanner *scanner,
gchar **dest)
{
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
return FALSE;
g_scanner_get_next_token (scanner);
if (*scanner->value.v_string)
{
if (! g_utf8_validate (scanner->value.v_string, -1, NULL))
{
g_scanner_warn (scanner, _("invalid UTF-8 string"));
return FALSE;
}
*dest = g_strdup (scanner->value.v_string);
}
else
{
*dest = NULL;
}
return TRUE;
}
/**
* pika_scanner_parse_string_no_validate:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed string
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_string_no_validate (PikaScanner *scanner,
gchar **dest)
{
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
return FALSE;
g_scanner_get_next_token (scanner);
if (*scanner->value.v_string)
*dest = g_strdup (scanner->value.v_string);
else
*dest = NULL;
return TRUE;
}
/**
* pika_scanner_parse_data:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @length: Length of the data to parse
* @dest: (out) (array length=length): Return location for the parsed data
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_data (PikaScanner *scanner,
gint length,
guint8 **dest)
{
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
return FALSE;
g_scanner_get_next_token (scanner);
if (scanner->value.v_string)
*dest = g_memdup2 (scanner->value.v_string, length);
else
*dest = NULL;
return TRUE;
}
/**
* pika_scanner_parse_int:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed integer
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_int (PikaScanner *scanner,
gint *dest)
{
gboolean negate = FALSE;
if (g_scanner_peek_next_token (scanner) == '-')
{
negate = TRUE;
g_scanner_get_next_token (scanner);
}
if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
return FALSE;
g_scanner_get_next_token (scanner);
if (negate)
*dest = -scanner->value.v_int64;
else
*dest = scanner->value.v_int64;
return TRUE;
}
/**
* pika_scanner_parse_int64:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed integer
*
* Returns: %TRUE on success
*
* Since: 2.8
**/
gboolean
pika_scanner_parse_int64 (PikaScanner *scanner,
gint64 *dest)
{
gboolean negate = FALSE;
if (g_scanner_peek_next_token (scanner) == '-')
{
negate = TRUE;
g_scanner_get_next_token (scanner);
}
if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT)
return FALSE;
g_scanner_get_next_token (scanner);
if (negate)
*dest = -scanner->value.v_int64;
else
*dest = scanner->value.v_int64;
return TRUE;
}
/**
* pika_scanner_parse_float:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed float
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_float (PikaScanner *scanner,
gdouble *dest)
{
gboolean negate = FALSE;
if (g_scanner_peek_next_token (scanner) == '-')
{
negate = TRUE;
g_scanner_get_next_token (scanner);
}
if (g_scanner_peek_next_token (scanner) == G_TOKEN_FLOAT)
{
g_scanner_get_next_token (scanner);
if (negate)
*dest = -scanner->value.v_float;
else
*dest = scanner->value.v_float;
return TRUE;
}
else if (g_scanner_peek_next_token (scanner) == G_TOKEN_INT)
{
/* v_int is unsigned so we need to cast to
*
* gint64 first for negative values.
*/
g_scanner_get_next_token (scanner);
if (negate)
*dest = - (gint64) scanner->value.v_int;
else
*dest = scanner->value.v_int;
return TRUE;
}
return FALSE;
}
/**
* pika_scanner_parse_boolean:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out): Return location for the parsed boolean
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_boolean (PikaScanner *scanner,
gboolean *dest)
{
if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
return FALSE;
g_scanner_get_next_token (scanner);
if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
{
*dest = TRUE;
}
else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
{
*dest = FALSE;
}
else
{
g_scanner_error
(scanner,
/* please don't translate 'yes' and 'no' */
_("expected 'yes' or 'no' for boolean token, got '%s'"),
scanner->value.v_identifier);
return FALSE;
}
return TRUE;
}
enum
{
COLOR_RGB = 1,
COLOR_RGBA,
COLOR_HSV,
COLOR_HSVA
};
/**
* pika_scanner_parse_color:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out caller-allocates): Pointer to a color to store the result
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_color (PikaScanner *scanner,
PikaRGB *dest)
{
guint scope_id;
guint old_scope_id;
GTokenType token;
PikaRGB color = { 0.0, 0.0, 0.0, 1.0 };
scope_id = g_quark_from_static_string ("pika_scanner_parse_color");
old_scope_id = g_scanner_set_scope (scanner, scope_id);
if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb"))
{
g_scanner_scope_add_symbol (scanner, scope_id,
"color-rgb", GINT_TO_POINTER (COLOR_RGB));
g_scanner_scope_add_symbol (scanner, scope_id,
"color-rgba", GINT_TO_POINTER (COLOR_RGBA));
g_scanner_scope_add_symbol (scanner, scope_id,
"color-hsv", GINT_TO_POINTER (COLOR_HSV));
g_scanner_scope_add_symbol (scanner, scope_id,
"color-hsva", GINT_TO_POINTER (COLOR_HSVA));
}
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:
{
gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 };
gint n_channels = 4;
gboolean is_hsv = FALSE;
gint i;
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
{
case COLOR_RGB:
n_channels = 3;
/* fallthrough */
case COLOR_RGBA:
break;
case COLOR_HSV:
n_channels = 3;
/* fallthrough */
case COLOR_HSVA:
is_hsv = TRUE;
break;
}
token = G_TOKEN_FLOAT;
for (i = 0; i < n_channels; i++)
{
if (! pika_scanner_parse_float (scanner, &col[i]))
goto finish;
}
if (is_hsv)
{
PikaHSV hsv;
pika_hsva_set (&hsv, col[0], col[1], col[2], col[3]);
pika_hsv_to_rgb (&hsv, &color);
}
else
{
pika_rgba_set (&color, col[0], col[1], col[2], col[3]);
}
token = G_TOKEN_RIGHT_PAREN;
}
break;
case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_NONE; /* indicates success */
goto finish;
default: /* do nothing */
break;
}
}
finish:
if (token != G_TOKEN_NONE)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
}
else
{
*dest = color;
}
g_scanner_set_scope (scanner, old_scope_id);
return (token == G_TOKEN_NONE);
}
/**
* pika_scanner_parse_matrix2:
* @scanner: A #PikaScanner created by pika_scanner_new_file() or
* pika_scanner_new_string()
* @dest: (out caller-allocates): Pointer to a matrix to store the result
*
* Returns: %TRUE on success
*
* Since: 2.4
**/
gboolean
pika_scanner_parse_matrix2 (PikaScanner *scanner,
PikaMatrix2 *dest)
{
guint scope_id;
guint old_scope_id;
GTokenType token;
PikaMatrix2 matrix;
scope_id = g_quark_from_static_string ("pika_scanner_parse_matrix");
old_scope_id = g_scanner_set_scope (scanner, scope_id);
if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "matrix"))
g_scanner_scope_add_symbol (scanner, scope_id,
"matrix", GINT_TO_POINTER (0));
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:
{
token = G_TOKEN_FLOAT;
if (! pika_scanner_parse_float (scanner, &matrix.coeff[0][0]))
goto finish;
if (! pika_scanner_parse_float (scanner, &matrix.coeff[0][1]))
goto finish;
if (! pika_scanner_parse_float (scanner, &matrix.coeff[1][0]))
goto finish;
if (! pika_scanner_parse_float (scanner, &matrix.coeff[1][1]))
goto finish;
token = G_TOKEN_RIGHT_PAREN;
}
break;
case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_NONE; /* indicates success */
goto finish;
default: /* do nothing */
break;
}
}
finish:
if (token != G_TOKEN_NONE)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
}
else
{
*dest = matrix;
}
g_scanner_set_scope (scanner, old_scope_id);
return (token == G_TOKEN_NONE);
}
/* private functions */
static void
pika_scanner_message (PikaScanner *scanner,
gchar *message,
gboolean is_error)
{
PikaScannerData *data = scanner->user_data;
/* we don't expect warnings */
g_return_if_fail (is_error);
if (data->name)
g_set_error (data->error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
_("Error while parsing '%s' in line %d: %s"),
data->name, scanner->line, message);
else
/* should never happen, thus not marked for translation */
g_set_error (data->error, PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_PARSE,
"Error parsing internal buffer: %s", message);
}

View File

@ -0,0 +1,80 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikascanner.h
* Copyright (C) 2002 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_CONFIG_H_INSIDE__) && !defined (PIKA_CONFIG_COMPILATION)
#error "Only <libpikaconfig/pikaconfig.h> can be included directly."
#endif
#ifndef __PIKA_SCANNER_H__
#define __PIKA_SCANNER_H__
/**
* PIKA_TYPE_SCANNER:
*
* The type ID of the PIKA scanner type which is a boxed type, used to
* read config files.
*
* Since: 3.0
*/
#define PIKA_TYPE_SCANNER (pika_scnner_get_type ())
GType pika_scanner_get_type (void) G_GNUC_CONST;
PikaScanner * pika_scanner_new_file (GFile *file,
GError **error);
PikaScanner * pika_scanner_new_stream (GInputStream *input,
GError **error);
PikaScanner * pika_scanner_new_string (const gchar *text,
gint text_len,
GError **error);
PikaScanner * pika_scanner_ref (PikaScanner *scanner);
void pika_scanner_unref (PikaScanner *scanner);
gboolean pika_scanner_parse_token (PikaScanner *scanner,
GTokenType token);
gboolean pika_scanner_parse_identifier (PikaScanner *scanner,
const gchar *identifier);
gboolean pika_scanner_parse_string (PikaScanner *scanner,
gchar **dest);
gboolean pika_scanner_parse_string_no_validate (PikaScanner *scanner,
gchar **dest);
gboolean pika_scanner_parse_data (PikaScanner *scanner,
gint length,
guint8 **dest);
gboolean pika_scanner_parse_int (PikaScanner *scanner,
gint *dest);
gboolean pika_scanner_parse_int64 (PikaScanner *scanner,
gint64 *dest);
gboolean pika_scanner_parse_float (PikaScanner *scanner,
gdouble *dest);
gboolean pika_scanner_parse_boolean (PikaScanner *scanner,
gboolean *dest);
gboolean pika_scanner_parse_color (PikaScanner *scanner,
PikaRGB *dest);
gboolean pika_scanner_parse_matrix2 (PikaScanner *scanner,
PikaMatrix2 *dest);
#endif /* __PIKA_SCANNER_H__ */