/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2009 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "gth-script.h" #include "gth-script-file.h" /* version 1.0: Original version version 1.1: Changed command special codes to a single character. */ #define SCRIPT_FORMAT "1.1" enum { CHANGED, LAST_SIGNAL }; struct _GthScriptFilePrivate { gboolean loaded; GList *items; }; static guint gth_script_file_signals[LAST_SIGNAL] = { 0 }; static GType gth_script_file_get_type (void); G_DEFINE_TYPE_WITH_CODE (GthScriptFile, gth_script_file, G_TYPE_OBJECT, G_ADD_PRIVATE (GthScriptFile)) static void gth_script_file_finalize (GObject *object) { GthScriptFile *self; self = GTH_SCRIPT_FILE (object); _g_object_list_unref (self->priv->items); G_OBJECT_CLASS (gth_script_file_parent_class)->finalize (object); } static void gth_script_file_class_init (GthScriptFileClass *klass) { GObjectClass *object_class; object_class = (GObjectClass*) klass; object_class->finalize = gth_script_file_finalize; gth_script_file_signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GthScriptFileClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void gth_script_file_init (GthScriptFile *self) { self->priv = gth_script_file_get_instance_private (self); self->priv->items = NULL; self->priv->loaded = FALSE; } GthScriptFile * gth_script_file_get (void) { static GthScriptFile *script_file = NULL; if (script_file == NULL) script_file = g_object_new (GTH_TYPE_SCRIPT_FILE, NULL); return script_file; } /* -- convert_command_attributes_1_0 -- */ static gboolean convert_command_attributes_1_0_cb (const GMatchInfo *match_info, GString *result, gpointer user_data) { char *match; g_string_append_c (result, '%'); match = g_match_info_fetch (match_info, 0); if (strcmp (match, "%ask") == 0) g_string_append_c (result, GTH_SCRIPT_CODE_ASK_VALUE); else if (strcmp (match, "%quote") == 0) g_string_append_c (result, GTH_SCRIPT_CODE_QUOTE); if (strcmp (match, "%attr") == 0) g_string_append_c (result, GTH_SCRIPT_CODE_FILE_ATTRIBUTE); return FALSE; } static char * convert_command_attributes_1_0 (const char *command) { GRegex *re; char *new_command; re = g_regex_new ("%ask|%quote|%attr", 0, 0, NULL); new_command = g_regex_replace_eval (re, command, -1, 0, 0, convert_command_attributes_1_0_cb, NULL, NULL); g_regex_unref (re); return new_command; } static gboolean gth_script_file_load_from_data (GthScriptFile *self, const char *data, gsize length, GError **error) { DomDocument *doc; gboolean success; doc = dom_document_new (); success = dom_document_load (doc, data, length, error); if (success) { DomElement *scripts_node; DomElement *child; GList *new_items = NULL; scripts_node = DOM_ELEMENT (doc)->first_child; if ((scripts_node != NULL) && (g_strcmp0 (scripts_node->tag_name, "scripts") == 0)) { gboolean convert_format_1_0; convert_format_1_0 = _g_str_equal (dom_element_get_attribute (DOM_ELEMENT (scripts_node), "version"), "1.0"); for (child = scripts_node->first_child; child != NULL; child = child->next_sibling) { GthScript *script = NULL; if (strcmp (child->tag_name, "script") == 0) { script = gth_script_new (); dom_domizable_load_from_element (DOM_DOMIZABLE (script), child); if (convert_format_1_0) { char *new_command; new_command = convert_command_attributes_1_0 (gth_script_get_command (script)); g_object_set (script, "command", new_command, NULL); g_free (new_command); } } if (script == NULL) continue; new_items = g_list_prepend (new_items, script); } new_items = g_list_reverse (new_items); self->priv->items = g_list_concat (self->priv->items, new_items); } } g_object_unref (doc); return success; } static gboolean gth_script_file_load_from_file (GthScriptFile *self, GFile *file, GError **error) { char *buffer; gsize len; GError *read_error; gboolean retval; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (file != NULL, FALSE); read_error = NULL; _g_file_load_in_buffer (file, (void **) &buffer, &len, NULL, &read_error); if (read_error != NULL) { g_propagate_error (error, read_error); return FALSE; } read_error = NULL; retval = gth_script_file_load_from_data (self, buffer, len, &read_error); if (read_error != NULL) { g_propagate_error (error, read_error); g_free (buffer); return FALSE; } g_free (buffer); return retval; } static void _gth_script_file_load_if_needed (GthScriptFile *self) { GFile *default_script_file; if (self->priv->loaded) return; default_script_file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, PIX_DIR, "scripts.xml", NULL); gth_script_file_load_from_file (self, default_script_file, NULL); self->priv->loaded = TRUE; g_object_unref (default_script_file); } static char * gth_script_file_to_data (GthScriptFile *self, gsize *len, GError **data_error) { DomDocument *doc; DomElement *root; char *data; GList *scan; doc = dom_document_new (); root = dom_document_create_element (doc, "scripts", "version", SCRIPT_FORMAT, NULL); dom_element_append_child (DOM_ELEMENT (doc), root); for (scan = self->priv->items; scan; scan = scan->next) dom_element_append_child (root, dom_domizable_create_element (DOM_DOMIZABLE (scan->data), doc)); data = dom_document_dump (doc, len); g_object_unref (doc); return data; } static gboolean gth_script_file_to_file (GthScriptFile *self, GFile *file, GError **error) { char *data; GError *data_error, *write_error; gsize len; gboolean retval; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (file != NULL, FALSE); data_error = NULL; data = gth_script_file_to_data (self, &len, &data_error); if (data_error) { g_propagate_error (error, data_error); return FALSE; } write_error = NULL; if (! _g_file_write (file, FALSE, 0, data, len, NULL, &write_error)) { g_propagate_error (error, write_error); retval = FALSE; } else retval = TRUE; g_free (data); return retval; } GthScript * gth_script_file_get_script (GthScriptFile *self, const char *id) { GList *scan; for (scan = self->priv->items; scan; scan = scan->next) { GthScript *script = scan->data; if (g_strcmp0 (gth_script_get_id (script), id) == 0) return script; } return NULL; } gboolean gth_script_file_save (GthScriptFile *self, GError **error) { GFile *default_script_file; gboolean result; _gth_script_file_load_if_needed (self); default_script_file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, PIX_DIR, "scripts.xml", NULL); result = gth_script_file_to_file (self, default_script_file, error); if (result) g_signal_emit (G_OBJECT (self), gth_script_file_signals[CHANGED], 0); g_object_unref (default_script_file); return result; } GList * gth_script_file_get_scripts (GthScriptFile *self) { GList *list; GList *scan; _gth_script_file_load_if_needed (self); list = NULL; for (scan = self->priv->items; scan; scan = scan->next) list = g_list_prepend (list, gth_duplicable_duplicate (GTH_DUPLICABLE (scan->data))); return g_list_reverse (list); } static int find_by_id (gconstpointer a, gconstpointer b) { GthScript *script = (GthScript *) a; GthScript *script_to_find = (GthScript *) b; return g_strcmp0 (gth_script_get_id (script), gth_script_get_id (script_to_find)); } gboolean gth_script_file_has_script (GthScriptFile *self, GthScript *script) { return g_list_find_custom (self->priv->items, script, find_by_id) != NULL; } void gth_script_file_add (GthScriptFile *self, GthScript *script) { GList *link; _gth_script_file_load_if_needed (self); g_object_ref (script); link = g_list_find_custom (self->priv->items, script, find_by_id); if (link != NULL) { g_object_unref (link->data); link->data = script; } else self->priv->items = g_list_append (self->priv->items, script); } void gth_script_file_remove (GthScriptFile *self, GthScript *script) { GList *link; _gth_script_file_load_if_needed (self); link = g_list_find_custom (self->priv->items, script, find_by_id); if (link == NULL) return; self->priv->items = g_list_remove_link (self->priv->items, link); _g_object_list_unref (link); } void gth_script_file_clear (GthScriptFile *self) { _g_object_list_unref (self->priv->items); self->priv->items = NULL; }