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/>. */
17 /* A interface to allow a temporary file to be treated as an
22 #include <libpspp/tmpfile.h>
28 #include <libpspp/assertion.h>
34 #define _(msgid) gettext (msgid)
38 FILE *file; /* Underlying file. */
40 /* Current byte offset in file. We track this manually,
41 instead of using ftello, because in glibc ftello flushes
42 the stream buffer, making the common case of sequential
43 access to cases unreasonably slow. */
47 /* Creates and returns a new temporary file. The temporary file
48 will be automatically deleted when the process exits. */
52 struct tmpfile *tf = xmalloc (sizeof *tf);
53 tf->file = tmpfile ();
55 error (0, errno, _("failed to create temporary file"));
60 /* Closes and destroys temporary file TF. Returns true if I/O on
61 TF always succeeded, false if an I/O error occurred at some
64 tmpfile_destroy (struct tmpfile *tf)
69 ok = !tmpfile_error (tf);
77 /* Seeks TF's underlying file to the start of `union value'
78 VALUE_IDX within case CASE_IDX.
79 Returns true if the seek is successful and TF is not
80 otherwise tainted, false otherwise. */
82 do_seek (const struct tmpfile *tf_, off_t offset)
84 struct tmpfile *tf = (struct tmpfile *) tf_;
86 if (!tmpfile_error (tf))
88 if (tf->position == offset)
90 else if (fseeko (tf->file, offset, SEEK_SET) == 0)
92 tf->position = offset;
96 error (0, errno, _("seeking in temporary file"));
102 /* Reads BYTES bytes from TF's underlying file into BUFFER.
103 TF must not be tainted upon entry into this function.
104 Returns true if successful, false upon an I/O error (in which
105 case TF is marked tainted). */
107 do_read (const struct tmpfile *tf_, void *buffer, size_t bytes)
109 struct tmpfile *tf = (struct tmpfile *) tf_;
111 assert (!tmpfile_error (tf));
112 if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1)
114 if (ferror (tf->file))
115 error (0, errno, _("reading temporary file"));
116 else if (feof (tf->file))
117 error (0, 0, _("unexpected end of file reading temporary file"));
122 tf->position += bytes;
126 /* Writes BYTES bytes from BUFFER into TF's underlying file.
127 TF must not be tainted upon entry into this function.
128 Returns true if successful, false upon an I/O error (in which
129 case TF is marked tainted). */
131 do_write (struct tmpfile *tf, const void *buffer, size_t bytes)
133 assert (!tmpfile_error (tf));
134 if (bytes > 0 && fwrite (buffer, bytes, 1, tf->file) != 1)
136 error (0, errno, _("writing to temporary file"));
139 tf->position += bytes;
143 /* Reads N bytes from TF at byte offset OFFSET into DATA.
144 Returns true if successful, false on failure. */
146 tmpfile_read (const struct tmpfile *tf, off_t offset, size_t n, void *data)
148 return do_seek (tf, offset) && do_read (tf, data, n);
151 /* Writes the N bytes in DATA to TF at byte offset OFFSET.
152 Returns true if successful, false on failure. */
154 tmpfile_write (struct tmpfile *tf, off_t offset, size_t n, const void *data)
156 return do_seek (tf, offset) && do_write (tf, data, n);
159 /* Returns true if an error has occurred in I/O on TF,
160 false if no error has been detected. */
162 tmpfile_error (const struct tmpfile *tf)
164 return tf->file == NULL || ferror (tf->file) || feof (tf->file);