1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * merge.c: document merge module
8 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <glib/gi18n.h>
29 #include <gobject/gvaluecollector.h>
34 /*========================================================*/
36 /*========================================================*/
38 struct _glMergePrivate {
42 glMergeSrcType src_type;
56 glMergeSrcType src_type;
63 /*========================================================*/
64 /* Private globals. */
65 /*========================================================*/
67 static GList *backends = NULL;
69 /*========================================================*/
70 /* Private function prototypes. */
71 /*========================================================*/
73 static void gl_merge_finalize (GObject *object);
75 static void merge_open (glMerge *merge);
77 static void merge_close (glMerge *merge);
79 static glMergeRecord *merge_get_record (glMerge *merge);
81 static void merge_free_record (glMergeRecord **record);
83 static glMergeRecord *merge_dup_record (glMergeRecord *record);
85 static void merge_free_record_list (GList **record_list);
87 static GList *merge_dup_record_list (GList *record_list);
92 /*****************************************************************************/
93 /* Register a new merge backend. */
94 /*****************************************************************************/
96 gl_merge_register_backend (GType type,
99 glMergeSrcType src_type,
100 const gchar *first_arg_name,
109 guint n_params = 0, n_alloced_params = 16;
111 backend = g_new0 (Backend, 1);
113 backend->type = type;
114 backend->name = g_strdup (name);
115 backend->description = g_strdup (description);
116 backend->src_type = src_type;
118 params = g_new (GParameter, n_alloced_params);
119 va_start (args, first_arg_name);
120 for ( pname=first_arg_name; pname != NULL; pname=va_arg (args,gchar *) ) {
123 class = g_type_class_ref (type);
125 g_message ("%s: unknown object type %d",
126 G_STRLOC, (int)type);
129 pspec = g_object_class_find_property (class, pname);
131 g_message ("%s: object class `%s' has no property named `%s'",
132 G_STRLOC, g_type_name (type), pname);
135 if (n_params >= n_alloced_params) {
136 n_alloced_params += 16;
137 params = g_renew (GParameter, params, n_alloced_params);
139 params[n_params].name = pname;
140 params[n_params].value.g_type = 0;
141 g_value_init (¶ms[n_params].value, pspec->value_type);
142 G_VALUE_COLLECT (¶ms[n_params].value, args, 0, &error);
144 g_message ("%s: %s", G_STRLOC, error);
153 backend->n_params = n_params;
154 backend->params = params;
156 backends = g_list_append (backends, backend);
160 /*****************************************************************************/
161 /* Get list of registered backend descriptions. */
162 /*****************************************************************************/
164 gl_merge_get_descriptions (void)
166 GList *descriptions = NULL;
170 descriptions = g_list_append (descriptions, g_strdup(_("None")));
172 for ( p=backends; p!=NULL; p=p->next) {
173 backend = (Backend *)p->data;
174 descriptions = g_list_append (descriptions,
175 g_strdup(backend->description));
181 /*****************************************************************************/
182 /* Free list of descriptions. */
183 /*****************************************************************************/
185 gl_merge_free_descriptions (GList **descriptions)
189 gl_debug (DEBUG_MERGE, "START");
191 for (p = *descriptions; p != NULL; p = p->next) {
196 g_list_free (*descriptions);
197 *descriptions = NULL;
199 gl_debug (DEBUG_MERGE, "END");
202 /*****************************************************************************/
203 /* Lookup name of backend from description. */
204 /*****************************************************************************/
206 gl_merge_description_to_name (gchar *description)
211 if (g_strcasecmp(description, _("None")) == 0) {
212 return g_strdup("None");
215 for ( p=backends; p!=NULL; p=p->next) {
216 backend = (Backend *)p->data;
217 if (g_strcasecmp(description, backend->description) == 0) {
218 return g_strdup(backend->name);
222 return g_strdup("None");
225 /*****************************************************************************/
226 /* Boilerplate object stuff. */
227 /*****************************************************************************/
228 G_DEFINE_TYPE (glMerge, gl_merge, G_TYPE_OBJECT);
231 gl_merge_class_init (glMergeClass *class)
233 GObjectClass *object_class = G_OBJECT_CLASS (class);
235 gl_debug (DEBUG_MERGE, "START");
237 gl_merge_parent_class = g_type_class_peek_parent (class);
239 object_class->finalize = gl_merge_finalize;
241 gl_debug (DEBUG_MERGE, "END");
245 gl_merge_init (glMerge *merge)
247 gl_debug (DEBUG_MERGE, "START");
249 merge->priv = g_new0 (glMergePrivate, 1);
251 gl_debug (DEBUG_MERGE, "END");
255 gl_merge_finalize (GObject *object)
257 glMerge *merge = GL_MERGE (object);
259 gl_debug (DEBUG_MERGE, "START");
261 g_return_if_fail (object && GL_IS_MERGE (object));
263 merge_free_record_list (&merge->priv->record_list);
264 g_free (merge->priv->name);
265 g_free (merge->priv->description);
266 g_free (merge->priv->src);
267 g_free (merge->priv);
269 G_OBJECT_CLASS (gl_merge_parent_class)->finalize (object);
271 gl_debug (DEBUG_MERGE, "END");
274 /*****************************************************************************/
275 /* New merge object. */
276 /*****************************************************************************/
278 gl_merge_new (gchar *name)
280 glMerge *merge = NULL;
284 gl_debug (DEBUG_MERGE, "START");
286 for (p=backends; p!=NULL; p=p->next) {
287 backend = (Backend *)p->data;
289 if (g_strcasecmp(name, backend->name) == 0) {
291 merge = GL_MERGE (g_object_newv (backend->type,
295 merge->priv->name = g_strdup (name);
296 merge->priv->description = g_strdup (backend->description);
297 merge->priv->src_type = backend->src_type;
303 if ( (merge == NULL) && (g_strcasecmp (name, "None") != 0)) {
304 g_message ("Unknown merge backend \"%s\"", name);
307 gl_debug (DEBUG_MERGE, "END");
312 /*****************************************************************************/
313 /* Duplicate merge. */
314 /*****************************************************************************/
316 gl_merge_dup (glMerge *src_merge)
320 gl_debug (DEBUG_MERGE, "START");
322 if (src_merge == NULL) {
323 gl_debug (DEBUG_MERGE, "END (NULL)");
327 g_return_val_if_fail (GL_IS_MERGE (src_merge), NULL);
329 dst_merge = g_object_new (G_OBJECT_TYPE(src_merge), NULL);
330 dst_merge->priv->name = g_strdup (src_merge->priv->name);
331 dst_merge->priv->description = g_strdup (src_merge->priv->description);
332 dst_merge->priv->src = g_strdup (src_merge->priv->src);
333 dst_merge->priv->src_type = src_merge->priv->src_type;
334 dst_merge->priv->record_list
335 = merge_dup_record_list (src_merge->priv->record_list);
337 if ( GL_MERGE_GET_CLASS(src_merge)->copy != NULL ) {
339 /* We have an object specific method, use it */
340 GL_MERGE_GET_CLASS(src_merge)->copy (dst_merge, src_merge);
344 gl_debug (DEBUG_MERGE, "END");
349 /*****************************************************************************/
350 /* Get name of merge. */
351 /*****************************************************************************/
353 gl_merge_get_name (glMerge *merge)
355 gl_debug (DEBUG_MERGE, "");
358 return g_strdup("None");
361 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup("None"));
363 return g_strdup(merge->priv->name);
366 /*****************************************************************************/
367 /* Get description of merge. */
368 /*****************************************************************************/
370 gl_merge_get_description (glMerge *merge)
372 gl_debug (DEBUG_MERGE, "");
375 return g_strdup(_("None"));
378 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup(_("None")));
380 return g_strdup(merge->priv->description);
383 /*****************************************************************************/
384 /* Get source type of merge. */
385 /*****************************************************************************/
387 gl_merge_get_src_type (glMerge *merge)
389 gl_debug (DEBUG_MERGE, "");
392 return GL_MERGE_SRC_IS_FIXED;
395 g_return_val_if_fail (GL_IS_MERGE (merge), GL_MERGE_SRC_IS_FIXED);
397 return merge->priv->src_type;
400 /*****************************************************************************/
401 /* Set src of merge. */
402 /*****************************************************************************/
404 gl_merge_set_src (glMerge *merge,
407 GList *record_list = NULL;
408 glMergeRecord *record;
410 gl_debug (DEBUG_MERGE, "START");
414 gl_debug (DEBUG_MERGE, "END (NULL)");
418 g_return_if_fail (GL_IS_MERGE (merge));
423 if ( merge->priv->src != NULL )
425 g_free (merge->priv->src);
427 merge->priv->src = NULL;
428 merge_free_record_list (&merge->priv->record_list);
434 if ( merge->priv->src != NULL )
436 g_free(merge->priv->src);
438 merge->priv->src = g_strdup (src);
440 merge_free_record_list (&merge->priv->record_list);
443 while ( (record = merge_get_record (merge)) != NULL )
445 record_list = g_list_append( record_list, record );
448 merge->priv->record_list = record_list;
453 gl_debug (DEBUG_MERGE, "END");
456 /*****************************************************************************/
457 /* Get src of merge. */
458 /*****************************************************************************/
460 gl_merge_get_src (glMerge *merge)
462 gl_debug (DEBUG_MERGE, "");
468 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
470 return g_strdup(merge->priv->src);
473 /*****************************************************************************/
475 /*****************************************************************************/
477 gl_merge_get_key_list (glMerge *merge)
479 GList *key_list = NULL;
481 gl_debug (DEBUG_MERGE, "START");
487 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
489 if ( GL_MERGE_GET_CLASS(merge)->get_key_list != NULL ) {
491 key_list = GL_MERGE_GET_CLASS(merge)->get_key_list (merge);
495 gl_debug (DEBUG_MERGE, "END");
500 /*****************************************************************************/
501 /* Free a list of keys. */
502 /*****************************************************************************/
504 gl_merge_free_key_list (GList **key_list)
508 gl_debug (DEBUG_MERGE, "START");
510 for (p = *key_list; p != NULL; p = p->next) {
515 g_list_free (*key_list);
518 gl_debug (DEBUG_MERGE, "END");
521 /*****************************************************************************/
523 /*****************************************************************************/
525 gl_merge_get_primary_key (glMerge *merge)
529 gl_debug (DEBUG_MERGE, "START");
535 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
537 if ( GL_MERGE_GET_CLASS(merge)->get_primary_key != NULL ) {
539 key = GL_MERGE_GET_CLASS(merge)->get_primary_key (merge);
543 gl_debug (DEBUG_MERGE, "END");
548 /*---------------------------------------------------------------------------*/
549 /* Open merge source. */
550 /*---------------------------------------------------------------------------*/
552 merge_open (glMerge *merge)
554 gl_debug (DEBUG_MERGE, "START");
556 g_return_if_fail (merge && GL_IS_MERGE (merge));
558 if ( GL_MERGE_GET_CLASS(merge)->open != NULL ) {
560 GL_MERGE_GET_CLASS(merge)->open (merge);
564 gl_debug (DEBUG_MERGE, "END");
567 /*---------------------------------------------------------------------------*/
568 /* Close merge source. */
569 /*---------------------------------------------------------------------------*/
571 merge_close (glMerge *merge)
573 gl_debug (DEBUG_MERGE, "START");
575 g_return_if_fail (merge && GL_IS_MERGE (merge));
577 if ( GL_MERGE_GET_CLASS(merge)->close != NULL ) {
579 GL_MERGE_GET_CLASS(merge)->close (merge);
583 gl_debug (DEBUG_MERGE, "END");
586 /*---------------------------------------------------------------------------*/
587 /* Get next record (list of fields) from opened merge source. */
588 /*---------------------------------------------------------------------------*/
589 static glMergeRecord *
590 merge_get_record (glMerge *merge)
592 glMergeRecord *record = NULL;
594 gl_debug (DEBUG_MERGE, "START");
596 g_return_val_if_fail (merge && GL_IS_MERGE (merge), NULL);
598 if ( GL_MERGE_GET_CLASS(merge)->get_record != NULL ) {
600 record = GL_MERGE_GET_CLASS(merge)->get_record (merge);
604 gl_debug (DEBUG_MERGE, "END");
609 /*---------------------------------------------------------------------------*/
610 /* Free a merge record (list of fields) */
611 /*---------------------------------------------------------------------------*/
613 merge_free_record (glMergeRecord **record)
618 gl_debug (DEBUG_MERGE, "START");
620 for (p = (*record)->field_list; p != NULL; p = p->next) {
621 field = (glMergeField *) p->data;
625 g_free (field->value);
632 g_list_free ((*record)->field_list);
633 (*record)->field_list = NULL;
638 gl_debug (DEBUG_MERGE, "END");
641 /*---------------------------------------------------------------------------*/
642 /* Duplicate a merge record (list of fields) */
643 /*---------------------------------------------------------------------------*/
644 static glMergeRecord *
645 merge_dup_record (glMergeRecord *record)
647 glMergeRecord *dest_record;
649 glMergeField *dest_field, *field;
651 gl_debug (DEBUG_MERGE, "START");
653 dest_record = g_new0 (glMergeRecord, 1);
654 dest_record->select_flag = record->select_flag;
656 for (p = record->field_list; p != NULL; p = p->next) {
657 field = (glMergeField *) p->data;
659 dest_field = g_new0 (glMergeField, 1);
661 dest_field->key = g_strdup (field->key);
662 dest_field->value = g_strdup (field->value);
664 dest_record->field_list =
665 g_list_append (dest_record->field_list, dest_field);
669 gl_debug (DEBUG_MERGE, "END");
674 /*****************************************************************************/
675 /* Find key in given record and evaluate. */
676 /*****************************************************************************/
678 gl_merge_eval_key (glMergeRecord *record,
686 gl_debug (DEBUG_MERGE, "START");
688 if ( (record != NULL) ) {
689 for (p = record->field_list; p != NULL; p = p->next) {
690 field = (glMergeField *) p->data;
692 if (strcmp (key, field->key) == 0) {
693 val = g_strdup (field->value);
699 gl_debug (DEBUG_MERGE, "END");
704 /*****************************************************************************/
705 /* Read all records from merge source. */
706 /*****************************************************************************/
708 gl_merge_get_record_list (glMerge *merge)
710 gl_debug (DEBUG_MERGE, "");
712 if ( merge != NULL ) {
713 return merge->priv->record_list;
719 /*---------------------------------------------------------------------------*/
720 /* Free a list of records. */
721 /*---------------------------------------------------------------------------*/
723 merge_free_record_list (GList **record_list)
726 glMergeRecord *record;
728 gl_debug (DEBUG_MERGE, "START");
730 for (p = *record_list; p != NULL; p = p->next) {
731 record = (glMergeRecord *) p->data;
733 merge_free_record( &record );
737 g_list_free (*record_list);
740 gl_debug (DEBUG_MERGE, "END");
743 /*---------------------------------------------------------------------------*/
744 /* Duplicate a list of records. */
745 /*---------------------------------------------------------------------------*/
747 merge_dup_record_list (GList *record_list)
749 GList *dest_list = NULL, *p;
750 glMergeRecord *dest_record, *record;
752 gl_debug (DEBUG_MERGE, "START");
754 for (p = record_list; p != NULL; p = p->next) {
755 record = (glMergeRecord *) p->data;
757 dest_record = merge_dup_record( record );
758 dest_list = g_list_append (dest_list, dest_record);
762 gl_debug (DEBUG_MERGE, "END");
767 /*****************************************************************************/
768 /* Count selected records. */
769 /*****************************************************************************/
771 gl_merge_get_record_count (glMerge *merge)
774 glMergeRecord *record;
777 gl_debug (DEBUG_MERGE, "START");
780 for ( p=merge->priv->record_list; p!=NULL; p=p->next ) {
781 record = (glMergeRecord *)p->data;
783 if ( record->select_flag ) count ++;
786 gl_debug (DEBUG_MERGE, "END");