]> git.sur5r.net Git - glabels/commitdiff
Harvest line 1 of CSVs for field names
authorJim Evins <evins@snaught.com>
Fri, 30 Oct 2009 01:17:13 +0000 (21:17 -0400)
committerJim Evins <evins@snaught.com>
Fri, 30 Oct 2009 01:17:13 +0000 (21:17 -0400)
Added capability to text merge backend to harvest line 1 for field names (keys).

src/merge-init.c
src/merge-text.c
src/merge-text.h

index 9d5756444ec0d5bfd5ce6b37abd737db7c6a7c1a..550acbb322aa456bc55f6b8d5a9dd2450455091e 100644 (file)
@@ -54,36 +54,60 @@ gl_merge_init (void)
 
        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);
 
index 079eb5b9dd9af17e0408817a5bddf78715af1aca..201254afeafc50b66fca52637fdef665a426acda 100644 (file)
 /*===========================================*/
 
 struct _glMergeTextPrivate {
+
        gchar             delim;
+        gboolean          line1_has_keys;
+
        FILE             *fp;
+
+        GPtrArray        *keys;
+        gint              n_fields_max;
 };
 
 enum {
@@ -45,6 +51,7 @@ enum {
 enum {
        ARG_0,
        ARG_DELIM,
+       ARG_LINE1_HAS_KEYS,
 };
 
 
@@ -69,6 +76,10 @@ static void           gl_merge_text_get_property    (GObject          *object,
                                                     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);
@@ -83,6 +94,7 @@ static gchar         *parse_field                   (gchar            *raw_field
 static void           free_fields                   (GList           **fields);
 
 
+
 /*****************************************************************************/
 /* Boilerplate object stuff.                                                 */
 /*****************************************************************************/
@@ -109,6 +121,13 @@ gl_merge_text_class_init (glMergeTextClass *class)
                                    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;
@@ -129,6 +148,8 @@ gl_merge_text_init (glMergeText *merge_text)
 
        merge_text->priv = g_new0 (glMergeTextPrivate, 1);
 
+        merge_text->priv->keys = g_ptr_array_new ();
+
        gl_debug (DEBUG_MERGE, "END");
 }
 
@@ -137,11 +158,14 @@ static void
 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);
@@ -171,6 +195,12 @@ gl_merge_text_set_property (GObject      *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;
@@ -199,6 +229,10 @@ gl_merge_text_get_property (GObject     *object,
                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;
@@ -208,6 +242,41 @@ gl_merge_text_get_property (GObject     *object,
 }
 
 
+/*---------------------------------------------------------------------------*/
+/* 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.                                                            */
 /*--------------------------------------------------------------------------*/
@@ -218,32 +287,27 @@ gl_merge_text_get_key_list (glMerge *merge)
        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");
 
@@ -258,7 +322,7 @@ static gchar *
 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);
 }
 
 
@@ -271,15 +335,38 @@ gl_merge_text_open (glMerge *merge)
        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);
+
 }
 
 
@@ -321,10 +408,6 @@ gl_merge_text_get_record (glMerge *merge)
        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;
@@ -332,11 +415,10 @@ gl_merge_text_get_record (glMerge *merge)
 
        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
@@ -347,6 +429,11 @@ gl_merge_text_get_record (glMerge *merge)
        }
        free_fields (&fields);
 
+        if ( i_field > merge_text->priv->n_fields_max )
+        {
+                merge_text->priv->n_fields_max = i_field;
+        }
+
        return record;
 }
 
@@ -360,11 +447,19 @@ gl_merge_text_copy (glMerge *dst_merge,
 {
        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)));
+        }
 }
 
 
@@ -398,6 +493,10 @@ parse_line (FILE  *fp,
        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 ) {
index 9a1abbb7271f0933e4b2406e1374193e908918c0..e4180f1ff8fd774695a151a6efa65958247c3d4c 100644 (file)
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
  * name               type             description
  * ---------------------------------------------------------------------------
  * delim              gchar            Field delimiter.
+ * line1_has_keys     gboolean         Do we harvest key names from line 1?
  *
  */