stdlibc: \!perror()
[meinos.git] / apps / lib / stdlibc / stdio.c
blob1ffaa1a50b92dac0c2abc08fd3b28b01c8a4223d
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <stdarg.h>
22 #include <syscall.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <limits.h>
29 #define check_stream(stream) ((stream)!=NULL && (stream)->fh>=0)
31 //#define _STDIO_DEBUG
33 static FILE *create_stream(int fh,int oflag) {
34 FILE *stream = malloc(sizeof(FILE));
35 stream->fh = fh;
36 stream->oflag = oflag;
37 stream->error = 0;
38 stream->eof = 0;
39 stream->buf = malloc(BUFSIZ);
40 stream->bufcur = stream->buf;
41 stream->dobuf = 1;
42 return stream;
45 static void stdio_exit() {
46 fflush(stdout);
47 fflush(stderr);
48 fclose(stdin);
49 fclose(stdout);
50 fclose(stderr);
53 /**
54 * Initializes stdio
56 void stdio_init() {
57 stdin = create_stream(STDIN_FILENO,O_RDONLY);
58 stdout = create_stream(STDOUT_FILENO,O_WRONLY);
59 stderr = create_stream(STDERR_FILENO,O_WRONLY);
60 atexit(stdio_exit);
63 /**
64 * Converts a oflag string to a oflag number
65 * @param oflag Mode string
66 * @return Mode number
67 * @todo fix
69 static int oflag_str2num(const char *oflag) {
70 int m;
71 if (oflag[0]=='r') m = O_RDONLY;
72 else if (oflag[0]=='w') m = O_CREAT|O_WRONLY|O_TRUNC;
73 else if (oflag[0]=='a') m = O_CREAT|O_APPEND|O_TRUNC;
74 else m = -1;
75 if (oflag[1]=='+' && m!=-1) m |= O_RDONLY|O_WRONLY;
76 return m;
79 /**
80 * Creates a name for a temporary file
81 * @param s Buffer
82 * @return Filename
84 char *tmpnam(char *buf1) {
85 static unsigned int tmp_num = 0;
86 static char *buf2[L_tmpnam];
87 char *buf = buf1!=NULL?buf1:memset(buf2,0,L_tmpnam);
88 snprintf(buf,L_tmpnam,"%s/%04x",P_tmpdir,tmp_num++);
89 return buf;
92 /**
93 * Clears error in file
94 * @param file Filehandle
96 void clearerr(FILE *file) {
97 file->error = 0;
101 * Gets whether stream reached EOF
102 * @param stream Stream
103 * @return !=0 if EOF
105 int feof(FILE *stream) {
106 if (check_stream(stream)) return stream->eof;
107 else {
108 errno = EBADF;
109 return 0;
114 * Gets current error of stream
115 * @param steam Stream
116 * @return Error number
118 int ferror(FILE *stream) {
119 if (check_stream(stream)) return stream->error;
120 else {
121 errno = EBADF;
122 return 0;
127 * Closes file
128 * @param stream Stream
129 * @return 0=success; -1=failure
131 int fclose(FILE *stream) {
132 if (check_stream(stream)) {
133 if (fflush(stream)==0) {
134 if (close(stream->fh)==0) {
135 free(stream->buf);
136 free(stream);
140 else errno = EBADF;
141 return -1;
145 * Opens a file with Filedescriptor
146 * @param fh Filedescriptor
147 * @param oflag Mode
148 * @return Filehandle
150 FILE *fdopen(int fh,const char *oflag) {
151 return create_stream(fh,oflag_str2num(oflag));
155 * Maps a stream pointer to a file descriptor
156 * @param stream Stream
157 * @return Filedescriptor
159 int fileno(FILE *stream) {
160 if (check_stream(stream)) return stream->fh;
161 else {
162 errno = EBADF;
163 return 0;
168 * Opens a file
169 * @param name Path to file
170 * @param oflag Mode
171 * @return Filehandle
172 * @todo truncate
174 FILE *fopen(const char *name,const char *oflag) {
175 int m = oflag_str2num(oflag);
176 if (m>0) {
177 int fh = open(name,m,0777);
178 if (fh>=0) {
179 if ((m&O_TRUNC)) ftruncate(fh,0);
180 return create_stream(fh,m);
183 return NULL;
187 * Flushs a stream
188 * @param stream Stream to flush
189 * @return Success?
191 int fflush(FILE *stream) {
192 if (stream->dobuf) {
193 int ret;
194 #ifdef _STDIO_DEBUG
195 if (stream->fh==STDOUT_FILENO) ret = syscall_call(SYSCALL_PUTSN,3,0,stream->buf,stream->bufcur-stream->buf)==-1?EOF:0;
196 else if (stream->fh==STDERR_FILENO) ret = syscall_call(SYSCALL_PUTSN,3,1,stream->buf,stream->bufcur-stream->buf)==-1?EOF:0;
197 else {
198 #endif
199 ret = write(stream->fh,stream->buf,stream->bufcur-stream->buf);
200 if (ret>0 && ret<(stream->bufcur-stream->buf)) {
201 stream->eof = 1;
202 ret = EOF;
204 #ifdef _STDIO_DEBUG
206 #endif
207 stream->bufcur = stream->buf;
208 return ret;
210 return 0;
214 * Print string to stdout
215 * @param s String
216 * @return How many bytes put
218 int puts(const char *s) {
219 int ret = fputs(s,stdout);
220 if (ret>0) {
221 putchar('\n');
222 ret++;
224 return ret;
228 * Writes binary
229 * @param ptr Buffer to get data from
230 * @param size How many bytes to write
231 * @param stream Stream to write to
232 * @return How many elements written
234 size_t _fwrite(const void *ptr,size_t size,FILE *stream) {
235 if (size==0) return 0;
236 if (check_stream(stream)) {
237 if (stream->oflag&O_WRONLY) {
238 if (stream->dobuf /*&& size<BUFSIZ*/) {
239 if (stream->bufcur+size>stream->buf+BUFSIZ) fflush(stream);
240 if (size>BUFSIZ) size = BUFSIZ;
241 memcpy(stream->bufcur,ptr,size);
242 stream->bufcur += size;
243 if (memchr(ptr,'\n',size)!=NULL) fflush(stream);
244 return size;
246 else {
247 int ret = write(stream->fh,ptr,size);
248 if (ret>0 && ret<(stream->bufcur-stream->buf)) stream->eof = 1;
249 return ret;
252 else {
253 stream->eof = 1;
254 return 0;
257 else {
258 errno = EBADF;
259 return -1;
264 * Gets string from file
265 * @param s Destination for string
266 * @param n How many bytes to read
267 * @param stream Stream to read from
268 * @return String
270 char *fgets(char *s,int n,FILE *stream) {
271 int i,chr;
272 if (check_stream(stream)) {
273 for (i=0;i<n-1;i++) {
274 chr = fgetc(stream);
275 if (chr==EOF) break;
276 else s[i] = chr;
277 if (errno>0) {
278 stream->error = errno;
279 return NULL;
281 if (s[i]==0 || s[i]=='\n') break;
283 s[i] = 0;
284 return s;
286 else {
287 errno = EBADF;
288 return NULL;
293 * Reads binary
294 * @param ptr Buffer to store data
295 * @param size How many bytes to read
296 * @param stream Stream to read from
297 * @return How many elements read
299 size_t _fread(void *ptr,size_t size,FILE *stream) {
300 if (check_stream(stream)) {
301 ssize_t ret;
302 ret = read(stream->fh,ptr,size);
303 if (ret>0) {
304 if (ret<size) stream->eof = 1;
305 return ret;
307 else return -1;
309 else {
310 errno = EBADF;
311 return -1;
315 int fgetpos(FILE *stream,fpos_t *pos) {
316 if (check_stream(stream)) {
317 *pos = ftello(stream);
318 return 0;
320 else {
321 errno = EBADF;
322 return -1;
326 int fsetpos(FILE *stream,fpos_t *pos) {
327 if (check_stream(stream)) {
328 fseeko(stream,*pos,SEEK_SET);
329 return 0;
331 else {
332 errno = EBADF;
333 return -1;
337 FILE *freopen(const char *filename,const char *oflag,FILE *stream) {
338 if (check_stream(stream)) {
339 fflush(stream);
340 close(stream->fh);
341 stream->oflag = oflag_str2num(oflag);
342 stream->eof = 0;
343 stream->error = 0;
344 stream->fh = open(filename,stream->oflag);
345 return stream;
347 else {
348 errno = EBADF;
349 return NULL;
353 /// @todo Implement me
354 int fscanf(FILE *stream,const char *format,...) {
355 return 0;
358 /// @todo Implement me
359 int ungetc(int c,FILE *stream) {
360 return 0;