/* PSPP - computes sample statistics. Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. Written by Ben Pfaff . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "file-handle.h" #include "error.h" #include #include #include #include "alloc.h" #include "filename.h" #include "command.h" #include "getl.h" #include "error.h" #include "magic.h" #include "var.h" #include "file-handle-def.h" #include "gettext.h" #define _(msgid) gettext (msgid) /* (headers) */ /* File handle. */ struct file_handle { struct file_handle *next; /* Next in global list. */ char *name; /* File handle identifier. */ char *filename; /* Filename as provided by user. */ struct file_identity *identity; /* For checking file identity. */ struct file_locator where; /* Used for reporting error messages. */ enum file_handle_mode mode; /* File mode. */ size_t length; /* Length of fixed-format records. */ size_t tab_width; /* Tab width, 0=do not expand tabs. */ int open_cnt; /* 0=not open, otherwise # of openers. */ const char *type; /* If open, type of file. */ char open_mode[3]; /* "[rw][se]". */ void *aux; /* Aux data pointer for owner if any. */ }; static struct file_handle *file_handles; struct file_handle * get_handle_with_name (const char *handle_name) { struct file_handle *iter; for (iter = file_handles; iter != NULL; iter = iter->next) if (!strcasecmp (handle_name, iter->name)) return iter; return NULL; } struct file_handle * get_handle_for_filename (const char *filename) { 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) { for (iter = file_handles; iter != NULL; iter = iter->next) if (iter->identity != NULL && !fn_compare_file_identities (identity, iter->identity)) { fn_free_identity (identity); 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 (!strcmp (filename, iter->filename)) return iter; return NULL; } /* File handle functions. */ struct file_handle * create_file_handle_with_defaults (const char *handle_name, const char *filename) { return create_file_handle (handle_name, filename, MODE_TEXT,1024, 4); } /* Creates and returns a new file handle with the given values and defaults for other values. Adds the created file handle to the global list. */ struct file_handle * create_file_handle (const char *handle_name, const char *filename, enum file_handle_mode mode, size_t length, size_t tab_width ) { struct file_handle *handle; /* Create and initialize file handle. */ handle = xmalloc (sizeof *handle); handle->next = file_handles; handle->name = xstrdup (handle_name); handle->filename = xstrdup (filename); handle->identity = fn_get_identity (filename); handle->where.filename = handle->filename; handle->where.line_number = 0; handle->mode = mode; handle->length = length; handle->tab_width = tab_width; handle->open_cnt = 0; handle->type = NULL; handle->aux = NULL; file_handles = handle; return handle; } void destroy_file_handle(void *fh_, void *aux UNUSED) { struct file_handle *fh = fh_; free (fh->name); free (fh->filename); fn_free_identity (fh->identity); free (fh); } static const char * mode_name (const char *mode) { assert (mode != NULL); assert (mode[0] == 'r' || mode[0] == 'w'); return mode[0] == 'r' ? "reading" : "writing"; } /* Tries to open handle H with the given TYPE and MODE. TYPE is the sort of file, e.g. "system file". Only one given type of access is allowed on a given file handle at once. MODE combines the read or write mode with the sharing mode. The first character is 'r' for read, 'w' for write. The second character is 's' to permit sharing, 'e' to require exclusive access. Returns the address of a void * that the caller can use for data specific to the file handle if successful, or a null pointer on failure. For exclusive access modes the void * will always be a null pointer at return. In shared access modes the void * will necessarily be null only if no other sharers are active. If successful, a reference to type is retained, so it should probably be a string literal. */ void ** fh_open (struct file_handle *h, const char *type, const char *mode) { assert (h != NULL); assert (type != NULL); assert (mode != NULL); assert (mode[0] == 'r' || mode[0] == 'w'); assert (mode[1] == 's' || mode[1] == 'e'); assert (mode[2] == '\0'); if (h->open_cnt != 0) { if (strcmp (h->type, type)) { msg (SE, _("Can't open %s as a %s because it is " "already open as a %s"), handle_get_name (h), type, h->type); return NULL; } 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"), handle_get_name (h), type, mode_name (mode), mode_name (h->open_mode)); return NULL; } else if (h->open_mode[1] == 'e') { msg (SE, _("Can't re-open %s as a %s for %s"), handle_get_name (h), type, mode_name (mode)); return NULL; } } else { h->type = type; strcpy (h->open_mode, mode); assert (h->aux == NULL); } h->open_cnt++; return &h->aux; } /* Closes file handle H, which must have been open for the specified TYPE and MODE of access provided to fh_open(). Returns zero if the file is now closed, nonzero if it is still open due to another reference. */ int fh_close (struct file_handle *h, const char *type, const char *mode) { assert (h != NULL); assert (h->open_cnt > 0); assert (type != NULL); assert (!strcmp (type, h->type)); assert (mode != NULL); assert (!strcmp (mode, h->open_mode)); h->open_cnt--; if (h->open_cnt == 0) { h->type = NULL; h->aux = NULL; } return h->open_cnt; } /* 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. Useful for printing error messages about use of file handles. */ const char * handle_get_name (const struct file_handle *handle) { assert (handle != NULL); return handle->name; } /* Returns the name of the file associated with HANDLE. */ const char * handle_get_filename (const struct file_handle *handle) { assert (handle != NULL); return handle->filename; } /* Returns the mode of HANDLE. */ enum file_handle_mode handle_get_mode (const struct file_handle *handle) { assert (handle != NULL); return handle->mode; } /* Returns the width of a logical record on HANDLE. */ size_t handle_get_record_width (const struct file_handle *handle) { assert (handle != NULL); return handle->length; } /* Returns the number of characters per tab stop for HANDLE, or zero if tabs are not to be expanded. Applicable only to MODE_TEXT files. */ size_t handle_get_tab_width (const struct file_handle *handle) { assert (handle != NULL); return handle->tab_width; }