1 //========================================================================
5 // Implementations of internal C library stdio stream functions
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2006 eCosCentric Limited
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //========================================================================
39 //#####DESCRIPTIONBEGIN####
41 // Author(s): jlarmour
48 //####DESCRIPTIONEND####
50 //========================================================================
54 #include <pkgconf/libc_stdio.h> // Configuration header
58 #include <cyg/infra/cyg_type.h> // Common project-wide type definitions
59 #include <cyg/infra/cyg_ass.h> // Assertion infrastructure
60 #include <stddef.h> // NULL and size_t from compiler
61 #include <errno.h> // Error codes
62 #include <string.h> // memcpy() and memset()
63 #include <cyg/libc/stdio/stream.hxx> // Header for this file
64 #include <cyg/libc/stdio/stdiosupp.hxx> // Stdio support functions
67 #include <cyg/libc/stdio/io.inl> // I/O system inlines
72 Cyg_StdioStream::Cyg_StdioStream(cyg_stdio_handle_t dev,
74 cyg_bool append, cyg_bool binary,
75 int buffer_mode, cyg_ucount32 buffer_size,
76 cyg_uint8 *buffer_addr )
77 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
78 : io_buf( buffer_size, buffer_addr )
81 initialize( dev, open_mode, append, binary, buffer_mode,
82 buffer_size, buffer_addr);
85 void Cyg_StdioStream::initialize(cyg_stdio_handle_t dev,
87 cyg_bool append, cyg_bool binary,
88 int buffer_mode, cyg_ucount32 buffer_size,
89 cyg_uint8 *buffer_addr )
92 #ifdef CYGDBG_USE_ASSERTS
93 magic_validity_word = 0xbadbad;
99 memset( &flags, 0, sizeof(flags) );
102 case CYG_STREAM_READ:
103 flags.opened_for_read = true;
105 case CYG_STREAM_WRITE:
106 flags.opened_for_write = true;
108 case CYG_STREAM_READWRITE_NOCREATE:
109 case CYG_STREAM_READWRITE_CREATE:
110 flags.opened_for_read = true;
111 flags.opened_for_write = true;
119 if (flags.opened_for_write) {
121 // FIXME: need some replacement for this
122 if (!my_device->write_blocking) {
127 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
128 flags.last_buffer_op_was_read = false;
133 if (flags.opened_for_read) {
135 // FIXME: need some replacement for this
136 if (!my_device->read_blocking) {
142 // NB also if opened for read AND write, then say last op was read
143 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
144 flags.last_buffer_op_was_read = true;
148 flags.binary = binary ? 1 : 0;
152 // in due course we would do an equivalent to fseek(...,0, SEEK_END);
153 // when appending. for now, there's nothing, except set eof
155 flags.at_eof = append ? 1 : 0;
159 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
161 switch (buffer_mode) {
163 CYG_ASSERT( (buffer_size == 0) && (buffer_addr == NULL),
164 "No buffering wanted but size/address specified!" );
165 flags.buffering = flags.line_buffering = false;
168 flags.buffering = true;
169 flags.line_buffering = true;
172 flags.buffering = true;
173 flags.line_buffering = false;
180 // one way of checking the buffer was set up correctly
181 if (flags.buffering && io_buf.get_buffer_size()==-1) {
188 #if 0 // FIXME - Need to set binary mode.
189 if (my_device->open) {
190 error = (*my_device->open)( my_device->cookie,
191 binary ? CYG_DEVICE_OPEN_MODE_RAW
192 : CYG_DEVICE_OPEN_MODE_TEXT );
194 return; // keep error code the same
199 #ifdef CYGDBG_USE_ASSERTS
200 magic_validity_word = 0x7b4321ce;
203 } // Cyg_StdioStream constructor
206 Cyg_StdioStream::Cyg_StdioStream( OpenMode open_mode,
207 cyg_ucount32 buffer_size,
208 cyg_uint8 *buffer_addr )
209 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
210 : io_buf( buffer_size, buffer_addr )
213 initialize( CYG_STDIO_HANDLE_NULL, open_mode, false, false, _IOFBF,
214 buffer_size, buffer_addr );
216 if( error != ENOERR )
221 case CYG_STREAM_READ:
222 // Fix up the stream so it looks like the buffer contents has just
224 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
225 io_buf.set_bytes_written( buffer_size );
229 case CYG_STREAM_WRITE:
230 // Fix up the stream so it looks like the buffer is ready to accept
242 Cyg_StdioStream::refill_read_buffer( void )
248 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
251 return EBADF; // assume file is now invalid
253 // first just check that we _can_ read this device!
254 if (!flags.opened_for_read) {
259 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
260 // If there is pending output to write, then this will check and
262 if (flags.buffering) {
263 read_err = flush_output_unlocked();
266 flags.last_buffer_op_was_read = true;
269 if (read_err == ENOERR)
270 read_err = cyg_libc_stdio_flush_all_but(this);
272 if (read_err != ENOERR) {
277 len = io_buf.get_buffer_addr_to_write( (cyg_uint8**)&buffer );
278 if (!len) { // no buffer space available
280 return ENOERR; // isn't an error, just needs user to read out data
286 if (!flags.readbuf_char_in_use) {
288 buffer = &readbuf_char;
291 // no buffer space available
293 return ENOERR; // isn't an error, just needs user to read out data
296 read_err = cyg_stdio_read(my_device, buffer, &len);
299 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
301 io_buf.set_bytes_written( len );
304 flags.readbuf_char_in_use = len ? 1 : 0;
308 if (read_err == ENOERR) {
314 flags.at_eof = false;
318 } // refill_read_buffer()
322 Cyg_StdioStream::read( cyg_uint8 *user_buffer, cyg_ucount32 buffer_length,
323 cyg_ucount32 *bytes_read )
325 Cyg_ErrNo read_err=ENOERR;
326 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
331 return EBADF; // assume file is now invalid
333 if (!flags.opened_for_read) {
338 #ifdef CYGFUN_LIBC_STDIO_ungetc
339 if (flags.unread_char_buf_in_use && buffer_length) {
340 *user_buffer++ = unread_char_buf;
342 flags.unread_char_buf_in_use = false;
346 #endif // ifdef CYGFUN_LIBC_STDIO_ungetc
348 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
349 if (flags.buffering) {
351 // need to flush output if we were writing before
352 if (!flags.last_buffer_op_was_read) {
353 Cyg_ErrNo err = flush_output_unlocked();
361 cyg_uint8 *buff_to_read_from;
362 cyg_ucount32 bytes_available;
364 bytes_available = io_buf.get_buffer_addr_to_read(
365 (cyg_uint8 **)&buff_to_read_from );
368 (bytes_available < buffer_length) ? bytes_available : buffer_length;
371 memcpy( user_buffer, buff_to_read_from, count );
372 io_buf.set_bytes_read( count );
373 *bytes_read += count;
381 if (flags.readbuf_char_in_use && buffer_length) {
382 *user_buffer = readbuf_char;
384 flags.readbuf_char_in_use = false;
388 // if we are unbuffered, we read as much as we can directly from the
389 // file system at this point.
391 // unless we do this, we could end up reading byte-by-byte from the filing system
392 // due to the readbuf_char scheme.
394 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
397 (*bytes_read<buffer_length)) {
399 len=buffer_length-*bytes_read;
400 read_err = cyg_stdio_read(my_device, user_buffer + *bytes_read, &len);
404 position += *bytes_read;
413 Cyg_StdioStream::read_byte( cyg_uint8 *c )
415 Cyg_ErrNo err=ENOERR;
417 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
420 return EBADF; // assume file is now invalid
422 if (!flags.opened_for_read) {
427 # ifdef CYGFUN_LIBC_STDIO_ungetc
428 if (flags.unread_char_buf_in_use) {
429 *c = unread_char_buf;
430 flags.unread_char_buf_in_use = false;
435 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
437 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
438 if (flags.buffering) {
439 // need to flush output if we were writing before
440 if (!flags.last_buffer_op_was_read)
441 err = flush_output_unlocked();
448 cyg_uint8 *buff_to_read_from;
449 cyg_ucount32 bytes_available;
451 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
453 if (bytes_available) {
454 *c = *buff_to_read_from;
455 io_buf.set_bytes_read(1);
466 if (flags.readbuf_char_in_use) {
468 flags.readbuf_char_in_use = false;
481 Cyg_StdioStream::peek_byte( cyg_uint8 *c )
483 Cyg_ErrNo err=ENOERR;
485 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
488 return EBADF; // assume file is now invalid
490 if (!flags.opened_for_read) {
495 // this should really only be called after refill_read_buffer, but just
497 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
499 err = flush_output_unlocked();
505 flags.last_buffer_op_was_read = true;
508 # ifdef CYGFUN_LIBC_STDIO_ungetc
509 if (flags.unread_char_buf_in_use) {
510 *c = unread_char_buf;
514 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
516 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
517 if (flags.buffering) {
518 cyg_uint8 *buff_to_read_from;
519 cyg_ucount32 bytes_available;
521 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
523 if (bytes_available) {
524 *c = *buff_to_read_from;
534 if (flags.readbuf_char_in_use) {
547 Cyg_StdioStream::flush_output_unlocked( void )
549 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
550 Cyg_ErrNo write_err=ENOERR;
554 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
556 if ( flags.last_buffer_op_was_read )
559 // first just check that we _can_ write to the device!
560 if ( !flags.opened_for_write )
563 // shortcut if nothing to do
564 if (io_buf.get_buffer_space_used() == 0)
567 len = io_buf.get_buffer_addr_to_read( (cyg_uint8 **)&buffer );
570 "There should be data to read but there isn't!");
572 write_err = cyg_stdio_write(my_device, buffer, &len);
574 // since we're doing a concerted flush, we tell the I/O layer to
575 // flush too, otherwise output may just sit there forever
577 cyg_stdio_flush( my_device );
579 // we've just read it all, so just wipe it out
580 io_buf.drain_buffer();
584 #else // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
586 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
590 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
591 } // flush_output_unlocked()
596 Cyg_StdioStream::write( const cyg_uint8 *buffer,
597 cyg_ucount32 buffer_length,
598 cyg_ucount32 *bytes_written )
600 Cyg_ErrNo write_err = ENOERR;
602 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
607 return EBADF; // assume file is now invalid
609 // first just check that we _can_ write to the device!
610 if ( !flags.opened_for_write ) {
615 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
616 if (flags.last_buffer_op_was_read == true) {
617 #ifdef CYGPKG_LIBC_STDIO_FILEIO
618 if ( 0 != io_buf.get_buffer_space_used() )
620 off_t newpos = position;
621 io_buf.drain_buffer(); // nuke input bytes to prevent confusion
622 Cyg_ErrNo err = cyg_stdio_lseek( my_device, &newpos, SEEK_SET );
629 io_buf.drain_buffer(); // nuke input bytes to prevent confusion
633 flags.last_buffer_op_was_read = false;
635 if (!flags.buffering) {
637 cyg_uint32 len = buffer_length;
639 write_err = cyg_stdio_write(my_device, buffer, &len);
641 *bytes_written = len;
643 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
646 cyg_ucount32 bytes_available;
647 cyg_ucount32 bytes_to_write;
648 cyg_ucount32 newline_pos;
649 cyg_uint8 *write_addr;
650 cyg_bool must_flush = false;
652 while ( buffer_length > 0 ) {
654 io_buf.get_buffer_addr_to_write( &write_addr );
656 // we need to flush if we've no room or the buffer has an up
657 // and coming newline
658 if ( !bytes_available || must_flush ) {
659 write_err = flush_output_unlocked();
661 // harmless even if there was an error
663 io_buf.get_buffer_addr_to_write( &write_addr );
665 CYG_ASSERT( bytes_available > 0,
666 "Help! still no bytes available in "
675 // choose the lower of the buffer available and the length
677 bytes_to_write=(bytes_available < buffer_length)
681 // if we're line buffered, we may want want to flush if there's
682 // a newline character, so lets find out
684 if (flags.line_buffering) {
686 newline_pos<bytes_to_write;
688 if (buffer[newline_pos] == '\n') {
692 // if we didn't reach the end
693 if (newline_pos != bytes_to_write) {
694 // shrink bytes_to_write down to the bit we need to
695 // flush including the newline itself
696 bytes_to_write = newline_pos + 1;
701 memcpy( write_addr, buffer, bytes_to_write );
703 *bytes_written += bytes_to_write;
704 buffer += bytes_to_write;
705 buffer_length -= bytes_to_write;
706 io_buf.set_bytes_written( bytes_to_write );
708 position += bytes_to_write;
713 write_err = flush_output_unlocked();
716 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
724 // class Cyg_OutputStream
728 Cyg_OutputStream::write( const cyg_uint8 *buffer, cyg_ucount32 buffer_length,
729 cyg_ucount32 *bytes_written )
731 CYG_FAIL("Cyg_OutputStream::write(): pure virtual called");
736 Cyg_OutputStream::get_error( void )
738 CYG_FAIL("Cyg_OutputStream::get_error(): pure virtual called");