X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibc.so_src%2Fstdio.c;h=315f69858770625cfdc961e778eee97c8e0def1f;hb=c7946415abcd9c7a86ecde867d44cb50a249c349;hp=af8f00727a7893a042e21261b4d7c2e4cb1e4cd4;hpb=166ddd4673dc43e28659516b3f521ba357b9ab27;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libc.so_src/stdio.c b/Usermode/Libraries/libc.so_src/stdio.c index af8f0072..315f6985 100644 --- a/Usermode/Libraries/libc.so_src/stdio.c +++ b/Usermode/Libraries/libc.so_src/stdio.c @@ -9,8 +9,8 @@ #include #include "lib.h" #include "stdio_int.h" - -#define WRITE_STR(_fd, _str) write(_fd, _str, sizeof(_str)) +#include +#include #define DEBUG_BUILD 0 @@ -18,8 +18,11 @@ #define _stdin 0 #define _stdout 1 +#define FD_NOTOPEN -1 +#define FD_MEMFILE -2 +#define FD_MEMSTREAM -3 + // === PROTOTYPES === -EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned); struct sFILE *get_file_struct(); // === GLOBALS === @@ -28,8 +31,39 @@ struct sFILE *stdin; // Standard Input struct sFILE *stdout; // Standard Output struct sFILE *stderr; // Standard Error ///\note Initialised in SoMain +static const int STDIN_BUFSIZ = 512; +static const int STDOUT_BUFSIZ = 512; // === CODE === +void _stdio_init(void) +{ + // Init FileIO Pointers + stdin = &_iob[0]; + stdin->FD = 0; + stdin->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_READ|FILE_FLAG_LINEBUFFERED; + stdin->Buffer = malloc(STDIN_BUFSIZ); + stdin->BufferSpace = STDIN_BUFSIZ; + + stdout = &_iob[1]; + stdout->FD = 1; + stdout->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE|FILE_FLAG_LINEBUFFERED; + stdout->Buffer = malloc(STDOUT_BUFSIZ); + stdout->BufferSpace = STDOUT_BUFSIZ; + + stderr = &_iob[2]; + stderr->FD = 2; + stderr->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE; +} + +void _stdio_cleanup(void) +{ + int i; + for( i = 0; i < STDIO_MAX_STREAMS; i ++ ) + { + fclose( &_iob[i] ); + } +} + int _fopen_modetoflags(const char *mode) { int flags = 0; @@ -71,7 +105,7 @@ EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp) // Sanity Check Arguments if(!fp || !file || !mode) return NULL; - if(fp->FD != -1) { + if(fp->FD != FD_NOTOPEN) { fflush(fp); } @@ -108,17 +142,17 @@ EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp) } //Open File - if(fp->FD != -1) - fp->FD = reopen(fp->FD, file, openFlags); + if(fp->FD != FD_NOTOPEN) + fp->FD = _SysReopen(fp->FD, file, openFlags); else - fp->FD = open(file, openFlags); + fp->FD = _SysOpen(file, openFlags); if(fp->FD == -1) { fp->Flags = 0; return NULL; } if( (fp->Flags & FILE_FLAG_MODE_MASK) == FILE_FLAG_MODE_APPEND ) { - seek(fp->FD, 0, SEEK_END); //SEEK_END + _SysSeek(fp->FD, 0, SEEK_END); //SEEK_END } return fp; @@ -150,7 +184,7 @@ EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode) ret = get_file_struct(); - ret->FD = -2; + ret->FD = FD_MEMFILE; ret->Flags = _fopen_modetoflags(mode); if(ret->Flags == -1) { ret->Flags = 0; @@ -158,39 +192,164 @@ EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode) } ret->Buffer = buffer; - ret->BufferStart = 0; - ret->BufferSize = length; + ret->BufferPos = 0; + ret->BufferSpace = length; + + return ret; +} + +EXPORT FILE *open_memstream(char **bufferptr, size_t *lengthptr) +{ + FILE *ret = get_file_struct(); + ret->FD = FD_MEMSTREAM; + ret->Flags = FILE_FLAG_MODE_WRITE; + + ret->Buffer = NULL; + ret->BufferPos = 0; + ret->BufferSpace = 0; + ret->BufPtr = bufferptr; + ret->LenPtr = lengthptr; return ret; } EXPORT int fclose(FILE *fp) { + if( !(fp->Flags & FILE_FLAG_ALLOC) ) + return 0; fflush(fp); - if( fp->FD != -1 ) { - close(fp->FD); + if( fp->FD >= 0 ) { + _SysClose(fp->FD); } fp->Flags = 0; - fp->FD = -1; + fp->FD = FD_NOTOPEN; return 0; } -EXPORT void fflush(FILE *fp) +EXPORT int setvbuf(FILE *fp, char *buffer, int mode, size_t size) { - if( !fp || fp->FD == -1 ) - return ; + if( !fp ) { + errno = EINVAL; + return 1; + } + + // Check for memory files + if( fp->FD == FD_MEMFILE || fp->FD == FD_MEMSTREAM ) { + errno = EINVAL; + return 2; + } + + // Not strictly needed, as this should only be called before any IO + fflush(fp); + + // Eliminate any pre-existing buffer + if( fp->Buffer ) { + free( fp->Buffer ); + fp->Buffer = NULL; + fp->BufferSpace = 0; + fp->BufferPos = 0; + } + + if( mode == _IONBF ) { + // Do nothing, buffering was disabled above + } + else + { + // Sanity check buffering mode before allocating + if( mode != _IOLBF && mode != _IOFBF ) { + errno = EINVAL; + return 1; + } + // Allocate a buffer if one was not provided + if( !buffer ) { + buffer = malloc(size); + assert(buffer); + } + + // Set buffer pointer and size + fp->Buffer = buffer; + fp->BufferSpace = size; + + // Set mode flag + if( mode == _IOLBF ) + fp->Flags |= FILE_FLAG_LINEBUFFERED; + else + fp->Flags &= ~FILE_FLAG_LINEBUFFERED; + } - if( !(fp->Flags & FILE_FLAG_DIRTY) ) + return 0; +} + +int _fflush_int(FILE *fp) +{ + int ret = 0; + size_t len; + + // Check the buffer contains data + if( fp->BufferPos == 0 ) + return 0; + + switch(fp->Flags & FILE_FLAG_MODE_MASK) + { + // Read - Flush input buffer + case FILE_FLAG_MODE_READ: + fp->BufferPos = 0; + break; + + // Append - Seek to end and write + case FILE_FLAG_MODE_APPEND: + _SysSeek(fp->FD, fp->BufferOfs, SEEK_SET); + len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos); + if( len != fp->BufferPos ) + ret = 1; + if( len <= fp->BufferPos ) + { + fp->BufferPos -= len; + } + fp->BufferOfs = _SysTell(fp->FD); + break; + + // Write - Write buffer + case FILE_FLAG_MODE_WRITE: + //_SysDebug("Flushing to %i '%.*s'", fp->FD, fp->BufferPos, fp->Buffer); + len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos); + if( len != fp->BufferPos ) + ret = 1; + if( len <= fp->BufferPos ) + { + fp->BufferPos -= len; + } + //else { + // _SysDebug("Flush of %i failed, %s", fp->FD, strerror(errno)); + //} + break; + default: + break; + } + return ret; +} + +EXPORT void fflush(FILE *fp) +{ + if( !fp || fp->FD == FD_NOTOPEN ) return ; // Nothing to do for memory files - if( fp->FD == -2 ) + if( fp->FD == FD_MEMFILE ) + return ; + // Memory streams, update pointers + if( fp->FD == FD_MEMSTREAM ) { + *fp->BufPtr = fp->Buffer; + *fp->LenPtr = fp->BufferPos; return ; + } + + _fflush_int(fp); } EXPORT void clearerr(FILE *fp) { - if( !fp || fp->FD == -1 ) + if( !fp || fp->FD == FD_NOTOPEN ) return ; // TODO: Impliment clearerr() @@ -198,14 +357,14 @@ EXPORT void clearerr(FILE *fp) EXPORT int feof(FILE *fp) { - if( !fp || fp->FD == -1 ) + if( !fp || fp->FD == FD_NOTOPEN ) return 0; return !!(fp->Flags & FILE_FLAG_EOF); } EXPORT int ferror(FILE *fp) { - if( !fp || fp->FD == -1 ) + if( !fp || fp->FD == FD_NOTOPEN ) return 0; return 0; } @@ -216,115 +375,223 @@ EXPORT int fileno(FILE *stream) EXPORT off_t ftell(FILE *fp) { - if(!fp || fp->FD == -1) return -1; + if(!fp || fp->FD == FD_NOTOPEN) { + errno = EBADF; + return -1; + } - if( fp->FD == -2 ) + if( fp->FD == FD_MEMFILE || fp->FD == FD_MEMSTREAM ) return fp->Pos; else - return tell(fp->FD); + return _SysTell(fp->FD); +} + +int _fseek_memfile(FILE *fp, long int amt, int whence) +{ + switch(whence) + { + case SEEK_CUR: + fp->Pos += amt; + break; + case SEEK_SET: + fp->Pos = amt; + break; + case SEEK_END: + if( fp->BufferSpace < (size_t)amt ) + fp->Pos = 0; + else + fp->Pos = fp->BufferSpace - amt; + break; + } + if(fp->Pos > (off_t)fp->BufferSpace) { + fp->Pos = fp->BufferSpace; + fp->Flags |= FILE_FLAG_EOF; + } + return 0; +} + +int _fseek_memstream(FILE *fp, long int amt, int whence) +{ + switch(whence) + { + case SEEK_CUR: + fp->Pos += amt; + break; + case SEEK_SET: + fp->Pos = amt; + break; + case SEEK_END: + if( fp->BufferSpace < (size_t)amt ) + fp->Pos = 0; + else + fp->Pos = fp->BufferSpace - amt; + break; + } + if(fp->Pos > (off_t)fp->BufferSpace) { + fp->Pos = fp->BufferSpace; + fp->Flags |= FILE_FLAG_EOF; + } + return 0; } EXPORT int fseek(FILE *fp, long int amt, int whence) { - if(!fp || fp->FD == -1) return -1; + if(!fp || fp->FD == FD_NOTOPEN) { + errno = EBADF; + return -1; + } - if( fp->FD == -2 ) { - switch(whence) - { - case SEEK_CUR: - fp->Pos += amt; - break; - case SEEK_SET: - fp->Pos = amt; - break; - case SEEK_END: - if( fp->BufferSize < (size_t)amt ) - fp->Pos = 0; - else - fp->Pos = fp->BufferSize - amt; + if( fp->FD == FD_MEMFILE ) { + return _fseek_memfile(fp, amt, whence); + } + else if( fp->FD == FD_MEMSTREAM ) { + return _fseek_memstream(fp, amt, whence); + } + else { + fflush(fp); + _SysSeek(fp->FD, amt, whence); + fp->Pos = _SysTell(fp->FD); + return 0; + } +} + +size_t _fwrite_unbuffered(FILE *fp, size_t size, size_t num, const void *data) +{ + size_t ret = 0, bytes; + while( num -- ) + { + bytes = _SysWrite(fp->FD, data, size); + if( bytes == (size_t)-1 ) { + // Oops. + // TODO: Set error flag break; } - if(fp->Pos > (off_t)fp->BufferSize) { - fp->Pos = fp->BufferSize; - fp->Flags |= FILE_FLAG_EOF; + if( bytes != size ) { + _SysDebug("_fwrite_unbuffered: Oops, rollback %i/%i bytes!", bytes, size); + _SysSeek(fp->FD, -bytes, SEEK_CUR); + break; } - return 0; + data = (char*)data + size; } - else - return seek(fp->FD, amt, whence); + fp->Pos += ret * size; + return ret; } - -/** - * \fn EXPORT int vfprintf(FILE *fp, const char *format, va_list args) - * \brief Print to a file from a variable argument list - */ -EXPORT int vfprintf(FILE *fp, const char *format, va_list args) +size_t _fwrite_memfile(const void *ptr, size_t size, size_t num, FILE *fp) { - va_list tmpList; - int size; - - if(!fp || !format) return -1; - - va_copy(tmpList, args); - - size = vsnprintf(NULL, 0, (char*)format, tmpList); - char buf[size+1]; - vsnprintf(buf, size+1, (char*)format, args); - - // Write to stream - fwrite(buf, size, 1, fp); - - // Return written byte count - return size; + size_t avail = (fp->BufferSpace - fp->Pos) / size; + if( avail == 0 ) + fp->Flags |= FILE_FLAG_EOF; + if( num > avail ) + num = avail; + size_t bytes = num * size; + memcpy(fp->Buffer + fp->Pos, ptr, bytes); + fp->Pos += bytes; + return num; } -/** - * \fn int fprintf(FILE *fp, const char *format, ...) - * \brief Print a formatted string to a stream - */ -EXPORT int fprintf(FILE *fp, const char *format, ...) +size_t _fwrite_memstream(const void *ptr, size_t size, size_t num, FILE *fp) { - va_list args; - int ret; - - // Get Size - va_start(args, format); - ret = vfprintf(fp, (char*)format, args); - va_end(args); - - return ret; + size_t bytes = size*num; + // #1. Check if we need to expand + if( fp->Pos + bytes > fp->BufferSpace ) + { + void *newbuf = realloc(fp->Buffer, fp->BufferSpace + bytes); + if( !newbuf ) { + errno = ENOMEM; + return -1; + } + fp->Buffer = newbuf; + fp->BufferSpace = fp->Pos + bytes; + } + // #2. Write (use the memfile code for that) + return _fwrite_memfile(ptr, size, num, fp); } /** * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp) * \brief Write to a stream */ -EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp) +EXPORT size_t fwrite(const void *ptr, size_t size, size_t num, FILE *fp) { size_t ret; if(!fp || fp->FD == -1) return -1; + if( size == 0 || num == 0 ) + return 0; - if( fp->FD == -2 ) { - size_t avail = (fp->BufferSize - fp->Pos) / size; - if( avail == 0 ) - fp->Flags |= FILE_FLAG_EOF; - if( num > avail ) num = avail; - size_t bytes = num * size; - memcpy((char*)fp->Buffer + fp->Pos, ptr, bytes); - fp->Pos += bytes; - ret = num; - } - else { - ret = write(fp->FD, ptr, size*num); - ret /= size; + switch( _GetFileMode(fp) ) + { + case FILE_FLAG_MODE_READ: + case FILE_FLAG_MODE_EXEC: + errno = EBADF; + return 0; + case FILE_FLAG_MODE_APPEND: + fseek(fp, 0, SEEK_END); + case FILE_FLAG_MODE_WRITE: + // Handle memory files first + if( fp->FD == FD_MEMFILE ) { + return _fwrite_memfile(ptr, size, num, fp); + } + else if( fp->FD == FD_MEMSTREAM ) { + return _fwrite_memstream(ptr, size, num, fp); + } + else if( fp->BufferSpace ) + { + // Buffering enabled + if( fp->BufferSpace - fp->BufferPos < size*num ) + { + // If there's not enough space, flush and write-through + _fflush_int(fp); // TODO: check ret + ret = _fwrite_unbuffered(fp, size, num, ptr); + } + else if( (fp->Flags & FILE_FLAG_LINEBUFFERED) && memchr(ptr,'\n',size*num) ) + { + // Newline present? Flush though + _fflush_int(fp); // TODO: check ret + ret = _fwrite_unbuffered(fp, size, num, ptr); + } + else + { + // Copy to buffer + memcpy( fp->Buffer + fp->BufferPos, ptr, size*num ); + fp->BufferPos += size*num; + ret = num; + } + } + else + { + // Bufering disabled, write-though + ret = _fwrite_unbuffered(fp, size, num, ptr); + } + // errno should be set earlier + break; } return ret; } +size_t _fread_memfile(void *ptr, size_t size, size_t num, FILE *fp) +{ + size_t avail = (fp->BufferSpace - fp->Pos) / size; + if( avail == 0 ) + fp->Flags |= FILE_FLAG_EOF; + if( num > avail ) num = avail; + size_t bytes = num * size; + memcpy(ptr, fp->Buffer + fp->Pos, bytes); + fp->Pos += bytes; + return num; +} + +#if 0 +size_t _fread_memstream(void *ptr, size_t size, size_t num, FILE *fp) +{ + errno = ENOTIMPL; + return -1; +} +#endif + /** * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) * \brief Read from a stream @@ -335,25 +602,63 @@ EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) if(!fp || fp->FD == -1) return -1; + if( size == 0 || num == 0 ) + return 0; + + if( _GetFileMode(fp) != FILE_FLAG_MODE_READ ) { + errno = 0; + return -1; + } - if( fp->FD == -2 ) { - size_t avail = (fp->BufferSize - fp->Pos) / size; - if( avail == 0 ) - fp->Flags |= FILE_FLAG_EOF; - if( num > avail ) num = avail; - size_t bytes = num * size; - memcpy(ptr, (char*)fp->Buffer + fp->Pos, bytes); - fp->Pos += bytes; - ret = num; + if( fp->FD == FD_MEMFILE ) { + return _fread_memfile(ptr, size, num, fp); } - else { - ret = read(fp->FD, ptr, size*num); - ret /= size; + else if( fp->FD == FD_MEMSTREAM ) { + //return _fread_memstream(ptr, size, num, fp); + errno = EBADF; + return 0; } - + + // Standard file + ret = _SysRead(fp->FD, ptr, size*num); + if( ret == (size_t)-1) + return -1; + if( ret == 0 && size*num > 0 ) { + fp->Flags |= FILE_FLAG_EOF; + return 0; + } + ret /= size; + return ret; } +/** + * \brief Write a string to a stream (without trailing \n) + */ +EXPORT int fputs(const char *s, FILE *fp) +{ + int len = strlen(s); + return fwrite(s, 1, len, fp); +} + +/** + * \brief Read a line (and possible trailing \n into a buffer) + */ +EXPORT char *fgets(char *s, int size, FILE *fp) +{ + int ofs = 0; + char ch = '\0'; + while( ofs < size && ch != '\n' ) + { + if( fread(&ch, 1, 1, fp) != 1 ) + break; + s[ofs ++] = ch; + } + if( ofs < size ) + s[ofs] = '\0'; + return s; +} + /** * \fn EXPORT int fputc(int c, FILE *fp) * \brief Write a single character to the stream @@ -366,7 +671,7 @@ EXPORT int fputc(int c, FILE *fp) EXPORT int putchar(int c) { c &= 0xFF; - return write(_stdout, &c, 1); + return _SysWrite(_stdout, &c, 1); } /** @@ -376,7 +681,7 @@ EXPORT int putchar(int c) EXPORT int fgetc(FILE *fp) { char ret = 0; - if( fread(&ret, 1, 1, fp) == (size_t)-1 ) + if( fread(&ret, 1, 1, fp) != 1 ) return -1; return ret; } @@ -384,10 +689,22 @@ EXPORT int fgetc(FILE *fp) EXPORT int getchar(void) { char ret = 0; - if(read(_stdin, &ret, 1) != 1) return -1; + if(_SysRead(_stdin, &ret, 1) != 1) return -1; return ret; } +EXPORT int puts(const char *str) +{ + int len; + + if(!str) return 0; + len = strlen(str); + + len = _SysWrite(_stdout, str, len); + _SysWrite(_stdout, "\n", 1); + return len; +} + // --- INTERNAL --- /** * \fn FILE *get_file_struct() @@ -408,311 +725,3 @@ FILE *get_file_struct() return NULL; } -EXPORT int puts(const char *str) -{ - int len; - - if(!str) return 0; - len = strlen(str); - - len = write(_stdout, str, len); - write(_stdout, "\n", 1); - return len; -} - -EXPORT int vsprintf(char * __s, const char *__format, va_list __args) -{ - return vsnprintf(__s, 0x7FFFFFFF, __format, __args); -} - -//sprintfv -/** - * \fn EXPORT void vsnprintf(char *buf, const char *format, va_list args) - * \brief Prints a formatted string to a buffer - * \param buf Pointer - Destination Buffer - * \param format String - Format String - * \param args VarArgs List - Arguments - */ -EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args) -{ - char tmp[65]; - int c, minSize, precision, len; - size_t pos = 0; - char *p; - char pad; - uint64_t arg; - int bLongLong, bPadLeft; - - void _addchar(char ch) - { - if(buf && pos < __maxlen) buf[pos] = ch; - pos ++; - } - - tmp[32] = '\0'; - - while((c = *format++) != 0) - { - // Non-control character - if (c != '%') { - _addchar(c); - continue; - } - - // Control Character - c = *format++; - if(c == '%') { // Literal % - _addchar('%'); - continue; - } - - bPadLeft = 0; - bLongLong = 0; - minSize = 0; - precision = -1; - pad = ' '; - - // Padding Character - if(c == '0') { - pad = '0'; - c = *format++; - } - // Padding length - if( c == '*' ) { - // Variable length - minSize = va_arg(args, size_t); - c = *format++; - } - else { - if('1' <= c && c <= '9') - { - minSize = 0; - while('0' <= c && c <= '9') - { - minSize *= 10; - minSize += c - '0'; - c = *format++; - } - } - } - - // Precision - if(c == '.') { - c = *format++; - if(c == '*') { - precision = va_arg(args, size_t); - c = *format++; - } - else if('1' <= c && c <= '9') - { - precision = 0; - while('0' <= c && c <= '9') - { - precision *= 10; - precision += c - '0'; - c = *format++; - } - } - } - - // Check for long long - bLongLong = 0; - if(c == 'l') - { - c = *format++; - if(c == 'l') { - bLongLong = 1; - } - } - - // Just help things along later - p = tmp; - - // Get Type - switch( c ) - { - // Signed Integer - case 'd': case 'i': - // Get Argument - if(bLongLong) arg = va_arg(args, int64_t); - else arg = va_arg(args, int32_t); - itoa(tmp, arg, 10, minSize, pad, 1); - precision = -1; - goto sprintf_puts; - - // Unsigned Integer - case 'u': - // Get Argument - if(bLongLong) arg = va_arg(args, uint64_t); - else arg = va_arg(args, uint32_t); - itoa(tmp, arg, 10, minSize, pad, 0); - precision = -1; - goto sprintf_puts; - - // Pointer - case 'p': - _addchar('*'); - _addchar('0'); - _addchar('x'); - arg = va_arg(args, intptr_t); - itoa(tmp, arg, 16, minSize, pad, 0); - precision = -1; - goto sprintf_puts; - // Unsigned Hexadecimal - case 'x': - if(bLongLong) arg = va_arg(args, uint64_t); - else arg = va_arg(args, uint32_t); - itoa(tmp, arg, 16, minSize, pad, 0); - precision = -1; - goto sprintf_puts; - - // Unsigned Octal - case 'o': - if(bLongLong) arg = va_arg(args, uint64_t); - else arg = va_arg(args, uint32_t); - itoa(tmp, arg, 8, minSize, pad, 0); - precision = -1; - goto sprintf_puts; - - // Unsigned binary - case 'b': - if(bLongLong) arg = va_arg(args, uint64_t); - else arg = va_arg(args, uint32_t); - itoa(tmp, arg, 2, minSize, pad, 0); - precision = -1; - goto sprintf_puts; - - // String - case 's': - p = va_arg(args, char*); - sprintf_puts: - if(!p) p = "(null)"; - //_SysDebug("vsnprintf: p = '%s'", p); - if(precision >= 0) - len = strnlen(p, precision); - else - len = strlen(p); - if(bPadLeft) while(minSize > len++) _addchar(pad); - while( *p ) { - if(precision >= 0 && precision -- == 0) - break; - _addchar(*p++); - } - if(!bPadLeft) while(minSize > len++) _addchar(pad); - break; - - // Unknown, just treat it as a character - default: - arg = va_arg(args, uint32_t); - _addchar(arg); - break; - } - } - _addchar('\0'); - pos --; - - //_SysDebug("vsnprintf: buf = '%s'", buf); - - return pos; -} - -const char cUCDIGITS[] = "0123456789ABCDEF"; -/** - * \fn static void itoa(char *buf, uint64_t num, int base, int minLength, char pad, int bSigned) - * \brief Convert an integer into a character string - * \param buf Destination Buffer - * \param num Number to convert - * \param base Base-n number output - * \param minLength Minimum length of output - * \param pad Padding used to ensure minLength - * \param bSigned Signed number output? - */ -EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned) -{ - char tmpBuf[64]; - int pos=0, i; - - if(!buf) return; - if(base > 16 || base < 2) { - buf[0] = 0; - return; - } - - if(bSigned && (int64_t)num < 0) - { - num = -num; - bSigned = 1; - } else - bSigned = 0; - - // Encode into reversed string - while(num > base-1) { - tmpBuf[pos++] = cUCDIGITS[ num % base ]; - num = (uint64_t) num / (uint64_t)base; // Shift {number} right 1 digit - } - - tmpBuf[pos++] = cUCDIGITS[ num % base ]; // Last digit of {number} - if(bSigned) tmpBuf[pos++] = '-'; // Append sign symbol if needed - - i = 0; - minLength -= pos; - while(minLength-- > 0) buf[i++] = pad; - while(pos-- > 0) buf[i++] = tmpBuf[pos]; // Reverse the order of characters - buf[i] = 0; -} - -/** - * \fn EXPORT int printf(const char *format, ...) - * \brief Print a string to stdout - */ -EXPORT int printf(const char *format, ...) -{ - int size; - va_list args; - - // Get final size - va_start(args, format); - size = vsnprintf(NULL, 0, (char*)format, args); - va_end(args); - char buf[size+1]; - // Fill Buffer - va_start(args, format); - vsnprintf(buf, size+1, (char*)format, args); - va_end(args); - - // Send to stdout - write(_stdout, buf, size+1); - - // Free buffer - free(buf); - // Return - return size; -} - -/** - * \fn EXPORT int sprintf(const char *buf, char *format, ...) - * \brief Print a formatted string to a buffer - */ -EXPORT int sprintf(char *buf, const char *format, ...) -{ - int ret; - va_list args; - va_start(args, format); - ret = vsprintf((char*)buf, (char*)format, args); - va_end(args); - return ret; -} - -/** - * \fn EXPORT int snprintf(const char *buf, size_t maxlen, char *format, ...) - * \brief Print a formatted string to a buffer - */ -EXPORT int snprintf(char *buf, size_t maxlen, const char *format, ...) -{ - int ret; - va_list args; - va_start(args, format); - ret = vsnprintf((char*)buf, maxlen, (char*)format, args); - va_end(args); - return ret; -}