Subversion Repositories HelenOS

Rev

Rev 4514 | Rev 4590 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4514 Rev 4541
1
/*
1
/*
2
 * Copyright (c) 2005 Martin Decky
2
 * Copyright (c) 2005 Martin Decky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <unistd.h>
36
#include <unistd.h>
37
#include <fcntl.h>
37
#include <fcntl.h>
-
 
38
#include <assert.h>
38
#include <string.h>
39
#include <string.h>
39
#include <errno.h>
40
#include <errno.h>
40
#include <bool.h>
41
#include <bool.h>
41
#include <malloc.h>
42
#include <malloc.h>
42
#include <io/klog.h>
43
#include <io/klog.h>
43
#include <vfs/vfs.h>
44
#include <vfs/vfs.h>
44
#include <ipc/devmap.h>
45
#include <ipc/devmap.h>
45
#include <adt/list.h>
46
#include <adt/list.h>
46
 
47
 
-
 
48
static void _fflushbuf(FILE *stream);
-
 
49
 
47
static FILE stdin_null = {
50
static FILE stdin_null = {
48
    .fd = -1,
51
    .fd = -1,
49
    .error = true,
52
    .error = true,
50
    .eof = true,
53
    .eof = true,
51
    .klog = false,
54
    .klog = false,
52
    .phone = -1
55
    .phone = -1,
-
 
56
    .btype = _IONBF,
-
 
57
    .buf = NULL,
-
 
58
    .buf_size = 0,
-
 
59
    .buf_head = NULL
53
};
60
};
54
 
61
 
55
static FILE stdout_klog = {
62
static FILE stdout_klog = {
56
    .fd = -1,
63
    .fd = -1,
57
    .error = false,
64
    .error = false,
58
    .eof = false,
65
    .eof = false,
59
    .klog = true,
66
    .klog = true,
60
    .phone = -1
67
    .phone = -1,
-
 
68
    .btype = _IOLBF,
-
 
69
    .buf = NULL,
-
 
70
    .buf_size = BUFSIZ,
-
 
71
    .buf_head = NULL
61
};
72
};
62
 
73
 
63
static FILE stderr_klog = {
74
static FILE stderr_klog = {
64
    .fd = -1,
75
    .fd = -1,
65
    .error = false,
76
    .error = false,
66
    .eof = false,
77
    .eof = false,
67
    .klog = true,
78
    .klog = true,
68
    .phone = -1
79
    .phone = -1,
-
 
80
    .btype = _IONBF,
-
 
81
    .buf = NULL,
-
 
82
    .buf_size = 0,
-
 
83
    .buf_head = NULL
69
};
84
};
70
 
85
 
71
FILE *stdin = NULL;
86
FILE *stdin = NULL;
72
FILE *stdout = NULL;
87
FILE *stdout = NULL;
73
FILE *stderr = NULL;
88
FILE *stderr = NULL;
74
 
89
 
75
static LIST_INITIALIZE(files);
90
static LIST_INITIALIZE(files);
76
 
91
 
77
void stdio_init(int filc, fdi_node_t *filv[])
92
void stdio_init(int filc, fdi_node_t *filv[])
78
{
93
{
79
    if (filc > 0) {
94
    if (filc > 0) {
80
        stdin = fopen_node(filv[0], "r");
95
        stdin = fopen_node(filv[0], "r");
81
    } else {
96
    } else {
82
        stdin = &stdin_null;
97
        stdin = &stdin_null;
83
        list_append(&stdin->link, &files);
98
        list_append(&stdin->link, &files);
84
    }
99
    }
85
   
100
   
86
    if (filc > 1) {
101
    if (filc > 1) {
87
        stdout = fopen_node(filv[1], "w");
102
        stdout = fopen_node(filv[1], "w");
88
    } else {
103
    } else {
89
        stdout = &stdout_klog;
104
        stdout = &stdout_klog;
90
        list_append(&stdout->link, &files);
105
        list_append(&stdout->link, &files);
91
    }
106
    }
92
   
107
   
93
    if (filc > 2) {
108
    if (filc > 2) {
94
        stderr = fopen_node(filv[2], "w");
109
        stderr = fopen_node(filv[2], "w");
95
    } else {
110
    } else {
96
        stderr = &stderr_klog;
111
        stderr = &stderr_klog;
97
        list_append(&stderr->link, &files);
112
        list_append(&stderr->link, &files);
98
    }
113
    }
99
}
114
}
100
 
115
 
101
void stdio_done(void)
116
void stdio_done(void)
102
{
117
{
103
    link_t *link = files.next;
118
    link_t *link = files.next;
104
   
119
   
105
    while (link != &files) {
120
    while (link != &files) {
106
        FILE *file = list_get_instance(link, FILE, link);
121
        FILE *file = list_get_instance(link, FILE, link);
107
        fclose(file);
122
        fclose(file);
108
        link = files.next;
123
        link = files.next;
109
    }
124
    }
110
}
125
}
111
 
126
 
112
static bool parse_mode(const char *mode, int *flags)
127
static bool parse_mode(const char *mode, int *flags)
113
{
128
{
114
    /* Parse mode except first character. */
