#include <ctype.h>
#include <errno.h>
-#include <fcntl.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
-#include <unistd.h>
#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/missing-values.h>
+#include <data/short-names.h>
#include <data/value-labels.h>
#include <data/variable.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
+/* Maximum width of a variable in a portable file. */
+#define MAX_POR_WIDTH 255
+
/* Portable file writer. */
struct pfm_writer
{
static void write_variables (struct pfm_writer *, struct dictionary *);
static void write_value_labels (struct pfm_writer *,
const struct dictionary *);
+static void write_documents (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[]);
{
struct pfm_writer *w = NULL;
mode_t mode;
- int fd;
+ 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;
- fd = open (fh_get_file_name (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;
+ 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 = fdopen (fd, "w");
- if (w->file == NULL)
- {
- close (fd);
- goto open_error;
- }
+ w->file = file;
w->lc = 0;
w->var_cnt = 0;
{
const struct variable *dv = dict_get_var (dict, i);
struct pfm_var *pv = &w->vars[i];
- pv->width = var_get_width (dv);
+ pv->width = MIN (var_get_width (dv), MAX_POR_WIDTH);
pv->fv = var_get_case_index (dv);
}
write_version_data (w);
write_variables (w, dict);
write_value_labels (w, dict);
+ if (dict_get_document_line_cnt (dict) > 0)
+ write_documents (w, dict);
buf_write (w, "F", 1);
if (ferror (w->file))
- goto error;
- return casewriter_create (&por_file_casewriter_class, w);
-
- error:
- close_writer (w);
- return NULL;
-
- open_error:
- msg (ME, _("An error occurred while opening \"%s\" for writing "
- "as a portable file: %s."),
- fh_get_file_name (fh), strerror (errno));
- goto error;
+ {
+ close_writer (w);
+ return NULL;
+ }
+ return casewriter_create (dict_get_next_value_idx (dict),
+ &por_file_casewriter_class, w);
}
\f
/* Write NBYTES starting at BUF to the portable file represented by
write_string (w, host_system);
}
-/* Write format F to file H. */
+/* Write format F to file H. The format is first resized to fit
+ a value of the given WIDTH, which is handy in case F
+ represents a string longer than 255 bytes and thus WIDTH is
+ truncated to 255 bytes. */
static void
-write_format (struct pfm_writer *w, const struct fmt_spec *f)
+write_format (struct pfm_writer *w, struct fmt_spec f, int width)
{
- write_int (w, fmt_to_io (f->type));
- write_int (w, f->w);
- write_int (w, f->d);
+ fmt_resize (&f, width);
+ write_int (w, fmt_to_io (f.type));
+ write_int (w, f.w);
+ write_int (w, f.d);
}
/* Write value V for variable VV to file H. */
write_float (w, v->f);
else
{
- write_int (w, var_get_width (vv));
- buf_write (w, v->s, var_get_width (vv));
+ int width = MIN (var_get_width (vv), MAX_POR_WIDTH);
+ write_int (w, width);
+ buf_write (w, v->s, width);
}
}
{
int i;
- dict_assign_short_names (dict);
+ short_names_assign (dict);
+ if (dict_get_weight (dict) != NULL)
+ {
+ buf_write (w, "6", 1);
+ write_string (w, var_get_short_name (dict_get_weight (dict), 0));
+ }
+
buf_write (w, "4", 1);
write_int (w, dict_get_var_cnt (dict));
write_int (w, 161);
{
struct variable *v = dict_get_var (dict, i);
struct missing_values mv;
+ int width = MIN (var_get_width (v), MAX_POR_WIDTH);
buf_write (w, "7", 1);
- write_int (w, var_get_width (v));
- write_string (w, var_get_short_name (v));
- write_format (w, var_get_print_format (v));
- write_format (w, var_get_write_format (v));
+ write_int (w, width);
+ write_string (w, var_get_short_name (v, 0));
+ write_format (w, *var_get_print_format (v), width);
+ write_format (w, *var_get_write_format (v), width);
/* Write missing values. */
mv_copy (&mv, var_get_missing_values (v));
buf_write (w, "D", 1);
write_int (w, 1);
- write_string (w, var_get_short_name (v));
+ 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;
}
}
-/* Writes case C to the portable file represented by H. */
+/* Write documents in DICT to portable file W. */
+static void
+write_documents (struct pfm_writer *w, const struct dictionary *dict)
+{
+ size_t line_cnt = dict_get_document_line_cnt (dict);
+ struct string line = DS_EMPTY_INITIALIZER;
+ int i;
+
+ 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));
+ }
+ ds_destroy (&line);
+}
+
+/* Writes case C to the portable file represented by WRITER. */
static void
por_file_casewriter_write (struct casewriter *writer, void *w_,
struct ccase *c)