ff7f4ab6c923a4dd7bec8ea3e425e5523262b2bd
[pspp] / src / data / any-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2006, 2010, 2011, 2012, 2014 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "data/any-reader.h"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "data/casereader.h"
28 #include "data/dataset.h"
29 #include "data/dictionary.h"
30 #include "data/file-handle-def.h"
31 #include "data/file-name.h"
32 #include "libpspp/assertion.h"
33 #include "libpspp/cast.h"
34 #include "libpspp/message.h"
35 #include "libpspp/str.h"
36
37 #include "gl/xalloc.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) (msgid)
42
43 static const struct any_reader_class dataset_reader_class;
44
45 static const struct any_reader_class *classes[] =
46   {
47     &sys_file_reader_class,
48     &por_file_reader_class,
49     &pcp_file_reader_class,
50   };
51 enum { N_CLASSES = sizeof classes / sizeof *classes };
52
53 int
54 any_reader_detect (const struct file_handle *file_handle,
55                    const struct any_reader_class **classp)
56 {
57   struct detector
58     {
59       enum any_type type;
60       int (*detect) (FILE *);
61     };
62
63   FILE *file;
64   int retval;
65
66   if (classp)
67     *classp = NULL;
68
69   file = fn_open (file_handle, "rb");
70   if (file == NULL)
71     {
72       msg (ME, _("An error occurred while opening `%s': %s."),
73            fh_get_file_name (file_handle), strerror (errno));
74       return -errno;
75     }
76
77   retval = 0;
78   for (int i = 0; i < N_CLASSES; i++)
79     {
80       int rc = classes[i]->detect (file);
81       if (rc == 1)
82         {
83           retval = 1;
84           if (classp)
85             *classp = classes[i];
86           break;
87         }
88       else if (rc < 0)
89         retval = rc;
90     }
91
92   if (retval < 0)
93     msg (ME, _("Error reading `%s': %s."), fh_get_file_name (file_handle), strerror (-retval));
94
95   fn_close (file_handle, file);
96
97   return retval;
98 }
99
100 struct any_reader *
101 any_reader_open (struct file_handle *handle)
102 {
103   switch (fh_get_referent (handle))
104     {
105     case FH_REF_FILE:
106       {
107         const struct any_reader_class *class;
108         int retval;
109
110         retval = any_reader_detect (handle, &class);
111         if (retval <= 0)
112           {
113             if (retval == 0)
114               msg (SE, _("`%s' is not a system or portable file."),
115                    fh_get_file_name (handle));
116             return NULL;
117           }
118
119         return class->open (handle);
120       }
121
122     case FH_REF_INLINE:
123       msg (SE, _("The inline file is not allowed here."));
124       return NULL;
125
126     case FH_REF_DATASET:
127       return dataset_reader_class.open (handle);
128     }
129   NOT_REACHED ();
130 }
131
132 bool
133 any_reader_close (struct any_reader *any_reader)
134 {
135   return any_reader ? any_reader->klass->close (any_reader) : true;
136 }
137
138 struct casereader *
139 any_reader_decode (struct any_reader *any_reader,
140                    const char *encoding,
141                    struct dictionary **dictp,
142                    struct any_read_info *info)
143 {
144   const struct any_reader_class *class = any_reader->klass;
145   struct casereader *reader;
146
147   reader = any_reader->klass->decode (any_reader, encoding, dictp, info);
148   if (reader && info)
149     info->klass = class;
150   return reader;
151 }
152
153 size_t
154 any_reader_get_strings (const struct any_reader *any_reader, struct pool *pool,
155                         char ***labels, bool **ids, char ***values)
156 {
157   return (any_reader->klass->get_strings
158           ? any_reader->klass->get_strings (any_reader, pool, labels, ids,
159                                             values)
160           : 0);
161 }
162
163 struct casereader *
164 any_reader_open_and_decode (struct file_handle *handle,
165                             const char *encoding,
166                             struct dictionary **dictp,
167                             struct any_read_info *info)
168 {
169   struct any_reader *any_reader = any_reader_open (handle);
170   return (any_reader
171           ? any_reader_decode (any_reader, encoding, dictp, info)
172           : NULL);
173 }
174 \f
175 struct dataset_reader
176   {
177     struct any_reader any_reader;
178     struct dictionary *dict;
179     struct casereader *reader;
180   };
181
182 /* Opens FH, which must have referent type FH_REF_DATASET, and returns a
183    dataset_reader for it, or a null pointer on failure.  Stores a copy of the
184    dictionary for the dataset file into *DICT.  The caller takes ownership of
185    the casereader and the dictionary.  */
186 static struct any_reader *
187 dataset_reader_open (struct file_handle *fh)
188 {
189   struct dataset_reader *reader;
190   struct dataset *ds;
191
192   /* We don't bother doing fh_lock or fh_ref on the file handle,
193      as there's no advantage in this case, and doing these would
194      require us to keep track of the "struct file_handle" and
195      "struct fh_lock" and undo our work later. */
196   assert (fh_get_referent (fh) == FH_REF_DATASET);
197
198   ds = fh_get_dataset (fh);
199   if (ds == NULL || !dataset_has_source (ds))
200     {
201       msg (SE, _("Cannot read from dataset %s because no dictionary or data "
202                  "has been written to it yet."),
203            fh_get_name (fh));
204       return NULL;
205     }
206
207   reader = xmalloc (sizeof *reader);
208   reader->any_reader.klass = &dataset_reader_class;
209   reader->dict = dict_clone (dataset_dict (ds));
210   reader->reader = casereader_clone (dataset_source (ds));
211   return &reader->any_reader;
212 }
213
214 static struct dataset_reader *
215 dataset_reader_cast (const struct any_reader *r_)
216 {
217   assert (r_->klass == &dataset_reader_class);
218   return UP_CAST (r_, struct dataset_reader, any_reader);
219 }
220
221 static bool
222 dataset_reader_close (struct any_reader *r_)
223 {
224   struct dataset_reader *r = dataset_reader_cast (r_);
225   dict_destroy (r->dict);
226   casereader_destroy (r->reader);
227   free (r);
228
229   return true;
230 }
231
232 static struct casereader *
233 dataset_reader_decode (struct any_reader *r_, const char *encoding UNUSED,
234                        struct dictionary **dictp, struct any_read_info *info)
235 {
236   struct dataset_reader *r = dataset_reader_cast (r_);
237   struct casereader *reader;
238
239   *dictp = r->dict;
240   reader = r->reader;
241   if (info)
242     {
243       memset (info, 0, sizeof *info);
244       info->integer_format = INTEGER_NATIVE;
245       info->float_format = FLOAT_NATIVE_DOUBLE;
246       info->compression = ANY_COMP_NONE;
247       info->case_cnt = casereader_get_case_cnt (reader);
248     }
249   free (r);
250
251   return reader;
252 }
253
254 static const struct any_reader_class dataset_reader_class =
255   {
256     N_("Dataset"),
257     NULL,
258     dataset_reader_open,
259     dataset_reader_close,
260     dataset_reader_decode,
261     NULL,
262   };