X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fsfm-write.c;h=dcdab0b46d616dd6604adab4b33108fd69c80b5b;hb=92fb12eb06716d14c05b781f5d9dcde956d77c30;hp=7a5f10c40811ca13684857db1a2a36d931523061;hpb=4fdeb2145d081ff1b84e3f6c99f9d1c048c0d64a;p=pspp diff --git a/src/sfm-write.c b/src/sfm-write.c index 7a5f10c408..dcdab0b46d 100644 --- a/src/sfm-write.c +++ b/src/sfm-write.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #if HAVE_UNISTD_H #include /* Required by SunOS4. */ @@ -33,15 +35,20 @@ #include "dictionary.h" #include "error.h" #include "file-handle.h" -#include "getline.h" +#include "getl.h" #include "hash.h" #include "magic.h" #include "misc.h" +#include "settings.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" /* Compression bias used by PSPP. Values between (1 - @@ -104,32 +111,61 @@ var_flt64_cnt (const struct variable *v) return v->type == NUMERIC ? 1 : DIV_RND_UP (v->width, sizeof (flt64)); } +/* Returns default options for writing a system file. */ +struct sfm_write_options +sfm_writer_default_options (void) +{ + struct sfm_write_options opts; + opts.create_writeable = true; + opts.compress = get_scompression (); + opts.version = 3; + return opts; +} + /* Opens the system file designated by file handle FH for writing - cases from dictionary D. If COMPRESS is nonzero, the - system file will be compressed. If OMIT_LONGNAMES is nonzero, the - long name table will be omitted. + cases from dictionary D according to the given OPTS. If + COMPRESS is nonzero, the system file will be compressed. No reference to D is retained, so it may be modified or - destroyed at will after this function returns. */ + destroyed at will after this function returns. D is not + modified by this function, except to assign short names. */ struct sfm_writer * -sfm_open_writer (struct file_handle *fh, - const struct dictionary *d, int compress, - short omit_longnames) +sfm_open_writer (struct file_handle *fh, struct dictionary *d, + struct sfm_write_options opts) { struct sfm_writer *w = NULL; + mode_t mode; + int fd; int idx; int i; - if (!fh_open (fh, "system file", "we")) + /* Check version. */ + if (opts.version != 2 && opts.version != 3) + { + msg (ME, _("Unknown system file version %d. Treating as version %d."), + opts.version, 3); + opts.version = 3; + } + + /* 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, "system file", "we")) goto error; /* Create and initialize writer. */ w = xmalloc (sizeof *w); w->fh = fh; - w->file = fopen (handle_get_filename (fh), "wb"); + w->file = fdopen (fd, "w"); w->needs_translation = does_dict_need_translation (d); - w->compress = compress; + w->compress = opts.compress; w->case_cnt = 0; w->flt64_cnt = 0; @@ -137,7 +173,7 @@ sfm_open_writer (struct file_handle *fh, w->x = w->y = NULL; w->var_cnt = dict_get_var_cnt (d); - 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 (d, i); @@ -148,13 +184,10 @@ sfm_open_writer (struct file_handle *fh, } /* Check that file create succeeded. */ - if (w->file == NULL) + if (w->file == NULL) { - msg (ME, _("Error opening \"%s\" for writing " - "as a system file: %s."), - handle_get_filename (w->fh), strerror (errno)); - err_cond_fail (); - goto error; + close (fd); + goto open_error; } /* Write the file header. */ @@ -162,6 +195,7 @@ sfm_open_writer (struct file_handle *fh, goto error; /* Write basic variable info. */ + dict_assign_short_names (d); for (i = 0; i < dict_get_var_cnt (d); i++) write_variable (w, dict_get_var (d, i)); @@ -181,19 +215,16 @@ sfm_open_writer (struct file_handle *fh, if (!write_rec_7_34 (w)) goto error; - - /* Write variable display info. */ - if ( !write_variable_display_parameters(w, d)) + if (!write_variable_display_parameters (w, d)) goto error; - - if ( ! omit_longnames ) + if (opts.version >= 3) { if (!write_longvar_table (w, d)) goto error; } - /* Write record 999. */ + /* Write end-of-headers record. */ { struct { @@ -211,7 +242,7 @@ sfm_open_writer (struct file_handle *fh, if (w->compress) { - w->buf = xmalloc (sizeof *w->buf * 128); + w->buf = xnmalloc (128, sizeof *w->buf); w->ptr = w->buf; w->end = &w->buf[128]; w->x = (unsigned char *) w->ptr++; @@ -223,6 +254,12 @@ sfm_open_writer (struct file_handle *fh, error: sfm_close_writer (w); return NULL; + + open_error: + msg (ME, _("Error opening \"%s\" for writing as a system file: %s."), + fh_get_filename (fh), strerror (errno)); + err_cond_fail (); + goto error; } static int @@ -334,7 +371,7 @@ write_header (struct sfm_writer *w, const struct dictionary *d) if (label == NULL) label = ""; - st_bare_pad_copy (hdr.file_label, label, sizeof hdr.file_label); + buf_copy_str_rpad (hdr.file_label, sizeof hdr.file_label, label); } memset (hdr.padding, 0, sizeof hdr.padding); @@ -360,6 +397,7 @@ write_variable (struct sfm_writer *w, struct variable *v) struct sysfile_variable sv; /* Missing values. */ + struct missing_values mv; flt64 m[3]; /* Missing value values. */ int nm; /* Number of missing values, possibly negative. */ @@ -367,60 +405,32 @@ write_variable (struct sfm_writer *w, struct variable *v) sv.type = v->width; sv.has_var_label = (v->label != NULL); - switch (v->miss_type) + mv_copy (&mv, &v->miss); + nm = 0; + if (mv_has_range (&mv)) { - case MISSING_NONE: - nm = 0; - break; - case MISSING_1: - case MISSING_2: - case MISSING_3: - for (nm = 0; nm < v->miss_type; nm++) - m[nm] = v->missing[nm].f; - break; - case MISSING_RANGE: - m[0] = v->missing[0].f; - m[1] = v->missing[1].f; - nm = -2; - break; - case MISSING_LOW: - m[0] = second_lowest_flt64; - m[1] = v->missing[0].f; - nm = -2; - break; - case MISSING_HIGH: - m[0] = v->missing[0].f; - m[1] = FLT64_MAX; - nm = -2; - break; - case MISSING_RANGE_1: - m[0] = v->missing[0].f; - m[1] = v->missing[1].f; - m[2] = v->missing[2].f; - nm = -3; - break; - case MISSING_LOW_1: - m[0] = second_lowest_flt64; - m[1] = v->missing[0].f; - m[2] = v->missing[1].f; - nm = -3; - break; - case MISSING_HIGH_1: - m[0] = v->missing[0].f; - m[1] = second_lowest_flt64; - m[2] = v->missing[1].f; - nm = -3; - break; - default: - assert (0); - abort (); + double x, y; + mv_pop_range (&mv, &x, &y); + m[nm++] = x == LOWEST ? second_lowest_flt64 : x; + m[nm++] = y == HIGHEST ? FLT64_MAX : y; } + while (mv_has_value (&mv)) + { + union value value; + mv_pop_value (&mv, &value); + if (v->type == NUMERIC) + m[nm] = value.f; + else + buf_copy_rpad ((char *) &m[nm], sizeof m[nm], value.s, v->width); + nm++; + } + if (mv_has_range (&v->miss)) + nm = -nm; sv.n_missing_values = nm; write_format_spec (&v->print, &sv.print); write_format_spec (&v->write, &sv.write); - memcpy (sv.name, v->name, strlen (v->name)); - memset (&sv.name[strlen (v->name)], ' ', SHORT_NAME_LEN - strlen (v->name)); + buf_copy_str_rpad (sv.name, sizeof sv.name, v->short_name); if (!buf_write (w, &sv, sizeof sv)) return 0; @@ -444,7 +454,7 @@ write_variable (struct sfm_writer *w, struct variable *v) return 0; } - if (nm && !buf_write (w, m, sizeof *m * nm)) + if (nm && !buf_write (w, m, sizeof *m * abs (nm))) return 0; if (v->type == ALPHA && v->width > (int) sizeof (flt64)) @@ -517,8 +527,8 @@ write_value_labels (struct sfm_writer *w, struct variable *v, int idx) *loc++ = vl->value.f; *(unsigned char *) loc = len; - memcpy (&((unsigned char *) loc)[1], vl->label, len); - memset (&((unsigned char *) loc)[1 + len], ' ', + memcpy (&((char *) loc)[1], vl->label, len); + memset (&((char *) loc)[1 + len], ' ', REM_RND_UP (len + 1, sizeof (flt64))); loc += DIV_RND_UP (len + 1, sizeof (flt64)); } @@ -617,40 +627,42 @@ write_variable_display_parameters (struct sfm_writer *w, static int write_longvar_table (struct sfm_writer *w, const struct dictionary *dict) { - char *buf = 0; - int bufsize = 0; - struct - { - int32 rec_type P; - int32 subtype P; - int32 elem_size P; - int32 n_elem P; - } lv_hdr; + { + int32 rec_type P; + int32 subtype P; + int32 elem_size P; + int32 n_elem P; + } + lv_hdr; + + struct string long_name_map; + size_t i; + + ds_init (&long_name_map, 10 * dict_get_var_cnt (dict)); + for (i = 0; i < dict_get_var_cnt (dict); i++) + { + struct variable *v = dict_get_var (dict, i); + + if (i) + ds_putc (&long_name_map, '\t'); + ds_printf (&long_name_map, "%s=%s", v->short_name, v->name); + } lv_hdr.rec_type = 7; lv_hdr.subtype = 13; lv_hdr.elem_size = 1; + lv_hdr.n_elem = ds_length (&long_name_map); - - dict_get_varname_block(dict, &buf, &bufsize); - - if ( bufsize == 0 ) - return 1; - - lv_hdr.n_elem = bufsize ; - - if (!buf_write (w, &lv_hdr, sizeof(lv_hdr) )) - goto error; - - if (!buf_write (w, buf, bufsize)) + if (!buf_write (w, &lv_hdr, sizeof lv_hdr) + || !buf_write (w, ds_data (&long_name_map), ds_length (&long_name_map))) goto error; - free (buf); + ds_destroy (&long_name_map); return 1; error: - free ( buf ) ; + ds_destroy (&long_name_map); return 0; } @@ -737,7 +749,7 @@ buf_write (struct sfm_writer *w, const void *buf, size_t nbytes) if (fwrite (buf, nbytes, 1, w->file) != 1) { msg (ME, _("%s: Writing system file: %s."), - handle_get_filename (w->fh), strerror (errno)); + fh_get_filename (w->fh), strerror (errno)); return 0; } return 1; @@ -776,7 +788,7 @@ static void write_compressed_data (struct sfm_writer *w, const flt64 *elem); /* Writes case C to system file W. Returns nonzero if successful. */ int -sfm_write_case (struct sfm_writer *w, struct ccase *c) +sfm_write_case (struct sfm_writer *w, const struct ccase *c) { w->case_cnt++; @@ -892,8 +904,6 @@ sfm_close_writer (struct sfm_writer *w) if (w == NULL) return; - fh_close (w->fh, "system file", "we"); - if (w->file != NULL) { /* Flush buffer. */ @@ -917,9 +927,11 @@ sfm_close_writer (struct sfm_writer *w) if (fclose (w->file) == EOF) msg (ME, _("%s: Closing system file: %s."), - handle_get_filename (w->fh), strerror (errno)); + fh_get_filename (w->fh), strerror (errno)); } + fh_close (w->fh, "system file", "we"); + free (w->buf); free (w->vars); free (w);