f1c5f19b14928b2d44c458827ce5cb1c3e5084f4
[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., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, 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 #include "linked-list.h"
34
35 /* (headers) */
36
37 /* File handle. */
38 struct file_handle 
39   {
40     struct file_handle *next;   /* Next in global list. */
41     char *name;                 /* File handle identifier. */
42     char *filename;             /* Filename as provided by user. */
43     struct file_identity *identity; /* For checking file identity. */
44     struct file_locator where;  /* Used for reporting error messages. */
45     enum file_handle_mode mode; /* File mode. */
46     size_t length;              /* Length of fixed-format records. */
47     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
48
49     int open_cnt;               /* 0=not open, otherwise # of openers. */
50     const char *type;           /* If open, type of file. */
51     char open_mode[3];          /* "[rw][se]". */
52     void *aux;                  /* Aux data pointer for owner if any. */
53   };
54
55 static struct file_handle *file_handles;
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 *iter;
74
75   for (iter = file_handles; iter != NULL; iter = iter->next)
76     if (!strcasecmp (handle_name, iter->name))
77       return iter;
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 *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->identity != NULL
93             && !fn_compare_file_identities (identity, iter->identity))
94           {
95             fn_free_identity (identity);
96             return iter; 
97           }
98       fn_free_identity (identity);
99     }
100
101   /* Then check for a file with the same name. */
102   for (iter = file_handles; iter != NULL; iter = iter->next)
103     if (!strcmp (filename, iter->filename))
104       return iter; 
105
106   return NULL;
107 }
108
109 int
110 cmd_file_handle (void)
111 {
112   char handle_name[LONG_NAME_LEN + 1];
113
114   struct cmd_file_handle cmd;
115   struct file_handle *handle;
116
117   if (!lex_force_id ())
118     return CMD_FAILURE;
119   str_copy_trunc (handle_name, sizeof handle_name, tokid);
120
121   handle = get_handle_with_name (handle_name);
122   if (handle != NULL)
123     {
124       msg (SE, _("File handle %s already refers to file %s.  "
125                  "File handles cannot be redefined within a session."),
126            handle_name, handle->filename);
127       return CMD_FAILURE;
128     }
129
130   lex_get ();
131   if (!lex_force_match ('/'))
132     return CMD_FAILURE;
133
134   if (!parse_file_handle (&cmd))
135     return CMD_FAILURE;
136
137   if (token != '.')
138     {
139       lex_error (_("expecting end of command"));
140       goto lossage;
141     }
142
143   if (cmd.s_name == NULL)
144     {
145       msg (SE, _("The FILE HANDLE required subcommand NAME "
146                  "is not present."));
147       goto lossage;
148     }
149
150   handle = create_file_handle (handle_name, cmd.s_name);
151   switch (cmd.mode)
152     {
153     case FH_CHARACTER:
154       handle->mode = MODE_TEXT;
155       if (cmd.sbc_tabwidth)
156         handle->tab_width = cmd.n_tabwidth[0];
157       else
158         handle->tab_width = 4;
159       break;
160     case FH_IMAGE:
161       handle->mode = MODE_BINARY;
162       if (cmd.n_lrecl[0] == NOT_LONG)
163         {
164           msg (SE, _("Fixed-length records were specified on /RECFORM, but "
165                      "record length was not specified on /LRECL.  "
166                      "Assuming 1024-character records."));
167           handle->length = 1024;
168         }
169       else if (cmd.n_lrecl[0] < 1)
170         {
171           msg (SE, _("Record length (%ld) must be at least one byte.  "
172                      "1-character records will be assumed."), cmd.n_lrecl[0]);
173           handle->length = 1;
174         }
175       else
176         handle->length = cmd.n_lrecl[0];
177       break;
178     default:
179       assert (0);
180     }
181
182   return CMD_SUCCESS;
183
184  lossage:
185   free_file_handle (&cmd);
186   return CMD_FAILURE;
187 }
188 \f
189 /* File handle functions. */
190
191 /* Creates and returns a new file handle with the given values
192    and defaults for other values.  Adds the created file handle
193    to the global list. */
194 static struct file_handle *
195 create_file_handle (const char *handle_name, const char *filename)
196 {
197   struct file_handle *handle;
198
199   /* Create and initialize file handle. */
200   handle = xmalloc (sizeof *handle);
201   handle->next = file_handles;
202   handle->name = xstrdup (handle_name);
203   handle->filename = xstrdup (filename);
204   handle->identity = fn_get_identity (filename);
205   handle->where.filename = handle->filename;
206   handle->where.line_number = 0;
207   handle->mode = MODE_TEXT;
208   handle->length = 1024;
209   handle->tab_width = 4;
210   handle->open_cnt = 0;
211   handle->type = NULL;
212   handle->aux = NULL;
213   file_handles = handle;
214
215   return handle;
216 }
217
218 static void
219 destroy_file_handle(void *fh_, void *aux UNUSED)
220 {
221   struct file_handle *fh = fh_;
222   free (fh->name);
223   free (fh->filename);
224   fn_free_identity (fh->identity);
225   free (fh);
226 }
227
228 static const char *
229 mode_name (const char *mode) 
230 {
231   assert (mode != NULL);
232   assert (mode[0] == 'r' || mode[0] == 'w');
233
234   return mode[0] == 'r' ? "reading" : "writing";
235 }
236
237
238 /* Tries to open handle H with the given TYPE and MODE.
239
240    TYPE is the sort of file, e.g. "system file".  Only one given
241    type of access is allowed on a given file handle at once.
242
243    MODE combines the read or write mode with the sharing mode.
244    The first character is 'r' for read, 'w' for write.  The
245    second character is 's' to permit sharing, 'e' to require
246    exclusive access.
247
248    Returns the address of a void * that the caller can use for
249    data specific to the file handle if successful, or a null
250    pointer on failure.  For exclusive access modes the void *
251    will always be a null pointer at return.  In shared access
252    modes the void * will necessarily be null only if no other
253    sharers are active.
254
255    If successful, a reference to type is retained, so it should
256    probably be a string literal. */
257 void **
258 fh_open (struct file_handle *h, const char *type, const char *mode) 
259 {
260   assert (h != NULL);
261   assert (type != NULL);
262   assert (mode != NULL);
263   assert (mode[0] == 'r' || mode[0] == 'w');
264   assert (mode[1] == 's' || mode[1] == 'e');
265   assert (mode[2] == '\0');
266
267   if (h->open_cnt != 0) 
268     {
269       if (strcmp (h->type, type)) 
270         {
271           msg (SE, _("Can't open %s as a %s because it is "
272                      "already open as a %s"),
273                handle_get_name (h), type, h->type);
274           return NULL; 
275         }
276       else if (strcmp (h->open_mode, mode)) 
277         {
278           msg (SE, _("Can't open %s as a %s for %s because it is "
279                      "already open for %s"),
280                handle_get_name (h), type,
281                mode_name (mode), mode_name (h->open_mode));
282           return NULL;
283         }
284       else if (h->open_mode[1] == 'e')
285         {
286           msg (SE, _("Can't re-open %s as a %s for %s"),
287                handle_get_name (h), type, mode_name (mode));
288           return NULL;
289         }
290     }
291   else 
292     {
293       h->type = type;
294       strcpy (h->open_mode, mode);
295       assert (h->aux == NULL);
296     }
297   h->open_cnt++;
298
299   return &h->aux;
300 }
301
302 /* Closes file handle H, which must have been open for the
303    specified TYPE and MODE of access provided to fh_open().
304    Returns zero if the file is now closed, nonzero if it is still
305    open due to another reference. */
306 int
307 fh_close (struct file_handle *h, const char *type, const char *mode)
308 {
309   assert (h != NULL);
310   assert (h->open_cnt > 0);
311   assert (type != NULL);
312   assert (!strcmp (type, h->type));
313   assert (mode != NULL);
314   assert (!strcmp (mode, h->open_mode));
315
316   h->open_cnt--;
317   if (h->open_cnt == 0) 
318     {
319       h->type = NULL;
320       h->aux = NULL;
321     }
322   return h->open_cnt;
323 }
324
325
326 static struct linked_list *handle_list;
327
328
329 /* Parses a file handle name, which may be a filename as a string or
330    a file handle name as an identifier.  Returns the file handle or
331    NULL on failure. */
332 struct file_handle *
333 fh_parse (void)
334 {
335   struct file_handle *handle;
336
337   if (token != T_ID && token != T_STRING)
338     {
339       lex_error (_("expecting a file name or handle name"));
340       return NULL;
341     }
342
343   /* Check for named handles first, then go by filename. */
344   handle = NULL;
345   if (token == T_ID) 
346     handle = get_handle_with_name (tokid);
347   if (handle == NULL)
348     handle = get_handle_for_filename (ds_c_str (&tokstr));
349   if (handle == NULL) 
350     {
351       char *filename = ds_c_str (&tokstr);
352       char *handle_name = xmalloc (strlen (filename) + 3);
353       sprintf (handle_name, "\"%s\"", filename);
354       handle = create_file_handle (handle_name, filename);
355       ll_push_front(handle_list, handle);
356       free (handle_name);
357     }
358
359   lex_get ();
360
361
362   return handle;
363 }
364
365 /* Returns the identifier of file HANDLE.  If HANDLE was created
366    by referring to a filename instead of a handle name, returns
367    the filename, enclosed in double quotes.  Return value is
368    owned by the file handle. 
369
370    Useful for printing error messages about use of file handles.  */
371 const char *
372 handle_get_name (const struct file_handle *handle)
373 {
374   assert (handle != NULL);
375   return handle->name;
376 }
377
378 /* Returns the name of the file associated with HANDLE. */
379 const char *
380 handle_get_filename (const struct file_handle *handle) 
381 {
382   assert (handle != NULL);
383   return handle->filename;
384 }
385
386 /* Returns the mode of HANDLE. */
387 enum file_handle_mode
388 handle_get_mode (const struct file_handle *handle) 
389 {
390   assert (handle != NULL);
391   return handle->mode;
392 }
393
394 /* Returns the width of a logical record on HANDLE. */
395 size_t
396 handle_get_record_width (const struct file_handle *handle)
397 {
398   assert (handle != NULL);
399   return handle->length;
400 }
401
402 /* Returns the number of characters per tab stop for HANDLE, or
403    zero if tabs are not to be expanded.  Applicable only to
404    MODE_TEXT files. */
405 size_t
406 handle_get_tab_width (const struct file_handle *handle) 
407 {
408   assert (handle != NULL);
409   return handle->tab_width;
410 }
411
412
413 void 
414 fh_init(void)
415 {
416   handle_list = ll_create(destroy_file_handle,0);
417 }
418
419 void 
420 fh_done(void)
421 {
422   if ( handle_list )  
423   {
424     ll_destroy(handle_list);
425     handle_list = 0;
426   }
427 }
428
429
430 /*
431    Local variables:
432    mode: c
433    End:
434 */