1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006 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 "file-handle-def.h"
26 #include <libpspp/alloc.h>
27 #include <libpspp/compiler.h>
28 #include <libpspp/message.h>
29 #include <libpspp/str.h>
30 #include <data/file-name.h>
31 #include <data/variable.h>
32 #include <data/scratch-handle.h>
35 #define _(msgid) gettext (msgid)
42 struct file_handle *next; /* Next in global list. */
43 int open_cnt; /* 0=not open, otherwise # of openers. */
44 bool deleted; /* Destroy handle when open_cnt goes to 0? */
46 char id[LONG_NAME_LEN + 1]; /* Identifier token; empty string if none. */
47 char *name; /* User-friendly identifying name. */
48 const char *type; /* If open, type of file. */
49 char open_mode[3]; /* "[rw][se]". */
50 void *aux; /* Aux data pointer for owner if any. */
51 enum fh_referent referent; /* What the file handle refers to. */
53 /* FH_REF_FILE only. */
54 char *file_name; /* File name as provided by user. */
55 struct file_identity *identity; /* For checking file identity. */
56 enum fh_mode mode; /* File mode. */
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. */
62 /* FH_REF_SCRATCH only. */
63 struct scratch_handle *sh; /* Scratch file data. */
66 /* List of all handles. */
67 static struct file_handle *file_handles;
69 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
71 static struct file_handle *default_handle;
73 /* The "file" that reads from BEGIN DATA...END DATA. */
74 static struct file_handle *inline_file;
76 static struct file_handle *create_handle (const char *id,
77 const char *name, enum fh_referent);
79 /* File handle initialization routine. */
83 inline_file = create_handle ("INLINE", "INLINE", FH_REF_INLINE);
84 inline_file->record_width = 80;
85 inline_file->tab_width = 8;
88 /* Free HANDLE and remove it from the global list. */
90 free_handle (struct file_handle *handle)
92 /* Remove handle from global list. */
93 if (file_handles == handle)
94 file_handles = handle->next;
97 struct file_handle *iter = file_handles;
98 while (iter->next != handle)
100 iter->next = handle->next;
105 free (handle->file_name);
106 fn_free_identity (handle->identity);
107 scratch_handle_destroy (handle->sh);
111 /* Frees all the file handles. */
115 while (file_handles != NULL)
116 free_handle (file_handles);
119 /* Returns the handle with the given ID, or a null pointer if
122 fh_from_id (const char *id)
124 struct file_handle *iter;
126 for (iter = file_handles; iter != NULL; iter = iter->next)
127 if (!iter->deleted && !strcasecmp (id, iter->id))
132 /* Returns the handle for the file named FILE_NAME,
133 or a null pointer if none exists.
134 Different names for the same file (e.g. "x" and "./x") are
135 considered equivalent. */
137 fh_from_file_name (const char *file_name)
139 struct file_identity *identity;
140 struct file_handle *iter;
142 /* First check for a file with the same identity. */
143 identity = fn_get_identity (file_name);
144 if (identity != NULL)
146 for (iter = file_handles; iter != NULL; iter = iter->next)
148 && iter->referent == FH_REF_FILE
149 && iter->identity != NULL
150 && !fn_compare_file_identities (identity, iter->identity))
152 fn_free_identity (identity);
155 fn_free_identity (identity);
158 /* Then check for a file with the same name. */
159 for (iter = file_handles; iter != NULL; iter = iter->next)
161 && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
167 /* Creates a new handle with identifier ID (which may be null)
168 and name HANDLE_NAME that refers to REFERENT. Links the new
169 handle into the global list. Returns the new handle.
171 The new handle is not fully initialized. The caller is
172 responsible for completing its initialization. */
173 static struct file_handle *
174 create_handle (const char *id, const char *handle_name,
175 enum fh_referent referent)
177 struct file_handle *handle = xzalloc (sizeof *handle);
178 assert (id == NULL || fh_from_id (id) == NULL);
179 handle->next = file_handles;
180 handle->open_cnt = 0;
181 handle->deleted = false;
182 str_copy_trunc (handle->id, sizeof handle->id, id != NULL ? id : "");
183 handle->name = xstrdup (handle_name);
186 handle->referent = referent;
187 file_handles = handle;
191 /* Returns the unique handle of referent type FH_REF_INLINE,
192 which refers to the "inline file" that represents character
193 data in the command file between BEGIN DATA and END DATA. */
195 fh_inline_file (void)
200 /* Creates a new file handle with the given ID, which may be
201 null. If it is non-null, it must be unique among existing
202 file identifiers. The new handle is associated with file
203 FILE_NAME and the given PROPERTIES. */
205 fh_create_file (const char *id, const char *file_name,
206 const struct fh_properties *properties)
209 struct file_handle *handle;
211 handle_name = id != NULL ? (char *) id : xasprintf ("\"%s\"", file_name);
212 handle = create_handle (id, handle_name, FH_REF_FILE);
215 handle->file_name = xstrdup (file_name);
216 handle->identity = fn_get_identity (file_name);
217 handle->mode = properties->mode;
218 handle->record_width = properties->record_width;
219 handle->tab_width = properties->tab_width;
223 /* Creates a new file handle with the given ID, which must be
224 unique among existing file identifiers. The new handle is
225 associated with a scratch file (initially empty). */
227 fh_create_scratch (const char *id)
229 struct file_handle *handle;
231 handle = create_handle (id, id, FH_REF_SCRATCH);
236 /* Returns a set of default properties for a file handle. */
237 const struct fh_properties *
238 fh_default_properties (void)
240 static const struct fh_properties default_properties
241 = {FH_MODE_TEXT, 1024, 4};
242 return &default_properties;
245 /* Deletes FH from the global list of file handles. Afterward,
246 attempts to search for it will fail. Unless the file handle
247 is currently open, it will be destroyed; otherwise, it will be
248 destroyed later when it is closed.
249 Normally needed only if a file_handle needs to be re-assigned.
250 Otherwise, just let fh_done() destroy the handle. */
252 fh_free (struct file_handle *handle)
254 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
256 handle->deleted = true;
258 if (handle == default_handle)
259 default_handle = fh_inline_file ();
261 if (handle->open_cnt == 0)
262 free_handle (handle);
265 /* Returns an English description of MODE,
266 which is in the format of the MODE argument to fh_open(). */
268 mode_name (const char *mode)
270 assert (mode != NULL);
271 assert (mode[0] == 'r' || mode[0] == 'w');
273 return mode[0] == 'r' ? "reading" : "writing";
276 /* Tries to open handle H with the given TYPE and MODE.
278 H's referent type must be one of the bits in MASK. The caller
279 must verify this ahead of time; we simply assert it here.
281 TYPE is the sort of file, e.g. "system file". Only one given
282 type of access is allowed on a given file handle at once.
283 If successful, a reference to TYPE is retained, so it should
284 probably be a string literal.
286 MODE combines the read or write mode with the sharing mode.
287 The first character is 'r' for read, 'w' for write. The
288 second character is 's' to permit sharing, 'e' to require
291 Returns the address of a void * that the caller can use for
292 data specific to the file handle if successful, or a null
293 pointer on failure. For exclusive access modes the void *
294 will always be a null pointer at return. In shared access
295 modes the void * will necessarily be null only if no other
296 sharers are active. */
298 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
299 const char *type, const char *mode)
302 assert ((fh_get_referent (h) & mask) != 0);
303 assert (type != NULL);
304 assert (mode != NULL);
305 assert (mode[0] == 'r' || mode[0] == 'w');
306 assert (mode[1] == 's' || mode[1] == 'e');
307 assert (mode[2] == '\0');
309 if (h->open_cnt != 0)
311 if (strcmp (h->type, type))
313 msg (SE, _("Can't open %s as a %s because it is "
314 "already open as a %s."),
315 fh_get_name (h), type, h->type);
318 else if (strcmp (h->open_mode, mode))
320 msg (SE, _("Can't open %s as a %s for %s because it is "
321 "already open for %s."),
322 fh_get_name (h), type, mode_name (mode),
323 mode_name (h->open_mode));
326 else if (h->open_mode[1] == 'e')
328 msg (SE, _("Can't re-open %s as a %s for %s."),
329 fh_get_name (h), type, mode_name (mode));
336 strcpy (h->open_mode, mode);
337 assert (h->aux == NULL);
344 /* Closes file handle H, which must have been open for the
345 specified TYPE and MODE of access provided to fh_open().
346 Returns zero if the file is now closed, nonzero if it is still
347 open due to another reference.
349 After fh_close() returns zero for a handle, it is unsafe to
350 reference that file handle again in any way, because its
351 storage may have been freed. */
353 fh_close (struct file_handle *h, const char *type, const char *mode)
356 assert (h->open_cnt > 0);
357 assert (type != NULL);
358 assert (!strcmp (type, h->type));
359 assert (mode != NULL);
360 assert (!strcmp (mode, h->open_mode));
362 if (--h->open_cnt == 0)
373 /* Is the file open? BEGIN DATA...END DATA uses this to detect
374 whether the inline file is actually in use. */
376 fh_is_open (const struct file_handle *handle)
378 return handle->open_cnt > 0;
381 /* Returns the identifier that may be used in syntax to name the
382 given HANDLE, which takes the form of a PSPP identifier. If
383 HANDLE has no identifier, returns a null pointer.
385 Return value is owned by the file handle.*/
387 fh_get_id (const struct file_handle *handle)
389 return handle->id[0] != '\0' ? handle->id : NULL;
392 /* Returns a user-friendly string to identify the given HANDLE.
393 If HANDLE was created by referring to a file name, returns the
394 file name, enclosed in double quotes. Return value is owned
397 Useful for printing error messages about use of file handles. */
399 fh_get_name (const struct file_handle *handle)
404 /* Returns the type of object that HANDLE refers to. */
406 fh_get_referent (const struct file_handle *handle)
408 return handle->referent;
411 /* Returns the name of the file associated with HANDLE. */
413 fh_get_file_name (const struct file_handle *handle)
415 assert (handle->referent == FH_REF_FILE);
416 return handle->file_name;
419 /* Returns the mode of HANDLE. */
421 fh_get_mode (const struct file_handle *handle)
423 assert (handle->referent == FH_REF_FILE);
427 /* Returns the width of a logical record on HANDLE. */
429 fh_get_record_width (const struct file_handle *handle)
431 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
432 return handle->record_width;
435 /* Returns the number of characters per tab stop for HANDLE, or
436 zero if tabs are not to be expanded. Applicable only to
437 FH_MODE_TEXT files. */
439 fh_get_tab_width (const struct file_handle *handle)
441 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
442 return handle->tab_width;
445 /* Returns the scratch file handle associated with HANDLE.
446 Applicable to only FH_REF_SCRATCH files. */
447 struct scratch_handle *
448 fh_get_scratch_handle (struct file_handle *handle)
450 assert (handle->referent == FH_REF_SCRATCH);
454 /* Sets SH to be the scratch file handle associated with HANDLE.
455 Applicable to only FH_REF_SCRATCH files. */
457 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
459 assert (handle->referent == FH_REF_SCRATCH);
463 /* Returns the current default handle. */
465 fh_get_default_handle (void)
467 return default_handle ? default_handle : fh_inline_file ();
470 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
472 fh_set_default_handle (struct file_handle *new_default_handle)
474 assert (new_default_handle == NULL
475 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
476 default_handle = new_default_handle;