1 /* PSPP - computes sample statistics.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <data/case-tmpfile.h>
27 #include <libpspp/assertion.h>
28 #include <libpspp/taint.h>
34 #define _(msgid) gettext (msgid)
36 /* A temporary file that stores an array of cases. */
39 struct taint *taint; /* Taint. */
40 FILE *file; /* Underlying file. */
41 size_t value_cnt; /* Number of `union value's per case. */
43 /* Current byte offset in file. We track this manually,
44 instead of using ftello, because in glibc ftello flushes
45 the stream buffer, making the common case of sequential
46 access to cases unreasonably slow. */
50 /* Creates and returns a new case_tmpfile. */
52 case_tmpfile_create (size_t value_cnt)
54 struct case_tmpfile *ctf = xmalloc (sizeof *ctf);
55 ctf->taint = taint_create ();
56 ctf->file = tmpfile ();
57 if (ctf->file == NULL)
59 error (0, errno, _("failed to create temporary file"));
60 taint_set_taint (ctf->taint);
62 ctf->value_cnt = value_cnt;
67 /* Destroys case_tmpfile CTF.
68 Returns true if CTF was tainted, which is caused by an I/O
69 error on case_tmpfile access or by taint propagation to the
72 case_tmpfile_destroy (struct case_tmpfile *ctf)
77 struct taint *taint = ctf->taint;
78 if (ctf->file != NULL)
81 ok = taint_destroy (taint);
86 /* Returns true if CTF is tainted, which is caused by an I/O
87 error on case_tmpfile access or by taint propagation to the
90 case_tmpfile_error (const struct case_tmpfile *ctf)
92 return taint_is_tainted (ctf->taint);
95 /* Marks CTF as tainted. */
97 case_tmpfile_force_error (struct case_tmpfile *ctf)
99 taint_set_taint (ctf->taint);
102 /* Returns CTF's taint object. */
104 case_tmpfile_get_taint (const struct case_tmpfile *ctf)
109 /* Seeks CTF's underlying file to the start of `union value'
110 VALUE_IDX within case CASE_IDX.
111 Returns true if the seek is successful and CTF is not
112 otherwise tainted, false otherwise. */
114 do_seek (const struct case_tmpfile *ctf_,
115 casenumber case_idx, size_t value_idx)
117 struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
119 if (!case_tmpfile_error (ctf))
121 off_t value_ofs = value_idx + (off_t) ctf->value_cnt * case_idx;
122 off_t byte_ofs = sizeof (union value) * value_ofs;
124 if (ctf->position == byte_ofs)
126 else if (fseeko (ctf->file, byte_ofs, SEEK_SET) == 0)
128 ctf->position = byte_ofs;
133 error (0, errno, _("seeking in temporary file"));
134 case_tmpfile_force_error (ctf);
141 /* Reads BYTES bytes from CTF's underlying file into BUFFER.
142 CTF must not be tainted upon entry into this function.
143 Returns true if successful, false upon an I/O error (in which
144 case CTF is marked tainted). */
146 do_read (const struct case_tmpfile *ctf_, size_t bytes, void *buffer)
148 struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
150 assert (!case_tmpfile_error (ctf));
151 if (fread (buffer, bytes, 1, ctf->file) != 1)
153 case_tmpfile_force_error (ctf);
154 if (ferror (ctf->file))
155 error (0, errno, _("reading temporary file"));
156 else if (feof (ctf->file))
157 error (0, 0, _("unexpected end of file reading temporary file"));
162 ctf->position += bytes;
166 /* Writes BYTES bytes from BUFFER into CTF's underlying file.
167 CTF must not be tainted upon entry into this function.
168 Returns true if successful, false upon an I/O error (in which
169 case CTF is marked tainted). */
171 do_write (struct case_tmpfile *ctf, size_t bytes, const void *buffer)
173 assert (!case_tmpfile_error (ctf));
174 if (fwrite (buffer, bytes, 1, ctf->file) != 1)
176 case_tmpfile_force_error (ctf);
177 error (0, errno, _("writing to temporary file"));
180 ctf->position += bytes;
184 /* Reads VALUE_CNT values into VALUES, from the case numbered
185 CASE_IDX starting START_VALUE values into that case.
186 Returns true if successful, false if CTF is tainted or an I/O
187 error occurs during the operation.
189 The results of this function are undefined if any of the
190 values read have not been previously written to CTF. */
192 case_tmpfile_get_values (const struct case_tmpfile *ctf,
193 casenumber case_idx, size_t start_value,
194 union value values[], size_t value_cnt)
196 assert (value_cnt <= ctf->value_cnt);
197 assert (value_cnt + start_value <= ctf->value_cnt);
199 return (do_seek (ctf, case_idx, start_value)
200 && do_read (ctf, sizeof *values * value_cnt, values));
203 /* Reads the case numbered CASE_IDX from CTF into C.
204 Returns true if successful, false if CTF is tainted or an I/O
205 error occurs during the operation.
207 The results of this function are undefined if the case read
208 from CTF had not previously been written. */
210 case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx,
213 case_create (c, ctf->value_cnt);
214 if (case_tmpfile_get_values (ctf, case_idx, 0,
215 case_data_all_rw (c), ctf->value_cnt))
225 /* Writes VALUE_CNT values from VALUES, into the case numbered
226 CASE_IDX starting START_VALUE values into that case.
227 Returns true if successful, false if CTF is tainted or an I/O
228 error occurs during the operation. */
230 case_tmpfile_put_values (struct case_tmpfile *ctf,
231 casenumber case_idx, size_t start_value,
232 const union value values[], size_t value_cnt)
235 assert (value_cnt <= ctf->value_cnt);
236 assert (value_cnt + start_value <= ctf->value_cnt);
238 return (do_seek (ctf, case_idx, start_value)
239 && do_write (ctf, sizeof *values * value_cnt, values));
242 /* Writes C to CTF as the case numbered CASE_IDX.
243 Returns true if successful, false if CTF is tainted or an I/O
244 error occurs during the operation. */
246 case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
249 bool ok = case_tmpfile_put_values (ctf, case_idx, 0,
250 case_data_all (c), ctf->value_cnt);