X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fpfm-write.c;h=132216d5cbe6ff2a58fc4072d004c0d369eab706;hb=92fb12eb06716d14c05b781f5d9dcde956d77c30;hp=b900c2292f81f19801e4fe8da794aeff581bb020;hpb=b33110f85730ee1b789c4d8c268c1f9bd8c7fc71;p=pspp diff --git a/src/pfm-write.c b/src/pfm-write.c index b900c2292f..132216d5cb 100644 --- a/src/pfm-write.c +++ b/src/pfm-write.c @@ -22,11 +22,14 @@ #include "error.h" #include #include +#include #include #include #include #include +#include #include +#include #include "alloc.h" #include "case.h" #include "dictionary.h" @@ -35,11 +38,15 @@ #include "hash.h" #include "magic.h" #include "misc.h" +#include "stat-macros.h" #include "str.h" #include "value-labels.h" #include "var.h" #include "version.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + #include "debug-print.h" /* Portable file writer. */ @@ -52,6 +59,8 @@ struct pfm_writer size_t var_cnt; /* Number of variables. */ struct pfm_var *vars; /* Variables. */ + + int digits; /* Digits of precision. */ }; /* A variable to write to the portable file. */ @@ -70,38 +79,57 @@ static int write_value_labels (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[]); -/* Writes the dictionary DICT to portable file HANDLE. Returns - nonzero only if successful. DICT will not be modified, except - to assign short names. */ +/* Returns default options for writing a portable file. */ +struct pfm_write_options +pfm_writer_default_options (void) +{ + struct pfm_write_options opts; + opts.create_writeable = true; + opts.type = PFM_COMM; + opts.digits = DBL_DIG; + return opts; +} + +/* Writes the dictionary DICT to portable file HANDLE according + to the given OPTS. Returns nonzero only if successful. DICT + will not be modified, except to assign short names. */ struct pfm_writer * -pfm_open_writer (struct file_handle *fh, struct dictionary *dict) +pfm_open_writer (struct file_handle *fh, struct dictionary *dict, + struct pfm_write_options opts) { struct pfm_writer *w = NULL; + mode_t mode; + int fd; size_t i; - if (!fh_open (fh, "portable file", "we")) + /* Create file. */ + mode = S_IRUSR | S_IRGRP | S_IROTH; + if (opts.create_writeable) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + fd = open (fh_get_filename (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; - - /* Open the physical disk file. */ + + /* Initialize data structures. */ w = xmalloc (sizeof *w); w->fh = fh; - w->file = fopen (handle_get_filename (fh), "wb"); + w->file = fdopen (fd, "w"); + if (w->file == NULL) + { + close (fd); + goto open_error; + } + w->lc = 0; w->var_cnt = 0; w->vars = NULL; - /* Check that file create succeeded. */ - if (w->file == NULL) - { - msg (ME, _("An error occurred while opening \"%s\" for writing " - "as a portable file: %s."), - handle_get_filename (fh), strerror (errno)); - err_cond_fail (); - goto error; - } - w->var_cnt = dict_get_var_cnt (dict); - w->vars = xmalloc (sizeof *w->vars * w->var_cnt); + w->vars = xnmalloc (w->var_cnt, sizeof *w->vars); for (i = 0; i < w->var_cnt; i++) { const struct variable *dv = dict_get_var (dict, i); @@ -110,6 +138,14 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict) pv->fv = dv->fv; } + w->digits = opts.digits; + if (w->digits < 1) + { + msg (ME, _("Invalid decimal digits count %d. Treating as %d."), + w->digits, DBL_DIG); + w->digits = DBL_DIG; + } + /* Write file header. */ if (!write_header (w) || !write_version_data (w) @@ -120,9 +156,16 @@ pfm_open_writer (struct file_handle *fh, struct dictionary *dict) return w; -error: + error: pfm_close_writer (w); return NULL; + + open_error: + msg (ME, _("An error occurred while opening \"%s\" for writing " + "as a portable file: %s."), + fh_get_filename (fh), strerror (errno)); + err_cond_fail (); + goto error; } /* Write NBYTES starting at BUF to the portable file represented by @@ -156,7 +199,7 @@ buf_write (struct pfm_writer *w, const void *buf_, size_t nbytes) error: msg (ME, _("%s: Writing portable file: %s."), - handle_get_filename (w->fh), strerror (errno)); + fh_get_filename (w->fh), strerror (errno)); return 0; } @@ -166,7 +209,7 @@ static int write_float (struct pfm_writer *w, double d) { char buffer[64]; - format_trig_double (d, DBL_DIG, buffer); + format_trig_double (d, floor (d) == d ? DBL_DIG : w->digits, buffer); return buf_write (w, buffer, strlen (buffer)) && buf_write (w, "/", 1); } @@ -203,7 +246,7 @@ write_header (struct pfm_writer *w) { /* PORTME: Translation table from SPSS character code to this computer's native character code (which is probably ASCII). */ - static const unsigned char spss2ascii[256] = + static const char spss2ascii[256] = { "0000000000000000000000000000000000000000000000000000000000000000" "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ." @@ -295,25 +338,43 @@ write_variables (struct pfm_writer *w, struct dictionary *dict) for (i = 0; i < dict_get_var_cnt (dict); i++) { - static const char *miss_types[MISSING_COUNT] = - { - "", "8", "88", "888", "B ", "9", "A", "B 8", "98", "A8", - }; - - const char *m; - int j; - struct variable *v = dict_get_var (dict, i); + struct missing_values mv; if (!buf_write (w, "7", 1) || !write_int (w, v->width) || !write_string (w, v->short_name) || !write_format (w, &v->print) || !write_format (w, &v->write)) return 0; - for (m = miss_types[v->miss_type], j = 0; j < (int) strlen (m); j++) - if ((m[j] != ' ' && !buf_write (w, &m[j], 1)) - || !write_value (w, &v->missing[j], v)) - return 0; + /* Write missing values. */ + mv_copy (&mv, &v->miss); + while (mv_has_range (&mv)) + { + double x, y; + mv_pop_range (&mv, &x, &y); + if (x == LOWEST) + { + if (!buf_write (w, "9", 1) || !write_float (w, y)) + return 0; + } + else if (y == HIGHEST) + { + if (!buf_write (w, "A", 1) || !write_float (w, y)) + return 0; + } + else { + if (!buf_write (w, "B", 1) || !write_float (w, x) + || !write_float (w, y)) + return 0; + } + } + while (mv_has_value (&mv)) + { + union value value; + mv_pop_value (&mv, &value); + if (!buf_write (w, "8", 1) || !write_value (w, &value, v)) + return 0; + } if (v->label && (!buf_write (w, "C", 1) || !write_string (w, v->label))) return 0; @@ -359,7 +420,7 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict) /* Writes case ELEM to the portable file represented by H. Returns success. */ int -pfm_write_case (struct pfm_writer *w, struct ccase *c) +pfm_write_case (struct pfm_writer *w, const struct ccase *c) { int i; @@ -390,8 +451,6 @@ pfm_close_writer (struct pfm_writer *w) if (w == NULL) return; - fh_close (w->fh, "portable file", "we"); - if (w->file != NULL) { char buf[80]; @@ -405,9 +464,11 @@ pfm_close_writer (struct pfm_writer *w) if (fclose (w->file) == EOF) msg (ME, _("%s: Closing portable file: %s."), - handle_get_filename (w->fh), strerror (errno)); + fh_get_filename (w->fh), strerror (errno)); } + fh_close (w->fh, "portable file", "we"); + free (w->vars); free (w); } @@ -733,6 +794,8 @@ format_trig_double (long double value, int base_10_precision, char output[]) required base-30 precision as 2/3 of the base-10 precision (log30(10) = .68). */ assert (base_10_precision > 0); + 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) {