129
    /* Parse mode except first character. */
115
    const char *mp = mode;
130
    const char *mp = mode;
116
    if (*mp++ == 0) {
131
    if (*mp++ == 0) {
117
        errno = EINVAL;
132
        errno = EINVAL;
118
        return false;
133
        return false;
119
    }
134
    }
120
   
135
   
121
    if ((*mp == 'b') || (*mp == 't'))
136
    if ((*mp == 'b') || (*mp == 't'))
122
        mp++;
137
        mp++;
123
   
138
   
124
    bool plus;
139
    bool plus;
125
    if (*mp == '+') {
140
    if (*mp == '+') {
126
        mp++;
141
        mp++;
127
        plus = true;
142
        plus = true;
128
    } else
143
    } else
129
        plus = false;
144
        plus = false;
130
   
145
   
131
    if (*mp != 0) {
146
    if (*mp != 0) {
132
        errno = EINVAL;
147
        errno = EINVAL;
133
        return false;
148
        return false;
134
    }
149
    }
135
   
150
   
136
    /* Parse first character of mode and determine flags for open(). */
151
    /* Parse first character of mode and determine flags for open(). */
137
    switch (mode[0]) {
152
    switch (mode[0]) {
138
    case 'r':
153
    case 'r':
139
        *flags = plus ? O_RDWR : O_RDONLY;
154
        *flags = plus ? O_RDWR : O_RDONLY;
140
        break;
155
        break;
141
    case 'w':
156
    case 'w':
142
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
157
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
143
        break;
158
        break;
144
    case 'a':
159
    case 'a':
145
        /* TODO: a+ must read from beginning, append to the end. */
160
        /* TODO: a+ must read from beginning, append to the end. */
146
        if (plus) {
161
        if (plus) {
147
            errno = ENOTSUP;
162
            errno = ENOTSUP;
148
            return false;
163
            return false;
149
        }
164
        }
150
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
165
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
151
    default:
166
    default:
152
        errno = EINVAL;
167
        errno = EINVAL;
153
        return false;
168
        return false;
154
    }
169
    }
155
   
170
   
156
    return true;
171
    return true;
157
}
172
}
158
 
173
 
-
 
174
/** Set stream buffer. */
-
 
175
void setvbuf(FILE *stream, void *buf, int mode, size_t size)
-
 
176
{
-
 
177
    stream->btype = mode;
-
 
178
    stream->buf = buf;
-
 
179
    stream->buf_size = size;
-
 
180
    stream->buf_head = stream->buf;
-
 
181
}
-
 
182
 
-
 
183
/** Allocate stream buffer. */
-
 
184
static int _fallocbuf(FILE *stream)
-
 
185
{
-
 
186
    assert(stream->buf == NULL);
-
 
187
 
-
 
188
    stream->buf = malloc(stream->buf_size);
-
 
189
    if (stream->buf == NULL) {
-
 
190
        errno = ENOMEM;
-
 
191
        return -1;
-
 
192
    }
-
 
193
 
-
 
194
    stream->buf_head = stream->buf;
-
 
195
    return 0;
-
 
196
}
-
 
197
 
159
/** Open a stream.
198
/** Open a stream.
160
 *
199
 *
161
 * @param path Path of the file to open.
200
 * @param path Path of the file to open.
162
 * @param mode Mode string, (r|w|a)[b|t][+].
201
 * @param mode Mode string, (r|w|a)[b|t][+].
163
 *
202
 *
164
 */
203
 */
