Patch #6258.
[pspp-builds.git] / src / data / file-handle-def.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU 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, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "file-handle-def.h"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <libpspp/compiler.h>
27 #include <libpspp/hash.h>
28 #include <libpspp/ll.h>
29 #include <libpspp/message.h>
30 #include <libpspp/str.h>
31 #include <data/file-name.h>
32 #include <data/variable.h>
33 #include <data/scratch-handle.h>
34
35 #include "xalloc.h"
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39
40 /* File handle. */
41 struct file_handle
42   {
43     struct ll ll;               /* Element in global list. */
44     size_t ref_cnt;             /* Number of references. */
45     char *id;                   /* Identifier token, NULL if none. */
46     char *name;                 /* User-friendly identifying name. */
47     enum fh_referent referent;  /* What the file handle refers to. */
48
49     /* FH_REF_FILE only. */
50     char *file_name;            /* File name as provided by user. */
51     enum fh_mode mode;          /* File mode. */
52
53     /* FH_REF_FILE and FH_REF_INLINE only. */
54     size_t record_width;        /* Length of fixed-format records. */
55     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
56
57     /* FH_REF_SCRATCH only. */
58     struct scratch_handle *sh;  /* Scratch file data. */
59   };
60
61 static struct file_handle *
62 file_handle_from_ll (struct ll *ll)
63 {
64   return ll_data (ll, struct file_handle, ll);
65 }
66
67 /* List of all named handles. */
68 static struct ll_list named_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 *id,
78                                           char *name, enum fh_referent);
79 static void free_handle (struct file_handle *);
80 static void unname_handle (struct file_handle *);
81
82 /* File handle initialization routine. */
83 void
84 fh_init (void)
85 {
86   ll_init (&named_handles);
87   inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE);
88   inline_file->record_width = 80;
89   inline_file->tab_width = 8;
90 }
91
92 /* Removes all named file handles from the global list. */
93 void
94 fh_done (void)
95 {
96   while (!ll_is_empty (&named_handles))
97     unname_handle (file_handle_from_ll (ll_head (&named_handles)));
98 }
99
100 /* Free HANDLE and remove it from the global list. */
101 static void
102 free_handle (struct file_handle *handle)
103 {
104   /* Remove handle from global list. */
105   if (handle->id != NULL)
106     ll_remove (&handle->ll);
107
108   /* Free data. */
109   free (handle->id);
110   free (handle->name);
111   free (handle->file_name);
112   scratch_handle_destroy (handle->sh);
113   free (handle);
114 }
115
116 /* Make HANDLE unnamed, so that it can no longer be referenced by
117    name.  The caller must hold a reference to HANDLE, which is
118    not affected by this function. */
119 static void
120 unname_handle (struct file_handle *handle)
121 {
122   assert (handle->id != NULL);
123   free (handle->id);
124   handle->id = NULL;
125   ll_remove (&handle->ll);
126
127   /* Drop the reference held by the named_handles table. */
128   fh_unref (handle);
129 }
130
131 /* Increments HANDLE's reference count and returns HANDLE. */
132 struct file_handle *
133 fh_ref (struct file_handle *handle)
134 {
135   assert (handle->ref_cnt > 0);
136   handle->ref_cnt++;
137   return handle;
138 }
139
140 /* Decrements HANDLE's reference count.
141    If the reference count drops to 0, HANDLE is destroyed. */
142 void
143 fh_unref (struct file_handle *handle)
144 {
145   if (handle != NULL)
146     {
147       assert (handle->ref_cnt > 0);
148       if (--handle->ref_cnt == 0)
149         free_handle (handle);
150     }
151 }
152
153 /* Make HANDLE unnamed, so that it can no longer be referenced by
154    name.  The caller must hold a reference to HANDLE, which is
155    not affected by this function.
156
157    This function ignores a null pointer as input.  It has no
158    effect on the inline handle, which is always named INLINE.*/
159 void
160 fh_unname (struct file_handle *handle)
161 {
162   assert (handle->ref_cnt > 1);
163   if (handle != fh_inline_file () && handle->id != NULL)
164     unname_handle (handle);
165 }
166
167 /* Returns the handle with the given ID, or a null pointer if
168    there is none. */
169 struct file_handle *
170 fh_from_id (const char *id)
171 {
172   struct file_handle *handle;
173
174   ll_for_each (handle, struct file_handle, ll, &named_handles)
175     if (!strcasecmp (id, handle->id))
176       {
177         handle->ref_cnt++;
178         return handle;
179       }
180
181   return NULL;
182 }
183
184 /* Creates a new handle with identifier ID (which may be null)
185    and name HANDLE_NAME that refers to REFERENT.  Links the new
186    handle into the global list.  Returns the new handle.
187
188    The new handle is not fully initialized.  The caller is
189    responsible for completing its initialization. */
190 static struct file_handle *
191 create_handle (const char *id, char *handle_name, enum fh_referent referent)
192 {
193   struct file_handle *handle = xzalloc (sizeof *handle);
194
195   handle->ref_cnt = 1;
196   handle->id = id != NULL ? xstrdup (id) : NULL;
197   handle->name = handle_name;
198   handle->referent = referent;
199
200   if (id != NULL)
201     {
202       assert (fh_from_id (id) == NULL);
203       ll_push_tail (&named_handles, &handle->ll);
204       handle->ref_cnt++;
205     }
206
207   return handle;
208 }
209
210 /* Returns the unique handle of referent type FH_REF_INLINE,
211    which refers to the "inline file" that represents character
212    data in the command file between BEGIN DATA and END DATA. */
213 struct file_handle *
214 fh_inline_file (void)
215 {
216   fh_ref (inline_file);
217   return inline_file;
218 }
219
220 /* Creates and returns a new file handle with the given ID, which
221    may be null.  If it is non-null, it must be unique among
222    existing file identifiers.  The new handle is associated with
223    file FILE_NAME and the given PROPERTIES. */
224 struct file_handle *
225 fh_create_file (const char *id, const char *file_name,
226                 const struct fh_properties *properties)
227 {
228   char *handle_name;
229   struct file_handle *handle;
230
231   handle_name = id != NULL ? xstrdup (id) : xasprintf ("\"%s\"", file_name);
232   handle = create_handle (id, handle_name, FH_REF_FILE);
233   handle->file_name = xstrdup (file_name);
234   handle->mode = properties->mode;
235   handle->record_width = properties->record_width;
236   handle->tab_width = properties->tab_width;
237   return handle;
238 }
239
240 /* Creates a new file handle with the given ID, which must be
241    unique among existing file identifiers.  The new handle is
242    associated with a scratch file (initially empty). */
243 struct file_handle *
244 fh_create_scratch (const char *id)
245 {
246   struct file_handle *handle;
247   handle = create_handle (id, xstrdup (id), FH_REF_SCRATCH);
248   handle->sh = NULL;
249   return handle;
250 }
251
252 /* Returns a set of default properties for a file handle. */
253 const struct fh_properties *
254 fh_default_properties (void)
255 {
256   static const struct fh_properties default_properties
257     = {FH_MODE_TEXT, 1024, 4};
258   return &default_properties;
259 }
260
261 /* Returns the identifier that may be used in syntax to name the
262    given HANDLE, which takes the form of a PSPP identifier.  If
263    HANDLE has no identifier, returns a null pointer.
264
265    Return value is owned by the file handle.*/
266 const char *
267 fh_get_id (const struct file_handle *handle)
268 {
269   return handle->id;
270 }
271
272 /* Returns a user-friendly string to identify the given HANDLE.
273    If HANDLE was created by referring to a file name, returns the
274    file name, enclosed in double quotes.  Return value is owned
275    by the file handle.
276
277    Useful for printing error messages about use of file handles.  */
278 const char *
279 fh_get_name (const struct file_handle *handle)
280 {
281   return handle->name;
282 }
283
284 /* Returns the type of object that HANDLE refers to. */
285 enum fh_referent
286 fh_get_referent (const struct file_handle *handle)
287 {
288   return handle->referent;
289 }
290
291 /* Returns the name of the file associated with HANDLE. */
292 const char *
293 fh_get_file_name (const struct file_handle *handle)
294 {
295   assert (handle->referent == FH_REF_FILE);
296   return handle->file_name;
297 }
298
299 /* Returns the mode of HANDLE. */
300 enum fh_mode
301 fh_get_mode (const struct file_handle *handle)
302 {
303   assert (handle->referent == FH_REF_FILE);
304   return handle->mode;
305 }
306
307 /* Returns the width of a logical record on HANDLE. */
308 size_t
309 fh_get_record_width (const struct file_handle *handle)
310 {
311   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
312   return handle->record_width;
313 }
314
315 /* Returns the number of characters per tab stop for HANDLE, or
316    zero if tabs are not to be expanded.  Applicable only to
317    FH_MODE_TEXT files. */
318 size_t
319 fh_get_tab_width (const struct file_handle *handle)
320 {
321   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
322   return handle->tab_width;
323 }
324
325 /* Returns the scratch file handle associated with HANDLE.
326    Applicable to only FH_REF_SCRATCH files. */
327 struct scratch_handle *
328 fh_get_scratch_handle (const struct file_handle *handle)
329 {
330   assert (handle->referent == FH_REF_SCRATCH);
331   return handle->sh;
332 }
333
334 /* Sets SH to be the scratch file handle associated with HANDLE.
335    Applicable to only FH_REF_SCRATCH files. */
336 void
337 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
338 {
339   assert (handle->referent == FH_REF_SCRATCH);
340   handle->sh = sh;
341 }
342
343 /* Returns the current default handle. */
344 struct file_handle *
345 fh_get_default_handle (void)
346 {
347   return default_handle ? fh_ref (default_handle) : fh_inline_file ();
348 }
349
350 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
351 void
352 fh_set_default_handle (struct file_handle *new_default_handle)
353 {
354   assert (new_default_handle == NULL
355           || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
356   if (default_handle != NULL)
357     fh_unref (default_handle);
358   default_handle = new_default_handle;
359   if (default_handle != NULL)
360     fh_ref (default_handle);
361 }
362 \f
363 /* Information about a file handle's readers or writers. */
364 struct fh_lock
365   {
366     /* Hash key. */
367     enum fh_referent referent;  /* Type of underlying file. */
368     union
369       {
370         struct file_identity *file; /* FH_REF_FILE only. */
371         unsigned int unique_id;    /* FH_REF_SCRATCH only. */
372       }
373     u;
374     enum fh_access access;      /* Type of file access. */
375
376     /* Number of openers. */
377     size_t open_cnt;
378
379     /* Applicable only when open_cnt > 0. */
380     bool exclusive;             /* No other openers allowed? */
381     const char *type;           /* Human-readable type of file. */
382     void *aux;                  /* Owner's auxiliary data. */
383   };
384
385 /* Hash table of all active locks. */
386 static struct hsh_table *locks;
387
388 static void make_key (struct fh_lock *, const struct file_handle *,
389                       enum fh_access);
390 static void free_key (struct fh_lock *);
391 static int compare_fh_locks (const void *, const void *, const void *);
392 static unsigned int hash_fh_lock (const void *, const void *);
393
394 /* Tries to lock handle H for the given kind of ACCESS and TYPE
395    of file.  Returns a pointer to a struct fh_lock if successful,
396    otherwise a null pointer.
397
398    H's referent type must be one of the bits in MASK.  The caller
399    must verify this ahead of time; we simply assert it here.
400
401    TYPE is the sort of file, e.g. "system file".  Only one type
402    of access is allowed on a given file at a time for reading,
403    and similarly for writing.  If successful, a reference to TYPE
404    is retained, so it should probably be a string literal.
405
406    TYPE should be marked with N_() in the caller: that is, the
407    caller should not translate it with gettext, but fh_lock will
408    do so.
409
410    ACCESS specifies whether the lock is for reading or writing.
411    EXCLUSIVE is true to require exclusive access, false to allow
412    sharing with other accessors.  Exclusive read access precludes
413    other readers, but not writers; exclusive write access
414    precludes other writers, but not readers.  A sharable read or
415    write lock precludes reader or writers, respectively, of a
416    different TYPE.
417
418    A lock may be associated with auxiliary data.  See
419    fh_lock_get_aux and fh_lock_set_aux for more details. */
420 struct fh_lock *
421 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
422          const char *type, enum fh_access access, bool exclusive)
423 {
424   struct fh_lock key, *lock;
425   void **lockp;
426
427   assert ((fh_get_referent (h) & mask) != 0);
428   assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
429
430   if (locks == NULL)
431     locks = hsh_create (0, compare_fh_locks, hash_fh_lock, NULL, NULL);
432
433   make_key (&key, h, access);
434   lockp = hsh_probe (locks, &key);
435   if (*lockp == NULL)
436     {
437       lock = *lockp = xmalloc (sizeof *lock);
438       *lock = key;
439       lock->open_cnt = 1;
440       lock->exclusive = exclusive;
441       lock->type = type;
442       lock->aux = NULL;
443     }
444   else
445     {
446       free_key (&key);
447
448       lock = *lockp;
449       if (strcmp (lock->type, type))
450         {
451           if (access == FH_ACC_READ)
452             msg (SE, _("Can't read from %s as a %s because it is "
453                        "already being read as a %s."),
454                  fh_get_name (h), gettext (type), gettext (lock->type));
455           else
456             msg (SE, _("Can't write to %s as a %s because it is "
457                        "already being written as a %s."),
458                  fh_get_name (h), gettext (type), gettext (lock->type));
459           return NULL;
460         }
461       else if (exclusive || lock->exclusive)
462         {
463           msg (SE, _("Can't re-open %s as a %s."),
464                fh_get_name (h), gettext (type));
465           return NULL;
466         }
467       lock->open_cnt++;
468     }
469
470   return lock;
471 }
472
473 /* Releases LOCK that was acquired with fh_lock.
474    Returns true if LOCK is still locked, because other clients
475    also had it locked.
476
477    Returns false if LOCK has now been destroyed.  In this case
478    the caller must ensure that any auxiliary data associated with
479    LOCK is destroyed, to avoid a memory leak.  The caller must
480    obtain a pointer to the auxiliary data, e.g. via
481    fh_lock_get_aux *before* calling fh_unlock (because it yields
482    undefined behavior to call fh_lock_get_aux on a destroyed
483    lock).  */
484 bool
485 fh_unlock (struct fh_lock *lock)
486 {
487   if (lock != NULL)
488     {
489       assert (lock->open_cnt > 0);
490       if (--lock->open_cnt == 0)
491         {
492           hsh_delete (locks, lock);
493           free_key (lock);
494           free (lock);
495           return false;
496         }
497     }
498   return true;
499 }
500
501 /* Returns auxiliary data for LOCK.
502
503    Auxiliary data is shared by every client that holds LOCK (for
504    an exclusive lock, this is a single client).  To avoid leaks,
505    auxiliary data must be released before LOCK is destroyed. */
506 void *
507 fh_lock_get_aux (const struct fh_lock *lock)
508 {
509   return lock->aux;
510 }
511
512 /* Sets the auxiliary data for LOCK to AUX. */
513 void
514 fh_lock_set_aux (struct fh_lock *lock, void *aux)
515 {
516   lock->aux = aux;
517 }
518
519 /* Returns true if HANDLE is locked for the given type of ACCESS,
520    false otherwise. */
521 bool
522 fh_is_locked (const struct file_handle *handle, enum fh_access access)
523 {
524   struct fh_lock key;
525   bool is_locked;
526
527   make_key (&key, handle, access);
528   is_locked = hsh_find (locks, &key) != NULL;
529   free_key (&key);
530
531   return is_locked;
532 }
533
534 /* Initializes the key fields in LOCK for looking up or inserting
535    handle H for the given kind of ACCESS. */
536 static void
537 make_key (struct fh_lock *lock, const struct file_handle *h,
538           enum fh_access access)
539 {
540   lock->referent = fh_get_referent (h);
541   lock->access = access;
542   if (lock->referent == FH_REF_FILE)
543     lock->u.file = fn_get_identity (fh_get_file_name (h));
544   else if (lock->referent == FH_REF_SCRATCH)
545     {
546       struct scratch_handle *sh = fh_get_scratch_handle (h);
547       lock->u.unique_id = sh != NULL ? sh->unique_id : 0;
548     }
549 }
550
551 /* Frees the key fields in LOCK. */
552 static void
553 free_key (struct fh_lock *lock)
554 {
555   if (lock->referent == FH_REF_FILE)
556     fn_free_identity (lock->u.file);
557 }
558
559 /* Compares the key fields in struct fh_lock objects A and B and
560    returns a strcmp()-type result. */
561 static int
562 compare_fh_locks (const void *a_, const void *b_, const void *aux UNUSED)
563 {
564   const struct fh_lock *a = a_;
565   const struct fh_lock *b = b_;
566
567   if (a->referent != b->referent)
568     return a->referent < b->referent ? -1 : 1;
569   else if (a->access != b->access)
570     return a->access < b->access ? -1 : 1;
571   else if (a->referent == FH_REF_FILE)
572     return fn_compare_file_identities (a->u.file, b->u.file);
573   else if (a->referent == FH_REF_SCRATCH)
574     return (a->u.unique_id < b->u.unique_id ? -1
575             : a->u.unique_id > b->u.unique_id);
576   else
577     return 0;
578 }
579
580 /* Returns a hash value for LOCK. */
581 static unsigned int
582 hash_fh_lock (const void *lock_, const void *aux UNUSED)
583 {
584   const struct fh_lock *lock = lock_;
585   unsigned int hash = hsh_hash_int ((lock->referent << 3) | lock->access);
586   if (lock->referent == FH_REF_FILE)
587     hash ^= fn_hash_identity (lock->u.file);
588   else if (lock->referent == FH_REF_SCRATCH)
589     hash ^= hsh_hash_int (lock->u.unique_id);
590   return hash;
591 }