X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Futils.c;h=ad28086eaf41b1c2dfb379714479192dbe9354e9;hb=c3424008c9b9b1ee9ffff7ca4e92812b9021ad93;hp=1e3c363663160ac6af2724ea923f89ea7ef2e687;hpb=be6e50bfea8de4f01e6e30adfa3bcaf3f6243886;p=ashd.git diff --git a/lib/utils.c b/lib/utils.c index 1e3c363..ad28086 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -16,14 +16,15 @@ along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include +#endif #include #include #include #include +#include -#ifdef HAVE_CONFIG_H -#include -#endif #include static char *base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -306,3 +307,314 @@ char *base64decode(char *data, size_t *datalen) bufadd(buf, 0); return(buf.b); } + +int hexdigit(char c) +{ + if((c >= '0') && (c <= '9')) return(c - '0'); + else if((c >= 'a') && (c <= 'f')) return(c - 'a' + 10); + else if((c >= 'A') && (c <= 'F')) return(c - 'A' + 10); + return(-1); +} + +static int btheight(struct btree *tree) +{ + if(tree == NULL) + return(0); + return(tree->h); +} + +static void btsetheight(struct btree *tree) +{ + if(tree == NULL) + return; + tree->h = max(btheight(tree->l), btheight(tree->r)) + 1; +} + +static void bbtrl(struct btree **tree); + +static void bbtrr(struct btree **tree) +{ + struct btree *m, *l, *r; + + if(btheight((*tree)->l->r) > btheight((*tree)->l->l)) + bbtrl(&(*tree)->l); + r = (*tree); + l = r->l; + m = l->r; + r->l = m; + btsetheight(r); + l->r = r; + btsetheight(l); + *tree = l; +} + +static void bbtrl(struct btree **tree) +{ + struct btree *m, *l, *r; + + if(btheight((*tree)->r->l) > btheight((*tree)->r->r)) + bbtrr(&(*tree)->r); + l = (*tree); + r = l->r; + m = r->l; + l->r = m; + btsetheight(l); + r->l = l; + btsetheight(r); + *tree = r; +} + +static int ptrcmp(void *a, void *b) +{ + if(a < b) + return(-1); + else if(a > b) + return(1); + return(0); +} + +int bbtreedel(struct btree **tree, void *item, int (*cmp)(void *, void *)) +{ + int c, r; + struct btree *s, **sp, *o; + + if(cmp == NULL) + cmp = ptrcmp; + if(*tree == NULL) + return(0); + if((c = cmp(item, (*tree)->d)) < 0) { + r = bbtreedel(&(*tree)->l, item, cmp); + } else if(c > 0) { + r = bbtreedel(&(*tree)->r, item, cmp); + } else { + r = 1; + o = *tree; + if(((*tree)->r != NULL) && ((*tree)->l != NULL)) { + sp = &(*tree)->r; + s = *sp; + while(s->l != NULL) { + sp = &(s->l); + s = *sp; + } + *sp = (*sp)->r; + s->l = (*tree)->l; + s->r = (*tree)->r; + *tree = s; + } else if((*tree)->l != NULL) { + *tree = (*tree)->l; + } else if((*tree)->r != NULL) { + *tree = (*tree)->r; + } else { + *tree = NULL; + } + free(o); + } + if(*tree != NULL) { + btsetheight(*tree); + if(btheight((*tree)->l) > btheight((*tree)->r) + 1) + bbtrr(tree); + if(btheight((*tree)->r) > btheight((*tree)->l) + 1) + bbtrl(tree); + } + return(r); +} + +void freebtree(struct btree **tree, void (*ffunc)(void *)) +{ + if(*tree == NULL) + return; + freebtree(&(*tree)->l, ffunc); + freebtree(&(*tree)->r, ffunc); + if(ffunc != NULL) + ffunc((*tree)->d); + free(*tree); + *tree = NULL; +} + +int bbtreeput(struct btree **tree, void *item, int (*cmp)(void *, void *)) +{ + int c, r; + + if(cmp == NULL) + cmp = ptrcmp; + if(*tree == NULL) { + *tree = szmalloc(sizeof(**tree)); + (*tree)->d = item; + (*tree)->h = 1; + return(1); + } + if((c = cmp(item, (*tree)->d)) < 0) + r = bbtreeput(&(*tree)->l, item, cmp); + else if(c > 0) + r = bbtreeput(&(*tree)->r, item, cmp); + else + return(0); + btsetheight(*tree); + if(btheight((*tree)->l) > btheight((*tree)->r) + 1) + bbtrr(tree); + if(btheight((*tree)->r) > btheight((*tree)->l) + 1) + bbtrl(tree); + return(r); +} + +void *btreeget(struct btree *tree, void *key, int (*cmp)(void *, void *)) +{ + int c; + + if(cmp == NULL) + cmp = ptrcmp; + while(1) { + if(tree == NULL) + return(NULL); + c = cmp(key, tree->d); + if(c < 0) + tree = tree->l; + else if(c > 0) + tree = tree->r; + else + return(tree->d); + } +} + +struct stdif { + ssize_t (*read)(void *pdata, void *buf, size_t len); + ssize_t (*write)(void *pdata, const void *buf, size_t len); + off_t (*seek)(void *pdata, off_t offset, int whence); + int (*close)(void *pdata); + void *pdata; +}; + +#if defined(HAVE_GLIBC_STDIO) +static ssize_t wrapread(void *pdata, char *buf, size_t len) +{ + struct stdif *nf = pdata; + + return(nf->read(nf->pdata, buf, len)); +} + +static ssize_t wrapwrite(void *pdata, const char *buf, size_t len) +{ + struct stdif *nf = pdata; + size_t off; + ssize_t ret; + + /* + * XXX? In seeming violation of its own manual, glibc requires the + * cookie-write function to complete writing the entire buffer, + * rather than working like write(2). + */ + off = 0; + while(off < len) { + ret = nf->write(nf->pdata, buf + off, len - off); + if(ret < 0) + return(off); + off += ret; + } + return(off); +} + +static int wrapseek(void *pdata, off_t *pos, int whence) +{ + struct stdif *nf = pdata; + off_t ret; + + ret = nf->seek(nf->pdata, *pos, whence); + if(ret < 0) + return(-1); + *pos = ret; + return(0); +} + +static int wrapclose(void *pdata) +{ + struct stdif *nf = pdata; + int ret; + + if(nf->close != NULL) + ret = nf->close(nf->pdata); + else + ret = 0; + free(nf); + return(ret); +} + +FILE *funstdio(void *pdata, + ssize_t (*read)(void *pdata, void *buf, size_t len), + ssize_t (*write)(void *pdata, const void *buf, size_t len), + off_t (*seek)(void *pdata, off_t offset, int whence), + int (*close)(void *pdata)) +{ + struct stdif *nf; + cookie_io_functions_t io; + char *mode; + + if(read && write) { + mode = "r+"; + } else if(read) { + mode = "r"; + } else if(write) { + mode = "w"; + } else { + errno = EINVAL; + return(NULL); + } + omalloc(nf); + *nf = (struct stdif){.read = read, .write = write, .seek = seek, .close = close, .pdata = pdata}; + io = (cookie_io_functions_t) { + .read = read?wrapread:NULL, + .write = write?wrapwrite:NULL, + .seek = seek?wrapseek:NULL, + .close = wrapclose, + }; + return(fopencookie(nf, mode, io)); +} +#elif defined(HAVE_BSD_STDIO) +static int wrapread(void *pdata, char *buf, int len) +{ + struct stdif *nf = pdata; + + return(nf->read(nf->pdata, buf, len)); +} + +static int wrapwrite(void *pdata, const char *buf, int len) +{ + struct stdif *nf = pdata; + + return(nf->write(nf->pdata, buf, len)); +} + +static fpos_t wrapseek(void *pdata, fpos_t pos, int whence) +{ + struct stdif *nf = pdata; + + return(nf->seek(nf->pdata, pos, whence)); +} + +static int wrapclose(void *pdata) +{ + struct stdif *nf = pdata; + int ret; + + if(nf->close != NULL) + ret = nf->close(nf->pdata); + else + ret = 0; + free(nf); + return(ret); +} + +FILE *funstdio(void *pdata, + ssize_t (*read)(void *pdata, void *buf, size_t len), + ssize_t (*write)(void *pdata, const void *buf, size_t len), + off_t (*seek)(void *pdata, off_t offset, int whence), + int (*close)(void *pdata)) +{ + struct stdif *nf; + + omalloc(nf); + *nf = (struct stdif){.read = read, .write = write, .seek = seek, .close = close, .pdata = pdata}; + return(funopen(nf, read?wrapread:NULL, write?wrapwrite:NULL, seek?wrapseek:NULL, wrapclose)); +} +#else +#error "No stdio implementation for this system" +#endif