Subversion Repositories HelenOS

Rev

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

Rev 4420 Rev 4537
Line 28... Line 28...
28
 
28
 
29
/** @addtogroup libc
29
/** @addtogroup libc
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <libc.h>
-
 
36
#include <unistd.h>
-
 
37
#include <stdio.h>
35
#include <stdio.h>
-
 
36
#include <unistd.h>
38
#include <io/io.h>
37
#include <fcntl.h>
39
#include <string.h>
38
#include <string.h>
40
#include <errno.h>
39
#include <errno.h>
41
#include <console.h>
40
#include <bool.h>
-
 
41
#include <malloc.h>
-
 
42
#include <io/klog.h>
-
 
43
#include <vfs/vfs.h>
-
 
44
#include <ipc/devmap.h>
-
 
45
#include <adt/list.h>
-
 
46
 
-
 
47
static FILE stdin_null = {
-
 
48
    .fd = -1,
-
 
49
    .error = true,
-
 
50
    .eof = true,
-
 
51
    .klog = false,
-
 
52
    .phone = -1
-
 
53
};
-
 
54
 
-
 
55
static FILE stdout_klog = {
-
 
56
    .fd = -1,
-
 
57
    .error = false,
-
 
58
    .eof = false,
-
 
59
    .klog = true,
-
 
60
    .phone = -1
-
 
61
};
-
 
62
 
-
 
63
static FILE stderr_klog = {
-
 
64
    .fd = -1,
-
 
65
    .error = false,
-
 
66
    .eof = false,
-
 
67
    .klog = true,
-
 
68
    .phone = -1
-
 
69
};
-
 
70
 
-
 
71
FILE *stdin = NULL;
-
 
72
FILE *stdout = NULL;
-
 
73
FILE *stderr = NULL;
42
 
74
 
43
const static char nl = '\n';
75
static LIST_INITIALIZE(files);
44
 
76
 
45
int puts(const char *str)
77
void stdio_init(int filc, fdi_node_t *filv[])
46
{
78
{
-
 
79
    if (filc > 0) {
-
 
80
        stdin = fopen_node(filv[0], "r");
-
 
81
    } else {
47
    size_t count;
82
        stdin = &stdin_null;
-
 
83
        list_append(&stdin->link, &files);
-
 
84
    }
48
   
85
   
49
    if (str == NULL)
86
    if (filc > 1) {
50
        return putnchars("(NULL)", 6);
87
        stdout = fopen_node(filv[1], "w");
-
 
88
    } else {
-
 
89
        stdout = &stdout_klog;
-
 
90
        list_append(&stdout->link, &files);
-
 
91
    }
51
   
92
   
-
 
93
    if (filc > 2) {
52
    for (count = 0; str[count] != 0; count++);
94
        stderr = fopen_node(filv[2], "w");
-
 
95
    } else {
-
 
96
        stderr = &stderr_klog;
-
 
97
        list_append(&stderr->link, &files);
-
 
98
    }
-
 
99
}
-
 
100
 
-
 
101
void stdio_done(void)
-
 
102
{
-
 
103
    link_t *link = files.next;
53
   
104
   
-
 
105
    while (link != &files) {
-
 
106
        FILE *file = list_get_instance(link, FILE, link);
-
 
107
        fclose(file);
-
 
108
        link = files.next;
-
 
109
    }
-
 
110
}
-
 
111
 
54
    if (console_write((void *) str, count) == count) {
112
static bool parse_mode(const char *mode, int *flags)
-
 
113
{
-
 
114
    /* Parse mode except first character. */
55
        if (console_write(&nl, 1) == 1)
115
    const char *mp = mode;
-
 
116
    if (*mp++ == 0) {
-
 
117
        errno = EINVAL;
56
            return 0;
118
        return false;
57
    }
119
    }
58
   
120
   
-
 
121
    if ((*mp == 'b') || (*mp == 't'))
-
 
122
        mp++;
-
 
123
   
-
 
124
    bool plus;
-
 
