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