Make cases simpler, faster, and easier to understand.
[pspp-builds.git] / src / data / sys-file-writer.c
index d25d5e8d62529606474901336cfdb079701c4527..393be4e1265292b58fc37daa64bfaf4a4ff40a15 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@
 #include <libpspp/str.h>
 #include <libpspp/version.h>
 
+#include <data/attributes.h>
 #include <data/case.h>
 #include <data/casewriter-provider.h>
 #include <data/casewriter.h>
@@ -53,6 +54,7 @@
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
 
 /* Compression bias used by PSPP.  Values between (1 -
    COMPRESSION_BIAS) and (251 - COMPRESSION_BIAS) inclusive can be
@@ -89,7 +91,7 @@ struct sfm_writer
                                    for long string variables. */
   };
 
-static struct casewriter_class sys_file_casewriter_class;
+static const struct casewriter_class sys_file_casewriter_class;
 
 static void write_header (struct sfm_writer *, const struct dictionary *);
 static void write_variable (struct sfm_writer *, const struct variable *);
@@ -110,6 +112,11 @@ static void write_variable_display_parameters (struct sfm_writer *w,
 
 static void write_documents (struct sfm_writer *, const struct dictionary *);
 
+static void write_data_file_attributes (struct sfm_writer *,
+                                        const struct dictionary *);
+static void write_variable_attributes (struct sfm_writer *,
+                                       const struct dictionary *);
+
 static void write_int (struct sfm_writer *, int32_t);
 static inline void convert_double_to_output_format (double, uint8_t[8]);
 static void write_float (struct sfm_writer *, double);
@@ -119,8 +126,9 @@ static void write_zeros (struct sfm_writer *, size_t);
 static void write_spaces (struct sfm_writer *, size_t);
 static void write_value (struct sfm_writer *, const union value *, int width);
 
-static void write_case_uncompressed (struct sfm_writer *, struct ccase *);
-static void write_case_compressed (struct sfm_writer *, struct ccase *);
+static void write_case_uncompressed (struct sfm_writer *,
+                                     const struct ccase *);
+static void write_case_compressed (struct sfm_writer *, const struct ccase *);
 static void flush_compressed (struct sfm_writer *);
 static void put_cmp_opcode (struct sfm_writer *, uint8_t);
 static void put_cmp_number (struct sfm_writer *, double);
@@ -135,7 +143,7 @@ sfm_writer_default_options (void)
 {
   struct sfm_write_options opts;
   opts.create_writeable = true;
-  opts.compress = get_scompression ();
+  opts.compress = settings_get_scompression ();
   opts.version = 3;
   return opts;
 }
@@ -184,7 +192,9 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
                                                &w->sfm_var_cnt);
 
   /* Open file handle as an exclusive writer. */
-  w->lock = fh_lock (fh, FH_REF_FILE, "system file", FH_ACC_WRITE, true);
+  /* TRANSLATORS: this fragment will be interpolated into
+     messages in fh_lock() that identify types of files. */
+  w->lock = fh_lock (fh, FH_REF_FILE, N_("system file"), FH_ACC_WRITE, true);
   if (w->lock == NULL)
     goto error;
 
@@ -232,6 +242,10 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
 
   write_vls_length_table (w, d);
 
+  if (attrset_count (dict_get_attributes (d)))
+    write_data_file_attributes (w, d);
+  write_variable_attributes (w, d);
+
   /* Write end-of-headers record. */
   write_int (w, 999);
   write_int (w, 0);
