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/>. */
19 #include "data/case-tmpfile.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. */
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. */
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. */
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));
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. */
66 case_tmpfile_create (const struct caseproto
*proto
)
68 struct case_tmpfile
*ctf
;
72 ctf
= xmalloc (sizeof *ctf
);
73 ctf
->taint
= taint_create ();
74 ctf
->ext_array
= ext_array_create ();
75 ctf
->proto
= caseproto_ref (proto
);
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
;
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
93 case_tmpfile_destroy (struct case_tmpfile
*ctf
)
98 struct taint
*taint
= ctf
->taint
;
99 ext_array_destroy (ctf
->ext_array
);
100 caseproto_unref (ctf
->proto
);
103 ok
= taint_destroy (taint
);
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
112 case_tmpfile_error (const struct case_tmpfile
*ctf
)
114 return taint_is_tainted (ctf
->taint
);
117 /* Marks CTF as tainted. */
119 case_tmpfile_force_error (struct case_tmpfile
*ctf
)
121 taint_set_taint (ctf
->taint
);
124 /* Returns CTF's taint object. */
126 case_tmpfile_get_taint (const struct case_tmpfile
*ctf
)
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. */
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
;
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
);
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
)))
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. */
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
)))
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. */
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
;
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
);
196 && !ext_array_write (ctf
->ext_array
, case_offset
+ ctf
->offsets
[i
],
197 width_to_n_bytes (width
),
198 value_to_data (values
++, width
)))
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. */
208 case_tmpfile_put_case (struct case_tmpfile
*ctf
, casenumber case_idx
,
211 bool ok
= case_tmpfile_put_values (ctf
, case_idx
, 0, case_data_all (c
),
212 caseproto_get_n_widths (ctf
->proto
));