Change the return type of psppire_delimited_text_new.
[pspp] / src / ui / gui / psppire-delimited-text.c
index c999f220eb1afb376d1b89578d2b5483403c6637..dd13f1c384edf73a93f83027683a431ee39fe44c 100644 (file)
@@ -35,38 +35,73 @@ enum
     PROP_FIRST_LINE
   };
 
+struct enclosure
+{
+  gunichar opening;
+  gunichar closing;
+};
+
+static const struct enclosure enclosures[3] =
+  {
+    {'(',   ')'},
+    {'"',   '"'},
+    {'\'',  '\''}
+  };
+
 static void
 count_delims (PsppireDelimitedText *tf)
 {
-  if (tf->child)
+  if (tf->child == NULL)
+    return;
+
+  tf->max_delimiters = 0;
+  GtkTreeIter iter;
+  gboolean valid;
+  for (valid = gtk_tree_model_get_iter_first (tf->child, &iter);
+       valid;
+       valid = gtk_tree_model_iter_next (tf->child, &iter))
     {
-      tf->max_delimiters = 0;
-      GtkTreeIter iter;
-      gboolean valid;
-      for (valid = gtk_tree_model_get_iter_first (tf->child, &iter);
-          valid;
-          valid = gtk_tree_model_iter_next (tf->child, &iter))
-       {
-         // FIXME: Box these lines to avoid constant allocation/deallocation
-         gchar *foo = 0;
-         gtk_tree_model_get (tf->child, &iter, 1, &foo, -1);
+      gint enc = -1;
+      // FIXME: Box these lines to avoid constant allocation/deallocation
+      gchar *line = NULL;
+      gtk_tree_model_get (tf->child, &iter, 1, &line, -1);
+      {
+       char *p;
+       gint count = 0;
+       for (p = line; ; p = g_utf8_find_next_char (p, NULL))
          {
-           char *line = foo;
-           gint count = 0;
-           while (*line)
+           const gunichar c = g_utf8_get_char (p);
+           if (c == 0)
+             break;
+           if (enc == -1)
+             {
+               gint i;
+               for (i = 0; i < 3; ++i)
+                 {
+                   if (c == enclosures[i].opening)
+                     {
+                       enc = i;
+                       break;
+                     }
+                 }
+             }
+           else if (c == enclosures[enc].closing)
+             {
+               enc = -1;
+             }
+           if (enc == -1)
              {
                GSList *del;
                for (del = tf->delimiters; del; del = g_slist_next (del))
                  {
-                   if (*line == GPOINTER_TO_INT (del->data))
+                   if (c == GPOINTER_TO_INT (del->data))
                      count++;
                  }
-               line++;
              }
-           tf->max_delimiters = MAX (tf->max_delimiters, count);
          }
-         g_free (foo);
-       }
+       tf->max_delimiters = MAX (tf->max_delimiters, count);
+      }
+      g_free (line);
     }
 }
 
@@ -313,6 +348,18 @@ __iter_nth_child (GtkTreeModel *tree_model,
 }
 
 
+static void
+nullify_char (struct substring cs)
+{
+  int char_len = ss_first_mblen (cs);
+  while (char_len > 0)
+    {
+      cs.string[char_len - 1] = '\0';
+      char_len--;
+    }
+}
+
+
 /* Split row N into it's delimited fields (if it is not already cached)
    and set this row as the current cache. */
 static void
@@ -334,25 +381,47 @@ split_row_into_fields (PsppireDelimitedText *file, gint n)
   struct substring cs = file->const_cache;
   int field = 0;
   file->cache_starts[0] = cs.string;
+  gint enc = -1;
   for (;
        UINT32_MAX != ss_first_mb (cs);
        ss_get_mb (&cs))
     {
-      ucs4_t xx = ss_first_mb (cs);
-      GSList *del;
-      for (del = file->delimiters; del; del = g_slist_next (del))
+      ucs4_t character = ss_first_mb (cs);
+      gboolean char_is_quote = FALSE;
+      if (enc == -1)
        {
-         if (xx == GPOINTER_TO_INT (del->data))
+         gint i;
+         for (i = 0; i < 3; ++i)
            {
-             field++;
-             int char_len = ss_first_mblen (cs);
-             file->cache_starts[field] = cs.string + char_len;
-             while (char_len > 0)
+             if (character == enclosures[i].opening)
                {
-                 cs.string[char_len - 1] = '\0';
-                 char_len--;
+                 enc = i;
+                 char_is_quote = TRUE;
+                 file->cache_starts[field] += ss_first_mblen (cs);
+                 break;
+               }
+           }
+       }
+      else if (character == enclosures[enc].closing)
+       {
+         char_is_quote = TRUE;
+         nullify_char (cs);
+         enc = -1;
+       }
+
+      if (enc == -1 && char_is_quote == FALSE)
+       {
+         GSList *del;
+         for (del = file->delimiters; del; del = g_slist_next (del))
+           {
+             if (character == GPOINTER_TO_INT (del->data))
+               {
+                 field++;
+                 int char_len = ss_first_mblen (cs);
+                 file->cache_starts[field] = cs.string + char_len;
+                 nullify_char (cs);
+                 break;
                }
-             break;
            }
        }
     }
@@ -523,15 +592,13 @@ psppire_delimited_text_init (PsppireDelimitedText *text_file)
 }
 
 
-GtkTreeModel *
+PsppireDelimitedText *
 psppire_delimited_text_new (GtkTreeModel *child)
 {
-  PsppireDelimitedText *retval =
+  return
     g_object_new (PSPPIRE_TYPE_DELIMITED_TEXT,
                  "child", child,
                  NULL);
-
-  return retval;
 }
 
 static void