@@ -330,7 +344,7 @@ write_header (struct sfm_writer *w, const struct dictionary *d)
     }
   else
     {
-      static const char *month_name[12] =
+      static const char *const month_name[12] =
         {
           "Jan", "Feb", "Mar", "Apr", "May", "Jun",
           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
@@ -418,7 +432,7 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   /* Number of missing values.  If there is a range, then the
      range counts as 2 missing values and causes the number to be
      negated. */
-  write_int (w, mv_has_range (mv) ? 2 - mv_n_values (mv) : mv_n_values (mv));
+  write_int (w, mv_has_range (mv) ? -2 - mv_n_values (mv) : mv_n_values (mv));
 
   /* Print and write formats. */
   write_format (w, *var_get_print_format (v), seg0_width);
@@ -442,14 +456,14 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   if (mv_has_range (mv))
     {
       double x, y;
-      mv_peek_range (mv, &x, &y);
+      mv_get_range (mv, &x, &y);
       write_float (w, x);
       write_float (w, y);
     }
   for (i = 0; i < mv_n_values (mv); i++)
     {
       union value value;
-      mv_peek_value (mv, &value, i);
+      mv_get_value (mv, &value, i);
       write_value (w, &value, seg0_width);
     }
 
@@ -517,6 +531,72 @@ write_documents (struct sfm_writer *w, const struct dictionary *d)
   write_bytes (w, dict_get_documents (d), line_cnt * DOC_LINE_LENGTH);
 }
 
+static void
+put_attrset (struct string *string, const struct attrset *attrs)
+{
+  const struct attribute *attr;
+  struct attrset_iterator i;
+
+  for (attr = attrset_first (attrs, &i); attr != NULL;
+       attr = attrset_next (attrs, &i)) 
+    {
+      size_t n_values = attribute_get_n_values (attr);
+      size_t j;
+
+      ds_put_cstr (string, attribute_get_name (attr));
+      ds_put_char (string, '(');
+      for (j = 0; j < n_values; j++) 
+        ds_put_format (string, "'%s'\n", attribute_get_value (attr, j));
+      ds_put_char (string, ')');
+    }
+}
+
+static void
+write_attribute_record (struct sfm_writer *w, const struct string *content,
+                        int subtype) 
+{
+  write_int (w, 7);
+  write_int (w, subtype);
+  write_int (w, 1);
+  write_int (w, ds_length (content));
+  write_bytes (w, ds_data (content), ds_length (content));
+}
+
+static void
+write_data_file_attributes (struct sfm_writer *w,
+                            const struct dictionary *d)
+{
+  struct string s = DS_EMPTY_INITIALIZER;
+  put_attrset (&s, dict_get_attributes (d));
+  write_attribute_record (w, &s, 17);
+  ds_destroy (&s);
+}
+
+static void
+write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
+{
+  struct string s = DS_EMPTY_INITIALIZER;
+  size_t n_vars = dict_get_var_cnt (d);
+  size_t n_attrsets = 0;
+  size_t i;
+
+  for (i = 0; i < n_vars; i++)
+    { 
+      struct variable *v = dict_get_var (d, i);
+      struct attrset *attrs = var_get_attributes (v);
+      if (attrset_count (attrs)) 
+        {
+          if (n_attrsets++)
+            ds_put_char (&s, '/');
+          ds_put_format (&s, "%s:", var_get_short_name (v, 0));
+          put_attrset (&s, attrs);
+        }
+    }
+  if (n_attrsets) 
+    write_attribute_record (w, &s, 18);
+  ds_destroy (&s);
+}
+
 /* Write the alignment, width and scale values. */
 static void
 write_variable_display_parameters (struct sfm_writer *w,
@@ -668,7 +748,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_,
   if (ferror (w->file))
     {
       casewriter_force_error (writer);
-      case_destroy (c);
+      case_unref (c);
       return;
     }
 
@@ -679,7 +759,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_,
   else
     write_case_compressed (w, c);
 
-  case_destroy (c);
+  case_unref (c);
 }
 
 /* Destroys system file writer W. */
@@ -748,7 +828,7 @@ close_writer (struct sfm_writer *w)
 }
 
 /* System file writer casewriter class. */
-static struct casewriter_class sys_file_casewriter_class =
+static const struct casewriter_class sys_file_casewriter_class =
   {
     sys_file_casewriter_write,
     sys_file_casewriter_destroy,
@@ -757,7 +837,7 @@ static struct casewriter_class sys_file_casewriter_class =
 \f
 /* Writes case C to system file W, without compressing it. */
 static void
-write_case_uncompressed (struct sfm_writer *w, struct ccase *c)
+write_case_uncompressed (struct sfm_writer *w, const struct ccase *c)
 {
   size_t i;
 
@@ -778,7 +858,7 @@ write_case_uncompressed (struct sfm_writer *w, struct ccase *c)
 
 /* Writes case C to system file W, with compression. */
 static void
-write_case_compressed (struct sfm_writer *w, struct ccase *c)
+write_case_compressed (struct sfm_writer *w, const struct ccase *c)
 {
   size_t i;