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.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
50 //####DESCRIPTIONEND####
52 //========================================================================
56 #include <pkgconf/libc_stdio.h> // Configuration header
60 #include <cyg/infra/cyg_type.h> // Common project-wide type definitions
61 #include <cyg/infra/cyg_ass.h> // Assertion infrastructure
62 #include <stddef.h> // NULL and size_t from compiler
63 #include <errno.h> // Error codes
64 #include <string.h> // memcpy() and memset()
65 #include <cyg/libc/stdio/stream.hxx> // Header for this file
66 #include <cyg/libc/stdio/stdiosupp.hxx> // Stdio support functions
69 #include <cyg/libc/stdio/io.inl> // I/O system inlines
74 Cyg_StdioStream::Cyg_StdioStream(cyg_stdio_handle_t dev,
76 cyg_bool append, cyg_bool binary,
77 int buffer_mode, cyg_ucount32 buffer_size,
78 cyg_uint8 *buffer_addr )
79 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
80 : io_buf( buffer_size, buffer_addr )
83 initialize( dev, open_mode, append, binary, buffer_mode,
84 buffer_size, buffer_addr);
87 void Cyg_StdioStream::initialize(cyg_stdio_handle_t dev,
89 cyg_bool append, cyg_bool binary,
90 int buffer_mode, cyg_ucount32 buffer_size,
91 cyg_uint8 *buffer_addr )
94 #ifdef CYGDBG_USE_ASSERTS
95 magic_validity_word = 0xbadbad;
101 memset( &flags, 0, sizeof(flags) );
104 case CYG_STREAM_READ:
105 flags.opened_for_read = true;
107 case CYG_STREAM_WRITE:
108 flags.opened_for_write = true;
110 case CYG_STREAM_READWRITE_NOCREATE:
111 case CYG_STREAM_READWRITE_CREATE:
112 flags.opened_for_read = true;
113 flags.opened_for_write = true;
121 if (flags.opened_for_write) {
123 // FIXME: need some replacement for this
124 if (!my_device->write_blocking) {
129 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
130 flags.last_buffer_op_was_read = false;
135 if (flags.opened_for_read) {
137 // FIXME: need some replacement for this
138 if (!my_device->read_blocking) {
144 // NB also if opened for read AND write, then say last op was read
145 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
146 flags.last_buffer_op_was_read = true;
150 flags.binary = binary ? 1 : 0;
154 // in due course we would do an equivalent to fseek(...,0, SEEK_END);
155 // when appending. for now, there's nothing, except set eof
157 flags.at_eof = append ? 1 : 0;
161 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
163 switch (buffer_mode) {
165 CYG_ASSERT( (buffer_size == 0) && (buffer_addr == NULL),
166 "No buffering wanted but size/address specified!" );
167 flags.buffering = flags.line_buffering = false;
170 flags.buffering = true;
171 flags.line_buffering = true;
174 flags.buffering = true;
175 flags.line_buffering = false;
182 // one way of checking the buffer was set up correctly
183 if (flags.buffering && io_buf.get_buffer_size()==-1) {
190 #if 0 // FIXME - Need to set binary mode.
191 if (my_device->open) {
192 error = (*my_device->open)( my_device->cookie,
193 binary ? CYG_DEVICE_OPEN_MODE_RAW
194 : CYG_DEVICE_OPEN_MODE_TEXT );
196 return; // keep error code the same
201 #ifdef CYGDBG_USE_ASSERTS
202 magic_validity_word = 0x7b4321ce;
205 } // Cyg_StdioStream constructor
208 Cyg_StdioStream::Cyg_StdioStream( OpenMode open_mode,
209 cyg_ucount32 buffer_size,
210 cyg_uint8 *buffer_addr )
211 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
212 : io_buf( buffer_size, buffer_addr )
215 initialize( CYG_STDIO_HANDLE_NULL, open_mode, false, false, _IOFBF,
216 buffer_size, buffer_addr );
218 if( error != ENOERR )
223 case CYG_STREAM_READ:
224 // Fix up the stream so it looks like the buffer contents has just
226 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
227 io_buf.set_bytes_written( buffer_size );
231 case CYG_STREAM_WRITE:
232 // Fix up the stream so it looks like the buffer is ready to accept
244 Cyg_StdioStream::refill_read_buffer( void )
250 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
253 return EBADF; // assume file is now invalid
255 // first just check that we _can_ read this device!
256 if (!flags.opened_for_read) {
261 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
262 // If there is pending output to write, then this will check and
264 if (flags.buffering) {
265 read_err = flush_output_unlocked();
268 flags.last_buffer_op_was_read = true;
271 if (read_err == ENOERR)
272 read_err = cyg_libc_stdio_flush_all_but(this);
274 if (read_err != ENOERR) {
279 len = io_buf.get_buffer_addr_to_write( (cyg_uint8**)&buffer );
280 if (!len) { // no buffer space available
282 return ENOERR; // isn't an error, just needs user to read out data
288 if (!flags.readbuf_char_in_use) {
290 buffer = &readbuf_char;
293 // no buffer space available
295 return ENOERR; // isn't an error, just needs user to read out data
298 read_err = cyg_stdio_read(my_device, buffer, &len);
301 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
303 io_buf.set_bytes_written( len );
306 flags.readbuf_char_in_use = len ? 1 : 0;
310 if (read_err == ENOERR) {
316 flags.at_eof = false;
320 } // refill_read_buffer()
324 Cyg_StdioStream::read( cyg_uint8 *user_buffer, cyg_ucount32 buffer_length,
325 cyg_ucount32 *bytes_read )
327 Cyg_ErrNo read_err=ENOERR;
328 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
333 return EBADF; // assume file is now invalid
335 if (!flags.opened_for_read) {
340 #ifdef CYGFUN_LIBC_STDIO_ungetc
341 if (flags.unread_char_buf_in_use && buffer_length) {
342 *user_buffer++ = unread_char_buf;
344 flags.unread_char_buf_in_use = false;
348 #endif // ifdef CYGFUN_LIBC_STDIO_ungetc
350 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
351 if (flags.buffering) {
353 // need to flush output if we were writing before
354 if (!flags.last_buffer_op_was_read) {
355 Cyg_ErrNo err = flush_output_unlocked();
363 cyg_uint8 *buff_to_read_from;
364 cyg_ucount32 bytes_available;
366 bytes_available = io_buf.get_buffer_addr_to_read(
367 (cyg_uint8 **)&buff_to_read_from );
370 (bytes_available < buffer_length) ? bytes_available : buffer_length;
373 memcpy( user_buffer, buff_to_read_from, count );
374 io_buf.set_bytes_read( count );
375 *bytes_read += count;
383 if (flags.readbuf_char_in_use && buffer_length) {
384 *user_buffer = readbuf_char;
386 flags.readbuf_char_in_use = false;
389 position += *bytes_read;
392 // if we are unbuffered, we read as much as we can directly from the
393 // file system at this point.
395 // unless we do this, we could end up reading byte-by-byte from the filing system
396 // due to the readbuf_char scheme.
398 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
401 (*bytes_read<buffer_length)) {
403 len=buffer_length-*bytes_read;
404 read_err = cyg_stdio_read(my_device, user_buffer + *bytes_read, &len);
415 Cyg_StdioStream::read_byte( cyg_uint8 *c )
417 Cyg_ErrNo err=ENOERR;
419 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
422 return EBADF; // assume file is now invalid
424 if (!flags.opened_for_read) {
429 # ifdef CYGFUN_LIBC_STDIO_ungetc
430 if (flags.unread_char_buf_in_use) {
431 *c = unread_char_buf;
432 flags.unread_char_buf_in_use = false;
437 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
439 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
440 if (flags.buffering) {
441 // need to flush output if we were writing before
442 if (!flags.last_buffer_op_was_read)
443 err = flush_output_unlocked();
450 cyg_uint8 *buff_to_read_from;
451 cyg_ucount32 bytes_available;
453 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
455 if (bytes_available) {
456 *c = *buff_to_read_from;
457 io_buf.set_bytes_read(1);
468 if (flags.readbuf_char_in_use) {
470 flags.readbuf_char_in_use = false;
483 Cyg_StdioStream::peek_byte( cyg_uint8 *c )
485 Cyg_ErrNo err=ENOERR;
487 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
490 return EBADF; // assume file is now invalid
492 if (!flags.opened_for_read) {
497 // this should really only be called after refill_read_buffer, but just
499 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
501 err = flush_output_unlocked();
507 flags.last_buffer_op_was_read = true;
510 # ifdef CYGFUN_LIBC_STDIO_ungetc
511 if (flags.unread_char_buf_in_use) {
512 *c = unread_char_buf;
516 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
518 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
519 if (flags.buffering) {
520 cyg_uint8 *buff_to_read_from;
521 cyg_ucount32 bytes_available;
523 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
525 if (bytes_available) {
526 *c = *buff_to_read_from;
536 if (flags.readbuf_char_in_use) {
549 Cyg_StdioStream::flush_output_unlocked( void )
551 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
552 Cyg_ErrNo write_err=ENOERR;
556 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
558 if ( flags.last_buffer_op_was_read )
561 // first just check that we _can_ write to the device!
562 if ( !flags.opened_for_write )
565 // shortcut if nothing to do
566 if (io_buf.get_buffer_space_used() == 0)
569 len = io_buf.get_buffer_addr_to_read( (cyg_uint8 **)&buffer );
572 "There should be data to read but there isn't!");
574 write_err = cyg_stdio_write(my_device, buffer, &len);
576 // since we're doing a concerted flush, we tell the I/O layer to
577 // flush too, otherwise output may just sit there forever
579 cyg_stdio_flush( my_device );
581 // we've just read it all, so just wipe it out
582 io_buf.drain_buffer();
586 #else // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
588 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
592 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
593 } // flush_output_unlocked()
598 Cyg_StdioStream::write( const cyg_uint8 *buffer,
599 cyg_ucount32 buffer_length,
600 cyg_ucount32 *bytes_written )
602 Cyg_ErrNo write_err = ENOERR;
604 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
609 return EBADF; // assume file is now invalid
611 // first just check that we _can_ write to the device!
612 if ( !flags.opened_for_write ) {
617 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
618 if (flags.last_buffer_op_was_read == true)
619 io_buf.drain_buffer(); // nuke input bytes to prevent confusion
621 flags.last_buffer_op_was_read = false;
623 if (!flags.buffering) {
625 cyg_uint32 len = buffer_length;
627 write_err = cyg_stdio_write(my_device, buffer, &len);
629 *bytes_written = len;
631 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
634 cyg_ucount32 bytes_available;
635 cyg_ucount32 bytes_to_write;
636 cyg_ucount32 newline_pos;
637 cyg_uint8 *write_addr;
638 cyg_bool must_flush = false;
640 while ( buffer_length > 0 ) {
642 io_buf.get_buffer_addr_to_write( &write_addr );
644 // we need to flush if we've no room or the buffer has an up
645 // and coming newline
646 if ( !bytes_available || must_flush ) {
647 write_err = flush_output_unlocked();
649 // harmless even if there was an error
651 io_buf.get_buffer_addr_to_write( &write_addr );
653 CYG_ASSERT( bytes_available > 0,
654 "Help! still no bytes available in "
663 // choose the lower of the buffer available and the length
665 bytes_to_write=(bytes_available < buffer_length)
669 // if we're line buffered, we may want want to flush if there's
670 // a newline character, so lets find out
672 if (flags.line_buffering) {
674 newline_pos<bytes_to_write;
676 if (buffer[newline_pos] == '\n') {
680 // if we didn't reach the end
681 if (newline_pos != bytes_to_write) {
682 // shrink bytes_to_write down to the bit we need to
683 // flush including the newline itself
684 bytes_to_write = newline_pos + 1;
689 memcpy( write_addr, buffer, bytes_to_write );
691 *bytes_written += bytes_to_write;
692 buffer += bytes_to_write;
693 buffer_length -= bytes_to_write;
694 io_buf.set_bytes_written( bytes_to_write );
696 position += bytes_to_write;
701 write_err = flush_output_unlocked();
704 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO