3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
7 * gLabels is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * gLabels is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
25 #include <glib/gi18n.h>
26 #include <gobject/gvaluecollector.h>
29 #include <libglabels/libglabels.h>
33 /*========================================================*/
35 /*========================================================*/
37 struct _glMergePrivate {
41 glMergeSrcType src_type;
55 glMergeSrcType src_type;
62 /*========================================================*/
63 /* Private globals. */
64 /*========================================================*/
66 static GList *backends = NULL;
68 /*========================================================*/
69 /* Private function prototypes. */
70 /*========================================================*/
72 static void gl_merge_finalize (GObject *object);
74 static void merge_open (glMerge *merge);
76 static void merge_close (glMerge *merge);
78 static glMergeRecord *merge_get_record (glMerge *merge);
80 static void merge_free_record (glMergeRecord **record);
82 static glMergeRecord *merge_dup_record (glMergeRecord *record);
84 static void merge_free_record_list (GList **record_list);
86 static GList *merge_dup_record_list (GList *record_list);
91 /*****************************************************************************/
92 /* Register a new merge backend. */
93 /*****************************************************************************/
95 gl_merge_register_backend (GType type,
98 glMergeSrcType src_type,
99 const gchar *first_arg_name,
108 guint n_params = 0, n_alloced_params = 16;
110 backend = g_new0 (Backend, 1);
112 backend->type = type;
113 backend->name = g_strdup (name);
114 backend->description = g_strdup (description);
115 backend->src_type = src_type;
117 params = g_new (GParameter, n_alloced_params);
118 va_start (args, first_arg_name);
119 for ( pname=first_arg_name; pname != NULL; pname=va_arg (args,gchar *) ) {
122 class = g_type_class_ref (type);
124 g_message ("%s: unknown object type %d",
125 G_STRLOC, (int)type);
128 pspec = g_object_class_find_property (class, pname);
130 g_message ("%s: object class `%s' has no property named `%s'",
131 G_STRLOC, g_type_name (type), pname);
134 if (n_params >= n_alloced_params) {
135 n_alloced_params += 16;
136 params = g_renew (GParameter, params, n_alloced_params);
138 params[n_params].name = pname;
139 params[n_params].value.g_type = 0;
140 g_value_init (¶ms[n_params].value, pspec->value_type);
141 G_VALUE_COLLECT (¶ms[n_params].value, args, 0, &error);
143 g_message ("%s: %s", G_STRLOC, error);
152 backend->n_params = n_params;
153 backend->params = params;
155 backends = g_list_append (backends, backend);
159 /*****************************************************************************/
160 /* Get list of registered backend descriptions. */
161 /*****************************************************************************/
163 gl_merge_get_descriptions (void)
165 GList *descriptions = NULL;
169 descriptions = g_list_append (descriptions, g_strdup(_("None")));
171 for ( p=backends; p!=NULL; p=p->next) {
172 backend = (Backend *)p->data;
173 descriptions = g_list_append (descriptions,
174 g_strdup(backend->description));
180 /*****************************************************************************/
181 /* Free list of descriptions. */
182 /*****************************************************************************/
184 gl_merge_free_descriptions (GList **descriptions)
188 gl_debug (DEBUG_MERGE, "START");
190 for (p = *descriptions; p != NULL; p = p->next) {
195 g_list_free (*descriptions);
196 *descriptions = NULL;
198 gl_debug (DEBUG_MERGE, "END");
201 /*****************************************************************************/
202 /* Lookup name of backend from description. */
203 /*****************************************************************************/
205 gl_merge_description_to_name (gchar *description)
210 if (lgl_str_utf8_casecmp(description, _("None")) == 0) {
211 return g_strdup("None");
214 for ( p=backends; p!=NULL; p=p->next) {
215 backend = (Backend *)p->data;
216 if (lgl_str_utf8_casecmp(description, backend->description) == 0) {
217 return g_strdup(backend->name);
221 return g_strdup("None");
224 /*****************************************************************************/
225 /* Boilerplate object stuff. */
226 /*****************************************************************************/
227 G_DEFINE_TYPE (glMerge, gl_merge, G_TYPE_OBJECT);
230 gl_merge_class_init (glMergeClass *class)
232 GObjectClass *object_class = G_OBJECT_CLASS (class);
234 gl_debug (DEBUG_MERGE, "START");
236 gl_merge_parent_class = g_type_class_peek_parent (class);
238 object_class->finalize = gl_merge_finalize;
240 gl_debug (DEBUG_MERGE, "END");
244 gl_merge_init (glMerge *merge)
246 gl_debug (DEBUG_MERGE, "START");
248 merge->priv = g_new0 (glMergePrivate, 1);
250 gl_debug (DEBUG_MERGE, "END");
254 gl_merge_finalize (GObject *object)
256 glMerge *merge = GL_MERGE (object);
258 gl_debug (DEBUG_MERGE, "START");
260 g_return_if_fail (object && GL_IS_MERGE (object));
262 merge_free_record_list (&merge->priv->record_list);
263 g_free (merge->priv->name);
264 g_free (merge->priv->description);
265 g_free (merge->priv->src);
266 g_free (merge->priv);
268 G_OBJECT_CLASS (gl_merge_parent_class)->finalize (object);
270 gl_debug (DEBUG_MERGE, "END");
273 /*****************************************************************************/
274 /* New merge object. */
275 /*****************************************************************************/
277 gl_merge_new (gchar *name)
279 glMerge *merge = NULL;
283 gl_debug (DEBUG_MERGE, "START");
285 for (p=backends; p!=NULL; p=p->next) {
286 backend = (Backend *)p->data;
288 if (g_strcasecmp(name, backend->name) == 0) {
290 merge = GL_MERGE (g_object_newv (backend->type,
294 merge->priv->name = g_strdup (name);
295 merge->priv->description = g_strdup (backend->description);
296 merge->priv->src_type = backend->src_type;
302 if ( (merge == NULL) && (g_strcasecmp (name, "None") != 0)) {
303 g_message ("Unknown merge backend \"%s\"", name);
306 gl_debug (DEBUG_MERGE, "END");
311 /*****************************************************************************/
312 /* Duplicate merge. */
313 /*****************************************************************************/
315 gl_merge_dup (glMerge *src_merge)
319 gl_debug (DEBUG_MERGE, "START");
321 if (src_merge == NULL) {
322 gl_debug (DEBUG_MERGE, "END (NULL)");
326 g_return_val_if_fail (GL_IS_MERGE (src_merge), NULL);
328 dst_merge = g_object_new (G_OBJECT_TYPE(src_merge), NULL);
329 dst_merge->priv->name = g_strdup (src_merge->priv->name);
330 dst_merge->priv->description = g_strdup (src_merge->priv->description);
331 dst_merge->priv->src = g_strdup (src_merge->priv->src);
332 dst_merge->priv->src_type = src_merge->priv->src_type;
333 dst_merge->priv->record_list
334 = merge_dup_record_list (src_merge->priv->record_list);
336 if ( GL_MERGE_GET_CLASS(src_merge)->copy != NULL ) {
338 /* We have an object specific method, use it */
339 GL_MERGE_GET_CLASS(src_merge)->copy (dst_merge, src_merge);
343 gl_debug (DEBUG_MERGE, "END");
348 /*****************************************************************************/
349 /* Get name of merge. */
350 /*****************************************************************************/
352 gl_merge_get_name (glMerge *merge)
354 gl_debug (DEBUG_MERGE, "");
357 return g_strdup("None");
360 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup("None"));
362 return g_strdup(merge->priv->name);
365 /*****************************************************************************/
366 /* Get description of merge. */
367 /*****************************************************************************/
369 gl_merge_get_description (glMerge *merge)
371 gl_debug (DEBUG_MERGE, "");
374 return g_strdup(_("None"));
377 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup(_("None")));
379 return g_strdup(merge->priv->description);
382 /*****************************************************************************/
383 /* Get source type of merge. */
384 /*****************************************************************************/
386 gl_merge_get_src_type (glMerge *merge)
388 gl_debug (DEBUG_MERGE, "");
391 return GL_MERGE_SRC_IS_FIXED;
394 g_return_val_if_fail (GL_IS_MERGE (merge), GL_MERGE_SRC_IS_FIXED);
396 return merge->priv->src_type;
399 /*****************************************************************************/
400 /* Set src of merge. */
401 /*****************************************************************************/
403 gl_merge_set_src (glMerge *merge,
406 GList *record_list = NULL;
407 glMergeRecord *record;
409 gl_debug (DEBUG_MERGE, "START");
413 gl_debug (DEBUG_MERGE, "END (NULL)");
417 g_return_if_fail (GL_IS_MERGE (merge));
422 if ( merge->priv->src != NULL )
424 g_free (merge->priv->src);
426 merge->priv->src = NULL;
427 merge_free_record_list (&merge->priv->record_list);
433 if ( merge->priv->src != NULL )
435 g_free(merge->priv->src);
437 merge->priv->src = g_strdup (src);
439 merge_free_record_list (&merge->priv->record_list);
442 while ( (record = merge_get_record (merge)) != NULL )
444 record_list = g_list_append( record_list, record );
447 merge->priv->record_list = record_list;
452 gl_debug (DEBUG_MERGE, "END");
455 /*****************************************************************************/
456 /* Get src of merge. */
457 /*****************************************************************************/
459 gl_merge_get_src (glMerge *merge)
461 gl_debug (DEBUG_MERGE, "");
467 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
469 return g_strdup(merge->priv->src);
472 /*****************************************************************************/
474 /*****************************************************************************/
476 gl_merge_get_key_list (glMerge *merge)
478 GList *key_list = NULL;
480 gl_debug (DEBUG_MERGE, "START");
486 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
488 if ( GL_MERGE_GET_CLASS(merge)->get_key_list != NULL ) {
490 key_list = GL_MERGE_GET_CLASS(merge)->get_key_list (merge);
494 gl_debug (DEBUG_MERGE, "END");
499 /*****************************************************************************/
500 /* Free a list of keys. */
501 /*****************************************************************************/
503 gl_merge_free_key_list (GList **key_list)
507 gl_debug (DEBUG_MERGE, "START");
509 for (p = *key_list; p != NULL; p = p->next) {
514 g_list_free (*key_list);
517 gl_debug (DEBUG_MERGE, "END");
520 /*****************************************************************************/
522 /*****************************************************************************/
524 gl_merge_get_primary_key (glMerge *merge)
528 gl_debug (DEBUG_MERGE, "START");
534 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
536 if ( GL_MERGE_GET_CLASS(merge)->get_primary_key != NULL ) {
538 key = GL_MERGE_GET_CLASS(merge)->get_primary_key (merge);
542 gl_debug (DEBUG_MERGE, "END");
547 /*---------------------------------------------------------------------------*/
548 /* Open merge source. */
549 /*---------------------------------------------------------------------------*/
551 merge_open (glMerge *merge)
553 gl_debug (DEBUG_MERGE, "START");
555 g_return_if_fail (merge && GL_IS_MERGE (merge));
557 if ( GL_MERGE_GET_CLASS(merge)->open != NULL ) {
559 GL_MERGE_GET_CLASS(merge)->open (merge);
563 gl_debug (DEBUG_MERGE, "END");
566 /*---------------------------------------------------------------------------*/
567 /* Close merge source. */
568 /*---------------------------------------------------------------------------*/
570 merge_close (glMerge *merge)
572 gl_debug (DEBUG_MERGE, "START");
574 g_return_if_fail (merge && GL_IS_MERGE (merge));
576 if ( GL_MERGE_GET_CLASS(merge)->close != NULL ) {
578 GL_MERGE_GET_CLASS(merge)->close (merge);
582 gl_debug (DEBUG_MERGE, "END");
585 /*---------------------------------------------------------------------------*/
586 /* Get next record (list of fields) from opened merge source. */
587 /*---------------------------------------------------------------------------*/
588 static glMergeRecord *
589 merge_get_record (glMerge *merge)
591 glMergeRecord *record = NULL;
593 gl_debug (DEBUG_MERGE, "START");
595 g_return_val_if_fail (merge && GL_IS_MERGE (merge), NULL);
597 if ( GL_MERGE_GET_CLASS(merge)->get_record != NULL ) {
599 record = GL_MERGE_GET_CLASS(merge)->get_record (merge);
603 gl_debug (DEBUG_MERGE, "END");
608 /*---------------------------------------------------------------------------*/
609 /* Free a merge record (list of fields) */
610 /*---------------------------------------------------------------------------*/
612 merge_free_record (glMergeRecord **record)
617 gl_debug (DEBUG_MERGE, "START");
619 for (p = (*record)->field_list; p != NULL; p = p->next) {
620 field = (glMergeField *) p->data;
624 g_free (field->value);
631 g_list_free ((*record)->field_list);
632 (*record)->field_list = NULL;
637 gl_debug (DEBUG_MERGE, "END");
640 /*---------------------------------------------------------------------------*/
641 /* Duplicate a merge record (list of fields) */
642 /*---------------------------------------------------------------------------*/
643 static glMergeRecord *
644 merge_dup_record (glMergeRecord *record)
646 glMergeRecord *dest_record;
648 glMergeField *dest_field, *field;
650 gl_debug (DEBUG_MERGE, "START");
652 dest_record = g_new0 (glMergeRecord, 1);
653 dest_record->select_flag = record->select_flag;
655 for (p = record->field_list; p != NULL; p = p->next) {
656 field = (glMergeField *) p->data;
658 dest_field = g_new0 (glMergeField, 1);
660 dest_field->key = g_strdup (field->key);
661 dest_field->value = g_strdup (field->value);
663 dest_record->field_list =
664 g_list_append (dest_record->field_list, dest_field);
668 gl_debug (DEBUG_MERGE, "END");
673 /*****************************************************************************/
674 /* Find key in given record and evaluate. */
675 /*****************************************************************************/
677 gl_merge_eval_key (glMergeRecord *record,
685 gl_debug (DEBUG_MERGE, "START");
687 if ( (record != NULL) && (key != NULL) ) {
688 for (p = record->field_list; p != NULL; p = p->next) {
689 field = (glMergeField *) p->data;
691 if (strcmp (key, field->key) == 0) {
692 val = g_strdup (field->value);
698 gl_debug (DEBUG_MERGE, "END");
703 /*****************************************************************************/
704 /* Read all records from merge source. */
705 /*****************************************************************************/
707 gl_merge_get_record_list (glMerge *merge)
709 gl_debug (DEBUG_MERGE, "");
711 if ( merge != NULL ) {
712 return merge->priv->record_list;
718 /*---------------------------------------------------------------------------*/
719 /* Free a list of records. */
720 /*---------------------------------------------------------------------------*/
722 merge_free_record_list (GList **record_list)
725 glMergeRecord *record;
727 gl_debug (DEBUG_MERGE, "START");
729 for (p = *record_list; p != NULL; p = p->next) {
730 record = (glMergeRecord *) p->data;
732 merge_free_record( &record );
736 g_list_free (*record_list);
739 gl_debug (DEBUG_MERGE, "END");
742 /*---------------------------------------------------------------------------*/
743 /* Duplicate a list of records. */
744 /*---------------------------------------------------------------------------*/
746 merge_dup_record_list (GList *record_list)
748 GList *dest_list = NULL, *p;
749 glMergeRecord *dest_record, *record;
751 gl_debug (DEBUG_MERGE, "START");
753 for (p = record_list; p != NULL; p = p->next) {
754 record = (glMergeRecord *) p->data;
756 dest_record = merge_dup_record( record );
757 dest_list = g_list_append (dest_list, dest_record);
761 gl_debug (DEBUG_MERGE, "END");
766 /*****************************************************************************/
767 /* Count selected records. */
768 /*****************************************************************************/
770 gl_merge_get_record_count (glMerge *merge)
773 glMergeRecord *record;
776 gl_debug (DEBUG_MERGE, "START");
779 for ( p=merge->priv->record_list; p!=NULL; p=p->next ) {
780 record = (glMergeRecord *)p->data;
782 if ( record->select_flag ) count ++;
785 gl_debug (DEBUG_MERGE, "END");
793 * Local Variables: -- emacs
795 * c-basic-offset: 8 -- emacs
796 * tab-width: 8 -- emacs
797 * indent-tabs-mode: nil -- emacs