]> git.sur5r.net Git - glabels/commitdiff
Added get_primary_key method.
authorJim Evins <evins@snaught.com>
Sun, 8 Dec 2002 06:40:09 +0000 (06:40 +0000)
committerJim Evins <evins@snaught.com>
Sun, 8 Dec 2002 06:40:09 +0000 (06:40 +0000)
Rewrote  gl_merge_get_key_list() to use record_list().
Ported improved CSV parser from 0.4.6.

git-svn-id: https://glabels.svn.sourceforge.net/svnroot/glabels/trunk@207 f5e0f49d-192f-0410-a22d-a8d8700d0965

glabels2/src/merge-text.c

index 7259c3fc7832256e9198541afe0b90cb3ffadd8f..1c3c394e61083759fe8cec57c596184596e88eff 100644 (file)
@@ -61,30 +61,31 @@ static guint signals[LAST_SIGNAL] = {0};
 /* Local function prototypes                 */
 /*===========================================*/
 
-static void           gl_merge_text_class_init     (glMergeTextClass *klass);
-static void           gl_merge_text_instance_init  (glMergeText      *object);
-static void           gl_merge_text_finalize       (GObject          *object);
-
-static void           gl_merge_text_set_property   (GObject          *object,
-                                                   guint             param_id,
-                                                   const GValue     *value,
-                                                   GParamSpec       *pspec);
-
-static void           gl_merge_text_get_property   (GObject          *object,
-                                                   guint             param_id,
-                                                   GValue           *value,
-                                                   GParamSpec       *pspec);
-
-static GList         *gl_merge_text_get_key_list   (glMerge          *merge);
-static void           gl_merge_text_open           (glMerge          *merge);
-static void           gl_merge_text_close          (glMerge          *merge);
-static glMergeRecord *gl_merge_text_get_record     (glMerge          *merge);
-static void           gl_merge_text_copy           (glMerge          *dst_merge,
-                                                   glMerge          *src_merge);
-
-static GList         *split_fields                 (gchar            *line,
-                                                   gchar             delim);
-static void           free_fields                  (GList           **fields);
+static void           gl_merge_text_class_init      (glMergeTextClass *klass);
+static void           gl_merge_text_instance_init   (glMergeText      *object);
+static void           gl_merge_text_finalize        (GObject          *object);
+
+static void           gl_merge_text_set_property    (GObject          *object,
+                                                    guint             param_id,
+                                                    const GValue     *value,
+                                                    GParamSpec       *pspec);
+
+static void           gl_merge_text_get_property    (GObject          *object,
+                                                    guint             param_id,
+                                                    GValue           *value,
+                                                    GParamSpec       *pspec);
+
+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           gl_merge_text_close           (glMerge          *merge);
+static glMergeRecord *gl_merge_text_get_record      (glMerge          *merge);
+static void           gl_merge_text_copy            (glMerge          *dst_merge,
+                                                    glMerge          *src_merge);
+
+static GList         *parse_line                    (FILE             *fp,
+                                                    gchar             delim);
+static void           free_fields                   (GList           **fields);
 
 \f
 /*****************************************************************************/
@@ -137,11 +138,12 @@ gl_merge_text_class_init (glMergeTextClass *klass)
 
        object_class->finalize = gl_merge_text_finalize;
 
-       merge_class->get_key_list = gl_merge_text_get_key_list;
-       merge_class->open         = gl_merge_text_open;
-       merge_class->close        = gl_merge_text_close;
-       merge_class->get_record   = gl_merge_text_get_record;
-       merge_class->copy         = gl_merge_text_copy;
+       merge_class->get_key_list    = gl_merge_text_get_key_list;
+       merge_class->get_primary_key = gl_merge_text_get_primary_key;
+       merge_class->open            = gl_merge_text_open;
+       merge_class->close           = gl_merge_text_close;
+       merge_class->get_record      = gl_merge_text_get_record;
+       merge_class->copy            = gl_merge_text_copy;
 
        gl_debug (DEBUG_MERGE, "END");
 }
