X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fdata%2Fpor-file-writer.c;h=5795b817dcf2b9cefafb42d342fe715ac96f1117;hb=d9153beacc1308b37dbaf4f64155553360aa0173;hp=be8aba96dc873a7dc079de3539a1669746e167c2;hpb=67ab74956960acef3c4e86886504b93253eb3e4e;p=pspp
diff --git a/src/data/por-file-writer.c b/src/data/por-file-writer.c
index be8aba96dc..5795b817dc 100644
--- a/src/data/por-file-writer.c
+++ b/src/data/por-file-writer.c
@@ -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,40 +15,40 @@
along with this program. If not, see . */
#include
-#include "por-file-writer.h"
+
+#include "data/por-file-writer.h"
#include
#include
-#include
#include
#include
#include
#include
#include
#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+
+#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)
+#define N_(msgid) (msgid)
/* Maximum width of a variable in a portable file. */
#define MAX_POR_WIDTH 255
@@ -57,7 +57,9 @@
struct pfm_writer
{
struct file_handle *fh; /* File handle. */
+ struct fh_lock *lock; /* Lock on file handle. */
FILE *file; /* File stream. */
+ struct replace_file *rf; /* Ticket for replacing output file. */
int lc; /* Number of characters on this line so far. */
@@ -71,10 +73,10 @@ 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 struct casewriter_class por_file_casewriter_class;
+static const struct casewriter_class por_file_casewriter_class;
static bool close_writer (struct pfm_writer *);
static void buf_write (struct pfm_writer *, const void *, size_t);
@@ -83,6 +85,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[]);
@@ -107,31 +111,14 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
{
struct pfm_writer *w = NULL;
mode_t mode;
- int fd;
size_t i;
- /* Create file. */
- mode = S_IRUSR | S_IRGRP | S_IROTH;
- if (opts.create_writeable)
- mode |= S_IWUSR | S_IWGRP | S_IWOTH;
- fd = open (fh_get_file_name (fh), O_WRONLY | O_CREAT | O_TRUNC, mode);
- if (fd < 0)
- goto open_error;
-
- /* Open file handle. */
- if (!fh_open (fh, FH_REF_FILE, "portable file", "we"))
- goto error;
-
/* Initialize data structures. */
w = xmalloc (sizeof *w);
- w->fh = fh;
- w->file = fdopen (fd, "w");
- if (w->file == NULL)
- {
- close (fd);
- goto open_error;
- }
-
+ w->fh = fh_ref (fh);
+ w->lock = NULL;
+ w->file = NULL;
+ w->rf = NULL;
w->lc = 0;
w->var_cnt = 0;
w->vars = NULL;
@@ -143,7 +130,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 = 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;
@@ -154,25 +141,42 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
w->digits = DBL_DIG;
}
+ /* Lock file. */
+ /* 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_("portable file"), FH_ACC_WRITE, true);
+ if (w->lock == NULL)
+ goto error;
+
+ /* Create file. */
+ mode = 0444;
+ if (opts.create_writeable)
+ 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."),
+ fh_get_file_name (fh), strerror (errno));
+ goto error;
+ }
+
/* Write file header. */
write_header (w);
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;
- return casewriter_create (&por_file_casewriter_class, w);
+ return casewriter_create (dict_get_proto (dict),
+ &por_file_casewriter_class, w);
- error:
+error:
close_writer (w);
return NULL;
-
- open_error:
- msg (ME, _("An error occurred while opening \"%s\" for writing "
- "as a portable file: %s."),
- fh_get_file_name (fh), strerror (errno));
- goto error;
}
/* Write NBYTES starting at BUF to the portable file represented by
@@ -210,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. */
@@ -256,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;
@@ -271,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);
@@ -300,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);
}
@@ -322,15 +328,24 @@ 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);
+
+ buf_write (w, "5", 1);
+ write_int (w, ceil (w->digits * (log (10) / log (30))));
for (i = 0; i < dict_get_var_cnt (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);
@@ -340,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);
@@ -361,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)
@@ -386,12 +402,13 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
for (i = 0; i < dict_get_var_cnt (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);
@@ -399,16 +416,34 @@ 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);
}
}
-/* 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++)
+ write_string (w, dict_get_document_line (dict, i));
+ 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)
@@ -423,18 +458,18 @@ por_file_casewriter_write (struct casewriter *writer, void *w_,
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
@@ -467,11 +502,15 @@ 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))
+ ok = false;
}
- fh_close (w->fh, "portable file", "we");
+ fh_unlock (w->lock);
+ fh_unref (w->fh);
free (w->vars);
free (w);
@@ -744,7 +783,7 @@ format_trig_double (long double value, int base_10_precision, char output[])
0...30**6, an invariant of the loop below. */
errno = 0;
base_2_sig = frexp (value, &base_2_exp);
- if (errno != 0 || !finite (base_2_sig))
+ if (errno != 0 || !isfinite (base_2_sig))
goto missing_value;
if (base_2_exp == 0 && base_2_sig == 0.)
goto zero;
@@ -865,7 +904,7 @@ format_trig_double (long double value, int base_10_precision, char output[])
return;
}
-static struct casewriter_class por_file_casewriter_class =
+static const struct casewriter_class por_file_casewriter_class =
{
por_file_casewriter_write,
por_file_casewriter_destroy,