X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Ffile-handle.q;h=3f09d1946fecd87ddb6b8daefebbc044d7a49d2b;hb=5a33cc6d78fe87ff5e9bd32ea4af3f895e4ad2fc;hp=1133fd31286367695eecf4c815d7eeabf96de2f8;hpb=205ac3afa4c2b19c85819d8695abf3975bb11807;p=pspp-builds.git diff --git a/src/file-handle.q b/src/file-handle.q index 1133fd31..3f09d194 100644 --- a/src/file-handle.q +++ b/src/file-handle.q @@ -14,8 +14,8 @@ 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 #include "file-handle.h" @@ -30,28 +30,29 @@ #include "error.h" #include "magic.h" #include "var.h" +#include "linked-list.h" + /* (headers) */ -/* File handle private data. */ -struct private_file_handle +/* 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. */ -/* Linked list of file handles. */ -struct file_handle_list - { - struct file_handle *handle; - struct file_handle_list *next; + 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_list *file_handles; -struct file_handle *inline_file; +static struct file_handle *file_handles; static struct file_handle *create_file_handle (const char *handle_name, const char *filename); @@ -59,9 +60,9 @@ static struct file_handle *create_file_handle (const char *handle_name, /* (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. */ /* (declarations) */ /* (functions) */ @@ -69,11 +70,11 @@ static struct file_handle *create_file_handle (const char *handle_name, static struct file_handle * get_handle_with_name (const char *handle_name) { - struct file_handle_list *iter; + struct file_handle *iter; for (iter = file_handles; iter != NULL; iter = iter->next) - if (!strcmp (handle_name, iter->handle->private->name)) - return iter->handle; + if (!strcasecmp (handle_name, iter->name)) + return iter; return NULL; } @@ -81,27 +82,26 @@ static struct file_handle * get_handle_for_filename (const char *filename) { struct file_identity *identity; - struct file_handle_list *iter; + 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->handle->private->identity != NULL - && !fn_compare_file_identities (identity, - iter->handle->private->identity)) + if (iter->identity != NULL + && !fn_compare_file_identities (identity, iter->identity)) { fn_free_identity (identity); - return iter->handle; + 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->handle->private->filename)) - return iter->handle; + if (!strcmp (filename, iter->filename)) + return iter; return NULL; } @@ -109,22 +109,21 @@ get_handle_for_filename (const char *filename) int cmd_file_handle (void) { - char handle_name[9]; + char handle_name[LONG_NAME_LEN + 1]; struct cmd_file_handle cmd; struct file_handle *handle; if (!lex_force_id ()) return CMD_FAILURE; - strcpy (handle_name, tokid); + str_copy_trunc (handle_name, sizeof handle_name, tokid); handle = get_handle_with_name (handle_name); if (handle != NULL) { - msg (SE, _("File handle %s already refers to " - "file %s. File handle cannot be redefined within a " - "session."), - tokid, handle->private->filename); + msg (SE, _("File handle %s already refers to file %s. " + "File handles cannot be redefined within a session."), + handle_name, handle->filename); return CMD_FAILURE; } @@ -152,25 +151,29 @@ cmd_file_handle (void) switch (cmd.mode) { case FH_CHARACTER: - handle->private->mode = MODE_TEXT; + handle->mode = MODE_TEXT; + if (cmd.sbc_tabwidth) + handle->tab_width = cmd.n_tabwidth[0]; + else + handle->tab_width = 4; break; case FH_IMAGE: - handle->private->mode = MODE_BINARY; - if (cmd.n_lrecl == NOT_LONG) + handle->mode = 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 1024-character records.")); - handle->private->length = 1024; + handle->length = 1024; } - else if (cmd.n_lrecl < 1) + else if (cmd.n_lrecl[0] < 1) { msg (SE, _("Record length (%ld) must be at least one byte. " "1-character records will be assumed."), cmd.n_lrecl); - handle->private->length = 1; + handle->length = 1; } else - handle->private->length = cmd.n_lrecl; + handle->length = cmd.n_lrecl[0]; break; default: assert (0); @@ -192,62 +195,142 @@ static struct file_handle * create_file_handle (const char *handle_name, const char *filename) { struct file_handle *handle; - struct file_handle_list *list; /* Create and initialize file handle. */ handle = xmalloc (sizeof *handle); - handle->private = xmalloc (sizeof *handle->private); - handle->private->name = xstrdup (handle_name); - handle->private->filename = xstrdup (filename); - handle->private->identity = fn_get_identity (filename); - handle->private->where.filename = handle->private->filename; - handle->private->where.line_number = 0; - handle->private->mode = MODE_TEXT; - handle->private->length = 1024; - handle->ext = NULL; - handle->class = NULL; - - /* Add file handle to global list. */ - list = xmalloc (sizeof *list); - list->handle = handle; - list->next = file_handles; - file_handles = list; + 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_TEXT; + handle->length = 1024; + handle->tab_width = 4; + handle->open_cnt = 0; + handle->type = NULL; + handle->aux = NULL; + file_handles = handle; return handle; } -/* 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) +static void +destroy_file_handle(void *fh_, void *aux UNUSED) { - if (h == NULL) - return; + struct file_handle *fh = fh_; + free (fh->name); + free (fh->filename); + fn_free_identity (fh->identity); + free (fh); +} - if (h->class != NULL) - h->class->close (h); - h->class = NULL; - h->ext = NULL; +static const char * +mode_name (const char *mode) +{ + assert (mode != NULL); + assert (mode[0] == 'r' || mode[0] == 'w'); + + return mode[0] == 'r' ? "reading" : "writing"; } -/* Initialize the hash of file handles; inserts the "inline file" - inline_file. */ -void -fh_init_files (void) + +/* Tries to open FILE 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) { - if (inline_file == NULL) + 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) { - inline_file = create_file_handle ("INLINE", _("")); - inline_file->private->length = 80; + h->type = NULL; + h->aux = NULL; } + return h->open_cnt; } + +static struct linked_list *handle_list; + + /* 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. */ struct file_handle * -fh_parse_file_handle (void) +fh_parse (void) { struct file_handle *handle; @@ -262,18 +345,20 @@ fh_parse_file_handle (void) if (token == T_ID) handle = get_handle_with_name (tokid); if (handle == NULL) - handle = get_handle_for_filename (ds_value (&tokstr)); + handle = get_handle_for_filename (ds_c_str (&tokstr)); if (handle == NULL) { - char *filename = ds_value (&tokstr); + char *filename = ds_c_str (&tokstr); char *handle_name = xmalloc (strlen (filename) + 3); sprintf (handle_name, "\"%s\"", filename); handle = create_file_handle (handle_name, filename); + ll_push_front(handle_list, handle); free (handle_name); } lex_get (); + return handle; } @@ -286,14 +371,16 @@ fh_parse_file_handle (void) const char * handle_get_name (const struct file_handle *handle) { - return handle->private->name; + 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) { - return handle->private->filename; + assert (handle != NULL); + return handle->filename; } /* Returns the mode of HANDLE. */ @@ -301,17 +388,46 @@ enum file_handle_mode handle_get_mode (const struct file_handle *handle) { assert (handle != NULL); - return handle->private->mode; + return handle->mode; } -/* Returns the width of a logical record on HANDLE. */ +/* Returns the width of a logical record on HANDLE. Applicable + only to MODE_BINARY files. */ size_t handle_get_record_width (const struct file_handle *handle) { assert (handle != NULL); - return handle->private->length; + 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; +} + + +void +fh_init(void) +{ + handle_list = ll_create(destroy_file_handle,0); } +void +fh_done(void) +{ + if ( handle_list ) + { + ll_destroy(handle_list); + handle_list = 0; + } +} + + /* Local variables: mode: c