@@ -230,52 +232,52 @@ gl_merge_text_get_property (GObject     *object,
 static GList *
 gl_merge_text_get_key_list (glMerge *merge)
 {
-       glMergeText *merge_text;
-       gchar       *src;
-       FILE        *fp;
-       gchar        delim;
-       gchar        line[LINE_BUF_LEN];
-       GList       *fields, *p;
-       gint         i_field, n_fields, n_fields_max = 0;
-       GList       *key_list;
+       glMergeText   *merge_text;
+       GList         *record_list, *p_rec;
+       glMergeRecord *record;
+       GList         *p_field;
+       gint           i_field, n_fields, n_fields_max = 0;
+       GList         *key_list;
        
-       /* Fields are simply column numbers. */
-       /* FIXME:  the key_list should probably be cached, and only re-evaluated */
-       /*         if the source has changed. */
+       /* Field keys are simply column numbers. */
 
-       merge_text = GL_MERGE_TEXT (merge);
+       gl_debug (DEBUG_MERGE, "BEGIN");
 
-       src = gl_merge_get_src (merge);
-       delim = merge_text->private->delim;
+       merge_text = GL_MERGE_TEXT (merge);
 
-       fp = fopen (src, "r");
-       if ( fp == NULL ) {
-               return NULL;
-       }
+       record_list = (GList *)gl_merge_get_record_list (merge);
 
-       while ( fgets (line, LINE_BUF_LEN, fp) != NULL ) {
+       for ( p_rec=record_list; p_rec!=NULL; p_rec=p_rec->next ) {
+               record = (glMergeRecord *)p_rec->data;
 
-               if (TRUE /* TODO: skip blank lines or comments */ ) {
-                       g_strchomp (line);
-                       fields = split_fields (line, delim);
-                       n_fields = 0;
-                       for (p=fields; p != NULL; p=p->next) {
-                               n_fields++;
-                       }
-                       free_fields (&fields);
-                       if ( n_fields > n_fields_max ) n_fields = n_fields_max;
+               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; i_field++) {
+       for (i_field=1; i_field <= n_fields_max; i_field++) {
                key_list = g_list_append (key_list, g_strdup_printf ("%d", i_field));
        }
 
+
+       gl_debug (DEBUG_MERGE, "END");
+
        return key_list;
 }
 
+/*--------------------------------------------------------------------------*/
+/* Get "primary" key.                                                       */
+/*--------------------------------------------------------------------------*/
+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");
+}
+
 /*--------------------------------------------------------------------------*/
 /* Open merge source.                                                       */
 /*--------------------------------------------------------------------------*/
@@ -323,8 +325,7 @@ gl_merge_text_get_record (glMerge *merge)
        glMergeText   *merge_text;
        gchar          delim;
        FILE          *fp;
-       gchar          line[LINE_BUF_LEN];
-       glMergeRecord *record = NULL;
+       glMergeRecord *record;
        GList         *fields, *p;
        gint           i_field;
        glMergeField  *field;
@@ -338,30 +339,25 @@ gl_merge_text_get_record (glMerge *merge)
                return NULL;
        }
               
-       while ( fgets (line, LINE_BUF_LEN, fp) != NULL ) {
-
-               if (TRUE /* TODO: skip blank lines or comments */ ) {
-                       g_strchomp (line);
-                       record = g_new0 (glMergeRecord, 1);
-                       record->select_flag = TRUE;
-                       fields = split_fields (line, delim);
-                       i_field = 1;
-                       for (p=fields; p != NULL; p=p->next) {
-                               
-                               field = g_new0 (glMergeField, 1);
-                               field->key = g_strdup_printf ("%d", i_field++);
-                               field->value = g_strdup (p->data);
-
-                               record->field_list =
-                                       g_list_append (record->field_list, field);
-                       }
-                       free_fields (&fields);
-                       return record;
-               }
+       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) {
 
+               field = g_new0 (glMergeField, 1);
+               field->key = g_strdup_printf ("%d", i_field++);
+               field->value = g_strdup (p->data);
+
+               record->field_list = g_list_append (record->field_list, field);
        }
+       free_fields (&fields);
 
-       return NULL;
+       return record;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -381,49 +377,185 @@ gl_merge_text_copy (glMerge *dst_merge,
 }
 
 /*---------------------------------------------------------------------------*/
-/* PRIVATE.  Split out fields by delimiter while decoding things like "\n".  */
+/* PRIVATE.  Parse line (quoted values may span multiple lines).             */
 /*---------------------------------------------------------------------------*/
-static GList * split_fields ( gchar *line,
-                             gchar delim )
+static GList *
+parse_line (FILE  *fp,
+           gchar  delim )
 {
        GList *list = NULL;
        GString *string;
-       gchar *c;
-       enum { NORMAL, ESCAPED } state;
-
-       g_return_val_if_fail (line != NULL, NULL);
+       gint c;
+       enum { BEGIN, NORMAL, NORMAL_ESCAPED,
+              QUOTED, QUOTED_ESCAPED, QUOTED_QUOTE1,
+              DONE } state;
 
-       state = NORMAL;
+       state = BEGIN;
        string = g_string_new( "" );
-       for ( c=line; *c!=0; c++ ) {
+       while ( state != DONE ) {
+               c=getc (fp);
 
                switch (state) {
 
+               case BEGIN:
+                       switch (c) {
+                       case '\\':
+                               state = NORMAL_ESCAPED;
+                               break;
+                       case '"':
+                               state = QUOTED;
+                               break;
+                       case '\r':
+                               /* Strip CR. */
+                               state = NORMAL;
+                               break;
+                       case '\n':
+                       case EOF:
+                               state = DONE;
+                               break;
+                       default:
+                               if ( c != delim ) {
+                                       string = g_string_append_c (string, c);
+                               } else {
+                                       list = g_list_append (list,
+                                                     g_strdup (string->str));
+                                       string = g_string_assign( string, "" );
+                               }
+                               state = NORMAL;
+                               break;
+                       }
+                       break;
+
                case NORMAL:
-                       if ( *c == '\\' ) {
-                               state = ESCAPED;
-                       } else if ( *c != delim ) {
-                               string = g_string_append_c (string, *c);
-                       } else {
+                       switch (c) {
+                       case '\\':
+                               state = NORMAL_ESCAPED;
+                               break;
+                       case '"':
+                               state = QUOTED;
+                               break;
+                       case '\r':
+                               /* Strip CR. */
+                               break;
+                       case '\n':
+                       case EOF:
                                list = g_list_append (list,
                                                      g_strdup (string->str));
-                               string = g_string_assign( string, "" );
+                               state = DONE;
+                               break;
+                       default:
+                               if ( c != delim ) {
+                                       string = g_string_append_c (string, c);
+                               } else {
+                                       list = g_list_append (list,
+                                                     g_strdup (string->str));
+                                       string = g_string_assign( string, "" );
+                               }
+                               break;
                        }
                        break;
 
-               case ESCAPED:
-                       switch (*c) {
+               case NORMAL_ESCAPED:
+                       switch (c) {
                        case 'n':
                                string = g_string_append_c (string, '\n');
+                               state = NORMAL;
                                break;
                        case 't':
                                string = g_string_append_c (string, '\t');
+                               state = NORMAL;
+                               break;
+                       case '\r':
+                               /* Strip CR, stay ESCAPED. */
+                               break;
+                       case EOF:
+                               state = DONE;
                                break;
                        default:
-                               string = g_string_append_c (string, *c);
+                               string = g_string_append_c (string, c);
+                               state = NORMAL;
+                               break;
+                       }
+                       break;
+
+               case QUOTED:
+                       switch (c) {
+                       case '\\':
+                               state = QUOTED_ESCAPED;
+                               break;
+                       case '"':
+                               state = QUOTED_QUOTE1;
+                               break;
+                       case '\r':
+                               /* Strip CR. */
+                               break;
+                       case EOF:
+                               /* File ended mid way through quoted item */
+                               list = g_list_append (list,
+                                                     g_strdup (string->str));
+                               state = DONE;
+                               break;
+                       default:
+                               string = g_string_append_c (string, c);
+                               break;
+                       }
+                       break;
+
+               case QUOTED_ESCAPED:
+                       switch (c) {
+                       case 'n':
+                               string = g_string_append_c (string, '\n');
+                               state = QUOTED;
+                               break;
+                       case 't':
+                               string = g_string_append_c (string, '\t');
+                               state = QUOTED;
+                               break;
+                       case '\r':
+                               /* Strip CR, stay ESCAPED. */
+                               break;
+                       case EOF:
+                               /* File ended mid way through quoted item */
+                               list = g_list_append (list,
+                                                     g_strdup (string->str));
+                               state = DONE;
+                               break;
+                       default:
+                               string = g_string_append_c (string, c);
+                               state = QUOTED;
+                               break;
+                       }
+                       break;
+
+               case QUOTED_QUOTE1:
+                       switch (c) {
+                       case '"':
+                               /* insert quotes in string, stay quoted. */
+                               string = g_string_append_c (string, c);
+                               state = QUOTED;
+                               break;
+                       case '\r':
+                               /* Strip CR, return to NORMAL. */
+                               state = NORMAL;
+                               break;
+                       case '\n':
+                       case EOF:
+                               /* line or file ended after quoted item */
+                               list = g_list_append (list,
+                                                     g_strdup (string->str));
+                               state = DONE;
+                               break;
+                       default:
+                               if ( c != delim ) {
+                                       string = g_string_append_c (string, c);
+                               } else {
+                                       list = g_list_append (list,
+                                                     g_strdup (string->str));
+                                       string = g_string_assign( string, "" );
+                               }
+                               state = NORMAL;
                                break;
                        }
-                       state = NORMAL;
                        break;
 
                default:
@@ -432,7 +564,6 @@ static GList * split_fields ( gchar *line,
                }
 
        }
-       list = g_list_append( list, g_strdup(string->str) );
        g_string_free( string, TRUE );
 
        return list;