/* PSPP - computes sample statistics.
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
modify it under the terms of the GNU General Public License as
02110-1301, USA. */
#include <config.h>
+
#include "file-handle-def.h"
-#include "message.h"
+
+#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
-#include "alloc.h"
-#include "filename.h"
-#include "message.h"
-#include "magic.h"
-#include "variable.h"
-#include "scratch-handle.h"
+
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/magic.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
+#include <data/file-name.h>
+#include <data/variable.h>
+#include <data/scratch-handle.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
/* (headers) */
/* File handle. */
-struct file_handle
+struct file_handle
{
struct file_handle *next; /* Next in global list. */
int open_cnt; /* 0=not open, otherwise # of openers. */
bool deleted; /* Destroy handle when open_cnt goes to 0? */
- char *name; /* File handle identifier. */
+ char id[LONG_NAME_LEN + 1]; /* Identifier token; empty string if none. */
+ char *name; /* User-friendly identifying name. */
const char *type; /* If open, type of file. */
char open_mode[3]; /* "[rw][se]". */
void *aux; /* Aux data pointer for owner if any. */
enum fh_referent referent; /* What the file handle refers to. */
/* FH_REF_FILE only. */
- char *filename; /* Filename as provided by user. */
+ char *file_name; /* File name as provided by user. */
struct file_identity *identity; /* For checking file identity. */
enum fh_mode mode; /* File mode. */
/* The "file" that reads from BEGIN DATA...END DATA. */
static struct file_handle *inline_file;
-static struct file_handle *create_handle (const char *name, enum fh_referent);
+static struct file_handle *create_handle (const char *id,
+ const char *name, enum fh_referent);
/* File handle initialization routine. */
-void
+void
fh_init (void)
{
- inline_file = create_handle ("INLINE", FH_REF_INLINE);
+ inline_file = create_handle ("INLINE", "INLINE", FH_REF_INLINE);
inline_file->record_width = 80;
inline_file->tab_width = 8;
}
/* Free HANDLE and remove it from the global list. */
static void
-free_handle (struct file_handle *handle)
+free_handle (struct file_handle *handle)
{
/* Remove handle from global list. */
if (file_handles == handle)
file_handles = handle->next;
- else
+ else
{
struct file_handle *iter = file_handles;
while (iter->next != handle)
/* Free data. */
free (handle->name);
- free (handle->filename);
+ free (handle->file_name);
fn_free_identity (handle->identity);
scratch_handle_destroy (handle->sh);
free (handle);
}
/* Frees all the file handles. */
-void
+void
fh_done (void)
{
- while (file_handles != NULL)
+ while (file_handles != NULL)
free_handle (file_handles);
}
-/* Returns the handle named HANDLE_NAME, or a null pointer if
+/* Returns the handle with the given ID, or a null pointer if
there is none. */
struct file_handle *
-fh_from_name (const char *handle_name)
+fh_from_id (const char *id)
{
struct file_handle *iter;
for (iter = file_handles; iter != NULL; iter = iter->next)
- if (!iter->deleted && !strcasecmp (handle_name, iter->name))
+ if (!iter->deleted && !strcasecmp (id, iter->id))
return iter;
return NULL;
}
-/* Returns the handle for the file named FILENAME,
+/* Returns the handle for the file named FILE_NAME,
or a null pointer if none exists.
Different names for the same file (e.g. "x" and "./x") are
considered equivalent. */
struct file_handle *
-fh_from_filename (const char *filename)
+fh_from_file_name (const char *file_name)
{
struct file_identity *identity;
struct file_handle *iter;
-
+
/* First check for a file with the same identity. */
- identity = fn_get_identity (filename);
- if (identity != NULL)
+ identity = fn_get_identity (file_name);
+ if (identity != NULL)
{
for (iter = file_handles; iter != NULL; iter = iter->next)
if (!iter->deleted
&& !fn_compare_file_identities (identity, iter->identity))
{
fn_free_identity (identity);
- return iter;
+ return iter;
}
fn_free_identity (identity);
}
/* Then check for a file with the same name. */
for (iter = file_handles; iter != NULL; iter = iter->next)
if (!iter->deleted
- && iter->referent == FH_REF_FILE && !strcmp (filename, iter->filename))
- return iter;
+ && iter->referent == FH_REF_FILE && !strcmp (file_name, iter->file_name))
+ return iter;
return NULL;
}
-/* Creates a new handle with name HANDLE_NAME that refers to
- REFERENT. Links the new handle into the global list. Returns
- the new handle.
+/* Creates a new handle with identifier ID (which may be null)
+ and name HANDLE_NAME that refers to REFERENT. Links the new
+ handle into the global list. Returns the new handle.
The new handle is not fully initialized. The caller is
responsible for completing its initialization. */
static struct file_handle *
-create_handle (const char *handle_name, enum fh_referent referent)
+create_handle (const char *id, const char *handle_name,
+ enum fh_referent referent)
{
struct file_handle *handle = xzalloc (sizeof *handle);
+ assert (id == NULL || fh_from_id (id) == NULL);
handle->next = file_handles;
handle->open_cnt = 0;
handle->deleted = false;
+ str_copy_trunc (handle->id, sizeof handle->id, id != NULL ? id : "");
handle->name = xstrdup (handle_name);
handle->type = NULL;
handle->aux = NULL;
which refers to the "inline file" that represents character
data in the command file between BEGIN DATA and END DATA. */
struct file_handle *
-fh_inline_file (void)
+fh_inline_file (void)
{
return inline_file;
}
-/* Creates a new file handle named HANDLE_NAME, which must not be
- the name of an existing file handle. The new handle is
- associated with file FILENAME and the given PROPERTIES. */
+/* Creates a new file handle with the given ID, which may be
+ null. If it is non-null, it must be unique among existing
+ file identifiers. The new handle is associated with file
+ FILE_NAME and the given PROPERTIES. */
struct file_handle *
-fh_create_file (const char *handle_name, const char *filename,
+fh_create_file (const char *id, const char *file_name,
const struct fh_properties *properties)
{
+ char *handle_name;
struct file_handle *handle;
- assert (fh_from_name (handle_name) == NULL);
- handle = create_handle (handle_name, FH_REF_FILE);
- handle->filename = xstrdup (filename);
- handle->identity = fn_get_identity (filename);
+
+ handle_name = id != NULL ? (char *) id : xasprintf ("\"%s\"", file_name);
+ handle = create_handle (id, handle_name, FH_REF_FILE);
+ if (id == NULL)
+ free (handle_name);
+ handle->file_name = xstrdup (file_name);
+ handle->identity = fn_get_identity (file_name);
handle->mode = properties->mode;
handle->record_width = properties->record_width;
handle->tab_width = properties->tab_width;
return handle;
}
-/* Creates a new file handle named HANDLE_NAME, which must not be
- the name of an existing file handle. The new handle is
+/* Creates a new file handle with the given ID, which must be
+ unique among existing file identifiers. The new handle is
associated with a scratch file (initially empty). */
struct file_handle *
-fh_create_scratch (const char *handle_name)
+fh_create_scratch (const char *id)
{
- struct file_handle *handle = create_handle (handle_name, FH_REF_SCRATCH);
+ struct file_handle *handle;
+ assert (id != NULL);
+ handle = create_handle (id, id, FH_REF_SCRATCH);
handle->sh = NULL;
return handle;
}
destroyed later when it is closed.
Normally needed only if a file_handle needs to be re-assigned.
Otherwise, just let fh_done() destroy the handle. */
-void
+void
fh_free (struct file_handle *handle)
{
if (handle == fh_inline_file () || handle == NULL || handle->deleted)
/* Returns an English description of MODE,
which is in the format of the MODE argument to fh_open(). */
static const char *
-mode_name (const char *mode)
+mode_name (const char *mode)
{
assert (mode != NULL);
assert (mode[0] == 'r' || mode[0] == 'w');
sharers are active. */
void **
fh_open (struct file_handle *h, enum fh_referent mask UNUSED,
- const char *type, const char *mode)
+ const char *type, const char *mode)
{
assert (h != NULL);
assert ((fh_get_referent (h) & mask) != 0);
assert (mode[1] == 's' || mode[1] == 'e');
assert (mode[2] == '\0');
- if (h->open_cnt != 0)
+ if (h->open_cnt != 0)
{
- if (strcmp (h->type, type))
+ if (strcmp (h->type, type))
{
msg (SE, _("Can't open %s as a %s because it is "
"already open as a %s."),
fh_get_name (h), type, h->type);
- return NULL;
+ return NULL;
}
- else if (strcmp (h->open_mode, mode))
+ else if (strcmp (h->open_mode, mode))
{
msg (SE, _("Can't open %s as a %s for %s because it is "
"already open for %s."),
return NULL;
}
}
- else
+ else
{
h->type = type;
strcpy (h->open_mode, mode);
assert (mode != NULL);
assert (!strcmp (mode, h->open_mode));
- if (--h->open_cnt == 0)
+ if (--h->open_cnt == 0)
{
h->type = NULL;
h->aux = NULL;
/* Is the file open? BEGIN DATA...END DATA uses this to detect
whether the inline file is actually in use. */
bool
-fh_is_open (const struct file_handle *handle)
+fh_is_open (const struct file_handle *handle)
{
return handle->open_cnt > 0;
}
-/* Returns the identifier of file HANDLE. If HANDLE was created
- by referring to a filename instead of a handle name, returns
- the filename, enclosed in double quotes. Return value is
- owned by the file handle.
+/* Returns the identifier that may be used in syntax to name the
+ given HANDLE, which takes the form of a PSPP identifier. If
+ HANDLE has no identifier, returns a null pointer.
+
+ Return value is owned by the file handle.*/
+const char *
+fh_get_id (const struct file_handle *handle)
+{
+ return handle->id[0] != '\0' ? handle->id : NULL;
+}
+
+/* Returns a user-friendly string to identify the given HANDLE.
+ If HANDLE was created by referring to a file name, returns the
+ file name, enclosed in double quotes. Return value is owned
+ by the file handle.
Useful for printing error messages about use of file handles. */
const char *
/* Returns the type of object that HANDLE refers to. */
enum fh_referent
-fh_get_referent (const struct file_handle *handle)
+fh_get_referent (const struct file_handle *handle)
{
return handle->referent;
}
/* Returns the name of the file associated with HANDLE. */
const char *
-fh_get_filename (const struct file_handle *handle)
+fh_get_file_name (const struct file_handle *handle)
{
assert (handle->referent == FH_REF_FILE);
- return handle->filename;
+ return handle->file_name;
}
/* Returns the mode of HANDLE. */
enum fh_mode
-fh_get_mode (const struct file_handle *handle)
+fh_get_mode (const struct file_handle *handle)
{
assert (handle->referent == FH_REF_FILE);
return handle->mode;
zero if tabs are not to be expanded. Applicable only to
FH_MODE_TEXT files. */
size_t
-fh_get_tab_width (const struct file_handle *handle)
+fh_get_tab_width (const struct file_handle *handle)
{
assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
return handle->tab_width;
/* Returns the scratch file handle associated with HANDLE.
Applicable to only FH_REF_SCRATCH files. */
struct scratch_handle *
-fh_get_scratch_handle (struct file_handle *handle)
+fh_get_scratch_handle (struct file_handle *handle)
{
assert (handle->referent == FH_REF_SCRATCH);
return handle->sh;
/* Returns the current default handle. */
struct file_handle *
-fh_get_default_handle (void)
+fh_get_default_handle (void)
{
return default_handle ? default_handle : fh_inline_file ();
}
/* Sets NEW_DEFAULT_HANDLE as the default handle. */
void
-fh_set_default_handle (struct file_handle *new_default_handle)
+fh_set_default_handle (struct file_handle *new_default_handle)
{
assert (new_default_handle == NULL
|| (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));