GNU standards require "file name" instead of "filename" in
[pspp-builds.git] / src / data / file-handle-def.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 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-def.h"
22 #include <libpspp/message.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <libpspp/alloc.h>
27 #include <libpspp/compiler.h>
28 #include "file-name.h"
29 #include <libpspp/message.h>
30 #include <libpspp/magic.h>
31 #include "variable.h"
32 #include "scratch-handle.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36
37 /* (headers) */
38
39 /* File handle. */
40 struct file_handle 
41   {
42     struct file_handle *next;   /* Next in global list. */
43     int open_cnt;               /* 0=not open, otherwise # of openers. */
44     bool deleted;               /* Destroy handle when open_cnt goes to 0? */
45
46     char *name;                 /* File handle identifier. */
47     const char *type;           /* If open, type of file. */
48     char open_mode[3];          /* "[rw][se]". */
49     void *aux;                  /* Aux data pointer for owner if any. */
50     enum fh_referent referent;  /* What the file handle refers to. */
51
52     /* FH_REF_FILE only. */
53     char *file_name;            /* File name as provided by user. */
54     struct file_identity *identity; /* For checking file identity. */
55     enum fh_mode mode;          /* File mode. */
56
57     /* FH_REF_FILE and FH_REF_INLINE only. */
58     size_t record_width;        /* Length of fixed-format records. */
59     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
60
61     /* FH_REF_SCRATCH only. */
62     struct scratch_handle *sh;  /* Scratch file data. */
63   };
64
65 /* List of all handles. */
66 static struct file_handle *file_handles;
67
68 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
69    commands. */
70 static struct file_handle *default_handle;
71
72 /* The "file" that reads from BEGIN DATA...END DATA. */
73 static struct file_handle *inline_file;
74
75 static struct file_handle *create_handle (const char *name, enum fh_referent);
76
77 /* File handle initialization routine. */
78 void 
79 fh_init (void)
80 {
81   inline_file = create_handle ("INLINE", FH_REF_INLINE);
82   inline_file->record_width = 80;
83   inline_file->tab_width = 8;
84 }
85
86 /* Free HANDLE and remove it from the global list. */
87 static void
88 free_handle (struct file_handle *handle) 
89 {
90   /* Remove handle from global list. */
91   if (file_handles == handle)
92     file_handles = handle->next;
93   else 
94     {
95       struct file_handle *iter = file_handles;
96       while (iter->next != handle)
97         iter = iter->next;
98       iter->next = handle->next;
99     }
100
101   /* Free data. */
102   free (handle->name);
103   free (handle->file_name);
104   fn_free_identity (handle->identity);
105   scratch_handle_destroy (handle->sh);
106   free (handle);
107 }
108
109 /* Frees all the file handles. */
110 void 
111 fh_done (void)
112 {
113   while (file_handles != NULL) 
114     free_handle (file_handles);
115 }
116
117 /* Returns the handle named HANDLE_NAME, or a null pointer if
118    there is none. */
119 struct file_handle *
120 fh_from_name (const char *handle_name) 
121 {
122   struct file_handle *iter;
123
124   for (iter = file_handles; iter != NULL; iter = iter->next)
125     if (!iter->deleted && !strcasecmp (handle_name, iter->name))
126       return iter;
127   return NULL;
128 }
129
130 /* Returns the handle for the file named FILE_NAME,
131    or a null pointer if none exists.
132    Different names for the same file (e.g. "x" and "./x") are
133    considered equivalent. */
134 struct file_handle *
135 fh_from_file_name (const char *file_name)
136 {
137   struct file_identity *identity;
138   struct file_handle *iter;
139       
140   /* First check for a file with the same identity. */
141   identity = fn_get_identity (file_name);
142   if (identity != NULL) 
143     {
144       for (iter = file_handles; iter != NULL; iter = iter->next)
145         if (!iter->deleted
146             && iter->referent == FH_REF_FILE
147             && iter->identity != NULL
148             && !fn_compare_file_identities (identity, iter->identity))
149           {
150             fn_free_identity (identity);
151             return iter; 
152           }
153       fn_free_identity (identity);
154     }
155
156   /* Then check for a file with the same name. */
157   for (iter = file_handles; iter != NULL; iter = iter->next)
158     if (!iter->deleted
159         && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
160       return iter; 
161
162   return NULL;
163 }
164
165 /* Creates a new handle with name HANDLE_NAME that refers to
166    REFERENT.  Links the new handle into the global list.  Returns
167    the new handle.
168
169    The new handle is not fully initialized.  The caller is
170    responsible for completing its initialization. */
171 static struct file_handle *
172 create_handle (const char *handle_name, enum fh_referent referent) 
173 {
174   struct file_handle *handle = xzalloc (sizeof *handle);
175   handle->next = file_handles;
176   handle->open_cnt = 0;
177   handle->deleted = false;
178   handle->name = xstrdup (handle_name);
179   handle->type = NULL;
180   handle->aux = NULL;
181   handle->referent = referent;
182   file_handles = handle;
183   return handle;
184 }
185
186 /* Returns the unique handle of referent type FH_REF_INLINE,
187    which refers to the "inline file" that represents character
188    data in the command file between BEGIN DATA and END DATA. */
189 struct file_handle *
190 fh_inline_file (void) 
191 {
192   return inline_file;
193 }
194
195 /* Creates a new file handle named HANDLE_NAME, which must not be
196    the name of an existing file handle.  The new handle is
197    associated with file FILE_NAME and the given PROPERTIES. */
198 struct file_handle *
199 fh_create_file (const char *handle_name, const char *file_name,
200                 const struct fh_properties *properties)
201 {
202   struct file_handle *handle;
203   assert (fh_from_name (handle_name) == NULL);
204   handle = create_handle (handle_name, FH_REF_FILE);
205   handle->file_name = xstrdup (file_name);
206   handle->identity = fn_get_identity (file_name);
207   handle->mode = properties->mode;
208   handle->record_width = properties->record_width;
209   handle->tab_width = properties->tab_width;
210   return handle;
211 }
212
213 /* Creates a new file handle named HANDLE_NAME, which must not be
214    the name of an existing file handle.  The new handle is
215    associated with a scratch file (initially empty). */
216 struct file_handle *
217 fh_create_scratch (const char *handle_name) 
218 {
219   struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
220   handle->sh = NULL;
221   return handle;
222 }
223
224 /* Returns a set of default properties for a file handle. */
225 const struct fh_properties *
226 fh_default_properties (void)
227 {
228   static const struct fh_properties default_properties
229     = {FH_MODE_TEXT, 1024, 4};
230   return &default_properties;
231 }
232
233 /* Deletes FH from the global list of file handles.  Afterward,
234    attempts to search for it will fail.  Unless the file handle
235    is currently open, it will be destroyed; otherwise, it will be
236    destroyed later when it is closed.
237    Normally needed only if a file_handle needs to be re-assigned.
238    Otherwise, just let fh_done() destroy the handle. */
239 void 
240 fh_free (struct file_handle *handle)
241 {
242   if (handle == fh_inline_file () || handle == NULL || handle->deleted)
243     return;
244   handle->deleted = true;
245
246   if (handle == default_handle)
247     default_handle = fh_inline_file ();
248
249   if (handle->open_cnt == 0)
250     free_handle (handle);
251 }
252
253 /* Returns an English description of MODE,
254    which is in the format of the MODE argument to fh_open(). */
255 static const char *
256 mode_name (const char *mode) 
257 {
258   assert (mode != NULL);
259   assert (mode[0] == 'r' || mode[0] == 'w');
260
261   return mode[0] == 'r' ? "reading" : "writing";
262 }
263
264 /* Tries to open handle H with the given TYPE and MODE.
265
266    H's referent type must be one of the bits in MASK.  The caller
267    must verify this ahead of time; we simply assert it here.
268
269    TYPE is the sort of file, e.g. "system file".  Only one given
270    type of access is allowed on a given file handle at once.
271    If successful, a reference to TYPE is retained, so it should
272    probably be a string literal.
273
274    MODE combines the read or write mode with the sharing mode.
275    The first character is 'r' for read, 'w' for write.  The
276    second character is 's' to permit sharing, 'e' to require
277    exclusive access.
278
279    Returns the address of a void * that the caller can use for
280    data specific to the file handle if successful, or a null
281    pointer on failure.  For exclusive access modes the void *
282    will always be a null pointer at return.  In shared access
283    modes the void * will necessarily be null only if no other
284    sharers are active. */
285 void **
286 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
287          const char *type, const char *mode) 
288 {
289   assert (h != NULL);
290   assert ((fh_get_referent (h) & mask) != 0);
291   assert (type != NULL);
292   assert (mode != NULL);
293   assert (mode[0] == 'r' || mode[0] == 'w');
294   assert (mode[1] == 's' || mode[1] == 'e');
295   assert (mode[2] == '\0');
296
297   if (h->open_cnt != 0) 
298     {
299       if (strcmp (h->type, type)) 
300         {
301           msg (SE, _("Can't open %s as a %s because it is "
302                      "already open as a %s."),
303                fh_get_name (h), type, h->type);
304           return NULL; 
305         }
306       else if (strcmp (h->open_mode, mode)) 
307         {
308           msg (SE, _("Can't open %s as a %s for %s because it is "
309                      "already open for %s."),
310                fh_get_name (h), type, mode_name (mode),
311                mode_name (h->open_mode));
312           return NULL;
313         }
314       else if (h->open_mode[1] == 'e')
315         {
316           msg (SE, _("Can't re-open %s as a %s for %s."),
317                fh_get_name (h), type, mode_name (mode));
318           return NULL;
319         }
320     }
321   else 
322     {
323       h->type = type;
324       strcpy (h->open_mode, mode);
325       assert (h->aux == NULL);
326     }
327   h->open_cnt++;
328
329   return &h->aux;
330 }
331
332 /* Closes file handle H, which must have been open for the
333    specified TYPE and MODE of access provided to fh_open().
334    Returns zero if the file is now closed, nonzero if it is still
335    open due to another reference.
336
337    After fh_close() returns zero for a handle, it is unsafe to
338    reference that file handle again in any way, because its
339    storage may have been freed. */
340 int
341 fh_close (struct file_handle *h, const char *type, const char *mode)
342 {
343   assert (h != NULL);
344   assert (h->open_cnt > 0);
345   assert (type != NULL);
346   assert (!strcmp (type, h->type));
347   assert (mode != NULL);
348   assert (!strcmp (mode, h->open_mode));
349
350   if (--h->open_cnt == 0) 
351     {
352       h->type = NULL;
353       h->aux = NULL;
354       if (h->deleted)
355         free_handle (h);
356       return 0;
357     }
358   return 1;
359 }
360
361 /* Is the file open?  BEGIN DATA...END DATA uses this to detect
362    whether the inline file is actually in use. */
363 bool
364 fh_is_open (const struct file_handle *handle) 
365 {
366   return handle->open_cnt > 0;
367 }
368
369 /* Returns the identifier of file HANDLE.  If HANDLE was created
370    by referring to a file name instead of a handle name, returns
371    the file name, enclosed in double quotes.  Return value is
372    owned by the file handle. 
373
374    Useful for printing error messages about use of file handles.  */
375 const char *
376 fh_get_name (const struct file_handle *handle)
377 {
378   return handle->name;
379 }
380
381 /* Returns the type of object that HANDLE refers to. */
382 enum fh_referent
383 fh_get_referent (const struct file_handle *handle) 
384 {
385   return handle->referent;
386 }
387
388 /* Returns the name of the file associated with HANDLE. */
389 const char *
390 fh_get_file_name (const struct file_handle *handle) 
391 {
392   assert (handle->referent == FH_REF_FILE);
393   return handle->file_name;
394 }
395
396 /* Returns the mode of HANDLE. */
397 enum fh_mode
398 fh_get_mode (const struct file_handle *handle) 
399 {
400   assert (handle->referent == FH_REF_FILE);
401   return handle->mode;
402 }
403
404 /* Returns the width of a logical record on HANDLE. */
405 size_t
406 fh_get_record_width (const struct file_handle *handle)
407 {
408   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
409   return handle->record_width;
410 }
411
412 /* Returns the number of characters per tab stop for HANDLE, or
413    zero if tabs are not to be expanded.  Applicable only to
414    FH_MODE_TEXT files. */
415 size_t
416 fh_get_tab_width (const struct file_handle *handle) 
417 {
418   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
419   return handle->tab_width;
420 }
421
422 /* Returns the scratch file handle associated with HANDLE.
423    Applicable to only FH_REF_SCRATCH files. */
424 struct scratch_handle *
425 fh_get_scratch_handle (struct file_handle *handle) 
426 {
427   assert (handle->referent == FH_REF_SCRATCH);
428   return handle->sh;
429 }
430
431 /* Sets SH to be the scratch file handle associated with HANDLE.
432    Applicable to only FH_REF_SCRATCH files. */
433 void
434 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
435 {
436   assert (handle->referent == FH_REF_SCRATCH);
437   handle->sh = sh;
438 }
439
440 /* Returns the current default handle. */
441 struct file_handle *
442 fh_get_default_handle (void) 
443 {
444   return default_handle ? default_handle : fh_inline_file ();
445 }
446
447 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
448 void
449 fh_set_default_handle (struct file_handle *new_default_handle) 
450 {
451   assert (new_default_handle == NULL
452           || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
453   default_handle = new_default_handle;
454 }