OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [language/] [c/] [libc/] [stdio/] [v2_0/] [src/] [common/] [stream.cxx] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//========================================================================
2
//
3
//      stream.cxx
4
//
5
//      Implementations of internal C library stdio stream functions
6
//
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
//
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.
16
//
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
20
// for more details.
21
//
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.
25
//
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.
32
//
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.
35
//
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####
42
//
43
// Author(s):     jlarmour
44
// Contributors:  
45
// Date:          2000-04-20
46
// Purpose:     
47
// Description: 
48
// Usage:       
49
//
50
//####DESCRIPTIONEND####
51
//
52
//========================================================================
53
 
54
// CONFIGURATION
55
 
56
#include <pkgconf/libc_stdio.h>   // Configuration header
57
 
58
// INCLUDES
59
 
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
67
 
68
 
69
#include <cyg/libc/stdio/io.inl>     // I/O system inlines
70
 
71
 
72
// FUNCTIONS
73
 
74
Cyg_StdioStream::Cyg_StdioStream(cyg_stdio_handle_t dev,
75
                                 OpenMode open_mode,
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 )
81
#endif
82
{
83
    initialize( dev, open_mode, append, binary, buffer_mode,
84
                buffer_size, buffer_addr);
85
}
86
 
87
void Cyg_StdioStream::initialize(cyg_stdio_handle_t dev,
88
                                 OpenMode open_mode,
89
                                 cyg_bool append, cyg_bool binary,
90
                                 int buffer_mode, cyg_ucount32 buffer_size,
91
                                 cyg_uint8 *buffer_addr )
92
{
93
 
94
#ifdef CYGDBG_USE_ASSERTS
95
    magic_validity_word = 0xbadbad;
96
#endif
97
 
98
    my_device = dev;
99
 
100
    // Clear all flags
101
    memset( &flags, 0, sizeof(flags) );
102
 
103
    switch (open_mode) {
104
    case CYG_STREAM_READ:
105
        flags.opened_for_read = true;
106
        break;
107
    case CYG_STREAM_WRITE:
108
        flags.opened_for_write = true;
109
        break;
110
    case CYG_STREAM_READWRITE:
111
        flags.opened_for_read = true;
112
        flags.opened_for_write = true;
113
        break;
114
    default:
115
        error=EINVAL;
116
        return;
117
    } // switch
118
 
119
 
120
    if (flags.opened_for_write) {
121
#if 0
122
        // FIXME: need some replacement for this
123
        if (!my_device->write_blocking) {
124
            error = EDEVNOSUPP;
125
            return;
126
        } // if
127
#endif
128
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
129
        flags.last_buffer_op_was_read = false;
130
#endif
131
    } // if
132
 
133
 
134
    if (flags.opened_for_read) {
135
#if 0
136
        // FIXME: need some replacement for this
137
        if (!my_device->read_blocking) {
138
            error = EDEVNOSUPP;
139
            return;
140
        } // if
141
#endif
142
 
143
        // NB also if opened for read AND write, then say last op was read
144
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
145
        flags.last_buffer_op_was_read = true;
146
#endif
147
    } // if
148
 
149
    flags.binary = binary ? 1 : 0;
150
 
151
    error = ENOERR;
152
 
153
    // in due course we would do an equivalent to fseek(...,0, SEEK_END);
154
    // when appending. for now, there's nothing, except set eof
155
 
156
    flags.at_eof = append ? 1 : 0;
157
 
158
    position = 0;
159
 
160
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
161
 
162
    switch (buffer_mode) {
163
    case _IONBF:
164
        CYG_ASSERT( (buffer_size == 0) && (buffer_addr == NULL),
165
                    "No buffering wanted but size/address specified!" );
166
        flags.buffering = flags.line_buffering = false;
167
        break;
168
    case _IOLBF:
169
        flags.buffering = true;
170
        flags.line_buffering = true;
171
        break;
172
    case _IOFBF:
173
        flags.buffering = true;
174
        flags.line_buffering = false;
175
        break;
176
    default:
177
        error = EINVAL;
178
        return;
179
    } // switch
180
 
181
    // one way of checking the buffer was set up correctly
182
    if (flags.buffering && io_buf.get_buffer_size()==-1) {
183
        error = ENOMEM;
184
        return;
185
    }
186
 
187
#endif
188
 
189
#if 0 // FIXME - Need to set binary mode.
190
    if (my_device->open) {
191
        error = (*my_device->open)( my_device->cookie,
192
                                    binary ? CYG_DEVICE_OPEN_MODE_RAW
193
                                           : CYG_DEVICE_OPEN_MODE_TEXT );
194
        if (error != ENOERR)
195
            return; // keep error code the same
196
    } // if
197
 
198
#endif
199
 
200
#ifdef CYGDBG_USE_ASSERTS
201
    magic_validity_word = 0x7b4321ce;
202
#endif
203
 
204
} // Cyg_StdioStream constructor
205
 
