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(void *fh_, void *aux UNUSED)
223 struct file_handle *fh = fh_;
226 fn_free_identity (fh->identity);
231 mode_name (const char *mode)
233 assert (mode != NULL);
234 assert (mode[0] == 'r' || mode[0] == 'w');
236 return mode[0] == 'r' ? "reading" : "writing";
240 /* Tries to open FILE with the given TYPE and MODE.
242 TYPE is the sort of file, e.g. "system file". Only one given
243 type of access is allowed on a given file handle at once.
245 MODE combines the read or write mode with the sharing mode.
246 The first character is 'r' for read, 'w' for write. The
247 second character is 's' to permit sharing, 'e' to require
250 Returns the address of a void * that the caller can use for
251 data specific to the file handle if successful, or a null
252 pointer on failure. For exclusive access modes the void *
253 will always be a null pointer at return. In shared access
254 modes the void * will necessarily be null only if no other
257 If successful, references to type and mode are retained, so
258 they should probably be string literals. */
260 fh_open (struct file_handle *h, const char *type, const char *mode)
263 assert (type != NULL);
264 assert (mode != NULL);
265 assert (mode[0] == 'r' || mode[0] == 'w');
266 assert (mode[1] == 's' || mode[1] == 'e');
267 assert (mode[2] == '\0');
269 if (h->open_cnt != 0)
271 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);
275 else if (strcmp (h->open_mode, mode))
276 msg (SE, _("Can't open %s as a %s for %s because it is "
277 "already open for %s"),
278 handle_get_name (h), type,
279 mode_name (mode), mode_name (h->open_mode));
280 else if (h->open_mode[1] == 'e')
281 msg (SE, _("Can't re-open %s as a %s for %s"),
282 handle_get_name (h), type, mode_name (mode));
288 assert (h->aux == NULL);
295 /* Closes file handle H, which must have been open for the
296 specified TYPE and MODE of access provided to fh_open().
297 Returns zero if the file is now closed, nonzero if it is still
298 open due to another reference. */
300 fh_close (struct file_handle *h, const char *type, const char *mode)
303 assert (h->open_cnt > 0);
304 assert (type != NULL);
305 assert (!strcmp (type, h->type));
306 assert (mode != NULL);
307 assert (!strcmp (mode, h->open_mode));
310 if (h->open_cnt == 0)
320 static struct linked_list *handle_list;
323 /* Parses a file handle name, which may be a filename as a string or
324 a file handle name as an identifier. Returns the file handle or
329 struct file_handle *handle;
331 if (token != T_ID && token != T_STRING)
333 lex_error (_("expecting a file name or handle name"));
337 /* Check for named handles first, then go by filename. */
340 handle = get_handle_with_name (tokid);
342 handle = get_handle_for_filename (ds_c_str (&tokstr));
345 char *filename = ds_c_str (&tokstr);
346 char *handle_name = xmalloc (strlen (filename) + 3);
347 sprintf (handle_name, "\"%s\"", filename);
348 handle = create_file_handle (handle_name, filename);
349 ll_push_front(handle_list, handle);
359 /* Returns the identifier of file HANDLE. If HANDLE was created
360 by referring to a filename instead of a handle name, returns
361 the filename, enclosed in double quotes. Return value is
362 owned by the file handle.
364 Useful for printing error messages about use of file handles. */
366 handle_get_name (const struct file_handle *handle)
368 assert (handle != NULL);
372 /* Returns the name of the file associated with HANDLE. */
374 handle_get_filename (const struct file_handle *handle)
376 assert (handle != NULL);
377 return handle->filename;
380 /* Returns the mode of HANDLE. */
381 enum file_handle_mode
382 handle_get_mode (const struct file_handle *handle)
384 assert (handle != NULL);
388 /* Returns the width of a logical record on HANDLE. Applicable
389 only to MODE_BINARY files. */
391 handle_get_record_width (const struct file_handle *handle)
393 assert (handle != NULL);
394 return handle->length;
397 /* Returns the number of characters per tab stop for HANDLE, or
398 zero if tabs are not to be expanded. Applicable only to
401 handle_get_tab_width (const struct file_handle *handle)
403 assert (handle != NULL);
404 return handle->tab_width;
411 handle_list = ll_create(destroy_file_handle,0);
419 ll_destroy(handle_list);