1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include "file-handle-def.h"
29 #include <libpspp/alloc.h>
30 #include <libpspp/compiler.h>
31 #include <libpspp/magic.h>
32 #include <libpspp/message.h>
33 #include "file-name.h"
35 #include "scratch-handle.h"
38 #define _(msgid) gettext (msgid)
45 struct file_handle *next; /* Next in global list. */
46 int open_cnt; /* 0=not open, otherwise # of openers. */
47 bool deleted; /* Destroy handle when open_cnt goes to 0? */
49 char *name; /* File handle identifier. */
50 const char *type; /* If open, type of file. */
51 char open_mode[3]; /* "[rw][se]". */
52 void *aux; /* Aux data pointer for owner if any. */
53 enum fh_referent referent; /* What the file handle refers to. */
55 /* FH_REF_FILE only. */
56 char *file_name; /* File name as provided by user. */
57 struct file_identity *identity; /* For checking file identity. */
58 enum fh_mode mode; /* File mode. */
60 /* FH_REF_FILE and FH_REF_INLINE only. */
61 size_t record_width; /* Length of fixed-format records. */
62 size_t tab_width; /* Tab width, 0=do not expand tabs. */
64 /* FH_REF_SCRATCH only. */
65 struct scratch_handle *sh; /* Scratch file data. */
68 /* List of all handles. */
69 static struct file_handle *file_handles;
71 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
73 static struct file_handle *default_handle;
75 /* The "file" that reads from BEGIN DATA...END DATA. */
76 static struct file_handle *inline_file;
78 static struct file_handle *create_handle (const char *name, enum fh_referent);
80 /* File handle initialization routine. */
84 inline_file = create_handle ("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 named HANDLE_NAME, or a null pointer if
123 fh_from_name (const char *handle_name)
125 struct file_handle *iter;
127 for (iter = file_handles; iter != NULL; iter = iter->next)
128 if (!iter->deleted && !strcasecmp (handle_name, iter->name))
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 name HANDLE_NAME that refers to
169 REFERENT. Links the new handle into the global list. Returns
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 *handle_name, enum fh_referent referent)
177 struct file_handle *handle = xzalloc (sizeof *handle);
178 handle->next = file_handles;
179 handle->open_cnt = 0;
180 handle->deleted = false;
181 handle->name = xstrdup (handle_name);
184 handle->referent = referent;
185 file_handles = handle;
189 /* Returns the unique handle of referent type FH_REF_INLINE,
190 which refers to the "inline file" that represents character
191 data in the command file between BEGIN DATA and END DATA. */
193 fh_inline_file (void)
198 /* Creates a new file handle named HANDLE_NAME, which must not be
199 the name of an existing file handle. The new handle is
200 associated with file FILE_NAME and the given PROPERTIES. */
202 fh_create_file (const char *handle_name, const char *file_name,
203 const struct fh_properties *properties)
205 struct file_handle *handle;
206 assert (fh_from_name (handle_name) == NULL);
207 handle = create_handle (handle_name, FH_REF_FILE);
208 handle->file_name = xstrdup (file_name);
209 handle->identity = fn_get_identity (file_name);
210 handle->mode = properties->mode;
211 handle->record_width = properties->record_width;
212 handle->tab_width = properties->tab_width;
216 /* Creates a new file handle named HANDLE_NAME, which must not be
217 the name of an existing file handle. The new handle is
218 associated with a scratch file (initially empty). */
220 fh_create_scratch (const char *handle_name)
222 struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
227 /* Returns a set of default properties for a file handle. */
228 const struct fh_properties *
229 fh_default_properties (void)
231 static const struct fh_properties default_properties
232 = {FH_MODE_TEXT, 1024, 4};
233 return &default_properties;
236 /* Deletes FH from the global list of file handles. Afterward,
237 attempts to search for it will fail. Unless the file handle
238 is currently open, it will be destroyed; otherwise, it will be
239 destroyed later when it is closed.
240 Normally needed only if a file_handle needs to be re-assigned.
241 Otherwise, just let fh_done() destroy the handle. */
243 fh_free (struct file_handle *handle)
245 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
247 handle->deleted = true;
249 if (handle == default_handle)
250 default_handle = fh_inline_file ();
252 if (handle->open_cnt == 0)
253 free_handle (handle);
256 /* Returns an English description of MODE,
257 which is in the format of the MODE argument to fh_open(). */
259 mode_name (const char *mode)
261 assert (mode != NULL);
262 assert (mode[0] == 'r' || mode[0] == 'w');
264 return mode[0] == 'r' ? "reading" : "writing";
267 /* Tries to open handle H with the given TYPE and MODE.
269 H's referent type must be one of the bits in MASK. The caller
270 must verify this ahead of time; we simply assert it here.
272 TYPE is the sort of file, e.g. "system file". Only one given
273 type of access is allowed on a given file handle at once.
274 If successful, a reference to TYPE is retained, so it should
275 probably be a string literal.
277 MODE combines the read or write mode with the sharing mode.
278 The first character is 'r' for read, 'w' for write. The
279 second character is 's' to permit sharing, 'e' to require
282 Returns the address of a void * that the caller can use for
283 data specific to the file handle if successful, or a null
284 pointer on failure. For exclusive access modes the void *
285 will always be a null pointer at return. In shared access
286 modes the void * will necessarily be null only if no other
287 sharers are active. */
289 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
290 const char *type, const char *mode)
293 assert ((fh_get_referent (h) & mask) != 0);
294 assert (type != NULL);
295 assert (mode != NULL);
296 assert (mode[0] == 'r' || mode[0] == 'w');
297 assert (mode[1] == 's' || mode[1] == 'e');
298 assert (mode[2] == '\0');
300 if (h->open_cnt != 0)
302 if (strcmp (h->type, type))
304 msg (SE, _("Can't open %s as a %s because it is "
305 "already open as a %s."),
306 fh_get_name (h), type, h->type);
309 else if (strcmp (h->open_mode, mode))
311 msg (SE, _("Can't open %s as a %s for %s because it is "
312 "already open for %s."),
313 fh_get_name (h), type, mode_name (mode),
314 mode_name (h->open_mode));
317 else if (h->open_mode[1] == 'e')
319 msg (SE, _("Can't re-open %s as a %s for %s."),
320 fh_get_name (h), type, mode_name (mode));
327 strcpy (h->open_mode, mode);
328 assert (h->aux == NULL);
335 /* Closes file handle H, which must have been open for the
336 specified TYPE and MODE of access provided to fh_open().
337 Returns zero if the file is now closed, nonzero if it is still
338 open due to another reference.
340 After fh_close() returns zero for a handle, it is unsafe to
341 reference that file handle again in any way, because its
342 storage may have been freed. */
344 fh_close (struct file_handle *h, const char *type, const char *mode)
347 assert (h->open_cnt > 0);
348 assert (type != NULL);
349 assert (!strcmp (type, h->type));
350 assert (mode != NULL);
351 assert (!strcmp (mode, h->open_mode));
353 if (--h->open_cnt == 0)
364 /* Is the file open? BEGIN DATA...END DATA uses this to detect
365 whether the inline file is actually in use. */
367 fh_is_open (const struct file_handle *handle)
369 return handle->open_cnt > 0;
372 /* Returns the identifier of file HANDLE. If HANDLE was created
373 by referring to a file name instead of a handle name, returns
374 the file name, enclosed in double quotes. Return value is
375 owned by the file handle.
377 Useful for printing error messages about use of file handles. */
379 fh_get_name (const struct file_handle *handle)
384 /* Returns the type of object that HANDLE refers to. */
386 fh_get_referent (const struct file_handle *handle)
388 return handle->referent;
391 /* Returns the name of the file associated with HANDLE. */
393 fh_get_file_name (const struct file_handle *handle)
395 assert (handle->referent == FH_REF_FILE);
396 return handle->file_name;
399 /* Returns the mode of HANDLE. */
401 fh_get_mode (const struct file_handle *handle)
403 assert (handle->referent == FH_REF_FILE);
407 /* Returns the width of a logical record on HANDLE. */
409 fh_get_record_width (const struct file_handle *handle)
411 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
412 return handle->record_width;
415 /* Returns the number of characters per tab stop for HANDLE, or
416 zero if tabs are not to be expanded. Applicable only to
417 FH_MODE_TEXT files. */
419 fh_get_tab_width (const struct file_handle *handle)
421 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
422 return handle->tab_width;
425 /* Returns the scratch file handle associated with HANDLE.
426 Applicable to only FH_REF_SCRATCH files. */
427 struct scratch_handle *
428 fh_get_scratch_handle (struct file_handle *handle)
430 assert (handle->referent == FH_REF_SCRATCH);
434 /* Sets SH to be the scratch file handle associated with HANDLE.
435 Applicable to only FH_REF_SCRATCH files. */
437 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
439 assert (handle->referent == FH_REF_SCRATCH);
443 /* Returns the current default handle. */
445 fh_get_default_handle (void)
447 return default_handle ? default_handle : fh_inline_file ();
450 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
452 fh_set_default_handle (struct file_handle *new_default_handle)
454 assert (new_default_handle == NULL
455 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
456 default_handle = new_default_handle;