Usermode/libc - Fixed DIV0 in fread/fopen
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / stdio.c
1 /*\r
2  * AcessOS Basic C Library\r
3  * stdio.c\r
4  */\r
5 #include "config.h"\r
6 #include <acess/sys.h>\r
7 #include <stdlib.h>\r
8 #include <stdio.h>\r
9 #include <string.h>\r
10 #include "lib.h"\r
11 #include "stdio_int.h"\r
12 \r
13 #define WRITE_STR(_fd, _str)    write(_fd, _str, sizeof(_str))\r
14 \r
15 #define DEBUG_BUILD     0\r
16 \r
17 // === CONSTANTS ===\r
18 #define _stdin  0\r
19 #define _stdout 1\r
20 \r
21 // === PROTOTYPES ===\r
22 EXPORT void     itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned);\r
23 struct sFILE    *get_file_struct();\r
24 \r
25 // === GLOBALS ===\r
26 struct sFILE    _iob[STDIO_MAX_STREAMS];        // IO Buffer\r
27 struct sFILE    *stdin; // Standard Input\r
28 struct sFILE    *stdout;        // Standard Output\r
29 struct sFILE    *stderr;        // Standard Error\r
30 ///\note Initialised in SoMain\r
31 \r
32 // === CODE ===\r
33 int _fopen_modetoflags(const char *mode)\r
34 {\r
35         int flags = 0;\r
36         \r
37         // Get main mode\r
38         switch(*mode)\r
39         {\r
40         case 'r':       flags = FILE_FLAG_MODE_READ;    break;\r
41         case 'w':       flags = FILE_FLAG_MODE_WRITE;   break;\r
42         case 'a':       flags = FILE_FLAG_MODE_APPEND;  break;\r
43         case 'x':       flags = FILE_FLAG_MODE_EXEC;    break;  // Acess addon\r
44         default:\r
45                 return -1;\r
46         }\r
47         mode ++;\r
48 \r
49         // Get Modifiers\r
50         for( ; *mode; mode ++ )\r
51         {\r
52                 switch(*mode)\r
53                 {\r
54                 case 'b':       flags |= FILE_FLAG_M_BINARY;    break;\r
55                 case '+':       flags |= FILE_FLAG_M_EXT;       break;\r
56                 default:\r
57                         return -1;\r
58                 }\r
59         }\r
60         \r
61         return flags;\r
62 }\r
63 \r
64 /**\r
65  * \fn FILE *freopen(char *file, char *mode, FILE *fp)\r
66  */\r
67 EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp)\r
68 {\r
69          int    openFlags = 0;\r
70         \r
71         // Sanity Check Arguments\r
72         if(!fp || !file || !mode)       return NULL;\r
73         \r
74         if(fp->FD != -1) {\r
75                 fflush(fp);\r
76         }\r
77 \r
78         // Get stdio flags\r
79         fp->Flags = _fopen_modetoflags(mode);\r
80         if(fp->Flags == -1)\r
81                 return NULL;\r
82         \r
83         // Get Open Flags\r
84         switch(fp->Flags & FILE_FLAG_MODE_MASK)\r
85         {\r
86         // Read\r
87         case FILE_FLAG_MODE_READ:\r
88                 openFlags = OPENFLAG_READ;\r
89                 if(fp->Flags & FILE_FLAG_M_EXT)\r
90                         openFlags |= OPENFLAG_WRITE;\r
91                 break;\r
92         // Write\r
93         case FILE_FLAG_MODE_WRITE:\r
94                 openFlags = OPENFLAG_WRITE;\r
95                 if(fp->Flags & FILE_FLAG_M_EXT)\r
96                         openFlags |= OPENFLAG_READ;\r
97                 break;\r
98         // Execute\r
99         case FILE_FLAG_MODE_APPEND:\r
100                 openFlags = OPENFLAG_APPEND;\r
101                 if(fp->Flags & FILE_FLAG_M_EXT)\r
102                         openFlags |= OPENFLAG_READ;\r
103                 break;\r
104         // Execute\r
105         case FILE_FLAG_MODE_EXEC:\r
106                 openFlags = OPENFLAG_EXEC;\r
107                 break;\r
108         }\r
109 \r
110         //Open File\r
111         if(fp->FD != -1)\r
112                 fp->FD = _SysReopen(fp->FD, file, openFlags);\r
113         else\r
114                 fp->FD = _SysOpen(file, openFlags);\r
115         if(fp->FD == -1) {\r
116                 fp->Flags = 0;\r
117                 return NULL;\r
118         }\r
119         \r
120         if( (fp->Flags & FILE_FLAG_MODE_MASK) == FILE_FLAG_MODE_APPEND ) {\r
121                 _SysSeek(fp->FD, 0, SEEK_END);  //SEEK_END\r
122         }\r
123         \r
124         return fp;\r
125 }\r
126 /**\r
127  \fn FILE *fopen(const char *file, const char *mode)\r
128  \brief Opens a file and returns the pointer\r
129  \param file    String - Filename to open\r
130  \param mode    Mode to open in\r
131 */\r
132 EXPORT FILE *fopen(const char *file, const char *mode)\r
133 {\r
134         FILE    *retFile;\r
135         \r
136         // Sanity Check Arguments\r
137         if(!file || !mode)      return NULL;\r
138         \r
139         // Create Return Structure\r
140         retFile = get_file_struct();\r
141         \r
142         return freopen(file, mode, retFile);\r
143 }\r
144 \r
145 EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode)\r
146 {\r
147         FILE    *ret;\r
148         \r
149         if( !buffer || !mode )  return NULL;\r
150         \r
151         ret = get_file_struct();\r
152         \r
153         ret->FD = -2;\r
154         ret->Flags = _fopen_modetoflags(mode);\r
155         if(ret->Flags == -1) {\r
156                 ret->Flags = 0;\r
157                 return NULL;\r
158         }\r
159         \r
160         ret->Buffer = buffer;\r
161         ret->BufferStart = 0;\r
162         ret->BufferSize = length;\r
163         \r
164         return ret;\r
165 }\r
166 \r
167 EXPORT int fclose(FILE *fp)\r
168 {\r
169         fflush(fp);\r
170         if( fp->FD != -1 ) {\r
171                 _SysClose(fp->FD);\r
172         }\r
173         fp->Flags = 0;\r
174         fp->FD = -1;\r
175         return 0;\r
176 }\r
177 \r
178 EXPORT void fflush(FILE *fp)\r
179 {\r
180         if( !fp || fp->FD == -1 )\r
181                 return ;\r
182         \r
183         if( !(fp->Flags & FILE_FLAG_DIRTY) )\r
184                 return ;\r
185         \r
186         // Nothing to do for memory files\r
187         if( fp->FD == -2 )\r
188                 return ;\r
189 }\r
190 \r
191 EXPORT void clearerr(FILE *fp)\r
192 {\r
193         if( !fp || fp->FD == -1 )\r
194                 return ;\r
195         \r
196         // TODO: Impliment clearerr()\r
197 }\r
198 \r
199 EXPORT int feof(FILE *fp)\r
200 {\r
201         if( !fp || fp->FD == -1 )\r
202                 return 0;\r
203         return !!(fp->Flags & FILE_FLAG_EOF);\r
204 }\r
205 \r
206 EXPORT int ferror(FILE *fp)\r
207 {\r
208         if( !fp || fp->FD == -1 )\r
209                 return 0;\r
210         return 0;\r
211 }\r
212 EXPORT int fileno(FILE *stream)\r
213 {\r
214         return stream->FD;\r
215 }\r
216 \r
217 EXPORT off_t ftell(FILE *fp)\r
218 {\r
219         if(!fp || fp->FD == -1) return -1;\r
220 \r
221         if( fp->FD == -2 )\r
222                 return fp->Pos; \r
223         else\r
224                 return _SysTell(fp->FD);\r
225 }\r
226 \r
227 EXPORT int fseek(FILE *fp, long int amt, int whence)\r
228 {\r
229         if(!fp || fp->FD == -1) return -1;\r
230 \r
231         if( fp->FD == -2 ) {\r
232                 switch(whence)\r
233                 {\r
234                 case SEEK_CUR:\r
235                         fp->Pos += amt;\r
236                         break;\r
237                 case SEEK_SET:\r
238                         fp->Pos = amt;\r
239                         break;\r
240                 case SEEK_END:\r
241                         if( fp->BufferSize < (size_t)amt )\r
242                                 fp->Pos = 0;\r
243                         else\r
244                                 fp->Pos = fp->BufferSize - amt;\r
245                         break;\r
246                 }\r
247                 if(fp->Pos > (off_t)fp->BufferSize) {\r
248                         fp->Pos = fp->BufferSize;\r
249                         fp->Flags |= FILE_FLAG_EOF;\r
250                 }\r
251                 return 0;\r
252         }\r
253         else\r
254                 return _SysSeek(fp->FD, amt, whence);\r
255 }\r
256 \r
257 /**\r
258  * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
259  * \brief Write to a stream\r
260  */\r
261 EXPORT size_t fwrite(const void *ptr, size_t size, size_t num, FILE *fp)\r
262 {\r
263         size_t  ret;\r
264         \r
265         if(!fp || fp->FD == -1)\r
266                 return -1;\r
267         if( size == 0 || num == 0 )\r
268                 return 0;\r
269 \r
270         if( fp->FD == -2 ) {\r
271                 size_t  avail = (fp->BufferSize - fp->Pos) / size;\r
272                 if( avail == 0 )\r
273                         fp->Flags |= FILE_FLAG_EOF;\r
274                 if( num > avail )       num = avail;\r
275                 size_t  bytes = num * size;\r
276                 memcpy((char*)fp->Buffer + fp->Pos, ptr, bytes);\r
277                 fp->Pos += bytes;\r
278                 ret = num;\r
279         }\r
280         else {  \r
281                 ret = _SysWrite(fp->FD, ptr, size*num);\r
282                 ret /= size;\r
283         }\r
284         \r
285         return ret;\r
286 }\r
287 \r
288 /**\r
289  * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
290  * \brief Read from a stream\r
291  */\r
292 EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
293 {\r
294         size_t  ret;\r
295         \r
296         if(!fp || fp->FD == -1)\r
297                 return -1;\r
298         if( size == 0 || num == 0 )\r
299                 return 0;\r
300 \r
301         if( fp->FD == -2 ) {\r
302                 size_t  avail = (fp->BufferSize - fp->Pos) / size;\r
303                 if( avail == 0 )\r
304                         fp->Flags |= FILE_FLAG_EOF;\r
305                 if( num > avail )       num = avail;\r
306                 size_t  bytes = num * size;\r
307                 memcpy(ptr, (char*)fp->Buffer + fp->Pos, bytes);\r
308                 fp->Pos += bytes;\r
309                 ret = num;\r
310         }\r
311         else {\r
312                 ret = _SysRead(fp->FD, ptr, size*num);\r
313                 if( ret == (size_t)-1)\r
314                         return -1;\r
315                 if( ret == 0 && size*num > 0 ) {\r
316                         fp->Flags |= FILE_FLAG_EOF;\r
317                         return 0;\r
318                 }\r
319                 ret /= size;\r
320         }\r
321                 \r
322         return ret;\r
323 }\r
324 \r
325 /**\r
326  * \brief Write a string to a stream (without trailing \n)\r
327  */\r
328 EXPORT int fputs(const char *s, FILE *fp)\r
329 {\r
330         int len = strlen(s);\r
331         return fwrite(s, 1, len, fp);\r
332 }\r
333 \r
334 /**\r
335  * \brief Read a line (and possible trailing \n into a buffer)\r
336  */\r
337 EXPORT char *fgets(char *s, int size, FILE *fp)\r
338 {\r
339         int ofs = 0;\r
340         char    ch = '\0';\r
341         while( ofs < size && ch != '\n' )\r
342         {\r
343                 if( fread(&ch, 1, 1, fp) != 1 )\r
344                         break;\r
345                 s[ofs ++] = ch;\r
346         }\r
347         if( ofs < size )\r
348                 s[ofs] = '\0';\r
349         return s;\r
350 }\r
351 \r
352 /**\r
353  * \fn EXPORT int fputc(int c, FILE *fp)\r
354  * \brief Write a single character to the stream\r
355  */\r
356 EXPORT int fputc(int c, FILE *fp)\r
357 {\r
358         return fwrite(&c, 1, 1, fp);\r
359 }\r
360 \r
361 EXPORT int putchar(int c)\r
362 {\r
363         c &= 0xFF;\r
364         return _SysWrite(_stdout, &c, 1);\r
365 }\r
366 \r
367 /**\r
368  * \fn EXPORT int fgetc(FILE *fp)\r
369  * \brief Read a character from the stream\r
370  */\r
371 EXPORT int fgetc(FILE *fp)\r
372 {\r
373         char    ret = 0;\r
374         if( fread(&ret, 1, 1, fp) != 1 )\r
375                 return -1;\r
376         return ret;\r
377 }\r
378 \r
379 EXPORT int getchar(void)\r
380 {\r
381         char    ret = 0;\r
382         if(_SysRead(_stdin, &ret, 1) != 1)      return -1;\r
383         return ret;\r
384 }\r
385 \r
386 // --- INTERNAL ---\r
387 /**\r
388  * \fn FILE *get_file_struct()\r
389  * \brief Returns a file descriptor structure\r
390  */\r
391 FILE *get_file_struct()\r
392 {\r
393          int    i;\r
394         for(i=0;i<STDIO_MAX_STREAMS;i++)\r
395         {\r
396                 if(_iob[i].Flags & FILE_FLAG_ALLOC)\r
397                         continue ;\r
398                 _iob[i].Flags |= FILE_FLAG_ALLOC;\r
399                 _iob[i].FD = -1;\r
400                 _iob[i].Pos = 0;\r
401                 return &_iob[i];\r
402         }\r
403         return NULL;\r
404 }\r
405 \r
406 EXPORT int puts(const char *str)\r
407 {\r
408          int    len;\r
409         \r
410         if(!str)        return 0;\r
411         len = strlen(str);\r
412         \r
413         len = _SysWrite(_stdout, str, len);\r
414         _SysWrite(_stdout, "\n", 1);\r
415         return len;\r
416 }\r
417 \r

UCC git Repository :: git.ucc.asn.au