Usermode/libc - scanf/stdio fixes
[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 /**\r
259  * \fn EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
260  * \brief Print to a file from a variable argument list\r
261  */\r
262 EXPORT int vfprintf(FILE *fp, const char *format, va_list args)\r
263 {\r
264         va_list tmpList;\r
265          int    size;\r
266 \r
267         if(!fp || !format)      return -1;\r
268 \r
269         va_copy(tmpList, args);\r
270         \r
271         size = vsnprintf(NULL, 0, (char*)format, tmpList);\r
272         char    buf[size+1];\r
273         vsnprintf(buf, size+1, (char*)format, args);\r
274         \r
275         // Write to stream\r
276         fwrite(buf, size, 1, fp);\r
277         \r
278         // Return written byte count\r
279         return size;\r
280 }\r
281 \r
282 /**\r
283  * \fn int fprintf(FILE *fp, const char *format, ...)\r
284  * \brief Print a formatted string to a stream\r
285  */\r
286 EXPORT int fprintf(FILE *fp, const char *format, ...)\r
287 {\r
288         va_list args;\r
289          int    ret;\r
290         \r
291         // Get Size\r
292         va_start(args, format);\r
293         ret = vfprintf(fp, (char*)format, args);\r
294         va_end(args);\r
295         \r
296         return ret;\r
297 }\r
298 \r
299 /**\r
300  * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)\r
301  * \brief Write to a stream\r
302  */\r
303 EXPORT size_t fwrite(const void *ptr, size_t size, size_t num, FILE *fp)\r
304 {\r
305         size_t  ret;\r
306         \r
307         if(!fp || fp->FD == -1)\r
308                 return -1;\r
309 \r
310         if( fp->FD == -2 ) {\r
311                 size_t  avail = (fp->BufferSize - fp->Pos) / size;\r
312                 if( avail == 0 )\r
313                         fp->Flags |= FILE_FLAG_EOF;\r
314                 if( num > avail )       num = avail;\r
315                 size_t  bytes = num * size;\r
316                 memcpy((char*)fp->Buffer + fp->Pos, ptr, bytes);\r
317                 fp->Pos += bytes;\r
318                 ret = num;\r
319         }\r
320         else {  \r
321                 ret = _SysWrite(fp->FD, ptr, size*num);\r
322                 ret /= size;\r
323         }\r
324         \r
325         return ret;\r
326 }\r
327 \r
328 /**\r
329  * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
330  * \brief Read from a stream\r
331  */\r
332 EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)\r
333 {\r
334         size_t  ret;\r
335         \r
336         if(!fp || fp->FD == -1)\r
337                 return -1;\r
338 \r
339         if( fp->FD == -2 ) {\r
340                 size_t  avail = (fp->BufferSize - fp->Pos) / size;\r
341                 if( avail == 0 )\r
342                         fp->Flags |= FILE_FLAG_EOF;\r
343                 if( num > avail )       num = avail;\r
344                 size_t  bytes = num * size;\r
345                 memcpy(ptr, (char*)fp->Buffer + fp->Pos, bytes);\r
346                 fp->Pos += bytes;\r
347                 ret = num;\r
348         }\r
349         else {\r
350                 ret = _SysRead(fp->FD, ptr, size*num);\r
351                 if( ret == (size_t)-1)\r
352                         return -1;\r
353                 if( ret == 0 && size*num > 0 ) {\r
354                         fp->Flags |= FILE_FLAG_EOF;\r
355                         return 0;\r
356                 }\r
357                 ret /= size;\r
358         }\r
359                 \r
360         return ret;\r
361 }\r
362 \r
363 /**\r
364  * \brief Write a string to a stream (without trailing \n)\r
365  */\r
366 EXPORT int fputs(const char *s, FILE *fp)\r
367 {\r
368         int len = strlen(s);\r
369         return fwrite(s, 1, len, fp);\r
370 }\r
371 \r
372 /**\r
373  * \brief Read a line (and possible trailing \n into a buffer)\r
374  */\r
375 EXPORT char *fgets(char *s, int size, FILE *fp)\r
376 {\r
377         int ofs = 0;\r
378         char    ch = '\0';\r
379         while( ofs < size && ch != '\n' )\r
380         {\r
381                 if( fread(&ch, 1, 1, fp) != 1 )\r
382                         break;\r
383                 s[ofs ++] = ch;\r
384         }\r
385         if( ofs < size )\r
386                 s[ofs] = '\0';\r
387         return s;\r
388 }\r
389 \r
390 /**\r
391  * \fn EXPORT int fputc(int c, FILE *fp)\r
392  * \brief Write a single character to the stream\r
393  */\r
394 EXPORT int fputc(int c, FILE *fp)\r
395 {\r
396         return fwrite(&c, 1, 1, fp);\r
397 }\r
398 \r
399 EXPORT int putchar(int c)\r
400 {\r
401         c &= 0xFF;\r
402         return _SysWrite(_stdout, &c, 1);\r
403 }\r
404 \r
405 /**\r
406  * \fn EXPORT int fgetc(FILE *fp)\r
407  * \brief Read a character from the stream\r
408  */\r
409 EXPORT int fgetc(FILE *fp)\r
410 {\r
411         char    ret = 0;\r
412         if( fread(&ret, 1, 1, fp) != 1 )\r
413                 return -1;\r
414         return ret;\r
415 }\r
416 \r
417 EXPORT int getchar(void)\r
418 {\r
419         char    ret = 0;\r
420         if(_SysRead(_stdin, &ret, 1) != 1)      return -1;\r
421         return ret;\r
422 }\r
423 \r
424 // --- INTERNAL ---\r
425 /**\r
426  * \fn FILE *get_file_struct()\r
427  * \brief Returns a file descriptor structure\r
428  */\r
429 FILE *get_file_struct()\r
430 {\r
431          int    i;\r
432         for(i=0;i<STDIO_MAX_STREAMS;i++)\r
433         {\r
434                 if(_iob[i].Flags & FILE_FLAG_ALLOC)\r
435                         continue ;\r
436                 _iob[i].Flags |= FILE_FLAG_ALLOC;\r
437                 _iob[i].FD = -1;\r
438                 _iob[i].Pos = 0;\r
439                 return &_iob[i];\r
440         }\r
441         return NULL;\r
442 }\r
443 \r
444 EXPORT int puts(const char *str)\r
445 {\r
446          int    len;\r
447         \r
448         if(!str)        return 0;\r
449         len = strlen(str);\r
450         \r
451         len = _SysWrite(_stdout, str, len);\r
452         _SysWrite(_stdout, "\n", 1);\r
453         return len;\r
454 }\r
455 \r
456 EXPORT int vsprintf(char * __s, const char *__format, va_list __args)\r
457 {\r
458         return vsnprintf(__s, 0x7FFFFFFF, __format, __args);\r
459 }\r
460 \r
461 //sprintfv\r
462 /**\r
463  * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args)\r
464  * \brief Prints a formatted string to a buffer\r
465  * \param buf   Pointer - Destination Buffer\r
466  * \param format        String - Format String\r
467  * \param args  VarArgs List - Arguments\r
468  */\r
469 EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args)\r
470 {\r
471         char    tmp[65];\r
472          int    c, minSize, precision, len;\r
473         size_t  pos = 0;\r
474         char    *p;\r
475         char    pad;\r
476         uint64_t        arg;\r
477          int    bLongLong, bPadLeft;\r
478 \r
479         void _addchar(char ch)\r
480         {\r
481                 if(buf && pos < __maxlen)       buf[pos] = ch;\r
482                 pos ++;\r
483         }\r
484 \r
485         tmp[32] = '\0';\r
486         \r
487         while((c = *format++) != 0)\r
488         {\r
489                 // Non-control character\r
490                 if (c != '%') {\r
491                         _addchar(c);\r
492                         continue;\r
493                 }\r
494                 \r
495                 // Control Character\r
496                 c = *format++;\r
497                 if(c == '%') {  // Literal %\r
498                         _addchar('%');\r
499                         continue;\r
500                 }\r
501                 \r
502                 bPadLeft = 0;\r
503                 bLongLong = 0;\r
504                 minSize = 0;\r
505                 precision = -1;\r
506                 pad = ' ';\r
507                 \r
508                 // Padding Character\r
509                 if(c == '0') {\r
510                         pad = '0';\r
511                         c = *format++;\r
512                 }\r
513                 // Padding length\r
514                 if( c == '*' ) {\r
515                         // Variable length\r
516                         minSize = va_arg(args, size_t);\r
517                         c = *format++;\r
518                 }\r
519                 else {\r
520                         if('1' <= c && c <= '9')\r
521                         {\r
522                                 minSize = 0;\r
523                                 while('0' <= c && c <= '9')\r
524                                 {\r
525                                         minSize *= 10;\r
526                                         minSize += c - '0';\r
527                                         c = *format++;\r
528                                 }\r
529                         }\r
530                 }\r
531 \r
532                 // Precision\r
533                 if(c == '.') {\r
534                         c = *format++;\r
535                         if(c == '*') {\r
536                                 precision = va_arg(args, size_t);\r
537                                 c = *format++;\r
538                         }\r
539                         else if('1' <= c && c <= '9')\r
540                         {\r
541                                 precision = 0;\r
542                                 while('0' <= c && c <= '9')\r
543                                 {\r
544                                         precision *= 10;\r
545                                         precision += c - '0';\r
546                                         c = *format++;\r
547                                 }\r
548                         }\r
549                 }\r
550         \r
551                 // Check for long long\r
552                 bLongLong = 0;\r
553                 if(c == 'l')\r
554                 {\r
555                         c = *format++;\r
556                         if(c == 'l') {\r
557                                 bLongLong = 1;\r
558                         }\r
559                 }\r
560                 \r
561                 // Just help things along later\r
562                 p = tmp;\r
563                 \r
564                 // Get Type\r
565                 switch( c )\r
566                 {\r
567                 // Signed Integer\r
568                 case 'd':       case 'i':\r
569                         // Get Argument\r
570                         if(bLongLong)   arg = va_arg(args, int64_t);\r
571                         else                    arg = va_arg(args, int32_t);\r
572                         itoa(tmp, arg, 10, minSize, pad, 1);\r
573                         precision = -1;\r
574                         goto sprintf_puts;\r
575                 \r
576                 // Unsigned Integer\r
577                 case 'u':\r
578                         // Get Argument\r
579                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
580                         else                    arg = va_arg(args, uint32_t);\r
581                         itoa(tmp, arg, 10, minSize, pad, 0);\r
582                         precision = -1;\r
583                         goto sprintf_puts;\r
584                 \r
585                 // Pointer\r
586                 case 'p':\r
587                         _addchar('*');\r
588                         _addchar('0');\r
589                         _addchar('x');\r
590                         arg = va_arg(args, intptr_t);\r
591                         itoa(tmp, arg, 16, minSize, pad, 0);\r
592                         precision = -1;\r
593                         goto sprintf_puts;\r
594                 // Unsigned Hexadecimal\r
595                 case 'x':\r
596                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
597                         else                    arg = va_arg(args, uint32_t);\r
598                         itoa(tmp, arg, 16, minSize, pad, 0);\r
599                         precision = -1;\r
600                         goto sprintf_puts;\r
601                 \r
602                 // Unsigned Octal\r
603                 case 'o':\r
604                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
605                         else                    arg = va_arg(args, uint32_t);\r
606                         itoa(tmp, arg, 8, minSize, pad, 0);\r
607                         precision = -1;\r
608                         goto sprintf_puts;\r
609                 \r
610                 // Unsigned binary\r
611                 case 'b':\r
612                         if(bLongLong)   arg = va_arg(args, uint64_t);\r
613                         else                    arg = va_arg(args, uint32_t);\r
614                         itoa(tmp, arg, 2, minSize, pad, 0);\r
615                         precision = -1;\r
616                         goto sprintf_puts;\r
617 \r
618                 // String\r
619                 case 's':\r
620                         p = va_arg(args, char*);\r
621                 sprintf_puts:\r
622                         if(!p)  p = "(null)";\r
623                         //_SysDebug("vsnprintf: p = '%s'", p);\r
624                         if(precision >= 0)\r
625                                 len = strnlen(p, precision);\r
626                         else\r
627                                 len = strlen(p);\r
628                         if(bPadLeft)    while(minSize > len++)  _addchar(pad);\r
629                         while( *p ) {\r
630                                 if(precision >= 0 && precision -- == 0)\r
631                                         break;\r
632                                 _addchar(*p++);\r
633                         }\r
634                         if(!bPadLeft)   while(minSize > len++)  _addchar(pad);\r
635                         break;\r
636 \r
637                 // Unknown, just treat it as a character\r
638                 default:\r
639                         arg = va_arg(args, uint32_t);\r
640                         _addchar(arg);\r
641                         break;\r
642                 }\r
643         }\r
644         _addchar('\0');\r
645         pos --;\r
646         \r
647         //_SysDebug("vsnprintf: buf = '%s'", buf);\r
648         \r
649         return pos;\r
650 }\r
651 \r
652 const char cUCDIGITS[] = "0123456789ABCDEF";\r
653 /**\r
654  * \fn static void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned)\r
655  * \brief Convert an integer into a character string\r
656  * \param buf   Destination Buffer\r
657  * \param num   Number to convert\r
658  * \param base  Base-n number output\r
659  * \param minLength     Minimum length of output\r
660  * \param pad   Padding used to ensure minLength\r
661  * \param bSigned       Signed number output?\r
662  */\r
663 EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned)\r
664 {\r
665         char    tmpBuf[64];\r
666          int    pos=0, i;\r
667 \r
668         if(!buf)        return;\r
669         if(base > 16 || base < 2) {\r
670                 buf[0] = 0;\r
671                 return;\r
672         }\r
673         \r
674         if(bSigned && (int64_t)num < 0)\r
675         {\r
676                 num = -num;\r
677                 bSigned = 1;\r
678         } else\r
679                 bSigned = 0;\r
680         \r
681         // Encode into reversed string\r
682         while(num > base-1) {\r
683                 tmpBuf[pos++] = cUCDIGITS[ num % base ];\r
684                 num = (uint64_t) num / (uint64_t)base;          // Shift {number} right 1 digit\r
685         }\r
686 \r
687         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of {number}\r
688         if(bSigned)     tmpBuf[pos++] = '-';    // Append sign symbol if needed\r
689         \r
690         i = 0;\r
691         minLength -= pos;\r
692         while(minLength-- > 0)  buf[i++] = pad;\r
693         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters\r
694         buf[i] = 0;\r
695 }\r
696 \r
697 /**\r
698  * \fn EXPORT int printf(const char *format, ...)\r
699  * \brief Print a string to stdout\r
700  */\r
701 EXPORT int printf(const char *format, ...)\r
702 {\r
703          int    size;\r
704         va_list args;\r
705         \r
706         // Get final size\r
707         va_start(args, format);\r
708         size = vsnprintf(NULL, 0, (char*)format, args);\r
709         va_end(args);\r
710         char buf[size+1];\r
711         // Fill Buffer\r
712         va_start(args, format);\r
713         vsnprintf(buf, size+1, (char*)format, args);\r
714         va_end(args);\r
715         \r
716         // Send to stdout\r
717         _SysWrite(_stdout, buf, size+1);\r
718         \r
719         // Free buffer\r
720         free(buf);\r
721         // Return\r
722         return size;\r
723 }\r
724 \r
725 /**\r
726  * \fn EXPORT int sprintf(const char *buf, char *format, ...)\r
727  * \brief Print a formatted string to a buffer\r
728  */\r
729 EXPORT int sprintf(char *buf, const char *format, ...)\r
730 {\r
731          int    ret;\r
732         va_list args;\r
733         va_start(args, format);\r
734         ret = vsprintf((char*)buf, (char*)format, args);\r
735         va_end(args);\r
736         return ret;\r
737 }\r
738 \r
739 /**\r
740  * \fn EXPORT int snprintf(const char *buf, size_t maxlen, char *format, ...)\r
741  * \brief Print a formatted string to a buffer\r
742  */\r
743 EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...)\r
744 {\r
745          int    ret;\r
746         va_list args;\r
747         va_start(args, format);\r
748         ret = vsnprintf((char*)buf, maxlen, (char*)format, args);\r
749         va_end(args);\r
750         return ret;\r
751 }\r

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