treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / data / por-file-writer.c
index 8a27f6b785ccc548d5a14436cfe221ee7476d3e6..be35418ce7de9b7de7ed43688470ebe9f3c2a313 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 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
@@ -15,7 +15,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "por-file-writer.h"
+
+#include "data/por-file-writer.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <time.h>
 
-#include <data/case.h>
-#include <data/casewriter-provider.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/file-name.h>
-#include <data/format.h>
-#include <data/make-file.h>
-#include <data/missing-values.h>
-#include <data/short-names.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-
-#include <libpspp/hash.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <libpspp/version.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casewriter-provider.h"
+#include "data/casewriter.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/format.h"
+#include "data/make-file.h"
+#include "data/missing-values.h"
+#include "data/short-names.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -64,7 +63,7 @@ struct pfm_writer
 
     int lc;                    /* Number of characters on this line so far. */
 
-    size_t var_cnt;             /* Number of variables. */
+    size_t n_vars;              /* Number of variables. */
     struct pfm_var *vars;       /* Variables. */
 
     int digits;                 /* Digits of precision. */
@@ -74,7 +73,7 @@ struct pfm_writer
 struct pfm_var
   {
     int width;                  /* 0=numeric, otherwise string var width. */
-    int fv;                     /* Starting case index. */
+    int case_index;             /* Index in case. */
   };
 
 static const struct casewriter_class por_file_casewriter_class;
@@ -121,17 +120,17 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
   w->file = NULL;
   w->rf = NULL;
   w->lc = 0;
-  w->var_cnt = 0;
+  w->n_vars = 0;
   w->vars = NULL;
 
-  w->var_cnt = dict_get_var_cnt (dict);
-  w->vars = xnmalloc (w->var_cnt, sizeof *w->vars);
-  for (i = 0; i < w->var_cnt; i++)
+  w->n_vars = dict_get_n_vars (dict);
+  w->vars = xnmalloc (w->n_vars, sizeof *w->vars);
+  for (i = 0; i < w->n_vars; i++)
     {
       const struct variable *dv = dict_get_var (dict, i);
       struct pfm_var *pv = &w->vars[i];
       pv->width = MIN (var_get_width (dv), MAX_POR_WIDTH);
-      pv->fv = var_get_case_index (dv);
+      pv->case_index = var_get_case_index (dv);
     }
 
   w->digits = opts.digits;
@@ -150,14 +149,14 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
     goto error;
 
   /* Create file. */
-  mode = S_IRUSR | S_IRGRP | S_IROTH;
+  mode = 0444;
   if (opts.create_writeable)
-    mode |= S_IWUSR | S_IWGRP | S_IWOTH;
-  w->rf = replace_file_start (fh_get_file_name (fh), "w", mode,
-                              &w->file, NULL);
+    mode |= 0222;
+  w->rf = replace_file_start (fh, "w", mode,
+                              &w->file);
   if (w->rf == NULL)
     {
-      msg (ME, _("Error opening \"%s\" for writing as a portable file: %s."),
+      msg (ME, _("Error opening `%s' for writing as a portable file: %s."),
            fh_get_file_name (fh), strerror (errno));
       goto error;
     }
@@ -167,12 +166,12 @@ 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)
+  if (dict_get_document_n_lines (dict) > 0)
     write_documents (w, dict);
   buf_write (w, "F", 1);
   if (ferror (w->file))
     goto error;
-  return casewriter_create (dict_get_next_value_idx (dict),
+  return casewriter_create (dict_get_proto (dict),
                             &por_file_casewriter_class, w);
 
 error:
@@ -215,7 +214,8 @@ write_float (struct pfm_writer *w, double d)
   char buffer[64];
   format_trig_double (d, floor (d) == d ? DBL_DIG : w->digits, buffer);
   buf_write (w, buffer, strlen (buffer));
-  buf_write (w, "/", 1);
+  if (d != SYSMIS)
+    buf_write (w, "/", 1);
 }
 
 /* Write N to the portable file as an integer field. */
