mirror of git://gcc.gnu.org/git/gcc.git
[multiple changes]
2009-04-05 Daniel Kraft <d@domob.eu>
PR fortran/38654
* io/read.c (read_f): Reworked to speed up floating point parsing.
(convert_real): Use pointer-casting instead of memcpy and temporaries.
2009-04-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libfortran/37754
* io/io.h (format_hash_entry): New structure for hash table.
(format_hash_table): The hash table itself.
(free_format_data): Revise function prototype.
(free_format_hash_table, init_format_hash,
free_format_hash): New function prototypes.
* io/unit.c (close_unit_1): Use free_format_hash_table.
* io/transfer.c (st_read_done, st_write_done): Free format data if
internal unit.
* io/format.c (free_format_hash_table): New function that frees any
memory allocated previously for cached format data.
(reset_node): New static helper function to reset the format counters
for a format node.
(reset_fnode_counters): New static function recursively calls reset_node
to traverse the fnode tree.
(format_hash): New simple hash function based on XOR, probabalistic,
tosses collisions.
(save_parsed_format): New static function to save the parsed format
data to use again.
(find_parsed_format): New static function searches the hash table
looking for a match.
(free_format_data): Revised to accept pointer to format data rather than
the dtp pointer so that the function can be used in more places.
(format_lex): Editorial.
(parse_format_list): Set flag used to determine of format data hashing
is to be used. Internal units are not persistent enough for this.
(revert): Move to ne location in file.
(parse_format): Use new functions to look for previously parsed
format strings and use them rather than re-parse. If not found, saves
the parsed format data for later use.
2009-04-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libfortran/37754
* io/transfer.c (formatted_transfer_scalar): Remove this function by
factoring it into two new functions, one for read and one for write,
eliminating all the conditionals for read or write mode.
(formatted transfer_scalar_read): New function.
(formatted transfer_scalar_write): New function.
(formatted_transfer): Use new functions.
2009-04-05 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/25561 libfortran/37754
* io/io.h (struct stream): Define new stream interface function
pointers, and inline functions for accessing it.
(struct fbuf): Use int instead of size_t, remove flushed element.
(mem_alloc_w): New prototype.
(mem_alloc_r): New prototype.
(stream_at_bof): Remove prototype.
(stream_at_eof): Remove prototype.
(file_position): Remove prototype.
(flush): Remove prototype.
(stream_offset): Remove prototype.
(unit_truncate): New prototype.
(read_block_form): Change to return pointer, int* argument.
(hit_eof): New prototype.
(fbuf_init): Change prototype.
(fbuf_reset): Change prototype.
(fbuf_alloc): Change prototype.
(fbuf_flush): Change prototype.
(fbuf_seek): Change prototype.
(fbuf_read): New prototype.
(fbuf_getc_refill): New prototype.
(fbuf_getc): New inline function.
* io/fbuf.c (fbuf_init): Use int, get rid of flushed.
(fbuf_debug): New function.
(fbuf_reset): Flush, and return position offset.
(fbuf_alloc): Simplify, don't flush, just realloc.
(fbuf_flush): Make usable for read mode, salvage remaining bytes.
(fbuf_seek): New whence argument.
(fbuf_read): New function.
(fbuf_getc_refill): New function.
* io/file_pos.c (formatted_backspace): Use new stream interface.
(unformatted_backspace): Likewise.
(st_backspace): Make sure format buffer is reset, use new stream
interface, use unit_truncate.
(st_endfile): Likewise.
(st_rewind): Likewise.
* io/intrinsics.c: Use new stream interface.
* io/list_read.c (push_char): Don't use u.p.scratch, use realloc
to resize.
(free_saved): Don't check u.p.scratch.
(next_char): Use new stream interface, use fbuf_getc() for external files.
(finish_list_read): flush format buffer.
(nml_query): Update to use modified interface:s
* io/open.c (test_endfile): Use new stream interface.
(edit_modes): Likewise.
(new_unit): Likewise, set bytes_left to 1 for stream files.
* io/read.c (read_l): Use new read_block_form interface.
(read_utf8): Likewise.
(read_utf8_char1): Likewise.
(read_default_char1): Likewise.
(read_utf8_char4): Likewise.
(read_default_char4): Likewise.
(read_a): Likewise.
(read_a_char4): Likewise.
(read_decimal): Likewise.
(read_radix): Likewise.
(read_f): Likewise.
* io/transfer.c (read_sf): Use fbuf_read and mem_alloc_r, remove
usage of u.p.line_buffer.
(read_block_form): Update interface to return pointer, use
fbuf_read for direct access.
(read_block_direct): Update to new stream interface.
(write_block): Use mem_alloc_w for internal I/O.
(write_buf): Update to new stream interface.
(formatted_transfer_scalar): Don't use u.p.line_buffer, use
fbuf_seek for external files.
(us_read): Update to new stream interface.
(us_write): Likewise.
(data_transfer_init): Always check if we switch modes and flush.
(skip_record): Use new stream interface, fix comparison.
(next_record_r): Check for and reset u.p.at_eof, use new stream
interface, use fbuf_getc for spacing.
(write_us_marker): Update to new stream interface, don't inline.
(next_record_w_unf): Likewise.
(sset): New function.
(next_record_w): Use new stream interface, use fbuf for printing
newline.
(next_record): Use new stream interface.
(finalize_transfer): Remove sfree call, use new stream interface.
(st_iolength_done): Don't use u.p.scratch.
(st_read): Don't check for end of file.
(st_read_done): Don't use u.p.scratch, use unit_truncate.
(hit_eof): New function.
* io/unit.c (init_units): Always init fbuf for formatted units.
(update_position): Use new stream interface.
(unit_truncate): New function.
(finish_last_advance_record): Use fbuf to print newline.
* io/unix.c: Remove unused SSIZE_MAX macro.
(BUFFER_SIZE): Make static const variable rather than macro.
(struct unix_stream): Remove dirty_offset, len, method,
small_buffer. Order elements by decreasing size.
(struct int_stream): Remove.
(move_pos_offset): Remove usage of dirty_offset.
(reset_stream): Remove.
(do_read): Rename to raw_read, update to match new stream
interface.
(do_write): Rename to raw_write, update to new stream interface.
(raw_seek): New function.
(raw_tell): New function.
(raw_truncate): New function.
(raw_close): New function.
(raw_flush): New function.
(raw_init): New function.
(fd_alloc): Remove.
(fd_alloc_r_at): Remove.
(fd_alloc_w_at): Remove.
(fd_sfree): Remove.
(fd_seek): Remove.
(fd_truncate): Remove.
(fd_sset): Remove.
(fd_read): Remove.
(fd_write): Remove.
(fd_close): Remove.
(fd_open): Remove.
(fd_flush): Rename to buf_flush, update to new stream interface
and unix_stream.
(buf_read): New function.
(buf_write): New function.
(buf_seek): New function.
(buf_tell): New function.
(buf_truncate): New function.
(buf_close): New function.
(buf_init): New function.
(mem_alloc_r_at): Rename to mem_alloc_r, change prototype.
(mem_alloc_w_at): Rename to mem_alloc_w, change prototype.
(mem_read): Change to match new stream interface.
(mem_write): Likewise.
(mem_seek): Likewise.
(mem_tell): Likewise.
(mem_truncate): Likewise.
(mem_close): Likewise.
(mem_flush): New function.
(mem_sfree): Remove.
(empty_internal_buffer): Cast to correct type.
(open_internal): Use correct type, init function pointers.
(fd_to_stream): Test whether to open file as buffered or raw.
(output_stream): Remove mode set.
(error_stream): Likewise.
(flush_all_units_1): Use new stream interface.
(flush_all_units): Likewise.
(stream_at_bof): Remove.
(stream_at_eof): Remove.
(file_position): Remove.
(file_length): Update logic to use stream interface.
(flush): Remove.
(stream_offset): Remove.
* io/write.c (write_utf8_char4): Use int instead of size_t.
(write_x): Extra safety check.
(namelist_write_newline): Use new stream interface.
From-SVN: r145571
This commit is contained in:
parent
941c3614de
commit
7812c78c34
|
|
@ -1,3 +1,204 @@
|
||||||
|
2009-04-05 Daniel Kraft <d@domob.eu>
|
||||||
|
|
||||||
|
PR fortran/38654
|
||||||
|
* io/read.c (read_f): Reworked to speed up floating point parsing.
|
||||||
|
(convert_real): Use pointer-casting instead of memcpy and temporaries.
|
||||||
|
|
||||||
|
2009-04-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libfortran/37754
|
||||||
|
* io/io.h (format_hash_entry): New structure for hash table.
|
||||||
|
(format_hash_table): The hash table itself.
|
||||||
|
(free_format_data): Revise function prototype.
|
||||||
|
(free_format_hash_table, init_format_hash,
|
||||||
|
free_format_hash): New function prototypes.
|
||||||
|
* io/unit.c (close_unit_1): Use free_format_hash_table.
|
||||||
|
* io/transfer.c (st_read_done, st_write_done): Free format data if
|
||||||
|
internal unit.
|
||||||
|
* io/format.c (free_format_hash_table): New function that frees any
|
||||||
|
memory allocated previously for cached format data.
|
||||||
|
(reset_node): New static helper function to reset the format counters
|
||||||
|
for a format node.
|
||||||
|
(reset_fnode_counters): New static function recursively calls reset_node
|
||||||
|
to traverse the fnode tree.
|
||||||
|
(format_hash): New simple hash function based on XOR, probabalistic,
|
||||||
|
tosses collisions.
|
||||||
|
(save_parsed_format): New static function to save the parsed format
|
||||||
|
data to use again.
|
||||||
|
(find_parsed_format): New static function searches the hash table
|
||||||
|
looking for a match.
|
||||||
|
(free_format_data): Revised to accept pointer to format data rather than
|
||||||
|
the dtp pointer so that the function can be used in more places.
|
||||||
|
(format_lex): Editorial.
|
||||||
|
(parse_format_list): Set flag used to determine of format data hashing
|
||||||
|
is to be used. Internal units are not persistent enough for this.
|
||||||
|
(revert): Move to ne location in file.
|
||||||
|
(parse_format): Use new functions to look for previously parsed
|
||||||
|
format strings and use them rather than re-parse. If not found, saves
|
||||||
|
the parsed format data for later use.
|
||||||
|
|
||||||
|
2009-04-05 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libfortran/37754
|
||||||
|
* io/transfer.c (formatted_transfer_scalar): Remove this function by
|
||||||
|
factoring it into two new functions, one for read and one for write,
|
||||||
|
eliminating all the conditionals for read or write mode.
|
||||||
|
(formatted transfer_scalar_read): New function.
|
||||||
|
(formatted transfer_scalar_write): New function.
|
||||||
|
(formatted_transfer): Use new functions.
|
||||||
|
|
||||||
|
2009-04-05 Janne Blomqvist <jb@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR libfortran/25561 libfortran/37754
|
||||||
|
* io/io.h (struct stream): Define new stream interface function
|
||||||
|
pointers, and inline functions for accessing it.
|
||||||
|
(struct fbuf): Use int instead of size_t, remove flushed element.
|
||||||
|
(mem_alloc_w): New prototype.
|
||||||
|
(mem_alloc_r): New prototype.
|
||||||
|
(stream_at_bof): Remove prototype.
|
||||||
|
(stream_at_eof): Remove prototype.
|
||||||
|
(file_position): Remove prototype.
|
||||||
|
(flush): Remove prototype.
|
||||||
|
(stream_offset): Remove prototype.
|
||||||
|
(unit_truncate): New prototype.
|
||||||
|
(read_block_form): Change to return pointer, int* argument.
|
||||||
|
(hit_eof): New prototype.
|
||||||
|
(fbuf_init): Change prototype.
|
||||||
|
(fbuf_reset): Change prototype.
|
||||||
|
(fbuf_alloc): Change prototype.
|
||||||
|
(fbuf_flush): Change prototype.
|
||||||
|
(fbuf_seek): Change prototype.
|
||||||
|
(fbuf_read): New prototype.
|
||||||
|
(fbuf_getc_refill): New prototype.
|
||||||
|
(fbuf_getc): New inline function.
|
||||||
|
* io/fbuf.c (fbuf_init): Use int, get rid of flushed.
|
||||||
|
(fbuf_debug): New function.
|
||||||
|
(fbuf_reset): Flush, and return position offset.
|
||||||
|
(fbuf_alloc): Simplify, don't flush, just realloc.
|
||||||
|
(fbuf_flush): Make usable for read mode, salvage remaining bytes.
|
||||||
|
(fbuf_seek): New whence argument.
|
||||||
|
(fbuf_read): New function.
|
||||||
|
(fbuf_getc_refill): New function.
|
||||||
|
* io/file_pos.c (formatted_backspace): Use new stream interface.
|
||||||
|
(unformatted_backspace): Likewise.
|
||||||
|
(st_backspace): Make sure format buffer is reset, use new stream
|
||||||
|
interface, use unit_truncate.
|
||||||
|
(st_endfile): Likewise.
|
||||||
|
(st_rewind): Likewise.
|
||||||
|
* io/intrinsics.c: Use new stream interface.
|
||||||
|
* io/list_read.c (push_char): Don't use u.p.scratch, use realloc
|
||||||
|
to resize.
|
||||||
|
(free_saved): Don't check u.p.scratch.
|
||||||
|
(next_char): Use new stream interface, use fbuf_getc() for external files.
|
||||||
|
(finish_list_read): flush format buffer.
|
||||||
|
(nml_query): Update to use modified interface:s
|
||||||
|
* io/open.c (test_endfile): Use new stream interface.
|
||||||
|
(edit_modes): Likewise.
|
||||||
|
(new_unit): Likewise, set bytes_left to 1 for stream files.
|
||||||
|
* io/read.c (read_l): Use new read_block_form interface.
|
||||||
|
(read_utf8): Likewise.
|
||||||
|
(read_utf8_char1): Likewise.
|
||||||
|
(read_default_char1): Likewise.
|
||||||
|
(read_utf8_char4): Likewise.
|
||||||
|
(read_default_char4): Likewise.
|
||||||
|
(read_a): Likewise.
|
||||||
|
(read_a_char4): Likewise.
|
||||||
|
(read_decimal): Likewise.
|
||||||
|
(read_radix): Likewise.
|
||||||
|
(read_f): Likewise.
|
||||||
|
* io/transfer.c (read_sf): Use fbuf_read and mem_alloc_r, remove
|
||||||
|
usage of u.p.line_buffer.
|
||||||
|
(read_block_form): Update interface to return pointer, use
|
||||||
|
fbuf_read for direct access.
|
||||||
|
(read_block_direct): Update to new stream interface.
|
||||||
|
(write_block): Use mem_alloc_w for internal I/O.
|
||||||
|
(write_buf): Update to new stream interface.
|
||||||
|
(formatted_transfer_scalar): Don't use u.p.line_buffer, use
|
||||||
|
fbuf_seek for external files.
|
||||||
|
(us_read): Update to new stream interface.
|
||||||
|
(us_write): Likewise.
|
||||||
|
(data_transfer_init): Always check if we switch modes and flush.
|
||||||
|
(skip_record): Use new stream interface, fix comparison.
|
||||||
|
(next_record_r): Check for and reset u.p.at_eof, use new stream
|
||||||
|
interface, use fbuf_getc for spacing.
|
||||||
|
(write_us_marker): Update to new stream interface, don't inline.
|
||||||
|
(next_record_w_unf): Likewise.
|
||||||
|
(sset): New function.
|
||||||
|
(next_record_w): Use new stream interface, use fbuf for printing
|
||||||
|
newline.
|
||||||
|
(next_record): Use new stream interface.
|
||||||
|
(finalize_transfer): Remove sfree call, use new stream interface.
|
||||||
|
(st_iolength_done): Don't use u.p.scratch.
|
||||||
|
(st_read): Don't check for end of file.
|
||||||
|
(st_read_done): Don't use u.p.scratch, use unit_truncate.
|
||||||
|
(hit_eof): New function.
|
||||||
|
* io/unit.c (init_units): Always init fbuf for formatted units.
|
||||||
|
(update_position): Use new stream interface.
|
||||||
|
(unit_truncate): New function.
|
||||||
|
(finish_last_advance_record): Use fbuf to print newline.
|
||||||
|
* io/unix.c: Remove unused SSIZE_MAX macro.
|
||||||
|
(BUFFER_SIZE): Make static const variable rather than macro.
|
||||||
|
(struct unix_stream): Remove dirty_offset, len, method,
|
||||||
|
small_buffer. Order elements by decreasing size.
|
||||||
|
(struct int_stream): Remove.
|
||||||
|
(move_pos_offset): Remove usage of dirty_offset.
|
||||||
|
(reset_stream): Remove.
|
||||||
|
(do_read): Rename to raw_read, update to match new stream
|
||||||
|
interface.
|
||||||
|
(do_write): Rename to raw_write, update to new stream interface.
|
||||||
|
(raw_seek): New function.
|
||||||
|
(raw_tell): New function.
|
||||||
|
(raw_truncate): New function.
|
||||||
|
(raw_close): New function.
|
||||||
|
(raw_flush): New function.
|
||||||
|
(raw_init): New function.
|
||||||
|
(fd_alloc): Remove.
|
||||||
|
(fd_alloc_r_at): Remove.
|
||||||
|
(fd_alloc_w_at): Remove.
|
||||||
|
(fd_sfree): Remove.
|
||||||
|
(fd_seek): Remove.
|
||||||
|
(fd_truncate): Remove.
|
||||||
|
(fd_sset): Remove.
|
||||||
|
(fd_read): Remove.
|
||||||
|
(fd_write): Remove.
|
||||||
|
(fd_close): Remove.
|
||||||
|
(fd_open): Remove.
|
||||||
|
(fd_flush): Rename to buf_flush, update to new stream interface
|
||||||
|
and unix_stream.
|
||||||
|
(buf_read): New function.
|
||||||
|
(buf_write): New function.
|
||||||
|
(buf_seek): New function.
|
||||||
|
(buf_tell): New function.
|
||||||
|
(buf_truncate): New function.
|
||||||
|
(buf_close): New function.
|
||||||
|
(buf_init): New function.
|
||||||
|
(mem_alloc_r_at): Rename to mem_alloc_r, change prototype.
|
||||||
|
(mem_alloc_w_at): Rename to mem_alloc_w, change prototype.
|
||||||
|
(mem_read): Change to match new stream interface.
|
||||||
|
(mem_write): Likewise.
|
||||||
|
(mem_seek): Likewise.
|
||||||
|
(mem_tell): Likewise.
|
||||||
|
(mem_truncate): Likewise.
|
||||||
|
(mem_close): Likewise.
|
||||||
|
(mem_flush): New function.
|
||||||
|
(mem_sfree): Remove.
|
||||||
|
(empty_internal_buffer): Cast to correct type.
|
||||||
|
(open_internal): Use correct type, init function pointers.
|
||||||
|
(fd_to_stream): Test whether to open file as buffered or raw.
|
||||||
|
(output_stream): Remove mode set.
|
||||||
|
(error_stream): Likewise.
|
||||||
|
(flush_all_units_1): Use new stream interface.
|
||||||
|
(flush_all_units): Likewise.
|
||||||
|
(stream_at_bof): Remove.
|
||||||
|
(stream_at_eof): Remove.
|
||||||
|
(file_position): Remove.
|
||||||
|
(file_length): Update logic to use stream interface.
|
||||||
|
(flush): Remove.
|
||||||
|
(stream_offset): Remove.
|
||||||
|
* io/write.c (write_utf8_char4): Use int instead of size_t.
|
||||||
|
(write_x): Extra safety check.
|
||||||
|
(namelist_write_newline): Use new stream interface.
|
||||||
|
|
||||||
2009-03-29 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
2009-03-29 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
||||||
|
|
||||||
PR fortran/33595
|
PR fortran/33595
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,11 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
//#define FBUF_DEBUG
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fbuf_init (gfc_unit * u, size_t len)
|
fbuf_init (gfc_unit * u, int len)
|
||||||
{
|
{
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
len = 512; /* Default size. */
|
len = 512; /* Default size. */
|
||||||
|
|
@ -42,14 +45,7 @@ fbuf_init (gfc_unit * u, size_t len)
|
||||||
u->fbuf = get_mem (sizeof (fbuf));
|
u->fbuf = get_mem (sizeof (fbuf));
|
||||||
u->fbuf->buf = get_mem (len);
|
u->fbuf->buf = get_mem (len);
|
||||||
u->fbuf->len = len;
|
u->fbuf->len = len;
|
||||||
u->fbuf->act = u->fbuf->flushed = u->fbuf->pos = 0;
|
u->fbuf->act = u->fbuf->pos = 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
fbuf_reset (gfc_unit * u)
|
|
||||||
{
|
|
||||||
u->fbuf->act = u->fbuf->flushed = u->fbuf->pos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -61,58 +57,79 @@ fbuf_destroy (gfc_unit * u)
|
||||||
if (u->fbuf->buf)
|
if (u->fbuf->buf)
|
||||||
free_mem (u->fbuf->buf);
|
free_mem (u->fbuf->buf);
|
||||||
free_mem (u->fbuf);
|
free_mem (u->fbuf);
|
||||||
|
u->fbuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
#ifdef FBUF_DEBUG
|
||||||
|
fbuf_debug (gfc_unit * u, const char * format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vfprintf(stderr, format, args);
|
||||||
|
va_end(args);
|
||||||
|
fprintf (stderr, "fbuf_debug pos: %d, act: %d, buf: ''",
|
||||||
|
u->fbuf->pos, u->fbuf->act);
|
||||||
|
for (int ii = 0; ii < u->fbuf->act; ii++)
|
||||||
|
{
|
||||||
|
putc (u->fbuf->buf[ii], stderr);
|
||||||
|
}
|
||||||
|
fprintf (stderr, "''\n");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
fbuf_debug (gfc_unit * u __attribute__ ((unused)),
|
||||||
|
const char * format __attribute__ ((unused)),
|
||||||
|
...) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* You should probably call this before doing a physical seek on the
|
||||||
|
underlying device. Returns how much the physical position was
|
||||||
|
modified. */
|
||||||
|
|
||||||
|
int
|
||||||
|
fbuf_reset (gfc_unit * u)
|
||||||
|
{
|
||||||
|
int seekval = 0;
|
||||||
|
|
||||||
|
if (!u->fbuf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fbuf_debug (u, "fbuf_reset: ");
|
||||||
|
fbuf_flush (u, u->mode);
|
||||||
|
/* If we read past the current position, seek the underlying device
|
||||||
|
back. */
|
||||||
|
if (u->mode == READING && u->fbuf->act > u->fbuf->pos)
|
||||||
|
{
|
||||||
|
seekval = - (u->fbuf->act - u->fbuf->pos);
|
||||||
|
fbuf_debug (u, "fbuf_reset seekval %d, ", seekval);
|
||||||
|
}
|
||||||
|
u->fbuf->act = u->fbuf->pos = 0;
|
||||||
|
return seekval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a pointer to the current position in the buffer, and increase
|
/* Return a pointer to the current position in the buffer, and increase
|
||||||
the pointer by len. Makes sure that the buffer is big enough,
|
the pointer by len. Makes sure that the buffer is big enough,
|
||||||
reallocating if necessary. If the buffer is not big enough, there are
|
reallocating if necessary. */
|
||||||
three cases to consider:
|
|
||||||
1. If we haven't flushed anything, realloc
|
|
||||||
2. If we have flushed enough that by discarding the flushed bytes
|
|
||||||
the request fits into the buffer, do that.
|
|
||||||
3. Else allocate a new buffer, memcpy unflushed active bytes from old
|
|
||||||
buffer. */
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
fbuf_alloc (gfc_unit * u, size_t len)
|
fbuf_alloc (gfc_unit * u, int len)
|
||||||
{
|
{
|
||||||
size_t newlen;
|
int newlen;
|
||||||
char *dest;
|
char *dest;
|
||||||
|
fbuf_debug (u, "fbuf_alloc len %d, ", len);
|
||||||
if (u->fbuf->pos + len > u->fbuf->len)
|
if (u->fbuf->pos + len > u->fbuf->len)
|
||||||
{
|
{
|
||||||
if (u->fbuf->flushed == 0)
|
/* Round up to nearest multiple of the current buffer length. */
|
||||||
{
|
newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
|
||||||
/* Round up to nearest multiple of the current buffer length. */
|
dest = realloc (u->fbuf->buf, newlen);
|
||||||
newlen = ((u->fbuf->pos + len) / u->fbuf->len + 1) * u->fbuf->len;
|
if (dest == NULL)
|
||||||
dest = realloc (u->fbuf->buf, newlen);
|
return NULL;
|
||||||
if (dest == NULL)
|
u->fbuf->buf = dest;
|
||||||
return NULL;
|
u->fbuf->len = newlen;
|
||||||
u->fbuf->buf = dest;
|
|
||||||
u->fbuf->len = newlen;
|
|
||||||
}
|
|
||||||
else if (u->fbuf->act - u->fbuf->flushed + len < u->fbuf->len)
|
|
||||||
{
|
|
||||||
memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->flushed,
|
|
||||||
u->fbuf->act - u->fbuf->flushed);
|
|
||||||
u->fbuf->act -= u->fbuf->flushed;
|
|
||||||
u->fbuf->pos -= u->fbuf->flushed;
|
|
||||||
u->fbuf->flushed = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Most general case, flushed != 0, request doesn't fit. */
|
|
||||||
newlen = ((u->fbuf->pos - u->fbuf->flushed + len)
|
|
||||||
/ u->fbuf->len + 1) * u->fbuf->len;
|
|
||||||
dest = get_mem (newlen);
|
|
||||||
memcpy (dest, u->fbuf->buf + u->fbuf->flushed,
|
|
||||||
u->fbuf->act - u->fbuf->flushed);
|
|
||||||
u->fbuf->act -= u->fbuf->flushed;
|
|
||||||
u->fbuf->pos -= u->fbuf->flushed;
|
|
||||||
u->fbuf->flushed = 0;
|
|
||||||
u->fbuf->buf = dest;
|
|
||||||
u->fbuf->len = newlen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = u->fbuf->buf + u->fbuf->pos;
|
dest = u->fbuf->buf + u->fbuf->pos;
|
||||||
|
|
@ -123,42 +140,134 @@ fbuf_alloc (gfc_unit * u, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* mode argument is WRITING for write mode and READING for read
|
||||||
|
mode. Return value is 0 for success, -1 on failure. */
|
||||||
|
|
||||||
int
|
int
|
||||||
fbuf_flush (gfc_unit * u, int record_done)
|
fbuf_flush (gfc_unit * u, unit_mode mode)
|
||||||
{
|
{
|
||||||
int status;
|
int nwritten;
|
||||||
size_t nbytes;
|
|
||||||
|
|
||||||
if (!u->fbuf)
|
if (!u->fbuf)
|
||||||
return 0;
|
return 0;
|
||||||
if (u->fbuf->act - u->fbuf->flushed != 0)
|
|
||||||
|
fbuf_debug (u, "fbuf_flush with mode %d: ", mode);
|
||||||
|
|
||||||
|
if (mode == WRITING)
|
||||||
{
|
{
|
||||||
if (record_done)
|
if (u->fbuf->pos > 0)
|
||||||
nbytes = u->fbuf->act - u->fbuf->flushed;
|
{
|
||||||
else
|
nwritten = swrite (u->s, u->fbuf->buf, u->fbuf->pos);
|
||||||
nbytes = u->fbuf->pos - u->fbuf->flushed;
|
if (nwritten < 0)
|
||||||
status = swrite (u->s, u->fbuf->buf + u->fbuf->flushed, &nbytes);
|
return -1;
|
||||||
u->fbuf->flushed += nbytes;
|
}
|
||||||
}
|
}
|
||||||
else
|
/* Salvage remaining bytes for both reading and writing. This
|
||||||
status = 0;
|
happens with the combination of advance='no' and T edit
|
||||||
if (record_done)
|
descriptors leaving the final position somewhere not at the end
|
||||||
fbuf_reset (u);
|
of the record. For reading, this also happens if we sread() past
|
||||||
return status;
|
the record boundary. */
|
||||||
|
if (u->fbuf->act > u->fbuf->pos && u->fbuf->pos > 0)
|
||||||
|
memmove (u->fbuf->buf, u->fbuf->buf + u->fbuf->pos,
|
||||||
|
u->fbuf->act - u->fbuf->pos);
|
||||||
|
|
||||||
|
u->fbuf->act -= u->fbuf->pos;
|
||||||
|
u->fbuf->pos = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fbuf_seek (gfc_unit * u, gfc_offset off)
|
fbuf_seek (gfc_unit * u, int off, int whence)
|
||||||
{
|
{
|
||||||
gfc_offset pos = u->fbuf->pos + off;
|
if (!u->fbuf)
|
||||||
/* Moving to the left past the flushed marked would imply moving past
|
|
||||||
the left tab limit, which is never allowed. So return error if
|
|
||||||
that is attempted. */
|
|
||||||
if (pos < (gfc_offset) u->fbuf->flushed)
|
|
||||||
return -1;
|
return -1;
|
||||||
u->fbuf->pos = pos;
|
|
||||||
return 0;
|
switch (whence)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
off += u->fbuf->pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
off += u->fbuf->act;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fbuf_debug (u, "fbuf_seek, off %d ", off);
|
||||||
|
/* The start of the buffer is always equal to the left tab
|
||||||
|
limit. Moving to the left past the buffer is illegal in C and
|
||||||
|
would also imply moving past the left tab limit, which is never
|
||||||
|
allowed in Fortran. Similarly, seeking past the end of the buffer
|
||||||
|
is not possible, in that case the user must make sure to allocate
|
||||||
|
space with fbuf_alloc(). So return error if that is
|
||||||
|
attempted. */
|
||||||
|
if (off < 0 || off > u->fbuf->act)
|
||||||
|
return -1;
|
||||||
|
u->fbuf->pos = off;
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fill the buffer with bytes for reading. Returns a pointer to start
|
||||||
|
reading from. If we hit EOF, returns a short read count. If any
|
||||||
|
other error occurs, return NULL. After reading, the caller is
|
||||||
|
expected to call fbuf_seek to update the position with the number
|
||||||
|
of bytes actually processed. */
|
||||||
|
|
||||||
|
char *
|
||||||
|
fbuf_read (gfc_unit * u, int * len)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
int oldact, oldpos;
|
||||||
|
int readlen = 0;
|
||||||
|
|
||||||
|
fbuf_debug (u, "fbuf_read, len %d: ", *len);
|
||||||
|
oldact = u->fbuf->act;
|
||||||
|
oldpos = u->fbuf->pos;
|
||||||
|
ptr = fbuf_alloc (u, *len);
|
||||||
|
u->fbuf->pos = oldpos;
|
||||||
|
if (oldpos + *len > oldact)
|
||||||
|
{
|
||||||
|
fbuf_debug (u, "reading %d bytes starting at %d ",
|
||||||
|
oldpos + *len - oldact, oldact);
|
||||||
|
readlen = sread (u->s, u->fbuf->buf + oldact, oldpos + *len - oldact);
|
||||||
|
if (readlen < 0)
|
||||||
|
return NULL;
|
||||||
|
*len = oldact - oldpos + readlen;
|
||||||
|
}
|
||||||
|
u->fbuf->act = oldact + readlen;
|
||||||
|
fbuf_debug (u, "fbuf_read done: ");
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* When the fbuf_getc() inline function runs out of buffer space, it
|
||||||
|
calls this function to fill the buffer with bytes for
|
||||||
|
reading. Never call this function directly. */
|
||||||
|
|
||||||
|
int
|
||||||
|
fbuf_getc_refill (gfc_unit * u)
|
||||||
|
{
|
||||||
|
int nread;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
fbuf_debug (u, "fbuf_getc_refill ");
|
||||||
|
|
||||||
|
/* Read 80 bytes (average line length?). This is a compromise
|
||||||
|
between not needing to call the read() syscall all the time and
|
||||||
|
not having to memmove unnecessary stuff when switching to the
|
||||||
|
next record. */
|
||||||
|
nread = 80;
|
||||||
|
|
||||||
|
p = fbuf_read (u, &nread);
|
||||||
|
|
||||||
|
if (p && nread > 0)
|
||||||
|
return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
|
||||||
|
else
|
||||||
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,17 @@ formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
{
|
{
|
||||||
gfc_offset base;
|
gfc_offset base;
|
||||||
char p[READ_CHUNK];
|
char p[READ_CHUNK];
|
||||||
size_t n;
|
ssize_t n;
|
||||||
|
|
||||||
base = file_position (u->s) - 1;
|
base = stell (u->s) - 1;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
n = (base < READ_CHUNK) ? base : READ_CHUNK;
|
n = (base < READ_CHUNK) ? base : READ_CHUNK;
|
||||||
base -= n;
|
base -= n;
|
||||||
if (sseek (u->s, base) == FAILURE)
|
if (sseek (u->s, base, SEEK_SET) < 0)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
if (sread (u->s, p, &n) != 0)
|
if (sread (u->s, p, n) != n)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
|
|
||||||
/* We have moved backwards from the current position, it should
|
/* We have moved backwards from the current position, it should
|
||||||
|
|
@ -81,7 +81,7 @@ formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
|
|
||||||
/* base is the new pointer. Seek to it exactly. */
|
/* base is the new pointer. Seek to it exactly. */
|
||||||
done:
|
done:
|
||||||
if (sseek (u->s, base) == FAILURE)
|
if (sseek (u->s, base, SEEK_SET) < 0)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
u->last_record--;
|
u->last_record--;
|
||||||
u->endfile = NO_ENDFILE;
|
u->endfile = NO_ENDFILE;
|
||||||
|
|
@ -100,10 +100,10 @@ formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
static void
|
static void
|
||||||
unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
{
|
{
|
||||||
gfc_offset m, new;
|
gfc_offset m, slen;
|
||||||
GFC_INTEGER_4 m4;
|
GFC_INTEGER_4 m4;
|
||||||
GFC_INTEGER_8 m8;
|
GFC_INTEGER_8 m8;
|
||||||
size_t length;
|
ssize_t length;
|
||||||
int continued;
|
int continued;
|
||||||
char p[sizeof (GFC_INTEGER_8)];
|
char p[sizeof (GFC_INTEGER_8)];
|
||||||
|
|
||||||
|
|
@ -114,9 +114,10 @@ unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (sseek (u->s, file_position (u->s) - length) == FAILURE)
|
slen = - (gfc_offset) length;
|
||||||
|
if (sseek (u->s, slen, SEEK_CUR) < 0)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
if (sread (u->s, p, &length) != 0)
|
if (sread (u->s, p, length) != length)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
|
|
||||||
/* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
|
/* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
|
||||||
|
|
@ -164,10 +165,7 @@ unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
|
||||||
if (continued)
|
if (continued)
|
||||||
m = -m;
|
m = -m;
|
||||||
|
|
||||||
if ((new = file_position (u->s) - m - 2*length) < 0)
|
if (sseek (u->s, -m -2 * length, SEEK_CUR) < 0)
|
||||||
new = 0;
|
|
||||||
|
|
||||||
if (sseek (u->s, new) == FAILURE)
|
|
||||||
goto io_error;
|
goto io_error;
|
||||||
} while (continued);
|
} while (continued);
|
||||||
|
|
||||||
|
|
@ -206,15 +204,21 @@ st_backspace (st_parameter_filepos *fpp)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->flags.access == ACCESS_STREAM && u->flags.form == FORM_UNFORMATTED)
|
if (u->flags.access == ACCESS_STREAM && u->flags.form == FORM_UNFORMATTED)
|
||||||
{
|
{
|
||||||
generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
|
generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
|
||||||
"Cannot BACKSPACE an unformatted stream file");
|
"Cannot BACKSPACE an unformatted stream file");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure format buffer is flushed and reset. */
|
||||||
|
if (u->flags.form == FORM_FORMATTED)
|
||||||
|
{
|
||||||
|
int pos = fbuf_reset (u);
|
||||||
|
if (pos != 0)
|
||||||
|
sseek (u->s, pos, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure format buffer is flushed. */
|
|
||||||
fbuf_flush (u, 1);
|
|
||||||
|
|
||||||
/* Check for special cases involving the ENDFILE record first. */
|
/* Check for special cases involving the ENDFILE record first. */
|
||||||
|
|
||||||
|
|
@ -222,11 +226,11 @@ st_backspace (st_parameter_filepos *fpp)
|
||||||
{
|
{
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
u->flags.position = POSITION_APPEND;
|
u->flags.position = POSITION_APPEND;
|
||||||
flush (u->s);
|
sflush (u->s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (file_position (u->s) == 0)
|
if (stell (u->s) == 0)
|
||||||
{
|
{
|
||||||
u->flags.position = POSITION_REWIND;
|
u->flags.position = POSITION_REWIND;
|
||||||
goto done; /* Common special case */
|
goto done; /* Common special case */
|
||||||
|
|
@ -243,8 +247,7 @@ st_backspace (st_parameter_filepos *fpp)
|
||||||
|
|
||||||
u->previous_nonadvancing_write = 0;
|
u->previous_nonadvancing_write = 0;
|
||||||
|
|
||||||
flush (u->s);
|
unit_truncate (u, stell (u->s), &fpp->common);
|
||||||
struncate (u->s);
|
|
||||||
u->mode = READING;
|
u->mode = READING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,7 +256,7 @@ st_backspace (st_parameter_filepos *fpp)
|
||||||
else
|
else
|
||||||
unformatted_backspace (fpp, u);
|
unformatted_backspace (fpp, u);
|
||||||
|
|
||||||
update_position (u);
|
u->flags.position = POSITION_UNSPECIFIED;
|
||||||
u->endfile = NO_ENDFILE;
|
u->endfile = NO_ENDFILE;
|
||||||
u->current_record = 0;
|
u->current_record = 0;
|
||||||
u->bytes_left = 0;
|
u->bytes_left = 0;
|
||||||
|
|
@ -305,10 +308,10 @@ st_endfile (st_parameter_filepos *fpp)
|
||||||
next_record (&dtp, 1);
|
next_record (&dtp, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
flush (u->s);
|
unit_truncate (u, stell (u->s), &fpp->common);
|
||||||
struncate (u->s);
|
|
||||||
u->endfile = AFTER_ENDFILE;
|
u->endfile = AFTER_ENDFILE;
|
||||||
update_position (u);
|
if (0 == stell (u->s))
|
||||||
|
u->flags.position = POSITION_REWIND;
|
||||||
done:
|
done:
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
}
|
}
|
||||||
|
|
@ -347,14 +350,25 @@ st_rewind (st_parameter_filepos *fpp)
|
||||||
written record is the last record in the file, so truncate the
|
written record is the last record in the file, so truncate the
|
||||||
file now. Reset to read mode so two consecutive rewind
|
file now. Reset to read mode so two consecutive rewind
|
||||||
statements do not delete the file contents. */
|
statements do not delete the file contents. */
|
||||||
flush (u->s);
|
if (u->mode == WRITING)
|
||||||
if (u->mode == WRITING && u->flags.access != ACCESS_STREAM)
|
{
|
||||||
struncate (u->s);
|
/* unit_truncate takes care of flushing. */
|
||||||
|
unit_truncate (u, stell (u->s), &fpp->common);
|
||||||
|
/* .. but we still need to reset since we're going to seek. */
|
||||||
|
fbuf_reset (u);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Make sure buffers are reset. */
|
||||||
|
if (u->flags.form == FORM_FORMATTED)
|
||||||
|
fbuf_reset (u);
|
||||||
|
sflush (u->s);
|
||||||
|
}
|
||||||
|
|
||||||
u->mode = READING;
|
u->mode = READING;
|
||||||
u->last_record = 0;
|
u->last_record = 0;
|
||||||
|
|
||||||
if (file_position (u->s) != 0 && sseek (u->s, 0) == FAILURE)
|
if (sseek (u->s, 0, SEEK_SET) < 0)
|
||||||
generate_error (&fpp->common, LIBERROR_OS, NULL);
|
generate_error (&fpp->common, LIBERROR_OS, NULL);
|
||||||
|
|
||||||
/* Handle special files like /dev/null differently. */
|
/* Handle special files like /dev/null differently. */
|
||||||
|
|
@ -366,7 +380,7 @@ st_rewind (st_parameter_filepos *fpp)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Set this for compatibilty with g77 for /dev/null. */
|
/* Set this for compatibilty with g77 for /dev/null. */
|
||||||
if (file_length (u->s) == 0 && file_position (u->s) == 0)
|
if (file_length (u->s) == 0 && stell (u->s) == 0)
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
/* Future refinements on special files can go here. */
|
/* Future refinements on special files can go here. */
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +411,11 @@ st_flush (st_parameter_filepos *fpp)
|
||||||
u = find_unit (fpp->common.unit);
|
u = find_unit (fpp->common.unit);
|
||||||
if (u != NULL)
|
if (u != NULL)
|
||||||
{
|
{
|
||||||
flush (u->s);
|
/* Make sure format buffer is flushed. */
|
||||||
|
if (u->flags.form == FORM_FORMATTED)
|
||||||
|
fbuf_flush (u, u->mode);
|
||||||
|
|
||||||
|
sflush (u->s);
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define FARRAY_SIZE 64
|
#define FARRAY_SIZE 64
|
||||||
|
|
||||||
|
|
@ -63,7 +64,7 @@ format_data;
|
||||||
static const fnode colon_node = { FMT_COLON, 0, NULL, NULL, {{ 0, 0, 0 }}, 0,
|
static const fnode colon_node = { FMT_COLON, 0, NULL, NULL, {{ 0, 0, 0 }}, 0,
|
||||||
NULL };
|
NULL };
|
||||||
|
|
||||||
/* Error messages */
|
/* Error messages. */
|
||||||
|
|
||||||
static const char posint_required[] = "Positive width required in format",
|
static const char posint_required[] = "Positive width required in format",
|
||||||
period_required[] = "Period required in format",
|
period_required[] = "Period required in format",
|
||||||
|
|
@ -75,6 +76,129 @@ static const char posint_required[] = "Positive width required in format",
|
||||||
reversion_error[] = "Exhausted data descriptors in format",
|
reversion_error[] = "Exhausted data descriptors in format",
|
||||||
zero_width[] = "Zero width in format descriptor";
|
zero_width[] = "Zero width in format descriptor";
|
||||||
|
|
||||||
|
/* The following routines support caching format data from parsed format strings
|
||||||
|
into a hash table. This avoids repeatedly parsing duplicate format strings
|
||||||
|
or format strings in I/O statements that are repeated in loops. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Traverse the table and free all data. */
|
||||||
|
|
||||||
|
void
|
||||||
|
free_format_hash_table (gfc_unit *u)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* free_format_data handles any NULL pointers. */
|
||||||
|
for (i = 0; i < FORMAT_HASH_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (u->format_hash_table[i].hashed_fmt != NULL)
|
||||||
|
free_format_data (u->format_hash_table[i].hashed_fmt);
|
||||||
|
u->format_hash_table[i].hashed_fmt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse the format_data structure and reset the fnode counters. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
reset_node (fnode *fn)
|
||||||
|
{
|
||||||
|
fnode *f;
|
||||||
|
|
||||||
|
fn->count = 0;
|
||||||
|
fn->current = NULL;
|
||||||
|
|
||||||
|
if (fn->format != FMT_LPAREN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (f = fn->u.child; f; f = f->next)
|
||||||
|
{
|
||||||
|
if (f->format == FMT_RPAREN)
|
||||||
|
break;
|
||||||
|
reset_node (f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reset_fnode_counters (st_parameter_dt *dtp)
|
||||||
|
{
|
||||||
|
fnode *f;
|
||||||
|
format_data *fmt;
|
||||||
|
|
||||||
|
fmt = dtp->u.p.fmt;
|
||||||
|
|
||||||
|
/* Clear this pointer at the head so things start at the right place. */
|
||||||
|
fmt->array.array[0].current = NULL;
|
||||||
|
|
||||||
|
for (f = fmt->last->array[0].u.child; f; f = f->next)
|
||||||
|
reset_node (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A simple hashing function to generate an index into the hash table. */
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint32_t format_hash (st_parameter_dt *dtp)
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
size_t key_len;
|
||||||
|
uint32_t hash = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Hash the format string. Super simple, but what the heck! */
|
||||||
|
key = dtp->format;
|
||||||
|
key_len = dtp->format_len;
|
||||||
|
for (i = 0; i < key_len; i++)
|
||||||
|
hash ^= key[i];
|
||||||
|
hash &= (FORMAT_HASH_SIZE - 1);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_parsed_format (st_parameter_dt *dtp)
|
||||||
|
{
|
||||||
|
uint32_t hash;
|
||||||
|
gfc_unit *u;
|
||||||
|
|
||||||
|
hash = format_hash (dtp);
|
||||||
|
u = dtp->u.p.current_unit;
|
||||||
|
|
||||||
|
/* Index into the hash table. We are simply replacing whatever is there
|
||||||
|
relying on probability. */
|
||||||
|
if (u->format_hash_table[hash].hashed_fmt != NULL)
|
||||||
|
free_format_data (u->format_hash_table[hash].hashed_fmt);
|
||||||
|
u->format_hash_table[hash].hashed_fmt = NULL;
|
||||||
|
|
||||||
|
u->format_hash_table[hash].key = dtp->format;
|
||||||
|
u->format_hash_table[hash].key_len = dtp->format_len;
|
||||||
|
u->format_hash_table[hash].hashed_fmt = dtp->u.p.fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static format_data *
|
||||||
|
find_parsed_format (st_parameter_dt *dtp)
|
||||||
|
{
|
||||||
|
uint32_t hash;
|
||||||
|
gfc_unit *u;
|
||||||
|
|
||||||
|
hash = format_hash (dtp);
|
||||||
|
u = dtp->u.p.current_unit;
|
||||||
|
|
||||||
|
if (u->format_hash_table[hash].key != NULL)
|
||||||
|
{
|
||||||
|
/* See if it matches. */
|
||||||
|
if (u->format_hash_table[hash].key_len == dtp->format_len)
|
||||||
|
{
|
||||||
|
/* So far so good. */
|
||||||
|
if (strncmp (u->format_hash_table[hash].key,
|
||||||
|
dtp->format, dtp->format_len) == 0)
|
||||||
|
return u->format_hash_table[hash].hashed_fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* next_char()-- Return the next character in the format string.
|
/* next_char()-- Return the next character in the format string.
|
||||||
* Returns -1 when the string is done. If the literal flag is set,
|
* Returns -1 when the string is done. If the literal flag is set,
|
||||||
* spaces are significant, otherwise they are not. */
|
* spaces are significant, otherwise they are not. */
|
||||||
|
|
@ -90,7 +214,8 @@ next_char (format_data *fmt, int literal)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
fmt->format_string_len--;
|
fmt->format_string_len--;
|
||||||
fmt->error_element = c = toupper (*fmt->format_string++);
|
c = toupper (*fmt->format_string++);
|
||||||
|
fmt->error_element = c;
|
||||||
}
|
}
|
||||||
while ((c == ' ' || c == '\t') && !literal);
|
while ((c == ' ' || c == '\t') && !literal);
|
||||||
|
|
||||||
|
|
@ -141,10 +266,10 @@ get_fnode (format_data *fmt, fnode **head, fnode **tail, format_token t)
|
||||||
/* free_format_data()-- Free all allocated format data. */
|
/* free_format_data()-- Free all allocated format data. */
|
||||||
|
|
||||||
void
|
void
|
||||||
free_format_data (st_parameter_dt *dtp)
|
free_format_data (format_data *fmt)
|
||||||
{
|
{
|
||||||
fnode_array *fa, *fa_next;
|
fnode_array *fa, *fa_next;
|
||||||
format_data *fmt = dtp->u.p.fmt;
|
|
||||||
|
|
||||||
if (fmt == NULL)
|
if (fmt == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
@ -156,7 +281,7 @@ free_format_data (st_parameter_dt *dtp)
|
||||||
}
|
}
|
||||||
|
|
||||||
free_mem (fmt);
|
free_mem (fmt);
|
||||||
dtp->u.p.fmt = NULL;
|
fmt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -184,6 +309,14 @@ format_lex (format_data *fmt)
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
case '(':
|
||||||
|
token = FMT_LPAREN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
token = FMT_RPAREN;
|
||||||
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
negative_flag = 1;
|
negative_flag = 1;
|
||||||
/* Fall Through */
|
/* Fall Through */
|
||||||
|
|
@ -276,14 +409,6 @@ format_lex (format_data *fmt)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '(':
|
|
||||||
token = FMT_LPAREN;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ')':
|
|
||||||
token = FMT_RPAREN;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'X':
|
case 'X':
|
||||||
token = FMT_X;
|
token = FMT_X;
|
||||||
break;
|
break;
|
||||||
|
|
@ -455,8 +580,10 @@ parse_format_list (st_parameter_dt *dtp)
|
||||||
format_token t, u, t2;
|
format_token t, u, t2;
|
||||||
int repeat;
|
int repeat;
|
||||||
format_data *fmt = dtp->u.p.fmt;
|
format_data *fmt = dtp->u.p.fmt;
|
||||||
|
bool save_format;
|
||||||
|
|
||||||
head = tail = NULL;
|
head = tail = NULL;
|
||||||
|
save_format = !is_internal_unit (dtp);
|
||||||
|
|
||||||
/* Get the next format item */
|
/* Get the next format item */
|
||||||
format_item:
|
format_item:
|
||||||
|
|
@ -567,6 +694,7 @@ parse_format_list (st_parameter_dt *dtp)
|
||||||
case FMT_DP:
|
case FMT_DP:
|
||||||
notify_std (&dtp->common, GFC_STD_F2003, "Fortran 2003: DC or DP "
|
notify_std (&dtp->common, GFC_STD_F2003, "Fortran 2003: DC or DP "
|
||||||
"descriptor not allowed");
|
"descriptor not allowed");
|
||||||
|
save_format = true;
|
||||||
/* Fall through. */
|
/* Fall through. */
|
||||||
case FMT_S:
|
case FMT_S:
|
||||||
case FMT_SS:
|
case FMT_SS:
|
||||||
|
|
@ -592,6 +720,7 @@ parse_format_list (st_parameter_dt *dtp)
|
||||||
get_fnode (fmt, &head, &tail, FMT_DOLLAR);
|
get_fnode (fmt, &head, &tail, FMT_DOLLAR);
|
||||||
tail->repeat = 1;
|
tail->repeat = 1;
|
||||||
notify_std (&dtp->common, GFC_STD_GNU, "Extension: $ descriptor");
|
notify_std (&dtp->common, GFC_STD_GNU, "Extension: $ descriptor");
|
||||||
|
save_format = false;
|
||||||
goto between_desc;
|
goto between_desc;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -689,6 +818,7 @@ parse_format_list (st_parameter_dt *dtp)
|
||||||
fmt->saved_token = t;
|
fmt->saved_token = t;
|
||||||
fmt->value = 1; /* Default width */
|
fmt->value = 1; /* Default width */
|
||||||
notify_std (&dtp->common, GFC_STD_GNU, posint_required);
|
notify_std (&dtp->common, GFC_STD_GNU, posint_required);
|
||||||
|
save_format = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -999,6 +1129,33 @@ format_error (st_parameter_dt *dtp, const fnode *f, const char *message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* revert()-- Do reversion of the format. Control reverts to the left
|
||||||
|
* parenthesis that matches the rightmost right parenthesis. From our
|
||||||
|
* tree structure, we are looking for the rightmost parenthesis node
|
||||||
|
* at the second level, the first level always being a single
|
||||||
|
* parenthesis node. If this node doesn't exit, we use the top
|
||||||
|
* level. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
revert (st_parameter_dt *dtp)
|
||||||
|
{
|
||||||
|
fnode *f, *r;
|
||||||
|
format_data *fmt = dtp->u.p.fmt;
|
||||||
|
|
||||||
|
dtp->u.p.reversion_flag = 1;
|
||||||
|
|
||||||
|
r = NULL;
|
||||||
|
|
||||||
|
for (f = fmt->array.array[0].u.child; f; f = f->next)
|
||||||
|
if (f->format == FMT_LPAREN)
|
||||||
|
r = f;
|
||||||
|
|
||||||
|
/* If r is NULL because no node was found, the whole tree will be used */
|
||||||
|
|
||||||
|
fmt->array.array[0].current = r;
|
||||||
|
fmt->array.array[0].count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse_format()-- Parse a format string. */
|
/* parse_format()-- Parse a format string. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1006,6 +1163,21 @@ parse_format (st_parameter_dt *dtp)
|
||||||
{
|
{
|
||||||
format_data *fmt;
|
format_data *fmt;
|
||||||
|
|
||||||
|
/* Lookup format string to see if it has already been parsed. */
|
||||||
|
|
||||||
|
dtp->u.p.fmt = find_parsed_format (dtp);
|
||||||
|
|
||||||
|
if (dtp->u.p.fmt != NULL)
|
||||||
|
{
|
||||||
|
dtp->u.p.fmt->reversion_ok = 0;
|
||||||
|
dtp->u.p.fmt->saved_token = FMT_NONE;
|
||||||
|
dtp->u.p.fmt->saved_format = NULL;
|
||||||
|
reset_fnode_counters (dtp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found so proceed as follows. */
|
||||||
|
|
||||||
dtp->u.p.fmt = fmt = get_mem (sizeof (format_data));
|
dtp->u.p.fmt = fmt = get_mem (sizeof (format_data));
|
||||||
fmt->format_string = dtp->format;
|
fmt->format_string = dtp->format;
|
||||||
fmt->format_string_len = dtp->format_len;
|
fmt->format_string_len = dtp->format_len;
|
||||||
|
|
@ -1037,35 +1209,12 @@ parse_format (st_parameter_dt *dtp)
|
||||||
fmt->error = "Missing initial left parenthesis in format";
|
fmt->error = "Missing initial left parenthesis in format";
|
||||||
|
|
||||||
if (fmt->error)
|
if (fmt->error)
|
||||||
format_error (dtp, NULL, fmt->error);
|
{
|
||||||
}
|
format_error (dtp, NULL, fmt->error);
|
||||||
|
free_format_hash_table (dtp->u.p.current_unit);
|
||||||
|
return;
|
||||||
/* revert()-- Do reversion of the format. Control reverts to the left
|
}
|
||||||
* parenthesis that matches the rightmost right parenthesis. From our
|
save_parsed_format (dtp);
|
||||||
* tree structure, we are looking for the rightmost parenthesis node
|
|
||||||
* at the second level, the first level always being a single
|
|
||||||
* parenthesis node. If this node doesn't exit, we use the top
|
|
||||||
* level. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
revert (st_parameter_dt *dtp)
|
|
||||||
{
|
|
||||||
fnode *f, *r;
|
|
||||||
format_data *fmt = dtp->u.p.fmt;
|
|
||||||
|
|
||||||
dtp->u.p.reversion_flag = 1;
|
|
||||||
|
|
||||||
r = NULL;
|
|
||||||
|
|
||||||
for (f = fmt->array.array[0].u.child; f; f = f->next)
|
|
||||||
if (f->format == FMT_LPAREN)
|
|
||||||
r = f;
|
|
||||||
|
|
||||||
/* If r is NULL because no node was found, the whole tree will be used */
|
|
||||||
|
|
||||||
fmt->array.array[0].current = r;
|
|
||||||
fmt->array.array[0].count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,13 @@ PREFIX(fgetc) (const int * unit, char * c, gfc_charlen_type c_len)
|
||||||
|
|
||||||
s = 1;
|
s = 1;
|
||||||
memset (c, ' ', c_len);
|
memset (c, ' ', c_len);
|
||||||
ret = sread (u->s, c, &s);
|
ret = sread (u->s, c, s);
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (s != 1)
|
if (ret != 1)
|
||||||
return -1;
|
return -1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -119,17 +119,17 @@ int
|
||||||
PREFIX(fputc) (const int * unit, char * c,
|
PREFIX(fputc) (const int * unit, char * c,
|
||||||
gfc_charlen_type c_len __attribute__((unused)))
|
gfc_charlen_type c_len __attribute__((unused)))
|
||||||
{
|
{
|
||||||
size_t s;
|
ssize_t s;
|
||||||
int ret;
|
|
||||||
gfc_unit * u = find_unit (*unit);
|
gfc_unit * u = find_unit (*unit);
|
||||||
|
|
||||||
if (u == NULL)
|
if (u == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s = 1;
|
s = swrite (u->s, c, 1);
|
||||||
ret = swrite (u->s, c, &s);
|
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
return ret;
|
if (s < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ flush_i4 (GFC_INTEGER_4 *unit)
|
||||||
us = find_unit (*unit);
|
us = find_unit (*unit);
|
||||||
if (us != NULL)
|
if (us != NULL)
|
||||||
{
|
{
|
||||||
flush (us->s);
|
sflush (us->s);
|
||||||
unlock_unit (us);
|
unlock_unit (us);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +219,7 @@ flush_i8 (GFC_INTEGER_8 *unit)
|
||||||
us = find_unit (*unit);
|
us = find_unit (*unit);
|
||||||
if (us != NULL)
|
if (us != NULL)
|
||||||
{
|
{
|
||||||
flush (us->s);
|
sflush (us->s);
|
||||||
unlock_unit (us);
|
unlock_unit (us);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -234,22 +234,17 @@ void
|
||||||
fseek_sub (int * unit, GFC_IO_INT * offset, int * whence, int * status)
|
fseek_sub (int * unit, GFC_IO_INT * offset, int * whence, int * status)
|
||||||
{
|
{
|
||||||
gfc_unit * u = find_unit (*unit);
|
gfc_unit * u = find_unit (*unit);
|
||||||
try result = FAILURE;
|
ssize_t result = -1;
|
||||||
|
|
||||||
if (u != NULL && is_seekable(u->s))
|
if (u != NULL && is_seekable(u->s))
|
||||||
{
|
{
|
||||||
if (*whence == 0)
|
result = sseek(u->s, *offset, *whence);
|
||||||
result = sseek(u->s, *offset); /* SEEK_SET */
|
|
||||||
else if (*whence == 1)
|
|
||||||
result = sseek(u->s, file_position(u->s) + *offset); /* SEEK_CUR */
|
|
||||||
else if (*whence == 2)
|
|
||||||
result = sseek(u->s, file_length(u->s) + *offset); /* SEEK_END */
|
|
||||||
|
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
*status = (result == FAILURE ? -1 : 0);
|
*status = (result < 0 ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -266,7 +261,7 @@ PREFIX(ftell) (int * unit)
|
||||||
size_t ret;
|
size_t ret;
|
||||||
if (u == NULL)
|
if (u == NULL)
|
||||||
return ((size_t) -1);
|
return ((size_t) -1);
|
||||||
ret = (size_t) stream_offset (u->s);
|
ret = (size_t) stell (u->s);
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +277,7 @@ PREFIX(ftell) (int * unit)
|
||||||
*offset = -1; \
|
*offset = -1; \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
*offset = stream_offset (u->s); \
|
*offset = stell (u->s); \
|
||||||
unlock_unit (u); \
|
unlock_unit (u); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,34 +49,59 @@ struct st_parameter_dt;
|
||||||
|
|
||||||
typedef struct stream
|
typedef struct stream
|
||||||
{
|
{
|
||||||
char *(*alloc_w_at) (struct stream *, int *);
|
ssize_t (*read) (struct stream *, void *, ssize_t);
|
||||||
try (*sfree) (struct stream *);
|
ssize_t (*write) (struct stream *, const void *, ssize_t);
|
||||||
try (*close) (struct stream *);
|
off_t (*seek) (struct stream *, off_t, int);
|
||||||
try (*seek) (struct stream *, gfc_offset);
|
off_t (*tell) (struct stream *);
|
||||||
try (*trunc) (struct stream *);
|
int (*truncate) (struct stream *, off_t);
|
||||||
int (*read) (struct stream *, void *, size_t *);
|
int (*flush) (struct stream *);
|
||||||
int (*write) (struct stream *, const void *, size_t *);
|
int (*close) (struct stream *);
|
||||||
try (*set) (struct stream *, int, size_t);
|
|
||||||
}
|
}
|
||||||
stream;
|
stream;
|
||||||
|
|
||||||
typedef enum
|
/* Inline functions for doing file I/O given a stream. */
|
||||||
{ SYNC_BUFFERED, SYNC_UNBUFFERED, ASYNC }
|
static inline ssize_t
|
||||||
io_mode;
|
sread (stream * s, void * buf, ssize_t nbyte)
|
||||||
|
{
|
||||||
|
return s->read (s, buf, nbyte);
|
||||||
|
}
|
||||||
|
|
||||||
/* Macros for doing file I/O given a stream. */
|
static inline ssize_t
|
||||||
|
swrite (stream * s, const void * buf, ssize_t nbyte)
|
||||||
|
{
|
||||||
|
return s->write (s, buf, nbyte);
|
||||||
|
}
|
||||||
|
|
||||||
#define sfree(s) ((s)->sfree)(s)
|
static inline off_t
|
||||||
#define sclose(s) ((s)->close)(s)
|
sseek (stream * s, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
return s->seek (s, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
#define salloc_w(s, len) ((s)->alloc_w_at)(s, len)
|
static inline off_t
|
||||||
|
stell (stream * s)
|
||||||
|
{
|
||||||
|
return s->tell (s);
|
||||||
|
}
|
||||||
|
|
||||||
#define sseek(s, pos) ((s)->seek)(s, pos)
|
static inline int
|
||||||
#define struncate(s) ((s)->trunc)(s)
|
struncate (stream * s, off_t length)
|
||||||
#define sread(s, buf, nbytes) ((s)->read)(s, buf, nbytes)
|
{
|
||||||
#define swrite(s, buf, nbytes) ((s)->write)(s, buf, nbytes)
|
return s->truncate (s, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
sflush (stream * s)
|
||||||
|
{
|
||||||
|
return s->flush (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
sclose (stream * s)
|
||||||
|
{
|
||||||
|
return s->close (s);
|
||||||
|
}
|
||||||
|
|
||||||
#define sset(s, c, n) ((s)->set)(s, c, n)
|
|
||||||
|
|
||||||
/* Macros for testing what kinds of I/O we are doing. */
|
/* Macros for testing what kinds of I/O we are doing. */
|
||||||
|
|
||||||
|
|
@ -106,6 +131,18 @@ typedef struct array_loop_spec
|
||||||
}
|
}
|
||||||
array_loop_spec;
|
array_loop_spec;
|
||||||
|
|
||||||
|
/* A stucture to build a hash table for format data. */
|
||||||
|
|
||||||
|
#define FORMAT_HASH_SIZE 16
|
||||||
|
|
||||||
|
typedef struct format_hash_entry
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
gfc_charlen_type key_len;
|
||||||
|
struct format_data *hashed_fmt;
|
||||||
|
}
|
||||||
|
format_hash_entry;
|
||||||
|
|
||||||
/* Representation of a namelist object in libgfortran
|
/* Representation of a namelist object in libgfortran
|
||||||
|
|
||||||
Namelist Records
|
Namelist Records
|
||||||
|
|
@ -127,7 +164,6 @@ array_loop_spec;
|
||||||
|
|
||||||
typedef struct namelist_type
|
typedef struct namelist_type
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Object type, stored as GFC_DTYPE_xxxx. */
|
/* Object type, stored as GFC_DTYPE_xxxx. */
|
||||||
bt type;
|
bt type;
|
||||||
|
|
||||||
|
|
@ -538,10 +574,9 @@ unit_flags;
|
||||||
typedef struct fbuf
|
typedef struct fbuf
|
||||||
{
|
{
|
||||||
char *buf; /* Start of buffer. */
|
char *buf; /* Start of buffer. */
|
||||||
size_t len; /* Length of buffer. */
|
int len; /* Length of buffer. */
|
||||||
size_t act; /* Active bytes in buffer. */
|
int act; /* Active bytes in buffer. */
|
||||||
size_t flushed; /* Flushed bytes from beginning of buffer. */
|
int pos; /* Current position in buffer. */
|
||||||
size_t pos; /* Current position in buffer. */
|
|
||||||
}
|
}
|
||||||
fbuf;
|
fbuf;
|
||||||
|
|
||||||
|
|
@ -599,6 +634,9 @@ typedef struct gfc_unit
|
||||||
|
|
||||||
int file_len;
|
int file_len;
|
||||||
char *file;
|
char *file;
|
||||||
|
|
||||||
|
/* The format hash table. */
|
||||||
|
struct format_hash_entry format_hash_table[FORMAT_HASH_SIZE];
|
||||||
|
|
||||||
/* Formatting buffer. */
|
/* Formatting buffer. */
|
||||||
struct fbuf *fbuf;
|
struct fbuf *fbuf;
|
||||||
|
|
@ -683,6 +721,12 @@ internal_proto(open_external);
|
||||||
extern stream *open_internal (char *, int, gfc_offset);
|
extern stream *open_internal (char *, int, gfc_offset);
|
||||||
internal_proto(open_internal);
|
internal_proto(open_internal);
|
||||||
|
|
||||||
|
extern char * mem_alloc_w (stream *, int *);
|
||||||
|
internal_proto(mem_alloc_w);
|
||||||
|
|
||||||
|
extern char * mem_alloc_r (stream *, int *);
|
||||||
|
internal_proto(mem_alloc_w);
|
||||||
|
|
||||||
extern stream *input_stream (void);
|
extern stream *input_stream (void);
|
||||||
internal_proto(input_stream);
|
internal_proto(input_stream);
|
||||||
|
|
||||||
|
|
@ -698,12 +742,6 @@ internal_proto(compare_file_filename);
|
||||||
extern gfc_unit *find_file (const char *file, gfc_charlen_type file_len);
|
extern gfc_unit *find_file (const char *file, gfc_charlen_type file_len);
|
||||||
internal_proto(find_file);
|
internal_proto(find_file);
|
||||||
|
|
||||||
extern int stream_at_bof (stream *);
|
|
||||||
internal_proto(stream_at_bof);
|
|
||||||
|
|
||||||
extern int stream_at_eof (stream *);
|
|
||||||
internal_proto(stream_at_eof);
|
|
||||||
|
|
||||||
extern int delete_file (gfc_unit *);
|
extern int delete_file (gfc_unit *);
|
||||||
internal_proto(delete_file);
|
internal_proto(delete_file);
|
||||||
|
|
||||||
|
|
@ -734,9 +772,6 @@ internal_proto(inquire_readwrite);
|
||||||
extern gfc_offset file_length (stream *);
|
extern gfc_offset file_length (stream *);
|
||||||
internal_proto(file_length);
|
internal_proto(file_length);
|
||||||
|
|
||||||
extern gfc_offset file_position (stream *);
|
|
||||||
internal_proto(file_position);
|
|
||||||
|
|
||||||
extern int is_seekable (stream *);
|
extern int is_seekable (stream *);
|
||||||
internal_proto(is_seekable);
|
internal_proto(is_seekable);
|
||||||
|
|
||||||
|
|
@ -752,18 +787,12 @@ internal_proto(flush_if_preconnected);
|
||||||
extern void empty_internal_buffer(stream *);
|
extern void empty_internal_buffer(stream *);
|
||||||
internal_proto(empty_internal_buffer);
|
internal_proto(empty_internal_buffer);
|
||||||
|
|
||||||
extern try flush (stream *);
|
|
||||||
internal_proto(flush);
|
|
||||||
|
|
||||||
extern int stream_isatty (stream *);
|
extern int stream_isatty (stream *);
|
||||||
internal_proto(stream_isatty);
|
internal_proto(stream_isatty);
|
||||||
|
|
||||||
extern char * stream_ttyname (stream *);
|
extern char * stream_ttyname (stream *);
|
||||||
internal_proto(stream_ttyname);
|
internal_proto(stream_ttyname);
|
||||||
|
|
||||||
extern gfc_offset stream_offset (stream *s);
|
|
||||||
internal_proto(stream_offset);
|
|
||||||
|
|
||||||
extern int unpack_filename (char *, const char *, int);
|
extern int unpack_filename (char *, const char *, int);
|
||||||
internal_proto(unpack_filename);
|
internal_proto(unpack_filename);
|
||||||
|
|
||||||
|
|
@ -807,6 +836,9 @@ internal_proto(update_position);
|
||||||
extern void finish_last_advance_record (gfc_unit *u);
|
extern void finish_last_advance_record (gfc_unit *u);
|
||||||
internal_proto (finish_last_advance_record);
|
internal_proto (finish_last_advance_record);
|
||||||
|
|
||||||
|
extern int unit_truncate (gfc_unit *, gfc_offset, st_parameter_common *);
|
||||||
|
internal_proto (unit_truncate);
|
||||||
|
|
||||||
/* open.c */
|
/* open.c */
|
||||||
|
|
||||||
extern gfc_unit *new_unit (st_parameter_open *, gfc_unit *, unit_flags *);
|
extern gfc_unit *new_unit (st_parameter_open *, gfc_unit *, unit_flags *);
|
||||||
|
|
@ -826,9 +858,18 @@ internal_proto(unget_format);
|
||||||
extern void format_error (st_parameter_dt *, const fnode *, const char *);
|
extern void format_error (st_parameter_dt *, const fnode *, const char *);
|
||||||
internal_proto(format_error);
|
internal_proto(format_error);
|
||||||
|
|
||||||
extern void free_format_data (st_parameter_dt *);
|
extern void free_format_data (struct format_data *);
|
||||||
internal_proto(free_format_data);
|
internal_proto(free_format_data);
|
||||||
|
|
||||||
|
extern void free_format_hash_table (gfc_unit *);
|
||||||
|
internal_proto(free_format_hash_table);
|
||||||
|
|
||||||
|
extern void init_format_hash (st_parameter_dt *);
|
||||||
|
internal_proto(init_format_hash);
|
||||||
|
|
||||||
|
extern void free_format_hash (st_parameter_dt *);
|
||||||
|
internal_proto(free_format_hash);
|
||||||
|
|
||||||
/* transfer.c */
|
/* transfer.c */
|
||||||
|
|
||||||
#define SCRATCH_SIZE 300
|
#define SCRATCH_SIZE 300
|
||||||
|
|
@ -836,7 +877,7 @@ internal_proto(free_format_data);
|
||||||
extern const char *type_name (bt);
|
extern const char *type_name (bt);
|
||||||
internal_proto(type_name);
|
internal_proto(type_name);
|
||||||
|
|
||||||
extern try read_block_form (st_parameter_dt *, void *, size_t *);
|
extern void * read_block_form (st_parameter_dt *, int *);
|
||||||
internal_proto(read_block_form);
|
internal_proto(read_block_form);
|
||||||
|
|
||||||
extern char *read_sf (st_parameter_dt *, int *, int);
|
extern char *read_sf (st_parameter_dt *, int *, int);
|
||||||
|
|
@ -862,6 +903,9 @@ internal_proto (reverse_memcpy);
|
||||||
extern void st_wait (st_parameter_wait *);
|
extern void st_wait (st_parameter_wait *);
|
||||||
export_proto(st_wait);
|
export_proto(st_wait);
|
||||||
|
|
||||||
|
extern void hit_eof (st_parameter_dt *);
|
||||||
|
internal_proto(hit_eof);
|
||||||
|
|
||||||
/* read.c */
|
/* read.c */
|
||||||
|
|
||||||
extern void set_integer (void *, GFC_INTEGER_LARGEST, int);
|
extern void set_integer (void *, GFC_INTEGER_LARGEST, int);
|
||||||
|
|
@ -968,24 +1012,39 @@ extern size_t size_from_complex_kind (int);
|
||||||
internal_proto(size_from_complex_kind);
|
internal_proto(size_from_complex_kind);
|
||||||
|
|
||||||
/* fbuf.c */
|
/* fbuf.c */
|
||||||
extern void fbuf_init (gfc_unit *, size_t);
|
extern void fbuf_init (gfc_unit *, int);
|
||||||
internal_proto(fbuf_init);
|
internal_proto(fbuf_init);
|
||||||
|
|
||||||
extern void fbuf_destroy (gfc_unit *);
|
extern void fbuf_destroy (gfc_unit *);
|
||||||
internal_proto(fbuf_destroy);
|
internal_proto(fbuf_destroy);
|
||||||
|
|
||||||
extern void fbuf_reset (gfc_unit *);
|
extern int fbuf_reset (gfc_unit *);
|
||||||
internal_proto(fbuf_reset);
|
internal_proto(fbuf_reset);
|
||||||
|
|
||||||
extern char * fbuf_alloc (gfc_unit *, size_t);
|
extern char * fbuf_alloc (gfc_unit *, int);
|
||||||
internal_proto(fbuf_alloc);
|
internal_proto(fbuf_alloc);
|
||||||
|
|
||||||
extern int fbuf_flush (gfc_unit *, int);
|
extern int fbuf_flush (gfc_unit *, unit_mode);
|
||||||
internal_proto(fbuf_flush);
|
internal_proto(fbuf_flush);
|
||||||
|
|
||||||
extern int fbuf_seek (gfc_unit *, gfc_offset);
|
extern int fbuf_seek (gfc_unit *, int, int);
|
||||||
internal_proto(fbuf_seek);
|
internal_proto(fbuf_seek);
|
||||||
|
|
||||||
|
extern char * fbuf_read (gfc_unit *, int *);
|
||||||
|
internal_proto(fbuf_read);
|
||||||
|
|
||||||
|
/* Never call this function, only use fbuf_getc(). */
|
||||||
|
extern int fbuf_getc_refill (gfc_unit *);
|
||||||
|
internal_proto(fbuf_getc_refill);
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
fbuf_getc (gfc_unit * u)
|
||||||
|
{
|
||||||
|
if (u->fbuf->pos < u->fbuf->act)
|
||||||
|
return (unsigned char) u->fbuf->buf[u->fbuf->pos++];
|
||||||
|
return fbuf_getc_refill (u);
|
||||||
|
}
|
||||||
|
|
||||||
/* lock.c */
|
/* lock.c */
|
||||||
extern void free_ionml (st_parameter_dt *);
|
extern void free_ionml (st_parameter_dt *);
|
||||||
internal_proto(free_ionml);
|
internal_proto(free_ionml);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,9 +80,8 @@ push_char (st_parameter_dt *dtp, char c)
|
||||||
|
|
||||||
if (dtp->u.p.saved_string == NULL)
|
if (dtp->u.p.saved_string == NULL)
|
||||||
{
|
{
|
||||||
if (dtp->u.p.scratch == NULL)
|
dtp->u.p.saved_string = get_mem (SCRATCH_SIZE);
|
||||||
dtp->u.p.scratch = get_mem (SCRATCH_SIZE);
|
// memset below should be commented out.
|
||||||
dtp->u.p.saved_string = dtp->u.p.scratch;
|
|
||||||
memset (dtp->u.p.saved_string, 0, SCRATCH_SIZE);
|
memset (dtp->u.p.saved_string, 0, SCRATCH_SIZE);
|
||||||
dtp->u.p.saved_length = SCRATCH_SIZE;
|
dtp->u.p.saved_length = SCRATCH_SIZE;
|
||||||
dtp->u.p.saved_used = 0;
|
dtp->u.p.saved_used = 0;
|
||||||
|
|
@ -90,15 +90,15 @@ push_char (st_parameter_dt *dtp, char c)
|
||||||
if (dtp->u.p.saved_used >= dtp->u.p.saved_length)
|
if (dtp->u.p.saved_used >= dtp->u.p.saved_length)
|
||||||
{
|
{
|
||||||
dtp->u.p.saved_length = 2 * dtp->u.p.saved_length;
|
dtp->u.p.saved_length = 2 * dtp->u.p.saved_length;
|
||||||
new = get_mem (2 * dtp->u.p.saved_length);
|
new = realloc (dtp->u.p.saved_string, dtp->u.p.saved_length);
|
||||||
|
if (new == NULL)
|
||||||
memset (new, 0, 2 * dtp->u.p.saved_length);
|
generate_error (&dtp->common, LIBERROR_OS, NULL);
|
||||||
|
|
||||||
memcpy (new, dtp->u.p.saved_string, dtp->u.p.saved_used);
|
|
||||||
if (dtp->u.p.saved_string != dtp->u.p.scratch)
|
|
||||||
free_mem (dtp->u.p.saved_string);
|
|
||||||
|
|
||||||
dtp->u.p.saved_string = new;
|
dtp->u.p.saved_string = new;
|
||||||
|
|
||||||
|
// Also this should not be necessary.
|
||||||
|
memset (new + dtp->u.p.saved_used, 0,
|
||||||
|
dtp->u.p.saved_length - dtp->u.p.saved_used);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dtp->u.p.saved_string[dtp->u.p.saved_used++] = c;
|
dtp->u.p.saved_string[dtp->u.p.saved_used++] = c;
|
||||||
|
|
@ -113,8 +113,7 @@ free_saved (st_parameter_dt *dtp)
|
||||||
if (dtp->u.p.saved_string == NULL)
|
if (dtp->u.p.saved_string == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dtp->u.p.saved_string != dtp->u.p.scratch)
|
free_mem (dtp->u.p.saved_string);
|
||||||
free_mem (dtp->u.p.saved_string);
|
|
||||||
|
|
||||||
dtp->u.p.saved_string = NULL;
|
dtp->u.p.saved_string = NULL;
|
||||||
dtp->u.p.saved_used = 0;
|
dtp->u.p.saved_used = 0;
|
||||||
|
|
@ -140,9 +139,10 @@ free_line (st_parameter_dt *dtp)
|
||||||
static char
|
static char
|
||||||
next_char (st_parameter_dt *dtp)
|
next_char (st_parameter_dt *dtp)
|
||||||
{
|
{
|
||||||
size_t length;
|
ssize_t length;
|
||||||
gfc_offset record;
|
gfc_offset record;
|
||||||
char c;
|
char c;
|
||||||
|
int cc;
|
||||||
|
|
||||||
if (dtp->u.p.last_char != '\0')
|
if (dtp->u.p.last_char != '\0')
|
||||||
{
|
{
|
||||||
|
|
@ -194,7 +194,7 @@ next_char (st_parameter_dt *dtp)
|
||||||
}
|
}
|
||||||
|
|
||||||
record *= dtp->u.p.current_unit->recl;
|
record *= dtp->u.p.current_unit->recl;
|
||||||
if (sseek (dtp->u.p.current_unit->s, record) == FAILURE)
|
if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
|
||||||
longjmp (*dtp->u.p.eof_jump, 1);
|
longjmp (*dtp->u.p.eof_jump, 1);
|
||||||
|
|
||||||
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
|
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
|
||||||
|
|
@ -204,19 +204,15 @@ next_char (st_parameter_dt *dtp)
|
||||||
|
|
||||||
/* Get the next character and handle end-of-record conditions. */
|
/* Get the next character and handle end-of-record conditions. */
|
||||||
|
|
||||||
length = 1;
|
|
||||||
|
|
||||||
if (sread (dtp->u.p.current_unit->s, &c, &length) != 0)
|
|
||||||
{
|
|
||||||
generate_error (&dtp->common, LIBERROR_OS, NULL);
|
|
||||||
return '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_stream_io (dtp) && length == 1)
|
|
||||||
dtp->u.p.current_unit->strm_pos++;
|
|
||||||
|
|
||||||
if (is_internal_unit (dtp))
|
if (is_internal_unit (dtp))
|
||||||
{
|
{
|
||||||
|
length = sread (dtp->u.p.current_unit->s, &c, 1);
|
||||||
|
if (length < 0)
|
||||||
|
{
|
||||||
|
generate_error (&dtp->common, LIBERROR_OS, NULL);
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array_io (dtp))
|
if (is_array_io (dtp))
|
||||||
{
|
{
|
||||||
/* Check whether we hit EOF. */
|
/* Check whether we hit EOF. */
|
||||||
|
|
@ -240,13 +236,20 @@ next_char (st_parameter_dt *dtp)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (length == 0)
|
cc = fbuf_getc (dtp->u.p.current_unit);
|
||||||
|
|
||||||
|
if (cc == EOF)
|
||||||
{
|
{
|
||||||
if (dtp->u.p.current_unit->endfile == AT_ENDFILE)
|
if (dtp->u.p.current_unit->endfile == AT_ENDFILE)
|
||||||
longjmp (*dtp->u.p.eof_jump, 1);
|
longjmp (*dtp->u.p.eof_jump, 1);
|
||||||
dtp->u.p.current_unit->endfile = AT_ENDFILE;
|
dtp->u.p.current_unit->endfile = AT_ENDFILE;
|
||||||
c = '\n';
|
c = '\n';
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
c = (char) cc;
|
||||||
|
if (is_stream_io (dtp) && cc != EOF)
|
||||||
|
dtp->u.p.current_unit->strm_pos++;
|
||||||
|
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
dtp->u.p.at_eol = (c == '\n' || c == '\r');
|
dtp->u.p.at_eol = (c == '\n' || c == '\r');
|
||||||
|
|
@ -1698,7 +1701,7 @@ list_formatted_read_scalar (st_parameter_dt *dtp, volatile bt type, void *p,
|
||||||
dtp->u.p.input_complete = 0;
|
dtp->u.p.input_complete = 0;
|
||||||
dtp->u.p.repeat_count = 1;
|
dtp->u.p.repeat_count = 1;
|
||||||
dtp->u.p.at_eol = 0;
|
dtp->u.p.at_eol = 0;
|
||||||
|
|
||||||
c = eat_spaces (dtp);
|
c = eat_spaces (dtp);
|
||||||
if (is_separator (c))
|
if (is_separator (c))
|
||||||
{
|
{
|
||||||
|
|
@ -1726,6 +1729,9 @@ list_formatted_read_scalar (st_parameter_dt *dtp, volatile bt type, void *p,
|
||||||
return;
|
return;
|
||||||
goto set_value;
|
goto set_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dtp->u.p.input_complete)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (dtp->u.p.input_complete)
|
if (dtp->u.p.input_complete)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
@ -1853,6 +1859,8 @@ finish_list_read (st_parameter_dt *dtp)
|
||||||
|
|
||||||
free_saved (dtp);
|
free_saved (dtp);
|
||||||
|
|
||||||
|
fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
|
||||||
|
|
||||||
if (dtp->u.p.at_eol)
|
if (dtp->u.p.at_eol)
|
||||||
{
|
{
|
||||||
dtp->u.p.at_eol = 0;
|
dtp->u.p.at_eol = 0;
|
||||||
|
|
@ -2261,8 +2269,8 @@ nml_query (st_parameter_dt *dtp, char c)
|
||||||
|
|
||||||
/* Flush the stream to force immediate output. */
|
/* Flush the stream to force immediate output. */
|
||||||
|
|
||||||
fbuf_flush (dtp->u.p.current_unit, 1);
|
fbuf_flush (dtp->u.p.current_unit, WRITING);
|
||||||
flush (dtp->u.p.current_unit->s);
|
sflush (dtp->u.p.current_unit->s);
|
||||||
unlock_unit (dtp->u.p.current_unit);
|
unlock_unit (dtp->u.p.current_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2903,7 +2911,7 @@ find_nml_name:
|
||||||
st_printf ("%s\n", nml_err_msg);
|
st_printf ("%s\n", nml_err_msg);
|
||||||
if (u != NULL)
|
if (u != NULL)
|
||||||
{
|
{
|
||||||
flush (u->s);
|
sflush (u->s);
|
||||||
unlock_unit (u);
|
unlock_unit (u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ static const st_option async_opt[] =
|
||||||
static void
|
static void
|
||||||
test_endfile (gfc_unit * u)
|
test_endfile (gfc_unit * u)
|
||||||
{
|
{
|
||||||
if (u->endfile == NO_ENDFILE && file_length (u->s) == file_position (u->s))
|
if (u->endfile == NO_ENDFILE && file_length (u->s) == stell (u->s))
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +271,7 @@ edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POSITION_REWIND:
|
case POSITION_REWIND:
|
||||||
if (sseek (u->s, 0) == FAILURE)
|
if (sseek (u->s, 0, SEEK_SET) != 0)
|
||||||
goto seek_error;
|
goto seek_error;
|
||||||
|
|
||||||
u->current_record = 0;
|
u->current_record = 0;
|
||||||
|
|
@ -281,7 +281,7 @@ edit_modes (st_parameter_open *opp, gfc_unit * u, unit_flags * flags)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POSITION_APPEND:
|
case POSITION_APPEND:
|
||||||
if (sseek (u->s, file_length (u->s)) == FAILURE)
|
if (sseek (u->s, 0, SEEK_END) < 0)
|
||||||
goto seek_error;
|
goto seek_error;
|
||||||
|
|
||||||
if (flags->access != ACCESS_STREAM)
|
if (flags->access != ACCESS_STREAM)
|
||||||
|
|
@ -557,7 +557,7 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
|
||||||
|
|
||||||
if (flags->position == POSITION_APPEND)
|
if (flags->position == POSITION_APPEND)
|
||||||
{
|
{
|
||||||
if (sseek (u->s, file_length (u->s)) == FAILURE)
|
if (sseek (u->s, 0, SEEK_END) < 0)
|
||||||
generate_error (&opp->common, LIBERROR_OS, NULL);
|
generate_error (&opp->common, LIBERROR_OS, NULL);
|
||||||
u->endfile = AT_ENDFILE;
|
u->endfile = AT_ENDFILE;
|
||||||
}
|
}
|
||||||
|
|
@ -611,7 +611,8 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
|
||||||
{
|
{
|
||||||
u->maxrec = max_offset;
|
u->maxrec = max_offset;
|
||||||
u->recl = 1;
|
u->recl = 1;
|
||||||
u->strm_pos = file_position (u->s) + 1;
|
u->bytes_left = 1;
|
||||||
|
u->strm_pos = stell (u->s) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memmove (u->file, opp->file, opp->file_len);
|
memmove (u->file, opp->file, opp->file_len);
|
||||||
|
|
@ -627,7 +628,7 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
|
||||||
if (flags->status == STATUS_SCRATCH && opp->file != NULL)
|
if (flags->status == STATUS_SCRATCH && opp->file != NULL)
|
||||||
free_mem (opp->file);
|
free_mem (opp->file);
|
||||||
|
|
||||||
if (flags->form == FORM_FORMATTED && (flags->action != ACTION_READ))
|
if (flags->form == FORM_FORMATTED)
|
||||||
{
|
{
|
||||||
if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
|
if ((opp->common.flags & IOPARM_OPEN_HAS_RECL_IN))
|
||||||
fbuf_init (u, u->recl);
|
fbuf_init (u, u->recl);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
|
|
||||||
|
|
@ -141,38 +142,30 @@ convert_real (st_parameter_dt *dtp, void *dest, const char *buffer, int length)
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 4:
|
case 4:
|
||||||
{
|
*((GFC_REAL_4*) dest) =
|
||||||
GFC_REAL_4 tmp =
|
|
||||||
#if defined(HAVE_STRTOF)
|
#if defined(HAVE_STRTOF)
|
||||||
strtof (buffer, NULL);
|
strtof (buffer, NULL);
|
||||||
#else
|
#else
|
||||||
(GFC_REAL_4) strtod (buffer, NULL);
|
(GFC_REAL_4) strtod (buffer, NULL);
|
||||||
#endif
|
#endif
|
||||||
memcpy (dest, (void *) &tmp, length);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
{
|
*((GFC_REAL_8*) dest) = strtod (buffer, NULL);
|
||||||
GFC_REAL_8 tmp = strtod (buffer, NULL);
|
|
||||||
memcpy (dest, (void *) &tmp, length);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(HAVE_GFC_REAL_10) && defined (HAVE_STRTOLD)
|
#if defined(HAVE_GFC_REAL_10) && defined (HAVE_STRTOLD)
|
||||||
case 10:
|
case 10:
|
||||||
{
|
*((GFC_REAL_10*) dest) = strtold (buffer, NULL);
|
||||||
GFC_REAL_10 tmp = strtold (buffer, NULL);
|
|
||||||
memcpy (dest, (void *) &tmp, length);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_GFC_REAL_16) && defined (HAVE_STRTOLD)
|
#if defined(HAVE_GFC_REAL_16) && defined (HAVE_STRTOLD)
|
||||||
case 16:
|
case 16:
|
||||||
{
|
*((GFC_REAL_16*) dest) = strtold (buffer, NULL);
|
||||||
GFC_REAL_16 tmp = strtold (buffer, NULL);
|
|
||||||
memcpy (dest, (void *) &tmp, length);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
internal_error (&dtp->common, "Unsupported real kind during IO");
|
internal_error (&dtp->common, "Unsupported real kind during IO");
|
||||||
}
|
}
|
||||||
|
|
@ -195,13 +188,13 @@ void
|
||||||
read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
size_t w;
|
int w;
|
||||||
|
|
||||||
w = f->u.w;
|
w = f->u.w;
|
||||||
|
|
||||||
p = gfc_alloca (w);
|
p = read_block_form (dtp, &w);
|
||||||
|
|
||||||
if (read_block_form (dtp, p, &w) == FAILURE)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (*p == ' ')
|
while (*p == ' ')
|
||||||
|
|
@ -238,28 +231,26 @@ read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline gfc_char4_t
|
static gfc_char4_t
|
||||||
read_utf8 (st_parameter_dt *dtp, size_t *nbytes)
|
read_utf8 (st_parameter_dt *dtp, int *nbytes)
|
||||||
{
|
{
|
||||||
static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 };
|
static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 };
|
||||||
static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
static uchar buffer[6];
|
int i, nb, nread;
|
||||||
size_t i, nb, nread;
|
|
||||||
gfc_char4_t c;
|
gfc_char4_t c;
|
||||||
int status;
|
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
*nbytes = 1;
|
*nbytes = 1;
|
||||||
s = (char *) &buffer[0];
|
|
||||||
status = read_block_form (dtp, s, nbytes);
|
s = read_block_form (dtp, nbytes);
|
||||||
if (status == FAILURE)
|
if (s == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If this is a short read, just return. */
|
/* If this is a short read, just return. */
|
||||||
if (*nbytes == 0)
|
if (*nbytes == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
c = buffer[0];
|
c = (uchar) s[0];
|
||||||
if (c < 0x80)
|
if (c < 0x80)
|
||||||
return c;
|
return c;
|
||||||
|
|
||||||
|
|
@ -274,9 +265,8 @@ read_utf8 (st_parameter_dt *dtp, size_t *nbytes)
|
||||||
c = (c & masks[nb-1]);
|
c = (c & masks[nb-1]);
|
||||||
nread = nb - 1;
|
nread = nb - 1;
|
||||||
|
|
||||||
s = (char *) &buffer[1];
|
s = read_block_form (dtp, &nread);
|
||||||
status = read_block_form (dtp, s, &nread);
|
if (s == NULL)
|
||||||
if (status == FAILURE)
|
|
||||||
return 0;
|
return 0;
|
||||||
/* Decode the bytes read. */
|
/* Decode the bytes read. */
|
||||||
for (i = 1; i < nb; i++)
|
for (i = 1; i < nb; i++)
|
||||||
|
|
@ -309,14 +299,14 @@ read_utf8 (st_parameter_dt *dtp, size_t *nbytes)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, size_t width)
|
read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, int width)
|
||||||
{
|
{
|
||||||
gfc_char4_t c;
|
gfc_char4_t c;
|
||||||
char *dest;
|
char *dest;
|
||||||
size_t nbytes;
|
int nbytes;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
len = ((int) width < len) ? len : (int) width;
|
len = (width < len) ? len : width;
|
||||||
|
|
||||||
dest = (char *) p;
|
dest = (char *) p;
|
||||||
|
|
||||||
|
|
@ -339,21 +329,19 @@ read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, size_t width)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_default_char1 (st_parameter_dt *dtp, char *p, int len, size_t width)
|
read_default_char1 (st_parameter_dt *dtp, char *p, int len, int width)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int m, n, status;
|
int m, n;
|
||||||
|
|
||||||
s = gfc_alloca (width);
|
s = read_block_form (dtp, &width);
|
||||||
|
|
||||||
status = read_block_form (dtp, s, &width);
|
|
||||||
|
|
||||||
if (status == FAILURE)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
if (width > (size_t) len)
|
if (width > len)
|
||||||
s += (width - len);
|
s += (width - len);
|
||||||
|
|
||||||
m = ((int) width > len) ? len : (int) width;
|
m = (width > len) ? len : width;
|
||||||
memcpy (p, s, m);
|
memcpy (p, s, m);
|
||||||
|
|
||||||
n = len - width;
|
n = len - width;
|
||||||
|
|
@ -363,13 +351,13 @@ read_default_char1 (st_parameter_dt *dtp, char *p, int len, size_t width)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, size_t width)
|
read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, int width)
|
||||||
{
|
{
|
||||||
gfc_char4_t *dest;
|
gfc_char4_t *dest;
|
||||||
size_t nbytes;
|
int nbytes;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
len = ((int) width < len) ? len : (int) width;
|
len = (width < len) ? len : width;
|
||||||
|
|
||||||
dest = (gfc_char4_t *) p;
|
dest = (gfc_char4_t *) p;
|
||||||
|
|
||||||
|
|
@ -391,19 +379,17 @@ read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, size_t width)
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_default_char4 (st_parameter_dt *dtp, char *p, int len, size_t width)
|
read_default_char4 (st_parameter_dt *dtp, char *p, int len, int width)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
gfc_char4_t *dest;
|
gfc_char4_t *dest;
|
||||||
int m, n, status;
|
int m, n;
|
||||||
|
|
||||||
s = gfc_alloca (width);
|
s = read_block_form (dtp, &width);
|
||||||
|
|
||||||
status = read_block_form (dtp, s, &width);
|
|
||||||
|
|
||||||
if (status == FAILURE)
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
if (width > (size_t) len)
|
if (width > len)
|
||||||
s += (width - len);
|
s += (width - len);
|
||||||
|
|
||||||
m = ((int) width > len) ? len : (int) width;
|
m = ((int) width > len) ? len : (int) width;
|
||||||
|
|
@ -425,7 +411,7 @@ void
|
||||||
read_a (st_parameter_dt *dtp, const fnode *f, char *p, int length)
|
read_a (st_parameter_dt *dtp, const fnode *f, char *p, int length)
|
||||||
{
|
{
|
||||||
int wi;
|
int wi;
|
||||||
size_t w;
|
int w;
|
||||||
|
|
||||||
wi = f->u.w;
|
wi = f->u.w;
|
||||||
if (wi == -1) /* '(A)' edit descriptor */
|
if (wi == -1) /* '(A)' edit descriptor */
|
||||||
|
|
@ -451,13 +437,11 @@ read_a (st_parameter_dt *dtp, const fnode *f, char *p, int length)
|
||||||
void
|
void
|
||||||
read_a_char4 (st_parameter_dt *dtp, const fnode *f, char *p, int length)
|
read_a_char4 (st_parameter_dt *dtp, const fnode *f, char *p, int length)
|
||||||
{
|
{
|
||||||
int wi;
|
int w;
|
||||||
size_t w;
|
|
||||||
|
|
||||||
wi = f->u.w;
|
w = f->u.w;
|
||||||
if (wi == -1) /* '(A)' edit descriptor */
|
if (w == -1) /* '(A)' edit descriptor */
|
||||||
wi = length;
|
w = length;
|
||||||
w = wi;
|
|
||||||
|
|
||||||
/* Read in w characters, treating comma as not a separator. */
|
/* Read in w characters, treating comma as not a separator. */
|
||||||
dtp->u.p.sf_read_comma = 0;
|
dtp->u.p.sf_read_comma = 0;
|
||||||
|
|
@ -532,18 +516,15 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
GFC_UINTEGER_LARGEST value, maxv, maxv_10;
|
GFC_UINTEGER_LARGEST value, maxv, maxv_10;
|
||||||
GFC_INTEGER_LARGEST v;
|
GFC_INTEGER_LARGEST v;
|
||||||
int w, negative;
|
int w, negative;
|
||||||
size_t wu;
|
|
||||||
char c, *p;
|
char c, *p;
|
||||||
|
|
||||||
wu = f->u.w;
|
w = f->u.w;
|
||||||
|
|
||||||
p = gfc_alloca (wu);
|
p = read_block_form (dtp, &w);
|
||||||
|
|
||||||
if (read_block_form (dtp, p, &wu) == FAILURE)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
w = wu;
|
|
||||||
|
|
||||||
p = eat_leading_spaces (&w, p);
|
p = eat_leading_spaces (&w, p);
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -636,17 +617,14 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length,
|
||||||
GFC_INTEGER_LARGEST v;
|
GFC_INTEGER_LARGEST v;
|
||||||
int w, negative;
|
int w, negative;
|
||||||
char c, *p;
|
char c, *p;
|
||||||
size_t wu;
|
|
||||||
|
|
||||||
wu = f->u.w;
|
w = f->u.w;
|
||||||
|
|
||||||
p = gfc_alloca (wu);
|
p = read_block_form (dtp, &w);
|
||||||
|
|
||||||
if (read_block_form (dtp, p, &wu) == FAILURE)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
w = wu;
|
|
||||||
|
|
||||||
p = eat_leading_spaces (&w, p);
|
p = eat_leading_spaces (&w, p);
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -783,75 +761,83 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length,
|
||||||
void
|
void
|
||||||
read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
{
|
{
|
||||||
size_t wu;
|
|
||||||
int w, seen_dp, exponent;
|
int w, seen_dp, exponent;
|
||||||
int exponent_sign, val_sign;
|
int exponent_sign;
|
||||||
int ndigits;
|
const char *p;
|
||||||
int edigits;
|
char *buffer;
|
||||||
int i;
|
char *out;
|
||||||
char *p, *buffer;
|
int seen_int_digit; /* Seen a digit before the decimal point? */
|
||||||
char *digits;
|
int seen_dec_digit; /* Seen a digit after the decimal point? */
|
||||||
char scratch[SCRATCH_SIZE];
|
|
||||||
|
|
||||||
val_sign = 1;
|
|
||||||
seen_dp = 0;
|
seen_dp = 0;
|
||||||
wu = f->u.w;
|
seen_int_digit = 0;
|
||||||
|
seen_dec_digit = 0;
|
||||||
|
exponent_sign = 1;
|
||||||
|
exponent = 0;
|
||||||
|
w = f->u.w;
|
||||||
|
|
||||||
p = gfc_alloca (wu);
|
/* Read in the next block. */
|
||||||
|
p = read_block_form (dtp, &w);
|
||||||
if (read_block_form (dtp, p, &wu) == FAILURE)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
p = eat_leading_spaces (&w, (char*) p);
|
||||||
w = wu;
|
|
||||||
|
|
||||||
p = eat_leading_spaces (&w, p);
|
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
goto zero;
|
goto zero;
|
||||||
|
|
||||||
/* Optional sign */
|
/* In this buffer we're going to re-format the number cleanly to be parsed
|
||||||
|
by convert_real in the end; this assures we're using strtod from the
|
||||||
|
C library for parsing and thus probably get the best accuracy possible.
|
||||||
|
This process may add a '+0.0' in front of the number as well as change the
|
||||||
|
exponent because of an implicit decimal point or the like. Thus allocating
|
||||||
|
strlen ("+0.0e-1000") == 10 characters plus one for NUL more than the
|
||||||
|
original buffer had should be enough. */
|
||||||
|
buffer = gfc_alloca (w + 11);
|
||||||
|
out = buffer;
|
||||||
|
|
||||||
|
/* Optional sign */
|
||||||
if (*p == '-' || *p == '+')
|
if (*p == '-' || *p == '+')
|
||||||
{
|
{
|
||||||
if (*p == '-')
|
if (*p == '-')
|
||||||
val_sign = -1;
|
*(out++) = '-';
|
||||||
p++;
|
++p;
|
||||||
w--;
|
--w;
|
||||||
}
|
}
|
||||||
|
|
||||||
exponent_sign = 1;
|
p = eat_leading_spaces (&w, (char*) p);
|
||||||
p = eat_leading_spaces (&w, p);
|
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
goto zero;
|
goto zero;
|
||||||
|
|
||||||
/* A digit, a '.' or a exponent character ('e', 'E', 'd' or 'D')
|
/* Process the mantissa string. */
|
||||||
is required at this point */
|
|
||||||
|
|
||||||
if (!isdigit (*p) && *p != '.' && *p != ',' && *p != 'd' && *p != 'D'
|
|
||||||
&& *p != 'e' && *p != 'E')
|
|
||||||
goto bad_float;
|
|
||||||
|
|
||||||
/* Remember the position of the first digit. */
|
|
||||||
digits = p;
|
|
||||||
ndigits = 0;
|
|
||||||
|
|
||||||
/* Scan through the string to find the exponent. */
|
|
||||||
while (w > 0)
|
while (w > 0)
|
||||||
{
|
{
|
||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
case ',':
|
case ',':
|
||||||
if (dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA
|
if (dtp->u.p.current_unit->decimal_status != DECIMAL_COMMA)
|
||||||
&& *p == ',')
|
|
||||||
*p = '.';
|
|
||||||
else
|
|
||||||
goto bad_float;
|
goto bad_float;
|
||||||
/* Fall through */
|
/* Fall through. */
|
||||||
case '.':
|
case '.':
|
||||||
if (seen_dp)
|
if (seen_dp)
|
||||||
goto bad_float;
|
goto bad_float;
|
||||||
|
if (!seen_int_digit)
|
||||||
|
*(out++) = '0';
|
||||||
|
*(out++) = '.';
|
||||||
seen_dp = 1;
|
seen_dp = 1;
|
||||||
/* Fall through */
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
if (dtp->u.p.blank_status == BLANK_ZERO)
|
||||||
|
{
|
||||||
|
*(out++) = '0';
|
||||||
|
goto found_digit;
|
||||||
|
}
|
||||||
|
else if (dtp->u.p.blank_status == BLANK_NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
/* TODO: Should we check instead that there are only trailing
|
||||||
|
blanks here, as is done below for exponents? */
|
||||||
|
goto done;
|
||||||
|
/* Fall through. */
|
||||||
case '0':
|
case '0':
|
||||||
case '1':
|
case '1':
|
||||||
case '2':
|
case '2':
|
||||||
|
|
@ -862,65 +848,160 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
case '7':
|
case '7':
|
||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
case ' ':
|
*(out++) = *p;
|
||||||
ndigits++;
|
found_digit:
|
||||||
p++;
|
if (!seen_dp)
|
||||||
w--;
|
seen_int_digit = 1;
|
||||||
|
else
|
||||||
|
seen_dec_digit = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
exponent_sign = -1;
|
|
||||||
/* Fall through */
|
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
p++;
|
goto exponent;
|
||||||
w--;
|
|
||||||
goto exp2;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'D':
|
|
||||||
case 'E':
|
case 'E':
|
||||||
p++;
|
case 'd':
|
||||||
w--;
|
case 'D':
|
||||||
goto exp1;
|
++p;
|
||||||
|
--w;
|
||||||
|
goto exponent;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto bad_float;
|
goto bad_float;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* No exponent has been seen, so we use the current scale factor */
|
++p;
|
||||||
exponent = -dtp->u.p.scale_factor;
|
--w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No exponent has been seen, so we use the current scale factor. */
|
||||||
|
exponent = - dtp->u.p.scale_factor;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
bad_float:
|
/* At this point the start of an exponent has been found. */
|
||||||
generate_error (&dtp->common, LIBERROR_READ_VALUE,
|
exponent:
|
||||||
"Bad value during floating point read");
|
p = eat_leading_spaces (&w, (char*) p);
|
||||||
next_record (dtp, 1);
|
if (*p == '-' || *p == '+')
|
||||||
|
{
|
||||||
|
if (*p == '-')
|
||||||
|
exponent_sign = -1;
|
||||||
|
++p;
|
||||||
|
--w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point a digit string is required. We calculate the value
|
||||||
|
of the exponent in order to take account of the scale factor and
|
||||||
|
the d parameter before explict conversion takes place. */
|
||||||
|
|
||||||
|
if (w == 0)
|
||||||
|
goto bad_float;
|
||||||
|
|
||||||
|
if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
|
||||||
|
{
|
||||||
|
while (w > 0 && isdigit (*p))
|
||||||
|
{
|
||||||
|
exponent *= 10;
|
||||||
|
exponent += *p - '0';
|
||||||
|
++p;
|
||||||
|
--w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only allow trailing blanks. */
|
||||||
|
while (w > 0)
|
||||||
|
{
|
||||||
|
if (*p != ' ')
|
||||||
|
goto bad_float;
|
||||||
|
++p;
|
||||||
|
--w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* BZ or BN status is enabled. */
|
||||||
|
{
|
||||||
|
while (w > 0)
|
||||||
|
{
|
||||||
|
if (*p == ' ')
|
||||||
|
{
|
||||||
|
if (dtp->u.p.blank_status == BLANK_ZERO)
|
||||||
|
exponent *= 10;
|
||||||
|
else
|
||||||
|
assert (dtp->u.p.blank_status == BLANK_NULL);
|
||||||
|
}
|
||||||
|
else if (!isdigit (*p))
|
||||||
|
goto bad_float;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exponent *= 10;
|
||||||
|
exponent += *p - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
--w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exponent *= exponent_sign;
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* Use the precision specified in the format if no decimal point has been
|
||||||
|
seen. */
|
||||||
|
if (!seen_dp)
|
||||||
|
exponent -= f->u.real.d;
|
||||||
|
|
||||||
|
/* Output a trailing '0' after decimal point if not yet found. */
|
||||||
|
if (seen_dp && !seen_dec_digit)
|
||||||
|
*(out++) = '0';
|
||||||
|
|
||||||
|
/* Print out the exponent to finish the reformatted number. Maximum 4
|
||||||
|
digits for the exponent. */
|
||||||
|
if (exponent != 0)
|
||||||
|
{
|
||||||
|
int dig;
|
||||||
|
|
||||||
|
*(out++) = 'e';
|
||||||
|
if (exponent < 0)
|
||||||
|
{
|
||||||
|
*(out++) = '-';
|
||||||
|
exponent = - exponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (exponent < 10000);
|
||||||
|
for (dig = 3; dig >= 0; --dig)
|
||||||
|
{
|
||||||
|
out[dig] = (char) ('0' + exponent % 10);
|
||||||
|
exponent /= 10;
|
||||||
|
}
|
||||||
|
out += 4;
|
||||||
|
}
|
||||||
|
*(out++) = '\0';
|
||||||
|
|
||||||
|
/* Do the actual conversion. */
|
||||||
|
convert_real (dtp, dest, buffer, length);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* The value read is zero */
|
/* The value read is zero. */
|
||||||
zero:
|
zero:
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 4:
|
case 4:
|
||||||
*((GFC_REAL_4 *) dest) = 0;
|
*((GFC_REAL_4 *) dest) = 0.0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
*((GFC_REAL_8 *) dest) = 0;
|
*((GFC_REAL_8 *) dest) = 0.0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_10
|
#ifdef HAVE_GFC_REAL_10
|
||||||
case 10:
|
case 10:
|
||||||
*((GFC_REAL_10 *) dest) = 0;
|
*((GFC_REAL_10 *) dest) = 0.0;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GFC_REAL_16
|
#ifdef HAVE_GFC_REAL_16
|
||||||
case 16:
|
case 16:
|
||||||
*((GFC_REAL_16 *) dest) = 0;
|
*((GFC_REAL_16 *) dest) = 0.0;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -929,140 +1010,11 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* At this point the start of an exponent has been found */
|
bad_float:
|
||||||
exp1:
|
generate_error (&dtp->common, LIBERROR_READ_VALUE,
|
||||||
while (w > 0 && *p == ' ')
|
"Bad value during floating point read");
|
||||||
{
|
next_record (dtp, 1);
|
||||||
w--;
|
return;
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (*p)
|
|
||||||
{
|
|
||||||
case '-':
|
|
||||||
exponent_sign = -1;
|
|
||||||
/* Fall through */
|
|
||||||
|
|
||||||
case '+':
|
|
||||||
p++;
|
|
||||||
w--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w == 0)
|
|
||||||
goto bad_float;
|
|
||||||
|
|
||||||
/* At this point a digit string is required. We calculate the value
|
|
||||||
of the exponent in order to take account of the scale factor and
|
|
||||||
the d parameter before explict conversion takes place. */
|
|
||||||
exp2:
|
|
||||||
/* Normal processing of exponent */
|
|
||||||
exponent = 0;
|
|
||||||
if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
|
|
||||||
{
|
|
||||||
while (w > 0 && isdigit (*p))
|
|
||||||
{
|
|
||||||
exponent = 10 * exponent + *p - '0';
|
|
||||||
p++;
|
|
||||||
w--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only allow trailing blanks */
|
|
||||||
|
|
||||||
while (w > 0)
|
|
||||||
{
|
|
||||||
if (*p != ' ')
|
|
||||||
goto bad_float;
|
|
||||||
p++;
|
|
||||||
w--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* BZ or BN status is enabled */
|
|
||||||
{
|
|
||||||
while (w > 0)
|
|
||||||
{
|
|
||||||
if (*p == ' ')
|
|
||||||
{
|
|
||||||
if (dtp->u.p.blank_status == BLANK_ZERO) *p = '0';
|
|
||||||
if (dtp->u.p.blank_status == BLANK_NULL)
|
|
||||||
{
|
|
||||||
p++;
|
|
||||||
w--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!isdigit (*p))
|
|
||||||
goto bad_float;
|
|
||||||
|
|
||||||
exponent = 10 * exponent + *p - '0';
|
|
||||||
p++;
|
|
||||||
w--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exponent = exponent * exponent_sign;
|
|
||||||
|
|
||||||
done:
|
|
||||||
/* Use the precision specified in the format if no decimal point has been
|
|
||||||
seen. */
|
|
||||||
if (!seen_dp)
|
|
||||||
exponent -= f->u.real.d;
|
|
||||||
|
|
||||||
if (exponent > 0)
|
|
||||||
{
|
|
||||||
edigits = 2;
|
|
||||||
i = exponent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
edigits = 3;
|
|
||||||
i = -exponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i >= 10)
|
|
||||||
{
|
|
||||||
i /= 10;
|
|
||||||
edigits++;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = ndigits + edigits + 1;
|
|
||||||
if (val_sign < 0)
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i < SCRATCH_SIZE)
|
|
||||||
buffer = scratch;
|
|
||||||
else
|
|
||||||
buffer = get_mem (i);
|
|
||||||
|
|
||||||
/* Reformat the string into a temporary buffer. As we're using atof it's
|
|
||||||
easiest to just leave the decimal point in place. */
|
|
||||||
p = buffer;
|
|
||||||
if (val_sign < 0)
|
|
||||||
*(p++) = '-';
|
|
||||||
for (; ndigits > 0; ndigits--)
|
|
||||||
{
|
|
||||||
if (*digits == ' ')
|
|
||||||
{
|
|
||||||
if (dtp->u.p.blank_status == BLANK_ZERO) *digits = '0';
|
|
||||||
if (dtp->u.p.blank_status == BLANK_NULL)
|
|
||||||
{
|
|
||||||
digits++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = *digits;
|
|
||||||
p++;
|
|
||||||
digits++;
|
|
||||||
}
|
|
||||||
*(p++) = 'e';
|
|
||||||
sprintf (p, "%d", exponent);
|
|
||||||
|
|
||||||
/* Do the actual conversion. */
|
|
||||||
convert_real (dtp, dest, buffer, length);
|
|
||||||
|
|
||||||
if (buffer != scratch)
|
|
||||||
free_mem (buffer);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -540,6 +540,8 @@ init_units (void)
|
||||||
u->file_len = strlen (stdin_name);
|
u->file_len = strlen (stdin_name);
|
||||||
u->file = get_mem (u->file_len);
|
u->file = get_mem (u->file_len);
|
||||||
memmove (u->file, stdin_name, u->file_len);
|
memmove (u->file, stdin_name, u->file_len);
|
||||||
|
|
||||||
|
fbuf_init (u, 0);
|
||||||
|
|
||||||
__gthread_mutex_unlock (&u->lock);
|
__gthread_mutex_unlock (&u->lock);
|
||||||
}
|
}
|
||||||
|
|
@ -640,7 +642,8 @@ close_unit_1 (gfc_unit *u, int locked)
|
||||||
free_mem (u->file);
|
free_mem (u->file);
|
||||||
u->file = NULL;
|
u->file = NULL;
|
||||||
u->file_len = 0;
|
u->file_len = 0;
|
||||||
|
|
||||||
|
free_format_hash_table (u);
|
||||||
fbuf_destroy (u);
|
fbuf_destroy (u);
|
||||||
|
|
||||||
if (!locked)
|
if (!locked)
|
||||||
|
|
@ -697,15 +700,62 @@ close_units (void)
|
||||||
void
|
void
|
||||||
update_position (gfc_unit *u)
|
update_position (gfc_unit *u)
|
||||||
{
|
{
|
||||||
if (file_position (u->s) == 0)
|
if (stell (u->s) == 0)
|
||||||
u->flags.position = POSITION_REWIND;
|
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;
|
u->flags.position = POSITION_APPEND;
|
||||||
else
|
else
|
||||||
u->flags.position = POSITION_ASIS;
|
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
|
/* 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
|
name of the associated file, otherwise return the empty string. The caller
|
||||||
must free memory allocated for the filename string. */
|
must free memory allocated for the filename string. */
|
||||||
|
|
@ -746,23 +796,25 @@ finish_last_advance_record (gfc_unit *u)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (u->saved_pos > 0)
|
if (u->saved_pos > 0)
|
||||||
fbuf_seek (u, u->saved_pos);
|
fbuf_seek (u, u->saved_pos, SEEK_CUR);
|
||||||
|
|
||||||
fbuf_flush (u, 1);
|
|
||||||
|
|
||||||
if (!(u->unit_number == options.stdout_unit
|
if (!(u->unit_number == options.stdout_unit
|
||||||
|| u->unit_number == options.stderr_unit))
|
|| u->unit_number == options.stderr_unit))
|
||||||
{
|
{
|
||||||
size_t len;
|
|
||||||
|
|
||||||
const char crlf[] = "\r\n";
|
|
||||||
#ifdef HAVE_CRLF
|
#ifdef HAVE_CRLF
|
||||||
len = 2;
|
const int len = 2;
|
||||||
#else
|
#else
|
||||||
len = 1;
|
const int len = 1;
|
||||||
#endif
|
#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");
|
os_error ("Completing record after ADVANCE_NO failed");
|
||||||
|
#ifdef HAVE_CRLF
|
||||||
|
*(p++) = '\r';
|
||||||
|
#endif
|
||||||
|
*p = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fbuf_flush (u, u->mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -113,7 +113,7 @@ write_utf8_char4 (st_parameter_dt *dtp, gfc_char4_t *source,
|
||||||
gfc_char4_t c;
|
gfc_char4_t c;
|
||||||
static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
static const uchar masks[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
|
static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
|
||||||
size_t nbytes;
|
int nbytes;
|
||||||
uchar buf[6], d, *q;
|
uchar buf[6], d, *q;
|
||||||
|
|
||||||
/* Take care of preceding blanks. */
|
/* Take care of preceding blanks. */
|
||||||
|
|
@ -784,8 +784,7 @@ write_x (st_parameter_dt *dtp, int len, int nspaces)
|
||||||
p = write_block (dtp, len);
|
p = write_block (dtp, len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
if (nspaces > 0 && len - nspaces >= 0)
|
||||||
if (nspaces > 0)
|
|
||||||
memset (&p[len - nspaces], ' ', nspaces);
|
memset (&p[len - nspaces], ' ', nspaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1173,7 +1172,7 @@ namelist_write_newline (st_parameter_dt *dtp)
|
||||||
/* Now seek to this record */
|
/* Now seek to this record */
|
||||||
record = record * dtp->u.p.current_unit->recl;
|
record = record * dtp->u.p.current_unit->recl;
|
||||||
|
|
||||||
if (sseek (dtp->u.p.current_unit->s, record) == FAILURE)
|
if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
|
||||||
{
|
{
|
||||||
generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
|
generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue