7043b65e55e7305ae2c7b27b35de7dd048224167
[pspp-builds.git] / src / data / any-writer.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "any-writer.h"
22 #include <assert.h>
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <libpspp/assertion.h>
28 #include <libpspp/message.h>
29 #include "file-handle-def.h"
30 #include "file-name.h"
31 #include "por-file-writer.h"
32 #include "sys-file-writer.h"
33 #include <libpspp/str.h>
34 #include "scratch-writer.h"
35 #include "xalloc.h"
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39
40 /* Type of file backing an any_writer. */
41 enum any_writer_type
42   {
43     SYSTEM_FILE,                /* System file. */
44     PORTABLE_FILE,              /* Portable file. */
45     SCRATCH_FILE                /* Scratch file. */
46   };
47
48 /* Writer for any type of case-structured file. */
49 struct any_writer 
50   {
51     enum any_writer_type type;  /* Type of file. */
52     void *private;              /* Private data. */
53   };
54
55 /* Creates and returns a writer for HANDLE with the given DICT. */
56 struct any_writer *
57 any_writer_open (struct file_handle *handle, struct dictionary *dict)
58 {
59   switch (fh_get_referent (handle)) 
60     {
61     case FH_REF_FILE:
62       {
63         struct any_writer *writer;
64         char *extension;
65
66         extension = fn_extension (fh_get_file_name (handle));
67         str_lowercase (extension);
68
69         if (!strcmp (extension, ".por"))
70           writer = any_writer_from_pfm_writer (
71             pfm_open_writer (handle, dict, pfm_writer_default_options ()));
72         else
73           writer = any_writer_from_sfm_writer (
74             sfm_open_writer (handle, dict, sfm_writer_default_options ()));
75         free (extension);
76
77         return writer;
78       }
79
80     case FH_REF_INLINE:
81       msg (ME, _("The inline file is not allowed here."));
82       return NULL;
83
84     case FH_REF_SCRATCH:
85       return any_writer_from_scratch_writer (scratch_writer_open (handle,
86                                                                   dict));
87     }
88
89   NOT_REACHED ();
90 }
91
92 /* If PRIVATE is non-null, creates and returns a new any_writer,
93    initializing its fields to TYPE and PRIVATE.  If PRIVATE is a
94    null pointer, just returns a null pointer. */   
95 static struct any_writer *
96 make_any_writer (enum any_writer_type type, void *private) 
97 {
98   if (private != NULL) 
99     {
100       struct any_writer *writer = xmalloc (sizeof *writer);
101       writer->type = type;
102       writer->private = private;
103       return writer; 
104     }
105   else
106     return NULL;
107 }
108   
109 /* If SFM_WRITER is non-null, encapsulates SFM_WRITER in an
110    any_writer and returns it.  If SFM_WRITER is null, just
111    returns a null pointer.
112
113    Useful when you need to pass options to sfm_open_writer().
114    Typical usage:
115         any_writer_from_sfm_writer (sfm_open_writer (fh, dict, opts))
116    If you don't need to pass options, then any_writer_open() by
117    itself is easier and more straightforward. */
118 struct any_writer *
119 any_writer_from_sfm_writer (struct sfm_writer *sfm_writer) 
120 {
121   return make_any_writer (SYSTEM_FILE, sfm_writer);
122 }
123
124 /* If PFM_WRITER is non-null, encapsulates PFM_WRITER in an
125    any_writer and returns it.  If PFM_WRITER is null, just
126    returns a null pointer.
127
128    Useful when you need to pass options to pfm_open_writer().
129    Typical usage:
130         any_writer_from_pfm_writer (pfm_open_writer (fh, dict, opts))
131    If you don't need to pass options, then any_writer_open() by
132    itself is easier and more straightforward. */
133 struct any_writer *
134 any_writer_from_pfm_writer (struct pfm_writer *pfm_writer) 
135 {
136   return make_any_writer (PORTABLE_FILE, pfm_writer);
137 }
138
139 /* If SCRATCH_WRITER is non-null, encapsulates SCRATCH_WRITER in
140    an any_writer and returns it.  If SCRATCH_WRITER is null, just
141    returns a null pointer.
142
143    Not particularly useful.  Included just for consistency. */
144 struct any_writer *
145 any_writer_from_scratch_writer (struct scratch_writer *scratch_writer) 
146 {
147   return make_any_writer (SCRATCH_FILE, scratch_writer);
148 }
149
150 /* Writes cases C to WRITER.
151    Returns true if successful, false on failure. */
152 bool
153 any_writer_write (struct any_writer *writer, const struct ccase *c) 
154 {
155   switch (writer->type) 
156     {
157     case SYSTEM_FILE:
158       return sfm_write_case (writer->private, c);
159
160     case PORTABLE_FILE:
161       return pfm_write_case (writer->private, c);
162
163     case SCRATCH_FILE:
164       return scratch_writer_write_case (writer->private, c);
165     }
166   NOT_REACHED ();
167 }
168
169 /* Returns true if an I/O error has occurred on WRITER, false
170    otherwise. */
171 bool
172 any_writer_error (const struct any_writer *writer) 
173 {
174   switch (writer->type) 
175     {
176     case SYSTEM_FILE:
177       return sfm_write_error (writer->private);
178
179     case PORTABLE_FILE:
180       return pfm_write_error (writer->private);
181
182     case SCRATCH_FILE:
183       return scratch_writer_error (writer->private);
184     }
185   NOT_REACHED ();
186 }
187
188 /* Closes WRITER.
189    Returns true if successful, false if an I/O error occurred. */
190 bool
191 any_writer_close (struct any_writer *writer) 
192 {
193   bool ok;
194   
195   if (writer == NULL)
196     return true;
197
198   switch (writer->type) 
199     {
200     case SYSTEM_FILE:
201       ok = sfm_close_writer (writer->private);
202       break;
203
204     case PORTABLE_FILE:
205       ok = pfm_close_writer (writer->private);
206       break;
207
208     case SCRATCH_FILE:
209       ok = scratch_writer_close (writer->private);
210       break;
211       
212     default:
213       NOT_REACHED ();
214     }
215
216   free (writer);
217   return ok;
218 }