1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "file-handle-def.h"
28 #include <libpspp/alloc.h>
29 #include <libpspp/compiler.h>
30 #include <libpspp/magic.h>
31 #include <libpspp/message.h>
32 #include "file-name.h"
34 #include "scratch-handle.h"
37 #define _(msgid) gettext (msgid)
44 struct file_handle *next; /* Next in global list. */
45 int open_cnt; /* 0=not open, otherwise # of openers. */
46 bool deleted; /* Destroy handle when open_cnt goes to 0? */
48 char *name; /* File handle identifier. */
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 *name, enum fh_referent);
79 /* File handle initialization routine. */
83 inline_file = create_handle ("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 named HANDLE_NAME, or a null pointer if
122 fh_from_name (const char *handle_name)
124 struct file_handle *iter;
126 for (iter = file_handles; iter != NULL; iter = iter->next)
127 if (!iter->deleted && !strcasecmp (handle_name, iter->name))
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 name HANDLE_NAME that refers to
168 REFERENT. Links the new handle into the global list. Returns
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 *handle_name, enum fh_referent referent)
176 struct file_handle *handle = xzalloc (sizeof *handle);
177 handle->next = file_handles;
178 handle->open_cnt = 0;
179 handle->deleted = false;
180 handle->name = xstrdup (handle_name);
183 handle->referent = referent;
184 file_handles = handle;
188 /* Returns the unique handle of referent type FH_REF_INLINE,
189 which refers to the "inline file" that represents character
190 data in the command file between BEGIN DATA and END DATA. */
192 fh_inline_file (void)
197 /* Creates a new file handle named HANDLE_NAME, which must not be
198 the name of an existing file handle. The new handle is
199 associated with file FILE_NAME and the given PROPERTIES. */
201 fh_create_file (const char *handle_name, const char *file_name,
202 const struct fh_properties *properties)
204 struct file_handle *handle;
205 assert (fh_from_name (handle_name) == NULL);
206 handle = create_handle (handle_name, FH_REF_FILE);
207 handle->file_name = xstrdup (file_name);
208 handle->identity = fn_get_identity (file_name);
209 handle->mode = properties->mode;
210 handle->record_width = properties->record_width;
211 handle->tab_width = properties->tab_width;
215 /* Creates a new file handle named HANDLE_NAME, which must not be
216 the name of an existing file handle. The new handle is
217 associated with a scratch file (initially empty). */
219 fh_create_scratch (const char *handle_name)
221 struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
226 /* Returns a set of default properties for a file handle. */
227 const struct fh_properties *
228 fh_default_properties (void)
230 static const struct fh_properties default_properties
231 = {FH_MODE_TEXT, 1024, 4};
232 return &default_properties;
235 /* Deletes FH from the global list of file handles. Afterward,
236 attempts to search for it will fail. Unless the file handle
237 is currently open, it will be destroyed; otherwise, it will be
238 destroyed later when it is closed.
239 Normally needed only if a file_handle needs to be re-assigned.
240 Otherwise, just let fh_done() destroy the handle. */
242 fh_free (struct file_handle *handle)
244 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
246 handle->deleted = true;
248 if (handle == default_handle)
249 default_handle = fh_inline_file ();
251 if (handle->open_cnt == 0)
252 free_handle (handle);
255 /* Returns an English description of MODE,
256 which is in the format of the MODE argument to fh_open(). */
258 mode_name (const char *mode)
260 assert (mode != NULL);
261 assert (mode[0] == 'r' || mode[0] == 'w');
263 return mode[0] == 'r' ? "reading" : "writing";
266 /* Tries to open handle H with the given TYPE and MODE.
268 H's referent type must be one of the bits in MASK. The caller
269 must verify this ahead of time; we simply assert it here.
271 TYPE is the sort of file, e.g. "system file". Only one given
272 type of access is allowed on a given file handle at once.
273 If successful, a reference to TYPE is retained, so it should
274 probably be a string literal.
276 MODE combines the read or write mode with the sharing mode.
277 The first character is 'r' for read, 'w' for write. The
278 second character is 's' to permit sharing, 'e' to require
281 Returns the address of a void * that the caller can use for
282 data specific to the file handle if successful, or a null
283 pointer on failure. For exclusive access modes the void *
284 will always be a null pointer at return. In shared access
285 modes the void * will necessarily be null only if no other
286 sharers are active. */
288 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
289 const char *type, const char *mode)
292 assert ((fh_get_referent (h) & mask) != 0);
293 assert (type != NULL);
294 assert (mode != NULL);
295 assert (mode[0] == 'r' || mode[0] == 'w');
296 assert (mode[1] == 's' || mode[1] == 'e');
297 assert (mode[2] == '\0');
299 if (h->open_cnt != 0)
301 if (strcmp (h->type, type))
303 msg (SE, _("Can't open %s as a %s because it is "
304 "already open as a %s."),
305 fh_get_name (h), type, h->type);
308 else if (strcmp (h->open_mode, mode))
310 msg (SE, _("Can't open %s as a %s for %s because it is "
311 "already open for %s."),
312 fh_get_name (h), type, mode_name (mode),
313 mode_name (h->open_mode));
316 else if (h->open_mode[1] == 'e')
318 msg (SE, _("Can't re-open %s as a %s for %s."),
319 fh_get_name (h), type, mode_name (mode));
326 strcpy (h->open_mode, mode);
327 assert (h->aux == NULL);
334 /* Closes file handle H, which must have been open for the
335 specified TYPE and MODE of access provided to fh_open().
336 Returns zero if the file is now closed, nonzero if it is still
337 open due to another reference.
339 After fh_close() returns zero for a handle, it is unsafe to
340 reference that file handle again in any way, because its
341 storage may have been freed. */
343 fh_close (struct file_handle *h, const char *type, const char *mode)
346 assert (h->open_cnt > 0);
347 assert (type != NULL);
348 assert (!strcmp (type, h->type));
349 assert (mode != NULL);
350 assert (!strcmp (mode, h->open_mode));
352 if (--h->open_cnt == 0)
363 /* Is the file open? BEGIN DATA...END DATA uses this to detect
364 whether the inline file is actually in use. */
366 fh_is_open (const struct file_handle *handle)
368 return handle->open_cnt > 0;
371 /* Returns the identifier of file HANDLE. If HANDLE was created
372 by referring to a file name instead of a handle name, returns
373 the file name, enclosed in double quotes. Return value is
374 owned by the file handle.
376 Useful for printing error messages about use of file handles. */
378 fh_get_name (const struct file_handle *handle)
383 /* Returns the type of object that HANDLE refers to. */
385 fh_get_referent (const struct file_handle *handle)
387 return handle->referent;
390 /* Returns the name of the file associated with HANDLE. */
392 fh_get_file_name (const struct file_handle *handle)
394 assert (handle->referent == FH_REF_FILE);
395 return handle->file_name;
398 /* Returns the mode of HANDLE. */
400 fh_get_mode (const struct file_handle *handle)
402 assert (handle->referent == FH_REF_FILE);
406 /* Returns the width of a logical record on HANDLE. */
408 fh_get_record_width (const struct file_handle *handle)
410 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
411 return handle->record_width;
414 /* Returns the number of characters per tab stop for HANDLE, or
415 zero if tabs are not to be expanded. Applicable only to
416 FH_MODE_TEXT files. */
418 fh_get_tab_width (const struct file_handle *handle)
420 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
421 return handle->tab_width;
424 /* Returns the scratch file handle associated with HANDLE.
425 Applicable to only FH_REF_SCRATCH files. */
426 struct scratch_handle *
427 fh_get_scratch_handle (struct file_handle *handle)
429 assert (handle->referent == FH_REF_SCRATCH);
433 /* Sets SH to be the scratch file handle associated with HANDLE.
434 Applicable to only FH_REF_SCRATCH files. */
436 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
438 assert (handle->referent == FH_REF_SCRATCH);
442 /* Returns the current default handle. */
444 fh_get_default_handle (void)
446 return default_handle ? default_handle : fh_inline_file ();
449 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
451 fh_set_default_handle (struct file_handle *new_default_handle)
453 assert (new_default_handle == NULL
454 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
455 default_handle = new_default_handle;