1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <data/case-tmpfile.h>
25 #include <libpspp/assertion.h>
26 #include <libpspp/taint.h>
27 #include <libpspp/tmpfile.h>
32 /* A temporary file that stores an array of cases. */
35 struct taint *taint; /* Taint. */
36 struct caseproto *proto; /* Format of cases in the tmpfile. */
37 size_t case_size; /* Number of bytes per case. */
38 size_t *offsets; /* Offset to each value. */
39 struct tmpfile *tmpfile; /* Temporary file. */
42 /* Returns the number of bytes needed to store a value with the
43 given WIDTH on disk. */
45 width_to_n_bytes (int width)
47 return width == 0 ? sizeof (double) : width;
50 /* Returns the address of the data in VALUE (for reading or
51 writing to/from disk). VALUE must have the given WIDTH. */
53 value_to_data (const union value *value_, int width)
55 union value *value = (union value *) value_;
56 assert (sizeof value->f == sizeof (double));
60 return value_str_rw (value, width);
63 /* Creates and returns a new case_tmpfile that will store cases
64 that match case prototype PROTO. The caller retains
65 ownership of PROTO. */
67 case_tmpfile_create (const struct caseproto *proto)
69 struct case_tmpfile *ctf;
73 ctf = xmalloc (sizeof *ctf);
74 ctf->taint = taint_create ();
75 ctf->tmpfile = tmpfile_create ();
76 ctf->proto = caseproto_ref (proto);
78 n_values = caseproto_get_n_widths (proto);
79 ctf->offsets = xmalloc (n_values * sizeof *ctf->offsets);
80 for (i = 0; i < n_values; i++)
82 size_t width = caseproto_get_width (proto, i);
83 ctf->offsets[i] = ctf->case_size;
84 ctf->case_size += width == -1 ? 0 : width == 0 ? sizeof (double) : width;
89 /* Destroys case_tmpfile CTF.
90 Returns true if CTF was tainted, which is caused by an I/O
91 error on case_tmpfile access or by taint propagation to the
94 case_tmpfile_destroy (struct case_tmpfile *ctf)
99 struct taint *taint = ctf->taint;
100 tmpfile_destroy (ctf->tmpfile);
101 caseproto_unref (ctf->proto);
104 ok = taint_destroy (taint);
109 /* Returns true if CTF is tainted, which is caused by an I/O
110 error on case_tmpfile access or by taint propagation to the
113 case_tmpfile_error (const struct case_tmpfile *ctf)
115 return taint_is_tainted (ctf->taint);
118 /* Marks CTF as tainted. */
120 case_tmpfile_force_error (struct case_tmpfile *ctf)
122 taint_set_taint (ctf->taint);
125 /* Returns CTF's taint object. */
127 case_tmpfile_get_taint (const struct case_tmpfile *ctf)
132 /* Reads N_VALUES values into VALUES, from the case numbered
133 CASE_IDX starting START_VALUE values into that case. Returns
134 true if successful, false if CTF is tainted or an I/O error
135 occurs during the operation.
137 The results of this function are undefined if any of the
138 values read have not been previously written to CTF. */
140 case_tmpfile_get_values (const struct case_tmpfile *ctf,
141 casenumber case_idx, size_t start_value,
142 union value values[], size_t n_values)
144 off_t case_offset = (off_t) ctf->case_size * case_idx;
147 assert (caseproto_range_is_valid (ctf->proto, start_value, n_values));
148 for (i = start_value; i < start_value + n_values; i++)
150 int width = caseproto_get_width (ctf->proto, i);
152 && !tmpfile_read (ctf->tmpfile, case_offset + ctf->offsets[i],
153 width_to_n_bytes (width),
154 value_to_data (&values[i], width)))
160 /* Reads the case numbered CASE_IDX from CTF.
161 Returns the case if successful or a null pointer if CTF is
162 tainted or an I/O error occurs during the operation.
164 The results of this function are undefined if the case read
165 from CTF had not previously been written. */
167 case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx)
169 struct ccase *c = case_create (ctf->proto);
170 if (case_tmpfile_get_values (ctf, case_idx, 0, case_data_all_rw (c),
171 caseproto_get_n_widths (ctf->proto)))
180 /* Writes N_VALUES values from VALUES, into the case numbered
181 CASE_IDX starting START_VALUE values into that case.
182 Returns true if successful, false if CTF is tainted or an I/O
183 error occurs during the operation. */
185 case_tmpfile_put_values (struct case_tmpfile *ctf,
186 casenumber case_idx, size_t start_value,
187 const union value values[], size_t n_values)
189 off_t case_offset = (off_t) ctf->case_size * case_idx;
192 assert (caseproto_range_is_valid (ctf->proto, start_value, n_values));
193 for (i = start_value; i < start_value + n_values; i++)
195 int width = caseproto_get_width (ctf->proto, i);
197 && !tmpfile_write (ctf->tmpfile, case_offset + ctf->offsets[i],
198 width_to_n_bytes (width),
199 value_to_data (values++, width)))
205 /* Writes C to CTF as the case numbered CASE_IDX.
206 Returns true if successful, false if CTF is tainted or an I/O
207 error occurs during the operation. */
209 case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
212 bool ok = case_tmpfile_put_values (ctf, case_idx, 0, case_data_all (c),
213 caseproto_get_n_widths (ctf->proto));