1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011, 2012 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 /* An interface to an array of octets that is stored on disk as a temporary
22 #include "libpspp/ext-array.h"
23 #include "libpspp/message.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/cast.h"
31 #include "libpspp/temp-file.h"
33 #include "gl/unlocked-io.h"
34 #include "gl/xalloc.h"
37 #define _(msgid) gettext (msgid)
41 OP_WRITE, /* writing */
47 FILE *file; /* Underlying file. */
49 /* Current byte offset in file. We track this manually,
50 instead of using ftello, because in glibc ftello flushes
51 the stream buffer, making the common case of sequential
52 access to cases unreasonably slow. */
55 /* The most recent operation performed */
59 /* Creates and returns a new external array. */
61 ext_array_create (void)
63 struct ext_array *ea = xmalloc (sizeof *ea);
64 ea->file = create_temp_file ();
66 msg_error (errno, _("failed to create temporary file"));
72 /* Closes and destroys external array EA. Returns true if I/O on EA always
73 succeeded, false if an I/O error occurred at some point. */
75 ext_array_destroy (struct ext_array *ea)
80 ok = !ext_array_error (ea);
82 close_temp_file (ea->file);
88 /* Seeks EA's underlying file to the start of `union value'
89 VALUE_IDX within case CASE_IDX.
90 Returns true if the seek is successful and EA is not
91 otherwise tainted, false otherwise. */
93 do_seek (const struct ext_array *ea_, off_t offset, enum op op)
95 struct ext_array *ea = CONST_CAST (struct ext_array *, ea_);
96 if (!ext_array_error (ea))
98 if (ea->position == offset && ea->op == op)
100 else if (fseeko (ea->file, offset, SEEK_SET) == 0)
102 ea->position = offset;
106 msg_error (errno, _("seeking in temporary file"));
112 /* Reads BYTES bytes from EA's underlying file into BUFFER.
113 EA must not be tainted upon entry into this function.
114 Returns true if successful, false upon an I/O error (in which
115 case EA is marked tainted). */
117 do_read (const struct ext_array *ea_, void *buffer, size_t bytes)
119 struct ext_array *ea = CONST_CAST (struct ext_array *, ea_);
121 assert (!ext_array_error (ea));
122 if (bytes > 0 && fread (buffer, bytes, 1, ea->file) != 1)
124 if (ferror (ea->file))
125 msg_error (errno, _("reading temporary file"));
126 else if (feof (ea->file))
127 msg_error ( 0, _("unexpected end of file reading temporary file"));
132 ea->position += bytes;
137 /* Writes BYTES bytes from BUFFER into EA's underlying file.
138 EA must not be tainted upon entry into this function.
139 Returns true if successful, false upon an I/O error (in which
140 case EA is marked tainted). */
142 do_write (struct ext_array *ea, const void *buffer, size_t bytes)
144 assert (!ext_array_error (ea));
145 if (bytes > 0 && fwrite (buffer, bytes, 1, ea->file) != 1)
147 msg_error (errno, _("writing to temporary file"));
150 ea->position += bytes;
155 /* Reads N bytes from EA at byte offset OFFSET into DATA.
156 Returns true if successful, false on failure. */
158 ext_array_read (const struct ext_array *ea, off_t offset, size_t n, void *data)
160 return do_seek (ea, offset, OP_READ) && do_read (ea, data, n);
164 /* Writes the N bytes in DATA to EA at byte offset OFFSET.
165 Returns true if successful, false on failure. */
167 ext_array_write (struct ext_array *ea, off_t offset, size_t n,
170 return do_seek (ea, offset, OP_WRITE) && do_write (ea, data, n);
173 /* Returns true if an error has occurred in I/O on EA,
174 false if no error has been detected. */
176 ext_array_error (const struct ext_array *ea)
178 return ea->file == NULL || ferror (ea->file) || feof (ea->file);