diff options
Diffstat (limited to 'qdbm/cabin.c')
-rw-r--r-- | qdbm/cabin.c | 3529 |
1 files changed, 0 insertions, 3529 deletions
diff --git a/qdbm/cabin.c b/qdbm/cabin.c deleted file mode 100644 index 262cb3eb..00000000 --- a/qdbm/cabin.c +++ /dev/null @@ -1,3529 +0,0 @@ -/************************************************************************************************* - * Implementation of Cabin - * Copyright (C) 2000-2007 Mikio Hirabayashi - * This file is part of QDBM, Quick Database Manager. - * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU - * Lesser General Public License as published by the Free Software Foundation; either version - * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * You should have received a copy of the GNU Lesser General Public License along with QDBM; if - * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - *************************************************************************************************/ - - -#define QDBM_INTERNAL 1 - -#include "cabin.h" -#include "myconf.h" - -#define CB_GCUNIT 64 /* allocation unit size of a buffer in gc */ -#define CB_SPBUFSIZ 32 /* size of a buffer for sprintf */ -#define CB_SPMAXWIDTH 128 /* max width of a column for sprintf */ -#define CB_MAPPBNUM 251 /* bucket size of a petit map handle */ -#define CB_MAPCSUNIT 52 /* small allocation unit size of map concatenation */ -#define CB_MAPCBUNIT 252 /* big allocation unit size of map concatenation */ -#define CB_MSGBUFSIZ 256 /* size of a buffer for log message */ -#define CB_IOBUFSIZ 8192 /* size of an I/O buffer */ -#define CB_FILEMODE 00644 /* permission of a creating file */ -#define CB_NUMBUFSIZ 32 /* size of a buffer for a number */ -#define CB_ENCBUFSIZ 32 /* size of a buffer for encoding name */ -#define CB_DATEBUFSIZ 64 /* size of a buffer for date expression */ -#define CB_VNUMBUFSIZ 8 /* size of a buffer for variable length number */ - -/* set a buffer for a variable length number */ -#define CB_SETVNUMBUF(CB_len, CB_buf, CB_num) \ - do { \ - int _CB_num; \ - _CB_num = (CB_num); \ - if(_CB_num == 0){ \ - ((signed char *)(CB_buf))[0] = 0; \ - (CB_len) = 1; \ - } else { \ - (CB_len) = 0; \ - while(_CB_num > 0){ \ - int _CB_rem = _CB_num & 0x7f; \ - _CB_num >>= 7; \ - if(_CB_num > 0){ \ - ((signed char *)(CB_buf))[(CB_len)] = -_CB_rem - 1; \ - } else { \ - ((signed char *)(CB_buf))[(CB_len)] = _CB_rem; \ - } \ - (CB_len)++; \ - } \ - } \ - } while(FALSE) - -/* read a variable length buffer */ -#define CB_READVNUMBUF(CB_buf, CB_size, CB_num, CB_step) \ - do { \ - int _CB_i, _CB_base; \ - CB_num = 0; \ - _CB_base = 1; \ - if((size) < 2){ \ - CB_num = ((signed char *)(CB_buf))[0]; \ - (CB_step) = 1; \ - } else { \ - for(_CB_i = 0; _CB_i < (size); _CB_i++){ \ - if(((signed char *)(CB_buf))[_CB_i] >= 0){ \ - CB_num += ((signed char *)(CB_buf))[_CB_i] * _CB_base; \ - break; \ - } \ - CB_num += _CB_base * (((signed char *)(CB_buf))[_CB_i] + 1) * -1; \ - _CB_base *= 128; \ - } \ - (CB_step) = _CB_i + 1; \ - } \ - } while(FALSE) - -/* get the first hash value */ -#define CB_FIRSTHASH(CB_res, CB_kbuf, CB_ksiz) \ - do { \ - const unsigned char *_CB_p; \ - int _CB_ksiz; \ - _CB_p = (const unsigned char *)(CB_kbuf); \ - _CB_ksiz = CB_ksiz; \ - for((CB_res) = 19780211; _CB_ksiz--;){ \ - (CB_res) = (CB_res) * 37 + *(_CB_p)++; \ - } \ - (CB_res) &= INT_MAX; \ - } while(FALSE) - -/* get the second hash value */ -#define CB_SECONDHASH(CB_res, CB_kbuf, CB_ksiz) \ - do { \ - const unsigned char *_CB_p; \ - int _CB_ksiz; \ - _CB_p = (const unsigned char *)(CB_kbuf) + CB_ksiz - 1; \ - _CB_ksiz = CB_ksiz; \ - for((CB_res) = 0x13579bdf; _CB_ksiz--;){ \ - (CB_res) = (CB_res) * 31 + *(_CB_p)--; \ - } \ - (CB_res) &= INT_MAX; \ - } while(FALSE) - - -/* private function prototypes */ -static void cbggchandler(void); -static void cbggckeeper(void *ptr, void (*func)(void *)); -static void cbqsortsub(char *bp, int nmemb, int size, char *pswap, char *vswap, - int(*compar)(const void *, const void *)); -static int cblistelemcmp(const void *a, const void *b); -static int cbkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz); - - - -/************************************************************************************************* - * public objects - *************************************************************************************************/ - - -/* Call back function for handling a fatal error. */ -void (*cbfatalfunc)(const char *message) = NULL; - - -/* Allocate a region on memory. */ -void *cbmalloc(size_t size){ - char *p; - assert(size > 0 && size < INT_MAX); - if(!(p = malloc(size))) cbmyfatal("out of memory"); - return p; -} - - -/* Re-allocate a region on memory. */ -void *cbrealloc(void *ptr, size_t size){ - char *p; - assert(size > 0); - if(!(p = realloc(ptr, size))) cbmyfatal("out of memory"); - return p; -} - - -/* Duplicate a region on memory. */ -char *cbmemdup(const char *ptr, int size){ - char *p; - assert(ptr); - if(size < 0) size = strlen(ptr); - CB_MALLOC(p, size + 1); - memcpy(p, ptr, size); - p[size] = '\0'; - return p; -} - - -/* Free a region on memory. */ -void cbfree(void *ptr){ - free(ptr); -} - - -/* Register the pointer or handle of an object to the global garbage collector. */ -void cbglobalgc(void *ptr, void (*func)(void *)){ - assert(ptr && func); - cbggckeeper(ptr, func); -} - - -/* Exercise the global garbage collector explicitly. */ -void cbggcsweep(void){ - cbggckeeper(NULL, NULL); -} - - -/* Check availability of allocation of the virtual memory. */ -int cbvmemavail(size_t size){ - assert(size >= 0); - return _qdbm_vmemavail(size); -} - - -/* Sort an array using insert sort. */ -void cbisort(void *base, int nmemb, int size, int(*compar)(const void *, const void *)){ - char *bp, *swap; - int i, j; - assert(base && nmemb >= 0 && size > 0 && compar); - bp = (char *)base; - CB_MALLOC(swap, size); - for(i = 1; i < nmemb; i++){ - if(compar(bp + (i - 1) * size, bp + i * size) > 0){ - memcpy(swap, bp + i * size, size); - for(j = i; j > 0; j--){ - if(compar(bp + (j - 1) * size, swap) < 0) break; - memcpy(bp + j * size, bp + (j - 1) * size, size); - } - memcpy(bp + j * size, swap, size); - } - } - free(swap); -} - - -/* Sort an array using shell sort. */ -void cbssort(void *base, int nmemb, int size, int(*compar)(const void *, const void *)){ - char *bp, *swap; - int step, bottom, i, j; - assert(base && nmemb >= 0 && size > 0 && compar); - bp = (char *)base; - CB_MALLOC(swap, size); - for(step = (nmemb - 1) / 3; step >= 0; step = (step - 1) / 3){ - if(step < 5) step = 1; - for(bottom = 0; bottom < step; bottom++){ - for(i = bottom + step; i < nmemb; i += step){ - if(compar(bp + (i - step) * size, bp + i * size) > 0){ - memcpy(swap, bp + i * size, size); - for(j = i; j > step - 1; j -= step){ - if(compar(bp + (j - step) * size, swap) < 0) break; - memcpy(bp + j * size, bp + (j - step) * size, size); - } - memcpy(bp + j * size, swap, size); - } - } - } - if(step < 2) break; - } - free(swap); -} - - -/* Sort an array using heap sort. */ -void cbhsort(void *base, int nmemb, int size, int(*compar)(const void *, const void *)){ - char *bp, *swap; - int top, bottom, mybot, i; - assert(base && nmemb >= 0 && size > 0 && compar); - bp = (char *)base; - nmemb--; - bottom = nmemb / 2 + 1; - top = nmemb; - CB_MALLOC(swap, size); - while(bottom > 0){ - bottom--; - mybot = bottom; - i = 2 * mybot; - while(i <= top) { - if(i < top && compar(bp + (i + 1) * size, bp + i * size) > 0) i++; - if(compar(bp + mybot * size, bp + i * size) >= 0) break; - memcpy(swap, bp + mybot * size, size); - memcpy(bp + mybot * size, bp + i * size, size); - memcpy(bp + i * size, swap, size); - mybot = i; - i = 2 * mybot; - } - } - while(top > 0){ - memcpy(swap, bp, size); - memcpy(bp, bp + top * size, size); - memcpy(bp + top * size, swap, size); - top--; - mybot = bottom; - i = 2 * mybot; - while(i <= top){ - if(i < top && compar(bp + (i + 1) * size, bp + i * size) > 0) i++; - if(compar(bp + mybot * size, bp + i * size) >= 0) break; - memcpy(swap, bp + mybot * size, size); - memcpy(bp + mybot * size, bp + i * size, size); - memcpy(bp + i * size, swap, size); - mybot = i; - i = 2 * mybot; - } - } - free(swap); -} - - -/* Sort an array using quick sort. */ -void cbqsort(void *base, int nmemb, int size, int(*compar)(const void *, const void *)){ - char *pswap, *vswap; - assert(base && nmemb >= 0 && size > 0 && compar); - CB_MALLOC(pswap, size); - CB_MALLOC(vswap, size); - cbqsortsub(base, nmemb, size, pswap, vswap, compar); - free(vswap); - free(pswap); -} - - -/* Compare two strings with case insensitive evaluation. */ -int cbstricmp(const char *astr, const char *bstr){ - int ac, bc; - assert(astr && bstr); - while(*astr != '\0'){ - if(*bstr == '\0') return 1; - ac = (*astr >= 'A' && *astr <= 'Z') ? *astr + ('a' - 'A') : *(unsigned char *)astr; - bc = (*bstr >= 'A' && *bstr <= 'Z') ? *bstr + ('a' - 'A') : *(unsigned char *)bstr; - if(ac != bc) return ac - bc; - astr++; - bstr++; - } - return *bstr == '\0' ? 0 : -1; -} - - -/* Check whether a string begins with a key. */ -int cbstrfwmatch(const char *str, const char *key){ - assert(str && key); - while(*key != '\0'){ - if(*str != *key || *str == '\0') return FALSE; - key++; - str++; - } - return TRUE; -} - - -/* Check whether a string begins with a key, with case insensitive evaluation. */ -int cbstrfwimatch(const char *str, const char *key){ - int sc, kc; - assert(str && key); - while(*key != '\0'){ - if(*str == '\0') return FALSE; - sc = *str; - if(sc >= 'A' && sc <= 'Z') sc += 'a' - 'A'; - kc = *key; - if(kc >= 'A' && kc <= 'Z') kc += 'a' - 'A'; - if(sc != kc) return FALSE; - key++; - str++; - } - return TRUE; -} - - -/* Check whether a string ends with a key. */ -int cbstrbwmatch(const char *str, const char *key){ - int slen, klen, i; - assert(str && key); - slen = strlen(str); - klen = strlen(key); - for(i = 1; i <= klen; i++){ - if(i > slen || str[slen-i] != key[klen-i]) return FALSE; - } - return TRUE; -} - - -/* Check whether a string ends with a key, with case insensitive evaluation. */ -int cbstrbwimatch(const char *str, const char *key){ - int slen, klen, i, sc, kc; - assert(str && key); - slen = strlen(str); - klen = strlen(key); - for(i = 1; i <= klen; i++){ - if(i > slen) return FALSE; - sc = str[slen-i]; - if(sc >= 'A' && sc <= 'Z') sc += 'a' - 'A'; - kc = key[klen-i]; - if(kc >= 'A' && kc <= 'Z') kc += 'a' - 'A'; - if(sc != kc) return FALSE; - } - return TRUE; -} - - -/* Locate a substring in a string using KMP method. */ -char *cbstrstrkmp(const char *haystack, const char *needle){ - int i, j, hlen, nlen; - signed char tbl[0x100]; - assert(haystack && needle); - nlen = strlen(needle); - if(nlen >= 0x100) return strstr(haystack, needle); - tbl[0] = -1; - i = 0; - j = -1; - while(i < nlen){ - while((j >= 0) && (needle[i] != needle[j])){ - j = tbl[j]; - } - i++; - j++; - tbl[i] = j; - } - hlen = strlen(haystack); - i = 0; - j = 0; - while(i < hlen && j < nlen){ - while((j >= 0) && (haystack[i] != needle[j])){ - j = tbl[j]; - } - i++; - j++; - } - if(j == nlen) return (char *)(haystack + i - nlen); - return NULL; -} - - -/* Locate a substring in a string using BM method. */ -char *cbstrstrbm(const char *haystack, const char *needle){ - const unsigned char *rp; - const char *ep; - unsigned char tbl[0x100]; - int i, j, nlen, len, idx; - assert(haystack && needle); - nlen = strlen(needle); - if(nlen < 3 || nlen >= 0x100) return strstr(haystack, needle); - for(i = 0; i < 0x100; i++){ - tbl[i] = nlen; - } - len = nlen; - rp = (const unsigned char *)needle; - while(len > 0){ - tbl[*rp++] = --len; - } - nlen--; - ep = haystack + strlen(haystack) - nlen; - while(haystack < ep){ - for(i = nlen; haystack[i] == needle[i]; i--){ - if(i == 0) return (char *)haystack; - } - idx = ((unsigned char *)haystack)[i]; - j = tbl[idx] - nlen + i; - haystack += j > 0 ? j : 2; - } - return NULL; -} - - -/* Convert the letters of a string to upper case. */ -char *cbstrtoupper(char *str){ - int i; - assert(str); - for(i = 0; str[i] != '\0'; i++){ - if(str[i] >= 'a' && str[i] <= 'z') str[i] -= 'a' - 'A'; - } - return str; -} - - -/* Convert the letters of a string to lower case. */ -char *cbstrtolower(char *str){ - int i; - assert(str); - for(i = 0; str[i] != '\0'; i++){ - if(str[i] >= 'A' && str[i] <= 'Z') str[i] += 'a' - 'A'; - } - return str; -} - - -/* Cut space characters at head or tail of a string. */ -char *cbstrtrim(char *str){ - char *wp; - int i, head; - assert(str); - wp = str; - head = TRUE; - for(i = 0; str[i] != '\0'; i++){ - if((str[i] >= 0x07 && str[i] <= 0x0d) || str[i] == 0x20){ - if(!head) *(wp++) = str[i]; - } else { - *(wp++) = str[i]; - head = FALSE; - } - } - *wp = '\0'; - while(wp > str && ((wp[-1] >= 0x07 && wp[-1] <= 0x0d) || wp[-1] == 0x20)){ - *(--wp) = '\0'; - } - return str; -} - - -/* Squeeze space characters in a string and trim it. */ -char *cbstrsqzspc(char *str){ - char *wp; - int i, spc; - assert(str); - wp = str; - spc = TRUE; - for(i = 0; str[i] != '\0'; i++){ - if(str[i] > 0 && str[i] <= ' '){ - if(!spc) *(wp++) = str[i]; - spc = TRUE; - } else { - *(wp++) = str[i]; - spc = FALSE; - } - } - *wp = '\0'; - for(wp--; wp >= str; wp--){ - if(*wp > 0 && *wp <= ' '){ - *wp = '\0'; - } else { - break; - } - } - return str; -} - - -/* Count the number of characters in a string of UTF-8. */ -int cbstrcountutf(const char *str){ - const unsigned char *rp; - int cnt; - assert(str); - rp = (unsigned char *)str; - cnt = 0; - while(*rp != '\0'){ - if((*rp & 0x80) == 0x00 || (*rp & 0xe0) == 0xc0 || - (*rp & 0xf0) == 0xe0 || (*rp & 0xf8) == 0xf0) cnt++; - rp++; - } - return cnt; -} - - -/* Cut a string of UTF-8 at the specified number of characters. */ -char *cbstrcututf(char *str, int num){ - unsigned char *wp; - int cnt; - assert(str && num >= 0); - wp = (unsigned char *)str; - cnt = 0; - while(*wp != '\0'){ - if((*wp & 0x80) == 0x00 || (*wp & 0xe0) == 0xc0 || - (*wp & 0xf0) == 0xe0 || (*wp & 0xf8) == 0xf0){ - cnt++; - if(cnt > num){ - *wp = '\0'; - break; - } - } - wp++; - } - return str; -} - - -/* Get a datum handle. */ -CBDATUM *cbdatumopen(const char *ptr, int size){ - CBDATUM *datum; - CB_MALLOC(datum, sizeof(*datum)); - CB_MALLOC(datum->dptr, CB_DATUMUNIT); - datum->dptr[0] = '\0'; - datum->dsize = 0; - datum->asize = CB_DATUMUNIT; - if(ptr) CB_DATUMCAT(datum, ptr, (size >= 0 ? size : strlen(ptr))); - return datum; -} - - -/* Copy a datum. */ -CBDATUM *cbdatumdup(const CBDATUM *datum){ - assert(datum); - return cbdatumopen(datum->dptr, datum->dsize); -} - - -/* Free a datum handle. */ -void cbdatumclose(CBDATUM *datum){ - assert(datum); - free(datum->dptr); - free(datum); -} - - -/* Concatenate a datum and a region. */ -void cbdatumcat(CBDATUM *datum, const char *ptr, int size){ - assert(datum && ptr); - if(size < 0) size = strlen(ptr); - if(datum->dsize + size >= datum->asize){ - datum->asize = datum->asize * 2 + size + 1; - CB_REALLOC(datum->dptr, datum->asize); - } - memcpy(datum->dptr + datum->dsize, ptr, size); - datum->dsize += size; - datum->dptr[datum->dsize] = '\0'; -} - - -/* Get the pointer of the region of a datum. */ -const char *cbdatumptr(const CBDATUM *datum){ - assert(datum); - return datum->dptr; -} - - -/* Get the size of the region of a datum. */ -int cbdatumsize(const CBDATUM *datum){ - assert(datum); - return datum->dsize; -} - - -/* Set the size of the region of a datum. */ -void cbdatumsetsize(CBDATUM *datum, int size){ - assert(datum && size >= 0); - if(size <= datum->dsize){ - datum->dsize = size; - datum->dptr[size] = '\0'; - } else { - if(size >= datum->asize){ - datum->asize = datum->asize * 2 + size + 1; - CB_REALLOC(datum->dptr, datum->asize); - } - memset(datum->dptr + datum->dsize, 0, (size - datum->dsize) + 1); - datum->dsize = size; - } -} - - -/* Perform formatted output into a datum. */ -void cbdatumprintf(CBDATUM *datum, const char *format, ...){ - va_list ap; - char *tmp, cbuf[CB_NUMBUFSIZ], tbuf[CB_NUMBUFSIZ*2]; - unsigned char c; - int cblen, tlen; - assert(datum && format); - va_start(ap, format); - while(*format != '\0'){ - if(*format == '%'){ - cbuf[0] = '%'; - cblen = 1; - format++; - while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < CB_NUMBUFSIZ - 1){ - cbuf[cblen++] = *format; - format++; - } - cbuf[cblen++] = *format; - cbuf[cblen] = '\0'; - switch(*format){ - case 's': - tmp = va_arg(ap, char *); - if(!tmp) tmp = "(null)"; - cbdatumcat(datum, tmp, -1); - break; - case 'd': - tlen = sprintf(tbuf, cbuf, va_arg(ap, int)); - cbdatumcat(datum, tbuf, tlen); - break; - case 'o': case 'u': case 'x': case 'X': case 'c': - tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int)); - cbdatumcat(datum, tbuf, tlen); - break; - case 'e': case 'E': case 'f': case 'g': case 'G': - tlen = sprintf(tbuf, cbuf, va_arg(ap, double)); - cbdatumcat(datum, tbuf, tlen); - break; - case '@': - tmp = va_arg(ap, char *); - if(!tmp) tmp = "(null)"; - while(*tmp){ - switch(*tmp){ - case '&': cbdatumcat(datum, "&", 5); break; - case '<': cbdatumcat(datum, "<", 4); break; - case '>': cbdatumcat(datum, ">", 4); break; - case '"': cbdatumcat(datum, """, 6); break; - default: - if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f))) - cbdatumcat(datum, tmp, 1); - break; - } - tmp++; - } - break; - case '?': - tmp = va_arg(ap, char *); - if(!tmp) tmp = "(null)"; - while(*tmp){ - c = *(unsigned char *)tmp; - if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){ - cbdatumcat(datum, tmp, 1); - } else { - tlen = sprintf(tbuf, "%%%02X", c); - cbdatumcat(datum, tbuf, tlen); - } - tmp++; - } - break; - case ':': - tmp = va_arg(ap, char *); - if(!tmp) tmp = ""; - tmp = cbmimeencode(tmp, "UTF-8", TRUE); - cbdatumcat(datum, tmp, -1); - free(tmp); - break; - case '%': - cbdatumcat(datum, "%", 1); - break; - } - } else { - cbdatumcat(datum, format, 1); - } - format++; - } - va_end(ap); -} - - -/* Convert a datum to an allocated region. */ -char *cbdatumtomalloc(CBDATUM *datum, int *sp){ - char *ptr; - assert(datum); - ptr = datum->dptr; - if(sp) *sp = datum->dsize; - free(datum); - return ptr; -} - - -/* Get a list handle. */ -CBLIST *cblistopen(void){ - CBLIST *list; - CB_MALLOC(list, sizeof(*list)); - list->anum = CB_LISTUNIT; - CB_MALLOC(list->array, sizeof(list->array[0]) * list->anum); - list->start = 0; - list->num = 0; - return list; -} - - -/* Copy a list. */ -CBLIST *cblistdup(const CBLIST *list){ - CBLIST *newlist; - int i, size; - const char *val; - assert(list); - CB_LISTOPEN2(newlist, CB_LISTNUM(list)); - for(i = 0; i < CB_LISTNUM(list); i++){ - val = CB_LISTVAL2(list, i, size); - CB_LISTPUSH(newlist, val, size); - } - return newlist; -} - - -/* Close a list handle. */ -void cblistclose(CBLIST *list){ - int i, end; - assert(list); - end = list->start + list->num; - for(i = list->start; i < end; i++){ - free(list->array[i].dptr); - } - free(list->array); - free(list); -} - - -/* Get the number of elements of a list. */ -int cblistnum(const CBLIST *list){ - assert(list); - return list->num; -} - - -/* Get the pointer to the region of an element. */ -const char *cblistval(const CBLIST *list, int index, int *sp){ - assert(list && index >= 0); - if(index >= list->num) return NULL; - index += list->start; - if(sp) *sp = list->array[index].dsize; - return list->array[index].dptr; -} - - -/* Add an element at the end of a list. */ -void cblistpush(CBLIST *list, const char *ptr, int size){ - int index; - assert(list && ptr); - if(size < 0) size = strlen(ptr); - index = list->start + list->num; - if(index >= list->anum){ - list->anum *= 2; - CB_REALLOC(list->array, list->anum * sizeof(list->array[0])); - } - CB_MALLOC(list->array[index].dptr, (size < CB_DATUMUNIT ? CB_DATUMUNIT : size) + 1); - memcpy(list->array[index].dptr, ptr, size); - list->array[index].dptr[size] = '\0'; - list->array[index].dsize = size; - list->num++; -} - - -/* Remove an element of the end of a list. */ -char *cblistpop(CBLIST *list, int *sp){ - int index; - assert(list); - if(list->num < 1) return NULL; - index = list->start + list->num - 1; - list->num--; - if(sp) *sp = list->array[index].dsize; - return list->array[index].dptr; -} - - -/* Add an element at the top of a list. */ -void cblistunshift(CBLIST *list, const char *ptr, int size){ - int index; - assert(list && ptr); - if(size < 0) size = strlen(ptr); - if(list->start < 1){ - if(list->start + list->num >= list->anum){ - list->anum *= 2; - CB_REALLOC(list->array, list->anum * sizeof(list->array[0])); - } - list->start = list->anum - list->num; - memmove(list->array + list->start, list->array, list->num * sizeof(list->array[0])); - } - index = list->start - 1; - CB_MALLOC(list->array[index].dptr, (size < CB_DATUMUNIT ? CB_DATUMUNIT : size) + 1); - memcpy(list->array[index].dptr, ptr, size); - list->array[index].dptr[size] = '\0'; - list->array[index].dsize = size; - list->start--; - list->num++; -} - - -/* Remove an element of the top of a list. */ -char *cblistshift(CBLIST *list, int *sp){ - int index; - assert(list); - if(list->num < 1) return NULL; - index = list->start; - list->start++; - list->num--; - if(sp) *sp = list->array[index].dsize; - return list->array[index].dptr; -} - - -/* Add an element at the specified location of a list. */ -void cblistinsert(CBLIST *list, int index, const char *ptr, int size){ - assert(list && index >= 0); - if(index > list->num) return; - if(size < 0) size = strlen(ptr); - index += list->start; - if(list->start + list->num >= list->anum){ - list->anum *= 2; - CB_REALLOC(list->array, list->anum * sizeof(list->array[0])); - } - memmove(list->array + index + 1, list->array + index, - sizeof(list->array[0]) * (list->start + list->num - index)); - CB_MEMDUP(list->array[index].dptr, ptr, size); - list->array[index].dsize = size; - list->num++; -} - - -/* Remove an element at the specified location of a list. */ -char *cblistremove(CBLIST *list, int index, int *sp){ - char *dptr; - assert(list && index >= 0); - if(index >= list->num) return NULL; - index += list->start; - dptr = list->array[index].dptr; - if(sp) *sp = list->array[index].dsize; - list->num--; - memmove(list->array + index, list->array + index + 1, - sizeof(list->array[0]) * (list->start + list->num - index)); - return dptr; -} - - -/* Overwrite an element at the specified location of a list. */ -void cblistover(CBLIST *list, int index, const char *ptr, int size){ - assert(list && index >= 0); - if(index >= list->num) return; - if(size < 0) size = strlen(ptr); - index += list->start; - if(size > list->array[index].dsize) - CB_REALLOC(list->array[index].dptr, size + 1); - memcpy(list->array[index].dptr, ptr, size); - list->array[index].dsize = size; - list->array[index].dptr[size] = '\0'; -} - - -/* Sort elements of a list in lexical order. */ -void cblistsort(CBLIST *list){ - assert(list); - qsort(list->array + list->start, list->num, sizeof(list->array[0]), cblistelemcmp); -} - - -/* Search a list for an element using liner search. */ -int cblistlsearch(const CBLIST *list, const char *ptr, int size){ - int i, end; - assert(list && ptr); - if(size < 0) size = strlen(ptr); - end = list->start + list->num; - for(i = list->start; i < end; i++){ - if(list->array[i].dsize == size && !memcmp(list->array[i].dptr, ptr, size)) - return i - list->start; - } - return -1; -} - - -/* Search a list for an element using binary search. */ -int cblistbsearch(const CBLIST *list, const char *ptr, int size){ - CBLISTDATUM key, *res; - assert(list && ptr); - if(size < 0) size = strlen(ptr); - CB_MEMDUP(key.dptr, ptr, size); - key.dsize = size; - res = bsearch(&key, list->array + list->start, list->num, sizeof(list->array[0]), cblistelemcmp); - free(key.dptr); - return res ? (res - list->array - list->start) : -1; -} - - -/* Serialize a list into a byte array. */ -char *cblistdump(const CBLIST *list, int *sp){ - char *buf, vnumbuf[CB_VNUMBUFSIZ]; - const char *vbuf; - int i, bsiz, vnumsiz, ln, vsiz; - assert(list && sp); - ln = CB_LISTNUM(list); - CB_SETVNUMBUF(vnumsiz, vnumbuf, ln); - CB_MALLOC(buf, vnumsiz + 1); - memcpy(buf, vnumbuf, vnumsiz); - bsiz = vnumsiz; - for(i = 0; i < ln; i++){ - vbuf = CB_LISTVAL2(list, i, vsiz); - CB_SETVNUMBUF(vnumsiz, vnumbuf, vsiz); - CB_REALLOC(buf, bsiz + vnumsiz + vsiz + 1); - memcpy(buf + bsiz, vnumbuf, vnumsiz); - bsiz += vnumsiz; - memcpy(buf + bsiz, vbuf, vsiz); - bsiz += vsiz; - } - *sp = bsiz; - return buf; -} - - -/* Redintegrate a serialized list. */ -CBLIST *cblistload(const char *ptr, int size){ - CBLIST *list; - const char *rp; - int i, anum, step, ln, vsiz; - assert(ptr && size >= 0); - anum = size / (sizeof(CBLISTDATUM) + 1); - CB_LISTOPEN2(list, anum); - rp = ptr; - CB_READVNUMBUF(rp, size, ln, step); - rp += step; - size -= step; - if(ln > size) return list; - for(i = 0; i < ln; i++){ - if(size < 1) break; - CB_READVNUMBUF(rp, size, vsiz, step); - rp += step; - size -= step; - if(vsiz > size) break; - CB_LISTPUSH(list, rp, vsiz); - rp += vsiz; - } - return list; -} - - -/* Get a map handle. */ -CBMAP *cbmapopen(void){ - return cbmapopenex(CB_MAPBNUM); -} - - -/* Copy a map. */ -CBMAP *cbmapdup(CBMAP *map){ - CBMAP *newmap; - const char *kbuf, *vbuf; - int ksiz, vsiz; - assert(map); - cbmapiterinit(map); - newmap = map->rnum > CB_MAPPBNUM ? cbmapopen() : cbmapopenex(CB_MAPPBNUM); - while((kbuf = cbmapiternext(map, &ksiz)) != NULL){ - CB_MAPITERVAL(vbuf, kbuf, vsiz); - cbmapput(newmap, kbuf, ksiz, vbuf, vsiz, FALSE); - } - cbmapiterinit(map); - return newmap; -} - - -/* Close a map handle. */ -void cbmapclose(CBMAP *map){ - CBMAPDATUM *datum, *next; - datum = map->first; - while(datum){ - next = datum->next; - free(datum); - datum = next; - } - free(map->buckets); - free(map); -} - - -/* Store a record. */ -int cbmapput(CBMAP *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int over){ - CBMAPDATUM *datum, **entp, *old; - char *dbuf; - int bidx, hash, kcmp, psiz; - assert(map && kbuf && vbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - if(vsiz < 0) vsiz = strlen(vbuf); - CB_FIRSTHASH(hash, kbuf, ksiz); - bidx = hash % map->bnum; - datum = map->buckets[bidx]; - entp = map->buckets + bidx; - CB_SECONDHASH(hash, kbuf, ksiz); - while(datum){ - if(hash > datum->hash){ - entp = &(datum->left); - datum = datum->left; - } else if(hash < datum->hash){ - entp = &(datum->right); - datum = datum->right; - } else { - dbuf = (char *)datum + sizeof(*datum); - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - entp = &(datum->left); - datum = datum->left; - } else if(kcmp > 0){ - entp = &(datum->right); - datum = datum->right; - } else { - if(!over) return FALSE; - psiz = CB_ALIGNPAD(ksiz); - if(vsiz > datum->vsiz){ - old = datum; - CB_REALLOC(datum, sizeof(*datum) + ksiz + psiz + vsiz + 1); - if(datum != old){ - if(map->first == old) map->first = datum; - if(map->last == old) map->last = datum; - if(*entp == old) *entp = datum; - if(datum->prev) datum->prev->next = datum; - if(datum->next) datum->next->prev = datum; - dbuf = (char *)datum + sizeof(*datum); - } - } - memcpy(dbuf + ksiz + psiz, vbuf, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - datum->vsiz = vsiz; - return TRUE; - } - } - } - psiz = CB_ALIGNPAD(ksiz); - CB_MALLOC(datum, sizeof(*datum) + ksiz + psiz + vsiz + 1); - dbuf = (char *)datum + sizeof(*datum); - memcpy(dbuf, kbuf, ksiz); - dbuf[ksiz] = '\0'; - datum->ksiz = ksiz; - memcpy(dbuf + ksiz + psiz, vbuf, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - datum->vsiz = vsiz; - datum->hash = hash; - datum->left = NULL; - datum->right = NULL; - datum->prev = map->last; - datum->next = NULL; - *entp = datum; - if(!map->first) map->first = datum; - if(map->last) map->last->next = datum; - map->last = datum; - map->rnum++; - return TRUE; -} - - -/* Concatenate a value at the end of the value of the existing record. */ -void cbmapputcat(CBMAP *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz){ - CBMAPDATUM *datum, **entp, *old; - char *dbuf; - int bidx, hash, kcmp, psiz, asiz, unit; - assert(map && kbuf && vbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - if(vsiz < 0) vsiz = strlen(vbuf); - CB_FIRSTHASH(hash, kbuf, ksiz); - bidx = hash % map->bnum; - datum = map->buckets[bidx]; - entp = map->buckets + bidx; - CB_SECONDHASH(hash, kbuf, ksiz); - while(datum){ - if(hash > datum->hash){ - entp = &(datum->left); - datum = datum->left; - } else if(hash < datum->hash){ - entp = &(datum->right); - datum = datum->right; - } else { - dbuf = (char *)datum + sizeof(*datum); - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - entp = &(datum->left); - datum = datum->left; - } else if(kcmp > 0){ - entp = &(datum->right); - datum = datum->right; - } else { - psiz = CB_ALIGNPAD(ksiz); - asiz = sizeof(*datum) + ksiz + psiz + datum->vsiz + vsiz + 1; - unit = asiz <= CB_MAPCSUNIT ? CB_MAPCSUNIT : CB_MAPCBUNIT; - asiz = (asiz - 1) + unit - (asiz - 1) % unit; - old = datum; - CB_REALLOC(datum, asiz); - if(datum != old){ - if(map->first == old) map->first = datum; - if(map->last == old) map->last = datum; - if(*entp == old) *entp = datum; - if(datum->prev) datum->prev->next = datum; - if(datum->next) datum->next->prev = datum; - dbuf = (char *)datum + sizeof(*datum); - } - memcpy(dbuf + ksiz + psiz + datum->vsiz, vbuf, vsiz); - dbuf[ksiz+psiz+datum->vsiz+vsiz] = '\0'; - datum->vsiz += vsiz; - return; - } - } - } - psiz = CB_ALIGNPAD(ksiz); - asiz = sizeof(*datum) + ksiz + psiz + vsiz + 1; - unit = asiz <= CB_MAPCSUNIT ? CB_MAPCSUNIT : CB_MAPCBUNIT; - asiz = (asiz - 1) + unit - (asiz - 1) % unit; - CB_MALLOC(datum, asiz); - dbuf = (char *)datum + sizeof(*datum); - memcpy(dbuf, kbuf, ksiz); - dbuf[ksiz] = '\0'; - datum->ksiz = ksiz; - memcpy(dbuf + ksiz + psiz, vbuf, vsiz); - dbuf[ksiz+psiz+vsiz] = '\0'; - datum->vsiz = vsiz; - datum->hash = hash; - datum->left = NULL; - datum->right = NULL; - datum->prev = map->last; - datum->next = NULL; - *entp = datum; - if(!map->first) map->first = datum; - if(map->last) map->last->next = datum; - map->last = datum; - map->rnum++; -} - - -/* Delete a record. */ -int cbmapout(CBMAP *map, const char *kbuf, int ksiz){ - CBMAPDATUM *datum, **entp, *tmp; - char *dbuf; - int bidx, hash, kcmp; - assert(map && kbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - CB_FIRSTHASH(hash, kbuf, ksiz); - bidx = hash % map->bnum; - datum = map->buckets[bidx]; - entp = map->buckets + bidx; - CB_SECONDHASH(hash, kbuf, ksiz); - while(datum){ - if(hash > datum->hash){ - entp = &(datum->left); - datum = datum->left; - } else if(hash < datum->hash){ - entp = &(datum->right); - datum = datum->right; - } else { - dbuf = (char *)datum + sizeof(*datum); - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - entp = &(datum->left); - datum = datum->left; - } else if(kcmp > 0){ - entp = &(datum->right); - datum = datum->right; - } else { - if(datum->prev) datum->prev->next = datum->next; - if(datum->next) datum->next->prev = datum->prev; - if(datum == map->first) map->first = datum->next; - if(datum == map->last) map->last = datum->prev; - if(datum->left && !datum->right){ - *entp = datum->left; - } else if(!datum->left && datum->right){ - *entp = datum->right; - } else if(!datum->left && !datum->left){ - *entp = NULL; - } else { - *entp = datum->left; - tmp = *entp; - while(TRUE){ - if(hash > tmp->hash){ - if(tmp->left){ - tmp = tmp->left; - } else { - tmp->left = datum->right; - break; - } - } else if(hash < tmp->hash){ - if(tmp->right){ - tmp = tmp->right; - } else { - tmp->right = datum->right; - break; - } - } else { - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - if(tmp->left){ - tmp = tmp->left; - } else { - tmp->left = datum->right; - break; - } - } else { - if(tmp->right){ - tmp = tmp->right; - } else { - tmp->right = datum->right; - break; - } - } - } - } - } - free(datum); - map->rnum--; - return TRUE; - } - } - } - return FALSE; -} - - -/* Retrieve a record. */ -const char *cbmapget(const CBMAP *map, const char *kbuf, int ksiz, int *sp){ - CBMAPDATUM *datum; - char *dbuf; - int hash, kcmp; - assert(map && kbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - CB_FIRSTHASH(hash, kbuf, ksiz); - datum = map->buckets[hash%map->bnum]; - CB_SECONDHASH(hash, kbuf, ksiz); - while(datum){ - if(hash > datum->hash){ - datum = datum->left; - } else if(hash < datum->hash){ - datum = datum->right; - } else { - dbuf = (char *)datum + sizeof(*datum); - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - datum = datum->left; - } else if(kcmp > 0){ - datum = datum->right; - } else { - if(sp) *sp = datum->vsiz; - return dbuf + datum->ksiz + CB_ALIGNPAD(datum->ksiz); - } - } - } - return NULL; -} - - -/* Move a record to the edge. */ -int cbmapmove(CBMAP *map, const char *kbuf, int ksiz, int head){ - CBMAPDATUM *datum; - char *dbuf; - int hash, kcmp; - assert(map && kbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - CB_FIRSTHASH(hash, kbuf, ksiz); - datum = map->buckets[hash%map->bnum]; - CB_SECONDHASH(hash, kbuf, ksiz); - while(datum){ - if(hash > datum->hash){ - datum = datum->left; - } else if(hash < datum->hash){ - datum = datum->right; - } else { - dbuf = (char *)datum + sizeof(*datum); - kcmp = cbkeycmp(kbuf, ksiz, dbuf, datum->ksiz); - if(kcmp < 0){ - datum = datum->left; - } else if(kcmp > 0){ - datum = datum->right; - } else { - if(head){ - if(map->first == datum) return TRUE; - if(map->last == datum) map->last = datum->prev; - if(datum->prev) datum->prev->next = datum->next; - if(datum->next) datum->next->prev = datum->prev; - datum->prev = NULL; - datum->next = map->first; - map->first->prev = datum; - map->first = datum; - } else { - if(map->last == datum) return TRUE; - if(map->first == datum) map->first = datum->next; - if(datum->prev) datum->prev->next = datum->next; - if(datum->next) datum->next->prev = datum->prev; - datum->prev = map->last; - datum->next = NULL; - map->last->next = datum; - map->last = datum; - } - return TRUE; - } - } - } - return FALSE; -} - - -/* Initialize the iterator of a map handle. */ -void cbmapiterinit(CBMAP *map){ - assert(map); - map->cur = map->first; -} - - -/* Get the next key of the iterator. */ -const char *cbmapiternext(CBMAP *map, int *sp){ - CBMAPDATUM *datum; - assert(map); - if(!map->cur) return NULL; - datum = map->cur; - map->cur = datum->next; - if(sp) *sp = datum->ksiz; - return (char *)datum + sizeof(*datum); -} - - -/* Get the value binded to the key fetched from the iterator. */ -const char *cbmapiterval(const char *kbuf, int *sp){ - CBMAPDATUM *datum; - assert(kbuf); - datum = (CBMAPDATUM *)(kbuf - sizeof(*datum)); - if(sp) *sp = datum->vsiz; - return (char *)datum + sizeof(*datum) + datum->ksiz + CB_ALIGNPAD(datum->ksiz); -} - - -/* Get the number of the records stored in a map. */ -int cbmaprnum(const CBMAP *map){ - assert(map); - return map->rnum; -} - - -/* Get the list handle contains all keys in a map. */ -CBLIST *cbmapkeys(CBMAP *map){ - CBLIST *list; - const char *kbuf; - int anum, ksiz; - assert(map); - anum = cbmaprnum(map); - CB_LISTOPEN2(list, anum); - cbmapiterinit(map); - while((kbuf = cbmapiternext(map, &ksiz)) != NULL){ - CB_LISTPUSH(list, kbuf, ksiz); - } - return list; -} - - -/* Get the list handle contains all values in a map. */ -CBLIST *cbmapvals(CBMAP *map){ - CBLIST *list; - const char *kbuf, *vbuf; - int anum, ksiz, vsiz; - assert(map); - anum = cbmaprnum(map); - CB_LISTOPEN2(list, anum); - cbmapiterinit(map); - while((kbuf = cbmapiternext(map, &ksiz)) != NULL){ - CB_MAPITERVAL(vbuf, kbuf, vsiz); - CB_LISTPUSH(list, vbuf, vsiz); - } - return list; -} - - -/* Serialize a map into a byte array. */ -char *cbmapdump(CBMAP *map, int *sp){ - char *buf, vnumbuf[CB_VNUMBUFSIZ]; - const char *kbuf, *vbuf; - int bsiz, vnumsiz, rn, ksiz, vsiz; - assert(map && sp); - rn = cbmaprnum(map); - CB_SETVNUMBUF(vnumsiz, vnumbuf, rn); - CB_MALLOC(buf, vnumsiz + 1); - memcpy(buf, vnumbuf, vnumsiz); - bsiz = vnumsiz; - cbmapiterinit(map); - while((kbuf = cbmapiternext(map, &ksiz)) != NULL){ - CB_MAPITERVAL(vbuf, kbuf, vsiz); - CB_SETVNUMBUF(vnumsiz, vnumbuf, ksiz); - CB_REALLOC(buf, bsiz + vnumsiz + ksiz + 1); - memcpy(buf + bsiz, vnumbuf, vnumsiz); - bsiz += vnumsiz; - memcpy(buf + bsiz, kbuf, ksiz); - bsiz += ksiz; - CB_SETVNUMBUF(vnumsiz, vnumbuf, vsiz); - CB_REALLOC(buf, bsiz + vnumsiz + vsiz + 1); - memcpy(buf + bsiz, vnumbuf, vnumsiz); - bsiz += vnumsiz; - memcpy(buf + bsiz, vbuf, vsiz); - bsiz += vsiz; - } - *sp = bsiz; - return buf; -} - - -/* Redintegrate a serialized map. */ -CBMAP *cbmapload(const char *ptr, int size){ - CBMAP *map; - const char *rp, *kbuf, *vbuf; - int i, step, rn, ksiz, vsiz; - assert(ptr && size >= 0); - map = cbmapopenex(CB_MAPPBNUM); - rp = ptr; - CB_READVNUMBUF(rp, size, rn, step); - rp += step; - size -= step; - if(rn > size) return map; - for(i = 0; i < rn; i++){ - if(size < 1) break; - CB_READVNUMBUF(rp, size, ksiz, step); - rp += step; - size -= step; - if(ksiz > size) break; - kbuf = rp; - rp += ksiz; - if(size < 1) break; - CB_READVNUMBUF(rp, size, vsiz, step); - rp += step; - size -= step; - if(vsiz > size) break; - vbuf = rp; - rp += vsiz; - cbmapput(map, kbuf, ksiz, vbuf, vsiz, TRUE); - } - return map; -} - - -/* Redintegrate a serialized map and get one of the records. */ -char *cbmaploadone(const char *ptr, int size, const char *kbuf, int ksiz, int *sp){ - const char *rp, *tkbuf, *vbuf; - char *rv; - int i, step, rn, tksiz, vsiz; - assert(ptr && size >= 0 && kbuf); - if(ksiz < 0) ksiz = strlen(kbuf); - rp = ptr; - CB_READVNUMBUF(rp, size, rn, step); - rp += step; - size -= step; - if(rn > size) return NULL; - for(i = 0; i < rn; i++){ - if(size < 1) break; - CB_READVNUMBUF(rp, size, tksiz, step); - rp += step; - size -= step; - if(tksiz > size) break; - tkbuf = rp; - rp += tksiz; - if(size < 1) break; - CB_READVNUMBUF(rp, size, vsiz, step); - rp += step; - size -= step; - if(vsiz > size) break; - vbuf = rp; - rp += vsiz; - if(tksiz == ksiz && !memcmp(tkbuf, kbuf, ksiz)){ - if(sp) *sp = vsiz; - CB_MEMDUP(rv, vbuf, vsiz); - return rv; - } - } - return NULL; -} - - -/* Get a heap handle. */ -CBHEAP *cbheapopen(int size, int max, int(*compar)(const void *, const void *)){ - CBHEAP *heap; - assert(size > 0 && max >= 0 && compar); - CB_MALLOC(heap, sizeof(*heap)); - CB_MALLOC(heap->base, size * max + 1); - CB_MALLOC(heap->swap, size); - heap->size = size; - heap->num = 0; - heap->max = max; - heap->compar = compar; - return heap; -} - - -/* Copy a heap. */ -CBHEAP *cbheapdup(CBHEAP *heap){ - CBHEAP *newheap; - assert(heap); - CB_MALLOC(newheap, sizeof(*newheap)); - CB_MEMDUP(newheap->base, heap->base, heap->size * heap->max); - CB_MALLOC(newheap->swap, heap->size); - newheap->size = heap->size; - newheap->num = heap->num; - newheap->max = heap->max; - newheap->compar = heap->compar; - return newheap; -} - - -/* Close a heap handle. */ -void cbheapclose(CBHEAP *heap){ - assert(heap); - free(heap->swap); - free(heap->base); - free(heap); -} - - -/* Get the number of the records stored in a heap. */ -int cbheapnum(CBHEAP *heap){ - assert(heap); - return heap->num; -} - - -/* Insert a record into a heap. */ -int cbheapinsert(CBHEAP *heap, const void *ptr){ - char *base; - int size, pidx, cidx, bot; - assert(heap && ptr); - if(heap->max < 1) return FALSE; - base = heap->base; - size = heap->size; - if(heap->num >= heap->max){ - if(heap->compar(ptr, base) > 0) return FALSE; - memcpy(base, ptr, size); - pidx = 0; - bot = heap->num / 2; - while(pidx < bot){ - cidx = pidx * 2 + 1; - if(cidx < heap->num - 1 && heap->compar(base + cidx * size, base + (cidx + 1) * size) < 0) - cidx++; - if(heap->compar(base + pidx * size, base + cidx * size) > 0) break; - memcpy(heap->swap, base + pidx * size, size); - memcpy(base + pidx * size, base + cidx * size, size); - memcpy(base + cidx * size, heap->swap, size); - pidx = cidx; - } - } else { - memcpy(base + size * heap->num, ptr, size); - cidx = heap->num; - while(cidx > 0){ - pidx = (cidx - 1) / 2; - if(heap->compar(base + cidx * size, base + pidx * size) <= 0) break; - memcpy(heap->swap, base + cidx * size, size); - memcpy(base + cidx * size, base + pidx * size, size); - memcpy(base + pidx * size, heap->swap, size); - cidx = pidx; - } - heap->num++; - } - return TRUE; -} - - -/* Get the pointer to the region of a record in a heap. */ -const void *cbheapval(CBHEAP *heap, int index){ - assert(heap && index >= 0); - if(index >= heap->num) return NULL; - return heap->base + index * heap->size; -} - - -/* Convert a heap to an allocated region. */ -void *cbheaptomalloc(CBHEAP *heap, int *np){ - char *ptr; - assert(heap); - qsort(heap->base, heap->num, heap->size, heap->compar); - ptr = heap->base; - if(np) *np = heap->num; - free(heap->swap); - free(heap); - return ptr; -} - - -/* Allocate a formatted string on memory. */ -char *cbsprintf(const char *format, ...){ - va_list ap; - char *buf, cbuf[CB_SPBUFSIZ], *str; - int len, cblen, num, slen; - unsigned int unum; - double dnum; - va_start(ap, format); - assert(format); - CB_MALLOC(buf, 1); - len = 0; - while(*format != '\0'){ - if(*format == '%'){ - cbuf[0] = '%'; - cblen = 1; - format++; - while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < CB_SPBUFSIZ - 1){ - cbuf[cblen++] = *format; - format++; - } - cbuf[cblen] = '\0'; - if(atoi(cbuf + 1) > CB_SPMAXWIDTH - 16){ - sprintf(cbuf, "(err)"); - } else { - cbuf[cblen++] = *format; - cbuf[cblen] = '\0'; - } - switch(*format){ - case 'd': - num = va_arg(ap, int); - CB_REALLOC(buf, len + CB_SPMAXWIDTH + 2); - len += sprintf(buf + len, cbuf, num); - break; - case 'o': case 'u': case 'x': case 'X': case 'c': - unum = va_arg(ap, unsigned int); - CB_REALLOC(buf, len + CB_SPMAXWIDTH + 2); - len += sprintf(buf + len, cbuf, unum); - break; - case 'e': case 'E': case 'f': case 'g': case 'G': - dnum = va_arg(ap, double); - CB_REALLOC(buf, len + CB_SPMAXWIDTH + 2); - len += sprintf(buf + len, cbuf, dnum); - break; - case 's': - str = va_arg(ap, char *); - slen = strlen(str); - CB_REALLOC(buf, len + slen + 2); - memcpy(buf + len, str, slen); - len += slen; - break; - case '%': - CB_REALLOC(buf, len + 2); - buf[len++] = '%'; - break; - default: - break; - } - } else { - CB_REALLOC(buf, len + 2); - buf[len++] = *format; - } - format++; - } - buf[len] = '\0'; - va_end(ap); - return buf; -} - - -/* Replace some patterns in a string. */ -char *cbreplace(const char *str, CBMAP *pairs){ - int i, bsiz, wi, rep, ksiz, vsiz; - char *buf; - const char *key, *val; - assert(str && pairs); - bsiz = CB_DATUMUNIT; - CB_MALLOC(buf, bsiz); - wi = 0; - while(*str != '\0'){ - rep = FALSE; - cbmapiterinit(pairs); - while((key = cbmapiternext(pairs, &ksiz)) != NULL){ - for(i = 0; i < ksiz; i++){ - if(str[i] == '\0' || str[i] != key[i]) break; - } - if(i == ksiz){ - CB_MAPITERVAL(val, key, vsiz); - if(wi + vsiz >= bsiz){ - bsiz = bsiz * 2 + vsiz; - CB_REALLOC(buf, bsiz); - } - memcpy(buf + wi, val, vsiz); - wi += vsiz; - str += ksiz; - rep = TRUE; - break; - } - } - if(!rep){ - if(wi + 1 >= bsiz){ - bsiz = bsiz * 2 + 1; - CB_REALLOC(buf, bsiz); - } - buf[wi++] = *str; - str++; - } - } - CB_REALLOC(buf, wi + 1); - buf[wi] = '\0'; - return buf; -} - - -/* Make a list by split a serial datum. */ -CBLIST *cbsplit(const char *ptr, int size, const char *delim){ - CBLIST *list; - int bi, step; - assert(ptr); - CB_LISTOPEN(list); - if(size < 0) size = strlen(ptr); - if(delim){ - for(bi = 0; bi < size; bi += step){ - step = 0; - while(bi + step < size && !strchr(delim, ptr[bi+step])){ - step++; - } - cblistpush(list, ptr + bi, step); - step++; - } - if(size > 0 && strchr(delim, ptr[size-1])) cblistpush(list, "", 0); - } else { - for(bi = 0; bi < size; bi += step){ - step = 0; - while(bi + step < size && ptr[bi+step]){ - step++; - } - cblistpush(list, ptr + bi, step); - step++; - } - if(size > 0 && ptr[size-1] == 0) cblistpush(list, "", 0); - } - return list; -} - - -/* Read whole data of a file. */ -char *cbreadfile(const char *name, int *sp){ - struct stat sbuf; - char iobuf[CB_IOBUFSIZ], *buf; - int fd, size, asiz, rv; - asiz = CB_IOBUFSIZ * 2; - if(name){ - if((fd = open(name, O_RDONLY, 0)) == -1) return NULL; - if(fstat(fd, &sbuf) != -1) asiz = sbuf.st_size + 1; - } else { - fd = 0; - } - CB_MALLOC(buf, asiz + 1); - size = 0; - while((rv = read(fd, iobuf, CB_IOBUFSIZ)) > 0){ - if(size + rv >= asiz){ - asiz = asiz * 2 + size; - CB_REALLOC(buf, asiz + 1); - } - memcpy(buf + size, iobuf, rv); - size += rv; - } - buf[size] = '\0'; - if(close(fd) == -1 || rv == -1){ - free(buf); - return NULL; - } - if(sp) *sp = size; - return buf; -} - - -/* Write data of a region into a file. */ -int cbwritefile(const char *name, const char *ptr, int size){ - int fd, err, wb; - assert(ptr); - if(size < 0) size = strlen(ptr); - if(name){ - if((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, CB_FILEMODE)) == -1) return FALSE; - } else { - fd = 1; - } - err = FALSE; - wb = 0; - do { - wb = write(fd, ptr, size); - switch(wb){ - case -1: err = errno != EINTR ? TRUE : FALSE; break; - case 0: break; - default: - ptr += wb; - size -= wb; - break; - } - } while(size > 0); - if(close(fd) == -1) err = TRUE; - return err ? FALSE : TRUE; -} - - -/* Read every line of a file. */ -CBLIST *cbreadlines(const char *name){ - char *buf, *tmp; - int vsiz; - CBMAP *pairs; - CBLIST *list; - if(!(buf = cbreadfile(name, NULL))) return NULL; - pairs = cbmapopenex(3); - cbmapput(pairs, "\r\n", 2, "\n", 1, TRUE); - cbmapput(pairs, "\r", 1, "\n", 1, TRUE); - tmp = cbreplace(buf, pairs); - list = cbsplit(tmp, strlen(tmp), "\n"); - free(tmp); - cbmapclose(pairs); - free(buf); - if(CB_LISTNUM(list) > 0){ - cblistval(list, CB_LISTNUM(list) - 1, &vsiz); - if(vsiz < 1) CB_LISTDROP(list); - } - return list; -} - - -/* Read names of files in a directory. */ -CBLIST *cbdirlist(const char *name){ - DIR *DD; - struct dirent *dp; - CBLIST *list; - assert(name); - if(!(DD = opendir(name))) return NULL; - CB_LISTOPEN(list); - while((dp = readdir(DD)) != NULL){ - CB_LISTPUSH(list, dp->d_name, strlen(dp->d_name)); - } - if(closedir(DD) == -1){ - CB_LISTCLOSE(list); - return NULL; - } - return list; -} - - -/* Get the status of a file or a directory. */ -int cbfilestat(const char *name, int *isdirp, int *sizep, time_t *mtimep){ - struct stat sbuf; - assert(name); - if(lstat(name, &sbuf) == -1) return FALSE; - if(isdirp) *isdirp = S_ISDIR(sbuf.st_mode); - if(sizep) *sizep = (int)sbuf.st_size; - if(mtimep) *mtimep = sbuf.st_mtime; - return TRUE; -} - - -/* Remove a file or a directory and its sub ones recursively. */ -int cbremove(const char *name){ - CBLIST *list; - const char *elem; - char *path; - int i, err, tail; - struct stat sbuf; - assert(name); - if(lstat(name, &sbuf) == -1) return FALSE; - if(unlink(name) == 0) return TRUE; - if(!S_ISDIR(sbuf.st_mode) || !(list = cbdirlist(name))) return FALSE; - err = FALSE; - tail = name[0] != '\0' && name[strlen(name)-1] == MYPATHCHR; - for(i = 0; i < CB_LISTNUM(list); i++){ - elem = CB_LISTVAL(list, i); - if(!strcmp(MYCDIRSTR, elem) || !strcmp(MYPDIRSTR, elem)) continue; - if(tail){ - path = cbsprintf("%s%s", name, elem); - } else { - path = cbsprintf("%s%c%s", name, MYPATHCHR, elem); - } - if(!cbremove(path)) err = TRUE; - free(path); - } - CB_LISTCLOSE(list); - return rmdir(name) == 0 ? TRUE : FALSE; -} - - -/* Break up a URL into elements. */ -CBMAP *cburlbreak(const char *str){ - CBMAP *map; - char *tmp, *ep; - const char *rp; - int serv; - assert(str); - map = cbmapopenex(CB_MAPPBNUM); - CB_MEMDUP(tmp, str, strlen(str)); - rp = cbstrtrim(tmp); - cbmapput(map, "self", -1, rp, -1, TRUE); - serv = FALSE; - if(cbstrfwimatch(rp, "http://")){ - cbmapput(map, "scheme", -1, "http", -1, TRUE); - rp += 7; - serv = TRUE; - } else if(cbstrfwimatch(rp, "https://")){ - cbmapput(map, "scheme", -1, "https", -1, TRUE); - rp += 8; - serv = TRUE; - } else if(cbstrfwimatch(rp, "ftp://")){ - cbmapput(map, "scheme", -1, "ftp", -1, TRUE); - rp += 6; - serv = TRUE; - } else if(cbstrfwimatch(rp, "sftp://")){ - cbmapput(map, "scheme", -1, "sftp", -1, TRUE); - rp += 7; - serv = TRUE; - } else if(cbstrfwimatch(rp, "ftps://")){ - cbmapput(map, "scheme", -1, "ftps", -1, TRUE); - rp += 7; - serv = TRUE; - } else if(cbstrfwimatch(rp, "tftp://")){ - cbmapput(map, "scheme", -1, "tftp", -1, TRUE); - rp += 7; - serv = TRUE; - } else if(cbstrfwimatch(rp, "ldap://")){ - cbmapput(map, "scheme", -1, "ldap", -1, TRUE); - rp += 7; - serv = TRUE; - } else if(cbstrfwimatch(rp, "ldaps://")){ - cbmapput(map, "scheme", -1, "ldaps", -1, TRUE); - rp += 8; - serv = TRUE; - } else if(cbstrfwimatch(rp, "file://")){ - cbmapput(map, "scheme", -1, "file", -1, TRUE); - rp += 7; - serv = TRUE; - } - if((ep = strchr(rp, '#')) != NULL){ - cbmapput(map, "fragment", -1, ep + 1, -1, TRUE); - *ep = '\0'; - } - if((ep = strchr(rp, '?')) != NULL){ - cbmapput(map, "query", -1, ep + 1, -1, TRUE); - *ep = '\0'; - } - if(serv){ - if((ep = strchr(rp, '/')) != NULL){ - cbmapput(map, "path", -1, ep, -1, TRUE); - *ep = '\0'; - } else { - cbmapput(map, "path", -1, "/", -1, TRUE); - } - if((ep = strchr(rp, '@')) != NULL){ - *ep = '\0'; - if(rp[0] != '\0') cbmapput(map, "authority", -1, rp, -1, TRUE); - rp = ep + 1; - } - if((ep = strchr(rp, ':')) != NULL){ - if(ep[1] != '\0') cbmapput(map, "port", -1, ep + 1, -1, TRUE); - *ep = '\0'; - } - if(rp[0] != '\0') cbmapput(map, "host", -1, rp, -1, TRUE); - } else { - cbmapput(map, "path", -1, rp, -1, TRUE); - } - free(tmp); - if((rp = cbmapget(map, "path", -1, NULL)) != NULL){ - if((ep = strrchr(rp, '/')) != NULL){ - if(ep[1] != '\0') cbmapput(map, "file", -1, ep + 1, -1, TRUE); - } else { - cbmapput(map, "file", -1, rp, -1, TRUE); - } - } - if((rp = cbmapget(map, "file", -1, NULL)) != NULL && (!strcmp(rp, ".") || !strcmp(rp, ".."))) - cbmapout(map, "file", -1); - return map; -} - - -/* Resolve a relative URL with another absolute URL. */ -char *cburlresolve(const char *base, const char *target){ - CBMAP *telems, *belems; - CBLIST *bpaths, *opaths, *qelems; - CBDATUM *rbuf; - const char *vbuf, *path; - char *tmp, *wp, *enc, numbuf[CB_NUMBUFSIZ]; - int i, vsiz, port, num; - assert(base && target); - while(*base > '\0' && *base <= ' '){ - base++; - } - while(*target > '\0' && *target <= ' '){ - target++; - } - if(*target == '\0') target = base; - CB_DATUMOPEN(rbuf); - telems = cburlbreak(target); - port = 80; - belems = cburlbreak(cbmapget(telems, "scheme", -1, &vsiz) ? target : base); - if((vbuf = cbmapget(belems, "scheme", -1, &vsiz)) != NULL){ - CB_DATUMCAT(rbuf, vbuf, vsiz); - CB_DATUMCAT(rbuf, "://", 3); - if(!cbstricmp(vbuf, "https")){ - port = 443; - } else if(!cbstricmp(vbuf, "ftp")){ - port = 21; - } else if(!cbstricmp(vbuf, "sftp")){ - port = 115; - } else if(!cbstricmp(vbuf, "ftps")){ - port = 22; - } else if(!cbstricmp(vbuf, "tftp")){ - port = 69; - } else if(!cbstricmp(vbuf, "ldap")){ - port = 389; - } else if(!cbstricmp(vbuf, "ldaps")){ - port = 636; - } - } else { - CB_DATUMCAT(rbuf, "http://", 7); - } - if((vbuf = cbmapget(belems, "authority", -1, &vsiz)) != NULL){ - if((wp = strchr(vbuf, ':')) != NULL){ - *wp = '\0'; - tmp = cburldecode(vbuf, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - CB_DATUMCAT(rbuf, ":", 1); - wp++; - tmp = cburldecode(wp, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } else { - tmp = cburldecode(vbuf, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } - CB_DATUMCAT(rbuf, "@", 1); - } - if((vbuf = cbmapget(belems, "host", -1, &vsiz)) != NULL){ - tmp = cburldecode(vbuf, NULL); - cbstrtolower(tmp); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } else { - CB_DATUMCAT(rbuf, "localhost", 9); - } - if((vbuf = cbmapget(belems, "port", -1, &vsiz)) != NULL && - (num = atoi(vbuf)) != port && num > 1){ - sprintf(numbuf, ":%d", num); - CB_DATUMCAT(rbuf, numbuf, strlen(numbuf)); - } - if(!(path = cbmapget(telems, "path", -1, NULL))) path = "/"; - if(path[0] == '\0' && (vbuf = cbmapget(belems, "path", -1, NULL)) != NULL) path = vbuf; - if(path[0] == '\0') path = "/"; - CB_LISTOPEN(bpaths); - if(path[0] != '/' && (vbuf = cbmapget(belems, "path", -1, &vsiz)) != NULL){ - opaths = cbsplit(vbuf, vsiz, "/"); - } else { - opaths = cbsplit("/", 1, "/"); - } - CB_LISTDROP(opaths); - for(i = 0; i < CB_LISTNUM(opaths); i++){ - vbuf = CB_LISTVAL2(opaths, i, vsiz); - if(vsiz < 1 || !strcmp(vbuf, ".")) continue; - if(!strcmp(vbuf, "..")){ - CB_LISTDROP(bpaths); - } else { - CB_LISTPUSH(bpaths, vbuf, vsiz); - } - } - CB_LISTCLOSE(opaths); - opaths = cbsplit(path, -1, "/"); - for(i = 0; i < CB_LISTNUM(opaths); i++){ - vbuf = CB_LISTVAL2(opaths, i, vsiz); - if(vsiz < 1 || !strcmp(vbuf, ".")) continue; - if(!strcmp(vbuf, "..")){ - CB_LISTDROP(bpaths); - } else { - CB_LISTPUSH(bpaths, vbuf, vsiz); - } - } - CB_LISTCLOSE(opaths); - for(i = 0; i < CB_LISTNUM(bpaths); i++){ - vbuf = CB_LISTVAL(bpaths, i); - if(strchr(vbuf, '%')){ - tmp = cburldecode(vbuf, NULL); - } else { - CB_MEMDUP(tmp, vbuf, strlen(vbuf)); - } - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, "/", 1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } - if(cbstrbwmatch(path, "/")) CB_DATUMCAT(rbuf, "/", 1); - CB_LISTCLOSE(bpaths); - if((vbuf = cbmapget(telems, "query", -1, &vsiz)) != NULL){ - CB_DATUMCAT(rbuf, "?", 1); - qelems = cbsplit(vbuf, vsiz, "&;"); - for(i = 0; i < CB_LISTNUM(qelems); i++){ - vbuf = CB_LISTVAL(qelems, i); - if(i > 0) CB_DATUMCAT(rbuf, "&", 1); - if((wp = strchr(vbuf, '=')) != NULL){ - *wp = '\0'; - tmp = cburldecode(vbuf, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - CB_DATUMCAT(rbuf, "=", 1); - wp++; - tmp = cburldecode(wp, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } else { - tmp = cburldecode(vbuf, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } - } - CB_LISTCLOSE(qelems); - } - if((vbuf = cbmapget(telems, "fragment", -1, &vsiz)) != NULL){ - tmp = cburldecode(vbuf, NULL); - enc = cburlencode(tmp, -1); - CB_DATUMCAT(rbuf, "#", 1); - CB_DATUMCAT(rbuf, enc, strlen(enc)); - free(enc); - free(tmp); - } - cbmapclose(belems); - cbmapclose(telems); - return cbdatumtomalloc(rbuf, NULL); -} - - -/* Encode a serial object with URL encoding. */ -char *cburlencode(const char *ptr, int size){ - char *buf, *wp; - int i, c; - assert(ptr); - if(size < 0) size = strlen(ptr); - CB_MALLOC(buf, size * 3 + 1); - wp = buf; - for(i = 0; i < size; i++){ - c = ((unsigned char *)ptr)[i]; - if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.!~*'()", c))){ - *(wp++) = c; - } else { - wp += sprintf(wp, "%%%02X", c); - } - } - *wp = '\0'; - return buf; -} - - -/* Decode a string encoded with URL encoding. */ -char *cburldecode(const char *str, int *sp){ - char *buf, *wp; - unsigned char c; - CB_MEMDUP(buf, str, strlen(str)); - wp = buf; - while(*str != '\0'){ - if(*str == '%'){ - str++; - if(((str[0] >= '0' && str[0] <= '9') || (str[0] >= 'A' && str[0] <= 'F') || - (str[0] >= 'a' && str[0] <= 'f')) && - ((str[1] >= '0' && str[1] <= '9') || (str[1] >= 'A' && str[1] <= 'F') || - (str[1] >= 'a' && str[1] <= 'f'))){ - c = *str; - if(c >= 'A' && c <= 'Z') c += 'a' - 'A'; - if(c >= 'a' && c <= 'z'){ - *wp = c - 'a' + 10; - } else { - *wp = c - '0'; - } - *wp *= 0x10; - str++; - c = *str; - if(c >= 'A' && c <= 'Z') c += 'a' - 'A'; - if(c >= 'a' && c <= 'z'){ - *wp += c - 'a' + 10; - } else { - *wp += c - '0'; - } - str++; - wp++; - } else { - break; - } - } else if(*str == '+'){ - *wp = ' '; - str++; - wp++; - } else { - *wp = *str; - str++; - wp++; - } - } - *wp = '\0'; - if(sp) *sp = wp - buf; - return buf; -} - - -/* Encode a serial object with Base64 encoding. */ -char *cbbaseencode(const char *ptr, int size){ - char *tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - char *buf, *wp; - const unsigned char *obj; - int i; - assert(ptr); - if(size < 0) size = strlen(ptr); - CB_MALLOC(buf, 4 * (size + 2) / 3 + 1); - obj = (const unsigned char *)ptr; - wp = buf; - for(i = 0; i < size; i += 3){ - switch(size - i){ - case 1: - *wp++ = tbl[obj[0] >> 2]; - *wp++ = tbl[(obj[0] & 3) << 4]; - *wp++ = '='; - *wp++ = '='; - break; - case 2: - *wp++ = tbl[obj[0] >> 2]; - *wp++ = tbl[((obj[0] & 3) << 4) + (obj[1] >> 4)]; - *wp++ = tbl[(obj[1] & 0xf) << 2]; - *wp++ = '='; - break; - default: - *wp++ = tbl[obj[0] >> 2]; - *wp++ = tbl[((obj[0] & 3) << 4) + (obj[1] >> 4)]; - *wp++ = tbl[((obj[1] & 0xf) << 2) + (obj[2] >> 6)]; - *wp++ = tbl[obj[2] & 0x3f]; - break; - } - obj += 3; - } - *wp = '\0'; - return buf; -} - - -/* Decode a string encoded with Base64 encoding. */ -char *cbbasedecode(const char *str, int *sp){ - unsigned char *obj, *wp; - int len, cnt, bpos, i, bits, eqcnt; - assert(str); - cnt = 0; - bpos = 0; - eqcnt = 0; - len = strlen(str); - CB_MALLOC(obj, len + 4); - wp = obj; - while(bpos < len && eqcnt == 0){ - bits = 0; - for(i = 0; bpos < len && i < 4; bpos++){ - if(str[bpos] >= 'A' && str[bpos] <= 'Z'){ - bits = (bits << 6) | (str[bpos] - 'A'); - i++; - } else if(str[bpos] >= 'a' && str[bpos] <= 'z'){ - bits = (bits << 6) | (str[bpos] - 'a' + 26); - i++; - } else if(str[bpos] >= '0' && str[bpos] <= '9'){ - bits = (bits << 6) | (str[bpos] - '0' + 52); - i++; - } else if(str[bpos] == '+'){ - bits = (bits << 6) | 62; - i++; - } else if(str[bpos] == '/'){ - bits = (bits << 6) | 63; - i++; - } else if(str[bpos] == '='){ - bits <<= 6; - i++; - eqcnt++; - } - } - if(i == 0 && bpos >= len) continue; - switch(eqcnt){ - case 0: - *wp++ = (bits >> 16) & 0xff; - *wp++ = (bits >> 8) & 0xff; - *wp++ = bits & 0xff; - cnt += 3; - break; - case 1: - *wp++ = (bits >> 16) & 0xff; - *wp++ = (bits >> 8) & 0xff; - cnt += 2; - break; - case 2: - *wp++ = (bits >> 16) & 0xff; - cnt += 1; - break; - } - } - obj[cnt] = '\0'; - if(sp) *sp = cnt; - return (char *)obj; -} - - -/* Encode a serial object with quoted-printable encoding. */ -char *cbquoteencode(const char *ptr, int size){ - const unsigned char *rp; - char *buf, *wp; - int i, cols; - assert(ptr); - if(size < 0) size = strlen(ptr); - rp = (const unsigned char *)ptr; - CB_MALLOC(buf, size * 3 + 1); - wp = buf; - cols = 0; - for(i = 0; i < size; i++){ - if(rp[i] == '=' || (rp[i] < 0x20 && rp[i] != '\r' && rp[i] != '\n' && rp[i] != '\t') || - rp[i] > 0x7e){ - wp += sprintf(wp, "=%02X", rp[i]); - cols += 3; - } else { - *(wp++) = rp[i]; - cols++; - } - } - *wp = '\0'; - return buf; -} - - -/* Decode a string encoded with quoted-printable encoding. */ -char *cbquotedecode(const char *str, int *sp){ - char *buf, *wp; - assert(str); - CB_MALLOC(buf, strlen(str) + 1); - wp = buf; - for(; *str != '\0'; str++){ - if(*str == '='){ - str++; - if(*str == '\0'){ - break; - } else if(str[0] == '\r' && str[1] == '\n'){ - str++; - } else if(str[0] != '\n' && str[0] != '\r'){ - if(*str >= 'A' && *str <= 'Z'){ - *wp = (*str - 'A' + 10) * 16; - } else if(*str >= 'a' && *str <= 'z'){ - *wp = (*str - 'a' + 10) * 16; - } else { - *wp = (*str - '0') * 16; - } - str++; - if(*str == '\0') break; - if(*str >= 'A' && *str <= 'Z'){ - *wp += *str - 'A' + 10; - } else if(*str >= 'a' && *str <= 'z'){ - *wp += *str - 'a' + 10; - } else { - *wp += *str - '0'; - } - wp++; - } - } else { - *wp = *str; - wp++; - } - } - *wp = '\0'; - if(sp) *sp = wp - buf; - return buf; -} - - -/* Split a string of MIME into headers and the body. */ -char *cbmimebreak(const char *ptr, int size, CBMAP *attrs, int *sp){ - CBLIST *list; - const char *head, *line, *pv, *ep; - char *hbuf, *name, *rv; - int i, j, wi, hlen; - assert(ptr); - if(size < 0) size = strlen(ptr); - head = NULL; - hlen = 0; - for(i = 0; i < size; i++){ - if(i < size - 4 && ptr[i] == '\r' && ptr[i+1] == '\n' && - ptr[i+2] == '\r' && ptr[i+3] == '\n'){ - head = ptr; - hlen = i; - ptr += i + 4; - size -= i + 4; - break; - } else if(i < size - 2 && ptr[i] == '\n' && ptr[i+1] == '\n'){ - head = ptr; - hlen = i; - ptr += i + 2; - size -= i + 2; - break; - } - } - if(head && attrs){ - CB_MALLOC(hbuf, hlen + 1); - wi = 0; - for(i = 0; i < hlen; i++){ - if(head[i] == '\r') continue; - if(i < hlen - 1 && head[i] == '\n' && (head[i+1] == ' ' || head[i+1] == '\t')){ - hbuf[wi++] = ' '; - i++; - } else { - hbuf[wi++] = head[i]; - } - } - list = cbsplit(hbuf, wi, "\n"); - for(i = 0; i < CB_LISTNUM(list); i++){ - line = CB_LISTVAL(list, i); - if((pv = strchr(line, ':')) != NULL){ - CB_MEMDUP(name, line, pv - line); - for(j = 0; name[j] != '\0'; j++){ - if(name[j] >= 'A' && name[j] <= 'Z') name[j] -= 'A' - 'a'; - } - pv++; - while(*pv == ' ' || *pv == '\t'){ - pv++; - } - cbmapput(attrs, name, -1, pv, -1, TRUE); - free(name); - } - - } - CB_LISTCLOSE(list); - free(hbuf); - if((pv = cbmapget(attrs, "content-type", -1, NULL)) != NULL){ - if((ep = strchr(pv, ';')) != NULL){ - cbmapput(attrs, "TYPE", -1, pv, ep - pv, TRUE); - do { - ep++; - while(ep[0] == ' '){ - ep++; - } - if(cbstrfwimatch(ep, "charset=")){ - ep += 8; - while(*ep > '\0' && *ep <= ' '){ - ep++; - } - if(ep[0] == '"') ep++; - pv = ep; - while(ep[0] != '\0' && ep[0] != ' ' && ep[0] != '"' && ep[0] != ';'){ - ep++; - } - cbmapput(attrs, "CHARSET", -1, pv, ep - pv, TRUE); - } else if(cbstrfwimatch(ep, "boundary=")){ - ep += 9; - while(*ep > '\0' && *ep <= ' '){ - ep++; - } - if(ep[0] == '"'){ - ep++; - pv = ep; - while(ep[0] != '\0' && ep[0] != '"'){ - ep++; - } - } else { - pv = ep; - while(ep[0] != '\0' && ep[0] != ' ' && ep[0] != '"' && ep[0] != ';'){ - ep++; - } - } - cbmapput(attrs, "BOUNDARY", -1, pv, ep - pv, TRUE); - } - } while((ep = strchr(ep, ';')) != NULL); - } else { - cbmapput(attrs, "TYPE", -1, pv, -1, TRUE); - } - } - if((pv = cbmapget(attrs, "content-disposition", -1, NULL)) != NULL){ - if((ep = strchr(pv, ';')) != NULL){ - cbmapput(attrs, "DISPOSITION", -1, pv, ep - pv, TRUE); - do { - ep++; - while(ep[0] == ' '){ - ep++; - } - if(cbstrfwimatch(ep, "filename=")){ - ep += 9; - if(ep[0] == '"') ep++; - pv = ep; - while(ep[0] != '\0' && ep[0] != '"'){ - ep++; - } - cbmapput(attrs, "FILENAME", -1, pv, ep - pv, TRUE); - } else if(cbstrfwimatch(ep, "name=")){ - ep += 5; - if(ep[0] == '"') ep++; - pv = ep; - while(ep[0] != '\0' && ep[0] != '"'){ - ep++; - } - cbmapput(attrs, "NAME", -1, pv, ep - pv, TRUE); - } - } while((ep = strchr(ep, ';')) != NULL); - } else { - cbmapput(attrs, "DISPOSITION", -1, pv, -1, TRUE); - } - } - } - if(sp) *sp = size; - CB_MEMDUP(rv, ptr, size); - return rv; -} - - -/* Split multipart data in MIME into its parts. */ -CBLIST *cbmimeparts(const char *ptr, int size, const char *boundary){ - CBLIST *list; - const char *pv, *ep; - int i, blen; - assert(ptr && boundary); - if(size < 0) size = strlen(ptr); - CB_LISTOPEN(list); - if((blen = strlen(boundary)) < 1) return list; - pv = NULL; - for(i = 0; i < size; i++){ - if(ptr[i] == '-' && ptr[i+1] == '-' && i + 2 + blen < size && - cbstrfwmatch(ptr + i + 2, boundary) && strchr("\t\n\v\f\r ", ptr[i+2+blen])){ - pv = ptr + i + 2 + blen; - if(*pv == '\r') pv++; - if(*pv == '\n') pv++; - size -= pv - ptr; - ptr = pv; - break; - } - } - if(!pv) return list; - for(i = 0; i < size; i++){ - if(ptr[i] == '-' && ptr[i+1] == '-' && i + 2 + blen < size && - cbstrfwmatch(ptr + i + 2, boundary) && strchr("\t\n\v\f\r -", ptr[i+2+blen])){ - ep = ptr + i; - if(ep > ptr && ep[-1] == '\n') ep--; - if(ep > ptr && ep[-1] == '\r') ep--; - if(ep > pv) CB_LISTPUSH(list, pv, ep - pv); - pv = ptr + i + 2 + blen; - if(*pv == '\r') pv++; - if(*pv == '\n') pv++; - } - } - return list; -} - - -/* Encode a string with MIME encoding. */ -char *cbmimeencode(const char *str, const char *encname, int base){ - char *buf, *wp, *enc; - int len; - assert(str && encname); - len = strlen(str); - CB_MALLOC(buf, len * 3 + strlen(encname) + 16); - wp = buf; - wp += sprintf(wp, "=?%s?%c?", encname, base ? 'B' : 'Q'); - enc = base ? cbbaseencode(str, len) : cbquoteencode(str, len); - wp += sprintf(wp, "%s?=", enc); - free(enc); - return buf; -} - - -/* Decode a string encoded with MIME encoding. */ -char *cbmimedecode(const char *str, char *enp){ - char *buf, *wp, *tmp, *dec; - const char *pv, *ep; - int quoted; - assert(str); - if(enp) sprintf(enp, "US-ASCII"); - CB_MALLOC(buf, strlen(str) + 1); - wp = buf; - while(*str != '\0'){ - if(cbstrfwmatch(str, "=?")){ - str += 2; - pv = str; - if(!(ep = strchr(str, '?'))) continue; - if(enp && ep - pv < CB_ENCBUFSIZ){ - memcpy(enp, pv, ep - pv); - enp[ep-pv] = '\0'; - } - pv = ep + 1; - quoted = (*pv == 'Q' || *pv == 'q'); - if(*pv != '\0') pv++; - if(*pv != '\0') pv++; - if(!(ep = strchr(pv, '?'))) continue; - CB_MEMDUP(tmp, pv, ep - pv); - dec = quoted ? cbquotedecode(tmp, NULL) : cbbasedecode(tmp, NULL); - wp += sprintf(wp, "%s", dec); - free(dec); - free(tmp); - str = ep + 1; - if(*str != '\0') str++; - } else { - *(wp++) = *str; - str++; - } - } - *wp = '\0'; - return buf; -} - - -/* Split a string of CSV into rows. */ -CBLIST *cbcsvrows(const char *str){ - CBLIST *list; - const char *pv; - int quoted; - assert(str); - CB_LISTOPEN(list); - pv = str; - quoted = FALSE; - while(TRUE){ - if(*str == '"') quoted = !quoted; - if(!quoted && (*str == '\r' || *str == '\n')){ - CB_LISTPUSH(list, pv, str - pv); - if(str[0] == '\r' && str[1] == '\n') str++; - str++; - pv = str; - } else if(*str == '\0'){ - if(str > pv) CB_LISTPUSH(list, pv, str - pv); - break; - } else { - str++; - } - } - return list; -} - - -/* Split a string of a row of CSV into cells. */ -CBLIST *cbcsvcells(const char *str){ - CBLIST *list, *uelist; - const char *pv; - char *tmp; - int i, quoted; - assert(str); - CB_LISTOPEN(list); - pv = str; - quoted = FALSE; - while(TRUE){ - if(*str == '"') quoted = !quoted; - if(!quoted && *str == ','){ - CB_LISTPUSH(list, pv, str - pv); - str++; - pv = str; - } else if(*str == '\0'){ - CB_LISTPUSH(list, pv, str - pv); - break; - } else { - str++; - } - } - CB_LISTOPEN(uelist); - for(i = 0; i < CB_LISTNUM(list); i++){ - tmp = cbcsvunescape(CB_LISTVAL(list, i)); - CB_LISTPUSH(uelist, tmp, strlen(tmp)); - free(tmp); - } - CB_LISTCLOSE(list); - return uelist; -} - - -/* Escape a string with the meta characters of CSV. */ -char *cbcsvescape(const char *str){ - char *buf, *wp; - int i; - assert(str); - CB_MALLOC(buf, strlen(str) * 2 + 3); - wp = buf; - *(wp++) = '"'; - for(i = 0; str[i] != '\0'; i++){ - if(str[i] == '"') *(wp++) = '"'; - *(wp++) = str[i]; - } - *(wp++) = '"'; - *wp = '\0'; - return buf; -} - - -/* Unescape a string with the escaped meta characters of CSV. */ -char *cbcsvunescape(const char *str){ - char *buf, *wp; - int i, len; - assert(str); - len = strlen(str); - if(str[0] == '"'){ - str++; - len--; - if(str[len-1] == '"') len--; - } - CB_MALLOC(buf, len + 1); - wp = buf; - for(i = 0; i < len; i++){ - if(str[i] == '"'){ - if(str[i+1] == '"') *(wp++) = str[i++]; - } else { - *(wp++) = str[i]; - } - } - *wp = '\0'; - return buf; -} - - -/* Split a string of XML into tags and text sections. */ -CBLIST *cbxmlbreak(const char *str, int cr){ - CBLIST *list; - CBDATUM *datum; - int i, pv, tag; - char *ep; - assert(str); - CB_LISTOPEN(list); - i = 0; - pv = 0; - tag = FALSE; - while(TRUE){ - if(str[i] == '\0'){ - if(i > pv) CB_LISTPUSH(list, str + pv, i - pv); - break; - } else if(!tag && str[i] == '<'){ - if(str[i+1] == '!' && str[i+2] == '-' && str[i+3] == '-'){ - if(i > pv) CB_LISTPUSH(list, str + pv, i - pv); - if((ep = strstr(str + i, "-->")) != NULL){ - if(!cr) CB_LISTPUSH(list, str + i, ep - str - i + 3); - i = ep - str + 2; - pv = i + 1; - } - } else if(str[i+1] == '!' && str[i+2] == '[' && cbstrfwimatch(str + i, "<![CDATA[")){ - if(i > pv) CB_LISTPUSH(list, str + pv, i - pv); - if((ep = strstr(str + i, "]]>")) != NULL){ - i += 9; - CB_DATUMOPEN(datum); - while(str + i < ep){ - if(str[i] == '&'){ - CB_DATUMCAT(datum, "&", 5); - } else if(str[i] == '<'){ - CB_DATUMCAT(datum, "<", 4); - } else if(str[i] == '>'){ - CB_DATUMCAT(datum, ">", 4); - } else { - CB_DATUMCAT(datum, str + i, 1); - } - i++; - } - if(CB_DATUMSIZE(datum) > 0) CB_LISTPUSH(list, CB_DATUMPTR(datum), CB_DATUMSIZE(datum)); - CB_DATUMCLOSE(datum); - i = ep - str + 2; - pv = i + 1; - } - } else { - if(i > pv) CB_LISTPUSH(list, str + pv, i - pv); - tag = TRUE; - pv = i; - } - } else if(tag && str[i] == '>'){ - if(i > pv) CB_LISTPUSH(list, str + pv, i - pv + 1); - tag = FALSE; - pv = i + 1; - } - i++; - } - return list; -} - - -/* Get the map of attributes of a XML tag. */ -CBMAP *cbxmlattrs(const char *str){ - CBMAP *map; - const unsigned char *rp, *key, *val; - char *copy, *raw; - int ksiz, vsiz; - assert(str); - map = cbmapopenex(CB_MAPPBNUM); - rp = (unsigned char *)str; - while(*rp == '<' || *rp == '/' || *rp == '?' || *rp == '!' || *rp == ' '){ - rp++; - } - key = rp; - while(*rp > 0x20 && *rp != '/' && *rp != '>'){ - rp++; - } - cbmapput(map, "", -1, (char *)key, rp - key, FALSE); - while(*rp != '\0'){ - while(*rp != '\0' && (*rp <= 0x20 || *rp == '/' || *rp == '?' || *rp == '>')){ - rp++; - } - key = rp; - while(*rp > 0x20 && *rp != '/' && *rp != '>' && *rp != '='){ - rp++; - } - ksiz = rp - key; - while(*rp != '\0' && (*rp == '=' || *rp <= 0x20)){ - rp++; - } - if(*rp == '"'){ - rp++; - val = rp; - while(*rp != '\0' && *rp != '"'){ - rp++; - } - vsiz = rp - val; - } else if(*rp == '\''){ - rp++; - val = rp; - while(*rp != '\0' && *rp != '\''){ - rp++; - } - vsiz = rp - val; - } else { - val = rp; - while(*rp > 0x20 && *rp != '"' && *rp != '\'' && *rp != '>'){ - rp++; - } - vsiz = rp - val; - } - if(*rp != '\0') rp++; - if(ksiz > 0){ - CB_MEMDUP(copy, (char *)val, vsiz); - raw = cbxmlunescape(copy); - cbmapput(map, (char *)key, ksiz, raw, -1, FALSE); - free(raw); - free(copy); - } - } - return map; -} - - -/* Escape a string with the meta characters of XML. */ -char *cbxmlescape(const char *str){ - CBDATUM *datum; - assert(str); - CB_DATUMOPEN(datum); - while(*str != '\0'){ - switch(*str){ - case '&': - CB_DATUMCAT(datum, "&", 5); - break; - case '<': - CB_DATUMCAT(datum, "<", 4); - break; - case '>': - CB_DATUMCAT(datum, ">", 4); - break; - case '"': - CB_DATUMCAT(datum, """, 6); - break; - case '\'': - CB_DATUMCAT(datum, "'", 6); - break; - default: - CB_DATUMCAT(datum, str, 1); - break; - } - str++; - } - return cbdatumtomalloc(datum, NULL); -} - - -/* Unescape a string with the entity references of XML. */ -char *cbxmlunescape(const char *str){ - CBDATUM *datum; - assert(str); - CB_DATUMOPEN(datum); - while(*str != '\0'){ - if(*str == '&'){ - if(cbstrfwmatch(str, "&")){ - CB_DATUMCAT(datum, "&", 1); - str += 5; - } else if(cbstrfwmatch(str, "<")){ - CB_DATUMCAT(datum, "<", 1); - str += 4; - } else if(cbstrfwmatch(str, ">")){ - CB_DATUMCAT(datum, ">", 1); - str += 4; - } else if(cbstrfwmatch(str, """)){ - CB_DATUMCAT(datum, "\"", 1); - str += 6; - } else if(cbstrfwmatch(str, "'")){ - CB_DATUMCAT(datum, "'", 1); - str += 6; - } else { - CB_DATUMCAT(datum, str, 1); - str++; - } - } else { - CB_DATUMCAT(datum, str, 1); - str++; - } - } - return cbdatumtomalloc(datum, NULL); -} - - -/* Compress a serial object with ZLIB. */ -char *cbdeflate(const char *ptr, int size, int *sp){ - assert(ptr && sp); - if(!_qdbm_deflate) return NULL; - return _qdbm_deflate(ptr, size, sp, _QDBM_ZMZLIB); -} - - -/* Decompress a serial object compressed with ZLIB. */ -char *cbinflate(const char *ptr, int size, int *sp){ - assert(ptr && size >= 0); - if(!_qdbm_inflate) return NULL; - return _qdbm_inflate(ptr, size, sp, _QDBM_ZMZLIB); -} - - -/* Compress a serial object with GZIP. */ -char *cbgzencode(const char *ptr, int size, int *sp){ - assert(ptr && sp); - if(!_qdbm_deflate) return NULL; - return _qdbm_deflate(ptr, size, sp, _QDBM_ZMGZIP); -} - - -/* Decompress a serial object compressed with GZIP. */ -char *cbgzdecode(const char *ptr, int size, int *sp){ - assert(ptr && size >= 0); - if(!_qdbm_inflate) return NULL; - return _qdbm_inflate(ptr, size, sp, _QDBM_ZMGZIP); -} - - -/* Get the CRC32 checksum of a serial object. */ -unsigned int cbgetcrc(const char *ptr, int size){ - assert(ptr); - if(!_qdbm_inflate) return 0; - return _qdbm_getcrc(ptr, size); -} - - -/* Compress a serial object with LZO. */ -char *cblzoencode(const char *ptr, int size, int *sp){ - assert(ptr && sp); - if(!_qdbm_lzoencode) return NULL; - return _qdbm_lzoencode(ptr, size, sp); -} - - -/* Decompress a serial object compressed with LZO. */ -char *cblzodecode(const char *ptr, int size, int *sp){ - assert(ptr && size >= 0); - if(!_qdbm_lzodecode) return NULL; - return _qdbm_lzodecode(ptr, size, sp); -} - - -/* Compress a serial object with BZIP2. */ -char *cbbzencode(const char *ptr, int size, int *sp){ - assert(ptr && sp); - if(!_qdbm_bzencode) return NULL; - return _qdbm_bzencode(ptr, size, sp); -} - - -/* Decompress a serial object compressed with BZIP2. */ -char *cbbzdecode(const char *ptr, int size, int *sp){ - assert(ptr && size >= 0); - if(!_qdbm_bzdecode) return NULL; - return _qdbm_bzdecode(ptr, size, sp); -} - - -/* Convert the character encoding of a string. */ -char *cbiconv(const char *ptr, int size, const char *icode, const char *ocode, int *sp, int *mp){ - char *res; - assert(ptr && icode && ocode); - if(!_qdbm_iconv) return NULL; - if((res = _qdbm_iconv(ptr, size, icode, ocode, sp, mp)) != NULL) return res; - if(!cbstricmp(icode, ocode)){ - if(sp) *sp = size; - if(mp) *mp = 0; - CB_MEMDUP(res, ptr, size < 0 ? strlen(ptr) : size); - return res; - } - return NULL; -} - - -/* Detect the encoding of a string automatically. */ -const char *cbencname(const char *ptr, int size){ - assert(ptr); - if(!_qdbm_encname) return "ISO-8859-1"; - return _qdbm_encname(ptr, size); -} - - -/* Get the jet lag of the local time in seconds. */ -int cbjetlag(void){ - struct tm ts, *tp; - time_t t, gt, lt; - if((t = time(NULL)) < 0) return 0; - if(!(tp = _qdbm_gmtime(&t, &ts))) return 0; - if((gt = mktime(tp)) < 0) return 0; - if(!(tp = _qdbm_localtime(&t, &ts))) return 0; - if((lt = mktime(tp)) < 0) return 0; - return lt - gt; -} - - -/* Get the Gregorian calendar of a time. */ -void cbcalendar(time_t t, int jl, int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp){ - struct tm ts, *tp; - if(t < 0) t = time(NULL); - t += jl; - if(!(tp = _qdbm_gmtime(&t, &ts))) return; - if(yearp) *yearp = tp->tm_year + 1900; - if(monp) *monp = tp->tm_mon + 1; - if(dayp) *dayp = tp->tm_mday; - if(hourp) *hourp = tp->tm_hour; - if(minp) *minp = tp->tm_min; - if(secp) *secp = tp->tm_sec; -} - - -/* Get the day of week of a date. */ -int cbdayofweek(int year, int mon, int day){ - if(mon < 3){ - year--; - mon += 12; - } - return (day + ((8 + (13 * mon)) / 5) + (year + (year / 4) - (year / 100) + (year / 400))) % 7; -} - - -/* Get the string for a date in W3CDTF. */ -char *cbdatestrwww(time_t t, int jl){ - char date[CB_DATEBUFSIZ], tzone[CB_DATEBUFSIZ], *rv; - int year, mon, day, hour, min, sec; - cbcalendar(t, jl, &year, &mon, &day, &hour, &min, &sec); - jl /= 60; - if(jl == 0){ - sprintf(tzone, "Z"); - } else if(jl < 0){ - jl *= -1; - sprintf(tzone, "-%02d:%02d", jl / 60, jl % 60); - } else { - sprintf(tzone, "+%02d:%02d", jl / 60, jl % 60); - } - sprintf(date, "%04d-%02d-%02dT%02d:%02d:%02d%s", year, mon, day, hour, min, sec, tzone); - CB_MEMDUP(rv, date, strlen(date)); - return rv; -} - - -/* Get the string for a date in RFC 1123 format. */ -char *cbdatestrhttp(time_t t, int jl){ - char date[CB_DATEBUFSIZ], *wp, *rv; - int year, mon, day, hour, min, sec; - cbcalendar(t, jl, &year, &mon, &day, &hour, &min, &sec); - jl /= 60; - wp = date; - switch(cbdayofweek(year, mon, day)){ - case 0: wp += sprintf(wp, "Sun, "); break; - case 1: wp += sprintf(wp, "Mon, "); break; - case 2: wp += sprintf(wp, "Tue, "); break; - case 3: wp += sprintf(wp, "Wed, "); break; - case 4: wp += sprintf(wp, "Thu, "); break; - case 5: wp += sprintf(wp, "Fri, "); break; - case 6: wp += sprintf(wp, "Sat, "); break; - } - wp += sprintf(wp, "%02d ", day); - switch(mon){ - case 1: wp += sprintf(wp, "Jan "); break; - case 2: wp += sprintf(wp, "Feb "); break; - case 3: wp += sprintf(wp, "Mar "); break; - case 4: wp += sprintf(wp, "Apr "); break; - case 5: wp += sprintf(wp, "May "); break; - case 6: wp += sprintf(wp, "Jun "); break; - case 7: wp += sprintf(wp, "Jul "); break; - case 8: wp += sprintf(wp, "Aug "); break; - case 9: wp += sprintf(wp, "Sep "); break; - case 10: wp += sprintf(wp, "Oct "); break; - case 11: wp += sprintf(wp, "Nov "); break; - case 12: wp += sprintf(wp, "Dec "); break; - } - wp += sprintf(wp, "%04d %02d:%02d:%02d ", year, hour, min, sec); - if(jl == 0){ - wp += sprintf(wp, "GMT"); - } else if(jl < 0){ - jl *= -1; - wp += sprintf(wp, "-%02d%02d", jl / 60, jl % 60); - } else { - wp += sprintf(wp, "+%02d%02d", jl / 60, jl % 60); - } - CB_MEMDUP(rv, date, strlen(date)); - return rv; -} - - -/* Get the time value of a date string in decimal, W3CDTF, or RFC 1123. */ -time_t cbstrmktime(const char *str){ - const char *crp; - char *pv, *rp; - int len, clen; - time_t t; - struct tm ts; - assert(str); - while(*str > '\0' && *str <= ' '){ - str++; - } - if(*str == '\0') return -1; - if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) return (time_t)strtol(str + 2, NULL, 16); - memset(&ts, 0, sizeof(struct tm)); - ts.tm_year = 70; - ts.tm_mon = 0; - ts.tm_mday = 1; - ts.tm_hour = 0; - ts.tm_min = 0; - ts.tm_sec = 0; - ts.tm_isdst = 0; - len = strlen(str); - t = (time_t)strtol(str, &pv, 10); - if(*(signed char *)pv >= '\0' && *pv <= ' '){ - while(*pv > '\0' && *pv <= ' '){ - pv++; - } - if(*pv == '\0') return t; - } - if((pv[0] == 's' || pv[0] == 'S') && ((signed char *)pv)[1] >= '\0' && pv[1] <= ' ') - return t; - if((pv[0] == 'm' || pv[0] == 'M') && ((signed char *)pv)[1] >= '\0' && pv[1] <= ' ') - return t * 60; - if((pv[0] == 'h' || pv[0] == 'H') && ((signed char *)pv)[1] >= '\0' && pv[1] <= ' ') - return t * 60 * 60; - if((pv[0] == 'd' || pv[0] == 'D') && ((signed char *)pv)[1] >= '\0' && pv[1] <= ' ') - return t * 60 * 60 * 24; - if(len > 4 && str[4] == '-'){ - ts.tm_year = atoi(str) - 1900; - if((pv = strchr(str, '-')) != NULL && pv - str == 4){ - rp = pv + 1; - ts.tm_mon = atoi(rp) - 1; - if((pv = strchr(rp, '-')) != NULL && pv - str == 7){ - rp = pv + 1; - ts.tm_mday = atoi(rp); - if((pv = strchr(rp, 'T')) != NULL && pv - str == 10){ - rp = pv + 1; - ts.tm_hour = atoi(rp); - if((pv = strchr(rp, ':')) != NULL && pv - str == 13){ - rp = pv + 1; - ts.tm_min = atoi(rp); - } - if((pv = strchr(rp, ':')) != NULL && pv - str == 16){ - rp = pv + 1; - ts.tm_sec = atoi(rp); - } - if((pv = strchr(rp, '.')) != NULL && pv - str >= 19) rp = pv + 1; - strtol(rp, &pv, 10); - if((*pv == '+' || *pv == '-') && strlen(pv) >= 6 && pv[3] == ':') - ts.tm_sec -= (atoi(pv + 1) * 3600 + atoi(pv + 4) * 60) * (pv[0] == '+' ? 1 : -1); - } - } - } - ts.tm_sec += cbjetlag(); - return mktime(&ts); - } - if(len > 4 && str[4] == '/'){ - ts.tm_year = atoi(str) - 1900; - if((pv = strchr(str, '/')) != NULL && pv - str == 4){ - rp = pv + 1; - ts.tm_mon = atoi(rp) - 1; - if((pv = strchr(rp, '/')) != NULL && pv - str == 7){ - rp = pv + 1; - ts.tm_mday = atoi(rp); - if((pv = strchr(rp, ' ')) != NULL && pv - str == 10){ - rp = pv + 1; - ts.tm_hour = atoi(rp); - if((pv = strchr(rp, ':')) != NULL && pv - str == 13){ - rp = pv + 1; - ts.tm_min = atoi(rp); - } - if((pv = strchr(rp, ':')) != NULL && pv - str == 16){ - rp = pv + 1; - ts.tm_sec = atoi(rp); - } - if((pv = strchr(rp, '.')) != NULL && pv - str >= 19) rp = pv + 1; - strtol(rp, &pv, 10); - if((*pv == '+' || *pv == '-') && strlen(pv) >= 6 && pv[3] == ':') - ts.tm_sec -= (atoi(pv + 1) * 3600 + atoi(pv + 4) * 60) * (pv[0] == '+' ? 1 : -1); - } - } - } - ts.tm_sec += cbjetlag(); - return mktime(&ts); - } - crp = str; - if(len >= 4 && str[3] == ',') crp = str + 4; - while(*crp == ' '){ - crp++; - } - ts.tm_mday = atoi(crp); - while((*crp >= '0' && *crp <= '9') || *crp == ' '){ - crp++; - } - if(cbstrfwimatch(crp, "Jan")){ - ts.tm_mon = 0; - } else if(cbstrfwimatch(crp, "Feb")){ - ts.tm_mon = 1; - } else if(cbstrfwimatch(crp, "Mar")){ - ts.tm_mon = 2; - } else if(cbstrfwimatch(crp, "Apr")){ - ts.tm_mon = 3; - } else if(cbstrfwimatch(crp, "May")){ - ts.tm_mon = 4; - } else if(cbstrfwimatch(crp, "Jun")){ - ts.tm_mon = 5; - } else if(cbstrfwimatch(crp, "Jul")){ - ts.tm_mon = 6; - } else if(cbstrfwimatch(crp, "Aug")){ - ts.tm_mon = 7; - } else if(cbstrfwimatch(crp, "Sep")){ - ts.tm_mon = 8; - } else if(cbstrfwimatch(crp, "Oct")){ - ts.tm_mon = 9; - } else if(cbstrfwimatch(crp, "Nov")){ - ts.tm_mon = 10; - } else if(cbstrfwimatch(crp, "Dec")){ - ts.tm_mon = 11; - } else { - ts.tm_mon = -1; - } - if(ts.tm_mon >= 0) crp += 3; - while(*crp == ' '){ - crp++; - } - ts.tm_year = atoi(crp); - if(ts.tm_year >= 1969) ts.tm_year -= 1900; - while(*crp >= '0' && *crp <= '9'){ - crp++; - } - while(*crp == ' '){ - crp++; - } - if(ts.tm_mday > 0 && ts.tm_mon >= 0 && ts.tm_year >= 0){ - clen = strlen(crp); - if(clen >= 8 && crp[2] == ':' && crp[5] == ':'){ - ts.tm_hour = atoi(crp + 0); - ts.tm_min = atoi(crp + 3); - ts.tm_sec = atoi(crp + 6); - if(clen >= 14 && crp[8] == ' ' && (crp[9] == '+' || crp[9] == '-')){ - ts.tm_sec -= ((crp[10] - '0') * 36000 + (crp[11] - '0') * 3600 + - (crp[12] - '0') * 600 + (crp[13] - '0') * 60) * (crp[9] == '+' ? 1 : -1); - } else if(clen > 9){ - if(!strcmp(crp + 9, "JST")){ - ts.tm_sec -= 9 * 3600; - } else if(!strcmp(crp + 9, "CCT")){ - ts.tm_sec -= 8 * 3600; - } else if(!strcmp(crp + 9, "KST")){ - ts.tm_sec -= 9 * 3600; - } else if(!strcmp(crp + 9, "EDT")){ - ts.tm_sec -= -4 * 3600; - } else if(!strcmp(crp + 9, "EST")){ - ts.tm_sec -= -5 * 3600; - } else if(!strcmp(crp + 9, "CDT")){ - ts.tm_sec -= -5 * 3600; - } else if(!strcmp(crp + 9, "CST")){ - ts.tm_sec -= -6 * 3600; - } else if(!strcmp(crp + 9, "MDT")){ - ts.tm_sec -= -6 * 3600; - } else if(!strcmp(crp + 9, "MST")){ - ts.tm_sec -= -7 * 3600; - } else if(!strcmp(crp + 9, "PDT")){ - ts.tm_sec -= -7 * 3600; - } else if(!strcmp(crp + 9, "PST")){ - ts.tm_sec -= -8 * 3600; - } else if(!strcmp(crp + 9, "HDT")){ - ts.tm_sec -= -9 * 3600; - } else if(!strcmp(crp + 9, "HST")){ - ts.tm_sec -= -10 * 3600; - } - } - } - ts.tm_sec += cbjetlag(); - return mktime(&ts); - } - return -1; -} - - -/* Get user and system processing times. */ -void cbproctime(double *usrp, double *sysp){ - struct tms buf; - times(&buf); - if(usrp) *usrp = (double)buf.tms_utime / sysconf(_SC_CLK_TCK); - if(sysp) *sysp = (double)buf.tms_stime / sysconf(_SC_CLK_TCK); -} - - -/* Ensure that the standard I/O is binary mode. */ -void cbstdiobin(void){ - if(setmode(0, O_BINARY) == -1 || setmode(1, O_BINARY) == -1 || setmode(2, O_BINARY) == -1) - cbmyfatal("setmode failed"); -} - - - -/************************************************************************************************* - * features for experts - *************************************************************************************************/ - - -/* Show error message on the standard error output and exit. */ -void *cbmyfatal(const char *message){ - char buf[CB_MSGBUFSIZ]; - assert(message); - if(cbfatalfunc){ - cbfatalfunc(message); - } else { - sprintf(buf, "fatal error: %s\n", message); - write(2, buf, strlen(buf)); - } - exit(1); - return NULL; -} - - -/* Create a datum handle from an allocated region. */ -CBDATUM *cbdatumopenbuf(char *ptr, int size){ - CBDATUM *datum; - assert(ptr && size >= 0); - CB_REALLOC(ptr, size + 1); - CB_MALLOC(datum, sizeof(*datum)); - datum->dptr = ptr; - datum->dptr[size] = '\0'; - datum->dsize = size; - datum->asize = size; - return datum; -} - - -/* Set a buffer to a datum handle. */ -void cbdatumsetbuf(CBDATUM *datum, char *ptr, int size){ - assert(datum && ptr && size >= 0); - free(datum->dptr); - CB_REALLOC(ptr, size + 1); - datum->dptr = ptr; - datum->dptr[size] = '\0'; - datum->dsize = size; - datum->asize = size; -} - - -/* Add an allocated element at the end of a list. */ -void cblistpushbuf(CBLIST *list, char *ptr, int size){ - int index; - assert(list && ptr && size >= 0); - index = list->start + list->num; - if(index >= list->anum){ - list->anum *= 2; - CB_REALLOC(list->array, list->anum * sizeof(list->array[0])); - } - list->array[index].dptr = ptr; - list->array[index].dsize = size; - list->num++; -} - - -/* Get a map handle with specifying the number of buckets. */ -CBMAP *cbmapopenex(int bnum){ - CBMAP *map; - int i; - assert(bnum > 0); - CB_MALLOC(map, sizeof(*map)); - CB_MALLOC(map->buckets, sizeof(map->buckets[0]) * bnum); - for(i = 0; i < bnum; i++){ - map->buckets[i] = NULL; - } - map->first = NULL; - map->last = NULL; - map->cur = NULL; - map->bnum = bnum; - map->rnum = 0; - return map; -} - - - -/************************************************************************************************* - * private objects - *************************************************************************************************/ - - -/* Handler to invoke the global garbage collector. */ -static void cbggchandler(void){ - cbggckeeper(NULL, NULL); -} - - -/* Manage resources of the global garbage collector. - `ptr' specifies the pointer to add to the collection. If it is `NULL', all resources are - released. - `func' specifies the pointer to the function to release the resources. */ -static void cbggckeeper(void *ptr, void (*func)(void *)){ - static void **parray = NULL; - static void (**farray)(void *) = NULL; - static int onum = 0; - static int asiz = CB_GCUNIT; - int i; - if(!ptr){ - if(!parray) return; - for(i = onum - 1; i >= 0; i--){ - farray[i](parray[i]); - } - free(parray); - free(farray); - parray = NULL; - farray = NULL; - onum = 0; - asiz = CB_GCUNIT; - return; - } - if(!parray){ - CB_MALLOC(parray, sizeof(void *) * asiz); - CB_MALLOC(farray, sizeof(void *) * asiz); - if(atexit(cbggchandler) != 0) cbmyfatal("gc failed"); - } - if(onum >= asiz){ - asiz *= 2; - CB_REALLOC(parray, sizeof(void *) * asiz); - CB_REALLOC(farray, sizeof(void *) * asiz); - } - parray[onum] = ptr; - farray[onum] = func; - onum++; -} - - -/* Utility function for quick sort. - `bp' specifies the pointer to the pointer to an array. - `nmemb' specifies the number of elements of the array. - `size' specifies the size of each element. - `pswap' specifies the pointer to the swap region for a pivot. - `vswap' specifies the pointer to the swap region for elements. - `compar' specifies the pointer to comparing function. */ -static void cbqsortsub(char *bp, int nmemb, int size, char *pswap, char *vswap, - int(*compar)(const void *, const void *)){ - int top, bottom; - assert(bp && nmemb >= 0 && size > 0 && pswap && vswap && compar); - if(nmemb < 10){ - if(nmemb > 1) cbisort(bp, nmemb, size, compar); - return; - } - top = 0; - bottom = nmemb - 1; - memcpy(pswap, bp + (nmemb / 2) * size, size); - while(top - 1 < bottom){ - if(compar(bp + top * size, pswap) < 0){ - top++; - } else if(compar(bp + bottom * size, pswap) > 0){ - bottom--; - } else { - if(top != bottom){ - memcpy(vswap, bp + top * size, size); - memcpy(bp + top * size, bp + bottom * size, size); - memcpy(bp + bottom * size, vswap, size); - } - top++; - bottom--; - } - } - cbqsortsub(bp, top, size, pswap, vswap, compar); - cbqsortsub(bp + (bottom + 1) * size, nmemb - bottom - 1, size, pswap, vswap, compar); -} - - -/* Compare two list elements. - `a' specifies the pointer to one element. - `b' specifies the pointer to the other element. - The return value is positive if a is big, negative if b is big, else, it is 0. */ -static int cblistelemcmp(const void *a, const void *b){ - int i, size; - CBLISTDATUM *ap, *bp; - char *ao, *bo; - assert(a && b); - ap = (CBLISTDATUM *)a; - bp = (CBLISTDATUM *)b; - ao = ap->dptr; - bo = bp->dptr; - size = ap->dsize < bp->dsize ? ap->dsize : bp->dsize; - for(i = 0; i < size; i++){ - if(ao[i] > bo[i]) return 1; - if(ao[i] < bo[i]) return -1; - } - return ap->dsize - bp->dsize; -} - - -/* Compare two keys. - `abuf' specifies the pointer to the region of the former. - `asiz' specifies the size of the region. - `bbuf' specifies the pointer to the region of the latter. - `bsiz' specifies the size of the region. - The return value is 0 if two equals, positive if the formar is big, else, negative. */ -static int cbkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz){ - assert(abuf && asiz >= 0 && bbuf && bsiz >= 0); - if(asiz > bsiz) return 1; - if(asiz < bsiz) return -1; - return memcmp(abuf, bbuf, asiz); -} - - - -/* END OF FILE */ |