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"
36 #include "debug-print.h"
38 static struct hsh_table *files;
39 struct file_handle *inline_file;
41 static void init_file_handle (struct file_handle * handle);
46 recform=recform:fixed/!variable/spanned;
48 mode=mode:!character/image/binary/multipunch/_360.
54 cmd_file_handle (void)
57 char *handle_name_p = handle_name;
59 struct cmd_file_handle cmd;
60 struct file_handle *fp;
65 strcpy (handle_name, tokid);
69 fp = hsh_find (files, &handle_name_p);
72 msg (SE, _("File handle %s had already been defined to refer to "
73 "file %s. It is not possible to redefine a file "
74 "handle within a session."),
80 if (!lex_force_match ('/'))
83 if (!parse_file_handle (&cmd))
88 lex_error (_("expecting end of command"));
92 if (cmd.s_name == NULL)
94 msg (SE, _("The FILE HANDLE required subcommand NAME "
99 fp = xmalloc (sizeof *fp);
100 init_file_handle (fp);
105 if (cmd.n_lrecl == NOT_LONG)
107 msg (SE, _("Fixed length records were specified on /RECFORM, but "
108 "record length was not specified on /LRECL. 80-character "
109 "records will be assumed."));
112 else if (cmd.n_lrecl < 1)
114 msg (SE, _("Record length (%ld) must be at least one byte. "
115 "80-character records will be assumed."), cmd.n_lrecl);
118 fp->recform = FH_RF_FIXED;
119 fp->lrecl = cmd.n_lrecl;
122 fp->recform = FH_RF_VARIABLE;
126 _("%s is not implemented, as the author doesn't know what it is supposed to do. Send a note to %s.") ,
127 "/RECFORM SPANNED",PACKAGE_BUGREPORT);
136 fp->mode = FH_MD_CHARACTER;
140 _("%s is not implemented, as the author doesn't know what it is supposed to do. Send a note to %s.") ,
141 "/MODE IMAGE",PACKAGE_BUGREPORT);
144 fp->mode = FH_MD_BINARY;
147 msg (SE, _("%s is not implemented. If you care, complain."),"/MODE MULTIPUNCH");
150 msg (SE, _("%s is not implemented. If you care, complain."),"/MODE 360");
156 fp->name = xstrdup (handle_name);
157 fp->norm_fn = fn_normalize (cmd.s_name);
158 fp->where.filename = fp->fn = cmd.s_name;
159 hsh_force_insert (files, fp);
164 free_file_handle (&cmd);
168 /* File handle functions. */
170 /* Sets up some fields in H; caller should fill in
171 H->{NAME,NORM_FN,FN}. */
173 init_file_handle (struct file_handle *h)
175 h->recform = FH_RF_VARIABLE;
176 h->mode = FH_MD_CHARACTER;
181 /* Returns the handle corresponding to FILENAME. Creates the handle
182 if no handle exists for that file. All filenames are normalized
183 first, so different filenames referring to the same file will
184 return the same file handle. */
186 fh_get_handle_by_filename (const char *filename)
188 struct file_handle f, *fp;
194 fn = fn_normalize (filename);
197 /* Create handle name with invalid identifier character to prevent
198 conflicts with handles created with FILE HANDLE. */
199 name = xmalloc (len + 2);
201 strcpy (&name[1], fn);
204 fp = hsh_find (files, &f);
207 fp = xmalloc (sizeof *fp);
208 init_file_handle (fp);
211 fp->where.filename = fp->fn = xstrdup (filename);
212 hsh_force_insert (files, fp);
222 /* Returns the handle with identifier NAME, if it exists; otherwise
223 reports error to user and returns NULL. */
225 fh_get_handle_by_name (const char name[9])
227 struct file_handle f, *fp;
228 f.name = (char *) name;
229 fp = hsh_find (files, &f);
232 msg (SE, _("File handle `%s' has not been previously declared on "
233 "FILE HANDLE."), name);
237 /* Returns the identifier of file HANDLE. If HANDLE was created by
238 referring to a filename (i.e., DATA LIST FILE='yyy' instead of FILE
239 HANDLE XXX='yyy'), returns the filename, enclosed in double quotes.
240 Return value is in a static buffer.
242 Useful for printing error messages about use of file handles. */
244 fh_handle_name (const struct file_handle *h)
246 static char *buf = NULL;
256 if (h->name[0] == '*')
258 int len = strlen (h->fn);
260 buf = xmalloc (len + 3);
261 strcpy (&buf[1], h->fn);
262 buf[0] = buf[len + 1] = '"';
269 /* Closes the stdio FILE associated with handle H. Frees internal
270 buffers associated with that file. Does *not* destroy the file
271 handle H. (File handles are permanent during a session.) */
273 fh_close_handle (struct file_handle *h)
278 debug_printf (("Closing %s%s.\n", fh_handle_name (h),
279 h->class == NULL ? " (already closed)" : ""));
287 /* Hashes the name of file handle H. */
289 hash_file_handle (const void *handle_, void *param UNUSED)
291 const struct file_handle *handle = handle_;
293 return hsh_hash_string (handle->name);
296 /* Compares names of file handles A and B. */
298 cmp_file_handle (const void *a_, const void *b_, void *foo UNUSED)
300 const struct file_handle *a = a_;
301 const struct file_handle *b = b_;
303 return strcmp (a->name, b->name);
306 /* Initialize the hash of file handles; inserts the "inline file"
312 files = hsh_create (4, cmp_file_handle, hash_file_handle, NULL, NULL);
314 /* Insert inline file. */
315 inline_file = xmalloc (sizeof *inline_file);
316 init_file_handle (inline_file);
317 inline_file->name = "INLINE";
318 inline_file->where.filename
319 = inline_file->fn = inline_file->norm_fn = (char *) _("<Inline File>");
320 inline_file->where.line_number = 0;
321 hsh_force_insert (files, inline_file);
324 /* Parses a file handle name, which may be a filename as a string or
325 a file handle name as an identifier. Returns the file handle or
328 fh_parse_file_handle (void)
330 struct file_handle *handle;
333 handle = fh_get_handle_by_name (tokid);
334 else if (token == T_STRING)
335 handle = fh_get_handle_by_filename (ds_value (&tokstr));
338 lex_error (_("expecting a file name or handle"));
349 /* Returns the (normalized) filename associated with file handle H. */
351 fh_handle_filename (struct file_handle * h)
356 /* Returns the width of a logical record on file handle H. */
358 fh_record_width (struct file_handle *h)
360 if (h == inline_file)
362 else if (h->recform == FH_RF_FIXED)