Usermode/libc - Fixing little bugs/speed issues
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / fileIO.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 /**\r
34  * \fn FILE *freopen(char *file, char *mode, FILE *fp)\r
35  */\r
36 EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp)\r
37 {\r
38          int    openFlags = 0;\r
39          int    i;\r
40         \r
41         // Sanity Check Arguments\r
42         if(!fp || !file || !mode)       return NULL;\r
43         \r
44         if(fp->Flags) {\r
45                 fflush(fp);\r
46         } else\r
47                 fp->FD = -1;\r
48         \r
49         // Get main mode\r
50         switch(mode[0])\r
51         {\r
52         case 'r':       fp->Flags = FILE_FLAG_MODE_READ;        break;\r
53         case 'w':       fp->Flags = FILE_FLAG_MODE_WRITE;       break;\r
54         case 'a':       fp->Flags = FILE_FLAG_MODE_APPEND;      break;\r
55         case 'x':       fp->Flags = FILE_FLAG_MODE_EXEC;        break;\r
56         default:\r
57                 return NULL;\r
58         }\r
59         // Get Modifiers\r
60         for(i=1;mode[i];i++)\r
61         {\r
62                 switch(mode[i])\r
63                 {\r
64                 case '+':       fp->Flags |= FILE_FLAG_M_EXT;\r
65                 }\r
66         }\r
67         \r
68         // Get Open Flags\r
69         switch(mode[0])\r
70         {\r
71         // Read\r
72         case 'r':       openFlags = OPENFLAG_READ;\r
73                 if(fp->Flags & FILE_FLAG_M_EXT)\r
74                         openFlags |= OPENFLAG_WRITE;\r
75                 break;\r
76         // Write\r
77         case 'w':       openFlags = OPENFLAG_WRITE;\r
78                 if(fp->Flags & FILE_FLAG_M_EXT)\r
79                         openFlags |= OPENFLAG_READ;\r
80                 break;\r
81         // Execute\r
82         case 'x':       openFlags = OPENFLAG_EXEC;\r
83                 break;\r
84         }\r
85 \r
86         //Open File\r
87         if(fp->FD != -1)\r
88                 fp->FD = reopen(fp->FD, file, openFlags);\r
89         else\r
90                 fp->FD = open(file, openFlags);\r
91         if(fp->FD == -1) {\r
92                 fp->Flags = 0;\r
93                 return NULL;\r
94         }\r
95         \r
96         if(mode[0] == 'a') {\r
97                 seek(fp->FD, 0, SEEK_END);      //SEEK_END\r
98         }\r
99         \r
100         return fp;\r
101 }\r
102 /**\r
103  \fn FILE *fopen(const char *file, const char *mode)\r
104  \brief Opens a file and returns the pointer\r
105  \param file    String - Filename to open\r
106  \param mode    Mode to open in\r
107 */\r
108 EXPORT FILE *fopen(const char *file, const char *mode)\r
109 {\r
110         FILE    *retFile;\r
111         \r
112         // Sanity Check Arguments\r
113         if(!file || !mode)      return NULL;\r
114         \r
115         // Create Return Structure\r
116         retFile = get_file_struct();\r
117         \r
118         return freopen(file, mode, retFile);\r
119 }\r
120 \r
121 EXPORT int fclose(FILE *fp)\r
122 {\r
123         close(fp->FD);\r
124         fp->Flags = 0;\r
125         fp->FD = -1;\r
126         return 0;\r
127 }\r
128 \r
129 EXPORT void fflush(FILE *fp)\r
130 {\r
131         ///\todo Implement\r
132 }\r
133 \r
134 EXPORT off_t ftell(FILE *fp)\r
135 {\r
136         if(!fp || !fp->FD)      return -1;\r
137         \r
138         return tell(fp->FD);\r
139 }\r
140 \r
141 EXPORT int fseek(FILE *fp, long int amt, int whence)\r
142 {\r
143         if(!fp || !fp->FD)      return -1;\r
144         \r
145         return seek(fp->FD, amt, whence);\r
146 }\r
147 \r
148 \r
149 /**\r
150  * \fn EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
151  * \brief Print to a file from a variable argument list\r
152  */\r
153 EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
154 {\r
155         va_list tmpList;\r
156          int    size;\r
157         char    sbuf[1024];\r
158         char    *buf = sbuf;\r
159 \r
160         if(!fp || !format)      return -1;\r
161 \r
162         va_copy(tmpList, args);\r
163         \r
164         size = vsnprintf(sbuf, sizeof(sbuf), (char*)format, tmpList);\r
165         \r
166         if( size >= sizeof(sbuf) )\r
167         {\r
168                 buf = (char*)malloc(size+1);\r
169                 if(!buf) {\r
170                         WRITE_STR(_stdout, "vfprintf ERROR: malloc() failed");\r
171                         return 0;\r
172                 }\r
173                 buf[size] = '\0';\r
174         \r
175                 // Print\r
176                 vsnprintf(buf, size+1, (char*)format, args);\r
177         }\r
178         \r
179         // Write to stream\r
180         write(fp->FD, buf, size);\r
181         \r
182         // Free buffer\r
183         free(buf);\r
184         \r
185         // Return written byte count\r
186         return size;\r
187 }\r
188 \r
189 /**\r
190  * \fn int fprintf(FILE *fp, const char *format, ...)\r
191  * \brief Print a formatted string to a stream\r
192  */\r
193 EXPORT int fprintf(FILE *fp, const char *format, ...)\r
194 {\r
195         va_list args;\r
196          int    ret;\r
197         \r
198         // Get Size\r
199         va_start(args, format);\r
200         ret = vfprintf(fp, (char*)format, args);\r
201         va_end(args);\r
202         \r
203         return ret;\r
204 }\r
205 \r
206 /**\r
207  * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
208  * \brief Write to a stream\r
209  */\r
210 EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
211 {\r
212          int    ret;\r
213         if(!fp || !fp->FD)      return -1;\r
214         \r
215         ret = write(fp->FD, ptr, size*num);\r
216         \r
217         return ret;\r
218 }\r
219 \r
220 /**\r
221  * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
222  * \brief Read from a stream\r
223  */\r
224 EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
225 {\r
226          int    ret;\r
227         if(!fp || !fp->FD)      return -1;\r
228 \r
229         // TODO: Fit the spec better with the return value      \r
230         ret = read(fp->FD, ptr, size*num);\r
231         \r
232         return ret;\r
233 }\r
234 \r
235 /**\r
236  * \fn EXPORT int fputc(int c, FILE *fp)\r
237  * \brief Write a single character to the stream\r
238  */\r
239 EXPORT int fputc(int c, FILE *fp)\r
240 {\r
241         if(!fp || !fp->FD)      return -1;\r
242         return write(fp->FD, &c, 1);\r
243 }\r
244 \r
245 EXPORT int putchar(int c)\r
246 {\r
247         c &= 0xFF;\r
248         return write(_stdout, &c, 1);\r
249 }\r
250 \r
251 /**\r
252  * \fn EXPORT int fgetc(FILE *fp)\r
253  * \brief Read a character from the stream\r
254  */\r
255 EXPORT int fgetc(FILE *fp)\r
256 {\r
257         char    ret = 0;\r
258         if(!fp) return -1;\r
259         if(read(fp->FD, &ret, 1) == -1) return -1;\r
260         return ret;\r
261 }\r
262 \r
263 EXPORT int getchar(void)\r
264 {\r
265         char    ret = 0;\r
266         if(read(_stdin, &ret, 1) != 1)  return -1;\r
267         return ret;\r
268 }\r
269 \r
270 // --- INTERNAL ---\r
271 /**\r
272  * \fn FILE *get_file_struct()\r
273  * \brief Returns a file descriptor structure\r
274  */\r
275 FILE *get_file_struct()\r
276 {\r
277          int    i;\r
278         for(i=0;i<STDIO_MAX_STREAMS;i++)\r
279         {\r
280                 if(_iob[i].Flags == 0)  return &_iob[i];\r
281         }\r
282         return NULL;\r
283 }\r
284 \r
285 EXPORT int puts(const char *str)\r
286 {\r
287          int    len;\r
288         \r
289         if(!str)        return 0;\r
290         len = strlen(str);\r
291         \r
292         len = write(_stdout, str, len);\r
293         write(_stdout, "\n", 1);\r
294         return len;\r
295 }\r
296 \r
297 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)\r
298 {\r
299         return vsnprintf(__s, 0x7FFFFFFF, __format, __args);\r
300 }\r
301 \r
302 //sprintfv\r
303 /**\r
304  * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)\r
305  * \brief Prints a formatted string to a buffer\r
306  * \param buf   Pointer - Destination Buffer\r
307  * \param format        String - Format String\r
308  * \param args  VarArgs List - Arguments\r
309  */\r
310 EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args)\r
311 {\r
312         char    tmp[65];\r
313          int    c, minSize, precision, len;\r
314          int    pos = 0;\r
315         char    *p;\r
316         char    pad;\r
317         uint64_t        arg;\r
318          int    bLongLong, bPadLeft;\r
319 \r
320         void _addchar(char ch)\r
321         {\r
322                 if(buf && pos < __maxlen)       buf[pos] = ch;\r
323                 pos ++;\r
324         }\r
325 \r
326         tmp[32] = '\0';\r
327         \r
328         while((c = *format++) != 0)\r
329         {\r
330                 // Non-control character\r
331                 if (c != '%') {\r
332                         _addchar(c);\r
333                         continue;\r
334                 }\r
335                 \r
336                 // Control Character\r
337                 c = *format++;\r
338                 if(c == '%') {  // Literal %\r
339                         _addchar('%');\r
340                         continue;\r
341                 }\r
342                 \r
343                 bPadLeft = 0;\r
344                 bLongLong = 0;\r
345                 minSize = 0;\r
346                 precision = -1;\r
347                 pad = ' ';\r
348                 \r
349                 // Padding Character\r
350                 if(c == '0') {\r
351                         pad = '0';\r
352                         c = *format++;\r
353                 }\r
354                 // Padding length\r
355                 if( c == '*' ) {\r
356                         // Variable length\r
357                         minSize = va_arg(args, size_t);\r
358                         c = *format++;\r
359                 }\r
360                 else {\r
361                         if('1' <= c && c <= '9')\r
362                         {\r
363                                 minSize = 0;\r
364                                 while('0' <= c && c <= '9')\r
365                                 {\r
366                                         minSize *= 10;\r
367                                         minSize += c - '0';\r
368                                         c = *format++;\r
369                                 }\r
370                         }\r
371                 }\r
372 \r
373                 // Precision\r
374                 if(c == '.') {\r
375                         c = *format++;\r
376                         if(c == '*') {\r
377                                 precision = va_arg(args, size_t);\r
378                                 c = *format++;\r
379                         }\r
380                         else if('1' <= c && c <= '9')\r
381                         {\r
382                                 precision = 0;\r
383                                 while('0' <= c && c <= '9')\r
384                                 {\r
385                                         precision *= 10;\r
386                                         precision += c - '0';\r
387                                         c = *format++;\r
388                                 }\r
389                         }\r
390                 }\r
391         \r
392                 // Check for long long\r
393                 bLongLong = 0;\r
394                 if(c == 'l')\r
395                 {\r
396                         c = *format++;\r
397                         if(c == 'l') {\r
398                                 bLongLong = 1;\r
399                         }\r
400                 }\r
401                 \r
402                 // Just help things along later\r
403                 p = tmp;\r
404                 \r
405                 // Get Type\r
406                 switch( c )\r
407                 {\r
408                 // Signed Integer\r
409                 case 'd':       case 'i':\r
410                         // Get Argument\r
411                         if(bLongLong)   arg = va_arg(args, int64_t);\r
412                         else                    arg = va_arg(args, int32_t);\r
413                         itoa(tmp, arg, 10, minSize, pad, 1);\r
414                         precision = -1;\r
415                         goto sprintf_puts;\r
416                 \r
417                 // Unsigned Integer\r
418                 case 'u':\r
419                         // Get Argument\r
420                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
421                         else                    arg = va_arg(args, uint32_t);\r
422                         itoa(tmp, arg, 10, minSize, pad, 0);\r
423                         precision = -1;\r
424                         goto sprintf_puts;\r
425                 \r
426                 // Pointer\r
427                 case 'p':\r
428                         _addchar('*');\r
429                         _addchar('0');\r
430                         _addchar('x');\r
431                         arg = va_arg(args, intptr_t);\r
432                         itoa(tmp, arg, 16, minSize, pad, 0);\r
433                         precision = -1;\r
434                         goto sprintf_puts;\r
435                 // Unsigned Hexadecimal\r
436                 case 'x':\r
437                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
438                         else                    arg = va_arg(args, uint32_t);\r
439                         itoa(tmp, arg, 16, minSize, pad, 0);\r
440                         precision = -1;\r
441                         goto sprintf_puts;\r
442                 \r
443                 // Unsigned Octal\r
444                 case 'o':\r
445                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
446                         else                    arg = va_arg(args, uint32_t);\r
447                         itoa(tmp, arg, 8, minSize, pad, 0);\r
448                         precision = -1;\r
449                         goto sprintf_puts;\r
450                 \r
451                 // Unsigned binary\r
452                 case 'b':\r
453                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
454                         else                    arg = va_arg(args, uint32_t);\r
455                         itoa(tmp, arg, 2, minSize, pad, 0);\r
456                         precision = -1;\r
457                         goto sprintf_puts;\r
458 \r
459                 // String\r
460                 case 's':\r
461                         p = va_arg(args, char*);\r
462                 sprintf_puts:\r
463                         if(!p)  p = "(null)";\r
464                         //_SysDebug("vsnprintf: p = '%s'", p);\r
465                         if(precision >= 0)\r
466                                 len = strnlen(p, precision);\r
467                         else\r
468                                 len = strlen(p);\r
469                         if(bPadLeft)    while(minSize > len++)  _addchar(pad);\r
470                         while( *p ) {\r
471                                 if(precision >= 0 && precision -- == 0)\r
472                                         break;\r
473                                 _addchar(*p++);\r
474                         }\r
475                         if(!bPadLeft)   while(minSize > len++)  _addchar(pad);\r
476                         break;\r
477 \r
478                 // Unknown, just treat it as a character\r
479                 default:\r
480                         arg = va_arg(args, uint32_t);\r
481                         _addchar(arg);\r
482                         break;\r
483                 }\r
484         }\r
485         _addchar('\0');\r
486         pos --;\r
487         \r
488         //_SysDebug("vsnprintf: buf = '%s'", buf);\r
489         \r
490         return pos;\r
491 }\r
492 \r
493 const char cUCDIGITS[] = "0123456789ABCDEF";\r
494 /**\r
495  * \fn static void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned)\r
496  * \brief Convert an integer into a character string\r
497  * \param buf   Destination Buffer\r
498  * \param num   Number to convert\r
499  * \param base  Base-n number output\r
500  * \param minLength     Minimum length of output\r
501  * \param pad   Padding used to ensure minLength\r
502  * \param bSigned       Signed number output?\r
503  */\r
504 EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)\r
505 {\r
506         char    tmpBuf[64];\r
507          int    pos=0, i;\r
508 \r
509         if(!buf)        return;\r
510         if(base > 16 || base < 2) {\r
511                 buf[0] = 0;\r
512                 return;\r
513         }\r
514         \r
515         if(bSigned && (int64_t)num < 0)\r
516         {\r
517                 num = -num;\r
518                 bSigned = 1;\r
519         } else\r
520                 bSigned = 0;\r
521         \r
522         // Encode into reversed string\r
523         while(num > base-1) {\r
524                 tmpBuf[pos++] = cUCDIGITS[ num % base ];\r
525                 num = (uint64_t) num / (uint64_t)base;          // Shift {number} right 1 digit\r
526         }\r
527 \r
528         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of {number}\r
529         if(bSigned)     tmpBuf[pos++] = '-';    // Append sign symbol if needed\r
530         \r
531         i = 0;\r
532         minLength -= pos;\r
533         while(minLength-- > 0)  buf[i++] = pad;\r
534         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters\r
535         buf[i] = 0;\r
536 }\r
537 \r
538 /**\r
539  * \fn EXPORT int printf(const char *format, ...)\r
540  * \brief Print a string to stdout\r
541  */\r
542 EXPORT int printf(const char *format, ...)\r
543 {\r
544         #if 1\r
545          int    size;\r
546         char    sbuf[1024];\r
547         char    *buf = sbuf;\r
548         va_list args;\r
549         \r
550         // Get final size\r
551         va_start(args, format);\r
552         size = vsnprintf(sbuf, 1024, (char*)format, args);\r
553         va_end(args);\r
554         \r
555         if( size >= 1024 ) {\r
556                 // Allocate buffer\r
557                 buf = (char*)malloc(size+1);\r
558                 if(buf) {\r
559                         WRITE_STR(_stdout, "PRINTF ERROR: malloc() failed\n");\r
560                         return 0;\r
561                 }\r
562                 buf[size] = '\0';\r
563         \r
564                 // Fill Buffer\r
565                 va_start(args, format);\r
566                 vsnprintf(buf, size+1, (char*)format, args);\r
567                 va_end(args);\r
568         }\r
569         \r
570         // Send to stdout\r
571         write(_stdout, buf, size+1);\r
572         \r
573         // Free buffer\r
574         free(buf);\r
575         // Return\r
576         return size;\r
577         \r
578         #else\r
579         \r
580          int    ret;\r
581         va_list args;\r
582         va_start(args, format);\r
583         ret = fprintfv(stdout, (char*)format, args);\r
584         va_end(args);\r
585         return ret;\r
586         #endif\r
587 }\r
588 \r
589 /**\r
590  * \fn EXPORT int sprintf(const char *buf, char *format, ...)\r
591  * \brief Print a formatted string to a buffer\r
592  */\r
593 EXPORT int sprintf(char *buf, const char *format, ...)\r
594 {\r
595          int    ret;\r
596         va_list args;\r
597         va_start(args, format);\r
598         ret = vsprintf((char*)buf, (char*)format, args);\r
599         va_end(args);\r
600         return ret;\r
601 }\r
602 \r
603 /**\r
604  * \fn EXPORT int snprintf(const char *buf, size_t maxlen, char *format, ...)\r
605  * \brief Print a formatted string to a buffer\r
606  */\r
607 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)\r
608 {\r
609          int    ret;\r
610         va_list args;\r
611         va_start(args, format);\r
612         ret = vsnprintf((char*)buf, maxlen, (char*)format, args);\r
613         va_end(args);\r
614         return ret;\r
615 }\r

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