96aa9486cd894e18b2c1f5dfb33a3b478458191f
[pspp-builds.git] / src / file-handle.q
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "file-handle.h"
22 #include "error.h"
23 #include <errno.h>
24 #include <stdlib.h>
25 #include "alloc.h"
26 #include "filename.h"
27 #include "command.h"
28 #include "lexer.h"
29 #include "getline.h"
30 #include "error.h"
31 #include "magic.h"
32 #include "var.h"
33 /* (headers) */
34
35 /* File handle private data. */
36 struct private_file_handle 
37   {
38     char *name;                 /* File handle identifier. */
39     char *filename;             /* Filename as provided by user. */
40     struct file_identity *identity; /* For checking file identity. */
41     struct file_locator where;  /* Used for reporting error messages. */
42     enum file_handle_mode mode; /* File mode. */
43     size_t length;              /* Length of fixed-format records. */
44     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
45   };
46
47 /* Linked list of file handles. */
48 struct file_handle_list 
49   {
50     struct file_handle *handle;
51     struct file_handle_list *next;
52   };
53
54 static struct file_handle_list *file_handles;
55 struct file_handle *inline_file;
56
57 static struct file_handle *create_file_handle (const char *handle_name,
58                                                const char *filename);
59
60 /* (specification)
61    "FILE HANDLE" (fh_):
62      name=string;
63      lrecl=integer;
64      tabwidth=integer "x>=0" "%s must be nonnegative";
65      mode=mode:!character/image.
66 */
67 /* (declarations) */
68 /* (functions) */
69
70 static struct file_handle *
71 get_handle_with_name (const char *handle_name) 
72 {
73   struct file_handle_list *iter;
74
75   for (iter = file_handles; iter != NULL; iter = iter->next)
76     if (!strcmp (handle_name, iter->handle->private->name))
77       return iter->handle;
78   return NULL;
79 }
80
81 static struct file_handle *
82 get_handle_for_filename (const char *filename)
83 {
84   struct file_identity *identity;
85   struct file_handle_list *iter;
86       
87   /* First check for a file with the same identity. */
88   identity = fn_get_identity (filename);
89   if (identity != NULL) 
90     {
91       for (iter = file_handles; iter != NULL; iter = iter->next)
92         if (iter->handle->private->identity != NULL
93             && !fn_compare_file_identities (identity,
94                                          iter->handle->private->identity)) 
95           {
96             fn_free_identity (identity);
97             return iter->handle; 
98           }
99       fn_free_identity (identity);
100     }
101
102   /* Then check for a file with the same name. */
103   for (iter = file_handles; iter != NULL; iter = iter->next)
104     if (!strcmp (filename, iter->handle->private->filename))
105       return iter->handle; 
106
107   return NULL;
108 }
109
110 int
111 cmd_file_handle (void)
112 {
113   char handle_name[9];
114
115   struct cmd_file_handle cmd;
116   struct file_handle *handle;
117
118   if (!lex_force_id ())
119     return CMD_FAILURE;
120   strcpy (handle_name, tokid);
121
122   handle = get_handle_with_name (handle_name);
123   if (handle != NULL)
124     {
125       msg (SE, _("File handle %s already refers to "
126                  "file %s.  File handle cannot be redefined within a "
127                  "session."),
128            tokid, handle->private->filename);
129       return CMD_FAILURE;
130     }
131
132   lex_get ();
133   if (!lex_force_match ('/'))
134     return CMD_FAILURE;
135
136   if (!parse_file_handle (&cmd))
137     return CMD_FAILURE;
138
139   if (token != '.')
140     {
141       lex_error (_("expecting end of command"));
142       goto lossage;
143     }
144
145   if (cmd.s_name == NULL)
146     {
147       msg (SE, _("The FILE HANDLE required subcommand NAME "
148                  "is not present."));
149       goto lossage;
150     }
151
152   handle = create_file_handle (handle_name, cmd.s_name);
153   switch (cmd.mode)
154     {
155     case FH_CHARACTER:
156       handle->private->mode = MODE_TEXT;
157       if (cmd.sbc_tabwidth)
158         handle->private->tab_width = cmd.n_tabwidth;
159       else
160         handle->private->tab_width = 4;
161       break;
162     case FH_IMAGE:
163       handle->private->mode = MODE_BINARY;
164       if (cmd.n_lrecl == NOT_LONG)
165         {
166           msg (SE, _("Fixed-length records were specified on /RECFORM, but "
167                      "record length was not specified on /LRECL.  "
168                      "Assuming 1024-character records."));
169           handle->private->length = 1024;
170         }
171       else if (cmd.n_lrecl < 1)
172         {
173           msg (SE, _("Record length (%ld) must be at least one byte.  "
174                      "1-character records will be assumed."), cmd.n_lrecl);
175           handle->private->length = 1;
176         }
177       else
178         handle->private->length = cmd.n_lrecl;
179       break;
180     default:
181       assert (0);
182     }
183
184   return CMD_SUCCESS;
185
186  lossage:
187   free_file_handle (&cmd);
188   return CMD_FAILURE;
189 }
190 \f
191 /* File handle functions. */
192
193 /* Creates and returns a new file handle with the given values
194    and defaults for other values.  Adds the created file handle
195    to the global list. */
196 static struct file_handle *
197 create_file_handle (const char *handle_name, const char *filename)
198 {
199   struct file_handle *handle;
200   struct file_handle_list *list;
201
202   /* Create and initialize file handle. */
203   handle = xmalloc (sizeof *handle);
204   handle->private = xmalloc (sizeof *handle->private);
205   handle->private->name = xstrdup (handle_name);
206   handle->private->filename = xstrdup (filename);
207   handle->private->identity = fn_get_identity (filename);
208   handle->private->where.filename = handle->private->filename;
209   handle->private->where.line_number = 0;
210   handle->private->mode = MODE_TEXT;
211   handle->private->length = 1024;
212   handle->private->tab_width = 4;
213   handle->ext = NULL;
214   handle->class = NULL;
215
216   /* Add file handle to global list. */
217   list = xmalloc (sizeof *list);
218   list->handle = handle;
219   list->next = file_handles;
220   file_handles = list;
221
222   return handle;
223 }
224
225 /* Closes the stdio FILE associated with handle H.  Frees internal
226    buffers associated with that file.  Does *not* destroy the file
227    handle H.  (File handles are permanent during a session.)  */
228 void
229 fh_close_handle (struct file_handle *h)
230 {
231   if (h == NULL)
232     return;
233
234   if (h->class != NULL)
235     h->class->close (h);
236   h->class = NULL;
237   h->ext = NULL;
238 }
239
240 /* Initialize the hash of file handles; inserts the "inline file"
241    inline_file. */
242 void
243 fh_init_files (void)
244 {
245   if (inline_file == NULL) 
246     {
247       inline_file = create_file_handle ("INLINE", _("<Inline File>"));
248       inline_file->private->length = 80; 
249     }
250 }
251
252 /* Parses a file handle name, which may be a filename as a string or
253    a file handle name as an identifier.  Returns the file handle or
254    NULL on failure. */
255 struct file_handle *
256 fh_parse_file_handle (void)
257 {
258   struct file_handle *handle;
259
260   if (token != T_ID && token != T_STRING)
261     {
262       lex_error (_("expecting a file name or handle name"));
263       return NULL;
264     }
265
266   /* Check for named handles first, then go by filename. */
267   handle = NULL;
268   if (token == T_ID) 
269     handle = get_handle_with_name (tokid);
270   if (handle == NULL)
271     handle = get_handle_for_filename (ds_c_str (&tokstr));
272   if (handle == NULL) 
273     {
274       char *filename = ds_c_str (&tokstr);
275       char *handle_name = xmalloc (strlen (filename) + 3);
276       sprintf (handle_name, "\"%s\"", filename);
277       handle = create_file_handle (handle_name, filename);
278       free (handle_name);
279     }
280
281   lex_get ();
282
283   return handle;
284 }
285
286 /* Returns the identifier of file HANDLE.  If HANDLE was created
287    by referring to a filename instead of a handle name, returns
288    the filename, enclosed in double quotes.  Return value is
289    owned by the file handle. 
290
291    Useful for printing error messages about use of file handles.  */
292 const char *
293 handle_get_name (const struct file_handle *handle)
294 {
295   return handle->private->name;
296 }
297
298 /* Returns the name of the file associated with HANDLE. */
299 const char *
300 handle_get_filename (const struct file_handle *handle) 
301 {
302   return handle->private->filename;
303 }
304
305 /* Returns the mode of HANDLE. */
306 enum file_handle_mode
307 handle_get_mode (const struct file_handle *handle) 
308 {
309   assert (handle != NULL);
310   return handle->private->mode;
311 }
312
313 /* Returns the width of a logical record on HANDLE.  Applicable
314    only to MODE_BINARY files.  */
315 size_t
316 handle_get_record_width (const struct file_handle *handle)
317 {
318   assert (handle != NULL);
319   return handle->private->length;
320 }
321
322 /* Returns the number of characters per tab stop for HANDLE, or
323    zero if tabs are not to be expanded.  Applicable only to
324    MODE_TEXT files. */
325 size_t
326 handle_get_tab_width (const struct file_handle *handle) 
327 {
328   assert (handle != NULL);
329   return handle->private->tab_width;
330 }
331
332 /*
333    Local variables:
334    mode: c
335    End:
336 */