Fixed correctness in stdio, minor changes in ls to handle dirs with negative sizes
[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 DEBUG_BUILD     0\r
14 \r
15 // === CONSTANTS ===\r
16 #define _stdin  0\r
17 #define _stdout 1\r
18 \r
19 // === PROTOTYPES ===\r
20 EXPORT void     itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned);\r
21 struct sFILE    *get_file_struct();\r
22 \r
23 // === GLOBALS ===\r
24 struct sFILE    _iob[STDIO_MAX_STREAMS];        // IO Buffer\r
25 struct sFILE    *stdin; // Standard Input\r
26 struct sFILE    *stdout;        // Standard Output\r
27 struct sFILE    *stderr;        // Standard Error\r
28 ///\note Initialised in SoMain\r
29 \r
30 // === CODE ===\r
31 /**\r
32  * \fn FILE *freopen(FILE *fp, char *file, char *mode)\r
33  */\r
34 EXPORT FILE *freopen(FILE *fp, char *file, char *mode)\r
35 {\r
36          int    openFlags = 0;\r
37          int    i;\r
38         \r
39         // Sanity Check Arguments\r
40         if(!fp || !file || !mode)       return NULL;\r
41         \r
42         if(fp->Flags) {\r
43                 fflush(fp);\r
44                 close(fp->FD);\r
45         }\r
46         \r
47         // Get main mode\r
48         switch(mode[0])\r
49         {\r
50         case 'r':       fp->Flags = FILE_FLAG_MODE_READ;        break;\r
51         case 'w':       fp->Flags = FILE_FLAG_MODE_WRITE;       break;\r
52         case 'a':       fp->Flags = FILE_FLAG_MODE_APPEND;      break;\r
53         case 'x':       fp->Flags = FILE_FLAG_MODE_EXEC;        break;\r
54         default:\r
55                 return NULL;\r
56         }\r
57         // Get Modifiers\r
58         for(i=1;mode[i];i++)\r
59         {\r
60                 switch(mode[i])\r
61                 {\r
62                 case '+':       fp->Flags |= FILE_FLAG_M_EXT;\r
63                 }\r
64         }\r
65         \r
66         // Get Open Flags\r
67         switch(mode[0])\r
68         {\r
69         // Read\r
70         case 'r':       openFlags = OPENFLAG_READ;\r
71                 if(fp->Flags & FILE_FLAG_M_EXT)\r
72                         openFlags |= OPENFLAG_WRITE;\r
73                 break;\r
74         // Write\r
75         case 'w':       openFlags = OPENFLAG_WRITE;\r
76                 if(fp->Flags & FILE_FLAG_M_EXT)\r
77                         openFlags |= OPENFLAG_READ;\r
78                 break;\r
79         // Execute\r
80         case 'x':       openFlags = OPENFLAG_EXEC;\r
81                 break;\r
82         }\r
83         \r
84         //Open File\r
85         fp->FD = reopen(fp->FD, file, openFlags);\r
86         if(fp->FD == -1) {\r
87                 fp->Flags = 0;\r
88                 return NULL;\r
89         }\r
90         \r
91         if(mode[0] == 'a') {\r
92                 seek(fp->FD, 0, SEEK_END);      //SEEK_END\r
93         }\r
94         \r
95         return fp;\r
96 }\r
97 /**\r
98  \fn FILE *fopen(char *file, char *mode)\r
99  \brief Opens a file and returns the pointer\r
100  \param file    String - Filename to open\r
101  \param mode    Mode to open in\r
102 */\r
103 EXPORT FILE *fopen(char *file, char *mode)\r
104 {\r
105         FILE    *retFile;\r
106         \r
107         // Sanity Check Arguments\r
108         if(!file || !mode)      return NULL;\r
109         \r
110         // Create Return Structure\r
111         retFile = get_file_struct();\r
112         \r
113         return freopen(retFile, file, mode);\r
114 }\r
115 \r
116 EXPORT void fclose(FILE *fp)\r
117 {\r
118         close(fp->FD);\r
119         free(fp);\r
120 }\r
121 \r
122 EXPORT void fflush(FILE *fp)\r
123 {\r
124         ///\todo Implement\r
125 }\r
126 \r
127 /**\r
128  * \fn EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
129  * \brief Print to a file from a variable argument list\r
130  */\r
131 EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
132 {\r
133         va_list tmpList = args;\r
134          int    size;\r
135         char    *buf;\r
136          \r
137         if(!fp || !format)      return -1;\r
138         \r
139         size = vsprintf(NULL, (char*)format, tmpList);\r
140         \r
141         buf = (char*)malloc(size+1);\r
142         buf[size] = '\0';\r
143         \r
144         // Print\r
145         vsprintf(buf, (char*)format, args);\r
146         \r
147         // Write to stream\r
148         write(fp->FD, size+1, buf);\r
149         \r
150         // Free buffer\r
151         free(buf);\r
152         \r
153         // Return written byte count\r
154         return size;\r
155 }\r
156 \r
157 /**\r
158  * \fn int fprintf(FILE *fp, const char *format, ...)\r
159  * \brief Print a formatted string to a stream\r
160  */\r
161 EXPORT int fprintf(FILE *fp, const char *format, ...)\r
162 {\r
163         va_list args;\r
164          int    ret;\r
165         \r
166         // Get Size\r
167         va_start(args, format);\r
168         ret = vfprintf(fp, (char*)format, args);\r
169         va_end(args);\r
170         \r
171         return ret;\r
172 }\r
173 \r
174 /**\r
175  */\r
176 EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
177 {\r
178          int    ret;\r
179         if(!fp || !fp->FD)      return -1;\r
180         \r
181         ret = write(fp->FD, size*num, ptr);\r
182         \r
183         return ret;\r
184 }\r
185 \r
186 /**\r
187  * \fn EXPORT int fputc(int c, FILE *fp)\r
188  * \brief Write a single character to the stream\r
189  */\r
190 EXPORT int fputc(int c, FILE *fp)\r
191 {\r
192         if(!fp || !fp->FD)      return -1;\r
193         return write(fp->FD, 1, &c);\r
194 }\r
195 \r
196 /**\r
197  * \fn EXPORT int fgetc(FILE *fp)\r
198  * \brief Read a character from the stream\r
199  */\r
200 EXPORT int fgetc(FILE *fp)\r
201 {\r
202          int    ret = 0;\r
203         if(!fp) return -1;\r
204         if(read(fp->FD, 1, &ret) == -1) return -1;\r
205         return ret;\r
206 }\r
207 \r
208 // --- INTERNAL ---\r
209 /**\r
210  * \fn FILE *get_file_struct()\r
211  * \brief Returns a file descriptor structure\r
212  */\r
213 FILE *get_file_struct()\r
214 {\r
215          int    i;\r
216         for(i=0;i<STDIO_MAX_STREAMS;i++)\r
217         {\r
218                 if(_iob[i].Flags == 0)  return &_iob[i];\r
219         }\r
220         return NULL;\r
221 }\r
222 \r
223 EXPORT int putchar(int ch)\r
224 {\r
225         return write(_stdout, 1, (char*)&ch);\r
226 }\r
227 \r
228 EXPORT int      puts(const char *str)\r
229 {\r
230          int    len;\r
231         \r
232         if(!str)        return 0;\r
233         len = strlen(str);\r
234         \r
235         len = write(_stdout, len, (char*)str);\r
236         write(_stdout, 1, "\n");\r
237         return len;\r
238 }\r
239 \r
240 //sprintfv\r
241 /**\r
242  \fn EXPORT void vsprintf(char *buf, const char *format, va_list args)\r
243  \brief Prints a formatted string to a buffer\r
244  \param buf     Pointer - Destination Buffer\r
245  \param format  String - Format String\r
246  \param args    VarArgs List - Arguments\r
247 */\r
248 EXPORT int vsprintf(char *buf, const char *format, va_list args)\r
249 {\r
250         char    tmp[33];\r
251          int    c, minSize;\r
252          int    pos = 0;\r
253         char    *p;\r
254         char    pad;\r
255         uint64_t        arg;\r
256          int    bLongLong;\r
257 \r
258         tmp[32] = '\0';\r
259         \r
260         while((c = *format++) != 0)\r
261         {\r
262                 // Non-control character\r
263                 if (c != '%') {\r
264                         if(buf) buf[pos] = c;\r
265                         pos ++;\r
266                         continue;\r
267                 }\r
268                 \r
269                 // Control Character\r
270                 c = *format++;\r
271                 if(c == '%') {  // Literal %\r
272                         if(buf) buf[pos] = '%';\r
273                         pos ++;\r
274                         continue;\r
275                 }\r
276                 \r
277                 // Padding\r
278                 if(c == '0') {\r
279                         pad = '0';\r
280                         c = *format++;\r
281                 } else\r
282                         pad = ' ';\r
283                 minSize = 0;\r
284                 if('1' <= c && c <= '9')\r
285                 {\r
286                         while('0' <= c && c <= '9')\r
287                         {\r
288                                 minSize *= 10;\r
289                                 minSize += c - '0';\r
290                                 c = *format++;\r
291                         }\r
292                 }\r
293         \r
294                 // Check for long long\r
295                 bLongLong = 0;\r
296                 if(c == 'l')\r
297                 {\r
298                         c = *format++;\r
299                         if(c == 'l') {\r
300                                 bLongLong = 1;\r
301                         }\r
302                 }\r
303                         \r
304                 p = tmp;\r
305                 \r
306                 // Get Type\r
307                 switch( c )\r
308                 {\r
309                 // Signed Integer\r
310                 case 'd':       case 'i':\r
311                         // Get Argument\r
312                         if(bLongLong)   arg = va_arg(args, int64_t);\r
313                         else                    arg = va_arg(args, int32_t);\r
314                         itoa(tmp, arg, 10, minSize, pad, 1);\r
315                         goto sprintf_puts;\r
316                 \r
317                 // Unsigned Integer\r
318                 case 'u':\r
319                         // Get Argument\r
320                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
321                         else                    arg = va_arg(args, uint32_t);\r
322                         itoa(tmp, arg, 10, minSize, pad, 0);\r
323                         goto sprintf_puts;\r
324                 \r
325                 // Pointer\r
326                 case 'p':\r
327                         if(buf) {\r
328                                 buf[pos] = '*';\r
329                                 buf[pos+1] = '0';\r
330                                 buf[pos+2] = 'x';\r
331                         }\r
332                         pos += 3;\r
333                         // Fall through to hex\r
334                 // Unsigned Hexadecimal\r
335                 case 'x':\r
336                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
337                         else                    arg = va_arg(args, uint32_t);\r
338                         itoa(tmp, arg, 16, minSize, pad, 0);\r
339                         goto sprintf_puts;\r
340                 \r
341                 // Unsigned Octal\r
342                 case 'o':\r
343                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
344                         else                    arg = va_arg(args, uint32_t);\r
345                         itoa(tmp, arg, 8, minSize, pad, 0);\r
346                         goto sprintf_puts;\r
347                 \r
348                 // Unsigned binary\r
349                 case 'b':\r
350                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
351                         else                    arg = va_arg(args, uint32_t);\r
352                         itoa(tmp, arg, 2, minSize, pad, 0);\r
353                         goto sprintf_puts;\r
354 \r
355                 // String\r
356                 case 's':\r
357                         arg = va_arg(args, uint32_t);\r
358                         p = (void*)(intptr_t)arg;\r
359                 sprintf_puts:\r
360                         if(!p)  p = "(null)";\r
361                         if(buf) {\r
362                                 while(*p) {\r
363                                         buf[pos++] = *p++;\r
364                                 }\r
365                         }\r
366                         else {\r
367                                 while(*p) {\r
368                                         pos++; p++;\r
369                                 }\r
370                         }\r
371                         break;\r
372 \r
373                 // Unknown, just treat it as a character\r
374                 default:\r
375                         arg = va_arg(args, uint32_t);\r
376                         if(buf) buf[pos] = arg;\r
377                         pos ++;\r
378                         break;\r
379                 }\r
380     }\r
381         if(buf) buf[pos] = '\0';\r
382         \r
383         return pos;\r
384 }\r
385 \r
386 const char cUCDIGITS[] = "0123456789ABCDEF";\r
387 /**\r
388  * \fn static void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned)\r
389  * \brief Convert an integer into a character string\r
390  */\r
391 EXPORT void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned)\r
392 {\r
393         char    tmpBuf[32];\r
394          int    pos=0, i;\r
395 \r
396         if(!buf)        return;\r
397         if(base > 16) {\r
398                 buf[0] = 0;\r
399                 return;\r
400         }\r
401         \r
402         if(bSigned && (int64_t)num < 0)\r
403         {\r
404                 num = -num;\r
405                 bSigned = 1;\r
406         } else\r
407                 bSigned = 0;\r
408         \r
409         while(num > base-1) {\r
410                 tmpBuf[pos] = cUCDIGITS[ num % base ];\r
411                 num = (long) num / base;                // Shift {number} right 1 digit\r
412                 pos++;\r
413         }\r
414 \r
415         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of {number}\r
416         if(bSigned)     tmpBuf[pos++] = '-';    // Append sign symbol if needed\r
417         i = 0;\r
418         minLength -= pos;\r
419         while(minLength-- > 0)  buf[i++] = pad;\r
420         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters\r
421         buf[i] = 0;\r
422 }\r
423 \r
424 /**\r
425  * \fn EXPORT int printf(const char *format, ...)\r
426  * \brief Print a string to stdout\r
427  */\r
428 EXPORT int printf(const char *format, ...)\r
429 {\r
430         #if 1\r
431          int    size;\r
432         char    *buf;\r
433         va_list args;\r
434         \r
435         // Get final size\r
436         va_start(args, format);\r
437         size = vsprintf(NULL, (char*)format, args);\r
438         va_end(args);\r
439         \r
440         // Allocate buffer\r
441         buf = (char*)malloc(size+1);\r
442         buf[size] = '\0';\r
443         \r
444         // Fill Buffer\r
445         va_start(args, format);\r
446         vsprintf(buf, (char*)format, args);\r
447         va_end(args);\r
448         \r
449         // Send to stdout\r
450         write(_stdout, size+1, buf);\r
451         \r
452         // Free buffer\r
453         free(buf);\r
454         // Return\r
455         return size;\r
456         \r
457         #else\r
458         \r
459          int    ret;\r
460         va_list args;\r
461         va_start(args, format);\r
462         ret = fprintfv(stdout, (char*)format, args);\r
463         va_end(args);\r
464         return ret;\r
465         #endif\r
466 }\r
467 \r
468 /**\r
469  * \fn EXPORT int sprintf(const char *buf, char *format, ...)\r
470  * \brief Print a formatted string to a buffer\r
471  */\r
472 EXPORT int sprintf(char *buf, const char *format, ...)\r
473 {\r
474          int    ret;\r
475         va_list args;\r
476         va_start(args, format);\r
477         ret = vsprintf((char*)buf, (char*)format, args);\r
478         va_end(args);\r
479         return ret;\r
480 }\r

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