1 /*
2 * Copyright (c) 2013 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <lk/debug.h>
9 #include <lk/err.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <platform/debug.h>
16
17 #if defined(WITH_LIB_FS)
18 #define STDIO_FIELDS .use_fs = false,
19 #else
20 #define STDIO_FIELDS
21 #endif // WITH_LIB_FS
22
23 #define DEFINE_STDIO_DESC(id) \
24 [(id)] = { \
25 .io = &console_io, \
26 STDIO_FIELDS \
27 }
28
29 // The three main standard io file descriptors that just
30 // point to the main console.
31 FILE __stdio_FILEs[3] = {
32 DEFINE_STDIO_DESC(0), /* stdin */
33 DEFINE_STDIO_DESC(1), /* stdout */
34 DEFINE_STDIO_DESC(2), /* stderr */
35 };
36 #undef DEFINE_STDIO_DESC
37
fopen(const char * filename,const char * mode)38 FILE *fopen(const char *filename, const char *mode) {
39 #if defined(WITH_LIB_FS)
40 FILE *stream = (FILE *) malloc(sizeof(FILE));
41 if (stream == NULL) {
42 return NULL;
43 }
44
45 // TODO: handle more open modes
46
47 stream->use_fs = true;
48 stream->fs_handle.offset = 0;
49 stream->fs_handle.readonly = (!strchr(mode, 'w') && !strchr(mode, 'a'));
50
51 status_t ret = fs_open_file(filename, &(stream->fs_handle.handle));
52
53 if (ret == ERR_NOT_FOUND && !stream->fs_handle.readonly) {
54 ret = fs_create_file(filename, &(stream->fs_handle.handle), 0);
55 }
56
57 if (ret != NO_ERROR) {
58 free(stream);
59 return NULL;
60 }
61
62 if (strchr(mode, 'a')) {
63 struct file_stat stat;
64 if (NO_ERROR == fs_stat_file(stream->fs_handle.handle, &stat)) {
65 stream->fs_handle.offset = stat.size;
66 }
67 }
68
69 return stream;
70 #endif // WITH_LIB_FS
71 return NULL;
72 }
73
fclose(FILE * stream)74 int fclose(FILE *stream) {
75 #if defined(WITH_LIB_FS)
76 if (stream && !stream->use_fs) {
77 fs_close_file(stream->fs_handle.handle);
78 free(stream);
79 }
80 #endif // WITH_LIB_FS
81 return 0;
82 }
83
84 // Inner version of fread that returns a ssize_t to include the internal error code
85 // along with the length.
fread_error(void * ptr,size_t size,size_t count,FILE * stream)86 static ssize_t fread_error(void *ptr, size_t size, size_t count, FILE *stream) {
87 if (count == 0 || size == 0) {
88 return 0;
89 }
90 #if defined(WITH_LIB_FS)
91 if (stream->use_fs) {
92 ssize_t rsize = fs_read_file(stream->fs_handle.handle, ptr,
93 stream->fs_handle.offset, size * count);
94 if (rsize <= 0) {
95 return rsize;
96 }
97 stream->fs_handle.offset += rsize;
98 return rsize / size;
99 }
100 #endif // WITH_LIB_FS
101 ssize_t rsize = io_read(stream->io, ptr, size * count);
102 if (rsize <= 0) {
103 return rsize;
104 }
105 return rsize / size;
106 }
107
108 // Inner version of fwrite that returns a ssize_t to include the internal error code
109 // along with the length.
fwrite_error(const void * ptr,size_t size,size_t count,FILE * stream)110 static ssize_t fwrite_error(const void *ptr, size_t size, size_t count, FILE *stream) {
111 if (count == 0 || size == 0) {
112 return 0;
113 }
114 #if defined(WITH_LIB_FS)
115 if (stream->use_fs) {
116 if (stream->fs_handle.readonly) {
117 // return error here?
118 return 0;
119 }
120
121 // TODO: deal with append
122
123 ssize_t wsize = fs_write_file(stream->fs_handle.handle, ptr,
124 stream->fs_handle.offset, size * count);
125 if (wsize <= 0) {
126 return wsize;
127 }
128 stream->fs_handle.offset += wsize;
129
130 return wsize / size;
131 }
132 #endif
133 ssize_t wsize = io_write(stream->io, ptr, size * count);
134 if (wsize <= 0) {
135 return wsize;
136 }
137 return wsize / size;
138 }
139
fread(void * ptr,size_t size,size_t count,FILE * stream)140 size_t fread(void *ptr, size_t size, size_t count, FILE *stream) {
141 ssize_t read = fread_error(ptr, size, count, stream);
142 if (read < 0) {
143 // TODO: save error for ferror()
144 return 0;
145 }
146 return read;
147 }
148
fwrite(const void * ptr,size_t size,size_t count,FILE * stream)149 size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream) {
150 ssize_t written = fwrite_error(ptr, size, count, stream);
151 if (written < 0) {
152 // TODO: save error for ferror()
153 return 0;
154 }
155 return written;
156 }
157
fflush(FILE * stream)158 int fflush(FILE *stream) {
159 return 0;
160 }
161
feof(FILE * stream)162 int feof(FILE *stream) {
163 #if defined(WITH_LIB_FS)
164 if (!stream->use_fs) {
165 return 0;
166 }
167 struct file_stat stat;
168 if (NO_ERROR != fs_stat_file(stream->fs_handle.handle, &stat)) {
169 return 1;
170 }
171 return (uint64_t)stream->fs_handle.offset >= stat.size;
172 #endif // WITH_LIB_FS
173 return 0;
174 }
175
clamp(off_t val,off_t min,off_t max)176 static inline off_t clamp(off_t val, off_t min, off_t max) {
177 const off_t t = (val < min) ? min : val;
178 return (t > max) ? max : t;
179 }
180
fseek(FILE * stream,long offset,int whence)181 int fseek(FILE *stream, long offset, int whence) {
182 #if defined(WITH_LIB_FS)
183 if (!stream->use_fs) {
184 return 0;
185 }
186 struct file_stat stat;
187 if (NO_ERROR != fs_stat_file(stream->fs_handle.handle, &stat)) {
188 return -1;
189 }
190
191 switch (whence) {
192 case SEEK_SET:
193 stream->fs_handle.offset = clamp(offset, 0, stat.size);
194 break;
195 case SEEK_CUR:
196 stream->fs_handle.offset = clamp(stream->fs_handle.offset + offset, 0, stat.size);
197 break;
198 case SEEK_END:
199 stream->fs_handle.offset = clamp(stat.size - offset, 0, stat.size);
200 break;
201 default:
202 return -1;
203 }
204 #endif // WITH_LIB_FS
205 return 0;
206 }
207
ftell(FILE * stream)208 long ftell(FILE *stream) {
209 #if defined(WITH_LIB_FS)
210 if (!stream->use_fs) {
211 return 0;
212 }
213 return stream->fs_handle.offset;
214 #endif // WITH_LIB_FS
215 return 0;
216 }
217
fputc(int _c,FILE * fp)218 int fputc(int _c, FILE *fp) {
219 unsigned char c = _c;
220
221 size_t written = fwrite(&c, /*size=*/1, /*count=*/1, fp);
222 if (written == 0) {
223 return EOF;
224 }
225 return c;
226 }
227
putchar(int c)228 int putchar(int c) {
229 return fputc(c, stdout);
230 }
231
puts(const char * str)232 int puts(const char *str) {
233 int err = fputs(str, stdout);
234 if (err >= 0) {
235 err = fputc('\n', stdout);
236 }
237 return err;
238 }
239
fputs(const char * s,FILE * fp)240 int fputs(const char *s, FILE *fp) {
241 size_t len = strlen(s);
242 if (len == 0) {
243 return 0;
244 }
245
246 size_t written = fwrite(s, /*size=*/1, /*count=*/len, fp);
247 if (written == 0) {
248 return EOF;
249 }
250 return written;
251 }
252
fgetc(FILE * fp)253 int fgetc(FILE *fp) {
254 char c;
255
256 size_t err = fread(&c, /*size=*/1, /*count=*/1, fp);
257 if (err == 0) {
258 return EOF;
259 }
260 return c;
261 }
262
getchar(void)263 int getchar(void) {
264 return getc(stdin);
265 }
266
fgets(char * s,int size,FILE * stream)267 char *fgets(char *s, int size, FILE *stream) {
268 int c = -1;
269 char *cs = s;
270
271 if (size < 1) {
272 return NULL;
273 }
274
275 while (--size > 0 && (c = fgetc(stream)) != EOF) {
276 *cs++ = c;
277 if (c == '\n') {
278 break;
279 }
280 }
281
282 *cs = '\0';
283 return (c == EOF && cs == s) ? NULL : s;
284 }
285
_fprintf_output_func(const char * str,size_t len,void * state)286 int _fprintf_output_func(const char *str, size_t len, void *state) {
287 FILE *fp = (FILE *)state;
288
289 return fwrite_error(str, /*size=*/1, /*count=*/len, fp);
290 }
291