@@ -261,8 +261,6 @@ write_header (struct pfm_writer *w)
 static void
 write_version_data (struct pfm_writer *w)
 {
-  char date_str[9];
-  char time_str[7];
   time_t t;
   struct tm tm;
   struct tm *tmp;
@@ -276,12 +274,15 @@ write_version_data (struct pfm_writer *w)
   else
     tmp = localtime (&t);
 
-  sprintf (date_str, "%04d%02d%02d",
-           tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday);
-  sprintf (time_str, "%02d%02d%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+  char *date_str = xasprintf ("%04d%02d%02d", tmp->tm_year + 1900,
+                              tmp->tm_mon + 1, tmp->tm_mday);
+  char *time_str = xasprintf ("%02d%02d%02d",
+                              tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
   buf_write (w, "A", 1);
   write_string (w, date_str);
   write_string (w, time_str);
+  free (date_str);
+  free (time_str);
 
   /* Product identification. */
   buf_write (w, "1", 1);
@@ -305,15 +306,15 @@ write_format (struct pfm_writer *w, struct fmt_spec f, int width)
   write_int (w, f.d);
 }
 
-/* Write value V for variable VV to file H. */
+/* Write value V with width WIDTH to file H. */
 static void
-write_value (struct pfm_writer *w, union value *v, struct variable *vv)
+write_value (struct pfm_writer *w, const union value *v, int width)
 {
-  if (var_is_numeric (vv))
+  if (width == 0)
     write_float (w, v->f);
   else
     {
-      int width = MIN (var_get_width (vv), MAX_POR_WIDTH);
+      width = MIN (width, MAX_POR_WIDTH);
       write_int (w, width);
       buf_write (w, v->s, width);
     }
@@ -327,21 +328,24 @@ write_variables (struct pfm_writer *w, struct dictionary *dict)
 
   short_names_assign (dict);
 
-  if (dict_get_weight (dict) != NULL) 
+  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);
+  write_int (w, dict_get_n_vars (dict));
 
-  for (i = 0; i < dict_get_var_cnt (dict); i++)
+  buf_write (w, "5", 1);
+  write_int (w, ceil (w->digits * (log (10) / log (30))));
+
+  for (i = 0; i < dict_get_n_vars (dict); i++)
     {
       struct variable *v = dict_get_var (dict, i);
       struct missing_values mv;
       int width = MIN (var_get_width (v), MAX_POR_WIDTH);
+      int j;
 
       buf_write (w, "7", 1);
       write_int (w, width);
@@ -351,10 +355,12 @@ write_variables (struct pfm_writer *w, struct dictionary *dict)
 
       /* Write missing values. */
       mv_copy (&mv, var_get_missing_values (v));
-      while (mv_has_range (&mv))
+      if (var_get_width (v) > 8)
+        mv_resize (&mv, 8);
+      if (mv_has_range (&mv))
         {
           double x, y;
-          mv_pop_range (&mv, &x, &y);
+          mv_get_range (&mv, &x, &y);
           if (x == LOWEST)
             {
               buf_write (w, "9", 1);
@@ -372,13 +378,12 @@ write_variables (struct pfm_writer *w, struct dictionary *dict)
               write_float (w, y);
             }
         }
-      while (mv_has_value (&mv))
+      for (j = 0; j < mv_n_values (&mv); j++)
         {
-          union value value;
-          mv_pop_value (&mv, &value);
           buf_write (w, "8", 1);
-          write_value (w, &value, v);
+          write_value (w, mv_get_value (&mv, j), mv_get_width (&mv));
         }
+      mv_destroy (&mv);
 
       /* Write variable label. */
       if (var_get_label (v) != NULL)
@@ -395,14 +400,15 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
 {
   int i;
 
-  for (i = 0; i < dict_get_var_cnt (dict); i++)
+  for (i = 0; i < dict_get_n_vars (dict); i++)
     {
-      struct val_labs_iterator *j;
       struct variable *v = dict_get_var (dict, i);
       const struct val_labs *val_labs = var_get_value_labels (v);
-      struct val_lab *vl;
+      size_t n_labels = val_labs_count (val_labs);
+      const struct val_lab **labels;
+      int j;
 
-      if (val_labs == NULL)
+      if (n_labels == 0)
        continue;
 
       buf_write (w, "D", 1);
@@ -410,12 +416,15 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
       write_string (w, var_get_short_name (v, 0));
       write_int (w, val_labs_count (val_labs));
 
-      for (vl = val_labs_first_sorted (val_labs, &j); vl != NULL;
-           vl = val_labs_next (val_labs, &j))
+      n_labels = val_labs_count (val_labs);
+      labels = val_labs_sorted (val_labs);
+      for (j = 0; j < n_labels; j++)
         {
-          write_value (w, &vl->value, v);
-          write_string (w, vl->label);
+          const struct val_lab *vl = labels[j];
+          write_value (w, val_lab_get_value (vl), var_get_width (v));
+          write_string (w, val_lab_get_escaped_label (vl));
         }
+      free (labels);
     }
 }
 
@@ -423,17 +432,14 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
 static void
 write_documents (struct pfm_writer *w, const struct dictionary *dict)
 {
-  size_t line_cnt = dict_get_document_line_cnt (dict);
+  size_t n_lines = dict_get_document_n_lines (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));
-    }
+  write_int (w, n_lines);
+  for (i = 0; i < n_lines; i++)
+    write_string (w, dict_get_document_line (dict, i));
   ds_destroy (&line);
 }
 
