/*************************************************************************************************
 * The utitlity API of QDBM
 *                                                      Copyright (C) 2000-2003 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.
 *************************************************************************************************/


#ifndef _CABIN_H                         /* duplication check */
#define _CABIN_H

#include <stdlib.h>



/*************************************************************************************************
 * API
 *************************************************************************************************/


typedef struct {                         /* type of structure for a basic datum */
  char *dptr;                            /* pointer to the region */
  int dsize;                             /* size of the region */
  int asize;                             /* size of the allocated region */
} CBDATUM;

typedef struct {                         /* type of structure for an element of a list */
  char *dptr;                            /* pointer to the region */
  int dsize;                             /* size of the effective region */
} CBLISTDATUM;

typedef struct {                         /* type of structure for a list */
  CBLISTDATUM *array;                    /* array of data */
  int anum;                              /* number of the elements of the array */
  int start;                             /* start index of using elements */
  int num;                               /* number of using elements */
} CBLIST;

typedef struct {                         /* type of structure for an element of a map */
  char *kbuf;                            /* pointer to the region of the key */
  int ksiz;                              /* size of the region of the key */
  char *vbuf;                            /* pointer to the region of the value */
  int vsiz;                              /* size of the region of the value */
  int hash;                              /* second hash value */
  char *left;                            /* pointer to the left child */
  char *right;                           /* pointer to the right child */
  char *prev;                            /* pointer to the previous element */
  char *next;                            /* pointer to the next element */
} CBMAPDATUM;

typedef struct {                         /* type of structure for a map */
  CBMAPDATUM **buckets;                  /* bucket array */
  CBMAPDATUM *first;                     /* pointer to the first element */
  CBMAPDATUM *last;                      /* pointer to the last element */
  CBMAPDATUM *cur;                       /* pointer to the current element */
  int rnum;                              /* number of records */
} CBMAP;


/* Call back function for handling a fatal error.
   The argument specifies the error message.  The initial value of this variable is `NULL'.
   If the value is `NULL', the default function is called when a fatal error occurs. A fatal
   error occures when memory allocation is failed. */
extern void (*cbfatalfunc)(const char *);


/* Allocate a region on memory.
   `size' specifies the size of the region.
   The return value is the pointer to the allocated region.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
void *cbmalloc(size_t size);


/* Re-allocate a region on memory.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.
   The return value is the pointer to the re-allocated region.
   Because the region of the return value is allocated with the `realloc' call, it should be
   released with the `free' call if it is no longer in use. */
void *cbrealloc(void *ptr, size_t size);


/* Duplicate a region on memory.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the pointer to the allocated region of the duplicate.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if
   it is no longer in use. */
char *cbmemdup(const char *ptr, int size);


/* Sort an array using insert sort.
   `base' spacifies the pointer to an array.
   `nmemb' specifies the number of elements of the array.
   `size' specifies the size of each element.
   `compar' specifies the pointer to comparing function.  The two arguments specify the pointers
   of elements.  The comparing function should returns positive if the former is big, negative
   if the latter is big, 0 if both are equal.
   Insert sort is useful only if most elements have been sorted already. */
void cbisort(void *base, int nmemb, int size, int(*compar)(const void *, const void *));


/* Sort an array using shell sort.
   `base' spacifies the pointer to an array.
   `nmemb' specifies the number of elements of the array.
   `size' specifies the size of each element.
   `compar' specifies the pointer to comparing function.  The two arguments specify the pointers
   of elements.  The comparing function should returns positive if the former is big, negative
   if the latter is big, 0 if both are equal.
   If most elements have been sorted, shell sort may be faster than heap sort or quick sort. */
void cbssort(void *base, int nmemb, int size, int(*compar)(const void *, const void *));


/* Sort an array using heap sort.
   `base' spacifies the pointer to an array.
   `nmemb' specifies the number of elements of the array.
   `size' specifies the size of each element.
   `compar' specifies the pointer to comparing function.  The two arguments specify the pointers
   of elements.  The comparing function should returns positive if the former is big, negative
   if the latter is big, 0 if both are equal.
   Although heap sort is robust against bias of input, quick sort is faster in most cases. */
void cbhsort(void *base, int nmemb, int size, int(*compar)(const void *, const void *));


/* Sort an array using quick sort.
   `base' spacifies the pointer to an array.
   `nmemb' specifies the number of elements of the array.
   `size' specifies the size of each element.
   `compar' specifies the pointer to comparing function.  The two arguments specify the pointers
   of elements.  The comparing function should returns positive if the former is big, negative
   if the latter is big, 0 if both are equal.
   Being sensitive to bias of input, quick sort is the fastest sorting algorithm. */
