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
27 #include "file-handle.h"
36 #include "debug-print.h"
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 = avl_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;
125 msg (SE, _("/RECFORM SPANNED is not implemented, as the author doesn't "
126 "know what it is supposed to do. Send the author a note."));
135 fp->mode = FH_MD_CHARACTER;
138 msg (SE, _("/MODE IMAGE is not implemented, as the author doesn't know "
139 "what it is supposed to do. Send the author a note."));
142 fp->mode = FH_MD_BINARY;
145 msg (SE, _("/MODE MULTIPUNCH is not implemented. If you care, "
149 msg (SE, _("/MODE 360 is not implemented. If you care, complain."));
155 fp->name = xstrdup (handle_name);
156 fp->norm_fn = fn_normalize (cmd.s_name);
157 fp->where.filename = fp->fn = cmd.s_name;
158 avl_force_insert (files, fp);
163 free_file_handle (&cmd);
167 /* File handle functions. */
169 /* Sets up some fields in H; caller should fill in
170 H->{NAME,NORM_FN,FN}. */
172 init_file_handle (struct file_handle *h)
174 h->recform = FH_RF_VARIABLE;
175 h->mode = FH_MD_CHARACTER;
180 /* Returns the handle corresponding to FILENAME. Creates the handle
181 if no handle exists for that file. All filenames are normalized
182 first, so different filenames referring to the same file will
183 return the same file handle. */
185 fh_get_handle_by_filename (const char *filename)
187 struct file_handle f, *fp;
193 fn = fn_normalize (filename);
196 /* Create handle name with invalid identifier character to prevent
197 conflicts with handles created with FILE HANDLE. */
198 name = xmalloc (len + 2);
200 strcpy (&name[1], fn);
203 fp = avl_find (files, &f);
206 fp = xmalloc (sizeof *fp);
207 init_file_handle (fp);
210 fp->where.filename = fp->fn = xstrdup (filename);
211 avl_force_insert (files, fp);
221 /* Returns the handle with identifier NAME, if it exists; otherwise
222 reports error to user and returns NULL. */
224 fh_get_handle_by_name (const char name[9])
226 struct file_handle f, *fp;
227 f.name = (char *) name;
228 fp = avl_find (files, &f);
231 msg (SE, _("File handle `%s' has not been previously declared on "
232 "FILE HANDLE."), name);
236 /* Returns the identifier of file HANDLE. If HANDLE was created by
237 referring to a filename (i.e., DATA LIST FILE='yyy' instead of FILE
238 HANDLE XXX='yyy'), returns the filename, enclosed in double quotes.
239 Return value is in a static buffer.
241 Useful for printing error messages about use of file handles. */
243 fh_handle_name (struct file_handle *h)
245 static char *buf = NULL;
255 if (h->name[0] == '*')
257 int len = strlen (h->fn);
259 buf = xmalloc (len + 3);
260 strcpy (&buf[1], h->fn);
261 buf[0] = buf[len + 1] = '"';
268 /* Closes the stdio FILE associated with handle H. Frees internal
269 buffers associated with that file. Does *not* destroy the file
270 handle H. (File handles are permanent during a session.) */
272 fh_close_handle (struct file_handle *h)
277 debug_printf (("Closing %s%s.\n", fh_handle_name (h),
278 h->class == NULL ? " (already closed)" : ""));
286 /* Compares names of file handles A and B. */
288 cmp_file_handle (const void *a, const void *b, void *foo unused)
290 return strcmp (((struct file_handle *) a)->name,
291 ((struct file_handle *) b)->name);
294 /* Initialize the AVL tree of file handles; inserts the "inline file"
299 /* Create AVL tree. */
300 files = avl_create (NULL, cmp_file_handle, NULL);
302 /* Insert inline file. */
303 inline_file = xmalloc (sizeof *inline_file);
304 init_file_handle (inline_file);
305 inline_file->name = "INLINE";
306 inline_file->where.filename
307 = inline_file->fn = inline_file->norm_fn = (char *) _("<Inline File>");
308 inline_file->where.line_number = 0;
309 avl_force_insert (files, inline_file);
312 /* Parses a file handle name, which may be a filename as a string or
313 a file handle name as an identifier. Returns the file handle or
316 fh_parse_file_handle (void)
318 struct file_handle *handle;
321 handle = fh_get_handle_by_name (tokid);
322 else if (token == T_STRING)
323 handle = fh_get_handle_by_filename (ds_value (&tokstr));
326 lex_error (_("expecting a file name or handle"));
337 /* Returns the (normalized) filename associated with file handle H. */
339 fh_handle_filename (struct file_handle * h)
344 /* Returns the width of a logical record on file handle H. */
346 fh_record_width (struct file_handle *h)
348 if (h == inline_file)
350 else if (h->recform == FH_RF_FIXED)