2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * merge.c: document merge module
6 * Copyright (C) 2001-2002 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <glib/gi18n.h>
27 #include <gobject/gvaluecollector.h>
32 /*========================================================*/
34 /*========================================================*/
36 struct _glMergePrivate {
40 glMergeSrcType src_type;
54 glMergeSrcType src_type;
61 /*========================================================*/
62 /* Private globals. */
63 /*========================================================*/
65 static GObjectClass *parent_class = NULL;
67 static GList *backends = NULL;
69 /*========================================================*/
70 /* Private function prototypes. */
71 /*========================================================*/
73 static void gl_merge_class_init (glMergeClass *klass);
74 static void gl_merge_instance_init (glMerge *object);
75 static void gl_merge_finalize (GObject *object);
77 static void merge_open (glMerge *merge);
79 static void merge_close (glMerge *merge);
81 static glMergeRecord *merge_get_record (glMerge *merge);
83 static void merge_free_record (glMergeRecord **record);
85 static glMergeRecord *merge_dup_record (glMergeRecord *record);
87 static void merge_free_record_list (GList **record_list);
89 static GList *merge_dup_record_list (GList *record_list);
94 /*****************************************************************************/
95 /* Register a new merge backend. */
96 /*****************************************************************************/
98 gl_merge_register_backend (GType type,
101 glMergeSrcType src_type,
102 const gchar *first_arg_name,
111 guint n_params = 0, n_alloced_params = 16;
113 backend = g_new0 (Backend, 1);
115 backend->type = type;
116 backend->name = g_strdup (name);
117 backend->description = g_strdup (description);
118 backend->src_type = src_type;
120 params = g_new (GParameter, n_alloced_params);
121 va_start (args, first_arg_name);
122 for ( pname=first_arg_name; pname != NULL; pname=va_arg (args,gchar *) ) {
125 class = g_type_class_ref (type);
127 g_message ("%s: unknown object type %d",
131 pspec = g_object_class_find_property (class, pname);
133 g_message ("%s: object class `%s' has no property named `%s'",
134 G_STRLOC, g_type_name (type), pname);
137 if (n_params >= n_alloced_params) {
138 n_alloced_params += 16;
139 params = g_renew (GParameter, params, n_alloced_params);
141 params[n_params].name = pname;
142 params[n_params].value.g_type = 0;
143 g_value_init (¶ms[n_params].value, pspec->value_type);
144 G_VALUE_COLLECT (¶ms[n_params].value, args, 0, &error);
146 g_message ("%s: %s", G_STRLOC, error);
155 backend->n_params = n_params;
156 backend->params = params;
158 backends = g_list_append (backends, backend);
162 /*****************************************************************************/
163 /* Get list of registered backend descriptions. */
164 /*****************************************************************************/
166 gl_merge_get_descriptions (void)
168 GList *descriptions = NULL;
172 descriptions = g_list_append (descriptions, g_strdup(_("None")));
174 for ( p=backends; p!=NULL; p=p->next) {
175 backend = (Backend *)p->data;
176 descriptions = g_list_append (descriptions,
177 g_strdup(backend->description));
183 /*****************************************************************************/
184 /* Free list of descriptions. */
185 /*****************************************************************************/
187 gl_merge_free_descriptions (GList **descriptions)
191 gl_debug (DEBUG_MERGE, "START");
193 for (p = *descriptions; p != NULL; p = p->next) {
198 g_list_free (*descriptions);
199 *descriptions = NULL;
201 gl_debug (DEBUG_MERGE, "END");
204 /*****************************************************************************/
205 /* Lookup name of backend from description. */
206 /*****************************************************************************/
208 gl_merge_description_to_name (gchar *description)
213 if (g_strcasecmp(description, _("None")) == 0) {
214 return g_strdup("None");
217 for ( p=backends; p!=NULL; p=p->next) {
218 backend = (Backend *)p->data;
219 if (g_strcasecmp(description, backend->description) == 0) {
220 return g_strdup(backend->name);
224 return g_strdup("None");
227 /*****************************************************************************/
228 /* Boilerplate object stuff. */
229 /*****************************************************************************/
231 gl_merge_get_type (void)
233 static GType type = 0;
236 static const GTypeInfo info = {
237 sizeof (glMergeClass),
240 (GClassInitFunc) gl_merge_class_init,
245 (GInstanceInitFunc) gl_merge_instance_init,
249 type = g_type_register_static (G_TYPE_OBJECT,
250 "glMerge", &info, 0);
257 gl_merge_class_init (glMergeClass *klass)
259 GObjectClass *object_class = (GObjectClass *) klass;
261 gl_debug (DEBUG_MERGE, "START");
263 parent_class = g_type_class_peek_parent (klass);
265 object_class->finalize = gl_merge_finalize;
267 gl_debug (DEBUG_MERGE, "END");
271 gl_merge_instance_init (glMerge *merge)
273 gl_debug (DEBUG_MERGE, "START");
275 merge->private = g_new0 (glMergePrivate, 1);
277 gl_debug (DEBUG_MERGE, "END");
281 gl_merge_finalize (GObject *object)
283 gl_debug (DEBUG_MERGE, "START");
285 g_return_if_fail (object && GL_IS_MERGE (object));
287 merge_free_record_list (&GL_MERGE(object)->private->record_list);
288 g_free (GL_MERGE(object)->private->name);
289 g_free (GL_MERGE(object)->private->description);
290 g_free (GL_MERGE(object)->private->src);
291 g_free (GL_MERGE(object)->private);
293 G_OBJECT_CLASS (parent_class)->finalize (object);
295 gl_debug (DEBUG_MERGE, "END");
298 /*****************************************************************************/
299 /* New merge object. */
300 /*****************************************************************************/
302 gl_merge_new (gchar *name)
304 glMerge *merge = NULL;
308 gl_debug (DEBUG_MERGE, "START");
310 for (p=backends; p!=NULL; p=p->next) {
311 backend = (Backend *)p->data;
313 if (g_strcasecmp(name, backend->name) == 0) {
315 merge = GL_MERGE (g_object_newv (backend->type,
319 merge->private->name = g_strdup (name);
320 merge->private->description = g_strdup (backend->description);
321 merge->private->src_type = backend->src_type;
327 if ( (merge == NULL) && (g_strcasecmp (name, "None") != 0)) {
328 g_message ("Unknown merge backend \"%s\"", name);
331 gl_debug (DEBUG_MERGE, "END");
336 /*****************************************************************************/
337 /* Duplicate merge. */
338 /*****************************************************************************/
340 gl_merge_dup (glMerge *src_merge)
344 gl_debug (DEBUG_MERGE, "START");
346 if (src_merge == NULL) {
347 gl_debug (DEBUG_MERGE, "END (NULL)");
351 g_return_val_if_fail (GL_IS_MERGE (src_merge), NULL);
353 dst_merge = g_object_new (G_OBJECT_TYPE(src_merge), NULL);
354 dst_merge->private->name = g_strdup (src_merge->private->name);
355 dst_merge->private->description = g_strdup (src_merge->private->description);
356 dst_merge->private->src = g_strdup (src_merge->private->src);
357 dst_merge->private->src_type = src_merge->private->src_type;
358 dst_merge->private->record_list
359 = merge_dup_record_list (src_merge->private->record_list);
361 if ( GL_MERGE_GET_CLASS(src_merge)->copy != NULL ) {
363 /* We have an object specific method, use it */
364 GL_MERGE_GET_CLASS(src_merge)->copy (dst_merge, src_merge);
368 gl_debug (DEBUG_MERGE, "END");
373 /*****************************************************************************/
374 /* Get name of merge. */
375 /*****************************************************************************/
377 gl_merge_get_name (glMerge *merge)
379 gl_debug (DEBUG_MERGE, "");
382 return g_strdup("None");
385 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup("None"));
387 return g_strdup(merge->private->name);
390 /*****************************************************************************/
391 /* Get description of merge. */
392 /*****************************************************************************/
394 gl_merge_get_description (glMerge *merge)
396 gl_debug (DEBUG_MERGE, "");
399 return g_strdup(_("None"));
402 g_return_val_if_fail (GL_IS_MERGE (merge), g_strdup(_("None")));
404 return g_strdup(merge->private->description);
407 /*****************************************************************************/
408 /* Get source type of merge. */
409 /*****************************************************************************/
411 gl_merge_get_src_type (glMerge *merge)
413 gl_debug (DEBUG_MERGE, "");
416 return GL_MERGE_SRC_IS_FIXED;
419 g_return_val_if_fail (GL_IS_MERGE (merge), GL_MERGE_SRC_IS_FIXED);
421 return merge->private->src_type;
424 /*****************************************************************************/
425 /* Set src of merge. */
426 /*****************************************************************************/
428 gl_merge_set_src (glMerge *merge,
431 GList *record_list = NULL;
432 glMergeRecord *record;
434 gl_debug (DEBUG_MERGE, "START");
436 g_return_if_fail (merge && GL_IS_MERGE (merge));
440 if ( merge->private->src != NULL ) {
441 g_free (merge->private->src);
443 merge->private->src = NULL;
444 merge_free_record_list (&merge->private->record_list);
448 if ( merge->private->src != NULL ) {
449 g_free(merge->private->src);
451 merge->private->src = g_strdup (src);
453 merge_free_record_list (&merge->private->record_list);
456 while ( (record = merge_get_record (merge)) != NULL ) {
457 record_list = g_list_append( record_list, record );
460 merge->private->record_list = record_list;
465 gl_debug (DEBUG_MERGE, "END");
468 /*****************************************************************************/
469 /* Get src of merge. */
470 /*****************************************************************************/
472 gl_merge_get_src (glMerge *merge)
474 gl_debug (DEBUG_MERGE, "");
480 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
482 return g_strdup(merge->private->src);
485 /*****************************************************************************/
487 /*****************************************************************************/
489 gl_merge_get_key_list (glMerge *merge)
491 GList *key_list = NULL;
493 gl_debug (DEBUG_MERGE, "START");
499 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
501 if ( GL_MERGE_GET_CLASS(merge)->get_key_list != NULL ) {
503 key_list = GL_MERGE_GET_CLASS(merge)->get_key_list (merge);
507 gl_debug (DEBUG_MERGE, "END");
512 /*****************************************************************************/
513 /* Free a list of keys. */
514 /*****************************************************************************/
516 gl_merge_free_key_list (GList **key_list)
520 gl_debug (DEBUG_MERGE, "START");
522 for (p = *key_list; p != NULL; p = p->next) {
527 g_list_free (*key_list);
530 gl_debug (DEBUG_MERGE, "END");
533 /*****************************************************************************/
535 /*****************************************************************************/
537 gl_merge_get_primary_key (glMerge *merge)
541 gl_debug (DEBUG_MERGE, "START");
547 g_return_val_if_fail (GL_IS_MERGE (merge), NULL);
549 if ( GL_MERGE_GET_CLASS(merge)->get_primary_key != NULL ) {
551 key = GL_MERGE_GET_CLASS(merge)->get_primary_key (merge);
555 gl_debug (DEBUG_MERGE, "END");
560 /*---------------------------------------------------------------------------*/
561 /* Open merge source. */
562 /*---------------------------------------------------------------------------*/
564 merge_open (glMerge *merge)
566 gl_debug (DEBUG_MERGE, "START");
568 g_return_if_fail (merge && GL_IS_MERGE (merge));
570 if ( GL_MERGE_GET_CLASS(merge)->open != NULL ) {
572 GL_MERGE_GET_CLASS(merge)->open (merge);
576 gl_debug (DEBUG_MERGE, "END");
579 /*---------------------------------------------------------------------------*/
580 /* Close merge source. */
581 /*---------------------------------------------------------------------------*/
583 merge_close (glMerge *merge)
585 gl_debug (DEBUG_MERGE, "START");
587 g_return_if_fail (merge && GL_IS_MERGE (merge));
589 if ( GL_MERGE_GET_CLASS(merge)->close != NULL ) {
591 GL_MERGE_GET_CLASS(merge)->close (merge);
595 gl_debug (DEBUG_MERGE, "END");
598 /*---------------------------------------------------------------------------*/
599 /* Get next record (list of fields) from opened merge source. */
600 /*---------------------------------------------------------------------------*/
601 static glMergeRecord *
602 merge_get_record (glMerge *merge)
604 glMergeRecord *record = NULL;
606 gl_debug (DEBUG_MERGE, "START");
608 g_return_val_if_fail (merge && GL_IS_MERGE (merge), NULL);
610 if ( GL_MERGE_GET_CLASS(merge)->get_record != NULL ) {
612 record = GL_MERGE_GET_CLASS(merge)->get_record (merge);
616 gl_debug (DEBUG_MERGE, "END");
621 /*---------------------------------------------------------------------------*/
622 /* Free a merge record (list of fields) */
623 /*---------------------------------------------------------------------------*/
625 merge_free_record (glMergeRecord **record)
630 gl_debug (DEBUG_MERGE, "START");
632 for (p = (*record)->field_list; p != NULL; p = p->next) {
633 field = (glMergeField *) p->data;
637 g_free (field->value);
644 g_list_free ((*record)->field_list);
645 (*record)->field_list = NULL;
650 gl_debug (DEBUG_MERGE, "END");
653 /*---------------------------------------------------------------------------*/
654 /* Duplicate a merge record (list of fields) */
655 /*---------------------------------------------------------------------------*/
656 static glMergeRecord *
657 merge_dup_record (glMergeRecord *record)
659 glMergeRecord *dest_record;
661 glMergeField *dest_field, *field;
663 gl_debug (DEBUG_MERGE, "START");
665 dest_record = g_new0 (glMergeRecord, 1);
666 dest_record->select_flag = record->select_flag;
668 for (p = record->field_list; p != NULL; p = p->next) {
669 field = (glMergeField *) p->data;
671 dest_field = g_new0 (glMergeField, 1);
673 dest_field->key = g_strdup (field->key);
674 dest_field->value = g_strdup (field->value);
676 dest_record->field_list =
677 g_list_append (dest_record->field_list, dest_field);
681 gl_debug (DEBUG_MERGE, "END");
686 /*****************************************************************************/
687 /* Find key in given record and evaluate. */
688 /*****************************************************************************/
690 gl_merge_eval_key (glMergeRecord *record,
698 gl_debug (DEBUG_MERGE, "START");
700 if ( (record != NULL) ) {
701 for (p = record->field_list; p != NULL; p = p->next) {
702 field = (glMergeField *) p->data;
704 if (strcmp (key, field->key) == 0) {
705 val = g_strdup (field->value);
711 gl_debug (DEBUG_MERGE, "END");
716 /*****************************************************************************/
717 /* Read all records from merge source. */
718 /*****************************************************************************/
720 gl_merge_get_record_list (glMerge *merge)
722 gl_debug (DEBUG_MERGE, "");
724 if ( merge != NULL ) {
725 return merge->private->record_list;
731 /*---------------------------------------------------------------------------*/
732 /* Free a list of records. */
733 /*---------------------------------------------------------------------------*/
735 merge_free_record_list (GList **record_list)
738 glMergeRecord *record;
740 gl_debug (DEBUG_MERGE, "START");
742 for (p = *record_list; p != NULL; p = p->next) {
743 record = (glMergeRecord *) p->data;
745 merge_free_record( &record );
749 g_list_free (*record_list);
752 gl_debug (DEBUG_MERGE, "END");
755 /*---------------------------------------------------------------------------*/
756 /* Duplicate a list of records. */
757 /*---------------------------------------------------------------------------*/
759 merge_dup_record_list (GList *record_list)
761 GList *dest_list = NULL, *p;
762 glMergeRecord *dest_record, *record;
764 gl_debug (DEBUG_MERGE, "START");
766 for (p = record_list; p != NULL; p = p->next) {
767 record = (glMergeRecord *) p->data;
769 dest_record = merge_dup_record( record );
770 dest_list = g_list_append (dest_list, dest_record);
774 gl_debug (DEBUG_MERGE, "END");
779 /*****************************************************************************/
780 /* Count selected records. */
781 /*****************************************************************************/
783 gl_merge_get_record_count (glMerge *merge)
786 glMergeRecord *record;
789 gl_debug (DEBUG_MERGE, "START");
792 for ( p=merge->private->record_list; p!=NULL; p=p->next ) {
793 record = (glMergeRecord *)p->data;
795 if ( record->select_flag ) count ++;
798 gl_debug (DEBUG_MERGE, "END");