@@ -447,23 +453,23 @@ por_file_casewriter_write (struct casewriter *writer, void *w_,
 
   if (!ferror (w->file))
     {
-      for (i = 0; i < w->var_cnt; i++)
+      for (i = 0; i < w->n_vars; i++)
         {
           struct pfm_var *v = &w->vars[i];
 
           if (v->width == 0)
-            write_float (w, case_num_idx (c, v->fv));
+            write_float (w, case_num_idx (c, v->case_index));
           else
             {
               write_int (w, v->width);
-              buf_write (w, case_str_idx (c, v->fv), v->width);
+              buf_write (w, case_str_idx (c, v->case_index), v->width);
             }
         }
     }
   else
     casewriter_force_error (writer);
 
-  case_destroy (c);
+  case_unref (c);
 }
 
 static void
@@ -496,7 +502,7 @@ close_writer (struct pfm_writer *w)
         ok = false;
 
       if (!ok)
-        msg (ME, _("An I/O error occurred writing portable file \"%s\"."),
+        msg (ME, _("An I/O error occurred writing portable file `%s'."),
              fh_get_file_name (w->fh));
 
       if (ok ? !replace_file_commit (w->rf) : !replace_file_abort (w->rf))
@@ -600,7 +606,7 @@ trig_to_char (int trig)
    character after the formatted number. */
 static char *
 format_trig_digits (char *string,
-                    const char trigs[], int trig_cnt, int trig_places)
+                    const char trigs[], int n_trigs, int trig_places)
 {
   if (trig_places < 0)
     {
@@ -609,7 +615,7 @@ format_trig_digits (char *string,
         *string++ = '0';
       trig_places = -1;
     }
-  while (trig_cnt-- > 0)
+  while (n_trigs-- > 0)
     {
       if (trig_places-- == 0)
         *string++ = '.';
@@ -663,9 +669,9 @@ format_trig_int (int value, bool force_sign, char string[])
    is exactly half, examines TRIGS[-1] and returns true if odd,
    false if even ("round to even"). */
 static bool
-should_round_up (const char trigs[], int trig_cnt)
+should_round_up (const char trigs[], int n_trigs)
 {
-  assert (trig_cnt > 0);
+  assert (n_trigs > 0);
 
   if (*trigs < BASE / 2)
     {
@@ -681,7 +687,7 @@ should_round_up (const char trigs[], int trig_cnt)
     {
       /* Approximately half: look more closely. */
       int i;
-      for (i = 1; i < trig_cnt; i++)
+      for (i = 1; i < n_trigs; i++)
         if (trigs[i] > 0)
           {
             /* Slightly greater than half: round up. */
@@ -698,11 +704,11 @@ should_round_up (const char trigs[], int trig_cnt)
    successful, false on failure (due to a carry out of the
    leftmost position). */
 static bool
-try_round_up (char *trigs, int trig_cnt)
+try_round_up (char *trigs, int n_trigs)
 {
-  while (trig_cnt > 0)
+  while (n_trigs > 0)
     {
-      char *round_trig = trigs + --trig_cnt;
+      char *round_trig = trigs + --n_trigs;
       if (*round_trig != BASE - 1)
         {
           /* Round this trig up to the next value. */
@@ -739,7 +745,7 @@ format_trig_double (long double value, int base_10_precision, char output[])
   /* VALUE as a set of trigesimals. */
   char buffer[DBL_DIG + 16];
   char *trigs;
-  int trig_cnt;
+  int n_trigs;
 
   /* Number of trigesimal places for trigs.
      trigs[0] has coefficient 30**(trig_places - 1),
@@ -788,7 +794,7 @@ format_trig_double (long double value, int base_10_precision, char output[])
 
   /* Dump all the trigs to buffer[], CHUNK_SIZE at a time. */
   trigs = buffer;
-  trig_cnt = 0;
+  n_trigs = 0;
   for (trigs_to_output = DIV_RND_UP (DBL_DIG * 2, 3) + 1 + (CHUNK_SIZE / 2);
        trigs_to_output > 0;
        trigs_to_output -= CHUNK_SIZE)
@@ -806,14 +812,14 @@ format_trig_double (long double value, int base_10_precision, char output[])
       value -= chunk;
 
       /* Append the chunk, in base 30, to trigs[]. */
-      for (trigs_left = CHUNK_SIZE; chunk > 0 && trigs_left > 0; )
+      for (trigs_left = CHUNK_SIZE; chunk > 0 && trigs_left > 0;)
         {
-          trigs[trig_cnt + --trigs_left] = chunk % 30;
+          trigs[n_trigs + --trigs_left] = chunk % 30;
           chunk /= 30;
         }
       while (trigs_left > 0)
-        trigs[trig_cnt + --trigs_left] = 0;
-      trig_cnt += CHUNK_SIZE;
+        trigs[n_trigs + --trigs_left] = 0;
+      n_trigs += CHUNK_SIZE;
 
       /* Proceed to the next chunk. */
       if (value == 0.)
@@ -822,10 +828,10 @@ format_trig_double (long double value, int base_10_precision, char output[])
     }
 
   /* Strip leading zeros. */
-  while (trig_cnt > 1 && *trigs == 0)
+  while (n_trigs > 1 && *trigs == 0)
     {
       trigs++;
-      trig_cnt--;
+      n_trigs--;
       trig_places--;
     }
 
@@ -836,30 +842,30 @@ format_trig_double (long double value, int base_10_precision, char output[])
   if (base_10_precision > LDBL_DIG)
     base_10_precision = LDBL_DIG;
   base_30_precision = DIV_RND_UP (base_10_precision * 2, 3);
-  if (trig_cnt > base_30_precision)
+  if (n_trigs > base_30_precision)
     {
       if (should_round_up (trigs + base_30_precision,
-                           trig_cnt - base_30_precision))
+                           n_trigs - base_30_precision))
         {
           /* Try to round up. */
           if (try_round_up (trigs, base_30_precision))
             {
               /* Rounding up worked. */
-              trig_cnt = base_30_precision;
+              n_trigs = base_30_precision;
             }
           else
             {
               /* Couldn't round up because we ran out of trigs to
                  carry into.  Do the carry here instead. */
               *trigs = 1;
-              trig_cnt = 1;
+              n_trigs = 1;
               trig_places++;
             }
         }
       else
         {
           /* Round down. */
-          trig_cnt = base_30_precision;
+          n_trigs = base_30_precision;
         }
     }
   else
@@ -869,23 +875,23 @@ format_trig_double (long double value, int base_10_precision, char output[])
     }
 
   /* Strip trailing zeros. */
-  while (trig_cnt > 1 && trigs[trig_cnt - 1] == 0)
-    trig_cnt--;
+  while (n_trigs > 1 && trigs[n_trigs - 1] == 0)
+    n_trigs--;
 
   /* Write output. */
   if (negative)
     *output++ = '-';
-  if (trig_places >= -1 && trig_places < trig_cnt + 3)
+  if (trig_places >= -1 && trig_places < n_trigs + 3)
     {
       /* Use conventional notation. */
-      format_trig_digits (output, trigs, trig_cnt, trig_places);
+      format_trig_digits (output, trigs, n_trigs, trig_places);
     }
   else
     {
       /* Use scientific notation. */
       char *op;
-      op = format_trig_digits (output, trigs, trig_cnt, trig_cnt);
-      op = format_trig_int (trig_places - trig_cnt, true, op);
+      op = format_trig_digits (output, trigs, n_trigs, n_trigs);
+      op = format_trig_int (trig_places - n_trigs, true, op);
     }
   return;