import xhash, xrope, xfile, and xvect
This commit is contained in:
parent
aa3b385e27
commit
1861aff2d1
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef XFILE_H__
|
||||||
|
#define XFILE_H__
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ungot;
|
||||||
|
int flags;
|
||||||
|
/* operators */
|
||||||
|
struct {
|
||||||
|
void *cookie;
|
||||||
|
int (*read)(void *, char *, int);
|
||||||
|
int (*write)(void *, const char *, int);
|
||||||
|
long (*seek)(void *, long, int);
|
||||||
|
int (*flush)(void *);
|
||||||
|
int (*close)(void *);
|
||||||
|
} vtable;
|
||||||
|
} xFILE;
|
||||||
|
|
||||||
|
/* generic file constructor */
|
||||||
|
xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
|
||||||
|
|
||||||
|
/* resource aquisition */
|
||||||
|
xFILE *xfopen(const char *, const char *);
|
||||||
|
xFILE *xfpopen(FILE *);
|
||||||
|
xFILE *xmopen();
|
||||||
|
int xfclose(xFILE *);
|
||||||
|
|
||||||
|
/* buffer management */
|
||||||
|
int xfflush(xFILE *);
|
||||||
|
|
||||||
|
/* direct IO with buffering */
|
||||||
|
size_t xfread(void *, size_t, size_t, xFILE *);
|
||||||
|
size_t xfwrite(const void *, size_t, size_t, xFILE *);
|
||||||
|
|
||||||
|
/* indicator positioning */
|
||||||
|
long xfseek(xFILE *, long offset, int whence);
|
||||||
|
long xftell(xFILE *);
|
||||||
|
void xrewind(xFILE *);
|
||||||
|
|
||||||
|
/* stream status */
|
||||||
|
void xclearerr(xFILE *);
|
||||||
|
int xfeof(xFILE *);
|
||||||
|
int xferror(xFILE *);
|
||||||
|
|
||||||
|
/* character IO */
|
||||||
|
int xfgetc(xFILE *);
|
||||||
|
char *xfgets(char *, int, xFILE *);
|
||||||
|
int xfputc(int, xFILE *);
|
||||||
|
int xfputs(const char *, xFILE *);
|
||||||
|
char xgetc(xFILE *);
|
||||||
|
int xgetchar(void);
|
||||||
|
int xputc(int, xFILE *);
|
||||||
|
int xputchar(int);
|
||||||
|
int xputs(char *);
|
||||||
|
int xungetc(int, xFILE *);
|
||||||
|
|
||||||
|
/* formatted I/O */
|
||||||
|
int xprintf(const char *, ...);
|
||||||
|
int xfprintf(xFILE *, const char *, ...);
|
||||||
|
int xvfprintf(xFILE *, const char *, va_list);
|
||||||
|
|
||||||
|
/* standard I/O */
|
||||||
|
extern xFILE *xstdin;
|
||||||
|
extern xFILE *xstdout;
|
||||||
|
extern xFILE *xstderr;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,407 @@
|
||||||
|
#ifndef XHASH_H__
|
||||||
|
#define XHASH_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2014 by Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* simple object to object hash table */
|
||||||
|
|
||||||
|
#define XHASH_INIT_SIZE 11
|
||||||
|
#define XHASH_RESIZE_RATIO 0.75
|
||||||
|
|
||||||
|
#define XHASH_ALIGNMENT 3 /* quad word alignment */
|
||||||
|
#define XHASH_MASK (~((1 << XHASH_ALIGNMENT) - 1))
|
||||||
|
#define XHASH_ALIGN(i) ((((i) - 1) & XHASH_MASK) + (1 << XHASH_ALIGNMENT))
|
||||||
|
|
||||||
|
typedef struct xh_entry {
|
||||||
|
struct xh_entry *next;
|
||||||
|
int hash;
|
||||||
|
const char *key; /* == val + XHASH_ALIGN(vwidth) */
|
||||||
|
char val[];
|
||||||
|
} xh_entry;
|
||||||
|
|
||||||
|
#define xh_key(e,type) (*(type *)((e)->key))
|
||||||
|
#define xh_val(e,type) (*(type *)((e)->val))
|
||||||
|
|
||||||
|
typedef int (*xh_hashf)(const void *, void *);
|
||||||
|
typedef int (*xh_equalf)(const void *, const void *, void *);
|
||||||
|
|
||||||
|
typedef struct xhash {
|
||||||
|
xh_entry **buckets;
|
||||||
|
size_t size, count, kwidth, vwidth;
|
||||||
|
xh_hashf hashf;
|
||||||
|
xh_equalf equalf;
|
||||||
|
void *data;
|
||||||
|
} xhash;
|
||||||
|
|
||||||
|
static inline void xh_init_(xhash *x, size_t, size_t, xh_hashf, xh_equalf, void *);
|
||||||
|
static inline xh_entry *xh_get_(xhash *x, const void *key);
|
||||||
|
static inline xh_entry *xh_put_(xhash *x, const void *key, void *val);
|
||||||
|
static inline void xh_del_(xhash *x, const void *key);
|
||||||
|
static inline void xh_clear(xhash *x);
|
||||||
|
static inline void xh_destroy(xhash *x);
|
||||||
|
|
||||||
|
/* string map */
|
||||||
|
static inline void xh_init_str(xhash *x, size_t width);
|
||||||
|
static inline xh_entry *xh_get_str(xhash *x, const char *key);
|
||||||
|
static inline xh_entry *xh_put_str(xhash *x, const char *key, void *);
|
||||||
|
static inline void xh_del_str(xhash *x, const char *key);
|
||||||
|
|
||||||
|
/* object map */
|
||||||
|
static inline void xh_init_ptr(xhash *x, size_t width);
|
||||||
|
static inline xh_entry *xh_get_ptr(xhash *x, const void *key);
|
||||||
|
static inline xh_entry *xh_put_ptr(xhash *x, const void *key, void *);
|
||||||
|
static inline void xh_del_ptr(xhash *x, const void *key);
|
||||||
|
|
||||||
|
/* int map */
|
||||||
|
static inline void xh_init_int(xhash *x, size_t width);
|
||||||
|
static inline xh_entry *xh_get_int(xhash *x, int key);
|
||||||
|
static inline xh_entry *xh_put_int(xhash *x, int key, void *);
|
||||||
|
static inline void xh_del_int(xhash *x, int key);
|
||||||
|
|
||||||
|
typedef struct xh_iter {
|
||||||
|
xhash *x;
|
||||||
|
xh_entry *e, *next;
|
||||||
|
size_t bidx;
|
||||||
|
} xh_iter;
|
||||||
|
|
||||||
|
static inline void xh_begin(xh_iter *it, xhash *x);
|
||||||
|
static inline int xh_next(xh_iter *it);
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_bucket_realloc(xhash *x, size_t newsize)
|
||||||
|
{
|
||||||
|
x->size = newsize;
|
||||||
|
x->buckets = realloc(x->buckets, (x->size + 1) * sizeof(xh_entry *));
|
||||||
|
memset(x->buckets, 0, (x->size + 1) * sizeof(xh_entry *));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_init_(xhash *x, size_t kwidth, size_t vwidth, xh_hashf hashf, xh_equalf equalf, void *data)
|
||||||
|
{
|
||||||
|
x->size = 0;
|
||||||
|
x->buckets = NULL;
|
||||||
|
x->count = 0;
|
||||||
|
x->kwidth = kwidth;
|
||||||
|
x->vwidth = vwidth;
|
||||||
|
x->hashf = hashf;
|
||||||
|
x->equalf = equalf;
|
||||||
|
x->data = data;
|
||||||
|
|
||||||
|
xh_bucket_realloc(x, XHASH_INIT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_get_(xhash *x, const void *key)
|
||||||
|
{
|
||||||
|
int hash;
|
||||||
|
size_t idx;
|
||||||
|
xh_entry *e;
|
||||||
|
|
||||||
|
hash = x->hashf(key, x->data);
|
||||||
|
idx = ((unsigned)hash) % x->size;
|
||||||
|
for (e = x->buckets[idx]; e; e = e->next) {
|
||||||
|
if (e->hash == hash && x->equalf(key, e->key, x->data))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_resize_(xhash *x, size_t newsize)
|
||||||
|
{
|
||||||
|
xhash y;
|
||||||
|
xh_iter it;
|
||||||
|
size_t idx;
|
||||||
|
|
||||||
|
xh_init_(&y, x->kwidth, x->vwidth, x->hashf, x->equalf, x->data);
|
||||||
|
xh_bucket_realloc(&y, newsize);
|
||||||
|
|
||||||
|
xh_begin(&it, x);
|
||||||
|
while (xh_next(&it)) {
|
||||||
|
idx = ((unsigned)it.e->hash) % y.size;
|
||||||
|
/* reuse entry object */
|
||||||
|
it.e->next = y.buckets[idx];
|
||||||
|
y.buckets[idx] = it.e;
|
||||||
|
y.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(x->buckets);
|
||||||
|
|
||||||
|
/* copy all members from y to x */
|
||||||
|
memcpy(x, &y, sizeof(xhash));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_put_(xhash *x, const void *key, void *val)
|
||||||
|
{
|
||||||
|
int hash;
|
||||||
|
size_t idx;
|
||||||
|
xh_entry *e;
|
||||||
|
|
||||||
|
if ((e = xh_get_(x, key))) {
|
||||||
|
memcpy(e->val, val, x->vwidth);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->count + 1 > x->size * XHASH_RESIZE_RATIO) {
|
||||||
|
xh_resize_(x, x->size * 2 + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = x->hashf(key, x->data);
|
||||||
|
idx = ((unsigned)hash) % x->size;
|
||||||
|
e = (xh_entry *)malloc(offsetof(xh_entry, val) + XHASH_ALIGN(x->vwidth) + x->kwidth);
|
||||||
|
e->next = x->buckets[idx];
|
||||||
|
e->hash = hash;
|
||||||
|
e->key = e->val + XHASH_ALIGN(x->vwidth);
|
||||||
|
memcpy((void *)e->key, key, x->kwidth);
|
||||||
|
memcpy(e->val, val, x->vwidth);
|
||||||
|
|
||||||
|
x->count++;
|
||||||
|
|
||||||
|
return x->buckets[idx] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_del_(xhash *x, const void *key)
|
||||||
|
{
|
||||||
|
int hash;
|
||||||
|
size_t idx;
|
||||||
|
xh_entry *e, *d;
|
||||||
|
|
||||||
|
hash = x->hashf(key, x->data);
|
||||||
|
idx = ((unsigned)hash) % x->size;
|
||||||
|
if (x->buckets[idx]->hash == hash && x->equalf(key, x->buckets[idx]->key, x->data)) {
|
||||||
|
e = x->buckets[idx]->next;
|
||||||
|
free(x->buckets[idx]);
|
||||||
|
x->buckets[idx] = e;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (e = x->buckets[idx]; ; e = e->next) {
|
||||||
|
if (e->next->hash == hash && x->equalf(key, e->next->key, x->data))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d = e->next->next;
|
||||||
|
free(e->next);
|
||||||
|
e->next = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_clear(xhash *x)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
xh_entry *e, *d;
|
||||||
|
|
||||||
|
for (i = 0; i < x->size; ++i) {
|
||||||
|
e = x->buckets[i];
|
||||||
|
while (e) {
|
||||||
|
d = e->next;
|
||||||
|
free(e);
|
||||||
|
e = d;
|
||||||
|
}
|
||||||
|
x->buckets[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_destroy(xhash *x)
|
||||||
|
{
|
||||||
|
xh_clear(x);
|
||||||
|
free(x->buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* string map */
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_str_hash(const void *key, void *data)
|
||||||
|
{
|
||||||
|
const char *str = *(const char **)key;
|
||||||
|
int hash = 0;
|
||||||
|
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
hash = hash * 31 + *str++;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_str_equal(const void *key1, const void *key2, void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
return strcmp(*(const char **)key1, *(const char **)key2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_init_str(xhash *x, size_t width)
|
||||||
|
{
|
||||||
|
xh_init_(x, sizeof(const char *), width, xh_str_hash, xh_str_equal, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_get_str(xhash *x, const char *key)
|
||||||
|
{
|
||||||
|
return xh_get_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_put_str(xhash *x, const char *key, void *val)
|
||||||
|
{
|
||||||
|
return xh_put_(x, &key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_del_str(xhash *x, const char *key)
|
||||||
|
{
|
||||||
|
xh_del_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* object map */
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_ptr_hash(const void *key, void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
return (size_t)*(const void **)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_ptr_equal(const void *key1, const void *key2, void *data)
|
||||||
|
{
|
||||||
|
(void) data;
|
||||||
|
|
||||||
|
return *(const void **)key1 == *(const void **)key2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_init_ptr(xhash *x, size_t width)
|
||||||
|
{
|
||||||
|
xh_init_(x, sizeof(const void *), width, xh_ptr_hash, xh_ptr_equal, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_get_ptr(xhash *x, const void *key)
|
||||||
|
{
|
||||||
|
return xh_get_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_put_ptr(xhash *x, const void *key, void *val)
|
||||||
|
{
|
||||||
|
return xh_put_(x, &key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_del_ptr(xhash *x, const void *key)
|
||||||
|
{
|
||||||
|
xh_del_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* int map */
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_int_hash(const void *key, void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
return *(int *)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_int_equal(const void *key1, const void *key2, void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
return *(int *)key1 == *(int *)key2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_init_int(xhash *x, size_t width)
|
||||||
|
{
|
||||||
|
xh_init_(x, sizeof(int), width, xh_int_hash, xh_int_equal, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_get_int(xhash *x, int key)
|
||||||
|
{
|
||||||
|
return xh_get_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xh_entry *
|
||||||
|
xh_put_int(xhash *x, int key, void *val)
|
||||||
|
{
|
||||||
|
return xh_put_(x, &key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_del_int(xhash *x, int key)
|
||||||
|
{
|
||||||
|
xh_del_(x, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** iteration */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xh_begin(xh_iter *it, xhash *x)
|
||||||
|
{
|
||||||
|
size_t bidx;
|
||||||
|
|
||||||
|
it->x = x;
|
||||||
|
|
||||||
|
for (bidx = 0; bidx < x->size; ++bidx) {
|
||||||
|
if (x->buckets[bidx])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it->e = NULL;
|
||||||
|
it->next = x->buckets[bidx];
|
||||||
|
it->bidx = bidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
xh_next(xh_iter *it)
|
||||||
|
{
|
||||||
|
size_t bidx;
|
||||||
|
|
||||||
|
if (! it->next) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->e = it->next;
|
||||||
|
if (it->next->next) {
|
||||||
|
it->next = it->next->next;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (bidx = it->bidx + 1; bidx < it->x->size; ++bidx) {
|
||||||
|
if (it->x->buckets[bidx])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it->next = it->x->buckets[bidx];
|
||||||
|
it->bidx = bidx;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,329 @@
|
||||||
|
#ifndef XROPE_H__
|
||||||
|
#define XROPE_H__
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* public APIs */
|
||||||
|
|
||||||
|
typedef struct xrope xrope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* | name | frees buffer? | end with NULL? | complexity | misc
|
||||||
|
* | ---- | ---- | ---- | ---- | ---
|
||||||
|
* | xr_new_cstr | no | yes | O(1) | xr_new(_lit)
|
||||||
|
* | xr_new_imbed | no | no | O(1) |
|
||||||
|
* | xr_new_move | yes | yes | O(1) |
|
||||||
|
* | xr_new_copy | yes | no | O(n) |
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define xr_new(cstr) xr_new_cstr(cstr, strlen(cstr))
|
||||||
|
#define xr_new_lit(cstr) xr_new_cstr(cstr, sizeof(cstr) - 1)
|
||||||
|
static inline xrope *xr_new_cstr(const char *, size_t);
|
||||||
|
static inline xrope *xr_new_imbed(const char *, size_t);
|
||||||
|
static inline xrope *xr_new_move(const char *, size_t);
|
||||||
|
static inline xrope *xr_new_copy(const char *, size_t);
|
||||||
|
|
||||||
|
static inline void XROPE_INCREF(xrope *);
|
||||||
|
static inline void XROPE_DECREF(xrope *);
|
||||||
|
|
||||||
|
static inline size_t xr_len(xrope *);
|
||||||
|
static inline char xr_at(xrope *, size_t);
|
||||||
|
static inline xrope *xr_cat(xrope *, xrope *);
|
||||||
|
static inline xrope *xr_sub(xrope *, size_t, size_t);
|
||||||
|
static inline const char *xr_cstr(xrope *); /* returns NULL-terminated string */
|
||||||
|
|
||||||
|
|
||||||
|
/* impl */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *str;
|
||||||
|
int refcnt;
|
||||||
|
size_t len;
|
||||||
|
char autofree, zeroterm;
|
||||||
|
} xr_chunk;
|
||||||
|
|
||||||
|
#define XR_CHUNK_INCREF(c) do { \
|
||||||
|
(c)->refcnt++; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define XR_CHUNK_DECREF(c) do { \
|
||||||
|
xr_chunk *c__ = (c); \
|
||||||
|
if (! --c__->refcnt) { \
|
||||||
|
if (c__->autofree) \
|
||||||
|
free(c__->str); \
|
||||||
|
free(c__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
struct xrope {
|
||||||
|
int refcnt;
|
||||||
|
size_t weight;
|
||||||
|
xr_chunk *chunk;
|
||||||
|
size_t offset;
|
||||||
|
struct xrope *left, *right;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
XROPE_INCREF(xrope *x) {
|
||||||
|
x->refcnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
XROPE_DECREF(xrope *x) {
|
||||||
|
if (! --x->refcnt) {
|
||||||
|
if (x->chunk) {
|
||||||
|
XR_CHUNK_DECREF(x->chunk);
|
||||||
|
free(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XROPE_DECREF(x->left);
|
||||||
|
XROPE_DECREF(x->right);
|
||||||
|
free(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xrope *
|
||||||
|
xr_new_cstr(const char *cstr, size_t len)
|
||||||
|
{
|
||||||
|
xr_chunk *c;
|
||||||
|
xrope *x;
|
||||||
|
|
||||||
|
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||||
|
c->refcnt = 1;
|
||||||
|
c->str = (char *)cstr;
|
||||||
|
c->len = len;
|
||||||
|
c->autofree = 0;
|
||||||
|
c->zeroterm = 1;
|
||||||
|
|
||||||
|
x = (xrope *)malloc(sizeof(xrope));
|
||||||
|
x->refcnt = 1;
|
||||||
|
x->left = NULL;
|
||||||
|
x->right = NULL;
|
||||||
|
x->weight = c->len;
|
||||||
|
x->offset = 0;
|
||||||
|
x->chunk = c;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xrope *
|
||||||
|
xr_new_imbed(const char *str, size_t len)
|
||||||
|
{
|
||||||
|
xr_chunk *c;
|
||||||
|
xrope *x;
|
||||||
|
|
||||||
|
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||||
|
c->refcnt = 1;
|
||||||
|
c->str = (char *)str;
|
||||||
|
c->len = len;
|
||||||
|
c->autofree = 0;
|
||||||
|
c->zeroterm = 0;
|
||||||
|
|
||||||
|
x = (xrope *)malloc(sizeof(xrope));
|
||||||
|
x->refcnt = 1;
|
||||||
|
x->left = NULL;
|
||||||
|
x->right = NULL;
|
||||||
|
x->weight = c->len;
|
||||||
|
x->offset = 0;
|
||||||
|
x->chunk = c;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xrope *
|
||||||
|
xr_new_move(const char *cstr, size_t len)
|
||||||
|
{
|
||||||
|
xr_chunk *c;
|
||||||
|
xrope *x;
|
||||||
|
|
||||||
|
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||||
|
c->refcnt = 1;
|
||||||
|
c->str = (char *)cstr;
|
||||||
|
c->len = len;
|
||||||
|
c->autofree = 1;
|
||||||
|
c->zeroterm = 1;
|
||||||
|
|
||||||
|
x = (xrope *)malloc(sizeof(xrope));
|
||||||
|
x->refcnt = 1;
|
||||||
|
x->left = NULL;
|
||||||
|
x->right = NULL;
|
||||||
|
x->weight = c->len;
|
||||||
|
x->offset = 0;
|
||||||
|
x->chunk = c;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xrope *
|
||||||
|
xr_new_copy(const char *str, size_t len)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
xr_chunk *c;
|
||||||
|
xrope *x;
|
||||||
|
|
||||||
|
buf = (char *)malloc(len + 1);
|
||||||
|
buf[len] = '\0';
|
||||||
|
memcpy(buf, str, len);
|
||||||
|
|
||||||
|
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||||
|
c->refcnt = 1;
|
||||||
|
c->str = buf;
|
||||||
|
c->len = len;
|
||||||
|
c->autofree = 1;
|
||||||
|
c->zeroterm = 1;
|
||||||
|
|
||||||
|
x = (xrope *)malloc(sizeof(xrope));
|
||||||
|
x->refcnt = 1;
|
||||||
|
x->left = NULL;
|
||||||
|
x->right = NULL;
|
||||||
|
x->weight = c->len;
|
||||||
|
x->offset = 0;
|
||||||
|
x->chunk = c;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
xr_len(xrope *x)
|
||||||
|
{
|
||||||
|
return x->weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char
|
||||||
|
xr_at(xrope *x, size_t i)
|
||||||
|
{
|
||||||
|
if (x->weight <= i) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (x->chunk) {
|
||||||
|
return x->chunk->str[x->offset + i];
|
||||||
|
}
|
||||||
|
return (i < x->left->weight)
|
||||||
|
? xr_at(x->left, i)
|
||||||
|
: xr_at(x->right, i - x->left->weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xrope *
|
||||||
|
xr_cat(xrope *x, xrope *y)
|
||||||
|
{
|
||||||
|
xrope *z;
|
||||||
|
|
||||||
|
z = (xrope *)malloc(sizeof(xrope));
|
||||||
|
z->refcnt = 1;
|
||||||
|
z->left = x;
|
||||||
|
z->right = y;
|
||||||
|
z->weight = x->weight + y->weight;
|
||||||
|
z->offset = 0;
|
||||||
|
z->chunk = NULL;
|
||||||
|
|
||||||
|
XROPE_INCREF(x);
|
||||||
|
XROPE_INCREF(y);
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct xrope *
|
||||||
|
xr_sub(xrope *x, size_t i, size_t j)
|
||||||
|
{
|
||||||
|
assert(i <= j);
|
||||||
|
assert(j <= x->weight);
|
||||||
|
|
||||||
|
if (i == 0 && x->weight == j) {
|
||||||
|
XROPE_INCREF(x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->chunk) {
|
||||||
|
xrope *y;
|
||||||
|
|
||||||
|
y = (xrope *)malloc(sizeof(xrope));
|
||||||
|
y->refcnt = 1;
|
||||||
|
y->left = NULL;
|
||||||
|
y->right = NULL;
|
||||||
|
y->weight = j - i;
|
||||||
|
y->offset = x->offset + i;
|
||||||
|
y->chunk = x->chunk;
|
||||||
|
|
||||||
|
XR_CHUNK_INCREF(x->chunk);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j <= x->left->weight) {
|
||||||
|
return xr_sub(x->left, i, j);
|
||||||
|
}
|
||||||
|
else if (x->left->weight <= i) {
|
||||||
|
return xr_sub(x->right, i - x->left->weight, j - x->left->weight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xrope *r, *l;
|
||||||
|
|
||||||
|
l = xr_sub(x->left, i, x->left->weight);
|
||||||
|
r = xr_sub(x->right, 0, j - x->left->weight);
|
||||||
|
x = xr_cat(l, r);
|
||||||
|
|
||||||
|
XROPE_DECREF(l);
|
||||||
|
XROPE_DECREF(r);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xr_fold(xrope *x, xr_chunk *c, size_t offset)
|
||||||
|
{
|
||||||
|
if (x->chunk) {
|
||||||
|
memcpy(c->str + offset, x->chunk->str + x->offset, x->weight);
|
||||||
|
XR_CHUNK_DECREF(x->chunk);
|
||||||
|
|
||||||
|
x->chunk = c;
|
||||||
|
x->offset = offset;
|
||||||
|
XR_CHUNK_INCREF(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xr_fold(x->left, c, offset);
|
||||||
|
xr_fold(x->right, c, offset + x->left->weight);
|
||||||
|
|
||||||
|
XROPE_DECREF(x->left);
|
||||||
|
XROPE_DECREF(x->right);
|
||||||
|
x->left = x->right = NULL;
|
||||||
|
x->chunk = c;
|
||||||
|
x->offset = offset;
|
||||||
|
XR_CHUNK_INCREF(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *
|
||||||
|
xr_cstr(xrope *x)
|
||||||
|
{
|
||||||
|
xr_chunk *c;
|
||||||
|
|
||||||
|
if (x->chunk && x->offset == 0 && x->weight == x->chunk->len && x->chunk->zeroterm) {
|
||||||
|
return x->chunk->str; /* reuse cached chunk */
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||||
|
c->refcnt = 1;
|
||||||
|
c->len = x->weight;
|
||||||
|
c->autofree = 1;
|
||||||
|
c->zeroterm = 1;
|
||||||
|
c->str = (char *)malloc(c->len + 1);
|
||||||
|
c->str[c->len] = '\0';
|
||||||
|
|
||||||
|
xr_fold(x, c, 0);
|
||||||
|
|
||||||
|
XR_CHUNK_DECREF(c);
|
||||||
|
return c->str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,185 @@
|
||||||
|
#ifndef XVECT_H__
|
||||||
|
#define XVECT_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 by Yuichi Nishiwaki <yuichi@idylls.jp>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct xvect {
|
||||||
|
char *data;
|
||||||
|
size_t size, mask, head, tail, width;
|
||||||
|
} xvect;
|
||||||
|
|
||||||
|
static inline void xv_init(xvect *, size_t);
|
||||||
|
static inline void xv_destroy(xvect *);
|
||||||
|
|
||||||
|
static inline size_t xv_size(xvect *);
|
||||||
|
|
||||||
|
static inline void xv_reserve(xvect *, size_t);
|
||||||
|
static inline void xv_shrink(xvect *, size_t);
|
||||||
|
|
||||||
|
static inline void *xv_get(xvect *, size_t);
|
||||||
|
static inline void xv_set(xvect *, size_t, void *);
|
||||||
|
|
||||||
|
static inline void xv_push(xvect *, void *);
|
||||||
|
static inline void *xv_pop(xvect *);
|
||||||
|
|
||||||
|
static inline void *xv_shift(xvect *);
|
||||||
|
static inline void xv_unshift(xvect *, void *);
|
||||||
|
|
||||||
|
static inline void xv_splice(xvect *, size_t, ptrdiff_t);
|
||||||
|
static inline void xv_insert(xvect *, size_t, void *);
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_init(xvect *x, size_t width)
|
||||||
|
{
|
||||||
|
x->data = NULL;
|
||||||
|
x->width = width;
|
||||||
|
x->size = 0;
|
||||||
|
x->mask = -1;
|
||||||
|
x->head = 0;
|
||||||
|
x->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_destroy(xvect *x)
|
||||||
|
{
|
||||||
|
free(x->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
xv_size(xvect *x)
|
||||||
|
{
|
||||||
|
return x->tail < x->head
|
||||||
|
? x->tail + x->size - x->head
|
||||||
|
: x->tail - x->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
xv_round2(size_t x)
|
||||||
|
{
|
||||||
|
x -= 1;
|
||||||
|
x |= (x >> 1);
|
||||||
|
x |= (x >> 2);
|
||||||
|
x |= (x >> 4);
|
||||||
|
x |= (x >> 8);
|
||||||
|
x |= (x >> 16);
|
||||||
|
x |= (x >> 32);
|
||||||
|
x++;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_rotate(xvect *x)
|
||||||
|
{
|
||||||
|
if (x->tail < x->head) {
|
||||||
|
char buf[x->size * x->width];
|
||||||
|
|
||||||
|
/* perform rotation */
|
||||||
|
memcpy(buf, x->data, sizeof buf);
|
||||||
|
memcpy(x->data, buf + x->head * x->width, (x->size - x->head) * x->width);
|
||||||
|
memcpy(x->data + (x->size - x->head) * x->width, buf, x->tail * x->width);
|
||||||
|
x->tail = x->size - x->head + x->tail;
|
||||||
|
x->head = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_adjust(xvect *x, size_t size)
|
||||||
|
{
|
||||||
|
size = xv_round2(size);
|
||||||
|
if (size != x->size) {
|
||||||
|
xv_rotate(x);
|
||||||
|
x->data = realloc(x->data, size * x->width);
|
||||||
|
x->size = size;
|
||||||
|
x->mask = size - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_reserve(xvect *x, size_t mincapa)
|
||||||
|
{
|
||||||
|
if (x->size < mincapa + 1) {
|
||||||
|
xv_adjust(x, mincapa + 1); /* capa == size - 1 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_shrink(xvect *x, size_t maxcapa)
|
||||||
|
{
|
||||||
|
if (x->size > maxcapa + 1) {
|
||||||
|
xv_adjust(x, maxcapa + 1); /* capa == size - 1 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
xv_get(xvect *x, size_t i)
|
||||||
|
{
|
||||||
|
return x->data + ((x->head + x->size + i) & x->mask) * x->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_set(xvect *x, size_t i, void *src)
|
||||||
|
{
|
||||||
|
memcpy(xv_get(x, i), src, x->width);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_push(xvect *x, void *src)
|
||||||
|
{
|
||||||
|
xv_reserve(x, xv_size(x) + 1);
|
||||||
|
xv_set(x, xv_size(x), src);
|
||||||
|
x->tail = (x->tail + 1) & x->mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
xv_pop(xvect *x)
|
||||||
|
{
|
||||||
|
x->tail = (x->tail + x->size - 1) & x->mask;
|
||||||
|
return xv_get(x, xv_size(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
xv_shift(xvect *x)
|
||||||
|
{
|
||||||
|
x->head = (x->head + 1) & x->mask;
|
||||||
|
return xv_get(x, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_unshift(xvect *x, void *src)
|
||||||
|
{
|
||||||
|
xv_reserve(x, xv_size(x) + 1);
|
||||||
|
xv_set(x, -1, src);
|
||||||
|
x->head = (x->head + x->size - 1) & x->mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_splice(xvect *x, size_t i, ptrdiff_t c)
|
||||||
|
{
|
||||||
|
xv_reserve(x, xv_size(x) - c);
|
||||||
|
xv_rotate(x);
|
||||||
|
memmove(xv_get(x, i), xv_get(x, i + c), (xv_size(x) - i - c) * x->width);
|
||||||
|
x->tail -= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
xv_insert(xvect *x, size_t i, void *src)
|
||||||
|
{
|
||||||
|
xv_splice(x, i, -1);
|
||||||
|
xv_set(x, i, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,445 @@
|
||||||
|
#include "xfile.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define min(a,b) (((a)>(b))?(b):(a))
|
||||||
|
#define max(a,b) (((a)<(b))?(b):(a))
|
||||||
|
|
||||||
|
#define XF_EOF 1
|
||||||
|
#define XF_ERR 2
|
||||||
|
|
||||||
|
xFILE *
|
||||||
|
xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *))
|
||||||
|
{
|
||||||
|
xFILE *file;
|
||||||
|
|
||||||
|
file = (xFILE *)malloc(sizeof(xFILE));
|
||||||
|
if (! file) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
file->ungot = -1;
|
||||||
|
file->flags = 0;
|
||||||
|
/* set vtable */
|
||||||
|
file->vtable.cookie = cookie;
|
||||||
|
file->vtable.read = read;
|
||||||
|
file->vtable.write = write;
|
||||||
|
file->vtable.seek = seek;
|
||||||
|
file->vtable.flush = flush;
|
||||||
|
file->vtable.close = close;
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
xFILE *
|
||||||
|
xfopen(const char *filename, const char *mode)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
xFILE *file;
|
||||||
|
|
||||||
|
fp = fopen(filename, mode);
|
||||||
|
if (! fp) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = xfpopen(fp);
|
||||||
|
if (! file) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfclose(xFILE *file)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = file->vtable.close(file->vtable.cookie);
|
||||||
|
if (r == EOF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfflush(xFILE *file)
|
||||||
|
{
|
||||||
|
return file->vtable.flush(file->vtable.cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||||
|
{
|
||||||
|
char *dst = (char *)ptr;
|
||||||
|
char buf[block];
|
||||||
|
size_t i, offset;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems; ++i) {
|
||||||
|
offset = 0;
|
||||||
|
if (file->ungot != -1 && block > 0) {
|
||||||
|
buf[0] = file->ungot;
|
||||||
|
offset += 1;
|
||||||
|
file->ungot = -1;
|
||||||
|
}
|
||||||
|
while (offset < block) {
|
||||||
|
n = file->vtable.read(file->vtable.cookie, buf + offset, block - offset);
|
||||||
|
if (n < 0) {
|
||||||
|
file->flags |= XF_ERR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
file->flags |= XF_EOF;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
memcpy(dst, buf, block);
|
||||||
|
dst += block;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||||
|
{
|
||||||
|
char *dst = (char *)ptr;
|
||||||
|
size_t i, offset;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems; ++i) {
|
||||||
|
offset = 0;
|
||||||
|
while (offset < block) {
|
||||||
|
n = file->vtable.write(file->vtable.cookie, dst + offset, block - offset);
|
||||||
|
if (n < 0) {
|
||||||
|
file->flags |= XF_ERR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
dst += block;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
xfseek(xFILE *file, long offset, int whence)
|
||||||
|
{
|
||||||
|
file->ungot = -1;
|
||||||
|
return file->vtable.seek(file->vtable.cookie, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
xftell(xFILE *file)
|
||||||
|
{
|
||||||
|
return xfseek(file, 0, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xrewind(xFILE *file)
|
||||||
|
{
|
||||||
|
xfseek(file, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xclearerr(xFILE *file)
|
||||||
|
{
|
||||||
|
file->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfeof(xFILE *file)
|
||||||
|
{
|
||||||
|
return file->flags & XF_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xferror(xFILE *file)
|
||||||
|
{
|
||||||
|
return file->flags & XF_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfgetc(xFILE *file)
|
||||||
|
{
|
||||||
|
char buf[1];
|
||||||
|
|
||||||
|
xfread(buf, 1, 1, file);
|
||||||
|
|
||||||
|
if (xfeof(file)) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xungetc(int c, xFILE *file)
|
||||||
|
{
|
||||||
|
file->ungot = c;
|
||||||
|
if (c != EOF) {
|
||||||
|
file->flags &= ~XF_EOF;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xgetchar(void)
|
||||||
|
{
|
||||||
|
return xfgetc(xstdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfputc(int c, xFILE *file)
|
||||||
|
{
|
||||||
|
char buf[1];
|
||||||
|
|
||||||
|
buf[0] = c;
|
||||||
|
xfwrite(buf, 1, 1, file);
|
||||||
|
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xputchar(int c)
|
||||||
|
{
|
||||||
|
return xfputc(c, xstdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfputs(const char *str, xFILE *file)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen(str);
|
||||||
|
xfwrite(str, len, 1, file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
n = xvfprintf(xstdout, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfprintf(xFILE *stream, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
n = xvfprintf(stream, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
va_list ap2;
|
||||||
|
|
||||||
|
va_copy(ap2, ap);
|
||||||
|
{
|
||||||
|
char buf[vsnprintf(NULL, 0, fmt, ap2)];
|
||||||
|
|
||||||
|
vsnprintf(buf, sizeof buf + 1, fmt, ap);
|
||||||
|
|
||||||
|
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(ap2);
|
||||||
|
return sizeof buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derieved xFILE Classes
|
||||||
|
*/
|
||||||
|
|
||||||
|
static FILE *
|
||||||
|
unpack(void *cookie)
|
||||||
|
{
|
||||||
|
switch ((long)cookie) {
|
||||||
|
default: return cookie;
|
||||||
|
case 0: return stdin;
|
||||||
|
case 1: return stdout;
|
||||||
|
case -1: return stderr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_read(void *cookie, char *ptr, int size)
|
||||||
|
{
|
||||||
|
FILE *file = unpack(cookie);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = fread(ptr, 1, size, file);
|
||||||
|
if (r < size && ferror(file)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (r == 0 && feof(file)) {
|
||||||
|
clearerr(file);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_write(void *cookie, const char *ptr, int size)
|
||||||
|
{
|
||||||
|
FILE *file = unpack(cookie);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = fwrite(ptr, 1, size, file);
|
||||||
|
if (r < size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
file_seek(void *cookie, long pos, int whence)
|
||||||
|
{
|
||||||
|
return fseek(unpack(cookie), pos, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_flush(void *cookie)
|
||||||
|
{
|
||||||
|
return fflush(unpack(cookie));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_close(void *cookie)
|
||||||
|
{
|
||||||
|
return fclose(unpack(cookie));
|
||||||
|
}
|
||||||
|
|
||||||
|
xFILE *
|
||||||
|
xfpopen(FILE *fp)
|
||||||
|
{
|
||||||
|
xFILE *file;
|
||||||
|
|
||||||
|
file = xfunopen(fp, file_read, file_write, file_seek, file_flush, file_close);
|
||||||
|
if (! file) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FILE_VTABLE file_read, file_write, file_seek, file_flush, file_close
|
||||||
|
|
||||||
|
static xFILE xfile_stdin = { -1, 0, { (void *)0, FILE_VTABLE } };
|
||||||
|
static xFILE xfile_stdout = { -1, 0, { (void *)1, FILE_VTABLE } };
|
||||||
|
static xFILE xfile_stderr = { -1, 0, { (void *)-1, FILE_VTABLE } };
|
||||||
|
|
||||||
|
xFILE *xstdin = &xfile_stdin;
|
||||||
|
xFILE *xstdout = &xfile_stdout;
|
||||||
|
xFILE *xstderr = &xfile_stderr;
|
||||||
|
|
||||||
|
struct membuf {
|
||||||
|
char *buf;
|
||||||
|
long pos, end, capa;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
mem_read(void *cookie, char *ptr, int size)
|
||||||
|
{
|
||||||
|
struct membuf *mem;
|
||||||
|
|
||||||
|
mem = (struct membuf *)cookie;
|
||||||
|
|
||||||
|
size = min(size, mem->end - mem->pos);
|
||||||
|
memcpy(ptr, mem->buf + mem->pos, size);
|
||||||
|
mem->pos += size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mem_write(void *cookie, const char *ptr, int size)
|
||||||
|
{
|
||||||
|
struct membuf *mem;
|
||||||
|
|
||||||
|
mem = (struct membuf *)cookie;
|
||||||
|
|
||||||
|
if (mem->pos + size >= mem->capa) {
|
||||||
|
mem->capa = (mem->pos + size) * 2;
|
||||||
|
mem->buf = realloc(mem->buf, mem->capa);
|
||||||
|
}
|
||||||
|
memcpy(mem->buf + mem->pos, ptr, size);
|
||||||
|
mem->pos += size;
|
||||||
|
mem->end = max(mem->pos, mem->end);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
mem_seek(void *cookie, long pos, int whence)
|
||||||
|
{
|
||||||
|
struct membuf *mem;
|
||||||
|
|
||||||
|
mem = (struct membuf *)cookie;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
mem->pos = pos;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
mem->pos += pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
mem->pos = mem->end + pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mem_flush(void *cookie)
|
||||||
|
{
|
||||||
|
(void)cookie;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mem_close(void *cookie)
|
||||||
|
{
|
||||||
|
struct membuf *mem;
|
||||||
|
|
||||||
|
mem = (struct membuf *)cookie;
|
||||||
|
free(mem->buf);
|
||||||
|
free(mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xFILE *
|
||||||
|
xmopen()
|
||||||
|
{
|
||||||
|
struct membuf *mem;
|
||||||
|
|
||||||
|
mem = (struct membuf *)malloc(sizeof(struct membuf));
|
||||||
|
mem->buf = (char *)malloc(BUFSIZ);
|
||||||
|
mem->pos = 0;
|
||||||
|
mem->end = 0;
|
||||||
|
mem->capa = BUFSIZ;
|
||||||
|
|
||||||
|
return xfunopen(mem, mem_read, mem_write, mem_seek, mem_flush, mem_close);
|
||||||
|
}
|
Loading…
Reference in New Issue