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"
36 #define _(msgid) gettext (msgid)
43 struct file_handle *next; /* Next in global list. */
44 char *name; /* File handle identifier. */
45 char *filename; /* Filename as provided by user. */
46 struct file_identity *identity; /* For checking file identity. */
47 struct file_locator where; /* Used for reporting error messages. */
48 enum file_handle_mode mode; /* File mode. */
49 size_t length; /* Length of fixed-format records. */
50 size_t tab_width; /* Tab width, 0=do not expand tabs. */
52 int open_cnt; /* 0=not open, otherwise # of openers. */
53 const char *type; /* If open, type of file. */
54 char open_mode[3]; /* "[rw][se]". */
55 void *aux; /* Aux data pointer for owner if any. */
58 static struct file_handle *file_handles;
60 static struct file_handle *create_file_handle (const char *handle_name,
61 const char *filename);
67 tabwidth=integer "x>=0" "%s must be nonnegative";
68 mode=mode:!character/image.
73 static struct file_handle *
74 get_handle_with_name (const char *handle_name)
76 struct file_handle *iter;
78 for (iter = file_handles; iter != NULL; iter = iter->next)
79 if (!strcasecmp (handle_name, iter->name))
84 static struct file_handle *
85 get_handle_for_filename (const char *filename)
87 struct file_identity *identity;
88 struct file_handle *iter;
90 /* First check for a file with the same identity. */
91 identity = fn_get_identity (filename);
94 for (iter = file_handles; iter != NULL; iter = iter->next)
95 if (iter->identity != NULL
96 && !fn_compare_file_identities (identity, iter->identity))
98 fn_free_identity (identity);
101 fn_free_identity (identity);
104 /* Then check for a file with the same name. */
105 for (iter = file_handles; iter != NULL; iter = iter->next)
106 if (!strcmp (filename, iter->filename))
113 cmd_file_handle (void)
115 char handle_name[LONG_NAME_LEN + 1];
117 struct cmd_file_handle cmd;
118 struct file_handle *handle;
120 if (!lex_force_id ())
122 str_copy_trunc (handle_name, sizeof handle_name, tokid);
124 handle = get_handle_with_name (handle_name);
127 msg (SE, _("File handle %s already refers to file %s. "
128 "File handles cannot be redefined within a session."),
129 handle_name, handle->filename);
134 if (!lex_force_match ('/'))
137 if (!parse_file_handle (&cmd))
142 lex_error (_("expecting end of command"));
146 if (cmd.s_name == NULL)
148 msg (SE, _("The FILE HANDLE required subcommand NAME "
153 handle = create_file_handle (handle_name, cmd.s_name);
157 handle->mode = MODE_TEXT;
158 if (cmd.sbc_tabwidth)
159 handle->tab_width = cmd.n_tabwidth[0];
161 handle->tab_width = 4;
164 handle->mode = MODE_BINARY;
165 if (cmd.n_lrecl[0] == NOT_LONG)
167 msg (SE, _("Fixed-length records were specified on /RECFORM, but "
168 "record length was not specified on /LRECL. "
169 "Assuming 1024-character records."));
170 handle->length = 1024;
172 else if (cmd.n_lrecl[0] < 1)
174 msg (SE, _("Record length (%ld) must be at least one byte. "
175 "1-character records will be assumed."), cmd.n_lrecl[0]);
179 handle->length = cmd.n_lrecl[0];
188 free_file_handle (&cmd);
192 /* File handle functions. */
194 /* Creates and returns a new file handle with the given values
195 and defaults for other values. Adds the created file handle
196 to the global list. */
197 static struct file_handle *
198 create_file_handle (const char *handle_name, const char *filename)
200 struct file_handle *handle;
202 /* Create and initialize file handle. */
203 handle = xmalloc (sizeof *handle);
204 handle->next = file_handles;
205 handle->name = xstrdup (handle_name);
206 handle->filename = xstrdup (filename);
207 handle->identity = fn_get_identity (filename);
208 handle->where.filename = handle->filename;
209 handle->where.line_number = 0;
210 handle->mode = MODE_TEXT;
211 handle->length = 1024;
212 handle->tab_width = 4;
213 handle->open_cnt = 0;
216 file_handles = handle;
222 destroy_file_handle(void *fh_, void *aux UNUSED)
224 struct file_handle *fh = fh_;
227 fn_free_identity (fh->identity);
232 mode_name (const char *mode)
234 assert (mode != NULL);
235 assert (mode[0] == 'r' || mode[0] == 'w');
237 return mode[0] == 'r' ? "reading" : "writing";
241 /* Tries to open handle H with the given TYPE and MODE.
243 TYPE is the sort of file, e.g. "system file". Only one given
244 type of access is allowed on a given file handle at once.
246 MODE combines the read or write mode with the sharing mode.
247 The first character is 'r' for read, 'w' for write. The
248 second character is 's' to permit sharing, 'e' to require
251 Returns the address of a void * that the caller can use for
252 data specific to the file handle if successful, or a null
253 pointer on failure. For exclusive access modes the void *
254 will always be a null pointer at return. In shared access
255 modes the void * will necessarily be null only if no other
258 If successful, a reference to type is retained, so it should
259 probably be a string literal. */
261 fh_open (struct file_handle *h, const char *type, const char *mode)
264 assert (type != NULL);
265 assert (mode != NULL);
266 assert (mode[0] == 'r' || mode[0] == 'w');
267 assert (mode[1] == 's' || mode[1] == 'e');
268 assert (mode[2] == '\0');
270 if (h->open_cnt != 0)
272 if (strcmp (h->type, type))
274 msg (SE, _("Can't open %s as a %s because it is "
275 "already open as a %s"),
276 handle_get_name (h), type, h->type);
279 else if (strcmp (h->open_mode, mode))
281 msg (SE, _("Can't open %s as a %s for %s because it is "
282 "already open for %s"),
283 handle_get_name (h), type,
284 mode_name (mode), mode_name (h->open_mode));
287 else if (h->open_mode[1] == 'e')
289 msg (SE, _("Can't re-open %s as a %s for %s"),
290 handle_get_name (h), type, mode_name (mode));
297 strcpy (h->open_mode, mode);
298 assert (h->aux == NULL);
305 /* Closes file handle H, which must have been open for the
306 specified TYPE and MODE of access provided to fh_open().
307 Returns zero if the file is now closed, nonzero if it is still
308 open due to another reference. */
310 fh_close (struct file_handle *h, const char *type, const char *mode)
313 assert (h->open_cnt > 0);
314 assert (type != NULL);
315 assert (!strcmp (type, h->type));
316 assert (mode != NULL);
317 assert (!strcmp (mode, h->open_mode));
320 if (h->open_cnt == 0)
329 static struct linked_list *handle_list;
332 /* Parses a file handle name, which may be a filename as a string or
333 a file handle name as an identifier. Returns the file handle or
338 struct file_handle *handle;
340 if (token != T_ID && token != T_STRING)
342 lex_error (_("expecting a file name or handle name"));
346 /* Check for named handles first, then go by filename. */
349 handle = get_handle_with_name (tokid);
351 handle = get_handle_for_filename (ds_c_str (&tokstr));
354 char *filename = ds_c_str (&tokstr);
355 char *handle_name = xmalloc (strlen (filename) + 3);
356 sprintf (handle_name, "\"%s\"", filename);
357 handle = create_file_handle (handle_name, filename);
358 ll_push_front(handle_list, handle);
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 handle_get_name (const struct file_handle *handle)
377 assert (handle != NULL);
381 /* Returns the name of the file associated with HANDLE. */
383 handle_get_filename (const struct file_handle *handle)
385 assert (handle != NULL);
386 return handle->filename;
389 /* Returns the mode of HANDLE. */
390 enum file_handle_mode
391 handle_get_mode (const struct file_handle *handle)
393 assert (handle != NULL);
397 /* Returns the width of a logical record on HANDLE. */
399 handle_get_record_width (const struct file_handle *handle)
401 assert (handle != NULL);
402 return handle->length;
405 /* Returns the number of characters per tab stop for HANDLE, or
406 zero if tabs are not to be expanded. Applicable only to
409 handle_get_tab_width (const struct file_handle *handle)
411 assert (handle != NULL);
412 return handle->tab_width;
419 handle_list = ll_create(destroy_file_handle,0);
427 ll_destroy(handle_list);