206
 
207
Cyg_StdioStream::Cyg_StdioStream( OpenMode open_mode,
208
                                 cyg_ucount32 buffer_size,
209
                                  cyg_uint8 *buffer_addr )
210
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
211
    : io_buf( buffer_size, buffer_addr )
212
#endif
213
{
214
    initialize( CYG_STDIO_HANDLE_NULL, open_mode, false, false, _IOFBF,
215
                buffer_size, buffer_addr );
216
 
217
    if( error != ENOERR )
218
        return;
219
 
220
    switch( open_mode )
221
    {
222
    case CYG_STREAM_READ:
223
        // Fix up the stream so it looks like the buffer contents has just
224
        // been read in.
225
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
226
        io_buf.set_bytes_written( buffer_size );
227
#endif
228
        break;
229
 
230
    case CYG_STREAM_WRITE:
231
        // Fix up the stream so it looks like the buffer is ready to accept
232
        // new data.
233
        break;
234
 
235
    default:
236
        error = EINVAL;
237
        return;
238
    }
239
}
240
 
241
 
242
Cyg_ErrNo
243
Cyg_StdioStream::refill_read_buffer( void )
244
{
245
    Cyg_ErrNo read_err;
246
    cyg_uint8 *buffer;
247
    cyg_uint32 len;
248
 
249
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
250
 
251
    if (!lock_me())
252
        return EBADF;  // assume file is now invalid
253
 
254
    // first just check that we _can_ read this device!
255
    if (!flags.opened_for_read) {
256
        unlock_me();
257
        return EINVAL;
258
    }
259
 
260
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
261
    // If there is pending output to write, then this will check and
262
    // write it
263
    if (flags.buffering) {
264
        read_err = flush_output_unlocked();
265
 
266
        // we're now reading
267
        flags.last_buffer_op_was_read = true;
268
 
269
        // flush ALL streams
270
        if (read_err == ENOERR)
271
            read_err = cyg_libc_stdio_flush_all_but(this);
272
 
273
        if (read_err != ENOERR) {
274
            unlock_me();
275
            return read_err;
276
        } // if
277
 
278
        len = io_buf.get_buffer_addr_to_write( (cyg_uint8**)&buffer );
279
        if (!len) { // no buffer space available
280
            unlock_me();
281
            return ENOERR;  // isn't an error, just needs user to read out data
282
        } // if
283
    }
284
    else
285
#endif
286
 
287
    if (!flags.readbuf_char_in_use) {
288
        len = 1;
289
        buffer = &readbuf_char;
290
    }
291
    else {
292
        // no buffer space available
293
        unlock_me();
294
        return ENOERR;  // isn't an error, just needs user to read out data
295
    } // else
296
 
297
    read_err = cyg_stdio_read(my_device, buffer, &len);
298
 
299
 
300
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
301
    if (flags.buffering)
302
        io_buf.set_bytes_written( len );
303
    else
304
#endif
305
        flags.readbuf_char_in_use = len ? 1 : 0;
306
 
307
    unlock_me();
308
 
309
    if (read_err == ENOERR) {
310
        if (len == 0) {
311
            read_err = EAGAIN;
312
            flags.at_eof = true;
313
        }
314
        else
315
            flags.at_eof = false;
316
    } // if
317
 
318
    return read_err;
319
} // refill_read_buffer()
320
 
321
 
322
Cyg_ErrNo
323
Cyg_StdioStream::read( cyg_uint8 *user_buffer, cyg_ucount32 buffer_length,
324
                       cyg_ucount32 *bytes_read )
325
{
326
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
327
 
328
    *bytes_read = 0;
329
 
330
    if (!lock_me())
331
        return EBADF;  // assume file is now invalid
332
 
333
    if (!flags.opened_for_read) {
334
        unlock_me();
335
        return EINVAL;
336
    }
337
 
338
#ifdef CYGFUN_LIBC_STDIO_ungetc
339
    if (flags.unread_char_buf_in_use && buffer_length) {
340
        *user_buffer++ = unread_char_buf;
341
        ++*bytes_read;
342
        flags.unread_char_buf_in_use = false;
343
        --buffer_length;
344
    } // if
345
 
346
#endif // ifdef CYGFUN_LIBC_STDIO_ungetc
347
 
348
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
349
    if (flags.buffering) {
350
 
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();
354
 
355
            if (ENOERR != err) {
356
                unlock_me();
357
                return err;
358
            }
359
        }
360
 
361
        cyg_uint8 *buff_to_read_from;
362
        cyg_ucount32 bytes_available;
363
 
364
        bytes_available = io_buf.get_buffer_addr_to_read(
365
              (cyg_uint8 **)&buff_to_read_from );
366
 
367
        cyg_ucount32 count =
368
            (bytes_available < buffer_length) ? bytes_available : buffer_length;
369
 
370
        if (count) {
371
            memcpy( user_buffer, buff_to_read_from, count );
372
            io_buf.set_bytes_read( count );
373
            *bytes_read += count;
374
        } // if
375
 
376
    } // if
