We are using a single member in struct file_handle, the "name"
[pspp-builds.git] / src / language / data-io / file-handle.q
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 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 <language/data-io/file-handle.h>
21 #include <libpspp/message.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <libpspp/alloc.h>
25 #include <data/file-name.h>
26 #include <language/command.h>
27 #include <language/lexer/lexer.h>
28 #include <libpspp/assertion.h>
29 #include <libpspp/message.h>
30 #include <libpspp/magic.h>
31 #include <libpspp/str.h>
32 #include <data/variable.h>
33 #include <data/file-handle-def.h>
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37
38 /* (headers) */
39
40
41 /* (specification)
42    "FILE HANDLE" (fh_):
43      name=string;
44      lrecl=integer;
45      tabwidth=integer "x>=0" "%s must be nonnegative";
46      mode=mode:!character/image/scratch.
47 */
48 /* (declarations) */
49 /* (functions) */
50
51 int
52 cmd_file_handle (struct lexer *lexer, struct dataset *ds)
53 {
54   char handle_name[LONG_NAME_LEN + 1];
55   struct fh_properties properties = *fh_default_properties ();
56
57   struct cmd_file_handle cmd;
58   struct file_handle *handle;
59
60   if (!lex_force_id (lexer))
61     return CMD_CASCADING_FAILURE;
62   str_copy_trunc (handle_name, sizeof handle_name, lex_tokid (lexer));
63
64   handle = fh_from_id (handle_name);
65   if (handle != NULL)
66     {
67       msg (SE, _("File handle %s is already defined.  "
68                  "Use CLOSE FILE HANDLE before redefining a file handle."),
69            handle_name);
70       return CMD_CASCADING_FAILURE;
71     }
72
73   lex_get (lexer);
74   if (!lex_force_match (lexer, '/'))
75     return CMD_CASCADING_FAILURE;
76
77   if (!parse_file_handle (lexer, ds, &cmd, NULL))
78     return CMD_CASCADING_FAILURE;
79
80   if (lex_end_of_command (lexer) != CMD_SUCCESS)
81     goto lossage;
82
83   if (cmd.s_name == NULL && cmd.mode != FH_SCRATCH)
84     {
85       lex_sbc_missing (lexer, "NAME");
86       goto lossage;
87     }
88
89   switch (cmd.mode)
90     {
91     case FH_CHARACTER:
92       properties.mode = FH_MODE_TEXT;
93       if (cmd.sbc_tabwidth)
94         properties.tab_width = cmd.n_tabwidth[0];
95       break;
96     case FH_IMAGE:
97       properties.mode = FH_MODE_BINARY;
98       if (cmd.n_lrecl[0] == NOT_LONG)
99         msg (SE, _("Fixed-length records were specified on /RECFORM, but "
100                    "record length was not specified on /LRECL.  "
101                    "Assuming %d-character records."),
102              properties.record_width);
103       else if (cmd.n_lrecl[0] < 1)
104         msg (SE, _("Record length (%ld) must be at least one byte.  "
105                    "Assuming %d-character records."),
106              cmd.n_lrecl[0], properties.record_width);
107       else
108         properties.record_width = cmd.n_lrecl[0];
109       break;
110     default:
111       NOT_REACHED ();
112     }
113
114   if (cmd.mode != FH_SCRATCH)
115     fh_create_file (handle_name, cmd.s_name, &properties);
116   else
117     fh_create_scratch (handle_name);
118
119   free_file_handle (&cmd);
120   return CMD_SUCCESS;
121
122  lossage:
123   free_file_handle (&cmd);
124   return CMD_CASCADING_FAILURE;
125 }
126
127 int
128 cmd_close_file_handle (struct lexer *lexer, struct dataset *ds UNUSED) 
129 {
130   struct file_handle *handle;
131
132   if (!lex_force_id (lexer))
133     return CMD_CASCADING_FAILURE;
134   handle = fh_from_id (lex_tokid (lexer));
135   if (handle == NULL)
136     return CMD_CASCADING_FAILURE;
137
138   fh_free (handle);
139
140   return CMD_SUCCESS;
141 }
142
143 /* Returns the name for REFERENT. */
144 static const char *
145 referent_name (enum fh_referent referent) 
146 {
147   switch (referent) 
148     {
149     case FH_REF_FILE:
150       return _("file");
151     case FH_REF_INLINE:
152       return _("inline file");
153     case FH_REF_SCRATCH:
154       return _("scratch file");
155     default:
156       NOT_REACHED ();
157     }
158 }
159
160 /* Parses a file handle name, which may be a file name as a string
161    or a file handle name as an identifier.  The allowed types of
162    file handle are restricted to those in REFERENT_MASK.  Returns
163    the file handle when successful, a null pointer on failure. */
164 struct file_handle *
165 fh_parse (struct lexer *lexer, enum fh_referent referent_mask)
166 {
167   struct file_handle *handle;
168
169   if (lex_match_id (lexer, "INLINE")) 
170     handle = fh_inline_file ();
171   else 
172     {
173       if (lex_token (lexer) != T_ID && lex_token (lexer) != T_STRING)
174         {
175           lex_error (lexer, _("expecting a file name or handle name"));
176           return NULL;
177         }
178
179       handle = NULL;
180       if (lex_token (lexer) == T_ID) 
181         handle = fh_from_id (lex_tokid (lexer));
182       if (handle == NULL) 
183         handle = fh_from_file_name (ds_cstr (lex_tokstr (lexer))); 
184       if (handle == NULL)
185         {
186           if (lex_token (lexer) != T_ID || lex_tokid (lexer)[0] != '#' || get_syntax () != ENHANCED) 
187             handle = fh_create_file (NULL, ds_cstr (lex_tokstr (lexer)),
188                                      fh_default_properties ());
189           else
190             handle = fh_create_scratch (lex_tokid (lexer));
191         }
192       lex_get (lexer);
193     }
194
195   if (!(fh_get_referent (handle) & referent_mask)) 
196     {
197       msg (SE, _("Handle for %s not allowed here."),
198            referent_name (fh_get_referent (handle)));
199       return NULL;
200     }
201
202   return handle;
203 }
204
205 /*
206    Local variables:
207    mode: c
208    End:
209 */