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 char *file_name_encoding; /* The character encoding of file_name,
54 This is NOT the encoding of the file contents! */
55 enum fh_mode mode; /* File mode. */
56 enum fh_line_ends line_ends; /* Line ends for text files. */
58 /* FH_REF_FILE and FH_REF_INLINE only. */
59 size_t record_width; /* Length of fixed-format records. */
60 size_t tab_width; /* Tab width, 0=do not expand tabs. */
61 char *encoding; /* Charset for contents. */
63 /* FH_REF_DATASET only. */
64 struct dataset *ds; /* Dataset. */
67 /* All "struct file_handle"s with nonnull 'id' member. */
68 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
70 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
72 static struct file_handle *default_handle;
74 /* The "file" that reads from BEGIN DATA...END DATA. */
75 static struct file_handle *inline_file;
77 static struct file_handle *create_handle (const char *id,
78 char *name, enum fh_referent,
79 const char *encoding);
80 static void free_handle (struct file_handle *);
81 static void unname_handle (struct file_handle *);
83 /* Hash table of all active locks. */
84 static struct hmap locks = HMAP_INITIALIZER (locks);
86 /* File handle initialization routine. */
90 inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
92 inline_file->record_width = 80;
93 inline_file->tab_width = 8;
96 /* Removes all named file handles from the global list. */
100 struct file_handle *handle, *next;
102 HMAP_FOR_EACH_SAFE (handle, next,
103 struct file_handle, name_node, &named_handles)
104 unname_handle (handle);
107 /* Free HANDLE and remove it from the global list. */
109 free_handle (struct file_handle *handle)
111 /* Remove handle from global list. */
112 if (handle->id != NULL)
113 hmap_delete (&named_handles, &handle->name_node);
118 free (handle->file_name);
119 free (handle->file_name_encoding);
120 free (handle->encoding);
124 /* Make HANDLE unnamed, so that it can no longer be referenced by
125 name. The caller must hold a reference to HANDLE, which is
126 not affected by this function. */
128 unname_handle (struct file_handle *handle)
130 assert (handle->id != NULL);
133 hmap_delete (&named_handles, &handle->name_node);
135 /* Drop the reference held by the named_handles table. */
139 /* Increments HANDLE's reference count and returns HANDLE. */
141 fh_ref (struct file_handle *handle)
143 assert (handle->ref_cnt > 0);
148 /* Decrements HANDLE's reference count.
149 If the reference count drops to 0, HANDLE is destroyed. */
151 fh_unref (struct file_handle *handle)
155 assert (handle->ref_cnt > 0);
156 if (--handle->ref_cnt == 0)
157 free_handle (handle);
161 /* Make HANDLE unnamed, so that it can no longer be referenced by
162 name. The caller must hold a reference to HANDLE, which is
163 not affected by this function.
165 This function ignores a null pointer as input. It has no
166 effect on the inline handle, which is always named INLINE.*/
168 fh_unname (struct file_handle *handle)
170 assert (handle->ref_cnt > 1);
171 if (handle != fh_inline_file () && handle->id != NULL)
172 unname_handle (handle);
175 /* Returns the handle with the given ID, or a null pointer if
178 fh_from_id (const char *id)
180 struct file_handle *handle;
182 HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
183 utf8_hash_case_string (id, 0), &named_handles)
184 if (!utf8_strcasecmp (id, handle->id))
186 return fh_ref (handle);
192 /* Creates a new handle with identifier ID (which may be null)
193 and name HANDLE_NAME that refers to REFERENT. Links the new
194 handle into the global list. Returns the new handle.
196 The new handle is not fully initialized. The caller is
197 responsible for completing its initialization. */
198 static struct file_handle *
199 create_handle (const char *id, char *handle_name, enum fh_referent referent,
200 const char *encoding)
202 struct file_handle *handle = xzalloc (sizeof *handle);
205 handle->id = id != NULL ? xstrdup (id) : NULL;
206 handle->name = handle_name;
207 handle->referent = referent;
208 handle->encoding = xstrdup (encoding);
212 hmap_insert (&named_handles, &handle->name_node,
213 utf8_hash_case_string (handle->id, 0));
219 /* Returns the unique handle of referent type FH_REF_INLINE,
220 which refers to the "inline file" that represents character
221 data in the command file between BEGIN DATA and END DATA. */
223 fh_inline_file (void)
228 /* Creates and returns a new file handle with the given ID, which may be null.
229 If it is non-null, it must be a UTF-8 encoded string that is unique among
230 existing file identifiers. The new handle is associated with file FILE_NAME
231 and the given PROPERTIES. */
233 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
234 const struct fh_properties *properties)
237 struct file_handle *handle;
239 handle_name = id != NULL ? xstrdup (id) : xasprintf ("`%s'", file_name);
240 handle = create_handle (id, handle_name, FH_REF_FILE, properties->encoding);
241 handle->file_name = xstrdup (file_name);
242 handle->file_name_encoding = file_name_encoding ? xstrdup (file_name_encoding) : NULL;
243 handle->mode = properties->mode;
244 handle->line_ends = properties->line_ends;
245 handle->record_width = properties->record_width;
246 handle->tab_width = properties->tab_width;
250 /* Creates a new file handle with the given ID, which must be
251 unique among existing file identifiers. The new handle is
252 associated with a dataset file (initially empty). */
254 fh_create_dataset (struct dataset *ds)
257 struct file_handle *handle;
259 name = dataset_name (ds);
261 name = _("active dataset");
263 handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
268 /* Returns a set of default properties for a file handle. */
269 const struct fh_properties *
270 fh_default_properties (void)
272 #if defined _WIN32 || defined __WIN32__
273 #define DEFAULT_LINE_ENDS FH_END_CRLF
275 #define DEFAULT_LINE_ENDS FH_END_LF
278 static const struct fh_properties default_properties
279 = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
280 return &default_properties;
283 /* Returns the identifier that may be used in syntax to name the
284 given HANDLE, which takes the form of a PSPP identifier. If
285 HANDLE has no identifier, returns a null pointer.
287 Return value is owned by the file handle.*/
289 fh_get_id (const struct file_handle *handle)
294 /* Returns a user-friendly string to identify the given HANDLE.
295 If HANDLE was created by referring to a file name, returns the
296 file name, enclosed in double quotes. Return value is owned
299 Useful for printing error messages about use of file handles. */
301 fh_get_name (const struct file_handle *handle)
306 /* Returns the type of object that HANDLE refers to. */
308 fh_get_referent (const struct file_handle *handle)
310 return handle->referent;
313 /* Returns the name of the file associated with HANDLE. */
315 fh_get_file_name (const struct file_handle *handle)
317 assert (handle->referent == FH_REF_FILE);
318 return handle->file_name;
322 /* Returns the character encoding of the name of the file associated with HANDLE. */
324 fh_get_file_name_encoding (const struct file_handle *handle)
326 assert (handle->referent == FH_REF_FILE);
327 return handle->file_name_encoding;
331 /* Returns the mode of HANDLE. */
333 fh_get_mode (const struct file_handle *handle)
335 assert (handle->referent == FH_REF_FILE);
339 /* Returns the line ends of HANDLE, which must be a handle associated with a
342 fh_get_line_ends (const struct file_handle *handle)
344 assert (handle->referent == FH_REF_FILE);
345 return handle->line_ends;
348 /* Returns the width of a logical record on HANDLE. */
350 fh_get_record_width (const struct file_handle *handle)
352 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
353 return handle->record_width;
356 /* Returns the number of characters per tab stop for HANDLE, or
357 zero if tabs are not to be expanded. Applicable only to
358 FH_MODE_TEXT files. */
360 fh_get_tab_width (const struct file_handle *handle)
362 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
363 return handle->tab_width;
366 /* Returns the encoding of characters read from HANDLE. */
368 fh_get_encoding (const struct file_handle *handle)
370 return handle->encoding;
373 /* Returns the dataset handle associated with HANDLE.
374 Applicable to only FH_REF_DATASET files. */
376 fh_get_dataset (const struct file_handle *handle)
378 assert (handle->referent == FH_REF_DATASET);
382 /* Returns the current default handle. */
384 fh_get_default_handle (void)
386 return default_handle ? default_handle : fh_inline_file ();
389 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
391 fh_set_default_handle (struct file_handle *new_default_handle)
393 assert (new_default_handle == NULL
394 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
395 if (default_handle != NULL && default_handle != inline_file)
396 fh_unref (default_handle);
397 default_handle = new_default_handle;
398 if (default_handle != NULL)
399 fh_ref (default_handle);
402 /* Information about a file handle's readers or writers. */
405 struct hmap_node node; /* hmap_node member. */
408 enum fh_referent referent; /* Type of underlying file. */
411 struct file_identity *file; /* FH_REF_FILE only. */
412 unsigned int unique_id; /* FH_REF_DATASET only. */
415 enum fh_access access; /* Type of file access. */
417 /* Number of openers. */
420 /* Applicable only when open_cnt > 0. */
421 bool exclusive; /* No other openers allowed? */
422 const char *type; /* Human-readable type of file. */
423 void *aux; /* Owner's auxiliary data. */
427 static void make_key (struct fh_lock *, const struct file_handle *,
429 static void free_key (struct fh_lock *);
430 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
431 static unsigned int hash_fh_lock (const struct fh_lock *lock);
433 /* Tries to lock handle H for the given kind of ACCESS and TYPE
434 of file. Returns a pointer to a struct fh_lock if successful,
435 otherwise a null pointer.
437 H's referent type must be one of the bits in MASK. The caller
438 must verify this ahead of time; we simply assert it here.
440 TYPE is the sort of file, e.g. "system file". Only one type
441 of access is allowed on a given file at a time for reading,
442 and similarly for writing. If successful, a reference to TYPE
443 is retained, so it should probably be a string literal.
445 TYPE should be marked with N_() in the caller: that is, the
446 caller should not translate it with gettext, but fh_lock will
449 ACCESS specifies whether the lock is for reading or writing.
450 EXCLUSIVE is true to require exclusive access, false to allow
451 sharing with other accessors. Exclusive read access precludes
452 other readers, but not writers; exclusive write access
453 precludes other writers, but not readers. A sharable read or
454 write lock precludes reader or writers, respectively, of a
457 A lock may be associated with auxiliary data. See
458 fh_lock_get_aux and fh_lock_set_aux for more details. */
460 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
461 const char *type, enum fh_access access, bool exclusive)
463 struct fh_lock *key = NULL;
465 struct fh_lock *lock = NULL;
466 bool found_lock = false;
468 assert ((fh_get_referent (h) & mask) != 0);
469 assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
471 key = xmalloc (sizeof *key);
473 make_key (key, h, access);
476 key->exclusive = exclusive;
480 hash = hash_fh_lock (key);
482 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
484 if ( 0 == compare_fh_locks (lock, key))
493 if (strcmp (lock->type, type))
495 if (access == FH_ACC_READ)
496 msg (SE, _("Can't read from %s as a %s because it is "
497 "already being read as a %s."),
498 fh_get_name (h), gettext (type), gettext (lock->type));
500 msg (SE, _("Can't write to %s as a %s because it is "
501 "already being written as a %s."),
502 fh_get_name (h), gettext (type), gettext (lock->type));
505 else if (exclusive || lock->exclusive)
507 msg (SE, _("Can't re-open %s as a %s."),
508 fh_get_name (h), gettext (type));
519 hmap_insert (&locks, &key->node, hash);
521 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
523 if ( 0 == compare_fh_locks (lock, key))
535 /* Releases LOCK that was acquired with fh_lock.
536 Returns true if LOCK is still locked, because other clients
539 Returns false if LOCK has now been destroyed. In this case
540 the caller must ensure that any auxiliary data associated with
541 LOCK is destroyed, to avoid a memory leak. The caller must
542 obtain a pointer to the auxiliary data, e.g. via
543 fh_lock_get_aux *before* calling fh_unlock (because it yields
544 undefined behavior to call fh_lock_get_aux on a destroyed
547 fh_unlock (struct fh_lock *lock)
551 assert (lock->open_cnt > 0);
552 if (--lock->open_cnt == 0)
554 hmap_delete (&locks, &lock->node);
563 /* Returns auxiliary data for LOCK.
565 Auxiliary data is shared by every client that holds LOCK (for
566 an exclusive lock, this is a single client). To avoid leaks,
567 auxiliary data must be released before LOCK is destroyed. */
569 fh_lock_get_aux (const struct fh_lock *lock)
574 /* Sets the auxiliary data for LOCK to AUX. */
576 fh_lock_set_aux (struct fh_lock *lock, void *aux)
581 /* Returns true if HANDLE is locked for the given type of ACCESS,
584 fh_is_locked (const struct file_handle *handle, enum fh_access access)
587 const struct fh_lock *k = NULL;
588 bool is_locked = false;
591 make_key (&key, handle, access);
593 hash = hash_fh_lock (&key);
596 HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
598 if ( 0 == compare_fh_locks (k, &key))
610 /* Initializes the key fields in LOCK for looking up or inserting
611 handle H for the given kind of ACCESS. */
613 make_key (struct fh_lock *lock, const struct file_handle *h,
614 enum fh_access access)
616 lock->referent = fh_get_referent (h);
617 lock->access = access;
618 if (lock->referent == FH_REF_FILE)
619 lock->u.file = fn_get_identity (fh_get_file_name (h));
620 else if (lock->referent == FH_REF_DATASET)
621 lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
624 /* Frees the key fields in LOCK. */
626 free_key (struct fh_lock *lock)
628 if (lock->referent == FH_REF_FILE)
629 fn_free_identity (lock->u.file);
632 /* Compares the key fields in struct fh_lock objects A and B and
633 returns a strcmp()-type result. */
635 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
637 if (a->referent != b->referent)
638 return a->referent < b->referent ? -1 : 1;
639 else if (a->access != b->access)
640 return a->access < b->access ? -1 : 1;
641 else if (a->referent == FH_REF_FILE)
642 return fn_compare_file_identities (a->u.file, b->u.file);
643 else if (a->referent == FH_REF_DATASET)
644 return (a->u.unique_id < b->u.unique_id ? -1
645 : a->u.unique_id > b->u.unique_id);
650 /* Returns a hash value for LOCK. */
652 hash_fh_lock (const struct fh_lock *lock)
655 if (lock->referent == FH_REF_FILE)
656 basis = fn_hash_identity (lock->u.file);
657 else if (lock->referent == FH_REF_DATASET)
658 basis = lock->u.unique_id;
661 return hash_int ((lock->referent << 3) | lock->access, basis);