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