X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpor-file-writer.c;h=ea0f9dc88bfe98bebbbd2422881c664d2b76fbaa;hb=9ade26c8349b4434008c46cf09bc7473ec743972;hp=cfb9c30362837067136d24e1db34e6d84e2a8d64;hpb=c3bd77adba5746aae895e6a354aada4e694c0e3f;p=pspp-builds.git diff --git a/src/data/por-file-writer.c b/src/data/por-file-writer.c index cfb9c303..ea0f9dc8 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 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 . */ #include -#include "por-file-writer.h" + +#include "data/por-file-writer.h" #include #include @@ -26,27 +27,29 @@ #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/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/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 @@ -55,7 +58,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. */ @@ -72,7 +77,7 @@ struct pfm_var int fv; /* Starting case index. */ }; -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); @@ -107,32 +112,14 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict, { struct pfm_writer *w = NULL; mode_t mode; - FILE *file; size_t i; - /* Open file handle. */ - if (!fh_open (fh, FH_REF_FILE, "portable file", "we")) - return NULL; - - /* Create file. */ - mode = S_IRUSR | S_IRGRP | S_IROTH; - if (opts.create_writeable) - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - file = create_stream (fh_get_file_name (fh), "w", mode); - if (file == NULL) - { - fh_close (fh, "portable file", "we"); - msg (ME, _("An error occurred while opening \"%s\" for writing " - "as a portable file: %s."), - fh_get_file_name (fh), strerror (errno)); - return NULL; - } - /* Initialize data structures. */ w = xmalloc (sizeof *w); - w->fh = fh; - w->file = file; - + w->fh = fh_ref (fh); + w->lock = NULL; + w->file = NULL; + w->rf = NULL; w->lc = 0; w->var_cnt = 0; w->vars = NULL; @@ -155,6 +142,26 @@ 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_get_file_name (fh), "w", mode, + &w->file, NULL); + 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); @@ -164,12 +171,13 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict, write_documents (w, dict); buf_write (w, "F", 1); if (ferror (w->file)) - { - close_writer (w); - return NULL; - } - return casewriter_create (dict_get_next_value_idx (dict), + goto error; + return casewriter_create (dict_get_proto (dict), &por_file_casewriter_class, w); + +error: + close_writer (w); + return NULL; } /* Write NBYTES starting at BUF to the portable file represented by @@ -207,7 +215,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. */ @@ -297,17 +306,17 @@ 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); + buf_write (w, value_str (v, width), width); } } @@ -334,6 +343,7 @@ 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); + int j; buf_write (w, "7", 1); write_int (w, width); @@ -343,10 +353,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); @@ -364,13 +376,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) @@ -389,12 +400,12 @@ 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; - if (val_labs == NULL) + if (n_labels == 0) continue; buf_write (w, "D", 1); @@ -402,12 +413,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 (i = 0; i < n_labels; i++) { - write_value (w, &vl->value, v); - write_string (w, vl->label); + const struct val_lab *vl = labels[i]; + write_value (w, val_lab_get_value (vl), var_get_width (v)); + write_string (w, val_lab_get_label (vl)); } + free (labels); } } @@ -422,10 +436,7 @@ write_documents (struct pfm_writer *w, const struct dictionary *dict) 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_string (w, dict_get_document_line (dict, i)); ds_destroy (&line); } @@ -455,7 +466,7 @@ por_file_casewriter_write (struct casewriter *writer, void *w_, else casewriter_force_error (writer); - case_destroy (c); + case_unref (c); } static void @@ -488,11 +499,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); @@ -765,7 +780,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; @@ -886,7 +901,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,