165
FILE *fopen(const char *path, const char *mode)
204
FILE *fopen(const char *path, const char *mode)
166
{
205
{
167
    int flags;
206
    int flags;
168
    if (!parse_mode(mode, &flags))
207
    if (!parse_mode(mode, &flags))
169
        return NULL;
208
        return NULL;
170
   
209
   
171
    /* Open file. */
210
    /* Open file. */
172
    FILE *stream = malloc(sizeof(FILE));
211
    FILE *stream = malloc(sizeof(FILE));
173
    if (stream == NULL) {
212
    if (stream == NULL) {
174
        errno = ENOMEM;
213
        errno = ENOMEM;
175
        return NULL;
214
        return NULL;
176
    }
215
    }
177
   
216
   
178
    stream->fd = open(path, flags, 0666);
217
    stream->fd = open(path, flags, 0666);
179
    if (stream->fd < 0) {
218
    if (stream->fd < 0) {
180
        /* errno was set by open() */
219
        /* errno was set by open() */
181
        free(stream);
220
        free(stream);
182
        return NULL;
221
        return NULL;
183
    }
222
    }
184
   
223
   
185
    stream->error = false;
224
    stream->error = false;
186
    stream->eof = false;
225
    stream->eof = false;
187
    stream->klog = false;
226
    stream->klog = false;
188
    stream->phone = -1;
227
    stream->phone = -1;
-
 
228
 
-
 
229
    /* FIXME: Should select buffering type based on what was opened. */
-
 
230
    setvbuf(stream, NULL, _IOFBF, BUFSIZ);
189
   
231
   
190
    list_append(&stream->link, &files);
232
    list_append(&stream->link, &files);
191
   
233
   
192
    return stream;
234
    return stream;
193
}
235
}
194
 
236
 
195
FILE *fdopen(int fd, const char *mode)
237
FILE *fdopen(int fd, const char *mode)
196
{
238
{
197
    /* Open file. */
239
    /* Open file. */
198
    FILE *stream = malloc(sizeof(FILE));
240
    FILE *stream = malloc(sizeof(FILE));
199
    if (stream == NULL) {
241
    if (stream == NULL) {
200
        errno = ENOMEM;
242
        errno = ENOMEM;
201
        return NULL;
243
        return NULL;
202
    }
244
    }
203
   
245
   
204
    stream->fd = fd;
246
    stream->fd = fd;
205
    stream->error = false;
247
    stream->error = false;
206
    stream->eof = false;
248
    stream->eof = false;
207
    stream->klog = false;
249
    stream->klog = false;
208
    stream->phone = -1;
250
    stream->phone = -1;
-
 
251
 
-
 
252
    /* FIXME: Should select buffering type based on what was opened. */
-
 
253
    setvbuf(stream, NULL, _IOLBF, BUFSIZ);
209
   
254
   
210
    list_append(&stream->link, &files);
255
    list_append(&stream->link, &files);
211
   
256
   
212
    return stream;
257
    return stream;
213
}
258
}
214
 
259
 
215
FILE *fopen_node(fdi_node_t *node, const char *mode)
260
FILE *fopen_node(fdi_node_t *node, const char *mode)
216
{
261
{
217
    int flags;
262
    int flags;
218
    if (!parse_mode(mode, &flags))
263
    if (!parse_mode(mode, &flags))
219
        return NULL;
264
        return NULL;
220
   
265
   
221
    /* Open file. */
266
    /* Open file. */
222
    FILE *stream = malloc(sizeof(FILE));
267
    FILE *stream = malloc(sizeof(FILE));
223
    if (stream == NULL) {
268
    if (stream == NULL) {
224
        errno = ENOMEM;
269
        errno = ENOMEM;
225
        return NULL;
270
        return NULL;
226
    }
271
    }
227
   
272
   
228
    stream->fd = open_node(node, flags);
273
    stream->fd = open_node(node, flags);
229
    if (stream->fd < 0) {
274
    if (stream->fd < 0) {
230
        /* errno was set by open_node() */
275
        /* errno was set by open_node() */
231
        free(stream);
276
        free(stream);
232
        return NULL;
277
        return NULL;
233
    }
278
    }
234
   
279
   
235
    stream->error = false;
280
    stream->error = false;
236
    stream->eof = false;
281
    stream->eof = false;
237
    stream->klog = false;
282
    stream->klog = false;
238
    stream->phone = -1;
283
    stream->phone = -1;
-
 
284
 
-
 
285
    /* FIXME: Should select buffering type based on what was opened. */
-
 
286
    setvbuf(stream, NULL, _IOLBF, BUFSIZ);
239
   
287
   
240
    list_append(&stream->link, &files);
288
    list_append(&stream->link, &files);
241
   
289
   
242
    return stream;
290
    return stream;
243
}
291
}
244
 
