comparison packages/language/c/libc/current/src/stdio/common/stream.cxx @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
comparison
equal deleted inserted replaced
-1:000000000000 0:3111d98ba7b3
1 //========================================================================
2 //
3 // stream.cxx
4 //
5 // Implementations of internal C library stdio stream functions
6 //
7 //========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Cygnus eCos Public License
12 // Version 1.0 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://sourceware.cygnus.com/ecos
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Cygnus Operating System, released
22 // September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Cygnus. Portions created
25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved.
26 // -------------------------------------------
27 //
28 //####COPYRIGHTEND####
29 //========================================================================
30 //#####DESCRIPTIONBEGIN####
31 //
32 // Author(s): jlarmour@cygnus.co.uk
33 // Contributors: jlarmour@cygnus.co.uk
34 // Date: 1998-02-13
35 // Purpose:
36 // Description:
37 // Usage:
38 //
39 //####DESCRIPTIONEND####
40 //
41 //========================================================================
42
43 // CONFIGURATION
44
45 #include <pkgconf/libc.h> // Configuration header
46
47
48 // Include the C library? And do we want the stdio stuff?
49 #if defined(CYGPKG_LIBC) && defined(CYGPKG_LIBC_STDIO)
50
51 // INCLUDES
52
53 #include <cyg/infra/cyg_type.h> // Common project-wide type definitions
54 #include <stddef.h> // NULL and size_t from compiler
55 #include <errno.h> // Error codes
56 #include "clibincl/stringsupp.hxx" // _memcpy()
57 #include "clibincl/stream.hxx" // Header for this file
58 #include <cyg/devs/common/iorb.h> // Cyg_IORB
59 #include <cyg/devs/common/table.h> // Device table
60
61
62 // FUNCTIONS
63
64 Cyg_StdioStream::Cyg_StdioStream(Cyg_Device_Table_t *dev,
65 OpenMode open_mode,
66 cyg_bool append, cyg_bool binary,
67 int buffer_mode, cyg_ucount32 buffer_size,
68 cyg_uint8 *buffer_addr )
69 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
70 : io_buf( buffer_size, buffer_addr )
71 #endif
72
73 {
74 #ifdef CYGDBG_USE_ASSERTS
75 magic_validity_word = 0xbadbad;
76 #endif
77
78 my_device = dev;
79
80 // Clear all flags
81 _memset( &flags, 0, sizeof(flags) );
82
83 switch (open_mode) {
84 case CYG_STREAM_READ:
85 flags.opened_for_read = true;
86 break;
87 case CYG_STREAM_WRITE:
88 flags.opened_for_write = true;
89 break;
90 case CYG_STREAM_READWRITE:
91 flags.opened_for_read = true;
92 flags.opened_for_write = true;
93 break;
94 default:
95 error=EINVAL;
96 return;
97 } // switch
98
99
100 if (flags.opened_for_write) {
101 if (!my_device->write_blocking) {
102 error = EDEVNOSUPP;
103 return;
104 } // if
105
106 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
107 flags.last_buffer_op_was_read = false;
108 #endif
109 } // if
110
111
112 if (flags.opened_for_read) {
113 if (!my_device->read_blocking) {
114 error = EDEVNOSUPP;
115 return;
116 } // if
117
118 // NB also if opened for read AND write, then say last op was read
119 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
120 flags.last_buffer_op_was_read = true;
121 #endif
122 } // if
123
124 flags.binary = binary ? 1 : 0;
125
126 error = ENOERR;
127
128 // in due course we would do an equivalent to fseek(...,0, SEEK_END);
129 // when appending. for now, there's nothing, except set eof
130
131 flags.at_eof = append ? 1 : 0;
132
133 position = 0;
134
135 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
136
137 switch (buffer_mode) {
138 case _IONBF:
139 CYG_ASSERT( (buffer_size == 0) && (buffer_addr == NULL),
140 "No buffering wanted but size/address specified!" );
141 flags.buffering = flags.line_buffering = false;
142 break;
143 case _IOLBF:
144 flags.buffering = true;
145 flags.line_buffering = true;
146 break;
147 case _IOFBF:
148 flags.buffering = true;
149 flags.line_buffering = false;
150 break;
151 default:
152 error = EINVAL;
153 return;
154 } // switch
155
156 // one way of checking the buffer was set up correctly
157 if (io_buf.get_buffer_size()==-1) {
158 error = ENOMEM;
159 return;
160 }
161
162 #endif
163
164 if (my_device->open) {
165 error = (*my_device->open)( my_device->cookie,
166 binary ? CYG_DEVICE_OPEN_MODE_RAW
167 : CYG_DEVICE_OPEN_MODE_TEXT );
168 if (error != ENOERR)
169 return; // keep error code the same
170 } // if
171
172
173 #ifdef CYGDBG_USE_ASSERTS
174 magic_validity_word = 0x7b4321ce;
175 #endif
176
177 } // Cyg_StdioStream constructor
178
179
180
181 Cyg_ErrNo
182 Cyg_StdioStream::refill_read_buffer( void )
183 {
184 Cyg_ErrNo read_err;
185 Cyg_IORB iorb;
186
187 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
188
189 if (!lock_me())
190 return EBADF; // assume file is now invalid
191
192 // first just check that we _can_ read this device!
193 if (!flags.opened_for_read) {
194 unlock_me();
195 return EINVAL;
196 }
197
198 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
199 // If there is pending output to write, then this will check and
200 // write it
201 if (flags.buffering) {
202 read_err = flush_output_unlocked();
203
204 if (read_err != ENOERR) {
205 unlock_me();
206 return read_err;
207 } // if
208 } // if
209 #endif
210
211 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
212 // we're now reading
213 flags.last_buffer_op_was_read = true;
214
215 if (flags.buffering) {
216 iorb.buffer_length =
217 io_buf.get_buffer_addr_to_write( (cyg_uint8**)&iorb.buffer );
218 }
219 else
220 #endif
221
222 if (!flags.readbuf_char_in_use) {
223 iorb.buffer_length = 1;
224 iorb.buffer = &readbuf_char;
225 }
226 else
227 iorb.buffer_length = 0;
228
229 if (!iorb.buffer_length) { // no buffer space available
230 unlock_me();
231 return ENOERR; // isn't an error, just needs user to read out data
232 } // if
233
234 read_err = (*my_device->read_blocking)( my_device->cookie, &iorb );
235
236
237 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
238 if (flags.buffering)
239 io_buf.set_bytes_written( iorb.xferred_length );
240 else
241 #endif
242 flags.readbuf_char_in_use = iorb.xferred_length ? 1 : 0;
243
244 unlock_me();
245
246 if (read_err == ENOERR) {
247 if (iorb.xferred_length == 0)
248 read_err = EAGAIN;
249 } // if
250
251 return read_err;
252 } // refill_read_buffer()
253
254
255 Cyg_ErrNo
256 Cyg_StdioStream::read( cyg_uint8 *user_buffer, cyg_ucount32 buffer_length,
257 cyg_ucount32 *bytes_read )
258 {
259 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
260
261 *bytes_read = 0;
262
263 if (!lock_me())
264 return EBADF; // assume file is now invalid
265
266 if (!flags.opened_for_read) {
267 unlock_me();
268 return EINVAL;
269 }
270
271 #ifdef CYGFUN_LIBC_STDIO_ungetc
272 if (flags.unread_char_buf_in_use && buffer_length) {
273 *user_buffer++ = unread_char_buf;
274 ++*bytes_read;
275 flags.unread_char_buf_in_use = false;
276 --buffer_length;
277 } // if
278
279 #endif // ifdef CYGFUN_LIBC_STDIO_ungetc
280
281 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
282 if (flags.buffering) {
283 cyg_uint8 *buff_to_read_from;
284 cyg_ucount32 bytes_available;
285 Cyg_ErrNo err;
286
287 // this should really only be called after refill_read_buffer, but
288 // just in case
289 err = flush_output_unlocked();
290
291 if (err != ENOERR) {
292 unlock_me();
293 return err;
294 }
295
296 // we're now reading
297 flags.last_buffer_op_was_read = true;
298
299 bytes_available = io_buf.get_buffer_addr_to_read(
300 (cyg_uint8 **)&buff_to_read_from );
301
302 *bytes_read += (bytes_available < buffer_length) ? bytes_available
303 : buffer_length;
304 if (*bytes_read) {
305 memcpy( user_buffer, buff_to_read_from, *bytes_read );
306 io_buf.set_bytes_read( *bytes_read );
307 } // if
308
309 } // if
310 else
311
312 #endif
313
314 if (flags.readbuf_char_in_use && buffer_length) {
315 *user_buffer = readbuf_char;
316 *bytes_read = 1;
317 flags.readbuf_char_in_use = false;
318 }
319
320 unlock_me();
321
322 return ENOERR;
323 } // read()
324
325
326 Cyg_ErrNo
327 Cyg_StdioStream::read_byte( cyg_uint8 *c )
328 {
329 Cyg_ErrNo err=ENOERR;
330
331 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
332
333 if (!lock_me())
334 return EBADF; // assume file is now invalid
335
336 if (!flags.opened_for_read) {
337 unlock_me();
338 return EINVAL;
339 }
340
341 // this should really only be called after refill_read_buffer, but just
342 // in case
343 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
344 if (flags.buffering)
345 err = flush_output_unlocked();
346
347 if (err != ENOERR)
348 return err;
349
350 // we're now reading
351 flags.last_buffer_op_was_read = true;
352 #endif
353
354 # ifdef CYGFUN_LIBC_STDIO_ungetc
355 if (flags.unread_char_buf_in_use) {
356 *c = unread_char_buf;
357 flags.unread_char_buf_in_use = false;
358 unlock_me();
359 return ENOERR;
360 } // if
361 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
362
363 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
364 if (flags.buffering) {
365 cyg_uint8 *buff_to_read_from;
366 cyg_ucount32 bytes_available;
367
368 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
369
370 if (bytes_available) {
371 *c = *buff_to_read_from;
372 io_buf.set_bytes_read(1);
373 }
374 else
375 err = EAGAIN;
376 } // if
377 else
378
379 #endif
380
381
382 if (flags.readbuf_char_in_use) {
383 *c = readbuf_char;
384 flags.readbuf_char_in_use = false;
385 }
386 else
387 err = EAGAIN;
388
389 unlock_me();
390
391 return err;
392 } // read_byte()
393
394
395 Cyg_ErrNo
396 Cyg_StdioStream::peek_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 // this should really only be called after refill_read_buffer, but just
411 // in case
412 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
413 if (flags.buffering)
414 err = flush_output_unlocked();
415
416 if (err != ENOERR)
417 return err;
418
419 // we're now reading
420 flags.last_buffer_op_was_read = true;
421 #endif
422
423 # ifdef CYGFUN_LIBC_STDIO_ungetc
424 if (flags.unread_char_buf_in_use) {
425 *c = unread_char_buf;
426 unlock_me();
427 return ENOERR;
428 } // if
429 # endif // ifdef CYGFUN_LIBC_STDIO_ungetc
430
431 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
432 if (flags.buffering) {
433 cyg_uint8 *buff_to_read_from;
434 cyg_ucount32 bytes_available;
435
436 bytes_available=io_buf.get_buffer_addr_to_read(&buff_to_read_from);
437
438 if (bytes_available) {
439 *c = *buff_to_read_from;
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 }
452 else
453 err = EAGAIN;
454
455 unlock_me();
456
457 return err;
458 } // peek_byte()
459
460
461 Cyg_ErrNo
462 Cyg_StdioStream::flush_output_unlocked( void )
463 {
464 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
465 Cyg_IORB iorb;
466 Cyg_ErrNo write_err=ENOERR;
467
468 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
469
470 if ( flags.last_buffer_op_was_read )
471 return ENOERR;
472
473 // first just check that we _can_ write to the device!
474 if ( !flags.opened_for_write )
475 return EINVAL;
476
477 // shortcut if nothing to do
478 if (io_buf.get_buffer_space_used() == 0)
479 return ENOERR;
480
481 iorb.buffer_length =
482 io_buf.get_buffer_addr_to_read( (cyg_uint8 **)&iorb.buffer );
483
484 CYG_ASSERT( iorb.buffer_length > 0,
485 "There should be data to read but there isn't!");
486
487 write_err = (*my_device->write_blocking)( my_device->cookie, &iorb );
488
489 // we've just read it all, so just wipe it out
490 io_buf.drain_buffer();
491
492 return write_err;
493
494 #else // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
495
496 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
497
498 return ENOERR;
499
500 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
501 } // flush_output_unlocked()
502
503
504
505 Cyg_ErrNo
506 Cyg_StdioStream::write( const cyg_uint8 *buffer,
507 cyg_ucount32 buffer_length,
508 cyg_ucount32 *bytes_written )
509 {
510 Cyg_ErrNo write_err = ENOERR;
511
512 CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
513
514 *bytes_written = 0;
515
516 if (!lock_me())
517 return EBADF; // assume file is now invalid
518
519 // first just check that we _can_ write to the device!
520 if ( !flags.opened_for_write ) {
521 unlock_me();
522 return EINVAL;
523 }
524
525 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
526 if (flags.last_buffer_op_was_read == true)
527 io_buf.drain_buffer(); // nuke input bytes to prevent confusion
528
529 flags.last_buffer_op_was_read = false;
530
531 if (!flags.buffering) {
532 #endif
533 Cyg_IORB iorb;
534 iorb.buffer = (char *)buffer;
535 iorb.buffer_length = buffer_length;
536
537 write_err = (*my_device->write_blocking)( my_device->cookie,
538 &iorb );
539
540 *bytes_written = iorb.xferred_length;
541
542 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
543 } // if
544 else {
545 cyg_ucount32 bytes_available;
546 cyg_ucount32 bytes_to_write;
547 cyg_ucount32 newline_pos;
548 cyg_uint8 *write_addr;
549 cyg_bool must_flush = false;
550
551 while ( buffer_length > 0 ) {
552 bytes_available =
553 io_buf.get_buffer_addr_to_write( &write_addr );
554
555 // we need to flush if we've no room or the buffer has an up
556 // and coming newline
557 if ( !bytes_available || must_flush ) {
558 write_err = flush_output_unlocked();
559
560 // harmless even if there was an error
561 bytes_available =
562 io_buf.get_buffer_addr_to_write( &write_addr );
563
564 CYG_ASSERT( bytes_available > 0,
565 "Help! still no bytes available in "
566 "write buffer" );
567 } // if
568
569 if (write_err) {
570 unlock_me();
571 return write_err;
572 } // if
573
574 // choose the lower of the buffer available and the length
575 // to write
576 bytes_to_write=(bytes_available < buffer_length)
577 ? bytes_available
578 : buffer_length;
579
580 // if we're line buffered, we may want want to flush if there's
581 // a newline character, so lets find out
582
583 if (flags.line_buffering) {
584 for (newline_pos=0;
585 newline_pos<bytes_to_write;
586 newline_pos++) {
587 if (buffer[newline_pos] == '\n') {
588 break;
589 } // if
590 } // for
591 // if we didn't reach the end
592 if (newline_pos != bytes_to_write) {
593 // shrink bytes_to_write down to the bit we need to
594 // flush including the newline itself
595 bytes_to_write = newline_pos + 1;
596 must_flush = true;
597 } // if
598 } // if
599
600 _memcpy( write_addr, buffer, bytes_to_write );
601
602 *bytes_written += bytes_to_write;
603 buffer += bytes_to_write;
604 buffer_length -= bytes_to_write;
605 io_buf.set_bytes_written( bytes_to_write );
606
607 } // while
608
609 if ( must_flush ) {
610 write_err = flush_output_unlocked();
611 } // if
612 } // else
613 #endif // ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
614
615 unlock_me();
616
617 return write_err;
618 } // write()
619
620
621 #endif // if defined(CYGPKG_LIBC) && defined(CYGPKG_LIBC_STDIO)
622
623 // EOF stream.cxx