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/magic.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>
36 #define _(msgid) gettext (msgid)
43 struct file_handle *next; /* Next in global list. */
44 int open_cnt; /* 0=not open, otherwise # of openers. */
45 bool deleted; /* Destroy handle when open_cnt goes to 0? */
47 char id[LONG_NAME_LEN + 1]; /* Identifier token; empty string if none. */
48 char *name; /* User-friendly identifying name. */
49 const char *type; /* If open, type of file. */
50 char open_mode[3]; /* "[rw][se]". */
51 void *aux; /* Aux data pointer for owner if any. */
52 enum fh_referent referent; /* What the file handle refers to. */
54 /* FH_REF_FILE only. */
55 char *file_name; /* File name as provided by user. */
56 struct file_identity *identity; /* For checking file identity. */
57 enum fh_mode mode; /* File mode. */
59 /* FH_REF_FILE and FH_REF_INLINE only. */
60 size_t record_width; /* Length of fixed-format records. */
61 size_t tab_width; /* Tab width, 0=do not expand tabs. */
63 /* FH_REF_SCRATCH only. */
64 struct scratch_handle *sh; /* Scratch file data. */
67 /* List of all handles. */
68 static struct file_handle *file_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 const char *name, enum fh_referent);
80 /* File handle initialization routine. */
84 inline_file = create_handle ("INLINE", "INLINE", FH_REF_INLINE);
85 inline_file->record_width = 80;
86 inline_file->tab_width = 8;
89 /* Free HANDLE and remove it from the global list. */
91 free_handle (struct file_handle *handle)
93 /* Remove handle from global list. */
94 if (file_handles == handle)
95 file_handles = handle->next;
98 struct file_handle *iter = file_handles;
99 while (iter->next != handle)
101 iter->next = handle->next;
106 free (handle->file_name);
107 fn_free_identity (handle->identity);
108 scratch_handle_destroy (handle->sh);
112 /* Frees all the file handles. */
116 while (file_handles != NULL)
117 free_handle (file_handles);
120 /* Returns the handle with the given ID, or a null pointer if
123 fh_from_id (const char *id)
125 struct file_handle *iter;
127 for (iter = file_handles; iter != NULL; iter = iter->next)
128 if (!iter->deleted && !strcasecmp (id, iter->id))
133 /* Returns the handle for the file named FILE_NAME,
134 or a null pointer if none exists.
135 Different names for the same file (e.g. "x" and "./x") are
136 considered equivalent. */
138 fh_from_file_name (const char *file_name)
140 struct file_identity *identity;
141 struct file_handle *iter;
143 /* First check for a file with the same identity. */
144 identity = fn_get_identity (file_name);
145 if (identity != NULL)
147 for (iter = file_handles; iter != NULL; iter = iter->next)
149 && iter->referent == FH_REF_FILE
150 && iter->identity != NULL
151 && !fn_compare_file_identities (identity, iter->identity))
153 fn_free_identity (identity);
156 fn_free_identity (identity);
159 /* Then check for a file with the same name. */
160 for (iter = file_handles; iter != NULL; iter = iter->next)
162 && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
168 /* Creates a new handle with identifier ID (which may be null)
169 and name HANDLE_NAME that refers to REFERENT. Links the new
170 handle into the global list. Returns the new handle.
172 The new handle is not fully initialized. The caller is
173 responsible for completing its initialization. */
174 static struct file_handle *
175 create_handle (const char *id, const char *handle_name,
176 enum fh_referent referent)
178 struct file_handle *handle = xzalloc (sizeof *handle);
179 assert (id == NULL || fh_from_id (id) == NULL);
180 handle->next = file_handles;
181 handle->open_cnt = 0;
182 handle->deleted = false;
183 str_copy_trunc (handle->id, sizeof handle->id, id != NULL ? id : "");
184 handle->name = xstrdup (handle_name);
187 handle->referent = referent;
188 file_handles = handle;
192 /* Returns the unique handle of referent type FH_REF_INLINE,
193 which refers to the "inline file" that represents character
194 data in the command file between BEGIN DATA and END DATA. */
196 fh_inline_file (void)
201 /* Creates a new file handle with the given ID, which may be
202 null. If it is non-null, it must be unique among existing
203 file identifiers. The new handle is associated with file
204 FILE_NAME and the given PROPERTIES. */
206 fh_create_file (const char *id, const char *file_name,
207 const struct fh_properties *properties)
210 struct file_handle *handle;
212 handle_name = id != NULL ? (char *) id : xasprintf ("\"%s\"", file_name);
213 handle = create_handle (id, handle_name, FH_REF_FILE);
216 handle->file_name = xstrdup (file_name);
217 handle->identity = fn_get_identity (file_name);
218 handle->mode = properties->mode;
219 handle->record_width = properties->record_width;
220 handle->tab_width = properties->tab_width;
224 /* Creates a new file handle with the given ID, which must be
225 unique among existing file identifiers. The new handle is
226 associated with a scratch file (initially empty). */
228 fh_create_scratch (const char *id)
230 struct file_handle *handle;
232 handle = create_handle (id, id, FH_REF_SCRATCH);
237 /* Returns a set of default properties for a file handle. */
238 const struct fh_properties *
239 fh_default_properties (void)
241 static const struct fh_properties default_properties
242 = {FH_MODE_TEXT, 1024, 4};
243 return &default_properties;
246 /* Deletes FH from the global list of file handles. Afterward,
247 attempts to search for it will fail. Unless the file handle
248 is currently open, it will be destroyed; otherwise, it will be
249 destroyed later when it is closed.
250 Normally needed only if a file_handle needs to be re-assigned.
251 Otherwise, just let fh_done() destroy the handle. */
253 fh_free (struct file_handle *handle)
255 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
257 handle->deleted = true;
259 if (handle == default_handle)
260 default_handle = fh_inline_file ();
262 if (handle->open_cnt == 0)
263 free_handle (handle);
266 /* Returns an English description of MODE,
267 which is in the format of the MODE argument to fh_open(). */
269 mode_name (const char *mode)
271 assert (mode != NULL);
272 assert (mode[0] == 'r' || mode[0] == 'w');
274 return mode[0] == 'r' ? "reading" : "writing";
277 /* Tries to open handle H with the given TYPE and MODE.
279 H's referent type must be one of the bits in MASK. The caller
280 must verify this ahead of time; we simply assert it here.
282 TYPE is the sort of file, e.g. "system file". Only one given
283 type of access is allowed on a given file handle at once.
284 If successful, a reference to TYPE is retained, so it should
285 probably be a string literal.
287 MODE combines the read or write mode with the sharing mode.
288 The first character is 'r' for read, 'w' for write. The
289 second character is 's' to permit sharing, 'e' to require
292 Returns the address of a void * that the caller can use for
293 data specific to the file handle if successful, or a null
294 pointer on failure. For exclusive access modes the void *
295 will always be a null pointer at return. In shared access
296 modes the void * will necessarily be null only if no other
297 sharers are active. */
299 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
300 const char *type, const char *mode)
303 assert ((fh_get_referent (h) & mask) != 0);
304 assert (type != NULL);
305 assert (mode != NULL);
306 assert (mode[0] == 'r' || mode[0] == 'w');
307 assert (mode[1] == 's' || mode[1] == 'e');
308 assert (mode[2] == '\0');
310 if (h->open_cnt != 0)
312 if (strcmp (h->type, type))
314 msg (SE, _("Can't open %s as a %s because it is "
315 "already open as a %s."),
316 fh_get_name (h), type, h->type);
319 else if (strcmp (h->open_mode, mode))
321 msg (SE, _("Can't open %s as a %s for %s because it is "
322 "already open for %s."),
323 fh_get_name (h), type, mode_name (mode),
324 mode_name (h->open_mode));
327 else if (h->open_mode[1] == 'e')
329 msg (SE, _("Can't re-open %s as a %s for %s."),
330 fh_get_name (h), type, mode_name (mode));
337 strcpy (h->open_mode, mode);
338 assert (h->aux == NULL);
345 /* Closes file handle H, which must have been open for the
346 specified TYPE and MODE of access provided to fh_open().
347 Returns zero if the file is now closed, nonzero if it is still
348 open due to another reference.
350 After fh_close() returns zero for a handle, it is unsafe to
351 reference that file handle again in any way, because its
352 storage may have been freed. */
354 fh_close (struct file_handle *h, const char *type, const char *mode)
357 assert (h->open_cnt > 0);
358 assert (type != NULL);
359 assert (!strcmp (type, h->type));
360 assert (mode != NULL);
361 assert (!strcmp (mode, h->open_mode));
363 if (--h->open_cnt == 0)
374 /* Is the file open? BEGIN DATA...END DATA uses this to detect
375 whether the inline file is actually in use. */
377 fh_is_open (const struct file_handle *handle)
379 return handle->open_cnt > 0;
382 /* Returns the identifier that may be used in syntax to name the
383 given HANDLE, which takes the form of a PSPP identifier. If
384 HANDLE has no identifier, returns a null pointer.
386 Return value is owned by the file handle.*/
388 fh_get_id (const struct file_handle *handle)
390 return handle->id[0] != '\0' ? handle->id : NULL;
393 /* Returns a user-friendly string to identify the given HANDLE.
394 If HANDLE was created by referring to a file name, returns the
395 file name, enclosed in double quotes. Return value is owned
398 Useful for printing error messages about use of file handles. */
400 fh_get_name (const struct file_handle *handle)
405 /* Returns the type of object that HANDLE refers to. */
407 fh_get_referent (const struct file_handle *handle)
409 return handle->referent;
412 /* Returns the name of the file associated with HANDLE. */
414 fh_get_file_name (const struct file_handle *handle)
416 assert (handle->referent == FH_REF_FILE);
417 return handle->file_name;
420 /* Returns the mode of HANDLE. */
422 fh_get_mode (const struct file_handle *handle)
424 assert (handle->referent == FH_REF_FILE);
428 /* Returns the width of a logical record on HANDLE. */
430 fh_get_record_width (const struct file_handle *handle)
432 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
433 return handle->record_width;
436 /* Returns the number of characters per tab stop for HANDLE, or
437 zero if tabs are not to be expanded. Applicable only to
438 FH_MODE_TEXT files. */
440 fh_get_tab_width (const struct file_handle *handle)
442 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
443 return handle->tab_width;
446 /* Returns the scratch file handle associated with HANDLE.
447 Applicable to only FH_REF_SCRATCH files. */
448 struct scratch_handle *
449 fh_get_scratch_handle (struct file_handle *handle)
451 assert (handle->referent == FH_REF_SCRATCH);
455 /* Sets SH to be the scratch file handle associated with HANDLE.
456 Applicable to only FH_REF_SCRATCH files. */
458 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
460 assert (handle->referent == FH_REF_SCRATCH);
464 /* Returns the current default handle. */
466 fh_get_default_handle (void)
468 return default_handle ? default_handle : fh_inline_file ();
471 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
473 fh_set_default_handle (struct file_handle *new_default_handle)
475 assert (new_default_handle == NULL
476 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
477 default_handle = new_default_handle;