Initial checkin of Pika from heckimp
This commit is contained in:
32
libpikaconfig/Makefile.gi
Normal file
32
libpikaconfig/Makefile.gi
Normal 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
91
libpikaconfig/meson.build
Normal 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',
|
||||
)
|
1100
libpikaconfig/pikacolorconfig.c
Normal file
1100
libpikaconfig/pikacolorconfig.c
Normal file
File diff suppressed because it is too large
Load Diff
93
libpikaconfig/pikacolorconfig.h
Normal file
93
libpikaconfig/pikacolorconfig.h
Normal 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__ */
|
155
libpikaconfig/pikaconfig-array.c
Normal file
155
libpikaconfig/pikaconfig-array.c
Normal 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;
|
||||
}
|
47
libpikaconfig/pikaconfig-array.h
Normal file
47
libpikaconfig/pikaconfig-array.h
Normal 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__ */
|
1104
libpikaconfig/pikaconfig-deserialize.c
Normal file
1104
libpikaconfig/pikaconfig-deserialize.c
Normal file
File diff suppressed because it is too large
Load Diff
44
libpikaconfig/pikaconfig-deserialize.h
Normal file
44
libpikaconfig/pikaconfig-deserialize.h
Normal 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__ */
|
51
libpikaconfig/pikaconfig-error.c
Normal file
51
libpikaconfig/pikaconfig-error.c
Normal 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");
|
||||
}
|
59
libpikaconfig/pikaconfig-error.h
Normal file
59
libpikaconfig/pikaconfig-error.h
Normal 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__ */
|
839
libpikaconfig/pikaconfig-iface.c
Normal file
839
libpikaconfig/pikaconfig-iface.c
Normal 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, ¶site_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;
|
||||
}
|
135
libpikaconfig/pikaconfig-iface.h
Normal file
135
libpikaconfig/pikaconfig-iface.h
Normal 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__ */
|
388
libpikaconfig/pikaconfig-params.c
Normal file
388
libpikaconfig/pikaconfig-params.c
Normal 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;
|
||||
}
|
224
libpikaconfig/pikaconfig-params.h
Normal file
224
libpikaconfig/pikaconfig-params.h
Normal 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__ */
|
743
libpikaconfig/pikaconfig-path.c
Normal file
743
libpikaconfig/pikaconfig-path.c
Normal 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;
|
||||
}
|
109
libpikaconfig/pikaconfig-path.h
Normal file
109
libpikaconfig/pikaconfig-path.h
Normal 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__ */
|
244
libpikaconfig/pikaconfig-register.c
Normal file
244
libpikaconfig/pikaconfig-register.c
Normal 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);
|
||||
}
|
42
libpikaconfig/pikaconfig-register.h
Normal file
42
libpikaconfig/pikaconfig-register.h
Normal 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__ */
|
618
libpikaconfig/pikaconfig-serialize.c
Normal file
618
libpikaconfig/pikaconfig-serialize.c
Normal 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;
|
||||
}
|
52
libpikaconfig/pikaconfig-serialize.h
Normal file
52
libpikaconfig/pikaconfig-serialize.h
Normal 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__ */
|
482
libpikaconfig/pikaconfig-utils.c
Normal file
482
libpikaconfig/pikaconfig-utils.c
Normal 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);
|
||||
}
|
||||
}
|
52
libpikaconfig/pikaconfig-utils.h
Normal file
52
libpikaconfig/pikaconfig-utils.h
Normal 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__ */
|
102
libpikaconfig/pikaconfig.def
Normal file
102
libpikaconfig/pikaconfig.def
Normal 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
|
41
libpikaconfig/pikaconfig.h
Normal file
41
libpikaconfig/pikaconfig.h
Normal 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__ */
|
80
libpikaconfig/pikaconfigenums.c
Normal file
80
libpikaconfig/pikaconfigenums.c
Normal 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 */
|
||||
|
68
libpikaconfig/pikaconfigenums.h
Normal file
68
libpikaconfig/pikaconfigenums.h
Normal 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__ */
|
39
libpikaconfig/pikaconfigtypes.h
Normal file
39
libpikaconfig/pikaconfigtypes.h
Normal 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__ */
|
849
libpikaconfig/pikaconfigwriter.c
Normal file
849
libpikaconfig/pikaconfigwriter.c
Normal 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;
|
||||
}
|
86
libpikaconfig/pikaconfigwriter.h
Normal file
86
libpikaconfig/pikaconfigwriter.h
Normal 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
889
libpikaconfig/pikascanner.c
Normal 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);
|
||||
}
|
80
libpikaconfig/pikascanner.h
Normal file
80
libpikaconfig/pikascanner.h
Normal 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__ */
|
Reference in New Issue
Block a user