FILE HANDLE: Use system native line ends by default.
[pspp] / src / data / file-handle-def.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 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 "data/file-handle-def.h"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
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"
36
37 #include "gl/xalloc.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 /* File handle. */
43 struct file_handle
44   {
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. */
50
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. */
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     char *encoding;             /* Charset for contents. */
60
61     /* FH_REF_DATASET only. */
62     struct dataset *ds;         /* Dataset. */
63   };
64
65 /* All "struct file_handle"s with nonnull 'id' member. */
66 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
67
68 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
69    commands. */
70 static struct file_handle *default_handle;
71
72 /* The "file" that reads from BEGIN DATA...END DATA. */
73 static struct file_handle *inline_file;
74
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 *);
80
81 /* Hash table of all active locks. */
82 static struct hmap locks = HMAP_INITIALIZER (locks);
83
84 /* File handle initialization routine. */
85 void
86 fh_init (void)
87 {
88   inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
89                                "Auto");
90   inline_file->record_width = 80;
91   inline_file->tab_width = 8;
92 }
93
94 /* Removes all named file handles from the global list. */
95 void
96 fh_done (void)
97 {
98   struct file_handle *handle, *next;
99
100   HMAP_FOR_EACH_SAFE (handle, next,
101                       struct file_handle, name_node, &named_handles)
102     unname_handle (handle);
103 }
104
105 /* Free HANDLE and remove it from the global list. */
106 static void
107 free_handle (struct file_handle *handle)
108 {
109   /* Remove handle from global list. */
110   if (handle->id != NULL)
111     hmap_delete (&named_handles, &handle->name_node);
112
113   /* Free data. */
114   free (handle->id);
115   free (handle->name);
116   free (handle->file_name);
117   free (handle->encoding);
118   free (handle);
119 }
120
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. */
124 static void
125 unname_handle (struct file_handle *handle)
126 {
127   assert (handle->id != NULL);
128   free (handle->id);
129   handle->id = NULL;
130   hmap_delete (&named_handles, &handle->name_node);
131
132   /* Drop the reference held by the named_handles table. */
133   fh_unref (handle);
134 }
135
136 /* Increments HANDLE's reference count and returns HANDLE. */
137 struct file_handle *
138 fh_ref (struct file_handle *handle)
139 {
140   assert (handle->ref_cnt > 0);
141   handle->ref_cnt++;
142   return handle;
143 }
144
145 /* Decrements HANDLE's reference count.
146    If the reference count drops to 0, HANDLE is destroyed. */
147 void
148 fh_unref (struct file_handle *handle)
149 {
150   if (handle != NULL)
151     {
152       assert (handle->ref_cnt > 0);
153       if (--handle->ref_cnt == 0)
154         free_handle (handle);
155     }
156 }
157
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.
161
162    This function ignores a null pointer as input.  It has no
163    effect on the inline handle, which is always named INLINE.*/
164 void
165 fh_unname (struct file_handle *handle)
166 {
167   assert (handle->ref_cnt > 1);
168   if (handle != fh_inline_file () && handle->id != NULL)
169     unname_handle (handle);
170 }
171
172 /* Returns the handle with the given ID, or a null pointer if
173    there is none. */
174 struct file_handle *
175 fh_from_id (const char *id)
176 {
177   struct file_handle *handle;
178
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))
182       {
183         return fh_ref (handle);
184       }
185
186   return NULL;
187 }
188
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.
192
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)
198 {
199   struct file_handle *handle = xzalloc (sizeof *handle);
200
201   handle->ref_cnt = 1;
202   handle->id = id != NULL ? xstrdup (id) : NULL;
203   handle->name = handle_name;
204   handle->referent = referent;
205   handle->encoding = xstrdup (encoding);
206
207   if (id != NULL)
208     {
209       hmap_insert (&named_handles, &handle->name_node,
210                    utf8_hash_case_string (handle->id, 0));
211     }
212
213   return handle;
214 }
215
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. */
219 struct file_handle *
220 fh_inline_file (void)
221 {
222   return inline_file;
223 }
224
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. */
229 struct file_handle *
230 fh_create_file (const char *id, const char *file_name,
231                 const struct fh_properties *properties)
232 {
233   char *handle_name;
234   struct file_handle *handle;
235
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;
243   return handle;
244 }
245
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). */
249 struct file_handle *
250 fh_create_dataset (struct dataset *ds)
251 {
252   const char *name;
253   struct file_handle *handle;
254
255   name = dataset_name (ds);
256   if (name[0] == '\0')
257     name = _("active dataset");
258
259   handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
260   handle->ds = ds;
261   return handle;
262 }
263
264 /* Returns a set of default properties for a file handle. */
265 const struct fh_properties *
266 fh_default_properties (void)
267 {
268 #if defined _WIN32 || defined __WIN32__
269 #define DEFAULT_LINE_ENDS FH_END_CRLF
270 #else
271 #define DEFAULT_LINE_ENDS FH_END_LF
272 #endif
273
274   static const struct fh_properties default_properties
275     = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
276   return &default_properties;
277 }
278
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.
282
283    Return value is owned by the file handle.*/
284 const char *
285 fh_get_id (const struct file_handle *handle)
286 {
287   return handle->id;
288 }
289
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
293    by the file handle.
294
295    Useful for printing error messages about use of file handles.  */
296 const char *
297 fh_get_name (const struct file_handle *handle)
298 {
299   return handle->name;
300 }
301
302 /* Returns the type of object that HANDLE refers to. */
303 enum fh_referent
304 fh_get_referent (const struct file_handle *handle)
305 {
306   return handle->referent;
307 }
308
309 /* Returns the name of the file associated with HANDLE. */
310 const char *
311 fh_get_file_name (const struct file_handle *handle)
312 {
313   assert (handle->referent == FH_REF_FILE);
314   return handle->file_name;
315 }
316
317 /* Returns the mode of HANDLE. */
318 enum fh_mode
319 fh_get_mode (const struct file_handle *handle)
320 {
321   assert (handle->referent == FH_REF_FILE);
322   return handle->mode;
323 }
324
325 /* Returns the line ends of HANDLE, which must be a handle associated with a
326    file. */
327 enum fh_line_ends
328 fh_get_line_ends (const struct file_handle *handle)
329 {
330   assert (handle->referent == FH_REF_FILE);
331   return handle->line_ends;
332 }
333
334 /* Returns the width of a logical record on HANDLE. */
335 size_t
336 fh_get_record_width (const struct file_handle *handle)
337 {
338   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
339   return handle->record_width;
340 }
341
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. */
345 size_t
346 fh_get_tab_width (const struct file_handle *handle)
347 {
348   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
349   return handle->tab_width;
350 }
351
352 /* Returns the encoding of characters read from HANDLE. */
353 const char *
354 fh_get_encoding (const struct file_handle *handle)
355 {
356   return handle->encoding;
357 }
358
359 /* Returns the dataset handle associated with HANDLE.
360    Applicable to only FH_REF_DATASET files. */
361 struct dataset *
362 fh_get_dataset (const struct file_handle *handle)
363 {
364   assert (handle->referent == FH_REF_DATASET);
365   return handle->ds;
366 }
367
368 /* Returns the current default handle. */
369 struct file_handle *
370 fh_get_default_handle (void)
371 {
372   return default_handle ? default_handle : fh_inline_file ();
373 }
374
375 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
376 void
377 fh_set_default_handle (struct file_handle *new_default_handle)
378 {
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);
386 }
387 \f
388 /* Information about a file handle's readers or writers. */
389 struct fh_lock
390   {
391     struct hmap_node node;      /* hmap_node member. */
392
393     /* Hash key. */
394     enum fh_referent referent;  /* Type of underlying file. */
395     union
396       {
397         struct file_identity *file; /* FH_REF_FILE only. */
398         unsigned int unique_id;    /* FH_REF_DATASET only. */
399       }
400     u;
401     enum fh_access access;      /* Type of file access. */
402
403     /* Number of openers. */
404     size_t open_cnt;
405
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. */
410   };
411
412
413 static void make_key (struct fh_lock *, const struct file_handle *,
414                       enum fh_access);
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);
418
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.
422
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.
425
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.
430
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
433    do so.
434
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
441    different TYPE.
442
443    A lock may be associated with auxiliary data.  See
444    fh_lock_get_aux and fh_lock_set_aux for more details. */
445 struct fh_lock *
446 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
447          const char *type, enum fh_access access, bool exclusive)
448 {
449   struct fh_lock *key = NULL;
450   size_t hash ;
451   struct fh_lock *lock = NULL;
452   bool found_lock = false;
453
454   assert ((fh_get_referent (h) & mask) != 0);
455   assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
456
457   key = xmalloc (sizeof *key);
458
459   make_key (key, h, access);
460
461   key->open_cnt = 1;
462   key->exclusive = exclusive;
463   key->type = type;
464   key->aux = NULL;
465
466   hash = hash_fh_lock (key);
467
468   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
469     {
470       if ( 0 == compare_fh_locks (lock, key))
471         {
472           found_lock = true;
473           break;
474         }
475     }
476
477   if ( found_lock )
478     {
479       if (strcmp (lock->type, type))
480         {
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));
485           else
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));
489           return NULL;
490         }
491       else if (exclusive || lock->exclusive)
492         {
493           msg (SE, _("Can't re-open %s as a %s."),
494                fh_get_name (h), gettext (type));
495           return NULL;
496         }
497       lock->open_cnt++;
498       
499       free_key (key);
500       free (key);
501
502       return lock;
503     }
504
505   hmap_insert (&locks, &key->node, hash);
506   found_lock = false;
507   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
508     {
509       if ( 0 == compare_fh_locks (lock, key))
510         {
511           found_lock = true;
512           break;
513         }
514     }
515
516   assert (found_lock);
517
518   return key;
519 }
520
521 /* Releases LOCK that was acquired with fh_lock.
522    Returns true if LOCK is still locked, because other clients
523    also had it locked.
524
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
531    lock).  */
532 bool
533 fh_unlock (struct fh_lock *lock)
534 {
535   if (lock != NULL)
536     {
537       assert (lock->open_cnt > 0);
538       if (--lock->open_cnt == 0)
539         {
540           hmap_delete (&locks, &lock->node);
541           free_key (lock);
542           free (lock);
543           return false;
544         }
545     }
546   return true;
547 }
548
549 /* Returns auxiliary data for LOCK.
550
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. */
554 void *
555 fh_lock_get_aux (const struct fh_lock *lock)
556 {
557   return lock->aux;
558 }
559
560 /* Sets the auxiliary data for LOCK to AUX. */
561 void
562 fh_lock_set_aux (struct fh_lock *lock, void *aux)
563 {
564   lock->aux = aux;
565 }
566
567 /* Returns true if HANDLE is locked for the given type of ACCESS,
568    false otherwise. */
569 bool
570 fh_is_locked (const struct file_handle *handle, enum fh_access access)
571 {
572   struct fh_lock key;
573   const struct fh_lock *k = NULL;
574   bool is_locked = false;
575   size_t hash ;
576
577   make_key (&key, handle, access);
578
579   hash = hash_fh_lock (&key);
580
581
582   HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
583     {
584       if ( 0 == compare_fh_locks (k, &key))
585         {
586           is_locked = true;
587           break;
588         }
589     }
590
591   free_key (&key);
592
593   return is_locked;
594 }
595
596 /* Initializes the key fields in LOCK for looking up or inserting
597    handle H for the given kind of ACCESS. */
598 static void
599 make_key (struct fh_lock *lock, const struct file_handle *h,
600           enum fh_access access)
601 {
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));
608 }
609
610 /* Frees the key fields in LOCK. */
611 static void
612 free_key (struct fh_lock *lock)
613 {
614   if (lock->referent == FH_REF_FILE)
615     fn_free_identity (lock->u.file);
616 }
617
618 /* Compares the key fields in struct fh_lock objects A and B and
619    returns a strcmp()-type result. */
620 static int
621 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
622 {
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);
632   else
633     return 0;
634 }
635
636 /* Returns a hash value for LOCK. */
637 static unsigned int
638 hash_fh_lock (const struct fh_lock *lock)
639 {
640   unsigned int basis;
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;
645   else
646     basis = 0;
647   return hash_int ((lock->referent << 3) | lock->access, basis);
648 }