X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcase-tmpfile.c;h=5744786611a737fb467f8f7c4c9673164696cc40;hb=5c3291dc396b795696e94f47780308fd7ace6fc4;hp=ca3a6a564421552f4241900caa2fb21708f08226;hpb=cc57a28ef6796ae9a64ef80d453f72126956d49d;p=pspp-builds.git diff --git a/src/data/case-tmpfile.c b/src/data/case-tmpfile.c index ca3a6a56..57447866 100644 --- a/src/data/case-tmpfile.c +++ b/src/data/case-tmpfile.c @@ -24,41 +24,65 @@ #include #include +#include #include "error.h" #include "xalloc.h" -#include "gettext.h" -#define _(msgid) gettext (msgid) - /* A temporary file that stores an array of cases. */ struct case_tmpfile { struct taint *taint; /* Taint. */ - FILE *file; /* Underlying file. */ - size_t value_cnt; /* Number of `union value's per case. */ - - /* Current byte offset in file. We track this manually, - instead of using ftello, because in glibc ftello flushes - the stream buffer, making the common case of sequential - access to cases unreasonably slow. */ - off_t position; + struct caseproto *proto; /* Format of cases in the tmpfile. */ + size_t case_size; /* Number of bytes per case. */ + size_t *offsets; /* Offset to each value. */ + struct tmpfile *tmpfile; /* Temporary file. */ }; -/* Creates and returns a new case_tmpfile. */ +/* Returns the number of bytes needed to store a value with the + given WIDTH on disk. */ +static size_t +width_to_n_bytes (int width) +{ + return width == 0 ? sizeof (double) : width; +} + +/* Returns the address of the data in VALUE (for reading or + writing to/from disk). VALUE must have the given WIDTH. */ +static void * +value_to_data (const union value *value_, int width) +{ + union value *value = (union value *) value_; + assert (sizeof value->f == sizeof (double)); + if (width == 0) + return &value->f; + else + return value_str_rw (value, width); +} + +/* Creates and returns a new case_tmpfile that will store cases + that match case prototype PROTO. The caller retains + ownership of PROTO. */ struct case_tmpfile * -case_tmpfile_create (size_t value_cnt) +case_tmpfile_create (const struct caseproto *proto) { - struct case_tmpfile *ctf = xmalloc (sizeof *ctf); + struct case_tmpfile *ctf; + size_t n_values; + size_t i; + + ctf = xmalloc (sizeof *ctf); ctf->taint = taint_create (); - ctf->file = tmpfile (); - if (ctf->file == NULL) + ctf->tmpfile = tmpfile_create (); + ctf->proto = caseproto_ref (proto); + ctf->case_size = 0; + n_values = caseproto_get_n_widths (proto); + ctf->offsets = xmalloc (n_values * sizeof *ctf->offsets); + for (i = 0; i < n_values; i++) { - error (0, errno, _("failed to create temporary file")); - taint_set_taint (ctf->taint); + size_t width = caseproto_get_width (proto, i); + ctf->offsets[i] = ctf->case_size; + ctf->case_size += width == -1 ? 0 : width == 0 ? sizeof (double) : width; } - ctf->value_cnt = value_cnt; - ctf->position = 0; return ctf; } @@ -73,8 +97,9 @@ case_tmpfile_destroy (struct case_tmpfile *ctf) if (ctf != NULL) { struct taint *taint = ctf->taint; - if (ctf->file != NULL) - fclose (ctf->file); + tmpfile_destroy (ctf->tmpfile); + caseproto_unref (ctf->proto); + free (ctf->offsets); free (ctf); ok = taint_destroy (taint); } @@ -104,98 +129,32 @@ case_tmpfile_get_taint (const struct case_tmpfile *ctf) return ctf->taint; } -/* Seeks CTF's underlying file to the start of `union value' - VALUE_IDX within case CASE_IDX. - Returns true if the seek is successful and CTF is not - otherwise tainted, false otherwise. */ -static bool -do_seek (const struct case_tmpfile *ctf_, - casenumber case_idx, size_t value_idx) -{ - struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_; - - if (!case_tmpfile_error (ctf)) - { - off_t value_ofs = value_idx + (off_t) ctf->value_cnt * case_idx; - off_t byte_ofs = sizeof (union value) * value_ofs; - - if (ctf->position == byte_ofs) - return true; - else if (fseeko (ctf->file, byte_ofs, SEEK_SET) == 0) - { - ctf->position = byte_ofs; - return true; - } - else - { - error (0, errno, _("seeking in temporary file")); - case_tmpfile_force_error (ctf); - } - } - - return false; -} - -/* Reads BYTES bytes from CTF's underlying file into BUFFER. - CTF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case CTF is marked tainted). */ -static bool -do_read (const struct case_tmpfile *ctf_, size_t bytes, void *buffer) -{ - struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_; - - assert (!case_tmpfile_error (ctf)); - if (fread (buffer, bytes, 1, ctf->file) != 1) - { - case_tmpfile_force_error (ctf); - if (ferror (ctf->file)) - error (0, errno, _("reading temporary file")); - else if (feof (ctf->file)) - error (0, 0, _("unexpected end of file reading temporary file")); - else - NOT_REACHED (); - return false; - } - ctf->position += bytes; - return true; -} - -/* Writes BYTES bytes from BUFFER into CTF's underlying file. - CTF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case CTF is marked tainted). */ -static bool -do_write (struct case_tmpfile *ctf, size_t bytes, const void *buffer) -{ - assert (!case_tmpfile_error (ctf)); - if (fwrite (buffer, bytes, 1, ctf->file) != 1) - { - case_tmpfile_force_error (ctf); - error (0, errno, _("writing to temporary file")); - return false; - } - ctf->position += bytes; - return true; -} - -/* Reads VALUE_CNT values into VALUES, from the case numbered - CASE_IDX starting START_VALUE values into that case. - Returns true if successful, false if CTF is tainted or an I/O - error occurs during the operation. +/* Reads N_VALUES values into VALUES, from the case numbered + CASE_IDX starting START_VALUE values into that case. Returns + true if successful, false if CTF is tainted or an I/O error + occurs during the operation. The results of this function are undefined if any of the values read have not been previously written to CTF. */ bool case_tmpfile_get_values (const struct case_tmpfile *ctf, casenumber case_idx, size_t start_value, - union value values[], size_t value_cnt) + union value values[], size_t n_values) { - assert (value_cnt <= ctf->value_cnt); - assert (value_cnt + start_value <= ctf->value_cnt); + off_t case_offset = (off_t) ctf->case_size * case_idx; + size_t i; - return (do_seek (ctf, case_idx, start_value) - && do_read (ctf, sizeof *values * value_cnt, values)); + assert (caseproto_range_is_valid (ctf->proto, start_value, n_values)); + for (i = start_value; i < start_value + n_values; i++) + { + int width = caseproto_get_width (ctf->proto, i); + if (width != -1 + && !tmpfile_read (ctf->tmpfile, case_offset + ctf->offsets[i], + width_to_n_bytes (width), + value_to_data (&values[i], width))) + return false; + } + return true; } /* Reads the case numbered CASE_IDX from CTF. @@ -207,9 +166,9 @@ case_tmpfile_get_values (const struct case_tmpfile *ctf, struct ccase * case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx) { - struct ccase *c = case_create (ctf->value_cnt); - if (case_tmpfile_get_values (ctf, case_idx, 0, - case_data_all_rw (c), ctf->value_cnt)) + struct ccase *c = case_create (ctf->proto); + if (case_tmpfile_get_values (ctf, case_idx, 0, case_data_all_rw (c), + caseproto_get_n_widths (ctf->proto))) return c; else { @@ -218,21 +177,29 @@ case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx) } } -/* Writes VALUE_CNT values from VALUES, into the case numbered +/* Writes N_VALUES values from VALUES, into the case numbered CASE_IDX starting START_VALUE values into that case. Returns true if successful, false if CTF is tainted or an I/O error occurs during the operation. */ bool case_tmpfile_put_values (struct case_tmpfile *ctf, casenumber case_idx, size_t start_value, - const union value values[], size_t value_cnt) - + const union value values[], size_t n_values) { - assert (value_cnt <= ctf->value_cnt); - assert (value_cnt + start_value <= ctf->value_cnt); + off_t case_offset = (off_t) ctf->case_size * case_idx; + size_t i; - return (do_seek (ctf, case_idx, start_value) - && do_write (ctf, sizeof *values * value_cnt, values)); + assert (caseproto_range_is_valid (ctf->proto, start_value, n_values)); + for (i = start_value; i < start_value + n_values; i++) + { + int width = caseproto_get_width (ctf->proto, i); + if (width != -1 + && !tmpfile_write (ctf->tmpfile, case_offset + ctf->offsets[i], + width_to_n_bytes (width), + value_to_data (values++, width))) + return false; + } + return true; } /* Writes C to CTF as the case numbered CASE_IDX. @@ -242,8 +209,8 @@ bool case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx, struct ccase *c) { - bool ok = case_tmpfile_put_values (ctf, case_idx, 0, - case_data_all (c), ctf->value_cnt); + bool ok = case_tmpfile_put_values (ctf, case_idx, 0, case_data_all (c), + caseproto_get_n_widths (ctf->proto)); case_unref (c); return ok; }