void cbqsort(void *base, int nmemb, int size, int(*compar)(const void *, const void *));


/* Get a datum handle.
   `ptr' specifies the pointer to the region of the initial content.  If it is `NULL', an empty
   datum is created.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is a datum handle. */
CBDATUM *cbdatumopen(const char *ptr, int size);


/* Copy a datum.
   `datum' specifies a datum handle.
   The return value is a new datum handle. */
CBDATUM *cbdatumdup(const CBDATUM *datum);


/* Free a datum handle.
   `datum' specifies a datum handle.
   Because the region of a closed handle is released, it becomes impossible to use the handle. */
void cbdatumclose(CBDATUM *datum);


/* Concatenate a datum and a region.
   `datum' specifies a datum handle.
   `ptr' specifies the pointer to the region to be appended.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'. */
void cbdatumcat(CBDATUM *datum, const char *ptr, int size);


/* Get the pointer of the region of a datum.
   `datum' specifies a datum handle.
   The return value is the pointer of the region of a datum.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string. */
const char *cbdatumptr(const CBDATUM *datum);


/* Get the size of the region of a datum.
   `datum' specifies a datum handle.
   The return value is the size of the region of a datum. */
int cbdatumsize(const CBDATUM *datum);


/* Change the size of the region of a datum.
   `datum' specifies a datum handle.
   `size' specifies the new size of the region.
   If the new size is bigger than the one of old, the surplus region is filled with zero codes. */
void cbdatumsetsize(CBDATUM *datum, int size);


/* Get a list handle.
   The return value is a list handle. */
CBLIST *cblistopen(void);


/* Copy a list.
   `list' specifies a list handle.
   The return value is a new list handle. */
CBLIST *cblistdup(const CBLIST *list);


/* Close a list handle.
   `list' specifies a list handle.
   Because the region of a closed handle is released, it becomes impossible to use the handle. */
void cblistclose(CBLIST *list);


/* Get the number of elements of a list.
   `list' specifies a list handle.
   The return value is the number of elements of the list. */
int cblistnum(const CBLIST *list);


/* Get the pointer to the region of an element.
   `list' specifies a list handle.
   `index' specifies the index of an element.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the value.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  If `index' is equal to or more than
   the number of elements, the return value is `NULL'. */
const char *cblistval(const CBLIST *list, int index, int *sp);


/* Add an element at the end of a list.
   `list' specifies a list handle.
   `ptr' specifies the pointer to the region of an element.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'. */
void cblistpush(CBLIST *list, const char *ptr, int size);


/* Remove an element of the end of a list.
   `list' specifies a list handle.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the value.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if it
   is no longer in use.  If the list is empty, the return value is `NULL'. */
char *cblistpop(CBLIST *list, int *sp);


/* Add an element at the top of a list.
   `list' specifies a list handle.
   `ptr' specifies the pointer to the region of an element.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'. */
void cblistunshift(CBLIST *list, const char *ptr, int size);


/* Remove an element of the top of a list.
   `list' specifies a list handle.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the value.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if it
   is no longer in use.  If the list is empty, the return value is `NULL'. */
char *cblistshift(CBLIST *list, int *sp);


/* Add an element at the specified location of a list.
   `list' specifies a list handle.
   `index' specifies the index of an element.
   `ptr' specifies the pointer to the region of the element.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'. */
void cblistinsert(CBLIST *list, int index, const char *ptr, int size);


/* Remove an element at the specified location of a list.
   `list' specifies a list handle.
   `index' specifies the index of an element.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the value.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if it
   is no longer in use.  If `index' is equal to or more than the number of elements, no element
   is removed and the return value is `NULL'. */
char *cblistremove(CBLIST *list, int index, int *sp);


/* Sort elements of a list in lexical order.
   `list' specifies a list handle.
   Quick sort is used for sorting. */
void cblistsort(CBLIST *list);


/* Search a list for an element using liner search.
   `list' specifies a list handle.
   `ptr' specifies the pointer to the region of a key.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the index of a corresponding element or -1 if there is no corresponding
   element.  If two or more elements corresponds, the former returns. */
int cblistlsearch(const CBLIST *list, const char *ptr, int size);


/* Search a list for an element using binary search.
   `list' specifies a list handle.  It should be sorted in lexical order.
   `ptr' specifies the pointer to the region of a key.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the index of a corresponding element or -1 if there is no corresponding
   element.  If two or more elements corresponds, which returnes is not defined. */
int cblistbsearch(const CBLIST *list, const char *ptr, int size);