125
    if (*mp == '+') {
-
 
126
        mp++;
-
 
127
        plus = true;
-
 
128
    } else
-
 
129
        plus = false;
-
 
130
   
-
 
131
    if (*mp != 0) {
-
 
132
        errno = EINVAL;
-
 
133
        return false;
-
 
134
    }
-
 
135
   
-
 
136
    /* Parse first character of mode and determine flags for open(). */
-
 
137
    switch (mode[0]) {
-
 
138
    case 'r':
-
 
139
        *flags = plus ? O_RDWR : O_RDONLY;
-
 
140
        break;
-
 
141
    case 'w':
-
 
142
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
-
 
143
        break;
-
 
144
    case 'a':
-
 
145
        /* TODO: a+ must read from beginning, append to the end. */
-
 
146
        if (plus) {
-
 
147
            errno = ENOTSUP;
-
 
148
            return false;
-
 
149
        }
-
 
150
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
-
 
151
    default:
-
 
152
        errno = EINVAL;
-
 
153
        return false;
-
 
154
    }
-
 
155
   
59
    return EOF;
156
    return true;
60
}
157
}
61
 
158
 
62
/** Put count chars from buffer to stdout without adding newline
159
/** Open a stream.
-
 
160
 *
63
 * @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
161
 * @param path Path of the file to open.
64
 * @param count
-
 
65
 * @return 0 on succes, EOF on fail
162
 * @param mode Mode string, (r|w|a)[b|t][+].
-
 
163
 *
66
 */
164
 */
67
int putnchars(const char *buf, size_t count)
165
FILE *fopen(const char *path, const char *mode)
68
{
166
{
-
 
167
    int flags;
69
    if (console_write((void *) buf, count) == count)
168
    if (!parse_mode(mode, &flags))
70
        return 0;
169
        return NULL;
71
   
170
   
-
 
171
    /* Open file. */
-
 
172
    FILE *stream = malloc(sizeof(FILE));
-
 
173
    if (stream == NULL) {
-
 
174
        errno = ENOMEM;
-
 
175
        return NULL;
-
 
176
    }
-
 
177
   
-
 
178
    stream->fd = open(path, flags, 0666);
-
 
179
    if (stream->fd < 0) {
-
 
180
        /* errno was set by open() */
-
 
181
        free(stream);
-
 
182
        return NULL;
-
 
183
    }
-
 
184
   
-
 
185
    stream->error = false;
-
 
186
    stream->eof = false;
-
 
187
    stream->klog = false;
-
 
188
    stream->phone = -1;
-
 
189
   
-
 
190
    list_append(&stream->link, &files);
-
 
191
   
-
 
192
    return stream;
-
 
193
}
-
 
194
 
-
 
195
FILE *fdopen(int fd, const char *mode)
-
 
196
{
-
 
197
    /* Open file. */
-
 
198
    FILE *stream = malloc(sizeof(FILE));
-
 
199
    if (stream == NULL) {
-
 
200
        errno = ENOMEM;
-
 
201
        return NULL;
-
 
202
    }
-
 
203
   
-
 
204
    stream->fd = fd;
-
 
205
    stream->error = false;
-
 
206
    stream->eof = false;
-
 
207
    stream->klog = false;
-
 
208
    stream->phone = -1;
-
 
209
   
-
 
210
    list_append(&stream->link, &files);
-
 
211
   
-
 
212
    return stream;
-
 
213
}
-
 
214
 
-
 
215
FILE *fopen_node(fdi_node_t *node, const char *mode)
-
 
216
{
-
 
217
    int flags;
-
 
218
    if (!parse_mode(mode, &flags))
-
 
219
        return NULL;
-
 
220
   
-
 
221
    /* Open file. */
-
 
222
    FILE *stream = malloc(sizeof(FILE));
-
 
223
    if (stream == NULL) {
-
 
224
        errno = ENOMEM;
-
 
225
        return NULL;
-
 
226
    }
-
 
227
   
-
 
228
    stream->fd = open_node(node, flags);
-
 
229
    if (stream->fd < 0) {
-
 
230
        /* errno was set by open_node() */
-
 
231
        free(stream);
-
 
232
        return NULL;
-
 
233
    }
-
 
234
   
-
 
235
    stream->error = false;
-
 
236
    stream->eof = false;
-
 
237
    stream->klog = false;
-
 
238
    stream->phone = -1;
-
 
239
   
-
 
240
    list_append(&stream->link, &files);
-
 
241
   
-
 
242
    return stream;
-
 
243
}
-
 
244
 
-
 
245
int fclose(FILE *stream)
-
 
246
{
-
 
247
    int rc = 0;
-
 
248
   
-
 
249
    fflush(stream);
-
 
250
   
-
 
251
    if (stream->phone >= 0)
-
 
252
        ipc_hangup(stream->phone);
-
 
253
   
-
 
254
    if (stream->fd >= 0)
-
 
255
        rc = close(stream->fd);
-
 
256
   
-
 
257
    list_remove(&stream->link);
-
 
258
   
-
 
259
    if ((stream != &stdin_null)
-
 
260
        && (stream != &stdout_klog)
-
 
261
        && (stream != &stderr_klog))
-
 
262
        free(stream);
-
 
263
   
-
 
264
    stream = NULL;
-
 
265
   
-
 
266
    if (rc != 0) {
-
 
267
        /* errno was set by close() */
72
    return EOF;
268
        return EOF;
-
 
269
    }
-
 
270
   
-
 
271
    return 0;
73
}
272
}
74
 
