1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "data/file-handle-def.h"
26 #include "data/dataset.h"
27 #include "data/file-name.h"
28 #include "data/variable.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/compiler.h"
31 #include "libpspp/hash-functions.h"
32 #include "libpspp/hmap.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/message.h"
35 #include "libpspp/str.h"
37 #include "gl/xalloc.h"
40 #define _(msgid) gettext (msgid)
45 struct hmap_node name_node; /* Element in named_handles hmap. */
46 size_t ref_cnt; /* Number of references. */
47 char *id; /* Identifier token, NULL if none. */
48 char *name; /* User-friendly identifying name. */
49 enum fh_referent referent; /* What the file handle refers to. */
51 /* FH_REF_FILE only. */
52 char *file_name; /* File name as provided by user. */
53 enum fh_mode mode; /* File mode. */
54 enum fh_line_ends line_ends; /* Line ends for text files. */
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 char *encoding; /* Charset for contents. */
61 /* FH_REF_DATASET only. */
62 struct dataset *ds; /* Dataset. */
65 /* All "struct file_handle"s with nonnull 'id' member. */
66 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
68 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
70 static struct file_handle *default_handle;
72 /* The "file" that reads from BEGIN DATA...END DATA. */
73 static struct file_handle *inline_file;
75 static struct file_handle *create_handle (const char *id,
76 char *name, enum fh_referent,
77 const char *encoding);
78 static void free_handle (struct file_handle *);
79 static void unname_handle (struct file_handle *);
81 /* Hash table of all active locks. */
82 static struct hmap locks = HMAP_INITIALIZER (locks);
84 /* File handle initialization routine. */
88 inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
90 inline_file->record_width = 80;
91 inline_file->tab_width = 8;
94 /* Removes all named file handles from the global list. */
98 struct file_handle *handle, *next;
100 HMAP_FOR_EACH_SAFE (handle, next,
101 struct file_handle, name_node, &named_handles)
102 unname_handle (handle);
105 /* Free HANDLE and remove it from the global list. */
107 free_handle (struct file_handle *handle)
109 /* Remove handle from global list. */
110 if (handle->id != NULL)
111 hmap_delete (&named_handles, &handle->name_node);
116 free (handle->file_name);
117 free (handle->encoding);
121 /* Make HANDLE unnamed, so that it can no longer be referenced by
122 name. The caller must hold a reference to HANDLE, which is
123 not affected by this function. */
125 unname_handle (struct file_handle *handle)
127 assert (handle->id != NULL);
130 hmap_delete (&named_handles, &handle->name_node);
132 /* Drop the reference held by the named_handles table. */
136 /* Increments HANDLE's reference count and returns HANDLE. */
138 fh_ref (struct file_handle *handle)
140 assert (handle->ref_cnt > 0);
145 /* Decrements HANDLE's reference count.
146 If the reference count drops to 0, HANDLE is destroyed. */
148 fh_unref (struct file_handle *handle)
152 assert (handle->ref_cnt > 0);
153 if (--handle->ref_cnt == 0)
154 free_handle (handle);
158 /* Make HANDLE unnamed, so that it can no longer be referenced by
159 name. The caller must hold a reference to HANDLE, which is
160 not affected by this function.
162 This function ignores a null pointer as input. It has no
163 effect on the inline handle, which is always named INLINE.*/
165 fh_unname (struct file_handle *handle)
167 assert (handle->ref_cnt > 1);
168 if (handle != fh_inline_file () && handle->id != NULL)
169 unname_handle (handle);
172 /* Returns the handle with the given ID, or a null pointer if
175 fh_from_id (const char *id)
177 struct file_handle *handle;
179 HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
180 utf8_hash_case_string (id, 0), &named_handles)
181 if (!utf8_strcasecmp (id, handle->id))
183 return fh_ref (handle);
189 /* Creates a new handle with identifier ID (which may be null)
190 and name HANDLE_NAME that refers to REFERENT. Links the new
191 handle into the global list. Returns the new handle.
193 The new handle is not fully initialized. The caller is
194 responsible for completing its initialization. */
195 static struct file_handle *
196 create_handle (const char *id, char *handle_name, enum fh_referent referent,
197 const char *encoding)
199 struct file_handle *handle = xzalloc (sizeof *handle);
202 handle->id = id != NULL ? xstrdup (id) : NULL;
203 handle->name = handle_name;
204 handle->referent = referent;
205 handle->encoding = xstrdup (encoding);
209 hmap_insert (&named_handles, &handle->name_node,
210 utf8_hash_case_string (handle->id, 0));
216 /* Returns the unique handle of referent type FH_REF_INLINE,
217 which refers to the "inline file" that represents character
218 data in the command file between BEGIN DATA and END DATA. */
220 fh_inline_file (void)
225 /* Creates and returns a new file handle with the given ID, which may be null.
226 If it is non-null, it must be a UTF-8 encoded string that is unique among
227 existing file identifiers. The new handle is associated with file FILE_NAME
228 and the given PROPERTIES. */
230 fh_create_file (const char *id, const char *file_name,
231 const struct fh_properties *properties)
234 struct file_handle *handle;
236 handle_name = id != NULL ? xstrdup (id) : xasprintf ("`%s'", file_name);
237 handle = create_handle (id, handle_name, FH_REF_FILE, properties->encoding);
238 handle->file_name = xstrdup (file_name);
239 handle->mode = properties->mode;
240 handle->line_ends = properties->line_ends;
241 handle->record_width = properties->record_width;
242 handle->tab_width = properties->tab_width;
246 /* Creates a new file handle with the given ID, which must be
247 unique among existing file identifiers. The new handle is
248 associated with a dataset file (initially empty). */
250 fh_create_dataset (struct dataset *ds)
253 struct file_handle *handle;
255 name = dataset_name (ds);
257 name = _("active dataset");
259 handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
264 /* Returns a set of default properties for a file handle. */
265 const struct fh_properties *
266 fh_default_properties (void)
268 #if defined _WIN32 || defined __WIN32__
269 #define DEFAULT_LINE_ENDS FH_END_CRLF
271 #define DEFAULT_LINE_ENDS FH_END_LF
274 static const struct fh_properties default_properties
275 = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
276 return &default_properties;
279 /* Returns the identifier that may be used in syntax to name the
280 given HANDLE, which takes the form of a PSPP identifier. If
281 HANDLE has no identifier, returns a null pointer.
283 Return value is owned by the file handle.*/
285 fh_get_id (const struct file_handle *handle)
290 /* Returns a user-friendly string to identify the given HANDLE.
291 If HANDLE was created by referring to a file name, returns the
292 file name, enclosed in double quotes. Return value is owned
295 Useful for printing error messages about use of file handles. */
297 fh_get_name (const struct file_handle *handle)
302 /* Returns the type of object that HANDLE refers to. */
304 fh_get_referent (const struct file_handle *handle)
306 return handle->referent;
309 /* Returns the name of the file associated with HANDLE. */
311 fh_get_file_name (const struct file_handle *handle)
313 assert (handle->referent == FH_REF_FILE);
314 return handle->file_name;
317 /* Returns the mode of HANDLE. */
319 fh_get_mode (const struct file_handle *handle)
321 assert (handle->referent == FH_REF_FILE);
325 /* Returns the line ends of HANDLE, which must be a handle associated with a
328 fh_get_line_ends (const struct file_handle *handle)
330 assert (handle->referent == FH_REF_FILE);
331 return handle->line_ends;
334 /* Returns the width of a logical record on HANDLE. */
336 fh_get_record_width (const struct file_handle *handle)
338 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
339 return handle->record_width;
342 /* Returns the number of characters per tab stop for HANDLE, or
343 zero if tabs are not to be expanded. Applicable only to
344 FH_MODE_TEXT files. */
346 fh_get_tab_width (const struct file_handle *handle)
348 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
349 return handle->tab_width;
352 /* Returns the encoding of characters read from HANDLE. */
354 fh_get_encoding (const struct file_handle *handle)
356 return handle->encoding;
359 /* Returns the dataset handle associated with HANDLE.
360 Applicable to only FH_REF_DATASET files. */
362 fh_get_dataset (const struct file_handle *handle)
364 assert (handle->referent == FH_REF_DATASET);
368 /* Returns the current default handle. */
370 fh_get_default_handle (void)
372 return default_handle ? default_handle : fh_inline_file ();
375 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
377 fh_set_default_handle (struct file_handle *new_default_handle)
379 assert (new_default_handle == NULL
380 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
381 if (default_handle != NULL && default_handle != inline_file)
382 fh_unref (default_handle);
383 default_handle = new_default_handle;
384 if (default_handle != NULL)
385 fh_ref (default_handle);
388 /* Information about a file handle's readers or writers. */
391 struct hmap_node node; /* hmap_node member. */
394 enum fh_referent referent; /* Type of underlying file. */
397 struct file_identity *file; /* FH_REF_FILE only. */
398 unsigned int unique_id; /* FH_REF_DATASET only. */
401 enum fh_access access; /* Type of file access. */
403 /* Number of openers. */
406 /* Applicable only when open_cnt > 0. */
407 bool exclusive; /* No other openers allowed? */
408 const char *type; /* Human-readable type of file. */
409 void *aux; /* Owner's auxiliary data. */
413 static void make_key (struct fh_lock *, const struct file_handle *,
415 static void free_key (struct fh_lock *);
416 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
417 static unsigned int hash_fh_lock (const struct fh_lock *lock);
419 /* Tries to lock handle H for the given kind of ACCESS and TYPE
420 of file. Returns a pointer to a struct fh_lock if successful,
421 otherwise a null pointer.
423 H's referent type must be one of the bits in MASK. The caller
424 must verify this ahead of time; we simply assert it here.
426 TYPE is the sort of file, e.g. "system file". Only one type
427 of access is allowed on a given file at a time for reading,
428 and similarly for writing. If successful, a reference to TYPE
429 is retained, so it should probably be a string literal.
431 TYPE should be marked with N_() in the caller: that is, the
432 caller should not translate it with gettext, but fh_lock will
435 ACCESS specifies whether the lock is for reading or writing.
436 EXCLUSIVE is true to require exclusive access, false to allow
437 sharing with other accessors. Exclusive read access precludes
438 other readers, but not writers; exclusive write access
439 precludes other writers, but not readers. A sharable read or
440 write lock precludes reader or writers, respectively, of a
443 A lock may be associated with auxiliary data. See
444 fh_lock_get_aux and fh_lock_set_aux for more details. */
446 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
447 const char *type, enum fh_access access, bool exclusive)
449 struct fh_lock *key = NULL;
451 struct fh_lock *lock = NULL;
452 bool found_lock = false;
454 assert ((fh_get_referent (h) & mask) != 0);
455 assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
457 key = xmalloc (sizeof *key);
459 make_key (key, h, access);
462 key->exclusive = exclusive;
466 hash = hash_fh_lock (key);
468 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
470 if ( 0 == compare_fh_locks (lock, key))
479 if (strcmp (lock->type, type))
481 if (access == FH_ACC_READ)
482 msg (SE, _("Can't read from %s as a %s because it is "
483 "already being read as a %s."),
484 fh_get_name (h), gettext (type), gettext (lock->type));
486 msg (SE, _("Can't write to %s as a %s because it is "
487 "already being written as a %s."),
488 fh_get_name (h), gettext (type), gettext (lock->type));
491 else if (exclusive || lock->exclusive)
493 msg (SE, _("Can't re-open %s as a %s."),
494 fh_get_name (h), gettext (type));
505 hmap_insert (&locks, &key->node, hash);
507 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
509 if ( 0 == compare_fh_locks (lock, key))
521 /* Releases LOCK that was acquired with fh_lock.
522 Returns true if LOCK is still locked, because other clients
525 Returns false if LOCK has now been destroyed. In this case
526 the caller must ensure that any auxiliary data associated with
527 LOCK is destroyed, to avoid a memory leak. The caller must
528 obtain a pointer to the auxiliary data, e.g. via
529 fh_lock_get_aux *before* calling fh_unlock (because it yields
530 undefined behavior to call fh_lock_get_aux on a destroyed
533 fh_unlock (struct fh_lock *lock)
537 assert (lock->open_cnt > 0);
538 if (--lock->open_cnt == 0)
540 hmap_delete (&locks, &lock->node);
549 /* Returns auxiliary data for LOCK.
551 Auxiliary data is shared by every client that holds LOCK (for
552 an exclusive lock, this is a single client). To avoid leaks,
553 auxiliary data must be released before LOCK is destroyed. */
555 fh_lock_get_aux (const struct fh_lock *lock)
560 /* Sets the auxiliary data for LOCK to AUX. */
562 fh_lock_set_aux (struct fh_lock *lock, void *aux)
567 /* Returns true if HANDLE is locked for the given type of ACCESS,
570 fh_is_locked (const struct file_handle *handle, enum fh_access access)
573 const struct fh_lock *k = NULL;
574 bool is_locked = false;
577 make_key (&key, handle, access);
579 hash = hash_fh_lock (&key);
582 HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
584 if ( 0 == compare_fh_locks (k, &key))
596 /* Initializes the key fields in LOCK for looking up or inserting
597 handle H for the given kind of ACCESS. */
599 make_key (struct fh_lock *lock, const struct file_handle *h,
600 enum fh_access access)
602 lock->referent = fh_get_referent (h);
603 lock->access = access;
604 if (lock->referent == FH_REF_FILE)
605 lock->u.file = fn_get_identity (fh_get_file_name (h));
606 else if (lock->referent == FH_REF_DATASET)
607 lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
610 /* Frees the key fields in LOCK. */
612 free_key (struct fh_lock *lock)
614 if (lock->referent == FH_REF_FILE)
615 fn_free_identity (lock->u.file);
618 /* Compares the key fields in struct fh_lock objects A and B and
619 returns a strcmp()-type result. */
621 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
623 if (a->referent != b->referent)
624 return a->referent < b->referent ? -1 : 1;
625 else if (a->access != b->access)
626 return a->access < b->access ? -1 : 1;
627 else if (a->referent == FH_REF_FILE)
628 return fn_compare_file_identities (a->u.file, b->u.file);
629 else if (a->referent == FH_REF_DATASET)
630 return (a->u.unique_id < b->u.unique_id ? -1
631 : a->u.unique_id > b->u.unique_id);
636 /* Returns a hash value for LOCK. */
638 hash_fh_lock (const struct fh_lock *lock)
641 if (lock->referent == FH_REF_FILE)
642 basis = fn_hash_identity (lock->u.file);
643 else if (lock->referent == FH_REF_DATASET)
644 basis = lock->u.unique_id;
647 return hash_int ((lock->referent << 3) | lock->access, basis);