292
 
245
int fclose(FILE *stream)
293
int fclose(FILE *stream)
246
{
294
{
247
    int rc = 0;
295
    int rc = 0;
248
   
296
   
249
    fflush(stream);
297
    fflush(stream);
250
   
298
   
251
    if (stream->phone >= 0)
299
    if (stream->phone >= 0)
252
        ipc_hangup(stream->phone);
300
        ipc_hangup(stream->phone);
253
   
301
   
254
    if (stream->fd >= 0)
302
    if (stream->fd >= 0)
255
        rc = close(stream->fd);
303
        rc = close(stream->fd);
256
   
304
   
257
    list_remove(&stream->link);
305
    list_remove(&stream->link);
258
   
306
   
259
    if ((stream != &stdin_null)
307
    if ((stream != &stdin_null)
260
        && (stream != &stdout_klog)
308
        && (stream != &stdout_klog)
261
        && (stream != &stderr_klog))
309
        && (stream != &stderr_klog))
262
        free(stream);
310
        free(stream);
263
   
311
   
264
    stream = NULL;
312
    stream = NULL;
265
   
313
   
266
    if (rc != 0) {
314
    if (rc != 0) {
267
        /* errno was set by close() */
315
        /* errno was set by close() */
268
        return EOF;
316
        return EOF;
269
    }
317
    }
270
   
318
   
271
    return 0;
319
    return 0;
272
}
320
}
273
 
321
 
274
/** Read from a stream.
322
/** Read from a stream.
275
 *
323
 *
276
 * @param buf    Destination buffer.
324
 * @param buf    Destination buffer.
277
 * @param size   Size of each record.
325
 * @param size   Size of each record.
278
 * @param nmemb  Number of records to read.
326
 * @param nmemb  Number of records to read.
279
 * @param stream Pointer to the stream.
327
 * @param stream Pointer to the stream.
280
 *
328
 *
281
 */
329
 */
282
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
330
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
283
{
331
{
284
    size_t left = size * nmemb;
332
    size_t left = size * nmemb;
285
    size_t done = 0;
333
    size_t done = 0;
-
 
334
 
-
 
335
    /* Make sure no data is pending write. */
-
 
336
    _fflushbuf(stream);
286
   
337
 
287
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
338
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
288
        ssize_t rd = read(stream->fd, buf + done, left);
339
        ssize_t rd = read(stream->fd, buf + done, left);
289
       
340
       
290
        if (rd < 0)
341
        if (rd < 0)
291
            stream->error = true;
342
            stream->error = true;
292
        else if (rd == 0)
343
        else if (rd == 0)
293
            stream->eof = true;
344
            stream->eof = true;
294
        else {
345
        else {
295
            left -= rd;
346
            left -= rd;
296
            done += rd;
347
            done += rd;
297
        }
348
        }
298
    }
349
    }
299
   
350
   
300
    return (done / size);
351
    return (done / size);
301
}
352
}
302
 
353
 
303
/** Write to a stream.
-
 
304
 *
-
 
305
 * @param buf    Source buffer.
-
 
306
 * @param size   Size of each record.
-
 
307
 * @param nmemb  Number of records to write.
-
 
308
 * @param stream Pointer to the stream.
-
 
309
 *
-
 
310
 */
-
 
311
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
354
static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
312
{
355
{
313
    size_t left = size * nmemb;
356
    size_t left = size * nmemb;
314
    size_t done = 0;
357
    size_t done = 0;
315
   
358
   
316
    while ((left > 0) && (!stream->error)) {
359
    while ((left > 0) && (!stream->error)) {
317
        ssize_t wr;
360
        ssize_t wr;
318
       
361
       
319
        if (stream->klog)
362
        if (stream->klog)
320
            wr = klog_write(buf + done, left);
363
            wr = klog_write(buf + done, left);
321
        else
364
        else
322
            wr = write(stream->fd, buf + done, left);
365
            wr = write(stream->fd, buf + done, left);
323
       
366
       
324
        if (wr <= 0)
367
        if (wr <= 0)
325
            stream->error = true;
368
            stream->error = true;
326
        else {
369
        else {
327
            left -= wr;
370
            left -= wr;
328
            done += wr;
371
            done += wr;
329
        }
372
        }
330
    }
373
    }
331
   
374
   
332
    return (done / size);
375
    return (done / size);
333
}
376
}
334
 
