1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 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., 59 Temple Place - Suite 330, Boston, MA
21 #include "file-handle.h"
33 #include "linked-list.h"
40 struct file_handle *next; /* Next in global list. */
41 char *name; /* File handle identifier. */
42 char *filename; /* Filename as provided by user. */
43 struct file_identity *identity; /* For checking file identity. */
44 struct file_locator where; /* Used for reporting error messages. */
45 enum file_handle_mode mode; /* File mode. */
46 size_t length; /* Length of fixed-format records. */
47 size_t tab_width; /* Tab width, 0=do not expand tabs. */
49 int open_cnt; /* 0=not open, otherwise # of openers. */
50 const char *type; /* If open, type of file. */
51 const char *open_mode; /* "[rw][se]". */
52 void *aux; /* Aux data pointer for owner if any. */
55 static struct file_handle *file_handles;
57 static struct file_handle *create_file_handle (const char *handle_name,
58 const char *filename);
64 tabwidth=integer "x>=0" "%s must be nonnegative";
65 mode=mode:!character/image.
70 static struct file_handle *
71 get_handle_with_name (const char *handle_name)
73 struct file_handle *iter;
75 for (iter = file_handles; iter != NULL; iter = iter->next)
76 if (!strcmp (handle_name, iter->name))
81 static struct file_handle *
82 get_handle_for_filename (const char *filename)
84 struct file_identity *identity;
85 struct file_handle *iter;
87 /* First check for a file with the same identity. */
88 identity = fn_get_identity (filename);
91 for (iter = file_handles; iter != NULL; iter = iter->next)
92 if (iter->identity != NULL
93 && !fn_compare_file_identities (identity, iter->identity))
95 fn_free_identity (identity);
98 fn_free_identity (identity);
101 /* Then check for a file with the same name. */
102 for (iter = file_handles; iter != NULL; iter = iter->next)
103 if (!strcmp (filename, iter->filename))
110 cmd_file_handle (void)
114 struct cmd_file_handle cmd;
115 struct file_handle *handle;
117 if (!lex_force_id ())
119 strcpy (handle_name, tokid);
121 handle = get_handle_with_name (handle_name);
124 msg (SE, _("File handle %s already refers to "
125 "file %s. File handle cannot be redefined within a "
127 tokid, handle->filename);
132 if (!lex_force_match ('/'))
135 if (!parse_file_handle (&cmd))
140 lex_error (_("expecting end of command"));
144 if (cmd.s_name == NULL)
146 msg (SE, _("The FILE HANDLE required subcommand NAME "
151 handle = create_file_handle (handle_name, cmd.s_name);
155 handle->mode = MODE_TEXT;
156 if (cmd.sbc_tabwidth)
157 handle->tab_width = cmd.n_tabwidth[0];
159 handle->tab_width = 4;
162 handle->mode = MODE_BINARY;
163 if (cmd.n_lrecl[0] == NOT_LONG)
165 msg (SE, _("Fixed-length records were specified on /RECFORM, but "
166 "record length was not specified on /LRECL. "
167 "Assuming 1024-character records."));
168 handle->length = 1024;
170 else if (cmd.n_lrecl[0] < 1)
172 msg (SE, _("Record length (%ld) must be at least one byte. "
173 "1-character records will be assumed."), cmd.n_lrecl);
177 handle->length = cmd.n_lrecl[0];
186 free_file_handle (&cmd);
190 /* File handle functions. */
192 /* Creates and returns a new file handle with the given values
193 and defaults for other values. Adds the created file handle
194 to the global list. */
195 static struct file_handle *
196 create_file_handle (const char *handle_name, const char *filename)
198 struct file_handle *handle;
200 /* Create and initialize file handle. */
201 handle = xmalloc (sizeof *handle);
202 handle->next = file_handles;
203 handle->name = xstrdup (handle_name);
204 handle->filename = xstrdup (filename);
205 handle->identity = fn_get_identity (filename);
206 handle->where.filename = handle->filename;
207 handle->where.line_number = 0;
208 handle->mode = MODE_TEXT;
209 handle->length = 1024;
210 handle->tab_width = 4;
211 handle->open_cnt = 0;
213 handle->open_mode = NULL;
215 file_handles = handle;
221 destroy_file_handle(struct file_handle *fh, void *aux UNUSED)
225 fn_free_identity (fh->identity);
230 mode_name (const char *mode)
232 assert (mode != NULL);
233 assert (mode[0] == 'r' || mode[0] == 'w');
235 return mode[0] == 'r' ? "reading" : "writing";
239 /* Tries to open FILE with the given TYPE and MODE.
241 TYPE is the sort of file, e.g. "system file". Only one given
242 type of access is allowed on a given file handle at once.
244 MODE combines the read or write mode with the sharing mode.
245 The first character is 'r' for read, 'w' for write. The
246 second character is 's' to permit sharing, 'e' to require
249 Returns the address of a void * that the caller can use for
250 data specific to the file handle if successful, or a null
251 pointer on failure. For exclusive access modes the void *
252 will always be a null pointer at return. In shared access
253 modes the void * will necessarily be null only if no other
256 If successful, references to type and mode are retained, so
257 they should probably be string literals. */
259 fh_open (struct file_handle *h, const char *type, const char *mode)
262 assert (type != NULL);
263 assert (mode != NULL);
264 assert (mode[0] == 'r' || mode[0] == 'w');
265 assert (mode[1] == 's' || mode[1] == 'e');
266 assert (mode[2] == '\0');
268 if (h->open_cnt != 0)
270 if (strcmp (h->type, type))
271 msg (SE, _("Can't open %s as a %s because it is "
272 "already open as a %s"),
273 handle_get_name (h), type, h->type);
274 else if (strcmp (h->open_mode, mode))
275 msg (SE, _("Can't open %s as a %s for %s because it is "
276 "already open for %s"),
277 handle_get_name (h), type,
278 mode_name (mode), mode_name (h->open_mode));
279 else if (h->open_mode[1] == 'e')
280 msg (SE, _("Can't re-open %s as a %s for %s"),
281 handle_get_name (h), type, mode_name (mode));
287 assert (h->aux == NULL);
294 /* Closes file handle H, which must have been open for the
295 specified TYPE and MODE of access provided to fh_open().
296 Returns zero if the file is now closed, nonzero if it is still
297 open due to another reference. */
299 fh_close (struct file_handle *h, const char *type, const char *mode)
302 assert (h->open_cnt > 0);
303 assert (type != NULL);
304 assert (!strcmp (type, h->type));
305 assert (mode != NULL);
306 assert (!strcmp (mode, h->open_mode));
309 if (h->open_cnt == 0)
319 static struct linked_list *handle_list;
322 /* Parses a file handle name, which may be a filename as a string or
323 a file handle name as an identifier. Returns the file handle or
328 struct file_handle *handle;
330 if (token != T_ID && token != T_STRING)
332 lex_error (_("expecting a file name or handle name"));
336 /* Check for named handles first, then go by filename. */
339 handle = get_handle_with_name (tokid);
341 handle = get_handle_for_filename (ds_c_str (&tokstr));
344 char *filename = ds_c_str (&tokstr);
345 char *handle_name = xmalloc (strlen (filename) + 3);
346 sprintf (handle_name, "\"%s\"", filename);
347 handle = create_file_handle (handle_name, filename);
348 ll_push_front(handle_list, handle);
358 /* Returns the identifier of file HANDLE. If HANDLE was created
359 by referring to a filename instead of a handle name, returns
360 the filename, enclosed in double quotes. Return value is
361 owned by the file handle.
363 Useful for printing error messages about use of file handles. */
365 handle_get_name (const struct file_handle *handle)
367 assert (handle != NULL);
371 /* Returns the name of the file associated with HANDLE. */
373 handle_get_filename (const struct file_handle *handle)
375 assert (handle != NULL);
376 return handle->filename;
379 /* Returns the mode of HANDLE. */
380 enum file_handle_mode
381 handle_get_mode (const struct file_handle *handle)
383 assert (handle != NULL);
387 /* Returns the width of a logical record on HANDLE. Applicable
388 only to MODE_BINARY files. */
390 handle_get_record_width (const struct file_handle *handle)
392 assert (handle != NULL);
393 return handle->length;
396 /* Returns the number of characters per tab stop for HANDLE, or
397 zero if tabs are not to be expanded. Applicable only to
400 handle_get_tab_width (const struct file_handle *handle)
402 assert (handle != NULL);
403 return handle->tab_width;
410 handle_list = ll_create(destroy_file_handle,0);
418 ll_destroy(handle_list);