2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * merge_text.c: text-file merge backend module
6 * Copyright (C) 2001 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
27 #include "merge-text.h"
31 #define LINE_BUF_LEN 1024
33 /*===========================================*/
35 /*===========================================*/
37 struct _glMergeTextPrivate {
51 /*===========================================*/
53 /*===========================================*/
55 static glMergeClass *parent_class = NULL;
57 static guint signals[LAST_SIGNAL] = {0};
60 /*===========================================*/
61 /* Local function prototypes */
62 /*===========================================*/
64 static void gl_merge_text_class_init (glMergeTextClass *klass);
65 static void gl_merge_text_instance_init (glMergeText *object);
66 static void gl_merge_text_finalize (GObject *object);
68 static void gl_merge_text_set_property (GObject *object,
73 static void gl_merge_text_get_property (GObject *object,
78 static GList *gl_merge_text_get_key_list (glMerge *merge);
79 static void gl_merge_text_open (glMerge *merge);
80 static void gl_merge_text_close (glMerge *merge);
81 static glMergeRecord *gl_merge_text_get_record (glMerge *merge);
82 static void gl_merge_text_copy (glMerge *dst_merge,
85 static GList *split_fields (gchar *line,
87 static void free_fields (GList **fields);
90 /*****************************************************************************/
91 /* Boilerplate object stuff. */
92 /*****************************************************************************/
94 gl_merge_text_get_type (void)
96 static GType type = 0;
100 sizeof (glMergeTextClass),
103 (GClassInitFunc) gl_merge_text_class_init,
106 sizeof (glMergeText),
108 (GInstanceInitFunc) gl_merge_text_instance_init,
111 type = g_type_register_static (GL_TYPE_MERGE,
112 "glMergeText", &info, 0);
119 gl_merge_text_class_init (glMergeTextClass *klass)
121 GObjectClass *object_class = (GObjectClass *) klass;
122 glMergeClass *merge_class = (glMergeClass *) klass;
124 gl_debug (DEBUG_MERGE, "START");
126 parent_class = g_type_class_peek_parent (klass);
128 object_class->set_property = gl_merge_text_set_property;
129 object_class->get_property = gl_merge_text_get_property;
131 g_object_class_install_property
134 g_param_spec_char ("delim", NULL, NULL,
136 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
138 object_class->finalize = gl_merge_text_finalize;
140 merge_class->get_key_list = gl_merge_text_get_key_list;
141 merge_class->open = gl_merge_text_open;
142 merge_class->close = gl_merge_text_close;
143 merge_class->get_record = gl_merge_text_get_record;
144 merge_class->copy = gl_merge_text_copy;
146 gl_debug (DEBUG_MERGE, "END");
150 gl_merge_text_instance_init (glMergeText *merge_text)
152 gl_debug (DEBUG_MERGE, "START");
154 merge_text->private = g_new0 (glMergeTextPrivate, 1);
156 gl_debug (DEBUG_MERGE, "END");
160 gl_merge_text_finalize (GObject *object)
162 gl_debug (DEBUG_MERGE, "START");
164 g_return_if_fail (object && GL_IS_MERGE_TEXT (object));
166 G_OBJECT_CLASS (parent_class)->finalize (object);
168 gl_debug (DEBUG_MERGE, "END");
171 /*--------------------------------------------------------------------------*/
173 /*--------------------------------------------------------------------------*/
175 gl_merge_text_set_property (GObject *object,
180 glMergeText *merge_text;
182 merge_text = GL_MERGE_TEXT (object);
187 merge_text->private->delim = g_value_get_char (value);
188 gl_debug (DEBUG_MERGE, "ARG \"delim\" = \"%c\"",
189 merge_text->private->delim);
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
200 /*--------------------------------------------------------------------------*/
202 /*--------------------------------------------------------------------------*/
204 gl_merge_text_get_property (GObject *object,
209 glMergeText *merge_text;
211 merge_text = GL_MERGE_TEXT (object);
216 g_value_set_char (value, merge_text->private->delim);
220 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
227 /*--------------------------------------------------------------------------*/
229 /*--------------------------------------------------------------------------*/
231 gl_merge_text_get_key_list (glMerge *merge)
233 glMergeText *merge_text;
237 gchar line[LINE_BUF_LEN];
239 gint i_field, n_fields, n_fields_max = 0;
242 /* Fields are simply column numbers. */
243 /* FIXME: the key_list should probably be cached, and only re-evaluated */
244 /* if the source has changed. */
246 merge_text = GL_MERGE_TEXT (merge);
248 src = gl_merge_get_src (merge);
249 delim = merge_text->private->delim;
251 fp = fopen (src, "r");
256 while ( fgets (line, LINE_BUF_LEN, fp) != NULL ) {
258 if (TRUE /* TODO: skip blank lines or comments */ ) {
260 fields = split_fields (line, delim);
262 for (p=fields; p != NULL; p=p->next) {
265 free_fields (&fields);
266 if ( n_fields > n_fields_max ) n_fields = n_fields_max;
272 for (i_field=1; i_field <= n_fields; i_field++) {
273 key_list = g_list_append (key_list, g_strdup_printf ("%d", i_field));
279 /*--------------------------------------------------------------------------*/
280 /* Open merge source. */
281 /*--------------------------------------------------------------------------*/
283 gl_merge_text_open (glMerge *merge)
285 glMergeText *merge_text;
288 merge_text = GL_MERGE_TEXT (merge);
290 src = gl_merge_get_src (merge);
293 merge_text->private->fp = fopen (src, "r");
299 /*--------------------------------------------------------------------------*/
300 /* Close merge source. */
301 /*--------------------------------------------------------------------------*/
303 gl_merge_text_close (glMerge *merge)
305 glMergeText *merge_text;
307 merge_text = GL_MERGE_TEXT (merge);
309 if (merge_text->private->fp != NULL) {
311 fclose (merge_text->private->fp);
312 merge_text->private->fp = NULL;
317 /*--------------------------------------------------------------------------*/
318 /* Get next record from merge source, NULL if no records left (i.e EOF) */
319 /*--------------------------------------------------------------------------*/
320 static glMergeRecord *
321 gl_merge_text_get_record (glMerge *merge)
323 glMergeText *merge_text;
326 gchar line[LINE_BUF_LEN];
327 glMergeRecord *record = NULL;
332 merge_text = GL_MERGE_TEXT (merge);
334 delim = merge_text->private->delim;
335 fp = merge_text->private->fp;
341 while ( fgets (line, LINE_BUF_LEN, fp) != NULL ) {
343 if (TRUE /* TODO: skip blank lines or comments */ ) {
345 record = g_new0 (glMergeRecord, 1);
346 record->select_flag = TRUE;
347 fields = split_fields (line, delim);
349 for (p=fields; p != NULL; p=p->next) {
351 field = g_new0 (glMergeField, 1);
352 field->key = g_strdup_printf ("%d", i_field++);
353 field->value = g_strdup (p->data);
356 g_list_append (record->field_list, field);
358 free_fields (&fields);
367 /*---------------------------------------------------------------------------*/
368 /* Copy merge_text specific fields. */
369 /*---------------------------------------------------------------------------*/
371 gl_merge_text_copy (glMerge *dst_merge,
374 glMergeText *dst_merge_text;
375 glMergeText *src_merge_text;
377 dst_merge_text = GL_MERGE_TEXT (dst_merge);
378 src_merge_text = GL_MERGE_TEXT (src_merge);
380 dst_merge_text->private->delim = src_merge_text->private->delim;
383 /*---------------------------------------------------------------------------*/
384 /* PRIVATE. Split out fields by delimiter while decoding things like "\n". */
385 /*---------------------------------------------------------------------------*/
386 static GList * split_fields ( gchar *line,
392 enum { NORMAL, ESCAPED } state;
394 g_return_val_if_fail (line != NULL, NULL);
397 string = g_string_new( "" );
398 for ( c=line; *c!=0; c++ ) {
405 } else if ( *c != delim ) {
406 string = g_string_append_c (string, *c);
408 list = g_list_append (list,
409 g_strdup (string->str));
410 string = g_string_assign( string, "" );
417 string = g_string_append_c (string, '\n');
420 string = g_string_append_c (string, '\t');
423 string = g_string_append_c (string, *c);
430 g_assert_not_reached();
435 list = g_list_append( list, g_strdup(string->str) );
436 g_string_free( string, TRUE );
441 /*---------------------------------------------------------------------------*/
442 /* Free list of fields. */
443 /*---------------------------------------------------------------------------*/
445 free_fields (GList ** list)
449 for (p = *list; p != NULL; p = p->next) {