#include #include #include #include #include #include #include #include #include #include #include "libio.h" /* * *Buffering* I/O */ 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 */ }; /* 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 ) { 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 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). * 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 ) { 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. */ 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 ) { return -1; } return 0; } inline void file_fresh( FILE_T *file ) { file->cur = file->end = 0; } /* * fgetchr -- return next char from file *stream*. * @file: *stream*. */ inline int fgetchr( FILE_T *file ) { register int ret = 0; if(( ret = __save_fill( file )) < 0 ) { return ret; } return file->buf[file->cur++]; } /* 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 0xc0 #define code2 0xe0 #define code3 0xf0 #define min(a, b) (a) < (b) ? (a) : (b) int wgetchr( struct file_t *file, char *bytes) { register unsigned short i = 1, 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); if( i == 1 ) return 1; while( j < i-1 ) { j++; bytes[j] = (unsigned char)fgetchr(file); } return i; } /* * 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 fmt_print( 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; }