377
    else
378
 
379
#endif
380
 
381
    if (flags.readbuf_char_in_use && buffer_length) {
382
        *user_buffer = readbuf_char;
383
        *bytes_read = 1;
384
        flags.readbuf_char_in_use = false;
385
    }
386
 
387
    position += *bytes_read;
388
 
389
    unlock_me();
390
 
391
    return ENOERR;
392
} // read()
393
 
394
 
395
Cyg_ErrNo
396
Cyg_StdioStream::read_byte( cyg_uint8 *c )
397
{
398
    Cyg_ErrNo err=ENOERR;
399
 
400
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
401
 
402
    if (!lock_me())
403
        return EBADF;  // assume file is now invalid
404
 
405
    if (!flags.opened_for_read) {
406
        unlock_me();
407
        return EINVAL;
408
    }
409
 
410
# ifdef CYGFUN_LIBC_STDIO_ungetc
411
    if (flags.unread_char_buf_in_use) {
412
        *c = unread_char_buf;
413
        flags.unread_char_buf_in_use = false;
414
        position++;
415
        unlock_me();
416
        return ENOERR;
417
    } // if
418
# endif // ifdef CYGFUN_LIBC_STDIO_ungetc
419
 
420
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
421
    if (flags.buffering) {
422
        // need to flush output if we were writing before
423
        if (!flags.last_buffer_op_was_read)
424
            err = flush_output_unlocked();
425
 
426
        if (ENOERR != err) {
427
            unlock_me();
428
            return err;
429
        }
430
 
431
        cyg_uint8 *buff_to_read_from;
432
        cyg_ucount32 bytes_available;
433
 
434
        bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
435
 
436
        if (bytes_available) {
437
            *c = *buff_to_read_from;
438
            io_buf.set_bytes_read(1);
439
            position++;
440
        }
441
        else
442
            err = EAGAIN;
443
    } // if
444
    else
445
 
446
#endif
447
 
448
 
449
    if (flags.readbuf_char_in_use) {
450
        *c = readbuf_char;
451
        flags.readbuf_char_in_use = false;
452
        position++;
453
    }
454
    else
455
        err = EAGAIN;
456
 
457
    unlock_me();
458
 
459
    return err;
460
} // read_byte()
461
 
462
 
463
Cyg_ErrNo
464
Cyg_StdioStream::peek_byte( cyg_uint8 *c )
465
{
466
    Cyg_ErrNo err=ENOERR;
467
 
468
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
469
 
470
    if (!lock_me())
471
        return EBADF;  // assume file is now invalid
472
 
473
    if (!flags.opened_for_read) {
474
        unlock_me();
475
        return EINVAL;
476
    }
477
 
478
    // this should really only be called after refill_read_buffer, but just
479
    // in case
480
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
481
    if (flags.buffering)
482
        err = flush_output_unlocked();
483
 
484
    if (err != ENOERR)
485
        return err;
486
 
487
    // we're now reading
488
    flags.last_buffer_op_was_read = true;
489
#endif
490
 
491
# ifdef CYGFUN_LIBC_STDIO_ungetc
492
    if (flags.unread_char_buf_in_use) {
493
        *c = unread_char_buf;
494
        unlock_me();
495
        return ENOERR;
496
    } // if
497
# endif // ifdef CYGFUN_LIBC_STDIO_ungetc
498
 
499
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
500
    if (flags.buffering) {
501
        cyg_uint8 *buff_to_read_from;
502
        cyg_ucount32 bytes_available;
503
 
504
        bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
505
 
506
        if (bytes_available) {
507
            *c = *buff_to_read_from;
508
        }
509
        else
510
            err = EAGAIN;
511
    } // if
512
    else
513
 
514
#endif
515
 
516
 
517
    if (flags.readbuf_char_in_use) {
518
        *c = readbuf_char;
519
    }
520
    else
521
        err = EAGAIN;
522
 
523
    unlock_me();
524
 
525
    return err;
526
} // peek_byte()
527
 
528
 
