/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include <config.h>
#include "file-handle.h"
-#include <assert.h>
+#include "error.h"
#include <errno.h>
#include <stdlib.h>
#include "alloc.h"
#include "filename.h"
#include "command.h"
-#include "hash.h"
#include "lexer.h"
-#include "getline.h"
+#include "getl.h"
#include "error.h"
#include "magic.h"
+#include "str.h"
#include "var.h"
-/* (headers) */
+#include "linked-list.h"
+#include "file-handle-def.h"
-#include "debug-print.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
-static struct hsh_table *files;
-struct file_handle *inline_file;
+/* (headers) */
-static void init_file_handle (struct file_handle * handle);
/* (specification)
"FILE HANDLE" (fh_):
name=string;
- recform=recform:fixed/!variable/spanned;
lrecl=integer;
- mode=mode:!character/image/binary/multipunch/_360.
+ tabwidth=integer "x>=0" "%s must be nonnegative";
+ mode=mode:!character/image/scratch.
*/
/* (declarations) */
/* (functions) */
int
cmd_file_handle (void)
{
- char handle_name[9];
- char *handle_name_p = handle_name;
+ char handle_name[LONG_NAME_LEN + 1];
+ struct fh_properties properties = *fh_default_properties ();
struct cmd_file_handle cmd;
- struct file_handle *fp;
+ struct file_handle *handle;
- lex_get ();
if (!lex_force_id ())
return CMD_FAILURE;
- strcpy (handle_name, tokid);
+ str_copy_trunc (handle_name, sizeof handle_name, tokid);
- fp = NULL;
- if (files)
- fp = hsh_find (files, &handle_name_p);
- if (fp)
+ handle = fh_from_name (handle_name);
+ if (handle != NULL)
{
- msg (SE, _("File handle %s had already been defined to refer to "
- "file %s. It is not possible to redefine a file "
- "handle within a session."),
- tokid, fp->fn);
+ msg (SE, _("File handle %s is already defined. "
+ "Use CLOSE FILE HANDLE before redefining a file handle."),
+ handle_name);
return CMD_FAILURE;
}
if (!parse_file_handle (&cmd))
return CMD_FAILURE;
- if (token != '.')
- {
- lex_error (_("expecting end of command"));
- goto lossage;
- }
+ if (lex_end_of_command () != CMD_SUCCESS)
+ goto lossage;
- if (cmd.s_name == NULL)
+ if (cmd.s_name == NULL && cmd.mode != FH_SCRATCH)
{
- msg (SE, _("The FILE HANDLE required subcommand NAME "
- "is not present."));
+ lex_sbc_missing ("NAME");
goto lossage;
}
- fp = xmalloc (sizeof *fp);
- init_file_handle (fp);
-
- switch (cmd.recform)
- {
- case FH_FIXED:
- if (cmd.n_lrecl == NOT_LONG)
- {
- msg (SE, _("Fixed length records were specified on /RECFORM, but "
- "record length was not specified on /LRECL. 80-character "
- "records will be assumed."));
- cmd.n_lrecl = 80;
- }
- else if (cmd.n_lrecl < 1)
- {
- msg (SE, _("Record length (%ld) must be at least one byte. "
- "80-character records will be assumed."), cmd.n_lrecl);
- cmd.n_lrecl = 80;
- }
- fp->recform = FH_RF_FIXED;
- fp->lrecl = cmd.n_lrecl;
- break;
- case FH_VARIABLE:
- fp->recform = FH_RF_VARIABLE;
- break;
- case FH_SPANNED:
- msg (SE,
- _("%s is not implemented, as the author doesn't know what it is supposed to do. Send a note to %s.") ,
- "/RECFORM SPANNED",PACKAGE_BUGREPORT);
- break;
- default:
- assert (0);
- }
-
switch (cmd.mode)
{
case FH_CHARACTER:
- fp->mode = FH_MD_CHARACTER;
+ properties.mode = FH_MODE_TEXT;
+ if (cmd.sbc_tabwidth)
+ properties.tab_width = cmd.n_tabwidth[0];
break;
case FH_IMAGE:
- msg (SE,
- _("%s is not implemented, as the author doesn't know what it is supposed to do. Send a note to %s.") ,
- "/MODE IMAGE",PACKAGE_BUGREPORT);
- break;
- case FH_BINARY:
- fp->mode = FH_MD_BINARY;
- break;
- case FH_MULTIPUNCH:
- msg (SE, _("%s is not implemented. If you care, complain."),"/MODE MULTIPUNCH");
- break;
- case FH__360:
- msg (SE, _("%s is not implemented. If you care, complain."),"/MODE 360");
+ properties.mode = FH_MODE_BINARY;
+ if (cmd.n_lrecl[0] == NOT_LONG)
+ msg (SE, _("Fixed-length records were specified on /RECFORM, but "
+ "record length was not specified on /LRECL. "
+ "Assuming %d-character records."),
+ properties.record_width);
+ else if (cmd.n_lrecl[0] < 1)
+ msg (SE, _("Record length (%ld) must be at least one byte. "
+ "Assuming %d-character records."),
+ cmd.n_lrecl[0], properties.record_width);
+ else
+ properties.record_width = cmd.n_lrecl[0];
break;
default:
assert (0);
}
- fp->name = xstrdup (handle_name);
- fp->norm_fn = fn_normalize (cmd.s_name);
- fp->where.filename = fp->fn = cmd.s_name;
- hsh_force_insert (files, fp);
+ if (cmd.mode != FH_SCRATCH)
+ fh_create_file (handle_name, cmd.s_name, &properties);
+ else
+ fh_create_scratch (handle_name);
+ free_file_handle (&cmd);
return CMD_SUCCESS;
lossage:
free_file_handle (&cmd);
return CMD_FAILURE;
}
-\f
-/* File handle functions. */
-
-/* Sets up some fields in H; caller should fill in
- H->{NAME,NORM_FN,FN}. */
-static void
-init_file_handle (struct file_handle *h)
-{
- h->recform = FH_RF_VARIABLE;
- h->mode = FH_MD_CHARACTER;
- h->ext = NULL;
- h->class = NULL;
-}
-/* Returns the handle corresponding to FILENAME. Creates the handle
- if no handle exists for that file. All filenames are normalized
- first, so different filenames referring to the same file will
- return the same file handle. */
-struct file_handle *
-fh_get_handle_by_filename (const char *filename)
+int
+cmd_close_file_handle (void)
{
- struct file_handle f, *fp;
- char *fn;
- char *name;
- int len;
-
- /* Get filename. */
- fn = fn_normalize (filename);
- len = strlen (fn);
+ struct file_handle *handle;
- /* Create handle name with invalid identifier character to prevent
- conflicts with handles created with FILE HANDLE. */
- name = xmalloc (len + 2);
- name[0] = '*';
- strcpy (&name[1], fn);
+ if (!lex_force_id ())
+ return CMD_FAILURE;
+ handle = fh_from_name (tokid);
+ if (handle == NULL)
+ return CMD_FAILURE;
- f.name = name;
- fp = hsh_find (files, &f);
- if (!fp)
- {
- fp = xmalloc (sizeof *fp);
- init_file_handle (fp);
- fp->name = name;
- fp->norm_fn = fn;
- fp->where.filename = fp->fn = xstrdup (filename);
- hsh_force_insert (files, fp);
- }
- else
- {
- free (fn);
- free (name);
- }
- return fp;
-}
+ fh_free (handle);
-/* Returns the handle with identifier NAME, if it exists; otherwise
- reports error to user and returns NULL. */
-struct file_handle *
-fh_get_handle_by_name (const char name[9])
-{
- struct file_handle f, *fp;
- f.name = (char *) name;
- fp = hsh_find (files, &f);
-
- if (!fp)
- msg (SE, _("File handle `%s' has not been previously declared on "
- "FILE HANDLE."), name);
- return fp;
+ return CMD_SUCCESS;
}
-/* Returns the identifier of file HANDLE. If HANDLE was created by
- referring to a filename (i.e., DATA LIST FILE='yyy' instead of FILE
- HANDLE XXX='yyy'), returns the filename, enclosed in double quotes.
- Return value is in a static buffer.
-
- Useful for printing error messages about use of file handles. */
-const char *
-fh_handle_name (struct file_handle *h)
+/* Returns the name for REFERENT. */
+static const char *
+referent_name (enum fh_referent referent)
{
- static char *buf = NULL;
-
- if (buf)
- {
- free (buf);
- buf = NULL;
- }
- if (!h)
- return NULL;
-
- if (h->name[0] == '*')
+ switch (referent)
{
- int len = strlen (h->fn);
-
- buf = xmalloc (len + 3);
- strcpy (&buf[1], h->fn);
- buf[0] = buf[len + 1] = '"';
- buf[len + 2] = 0;
- return buf;
+ case FH_REF_FILE:
+ return _("file");
+ case FH_REF_INLINE:
+ return _("inline file");
+ case FH_REF_SCRATCH:
+ return _("scratch file");
+ default:
+ abort ();
}
- return h->name;
-}
-
-/* Closes the stdio FILE associated with handle H. Frees internal
- buffers associated with that file. Does *not* destroy the file
- handle H. (File handles are permanent during a session.) */
-void
-fh_close_handle (struct file_handle *h)
-{
- if (h == NULL)
- return;
-
- debug_printf (("Closing %s%s.\n", fh_handle_name (h),
- h->class == NULL ? " (already closed)" : ""));
-
- if (h->class)
- h->class->close (h);
- h->class = NULL;
- h->ext = NULL;
-}
-
-/* Hashes the name of file handle H. */
-static unsigned
-hash_file_handle (const void *handle_, void *param unused)
-{
- const struct file_handle *handle = handle_;
-
- return hsh_hash_string (handle->name);
}
-/* Compares names of file handles A and B. */
-static int
-cmp_file_handle (const void *a_, const void *b_, void *foo unused)
-{
- const struct file_handle *a = a_;
- const struct file_handle *b = b_;
-
- return strcmp (a->name, b->name);
-}
-
-/* Initialize the hash of file handles; inserts the "inline file"
- inline_file. */
-void
-fh_init_files (void)
-{
- /* Create hash. */
- files = hsh_create (4, cmp_file_handle, hash_file_handle, NULL, NULL);
-
- /* Insert inline file. */
- inline_file = xmalloc (sizeof *inline_file);
- init_file_handle (inline_file);
- inline_file->name = "INLINE";
- inline_file->where.filename
- = inline_file->fn = inline_file->norm_fn = (char *) _("<Inline File>");
- inline_file->where.line_number = 0;
- hsh_force_insert (files, inline_file);
-}
-
-/* Parses a file handle name, which may be a filename as a string or
- a file handle name as an identifier. Returns the file handle or
- NULL on failure. */
+/* Parses a file handle name, which may be a filename as a string
+ or a file handle name as an identifier. The allowed types of
+ file handle are restricted to those in REFERENT_MASK. Returns
+ the file handle when successful, a null pointer on failure. */
struct file_handle *
-fh_parse_file_handle (void)
+fh_parse (enum fh_referent referent_mask)
{
struct file_handle *handle;
- if (token == T_ID)
- handle = fh_get_handle_by_name (tokid);
- else if (token == T_STRING)
- handle = fh_get_handle_by_filename (ds_value (&tokstr));
- else
+ if (lex_match_id ("INLINE"))
+ handle = fh_inline_file ();
+ else
{
- lex_error (_("expecting a file name or handle"));
- return NULL;
+ if (token != T_ID && token != T_STRING)
+ {
+ lex_error (_("expecting a file name or handle name"));
+ return NULL;
+ }
+
+ handle = NULL;
+ if (token == T_ID)
+ handle = fh_from_name (tokid);
+ if (handle == NULL)
+ handle = fh_from_filename (ds_c_str (&tokstr));
+ if (handle == NULL)
+ {
+ if (token != T_ID || tokid[0] != '#' || get_syntax () != ENHANCED)
+ {
+ char *filename = ds_c_str (&tokstr);
+ char *handle_name = xasprintf ("\"%s\"", filename);
+ handle = fh_create_file (handle_name, filename,
+ fh_default_properties ());
+ free (handle_name);
+ }
+ else
+ handle = fh_create_scratch (tokid);
+ }
+ lex_get ();
}
- if (!handle)
- return NULL;
- lex_get ();
+ if (!(fh_get_referent (handle) & referent_mask))
+ {
+ msg (SE, _("Handle for %s not allowed here."),
+ referent_name (fh_get_referent (handle)));
+ return NULL;
+ }
return handle;
}
-/* Returns the (normalized) filename associated with file handle H. */
-char *
-fh_handle_filename (struct file_handle * h)
-{
- return h->norm_fn;
-}
-
-/* Returns the width of a logical record on file handle H. */
-size_t
-fh_record_width (struct file_handle *h)
-{
- if (h == inline_file)
- return 80;
- else if (h->recform == FH_RF_FIXED)
- return h->lrecl;
- else
- return 1024;
-}
-
/*
Local variables:
mode: c