gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
"Text/Comma",
- _("Text file with comma delimeters (CSV)"),
+ _("Text: Comma Separated Values (CSV)"),
GL_MERGE_SRC_IS_FILE,
"delim", ',',
NULL);
gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
- "Text/Colon",
- _("Text file with colon delimeters"),
+ "Text/Comma/Line1Keys",
+ _("Text: Comma Separated Values (CSV) with keys on line 1"),
GL_MERGE_SRC_IS_FILE,
- "delim", ':',
+ "delim", ',',
+ "line1_has_keys", TRUE,
NULL);
gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
"Text/Tab",
- _("Text file with tab delimeters"),
+ _("Text: Tab Separated Values (TSV)"),
+ GL_MERGE_SRC_IS_FILE,
+ "delim", '\t',
+ NULL);
+
+ gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
+ "Text/Tab/Line1Keys",
+ _("Text: Tab Separated Values (TSV) with keys on line 1"),
GL_MERGE_SRC_IS_FILE,
"delim", '\t',
+ "line1_has_keys", TRUE,
+ NULL);
+
+ gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
+ "Text/Colon",
+ _("Text: Colon separated values"),
+ GL_MERGE_SRC_IS_FILE,
+ "delim", ':',
+ NULL);
+
+ gl_merge_register_backend (GL_TYPE_MERGE_TEXT,
+ "Text/Colon/Line1Keys",
+ _("Text: Colon separated values with keys on line 1"),
+ GL_MERGE_SRC_IS_FILE,
+ "delim", ':',
+ "line1_has_keys", TRUE,
NULL);
#ifdef HAVE_LIBEBOOK
gl_merge_register_backend (GL_TYPE_MERGE_EVOLUTION,
"ebook/eds",
- _("Data from default Evolution Addressbook"),
+ _("Evolution Addressbook"),
GL_MERGE_SRC_IS_FIXED,
NULL);
gl_merge_register_backend (GL_TYPE_MERGE_VCARD,
"ebook/vcard",
- _("Data from a file containing VCards"),
+ _("VCards"),
GL_MERGE_SRC_IS_FILE,
NULL);
/*===========================================*/
struct _glMergeTextPrivate {
+
gchar delim;
+ gboolean line1_has_keys;
+
FILE *fp;
+
+ GPtrArray *keys;
+ gint n_fields_max;
};
enum {
enum {
ARG_0,
ARG_DELIM,
+ ARG_LINE1_HAS_KEYS,
};
GValue *value,
GParamSpec *pspec);
+static gchar *key_from_index (glMergeText *merge_text,
+ gint i_field);
+static void clear_keys (glMergeText *merge_text);
+
static GList *gl_merge_text_get_key_list (glMerge *merge);
static gchar *gl_merge_text_get_primary_key (glMerge *merge);
static void gl_merge_text_open (glMerge *merge);
static void free_fields (GList **fields);
+
/*****************************************************************************/
/* Boilerplate object stuff. */
/*****************************************************************************/
0, 0x7F, ',',
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (object_class,
+ ARG_LINE1_HAS_KEYS,
+ g_param_spec_boolean ("line1_has_keys", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
object_class->finalize = gl_merge_text_finalize;
merge_class->get_key_list = gl_merge_text_get_key_list;
merge_text->priv = g_new0 (glMergeTextPrivate, 1);
+ merge_text->priv->keys = g_ptr_array_new ();
+
gl_debug (DEBUG_MERGE, "END");
}
gl_merge_text_finalize (GObject *object)
{
glMergeText *merge_text = GL_MERGE_TEXT (object);
+ gint i;
gl_debug (DEBUG_MERGE, "START");
g_return_if_fail (object && GL_IS_MERGE_TEXT (object));
+ clear_keys (merge_text);
+ g_ptr_array_free (merge_text->priv->keys, TRUE);
g_free (merge_text->priv);
G_OBJECT_CLASS (gl_merge_text_parent_class)->finalize (object);
merge_text->priv->delim);
break;
+ case ARG_LINE1_HAS_KEYS:
+ merge_text->priv->line1_has_keys = g_value_get_boolean (value);
+ gl_debug (DEBUG_MERGE, "ARG \"line1_has_keys\" = \"%d\"",
+ merge_text->priv->line1_has_keys);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
g_value_set_char (value, merge_text->priv->delim);
break;
+ case ARG_LINE1_HAS_KEYS:
+ g_value_set_boolean (value, merge_text->priv->line1_has_keys);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
+/*---------------------------------------------------------------------------*/
+/* Lookup key name from zero based index. */
+/*---------------------------------------------------------------------------*/
+static gchar *
+key_from_index (glMergeText *merge_text,
+ gint i_field)
+{
+ if ( merge_text->priv->line1_has_keys &&
+ (i_field < merge_text->priv->keys->len) )
+ {
+ return g_strdup (g_ptr_array_index (merge_text->priv->keys, i_field));
+ }
+ else
+ {
+ return g_strdup_printf ("%d", i_field+1);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Clear stored keys. */
+/*---------------------------------------------------------------------------*/
+static void
+clear_keys (glMergeText *merge_text)
+{
+ gint i;
+
+ for ( i = 0; i < merge_text->priv->keys->len; i++ )
+ {
+ g_free (g_ptr_array_index (merge_text->priv->keys, i));
+ }
+ merge_text->priv->keys->len = 0;
+}
+
+
/*--------------------------------------------------------------------------*/
/* Get key list. */
/*--------------------------------------------------------------------------*/
GList *record_list, *p_rec;
glMergeRecord *record;
GList *p_field;
- gint i_field, n_fields, n_fields_max = 0;
+ gint i_field, n_fields_line, n_fields;
GList *key_list;
- /* Field keys are simply column numbers. */
-
gl_debug (DEBUG_MERGE, "BEGIN");
merge_text = GL_MERGE_TEXT (merge);
- record_list = (GList *)gl_merge_get_record_list (merge);
-
- for ( p_rec=record_list; p_rec!=NULL; p_rec=p_rec->next ) {
- record = (glMergeRecord *)p_rec->data;
-
- n_fields = 0;
- for ( p_field=record->field_list; p_field!=NULL; p_field=p_field->next ) {
- n_fields++;
- }
- if ( n_fields > n_fields_max ) n_fields_max = n_fields;
- }
-
- key_list = NULL;
- for (i_field=1; i_field <= n_fields_max; i_field++) {
- key_list = g_list_append (key_list, g_strdup_printf ("%d", i_field));
- }
+ if ( merge_text->priv->line1_has_keys )
+ {
+ n_fields = merge_text->priv->keys->len;
+ }
+ else
+ {
+ n_fields = merge_text->priv->n_fields_max;
+ }
+ key_list = NULL;
+ for ( i_field=0; i_field < n_fields; i_field++ )
+ {
+ key_list = g_list_append (key_list, key_from_index(merge_text, i_field));
+ }
gl_debug (DEBUG_MERGE, "END");
gl_merge_text_get_primary_key (glMerge *merge)
{
/* For now, let's always assume the first column is the primary key. */
- return g_strdup ("1");
+ return key_from_index (GL_MERGE_TEXT (merge), 0);
}
glMergeText *merge_text;
gchar *src;
+ GList *line1_fields;
+ GList *p;
+
merge_text = GL_MERGE_TEXT (merge);
src = gl_merge_get_src (merge);
- if (src != NULL) {
+ if (src != NULL)
+ {
merge_text->priv->fp = fopen (src, "r");
+ g_free (src);
+
+ clear_keys (merge_text);
+ merge_text->priv->n_fields_max = 0;
+
+ if ( merge_text->priv->line1_has_keys )
+ {
+ /*
+ * Extract keys from first line and discard line
+ */
+
+ line1_fields = parse_line (merge_text->priv->fp, merge_text->priv->delim);
+ for ( p = line1_fields; p != NULL; p = p->next )
+ {
+ g_ptr_array_add (merge_text->priv->keys, g_strdup (p->data));
+ }
+ free_fields (&line1_fields);
+ }
+
}
- g_free (src);
+
}
delim = merge_text->priv->delim;
fp = merge_text->priv->fp;
- if (fp == NULL) {
- return NULL;
- }
-
fields = parse_line (fp, delim);
if ( fields == NULL ) {
return NULL;
record = g_new0 (glMergeRecord, 1);
record->select_flag = TRUE;
- i_field = 1;
- for (p=fields; p != NULL; p=p->next) {
+ for (p=fields, i_field=0; p != NULL; p=p->next, i_field++) {
field = g_new0 (glMergeField, 1);
- field->key = g_strdup_printf ("%d", i_field++);
+ field->key = key_from_index (merge_text, i_field);
#ifndef CSV_ALWAYS_UTF8
field->value = g_locale_to_utf8 (p->data, -1, NULL, NULL, NULL);
#else
}
free_fields (&fields);
+ if ( i_field > merge_text->priv->n_fields_max )
+ {
+ merge_text->priv->n_fields_max = i_field;
+ }
+
return record;
}
{
glMergeText *dst_merge_text;
glMergeText *src_merge_text;
+ gint i;
dst_merge_text = GL_MERGE_TEXT (dst_merge);
src_merge_text = GL_MERGE_TEXT (src_merge);
- dst_merge_text->priv->delim = src_merge_text->priv->delim;
+ dst_merge_text->priv->delim = src_merge_text->priv->delim;
+ dst_merge_text->priv->line1_has_keys = src_merge_text->priv->line1_has_keys;
+
+ for ( i=0; i < src_merge_text->priv->keys->len; i++ )
+ {
+ g_ptr_array_add (dst_merge_text->priv->keys,
+ g_strdup ((gchar *)g_ptr_array_index (src_merge_text->priv->keys, i)));
+ }
}
enum { BEGIN, NORMAL, QUOTED, QUOTED_QUOTE1,
NORMAL_ESCAPED, QUOTED_ESCAPED, DONE } state;
+ if (fp == NULL) {
+ return NULL;
+ }
+
state = BEGIN;
string = g_string_new( "" );
while ( state != DONE ) {