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