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 (!strcasecmp (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)
112 char handle_name[LONG_NAME_LEN + 1];
114 struct cmd_file_handle cmd;
115 struct file_handle *handle;
117 if (!lex_force_id ())
119 st_trim_copy (handle_name, tokid, sizeof handle_name);
121 handle = get_handle_with_name (handle_name);
124 msg (SE, _("File handle %s already refers to file %s. "
125 "File handles cannot be redefined within a session."),
126 handle_name, handle->filename);
131 if (!lex_force_match ('/'))
134 if (!parse_file_handle (&cmd))
139 lex_error (_("expecting end of command"));
143 if (cmd.s_name == NULL)
145 msg (SE, _("The FILE HANDLE required subcommand NAME "
150 handle = create_file_handle (handle_name, cmd.s_name);
154 handle->mode = MODE_TEXT;
155 if (cmd.sbc_tabwidth)
156 handle->tab_width = cmd.n_tabwidth[0];
158 handle->tab_width = 4;
161 handle->mode = MODE_BINARY;
162 if (cmd.n_lrecl[0] == NOT_LONG)
164 msg (SE, _("Fixed-length records were specified on /RECFORM, but "
165 "record length was not specified on /LRECL. "
166 "Assuming 1024-character records."));
167 handle->length = 1024;
169 else if (cmd.n_lrecl[0] < 1)
171 msg (SE, _("Record length (%ld) must be at least one byte. "
172 "1-character records will be assumed."), cmd.n_lrecl);
176 handle->length = cmd.n_lrecl[0];
185 free_file_handle (&cmd);
189 /* File handle functions. */
191 /* Creates and returns a new file handle with the given values
192 and defaults for other values. Adds the created file handle
193 to the global list. */
194 static struct file_handle *
195 create_file_handle (const char *handle_name, const char *filename)
197 struct file_handle *handle;
199 /* Create and initialize file handle. */
200 handle = xmalloc (sizeof *handle);
201 handle->next = file_handles;
202 handle->name = xstrdup (handle_name);
203 handle->filename = xstrdup (filename);
204 handle->identity = fn_get_identity (filename);
205 handle->where.filename = handle->filename;
206 handle->where.line_number = 0;
207 handle->mode = MODE_TEXT;
208 handle->length = 1024;
209 handle->tab_width = 4;
210 handle->open_cnt = 0;
213 file_handles = handle;
219 destroy_file_handle(void *fh_, void *aux UNUSED)
221 struct file_handle *fh = fh_;
224 fn_free_identity (fh->identity);
229 mode_name (const char *mode)
231 assert (mode != NULL);
232 assert (mode[0] == 'r' || mode[0] == 'w');
234 return mode[0] == 'r' ? "reading" : "writing";
238 /* Tries to open FILE with the given TYPE and MODE.
240 TYPE is the sort of file, e.g. "system file". Only one given
241 type of access is allowed on a given file handle at once.
243 MODE combines the read or write mode with the sharing mode.
244 The first character is 'r' for read, 'w' for write. The
245 second character is 's' to permit sharing, 'e' to require
248 Returns the address of a void * that the caller can use for
249 data specific to the file handle if successful, or a null
250 pointer on failure. For exclusive access modes the void *
251 will always be a null pointer at return. In shared access
252 modes the void * will necessarily be null only if no other
255 If successful, a reference to type is retained, so it should
256 probably be a string literal. */
258 fh_open (struct file_handle *h, const char *type, const char *mode)
261 assert (type != NULL);
262 assert (mode != NULL);
263 assert (mode[0] == 'r' || mode[0] == 'w');
264 assert (mode[1] == 's' || mode[1] == 'e');
265 assert (mode[2] == '\0');
267 if (h->open_cnt != 0)
269 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);
276 else if (strcmp (h->open_mode, mode))
278 msg (SE, _("Can't open %s as a %s for %s because it is "
279 "already open for %s"),
280 handle_get_name (h), type,
281 mode_name (mode), mode_name (h->open_mode));
284 else if (h->open_mode[1] == 'e')
286 msg (SE, _("Can't re-open %s as a %s for %s"),
287 handle_get_name (h), type, mode_name (mode));
294 strcpy (h->open_mode, mode);
295 assert (h->aux == NULL);
302 /* Closes file handle H, which must have been open for the
303 specified TYPE and MODE of access provided to fh_open().
304 Returns zero if the file is now closed, nonzero if it is still
305 open due to another reference. */
307 fh_close (struct file_handle *h, const char *type, const char *mode)
310 assert (h->open_cnt > 0);
311 assert (type != NULL);
312 assert (!strcmp (type, h->type));
313 assert (mode != NULL);
314 assert (!strcmp (mode, h->open_mode));
317 if (h->open_cnt == 0)
326 static struct linked_list *handle_list;
329 /* Parses a file handle name, which may be a filename as a string or
330 a file handle name as an identifier. Returns the file handle or
335 struct file_handle *handle;
337 if (token != T_ID && token != T_STRING)
339 lex_error (_("expecting a file name or handle name"));
343 /* Check for named handles first, then go by filename. */
346 handle = get_handle_with_name (tokid);
348 handle = get_handle_for_filename (ds_c_str (&tokstr));
351 char *filename = ds_c_str (&tokstr);
352 char *handle_name = xmalloc (strlen (filename) + 3);
353 sprintf (handle_name, "\"%s\"", filename);
354 handle = create_file_handle (handle_name, filename);
355 ll_push_front(handle_list, handle);
365 /* Returns the identifier of file HANDLE. If HANDLE was created
366 by referring to a filename instead of a handle name, returns
367 the filename, enclosed in double quotes. Return value is
368 owned by the file handle.
370 Useful for printing error messages about use of file handles. */
372 handle_get_name (const struct file_handle *handle)
374 assert (handle != NULL);
378 /* Returns the name of the file associated with HANDLE. */
380 handle_get_filename (const struct file_handle *handle)
382 assert (handle != NULL);
383 return handle->filename;
386 /* Returns the mode of HANDLE. */
387 enum file_handle_mode
388 handle_get_mode (const struct file_handle *handle)
390 assert (handle != NULL);
394 /* Returns the width of a logical record on HANDLE. Applicable
395 only to MODE_BINARY files. */
397 handle_get_record_width (const struct file_handle *handle)
399 assert (handle != NULL);
400 return handle->length;
403 /* Returns the number of characters per tab stop for HANDLE, or
404 zero if tabs are not to be expanded. Applicable only to
407 handle_get_tab_width (const struct file_handle *handle)
409 assert (handle != NULL);
410 return handle->tab_width;
417 handle_list = ll_create(destroy_file_handle,0);
425 ll_destroy(handle_list);