#include "libio.h" #include /* * *Buffering* I/O */ static int errnum; /* Saved errno for library. */ static char *ERROR_BUFF = "Out of memory.\n"; /* Standard I/O streams. Suppose, there can be some stupid errors. */ FILE_T std_streams[3] = { { 0, 0, NULL, 0}, /* stdin */ { 0, 0, NULL, 1}, /* stdout */ { 0, 0, NULL, 2} /* stderr */ }; /* Print errnum, set by lib's functions. */ void perrnum( const char* src ) { fprint( STDERR_FILENO, "%s: %s\t%d\n", src, strerror(errnum), errnum ); } /* Return fd of the struct. Maybe, it's a bad decision. It looks like OOP[s].*/ int inline file_fd( FILE_T *file ) { return file->fd; } /* * __fill_buffer -- try read BUFSIZE bytes to FILE_T * @file: opened file; * errno is set by read(2). ( Need handle lseek? Simple you don't need lseek.) * Return: * -1 -- EOF; * -2 -- Error; * 0 -- Success. */ static int __fill_buffer( FILE_T *file ) { register ssize_t ret; if( file->buf == NULL ) if((file->buf = (char*)malloc(BUFSIZE*sizeof(char))) == NULL ) { write(2, ERROR_BUFF, 21); _exit(-1); } if((ret = read( file->fd, file->buf, BUFSIZE)) < 0 ) { errnum = errno; // Error file->cur = file->end = -2; return -2; } else if( ret == 0 ) { // Eof file->cur = file->end = -1; return -1; } file->cur = 0; file->end = ret; return 0; } /* * __save_fill -- not so save as I wish filling file's buffer. * @file: file. * Return: * -2 -- Error; * -1 -- EOF; * 0 -- Success. */ static inline int __save_fill( FILE_T *file ) { register int ret; if( file->end == -2) { return -2; } else if( file->end == -1 ) { return -1; } if( file->cur == file->end ) { /* Only at the end of buffer. */ if((ret = __fill_buffer( file )) < 0 ) { return ret; } } return 0; } /* * file_open -- init FILE_T structure and associate it with an open file. * @path: path to a desired file; * @flags: flags of open(2). * errnum is set by open(2). * Bad value of malloc causes to the Full Crash. */ FILE_T *file_open( const char* path, int flags ) { register int fd; FILE_T *file; if( (fd = open( path, flags ) ) < 0 ) { errnum = errno; return NULL; } if((file = (FILE_T*)malloc(sizeof(FILE_T))) == NULL ) { write(2, ERROR_BUFF, 21); _exit(-1); } file->cur = file->end = 0; file->fd = fd; file->buf = NULL; return file; } /* * file_close -- destroy FILE_T, close files and other things. * @file: struct for destruction. * errnum is set by close. ( Errnum is helpful? Do I need it? ) */ int file_close( FILE_T *file ) { register int fd = file->fd; if( file ) { if( file->buf ) free( file->buf ); free(file); } if(close(fd) < 0 ) { errnum = errno; return -1; } return 0; } inline void file_fresh( FILE_T *file ) { file->cur = file->end = 0; } /* * file_read -- read `count` bytes to previously allocated `buf` from `file` * @file: a file; * @buf: a buf; * @count: a count. * I don't now yet anything about this subroutine. * Return: * > 0 -- numbers of read count ( bytes if nmem size 1) * 0 -- 0; * -1 -- EOF; * -2 -- Error; */ ssize_t file_read( FILE_T *file, char *buf, size_t size, size_t nmem ) { /* If all bytes are in the buffer now, just copy them. */ register size_t total, boff = 0; register ssize_t off, sum = 0; register int state; if(( total = size*nmem) == 0 ) { return 0; } /* Check valid of `file`*/ if((state = __save_fill( file )) < 0 ) { return state; } while( total > 0) { off = file->end - file->cur; if( off <= 0 ) { /* Error or EOF. */ return sum; /* Handle. */ } else if( off >= total ) { /* Don't need to update buffer. */ memmove( (void*)(buf+boff), (void*)(file->buf+file->cur), total); sum += total; file->cur += total; break; } /* off < total => read ALL off & update. */ memmove( (void*)(buf+boff), (void*)(file->buf+file->cur), off ); total -= off; boff += off; sum += off; /* If an error is occured. */ if((state = __fill_buffer( file )) < -1){ return -2; } } return sum; } /* * __print_buffer */ int __print_buffer( FILE_T *file, int whence ) { register int ret = write( STDOUTF->fd, file->buf+whence, file->end ); if( ret < 0 ) { errnum = errno; return -1; } return 0; } /* * file_write -- write size*nmem item of `buf` to `file's` buffer. * @file: a file; * @buf: a buffer; * @size: a size; * @nmem: a size of piece of mem. ( Hmm. ) * It's not so easy to implement it, I suppose. So a kind of insane or * unsophisticated method was concocted. */ size_t file_write( FILE_T *file, char *buf, size_t size, size_t nmem ) { /* Oh, it wasn't.'*/ return 0; } /* * fgetchr -- return next char from file *stream*. * @file: *stream*. * Call __fill_buffer => errnum is set by read. */ inline int fgetchr( FILE_T *file ) { register int ret = 0; if(( ret = __save_fill( file )) < 0 ) { return ret; } return file->buf[file->cur++]; } /* * Another unuseful subroutine. */ int fgetstr( FILE_T *file ) { /* The most safe subroutine.*/ return 0; } /* UTF-8: 192 - 110xxxxx - for U+0080 to U+07FF 224 - 1110xxxx - for U+0800 to U+FFFF 240 - 11110xxx - for U+010000 to U+1FFFFF */ #define code1 192 #define code2 224 #define code3 240 #define min(a, b) (a) < (b) ? (a) : (b) int wgetchr( struct file_t *file, char *bytes) { register unsigned short i = 0, j = 0; register int ret; if ((ret = fgetchr(file)) < 0) { return ret; } bytes[0] = (unsigned char)ret; if ((bytes[0] & code1) == code1) i++; if ((bytes[0] & code2) == code2) i++; if ((bytes[0] & code3) == code3) i++; i = min(i, MB_CUR_MAX); while( j < i ) { j++; bytes[j] = (unsigned char)fgetchr(file); } return i + 1; } /* * I/O without buffering. * */ int putstr( int fd, const char* str ) { register int len = strlen(str); if( write( fd, str, len ) < 0 ) { return -1; } return 0; } int putchr( int fd, char c ) { char buf[2]; buf[0] = c; buf[1] = '\0'; if( write( fd, buf, 2) < 0 ) { return -1; } return 0; } int fprint( int fd, const char* fmt, ... ) { register int ret; char str[1024]; va_list args; va_start( args, fmt ); vsprintf( str, fmt, args); ret = putstr( fd, str ); va_end(args); return ret; } ssize_t getstr( int fd, char *buf, size_t len ) { register ssize_t ret; if((ret = read( fd, buf, len)) < 0 ) { return -1; } buf[ret] = '\0'; return ret; } int getchr( int fd ) { char buf[2]; register ssize_t ret = read( fd, buf, 1); if( ret <= 0 ) return -1; return buf[0]; }