377
 
-
 
378
/** Drain stream buffer, do not sync stream. */
-
 
379
static void _fflushbuf(FILE *stream)
-
 
380
{
-
 
381
    size_t bytes_used;
-
 
382
 
-
 
383
    if (!stream->buf || stream->btype == _IONBF || stream->error)
-
 
384
        return;
-
 
385
 
-
 
386
    bytes_used = stream->buf_head - stream->buf;
-
 
387
    if (bytes_used == 0)
-
 
388
        return;
-
 
389
 
-
 
390
    (void) _fwrite(stream->buf, 1, bytes_used, stream);
-
 
391
    stream->buf_head = stream->buf;
-
 
392
}
-
 
393
 
-
 
394
/** Write to a stream.
-
 
395
 *
-
 
396
 * @param buf    Source buffer.
-
 
397
 * @param size   Size of each record.
-
 
398
 * @param nmemb  Number of records to write.
-
 
399
 * @param stream Pointer to the stream.
-
 
400
 *
-
 
401
 */
-
 
402
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
-
 
403
{
-
 
404
    uint8_t *data;
-
 
405
    size_t bytes_left;
-
 
406
    size_t now;
-
 
407
    size_t buf_free;
-
 
408
    size_t total_written;
-
 
409
    size_t i;
-
 
410
    uint8_t b;
-
 
411
    bool need_flush;
-
 
412
 
-
 
413
    /* If not buffered stream, write out directly. */
-
 
414
    if (stream->btype == _IONBF)
-
 
415
        return _fwrite(buf, size, nmemb, stream);
-
 
416
 
-
 
417
    /* Perform lazy allocation of stream buffer. */
-
 
418
    if (stream->buf == NULL) {
-
 
419
        if (_fallocbuf(stream) != 0)
-
 
420
            return 0; /* Errno set by _fallocbuf(). */
-
 
421
    }
-
 
422
 
-
 
423
    data = (uint8_t *) buf;
-
 
424
    bytes_left = size * nmemb;
-
 
425
    total_written = 0;
-
 
426
    need_flush = false;
-
 
427
 
-
 
428
    while (!stream->error && bytes_left > 0) {
-
 
429
 
-
 
430
        buf_free = stream->buf_size - (stream->buf_head - stream->buf);
-
 
431
        if (bytes_left > buf_free)
-
 
432
            now = buf_free;
-
 
433
        else
-
 
434
            now = bytes_left;
-
 
435
 
-
 
436
        for (i = 0; i < now; i++) {
-
 
437
            b = data[i];
-
 
438
            stream->buf_head[i] = b;
-
 
439
 
-
 
440
            if (b == '\n' && stream->btype == _IOLBF)
-
 
441
                need_flush = true;
-
 
442
        }
-
 
443
 
-
 
444
        buf += now;
-
 
445
        stream->buf_head += now;
-
 
446
        buf_free -= now;
-
 
447
        bytes_left -= now;
-
 
448
        total_written += now;
-
 
449
 
-
 
450
        if (buf_free == 0) {
-
 
451
            /* Only need to drain buffer. */
-
 
452
            _fflushbuf(stream);
-
 
453
            need_flush = false;
-
 
454
        }
-
 
455
    }
-
 
456
 
-
 
457
    if (need_flush)
-
 
458
        fflush(stream);
-
 
459
 
-
 
460
    return (total_written / size);
-
 
461
}
-
 
462
 
335
int fputc(wchar_t c, FILE *stream)
463
int fputc(wchar_t c, FILE *stream)
336
{
464
{
337
    char buf[STR_BOUNDS(1)];
465
    char buf[STR_BOUNDS(1)];
338
    size_t sz = 0;
466
    size_t sz = 0;
339
   
467
   
340
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
468
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
341
        size_t wr = fwrite(buf, sz, 1, stream);
469
        size_t wr = fwrite(buf, sz, 1, stream);
342
       
470
       
343
        if (wr < sz)
471
        if (wr < sz)
344
            return EOF;
472
            return EOF;
345
       
473
       
346
        return (int) c;
474
        return (int) c;
347
    }
475
    }
348
   
476
   
349
    return EOF;
477
    return EOF;
350
}
478
}
351
 
479
 
352
int putchar(wchar_t c)
480
int putchar(wchar_t c)
353
{
481
{
354
    return fputc(c, stdout);
482
    return fputc(c, stdout);
355
}
483
}
356
 
