ad3fcb5b7a91a99c6acd22798c459037bc0b22c5
[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/dataset-reader.h"
28 #include "data/file-handle-def.h"
29 #include "data/file-name.h"
30 #include "data/por-file-reader.h"
31 #include "data/sys-file-reader.h"
32 #include "libpspp/assertion.h"
33 #include "libpspp/message.h"
34 #include "libpspp/str.h"
35
36 #include "gl/xalloc.h"
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40
41 /* Tries to detect whether FILE is a given type of file, by opening the file
42    and passing it to DETECT, and returns a detect_result. */
43 static enum detect_result
44 try_detect (const char *file_name, bool (*detect) (FILE *))
45 {
46   FILE *file;
47   bool is_type;
48
49   file = fn_open (file_name, "rb");
50   if (file == NULL)
51     {
52       msg (ME, _("An error occurred while opening `%s': %s."),
53            file_name, strerror (errno));
54       return ANY_ERROR;
55     }
56
57   is_type = detect (file);
58
59   fn_close (file_name, file);
60
61   return is_type ? ANY_YES : ANY_NO;
62 }
63
64 /* Returns true if any_reader_open() would be able to open FILE as a data
65    file, false otherwise. */
66 enum detect_result
67 any_reader_may_open (const char *file)
68 {
69   enum detect_result res = try_detect (file, sfm_detect);
70   
71   if (res == ANY_NO)
72     res = try_detect (file, pfm_detect);
73
74   return res;
75 }
76
77 /* Returns a casereader for HANDLE.  On success, returns the new
78    casereader and stores the file's dictionary into *DICT.  On
79    failure, returns a null pointer.
80
81    Ordinarily the reader attempts to automatically detect the character
82    encoding based on the file's contents.  This isn't always possible,
83    especially for files written by old versions of SPSS or PSPP, so specifying
84    a nonnull ENCODING overrides the choice of character encoding.  */
85 struct casereader *
86 any_reader_open (struct file_handle *handle, const char *encoding,
87                  struct dictionary **dict)
88 {
89   switch (fh_get_referent (handle))
90     {
91     case FH_REF_FILE:
92       {
93         enum detect_result result;
94
95         result = try_detect (fh_get_file_name (handle), sfm_detect);
96         if (result == ANY_ERROR)
97           return NULL;
98         else if (result == ANY_YES)
99           {
100             struct sfm_reader *r;
101
102             r = sfm_open (handle);
103             if (r == NULL)
104               return NULL;
105
106             return sfm_decode (r, encoding, dict, NULL);
107           }
108
109         result = try_detect (fh_get_file_name (handle), pfm_detect);
110         if (result == ANY_ERROR)
111           return NULL;
112         else if (result == ANY_YES)
113           return pfm_open_reader (handle, dict, NULL);
114
115         msg (SE, _("`%s' is not a system or portable file."),
116              fh_get_file_name (handle));
117         return NULL;
118       }
119
120     case FH_REF_INLINE:
121       msg (SE, _("The inline file is not allowed here."));
122       return NULL;
123
124     case FH_REF_DATASET:
125       return dataset_reader_open (handle, dict);
126     }
127   NOT_REACHED ();
128 }