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

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