#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#include <time.h>
#if HAVE_UNISTD_H
#include <unistd.h> /* Required by SunOS4. */
#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 -
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;
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);
}
/* 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. */
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));
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
{
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++;
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
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);
struct sysfile_variable sv;
/* Missing values. */
+ struct missing_values mv;
flt64 m[3]; /* Missing value values. */
int nm; /* Number of missing values, possibly negative. */
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;
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))
*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));
}
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;
}
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;
/* 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++;
if (w == NULL)
return;
- fh_close (w->fh, "system file", "we");
-
if (w->file != NULL)
{
/* Flush buffer. */
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);