Make PSPP able to read all the portable files I could find on the
[pspp-builds.git] / src / data / por-file-writer.c
index 5f91c7e684b21b56d93cbc02e4a1eae06e3a6a2b..cf4474569531ee723f2fbbb3ecb7a2b1e815b507 100644 (file)
@@ -50,6 +50,9 @@
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+/* Maximum width of a variable in a portable file. */
+#define MAX_POR_WIDTH 255
+
 /* Portable file writer. */
 struct pfm_writer
   {
@@ -80,6 +83,8 @@ static void write_version_data (struct pfm_writer *);
 static void write_variables (struct pfm_writer *, struct dictionary *);
 static void write_value_labels (struct pfm_writer *,
                                 const struct dictionary *);
+static void write_documents (struct pfm_writer *,
+                             const struct dictionary *);
 
 static void format_trig_double (long double, int base_10_precision, char[]);
 static char *format_trig_int (int, bool force_sign, char[]);
@@ -139,7 +144,7 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
     {
       const struct variable *dv = dict_get_var (dict, i);
       struct pfm_var *pv = &w->vars[i];
-      pv->width = var_get_width (dv);
+      pv->width = MIN (var_get_width (dv), MAX_POR_WIDTH);
       pv->fv = var_get_case_index (dv);
     }
 
@@ -156,6 +161,8 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
   write_version_data (w);
   write_variables (w, dict);
   write_value_labels (w, dict);
+  if (dict_get_document_line_cnt (dict) > 0)
+    write_documents (w, dict);
   buf_write (w, "F", 1);
   if (ferror (w->file))
     goto error;
@@ -284,13 +291,17 @@ write_version_data (struct pfm_writer *w)
   write_string (w, host_system);
 }
 
-/* Write format F to file H. */
+/* Write format F to file H.  The format is first resized to fit
+   a value of the given WIDTH, which is handy in case F
+   represents a string longer than 255 bytes and thus WIDTH is
+   truncated to 255 bytes.  */
 static void
-write_format (struct pfm_writer *w, const struct fmt_spec *f)
+write_format (struct pfm_writer *w, struct fmt_spec f, int width)
 {
-  write_int (w, fmt_to_io (f->type));
-  write_int (w, f->w);
-  write_int (w, f->d);
+  fmt_resize (&f, width);
+  write_int (w, fmt_to_io (f.type));
+  write_int (w, f.w);
+  write_int (w, f.d);
 }
 
 /* Write value V for variable VV to file H. */
@@ -301,8 +312,9 @@ write_value (struct pfm_writer *w, union value *v, struct variable *vv)
     write_float (w, v->f);
   else
     {
-      write_int (w, var_get_width (vv));
-      buf_write (w, v->s, var_get_width (vv));
+      int width = MIN (var_get_width (vv), MAX_POR_WIDTH);
+      write_int (w, width);
+      buf_write (w, v->s, width);
     }
 }
 
@@ -314,6 +326,12 @@ write_variables (struct pfm_writer *w, struct dictionary *dict)
 
   short_names_assign (dict);
 
+  if (dict_get_weight (dict) != NULL) 
+    {
+      buf_write (w, "6", 1);
+      write_string (w, var_get_short_name (dict_get_weight (dict), 0));
+    }
+  
   buf_write (w, "4", 1);
   write_int (w, dict_get_var_cnt (dict));
   write_int (w, 161);
@@ -322,12 +340,13 @@ write_variables (struct pfm_writer *w, struct dictionary *dict)
     {
       struct variable *v = dict_get_var (dict, i);
       struct missing_values mv;
+      int width = MIN (var_get_width (v), MAX_POR_WIDTH);
 
       buf_write (w, "7", 1);
-      write_int (w, var_get_width (v));
+      write_int (w, width);
       write_string (w, var_get_short_name (v, 0));
-      write_format (w, var_get_print_format (v));
-      write_format (w, var_get_write_format (v));
+      write_format (w, *var_get_print_format (v), width);
+      write_format (w, *var_get_write_format (v), width);
 
       /* Write missing values. */
       mv_copy (&mv, var_get_missing_values (v));
@@ -399,7 +418,25 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
     }
 }
 
-/* Writes case C to the portable file represented by H. */
+/* Write documents in DICT to portable file W. */
+static void
+write_documents (struct pfm_writer *w, const struct dictionary *dict)
+{
+  size_t line_cnt = dict_get_document_line_cnt (dict);
+  struct string line = DS_EMPTY_INITIALIZER;
+  int i;
+
+  buf_write (w, "E", 1);
+  write_int (w, line_cnt);
+  for (i = 0; i < line_cnt; i++)
+    {
+      dict_get_document_line (dict, i, &line);
+      write_string (w, ds_cstr (&line));
+    }
+  ds_destroy (&line);
+}
+
+/* Writes case C to the portable file represented by WRITER. */
 static void
 por_file_casewriter_write (struct casewriter *writer, void *w_,
                            struct ccase *c)