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., 51 Franklin Street, Fifth Floor, 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 char open_mode[3]; /* "[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;
214 file_handles = handle;
220 destroy_file_handle(void *fh_, void *aux UNUSED)
222 struct file_handle *fh = fh_;
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, a reference to type is retained, so it should
257 probably be a string literal. */
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))
272 msg (SE, _("Can't open %s as a %s because it is "
273 "already open as a %s"),
274 handle_get_name (h), type, h->type);
277 else if (strcmp (h->open_mode, mode))
279 msg (SE, _("Can't open %s as a %s for %s because it is "
280 "already open for %s"),
281 handle_get_name (h), type,
282 mode_name (mode), mode_name (h->open_mode));
285 else if (h->open_mode[1] == 'e')
287 msg (SE, _("Can't re-open %s as a %s for %s"),
288 handle_get_name (h), type, mode_name (mode));
295 strcpy (h->open_mode, mode);
296 assert (h->aux == NULL);
303 /* Closes file handle H, which must have been open for the
304 specified TYPE and MODE of access provided to fh_open().
305 Returns zero if the file is now closed, nonzero if it is still
306 open due to another reference. */
308 fh_close (struct file_handle *h, const char *type, const char *mode)
311 assert (h->open_cnt > 0);
312 assert (type != NULL);
313 assert (!strcmp (type, h->type));
314 assert (mode != NULL);
315 assert (!strcmp (mode, h->open_mode));
318 if (h->open_cnt == 0)
327 static struct linked_list *handle_list;
330 /* Parses a file handle name, which may be a filename as a string or
331 a file handle name as an identifier. Returns the file handle or
336 struct file_handle *handle;
338 if (token != T_ID && token != T_STRING)
340 lex_error (_("expecting a file name or handle name"));
344 /* Check for named handles first, then go by filename. */
347 handle = get_handle_with_name (tokid);
349 handle = get_handle_for_filename (ds_c_str (&tokstr));
352 char *filename = ds_c_str (&tokstr);
353 char *handle_name = xmalloc (strlen (filename) + 3);
354 sprintf (handle_name, "\"%s\"", filename);
355 handle = create_file_handle (handle_name, filename);
356 ll_push_front(handle_list, handle);
366 /* Returns the identifier of file HANDLE. If HANDLE was created
367 by referring to a filename instead of a handle name, returns
368 the filename, enclosed in double quotes. Return value is
369 owned by the file handle.
371 Useful for printing error messages about use of file handles. */
373 handle_get_name (const struct file_handle *handle)
375 assert (handle != NULL);
379 /* Returns the name of the file associated with HANDLE. */
381 handle_get_filename (const struct file_handle *handle)
383 assert (handle != NULL);
384 return handle->filename;
387 /* Returns the mode of HANDLE. */
388 enum file_handle_mode
389 handle_get_mode (const struct file_handle *handle)
391 assert (handle != NULL);
395 /* Returns the width of a logical record on HANDLE. Applicable
396 only to MODE_BINARY files. */
398 handle_get_record_width (const struct file_handle *handle)
400 assert (handle != NULL);
401 return handle->length;
404 /* Returns the number of characters per tab stop for HANDLE, or
405 zero if tabs are not to be expanded. Applicable only to
408 handle_get_tab_width (const struct file_handle *handle)
410 assert (handle != NULL);
411 return handle->tab_width;
418 handle_list = ll_create(destroy_file_handle,0);
426 ll_destroy(handle_list);