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
21 #include "file-handle-def.h"
22 #include <libpspp/message.h>
26 #include <libpspp/alloc.h>
27 #include <libpspp/compiler.h>
28 #include "file-name.h"
29 #include <libpspp/message.h>
30 #include <libpspp/magic.h>
32 #include "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 *name; /* File handle identifier. */
47 const char *type; /* If open, type of file. */
48 char open_mode[3]; /* "[rw][se]". */
49 void *aux; /* Aux data pointer for owner if any. */
50 enum fh_referent referent; /* What the file handle refers to. */
52 /* FH_REF_FILE only. */
53 char *file_name; /* File name as provided by user. */
54 struct file_identity *identity; /* For checking file identity. */
55 enum fh_mode mode; /* File mode. */
57 /* FH_REF_FILE and FH_REF_INLINE only. */
58 size_t record_width; /* Length of fixed-format records. */
59 size_t tab_width; /* Tab width, 0=do not expand tabs. */
61 /* FH_REF_SCRATCH only. */
62 struct scratch_handle *sh; /* Scratch file data. */
65 /* List of all handles. */
66 static struct file_handle *file_handles;
68 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
70 static struct file_handle *default_handle;
72 /* The "file" that reads from BEGIN DATA...END DATA. */
73 static struct file_handle *inline_file;
75 static struct file_handle *create_handle (const char *name, enum fh_referent);
77 /* File handle initialization routine. */
81 inline_file = create_handle ("INLINE", FH_REF_INLINE);
82 inline_file->record_width = 80;
83 inline_file->tab_width = 8;
86 /* Free HANDLE and remove it from the global list. */
88 free_handle (struct file_handle *handle)
90 /* Remove handle from global list. */
91 if (file_handles == handle)
92 file_handles = handle->next;
95 struct file_handle *iter = file_handles;
96 while (iter->next != handle)
98 iter->next = handle->next;
103 free (handle->file_name);
104 fn_free_identity (handle->identity);
105 scratch_handle_destroy (handle->sh);
109 /* Frees all the file handles. */
113 while (file_handles != NULL)
114 free_handle (file_handles);
117 /* Returns the handle named HANDLE_NAME, or a null pointer if
120 fh_from_name (const char *handle_name)
122 struct file_handle *iter;
124 for (iter = file_handles; iter != NULL; iter = iter->next)
125 if (!iter->deleted && !strcasecmp (handle_name, iter->name))
130 /* Returns the handle for the file named FILE_NAME,
131 or a null pointer if none exists.
132 Different names for the same file (e.g. "x" and "./x") are
133 considered equivalent. */
135 fh_from_file_name (const char *file_name)
137 struct file_identity *identity;
138 struct file_handle *iter;
140 /* First check for a file with the same identity. */
141 identity = fn_get_identity (file_name);
142 if (identity != NULL)
144 for (iter = file_handles; iter != NULL; iter = iter->next)
146 && iter->referent == FH_REF_FILE
147 && iter->identity != NULL
148 && !fn_compare_file_identities (identity, iter->identity))
150 fn_free_identity (identity);
153 fn_free_identity (identity);
156 /* Then check for a file with the same name. */
157 for (iter = file_handles; iter != NULL; iter = iter->next)
159 && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
165 /* Creates a new handle with name HANDLE_NAME that refers to
166 REFERENT. Links the new handle into the global list. Returns
169 The new handle is not fully initialized. The caller is
170 responsible for completing its initialization. */
171 static struct file_handle *
172 create_handle (const char *handle_name, enum fh_referent referent)
174 struct file_handle *handle = xzalloc (sizeof *handle);
175 handle->next = file_handles;
176 handle->open_cnt = 0;
177 handle->deleted = false;
178 handle->name = xstrdup (handle_name);
181 handle->referent = referent;
182 file_handles = handle;
186 /* Returns the unique handle of referent type FH_REF_INLINE,
187 which refers to the "inline file" that represents character
188 data in the command file between BEGIN DATA and END DATA. */
190 fh_inline_file (void)
195 /* Creates a new file handle named HANDLE_NAME, which must not be
196 the name of an existing file handle. The new handle is
197 associated with file FILE_NAME and the given PROPERTIES. */
199 fh_create_file (const char *handle_name, const char *file_name,
200 const struct fh_properties *properties)
202 struct file_handle *handle;
203 assert (fh_from_name (handle_name) == NULL);
204 handle = create_handle (handle_name, FH_REF_FILE);
205 handle->file_name = xstrdup (file_name);
206 handle->identity = fn_get_identity (file_name);
207 handle->mode = properties->mode;
208 handle->record_width = properties->record_width;
209 handle->tab_width = properties->tab_width;
213 /* Creates a new file handle named HANDLE_NAME, which must not be
214 the name of an existing file handle. The new handle is
215 associated with a scratch file (initially empty). */
217 fh_create_scratch (const char *handle_name)
219 struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
224 /* Returns a set of default properties for a file handle. */
225 const struct fh_properties *
226 fh_default_properties (void)
228 static const struct fh_properties default_properties
229 = {FH_MODE_TEXT, 1024, 4};
230 return &default_properties;
233 /* Deletes FH from the global list of file handles. Afterward,
234 attempts to search for it will fail. Unless the file handle
235 is currently open, it will be destroyed; otherwise, it will be
236 destroyed later when it is closed.
237 Normally needed only if a file_handle needs to be re-assigned.
238 Otherwise, just let fh_done() destroy the handle. */
240 fh_free (struct file_handle *handle)
242 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
244 handle->deleted = true;
246 if (handle == default_handle)
247 default_handle = fh_inline_file ();
249 if (handle->open_cnt == 0)
250 free_handle (handle);
253 /* Returns an English description of MODE,
254 which is in the format of the MODE argument to fh_open(). */
256 mode_name (const char *mode)
258 assert (mode != NULL);
259 assert (mode[0] == 'r' || mode[0] == 'w');
261 return mode[0] == 'r' ? "reading" : "writing";
264 /* Tries to open handle H with the given TYPE and MODE.
266 H's referent type must be one of the bits in MASK. The caller
267 must verify this ahead of time; we simply assert it here.
269 TYPE is the sort of file, e.g. "system file". Only one given
270 type of access is allowed on a given file handle at once.
271 If successful, a reference to TYPE is retained, so it should
272 probably be a string literal.
274 MODE combines the read or write mode with the sharing mode.
275 The first character is 'r' for read, 'w' for write. The
276 second character is 's' to permit sharing, 'e' to require
279 Returns the address of a void * that the caller can use for
280 data specific to the file handle if successful, or a null
281 pointer on failure. For exclusive access modes the void *
282 will always be a null pointer at return. In shared access
283 modes the void * will necessarily be null only if no other
284 sharers are active. */
286 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
287 const char *type, const char *mode)
290 assert ((fh_get_referent (h) & mask) != 0);
291 assert (type != NULL);
292 assert (mode != NULL);
293 assert (mode[0] == 'r' || mode[0] == 'w');
294 assert (mode[1] == 's' || mode[1] == 'e');
295 assert (mode[2] == '\0');
297 if (h->open_cnt != 0)
299 if (strcmp (h->type, type))
301 msg (SE, _("Can't open %s as a %s because it is "
302 "already open as a %s."),
303 fh_get_name (h), type, h->type);
306 else if (strcmp (h->open_mode, mode))
308 msg (SE, _("Can't open %s as a %s for %s because it is "
309 "already open for %s."),
310 fh_get_name (h), type, mode_name (mode),
311 mode_name (h->open_mode));
314 else if (h->open_mode[1] == 'e')
316 msg (SE, _("Can't re-open %s as a %s for %s."),
317 fh_get_name (h), type, mode_name (mode));
324 strcpy (h->open_mode, mode);
325 assert (h->aux == NULL);
332 /* Closes file handle H, which must have been open for the
333 specified TYPE and MODE of access provided to fh_open().
334 Returns zero if the file is now closed, nonzero if it is still
335 open due to another reference.
337 After fh_close() returns zero for a handle, it is unsafe to
338 reference that file handle again in any way, because its
339 storage may have been freed. */
341 fh_close (struct file_handle *h, const char *type, const char *mode)
344 assert (h->open_cnt > 0);
345 assert (type != NULL);
346 assert (!strcmp (type, h->type));
347 assert (mode != NULL);
348 assert (!strcmp (mode, h->open_mode));
350 if (--h->open_cnt == 0)
361 /* Is the file open? BEGIN DATA...END DATA uses this to detect
362 whether the inline file is actually in use. */
364 fh_is_open (const struct file_handle *handle)
366 return handle->open_cnt > 0;
369 /* Returns the identifier of file HANDLE. If HANDLE was created
370 by referring to a file name instead of a handle name, returns
371 the file name, enclosed in double quotes. Return value is
372 owned by the file handle.
374 Useful for printing error messages about use of file handles. */
376 fh_get_name (const struct file_handle *handle)
381 /* Returns the type of object that HANDLE refers to. */
383 fh_get_referent (const struct file_handle *handle)
385 return handle->referent;
388 /* Returns the name of the file associated with HANDLE. */
390 fh_get_file_name (const struct file_handle *handle)
392 assert (handle->referent == FH_REF_FILE);
393 return handle->file_name;
396 /* Returns the mode of HANDLE. */
398 fh_get_mode (const struct file_handle *handle)
400 assert (handle->referent == FH_REF_FILE);
404 /* Returns the width of a logical record on HANDLE. */
406 fh_get_record_width (const struct file_handle *handle)
408 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
409 return handle->record_width;
412 /* Returns the number of characters per tab stop for HANDLE, or
413 zero if tabs are not to be expanded. Applicable only to
414 FH_MODE_TEXT files. */
416 fh_get_tab_width (const struct file_handle *handle)
418 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
419 return handle->tab_width;
422 /* Returns the scratch file handle associated with HANDLE.
423 Applicable to only FH_REF_SCRATCH files. */
424 struct scratch_handle *
425 fh_get_scratch_handle (struct file_handle *handle)
427 assert (handle->referent == FH_REF_SCRATCH);
431 /* Sets SH to be the scratch file handle associated with HANDLE.
432 Applicable to only FH_REF_SCRATCH files. */
434 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
436 assert (handle->referent == FH_REF_SCRATCH);
440 /* Returns the current default handle. */
442 fh_get_default_handle (void)
444 return default_handle ? default_handle : fh_inline_file ();
447 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
449 fh_set_default_handle (struct file_handle *new_default_handle)
451 assert (new_default_handle == NULL
452 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
453 default_handle = new_default_handle;