Reworked very long string support for better encapsulation.
[pspp-builds.git] / src / data / sys-file-writer.c
index fe2c27c8102c71f23852d9d9ada4abd44b78f2b4..b4d4ff29b99cc9b8d8a8728f7510f78ba8159b62 100644 (file)
@@ -42,6 +42,7 @@
 #include "value-labels.h"
 #include "variable.h"
 #include <libpspp/version.h>
+#include <minmax.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -61,6 +62,7 @@ struct sfm_writer
     int compress;              /* 1=compressed, 0=not compressed. */
     int case_cnt;              /* Number of cases written so far. */
     size_t flt64_cnt;           /* Number of flt64 elements in case. */
+    bool has_vls;               /* Does the dict have very long strings? */
 
     /* Compression buffering. */
     flt64 *buf;                        /* Buffered data. */
@@ -103,7 +105,6 @@ static void write_variable_display_parameters (struct sfm_writer *w,
                                                const struct dictionary *dict);
 
 static void write_documents (struct sfm_writer *, const struct dictionary *);
-static int does_dict_need_translation (const struct dictionary *);
 
 static inline int
 var_flt64_cnt (const struct variable *v) 
@@ -194,10 +195,11 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
   w->fh = fh;
   w->file = fdopen (fd, "w");
 
-  w->needs_translation = does_dict_need_translation (d);
+  w->needs_translation = dict_compacting_would_change (d);
   w->compress = opts.compress;
   w->case_cnt = 0;
   w->flt64_cnt = 0;
+  w->has_vls = false;
 
   w->buf = w->end = w->ptr = NULL;
   w->x = w->y = NULL;
@@ -212,8 +214,8 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
       sv->width = dv->width;
       /* spss compatibility nonsense */
       if ( dv->width > MAX_LONG_STRING ) 
-       sv->width = (dv->width / MAX_LONG_STRING) * (MAX_LONG_STRING + 1)
-         + (dv->width % MAX_LONG_STRING) ;
+         w->has_vls = true;
+
       sv->fv = dv->fv;
       sv->flt64_cnt = var_flt64_cnt (dv);
     }
@@ -328,27 +330,6 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
   goto error;
 }
 
-/* Returns zero if dictionary D's cases are ordered in the
-   natural manner, with the first variable followed by the
-   second, and so on,
-   nonzero otherwise. */
-static int
-does_dict_need_translation (const struct dictionary *d)
-{
-  size_t case_idx;
-  size_t i;
-
-  case_idx = 0;
-  for (i = 0; i < dict_get_var_cnt (d); i++) 
-    {
-      struct variable *v = dict_get_var (d, i);
-      if (v->fv != case_idx)
-        return 1;
-      case_idx += v->nv;
-    }
-  return 0;
-}
-
 /* Returns value of X truncated to two least-significant digits. */
 static int
 rerange (int x)
@@ -892,7 +873,7 @@ sfm_write_case (struct sfm_writer *w, const struct ccase *c)
   w->case_cnt++;
 
   if (!w->needs_translation && !w->compress
-      && sizeof (flt64) == sizeof (union value)
+      && sizeof (flt64) == sizeof (union value) && ! w->has_vls )
     {
       /* Fast path: external and internal representations are the
          same and the dictionary is properly ordered.  Write
@@ -920,14 +901,23 @@ sfm_write_case (struct sfm_writer *w, const struct ccase *c)
          memset(bounce_cur, ' ', v->flt64_cnt * sizeof (flt64));
 
           if (v->width == 0) 
-            *bounce_cur = case_num (c, v->fv);
-          else 
            {
-             buf_copy_rpad((char*)bounce_cur, v->flt64_cnt * sizeof (flt64),
-                           case_data(c, v->fv)->s, 
-                           v->width);
+             *bounce_cur = case_num (c, v->fv);
+             bounce_cur += v->flt64_cnt;
+           }
+          else 
+           { int ofs = 0;
+           while (ofs < v->width)
+             {
+               int chunk = MIN (MAX_LONG_STRING, v->width - ofs);
+               int nv = DIV_RND_UP (chunk, sizeof (flt64));
+               buf_copy_rpad ((char *) bounce_cur, nv * sizeof (flt64),
+                              case_data (c, v->fv)->s + ofs, chunk);
+               bounce_cur += nv;
+               ofs += chunk;
+             }
            }
-          bounce_cur += v->flt64_cnt;
+
         }
 
       if (!w->compress)