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 <libpspp/str.h>
33 #include <data/file-name.h>
34 #include <data/variable.h>
35 #include <data/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 id[LONG_NAME_LEN + 1]; /* Identifier token; empty string if none. */
50 char *name; /* User-friendly identifying name. */
51 const char *type; /* If open, type of file. */
52 char open_mode[3]; /* "[rw][se]". */
53 void *aux; /* Aux data pointer for owner if any. */
54 enum fh_referent referent; /* What the file handle refers to. */
56 /* FH_REF_FILE only. */
57 char *file_name; /* File name as provided by user. */
58 struct file_identity *identity; /* For checking file identity. */
59 enum fh_mode mode; /* File mode. */
61 /* FH_REF_FILE and FH_REF_INLINE only. */
62 size_t record_width; /* Length of fixed-format records. */
63 size_t tab_width; /* Tab width, 0=do not expand tabs. */
65 /* FH_REF_SCRATCH only. */
66 struct scratch_handle *sh; /* Scratch file data. */
69 /* List of all handles. */
70 static struct file_handle *file_handles;
72 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
74 static struct file_handle *default_handle;
76 /* The "file" that reads from BEGIN DATA...END DATA. */
77 static struct file_handle *inline_file;
79 static struct file_handle *create_handle (const char *id,
80 const char *name, enum fh_referent);
82 /* File handle initialization routine. */
86 inline_file = create_handle ("INLINE", "INLINE", FH_REF_INLINE);
87 inline_file->record_width = 80;
88 inline_file->tab_width = 8;
91 /* Free HANDLE and remove it from the global list. */
93 free_handle (struct file_handle *handle)
95 /* Remove handle from global list. */
96 if (file_handles == handle)
97 file_handles = handle->next;
100 struct file_handle *iter = file_handles;
101 while (iter->next != handle)
103 iter->next = handle->next;
108 free (handle->file_name);
109 fn_free_identity (handle->identity);
110 scratch_handle_destroy (handle->sh);
114 /* Frees all the file handles. */
118 while (file_handles != NULL)
119 free_handle (file_handles);
122 /* Returns the handle with the given ID, or a null pointer if
125 fh_from_id (const char *id)
127 struct file_handle *iter;
129 for (iter = file_handles; iter != NULL; iter = iter->next)
130 if (!iter->deleted && !strcasecmp (id, iter->id))
135 /* Returns the handle for the file named FILE_NAME,
136 or a null pointer if none exists.
137 Different names for the same file (e.g. "x" and "./x") are
138 considered equivalent. */
140 fh_from_file_name (const char *file_name)
142 struct file_identity *identity;
143 struct file_handle *iter;
145 /* First check for a file with the same identity. */
146 identity = fn_get_identity (file_name);
147 if (identity != NULL)
149 for (iter = file_handles; iter != NULL; iter = iter->next)
151 && iter->referent == FH_REF_FILE
152 && iter->identity != NULL
153 && !fn_compare_file_identities (identity, iter->identity))
155 fn_free_identity (identity);
158 fn_free_identity (identity);
161 /* Then check for a file with the same name. */
162 for (iter = file_handles; iter != NULL; iter = iter->next)
164 && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
170 /* Creates a new handle with identifier ID (which may be null)
171 and name HANDLE_NAME that refers to REFERENT. Links the new
172 handle into the global list. Returns the new handle.
174 The new handle is not fully initialized. The caller is
175 responsible for completing its initialization. */
176 static struct file_handle *
177 create_handle (const char *id, const char *handle_name,
178 enum fh_referent referent)
180 struct file_handle *handle = xzalloc (sizeof *handle);
181 assert (id == NULL || fh_from_id (id) == NULL);
182 handle->next = file_handles;
183 handle->open_cnt = 0;
184 handle->deleted = false;
185 str_copy_trunc (handle->id, sizeof handle->id, id != NULL ? id : "");
186 handle->name = xstrdup (handle_name);
189 handle->referent = referent;
190 file_handles = handle;
194 /* Returns the unique handle of referent type FH_REF_INLINE,
195 which refers to the "inline file" that represents character
196 data in the command file between BEGIN DATA and END DATA. */
198 fh_inline_file (void)
203 /* Creates a new file handle with the given ID, which may be
204 null. If it is non-null, it must be unique among existing
205 file identifiers. The new handle is associated with file
206 FILE_NAME and the given PROPERTIES. */
208 fh_create_file (const char *id, const char *file_name,
209 const struct fh_properties *properties)
212 struct file_handle *handle;
214 handle_name = id != NULL ? (char *) id : xasprintf ("\"%s\"", file_name);
215 handle = create_handle (id, handle_name, FH_REF_FILE);
218 handle->file_name = xstrdup (file_name);
219 handle->identity = fn_get_identity (file_name);
220 handle->mode = properties->mode;
221 handle->record_width = properties->record_width;
222 handle->tab_width = properties->tab_width;
226 /* Creates a new file handle with the given ID, which must be
227 unique among existing file identifiers. The new handle is
228 associated with a scratch file (initially empty). */
230 fh_create_scratch (const char *id)
232 struct file_handle *handle;
234 handle = create_handle (id, id, FH_REF_SCRATCH);
239 /* Returns a set of default properties for a file handle. */
240 const struct fh_properties *
241 fh_default_properties (void)
243 static const struct fh_properties default_properties
244 = {FH_MODE_TEXT, 1024, 4};
245 return &default_properties;
248 /* Deletes FH from the global list of file handles. Afterward,
249 attempts to search for it will fail. Unless the file handle
250 is currently open, it will be destroyed; otherwise, it will be
251 destroyed later when it is closed.
252 Normally needed only if a file_handle needs to be re-assigned.
253 Otherwise, just let fh_done() destroy the handle. */
255 fh_free (struct file_handle *handle)
257 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
259 handle->deleted = true;
261 if (handle == default_handle)
262 default_handle = fh_inline_file ();
264 if (handle->open_cnt == 0)
265 free_handle (handle);
268 /* Returns an English description of MODE,
269 which is in the format of the MODE argument to fh_open(). */
271 mode_name (const char *mode)
273 assert (mode != NULL);
274 assert (mode[0] == 'r' || mode[0] == 'w');
276 return mode[0] == 'r' ? "reading" : "writing";
279 /* Tries to open handle H with the given TYPE and MODE.
281 H's referent type must be one of the bits in MASK. The caller
282 must verify this ahead of time; we simply assert it here.
284 TYPE is the sort of file, e.g. "system file". Only one given
285 type of access is allowed on a given file handle at once.
286 If successful, a reference to TYPE is retained, so it should
287 probably be a string literal.
289 MODE combines the read or write mode with the sharing mode.
290 The first character is 'r' for read, 'w' for write. The
291 second character is 's' to permit sharing, 'e' to require
294 Returns the address of a void * that the caller can use for
295 data specific to the file handle if successful, or a null
296 pointer on failure. For exclusive access modes the void *
297 will always be a null pointer at return. In shared access
298 modes the void * will necessarily be null only if no other
299 sharers are active. */
301 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
302 const char *type, const char *mode)
305 assert ((fh_get_referent (h) & mask) != 0);
306 assert (type != NULL);
307 assert (mode != NULL);
308 assert (mode[0] == 'r' || mode[0] == 'w');
309 assert (mode[1] == 's' || mode[1] == 'e');
310 assert (mode[2] == '\0');
312 if (h->open_cnt != 0)
314 if (strcmp (h->type, type))
316 msg (SE, _("Can't open %s as a %s because it is "
317 "already open as a %s."),
318 fh_get_name (h), type, h->type);
321 else if (strcmp (h->open_mode, mode))
323 msg (SE, _("Can't open %s as a %s for %s because it is "
324 "already open for %s."),
325 fh_get_name (h), type, mode_name (mode),
326 mode_name (h->open_mode));
329 else if (h->open_mode[1] == 'e')
331 msg (SE, _("Can't re-open %s as a %s for %s."),
332 fh_get_name (h), type, mode_name (mode));
339 strcpy (h->open_mode, mode);
340 assert (h->aux == NULL);
347 /* Closes file handle H, which must have been open for the
348 specified TYPE and MODE of access provided to fh_open().
349 Returns zero if the file is now closed, nonzero if it is still
350 open due to another reference.
352 After fh_close() returns zero for a handle, it is unsafe to
353 reference that file handle again in any way, because its
354 storage may have been freed. */
356 fh_close (struct file_handle *h, const char *type, const char *mode)
359 assert (h->open_cnt > 0);
360 assert (type != NULL);
361 assert (!strcmp (type, h->type));
362 assert (mode != NULL);
363 assert (!strcmp (mode, h->open_mode));
365 if (--h->open_cnt == 0)
376 /* Is the file open? BEGIN DATA...END DATA uses this to detect
377 whether the inline file is actually in use. */
379 fh_is_open (const struct file_handle *handle)
381 return handle->open_cnt > 0;
384 /* Returns the identifier that may be used in syntax to name the
385 given HANDLE, which takes the form of a PSPP identifier. If
386 HANDLE has no identifier, returns a null pointer.
388 Return value is owned by the file handle.*/
390 fh_get_id (const struct file_handle *handle)
392 return handle->id[0] != '\0' ? handle->id : NULL;
395 /* Returns a user-friendly string to identify the given HANDLE.
396 If HANDLE was created by referring to a file name, returns the
397 file name, enclosed in double quotes. Return value is owned
400 Useful for printing error messages about use of file handles. */
402 fh_get_name (const struct file_handle *handle)
407 /* Returns the type of object that HANDLE refers to. */
409 fh_get_referent (const struct file_handle *handle)
411 return handle->referent;
414 /* Returns the name of the file associated with HANDLE. */
416 fh_get_file_name (const struct file_handle *handle)
418 assert (handle->referent == FH_REF_FILE);
419 return handle->file_name;
422 /* Returns the mode of HANDLE. */
424 fh_get_mode (const struct file_handle *handle)
426 assert (handle->referent == FH_REF_FILE);
430 /* Returns the width of a logical record on HANDLE. */
432 fh_get_record_width (const struct file_handle *handle)
434 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
435 return handle->record_width;
438 /* Returns the number of characters per tab stop for HANDLE, or
439 zero if tabs are not to be expanded. Applicable only to
440 FH_MODE_TEXT files. */
442 fh_get_tab_width (const struct file_handle *handle)
444 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
445 return handle->tab_width;
448 /* Returns the scratch file handle associated with HANDLE.
449 Applicable to only FH_REF_SCRATCH files. */
450 struct scratch_handle *
451 fh_get_scratch_handle (struct file_handle *handle)
453 assert (handle->referent == FH_REF_SCRATCH);
457 /* Sets SH to be the scratch file handle associated with HANDLE.
458 Applicable to only FH_REF_SCRATCH files. */
460 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
462 assert (handle->referent == FH_REF_SCRATCH);
466 /* Returns the current default handle. */
468 fh_get_default_handle (void)
470 return default_handle ? default_handle : fh_inline_file ();
473 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
475 fh_set_default_handle (struct file_handle *new_default_handle)
477 assert (new_default_handle == NULL
478 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
479 default_handle = new_default_handle;