273
 
-
 
274
/** Read from a stream.
-
 
275
 *
-
 
276
 * @param buf    Destination buffer.
-
 
277
 * @param size   Size of each record.
75
/** Same as puts, but does not print newline at end
278
 * @param nmemb  Number of records to read.
-
 
279
 * @param stream Pointer to the stream.
76
 *
280
 *
77
 */
281
 */
78
int putstr(const char *str)
282
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
79
{
283
{
-
 
284
    size_t left = size * nmemb;
80
    size_t count;
285
    size_t done = 0;
-
 
286
   
-
 
287
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
-
 
288
        ssize_t rd = read(stream->fd, buf + done, left);
-
 
289
       
-
 
290
        if (rd < 0)
-
 
291
            stream->error = true;
-
 
292
        else if (rd == 0)
-
 
293
            stream->eof = true;
-
 
294
        else {
-
 
295
            left -= rd;
-
 
296
            done += rd;
-
 
297
        }
-
 
298
    }
81
   
299
   
82
    if (str == NULL)
-
 
83
        return putnchars("(NULL)", 6);
300
    return (done / size);
-
 
301
}
84
 
302
 
-
 
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.
85
    for (count = 0; str[count] != 0; count++);
308
 * @param stream Pointer to the stream.
-
 
309
 *
-
 
310
 */
86
    if (console_write((void *) str, count) == count)
311
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
-
 
312
{
-
 
313
    size_t left = size * nmemb;
87
        return 0;
314
    size_t done = 0;
88
   
315
   
-
 
316
    while ((left > 0) && (!stream->error)) {
-
 
317
        ssize_t wr;
-
 
318
       
-
 
319
        if (stream->klog)
-
 
320
            wr = klog_write(buf + done, left);
-
 
321
        else
-
 
322
            wr = write(stream->fd, buf + done, left);
-
 
323
       
-
 
324
        if (wr <= 0)
-
 
325
            stream->error = true;
-
 
326
        else {
89
    return EOF;
327
            left -= wr;
-
 
328
            done += wr;
-
 
329
        }
-
 
330
    }
-
 
331
   
-
 
332
    return (done / size);
90
}
333
}
91
 
334
 
92
int putchar(int c)
335
int fputc(wchar_t c, FILE *stream)
93
{
336
{
94
    char buf[STR_BOUNDS(1)];
337
    char buf[STR_BOUNDS(1)];
95
    size_t offs;
338
    size_t sz = 0;
-
 
339
   
-
 
340
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
-
 
341
        size_t wr = fwrite(buf, sz, 1, stream);
-
 
342
       
-
 
343
        if (wr < sz)
-
 
344
            return EOF;
-
 
345
       
-
 
346
        return (int) c;
-
 
347
    }
-
 
348
   
-
 
349
    return EOF;
-
 
350
}
96
 