484
 
357
int fputs(const char *str, FILE *stream)
485
int fputs(const char *str, FILE *stream)
358
{
486
{
359
    return fwrite(str, str_size(str), 1, stream);
487
    return fwrite(str, str_size(str), 1, stream);
360
}
488
}
361
 
489
 
362
int puts(const char *str)
490
int puts(const char *str)
363
{
491
{
364
    return fputs(str, stdout);
492
    return fputs(str, stdout);
365
}
493
}
366
 
494
 
367
int fgetc(FILE *stream)
495
int fgetc(FILE *stream)
368
{
496
{
369
    char c;
497
    char c;
370
 
498
 
371
    /* This could be made faster by only flushing when needed. */
499
    /* This could be made faster by only flushing when needed. */
372
    if (stdout)
500
    if (stdout)
373
        fflush(stdout);
501
        fflush(stdout);
374
    if (stderr)
502
    if (stderr)
375
        fflush(stderr);
503
        fflush(stderr);
376
 
504
 
377
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
505
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
378
        return EOF;
506
        return EOF;
379
   
507
   
380
    return (int) c;
508
    return (int) c;
381
}
509
}
382
 
510
 
383
int getchar(void)
511
int getchar(void)
384
{
512
{
385
    return fgetc(stdin);
513
    return fgetc(stdin);
386
}
514
}
387
 
515
 
388
int fseek(FILE *stream, long offset, int origin)
516
int fseek(FILE *stream, long offset, int origin)
389
{
517
{
390
    off_t rc = lseek(stream->fd, offset, origin);
518
    off_t rc = lseek(stream->fd, offset, origin);
391
    if (rc == (off_t) (-1)) {
519
    if (rc == (off_t) (-1)) {
392
        /* errno has been set by lseek. */
520
        /* errno has been set by lseek. */
393
        return -1;
521
        return -1;
394
    }
522
    }
395
   
523
   
396
    stream->eof = false;
524
    stream->eof = false;
397
   
525
   
398
    return 0;
526
    return 0;
399
}
527
}
400
 
528
 
401
void rewind(FILE *stream)
529
void rewind(FILE *stream)
402
{
530
{
403
    (void) fseek(stream, 0, SEEK_SET);
531
    (void) fseek(stream, 0, SEEK_SET);
404
}
532
}
405
 
533
 
406
int fflush(FILE *stream)
534
int fflush(FILE *stream)
407
{
535
{
-
 
536
    _fflushbuf(stream);
-
 
537
 
408
    if (stream->klog) {
538
    if (stream->klog) {
409
        klog_update();
539
        klog_update();
410
        return EOK;
540
        return EOK;
411
    }
541
    }
412
   
542
   
413
    if (stream->fd >= 0)
543
    if (stream->fd >= 0)
414
        return fsync(stream->fd);
544
        return fsync(stream->fd);
415
   
545
   
416
    return ENOENT;
546
    return ENOENT;
417
}
547
}
418
 
548
 
419
int feof(FILE *stream)
549
int feof(FILE *stream)
420
{
550
{
421
    return stream->eof;
551
    return stream->eof;
422
}
552
}
423
 
553
 
424
int ferror(FILE *stream)
554
int ferror(FILE *stream)
425
{
555
{
426
    return stream->error;
556
    return stream->error;
427
}
557
}
428
 
558
 
429
int fphone(FILE *stream)
559
int fphone(FILE *stream)
430
{
560
{
431
    if (stream->fd >= 0) {
561
    if (stream->fd >= 0) {
432
        if (stream->phone < 0)
562
        if (stream->phone < 0)
433
            stream->phone = fd_phone(stream->fd);
563
            stream->phone = fd_phone(stream->fd);
434
       
564
       
435
        return stream->phone;
565
        return stream->phone;
436
    }
566
    }
437
   
567
   
438
    return -1;
568
    return -1;
439
}
569
}
440
 
570
 
441
int fnode(FILE *stream, fdi_node_t *node)
571
int fnode(FILE *stream, fdi_node_t *node)
442
{
572
{
443
    if (stream->fd >= 0)
573
    if (stream->fd >= 0)
444
        return fd_node(stream->fd, node);
574
        return fd_node(stream->fd, node);
445
   
575
   
446
    return ENOENT;
576
    return ENOENT;
447
}
577
}
448
 
578
 
449
/** @}
579
/** @}
450
 */
580
 */
451
 
581