529
Cyg_ErrNo
530
Cyg_StdioStream::flush_output_unlocked( void )
531
{
532
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
533
    Cyg_ErrNo write_err=ENOERR;
534
    cyg_uint8 *buffer;
535
    cyg_uint32 len;
536
 
537
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
538
 
539
    if ( flags.last_buffer_op_was_read )
540
        return ENOERR;
541
 
542
    // first just check that we _can_ write to the device!
543
    if ( !flags.opened_for_write )
544
        return EINVAL;
545
 
546
    // shortcut if nothing to do
547
    if (io_buf.get_buffer_space_used() == 0)
548
        return ENOERR;
549
 
550
    len = io_buf.get_buffer_addr_to_read( (cyg_uint8 **)&buffer );
551
 
552
    CYG_ASSERT( len > 0,
553
                "There should be data to read but there isn't!");
554
 
555
    write_err = cyg_stdio_write(my_device, buffer, &len);
556
 
557
    // since we're doing a concerted flush, we tell the I/O layer to
558
    // flush too, otherwise output may just sit there forever
559
    if (!write_err)
560
        cyg_stdio_flush( my_device );
561
 
562
        // we've just read it all, so just wipe it out
563
    io_buf.drain_buffer();
564
 
565
    return write_err;
566
 
567
#else // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
568
 
569
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
570
 
571
    return ENOERR;
572
 
573
#endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
574
} // flush_output_unlocked()
575
 
576
 
577
 
578
Cyg_ErrNo
579
Cyg_StdioStream::write( const cyg_uint8 *buffer,
580
                        cyg_ucount32 buffer_length,
581
                        cyg_ucount32 *bytes_written )
582
{
583
    Cyg_ErrNo write_err = ENOERR;
584
 
585
    CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
586
 
587
    *bytes_written = 0;
588
 
589
    if (!lock_me())
590
        return EBADF;  // assume file is now invalid
591
 
592
    // first just check that we _can_ write to the device!
593
    if ( !flags.opened_for_write ) {
594
        unlock_me();
595
        return EINVAL;
596
    }
597
 
598
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
599
    if (flags.last_buffer_op_was_read == true)
600
        io_buf.drain_buffer();  // nuke input bytes to prevent confusion
601
 
602
    flags.last_buffer_op_was_read = false;
603
 
604
    if (!flags.buffering) {
605
#endif
606
        cyg_uint32 len = buffer_length;
607
 
608
        write_err = cyg_stdio_write(my_device, buffer, &len);
609
 
610
        *bytes_written = len;
611
 
612
#ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
613
    } // if
614
    else {
615
        cyg_ucount32 bytes_available;
616
        cyg_ucount32 bytes_to_write;
617
        cyg_ucount32 newline_pos;
618
        cyg_uint8 *write_addr;
619
        cyg_bool must_flush = false;
620
 
621
        while ( buffer_length > 0 ) {
622
            bytes_available =
623
                io_buf.get_buffer_addr_to_write( &write_addr );
624
 
625
            // we need to flush if we've no room or the buffer has an up
626
            // and coming newline
627
            if ( !bytes_available || must_flush ) {
628
                write_err = flush_output_unlocked();
629
 
630
                // harmless even if there was an error
631
                bytes_available =
632
                    io_buf.get_buffer_addr_to_write( &write_addr );
633
 
634
                CYG_ASSERT( bytes_available > 0,
635
                            "Help! still no bytes available in "
636
                            "write buffer" );
637
            } // if
638
 
639
            if (write_err) {
640
                unlock_me();
641
                return write_err;
642
            } // if
643
 
644
            // choose the lower of the buffer available and the length
645
            // to write
646
            bytes_to_write=(bytes_available < buffer_length)
647
                ? bytes_available
648
                : buffer_length;
649
 
650
            // if we're line buffered, we may want want to flush if there's
651
            // a newline character, so lets find out
652
 
653
            if (flags.line_buffering) {
654
                for (newline_pos=0;
655
                     newline_pos<bytes_to_write;
656
                     newline_pos++) {
657
                    if (buffer[newline_pos] == '\n') {
658
                        break;
659
                    } // if
660
                } // for
661
                // if we didn't reach the end
662
                if (newline_pos != bytes_to_write) {
663
                    // shrink bytes_to_write down to the bit we need to
664
                    // flush including the newline itself
665
                    bytes_to_write = newline_pos + 1;
666
                    must_flush = true;
667
                } // if
668
            } // if
669
 
670
            memcpy( write_addr, buffer, bytes_to_write );
671
 
672
            *bytes_written += bytes_to_write;
673
            buffer += bytes_to_write;
674
            buffer_length -= bytes_to_write;
675
            io_buf.set_bytes_written( bytes_to_write );
676
 
677
            position += bytes_to_write;
678
 
679
        } // while
680
 
681
        if ( must_flush ) {
682
            write_err = flush_output_unlocked();
683
        } // if
684
    } // else
685
#endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
686
 
687
    unlock_me();
688
 
689
    return write_err;
690
} // write()
691
 
692
// EOF stream.cxx

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.