Subversion Repositories HelenOS

Rev

Rev 4491 | Rev 4508 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
504 decky 1
/*
2071 jermar 2
 * Copyright (c) 2005 Martin Decky
504 decky 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.
1653 cejka 27
 */
28
 
1866 jermar 29
/** @addtogroup libc
1653 cejka 30
 * @{
31
 */
32
/** @file
4482 decky 33
 */
504 decky 34
 
4482 decky 35
#include <stdio.h>
504 decky 36
#include <unistd.h>
4482 decky 37
#include <fcntl.h>
4239 svoboda 38
#include <string.h>
39
#include <errno.h>
4482 decky 40
#include <bool.h>
41
#include <malloc.h>
42
#include <io/klog.h>
43
#include <vfs/vfs.h>
44
#include <ipc/devmap.h>
504 decky 45
 
4482 decky 46
FILE stdin_null = {
47
    .fd = -1,
48
    .error = true,
49
    .eof = true,
50
    .klog = false,
51
    .phone = -1
52
};
713 decky 53
 
4482 decky 54
FILE stdout_klog = {
55
    .fd = -1,
56
    .error = false,
57
    .eof = false,
58
    .klog = true,
59
    .phone = -1
60
};
61
 
62
FILE *stdin = &stdin_null;
63
FILE *stdout = &stdout_klog;
64
FILE *stderr = &stdout_klog;
65
 
66
static bool parse_mode(const char *mode, int *flags)
504 decky 67
{
4482 decky 68
    /* Parse mode except first character. */
69
    const char *mp = mode;
70
    if (*mp++ == 0) {
71
        errno = EINVAL;
72
        return false;
73
    }
504 decky 74
 
4482 decky 75
    if ((*mp == 'b') || (*mp == 't'))
76
        mp++;
1173 cejka 77
 
4482 decky 78
    bool plus;
79
    if (*mp == '+') {
80
        mp++;
81
        plus = true;
82
    } else
83
        plus = false;
4317 decky 84
 
4482 decky 85
    if (*mp != 0) {
86
        errno = EINVAL;
87
        return false;
713 decky 88
    }
89
 
4482 decky 90
    /* Parse first character of mode and determine flags for open(). */
91
    switch (mode[0]) {
92
    case 'r':
93
        *flags = plus ? O_RDWR : O_RDONLY;
94
        break;
95
    case 'w':
96
        *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
97
        break;
98
    case 'a':
99
        /* TODO: a+ must read from beginning, append to the end. */
100
        if (plus) {
101
            errno = ENOTSUP;
102
            return false;
103
        }
104
        *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
105
    default:
106
        errno = EINVAL;
107
        return false;
108
    }
109
 
110
    return true;
504 decky 111
}
112
 
4482 decky 113
/** Open a stream.
114
 *
115
 * @param path Path of the file to open.
116
 * @param mode Mode string, (r|w|a)[b|t][+].
117
 *
974 cejka 118
 */
4482 decky 119
FILE *fopen(const char *path, const char *mode)
974 cejka 120
{
4482 decky 121
    int flags;
122
    if (!parse_mode(mode, &flags))
123
        return NULL;
974 cejka 124
 
4482 decky 125
    /* Open file. */
126
    FILE *stream = malloc(sizeof(FILE));
127
    if (stream == NULL) {
128
        errno = ENOMEM;
129
        return NULL;
130
    }
131
 
132
    stream->fd = open(path, flags, 0666);
133
    if (stream->fd < 0) {
134
        /* errno was set by open() */
135
        free(stream);
136
        return NULL;
137
    }
138
 
139
    stream->error = false;
140
    stream->eof = false;
141
    stream->klog = false;
142
    stream->phone = -1;
143
 
144
    return stream;
974 cejka 145
}
146
 
4492 jermar 147
FILE *fopen_node(fdi_node_t *node, const char *mode)
4482 decky 148
{
149
    int flags;
150
    if (!parse_mode(mode, &flags))
151
        return NULL;
152
 
153
    /* Open file. */
154
    FILE *stream = malloc(sizeof(FILE));
155
    if (stream == NULL) {
156
        errno = ENOMEM;
157
        return NULL;
158
    }
159
 
160
    stream->fd = open_node(node, flags);
161
    if (stream->fd < 0) {
162
        /* errno was set by open_node() */
163
        free(stream);
164
        return NULL;
165
    }
166
 
167
    stream->error = false;
168
    stream->eof = false;
169
    stream->klog = false;
170
    stream->phone = -1;
171
 
172
    return stream;
173
}
174
 
175
int fclose(FILE *stream)
176
{
177
    int rc = 0;
178
 
179
    fflush(stream);
180
 
181
    if (stream->phone >= 0)
182
        ipc_hangup(stream->phone);
183
 
184
    if (stream->fd >= 0)
185
        rc = close(stream->fd);
186
 
187
    if ((stream != &stdin_null) && (stream != &stdout_klog))
188
        free(stream);
189
 
190
    stream = NULL;
191
 
192
    if (rc != 0) {
193
        /* errno was set by close() */
194
        return EOF;
195
    }
196
 
197
    return 0;
198
}
199
 