351
 
97
    offs = 0;
-
 
98
    if (chr_encode(c, buf, &offs, STR_BOUNDS(1)) != EOK)
352
int putchar(wchar_t c)
-
 
353
{
99
        return EOF;
354
    return fputc(c, stdout);
-
 
355
}
100
 
356
 
101
    if (console_write((void *) buf, offs) == offs)
357
int fputs(const char *str, FILE *stream)
-
 
358
{
102
        return c;
359
    return fwrite(str, str_size(str), 1, stream);
-
 
360
}
103
 
361
 
-
 
362
int puts(const char *str)
-
 
363
{
-
 
364
    return fputs(str, stdout);
-
 
365
}
-
 
366
 
-
 
367
int fgetc(FILE *stream)
-
 
368
{
-
 
369
    char c;
-
 
370
 
-
 
371
    /* This could be made faster by only flushing when needed. */
-
 
372
    if (stdout)
-
 
373
        fflush(stdout);
-
 
374
    if (stderr)
-
 
375
        fflush(stderr);
-
 
376
 
-
 
377
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
104
    return EOF;
378
        return EOF;
-
 
379
   
-
 
380
    return (int) c;
105
}
381
}
106
 
382
 
107
int getchar(void)
383
int getchar(void)
108
{
384
{
109
    unsigned char c;
385
    return fgetc(stdin);
-
 
386
}
-
 
387
 
-
 
388
int fseek(FILE *stream, long offset, int origin)
-
 
389
{
-
 
390
    off_t rc = lseek(stream->fd, offset, origin);
-
 
391
    if (rc == (off_t) (-1)) {
-
 
392
        /* errno has been set by lseek. */
-
 
393
        return -1;
-
 
394
    }
110
   
395
   
111
    console_flush();
396
    stream->eof = false;
112
    if (read_stdin((void *) &c, 1) == 1)
-
 
113
        return c;
-
 
114
   
397
   
115
    return EOF;
398
    return 0;
116
}
399
}
117
 
400
 
118
int fflush(FILE *f)
401
void rewind(FILE *stream)
119
{
402
{
-
 
403
    (void) fseek(stream, 0, SEEK_SET);
-
 
404
}
-
 
405
 
-
 
406
int fflush(FILE *stream)
-
 
407
{
120
    /* Dummy implementation */
408
    if (stream->klog) {
-
 
409
        klog_update();
121
    (void) f;
410
        return EOK;
-
 
411
    }
-
 
412
   
-
 
413
    if (stream->fd >= 0)
-
 
414
        return fsync(stream->fd);
-
 
415
   
-
 
416
    return ENOENT;
-
 
417
}
-
 
418
 
-
 
419
int feof(FILE *stream)
-
 
420
{
-
 
421
    return stream->eof;
-
 
422
}
-
 
423
 
-
 
424
int ferror(FILE *stream)
-
 
425
{
-
 
426
    return stream->error;
-
 
427
}
-
 
428
 
-
 
429
int fphone(FILE *stream)
-
 
430
{
-
 
431
    if (stream->fd >= 0) {
-
 
432
        if (stream->phone < 0)
-
 
433
            stream->phone = fd_phone(stream->fd);
-
 
434
       
122
    console_flush();
435
        return stream->phone;
-
 
436
    }
-
 
437
   
123
    return 0;
438
    return -1;
-
 
439
}
-
 
440
 
-
 
441
int fnode(FILE *stream, fdi_node_t *node)
-
 
442
{
-
 
443
    if (stream->fd >= 0)
-
 
444
        return fd_node(stream->fd, node);
-
 
445
   
-
 
446
    return ENOENT;
124
}
447
}
125
 
448
 
126
/** @}
449
/** @}
127
 */
450
 */