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"
31 #include "scratch-handle.h"
34 #define _(msgid) gettext (msgid)
41 struct file_handle *next; /* Next in global list. */
42 int open_cnt; /* 0=not open, otherwise # of openers. */
43 bool deleted; /* Destroy handle when open_cnt goes to 0? */
45 char *name; /* File handle identifier. */
46 const char *type; /* If open, type of file. */
47 char open_mode[3]; /* "[rw][se]". */
48 void *aux; /* Aux data pointer for owner if any. */
49 enum fh_referent referent; /* What the file handle refers to. */
51 /* FH_REF_FILE only. */
52 char *filename; /* Filename as provided by user. */
53 struct file_identity *identity; /* For checking file identity. */
54 enum fh_mode mode; /* File mode. */
56 /* FH_REF_FILE and FH_REF_INLINE only. */
57 size_t record_width; /* Length of fixed-format records. */
58 size_t tab_width; /* Tab width, 0=do not expand tabs. */
60 /* FH_REF_SCRATCH only. */
61 struct scratch_handle *sh; /* Scratch file data. */
64 /* List of all handles. */
65 static struct file_handle *file_handles;
67 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
69 static struct file_handle *default_handle;
71 /* The "file" that reads from BEGIN DATA...END DATA. */
72 static struct file_handle *inline_file;
74 static struct file_handle *create_handle (const char *name, enum fh_referent);
76 /* File handle initialization routine. */
80 inline_file = create_handle ("INLINE", FH_REF_INLINE);
81 inline_file->record_width = 80;
82 inline_file->tab_width = 8;
85 /* Free HANDLE and remove it from the global list. */
87 free_handle (struct file_handle *handle)
89 /* Remove handle from global list. */
90 if (file_handles == handle)
91 file_handles = handle->next;
94 struct file_handle *iter = file_handles;
95 while (iter->next != handle)
97 iter->next = handle->next;
102 free (handle->filename);
103 fn_free_identity (handle->identity);
104 scratch_handle_destroy (handle->sh);
108 /* Frees all the file handles. */
112 while (file_handles != NULL)
113 free_handle (file_handles);
116 /* Returns the handle named HANDLE_NAME, or a null pointer if
119 fh_from_name (const char *handle_name)
121 struct file_handle *iter;
123 for (iter = file_handles; iter != NULL; iter = iter->next)
124 if (!iter->deleted && !strcasecmp (handle_name, iter->name))
129 /* Returns the handle for the file named FILENAME,
130 or a null pointer if none exists.
131 Different names for the same file (e.g. "x" and "./x") are
132 considered equivalent. */
134 fh_from_filename (const char *filename)
136 struct file_identity *identity;
137 struct file_handle *iter;
139 /* First check for a file with the same identity. */
140 identity = fn_get_identity (filename);
141 if (identity != NULL)
143 for (iter = file_handles; iter != NULL; iter = iter->next)
145 && iter->referent == FH_REF_FILE
146 && iter->identity != NULL
147 && !fn_compare_file_identities (identity, iter->identity))
149 fn_free_identity (identity);
152 fn_free_identity (identity);
155 /* Then check for a file with the same name. */
156 for (iter = file_handles; iter != NULL; iter = iter->next)
158 && iter->referent == FH_REF_FILE && !strcmp (filename, iter->filename))
164 /* Creates a new handle with name HANDLE_NAME that refers to
165 REFERENT. Links the new handle into the global list. Returns
168 The new handle is not fully initialized. The caller is
169 responsible for completing its initialization. */
170 static struct file_handle *
171 create_handle (const char *handle_name, enum fh_referent referent)
173 struct file_handle *handle = xzalloc (sizeof *handle);
174 handle->next = file_handles;
175 handle->open_cnt = 0;
176 handle->deleted = false;
177 handle->name = xstrdup (handle_name);
180 handle->referent = referent;
181 file_handles = handle;
185 /* Returns the unique handle of referent type FH_REF_INLINE,
186 which refers to the "inline file" that represents character
187 data in the command file between BEGIN DATA and END DATA. */
189 fh_inline_file (void)
194 /* Creates a new file handle named HANDLE_NAME, which must not be
195 the name of an existing file handle. The new handle is
196 associated with file FILENAME and the given PROPERTIES. */
198 fh_create_file (const char *handle_name, const char *filename,
199 const struct fh_properties *properties)
201 struct file_handle *handle;
202 assert (fh_from_name (handle_name) == NULL);
203 handle = create_handle (handle_name, FH_REF_FILE);
204 handle->filename = xstrdup (filename);
205 handle->identity = fn_get_identity (filename);
206 handle->mode = properties->mode;
207 handle->record_width = properties->record_width;
208 handle->tab_width = properties->tab_width;
212 /* Creates a new file handle named HANDLE_NAME, which must not be
213 the name of an existing file handle. The new handle is
214 associated with a scratch file (initially empty). */
216 fh_create_scratch (const char *handle_name)
218 struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
223 /* Returns a set of default properties for a file handle. */
224 const struct fh_properties *
225 fh_default_properties (void)
227 static const struct fh_properties default_properties
228 = {FH_MODE_TEXT, 1024, 4};
229 return &default_properties;
232 /* Deletes FH from the global list of file handles. Afterward,
233 attempts to search for it will fail. Unless the file handle
234 is currently open, it will be destroyed; otherwise, it will be
235 destroyed later when it is closed.
236 Normally needed only if a file_handle needs to be re-assigned.
237 Otherwise, just let fh_done() destroy the handle. */
239 fh_free (struct file_handle *handle)
241 if (handle == fh_inline_file () || handle == NULL || handle->deleted)
243 handle->deleted = true;
245 if (handle == default_handle)
246 default_handle = fh_inline_file ();
248 if (handle->open_cnt == 0)
249 free_handle (handle);
252 /* Returns an English description of MODE,
253 which is in the format of the MODE argument to fh_open(). */
255 mode_name (const char *mode)
257 assert (mode != NULL);
258 assert (mode[0] == 'r' || mode[0] == 'w');
260 return mode[0] == 'r' ? "reading" : "writing";
263 /* Tries to open handle H with the given TYPE and MODE.
265 H's referent type must be one of the bits in MASK. The caller
266 must verify this ahead of time; we simply assert it here.
268 TYPE is the sort of file, e.g. "system file". Only one given
269 type of access is allowed on a given file handle at once.
270 If successful, a reference to TYPE is retained, so it should
271 probably be a string literal.
273 MODE combines the read or write mode with the sharing mode.
274 The first character is 'r' for read, 'w' for write. The
275 second character is 's' to permit sharing, 'e' to require
278 Returns the address of a void * that the caller can use for
279 data specific to the file handle if successful, or a null
280 pointer on failure. For exclusive access modes the void *
281 will always be a null pointer at return. In shared access
282 modes the void * will necessarily be null only if no other
283 sharers are active. */
285 fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
286 const char *type, const char *mode)
289 assert ((fh_get_referent (h) & mask) != 0);
290 assert (type != NULL);
291 assert (mode != NULL);
292 assert (mode[0] == 'r' || mode[0] == 'w');
293 assert (mode[1] == 's' || mode[1] == 'e');
294 assert (mode[2] == '\0');
296 if (h->open_cnt != 0)
298 if (strcmp (h->type, type))
300 msg (SE, _("Can't open %s as a %s because it is "
301 "already open as a %s."),
302 fh_get_name (h), type, h->type);
305 else if (strcmp (h->open_mode, mode))
307 msg (SE, _("Can't open %s as a %s for %s because it is "
308 "already open for %s."),
309 fh_get_name (h), type, mode_name (mode),
310 mode_name (h->open_mode));
313 else if (h->open_mode[1] == 'e')
315 msg (SE, _("Can't re-open %s as a %s for %s."),
316 fh_get_name (h), type, mode_name (mode));
323 strcpy (h->open_mode, mode);
324 assert (h->aux == NULL);
331 /* Closes file handle H, which must have been open for the
332 specified TYPE and MODE of access provided to fh_open().
333 Returns zero if the file is now closed, nonzero if it is still
334 open due to another reference.
336 After fh_close() returns zero for a handle, it is unsafe to
337 reference that file handle again in any way, because its
338 storage may have been freed. */
340 fh_close (struct file_handle *h, const char *type, const char *mode)
343 assert (h->open_cnt > 0);
344 assert (type != NULL);
345 assert (!strcmp (type, h->type));
346 assert (mode != NULL);
347 assert (!strcmp (mode, h->open_mode));
349 if (--h->open_cnt == 0)
360 /* Is the file open? BEGIN DATA...END DATA uses this to detect
361 whether the inline file is actually in use. */
363 fh_is_open (const struct file_handle *handle)
365 return handle->open_cnt > 0;
368 /* Returns the identifier of file HANDLE. If HANDLE was created
369 by referring to a filename instead of a handle name, returns
370 the filename, enclosed in double quotes. Return value is
371 owned by the file handle.
373 Useful for printing error messages about use of file handles. */
375 fh_get_name (const struct file_handle *handle)
380 /* Returns the type of object that HANDLE refers to. */
382 fh_get_referent (const struct file_handle *handle)
384 return handle->referent;
387 /* Returns the name of the file associated with HANDLE. */
389 fh_get_filename (const struct file_handle *handle)
391 assert (handle->referent == FH_REF_FILE);
392 return handle->filename;
395 /* Returns the mode of HANDLE. */
397 fh_get_mode (const struct file_handle *handle)
399 assert (handle->referent == FH_REF_FILE);
403 /* Returns the width of a logical record on HANDLE. */
405 fh_get_record_width (const struct file_handle *handle)
407 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
408 return handle->record_width;
411 /* Returns the number of characters per tab stop for HANDLE, or
412 zero if tabs are not to be expanded. Applicable only to
413 FH_MODE_TEXT files. */
415 fh_get_tab_width (const struct file_handle *handle)
417 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
418 return handle->tab_width;
421 /* Returns the scratch file handle associated with HANDLE.
422 Applicable to only FH_REF_SCRATCH files. */
423 struct scratch_handle *
424 fh_get_scratch_handle (struct file_handle *handle)
426 assert (handle->referent == FH_REF_SCRATCH);
430 /* Sets SH to be the scratch file handle associated with HANDLE.
431 Applicable to only FH_REF_SCRATCH files. */
433 fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
435 assert (handle->referent == FH_REF_SCRATCH);
439 /* Returns the current default handle. */
441 fh_get_default_handle (void)
443 return default_handle ? default_handle : fh_inline_file ();
446 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
448 fh_set_default_handle (struct file_handle *new_default_handle)
450 assert (new_default_handle == NULL
451 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
452 default_handle = new_default_handle;