200
/** Read from a stream.
974 cejka 201
 *
4482 decky 202
 * @param buf    Destination buffer.
203
 * @param size   Size of each record.
204
 * @param nmemb  Number of records to read.
205
 * @param stream Pointer to the stream.
206
 *
974 cejka 207
 */
4482 decky 208
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
974 cejka 209
{
4482 decky 210
    size_t left = size * nmemb;
211
    size_t done = 0;
974 cejka 212
 
4482 decky 213
    while ((left > 0) && (!stream->error) && (!stream->eof)) {
214
        ssize_t rd = read(stream->fd, buf + done, left);
215
 
216
        if (rd < 0)
217
            stream->error = true;
218
        else if (rd == 0)
219
            stream->eof = true;
220
        else {
221
            left -= rd;
222
            done += rd;
223
        }
224
    }
225
 
226
    return (done / size);
227
}
1010 cejka 228
 
4482 decky 229
/** Write to a stream.
230
 *
231
 * @param buf    Source buffer.
232
 * @param size   Size of each record.
233
 * @param nmemb  Number of records to write.
234
 * @param stream Pointer to the stream.
235
 *
236
 */
237
size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
238
{
239
    size_t left = size * nmemb;
240
    size_t done = 0;
974 cejka 241
 
4482 decky 242
    while ((left > 0) && (!stream->error)) {
243
        ssize_t wr;
244
 
245
        if (stream->klog)
246
            wr = klog_write(buf + done, left);
247
        else
248
            wr = write(stream->fd, buf + done, left);
249
 
250
        if (wr <= 0)
251
            stream->error = true;
252
        else {
253
            left -= wr;
254
            done += wr;
255
        }
256
    }
257
 
258
    return (done / size);
974 cejka 259
}
260
 
4482 decky 261
int fputc(wchar_t c, FILE *stream)
1173 cejka 262
{
4239 svoboda 263
    char buf[STR_BOUNDS(1)];
4482 decky 264
    size_t sz = 0;
265
 
266
    if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
267
        size_t wr = fwrite(buf, sz, 1, stream);
268
 
269
        if (wr < sz)
270
            return EOF;
271
 
272
        return (int) c;
273
    }
274
 
275
    return EOF;
276
}
4239 svoboda 277
 
4482 decky 278
int putchar(wchar_t c)
279
{
280
    return fputc(c, stdout);
281
}
4239 svoboda 282
 
4482 decky 283
int fputs(const char *str, FILE *stream)
284
{
285
    return fwrite(str, str_size(str), 1, stream);
286
}
4239 svoboda 287
 
4482 decky 288
int puts(const char *str)
289
{
290
    return fputs(str, stdout);
1173 cejka 291
}
1465 cejka 292
 
4482 decky 293
int fgetc(FILE *stream)
1465 cejka 294
{
4482 decky 295
    char c;
4317 decky 296
 
4482 decky 297
    if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
298
        return EOF;
1465 cejka 299
 
4482 decky 300
    return (int) c;
1465 cejka 301
}
302
 
4482 decky 303
int getchar(void)
4164 svoboda 304
{
4482 decky 305
    return fgetc(stdin);
306
}
307
 
308
int fseek(FILE *stream, long offset, int origin)
309
{
310
    off_t rc = lseek(stream->fd, offset, origin);
311
    if (rc == (off_t) (-1)) {
312
        /* errno has been set by lseek. */
313
        return -1;
314
    }
315
 
316
    stream->eof = false;
317
 
4317 decky 318
    return 0;
4164 svoboda 319
}
320
 
4482 decky 321
int fflush(FILE *stream)
322
{
323
    if (stream->klog) {
324
        klog_update();
325
        return EOK;
326
    }
327
 
328
    if (stream->fd >= 0)
329
        return fsync(stream->fd);
330
 
331
    return ENOENT;
332
}
333
 
334
int feof(FILE *stream)
335
{
336
    return stream->eof;
337
}
338
 
339
int ferror(FILE *stream)
340
{
341
    return stream->error;
342
}
343
 
344
int fphone(FILE *stream)
345
{
346
    if (stream->fd >= 0) {
347
        if (stream->phone < 0)
348
            stream->phone = fd_phone(stream->fd);
349
 
350
        return stream->phone;
351
    }
352
 
353
    return -1;
354
}
355
 
4492 jermar 356
void fnode(FILE *stream, fdi_node_t *node)
4482 decky 357
{
358
    if (stream->fd >= 0) {
359
        fd_node(stream->fd, node);
360
    } else {
361
        node->fs_handle = 0;
362
        node->dev_handle = 0;
363
        node->index = 0;
364
    }
365
}
366
 
1866 jermar 367
/** @}
1653 cejka 368
 */