/* Serialize a list into a byte array.
   `list' specifies a list handle.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.
   The return value is the pointer to the region of the result serial region.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cblistdump(const CBLIST *list, int *sp);


/* Redintegrate a serialized list.
   `ptr' specifies the pointer to a byte array.
   `size' specifies the size of the region.
   The return value is a new list handle. */
CBLIST *cblistload(const char *ptr, int size);


/* Get a map handle.
   The return value is a map handle. */
CBMAP *cbmapopen(void);


/* Copy a map.
   `map' specifies a map handle.
   The return value is a new map handle.
   The iterator of the source map is initialized. */
CBMAP *cbmapdup(CBMAP *map);


/* Close a map handle.
   `map' specifies a map handle.
   Because the region of a closed handle is released, it becomes impossible to use the handle. */
void cbmapclose(CBMAP *map);


/* Store a record.
   `map' specifies a map handle.
   `kbuf' specifies the pointer to the region of a key.
   `ksiz' specifies the size of the region of the key.  If it is negative, the size is assigned
   with `strlen(kbuf)'.
   `vbuf' specifies the pointer to the region of a value.
   `vsiz' specifies the size of the region of the value.  If it is negative, the size is
   assigned with `strlen(vbuf)'.
   `over' specifies whether the value of the duplicated record is overwritten or not.
   If `over' is false and the key is duplicated, the return value is false, else, it is true. */
int cbmapput(CBMAP *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int over);


/* Delete a record.
   `map' specifies a map handle.
   `kbuf' specifies the pointer to the region of a key.
   `ksiz' specifies the size of the region of the key.  If it is negative, the size is assigned
   with `strlen(kbuf)'.
   If successful, the return value is true.  False is returned when no record corresponds to
   the specified key. */
int cbmapout(CBMAP *map, const char *kbuf, int ksiz);


/* Retrieve a record.
   `map' specifies a map handle.
   `kbuf' specifies the pointer to the region of a key.
   `ksiz' specifies the size of the region of the key.  If it is negative, the size is assigned
   with `strlen(kbuf)'.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   If successful, the return value is the pointer to the region of the value of the
   corresponding record.  `NULL' is returned when no record corresponds.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string. */
const char *cbmapget(const CBMAP *map, const char *kbuf, int ksiz, int *sp);


/* Move a record to the edge.
   `map' specifies a map handle.
   `kbuf' specifies the pointer to the region of a key.
   `ksiz' specifies the size of the region of the key.  If it is negative, the size is assigned
   with `strlen(kbuf)'.
   `head' specifies the destination which is head if it is true or tail if else.
   If successful, the return value is true.  False is returned when no record corresponds to
   the specified key. */
int cbmapmove(CBMAP *map, const char *kbuf, int ksiz, int head);


/* Initialize the iterator of a map handle.
   `map' specifies a map handle.
   The iterator is used in order to access the key of every record stored in a map. */
void cbmapiterinit(CBMAP *map);


/* Get the next key of the iterator.
   `map' specifies a map handle.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   If successful, the return value is the pointer to the region of the next key, else, it is
   `NULL'.  `NULL' is returned when no record is to be get out of the iterator.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  The order of iteration is assured
   to be the same of the one of storing. */
const char *cbmapiternext(CBMAP *map, int *sp);


/* Get the number of the records stored in a map.
   `map' specifies a map handle.
   The return value is the number of the records stored in the map. */
int cbmaprnum(const CBMAP *map);


/* Serialize a map into a byte array.
   `map' specifies a map handle.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.
   The return value is the pointer to the region of the result serial region.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cbmapdump(CBMAP *map, int *sp);


/* Redintegrate a serialized map.
   `ptr' specifies the pointer to a byte array.
   `size' specifies the size of the region.
   The return value is a new map handle. */
CBMAP *cbmapload(const char *ptr, int size);


/* Allocate a formatted string on memory.
   `format' specifies a printf-like format string.  The conversion character `%' can be used
   with such flag characters as `d', `o', `u', `x', `X', `e', `E', `f', `g', `G', `c', `s', and
   `%'.  Specifiers of the field length and the precision can be put between the conversion
   characters and the flag characters.  The specifiers consist of decimal characters, `.', `+',
   `-', and the space character.
   The other arguments are used according to the format string.
   The return value is the pointer to the allocated region of the result string.  Because the
   region of the return value is allocated with the `malloc' call, it should be released with
   the `free' call if it is no longer in use. */
char *cbsprintf(const char *format, ...);


