1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010 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/>. */
17 /* A interface to allow a temporary file to be treated as an
22 #include <libpspp/temp-file.h>
28 #include <libpspp/assertion.h>
29 #include <libpspp/cast.h>
35 #define _(msgid) gettext (msgid)
39 FILE *file; /* Underlying file. */
41 /* Current byte offset in file. We track this manually,
42 instead of using ftello, because in glibc ftello flushes
43 the stream buffer, making the common case of sequential
44 access to cases unreasonably slow. */
48 /* Creates and returns a new temporary file. The temporary file
49 will be automatically deleted when the process exits. */
51 temp_file_create (void)
53 struct temp_file *tf = xmalloc (sizeof *tf);
54 tf->file = tmpfile ();
56 error (0, errno, _("failed to create temporary file"));
61 /* Closes and destroys temporary file TF. Returns true if I/O on
62 TF always succeeded, false if an I/O error occurred at some
65 temp_file_destroy (struct temp_file *tf)
70 ok = !temp_file_error (tf);
78 /* Seeks TF's underlying file to the start of `union value'
79 VALUE_IDX within case CASE_IDX.
80 Returns true if the seek is successful and TF is not
81 otherwise tainted, false otherwise. */
83 do_seek (const struct temp_file *tf_, off_t offset)
85 struct temp_file *tf = CONST_CAST (struct temp_file *, tf_);
87 if (!temp_file_error (tf))
89 if (tf->position == offset)
91 else if (fseeko (tf->file, offset, SEEK_SET) == 0)
93 tf->position = offset;
97 error (0, errno, _("seeking in temporary file"));
103 /* Reads BYTES bytes from TF's underlying file into BUFFER.
104 TF must not be tainted upon entry into this function.
105 Returns true if successful, false upon an I/O error (in which
106 case TF is marked tainted). */
108 do_read (const struct temp_file *tf_, void *buffer, size_t bytes)
110 struct temp_file *tf = CONST_CAST (struct temp_file *, tf_);
112 assert (!temp_file_error (tf));
113 if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1)
115 if (ferror (tf->file))
116 error (0, errno, _("reading temporary file"));
117 else if (feof (tf->file))
118 error (0, 0, _("unexpected end of file reading temporary file"));
123 tf->position += bytes;
127 /* Writes BYTES bytes from BUFFER into TF's underlying file.
128 TF must not be tainted upon entry into this function.
129 Returns true if successful, false upon an I/O error (in which
130 case TF is marked tainted). */
132 do_write (struct temp_file *tf, const void *buffer, size_t bytes)
134 assert (!temp_file_error (tf));
135 if (bytes > 0 && fwrite (buffer, bytes, 1, tf->file) != 1)
137 error (0, errno, _("writing to temporary file"));
140 tf->position += bytes;
144 /* Reads N bytes from TF at byte offset OFFSET into DATA.
145 Returns true if successful, false on failure. */
147 temp_file_read (const struct temp_file *tf, off_t offset, size_t n, void *data)
149 return do_seek (tf, offset) && do_read (tf, data, n);
152 /* Writes the N bytes in DATA to TF at byte offset OFFSET.
153 Returns true if successful, false on failure. */
155 temp_file_write (struct temp_file *tf, off_t offset, size_t n,
158 return do_seek (tf, offset) && do_write (tf, data, n);
161 /* Returns true if an error has occurred in I/O on TF,
162 false if no error has been detected. */
164 temp_file_error (const struct temp_file *tf)
166 return tf->file == NULL || ferror (tf->file) || feof (tf->file);