|
0
|
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 |