/* Replace some patterns in a string.
   `str' specifies the pointer to a source string.
   `pairs' specifies the handle of a map composed of pairs of replacement.  The key of each pair
   specifies a pattern before replacement and its value specifies the pattern after replacement.
   The return value is the pointer to the allocated region of the result string.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cbreplace(const char *str, CBMAP *pairs);


/* Make a list by splitting a serial datum.
   `ptr' specifies the pointer to the region of the source content.  If it is `NULL', an empty
   datum is created.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   `dalim' specifies a string containing delimiting characters.  If it is `NULL', zero code is
   used as a delimiter.
   The return value is a list handle.
   Because the handle of the return value is opened with the function `cblistopen', it should
   be closed with the function `cblistclose'. */
CBLIST *cbsplit(const char *ptr, int size, const char *delim);


/* Read whole data of a file.
   `name' specifies the name of a file.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the allocated region of the read data.  Because an
   additional zero code is appended at the end of the region of the return value, the return
   value can be treated as a character string.  Because the region of the return value is
   allocated with the `malloc' call, it should be released with the `free' call if it is no
   longer in use.  */
char *cbreadfile(const char *name, int *sp);


/* Read every line of a file.
   `name' specifies the name of a file.
   The return value is a list handle of the lines if successful, else it is NULL.
   Line separators are cut out. */
CBLIST *cbreadlines(const char *name);


/* Read names of files in a directory.
   `name' specifies the name of a directory.
   The return value is a list handle of names if successful, else it is NULL. */
CBLIST *cbdirlist(const char *name);


/* Get the status of a file or a directory.
   `name' specifies the name of a file or a directory.
   `dirp' specifies the pointer to a variable to which whether the file is a directory is
   assigned.  If it is `NULL', it is not used.
   `sizep' specifies the pointer to a variable to which the size of the file is assigned.  If it
   is `NULL', it is not used.
   `mtimep' specifies the pointer to a variable to which the last modified time of the file is
   assigned.  If it is `NULL', it is not used.
   If successful, the return value is true, else, false.  False is returned when the file does
   not exist or the permission is denied. */
int cbfilestat(const char *name, int *isdirp, int *sizep, int *mtimep);


/* Encode a serial object with URL encoding.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the pointer to the result string.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cburlencode(const char *ptr, int size);


/* Decode a string encoded with URL encoding.
   `str' specifies the pointer to an encoded string.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the result.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if
   it is no longer in use. */
char *cburldecode(const char *str, int *sp);


/* Encode a serial object with Base64 encoding.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the pointer to the result string.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cbbaseencode(const char *ptr, int size);


/* Decode a string encoded with Base64 encoding.
   `str' specifies the pointer to an encoded string.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the result.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if
   it is no longer in use. */
char *cbbasedecode(const char *str, int *sp);


/* Encode a serial object with quoted-printable encoding.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   The return value is the pointer to the result string.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use. */
char *cbquoteencode(const char *ptr, int size);


/* Decode a string encoded with quoted-printable encoding.
   `str' specifies the pointer to an encoded string.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   The return value is the pointer to the region of the result.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if
   it is no longer in use. */
char *cbquotedecode(const char *str, int *sp);


/* Compress a serial object with ZLIB.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.  If it is negative, the size is assigned with
   `strlen(ptr)'.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.
   If successful, the return value is the pointer to the result object, else, it is `NULL'.
   Because the region of the return value is allocated with the `malloc' call, it should be
   released with the `free' call if it is no longer in use.  This function is available only if
   QDBM is built with enabling ZLIB. */
char *cbdeflate(const char *ptr, int size, int *sp);


/* Decompress a serial object compressed with ZLIB.
   `ptr' specifies the pointer to a region.
   `size' specifies the size of the region.
   `sp' specifies the pointer to a variable to which the size of the region of the return
   value is assigned.  If it is `NULL', it is not used.
   If successful, the return value is the pointer to the result object, else, it is `NULL'.
   Because an additional zero code is appended at the end of the region of the return value,
   the return value can be treated as a character string.  Because the region of the return
   value is allocated with the `malloc' call, it should be released with the `free' call if it
   is no longer in use.  This function is available only if QDBM is built with enabling ZLIB. */
char *cbinflate(const char *ptr, int size, int *sp);



/*************************************************************************************************
 * Macros for Experts
 *************************************************************************************************/


/* Alias of `cbdatumptr'. */
#define CB_DATUMPTR(datum) ((const char *)(datum->dptr))


/* Alias of `cbdatumsize'. */
#define CB_DATUMSIZE(datum) ((int)(datum->dsize))


/* Alias of `cblistnum'. */
#define CB_LISTNUM(list) ((int)(list->num))


/* Alias of `cblistval'.
   However, `sp' is ignored. */
#define CB_LISTVAL(list,index,sp) ((const char *)(list->array[list->start+index].dptr))



#endif                                   /* duplication check */


/* END OF FILE */
