Subversion Repositories HelenOS

Rev

Rev 4537 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4537 Rev 4668
Line 33... Line 33...
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;
Line 96... Line 111...
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);
Line 154... Line 169...
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
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
 
-
 
200
/** Allocate stream buffer. */
-
 
201
static int _fallocbuf(FILE *stream)
-
 
202
{
-
 
203
    assert(stream->buf == NULL);
-
 
204
   
-
 
205
    stream->buf = malloc(stream->buf_size);
-
 
206
    if (stream->buf == NULL) {
-
 
207
        errno = ENOMEM;
-
 
208
        return -1;
-
 
209
    }
-
 
210
   
-
 
211
    stream->buf_head = stream->buf;
-
 
212
    return 0;
-
 
213
}
-
 
214
 
159
/** Open a stream.
215
/** Open a stream.
160
 *
216
 *
161
 * @param path Path of the file to open.
217
 * @param path Path of the file to open.
162
 * @param mode Mode string, (r|w|a)[b|t][+].
218
 * @param mode Mode string, (r|w|a)[b|t][+].
163
 *
219
 *
Line 184... Line 240...
184
   
240
   
185
    stream->error = false;
241
    stream->error = false;
186
    stream->eof = false;
242
    stream->eof = false;
187
    stream->klog = false;
243
    stream->klog = false;
188
    stream->phone = -1;
244
    stream->phone = -1;
-
 
245
    _setvbuf(stream);
189
   
246
   
190
    list_append(&stream->link, &files);
247
    list_append(&stream->link, &files);
191
   
248
   
192
    return stream;
249
    return stream;
193
}
250
}
Line 204... Line 261...
204
    stream->fd = fd;
261
    stream->fd = fd;
205
    stream->error = false;
262
    stream->error = false;
206
    stream->eof = false;
263
    stream->eof = false;
207
    stream->klog = false;
264
    stream->klog = false;
208
    stream->phone = -1;
265
    stream->phone = -1;
-
 
266
    _setvbuf(stream);
209
   
267
   
210
    list_append(&stream->link, &files);
268
    list_append(&stream->link, &files);
211
   
269
   
212
    return stream;
270
    return stream;
213
}
271
}
Line 234... Line 292...
234
   
292
   
235
    stream->error = false;
293
    stream->error = false;
236
    stream->eof = false;
294
    stream->eof = false;
237
    stream->klog = false;
295
    stream->klog = false;
238
    stream->phone = -1;
296
    stream->phone = -1;
-
 
297
    _setvbuf(stream);
239
   
298
   
240
    list_append(&stream->link, &files);
299
    list_append(&stream->link, &files);
241
   
300
   
242
    return stream;
301
    return stream;
243
}
302
}
Line 282... Line 341...
282
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)
283
{
342
{
284
    size_t left = size * nmemb;
343
    size_t left = size * nmemb;
285
    size_t done = 0;
344
    size_t done = 0;
286
   
345
   
-
 
346
    /* Make sure no data is pending write. */
-
 
347
    _fflushbuf(stream);
-
 
348
   
287
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
349
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
288
        ssize_t rd = read(stream->fd, buf + done, left);
350
        ssize_t rd = read(stream->fd, buf + done, left);
289
       
351
       
290
        if (rd < 0)
352
        if (rd < 0)
291
            stream->error = true;
353
            stream->error = true;
Line 298... Line 360...
298
    }
360
    }
299
   
361
   
300
    return (done / size);
362
    return (done / size);
301
}
363
}
302
 
364
 
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)
365
static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
312
{
366
{
313
    size_t left = size * nmemb;
367
    size_t left = size * nmemb;
314
    size_t done = 0;
368
    size_t done = 0;
315
   
369
   
316
    while ((left > 0) && (!stream->error)) {
370
    while ((left > 0) && (!stream->error)) {
Line 330... Line 384...
330
    }
384
    }
331
   
385
   
332
    return (done / size);
386
    return (done / size);
333
}
387
}
334
 
388
 
-
 
389
/** Drain stream buffer, do not sync stream. */
-
 
390
static void _fflushbuf(FILE *stream)
-
 
391
{
-
 
392
    size_t bytes_used;
-
 
393
   
-
 
394
    if ((!stream->buf) || (stream->btype == _IONBF) || (stream->error))
-
 
395
        return;
-
 
396
   
-
 
397
    bytes_used = stream->buf_head - stream->buf;
-
 
398
    if (bytes_used == 0)
-
 
399
        return;
-
 
400
   
-
 
401
    (void) _fwrite(stream->buf, 1, bytes_used, stream);
-
 
402
    stream->buf_head = stream->buf;
-
 
403
}
-
 
