]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/stdio/v2_0/include/stream.inl
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / language / c / libc / stdio / v2_0 / include / stream.inl
1 #ifndef CYGONCE_LIBC_STDIO_STREAM_INL
2 #define CYGONCE_LIBC_STDIO_STREAM_INL
3 //========================================================================
4 //
5 //      stream.inl
6 //
7 //      Inline functions for internal C library stdio stream interface
8 //
9 //========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 //
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //========================================================================
43 //#####DESCRIPTIONBEGIN####
44 //
45 // Author(s):     jlarmour
46 // Contributors:  
47 // Date:          2000-04-19
48 // Purpose:     
49 // Description: 
50 // Usage:         Do not include this file -
51 //                #include <cyg/libc/stdio/stream.hxx> instead.
52 //
53 //####DESCRIPTIONEND####
54 //
55 //========================================================================
56
57 // CONFIGURATION
58
59 #include <pkgconf/libc_stdio.h>    // Configuration header
60
61 // INCLUDES
62
63 #include <cyg/infra/cyg_type.h>    // Common project-wide type definitions
64 #include <stddef.h>                // NULL and size_t from compiler
65 #include <errno.h>                 // Error codes
66 #include <cyg/libc/stdio/stream.hxx> // Just be sure that this really is
67                                    // included
68
69 #include <cyg/libc/stdio/io.inl>     // I/O system inlines
70
71 // FUNCTIONS
72
73 #ifdef CYGDBG_USE_ASSERTS
74 inline cyg_bool
75 Cyg_StdioStream::check_this( cyg_assert_class_zeal zeal ) const
76 {
77     // check that it has the magic word set meaning it is valid.
78     if ( magic_validity_word != 0x7b4321ce )
79         return false;
80     return true;
81 } // check_this()
82
83 #endif // ifdef CYGDBG_USE_ASSERTS
84
85
86
87 // LOCKING FUNCTIONS
88
89 // returns true on success
90 inline cyg_bool
91 Cyg_StdioStream::lock_me( void )
92 {
93     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
94     
95 #ifdef CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS
96     return stream_lock.lock();
97 #else
98     // otherwise it "worked"
99     return true;
100 #endif
101     
102 } // lock_me()
103
104
105 // returns true on success
106 inline cyg_bool
107 Cyg_StdioStream::trylock_me( void )
108 {
109     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
110     
111 #ifdef CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS
112     return stream_lock.trylock();
113 #else
114     // otherwise it "worked"
115     return true;
116 #endif
117     
118 } // lock_me()
119
120
121 inline void
122 Cyg_StdioStream::unlock_me( void )
123 {
124     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
125     
126 #ifdef CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS
127     stream_lock.unlock();
128 #endif
129 } // unlock_me()
130
131
132 // DESTRUCTOR
133
134 inline Cyg_ErrNo
135 Cyg_StdioStream::close()
136 {
137     Cyg_ErrNo err = ENOERR;
138     
139     if (!lock_me())
140         return EBADF;
141
142     if( my_device != CYG_STDIO_HANDLE_NULL )
143     {
144         flush_output_unlocked();
145
146         err = cyg_stdio_close( my_device );
147     
148         if( err == ENOERR )
149             my_device = CYG_STDIO_HANDLE_NULL;
150     }
151     
152     unlock_me();
153     
154     return err;
155 } // close()
156
157 inline
158 Cyg_StdioStream::~Cyg_StdioStream()
159 {
160     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
161
162     // Close the device if it has not already been closed.
163     if( my_device != CYG_STDIO_HANDLE_NULL )
164         close();
165     
166 #ifdef CYGDBG_USE_ASSERTS
167     magic_validity_word = 0xbadbad;
168 #endif
169 } // Cyg_StdioStream destructor
170
171
172 // MEMBER FUNCTIONS
173
174
175 // this is currently just a wrapper around write, but having this interface
176 // leaves scope for optimisations in future
177 inline Cyg_ErrNo
178 Cyg_StdioStream::write_byte( cyg_uint8 c )
179 {
180     cyg_ucount32 dummy_bytes_written;
181     Cyg_ErrNo err;
182
183     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
184     
185     err = write( &c, 1, &dummy_bytes_written );
186
187     CYG_ASSERT( (err!=ENOERR) || (dummy_bytes_written==1),
188                 "Single byte not written, but no error returned!" );
189
190     return err;
191 } // write_byte()
192
193
194 inline Cyg_ErrNo
195 Cyg_StdioStream::unread_byte( cyg_uint8 c )
196 {
197     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
198     
199 #ifdef CYGFUN_LIBC_STDIO_ungetc
200     if (!lock_me())
201         return EBADF;  // assume file is now invalid
202
203     if (flags.unread_char_buf_in_use) {
204         unlock_me();
205         return ENOMEM;
206     } // if
207
208     flags.unread_char_buf_in_use = true;
209     unread_char_buf = c;
210
211     // can't be at EOF any more
212     flags.at_eof = false;
213
214     if (position)    // position is always 0 for certain devices
215         --position;
216     
217     unlock_me();
218
219     return ENOERR;
220
221 #else // ifdef CYGFUN_LIBC_STDIO_ungetc
222
223     return ENOSYS;
224 #endif // ifdef CYGFUN_LIBC_STDIO_ungetc
225 } // unread_byte()
226
227
228 inline cyg_ucount32
229 Cyg_StdioStream::bytes_available_to_read( void )
230 {
231     cyg_ucount32 bytes=0;
232
233     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
234     
235 #ifdef CYGFUN_LIBC_STDIO_ungetc
236     if (flags.unread_char_buf_in_use)
237         ++bytes;
238 #endif 
239
240 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
241
242     // either the last operation was a read, which attempted to read bytes
243     // into the buffer, or there are no bytes in the buffer
244
245     if (flags.buffering) {
246         if (flags.last_buffer_op_was_read == true)
247             bytes += io_buf.get_buffer_space_used();
248     }
249     else
250
251 #endif
252
253     if (flags.readbuf_char_in_use)
254         ++bytes;
255
256     return bytes;
257 } // bytes_available_to_read()
258
259
260
261 inline Cyg_ErrNo
262 Cyg_StdioStream::flush_output( void )
263 {
264     Cyg_ErrNo err;
265
266     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
267     
268     if (!lock_me())
269         return EBADF;  // assume file is now invalid
270     
271     err = flush_output_unlocked();
272
273     unlock_me();
274   
275     return err;
276 } // flush_output()
277
278
279 // get error status for this file
280 inline Cyg_ErrNo
281 Cyg_StdioStream::get_error( void )
282 {
283     Cyg_ErrNo err_temp;
284     
285     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
286     
287     if (!lock_me())
288         return EBADF;     // well, we've certainly got an error now!
289     
290     err_temp = error;
291
292     unlock_me();
293
294     return err_temp;
295 } // get_error()
296
297
298 // set error status for this file
299 inline void
300 Cyg_StdioStream::set_error( Cyg_ErrNo errno_to_set )
301 {
302     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
303     
304     if (!lock_me())
305     {
306         errno = EBADF; // best we can do - we can't trust error to be there
307         return;
308     } // if
309     
310     errno = error = errno_to_set;
311
312     if ( EEOF == error )
313         flags.at_eof = 1;
314
315     unlock_me();
316 } // set_error()
317
318
319 // are we at EOF? true means we are, false means no
320 inline cyg_bool
321 Cyg_StdioStream::get_eof_state( void )
322 {
323     cyg_bool eof_temp;
324
325     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
326     
327     if (!lock_me())
328         return false;     // not much we can do here
329     
330     eof_temp = flags.at_eof;
331
332     unlock_me();
333     
334     return eof_temp;
335 } // get_eof_state()
336
337
338 // Set whether we are at EOF.
339 inline void
340 Cyg_StdioStream::set_eof_state( cyg_bool eof_to_set )
341 {
342     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
343     
344     if (!lock_me())
345         return;     // not much we can do here
346     
347     flags.at_eof = eof_to_set;
348
349     unlock_me();
350 } // set_eof_state()
351
352
353 // retrieve position
354 inline Cyg_ErrNo
355 Cyg_StdioStream::get_position( fpos_t *pos )
356 {
357     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
358     
359     if (!lock_me())
360         return EBADF; // assume file is now invalid
361
362     *pos = position;
363
364     unlock_me();
365
366     return ENOERR;
367
368 } // get_position()
369
370
371 // set absolute position
372 inline Cyg_ErrNo
373 Cyg_StdioStream::set_position( fpos_t pos, int whence )
374 {
375     CYG_ASSERTCLASS( this, "Stream object is not a valid stream!" );
376     
377 #ifndef CYGPKG_LIBC_STDIO_FILEIO    
378     // this is currently a workaround until we have real files
379     // this will be corrected when we decide the true filesystem interface
380
381     Cyg_ErrNo err;
382     cyg_uint8 c;
383
384     if ((whence != SEEK_CUR) || pos < 0)
385         return ENOSYS;
386
387     if (!lock_me())
388         return EBADF; // assume file is now invalid
389
390     // Drain read buffer
391     
392     for ( ; pos > 0 ; pos-- ) {
393         err = read_byte( &c );
394         if (err == EAGAIN)
395             err=refill_read_buffer();
396
397         // if read_byte retured error, or refill_read_buffer returned error
398         if (err) {
399             unlock_me();
400             return err;
401         } // if
402     } // for
403
404     unlock_me();
405
406     return ENOERR;
407     
408 #else
409
410     if (!lock_me())
411         return EBADF; // assume file is now invalid
412
413     if ( whence != SEEK_END ) {
414         off_t bytesavail = (off_t)bytes_available_to_read();
415         off_t abspos = (whence == SEEK_CUR) ? position + pos : pos;
416         off_t posdiff = abspos - position;
417
418         if ( posdiff >= 0 && bytesavail > posdiff ) {
419             // can just "seek" within the existing buffer
420 #ifdef CYGFUN_LIBC_STDIO_ungetc
421             if (posdiff>0 && flags.unread_char_buf_in_use) {
422                 flags.unread_char_buf_in_use = false;
423                 posdiff--;
424             }
425 #endif
426 #ifdef CYGSEM_LIBC_STDIO_WANT_BUFFERED_IO
427             if (posdiff>0 && flags.buffering) {
428                 io_buf.set_bytes_read(posdiff);
429                 posdiff=0;
430             } else 
431 #endif
432             if (posdiff>0 && flags.readbuf_char_in_use) {
433                 flags.readbuf_char_in_use = false;
434                 posdiff--;
435             }
436             CYG_ASSERT(posdiff==0, "Failed to seek within buffer correctly");
437
438             position = abspos;
439             unlock_me();
440             return ENOERR;
441         } // endif (bytesavail > posdiff)
442
443         if (whence == SEEK_CUR) {
444             position += bytesavail;
445             pos -= bytesavail;
446         }
447     } //endif (whence != SEEK_END)
448
449     Cyg_ErrNo err;
450
451     // Flush output if any present.
452     err = flush_output_unlocked();
453
454     if( err == ENOERR )
455     {
456         off_t newpos=pos;
457  
458         // Clear any input out of input buffer and any ungot chars
459         // from unread buffer.
460         io_buf.drain_buffer();
461     
462 #ifdef CYGFUN_LIBC_STDIO_ungetc
463         flags.unread_char_buf_in_use = false;
464 #endif
465
466         // Clear EOF indicator.
467         flags.at_eof = false;
468
469         // Seek the file to the correct place
470         err = cyg_stdio_lseek( my_device, &newpos, whence );
471        
472         if ( err == ENOERR) {
473           // update stream pos
474           position = newpos;
475         }
476     }
477     
478     unlock_me();
479
480     return err;
481 #endif    
482     
483 } // set_position()
484
485
486 #endif // CYGONCE_LIBC_STDIO_STREAM_INL multiple inclusion protection
487
488 // EOF stream.inl