X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libgfortran%2Fio%2Funit.c;h=bbe112010ba73a55af405a3fe13445c8adb16555;hp=2ec776f0d688e2c81184ce2180cdaaad55d55de4;hb=09c759aaf6da911aa1a44898d2b84121991bced9;hpb=533d0ceb28088c9b755731b0a9179dbc857b7e72 diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c index 2ec776f0d68..bbe112010ba 100644 --- a/libgfortran/io/unit.c +++ b/libgfortran/io/unit.c @@ -1,33 +1,33 @@ -/* Copyright (C) 2002, 2003, 2005, 2007 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 @@ -71,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]; @@ -135,7 +137,6 @@ rotate_right (gfc_unit * t) } - static int compare (int a, int b) { @@ -209,14 +210,8 @@ insert_unit (int n) static void destroy_unit_mutex (gfc_unit * u) { -#ifdef __GTHREAD_MUTEX_DESTROY_FUNCTION - __GTHREAD_MUTEX_DESTROY_FUNCTION (&u->lock); -#else -#ifdef __CYGWIN__ - pthread_mutex_destroy (&u->lock); -#endif -#endif - free_mem (u); + __gthread_mutex_destroy (&u->lock); + free (u); } @@ -436,20 +431,25 @@ get_internal_unit (st_parameter_dt *dtp) iunit->maxrec=0; iunit->current_record=0; iunit->read_bad = 0; + iunit->endfile = NO_ENDFILE; /* Set flags for the internal unit. */ 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->endfile = NO_ENDFILE; + 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; @@ -474,10 +474,10 @@ free_internal_unit (st_parameter_dt *dtp) 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); } @@ -486,7 +486,7 @@ 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) @@ -495,7 +495,7 @@ get_unit (st_parameter_dt *dtp, int do_create) if ((dtp->common.flags & IOPARM_DT_HAS_INTERNAL_UNIT) != 0) 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; @@ -505,7 +505,7 @@ get_unit (st_parameter_dt *dtp, int do_create) /*************************/ -/* Initialize everything */ +/* Initialize everything. */ void init_units (void) @@ -517,6 +517,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); @@ -530,13 +532,20 @@ init_units (void) u->flags.blank = BLANK_NULL; u->flags.pad = PAD_YES; u->flags.position = POSITION_ASIS; - + 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); } @@ -553,6 +562,11 @@ init_units (void) u->flags.status = STATUS_OLD; u->flags.blank = BLANK_NULL; u->flags.position = POSITION_ASIS; + 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; @@ -560,6 +574,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); } @@ -576,6 +592,11 @@ init_units (void) u->flags.status = STATUS_OLD; u->flags.blank = BLANK_NULL; u->flags.position = POSITION_ASIS; + 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; @@ -583,15 +604,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); @@ -602,13 +624,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) @@ -621,10 +643,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); @@ -647,8 +672,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) @@ -658,11 +683,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) @@ -679,15 +704,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. */ @@ -726,24 +798,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; +}