X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibc.so_src%2FfileIO.c;h=af8f00727a7893a042e21261b4d7c2e4cb1e4cd4;hb=0eb50bc9e604f654bdb0409bb66da03b733f906c;hp=be6f80b229974299f07b6a8057037cdd667c9721;hpb=17e16b3110b4c5124b0707435e0427993d696545;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libc.so_src/fileIO.c b/Usermode/Libraries/libc.so_src/fileIO.c index be6f80b2..af8f0072 100644 --- a/Usermode/Libraries/libc.so_src/fileIO.c +++ b/Usermode/Libraries/libc.so_src/fileIO.c @@ -1,96 +1,135 @@ /* -AcessOS Basic C Library -*/ + * AcessOS Basic C Library + * stdio.c + */ #include "config.h" #include #include #include +#include +#include "lib.h" #include "stdio_int.h" +#define WRITE_STR(_fd, _str) write(_fd, _str, sizeof(_str)) + #define DEBUG_BUILD 0 // === CONSTANTS === +#define _stdin 0 +#define _stdout 1 // === PROTOTYPES === +EXPORT void itoa(char *buf, uint64_t num, size_t base, int minLength, char pad, int bSigned); struct sFILE *get_file_struct(); // === GLOBALS === struct sFILE _iob[STDIO_MAX_STREAMS]; // IO Buffer +struct sFILE *stdin; // Standard Input +struct sFILE *stdout; // Standard Output +struct sFILE *stderr; // Standard Error +///\note Initialised in SoMain // === CODE === -/** - * \fn FILE *freopen(FILE *fp, char *file, char *mode) - */ -FILE *freopen(FILE *fp, char *file, char *mode) +int _fopen_modetoflags(const char *mode) { - int openFlags = 0; - int i; - - // Sanity Check Arguments - if(!fp || !file || !mode) return NULL; - - if(fp->Flags) { - fflush(fp); - close(fp->FD); - } + int flags = 0; // Get main mode - switch(mode[0]) + switch(*mode) { - case 'r': fp->Flags = FILE_FLAG_MODE_READ; break; - case 'w': fp->Flags = FILE_FLAG_MODE_WRITE; break; - case 'a': fp->Flags = FILE_FLAG_MODE_APPEND; break; - case 'x': fp->Flags = FILE_FLAG_MODE_EXEC; break; + case 'r': flags = FILE_FLAG_MODE_READ; break; + case 'w': flags = FILE_FLAG_MODE_WRITE; break; + case 'a': flags = FILE_FLAG_MODE_APPEND; break; + case 'x': flags = FILE_FLAG_MODE_EXEC; break; // Acess addon default: - return NULL; + return -1; } + mode ++; + // Get Modifiers - for(i=1;mode[i];i++) + for( ; *mode; mode ++ ) { - switch(mode[i]) + switch(*mode) { - case '+': fp->Flags |= FILE_FLAG_M_EXT; + case 'b': flags |= FILE_FLAG_M_BINARY; break; + case '+': flags |= FILE_FLAG_M_EXT; break; + default: + return -1; } } + return flags; +} + +/** + * \fn FILE *freopen(char *file, char *mode, FILE *fp) + */ +EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp) +{ + int openFlags = 0; + + // Sanity Check Arguments + if(!fp || !file || !mode) return NULL; + + if(fp->FD != -1) { + fflush(fp); + } + + // Get stdio flags + fp->Flags = _fopen_modetoflags(mode); + if(fp->Flags == -1) + return NULL; + // Get Open Flags - switch(mode[0]) + switch(fp->Flags & FILE_FLAG_MODE_MASK) { // Read - case 'r': openFlags = OPENFLAG_READ; + case FILE_FLAG_MODE_READ: + openFlags = OPENFLAG_READ; if(fp->Flags & FILE_FLAG_M_EXT) openFlags |= OPENFLAG_WRITE; break; // Write - case 'w': openFlags = OPENFLAG_WRITE; + case FILE_FLAG_MODE_WRITE: + openFlags = OPENFLAG_WRITE; + if(fp->Flags & FILE_FLAG_M_EXT) + openFlags |= OPENFLAG_READ; + break; + // Execute + case FILE_FLAG_MODE_APPEND: + openFlags = OPENFLAG_APPEND; if(fp->Flags & FILE_FLAG_M_EXT) openFlags |= OPENFLAG_READ; break; // Execute - case 'x': openFlags = OPENFLAG_EXEC; + case FILE_FLAG_MODE_EXEC: + openFlags = OPENFLAG_EXEC; break; } - + //Open File - fp->FD = reopen(fp->FD, file, openFlags); + if(fp->FD != -1) + fp->FD = reopen(fp->FD, file, openFlags); + else + fp->FD = open(file, openFlags); if(fp->FD == -1) { fp->Flags = 0; return NULL; } - if(mode[0] == 'a') { + if( (fp->Flags & FILE_FLAG_MODE_MASK) == FILE_FLAG_MODE_APPEND ) { seek(fp->FD, 0, SEEK_END); //SEEK_END } return fp; } /** - \fn FILE *fopen(char *file, char *mode) + \fn FILE *fopen(const char *file, const char *mode) \brief Opens a file and returns the pointer \param file String - Filename to open \param mode Mode to open in */ -FILE *fopen(char *file, char *mode) +EXPORT FILE *fopen(const char *file, const char *mode) { FILE *retFile; @@ -100,54 +139,253 @@ FILE *fopen(char *file, char *mode) // Create Return Structure retFile = get_file_struct(); - return freopen(retFile, file, mode); + return freopen(file, mode, retFile); +} + +EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode) +{ + FILE *ret; + + if( !buffer || !mode ) return NULL; + + ret = get_file_struct(); + + ret->FD = -2; + ret->Flags = _fopen_modetoflags(mode); + if(ret->Flags == -1) { + ret->Flags = 0; + return NULL; + } + + ret->Buffer = buffer; + ret->BufferStart = 0; + ret->BufferSize = length; + + return ret; +} + +EXPORT int fclose(FILE *fp) +{ + fflush(fp); + if( fp->FD != -1 ) { + close(fp->FD); + } + fp->Flags = 0; + fp->FD = -1; + return 0; +} + +EXPORT void fflush(FILE *fp) +{ + if( !fp || fp->FD == -1 ) + return ; + + if( !(fp->Flags & FILE_FLAG_DIRTY) ) + return ; + + // Nothing to do for memory files + if( fp->FD == -2 ) + return ; +} + +EXPORT void clearerr(FILE *fp) +{ + if( !fp || fp->FD == -1 ) + return ; + + // TODO: Impliment clearerr() } -void fclose(FILE *fp) +EXPORT int feof(FILE *fp) { - close(fp->FD); - free(fp); + if( !fp || fp->FD == -1 ) + return 0; + return !!(fp->Flags & FILE_FLAG_EOF); } -void fflush(FILE *fp) +EXPORT int ferror(FILE *fp) +{ + if( !fp || fp->FD == -1 ) + return 0; + return 0; +} +EXPORT int fileno(FILE *stream) +{ + return stream->FD; +} + +EXPORT off_t ftell(FILE *fp) +{ + if(!fp || fp->FD == -1) return -1; + + if( fp->FD == -2 ) + return fp->Pos; + else + return tell(fp->FD); +} + +EXPORT int fseek(FILE *fp, long int amt, int whence) +{ + if(!fp || fp->FD == -1) 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; + break; + } + if(fp->Pos > (off_t)fp->BufferSize) { + fp->Pos = fp->BufferSize; + fp->Flags |= FILE_FLAG_EOF; + } + return 0; + } + else + return seek(fp->FD, amt, whence); +} + + +/** + * \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) { - ///\todo Implement + 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; } /** * \fn int fprintf(FILE *fp, const char *format, ...) * \brief Print a formatted string to a stream */ -int fprintf(FILE *fp, const char *format, ...) +EXPORT int fprintf(FILE *fp, const char *format, ...) { - int size; - char *buf; va_list args; - - if(!fp || !format) return -1; + int ret; // Get Size va_start(args, format); - size = ssprintfv((char*)format, args); + ret = vfprintf(fp, (char*)format, args); va_end(args); - // Allocate buffer - buf = (char*)malloc(size+1); - buf[size] = '\0'; - - // Print - va_start(args, format); - sprintfv(buf, (char*)format, args); - va_end(args); + return ret; +} + +/** + * \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) +{ + size_t ret; - // Write to stream - write(fp->FD, size+1, buf); + if(!fp || fp->FD == -1) + 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((char*)fp->Buffer + fp->Pos, ptr, bytes); + fp->Pos += bytes; + ret = num; + } + else { + ret = write(fp->FD, ptr, size*num); + ret /= size; + } - // Free buffer - free(buf); + return ret; +} + +/** + * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) + * \brief Read from a stream + */ +EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp) +{ + size_t ret; - // Return written byte count - return size; + if(!fp || fp->FD == -1) + 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; + } + else { + ret = read(fp->FD, ptr, size*num); + ret /= size; + } + + return ret; +} + +/** + * \fn EXPORT int fputc(int c, FILE *fp) + * \brief Write a single character to the stream + */ +EXPORT int fputc(int c, FILE *fp) +{ + return fwrite(&c, 1, 1, fp); +} + +EXPORT int putchar(int c) +{ + c &= 0xFF; + return write(_stdout, &c, 1); +} + +/** + * \fn EXPORT int fgetc(FILE *fp) + * \brief Read a character from the stream + */ +EXPORT int fgetc(FILE *fp) +{ + char ret = 0; + if( fread(&ret, 1, 1, fp) == (size_t)-1 ) + return -1; + return ret; +} + +EXPORT int getchar(void) +{ + char ret = 0; + if(read(_stdin, &ret, 1) != 1) return -1; + return ret; } // --- INTERNAL --- @@ -160,7 +398,321 @@ FILE *get_file_struct() int i; for(i=0;i= 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; +}