Reform string library.
[pspp-builds.git] / src / data / sys-file-writer.c
index 89a513d03b6539b6bd6dbd1d2fd588a35b314e67..2639c3587aa19011b8d7671990cf2a3806d46ff5 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,23 +330,6 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
   goto error;
 }
 
-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 0;
-      case_idx += v->nv;
-    }
-  return 1;
-}
-
 /* Returns value of X truncated to two least-significant digits. */
 static int
 rerange (int x)
@@ -701,7 +686,7 @@ write_vls_length_table (struct sfm_writer *w,
 
   struct string vls_length_map;
 
-  ds_init (&vls_length_map, 12 * dict_get_var_cnt (dict));
+  ds_init_empty (&vls_length_map);
 
   vls_hdr.rec_type = 7;
   vls_hdr.subtype = 14;
@@ -715,9 +700,9 @@ write_vls_length_table (struct sfm_writer *w,
       if ( v->width <=  MAX_LONG_STRING ) 
        continue;
 
-      ds_printf (&vls_length_map, "%s=%05d", v->short_name, v->width);
-      ds_putc (&vls_length_map, '\0');
-      ds_putc (&vls_length_map, '\t');
+      ds_put_format (&vls_length_map, "%s=%05d", v->short_name, v->width);
+      ds_put_char (&vls_length_map, '\0');
+      ds_put_char (&vls_length_map, '\t');
     }
 
   vls_hdr.n_elem = ds_length (&vls_length_map);
@@ -747,14 +732,14 @@ write_longvar_table (struct sfm_writer *w, const struct dictionary *dict)
   struct string long_name_map;
   size_t i;
 
-  ds_init (&long_name_map, 10 * dict_get_var_cnt (dict));
+  ds_init_empty (&long_name_map);
   for (i = 0; i < dict_get_var_cnt (dict); i++)
     {
       struct variable *v = dict_get_var (dict, i);
       
       if (i)
-        ds_putc (&long_name_map, '\t');
-      ds_printf (&long_name_map, "%s=%s", v->short_name, v->name);
+        ds_put_char (&long_name_map, '\t');
+      ds_put_format (&long_name_map, "%s=%s", v->short_name, v->name);
     }
 
   lv_hdr.rec_type = 7;
@@ -888,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
@@ -916,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)