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"
38 struct file_handle *next; /* Next in global list. */
39 char *name; /* File handle identifier. */
40 char *filename; /* Filename as provided by user. */
41 struct file_identity *identity; /* For checking file identity. */
42 struct file_locator where; /* Used for reporting error messages. */
43 enum file_handle_mode mode; /* File mode. */
44 size_t length; /* Length of fixed-format records. */
45 size_t tab_width; /* Tab width, 0=do not expand tabs. */
47 int open_cnt; /* 0=not open, otherwise # of openers. */
48 const char *type; /* If open, type of file. */
49 const char *open_mode; /* "[rw][se]". */
50 void *aux; /* Aux data pointer for owner if any. */
53 static struct file_handle *file_handles;
55 static struct file_handle *create_file_handle (const char *handle_name,
56 const char *filename);
62 tabwidth=integer "x>=0" "%s must be nonnegative";
63 mode=mode:!character/image.
68 static struct file_handle *
69 get_handle_with_name (const char *handle_name)
71 struct file_handle *iter;
73 for (iter = file_handles; iter != NULL; iter = iter->next)
74 if (!strcmp (handle_name, iter->name))
79 static struct file_handle *
80 get_handle_for_filename (const char *filename)
82 struct file_identity *identity;
83 struct file_handle *iter;
85 /* First check for a file with the same identity. */
86 identity = fn_get_identity (filename);
89 for (iter = file_handles; iter != NULL; iter = iter->next)
90 if (iter->identity != NULL
91 && !fn_compare_file_identities (identity, iter->identity))
93 fn_free_identity (identity);
96 fn_free_identity (identity);
99 /* Then check for a file with the same name. */
100 for (iter = file_handles; iter != NULL; iter = iter->next)
101 if (!strcmp (filename, iter->filename))
108 cmd_file_handle (void)
112 struct cmd_file_handle cmd;
113 struct file_handle *handle;
115 if (!lex_force_id ())
117 strcpy (handle_name, tokid);
119 handle = get_handle_with_name (handle_name);
122 msg (SE, _("File handle %s already refers to "
123 "file %s. File handle cannot be redefined within a "
125 tokid, handle->filename);
130 if (!lex_force_match ('/'))
133 if (!parse_file_handle (&cmd))
138 lex_error (_("expecting end of command"));
142 if (cmd.s_name == NULL)
144 msg (SE, _("The FILE HANDLE required subcommand NAME "
149 handle = create_file_handle (handle_name, cmd.s_name);
153 handle->mode = MODE_TEXT;
154 if (cmd.sbc_tabwidth)
155 handle->tab_width = cmd.n_tabwidth[0];
157 handle->tab_width = 4;
160 handle->mode = MODE_BINARY;
161 if (cmd.n_lrecl[0] == NOT_LONG)
163 msg (SE, _("Fixed-length records were specified on /RECFORM, but "
164 "record length was not specified on /LRECL. "
165 "Assuming 1024-character records."));
166 handle->length = 1024;
168 else if (cmd.n_lrecl[0] < 1)
170 msg (SE, _("Record length (%ld) must be at least one byte. "
171 "1-character records will be assumed."), cmd.n_lrecl);
175 handle->length = cmd.n_lrecl[0];
184 free_file_handle (&cmd);
188 /* File handle functions. */
190 /* Creates and returns a new file handle with the given values
191 and defaults for other values. Adds the created file handle
192 to the global list. */
193 static struct file_handle *
194 create_file_handle (const char *handle_name, const char *filename)
196 struct file_handle *handle;
198 /* Create and initialize file handle. */
199 handle = xmalloc (sizeof *handle);
200 handle->next = file_handles;
201 handle->name = xstrdup (handle_name);
202 handle->filename = xstrdup (filename);
203 handle->identity = fn_get_identity (filename);
204 handle->where.filename = handle->filename;
205 handle->where.line_number = 0;
206 handle->mode = MODE_TEXT;
207 handle->length = 1024;
208 handle->tab_width = 4;
209 handle->open_cnt = 0;
211 handle->open_mode = NULL;
213 file_handles = handle;
219 mode_name (const char *mode)
221 assert (mode != NULL);
222 assert (mode[0] == 'r' || mode[0] == 'w');
224 return mode[0] == 'r' ? "reading" : "writing";
228 /* Tries to open FILE with the given TYPE and MODE.
230 TYPE is the sort of file, e.g. "system file". Only one given
231 type of access is allowed on a given file handle at once.
233 MODE combines the read or write mode with the sharing mode.
234 The first character is 'r' for read, 'w' for write. The
235 second character is 's' to permit sharing, 'e' to require
238 Returns the address of a void * that the caller can use for
239 data specific to the file handle if successful, or a null
240 pointer on failure. For exclusive access modes the void *
241 will always be a null pointer at return. In shared access
242 modes the void * will necessarily be null only if no other
245 If successful, references to type and mode are retained, so
246 they should probably be string literals. */
248 fh_open (struct file_handle *h, const char *type, const char *mode)
251 assert (type != NULL);
252 assert (mode != NULL);
253 assert (mode[0] == 'r' || mode[0] == 'w');
254 assert (mode[1] == 's' || mode[1] == 'e');
255 assert (mode[2] == '\0');
257 if (h->open_cnt != 0)
259 if (strcmp (h->type, type))
260 msg (SE, _("Can't open %s as a %s because it is "
261 "already open as a %s"),
262 handle_get_name (h), type, h->type);
263 else if (strcmp (h->open_mode, mode))
264 msg (SE, _("Can't open %s as a %s for %s because it is "
265 "already open for %s"),
266 handle_get_name (h), type,
267 mode_name (mode), mode_name (h->open_mode));
268 else if (h->open_mode[1] == 'e')
269 msg (SE, _("Can't re-open %s as a %s for %s"),
270 handle_get_name (h), type, mode_name (mode));
276 assert (h->aux == NULL);
283 /* Closes file handle H, which must have been open for the
284 specified TYPE and MODE of access provided to fh_open().
285 Returns zero if the file is now closed, nonzero if it is still
286 open due to another reference. */
288 fh_close (struct file_handle *h, const char *type, const char *mode)
291 assert (h->open_cnt > 0);
292 assert (type != NULL);
293 assert (!strcmp (type, h->type));
294 assert (mode != NULL);
295 assert (!strcmp (mode, h->open_mode));
298 if (h->open_cnt == 0)
307 /* Parses a file handle name, which may be a filename as a string or
308 a file handle name as an identifier. Returns the file handle or
313 struct file_handle *handle;
315 if (token != T_ID && token != T_STRING)
317 lex_error (_("expecting a file name or handle name"));
321 /* Check for named handles first, then go by filename. */
324 handle = get_handle_with_name (tokid);
326 handle = get_handle_for_filename (ds_c_str (&tokstr));
329 char *filename = ds_c_str (&tokstr);
330 char *handle_name = xmalloc (strlen (filename) + 3);
331 sprintf (handle_name, "\"%s\"", filename);
332 handle = create_file_handle (handle_name, filename);
341 /* Returns the identifier of file HANDLE. If HANDLE was created
342 by referring to a filename instead of a handle name, returns
343 the filename, enclosed in double quotes. Return value is
344 owned by the file handle.
346 Useful for printing error messages about use of file handles. */
348 handle_get_name (const struct file_handle *handle)
350 assert (handle != NULL);
354 /* Returns the name of the file associated with HANDLE. */
356 handle_get_filename (const struct file_handle *handle)
358 assert (handle != NULL);
359 return handle->filename;
362 /* Returns the mode of HANDLE. */
363 enum file_handle_mode
364 handle_get_mode (const struct file_handle *handle)
366 assert (handle != NULL);
370 /* Returns the width of a logical record on HANDLE. Applicable
371 only to MODE_BINARY files. */
373 handle_get_record_width (const struct file_handle *handle)
375 assert (handle != NULL);
376 return handle->length;
379 /* Returns the number of characters per tab stop for HANDLE, or
380 zero if tabs are not to be expanded. Applicable only to
383 handle_get_tab_width (const struct file_handle *handle)
385 assert (handle != NULL);
386 return handle->tab_width;