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