source: mainline/uspace/lib/c/generic/io/io.c@ f1380b7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1380b7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 17.8 KB
RevLine 
[b861b58]1/*
[df4ed85]2 * Copyright (c) 2005 Martin Decky
[b861b58]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[b2951e2]27 */
28
[fadd381]29/** @addtogroup libc
[b2951e2]30 * @{
31 */
32/** @file
[2595dab]33 */
[b861b58]34
[cc6f688]35#include <stdio.h>
[ef8bcc6]36#include <assert.h>
[19f857a]37#include <str.h>
[56fa418]38#include <errno.h>
[3e6a98c5]39#include <stdbool.h>
[38d150e]40#include <stdlib.h>
[64d2b10]41#include <async.h>
[6fa9a99d]42#include <io/kio.h>
[2595dab]43#include <vfs/vfs.h>
[79ae36dd]44#include <vfs/vfs_sess.h>
[bb9ec2d]45#include <vfs/inbox.h>
[15f3c3f]46#include <ipc/loc.h>
[d9c8c81]47#include <adt/list.h>
[47b7006]48#include "../private/io.h"
[79ae36dd]49#include "../private/stdio.h"
[b861b58]50
[facebd56]51static void _ffillbuf(FILE *stream);
[ef8bcc6]52static void _fflushbuf(FILE *stream);
53
[a68f737]54static FILE stdin_null = {
[2595dab]55 .fd = -1,
[1b20da0]56 .pos = 0,
[2595dab]57 .error = true,
58 .eof = true,
[6fa9a99d]59 .kio = false,
[79ae36dd]60 .sess = NULL,
[ef8bcc6]61 .btype = _IONBF,
62 .buf = NULL,
63 .buf_size = 0,
[facebd56]64 .buf_head = NULL,
65 .buf_tail = NULL,
[c70703a]66 .buf_state = _bs_empty
[2595dab]67};
[350514c]68
[6fa9a99d]69static FILE stdout_kio = {
[2595dab]70 .fd = -1,
[1b20da0]71 .pos = 0,
[2595dab]72 .error = false,
73 .eof = false,
[6fa9a99d]74 .kio = true,
[79ae36dd]75 .sess = NULL,
[ef8bcc6]76 .btype = _IOLBF,
77 .buf = NULL,
78 .buf_size = BUFSIZ,
[facebd56]79 .buf_head = NULL,
80 .buf_tail = NULL,
81 .buf_state = _bs_empty
[2595dab]82};
83
[6fa9a99d]84static FILE stderr_kio = {
[a68f737]85 .fd = -1,
[1b20da0]86 .pos = 0,
[a68f737]87 .error = false,
88 .eof = false,
[6fa9a99d]89 .kio = true,
[79ae36dd]90 .sess = NULL,
[ef8bcc6]91 .btype = _IONBF,
92 .buf = NULL,
93 .buf_size = 0,
[facebd56]94 .buf_head = NULL,
95 .buf_tail = NULL,
96 .buf_state = _bs_empty
[a68f737]97};
98
99FILE *stdin = NULL;
100FILE *stdout = NULL;
101FILE *stderr = NULL;
102
103static LIST_INITIALIZE(files);
104
[bb9ec2d]105void __stdio_init(void)
[a68f737]106{
[bb9ec2d]107 /* The first three standard file descriptors are assigned for compatibility.
108 * This will probably be removed later.
109 */
110 int infd = inbox_get("stdin");
111 if (infd >= 0) {
[f77c1c9]112 int stdinfd = -1;
113 (void) vfs_clone(infd, -1, false, &stdinfd);
[bb9ec2d]114 assert(stdinfd == 0);
[b19e892]115 vfs_open(stdinfd, MODE_READ);
[bb9ec2d]116 stdin = fdopen(stdinfd, "r");
[a68f737]117 } else {
118 stdin = &stdin_null;
119 list_append(&stdin->link, &files);
120 }
[a35b458]121
[bb9ec2d]122 int outfd = inbox_get("stdout");
123 if (outfd >= 0) {
[f77c1c9]124 int stdoutfd = -1;
125 (void) vfs_clone(outfd, -1, false, &stdoutfd);
[bb9ec2d]126 assert(stdoutfd <= 1);
[fcab7ef]127 while (stdoutfd < 1)
[f77c1c9]128 (void) vfs_clone(outfd, -1, false, &stdoutfd);
[b19e892]129 vfs_open(stdoutfd, MODE_APPEND);
[bb9ec2d]130 stdout = fdopen(stdoutfd, "a");
[a68f737]131 } else {
[6fa9a99d]132 stdout = &stdout_kio;
[a68f737]133 list_append(&stdout->link, &files);
134 }
[a35b458]135
[bb9ec2d]136 int errfd = inbox_get("stderr");
137 if (errfd >= 0) {
[f77c1c9]138 int stderrfd = -1;
139 (void) vfs_clone(errfd, -1, false, &stderrfd);
[bb9ec2d]140 assert(stderrfd <= 2);
[fcab7ef]141 while (stderrfd < 2)
[f77c1c9]142 (void) vfs_clone(errfd, -1, false, &stderrfd);
[b19e892]143 vfs_open(stderrfd, MODE_APPEND);
[bb9ec2d]144 stderr = fdopen(stderrfd, "a");
[a68f737]145 } else {
[6fa9a99d]146 stderr = &stderr_kio;
[a68f737]147 list_append(&stderr->link, &files);
148 }
149}
150
[db24058]151void __stdio_done(void)
[a68f737]152{
[b72efe8]153 while (!list_empty(&files)) {
154 FILE *file = list_get_instance(list_first(&files), FILE, link);
[a68f737]155 fclose(file);
156 }
157}
[2595dab]158
[b19e892]159static bool parse_mode(const char *fmode, int *mode, bool *create, bool *truncate)
[b861b58]160{
[2595dab]161 /* Parse mode except first character. */
[b19e892]162 const char *mp = fmode;
[2595dab]163 if (*mp++ == 0) {
164 errno = EINVAL;
165 return false;
166 }
[a35b458]167
[2595dab]168 if ((*mp == 'b') || (*mp == 't'))
169 mp++;
[a35b458]170
[2595dab]171 bool plus;
172 if (*mp == '+') {
173 mp++;
174 plus = true;
175 } else
176 plus = false;
[a35b458]177
[2595dab]178 if (*mp != 0) {
179 errno = EINVAL;
180 return false;
[350514c]181 }
[b19e892]182
183 *create = false;
184 *truncate = false;
[a35b458]185
[b19e892]186 /* Parse first character of fmode and determine mode for vfs_open(). */
187 switch (fmode[0]) {
[2595dab]188 case 'r':
[b19e892]189 *mode = plus ? MODE_READ | MODE_WRITE : MODE_READ;
[2595dab]190 break;
191 case 'w':
[b19e892]192 *mode = plus ? MODE_READ | MODE_WRITE : MODE_WRITE;
193 *create = true;
194 if (!plus)
195 *truncate = true;
[2595dab]196 break;
197 case 'a':
198 /* TODO: a+ must read from beginning, append to the end. */
199 if (plus) {
200 errno = ENOTSUP;
201 return false;
202 }
[b19e892]203
204 *mode = MODE_APPEND | (plus ? MODE_READ | MODE_WRITE : MODE_WRITE);
205 *create = true;
[82582e4]206 break;
[2595dab]207 default:
208 errno = EINVAL;
209 return false;
210 }
[a35b458]211
[2595dab]212 return true;
[cc6f688]213}
[b861b58]214
[ef8bcc6]215/** Set stream buffer. */
216void setvbuf(FILE *stream, void *buf, int mode, size_t size)
217{
218 stream->btype = mode;
219 stream->buf = buf;
220 stream->buf_size = size;
221 stream->buf_head = stream->buf;
[facebd56]222 stream->buf_tail = stream->buf;
223 stream->buf_state = _bs_empty;
[ef8bcc6]224}
225
[7699c21]226/** Set stream buffer.
227 *
228 * When @p buf is NULL, the stream is set as unbuffered, otherwise
229 * full buffering is enabled.
230 */
231void setbuf(FILE *stream, void *buf)
232{
233 if (buf == NULL) {
234 setvbuf(stream, NULL, _IONBF, BUFSIZ);
235 } else {
236 setvbuf(stream, buf, _IOFBF, BUFSIZ);
237 }
238}
239
[bfd247f]240static void _setvbuf(FILE *stream)
241{
242 /* FIXME: Use more complex rules for setting buffering options. */
[a35b458]243
[bfd247f]244 switch (stream->fd) {
245 case 1:
246 setvbuf(stream, NULL, _IOLBF, BUFSIZ);
247 break;
248 case 0:
249 case 2:
250 setvbuf(stream, NULL, _IONBF, 0);
251 break;
252 default:
253 setvbuf(stream, NULL, _IOFBF, BUFSIZ);
254 }
255}
256
[ef8bcc6]257/** Allocate stream buffer. */
258static int _fallocbuf(FILE *stream)
259{
260 assert(stream->buf == NULL);
[a35b458]261
[ef8bcc6]262 stream->buf = malloc(stream->buf_size);
263 if (stream->buf == NULL) {
264 errno = ENOMEM;
[6afc9d7]265 return EOF;
[ef8bcc6]266 }
[a35b458]267
[ef8bcc6]268 stream->buf_head = stream->buf;
[facebd56]269 stream->buf_tail = stream->buf;
[ef8bcc6]270 return 0;
271}
272
[2595dab]273/** Open a stream.
274 *
275 * @param path Path of the file to open.
276 * @param mode Mode string, (r|w|a)[b|t][+].
277 *
[4e2cf8b]278 */
[b19e892]279FILE *fopen(const char *path, const char *fmode)
[4e2cf8b]280{
[b19e892]281 int mode;
282 bool create;
283 bool truncate;
284
285 if (!parse_mode(fmode, &mode, &create, &truncate))
[2595dab]286 return NULL;
[a35b458]287
[2595dab]288 /* Open file. */
289 FILE *stream = malloc(sizeof(FILE));
290 if (stream == NULL) {
291 errno = ENOMEM;
292 return NULL;
293 }
[b19e892]294
295 int flags = WALK_REGULAR;
296 if (create)
297 flags |= WALK_MAY_CREATE;
[f77c1c9]298 int file;
[b7fd2a0]299 errno_t rc = vfs_lookup(path, flags, &file);
[f77c1c9]300 if (rc != EOK) {
301 errno = rc;
[b19e892]302 free(stream);
303 return NULL;
304 }
305
[f77c1c9]306 rc = vfs_open(file, mode);
[b19e892]307 if (rc != EOK) {
308 errno = rc;
[9c4cf0d]309 vfs_put(file);
[2595dab]310 free(stream);
311 return NULL;
312 }
[a35b458]313
[b19e892]314 if (truncate) {
315 rc = vfs_resize(file, 0);
316 if (rc != EOK) {
317 errno = rc;
[9c4cf0d]318 vfs_put(file);
[b19e892]319 free(stream);
320 return NULL;
321 }
322 }
323
324 stream->fd = file;
[58898d1d]325 stream->pos = 0;
[2595dab]326 stream->error = false;
327 stream->eof = false;
[6fa9a99d]328 stream->kio = false;
[79ae36dd]329 stream->sess = NULL;
[facebd56]330 stream->need_sync = false;
[bfd247f]331 _setvbuf(stream);
[e86a617a]332 stream->ungetc_chars = 0;
[a35b458]333
[a68f737]334 list_append(&stream->link, &files);
[a35b458]335
[2595dab]336 return stream;
337}
338
[080ad7f]339FILE *fdopen(int fd, const char *mode)
340{
341 /* Open file. */
342 FILE *stream = malloc(sizeof(FILE));
343 if (stream == NULL) {
344 errno = ENOMEM;
345 return NULL;
346 }
[a35b458]347
[080ad7f]348 stream->fd = fd;
[58898d1d]349 stream->pos = 0;
[080ad7f]350 stream->error = false;
351 stream->eof = false;
[6fa9a99d]352 stream->kio = false;
[79ae36dd]353 stream->sess = NULL;
[facebd56]354 stream->need_sync = false;
[bfd247f]355 _setvbuf(stream);
[e86a617a]356 stream->ungetc_chars = 0;
[a35b458]357
[080ad7f]358 list_append(&stream->link, &files);
[a35b458]359
[080ad7f]360 return stream;
361}
362
[80bee81]363
364static int _fclose_nofree(FILE *stream)
[2595dab]365{
[b7fd2a0]366 errno_t rc = 0;
[a35b458]367
[2595dab]368 fflush(stream);
[a35b458]369
[79ae36dd]370 if (stream->sess != NULL)
371 async_hangup(stream->sess);
[a35b458]372
[2595dab]373 if (stream->fd >= 0)
[9c4cf0d]374 rc = vfs_put(stream->fd);
[a35b458]375
[a68f737]376 list_remove(&stream->link);
[a35b458]377
[f77c1c9]378 if (rc != EOK) {
379 errno = rc;
[80bee81]380 return EOF;
381 }
[a35b458]382
[80bee81]383 return 0;
384}
385
386int fclose(FILE *stream)
387{
388 int rc = _fclose_nofree(stream);
[a35b458]389
[a68f737]390 if ((stream != &stdin_null)
[6fa9a99d]391 && (stream != &stdout_kio)
392 && (stream != &stderr_kio))
[2595dab]393 free(stream);
[a35b458]394
[80bee81]395 return rc;
396}
397
398FILE *freopen(const char *path, const char *mode, FILE *stream)
399{
400 FILE *nstr;
[a35b458]401
[80bee81]402 if (path == NULL) {
403 /* Changing mode is not supported */
404 return NULL;
[2595dab]405 }
[a35b458]406
[80bee81]407 (void) _fclose_nofree(stream);
408 nstr = fopen(path, mode);
409 if (nstr == NULL) {
410 free(stream);
411 return NULL;
412 }
[a35b458]413
[80bee81]414 list_remove(&nstr->link);
415 *stream = *nstr;
416 list_append(&stream->link, &files);
[a35b458]417
[80bee81]418 free(nstr);
[a35b458]419
[80bee81]420 return stream;
[4e2cf8b]421}
422
[facebd56]423/** Read from a stream (unbuffered).
[2595dab]424 *
425 * @param buf Destination buffer.
426 * @param size Size of each record.
427 * @param nmemb Number of records to read.
428 * @param stream Pointer to the stream.
[6afc9d7]429 *
430 * @return Number of elements successfully read. On error this is less than
431 * nmemb, stream error indicator is set and errno is set.
[4e2cf8b]432 */
[facebd56]433static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
[4e2cf8b]434{
[b7fd2a0]435 errno_t rc;
[8e3498b]436 size_t nread;
437
[002252a]438 if (size == 0 || nmemb == 0)
439 return 0;
440
[8e3498b]441 rc = vfs_read(stream->fd, &stream->pos, buf, size * nmemb, &nread);
442 if (rc != EOK) {
443 errno = rc;
[58898d1d]444 stream->error = true;
[8e3498b]445 } else if (nread == 0) {
[58898d1d]446 stream->eof = true;
[2595dab]447 }
[8e3498b]448
449 return (nread / size);
[2595dab]450}
[55cff86]451
[facebd56]452/** Write to a stream (unbuffered).
453 *
454 * @param buf Source buffer.
455 * @param size Size of each record.
456 * @param nmemb Number of records to write.
457 * @param stream Pointer to the stream.
[6afc9d7]458 *
459 * @return Number of elements successfully written. On error this is less than
460 * nmemb, stream error indicator is set and errno is set.
[facebd56]461 */
[ef8bcc6]462static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
[2595dab]463{
[b7fd2a0]464 errno_t rc;
[8e3498b]465 size_t nwritten;
466
[002252a]467 if (size == 0 || nmemb == 0)
468 return 0;
469
[58898d1d]470 if (stream->kio) {
[8e3498b]471 rc = kio_write(buf, size * nmemb, &nwritten);
472 if (rc != EOK) {
[58898d1d]473 stream->error = true;
[8e3498b]474 nwritten = 0;
[6afc9d7]475 }
[58898d1d]476 } else {
[8e3498b]477 rc = vfs_write(stream->fd, &stream->pos, buf, size * nmemb,
478 &nwritten);
479 if (rc != EOK) {
480 errno = rc;
[2595dab]481 stream->error = true;
482 }
483 }
[facebd56]484
[8e3498b]485 if (nwritten > 0)
[facebd56]486 stream->need_sync = true;
[8e3498b]487
488 return (nwritten / size);
[4e2cf8b]489}
490
[6afc9d7]491/** Read some data in stream buffer.
492 *
493 * On error, stream error indicator is set and errno is set.
494 */
[facebd56]495static void _ffillbuf(FILE *stream)
496{
[b7fd2a0]497 errno_t rc;
[8e3498b]498 size_t nread;
[facebd56]499
500 stream->buf_head = stream->buf_tail = stream->buf;
501
[8e3498b]502 rc = vfs_read(stream->fd, &stream->pos, stream->buf, stream->buf_size,
503 &nread);
504 if (rc != EOK) {
[ce04ea44]505 errno = rc;
[facebd56]506 stream->error = true;
507 return;
508 }
509
[8e3498b]510 if (nread == 0) {
[facebd56]511 stream->eof = true;
512 return;
513 }
514
[8e3498b]515 stream->buf_head += nread;
[facebd56]516 stream->buf_state = _bs_read;
517}
518
519/** Write out stream buffer, do not sync stream. */
[ef8bcc6]520static void _fflushbuf(FILE *stream)
521{
522 size_t bytes_used;
[facebd56]523
[bfd247f]524 if ((!stream->buf) || (stream->btype == _IONBF) || (stream->error))
[ef8bcc6]525 return;
[facebd56]526
527 bytes_used = stream->buf_head - stream->buf_tail;
528
529 /* If buffer has prefetched read data, we need to seek back. */
[58898d1d]530 if (bytes_used > 0 && stream->buf_state == _bs_read)
531 stream->pos -= bytes_used;
[facebd56]532
533 /* If buffer has unwritten data, we need to write them out. */
[6afc9d7]534 if (bytes_used > 0 && stream->buf_state == _bs_write) {
[facebd56]535 (void) _fwrite(stream->buf_tail, 1, bytes_used, stream);
[6afc9d7]536 /* On error stream error indicator and errno are set by _fwrite */
537 if (stream->error)
538 return;
539 }
[facebd56]540
[ef8bcc6]541 stream->buf_head = stream->buf;
[facebd56]542 stream->buf_tail = stream->buf;
543 stream->buf_state = _bs_empty;
[ef8bcc6]544}
545
[facebd56]546/** Read from a stream.
547 *
548 * @param dest Destination buffer.
549 * @param size Size of each record.
550 * @param nmemb Number of records to read.
551 * @param stream Pointer to the stream.
552 *
553 */
554size_t fread(void *dest, size_t size, size_t nmemb, FILE *stream)
555{
556 uint8_t *dp;
557 size_t bytes_left;
558 size_t now;
559 size_t data_avail;
560 size_t total_read;
561 size_t i;
562
563 if (size == 0 || nmemb == 0)
564 return 0;
565
[bd5414e]566 bytes_left = size * nmemb;
567 total_read = 0;
568 dp = (uint8_t *) dest;
569
570 /* Bytes from ungetc() buffer */
571 while (stream->ungetc_chars > 0 && bytes_left > 0) {
572 *dp++ = stream->ungetc_buf[--stream->ungetc_chars];
573 ++total_read;
[a955fcc]574 --bytes_left;
[bd5414e]575 }
576
[facebd56]577 /* If not buffered stream, read in directly. */
578 if (stream->btype == _IONBF) {
[bd5414e]579 total_read += _fread(dest, 1, bytes_left, stream);
580 return total_read / size;
[facebd56]581 }
582
583 /* Make sure no data is pending write. */
584 if (stream->buf_state == _bs_write)
585 _fflushbuf(stream);
586
587 /* Perform lazy allocation of stream buffer. */
588 if (stream->buf == NULL) {
589 if (_fallocbuf(stream) != 0)
590 return 0; /* Errno set by _fallocbuf(). */
591 }
592
593 while ((!stream->error) && (!stream->eof) && (bytes_left > 0)) {
594 if (stream->buf_head == stream->buf_tail)
595 _ffillbuf(stream);
596
[6afc9d7]597 if (stream->error || stream->eof) {
598 /* On error errno was set by _ffillbuf() */
[facebd56]599 break;
[6afc9d7]600 }
[facebd56]601
602 data_avail = stream->buf_head - stream->buf_tail;
603
604 if (bytes_left > data_avail)
605 now = data_avail;
606 else
607 now = bytes_left;
608
609 for (i = 0; i < now; i++) {
610 dp[i] = stream->buf_tail[i];
611 }
612
613 dp += now;
614 stream->buf_tail += now;
615 bytes_left -= now;
616 total_read += now;
617 }
618
619 return (total_read / size);
620}
621
622
[ef8bcc6]623/** Write to a stream.
624 *
625 * @param buf Source buffer.
626 * @param size Size of each record.
627 * @param nmemb Number of records to write.
628 * @param stream Pointer to the stream.
629 *
630 */
631size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
632{
633 uint8_t *data;
634 size_t bytes_left;
635 size_t now;
636 size_t buf_free;
637 size_t total_written;
638 size_t i;
639 uint8_t b;
640 bool need_flush;
[002252a]641
642 if (size == 0 || nmemb == 0)
643 return 0;
644
[ef8bcc6]645 /* If not buffered stream, write out directly. */
[bfd247f]646 if (stream->btype == _IONBF) {
647 now = _fwrite(buf, size, nmemb, stream);
648 fflush(stream);
649 return now;
650 }
[facebd56]651
652 /* Make sure buffer contains no prefetched data. */
653 if (stream->buf_state == _bs_read)
654 _fflushbuf(stream);
655
[ef8bcc6]656 /* Perform lazy allocation of stream buffer. */
657 if (stream->buf == NULL) {
658 if (_fallocbuf(stream) != 0)
659 return 0; /* Errno set by _fallocbuf(). */
660 }
[a35b458]661
[ef8bcc6]662 data = (uint8_t *) buf;
663 bytes_left = size * nmemb;
664 total_written = 0;
665 need_flush = false;
[a35b458]666
[bfd247f]667 while ((!stream->error) && (bytes_left > 0)) {
[ef8bcc6]668 buf_free = stream->buf_size - (stream->buf_head - stream->buf);
669 if (bytes_left > buf_free)
670 now = buf_free;
671 else
672 now = bytes_left;
[a35b458]673
[ef8bcc6]674 for (i = 0; i < now; i++) {
675 b = data[i];
676 stream->buf_head[i] = b;
[a35b458]677
[bfd247f]678 if ((b == '\n') && (stream->btype == _IOLBF))
[ef8bcc6]679 need_flush = true;
680 }
[a35b458]681
[0803134]682 data += now;
[ef8bcc6]683 stream->buf_head += now;
684 buf_free -= now;
685 bytes_left -= now;
686 total_written += now;
[0803134]687 stream->buf_state = _bs_write;
[a35b458]688
[ef8bcc6]689 if (buf_free == 0) {
690 /* Only need to drain buffer. */
691 _fflushbuf(stream);
[6afc9d7]692 if (!stream->error)
693 need_flush = false;
[ef8bcc6]694 }
695 }
[facebd56]696
[ef8bcc6]697 if (need_flush)
698 fflush(stream);
[a35b458]699
[ef8bcc6]700 return (total_written / size);
701}
702
[2595dab]703int fputc(wchar_t c, FILE *stream)
[c9857c6]704{
[56fa418]705 char buf[STR_BOUNDS(1)];
[2595dab]706 size_t sz = 0;
[a35b458]707
[2595dab]708 if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
[2a5af223]709 size_t wr = fwrite(buf, 1, sz, stream);
[a35b458]710
[2595dab]711 if (wr < sz)
712 return EOF;
[a35b458]713
[2595dab]714 return (int) c;
715 }
[a35b458]716
[2595dab]717 return EOF;
718}
[56fa418]719
[2595dab]720int putchar(wchar_t c)
721{
722 return fputc(c, stdout);
723}
[56fa418]724
[2595dab]725int fputs(const char *str, FILE *stream)
726{
[7db5cfd]727 (void) fwrite(str, str_size(str), 1, stream);
728 if (ferror(stream))
729 return EOF;
730 return 0;
[2595dab]731}
[56fa418]732
[2595dab]733int puts(const char *str)
734{
735 return fputs(str, stdout);
[c9857c6]736}
[b27a97bb]737
[2595dab]738int fgetc(FILE *stream)
[b27a97bb]739{
[2595dab]740 char c;
[a35b458]741
[bac82eeb]742 /* This could be made faster by only flushing when needed. */
[b8e57e8c]743 if (stdout)
744 fflush(stdout);
745 if (stderr)
746 fflush(stderr);
[a35b458]747
[2595dab]748 if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
749 return EOF;
[a35b458]750
[2595dab]751 return (int) c;
752}
753
[c62d2e1]754char *fgets(char *str, int size, FILE *stream)
755{
[a634485]756 int c;
[c62d2e1]757 int idx;
758
759 idx = 0;
760 while (idx < size - 1) {
761 c = fgetc(stream);
762 if (c == EOF)
763 break;
764
765 str[idx++] = c;
766
767 if (c == '\n')
768 break;
769 }
770
771 if (ferror(stream))
772 return NULL;
773
774 if (idx == 0)
775 return NULL;
776
777 str[idx] = '\0';
778 return str;
779}
780
[2595dab]781int getchar(void)
782{
783 return fgetc(stdin);
[b27a97bb]784}
785
[bd5414e]786int ungetc(int c, FILE *stream)
787{
788 if (c == EOF)
789 return EOF;
790
791 if (stream->ungetc_chars >= UNGETC_MAX)
792 return EOF;
793
794 stream->ungetc_buf[stream->ungetc_chars++] =
795 (uint8_t)c;
796
797 stream->eof = false;
798 return (uint8_t)c;
799}
800
[1c7f381]801int fseek64(FILE *stream, off64_t offset, int whence)
[d2cc7e1]802{
[b7fd2a0]803 errno_t rc;
[23a0368]804
[6afc9d7]805 if (stream->error)
[58898d1d]806 return -1;
[6afc9d7]807
[facebd56]808 _fflushbuf(stream);
[6afc9d7]809 if (stream->error) {
810 /* errno was set by _fflushbuf() */
[58898d1d]811 return -1;
[6afc9d7]812 }
813
[bd5414e]814 stream->ungetc_chars = 0;
[facebd56]815
[39330200]816 vfs_stat_t st;
[58898d1d]817 switch (whence) {
818 case SEEK_SET:
819 stream->pos = offset;
820 break;
821 case SEEK_CUR:
822 stream->pos += offset;
823 break;
824 case SEEK_END:
[23a0368]825 rc = vfs_stat(stream->fd, &st);
826 if (rc != EOK) {
827 errno = rc;
[58898d1d]828 stream->error = true;
[1b20da0]829 return -1;
[58898d1d]830 }
831 stream->pos = st.size + offset;
832 break;
[2595dab]833 }
[facebd56]834
[2595dab]835 stream->eof = false;
[566f4cfb]836 return 0;
[d2cc7e1]837}
838
[1c7f381]839off64_t ftell64(FILE *stream)
[08232ee]840{
[6afc9d7]841 if (stream->error)
842 return EOF;
[a35b458]843
[8ad496d]844 _fflushbuf(stream);
[6afc9d7]845 if (stream->error) {
846 /* errno was set by _fflushbuf() */
847 return EOF;
848 }
849
[58898d1d]850 return stream->pos - stream->ungetc_chars;
[08232ee]851}
852
[1c7f381]853int fseek(FILE *stream, long offset, int whence)
854{
855 return fseek64(stream, offset, whence);
856}
857
858long ftell(FILE *stream)
859{
860 off64_t off = ftell64(stream);
861
862 /* The native position is too large for the C99-ish interface. */
863 if (off > LONG_MAX)
864 return EOF;
865
866 return off;
867}
868
[080ad7f]869void rewind(FILE *stream)
870{
871 (void) fseek(stream, 0, SEEK_SET);
872}
873
[2595dab]874int fflush(FILE *stream)
875{
[6afc9d7]876 if (stream->error)
877 return EOF;
[a35b458]878
[ef8bcc6]879 _fflushbuf(stream);
[6afc9d7]880 if (stream->error) {
881 /* errno was set by _fflushbuf() */
882 return EOF;
883 }
[a35b458]884
[6fa9a99d]885 if (stream->kio) {
886 kio_update();
[6afc9d7]887 return 0;
[2595dab]888 }
[a35b458]889
[79ae36dd]890 if ((stream->fd >= 0) && (stream->need_sync)) {
[b7fd2a0]891 errno_t rc;
[a56cef9]892
[facebd56]893 /**
894 * Better than syncing always, but probably still not the
895 * right thing to do.
896 */
897 stream->need_sync = false;
[a56cef9]898 rc = vfs_sync(stream->fd);
899 if (rc != EOK) {
900 errno = rc;
[6afc9d7]901 return EOF;
902 }
903
904 return 0;
[facebd56]905 }
[a35b458]906
[6afc9d7]907 return 0;
[2595dab]908}
909
910int feof(FILE *stream)
911{
912 return stream->eof;
913}
914
915int ferror(FILE *stream)
916{
917 return stream->error;
918}
919
[c77a64f]920void clearerr(FILE *stream)
921{
922 stream->eof = false;
923 stream->error = false;
924}
925
[3629481]926int fileno(FILE *stream)
927{
[6fa9a99d]928 if (stream->kio) {
[3629481]929 errno = EBADF;
[6afc9d7]930 return EOF;
[3629481]931 }
[a35b458]932
[3629481]933 return stream->fd;
934}
935
[6afc9d7]936async_sess_t *vfs_fsession(FILE *stream, iface_t iface)
[2595dab]937{
938 if (stream->fd >= 0) {
[79ae36dd]939 if (stream->sess == NULL)
[6afc9d7]940 stream->sess = vfs_fd_session(stream->fd, iface);
[a35b458]941
[79ae36dd]942 return stream->sess;
[2595dab]943 }
[a35b458]944
[79ae36dd]945 return NULL;
[2595dab]946}
947
[b7fd2a0]948errno_t vfs_fhandle(FILE *stream, int *handle)
[2595dab]949{
[7171760]950 if (stream->fd >= 0) {
951 *handle = stream->fd;
952 return EOK;
953 }
[a35b458]954
[a68f737]955 return ENOENT;
[2595dab]956}
957
[fadd381]958/** @}
[b2951e2]959 */
Note: See TracBrowser for help on using the repository browser.