X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fmdd-writer.c;fp=src%2Fdata%2Fmdd-writer.c;h=97efe22aa2f84ade92ad89953fd6006612a23ad7;hb=4063e370381d696fa221a5987e596b78abb4d7c3;hp=0000000000000000000000000000000000000000;hpb=e2f99612bf4f4691623f16730eed3e55afdc54f0;p=pspp diff --git a/src/data/mdd-writer.c b/src/data/mdd-writer.c new file mode 100644 index 0000000000..97efe22aa2 --- /dev/null +++ b/src/data/mdd-writer.c @@ -0,0 +1,245 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "data/mdd-writer.h" + +#include +#include +#include +#include +#include + +#include "data/dictionary.h" +#include "data/file-handle-def.h" +#include "data/make-file.h" +#include "data/short-names.h" +#include "data/value-labels.h" +#include "data/variable.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" + +#include "gl/ftoastr.h" +#include "gl/xalloc.h" +#include "gl/xmemdup0.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) (msgid) + +#define _xml(X) (CHAR_CAST (const xmlChar *, (X))) + +/* Metadata file writer. */ +struct mdd_writer + { + struct file_handle *fh; /* File handle. */ + struct fh_lock *lock; /* Mutual exclusion for file. */ + FILE *file; /* File stream. */ + struct replace_file *rf; /* Ticket for replacing output file. */ + + xmlTextWriter *writer; + }; + +/* Returns true if an I/O error has occurred on WRITER, false otherwise. */ +static bool +mdd_write_error (const struct mdd_writer *writer) +{ + return ferror (writer->file); +} + +static bool +mdd_close (struct mdd_writer *w) +{ + if (!w) + return true; + + if (w->writer) + xmlFreeTextWriter (w->writer); + + bool ok = true; + if (w->file) + { + fflush (w->file); + + ok = !mdd_write_error (w); + if (fclose (w->file) == EOF) + ok = false; + + if (!ok) + msg (ME, _("An I/O error occurred writing metadata file `%s'."), + fh_get_file_name (w->fh)); + + if (ok ? !replace_file_commit (w->rf) : !replace_file_abort (w->rf)) + ok = false; + } + + fh_unlock (w->lock); + fh_unref (w->fh); + + free (w); + + return ok; +} + +bool +mdd_write (struct file_handle *fh, struct dictionary *dict, + const char *sav_name) +{ + struct mdd_writer *w = xzalloc (sizeof *w); + + /* Open file handle as an exclusive writer. */ + /* TRANSLATORS: this fragment will be interpolated into + messages in fh_lock() that identify types of files. */ + w->lock = fh_lock (fh, FH_REF_FILE, N_("metadata file"), FH_ACC_WRITE, true); + if (w->lock == NULL) + goto error; + + /* Create the file on disk. */ + w->rf = replace_file_start (fh, "wb", 0444, &w->file); + if (w->rf == NULL) + { + msg (ME, _("Error opening `%s' for writing as a metadata file: %s."), + fh_get_file_name (fh), strerror (errno)); + goto error; + } + + w->writer = xmlNewTextWriter (xmlOutputBufferCreateFile (w->file, NULL)); + if (!w->writer) + { + msg (ME, _("Internal error creating xmlTextWriter.")); + goto error; + } + + xmlTextWriterStartDocument (w->writer, NULL, "UTF-8", NULL); + + /* */ + xmlTextWriterStartPI (w->writer, _xml ("xml-stylesheet")); + xmlTextWriterWriteString (w->writer, + _xml ("type=\"text/xsl\" href=\"mdd.xslt\"")); + xmlTextWriterEndPI (w->writer); + + xmlTextWriterStartElement (w->writer, _xml ("xml")); + + /* */ + xmlTextWriterStartElementNS ( + w->writer, _xml ("mdm"), _xml ("xml"), + _xml ("http://www.spss.com/mr/dm/metadatamodel/Arc 3/2000-02-04")); + static const struct pair + { + const char *key, *value; + } + pairs[] = + { + { "mdm_createversion", "7.0.0.0.331" }, + { "mdm_lastversion", "7.0.0.0.331" }, + { "id", "c4c181c1-0d7c-42e3-abcd-f08296d1dfdc" }, + { "data_version", "9" }, + { "data_sub_version", "1" }, + { "systemvariable", "0" }, + { "dbfiltervalidation", "-1" }, + }; + const int n_pairs = sizeof pairs / sizeof *pairs; + for (const struct pair *p = pairs; p < &pairs[n_pairs]; p++) + xmlTextWriterWriteAttribute (w->writer, _xml (p->key), _xml (p->value)); + xmlTextWriterEndElement (w->writer); + + /* */ + xmlTextWriterStartElement (w->writer, _xml ("atoms")); + xmlTextWriterEndElement (w->writer); + + /* */ + xmlTextWriterStartElement (w->writer, _xml ("datasources")); + xmlTextWriterWriteAttribute (w->writer, _xml ("default"), _xml ("mrSavDsc")); + + /* */ + xmlTextWriterStartElement (w->writer, _xml ("connection")); + xmlTextWriterWriteAttribute (w->writer, _xml ("name"), _xml ("mrSavDsc")); + xmlTextWriterWriteAttribute (w->writer, _xml ("dblocation"), + _xml (sav_name)); + xmlTextWriterWriteAttribute (w->writer, + _xml ("cdscname"), _xml ("mrSavDsc")); + xmlTextWriterWriteAttribute (w->writer, _xml ("project"), _xml ("126")); + + size_t n_vars = dict_get_var_cnt (dict); + short_names_assign (dict); + for (size_t i = 0; i < n_vars; i++) + { + const struct variable *var = dict_get_var (dict, i); + xmlTextWriterStartElement (w->writer, _xml ("var")); + + /* XXX Should convert short name to all-lowercase below. */ + xmlTextWriterWriteAttribute (w->writer, _xml ("fullname"), + _xml (var_get_short_name (var, 0))); + xmlTextWriterWriteAttribute (w->writer, _xml ("aliasname"), + _xml (var_get_name (var))); + + const struct val_labs *val_labs = var_get_value_labels (var); + size_t n_vls = val_labs_count (val_labs); + if (n_vls) + { + const struct val_lab **vls = val_labs_sorted (val_labs); + + xmlTextWriterStartElement (w->writer, _xml ("nativevalues")); + int width = var_get_width (var); + for (size_t j = 0; j < n_vls; j++) + { + const struct val_lab *vl = vls[j]; + xmlTextWriterStartElement (w->writer, _xml ("nativevalue")); + /* XXX Should convert to lowercase, change non-id characters to + _, prefix with _ if starts with non-letter */ + xmlTextWriterWriteAttribute (w->writer, _xml ("fullname"), + _xml (val_lab_get_label (vl))); + + /* XXX below would better use syntax_gen_value(). */ + const union value *value = val_lab_get_value (vl); + if (width) + { + char *s = xmemdup0 (value_str (value, width), width); + xmlTextWriterWriteAttribute (w->writer, _xml ("value"), + _xml (s)); + free (s); + } + else + { + char s[DBL_BUFSIZE_BOUND]; + + c_dtoastr (s, sizeof s, 0, 0, value->f); + xmlTextWriterWriteAttribute (w->writer, _xml ("value"), + _xml (s)); + } + xmlTextWriterEndElement (w->writer); + } + xmlTextWriterEndElement (w->writer); + + free (vls); + } + + xmlTextWriterEndElement (w->writer); + } + + xmlTextWriterEndElement (w->writer); /* */ + + xmlTextWriterEndDocument (w->writer); + +error: + mdd_close (w); + return NULL; +}