pc+-file-reader: Fix memory leak.
[pspp.git] / src / data / case-tmpfile.c
blob2b124341b67820f8be89c6f3224c1a48a4fcae52
1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011 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 #include <config.h>
19 #include "data/case-tmpfile.h"
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
25 #include "libpspp/assertion.h"
26 #include "libpspp/taint.h"
27 #include "libpspp/ext-array.h"
29 #include "gl/xalloc.h"
31 /* A temporary file that stores an array of cases. */
32 struct case_tmpfile
34 struct taint *taint; /* Taint. */
35 struct caseproto *proto; /* Format of cases in the tmpfile. */
36 size_t case_size; /* Number of bytes per case. */
37 size_t *offsets; /* Offset to each value. */
38 struct ext_array *ext_array; /* Temporary file. */
41 /* Returns the number of bytes needed to store a value with the
42 given WIDTH on disk. */
43 static size_t
44 width_to_n_bytes (int width)
46 return width == 0 ? sizeof (double) : width;
49 /* Returns the address of the data in VALUE (for reading or
50 writing to/from disk). VALUE must have the given WIDTH. */
51 static void *
52 value_to_data (const union value *value_, int width)
54 union value *value = CONST_CAST (union value *, value_);
55 assert (sizeof value->f == sizeof (double));
56 if (width == 0)
57 return &value->f;
58 else
59 return value_str_rw (value, width);
62 /* Creates and returns a new case_tmpfile that will store cases
63 that match case prototype PROTO. The caller retains
64 ownership of PROTO. */
65 struct case_tmpfile *
66 case_tmpfile_create (const struct caseproto *proto)
68 struct case_tmpfile *ctf;
69 size_t n_values;
70 size_t i;
72 ctf = xmalloc (sizeof *ctf);
73 ctf->taint = taint_create ();
74 ctf->ext_array = ext_array_create ();
75 ctf->proto = caseproto_ref (proto);
76 ctf->case_size = 0;
77 n_values = caseproto_get_n_widths (proto);
78 ctf->offsets = xmalloc (n_values * sizeof *ctf->offsets);
79 for (i = 0; i < n_values; i++)
81 size_t width = caseproto_get_width (proto, i);
82 ctf->offsets[i] = ctf->case_size;
83 ctf->case_size += width == -1 ? 0 : width == 0 ? sizeof (double) : width;
85 return ctf;
88 /* Destroys case_tmpfile CTF.
89 Returns true if CTF was tainted, which is caused by an I/O
90 error on case_tmpfile access or by taint propagation to the
91 case_tmpfile. */
92 bool
93 case_tmpfile_destroy (struct case_tmpfile *ctf)
95 bool ok = true;
96 if (ctf != NULL)
98 struct taint *taint = ctf->taint;
99 ext_array_destroy (ctf->ext_array);
100 caseproto_unref (ctf->proto);
101 free (ctf->offsets);
102 free (ctf);
103 ok = taint_destroy (taint);
105 return ok;
108 /* Returns true if CTF is tainted, which is caused by an I/O
109 error on case_tmpfile access or by taint propagation to the
110 case_tmpfile. */
111 bool
112 case_tmpfile_error (const struct case_tmpfile *ctf)
114 return taint_is_tainted (ctf->taint);
117 /* Marks CTF as tainted. */
118 void
119 case_tmpfile_force_error (struct case_tmpfile *ctf)
121 taint_set_taint (ctf->taint);
124 /* Returns CTF's taint object. */
125 const struct taint *
126 case_tmpfile_get_taint (const struct case_tmpfile *ctf)
128 return ctf->taint;
131 /* Reads N_VALUES values into VALUES, from the case numbered
132 CASE_IDX starting START_VALUE values into that case. Returns
133 true if successful, false if CTF is tainted or an I/O error
134 occurs during the operation.
136 The results of this function are undefined if any of the
137 values read have not been previously written to CTF. */
138 bool
139 case_tmpfile_get_values (const struct case_tmpfile *ctf,
140 casenumber case_idx, size_t start_value,
141 union value values[], size_t n_values)
143 off_t case_offset = (off_t) ctf->case_size * case_idx;
144 size_t i;
146 assert (caseproto_range_is_valid (ctf->proto, start_value, n_values));
147 for (i = start_value; i < start_value + n_values; i++)
149 int width = caseproto_get_width (ctf->proto, i);
150 if (width != -1
151 && !ext_array_read (ctf->ext_array, case_offset + ctf->offsets[i],
152 width_to_n_bytes (width),
153 value_to_data (&values[i], width)))
154 return false;
156 return true;
159 /* Reads the case numbered CASE_IDX from CTF.
160 Returns the case if successful or a null pointer if CTF is
161 tainted or an I/O error occurs during the operation.
163 The results of this function are undefined if the case read
164 from CTF had not previously been written. */
165 struct ccase *
166 case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx)
168 struct ccase *c = case_create (ctf->proto);
169 if (case_tmpfile_get_values (ctf, case_idx, 0, case_data_all_rw (c),
170 caseproto_get_n_widths (ctf->proto)))
171 return c;
172 else
174 case_unref (c);
175 return NULL;
179 /* Writes N_VALUES values from VALUES, into the case numbered
180 CASE_IDX starting START_VALUE values into that case.
181 Returns true if successful, false if CTF is tainted or an I/O
182 error occurs during the operation. */
183 bool
184 case_tmpfile_put_values (struct case_tmpfile *ctf,
185 casenumber case_idx, size_t start_value,
186 const union value values[], size_t n_values)
188 off_t case_offset = (off_t) ctf->case_size * case_idx;
189 size_t i;
191 assert (caseproto_range_is_valid (ctf->proto, start_value, n_values));
192 for (i = start_value; i < start_value + n_values; i++)
194 int width = caseproto_get_width (ctf->proto, i);
195 if (width != -1
196 && !ext_array_write (ctf->ext_array, case_offset + ctf->offsets[i],
197 width_to_n_bytes (width),
198 value_to_data (values++, width)))
199 return false;
201 return true;
204 /* Writes C to CTF as the case numbered CASE_IDX.
205 Returns true if successful, false if CTF is tainted or an I/O
206 error occurs during the operation. */
207 bool
208 case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
209 struct ccase *c)
211 bool ok = case_tmpfile_put_values (ctf, case_idx, 0, case_data_all (c),
212 caseproto_get_n_widths (ctf->proto));
213 case_unref (c);
214 return ok;