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"
37 /*#define DEBUGGING 1*/
38 #include "debug-print.h"
41 struct file_handle *inline_file;
43 static void init_file_handle (struct file_handle * handle);
48 recform=recform:fixed/!variable/spanned;
50 mode=mode:!character/image/binary/multipunch/_360.
56 cmd_file_handle (void)
59 char *handle_name_p = handle_name;
61 struct cmd_file_handle cmd;
62 struct file_handle *fp;
67 strcpy (handle_name, tokid);
71 fp = avl_find (files, &handle_name_p);
74 msg (SE, _("File handle %s had already been defined to refer to "
75 "file %s. It is not possible to redefine a file "
76 "handle within a session."),
82 if (!lex_force_match ('/'))
85 if (!parse_file_handle (&cmd))
90 lex_error (_("expecting end of command"));
94 if (cmd.s_name == NULL)
96 msg (SE, _("The FILE HANDLE required subcommand NAME "
101 fp = xmalloc (sizeof *fp);
102 init_file_handle (fp);
107 if (cmd.n_lrecl == NOT_LONG)
109 msg (SE, _("Fixed length records were specified on /RECFORM, but "
110 "record length was not specified on /LRECL. 80-character "
111 "records will be assumed."));
114 else if (cmd.n_lrecl < 1)
116 msg (SE, _("Record length (%ld) must be at least one byte. "
117 "80-character records will be assumed."), cmd.n_lrecl);
120 fp->recform = FH_RF_FIXED;
121 fp->lrecl = cmd.n_lrecl;
124 fp->recform = FH_RF_VARIABLE;
127 msg (SE, _("/RECFORM SPANNED is not implemented, as the author doesn't "
128 "know what it is supposed to do. Send the author a note."));
137 fp->mode = FH_MD_CHARACTER;
140 msg (SE, _("/MODE IMAGE is not implemented, as the author doesn't know "
141 "what it is supposed to do. Send the author a note."));
144 fp->mode = FH_MD_BINARY;
147 msg (SE, _("/MODE MULTIPUNCH is not implemented. If you care, "
151 msg (SE, _("/MODE 360 is not implemented. If you care, complain."));
157 fp->name = xstrdup (handle_name);
158 fp->norm_fn = fn_normalize (cmd.s_name);
159 fp->where.filename = fp->fn = cmd.s_name;
160 avl_force_insert (files, fp);
165 free_file_handle (&cmd);
169 /* File handle functions. */
171 /* Sets up some fields in H; caller should fill in
172 H->{NAME,NORM_FN,FN}. */
174 init_file_handle (struct file_handle *h)
176 h->recform = FH_RF_VARIABLE;
177 h->mode = FH_MD_CHARACTER;
182 /* Returns the handle corresponding to FILENAME. Creates the handle
183 if no handle exists for that file. All filenames are normalized
184 first, so different filenames referring to the same file will
185 return the same file handle. */
187 fh_get_handle_by_filename (const char *filename)
189 struct file_handle f, *fp;
195 fn = fn_normalize (filename);
198 /* Create handle name with invalid identifier character to prevent
199 conflicts with handles created with FILE HANDLE. */
200 name = xmalloc (len + 2);
202 strcpy (&name[1], fn);
205 fp = avl_find (files, &f);
208 fp = xmalloc (sizeof *fp);
209 init_file_handle (fp);
212 fp->where.filename = fp->fn = xstrdup (filename);
213 avl_force_insert (files, fp);
223 /* Returns the handle with identifier NAME, if it exists; otherwise
224 reports error to user and returns NULL. */
226 fh_get_handle_by_name (const char name[9])
228 struct file_handle f, *fp;
229 f.name = (char *) name;
230 fp = avl_find (files, &f);
233 msg (SE, _("File handle `%s' has not been previously declared on "
234 "FILE HANDLE."), name);
238 /* Returns the identifier of file HANDLE. If HANDLE was created by
239 referring to a filename (i.e., DATA LIST FILE='yyy' instead of FILE
240 HANDLE XXX='yyy'), returns the filename, enclosed in double quotes.
241 Return value is in a static buffer.
243 Useful for printing error messages about use of file handles. */
245 fh_handle_name (struct file_handle *h)
247 static char *buf = NULL;
257 if (h->name[0] == '*')
259 int len = strlen (h->fn);
261 buf = xmalloc (len + 3);
262 strcpy (&buf[1], h->fn);
263 buf[0] = buf[len + 1] = '"';
270 /* Closes the stdio FILE associated with handle H. Frees internal
271 buffers associated with that file. Does *not* destroy the file
272 handle H. (File handles are permanent during a session.) */
274 fh_close_handle (struct file_handle *h)
279 debug_printf (("Closing %s%s.\n", fh_handle_name (h),
280 h->class == NULL ? " (already closed)" : ""));
288 /* Compares names of file handles A and B. */
290 cmp_file_handle (const void *a, const void *b, void *foo unused)
292 return strcmp (((struct file_handle *) a)->name,
293 ((struct file_handle *) b)->name);
296 /* Initialize the AVL tree of file handles; inserts the "inline file"
301 /* Create AVL tree. */
302 files = avl_create (NULL, cmp_file_handle, NULL);
304 /* Insert inline file. */
305 inline_file = xmalloc (sizeof *inline_file);
306 init_file_handle (inline_file);
307 inline_file->name = "INLINE";
308 inline_file->where.filename
309 = inline_file->fn = inline_file->norm_fn = (char *) _("<Inline File>");
310 inline_file->where.line_number = 0;
311 avl_force_insert (files, inline_file);
314 /* Parses a file handle name, which may be a filename as a string or
315 a file handle name as an identifier. Returns the file handle or
318 fh_parse_file_handle (void)
320 struct file_handle *handle;
323 handle = fh_get_handle_by_name (tokid);
324 else if (token == T_STRING)
325 handle = fh_get_handle_by_filename (ds_value (&tokstr));
328 lex_error (_("expecting a file name or handle"));
339 /* Returns the (normalized) filename associated with file handle H. */
341 fh_handle_filename (struct file_handle * h)
346 /* Returns the width of a logical record on file handle H. */
348 fh_record_width (struct file_handle *h)
350 if (h == inline_file)
352 else if (h->recform == FH_RF_FIXED)