298 lines
7.8 KiB
C
298 lines
7.8 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
|
|
#if 1
|
|
#define V4K_IMPLEMENTATION
|
|
#include "/prj/v4k/engine/joint/v4k.h"
|
|
#define vl tempvl
|
|
#define test2 test2_
|
|
#else
|
|
#define vl(fmt, list) fmt // @fixme
|
|
|
|
static unsigned array_c;
|
|
#define array(t) t*
|
|
#define array_resize(arr, c) ( (arr) = vrealloc((arr), (c) * sizeof(0[arr])) )
|
|
#define array_push(arr, v) ( array_c = array_count(arr), array_c[(arr) = vrealloc((arr), (array_c + 1) * sizeof(0[arr]))] = (v) )
|
|
#define array_pop(arr) ( (arr) ? (arr) = vrealloc((arr), (array_count(arr)-1) * sizeof(0[arr])) : (0) )
|
|
#define array_count(arr) (int)( (arr) ? vlen(arr) / sizeof(0[arr]) : sizeof(0[arr]) - sizeof(0[arr]) )
|
|
#define array_free(arr) ( (arr) ? (vrealloc(arr, 0), 1) : 0 )
|
|
|
|
void* vrealloc( void* p, size_t sz ) {
|
|
if( !sz ) {
|
|
if( p ) {
|
|
size_t *ret = (size_t*)p - 2;
|
|
ret[0] = 0;
|
|
ret[1] = 0;
|
|
realloc( ret, 0 );
|
|
}
|
|
return 0;
|
|
} else {
|
|
size_t *ret;
|
|
if( !p ) {
|
|
ret = (size_t*)realloc( 0, sizeof(size_t) * 2 + sz );
|
|
ret[0] = sz;
|
|
ret[1] = 0;
|
|
} else {
|
|
ret = (size_t*)p - 2;
|
|
size_t osz = ret[0];
|
|
size_t ocp = ret[1];
|
|
if( sz <= (osz + ocp) ) {
|
|
ret[0] = sz;
|
|
ret[1] = ocp - (sz - osz);
|
|
} else {
|
|
ret = (size_t*)realloc( ret, sizeof(size_t) * 2 + sz * 1.75 );
|
|
ret[0] = sz;
|
|
ret[1] = (size_t)(sz * 1.75) - sz;
|
|
}
|
|
}
|
|
return &ret[2];
|
|
}
|
|
}
|
|
size_t vlen( void* p ) {
|
|
return p ? 0[ (size_t*)p - 2 ] : 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
typedef struct FILE2 {
|
|
FILE *fp;
|
|
int64_t pos;
|
|
int errno_;
|
|
array(char) arr;
|
|
} FILE2;
|
|
|
|
|
|
void *tmpfile2(void) {
|
|
FILE2 *mem = (FILE2*)calloc(1, sizeof(FILE2));
|
|
mem->fp = tmpfile();
|
|
return mem;
|
|
}
|
|
void *fopen2(void *buf, const char *mode) {
|
|
FILE2 *mem = (FILE2*)calloc(1, sizeof(FILE2));
|
|
|
|
if( mode[0] != 'm' && buf ) {
|
|
mem->fp = fopen((const char *)buf, mode);
|
|
}
|
|
|
|
return (FILE*)mem;
|
|
}
|
|
int fclose2(void* handler) {
|
|
FILE2 *mem = (FILE2*)handler;
|
|
if( mem->arr ) {
|
|
array_free(mem->arr);
|
|
}
|
|
if( mem->fp ) {
|
|
fclose(mem->fp);
|
|
}
|
|
memset(mem, 0, sizeof(FILE2));
|
|
free(mem);
|
|
return 0;
|
|
}
|
|
// r/w
|
|
int fwrite2(const void *buf, int size, int count, void *handler) {
|
|
FILE2 *mem = handler;
|
|
|
|
if( mem->fp ) return fwrite(buf, size, count, mem->fp);
|
|
|
|
size *= count;
|
|
size_t available = array_count(mem->arr) - mem->pos;
|
|
|
|
if( size > available ) {
|
|
if( 1 ) { // if growthable
|
|
array_resize(mem->arr, size - available);
|
|
} else {
|
|
size = available;
|
|
}
|
|
}
|
|
memcpy(mem->arr, buf, size);
|
|
mem->pos += size;
|
|
|
|
return count;
|
|
}
|
|
int fread2(void *buf, int size, int count, void *handler) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return fread(buf, size, count, mem->fp);
|
|
|
|
size_t available = array_count(mem->arr) - mem->pos;
|
|
size_t total = size * count;
|
|
|
|
while( (total/size) > count ) {
|
|
total -= size;
|
|
}
|
|
if( total > 0 ) {
|
|
memcpy(buf, mem->arr, total);
|
|
mem->pos += total;
|
|
return total / size;
|
|
}
|
|
return 0;
|
|
}
|
|
// cursor
|
|
int64_t ftello2(void *handler) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return ftell(mem->fp);
|
|
return mem->pos;
|
|
}
|
|
int64_t fseeko2(void *handler, int64_t offset, int whence) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return fseek(mem->fp, offset, whence);
|
|
/**/ if( whence == SEEK_SET ) mem->pos = offset;
|
|
else if( whence == SEEK_CUR ) mem->pos += offset;
|
|
else if( whence == SEEK_END ) mem->pos = array_count(mem->arr) + offset; // - 1 - offset;
|
|
else return -1;
|
|
if( mem->pos >= array_count(mem->arr) ) {
|
|
return -1;
|
|
}
|
|
return mem->pos; // (fpos_t)mem->pos;
|
|
}
|
|
// buffering
|
|
void setbuf2(void *handler, char *buffer) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) setbuf(mem->fp, buffer);
|
|
}
|
|
int setvbuf2(void *handler, char *buffer, int mode, size_t size) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return setvbuf2(mem->fp, buffer, mode, size);
|
|
return 0;
|
|
}
|
|
int fflush2(void *handler) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return fflush(mem->fp);
|
|
return 0;
|
|
}
|
|
int ungetc2(int ch, void *handler) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return ungetc(ch, mem->fp);
|
|
#if 0
|
|
// todo:
|
|
|
|
pushes the uint8_t character onto the specified stream so that
|
|
it's available for the next read operation.
|
|
|
|
#endif
|
|
return -1;
|
|
}
|
|
// internal
|
|
array(char)* fdata(void *handler) {
|
|
FILE2 *mem = handler;
|
|
if( mem->fp ) return NULL;
|
|
return &mem->arr;
|
|
}
|
|
|
|
|
|
|
|
#define FILE void
|
|
#define tmpfile tmpfile2
|
|
#define fopen fopen2
|
|
#define ftello ftello2
|
|
#define ftell (int)ftello2
|
|
#define fgetpos fgetpos2
|
|
#define fseeko fseeko2
|
|
#define fseek (int)fseeko2
|
|
#define fsetpos fsetpos2
|
|
#define rewind rewind2
|
|
#define fread fread2
|
|
#define fgets fgets2
|
|
#define fgetc fgetc2
|
|
#define getc getc2
|
|
#define fwrite fwrite2
|
|
#define fputs fputs2
|
|
#define fputc fputc2
|
|
#define putc putc2
|
|
#define ferror ferror2
|
|
#define feof feof2
|
|
#define clearerr clearerr2
|
|
#define vfprintf vfprintf2 // @fixme: return type
|
|
#define fprintf fprintf2
|
|
#define setbuf setbuf2
|
|
#define setvbuf setvbuf2
|
|
#define fflush fflush2
|
|
#define ungetc ungetc2
|
|
#define fclose fclose2
|
|
|
|
// not doing:
|
|
#define freopen(filename,mode,handler) freopen(filename,mode, ((FILE2*)(handler))->fp )
|
|
#define freopen(filename,mode,handler) freopen(filename,mode, ((FILE2*)(handler))->fp )
|
|
#define fscanf(handler,format,...) fscanf(((FILE2*)(handler))->fp, format, __VA_ARGS__)
|
|
|
|
|
|
// format
|
|
// int fscanf(FILE *fp, const char *format, ...);
|
|
int vfprintf(FILE *fp, const char *format, va_list args) { // @fixme: return type
|
|
const char *str = vl(format, args);
|
|
return fwrite(str, strlen(str), 1, fp) == 1;
|
|
}
|
|
int fprintf(FILE *fp, const char *fmt, ...) {
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
int rc = vfprintf(fp, fmt, va);
|
|
va_end(va);
|
|
return rc;
|
|
}
|
|
|
|
// error handling
|
|
int feof(FILE *fp) { return ((FILE2*)fp)->errno_ == EOF; }
|
|
int ferror(FILE *fp) { return ((FILE2*)fp)->errno_; }
|
|
void clearerr(FILE *fp) { ((FILE2*)fp)->errno_ = 0; }
|
|
|
|
// aliases
|
|
int fgetpos(FILE *fp, fpos_t *pos) { return (*pos = ftell(fp)) != -1L; }
|
|
int fsetpos(FILE *fp, const fpos_t *pos) { return fseek(fp, *pos, SEEK_SET); }
|
|
void rewind(FILE *fp) { fseek(fp, 0L, SEEK_SET); }
|
|
|
|
// aliases
|
|
int fgetc(FILE *fp) { int ch = EOF; return fread(&ch, sizeof(char), 1, fp) != 1 ? EOF : ch; }
|
|
int fputc(int ch, FILE *fp) { return fwrite(&ch, sizeof(char), 1, fp) == 1; }
|
|
int getc(FILE *fp) { return fgetc(fp); }
|
|
int putc(int ch, FILE *fp) { return fputc(ch, fp); }
|
|
int fputs(const char *str, FILE *fp) { return fwrite(str, strlen(str), 1, fp) == 1 && fwrite("\n",1,1,fp) == 1; }
|
|
char* fgets(char *str, int n, FILE *fp) {
|
|
char *cpy = str;
|
|
int ch = EOF;
|
|
while( n && (ch = fgetc(fp)) != EOF && !strchr("\r\n", ch) ) *str++ = ch, --n;
|
|
while( n && (ch = fgetc(fp)) != EOF && strchr("\r\n", ch) ) *str++ = ch, --n;
|
|
return ch == EOF ? NULL : cpy;
|
|
}
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
void test1() {
|
|
char buf[256] = {0};
|
|
FILE *fp = fopen(__FILE__,"rb");
|
|
assert(fp);
|
|
assert(fgets(buf, sizeof(buf), fp));
|
|
assert(~puts(buf));
|
|
assert(0 == fclose(fp));
|
|
assert(~puts("Ok"));
|
|
}
|
|
|
|
void test2() {
|
|
const char *buf = "hello world";
|
|
FILE *fp = fopen(NULL, "rb");
|
|
assert(fwrite(buf, strlen(buf), 1, fp));
|
|
puts(*fdata(fp));
|
|
assert(0 == fclose(fp));
|
|
assert(~puts("Ok"));
|
|
}
|
|
|
|
void test3() {
|
|
FILE *fp = fopen(NULL, "rb");
|
|
assert(fprintf(fp, "hello %s! %d\n", "world", 123));
|
|
puts(*fdata(fp));
|
|
assert(0 == fclose(fp));
|
|
assert(~puts("Ok"));
|
|
}
|
|
|
|
int main() {
|
|
test1();
|
|
test2();
|
|
test3();
|
|
}
|
|
|