404
 
-
 
405
/** Write to a stream.
-
 
406
 *
-
 
407
 * @param buf    Source buffer.
-
 
408
 * @param size   Size of each record.
-
 
409
 * @param nmemb  Number of records to write.
-
 
410
 * @param stream Pointer to the stream.
-
 
411
 *
-
 
412
 */
-
 
413
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
-
 
414
{
-
 
415
    uint8_t *data;
-
 
416
    size_t bytes_left;
-
 
417
    size_t now;
-
 
418
    size_t buf_free;
-
 
419
    size_t total_written;
-
 
420
    size_t i;
-
 
421
    uint8_t b;
-
 
422
    bool need_flush;
-
 
423
   
-
 
424
    /* If not buffered stream, write out directly. */
-
 
425
    if (stream->btype == _IONBF) {
-
 
426
        now = _fwrite(buf, size, nmemb, stream);
-
 
427
        fflush(stream);
-
 
428
        return now;
-
 
429
    }
-
 
430
   
-
 
431
    /* Perform lazy allocation of stream buffer. */
-
 
432
    if (stream->buf == NULL) {
-
 
433
        if (_fallocbuf(stream) != 0)
-
 
434
            return 0; /* Errno set by _fallocbuf(). */
-
 
435
    }
-
 
436
   
-
 
437
    data = (uint8_t *) buf;
-
 
438
    bytes_left = size * nmemb;
-
 
439
    total_written = 0;
-
 
440
    need_flush = false;
-
 
441
   
-
 
442
    while ((!stream->error) && (bytes_left > 0)) {
-
 
443
        buf_free = stream->buf_size - (stream->buf_head - stream->buf);
-
 
444
        if (bytes_left > buf_free)
-
 
445
            now = buf_free;
-
 
446
        else
-
 
447
            now = bytes_left;
-
 
448
       
-
 
449
        for (i = 0; i < now; i++) {
-
 
450
            b = data[i];
-
 
451
            stream->buf_head[i] = b;
-
 
452
           
-
 
453
            if ((b == '\n') && (stream->btype == _IOLBF))
-
 
454
                need_flush = true;
-
 
455
        }
-
 
456
       
-
 
457
        buf += now;
-
 
458
        stream->buf_head += now;
-
 
459
        buf_free -= now;
-
 
460
        bytes_left -= now;
-
 
461
        total_written += now;
-
 
462
       
-
 
463
        if (buf_free == 0) {
-
 
464
            /* Only need to drain buffer. */
-
 
465
            _fflushbuf(stream);
-
 
466
            need_flush = false;
-
 
467
        }
-
 
468
    }
-
 
469
   
-
 
470
    if (need_flush)
-
 
471
        fflush(stream);
-
 
472
   
-
 
473
    return (total_written / size);
-
 
474
}
-
 
475
 
335
int fputc(wchar_t c, FILE *stream)
476
int fputc(wchar_t c, FILE *stream)
336
{
477
{
337
    char buf[STR_BOUNDS(1)];
478
    char buf[STR_BOUNDS(1)];
338
    size_t sz = 0;
479
    size_t sz = 0;
339
   
480
   
Line 365... Line 506...
365
}
506
}
366
 
507
 
367
int fgetc(FILE *stream)
508
int fgetc(FILE *stream)
368
{
509
{
369
    char c;
510
    char c;
370
 
511
   
371
    /* This could be made faster by only flushing when needed. */
512
    /* This could be made faster by only flushing when needed. */
372
    if (stdout)
513
    if (stdout)
373
        fflush(stdout);
514
        fflush(stdout);
374
    if (stderr)
515
    if (stderr)
375
        fflush(stderr);
516
        fflush(stderr);
376
 
517
   
377
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
518
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
378
        return EOF;
519
        return EOF;
379
   
520
   
380
    return (int) c;
521
    return (int) c;
381
}
522
}
Line 403... Line 544...
403
    (void) fseek(stream, 0, SEEK_SET);
544
    (void) fseek(stream, 0, SEEK_SET);
404
}
545
}
405
 
546
 
406
int fflush(FILE *stream)
547
int fflush(FILE *stream)
407
{
548
{
-
 
549
    _fflushbuf(stream);
-
 
550
   
408
    if (stream->klog) {
551
    if (stream->klog) {
409
        klog_update();
552
        klog_update();
410
        return EOK;
553
        return EOK;
411
    }
554
    }
412
   
555