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