Subversion Repositories HelenOS

Rev

Rev 4581 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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