added automake.mk files in src/language
[pspp] / src / sfm-write.c
index 80b7840820761310cac33d384bb5ad8d56834255..dcdab0b46d616dd6604adab4b33108fd69c80b5b 100644 (file)
@@ -24,6 +24,8 @@
 #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. */
@@ -37,6 +39,8 @@
 #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"
@@ -107,33 +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_LONG_NAMES 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.  D is not
    modified by this function, except to assign short names. */
 struct sfm_writer *
-sfm_open_writer (struct file_handle *fh,
-                 struct dictionary *d, int compress, 
-                short omit_long_names)
+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;
 
@@ -141,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);
@@ -152,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. */
@@ -189,7 +218,7 @@ sfm_open_writer (struct file_handle *fh,
   if (!write_variable_display_parameters (w, d))
     goto error;
 
-  if (!omit_long_names
+  if (opts.version >= 3
     {
       if (!write_longvar_table (w, d))
        goto error;
@@ -213,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++;
@@ -225,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
@@ -492,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));
     }
@@ -714,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;
@@ -753,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++;
 
@@ -869,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. */
@@ -894,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);