X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libgfortran%2Fio%2Funit.c;h=a0018dbb4f7280fc95df24329cf8d53f168a2146;hb=74f57237faf0395958cd1ea90a519ce24b8cdebf;hp=f1928e6ed8a66c61cbbecfcb67cfa54fcff84968;hpb=84d33b914fb53fbd09cb43bf71f4265e4e275a02;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c index f1928e6ed8a..a0018dbb4f7 100644 --- a/libgfortran/io/unit.c +++ b/libgfortran/io/unit.c @@ -1,34 +1,33 @@ -/* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Andy Vaught F2003 I/O support contributed by Jerry DeLisle -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran 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, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file into combinations with other programs, -and to distribute those combinations without any restriction coming -from the use of this file. (The General Public License restrictions -do apply in other respects; for example, they cover modification of -the file, and distribution when not linked into a combine -executable.) - Libgfortran 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 Libgfortran; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ #include "io.h" +#include "fbuf.h" +#include "format.h" +#include "unix.h" #include #include @@ -72,6 +71,8 @@ Boston, MA 02110-1301, USA. */ /* Subroutines related to units */ +GFC_INTEGER_4 next_available_newunit; +#define GFC_FIRST_NEWUNIT -10 #define CACHE_SIZE 3 static gfc_unit *unit_cache[CACHE_SIZE]; @@ -136,7 +137,6 @@ rotate_right (gfc_unit * t) } - static int compare (int a, int b) { @@ -211,7 +211,7 @@ static void destroy_unit_mutex (gfc_unit * u) { __gthread_mutex_destroy (&u->lock); - free_mem (u); + free (u); } @@ -423,9 +423,16 @@ get_internal_unit (st_parameter_dt *dtp) } /* Set initial values for unit parameters. */ + if (dtp->common.unit) + { + iunit->s = open_internal4 (dtp->internal_unit - start_record, + dtp->internal_unit_len, -start_record); + fbuf_init (iunit, 256); + } + else + iunit->s = open_internal (dtp->internal_unit - start_record, + dtp->internal_unit_len, -start_record); - iunit->s = open_internal (dtp->internal_unit - start_record, - dtp->internal_unit_len, -start_record); iunit->bytes_left = iunit->recl; iunit->last_record=0; iunit->maxrec=0; @@ -437,17 +444,19 @@ get_internal_unit (st_parameter_dt *dtp) iunit->flags.access = ACCESS_SEQUENTIAL; iunit->flags.action = ACTION_READWRITE; + iunit->flags.blank = BLANK_NULL; iunit->flags.form = FORM_FORMATTED; iunit->flags.pad = PAD_YES; iunit->flags.status = STATUS_UNSPECIFIED; iunit->flags.sign = SIGN_SUPPRESS; iunit->flags.decimal = DECIMAL_POINT; iunit->flags.encoding = ENCODING_DEFAULT; + iunit->flags.async = ASYNC_NO; + iunit->flags.round = ROUND_COMPATIBLE; /* Initialize the data transfer parameters. */ dtp->u.p.advance_status = ADVANCE_YES; - dtp->u.p.blank_status = BLANK_UNSPECIFIED; dtp->u.p.seen_dollar = 0; dtp->u.p.skips = 0; dtp->u.p.pending_spaces = 0; @@ -469,13 +478,16 @@ free_internal_unit (st_parameter_dt *dtp) if (!is_internal_unit (dtp)) return; + if (unlikely (is_char4_unit (dtp))) + fbuf_destroy (dtp->u.p.current_unit); + if (dtp->u.p.current_unit != NULL) { if (dtp->u.p.current_unit->ls != NULL) - free_mem (dtp->u.p.current_unit->ls); + free (dtp->u.p.current_unit->ls); if (dtp->u.p.current_unit->s) - free_mem (dtp->u.p.current_unit->s); + free (dtp->u.p.current_unit->s); destroy_unit_mutex (dtp->u.p.current_unit); } @@ -484,16 +496,16 @@ free_internal_unit (st_parameter_dt *dtp) /* get_unit()-- Returns the unit structure associated with the integer - * unit or the internal file. */ + unit or the internal file. */ gfc_unit * get_unit (st_parameter_dt *dtp, int do_create) { if ((dtp->common.flags & IOPARM_DT_HAS_INTERNAL_UNIT) != 0) - return get_internal_unit(dtp); + return get_internal_unit (dtp); - /* Has to be an external unit */ + /* Has to be an external unit. */ dtp->u.p.unit_is_internal = 0; dtp->internal_unit_desc = NULL; @@ -503,7 +515,7 @@ get_unit (st_parameter_dt *dtp, int do_create) /*************************/ -/* Initialize everything */ +/* Initialize everything. */ void init_units (void) @@ -515,6 +527,8 @@ init_units (void) __GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock); #endif + next_available_newunit = GFC_FIRST_NEWUNIT; + if (options.stdin_unit >= 0) { /* STDIN */ u = insert_unit (options.stdin_unit); @@ -531,13 +545,17 @@ init_units (void) u->flags.sign = SIGN_SUPPRESS; u->flags.decimal = DECIMAL_POINT; u->flags.encoding = ENCODING_DEFAULT; - + u->flags.async = ASYNC_NO; + u->flags.round = ROUND_COMPATIBLE; + u->recl = options.default_recl; u->endfile = NO_ENDFILE; u->file_len = strlen (stdin_name); u->file = get_mem (u->file_len); memmove (u->file, stdin_name, u->file_len); + + fbuf_init (u, 0); __gthread_mutex_unlock (&u->lock); } @@ -557,6 +575,8 @@ init_units (void) u->flags.sign = SIGN_SUPPRESS; u->flags.decimal = DECIMAL_POINT; u->flags.encoding = ENCODING_DEFAULT; + u->flags.async = ASYNC_NO; + u->flags.round = ROUND_COMPATIBLE; u->recl = options.default_recl; u->endfile = AT_ENDFILE; @@ -564,6 +584,8 @@ init_units (void) u->file_len = strlen (stdout_name); u->file = get_mem (u->file_len); memmove (u->file, stdout_name, u->file_len); + + fbuf_init (u, 0); __gthread_mutex_unlock (&u->lock); } @@ -583,6 +605,8 @@ init_units (void) u->flags.sign = SIGN_SUPPRESS; u->flags.decimal = DECIMAL_POINT; u->flags.encoding = ENCODING_DEFAULT; + u->flags.async = ASYNC_NO; + u->flags.round = ROUND_COMPATIBLE; u->recl = options.default_recl; u->endfile = AT_ENDFILE; @@ -590,15 +614,16 @@ init_units (void) u->file_len = strlen (stderr_name); u->file = get_mem (u->file_len); memmove (u->file, stderr_name, u->file_len); + + fbuf_init (u, 256); /* 256 bytes should be enough, probably not doing + any kind of exotic formatting to stderr. */ __gthread_mutex_unlock (&u->lock); } /* Calculate the maximum file offset in a portable manner. - * max will be the largest signed number for the type gfc_offset. - * - * set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */ - + max will be the largest signed number for the type gfc_offset. + set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */ max_offset = 0; for (i = 0; i < sizeof (max_offset) * 8 - 1; i++) max_offset = max_offset + ((gfc_offset) 1 << i); @@ -609,13 +634,13 @@ static int close_unit_1 (gfc_unit *u, int locked) { int i, rc; - + /* If there are previously written bytes from a write with ADVANCE="no" Reposition the buffer before closing. */ if (u->previous_nonadvancing_write) finish_last_advance_record (u); - rc = (u->s == NULL) ? 0 : sclose (u->s) == FAILURE; + rc = (u->s == NULL) ? 0 : sclose (u->s) == -1; u->closed = 1; if (!locked) @@ -628,10 +653,13 @@ close_unit_1 (gfc_unit *u, int locked) delete_unit (u); if (u->file) - free_mem (u->file); + free (u->file); u->file = NULL; u->file_len = 0; + free_format_hash_table (u); + fbuf_destroy (u); + if (!locked) __gthread_mutex_unlock (&u->lock); @@ -654,8 +682,8 @@ unlock_unit (gfc_unit *u) } /* close_unit()-- Close a unit. The stream is closed, and any memory - * associated with the stream is freed. Returns nonzero on I/O error. - * Should be called with the u->lock locked. */ + associated with the stream is freed. Returns nonzero on I/O error. + Should be called with the u->lock locked. */ int close_unit (gfc_unit *u) @@ -665,11 +693,11 @@ close_unit (gfc_unit *u) /* close_units()-- Delete units on completion. We just keep deleting - * the root of the treap until there is nothing left. - * Not sure what to do with locking here. Some other thread might be - * holding some unit's lock and perhaps hold it indefinitely - * (e.g. waiting for input from some pipe) and close_units shouldn't - * delay the program too much. */ + the root of the treap until there is nothing left. + Not sure what to do with locking here. Some other thread might be + holding some unit's lock and perhaps hold it indefinitely + (e.g. waiting for input from some pipe) and close_units shouldn't + delay the program too much. */ void close_units (void) @@ -686,15 +714,62 @@ close_units (void) void update_position (gfc_unit *u) { - if (file_position (u->s) == 0) + if (stell (u->s) == 0) u->flags.position = POSITION_REWIND; - else if (file_length (u->s) == file_position (u->s)) + else if (file_length (u->s) == stell (u->s)) u->flags.position = POSITION_APPEND; else u->flags.position = POSITION_ASIS; } +/* High level interface to truncate a file safely, i.e. flush format + buffers, check that it's a regular file, and generate error if that + occurs. Just like POSIX ftruncate, returns 0 on success, -1 on + failure. */ + +int +unit_truncate (gfc_unit * u, gfc_offset pos, st_parameter_common * common) +{ + int ret; + + /* Make sure format buffer is flushed. */ + if (u->flags.form == FORM_FORMATTED) + { + if (u->mode == READING) + pos += fbuf_reset (u); + else + fbuf_flush (u, u->mode); + } + + /* Don't try to truncate a special file, just pretend that it + succeeds. */ + if (is_special (u->s) || !is_seekable (u->s)) + { + sflush (u->s); + return 0; + } + + /* struncate() should flush the stream buffer if necessary, so don't + bother calling sflush() here. */ + ret = struncate (u->s, pos); + + if (ret != 0) + { + generate_error (common, LIBERROR_OS, NULL); + u->endfile = NO_ENDFILE; + u->flags.position = POSITION_ASIS; + } + else + { + u->endfile = AT_ENDFILE; + u->flags.position = POSITION_APPEND; + } + + return ret; +} + + /* filename_from_unit()-- If the unit_number exists, return a pointer to the name of the associated file, otherwise return the empty string. The caller must free memory allocated for the filename string. */ @@ -733,24 +808,46 @@ filename_from_unit (int n) void finish_last_advance_record (gfc_unit *u) { - char *p; - + if (u->saved_pos > 0) - p = salloc_w (u->s, &u->saved_pos); + fbuf_seek (u, u->saved_pos, SEEK_CUR); if (!(u->unit_number == options.stdout_unit || u->unit_number == options.stderr_unit)) { - size_t len; - - const char crlf[] = "\r\n"; #ifdef HAVE_CRLF - len = 2; + const int len = 2; #else - len = 1; + const int len = 1; #endif - if (swrite (u->s, &crlf[2-len], &len) != 0) + char *p = fbuf_alloc (u, len); + if (!p) os_error ("Completing record after ADVANCE_NO failed"); +#ifdef HAVE_CRLF + *(p++) = '\r'; +#endif + *p = '\n'; } + + fbuf_flush (u, u->mode); } +/* Assign a negative number for NEWUNIT in OPEN statements. */ +GFC_INTEGER_4 +get_unique_unit_number (st_parameter_open *opp) +{ + GFC_INTEGER_4 num; + + __gthread_mutex_lock (&unit_lock); + num = next_available_newunit--; + + /* Do not allow NEWUNIT numbers to wrap. */ + if (next_available_newunit >= GFC_FIRST_NEWUNIT ) + { + __gthread_mutex_unlock (&unit_lock); + generate_error (&opp->common, LIBERROR_INTERNAL, "NEWUNIT exhausted"); + return 0; + } + __gthread_mutex_unlock (&unit_lock); + return num; +}