+++ /dev/null
-PWD=$(shell pwd)
-INCS=-I$(PWD)/src/include
-DEBUG=-g -ggdb
-BASE_FLAGS=$(INCS) $(DEBUG) -I$(LIBEDIT_DIR)/src/ -fPIC
-PICKY=-O2
-CFLAGS=$(BASE_FLAGS) $(PICKY)
-CXXFLAGS=$(BASE_FLAGS)
-MYLIB=libks.a
-LIBS=-lncurses -lks -lpthread -lm
-LDFLAGS=-L.
-OBJS=src/ks.o src/ks_threadmutex.o src/ks_config.o src/ks_json.o src/ks_buffer.o src/mpool.o src/table.o src/table_util.o src/simclist.o
-SRC=src/ks.c src/ks_json.c src/ks_threadmutex.c src/ks_config.c src/ks_json.c src/ks_buffer.c src/mpool.c src/table.c src/table_util.c src/simclist.c
-HEADERS=src/include/ks_config.h src/include/ks.h src/include/ks_threadmutex.h src/include/ks_json.h src/include/ks_buffer.h src/include/mpool.h src/include/mpool_loc.h src/include/table.h src/include/table_loc.h src/include/simclist.h
-SOLINK=-shared -Xlinker -x
-
-all: $(MYLIB)
-
-$(MYLIB): $(OBJS) $(HEADERS) $(SRC)
- ar rcs $(MYLIB) $(OBJS)
- ranlib $(MYLIB)
-
-%.o: %.c $(HEADERS)
- $(CC) $(CC_CFLAGS) $(CFLAGS) $(CXFLAGS) -c $< -o $@
-
-test-clean:
- rm -f test/testpools
-
-clean: test-clean
- rm -f *.o src/*.o libks.a *~ src/*~ src/include/*~
-
-test/testpools: $(MYLIB) test/testpools.c
- $(CC) $(CXFLAGS) test/testpools.c -Isrc/include/ libks.a -o test/testpools
-
-test-all: test/testpools
+++ /dev/null
-const char *cc = ".========================================================================================================.\n| ____ _____ ____ _ ____ _ _ _____ |\n| / ___|___ _ __ ___ ___ |_ _|__ / ___| |_ _ ___ / ___|___ _ __ ( ) |___ / |\n| | | / _ \\| '_ ` _ \\ / _ \\ | |/ _ \\ | | | | | | |/ _ \\ | / _ \\| '_ \\ |/| | |_ \\ |\n| | |__| (_) | | | | | | __/ | | (_) | | |___| | |_| | __/ |__| (_) | | | | | |___) | |\n| \\____\\___/|_| |_| |_|\\___| |_|\\___/ \\____|_|\\__,_|\\___|\\____\\___/|_| |_| |_|____/ |\n| |\n| ____ _ _ _ _ ____ _ |\n| / ___| |__ (_) ___ __ _ __ _ ___ | | | / ___| / \\ |\n| | | | '_ \\| |/ __/ _` |/ _` |/ _ \\ | | | \\___ \\ / _ \\ |\n| | |___| | | | | (_| (_| | (_| | (_) | | |_| |___) / ___ \\ |\n| \\____|_| |_|_|\\___\\__,_|\\__, |\\___( ) \\___/|____/_/ \\_\\ |\n| |___/ |/ |\n| _ _ __ _ _ ___ _ _ ____ ___ _ _____ |\n| / \\ _ _ __ _ _ _ ___| |_ / /_ | |_| |__ ( _ )| |_| |__ |___ \\ / _ \\/ |___ / |\n| / _ \\| | | |/ _` | | | / __| __| | '_ \\| __| '_ \\ _____ / _ \\| __| '_ \\ __) | | | | | |_ \\ |\n| / ___ \\ |_| | (_| | |_| \\__ \\ |_ | (_) | |_| | | | |_____| | (_) | |_| | | | / __/| |_| | |___) | |\n| /_/ \\_\\__,_|\\__, |\\__,_|___/\\__| \\___/ \\__|_| |_| \\___/ \\__|_| |_| |_____|\\___/|_|____/ |\n| |___/ |\n| _ |\n| __ ____ ____ __ ___| |_ _ ___ ___ ___ _ __ ___ ___ _ __ ___ |\n| \\ \\ /\\ / /\\ \\ /\\ / /\\ \\ /\\ / / / __| | | | |/ _ \\/ __/ _ \\| '_ \\ / __/ _ \\| '_ ` _ \\ |\n| \\ V V / \\ V V / \\ V V / _ | (__| | |_| | __/ (_| (_) | | | | _ | (_| (_) | | | | | | |\n| \\_/\\_/ \\_/\\_/ \\_/\\_/ (_) \\___|_|\\__,_|\\___|\\___\\___/|_| |_| (_) \\___\\___/|_| |_| |_| |\n| |\n.========================================================================================================.\n";
-
+++ /dev/null
-/*
- * Memory pool defines.
- *
- * Copyright 1996 by Gray Watson.
- *
- * This file is part of the mpool package.
- *
- * Permission to use, copy, modify, and distribute this software for
- * any purpose and without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies, and that the name of Gray Watson not be used in advertising
- * or publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: mpool.h,v 1.4 2006/05/31 20:26:11 gray Exp $
- */
-
-#ifndef __MPOOL_H__
-#define __MPOOL_H__
-
-#include "ks.h"
-#include <sys/types.h>
-
-/*
- * mpool flags to mpool_alloc or mpool_set_attr
- */
-
-/*
- * Choose a best fit algorithm not first fit. This takes more CPU
- * time but will result in a tighter heap.
- */
-#define MPOOL_FLAG_BEST_FIT (1<<0)
-
-/*
- * By default the library adds 2 bytes onto all allocations to insert
- * a magic number that it can look for to determine how large a freed
- * memory chunk is. This flag indicates that few if any frees are
- * going to be performed on the pool and to not waste memory on these
- * bytes.
- */
-#define MPOOL_FLAG_NO_FREE (1<<1)
-
-/*
- * This enables very heavy packing at the possible expense of CPU.
- * This affects a number of parts of the library.
- *
- * By default the 1st page of memory is reserved for the main mpool
- * structure. This flag will cause the rest of the 1st block to be
- * available for use as user memory.
- *
- * By default the library looks through the memory when freed looking
- * for a magic value. There is an internal max size that it will look
- * and then it will give up. This flag forces it to look until it
- * finds it.
- */
-#define MPOOL_FLAG_HEAVY_PACKING (1<<2)
-
-/*
- * Use MMAP_ANONYMOUS instead of /dev/zero
- */
-#define MPOOL_FLAG_ANONYMOUS (1<<3)
-
-/*
- * Mpool error codes
- */
-#define MPOOL_ERROR_NONE 1 /* no error */
-#define MPOOL_ERROR_ARG_NULL 2 /* function argument is null */
-#define MPOOL_ERROR_ARG_INVALID 3 /* function argument is invalid */
-#define MPOOL_ERROR_PNT 4 /* invalid mpool pointer */
-#define MPOOL_ERROR_POOL_OVER 5 /* mpool structure was overwritten */
-#define MPOOL_ERROR_PAGE_SIZE 6 /* could not get system page-size */
-#define MPOOL_ERROR_OPEN_ZERO 7 /* could not open /dev/zero */
-#define MPOOL_ERROR_NO_MEM 8 /* no memory available */
-#define MPOOL_ERROR_MMAP 9 /* problems with mmap */
-#define MPOOL_ERROR_SIZE 10 /* error processing requested size */
-#define MPOOL_ERROR_TOO_BIG 11 /* allocation exceeded max size */
-#define MPOOL_ERROR_MEM 12 /* invalid memory address */
-#define MPOOL_ERROR_MEM_OVER 13 /* memory lower bounds overwritten */
-#define MPOOL_ERROR_NOT_FOUND 14 /* memory block not found in pool */
-#define MPOOL_ERROR_IS_FREE 15 /* memory block already free */
-#define MPOOL_ERROR_BLOCK_STAT 16 /* invalid internal block status */
-#define MPOOL_ERROR_FREE_ADDR 17 /* invalid internal free address */
-#define MPOOL_ERROR_UNUSED 18 /* UNUSED */
-#define MPOOL_ERROR_NO_PAGES 19 /* ran out of pages in pool */
-#define MPOOL_ERROR_ALLOC 20 /* calloc,malloc,free,realloc failed */
-#define MPOOL_ERROR_PNT_OVER 21 /* pointer structure was overwritten */
-
-/*
- * Mpool function IDs for the mpool_log_func callback function.
- */
-#define MPOOL_FUNC_CLOSE 1 /* mpool_close function called */
-#define MPOOL_FUNC_CLEAR 2 /* mpool_clear function called */
-#define MPOOL_FUNC_ALLOC 3 /* mpool_alloc function called */
-#define MPOOL_FUNC_CALLOC 4 /* mpool_calloc function called */
-#define MPOOL_FUNC_FREE 5 /* mpool_free function called */
-#define MPOOL_FUNC_RESIZE 6 /* mpool_resize function called */
-
-/*
- * void mpool_log_func_t
- *
- * DESCRIPTION:
- *
- * Mpool transaction log function.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENT:
- *
- * mp_p -> Associated mpool address.
- *
- * func_id -> Integer function ID which identifies which mpool
- * function is being called.
- *
- * byte_size -> Optionally specified byte size.
- *
- * ele_n -> Optionally specified element number. For mpool_calloc
- * only.
- *
- * new_addr -> Optionally specified new address. For mpool_alloc,
- * mpool_calloc, and mpool_resize only.
- *
- * old_addr -> Optionally specified old address. For mpool_resize and
- * mpool_free only.
- *
- * old_byte_size -> Optionally specified old byte size. For
- * mpool_resize only.
- */
-typedef void (*mpool_log_func_t)(const void *mp_p,
- const int func_id,
- const unsigned long byte_size,
- const unsigned long ele_n,
- const void *old_addr, const void *new_addr,
- const unsigned long old_byte_size);
-
-#ifdef MPOOL_MAIN
-
-#include "mpool_loc.h"
-
-#else
-
-/* generic mpool type */
-typedef void mpool_t;
-
-#endif
-
-/*<<<<<<<<<< The below prototypes are auto-generated by fillproto */
-
-/*
- * mpool_t *mpool_open
- *
- * DESCRIPTION:
- *
- * Open/allocate a new memory pool.
- *
- * RETURNS:
- *
- * Success - Pool pointer which must be passed to mpool_close to
- * deallocate.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * flags -> Flags to set attributes of the memory pool. See the top
- * of mpool.h.
- *
- * page_size -> Set the internal memory page-size. This must be a
- * multiple of the getpagesize() value. Set to 0 for the default.
- *
- * start_addr -> Starting address to try and allocate memory pools.
- * This is ignored if the MPOOL_FLAG_USE_SBRK is enabled.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(mpool_t *) mpool_open(const unsigned int flags, const unsigned int page_size,
- void *start_addr, int *error_p);
-
-/*
- * int mpool_close
- *
- * DESCRIPTION:
- *
- * Close/free a memory allocation pool previously opened with
- * mpool_open.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to our memory pool.
- */
-KS_DECLARE(int) mpool_close(mpool_t *mp_p);
-
-/*
- * int mpool_clear
- *
- * DESCRIPTION:
- *
- * Wipe an opened memory pool clean so we can start again.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to our memory pool.
- */
-KS_DECLARE(int) mpool_clear(mpool_t *mp_p);
-
-/*
- * void *mpool_alloc
- *
- * DESCRIPTION:
- *
- * Allocate space for bytes inside of an already open memory pool.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal malloc.
- *
- * byte_size -> Number of bytes to allocate in the pool. Must be >0.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *) mpool_alloc(mpool_t *mp_p, const unsigned long byte_size,
- int *error_p);
-
-/*
- * void *mpool_calloc
- *
- * DESCRIPTION:
- *
- * Allocate space for elements of bytes in the memory pool and zero
- * the space afterwards.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal calloc.
- *
- * ele_n -> Number of elements to allocate.
- *
- * ele_size -> Number of bytes per element being allocated.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *)mpool_calloc(mpool_t *mp_p, const unsigned long ele_n,
- const unsigned long ele_size, int *error_p);
-
-/*
- * int mpool_free
- *
- * DESCRIPTION:
- *
- * Free an address from a memory pool.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal free.
- *
- * addr <-> Address to free.
- *
- * size -> Size of the address being freed.
- */
-
-KS_DECLARE(int) mpool_free(mpool_t *mp_p, void *addr, const unsigned long size);
-
-/*
- * void *mpool_resize
- *
- * DESCRIPTION:
- *
- * Reallocate an address in a mmeory pool to a new size. This is
- * different from realloc in that it needs the old address' size. If
- * you don't have it then you need to allocate new space, copy the
- * data, and free the old pointer yourself.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal realloc.
- *
- * old_addr -> Previously allocated address.
- *
- * old_byte_size -> Size of the old address. Must be known, cannot be
- * 0.
- *
- * new_byte_size -> New size of the allocation.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *) mpool_resize(mpool_t *mp_p, void *old_addr,
- const unsigned long old_byte_size,
- const unsigned long new_byte_size,
- int *error_p);
-
-/*
- * int mpool_stats
- *
- * DESCRIPTION:
- *
- * Return stats from the memory pool.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p -> Pointer to the memory pool.
- *
- * page_size_p <- Pointer to an unsigned integer which, if not NULL,
- * will be set to the page-size of the pool.
- *
- * num_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the number of pointers currently allocated in pool.
- *
- * user_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the number of user bytes allocated in this pool.
- *
- * max_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the maximum number of user bytes that have been
- * allocated in this pool.
- *
- * tot_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the total amount of space (including administrative
- * overhead) used by the pool.
- */
-KS_DECLARE(int) mpool_stats(const mpool_t *mp_p, unsigned int *page_size_p,
- unsigned long *num_alloced_p,
- unsigned long *user_alloced_p,
- unsigned long *max_alloced_p,
- unsigned long *tot_alloced_p);
-
-/*
- * int mpool_set_log_func
- *
- * DESCRIPTION:
- *
- * Set a logging callback function to be called whenever there was a
- * memory transaction. See mpool_log_func_t.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * log_func -> Log function (defined in mpool.h) which will be called
- * with each mpool transaction.
- */
-KS_DECLARE(int) mpool_set_log_func(mpool_t *mp_p, mpool_log_func_t log_func);
-
-/*
- * int mpool_set_max_pages
- *
- * DESCRIPTION:
- *
- * Set the maximum number of pages that the library will use. Once it
- * hits the limit it will return MPOOL_ERROR_NO_PAGES.
- *
- * NOTE: if the MPOOL_FLAG_HEAVY_PACKING is set then this max-pages
- * value will include the page with the mpool header structure in it.
- * If the flag is _not_ set then the max-pages will not include this
- * first page.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * max_pages -> Maximum number of pages used by the library.
- */
-KS_DECLARE(int) mpool_set_max_pages(mpool_t *mp_p, const unsigned int max_pages);
-
-/*
- * const char *mpool_strerror
- *
- * DESCRIPTION:
- *
- * Return the corresponding string for the error number.
- *
- * RETURNS:
- *
- * Success - String equivalient of the error.
- *
- * Failure - String "invalid error code"
- *
- * ARGUMENTS:
- *
- * error -> Error number that we are converting.
- */
-KS_DECLARE(const char *) mpool_strerror(const int error);
-
-/*<<<<<<<<<< This is end of the auto-generated output from fillproto. */
-
-#endif /* ! __MPOOL_H__ */
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * Memory pool local defines.
- *
- * Copyright 1996 by Gray Watson.
- *
- * This file is part of the mpool package.
- *
- * Permission to use, copy, modify, and distribute this software for
- * any purpose and without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies, and that the name of Gray Watson not be used in advertising
- * or publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: mpool_loc.h,v 1.2 2005/05/20 20:08:54 gray Exp $
- */
-
-#ifndef __MPOOL_LOC_H__
-#define __MPOOL_LOC_H__
-
-#define MPOOL_MAGIC 0xABACABA /* magic for struct */
-#define BLOCK_MAGIC 0xB1B1007 /* magic for blocks */
-#define FENCE_MAGIC0 (unsigned char)(0xFAU) /* 1st magic mem byte */
-#define FENCE_MAGIC1 (unsigned char)(0xD3U) /* 2nd magic mem byte */
-
-#define FENCE_SIZE 2 /* fence space */
-#define MIN_ALLOCATION (sizeof(mpool_free_t)) /* min alloc */
-#define MAX_FREE_SEARCH 10240 /* max size to search */
-#define MAX_FREE_LIST_SEARCH 100 /* max looking for free mem */
-
-/*
- * bitflag tools for Variable and a Flag
- */
-#define BIT_FLAG(x) (1 << (x))
-#define BIT_SET(v,f) (v) |= (f)
-#define BIT_CLEAR(v,f) (v) &= ~(f)
-#define BIT_IS_SET(v,f) ((v) & (f))
-#define BIT_TOGGLE(v,f) (v) ^= (f)
-
-#define SET_POINTER(pnt, val) \
- do { \
- if ((pnt) != NULL) { \
- (*(pnt)) = (val); \
- } \
- } while(0)
-
-#define BLOCK_FLAG_USED BIT_FLAG(0) /* block is used */
-#define BLOCK_FLAG_FREE BIT_FLAG(1) /* block is free */
-
-#define DEFAULT_PAGE_MULT 16 /* pagesize = this * getpagesize*/
-
-/* How many pages SIZE bytes resides in. We add in the block header. */
-#define PAGES_IN_SIZE(mp_p, size) (((size) + sizeof(mpool_block_t) + \
- (mp_p)->mp_page_size - 1) / \
- (mp_p)->mp_page_size)
-#define SIZE_OF_PAGES(mp_p, page_n) ((page_n) * (mp_p)->mp_page_size)
-#define MAX_BITS 30 /* we only can allocate 1gb chunks */
-
-#define MAX_BLOCK_USER_MEMORY(mp_p) ((mp_p)->mp_page_size - \
- sizeof(mpool_block_t))
-#define FIRST_ADDR_IN_BLOCK(block_p) (void *)((char *)(block_p) + \
- sizeof(mpool_block_t))
-#define MEMORY_IN_BLOCK(block_p) ((char *)(block_p)->mb_bounds_p - \
- ((char *)(block_p) + \
- sizeof(mpool_block_t)))
-
-typedef struct {
- unsigned int mp_magic; /* magic number for struct */
- unsigned int mp_flags; /* flags for the struct */
- unsigned int mp_mmflags; /* flags for mmap */
- unsigned long mp_alloc_c; /* number of allocations */
- unsigned long mp_user_alloc; /* user bytes allocated */
- unsigned long mp_max_alloc; /* maximum user bytes allocated */
- unsigned int mp_page_c; /* number of pages allocated */
- unsigned int mp_max_pages; /* maximum number of pages to use */
- unsigned int mp_page_size; /* page-size of our system */
- int mp_fd; /* fd for /dev/zero if mmap-ing */
- off_t mp_top; /* top of our allocations in fd */
- mpool_log_func_t mp_log_func; /* log callback function */
- void *mp_addr; /* current address for mmaping */
- void *mp_min_p; /* min address in pool for checks */
- void *mp_bounds_p; /* max address in pool for checks */
- struct mpool_block_st *mp_first_p; /* first memory block we are using */
- struct mpool_block_st *mp_last_p; /* last memory block we are using */
- struct mpool_block_st *mp_free[MAX_BITS + 1]; /* free lists based on size */
- unsigned int mp_magic2; /* upper magic for overwrite sanity */
-} mpool_t;
-
-/* for debuggers to be able to interrogate the generic type in the .h file */
-typedef mpool_t mpool_ext_t;
-
-/*
- * Block header structure. This structure *MUST* be long-word
- * aligned.
- */
-typedef struct mpool_block_st {
- unsigned int mb_magic; /* magic number for block header */
- void *mb_bounds_p; /* block boundary location */
- struct mpool_block_st *mb_next_p; /* linked list next pointer */
- unsigned int mb_magic2; /* upper magic for overwrite sanity */
-} mpool_block_t;
-
-/*
- * Free list structure.
- */
-typedef struct {
- void *mf_next_p; /* pointer to the next free address */
- unsigned long mf_size; /* size of the free block */
-} mpool_free_t;
-
-#endif /* ! __MPOOL_LOC_H__ */
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * Generic table defines...
- *
- * Copyright 2000 by Gray Watson.
- *
- * This file is part of the table package.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose and without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies,
- * and that the name of Gray Watson not be used in advertising or
- * publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: table.h,v 1.11 2000/03/09 03:30:42 gray Exp $
- */
-
-#ifndef __TABLE_H__
-#define __TABLE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
- /*
- * To build a "key" in any of the below routines, pass in a pointer to
- * the key and its size [i.e. sizeof(int), etc]. With any of the
- * "key" or "data" arguments, if their size is < 0, it will do an
- * internal strlen of the item and add 1 for the \0.
- *
- * If you are using firstkey() and nextkey() functions, be careful if,
- * after starting your firstkey loop, you use delete or insert, it
- * will not crash but may produce interesting results. If you are
- * deleting from firstkey to NULL it will work fine.
- */
-
- /* return types for table functions */
-#define TABLE_ERROR_NONE 1 /* no error from function */
-#define TABLE_ERROR_PNT 2 /* bad table pointer */
-#define TABLE_ERROR_ARG_NULL 3 /* buffer args were null */
-#define TABLE_ERROR_SIZE 4 /* size of data was bad */
-#define TABLE_ERROR_OVERWRITE 5 /* key exists and we cant overwrite */
-#define TABLE_ERROR_NOT_FOUND 6 /* key does not exist */
-#define TABLE_ERROR_ALLOC 7 /* memory allocation error */
-#define TABLE_ERROR_LINEAR 8 /* no linear access started */
-#define TABLE_ERROR_OPEN 9 /* could not open file */
-#define TABLE_ERROR_SEEK 10 /* could not seek to pos in file */
-#define TABLE_ERROR_READ 11 /* could not read from file */
-#define TABLE_ERROR_WRITE 12 /* could not write to file */
-#define TABLE_ERROR_MMAP_NONE 13 /* no mmap support */
-#define TABLE_ERROR_MMAP 14 /* could not mmap file */
-#define TABLE_ERROR_MMAP_OP 15 /* can't perform operation on mmap */
-#define TABLE_ERROR_EMPTY 16 /* table is empty */
-#define TABLE_ERROR_NOT_EMPTY 17 /* table contains data */
-#define TABLE_ERROR_ALIGNMENT 18 /* invalid alignment value */
-#define TABLE_ERROR_COMPARE 19 /* problems with internal comparison */
-#define TABLE_ERROR_FREE 20 /* memory free error */
-
- /*
- * Table flags set with table_attr.
- */
-
- /*
- * Automatically adjust the number of table buckets on the fly.
- * Whenever the number of entries gets above some threshold, the
- * number of buckets is realloced to a new size and each entry is
- * re-hashed. Although this may take some time when it re-hashes, the
- * table will perform better over time.
- */
-#define TABLE_FLAG_AUTO_ADJUST (1<<0)
-
- /*
- * If the above auto-adjust flag is set, also adjust the number of
- * table buckets down as we delete entries.
- */
-#define TABLE_FLAG_ADJUST_DOWN (1<<1)
-
- /* structure to walk through the fields in a linear order */
- typedef struct {
- unsigned int tl_magic; /* magic structure to ensure correct init */
- unsigned int tl_bucket_c; /* where in the table buck array we are */
- unsigned int tl_entry_c; /* in the bucket, which entry we are on */
- } table_linear_t;
-
- /*
- * int (*table_compare_t)
- *
- * DESCRIPTION
- *
- * Comparison function which compares two key/data pairs for table
- * order.
- *
- * RETURNS:
- *
- * -1, 0, or 1 if key1 is <, ==, or > than key2.
- *
- * ARGUMENTS:
- *
- * key1 - Pointer to the first key entry.
- *
- * key1_size - Pointer to the size of the first key entry.
- *
- * data1 - Pointer to the first data entry.
- *
- * data1_size - Pointer to the size of the first data entry.
- *
- * key2 - Pointer to the second key entry.
- *
- * key2_size - Pointer to the size of the second key entry.
- *
- * data2 - Pointer to the second data entry.
- *
- * data2_size - Pointer to the size of the second data entry.
- */
- typedef int (*table_compare_t)(const void *key1, const int key1_size,
- const void *data1, const int data1_size,
- const void *key2, const int key2_size,
- const void *data2, const int data2_size);
-
- /*
- * int (*table_mem_alloc_t)
- *
- * DESCRIPTION
- *
- * Function to override the table's allocation function.
- *
- * RETURNS:
- *
- * Success - Newly allocated pointer.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * pool_p <-> Pointer to our memory pool. If no pool is set then this
- * will be NULL.
- *
- * size -> Number of bytes that needs to be allocated.
- */
- typedef void *(*table_mem_alloc_t)(void *pool_p, const unsigned long size);
-
- /*
- * int (*table_mem_resize_t)
- *
- * DESCRIPTION
- *
- * Function to override the table's memory resize function. The
- * difference between this and realloc is that this provides the
- * previous allocation size. You can specify NULL for this function
- * in which cause the library will allocate, copy, and free itself.
- *
- * RETURNS:
- *
- * Success - Newly allocated pointer.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * pool_p <-> Pointer to our memory pool. If no pool is set then this
- * will be NULL.
- *
- * old_addr -> Previously allocated address.
- *
- * old_size -> Size of the old address. Since the system is
- * lightweight, it does not store size information on the pointer.
- *
- * new_size -> New size of the allocation.
- */
- typedef void *(*table_mem_resize_t)(void *pool_p, void *old_addr,
- const unsigned long old_size,
- const unsigned long new_size);
-
- /*
- * int (*table_mem_free_t)
- *
- * DESCRIPTION
- *
- * Function to override the table's free function.
- *
- * RETURNS:
- *
- * Success - 1
- *
- * Failure - 0
- *
- * ARGUMENTS:
- *
- * pool_p <-> Pointer to our memory pool. If no pool is set then this
- * will be NULL.
- *
- * addr -> Address that we are freeing.
- *
- * min_size -> Minimum size of the address being freed or 0 if not
- * known. This can also be the exact size if known.
- */
- typedef int (*table_mem_free_t)(void *pool_p, void *addr,
- const unsigned long min_size);
-
-#ifdef TABLE_MAIN
-
-#include "table_loc.h"
-
-#else
-
- /* generic table type */
- typedef void table_t;
-
- /* generic table entry type */
- typedef void table_entry_t;
-
-#endif
-
- /*<<<<<<<<<< The below prototypes are auto-generated by fillproto */
-
- /*
- * table_t *table_alloc
- *
- * DESCRIPTION:
- *
- * Allocate a new table structure.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_free to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * bucket_n - Number of buckets for the hash table. Our current hash
- * value works best with base two numbers. Set to 0 to take the
- * library default of 1024.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_t *table_alloc(const unsigned int bucket_n, int *error_p);
-
- /*
- * table_t *table_alloc_in_pool
- *
- * DESCRIPTION:
- *
- * Allocate a new table structure in a memory pool or using
- * alternative allocation and free functions.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_free to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * bucket_n - Number of buckets for the hash table. Our current hash
- * value works best with base two numbers. Set to 0 to take the
- * library default of 1024.
- *
- * mem_pool <-> Memory pool to associate with the table. Can be NULL.
- *
- * alloc_func -> Allocate function we are overriding malloc() with.
- *
- * resize_func -> Resize function we are overriding the standard
- * memory resize/realloc with. This can be NULL in which cause the
- * library will allocate, copy, and free itself.
- *
- * free_func -> Free function we are overriding free() with.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_t *table_alloc_in_pool(const unsigned int bucket_n,
- void *mem_pool,
- table_mem_alloc_t alloc_func,
- table_mem_resize_t resize_func,
- table_mem_free_t free_func, int *error_p);
-
- /*
- * int table_attr
- *
- * DESCRIPTION:
- *
- * Set the attributes for the table. The available attributes are
- * specified at the top of table.h.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to a table structure which we will be altering.
- *
- * attr - Attribute(s) that we will be applying to the table.
- */
- extern
- int table_attr(table_t *table_p, const int attr);
-
- /*
- * int table_set_data_alignment
- *
- * DESCRIPTION:
- *
- * Set the alignment for the data in the table. This is used when you
- * want to store binary data types and refer to them directly out of
- * the table storage. For instance if you are storing integers as
- * data in the table and want to be able to retrieve the location of
- * the interger and then increment it as (*loc_p)++. Otherwise you
- * would have to memcpy it out to an integer, increment it, and memcpy
- * it back. If you are storing character data, no alignment is
- * necessary.
- *
- * For most data elements, sizeof(long) is recommended unless you use
- * smaller data types exclusively.
- *
- * WARNING: If necessary, you must set the data alignment before any
- * data gets put into the table. Otherwise a TABLE_ERROR_NOT_EMPTY
- * error will be returned.
- *
- * NOTE: there is no way to set the key data alignment although it
- * should automatically be long aligned.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to a table structure which we will be altering.
- *
- * alignment - Alignment requested for the data. Must be a power of
- * 2. Set to 0 for none.
- */
- extern
- int table_set_data_alignment(table_t *table_p, const int alignment);
-
- /*
- * int table_clear
- *
- * DESCRIPTION:
- *
- * Clear out and free all elements in a table structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer that we will be clearing.
- */
- extern
- int table_clear(table_t *table_p);
-
- /*
- * int table_free
- *
- * DESCRIPTION:
- *
- * Deallocates a table structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer that we will be freeing.
- */
- extern
- int table_free(table_t *table_p);
-
- /*
- * int table_insert_kd
- *
- * DESCRIPTION:
- *
- * Like table_insert except it passes back a pointer to the key and
- * the data buffers after they have been inserted into the table
- * structure.
- *
- * This routine adds a key/data pair both of which are made up of a
- * buffer of bytes and an associated size. Both the key and the data
- * will be copied into buffers allocated inside the table. If the key
- * exists already, the associated data will be replaced if the
- * overwrite flag is set, otherwise an error is returned.
- *
- * NOTE: be very careful changing the values since the table library
- * provides the pointers to its memory. The key can _never_ be
- * changed otherwise you will not find it again. The data can be
- * changed but its length can never be altered unless you delete and
- * re-insert it into the table.
- *
- * WARNING: The pointers to the key and data are not in any specific
- * alignment. Accessing the key and/or data as an short, integer, or
- * long pointer directly can cause problems.
- *
- * WARNING: Replacing a data cell (not inserting) will cause the table
- * linked list to be temporarily invalid. Care must be taken with
- * multiple threaded programs which are relying on the first/next
- * linked list to be always valid.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be inserting a
- * new key/data pair.
- *
- * key_buf - Buffer of bytes of the key that we are inserting. If you
- * are storing an (int) as the key (for example) then key_buf should
- * be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are storing an (int) as the key (for example) then key_size should
- * be sizeof(int).
- *
- * data_buf - Buffer of bytes of the data that we are inserting. If
- * it is NULL then the library will allocate space for the data in the
- * table without copying in any information. If data_buf is NULL and
- * data_size is 0 then the library will associate a NULL data pointer
- * with the key. If you are storing a (long) as the data (for
- * example) then data_buf should be a (long *).
- *
- * data_size - Size of the data_buf buffer. If set to < 0 then the
- * library will do a strlen of data_buf and add 1 for the '\0'. If
- * you are storing an (long) as the key (for example) then key_size
- * should be sizeof(long).
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the key storage that was allocated in the table. If you are
- * storing an (int) as the key (for example) then key_buf_p should be
- * (int **) i.e. the address of a (int *).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table. If you are
- * storing an (long) as the data (for example) then data_buf_p should
- * be (long **) i.e. the address of a (long *).
- *
- * overwrite - Flag which, if set to 1, will allow the overwriting of
- * the data in the table with the new data if the key already exists
- * in the table.
- */
- extern
- int table_insert_kd(table_t *table_p,
- const void *key_buf, const int key_size,
- const void *data_buf, const int data_size,
- void **key_buf_p, void **data_buf_p,
- const char overwrite_b);
-
- /*
- * int table_insert
- *
- * DESCRIPTION:
- *
- * Exactly the same as table_insert_kd except it does not pass back a
- * pointer to the key after they have been inserted into the table
- * structure. This is still here for backwards compatibility.
- *
- * See table_insert_kd for more information.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be inserting a
- * new key/data pair.
- *
- * key_buf - Buffer of bytes of the key that we are inserting. If you
- * are storing an (int) as the key (for example) then key_buf should
- * be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are storing an (int) as the key (for example) then key_size should
- * be sizeof(int).
- *
- * data_buf - Buffer of bytes of the data that we are inserting. If
- * it is NULL then the library will allocate space for the data in the
- * table without copying in any information. If data_buf is NULL and
- * data_size is 0 then the library will associate a NULL data pointer
- * with the key. If you are storing a (long) as the data (for
- * example) then data_buf should be a (long *).
- *
- * data_size - Size of the data_buf buffer. If set to < 0 then the
- * library will do a strlen of data_buf and add 1 for the '\0'. If
- * you are storing an (long) as the key (for example) then key_size
- * should be sizeof(long).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table. If you are
- * storing an (long) as the data (for example) then data_buf_p should
- * be (long **) i.e. the address of a (long *).
- *
- * overwrite - Flag which, if set to 1, will allow the overwriting of
- * the data in the table with the new data if the key already exists
- * in the table.
- */
- extern
- int table_insert(table_t *table_p,
- const void *key_buf, const int key_size,
- const void *data_buf, const int data_size,
- void **data_buf_p, const char overwrite_b);
-
- /*
- * int table_retrieve
- *
- * DESCRIPTION:
- *
- * This routine looks up a key made up of a buffer of bytes and an
- * associated size in the table. If found then it returns the
- * associated data information.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be searching
- * for the key.
- *
- * key_buf - Buffer of bytes of the key that we are searching for. If
- * you are looking for an (int) as the key (for example) then key_buf
- * should be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are looking for an (int) as the key (for example) then key_size
- * should be sizeof(int).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that is
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data stored in the table that is associated with
- * the key.
- */
- extern
- int table_retrieve(table_t *table_p,
- const void *key_buf, const int key_size,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_delete
- *
- * DESCRIPTION:
- *
- * This routine looks up a key made up of a buffer of bytes and an
- * associated size in the table. If found then it will be removed
- * from the table. The associated data can be passed back to the user
- * if requested.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * NOTE: this could be an allocation error if the library is to return
- * the data to the user.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we will be deleteing
- * the key.
- *
- * key_buf - Buffer of bytes of the key that we are searching for to
- * delete. If you are deleting an (int) key (for example) then
- * key_buf should be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are deleting an (int) key (for example) then key_size should be
- * sizeof(int).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that was
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *). If a pointer is passed in, the caller is responsible for
- * freeing it after use. If data_buf_p is NULL then the library will
- * free up the data allocation itself.
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that was stored in the table and that was
- * associated with the key.
- */
- extern
- int table_delete(table_t *table_p,
- const void *key_buf, const int key_size,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_delete_first
- *
- * DESCRIPTION:
- *
- * This is like the table_delete routines except it deletes the first
- * key/data pair in the table instead of an entry corresponding to a
- * particular key. The associated key and data information can be
- * passed back to the user if requested. This routines is handy to
- * clear out a table.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * NOTE: this could be an allocation error if the library is to return
- * the data to the user.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we will be deleteing
- * the first key.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that was allocated in the table.
- * If an (int) was stored as the first key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *). If a
- * pointer is passed in, the caller is responsible for freeing it
- * after use. If key_buf_p is NULL then the library will free up the
- * key allocation itself.
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that was stored in the table and that was
- * associated with the key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that was
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *). If a pointer is passed in, the caller is responsible for
- * freeing it after use. If data_buf_p is NULL then the library will
- * free up the data allocation itself.
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that was stored in the table and that was
- * associated with the key.
- */
- extern
- int table_delete_first(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_info
- *
- * DESCRIPTION:
- *
- * Get some information about a table_p structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting
- * information.
- *
- * num_buckets_p - Pointer to an integer which, if not NULL, will
- * contain the number of buckets in the table.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries stored in the table.
- */
- extern
- int table_info(table_t *table_p, int *num_buckets_p, int *num_entries_p);
-
- /*
- * int table_adjust
- *
- * DESCRIPTION:
- *
- * Set the number of buckets in a table to a certain value.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer of which we are adjusting.
- *
- * bucket_n - Number buckets to adjust the table to. Set to 0 to
- * adjust the table to its number of entries.
- */
- extern
- int table_adjust(table_t *table_p, const int bucket_n);
-
- /*
- * int table_type_size
- *
- * DESCRIPTION:
- *
- * Return the size of the internal table type.
- *
- * RETURNS:
- *
- * The size of the table_t type.
- *
- * ARGUMENTS:
- *
- * None.
- */
- extern
- int table_type_size(void);
-
- /*
- * int table_first
- *
- * DESCRIPTION:
- *
- * Find first element in a table and pass back information about the
- * key/data pair. If any of the key/data pointers are NULL then they
- * are ignored.
- *
- * NOTE: This function is not reentrant. More than one thread cannot
- * be doing a first and next on the same table at the same time. Use
- * the table_first_r version below for this.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * first element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that is allocated in the table. If
- * an (int) is stored as the first key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the first key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the first key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the first key.
- */
- extern
- int table_first(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_next
- *
- * DESCRIPTION:
- *
- * Find the next element in a table and pass back information about
- * the key/data pair. If any of the key/data pointers are NULL then
- * they are ignored.
- *
- * NOTE: This function is not reentrant. More than one thread cannot
- * be doing a first and next on the same table at the same time. Use
- * the table_next_r version below for this.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * next element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the next key that is allocated in the table. If
- * an (int) is stored as the next key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the next key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the next key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the next key.
- */
- extern
- int table_next(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_this
- *
- * DESCRIPTION:
- *
- * Find the current element in a table and pass back information about
- * the key/data pair. If any of the key/data pointers are NULL then
- * they are ignored.
- *
- * NOTE: This function is not reentrant. Use the table_current_r
- * version below.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * current element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the current key that is allocated in the table.
- * If an (int) is stored as the current key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the current key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the current key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the current key.
- */
- extern
- int table_this(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_first_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_first routine above. Find first
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * first element.
- *
- * linear_p - Pointer to a table linear structure which is initialized
- * here. The same pointer should then be passed to table_next_r
- * below.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that is allocated in the table. If
- * an (int) is stored as the first key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the first key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the first key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the first key.
- */
- extern
- int table_first_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_next_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_next routine above. Find next
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * next element.
- *
- * linear_p - Pointer to a table linear structure which is incremented
- * here. The same pointer must have been passed to table_first_r
- * first so that it can be initialized.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the next key that is allocated in the table. If
- * an (int) is stored as the next key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL will be set
- * to the size of the key that is stored in the table and that is
- * associated with the next key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the next key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the next key.
- */
- extern
- int table_next_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * int table_this_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_this routine above. Find current
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * current element.
- *
- * linear_p - Pointer to a table linear structure which is accessed
- * here. The same pointer must have been passed to table_first_r
- * first so that it can be initialized.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the current key that is allocated in the table.
- * If an (int) is stored as the current key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the current key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the current key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the current key.
- */
- extern
- int table_this_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * table_t *table_mmap
- *
- * DESCRIPTION:
- *
- * Mmap a table from a file that had been written to disk earlier via
- * table_write.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_munmap to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * path - Table file to mmap in.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_t *table_mmap(const char *path, int *error_p);
-
- /*
- * int table_munmap
- *
- * DESCRIPTION:
- *
- * Unmmap a table that was previously mmapped using table_mmap.
- *
- * RETURNS:
- *
- * Returns table error codes.
- *
- * ARGUMENTS:
- *
- * table_p - Mmaped table pointer to unmap.
- */
- extern
- int table_munmap(table_t *table_p);
-
- /*
- * int table_read
- *
- * DESCRIPTION:
- *
- * Read in a table from a file that had been written to disk earlier
- * via table_write.
- *
- * RETURNS:
- *
- * Success - Pointer to the new table structure which must be passed
- * to table_free to be deallocated.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * path - Table file to read in.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_t *table_read(const char *path, int *error_p);
-
- /*
- * int table_write
- *
- * DESCRIPTION:
- *
- * Write a table from memory to file.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are writing to the file.
- *
- * path - Table file to write out to.
- *
- * mode - Mode of the file. This argument is passed on to open when
- * the file is created.
- */
- extern
- int table_write(const table_t *table_p, const char *path, const int mode);
-
- /*
- * table_entry_t *table_order
- *
- * DESCRIPTION:
- *
- * Order a table by building an array of table entry pointers and then
- * sorting this array using the qsort function. To retrieve the
- * sorted entries, you can then use the table_entry routine to access
- * each entry in order.
- *
- * NOTE: This routine is thread safe and makes use of an internal
- * status qsort function.
- *
- * RETURNS:
- *
- * Success - An allocated list of table-linear structures which must
- * be freed by table_order_free later.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are ordering.
- *
- * compare - Comparison function defined by the user. Its definition
- * is at the top of the table.h file. If this is NULL then it will
- * order the table my memcmp-ing the keys.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries in the returned entry pointer array.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_entry_t **table_order(table_t *table_p, table_compare_t compare,
- int *num_entries_p, int *error_p);
-
- /*
- * int table_order_free
- *
- * DESCRIPTION:
- *
- * Free the pointer returned by the table_order or table_order_pos
- * routines.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table.
- *
- * table_entries - Allocated list of entry pointers returned by
- * table_order.
- *
- * entry_n - Number of entries in the array as passed back by
- * table_order or table_order_pos in num_entries_p.
- */
- extern
- int table_order_free(table_t *table_p, table_entry_t **table_entries,
- const int entry_n);
-
- /*
- * int table_entry
- *
- * DESCRIPTION:
- *
- * Get information about an element. The element is one from the
- * array returned by the table_order function. If any of the key/data
- * pointers are NULL then they are ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * element.
- *
- * entry_p - Pointer to a table entry from the array returned by the
- * table_order function.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of this entry that is allocated in the table. If an
- * (int) is stored as this entry (for example) then key_buf_p should
- * be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage of this entry that is allocated in the table.
- * If a (long) is stored as this entry data (for example) then
- * data_buf_p should be (long **) i.e. the address of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table.
- */
- extern
- int table_entry(table_t *table_p, table_entry_t *entry_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * table_linear_t *table_order_pos
- *
- * DESCRIPTION:
- *
- * Order a table by building an array of table linear structures and
- * then sorting this array using the qsort function. To retrieve the
- * sorted entries, you can then use the table_entry_pos routine to
- * access each entry in order.
- *
- * NOTE: This routine is thread safe and makes use of an internal
- * status qsort function.
- *
- * RETURNS:
- *
- * Success - An allocated list of table-linear structures which must
- * be freed by table_order_pos_free later.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are ordering.
- *
- * compare - Comparison function defined by the user. Its definition
- * is at the top of the table.h file. If this is NULL then it will
- * order the table my memcmp-ing the keys.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries in the returned entry pointer array.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
- extern
- table_linear_t *table_order_pos(table_t *table_p, table_compare_t compare,
- int *num_entries_p, int *error_p);
-
- /*
- * int table_order_pos_free
- *
- * DESCRIPTION:
- *
- * Free the pointer returned by the table_order or table_order_pos
- * routines.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table.
- *
- * table_entries - Allocated list of entry pointers returned by
- * table_order_pos.
- *
- * entry_n - Number of entries in the array as passed back by
- * table_order or table_order_pos in num_entries_p.
- */
- extern
- int table_order_pos_free(table_t *table_p, table_linear_t *table_entries,
- const int entry_n);
-
- /*
- * int table_entry_pos
- *
- * DESCRIPTION:
- *
- * Get information about an element. The element is one from the
- * array returned by the table_order function. If any of the key/data
- * pointers are NULL then they are ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * element.
- *
- * linear_p - Pointer to a table linear structure from the array
- * returned by the table_order function.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of this entry that is allocated in the table. If an
- * (int) is stored as this entry (for example) then key_buf_p should
- * be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage of this entry that is allocated in the table.
- * If a (long) is stored as this entry data (for example) then
- * data_buf_p should be (long **) i.e. the address of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table.
- */
- extern
- int table_entry_pos(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p);
-
- /*
- * const char *table_strerror
- *
- * DESCRIPTION:
- *
- * Return the corresponding string for the error number.
- *
- * RETURNS:
- *
- * Success - String equivalient of the error.
- *
- * Failure - String "invalid error code"
- *
- * ARGUMENTS:
- *
- * error - Error number that we are converting.
- */
- extern
- const char *table_strerror(const int error);
-
- /*<<<<<<<<<< This is end of the auto-generated output from fillproto. */
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* ! __TABLE_H__ */
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * local defines for the table module
- *
- * Copyright 2000 by Gray Watson.
- *
- * This file is part of the table package.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose and without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies,
- * and that the name of Gray Watson not be used in advertising or
- * publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: table_loc.h,v 1.11 2000/03/09 03:30:42 gray Exp $
- */
-
-#ifndef __TABLE_LOC_H__
-#define __TABLE_LOC_H__
-
-#ifndef unix
-#define NO_MMAP
-#endif
-
-#ifndef BITSPERBYTE
-#define BITSPERBYTE 8
-#endif
-#ifndef BITS
-#define BITS(type) (BITSPERBYTE * (int)sizeof(type))
-#endif
-
-#define TABLE_MAGIC 0xBADF00D /* very magic magicness */
-#define LINEAR_MAGIC 0xAD00D00 /* magic value for linear struct */
-#define DEFAULT_SIZE 1024 /* default table size */
-#define MAX_ALIGNMENT 128 /* max alignment value */
-
-/*
- * Maximum number of splits. This should mean that these routines can
- * handle at least 2^128 different values (that's _quite_ a few). And
- * then you can always increase the value.
- */
-#define MAX_QSORT_SPLITS 128
-
-/*
- * Maximum number of entries that must be in list for it to be
- * partitioned. If there are fewer elements then just do our
- * insertion sort.
- */
-#define MAX_QSORT_MANY 8
-
-/*
- * Macros.
- */
-
-/* returns 1 when we should grow or shrink the table */
-#define SHOULD_TABLE_GROW(tab) ((tab)->ta_entry_n > (tab)->ta_bucket_n * 2)
-#define SHOULD_TABLE_SHRINK(tab) ((tab)->ta_entry_n < (tab)->ta_bucket_n / 2)
-
-/*
- * void HASH_MIX
- *
- * DESCRIPTION:
- *
- * Mix 3 32-bit values reversibly. For every delta with one or two
- * bits set, and the deltas of all three high bits or all three low
- * bits, whether the original value of a,b,c is almost all zero or is
- * uniformly distributed.
- *
- * If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c
- * have at least 1/4 probability of changing. If mix() is run
- * forward, every bit of c will change between 1/3 and 2/3 of the
- * time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
- *
- * HASH_MIX() takes 36 machine instructions, but only 18 cycles on a
- * superscalar machine (like a Pentium or a Sparc). No faster mixer
- * seems to work, that's the result of my brute-force search. There
- * were about 2^68 hashes to choose from. I only tested about a
- * billion of those.
- */
-#define HASH_MIX(a, b, c) \
- do { \
- a -= b; a -= c; a ^= (c >> 13); \
- b -= c; b -= a; b ^= (a << 8); \
- c -= a; c -= b; c ^= (b >> 13); \
- a -= b; a -= c; a ^= (c >> 12); \
- b -= c; b -= a; b ^= (a << 16); \
- c -= a; c -= b; c ^= (b >> 5); \
- a -= b; a -= c; a ^= (c >> 3); \
- b -= c; b -= a; b ^= (a << 10); \
- c -= a; c -= b; c ^= (b >> 15); \
- } while(0)
-
-#define SET_POINTER(pnt, val) \
- do { \
- if ((pnt) != NULL) { \
- (*(pnt)) = (val); \
- } \
- } while(0)
-
-/*
- * The following macros take care of the mmap case. When we are
- * mmaping a table from a disk file, all of the pointers in the table
- * structures are replaced with offsets into the file. The following
- * macro, for each pointer, adds the starting address of the mmaped
- * section onto each pointer/offset turning it back into a legitimate
- * pointer.
- */
-#ifdef NO_MMAP
-
-#define TABLE_POINTER(table, type, pnt) (pnt)
-
-#else
-
-#define TABLE_POINTER(tab_p, type, pnt) \
- ((tab_p)->ta_mmap == NULL || (pnt) == NULL ? (pnt) : \
- (type)((char *)((tab_p)->ta_mmap) + (long)(pnt)))
-
-#endif
-
-/*
- * Macros to get at the key and the data pointers
- */
-#define ENTRY_KEY_BUF(entry_p) ((entry_p)->te_key_buf)
-#define ENTRY_DATA_BUF(tab_p, entry_p) \
- (ENTRY_KEY_BUF(entry_p) + (entry_p)->te_key_size)
-
-/*
- * Table structures...
- */
-
-/*
- * HACK: this should be equiv as the table_entry_t without the key_buf
- * char. We use this with the ENTRY_SIZE() macro above which solves
- * the problem with the lack of the [0] GNU hack. We use the
- * table_entry_t structure to better map the memory and make things
- * faster.
- */
-typedef struct table_shell_st {
- unsigned int te_key_size; /* size of data */
- unsigned int te_data_size; /* size of data */
- struct table_shell_st *te_next_p; /* pointer to next in the list */
- /* NOTE: this does not have the te_key_buf field here */
-} table_shell_t;
-
-/*
- * Elements in the bucket linked-lists. The key[1] is the start of
- * the key with the rest of the key and all of the data information
- * packed in memory directly after the end of this structure.
- *
- * NOTE: if this structure is changed, the table_shell_t must be
- * changed to match.
- */
-typedef struct table_entry_st {
- unsigned int te_key_size; /* size of data */
- unsigned int te_data_size; /* size of data */
- struct table_entry_st *te_next_p; /* pointer to next in the list */
- unsigned char te_key_buf[1]; /* 1st byte of key buf */
-} table_entry_t;
-
-/* external structure for debuggers be able to see void */
-typedef table_entry_t table_entry_ext_t;
-
-/* main table structure */
-typedef struct table_st {
- unsigned int ta_magic; /* magic number */
- unsigned int ta_flags; /* table's flags defined in table.h */
- unsigned int ta_bucket_n; /* num of buckets, should be 2^X */
- unsigned int ta_entry_n; /* num of entries in all buckets */
- unsigned int ta_data_align; /* data alignment value */
- table_entry_t **ta_buckets; /* array of linked lists */
- table_linear_t ta_linear; /* linear tracking */
- struct table_st *ta_mmap; /* mmaped table */
- unsigned long ta_file_size; /* size of on-disk space */
-
- void *ta_mem_pool; /* pointer to some memory pool */
- table_mem_alloc_t ta_alloc_func; /* memory allocation function */
- table_mem_resize_t ta_resize_func; /* memory resize function */
- table_mem_free_t ta_free_func; /* memory free function */
-} table_t;
-
-/* external table structure for debuggers */
-typedef table_t table_ext_t;
-
-/* local comparison functions */
-typedef int (*compare_t)(const void *element1_p, const void *element2_p,
- table_compare_t user_compare,
- const table_t *table_p, int *err_bp);
-
-/*
- * to map error to string
- */
-typedef struct {
- int es_error; /* error number */
- char *es_string; /* assocaited string */
-} error_str_t;
-
-static error_str_t errors[] = {
- { TABLE_ERROR_NONE, "no error" },
- { TABLE_ERROR_PNT, "invalid table pointer" },
- { TABLE_ERROR_ARG_NULL, "buffer argument is null" },
- { TABLE_ERROR_SIZE, "incorrect size argument" },
- { TABLE_ERROR_OVERWRITE, "key exists and no overwrite" },
- { TABLE_ERROR_NOT_FOUND, "key does not exist" },
- { TABLE_ERROR_ALLOC, "error allocating memory" },
- { TABLE_ERROR_LINEAR, "linear access not in progress" },
- { TABLE_ERROR_OPEN, "could not open file" },
- { TABLE_ERROR_SEEK, "could not seek to position in file" },
- { TABLE_ERROR_READ, "could not read from file" },
- { TABLE_ERROR_WRITE, "could not write to file" },
- { TABLE_ERROR_MMAP_NONE, "no mmap support compiled in library" },
- { TABLE_ERROR_MMAP, "could not mmap the file" },
- { TABLE_ERROR_MMAP_OP, "operation not valid on mmap files" },
- { TABLE_ERROR_EMPTY, "table is empty" },
- { TABLE_ERROR_NOT_EMPTY, "table contains data" },
- { TABLE_ERROR_ALIGNMENT, "invalid alignment value" },
- { TABLE_ERROR_COMPARE, "problems with internal comparison" },
- { TABLE_ERROR_FREE, "memory free error" },
- { 0 }
-};
-
-#define INVALID_ERROR "invalid error code"
-
-#endif /* ! __TABLE_LOC_H__ */
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
-
+++ /dev/null
-/*
- * Cross Platform Thread/Mutex abstraction
- * Copyright(C) 2007 Michael Jerris
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so.
- *
- * This work is provided under this license on an "as is" basis, without warranty of any kind,
- * either expressed or implied, including, without limitation, warranties that the covered code
- * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
- * risk as to the quality and performance of the covered code is with you. Should any covered
- * code prove defective in any respect, you (not the initial developer or any other contributor)
- * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
- * constitutes an essential part of this license. No use of any covered code is authorized hereunder
- * except under this disclaimer.
- *
- */
-
-#ifdef WIN32
-/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */
-#define _WIN32_WINNT 0x0400
-#endif
-
-#include "ks.h"
-#include "ks_threadmutex.h"
-
-#ifdef WIN32
-#include <process.h>
-
-#define KS_THREAD_CALLING_CONVENTION __stdcall
-
-struct ks_mutex {
- CRITICAL_SECTION mutex;
-};
-
-#else
-
-#include <pthread.h>
-
-#define KS_THREAD_CALLING_CONVENTION
-
-struct ks_mutex {
- pthread_mutex_t mutex;
-};
-
-#endif
-
-struct ks_thread {
-#ifdef WIN32
- void *handle;
-#else
- pthread_t handle;
-#endif
- void *private_data;
- ks_thread_function_t function;
- size_t stack_size;
-#ifndef WIN32
- pthread_attr_t attribute;
-#endif
-};
-
-size_t thread_default_stacksize = 240 * 1024;
-
-void ks_thread_override_default_stacksize(size_t size)
-{
- thread_default_stacksize = size;
-}
-
-static void * KS_THREAD_CALLING_CONVENTION thread_launch(void *args)
-{
- void *exit_val;
- ks_thread_t *thread = (ks_thread_t *)args;
- exit_val = thread->function(thread, thread->private_data);
-#ifndef WIN32
- pthread_attr_destroy(&thread->attribute);
-#endif
- free(thread);
-
- return exit_val;
-}
-
-KS_DECLARE(ks_status_t) ks_thread_create_detached(ks_thread_function_t func, void *data)
-{
- return ks_thread_create_detached_ex(func, data, thread_default_stacksize);
-}
-
-ks_status_t ks_thread_create_detached_ex(ks_thread_function_t func, void *data, size_t stack_size)
-{
- ks_thread_t *thread = NULL;
- ks_status_t status = KS_FAIL;
-
- if (!func || !(thread = (ks_thread_t *)malloc(sizeof(ks_thread_t)))) {
- goto done;
- }
-
- thread->private_data = data;
- thread->function = func;
- thread->stack_size = stack_size;
-
-#if defined(WIN32)
- thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
- if (!thread->handle) {
- goto fail;
- }
- CloseHandle(thread->handle);
-
- status = KS_SUCCESS;
- goto done;
-#else
-
- if (pthread_attr_init(&thread->attribute) != 0) goto fail;
-
- if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
-
- if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
-
- if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
-
- status = KS_SUCCESS;
- goto done;
-
- failpthread:
-
- pthread_attr_destroy(&thread->attribute);
-#endif
-
- fail:
- if (thread) {
- free(thread);
- }
- done:
- return status;
-}
-
-
-KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex)
-{
- ks_status_t status = KS_FAIL;
-#ifndef WIN32
- pthread_mutexattr_t attr;
-#endif
- ks_mutex_t *check = NULL;
-
- check = (ks_mutex_t *)malloc(sizeof(**mutex));
- if (!check)
- goto done;
-#ifdef WIN32
- InitializeCriticalSection(&check->mutex);
-#else
- if (pthread_mutexattr_init(&attr))
- goto done;
-
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
- goto fail;
-
- if (pthread_mutex_init(&check->mutex, &attr))
- goto fail;
-
- goto success;
-
- fail:
- pthread_mutexattr_destroy(&attr);
- goto done;
-
- success:
-#endif
- *mutex = check;
- status = KS_SUCCESS;
-
- done:
- return status;
-}
-
-KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutex)
-{
- ks_mutex_t *mp = *mutex;
- *mutex = NULL;
- if (!mp) {
- return KS_FAIL;
- }
-#ifdef WIN32
- DeleteCriticalSection(&mp->mutex);
-#else
- if (pthread_mutex_destroy(&mp->mutex))
- return KS_FAIL;
-#endif
- free(mp);
- return KS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex)
-{
-#ifdef WIN32
- EnterCriticalSection(&mutex->mutex);
-#else
- if (pthread_mutex_lock(&mutex->mutex))
- return KS_FAIL;
-#endif
- return KS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex)
-{
-#ifdef WIN32
- if (!TryEnterCriticalSection(&mutex->mutex))
- return KS_FAIL;
-#else
- if (pthread_mutex_trylock(&mutex->mutex))
- return KS_FAIL;
-#endif
- return KS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex)
-{
-#ifdef WIN32
- LeaveCriticalSection(&mutex->mutex);
-#else
- if (pthread_mutex_unlock(&mutex->mutex))
- return KS_FAIL;
-#endif
- return KS_SUCCESS;
-}
-
-
-
-
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * Memory pool routines.
- *
- * Copyright 1996 by Gray Watson.
- *
- * This file is part of the mpool package.
- *
- * Permission to use, copy, modify, and distribute this software for
- * any purpose and without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies, and that the name of Gray Watson not be used in advertising
- * or publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $
- */
-
-/*
- * Memory-pool allocation routines. I got sick of the GNU mmalloc
- * library which was close to what we needed but did not exactly do
- * what I wanted.
- *
- * The following uses mmap from /dev/zero. It allows a number of
- * allocations to be made inside of a memory pool then with a clear or
- * close the pool can be reset without any memory fragmentation and
- * growth problems.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _MSC_VER
-#include <io.h>
-#ifndef open
-#define open _open
-#endif
-#ifndef close
-#define close _close
-#endif
-#else
-#include <unistd.h>
-#endif
-#include <sys/mman.h>
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-#define MPOOL_MAIN
-
-#include "mpool.h"
-#include "mpool_loc.h"
-
-#ifdef __GNUC__
-#ident "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $"
-#else
-static char *rcs_id = "$Id: mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $";
-#endif
-
-/* version */
-static char *version = "mpool library version 2.1.0";
-
-/* local variables */
-static int enabled_b = 0; /* lib initialized? */
-static unsigned int min_bit_free_next = 0; /* min size of next pnt */
-static unsigned int min_bit_free_size = 0; /* min size of next + size */
-static unsigned long bit_array[MAX_BITS + 1]; /* size -> bit */
-
-#ifdef _MSC_VER
-#include <Windows.h>
-long getpagesize(void) {
- static long g_pagesize = 0;
- if (!g_pagesize) {
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- g_pagesize = system_info.dwPageSize;
- }
- return g_pagesize;
-}
-#endif
-/****************************** local utilities ******************************/
-
-/*
- * static void startup
- *
- * DESCRIPTION:
- *
- * Perform any library level initialization.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * None.
- */
-static void startup(void)
-{
- int bit_c;
- unsigned long size = 1;
-
- if (enabled_b) {
- return;
- }
-
- /* allocate our free bit array list */
- for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
- bit_array[bit_c] = size;
-
- /*
- * Note our minimum number of bits that can store a pointer. This
- * is smallest address that we can have a linked list for.
- */
- if (min_bit_free_next == 0 && size >= sizeof(void *)) {
- min_bit_free_next = bit_c;
- }
- /*
- * Note our minimum number of bits that can store a pointer and
- * the size of the block.
- */
- if (min_bit_free_size == 0 && size >= sizeof(mpool_free_t)) {
- min_bit_free_size = bit_c;
- }
-
- size *= 2;
- }
-
- enabled_b = 1;
-}
-
-/*
- * static int size_to_bits
- *
- * DESCRIPTION:
- *
- * Calculate the number of bits in a size.
- *
- * RETURNS:
- *
- * Number of bits.
- *
- * ARGUMENTS:
- *
- * size -> Size of memory of which to calculate the number of bits.
- */
-static int size_to_bits(const unsigned long size)
-{
- int bit_c = 0;
-
- for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
- if (size <= bit_array[bit_c]) {
- break;
- }
- }
-
- return bit_c;
-}
-
-/*
- * static int size_to_free_bits
- *
- * DESCRIPTION:
- *
- * Calculate the number of bits in a size going on the free list.
- *
- * RETURNS:
- *
- * Number of bits.
- *
- * ARGUMENTS:
- *
- * size -> Size of memory of which to calculate the number of bits.
- */
-static int size_to_free_bits(const unsigned long size)
-{
- int bit_c = 0;
-
- if (size == 0) {
- return 0;
- }
-
- for (bit_c = 0; bit_c <= MAX_BITS; bit_c++) {
- if (size < bit_array[bit_c]) {
- break;
- }
- }
-
- return bit_c - 1;
-}
-
-/*
- * static int bits_to_size
- *
- * DESCRIPTION:
- *
- * Calculate the size represented by a number of bits.
- *
- * RETURNS:
- *
- * Number of bits.
- *
- * ARGUMENTS:
- *
- * bit_n -> Number of bits
- */
-static unsigned long bits_to_size(const int bit_n)
-{
- if (bit_n > MAX_BITS) {
- return bit_array[MAX_BITS];
- }
- else {
- return bit_array[bit_n];
- }
-}
-
-/*
- * static void *alloc_pages
- *
- * DESCRIPTION:
- *
- * Allocate space for a number of memory pages in the memory pool.
- *
- * RETURNS:
- *
- * Success - New pages of memory
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to our memory pool.
- *
- * page_n -> Number of pages to alloc.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-static void *alloc_pages(mpool_t *mp_p, const unsigned int page_n,
- int *error_p)
-{
- void *mem;
- unsigned long size;
- int state;
-
- /* are we over our max-pages? */
- if (mp_p->mp_max_pages > 0 && mp_p->mp_page_c >= mp_p->mp_max_pages) {
- SET_POINTER(error_p, MPOOL_ERROR_NO_PAGES);
- return NULL;
- }
-
- size = SIZE_OF_PAGES(mp_p, page_n);
-
-#ifdef DEBUG
- (void)printf("allocating %u pages or %lu bytes\n", page_n, size);
-#endif
-
-
- state = MAP_PRIVATE;
-
-#if defined(MAP_FILE)
- state |= MAP_FILE;
-#endif
-
-#if defined(MAP_VARIABLE)
- state |= MAP_VARIABLE;
-#endif
-
- /* mmap from /dev/zero */
- mem = mmap(mp_p->mp_addr, size, PROT_READ | PROT_WRITE, state | mp_p->mp_mmflags,
- mp_p->mp_fd, mp_p->mp_top);
- if (mem == (void *)MAP_FAILED) {
- if (errno == ENOMEM) {
- SET_POINTER(error_p, MPOOL_ERROR_NO_MEM);
- } else {
- SET_POINTER(error_p, MPOOL_ERROR_MMAP);
- }
- return NULL;
- }
-
- mp_p->mp_top += size;
-
- if (mp_p->mp_addr != NULL) {
- mp_p->mp_addr = (char *)mp_p->mp_addr + size;
- }
-
- mp_p->mp_page_c += page_n;
-
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return mem;
-}
-
-/*
- * static int free_pages
- *
- * DESCRIPTION:
- *
- * Free previously allocated pages of memory.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * pages <-> Pointer to memory pages that we are freeing.
- *
- * size -> Size of the block that we are freeing.
- *
- * sbrk_b -> Set to one if the pages were allocated with sbrk else mmap.
- */
-static int free_pages(void *pages, const unsigned long size)
-
-{
- (void)munmap(pages, size);
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * static int check_magic
- *
- * DESCRIPTION:
- *
- * Check for the existance of the magic ID in a memory pointer.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * addr -> Address inside of the block that we are tryign to locate.
- *
- * size -> Size of the block.
- */
-static int check_magic(const void *addr, const unsigned long size)
-{
- const unsigned char *mem_p;
-
- /* set our starting point */
- mem_p = (unsigned char *)addr + size;
-
- if (*mem_p == FENCE_MAGIC0 && *(mem_p + 1) == FENCE_MAGIC1) {
- return MPOOL_ERROR_NONE;
- }
- else {
- return MPOOL_ERROR_PNT_OVER;
- }
-}
-
-/*
- * static void write_magic
- *
- * DESCRIPTION:
- *
- * Write the magic ID to the address.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * addr -> Address where to write the magic.
- */
-static void write_magic(const void *addr)
-{
- *(unsigned char *)addr = FENCE_MAGIC0;
- *((unsigned char *)addr + 1) = FENCE_MAGIC1;
-}
-
-/*
- * static void free_pointer
- *
- * DESCRIPTION:
- *
- * Moved a pointer into our free lists.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * addr <-> Address where to write the magic. We may write a next
- * pointer to it.
- *
- * size -> Size of the address space.
- */
-static int free_pointer(mpool_t *mp_p, void *addr,
- const unsigned long size)
-{
- unsigned int bit_n;
- unsigned long real_size;
- mpool_free_t free_pnt;
-
-#ifdef DEBUG
- (void)printf("freeing a block at %lx of %lu bytes\n", (long)addr, size);
-#endif
-
- if (size == 0) {
- return MPOOL_ERROR_NONE;
- }
-
- /*
- * if the user size is larger then can fit in an entire block then
- * we change the size
- */
- if (size > MAX_BLOCK_USER_MEMORY(mp_p)) {
- real_size = SIZE_OF_PAGES(mp_p, PAGES_IN_SIZE(mp_p, size)) -
- sizeof(mpool_block_t);
- }
- else {
- real_size = size;
- }
-
- /*
- * We use a specific free bits calculation here because if we are
- * freeing 10 bytes then we will be putting it into the 8-byte free
- * list and not the 16 byte list. size_to_bits(10) will return 4
- * instead of 3.
- */
- bit_n = size_to_free_bits(real_size);
-
- /*
- * Minimal error checking. We could go all the way through the
- * list however this might be prohibitive.
- */
- if (mp_p->mp_free[bit_n] == addr) {
- return MPOOL_ERROR_IS_FREE;
- }
-
- /* add the freed pointer to the free list */
- if (bit_n < min_bit_free_next) {
- /*
- * Yes we know this will lose 99% of the allocations but what else
- * can we do? No space for a next pointer.
- */
- if (mp_p->mp_free[bit_n] == NULL) {
- mp_p->mp_free[bit_n] = addr;
- }
- }
- else if (bit_n < min_bit_free_size) {
- /* we copy, not assign, to maintain the free list */
- memcpy(addr, mp_p->mp_free + bit_n, sizeof(void *));
- mp_p->mp_free[bit_n] = addr;
- }
- else {
-
- /* setup our free list structure */
- free_pnt.mf_next_p = mp_p->mp_free[bit_n];
- free_pnt.mf_size = real_size;
-
- /* we copy the structure in since we don't know about alignment */
- memcpy(addr, &free_pnt, sizeof(free_pnt));
- mp_p->mp_free[bit_n] = addr;
- }
-
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * static int split_block
- *
- * DESCRIPTION:
- *
- * When freeing space in a multi-block chunk we have to create new
- * blocks out of the upper areas being freed.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * free_addr -> Address that we are freeing.
- *
- * size -> Size of the space that we are taking from address.
- */
-static int split_block(mpool_t *mp_p, void *free_addr,
- const unsigned long size)
-{
- mpool_block_t *block_p, *new_block_p;
- int ret, page_n;
- void *end_p;
-
- /*
- * 1st we find the block pointer from our free addr. At this point
- * the pointer must be the 1st one in the block if it is spans
- * multiple blocks.
- */
- block_p = (mpool_block_t *)((char *)free_addr - sizeof(mpool_block_t));
- if (block_p->mb_magic != BLOCK_MAGIC
- || block_p->mb_magic2 != BLOCK_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- page_n = PAGES_IN_SIZE(mp_p, size);
-
- /* we are creating a new block structure for the 2nd ... */
- new_block_p = (mpool_block_t *)((char *)block_p +
- SIZE_OF_PAGES(mp_p, page_n));
- new_block_p->mb_magic = BLOCK_MAGIC;
- /* New bounds is 1st block bounds. The 1st block's is reset below. */
- new_block_p->mb_bounds_p = block_p->mb_bounds_p;
- /* Continue the linked list. The 1st block will point to us below. */
- new_block_p->mb_next_p = block_p->mb_next_p;
- new_block_p->mb_magic2 = BLOCK_MAGIC;
-
- /* bounds for the 1st block are reset to the 1st page only */
- block_p->mb_bounds_p = (char *)new_block_p;
- /* the next block pointer for the 1st block is now the new one */
- block_p->mb_next_p = new_block_p;
-
- /* only free the space in the 1st block if it is only 1 block in size */
- if (page_n == 1) {
- /* now free the rest of the 1st block block */
- end_p = (char *)free_addr + size;
- ret = free_pointer(mp_p, end_p,
- (char *)block_p->mb_bounds_p - (char *)end_p);
- if (ret != MPOOL_ERROR_NONE) {
- return ret;
- }
- }
-
- /* now free the rest of the block */
- ret = free_pointer(mp_p, FIRST_ADDR_IN_BLOCK(new_block_p),
- MEMORY_IN_BLOCK(new_block_p));
- if (ret != MPOOL_ERROR_NONE) {
- return ret;
- }
-
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * static void *get_space
- *
- * DESCRIPTION:
- *
- * Moved a pointer into our free lists.
- *
- * RETURNS:
- *
- * Success - New address that we can use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * byte_size -> Size of the address space that we need.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-static void *get_space(mpool_t *mp_p, const unsigned long byte_size,
- int *error_p)
-{
- mpool_block_t *block_p;
- mpool_free_t free_pnt;
- int ret;
- unsigned long size;
- unsigned int bit_c, page_n, left;
- void *free_addr = NULL, *free_end;
-
- size = byte_size;
- while ((size & (sizeof(void *) - 1)) > 0) {
- size++;
- }
-
- /*
- * First we check the free lists looking for something with enough
- * pages. Maybe we should only look X bits higher in the list.
- *
- * XXX: this is where we'd do the best fit. We'd look for the
- * closest match. We then could put the rest of the allocation that
- * we did not use in a lower free list. Have a define which states
- * how deep in the free list to go to find the closest match.
- */
- for (bit_c = size_to_bits(size); bit_c <= MAX_BITS; bit_c++) {
- if (mp_p->mp_free[bit_c] != NULL) {
- free_addr = mp_p->mp_free[bit_c];
- break;
- }
- }
-
- /*
- * If we haven't allocated any blocks or if the last block doesn't
- * have enough memory then we need a new block.
- */
- if (bit_c > MAX_BITS) {
-
- /* we need to allocate more space */
-
- page_n = PAGES_IN_SIZE(mp_p, size);
-
- /* now we try and get the pages we need/want */
- block_p = alloc_pages(mp_p, page_n, error_p);
- if (block_p == NULL) {
- /* error_p set in alloc_pages */
- return NULL;
- }
-
- /* init the block header */
- block_p->mb_magic = BLOCK_MAGIC;
- block_p->mb_bounds_p = (char *)block_p + SIZE_OF_PAGES(mp_p, page_n);
- block_p->mb_next_p = mp_p->mp_first_p;
- block_p->mb_magic2 = BLOCK_MAGIC;
-
- /*
- * We insert it into the front of the queue. We could add it to
- * the end but there is not much use.
- */
- mp_p->mp_first_p = block_p;
- if (mp_p->mp_last_p == NULL) {
- mp_p->mp_last_p = block_p;
- }
-
- free_addr = FIRST_ADDR_IN_BLOCK(block_p);
-
-#ifdef DEBUG
- (void)printf("had to allocate space for %lx of %lu bytes\n",
- (long)free_addr, size);
-#endif
-
- free_end = (char *)free_addr + size;
- left = (char *)block_p->mb_bounds_p - (char *)free_end;
- }
- else {
-
- if (bit_c < min_bit_free_next) {
- mp_p->mp_free[bit_c] = NULL;
- /* calculate the number of left over bytes */
- left = bits_to_size(bit_c) - size;
- }
- else if (bit_c < min_bit_free_next) {
- /* grab the next pointer from the freed address into our list */
- memcpy(mp_p->mp_free + bit_c, free_addr, sizeof(void *));
- /* calculate the number of left over bytes */
- left = bits_to_size(bit_c) - size;
- }
- else {
- /* grab the free structure from the address */
- memcpy(&free_pnt, free_addr, sizeof(free_pnt));
- mp_p->mp_free[bit_c] = free_pnt.mf_next_p;
-
- /* are we are splitting up a multiblock chunk into fewer blocks? */
- if (PAGES_IN_SIZE(mp_p, free_pnt.mf_size) > PAGES_IN_SIZE(mp_p, size)) {
- ret = split_block(mp_p, free_addr, size);
- if (ret != MPOOL_ERROR_NONE) {
- SET_POINTER(error_p, ret);
- return NULL;
- }
- /* left over memory was taken care of in split_block */
- left = 0;
- }
- else {
- /* calculate the number of left over bytes */
- left = free_pnt.mf_size - size;
- }
- }
-
-#ifdef DEBUG
- (void)printf("found a free block at %lx of %lu bytes\n",
- (long)free_addr, left + size);
-#endif
-
- free_end = (char *)free_addr + size;
- }
-
- /*
- * If we have memory left over then we free it so someone else can
- * use it. We do not free the space if we just allocated a
- * multi-block chunk because we need to have every allocation easily
- * find the start of the block. Every user address % page-size
- * should take us to the start of the block.
- */
- if (left > 0 && size <= MAX_BLOCK_USER_MEMORY(mp_p)) {
- /* free the rest of the block */
- ret = free_pointer(mp_p, free_end, left);
- if (ret != MPOOL_ERROR_NONE) {
- SET_POINTER(error_p, ret);
- return NULL;
- }
- }
-
- /* update our bounds */
- if (free_addr > mp_p->mp_bounds_p) {
- mp_p->mp_bounds_p = free_addr;
- }
- else if (free_addr < mp_p->mp_min_p) {
- mp_p->mp_min_p = free_addr;
- }
-
- return free_addr;
-}
-
-/*
- * static void *alloc_mem
- *
- * DESCRIPTION:
- *
- * Allocate space for bytes inside of an already open memory pool.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal malloc.
- *
- * byte_size -> Number of bytes to allocate in the pool. Must be >0.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-static void *alloc_mem(mpool_t *mp_p, const unsigned long byte_size,
- int *error_p)
-{
- unsigned long size, fence;
- void *addr;
-
- /* make sure we have enough bytes */
- if (byte_size < MIN_ALLOCATION) {
- size = MIN_ALLOCATION;
- }
- else {
- size = byte_size;
- }
-
- if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
- fence = 0;
- }
- else {
- fence = FENCE_SIZE;
- }
-
- /* get our free space + the space for the fence post */
- addr = get_space(mp_p, size + fence, error_p);
- if (addr == NULL) {
- /* error_p set in get_space */
- return NULL;
- }
-
- if (! BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
- write_magic((char *)addr + size);
- }
-
- /* maintain our stats */
- mp_p->mp_alloc_c++;
- mp_p->mp_user_alloc += size;
- if (mp_p->mp_user_alloc > mp_p->mp_max_alloc) {
- mp_p->mp_max_alloc = mp_p->mp_user_alloc;
- }
-
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return addr;
-}
-
-/*
- * static int free_mem
- *
- * DESCRIPTION:
- *
- * Free an address from a memory pool.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal free.
- *
- * addr <-> Address to free.
- *
- * size -> Size of the address being freed.
- */
-static int free_mem(mpool_t *mp_p, void *addr, const unsigned long size)
-{
- unsigned long old_size, fence;
- int ret;
- mpool_block_t *block_p;
-
- /*
- * If the size is larger than a block then the allocation must be at
- * the front of the block.
- */
- if (size > MAX_BLOCK_USER_MEMORY(mp_p)) {
- block_p = (mpool_block_t *)((char *)addr - sizeof(mpool_block_t));
- if (block_p->mb_magic != BLOCK_MAGIC
- || block_p->mb_magic2 != BLOCK_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
- }
-
- /* make sure we have enough bytes */
- if (size < MIN_ALLOCATION) {
- old_size = MIN_ALLOCATION;
- }
- else {
- old_size = size;
- }
-
- /* if we are packing the pool smaller */
- if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
- fence = 0;
- }
- else {
- /* find the user's magic numbers if they were written */
- ret = check_magic(addr, old_size);
- if (ret != MPOOL_ERROR_NONE) {
- return ret;
- }
- fence = FENCE_SIZE;
- }
-
- /* now we free the pointer */
- ret = free_pointer(mp_p, addr, old_size + fence);
- if (ret != MPOOL_ERROR_NONE) {
- return ret;
- }
- mp_p->mp_user_alloc -= old_size;
-
- /* adjust our stats */
- mp_p->mp_alloc_c--;
-
- return MPOOL_ERROR_NONE;
-}
-
-/***************************** exported routines *****************************/
-
-/*
- * mpool_t *mpool_open
- *
- * DESCRIPTION:
- *
- * Open/allocate a new memory pool.
- *
- * RETURNS:
- *
- * Success - Pool pointer which must be passed to mpool_close to
- * deallocate.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * flags -> Flags to set attributes of the memory pool. See the top
- * of mpool.h.
- *
- * page_size -> Set the internal memory page-size. This must be a
- * multiple of the getpagesize() value. Set to 0 for the default.
- *
- * start_addr -> Starting address to try and allocate memory pools.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(mpool_t *) mpool_open(const unsigned int flags, const unsigned int page_size,
- void *start_addr, int *error_p)
-{
- mpool_block_t *block_p;
- int page_n, ret;
- mpool_t mp, *mp_p;
- void *free_addr;
-
- if (! enabled_b) {
- startup();
- }
-
- /* zero our temp struct */
- memset(&mp, 0, sizeof(mp));
-
- mp.mp_magic = MPOOL_MAGIC;
- mp.mp_flags = flags;
- mp.mp_alloc_c = 0;
- mp.mp_user_alloc = 0;
- mp.mp_max_alloc = 0;
- mp.mp_page_c = 0;
- /* mp.mp_page_size set below */
- /* mp.mp_blocks_bit_n set below */
- /* mp.mp_fd set below */
- /* mp.mp_top set below */
- /* mp.mp_addr set below */
- mp.mp_log_func = NULL;
- mp.mp_min_p = NULL;
- mp.mp_bounds_p = NULL;
- mp.mp_first_p = NULL;
- mp.mp_last_p = NULL;
- mp.mp_magic2 = MPOOL_MAGIC;
-
- /* get and sanity check our page size */
- if (page_size > 0) {
- mp.mp_page_size = page_size;
- if (mp.mp_page_size % getpagesize() != 0) {
- SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
- return NULL;
- }
- }
- else {
- mp.mp_page_size = getpagesize() * DEFAULT_PAGE_MULT;
- if (mp.mp_page_size % 1024 != 0) {
- SET_POINTER(error_p, MPOOL_ERROR_PAGE_SIZE);
- return NULL;
- }
- }
-
- mp.mp_mmflags = 0;
-
- if (BIT_IS_SET(flags, MPOOL_FLAG_ANONYMOUS)) {
- mp.mp_fd = -1;
- mp.mp_mmflags |= MAP_ANON;
- } else {
- /* open dev-zero for our mmaping */
- mp.mp_fd = open("/dev/zero", O_RDWR, 0);
- if (mp.mp_fd < 0) {
- SET_POINTER(error_p, MPOOL_ERROR_OPEN_ZERO);
- return NULL;
- }
- }
- mp.mp_addr = start_addr;
- /* we start at the front of the file */
- mp.mp_top = 0;
-
-
- /*
- * Find out how many pages we need for our mpool structure.
- *
- * NOTE: this adds possibly unneeded space for mpool_block_t which
- * may not be in this block.
- */
- page_n = PAGES_IN_SIZE(&mp, sizeof(mpool_t));
-
- /* now allocate us space for the actual struct */
- mp_p = alloc_pages(&mp, page_n, error_p);
- if (mp_p == NULL) {
- if (mp.mp_fd >= 0) {
- (void)close(mp.mp_fd);
- mp.mp_fd = -1;
- }
- return NULL;
- }
-
- /*
- * NOTE: we do not normally free the rest of the block here because
- * we want to lesson the chance of an allocation overwriting the
- * main structure.
- */
- if (BIT_IS_SET(flags, MPOOL_FLAG_HEAVY_PACKING)) {
-
- /* we add a block header to the front of the block */
- block_p = (mpool_block_t *)mp_p;
-
- /* init the block header */
- block_p->mb_magic = BLOCK_MAGIC;
- block_p->mb_bounds_p = (char *)block_p + SIZE_OF_PAGES(&mp, page_n);
- block_p->mb_next_p = NULL;
- block_p->mb_magic2 = BLOCK_MAGIC;
-
- /* the mpool pointer is then the 2nd thing in the block */
- mp_p = FIRST_ADDR_IN_BLOCK(block_p);
- free_addr = (char *)mp_p + sizeof(mpool_t);
-
- /* free the rest of the block */
- ret = free_pointer(&mp, free_addr,
- (char *)block_p->mb_bounds_p - (char *)free_addr);
- if (ret != MPOOL_ERROR_NONE) {
- if (mp.mp_fd >= 0) {
- (void)close(mp.mp_fd);
- mp.mp_fd = -1;
- }
- /* NOTE: after this line mp_p will be invalid */
- (void)free_pages(block_p, SIZE_OF_PAGES(&mp, page_n));
-
- SET_POINTER(error_p, ret);
- return NULL;
- }
-
- /*
- * NOTE: if we are HEAVY_PACKING then the 1st block with the mpool
- * header is not on the block linked list.
- */
-
- /* now copy our tmp structure into our new memory area */
- memcpy(mp_p, &mp, sizeof(mpool_t));
-
- /* we setup min/max to our current address which is as good as any */
- mp_p->mp_min_p = block_p;
- mp_p->mp_bounds_p = block_p->mb_bounds_p;
- }
- else {
- /* now copy our tmp structure into our new memory area */
- memcpy(mp_p, &mp, sizeof(mpool_t));
-
- /* we setup min/max to our current address which is as good as any */
- mp_p->mp_min_p = mp_p;
- mp_p->mp_bounds_p = (char *)mp_p + SIZE_OF_PAGES(mp_p, page_n);
- }
-
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return mp_p;
-}
-
-/*
- * int mpool_close
- *
- * DESCRIPTION:
- *
- * Close/free a memory allocation pool previously opened with
- * mpool_open.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to our memory pool.
- */
-KS_DECLARE(int) mpool_close(mpool_t *mp_p)
-{
- mpool_block_t *block_p, *next_p;
- void *addr;
- unsigned long size;
- int ret, final = MPOOL_ERROR_NONE;
-
- /* special case, just return no-error */
- if (mp_p == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_CLOSE, 0, 0, NULL, NULL, 0);
- }
-
- /*
- * NOTE: if we are HEAVY_PACKING then the 1st block with the mpool
- * header is not on the linked list.
- */
-
- /* free/invalidate the blocks */
- for (block_p = mp_p->mp_first_p; block_p != NULL; block_p = next_p) {
- if (block_p->mb_magic != BLOCK_MAGIC
- || block_p->mb_magic2 != BLOCK_MAGIC) {
- final = MPOOL_ERROR_POOL_OVER;
- break;
- }
- block_p->mb_magic = 0;
- block_p->mb_magic2 = 0;
- /* record the next pointer because it might be invalidated below */
- next_p = block_p->mb_next_p;
- ret = free_pages(block_p, (char *)block_p->mb_bounds_p - (char *)block_p);
-
- if (ret != MPOOL_ERROR_NONE) {
- final = ret;
- }
- }
-
- /* close /dev/zero if necessary */
- if (mp_p->mp_fd >= 0) {
- (void)close(mp_p->mp_fd);
- mp_p->mp_fd = -1;
- }
-
- /* invalidate the mpool before we ditch it */
- mp_p->mp_magic = 0;
- mp_p->mp_magic2 = 0;
-
- /* if we are heavy packing then we need to free the 1st block later */
- if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_HEAVY_PACKING)) {
- addr = (char *)mp_p - sizeof(mpool_block_t);
- }
- else {
- addr = mp_p;
- }
- size = SIZE_OF_PAGES(mp_p, PAGES_IN_SIZE(mp_p, sizeof(mpool_t)));
-
- (void)munmap(addr, size);
-
-
- return final;
-}
-
-/*
- * int mpool_clear
- *
- * DESCRIPTION:
- *
- * Wipe an opened memory pool clean so we can start again.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to our memory pool.
- */
-KS_DECLARE(int) mpool_clear(mpool_t *mp_p)
-{
- mpool_block_t *block_p;
- int final = MPOOL_ERROR_NONE, bit_n, ret;
- void *first_p;
-
- /* special case, just return no-error */
- if (mp_p == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_CLEAR, 0, 0, NULL, NULL, 0);
- }
-
- /* reset all of our free lists */
- for (bit_n = 0; bit_n <= MAX_BITS; bit_n++) {
- mp_p->mp_free[bit_n] = NULL;
- }
-
- /* free the blocks */
- for (block_p = mp_p->mp_first_p;
- block_p != NULL;
- block_p = block_p->mb_next_p) {
- if (block_p->mb_magic != BLOCK_MAGIC
- || block_p->mb_magic2 != BLOCK_MAGIC) {
- final = MPOOL_ERROR_POOL_OVER;
- break;
- }
-
- first_p = FIRST_ADDR_IN_BLOCK(block_p);
-
- /* free the memory */
- ret = free_pointer(mp_p, first_p, MEMORY_IN_BLOCK(block_p));
- if (ret != MPOOL_ERROR_NONE) {
- final = ret;
- }
- }
-
- return final;
-}
-
-/*
- * void *mpool_alloc
- *
- * DESCRIPTION:
- *
- * Allocate space for bytes inside of an already open memory pool.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal malloc.
- *
- * byte_size -> Number of bytes to allocate in the pool. Must be >0.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *) mpool_alloc(mpool_t *mp_p, const unsigned long byte_size,
- int *error_p)
-{
- void *addr;
-
- if (mp_p == NULL) {
- /* special case -- do a normal malloc */
- addr = (void *)malloc(byte_size);
- if (addr == NULL) {
- SET_POINTER(error_p, MPOOL_ERROR_ALLOC);
- return NULL;
- }
- else {
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return addr;
- }
- }
-
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_PNT);
- return NULL;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
- return NULL;
- }
-
- if (byte_size == 0) {
- SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
- return NULL;
- }
-
- addr = alloc_mem(mp_p, byte_size, error_p);
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_ALLOC, byte_size, 0, addr, NULL, 0);
- }
-
- return addr;
-}
-
-/*
- * void *mpool_calloc
- *
- * DESCRIPTION:
- *
- * Allocate space for elements of bytes in the memory pool and zero
- * the space afterwards.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal calloc.
- *
- * ele_n -> Number of elements to allocate.
- *
- * ele_size -> Number of bytes per element being allocated.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *) mpool_calloc(mpool_t *mp_p, const unsigned long ele_n,
- const unsigned long ele_size, int *error_p)
-{
- void *addr;
- unsigned long byte_size;
-
- if (mp_p == NULL) {
- /* special case -- do a normal calloc */
- addr = (void *)calloc(ele_n, ele_size);
- if (addr == NULL) {
- SET_POINTER(error_p, MPOOL_ERROR_ALLOC);
- return NULL;
- }
- else {
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return addr;
- }
-
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_PNT);
- return NULL;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
- return NULL;
- }
-
- if (ele_n == 0 || ele_size == 0) {
- SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
- return NULL;
- }
-
- byte_size = ele_n * ele_size;
- addr = alloc_mem(mp_p, byte_size, error_p);
- if (addr != NULL) {
- memset(addr, 0, byte_size);
- }
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_CALLOC, ele_size, ele_n, addr, NULL, 0);
- }
-
- /* NOTE: error_p set above */
- return addr;
-}
-
-/*
- * int mpool_free
- *
- * DESCRIPTION:
- *
- * Free an address from a memory pool.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal free.
- *
- * addr <-> Address to free.
- *
- * size -> Size of the address being freed.
- */
-KS_DECLARE(int) mpool_free(mpool_t *mp_p, void *addr, const unsigned long size)
-{
- if (mp_p == NULL) {
- /* special case -- do a normal free */
- free(addr);
- return MPOOL_ERROR_NONE;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_FREE, size, 0, NULL, addr, 0);
- }
-
- if (addr == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (size == 0) {
- return MPOOL_ERROR_ARG_INVALID;
- }
-
- return free_mem(mp_p, addr, size);
-}
-
-/*
- * void *mpool_resize
- *
- * DESCRIPTION:
- *
- * Reallocate an address in a mmeory pool to a new size. This is
- * different from realloc in that it needs the old address' size. If
- * you don't have it then you need to allocate new space, copy the
- * data, and free the old pointer yourself.
- *
- * RETURNS:
- *
- * Success - Pointer to the address to use.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool. If NULL then it will do a
- * normal realloc.
- *
- * old_addr -> Previously allocated address.
- *
- * old_byte_size -> Size of the old address. Must be known, cannot be
- * 0.
- *
- * new_byte_size -> New size of the allocation.
- *
- * error_p <- Pointer to integer which, if not NULL, will be set with
- * a mpool error code.
- */
-KS_DECLARE(void *) mpool_resize(mpool_t *mp_p, void *old_addr,
- const unsigned long old_byte_size,
- const unsigned long new_byte_size,
- int *error_p)
-{
- unsigned long copy_size, new_size, old_size, fence;
- void *new_addr;
- mpool_block_t *block_p;
- int ret;
-
- if (mp_p == NULL) {
- /* special case -- do a normal realloc */
- new_addr = (void *)realloc(old_addr, new_byte_size);
- if (new_addr == NULL) {
- SET_POINTER(error_p, MPOOL_ERROR_ALLOC);
- return NULL;
- }
- else {
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return new_addr;
- }
- }
-
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_PNT);
- return NULL;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
- return NULL;
- }
-
- if (old_addr == NULL) {
- SET_POINTER(error_p, MPOOL_ERROR_ARG_NULL);
- return NULL;
- }
- if (old_byte_size == 0) {
- SET_POINTER(error_p, MPOOL_ERROR_ARG_INVALID);
- return NULL;
- }
-
- /*
- * If the size is larger than a block then the allocation must be at
- * the front of the block.
- */
- if (old_byte_size > MAX_BLOCK_USER_MEMORY(mp_p)) {
- block_p = (mpool_block_t *)((char *)old_addr - sizeof(mpool_block_t));
- if (block_p->mb_magic != BLOCK_MAGIC
- || block_p->mb_magic2 != BLOCK_MAGIC) {
- SET_POINTER(error_p, MPOOL_ERROR_POOL_OVER);
- return NULL;
- }
- }
-
- /* make sure we have enough bytes */
- if (old_byte_size < MIN_ALLOCATION) {
- old_size = MIN_ALLOCATION;
- }
- else {
- old_size = old_byte_size;
- }
-
- /* verify that the size matches exactly if we can */
- if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_NO_FREE)) {
- fence = 0;
- }
- else if (old_size > 0) {
- ret = check_magic(old_addr, old_size);
- if (ret != MPOOL_ERROR_NONE) {
- SET_POINTER(error_p, ret);
- return NULL;
- }
- fence = FENCE_SIZE;
- }
-
- /* make sure we have enough bytes */
- if (new_byte_size < MIN_ALLOCATION) {
- new_size = MIN_ALLOCATION;
- }
- else {
- new_size = new_byte_size;
- }
-
- /*
- * NOTE: we could here see if the size is the same or less and then
- * use the current memory and free the space above. This is harder
- * than it sounds if we are changing the block size of the
- * allocation.
- */
-
- /* we need to get another address */
- new_addr = alloc_mem(mp_p, new_byte_size, error_p);
- if (new_addr == NULL) {
- /* error_p set in mpool_alloc */
- return NULL;
- }
-
- if (new_byte_size > old_byte_size) {
- copy_size = old_byte_size;
- }
- else {
- copy_size = new_byte_size;
- }
- memcpy(new_addr, old_addr, copy_size);
-
- /* free the old address */
- ret = free_mem(mp_p, old_addr, old_byte_size);
- if (ret != MPOOL_ERROR_NONE) {
- /* if the old free failed, try and free the new address */
- (void)free_mem(mp_p, new_addr, new_byte_size);
- SET_POINTER(error_p, ret);
- return NULL;
- }
-
- if (mp_p->mp_log_func != NULL) {
- mp_p->mp_log_func(mp_p, MPOOL_FUNC_RESIZE, new_byte_size,
- 0, new_addr, old_addr, old_byte_size);
- }
-
- SET_POINTER(error_p, MPOOL_ERROR_NONE);
- return new_addr;
-}
-
-/*
- * int mpool_stats
- *
- * DESCRIPTION:
- *
- * Return stats from the memory pool.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p -> Pointer to the memory pool.
- *
- * page_size_p <- Pointer to an unsigned integer which, if not NULL,
- * will be set to the page-size of the pool.
- *
- * num_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the number of pointers currently allocated in pool.
- *
- * user_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the number of user bytes allocated in this pool.
- *
- * max_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the maximum number of user bytes that have been
- * allocated in this pool.
- *
- * tot_alloced_p <- Pointer to an unsigned long which, if not NULL,
- * will be set to the total amount of space (including administrative
- * overhead) used by the pool.
- */
-KS_DECLARE(int) mpool_stats(const mpool_t *mp_p, unsigned int *page_size_p,
- unsigned long *num_alloced_p,
- unsigned long *user_alloced_p,
- unsigned long *max_alloced_p,
- unsigned long *tot_alloced_p)
-{
- if (mp_p == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- SET_POINTER(page_size_p, mp_p->mp_page_size);
- SET_POINTER(num_alloced_p, mp_p->mp_alloc_c);
- SET_POINTER(user_alloced_p, mp_p->mp_user_alloc);
- SET_POINTER(max_alloced_p, mp_p->mp_max_alloc);
- SET_POINTER(tot_alloced_p, SIZE_OF_PAGES(mp_p, mp_p->mp_page_c));
-
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * int mpool_set_log_func
- *
- * DESCRIPTION:
- *
- * Set a logging callback function to be called whenever there was a
- * memory transaction. See mpool_log_func_t.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * log_func -> Log function (defined in mpool.h) which will be called
- * with each mpool transaction.
- */
-KS_DECLARE(int) mpool_set_log_func(mpool_t *mp_p, mpool_log_func_t log_func)
-{
- if (mp_p == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- mp_p->mp_log_func = log_func;
-
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * int mpool_set_max_pages
- *
- * DESCRIPTION:
- *
- * Set the maximum number of pages that the library will use. Once it
- * hits the limit it will return MPOOL_ERROR_NO_PAGES.
- *
- * NOTE: if the MPOOL_FLAG_HEAVY_PACKING is set then this max-pages
- * value will include the page with the mpool header structure in it.
- * If the flag is _not_ set then the max-pages will not include this
- * first page.
- *
- * RETURNS:
- *
- * Success - MPOOL_ERROR_NONE
- *
- * Failure - Mpool error code
- *
- * ARGUMENTS:
- *
- * mp_p <-> Pointer to the memory pool.
- *
- * max_pages -> Maximum number of pages used by the library.
- */
-KS_DECLARE(int) mpool_set_max_pages(mpool_t *mp_p, const unsigned int max_pages)
-{
- if (mp_p == NULL) {
- return MPOOL_ERROR_ARG_NULL;
- }
- if (mp_p->mp_magic != MPOOL_MAGIC) {
- return MPOOL_ERROR_PNT;
- }
- if (mp_p->mp_magic2 != MPOOL_MAGIC) {
- return MPOOL_ERROR_POOL_OVER;
- }
-
- if (BIT_IS_SET(mp_p->mp_flags, MPOOL_FLAG_HEAVY_PACKING)) {
- mp_p->mp_max_pages = max_pages;
- }
- else {
- /*
- * If we are not heavy-packing the pool then we don't count the
- * 1st page allocated which holds the mpool header structure.
- */
- mp_p->mp_max_pages = max_pages + 1;
- }
-
- return MPOOL_ERROR_NONE;
-}
-
-/*
- * const char *mpool_strerror
- *
- * DESCRIPTION:
- *
- * Return the corresponding string for the error number.
- *
- * RETURNS:
- *
- * Success - String equivalient of the error.
- *
- * Failure - String "invalid error code"
- *
- * ARGUMENTS:
- *
- * error -> Error number that we are converting.
- */
-KS_DECLARE(const char *) mpool_strerror(const int error)
-{
- switch (error) {
- case MPOOL_ERROR_NONE:
- return "no error";
- break;
- case MPOOL_ERROR_ARG_NULL:
- return "function argument is null";
- break;
- case MPOOL_ERROR_ARG_INVALID:
- return "function argument is invalid";
- break;
- case MPOOL_ERROR_PNT:
- return "invalid mpool pointer";
- break;
- case MPOOL_ERROR_POOL_OVER:
- return "mpool structure was overwritten";
- break;
- case MPOOL_ERROR_PAGE_SIZE:
- return "could not get system page-size";
- break;
- case MPOOL_ERROR_OPEN_ZERO:
- return "could not open /dev/zero";
- break;
- case MPOOL_ERROR_NO_MEM:
- return "no memory available";
- break;
- case MPOOL_ERROR_MMAP:
- return "problems with mmap";
- break;
- case MPOOL_ERROR_SIZE:
- return "error processing requested size";
- break;
- case MPOOL_ERROR_TOO_BIG:
- return "allocation exceeds pool max size";
- break;
- case MPOOL_ERROR_MEM:
- return "invalid memory address";
- break;
- case MPOOL_ERROR_MEM_OVER:
- return "memory lower bounds overwritten";
- break;
- case MPOOL_ERROR_NOT_FOUND:
- return "memory block not found in pool";
- break;
- case MPOOL_ERROR_IS_FREE:
- return "memory address has already been freed";
- break;
- case MPOOL_ERROR_BLOCK_STAT:
- return "invalid internal block status";
- break;
- case MPOOL_ERROR_FREE_ADDR:
- return "invalid internal free address";
- break;
- case MPOOL_ERROR_NO_PAGES:
- return "no available pages left in pool";
- break;
- case MPOOL_ERROR_ALLOC:
- return "system alloc function failed";
- break;
- case MPOOL_ERROR_PNT_OVER:
- return "user pointer admin space overwritten";
- break;
- default:
- break;
- }
-
- return "invalid error code";
-}
-
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * Generic hash table handler...
- *
- * Copyright 2000 by Gray Watson.
- *
- * This file is part of the table package.
- *
- * Permission to use, copy, modify, and distribute this software for
- * any purpose and without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies, and that the name of Gray Watson not be used in advertising
- * or publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: table.c,v 1.19 2000/03/09 03:30:41 gray Exp $
- */
-
-/*
- * Handles basic hash-table manipulations. This is an implementation
- * of open hashing with an array of buckets holding linked lists of
- * elements. Each element has a key and a data. The user indexes on
- * the key to find the data. See the typedefs in table_loc.h for more
- * information.
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined(unix) || defined(__APPLE__)
-
-#include <unistd.h>
-
-#else
-
-#include <io.h>
-#include <malloc.h>
-#define NO_MMAP
-#ifndef open
-#define open _open
-#endif
-#ifndef fdopen
-#define fdopen _fdopen
-#endif
-#endif
-
-#ifndef NO_MMAP
-
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#ifndef MAP_FAILED
-#define MAP_FAILED (caddr_t)0L
-#endif
-
-#endif
-
-#define TABLE_MAIN
-
-#include "table.h"
-#include "table_loc.h"
-
-#ifdef DMALLOC
-#include "dmalloc.h"
-#endif
-
-static char *rcs_id =
- "$Id: table.c,v 1.19 2000/03/09 03:30:41 gray Exp $";
-
-/*
- * Version id for the library. You also need to add an entry to the
- * NEWS and ChangeLog files.
- */
-static char *version_id = "$TableVersion: 4.3.0 March 8, 2000 $";
-
-/****************************** local functions ******************************/
-
-/*
- * static table_entry_t *first_entry
- *
- * DESCRIPTION:
- *
- * Return the first entry in the table. It will set the linear
- * structure counter to the position of the first entry.
- *
- * RETURNS:
- *
- * Success: A pointer to the first entry in the table.
- *
- * Failure: NULL if there is no first entry.
- *
- * ARGUMENTS:
- *
- * table_p -> Table whose next entry we are finding.
- *
- * linear_p <-> Pointer to a linear structure which we will advance
- * and then find the corresponding entry.
- */
-static table_entry_t *first_entry(const table_t *table_p,
- table_linear_t *linear_p)
-{
- table_entry_t *entry_p;
- unsigned int bucket_c = 0;
-
- /* look for the first non-empty bucket */
- for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) {
- entry_p = table_p->ta_buckets[bucket_c];
- if (entry_p != NULL) {
- if (linear_p != NULL) {
- linear_p->tl_bucket_c = bucket_c;
- linear_p->tl_entry_c = 0;
- }
- return TABLE_POINTER(table_p, table_entry_t *, entry_p);
- }
- }
-
- return NULL;
-}
-
-/*
- * static table_entry_t *next_entry
- *
- * DESCRIPTION:
- *
- * Return the next entry in the table which is past the position in
- * our linear pointer. It will advance the linear structure counters.
- *
- * RETURNS:
- *
- * Success: A pointer to the next entry in the table.
- *
- * Failure: NULL.
- *
- * ARGUMENTS:
- *
- * table_p -> Table whose next entry we are finding.
- *
- * linear_p <-> Pointer to a linear structure which we will advance
- * and then find the corresponding entry.
- *
- * error_p <- Pointer to an integer which when the routine returns
- * will contain a table error code.
- */
-static table_entry_t *next_entry(const table_t *table_p,
- table_linear_t *linear_p, int *error_p)
-{
- table_entry_t *entry_p;
- int entry_c;
-
- /* can't next if we haven't first-ed */
- if (linear_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_LINEAR);
- return NULL;
- }
-
- if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) {
- /*
- * NOTE: this might happen if we delete an item which shortens the
- * table bucket numbers.
- */
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
- }
-
- linear_p->tl_entry_c++;
-
- /* find the entry which is the nth in the list */
- entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
- /* NOTE: we swap the order here to be more efficient */
- for (entry_c = linear_p->tl_entry_c; entry_c > 0; entry_c--) {
- /* did we reach the end of the list? */
- if (entry_p == NULL) {
- break;
- }
- entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p;
- }
-
- /* did we find an entry in the current bucket? */
- if (entry_p != NULL) {
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return TABLE_POINTER(table_p, table_entry_t *, entry_p);
- }
-
- /* find the first entry in the next non-empty bucket */
-
- linear_p->tl_entry_c = 0;
- for (linear_p->tl_bucket_c++; linear_p->tl_bucket_c < table_p->ta_bucket_n;
- linear_p->tl_bucket_c++) {
- entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
- if (entry_p != NULL) {
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return TABLE_POINTER(table_p, table_entry_t *, entry_p);
- }
- }
-
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
-}
-
-/*
- * static table_entry_t *this_entry
- *
- * DESCRIPTION:
- *
- * Return the entry pointer in the table which is currently being
- * indicated by our linear pointer.
- *
- * RETURNS:
- *
- * Success: A pointer to the next entry in the table.
- *
- * Failure: NULL.
- *
- * ARGUMENTS:
- *
- * table_p -> Table whose next entry we are finding.
- *
- * linear_p -> Pointer to a linear structure which we will find the
- * corresponding entry.
- *
- * error_p <- Pointer to an integer which when the routine returns
- * will contain a table error code.
- */
-static table_entry_t *this_entry(const table_t *table_p,
- const table_linear_t *linear_p,
- int *error_p)
-{
- table_entry_t *entry_p;
- int entry_c;
-
- /* can't next if we haven't first-ed */
- if (linear_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_LINEAR);
- return NULL;
- }
-
- if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) {
- /*
- * NOTE: this might happen if we delete an item which shortens the
- * table bucket numbers.
- */
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
- }
-
- /* find the entry which is the nth in the list */
- entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
-
- /* NOTE: we swap the order here to be more efficient */
- for (entry_c = linear_p->tl_entry_c; entry_c > 0; entry_c--) {
- /* did we reach the end of the list? */
- if (entry_p == NULL) {
- break;
- }
- entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p;
- }
-
- /* did we find an entry in the current bucket? */
- if (entry_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
- }
- else {
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return TABLE_POINTER(table_p, table_entry_t *, entry_p);
- }
-}
-
-/*
- * static unsigned int hash
- *
- * DESCRIPTION:
- *
- * Hash a variable-length key into a 32-bit value. Every bit of the
- * key affects every bit of the return value. Every 1-bit and 2-bit
- * delta achieves avalanche. About (6 * len + 35) instructions. The
- * best hash table sizes are powers of 2. There is no need to use mod
- * (sooo slow!). If you need less than 32 bits, use a bitmask. For
- * example, if you need only 10 bits, do h = (h & hashmask(10)); In
- * which case, the hash table should have hashsize(10) elements.
- *
- * By Bob Jenkins, 1996. bob_jenkins@compuserve.com. You may use
- * this code any way you wish, private, educational, or commercial.
- * It's free. See
- * http://ourworld.compuserve.com/homepages/bob_jenkins/evahash.htm
- * Use for hash table lookup, or anything where one collision in 2^^32
- * is acceptable. Do NOT use for cryptographic purposes.
- *
- * RETURNS:
- *
- * Returns a 32-bit hash value.
- *
- * ARGUMENTS:
- *
- * key - Key (the unaligned variable-length array of bytes) that we
- * are hashing.
- *
- * length - Length of the key in bytes.
- *
- * init_val - Initialization value of the hash if you need to hash a
- * number of strings together. For instance, if you are hashing N
- * strings (unsigned char **)keys, do it like this:
- *
- * for (i=0, h=0; i<N; ++i) h = hash( keys[i], len[i], h);
- */
-static unsigned int hash(const unsigned char *key,
- const unsigned int length,
- const unsigned int init_val)
-{
- const unsigned char *key_p = key;
- unsigned int a, b, c, len;
-
- /* set up the internal state */
- a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
- b = 0x9e3779b9;
- c = init_val; /* the previous hash value */
-
- /* handle most of the key */
- for (len = length; len >= 12; len -= 12) {
- a += (key_p[0]
- + ((unsigned int)key_p[1] << 8)
- + ((unsigned int)key_p[2] << 16)
- + ((unsigned int)key_p[3] << 24));
- b += (key_p[4]
- + ((unsigned int)key_p[5] << 8)
- + ((unsigned int)key_p[6] << 16)
- + ((unsigned int)key_p[7] << 24));
- c += (key_p[8]
- + ((unsigned int)key_p[9] << 8)
- + ((unsigned int)key_p[10] << 16)
- + ((unsigned int)key_p[11] << 24));
- HASH_MIX(a,b,c);
- key_p += 12;
- }
-
- c += length;
-
- /* all the case statements fall through to the next */
- switch(len) {
- case 11:
- c += ((unsigned int)key_p[10] << 24);
- case 10:
- c += ((unsigned int)key_p[9] << 16);
- case 9:
- c += ((unsigned int)key_p[8] << 8);
- /* the first byte of c is reserved for the length */
- case 8:
- b += ((unsigned int)key_p[7] << 24);
- case 7:
- b += ((unsigned int)key_p[6] << 16);
- case 6:
- b += ((unsigned int)key_p[5] << 8);
- case 5:
- b += key_p[4];
- case 4:
- a += ((unsigned int)key_p[3] << 24);
- case 3:
- a += ((unsigned int)key_p[2] << 16);
- case 2:
- a += ((unsigned int)key_p[1] << 8);
- case 1:
- a += key_p[0];
- /* case 0: nothing left to add */
- }
- HASH_MIX(a, b, c);
-
- return c;
-}
-
-/*
- * static int entry_size
- *
- * DESCRIPTION:
- *
- * Calculates the appropriate size of an entry to include the key and
- * data sizes as well as any associated alignment to the data.
- *
- * RETURNS:
- *
- * The associated size of the entry.
- *
- * ARGUMENTS:
- *
- * table_p - Table associated with the entries whose size we are
- * determining.
- *
- * key_size - Size of the entry key.
- *
- * data - Size of the entry data.
- */
-static int entry_size(const table_t *table_p, const unsigned int key_size,
- const unsigned int data_size)
-{
- int size, left;
-
- /* initial size -- key is already aligned if right after struct */
- size = sizeof(struct table_shell_st) + key_size;
-
- /* if there is no alignment then it is easy */
- if (table_p->ta_data_align == 0) {
- return size + data_size;
- }
-
- /* add in our alignement */
- left = size & (table_p->ta_data_align - 1);
- if (left > 0) {
- size += table_p->ta_data_align - left;
- }
-
- /* we add the data size here after the alignment */
- size += data_size;
-
- return size;
-}
-
-/*
- * static unsigned char *entry_data_buf
- *
- * DESCRIPTION:
- *
- * Companion to the ENTRY_DATA_BUF macro but this handles any
- * associated alignment to the data in the entry.
- *
- * NOTE: we assume here that the data-alignment is > 0.
- *
- * RETURNS:
- *
- * Pointer to the data segment of the entry.
- *
- * ARGUMENTS:
- *
- * table_p - Table associated with the entry.
- *
- * entry_p - Entry whose data pointer we are determining.
- */
-static unsigned char *entry_data_buf(const table_t *table_p,
- const table_entry_t *entry_p)
-{
- const unsigned char *buf_p;
- unsigned int size, pad;
-
- buf_p = entry_p->te_key_buf + entry_p->te_key_size;
-
- /* we need the size of the space before the data */
- size = sizeof(struct table_shell_st) + entry_p->te_key_size;
-
- /* add in our alignment */
- pad = size & (table_p->ta_data_align - 1);
- if (pad > 0) {
- pad = table_p->ta_data_align - pad;
- }
-
- return (unsigned char *)buf_p + pad;
-}
-
-/******************************* sort routines *******************************/
-
-/*
- * static int local_compare
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * compare - User comparison function. Ignored.
- *
- * table_p - Associated table being ordered. Ignored.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int local_compare(const void *p1, const void *p2,
- table_compare_t compare, const table_t *table_p,
- int *err_bp)
-{
- const table_entry_t * const *ent1_p = p1, * const *ent2_p = p2;
- int cmp;
- unsigned int size;
-
- /* compare as many bytes as we can */
- size = (*ent1_p)->te_key_size;
- if ((*ent2_p)->te_key_size < size) {
- size = (*ent2_p)->te_key_size;
- }
- cmp = memcmp(ENTRY_KEY_BUF(*ent1_p), ENTRY_KEY_BUF(*ent2_p), size);
- /* if common-size equal, then if next more bytes, it is larger */
- if (cmp == 0) {
- cmp = (*ent1_p)->te_key_size - (*ent2_p)->te_key_size;
- }
-
- *err_bp = 0;
- return cmp;
-}
-
-/*
- * static int local_compare_pos
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * compare - User comparison function. Ignored.
- *
- * table_p - Associated table being ordered.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int local_compare_pos(const void *p1, const void *p2,
- table_compare_t compare,
- const table_t *table_p, int *err_bp)
-{
- const table_linear_t *lin1_p = p1, *lin2_p = p2;
- const table_entry_t *ent1_p, *ent2_p;
- int cmp, ret;
- unsigned int size;
-
- /* get entry pointers */
- ent1_p = this_entry(table_p, lin1_p, &ret);
- ent2_p = this_entry(table_p, lin2_p, &ret);
- if (ent1_p == NULL || ent2_p == NULL) {
- *err_bp = 1;
- return 0;
- }
-
- /* compare as many bytes as we can */
- size = ent1_p->te_key_size;
- if (ent2_p->te_key_size < size) {
- size = ent2_p->te_key_size;
- }
- cmp = memcmp(ENTRY_KEY_BUF(ent1_p), ENTRY_KEY_BUF(ent2_p), size);
- /* if common-size equal, then if next more bytes, it is larger */
- if (cmp == 0) {
- cmp = ent1_p->te_key_size - ent2_p->te_key_size;
- }
-
- *err_bp = 0;
- return cmp;
-}
-
-/*
- * static int external_compare
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * user_compare - User comparison function.
- *
- * table_p - Associated table being ordered.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int external_compare(const void *p1, const void *p2,
- table_compare_t user_compare,
- const table_t *table_p, int *err_bp)
-{
- const table_entry_t * const *ent1_p = p1, * const *ent2_p = p2;
- /* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */
- *err_bp = 0;
- return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size,
- ENTRY_DATA_BUF(table_p, *ent1_p),
- (*ent1_p)->te_data_size,
- ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size,
- ENTRY_DATA_BUF(table_p, *ent2_p),
- (*ent2_p)->te_data_size);
-}
-
-/*
- * static int external_compare_pos
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * user_compare - User comparison function.
- *
- * table_p - Associated table being ordered.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int external_compare_pos(const void *p1, const void *p2,
- table_compare_t user_compare,
- const table_t *table_p, int *err_bp)
-{
- const table_linear_t *lin1_p = p1, *lin2_p = p2;
- const table_entry_t *ent1_p, *ent2_p;
- int ret;
-
- /* get entry pointers */
- ent1_p = this_entry(table_p, lin1_p, &ret);
- ent2_p = this_entry(table_p, lin2_p, &ret);
- if (ent1_p == NULL || ent2_p == NULL) {
- *err_bp = 1;
- return 0;
- }
-
- /* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */
- *err_bp = 0;
- return user_compare(ENTRY_KEY_BUF(ent1_p), (ent1_p)->te_key_size,
- ENTRY_DATA_BUF(table_p, ent1_p), ent1_p->te_data_size,
- ENTRY_KEY_BUF(ent2_p), ent2_p->te_key_size,
- ENTRY_DATA_BUF(table_p, ent2_p), ent2_p->te_data_size);
-}
-
-/*
- * static int external_compare_align
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp. Alignment information is necessary.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * user_compare - User comparison function.
- *
- * table_p - Associated table being ordered.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int external_compare_align(const void *p1, const void *p2,
- table_compare_t user_compare,
- const table_t *table_p, int *err_bp)
-{
- const table_entry_t * const *ent1_p = p1, * const *ent2_p = p2;
- /* since we are aligned we have to use the entry_data_buf function */
- *err_bp = 0;
- return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size,
- entry_data_buf(table_p, *ent1_p),
- (*ent1_p)->te_data_size,
- ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size,
- entry_data_buf(table_p, *ent2_p),
- (*ent2_p)->te_data_size);
-}
-
-/*
- * static int external_compare_align_pos
- *
- * DESCRIPTION:
- *
- * Compare two entries by calling user's compare program or by using
- * memcmp. Alignment information is necessary.
- *
- * RETURNS:
- *
- * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2.
- *
- * ARGUMENTS:
- *
- * p1 - First entry pointer to compare.
- *
- * p2 - Second entry pointer to compare.
- *
- * user_compare - User comparison function.
- *
- * table_p - Associated table being ordered.
- *
- * err_bp - Pointer to an integer which will be set with 1 if an error
- * has occurred. It cannot be NULL.
- */
-static int external_compare_align_pos(const void *p1, const void *p2,
- table_compare_t user_compare,
- const table_t *table_p, int *err_bp)
-{
- const table_linear_t *lin1_p = p1, *lin2_p = p2;
- const table_entry_t *ent1_p, *ent2_p;
- int ret;
-
- /* get entry pointers */
- ent1_p = this_entry(table_p, lin1_p, &ret);
- ent2_p = this_entry(table_p, lin2_p, &ret);
- if (ent1_p == NULL || ent2_p == NULL) {
- *err_bp = 1;
- return 0;
- }
-
- /* since we are aligned we have to use the entry_data_buf function */
- *err_bp = 0;
- return user_compare(ENTRY_KEY_BUF(ent1_p), ent1_p->te_key_size,
- entry_data_buf(table_p, ent1_p), ent1_p->te_data_size,
- ENTRY_KEY_BUF(ent2_p), ent2_p->te_key_size,
- entry_data_buf(table_p, ent2_p), ent2_p->te_data_size);
-}
-
-/*
- * static void swap_bytes
- *
- * DESCRIPTION:
- *
- * Swap the values between two items of a specified size.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * item1_p -> Pointer to the first item.
- *
- * item2_p -> Pointer to the first item.
- *
- * ele_size -> Size of the two items.
- */
-static void swap_bytes(unsigned char *item1_p, unsigned char *item2_p,
- int ele_size)
-{
- unsigned char char_temp;
-
- for (; ele_size > 0; ele_size--) {
- char_temp = *item1_p;
- *item1_p = *item2_p;
- *item2_p = char_temp;
- item1_p++;
- item2_p++;
- }
-}
-
-/*
- * static void insert_sort
- *
- * DESCRIPTION:
- *
- * Do an insertion sort which is faster for small numbers of items and
- * better if the items are already sorted.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * first_p <-> Start of the list that we are splitting.
- *
- * last_p <-> Last entry in the list that we are splitting.
- *
- * holder_p <-> Location of hold area we can store an entry.
- *
- * ele_size -> Size of the each element in the list.
- *
- * compare -> Our comparison function.
- *
- * user_compare -> User comparison function. Could be NULL if we are
- * just using a local comparison function.
- *
- * table_p -> Associated table being sorted.
- */
-static int insert_sort(unsigned char *first_p, unsigned char *last_p,
- unsigned char *holder_p,
- const unsigned int ele_size, compare_t compare,
- table_compare_t user_compare, table_t *table_p)
-{
- unsigned char *inner_p, *outer_p;
- int ret, err_b;
-
- for (outer_p = first_p + ele_size; outer_p <= last_p; ) {
-
- /* look for the place to insert the entry */
- for (inner_p = outer_p - ele_size;
- inner_p >= first_p;
- inner_p -= ele_size) {
- ret = compare(outer_p, inner_p, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret >= 0) {
- break;
- }
- }
- inner_p += ele_size;
-
- /* do we need to insert the entry in? */
- if (outer_p != inner_p) {
- /*
- * Now we shift the entry down into its place in the already
- * sorted list.
- */
- memcpy(holder_p, outer_p, ele_size);
- memmove(inner_p + ele_size, inner_p, outer_p - inner_p);
- memcpy(inner_p, holder_p, ele_size);
- }
-
- outer_p += ele_size;
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * static int split
- *
- * DESCRIPTION:
- *
- * This sorts an array of longs via the quick sort algorithm (it's
- * pretty quick)
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * first_p -> Start of the list that we are splitting.
- *
- * last_p -> Last entry in the list that we are splitting.
- *
- * ele_size -> Size of the each element in the list.
- *
- * compare -> Our comparison function.
- *
- * user_compare -> User comparison function. Could be NULL if we are
- * just using a local comparison function.
- *
- * table_p -> Associated table being sorted.
- */
-static int split(unsigned char *first_p, unsigned char *last_p,
- const unsigned int ele_size, compare_t compare,
- table_compare_t user_compare, table_t *table_p)
-{
- unsigned char *left_p, *right_p, *pivot_p, *left_last_p, *right_first_p;
- unsigned char *firsts[MAX_QSORT_SPLITS], *lasts[MAX_QSORT_SPLITS], *pivot;
- unsigned int width, split_c = 0;
- int size1, size2, min_qsort_size;
- int ret, err_b;
-
- /*
- * Allocate some space for our pivot value. We also use this as
- * holder space for our insert sort.
- */
- pivot = alloca(ele_size);
- if (pivot == NULL) {
- /* what else can we do? */
- abort();
- }
-
- min_qsort_size = MAX_QSORT_MANY * ele_size;
-
- while (1) {
-
- /* find the left, right, and mid point */
- left_p = first_p;
- right_p = last_p;
- /* is there a faster way to find this? */
- width = (last_p - first_p) / ele_size;
- pivot_p = first_p + ele_size * (width >> 1);
-
- /*
- * Find which of the left, middle, and right elements is the
- * median (Knuth vol3 p123).
- */
- ret = compare(first_p, pivot_p, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret > 0) {
- swap_bytes(first_p, pivot_p, ele_size);
- }
- ret = compare(pivot_p, last_p, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret > 0) {
- swap_bytes(pivot_p, last_p, ele_size);
- ret = compare(first_p, pivot_p, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret > 0) {
- swap_bytes(first_p, pivot_p, ele_size);
- }
- }
-
- /*
- * save our pivot so we don't have to worry about hitting and
- * swapping it elsewhere while we iterate across the list below.
- */
- memcpy(pivot, pivot_p, ele_size);
-
- do {
-
- /* shift the left side up until we reach the pivot value */
- while (1) {
- ret = compare(left_p, pivot, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret >= 0) {
- break;
- }
- left_p += ele_size;
- }
- /* shift the right side down until we reach the pivot value */
- while (1) {
- ret = compare(pivot, right_p, user_compare, table_p, &err_b);
- if (err_b) {
- return TABLE_ERROR_COMPARE;
- }
- if (ret >= 0) {
- break;
- }
- right_p -= ele_size;
- }
-
- /* if we met in the middle then we are done */
- if (left_p == right_p) {
- left_p += ele_size;
- right_p -= ele_size;
- break;
- }
- else if (left_p < right_p) {
- /*
- * swap the left and right since they both were on the wrong
- * size of the pivot and continue
- */
- swap_bytes(left_p, right_p, ele_size);
- left_p += ele_size;
- right_p -= ele_size;
- }
- } while (left_p <= right_p);
-
- /* Rename variables to make more sense. This will get optimized out. */
- right_first_p = left_p;
- left_last_p = right_p;
-
- /* determine the size of the left and right hand parts */
- size1 = left_last_p - first_p;
- size2 = last_p - right_first_p;
-
- /* is the 1st half small enough to just insert-sort? */
- if (size1 < min_qsort_size) {
-
- /* use the pivot as our temporary space */
- ret = insert_sort(first_p, left_last_p, pivot, ele_size, compare,
- user_compare, table_p);
- if (ret != TABLE_ERROR_NONE) {
- return ret;
- }
-
- /* is the 2nd part small as well? */
- if (size2 < min_qsort_size) {
-
- /* use the pivot as our temporary space */
- ret = insert_sort(right_first_p, last_p, pivot, ele_size, compare,
- user_compare, table_p);
- if (ret != TABLE_ERROR_NONE) {
- return ret;
- }
-
- /* pop a partition off our stack */
- if (split_c == 0) {
- /* we are done */
- return TABLE_ERROR_NONE;
- }
- split_c--;
- first_p = firsts[split_c];
- last_p = lasts[split_c];
- }
- else {
- /* we can just handle the right side immediately */
- first_p = right_first_p;
- /* last_p = last_p */
- }
- }
- else if (size2 < min_qsort_size) {
-
- /* use the pivot as our temporary space */
- ret = insert_sort(right_first_p, last_p, pivot, ele_size, compare,
- user_compare, table_p);
- if (ret != TABLE_ERROR_NONE) {
- return ret;
- }
-
- /* we can just handle the left side immediately */
- /* first_p = first_p */
- last_p = left_last_p;
- }
- else {
- /*
- * neither partition is small, we'll have to push the larger one
- * of them on the stack
- */
- if (split_c >= MAX_QSORT_SPLITS) {
- /* sanity check here -- we should never get here */
- abort();
- }
- if (size1 > size2) {
- /* push the left partition on the stack */
- firsts[split_c] = first_p;
- lasts[split_c] = left_last_p;
- split_c++;
- /* continue handling the right side */
- first_p = right_first_p;
- /* last_p = last_p */
- }
- else {
- /* push the right partition on the stack */
- firsts[split_c] = right_first_p;
- lasts[split_c] = last_p;
- split_c++;
- /* continue handling the left side */
- /* first_p = first_p */
- last_p = left_last_p;
- }
- }
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*************************** exported routines *******************************/
-
-/*
- * table_t *table_alloc
- *
- * DESCRIPTION:
- *
- * Allocate a new table structure.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_free to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * bucket_n - Number of buckets for the hash table. Our current hash
- * value works best with base two numbers. Set to 0 to take the
- * library default of 1024.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_t *table_alloc(const unsigned int bucket_n, int *error_p)
-{
- table_t *table_p = NULL;
- unsigned int buck_n;
-
- /* allocate a table structure */
- table_p = malloc(sizeof(table_t));
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- if (bucket_n > 0) {
- buck_n = bucket_n;
- }
- else {
- buck_n = DEFAULT_SIZE;
- }
-
- /* allocate the buckets which are NULLed */
- table_p->ta_buckets = (table_entry_t **)calloc(buck_n,
- sizeof(table_entry_t *));
- if (table_p->ta_buckets == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- free(table_p);
- return NULL;
- }
-
- /* initialize structure */
- table_p->ta_magic = TABLE_MAGIC;
- table_p->ta_flags = 0;
- table_p->ta_bucket_n = buck_n;
- table_p->ta_entry_n = 0;
- table_p->ta_data_align = 0;
- table_p->ta_linear.tl_magic = 0;
- table_p->ta_linear.tl_bucket_c = 0;
- table_p->ta_linear.tl_entry_c = 0;
- table_p->ta_mmap = NULL;
- table_p->ta_file_size = 0;
- table_p->ta_mem_pool = NULL;
- table_p->ta_alloc_func = NULL;
- table_p->ta_resize_func = NULL;
- table_p->ta_free_func = NULL;
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return table_p;
-}
-
-/*
- * table_t *table_alloc_in_pool
- *
- * DESCRIPTION:
- *
- * Allocate a new table structure in a memory pool or using
- * alternative allocation and free functions.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_free to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * bucket_n - Number of buckets for the hash table. Our current hash
- * value works best with base two numbers. Set to 0 to take the
- * library default of 1024.
- *
- * mem_pool <-> Memory pool to associate with the table. Can be NULL.
- *
- * alloc_func -> Allocate function we are overriding malloc() with.
- *
- * resize_func -> Resize function we are overriding the standard
- * memory resize/realloc with. This can be NULL in which cause the
- * library will allocate, copy, and free itself.
- *
- * free_func -> Free function we are overriding free() with.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_t *table_alloc_in_pool(const unsigned int bucket_n,
- void *mem_pool,
- table_mem_alloc_t alloc_func,
- table_mem_resize_t resize_func,
- table_mem_free_t free_func, int *error_p)
-{
- table_t *table_p = NULL;
- unsigned int buck_n, size;
-
- /* make sure we have real functions, mem_pool and resize_func can be NULL */
- if (alloc_func == NULL || free_func == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ARG_NULL);
- return NULL;
- }
-
- /* allocate a table structure */
- table_p = alloc_func(mem_pool, sizeof(table_t));
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- if (bucket_n > 0) {
- buck_n = bucket_n;
- }
- else {
- buck_n = DEFAULT_SIZE;
- }
-
- /* allocate the buckets which are NULLed */
- size = buck_n * sizeof(table_entry_t *);
- table_p->ta_buckets = (table_entry_t **)alloc_func(mem_pool, size);
- if (table_p->ta_buckets == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- (void)free_func(mem_pool, table_p, sizeof(table_t));
- return NULL;
- }
- /*
- * We zero it ourselves to save the necessity of having a
- * table_mem_calloc_t memory override function.
- */
- memset(table_p->ta_buckets, 0, size);
-
- /* initialize structure */
- table_p->ta_magic = TABLE_MAGIC;
- table_p->ta_flags = 0;
- table_p->ta_bucket_n = buck_n;
- table_p->ta_entry_n = 0;
- table_p->ta_data_align = 0;
- table_p->ta_linear.tl_magic = 0;
- table_p->ta_linear.tl_bucket_c = 0;
- table_p->ta_linear.tl_entry_c = 0;
- table_p->ta_mmap = NULL;
- table_p->ta_file_size = 0;
- table_p->ta_mem_pool = mem_pool;
- table_p->ta_alloc_func = alloc_func;
- table_p->ta_resize_func = resize_func;
- table_p->ta_free_func = free_func;
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return table_p;
-}
-
-/*
- * int table_attr
- *
- * DESCRIPTION:
- *
- * Set the attributes for the table. The available attributes are
- * specified at the top of table.h.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to a table structure which we will be altering.
- *
- * attr - Attribute(s) that we will be applying to the table.
- */
-int table_attr(table_t *table_p, const int attr)
-{
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- table_p->ta_flags = attr;
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_set_data_alignment
- *
- * DESCRIPTION:
- *
- * Set the alignment for the data in the table. This is used when you
- * want to store binary data types and refer to them directly out of
- * the table storage. For instance if you are storing integers as
- * data in the table and want to be able to retrieve the location of
- * the interger and then increment it as (*loc_p)++. Otherwise you
- * would have to memcpy it out to an integer, increment it, and memcpy
- * it back. If you are storing character data, no alignment is
- * necessary.
- *
- * For most data elements, sizeof(long) is recommended unless you use
- * smaller data types exclusively.
- *
- * WARNING: If necessary, you must set the data alignment before any
- * data gets put into the table. Otherwise a TABLE_ERROR_NOT_EMPTY
- * error will be returned.
- *
- * NOTE: there is no way to set the key data alignment although it
- * should automatically be long aligned.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to a table structure which we will be altering.
- *
- * alignment - Alignment requested for the data. Must be a power of
- * 2. Set to 0 for none.
- */
-int table_set_data_alignment(table_t *table_p, const int alignment)
-{
- int val;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (table_p->ta_entry_n > 0) {
- return TABLE_ERROR_NOT_EMPTY;
- }
-
- /* defaults */
- if (alignment < 2) {
- table_p->ta_data_align = 0;
- }
- else {
- /* verify we have a base 2 number */
- for (val = 2; val < MAX_ALIGNMENT; val *= 2) {
- if (val == alignment) {
- break;
- }
- }
- if (val >= MAX_ALIGNMENT) {
- return TABLE_ERROR_ALIGNMENT;
- }
- table_p->ta_data_align = alignment;
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_clear
- *
- * DESCRIPTION:
- *
- * Clear out and free all elements in a table structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer that we will be clearing.
- */
-int table_clear(table_t *table_p)
-{
- int final = TABLE_ERROR_NONE;
- table_entry_t *entry_p, *next_p;
- table_entry_t **bucket_p, **bounds_p;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- /* free the table allocation and table structure */
- bounds_p = table_p->ta_buckets + table_p->ta_bucket_n;
- for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) {
- for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) {
- /* record the next pointer before we free */
- next_p = entry_p->te_next_p;
- if (table_p->ta_free_func == NULL) {
- free(entry_p);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool, entry_p,
- entry_size(table_p,
- entry_p->te_key_size,
- entry_p->te_data_size))) {
- final = TABLE_ERROR_FREE;
- }
- }
-
- /* clear the bucket entry after we free its entries */
- *bucket_p = NULL;
- }
-
- /* reset table state info */
- table_p->ta_entry_n = 0;
- table_p->ta_linear.tl_magic = 0;
- table_p->ta_linear.tl_bucket_c = 0;
- table_p->ta_linear.tl_entry_c = 0;
-
- return final;
-}
-
-/*
- * int table_free
- *
- * DESCRIPTION:
- *
- * Deallocates a table structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer that we will be freeing.
- */
-int table_free(table_t *table_p)
-{
- int ret;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- ret = table_clear(table_p);
-
- if (table_p->ta_buckets != NULL) {
- if (table_p->ta_free_func == NULL) {
- free(table_p->ta_buckets);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool,
- table_p->ta_buckets,
- table_p->ta_bucket_n *
- sizeof(table_entry_t *))) {
- return TABLE_ERROR_FREE;
- }
- }
- table_p->ta_magic = 0;
- if (table_p->ta_free_func == NULL) {
- free(table_p);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool, table_p,
- sizeof(table_t))) {
- if (ret == TABLE_ERROR_NONE) {
- ret = TABLE_ERROR_FREE;
- }
- }
-
- return ret;
-}
-
-/*
- * int table_insert_kd
- *
- * DESCRIPTION:
- *
- * Like table_insert except it passes back a pointer to the key and
- * the data buffers after they have been inserted into the table
- * structure.
- *
- * This routine adds a key/data pair both of which are made up of a
- * buffer of bytes and an associated size. Both the key and the data
- * will be copied into buffers allocated inside the table. If the key
- * exists already, the associated data will be replaced if the
- * overwrite flag is set, otherwise an error is returned.
- *
- * NOTE: be very careful changing the values since the table library
- * provides the pointers to its memory. The key can _never_ be
- * changed otherwise you will not find it again. The data can be
- * changed but its length can never be altered unless you delete and
- * re-insert it into the table.
- *
- * WARNING: The pointers to the key and data are not in any specific
- * alignment. Accessing the key and/or data as an short, integer, or
- * long pointer directly can cause problems.
- *
- * WARNING: Replacing a data cell (not inserting) will cause the table
- * linked list to be temporarily invalid. Care must be taken with
- * multiple threaded programs which are relying on the first/next
- * linked list to be always valid.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be inserting a
- * new key/data pair.
- *
- * key_buf - Buffer of bytes of the key that we are inserting. If you
- * are storing an (int) as the key (for example) then key_buf should
- * be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are storing an (int) as the key (for example) then key_size should
- * be sizeof(int).
- *
- * data_buf - Buffer of bytes of the data that we are inserting. If
- * it is NULL then the library will allocate space for the data in the
- * table without copying in any information. If data_buf is NULL and
- * data_size is 0 then the library will associate a NULL data pointer
- * with the key. If you are storing a (long) as the data (for
- * example) then data_buf should be a (long *).
- *
- * data_size - Size of the data_buf buffer. If set to < 0 then the
- * library will do a strlen of data_buf and add 1 for the '\0'. If
- * you are storing an (long) as the key (for example) then key_size
- * should be sizeof(long).
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the key storage that was allocated in the table. If you are
- * storing an (int) as the key (for example) then key_buf_p should be
- * (int **) i.e. the address of a (int *).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table. If you are
- * storing an (long) as the data (for example) then data_buf_p should
- * be (long **) i.e. the address of a (long *).
- *
- * overwrite - Flag which, if set to 1, will allow the overwriting of
- * the data in the table with the new data if the key already exists
- * in the table.
- */
-int table_insert_kd(table_t *table_p,
- const void *key_buf, const int key_size,
- const void *data_buf, const int data_size,
- void **key_buf_p, void **data_buf_p,
- const char overwrite_b)
-{
- int bucket;
- unsigned int ksize, dsize, new_size, old_size, copy_size;
- table_entry_t *entry_p, *last_p, *new_entry_p;
- void *key_copy_p, *data_copy_p;
-
- /* check the arguments */
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (key_buf == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- /* data_buf can be null but size must be >= 0, if it isn't null size != 0 */
- if ((data_buf == NULL && data_size < 0)
- || (data_buf != NULL && data_size == 0)) {
- return TABLE_ERROR_SIZE;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- /* determine sizes of key and data */
- if (key_size < 0) {
- ksize = strlen((char *)key_buf) + sizeof(char);
- }
- else {
- ksize = key_size;
- }
- if (data_size < 0) {
- dsize = strlen((char *)data_buf) + sizeof(char);
- }
- else {
- dsize = data_size;
- }
-
- /* get the bucket number via a hash function */
- bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
-
- /* look for the entry in this bucket, only check keys of the same size */
- last_p = NULL;
- for (entry_p = table_p->ta_buckets[bucket];
- entry_p != NULL;
- last_p = entry_p, entry_p = entry_p->te_next_p) {
- if (entry_p->te_key_size == ksize
- && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) {
- break;
- }
- }
-
- /* did we find it? then we are in replace mode. */
- if (entry_p != NULL) {
-
- /* can we not overwrite existing data? */
- if (! overwrite_b) {
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- return TABLE_ERROR_OVERWRITE;
- }
-
- /* re-alloc entry's data if the new size != the old */
- if (dsize != entry_p->te_data_size) {
-
- /*
- * First we delete it from the list to keep the list whole.
- * This properly preserves the linked list in case we have a
- * thread marching through the linked list while we are
- * inserting. Maybe this is an unnecessary protection but it
- * should not harm that much.
- */
- if (last_p == NULL) {
- table_p->ta_buckets[bucket] = entry_p->te_next_p;
- }
- else {
- last_p->te_next_p = entry_p->te_next_p;
- }
-
- /*
- * Realloc the structure which may change its pointer. NOTE:
- * this may change any previous data_key_p and data_copy_p
- * pointers.
- */
- new_size = entry_size(table_p, entry_p->te_key_size, dsize);
- if (table_p->ta_resize_func == NULL) {
- /* if the alloc function has not been overriden do realloc */
- if (table_p->ta_alloc_func == NULL) {
- entry_p = (table_entry_t *)realloc(entry_p, new_size);
- if (entry_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- }
- else {
- old_size = new_size - dsize + entry_p->te_data_size;
- /*
- * if the user did override alloc but not resize, assume
- * that the user's allocation functions can't grok realloc
- * and do it ourselves the hard way.
- */
- new_entry_p =
- (table_entry_t *)table_p->ta_alloc_func(table_p->ta_mem_pool,
- new_size);
- if (new_entry_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- if (new_size > old_size) {
- copy_size = old_size;
- }
- else {
- copy_size = new_size;
- }
- memcpy(new_entry_p, entry_p, copy_size);
- if (! table_p->ta_free_func(table_p->ta_mem_pool, entry_p,
- old_size)) {
- return TABLE_ERROR_FREE;
- }
- entry_p = new_entry_p;
- }
- }
- else {
- old_size = new_size - dsize + entry_p->te_data_size;
- entry_p = (table_entry_t *)
- table_p->ta_resize_func(table_p->ta_mem_pool, entry_p,
- old_size, new_size);
- if (entry_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- }
-
- /* add it back to the front of the list */
- entry_p->te_data_size = dsize;
- entry_p->te_next_p = table_p->ta_buckets[bucket];
- table_p->ta_buckets[bucket] = entry_p;
- }
-
- /* copy or replace data in storage */
- if (dsize > 0) {
- if (table_p->ta_data_align == 0) {
- data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- data_copy_p = entry_data_buf(table_p, entry_p);
- }
- if (data_buf != NULL) {
- memcpy(data_copy_p, data_buf, dsize);
- }
- }
- else {
- data_copy_p = NULL;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(data_buf_p, data_copy_p);
-
- /* returning from the section where we were overwriting table data */
- return TABLE_ERROR_NONE;
- }
-
- /*
- * It is a new entry.
- */
-
- /* allocate a new entry */
- new_size = entry_size(table_p, ksize, dsize);
- if (table_p->ta_alloc_func == NULL) {
- entry_p = (table_entry_t *)malloc(new_size);
- }
- else {
- entry_p =
- (table_entry_t *)table_p->ta_alloc_func(table_p->ta_mem_pool, new_size);
- }
- if (entry_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
-
- /* copy key into storage */
- entry_p->te_key_size = ksize;
- key_copy_p = ENTRY_KEY_BUF(entry_p);
- memcpy(key_copy_p, key_buf, ksize);
-
- /* copy data in */
- entry_p->te_data_size = dsize;
- if (dsize > 0) {
- if (table_p->ta_data_align == 0) {
- data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- data_copy_p = entry_data_buf(table_p, entry_p);
- }
- if (data_buf != NULL) {
- memcpy(data_copy_p, data_buf, dsize);
- }
- }
- else {
- data_copy_p = NULL;
- }
-
- SET_POINTER(key_buf_p, key_copy_p);
- SET_POINTER(data_buf_p, data_copy_p);
-
- /* insert into list, no need to append */
- entry_p->te_next_p = table_p->ta_buckets[bucket];
- table_p->ta_buckets[bucket] = entry_p;
-
- table_p->ta_entry_n++;
-
- /* do we need auto-adjust? */
- if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST)
- && SHOULD_TABLE_GROW(table_p)) {
- return table_adjust(table_p, table_p->ta_entry_n);
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_insert
- *
- * DESCRIPTION:
- *
- * Exactly the same as table_insert_kd except it does not pass back a
- * pointer to the key after they have been inserted into the table
- * structure. This is still here for backwards compatibility.
- *
- * See table_insert_kd for more information.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be inserting a
- * new key/data pair.
- *
- * key_buf - Buffer of bytes of the key that we are inserting. If you
- * are storing an (int) as the key (for example) then key_buf should
- * be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are storing an (int) as the key (for example) then key_size should
- * be sizeof(int).
- *
- * data_buf - Buffer of bytes of the data that we are inserting. If
- * it is NULL then the library will allocate space for the data in the
- * table without copying in any information. If data_buf is NULL and
- * data_size is 0 then the library will associate a NULL data pointer
- * with the key. If you are storing a (long) as the data (for
- * example) then data_buf should be a (long *).
- *
- * data_size - Size of the data_buf buffer. If set to < 0 then the
- * library will do a strlen of data_buf and add 1 for the '\0'. If
- * you are storing an (long) as the key (for example) then key_size
- * should be sizeof(long).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table. If you are
- * storing an (long) as the data (for example) then data_buf_p should
- * be (long **) i.e. the address of a (long *).
- *
- * overwrite - Flag which, if set to 1, will allow the overwriting of
- * the data in the table with the new data if the key already exists
- * in the table.
- */
-int table_insert(table_t *table_p,
- const void *key_buf, const int key_size,
- const void *data_buf, const int data_size,
- void **data_buf_p, const char overwrite_b)
-{
- return table_insert_kd(table_p, key_buf, key_size, data_buf, data_size,
- NULL, data_buf_p, overwrite_b);
-}
-
-/*
- * int table_retrieve
- *
- * DESCRIPTION:
- *
- * This routine looks up a key made up of a buffer of bytes and an
- * associated size in the table. If found then it returns the
- * associated data information.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer into which we will be searching
- * for the key.
- *
- * key_buf - Buffer of bytes of the key that we are searching for. If
- * you are looking for an (int) as the key (for example) then key_buf
- * should be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are looking for an (int) as the key (for example) then key_size
- * should be sizeof(int).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that is
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data stored in the table that is associated with
- * the key.
- */
-int table_retrieve(table_t *table_p,
- const void *key_buf, const int key_size,
- void **data_buf_p, int *data_size_p)
-{
- int bucket;
- unsigned int ksize;
- table_entry_t *entry_p, **buckets;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (key_buf == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
-
- /* find key size */
- if (key_size < 0) {
- ksize = strlen((char *)key_buf) + sizeof(char);
- }
- else {
- ksize = key_size;
- }
-
- /* get the bucket number via a has function */
- bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
-
- /* look for the entry in this bucket, only check keys of the same size */
- buckets = table_p->ta_buckets;
- for (entry_p = buckets[bucket];
- entry_p != NULL;
- entry_p = entry_p->te_next_p) {
- entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p);
- if (entry_p->te_key_size == ksize
- && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) {
- break;
- }
- }
-
- /* not found? */
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_delete
- *
- * DESCRIPTION:
- *
- * This routine looks up a key made up of a buffer of bytes and an
- * associated size in the table. If found then it will be removed
- * from the table. The associated data can be passed back to the user
- * if requested.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * NOTE: this could be an allocation error if the library is to return
- * the data to the user.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we will be deleteing
- * the key.
- *
- * key_buf - Buffer of bytes of the key that we are searching for to
- * delete. If you are deleting an (int) key (for example) then
- * key_buf should be a (int *).
- *
- * key_size - Size of the key_buf buffer. If set to < 0 then the
- * library will do a strlen of key_buf and add 1 for the '\0'. If you
- * are deleting an (int) key (for example) then key_size should be
- * sizeof(int).
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that was
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *). If a pointer is passed in, the caller is responsible for
- * freeing it after use. If data_buf_p is NULL then the library will
- * free up the data allocation itself.
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that was stored in the table and that was
- * associated with the key.
- */
-int table_delete(table_t *table_p,
- const void *key_buf, const int key_size,
- void **data_buf_p, int *data_size_p)
-{
- int bucket;
- unsigned int ksize;
- unsigned char *data_copy_p;
- table_entry_t *entry_p, *last_p;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (key_buf == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- /* get the key size */
- if (key_size < 0) {
- ksize = strlen((char *)key_buf) + sizeof(char);
- }
- else {
- ksize = key_size;
- }
-
- /* find our bucket */
- bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n;
-
- /* look for the entry in this bucket, only check keys of the same size */
- for (last_p = NULL, entry_p = table_p->ta_buckets[bucket];
- entry_p != NULL;
- last_p = entry_p, entry_p = entry_p->te_next_p) {
- if (entry_p->te_key_size == ksize
- && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) {
- break;
- }
- }
-
- /* did we find it? */
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- /*
- * NOTE: we may want to adjust the linear counters here if the entry
- * we are deleting is the one we are pointing on or is ahead of the
- * one in the bucket list
- */
-
- /* remove entry from the linked list */
- if (last_p == NULL) {
- table_p->ta_buckets[bucket] = entry_p->te_next_p;
- }
- else {
- last_p->te_next_p = entry_p->te_next_p;
- }
-
- /* free entry */
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- /*
- * if we were storing it compacted, we now need to malloc some
- * space if the user wants the value after the delete.
- */
- if (table_p->ta_alloc_func == NULL) {
- *data_buf_p = malloc(entry_p->te_data_size);
- }
- else {
- *data_buf_p = table_p->ta_alloc_func(table_p->ta_mem_pool,
- entry_p->te_data_size);
- }
- if (*data_buf_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- if (table_p->ta_data_align == 0) {
- data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- data_copy_p = entry_data_buf(table_p, entry_p);
- }
- memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size);
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
- if (table_p->ta_free_func == NULL) {
- free(entry_p);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool, entry_p,
- entry_size(table_p,
- entry_p->te_key_size,
- entry_p->te_data_size))) {
- return TABLE_ERROR_FREE;
- }
-
- table_p->ta_entry_n--;
-
- /* do we need auto-adjust down? */
- if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST)
- && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN)
- && SHOULD_TABLE_SHRINK(table_p)) {
- return table_adjust(table_p, table_p->ta_entry_n);
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_delete_first
- *
- * DESCRIPTION:
- *
- * This is like the table_delete routines except it deletes the first
- * key/data pair in the table instead of an entry corresponding to a
- * particular key. The associated key and data information can be
- * passed back to the user if requested. This routines is handy to
- * clear out a table.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * NOTE: this could be an allocation error if the library is to return
- * the data to the user.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we will be deleteing
- * the first key.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that was allocated in the table.
- * If an (int) was stored as the first key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *). If a
- * pointer is passed in, the caller is responsible for freeing it
- * after use. If key_buf_p is NULL then the library will free up the
- * key allocation itself.
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that was stored in the table and that was
- * associated with the key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that was allocated in the table and that was
- * associated with the key. If a (long) was stored as the data (for
- * example) then data_buf_p should be (long **) i.e. the address of a
- * (long *). If a pointer is passed in, the caller is responsible for
- * freeing it after use. If data_buf_p is NULL then the library will
- * free up the data allocation itself.
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that was stored in the table and that was
- * associated with the key.
- */
-int table_delete_first(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- unsigned char *data_copy_p;
- table_entry_t *entry_p;
- table_linear_t linear;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- /* take the first entry */
- entry_p = first_entry(table_p, &linear);
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- /*
- * NOTE: we may want to adjust the linear counters here if the entry
- * we are deleting is the one we are pointing on or is ahead of the
- * one in the bucket list
- */
-
- /* remove entry from the linked list */
- table_p->ta_buckets[linear.tl_bucket_c] = entry_p->te_next_p;
-
- /* free entry */
- if (key_buf_p != NULL) {
- if (entry_p->te_key_size == 0) {
- *key_buf_p = NULL;
- }
- else {
- /*
- * if we were storing it compacted, we now need to malloc some
- * space if the user wants the value after the delete.
- */
- if (table_p->ta_alloc_func == NULL) {
- *key_buf_p = malloc(entry_p->te_key_size);
- }
- else {
- *key_buf_p = table_p->ta_alloc_func(table_p->ta_mem_pool,
- entry_p->te_key_size);
- }
- if (*key_buf_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- memcpy(*key_buf_p, ENTRY_KEY_BUF(entry_p), entry_p->te_key_size);
- }
- }
- SET_POINTER(key_size_p, entry_p->te_key_size);
-
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- /*
- * if we were storing it compacted, we now need to malloc some
- * space if the user wants the value after the delete.
- */
- if (table_p->ta_alloc_func == NULL) {
- *data_buf_p = malloc(entry_p->te_data_size);
- }
- else {
- *data_buf_p = table_p->ta_alloc_func(table_p->ta_mem_pool,
- entry_p->te_data_size);
- }
- if (*data_buf_p == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- if (table_p->ta_data_align == 0) {
- data_copy_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- data_copy_p = entry_data_buf(table_p, entry_p);
- }
- memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size);
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
- if (table_p->ta_free_func == NULL) {
- free(entry_p);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool, entry_p,
- entry_size(table_p,
- entry_p->te_key_size,
- entry_p->te_data_size))) {
- return TABLE_ERROR_FREE;
- }
-
- table_p->ta_entry_n--;
-
- /* do we need auto-adjust down? */
- if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST)
- && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN)
- && SHOULD_TABLE_SHRINK(table_p)) {
- return table_adjust(table_p, table_p->ta_entry_n);
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_info
- *
- * DESCRIPTION:
- *
- * Get some information about a table_p structure.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting
- * information.
- *
- * num_buckets_p - Pointer to an integer which, if not NULL, will
- * contain the number of buckets in the table.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries stored in the table.
- */
-int table_info(table_t *table_p, int *num_buckets_p, int *num_entries_p)
-{
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- SET_POINTER(num_buckets_p, table_p->ta_bucket_n);
- SET_POINTER(num_entries_p, table_p->ta_entry_n);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_adjust
- *
- * DESCRIPTION:
- *
- * Set the number of buckets in a table to a certain value.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer of which we are adjusting.
- *
- * bucket_n - Number buckets to adjust the table to. Set to 0 to
- * adjust the table to its number of entries.
- */
-int table_adjust(table_t *table_p, const int bucket_n)
-{
- table_entry_t *entry_p, *next_p;
- table_entry_t **buckets, **bucket_p, **bounds_p;
- int bucket;
- unsigned int buck_n, bucket_size;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
-#ifndef NO_MMAP
- /* no mmap support so immediate error */
- if (table_p->ta_mmap != NULL) {
- return TABLE_ERROR_MMAP_OP;
- }
-#endif
-
- /*
- * NOTE: we walk through the entries and rehash them. If we stored
- * the hash value as a full int in the table-entry, all we would
- * have to do is remod it.
- */
-
- /* normalize to the number of entries */
- if (bucket_n == 0) {
- buck_n = table_p->ta_entry_n;
- }
- else {
- buck_n = bucket_n;
- }
-
- /* we must have at least 1 bucket */
- if (buck_n == 0) {
- buck_n = 1;
- }
-
- (void)printf("growing table to %d\n", buck_n);
-
- /* make sure we have something to do */
- if (buck_n == table_p->ta_bucket_n) {
- return TABLE_ERROR_NONE;
- }
-
- /* allocate a new bucket list */
- bucket_size = buck_n * sizeof(table_entry_t *);
- if (table_p->ta_alloc_func == NULL) {
- buckets = (table_entry_t **)malloc(bucket_size);
- }
- else {
- buckets =
- (table_entry_t **)table_p->ta_alloc_func(table_p->ta_mem_pool,
- bucket_size);
- }
- if (buckets == NULL) {
- return TABLE_ERROR_ALLOC;
- }
- /*
- * We zero it ourselves to save the necessity of having a
- * table_mem_calloc_t memory override function.
- */
- memset(buckets, 0, bucket_size);
-
- /*
- * run through each of the items in the current table and rehash
- * them into the newest bucket sizes
- */
- bounds_p = table_p->ta_buckets + table_p->ta_bucket_n;
- for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) {
- for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) {
-
- /* hash the old data into the new table size */
- bucket = hash(ENTRY_KEY_BUF(entry_p), entry_p->te_key_size, 0) % buck_n;
-
- /* record the next one now since we overwrite next below */
- next_p = entry_p->te_next_p;
-
- /* insert into new list, no need to append */
- entry_p->te_next_p = buckets[bucket];
- buckets[bucket] = entry_p;
-
- /*
- * NOTE: we may want to adjust the bucket_c linear entry here to
- * keep it current
- */
- }
- /* remove the old table pointers as we go by */
- *bucket_p = NULL;
- }
-
- /* replace the table buckets with the new ones */
- if (table_p->ta_free_func == NULL) {
- free(table_p->ta_buckets);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool,
- table_p->ta_buckets,
- table_p->ta_bucket_n *
- sizeof(table_entry_t *))) {
- return TABLE_ERROR_FREE;
- }
- table_p->ta_buckets = buckets;
- table_p->ta_bucket_n = buck_n;
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_type_size
- *
- * DESCRIPTION:
- *
- * Return the size of the internal table type.
- *
- * RETURNS:
- *
- * The size of the table_t type.
- *
- * ARGUMENTS:
- *
- * None.
- */
-int table_type_size(void)
-{
- return sizeof(table_t);
-}
-
-/************************* linear access routines ****************************/
-
-/*
- * int table_first
- *
- * DESCRIPTION:
- *
- * Find first element in a table and pass back information about the
- * key/data pair. If any of the key/data pointers are NULL then they
- * are ignored.
- *
- * NOTE: This function is not reentrant. More than one thread cannot
- * be doing a first and next on the same table at the same time. Use
- * the table_first_r version below for this.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * first element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that is allocated in the table. If
- * an (int) is stored as the first key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the first key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the first key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the first key.
- */
-int table_first(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- /* initialize our linear magic number */
- table_p->ta_linear.tl_magic = LINEAR_MAGIC;
-
- entry_p = first_entry(table_p, &table_p->ta_linear);
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_next
- *
- * DESCRIPTION:
- *
- * Find the next element in a table and pass back information about
- * the key/data pair. If any of the key/data pointers are NULL then
- * they are ignored.
- *
- * NOTE: This function is not reentrant. More than one thread cannot
- * be doing a first and next on the same table at the same time. Use
- * the table_next_r version below for this.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * next element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the next key that is allocated in the table. If
- * an (int) is stored as the next key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the next key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the next key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the next key.
- */
-int table_next(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
- int error;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) {
- return TABLE_ERROR_LINEAR;
- }
-
- /* move to the next entry */
- entry_p = next_entry(table_p, &table_p->ta_linear, &error);
- if (entry_p == NULL) {
- return error;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_this
- *
- * DESCRIPTION:
- *
- * Find the current element in a table and pass back information about
- * the key/data pair. If any of the key/data pointers are NULL then
- * they are ignored.
- *
- * NOTE: This function is not reentrant. Use the table_current_r
- * version below.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * current element.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the current key that is allocated in the table.
- * If an (int) is stored as the current key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the current key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the current key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the current key.
- */
-int table_this(table_t *table_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p = NULL;
- int entry_c;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) {
- return TABLE_ERROR_LINEAR;
- }
-
- /* if we removed an item that shorted the bucket list, we may get this */
- if (table_p->ta_linear.tl_bucket_c >= table_p->ta_bucket_n) {
- /*
- * NOTE: this might happen if we delete an item which shortens the
- * table bucket numbers.
- */
- return TABLE_ERROR_NOT_FOUND;
- }
-
- /* find the entry which is the nth in the list */
- entry_p = table_p->ta_buckets[table_p->ta_linear.tl_bucket_c];
- /* NOTE: we swap the order here to be more efficient */
- for (entry_c = table_p->ta_linear.tl_entry_c; entry_c > 0; entry_c--) {
- /* did we reach the end of the list? */
- if (entry_p == NULL) {
- break;
- }
- entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p;
- }
-
- /* is this a NOT_FOUND or a LINEAR error */
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_first_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_first routine above. Find first
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * first element.
- *
- * linear_p - Pointer to a table linear structure which is initialized
- * here. The same pointer should then be passed to table_next_r
- * below.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the first key that is allocated in the table. If
- * an (int) is stored as the first key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the first key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the first key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the first key.
- */
-int table_first_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (linear_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
-
- /* initialize our linear magic number */
- linear_p->tl_magic = LINEAR_MAGIC;
-
- entry_p = first_entry(table_p, linear_p);
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_next_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_next routine above. Find next
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * next element.
- *
- * linear_p - Pointer to a table linear structure which is incremented
- * here. The same pointer must have been passed to table_first_r
- * first so that it can be initialized.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the next key that is allocated in the table. If
- * an (int) is stored as the next key (for example) then key_buf_p
- * should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL will be set
- * to the size of the key that is stored in the table and that is
- * associated with the next key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the next key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the next key.
- */
-int table_next_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
- int error;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (linear_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (linear_p->tl_magic != LINEAR_MAGIC) {
- return TABLE_ERROR_LINEAR;
- }
-
- /* move to the next entry */
- entry_p = next_entry(table_p, linear_p, &error);
- if (entry_p == NULL) {
- return error;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * int table_this_r
- *
- * DESCRIPTION:
- *
- * Reetrant version of the table_this routine above. Find current
- * element in a table and pass back information about the key/data
- * pair. If any of the key/data pointers are NULL then they are
- * ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * current element.
- *
- * linear_p - Pointer to a table linear structure which is accessed
- * here. The same pointer must have been passed to table_first_r
- * first so that it can be initialized.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of the current key that is allocated in the table.
- * If an (int) is stored as the current key (for example) then
- * key_buf_p should be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table and that is
- * associated with the current key.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage that is allocated in the table and that is
- * associated with the current key. If a (long) is stored as the data
- * (for example) then data_buf_p should be (long **) i.e. the address
- * of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table and that is
- * associated with the current key.
- */
-int table_this_r(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
- int entry_c;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (linear_p->tl_magic != LINEAR_MAGIC) {
- return TABLE_ERROR_LINEAR;
- }
-
- /* if we removed an item that shorted the bucket list, we may get this */
- if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) {
- /*
- * NOTE: this might happen if we delete an item which shortens the
- * table bucket numbers.
- */
- return TABLE_ERROR_NOT_FOUND;
- }
-
- /* find the entry which is the nth in the list */
- for (entry_c = linear_p->tl_entry_c,
- entry_p = table_p->ta_buckets[linear_p->tl_bucket_c];
- entry_p != NULL && entry_c > 0;
- entry_c--, entry_p = TABLE_POINTER(table_p, table_entry_t *,
- entry_p)->te_next_p) {
- }
-
- if (entry_p == NULL) {
- return TABLE_ERROR_NOT_FOUND;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/******************************* mmap routines *******************************/
-
-/*
- * table_t *table_mmap
- *
- * DESCRIPTION:
- *
- * Mmap a table from a file that had been written to disk earlier via
- * table_write.
- *
- * RETURNS:
- *
- * A pointer to the new table structure which must be passed to
- * table_munmap to be deallocated. On error a NULL is returned.
- *
- * ARGUMENTS:
- *
- * path - Table file to mmap in.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_t *table_mmap(const char *path, int *error_p)
-{
-#ifdef NO_MMAP
-
- /* no mmap support so immediate error */
- SET_POINTER(error_p, TABLE_ERROR_MMAP_NONE);
- return NULL;
-
-#else
-
- table_t *table_p;
- struct stat sbuf;
- int fd, state;
-
- table_p = (table_t *)malloc(sizeof(table_t));
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- /* open the mmap file */
- fd = open(path, O_RDONLY, 0);
- if (fd < 0) {
- free(table_p);
- SET_POINTER(error_p, TABLE_ERROR_OPEN);
- return NULL;
- }
-
- /* get the file size */
- if (fstat(fd, &sbuf) != 0) {
- free(table_p);
- SET_POINTER(error_p, TABLE_ERROR_OPEN);
- return NULL;
- }
-
- /* mmap the space and close the file */
-#ifdef __alpha
- state = (MAP_SHARED | MAP_FILE | MAP_VARIABLE);
-#else
- state = MAP_SHARED;
-#endif
-
- table_p->ta_mmap = (table_t *)mmap((caddr_t)0, sbuf.st_size, PROT_READ,
- state, fd, 0);
- (void)close(fd);
-
- if (table_p->ta_mmap == (table_t *)MAP_FAILED) {
- SET_POINTER(error_p, TABLE_ERROR_MMAP);
- return NULL;
- }
-
- /* is the mmap file contain bad info or maybe another system type? */
- if (table_p->ta_mmap->ta_magic != TABLE_MAGIC) {
- SET_POINTER(error_p, TABLE_ERROR_PNT);
- return NULL;
- }
-
- /* sanity check on the file size */
- if (table_p->ta_mmap->ta_file_size != sbuf.st_size) {
- SET_POINTER(error_p, TABLE_ERROR_SIZE);
- return NULL;
- }
-
- /* copy the fields out of the mmap file into our memory version */
- table_p->ta_magic = TABLE_MAGIC;
- table_p->ta_flags = table_p->ta_mmap->ta_flags;
- table_p->ta_bucket_n = table_p->ta_mmap->ta_bucket_n;
- table_p->ta_entry_n = table_p->ta_mmap->ta_entry_n;
- table_p->ta_data_align = table_p->ta_mmap->ta_data_align;
- table_p->ta_buckets = TABLE_POINTER(table_p, table_entry_t **,
- table_p->ta_mmap->ta_buckets);
- table_p->ta_linear.tl_magic = 0;
- table_p->ta_linear.tl_bucket_c = 0;
- table_p->ta_linear.tl_entry_c = 0;
- /* mmap is already set */
- table_p->ta_file_size = table_p->ta_mmap->ta_file_size;
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return table_p;
-
-#endif
-}
-
-/*
- * int table_munmap
- *
- * DESCRIPTION:
- *
- * Unmmap a table that was previously mmapped using table_mmap.
- *
- * RETURNS:
- *
- * Returns table error codes.
- *
- * ARGUMENTS:
- *
- * table_p - Mmaped table pointer to unmap.
- */
-int table_munmap(table_t *table_p)
-{
-#ifdef NO_MMAP
-
- /* no mmap support so immediate error */
- return TABLE_ERROR_MMAP_NONE;
-
-#else
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (table_p->ta_mmap == NULL) {
- return TABLE_ERROR_PNT;
- }
-
- (void)munmap((caddr_t)table_p->ta_mmap, table_p->ta_file_size);
- table_p->ta_magic = 0;
- free(table_p);
- return TABLE_ERROR_NONE;
-
-#endif
-}
-
-/******************************* file routines *******************************/
-
-/*
- * int table_read
- *
- * DESCRIPTION:
- *
- * Read in a table from a file that had been written to disk earlier
- * via table_write.
- *
- * RETURNS:
- *
- * Success - Pointer to the new table structure which must be passed
- * to table_free to be deallocated.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * path - Table file to read in.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_t *table_read(const char *path, int *error_p)
-{
- unsigned int size;
- int fd, ent_size;
- FILE *infile;
- table_entry_t entry, **bucket_p, *entry_p = NULL, *last_p;
- unsigned long pos;
- table_t *table_p;
-
- /* open the file */
- fd = open(path, O_RDONLY, 0);
- if (fd < 0) {
- SET_POINTER(error_p, TABLE_ERROR_OPEN);
- return NULL;
- }
-
- /* allocate a table structure */
- table_p = malloc(sizeof(table_t));
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- /* now open the fd to get buffered i/o */
- infile = fdopen(fd, "r");
- if (infile == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_OPEN);
- return NULL;
- }
-
- /* read the main table struct */
- if (fread(table_p, sizeof(table_t), 1, infile) != 1) {
- SET_POINTER(error_p, TABLE_ERROR_READ);
- free(table_p);
- return NULL;
- }
- table_p->ta_file_size = 0;
-
- /* is the mmap file contain bad info or maybe another system type? */
- if (table_p->ta_magic != TABLE_MAGIC) {
- SET_POINTER(error_p, TABLE_ERROR_PNT);
- return NULL;
- }
-
- /* allocate the buckets */
- table_p->ta_buckets = (table_entry_t **)calloc(table_p->ta_bucket_n,
- sizeof(table_entry_t *));
- if (table_p->ta_buckets == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- free(table_p);
- return NULL;
- }
-
- if (fread(table_p->ta_buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
- infile) != (size_t)table_p->ta_bucket_n) {
- SET_POINTER(error_p, TABLE_ERROR_READ);
- free(table_p->ta_buckets);
- free(table_p);
- return NULL;
- }
-
- /* read in the entries */
- for (bucket_p = table_p->ta_buckets;
- bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
- bucket_p++) {
-
- /* skip null buckets */
- if (*bucket_p == NULL) {
- continue;
- }
-
- /* run through the entry list */
- last_p = NULL;
- for (pos = *(unsigned long *)bucket_p;;
- pos = (unsigned long)entry_p->te_next_p) {
-
- /* read in the entry */
- if (fseek(infile, pos, SEEK_SET) != 0) {
- SET_POINTER(error_p, TABLE_ERROR_SEEK);
- free(table_p->ta_buckets);
- free(table_p);
- if (entry_p != NULL) {
- free(entry_p);
- }
- /* the other table elements will not be freed */
- return NULL;
- }
- if (fread(&entry, sizeof(struct table_shell_st), 1, infile) != 1) {
- SET_POINTER(error_p, TABLE_ERROR_READ);
- free(table_p->ta_buckets);
- free(table_p);
- if (entry_p != NULL) {
- free(entry_p);
- }
- /* the other table elements will not be freed */
- return NULL;
- }
-
- /* make a new entry */
- ent_size = entry_size(table_p, entry.te_key_size, entry.te_data_size);
- entry_p = (table_entry_t *)malloc(ent_size);
- if (entry_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- free(table_p->ta_buckets);
- free(table_p);
- /* the other table elements will not be freed */
- return NULL;
- }
- entry_p->te_key_size = entry.te_key_size;
- entry_p->te_data_size = entry.te_data_size;
- entry_p->te_next_p = entry.te_next_p;
-
- if (last_p == NULL) {
- *bucket_p = entry_p;
- }
- else {
- last_p->te_next_p = entry_p;
- }
-
- /* determine how much more we have to read */
- size = ent_size - sizeof(struct table_shell_st);
- if (fread(ENTRY_KEY_BUF(entry_p), sizeof(char), size, infile) != size) {
- SET_POINTER(error_p, TABLE_ERROR_READ);
- free(table_p->ta_buckets);
- free(table_p);
- free(entry_p);
- /* the other table elements will not be freed */
- return NULL;
- }
-
- /* we are done if the next pointer is null */
- if (entry_p->te_next_p == (unsigned long)0) {
- break;
- }
- last_p = entry_p;
- }
- }
-
- (void)fclose(infile);
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return table_p;
-}
-
-/*
- * int table_write
- *
- * DESCRIPTION:
- *
- * Write a table from memory to file.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are writing to the file.
- *
- * path - Table file to write out to.
- *
- * mode - Mode of the file. This argument is passed on to open when
- * the file is created.
- */
-int table_write(const table_t *table_p, const char *path, const int mode)
-{
- int fd, rem, ent_size;
- unsigned int bucket_c, bucket_size;
- unsigned long size;
- table_entry_t *entry_p, **buckets, **bucket_p, *next_p;
- table_t main_tab;
- FILE *outfile;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- fd = open(path, O_WRONLY | O_CREAT, mode);
- if (fd < 0) {
- return TABLE_ERROR_OPEN;
- }
-
- outfile = fdopen(fd, "w");
- if (outfile == NULL) {
- return TABLE_ERROR_OPEN;
- }
-
- /* allocate a block of sizes for each bucket */
- bucket_size = sizeof(table_entry_t *) * table_p->ta_bucket_n;
- if (table_p->ta_alloc_func == NULL) {
- buckets = (table_entry_t **)malloc(bucket_size);
- }
- else {
- buckets =
- (table_entry_t **)table_p->ta_alloc_func(table_p->ta_mem_pool,
- bucket_size);
- }
- if (buckets == NULL) {
- return TABLE_ERROR_ALLOC;
- }
-
- /* make a copy of the main struct */
- main_tab = *table_p;
-
- /* start counting the bytes */
- size = 0;
- size += sizeof(table_t);
-
- /* buckets go right after main struct */
- main_tab.ta_buckets = (table_entry_t **)size;
- size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
-
- /* run through and count the buckets */
- for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) {
- bucket_p = table_p->ta_buckets + bucket_c;
- if (*bucket_p == NULL) {
- buckets[bucket_c] = NULL;
- continue;
- }
- buckets[bucket_c] = (table_entry_t *)size;
- for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
- size += entry_size(table_p, entry_p->te_key_size, entry_p->te_data_size);
- /*
- * We now have to round the file to the nearest long so the
- * mmaping of the longs in the entry structs will work.
- */
- rem = size & (sizeof(long) - 1);
- if (rem > 0) {
- size += sizeof(long) - rem;
- }
- }
- }
- /* add a \0 at the end to fill the last section */
- size++;
-
- /* set the main fields */
- main_tab.ta_linear.tl_magic = 0;
- main_tab.ta_linear.tl_bucket_c = 0;
- main_tab.ta_linear.tl_entry_c = 0;
- main_tab.ta_mmap = NULL;
- main_tab.ta_file_size = size;
-
- /*
- * Now we can start the writing because we got the bucket offsets.
- */
-
- /* write the main table struct */
- size = 0;
- if (fwrite(&main_tab, sizeof(table_t), 1, outfile) != 1) {
- if (table_p->ta_free_func == NULL) {
- free(buckets);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, buckets, bucket_size);
- }
- return TABLE_ERROR_WRITE;
- }
- size += sizeof(table_t);
- if (fwrite(buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
- outfile) != (size_t)table_p->ta_bucket_n) {
- if (table_p->ta_free_func == NULL) {
- free(buckets);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, buckets, bucket_size);
- }
- return TABLE_ERROR_WRITE;
- }
- size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
-
- /* write out the entries */
- for (bucket_p = table_p->ta_buckets;
- bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
- bucket_p++) {
- for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
-
- ent_size = entry_size(table_p, entry_p->te_key_size,
- entry_p->te_data_size);
- size += ent_size;
- /* round to nearest long here so we can write copy */
- rem = size & (sizeof(long) - 1);
- if (rem > 0) {
- size += sizeof(long) - rem;
- }
- next_p = entry_p->te_next_p;
- if (next_p != NULL) {
- entry_p->te_next_p = (table_entry_t *)size;
- }
-
- /* now write to disk */
- if (fwrite(entry_p, ent_size, 1, outfile) != 1) {
- if (table_p->ta_free_func == NULL) {
- free(buckets);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, buckets,
- bucket_size);
- }
- return TABLE_ERROR_WRITE;
- }
-
- /* restore the next pointer */
- if (next_p != NULL) {
- entry_p->te_next_p = next_p;
- }
-
- /* now write the padding information */
- if (rem > 0) {
- rem = sizeof(long) - rem;
- /*
- * NOTE: this won't leave fseek'd space at the end but we
- * don't care there because there is no accessed memory
- * afterwards. We write 1 \0 at the end to make sure.
- */
- if (fseek(outfile, rem, SEEK_CUR) != 0) {
- if (table_p->ta_free_func == NULL) {
- free(buckets);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, buckets,
- bucket_size);
- }
- return TABLE_ERROR_SEEK;
- }
- }
- }
- }
- /*
- * Write a \0 at the end of the file to make sure that the last
- * fseek filled with nulls.
- */
- (void)fputc('\0', outfile);
-
- (void)fclose(outfile);
- if (table_p->ta_free_func == NULL) {
- free(buckets);
- }
- else if (! table_p->ta_free_func(table_p->ta_mem_pool, buckets,
- bucket_size)) {
- return TABLE_ERROR_FREE;
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/******************************** table order ********************************/
-
-/*
- * table_entry_t *table_order
- *
- * DESCRIPTION:
- *
- * Order a table by building an array of table entry pointers and then
- * sorting this array using the qsort function. To retrieve the
- * sorted entries, you can then use the table_entry routine to access
- * each entry in order.
- *
- * NOTE: This routine is thread safe and makes use of an internal
- * status qsort function.
- *
- * RETURNS:
- *
- * Success - An allocated list of table-linear structures which must
- * be freed by table_order_free later.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are ordering.
- *
- * compare - Comparison function defined by the user. Its definition
- * is at the top of the table.h file. If this is NULL then it will
- * order the table my memcmp-ing the keys.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries in the returned entry pointer array.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_entry_t **table_order(table_t *table_p, table_compare_t compare,
- int *num_entries_p, int *error_p)
-{
- table_entry_t *entry_p, **entries, **entries_p;
- table_linear_t linear;
- compare_t comp_func;
- unsigned int entries_size;
- int ret;
-
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ARG_NULL);
- return NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- SET_POINTER(error_p, TABLE_ERROR_PNT);
- return NULL;
- }
-
- /* there must be at least 1 element in the table for this to work */
- if (table_p->ta_entry_n == 0) {
- SET_POINTER(error_p, TABLE_ERROR_EMPTY);
- return NULL;
- }
-
- entries_size = table_p->ta_entry_n * sizeof(table_entry_t *);
- if (table_p->ta_alloc_func == NULL) {
- entries = (table_entry_t **)malloc(entries_size);
- }
- else {
- entries =
- (table_entry_t **)table_p->ta_alloc_func(table_p->ta_mem_pool,
- entries_size);
- }
- if (entries == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- /* get a pointer to all entries */
- entry_p = first_entry(table_p, &linear);
- if (entry_p == NULL) {
- if (table_p->ta_free_func == NULL) {
- free(entries);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, entries, entries_size);
- }
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
- }
-
- /* add all of the entries to the array */
- for (entries_p = entries;
- entry_p != NULL;
- entry_p = next_entry(table_p, &linear, &ret)) {
- *entries_p++ = entry_p;
- }
-
- if (ret != TABLE_ERROR_NOT_FOUND) {
- if (table_p->ta_free_func == NULL) {
- free(entries);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, entries, entries_size);
- }
- SET_POINTER(error_p, ret);
- return NULL;
- }
-
- if (compare == NULL) {
- /* this is regardless of the alignment */
- comp_func = local_compare;
- }
- else if (table_p->ta_data_align == 0) {
- comp_func = external_compare;
- }
- else {
- comp_func = external_compare_align;
- }
-
- /* now qsort the entire entries array from first to last element */
- ret = split((unsigned char *)entries,
- (unsigned char *)(entries + table_p->ta_entry_n - 1),
- sizeof(table_entry_t *), comp_func, compare, table_p);
- if (ret != TABLE_ERROR_NONE) {
- if (table_p->ta_free_func == NULL) {
- free(entries);
- }
- else {
- (void)table_p->ta_free_func(table_p->ta_mem_pool, entries, entries_size);
- }
- SET_POINTER(error_p, ret);
- return NULL;
- }
-
- SET_POINTER(num_entries_p, table_p->ta_entry_n);
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return entries;
-}
-
-/*
- * int table_order_free
- *
- * DESCRIPTION:
- *
- * Free the pointer returned by the table_order or table_order_pos
- * routines.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table.
- *
- * table_entries - Allocated list of entry pointers returned by
- * table_order.
- *
- * entry_n - Number of entries in the array as passed back by
- * table_order or table_order_pos in num_entries_p.
- */
-int table_order_free(table_t *table_p, table_entry_t **table_entries,
- const int entry_n)
-{
- int ret, final = TABLE_ERROR_NONE;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- if (table_p->ta_free_func == NULL) {
- free(table_entries);
- }
- else {
- ret = table_p->ta_free_func(table_p->ta_mem_pool, table_entries,
- sizeof(table_entry_t *) * entry_n);
- if (ret != 1) {
- final = TABLE_ERROR_FREE;
- }
- }
-
- return final;
-}
-
-/*
- * int table_entry
- *
- * DESCRIPTION:
- *
- * Get information about an element. The element is one from the
- * array returned by the table_order function. If any of the key/data
- * pointers are NULL then they are ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * element.
- *
- * entry_p - Pointer to a table entry from the array returned by the
- * table_order function.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of this entry that is allocated in the table. If an
- * (int) is stored as this entry (for example) then key_buf_p should
- * be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage of this entry that is allocated in the table.
- * If a (long) is stored as this entry data (for example) then
- * data_buf_p should be (long **) i.e. the address of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table.
- */
-int table_entry(table_t *table_p, table_entry_t *entry_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (entry_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
-
- SET_POINTER(key_buf_p, ENTRY_KEY_BUF(entry_p));
- SET_POINTER(key_size_p, entry_p->te_key_size);
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- SET_POINTER(data_size_p, entry_p->te_data_size);
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * table_linear_t *table_order_pos
- *
- * DESCRIPTION:
- *
- * Order a table by building an array of table linear structures and
- * then sorting this array using the qsort function. To retrieve the
- * sorted entries, you can then use the table_entry_pos routine to
- * access each entry in order.
- *
- * NOTE: This routine is thread safe and makes use of an internal
- * status qsort function.
- *
- * RETURNS:
- *
- * Success - An allocated list of table-linear structures which must
- * be freed by table_order_pos_free later.
- *
- * Failure - NULL
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table that we are ordering.
- *
- * compare - Comparison function defined by the user. Its definition
- * is at the top of the table.h file. If this is NULL then it will
- * order the table my memcmp-ing the keys.
- *
- * num_entries_p - Pointer to an integer which, if not NULL, will
- * contain the number of entries in the returned entry pointer array.
- *
- * error_p - Pointer to an integer which, if not NULL, will contain a
- * table error code.
- */
-table_linear_t *table_order_pos(table_t *table_p, table_compare_t compare,
- int *num_entries_p, int *error_p)
-{
- table_entry_t *entry_p;
- table_linear_t linear, *linears, *linears_p;
- compare_t comp_func;
- int ret;
-
- if (table_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ARG_NULL);
- return NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- SET_POINTER(error_p, TABLE_ERROR_PNT);
- return NULL;
- }
-
- /* there must be at least 1 element in the table for this to work */
- if (table_p->ta_entry_n == 0) {
- SET_POINTER(error_p, TABLE_ERROR_EMPTY);
- return NULL;
- }
-
- if (table_p->ta_alloc_func == NULL) {
- linears = (table_linear_t *)malloc(table_p->ta_entry_n *
- sizeof(table_linear_t));
- }
- else {
- linears =
- (table_linear_t *)table_p->ta_alloc_func(table_p->ta_mem_pool,
- table_p->ta_entry_n *
- sizeof(table_linear_t));
- }
- if (linears == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_ALLOC);
- return NULL;
- }
-
- /* get a pointer to all entries */
- entry_p = first_entry(table_p, &linear);
- if (entry_p == NULL) {
- SET_POINTER(error_p, TABLE_ERROR_NOT_FOUND);
- return NULL;
- }
-
- /* add all of the entries to the array */
- for (linears_p = linears;
- entry_p != NULL;
- entry_p = next_entry(table_p, &linear, &ret)) {
- *linears_p++ = linear;
- }
-
- if (ret != TABLE_ERROR_NOT_FOUND) {
- SET_POINTER(error_p, ret);
- return NULL;
- }
-
- if (compare == NULL) {
- /* this is regardless of the alignment */
- comp_func = local_compare_pos;
- }
- else if (table_p->ta_data_align == 0) {
- comp_func = external_compare_pos;
- }
- else {
- comp_func = external_compare_align_pos;
- }
-
- /* now qsort the entire entries array from first to last element */
- split((unsigned char *)linears,
- (unsigned char *)(linears + table_p->ta_entry_n - 1),
- sizeof(table_linear_t), comp_func, compare, table_p);
-
- if (num_entries_p != NULL) {
- *num_entries_p = table_p->ta_entry_n;
- }
-
- SET_POINTER(error_p, TABLE_ERROR_NONE);
- return linears;
-}
-
-/*
- * int table_order_pos_free
- *
- * DESCRIPTION:
- *
- * Free the pointer returned by the table_order or table_order_pos
- * routines.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Pointer to the table.
- *
- * table_entries - Allocated list of entry pointers returned by
- * table_order_pos.
- *
- * entry_n - Number of entries in the array as passed back by
- * table_order or table_order_pos in num_entries_p.
- */
-int table_order_pos_free(table_t *table_p, table_linear_t *table_entries,
- const int entry_n)
-{
- int ret, final = TABLE_ERROR_NONE;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
-
- if (table_p->ta_free_func == NULL) {
- free(table_entries);
- }
- else {
- ret = table_p->ta_free_func(table_p->ta_mem_pool, table_entries,
- sizeof(table_linear_t) * entry_n);
- if (ret != 1) {
- final = TABLE_ERROR_FREE;
- }
- }
-
- return final;
-}
-
-/*
- * int table_entry_pos
- *
- * DESCRIPTION:
- *
- * Get information about an element. The element is one from the
- * array returned by the table_order function. If any of the key/data
- * pointers are NULL then they are ignored.
- *
- * RETURNS:
- *
- * Success - TABLE_ERROR_NONE
- *
- * Failure - Table error code.
- *
- * ARGUMENTS:
- *
- * table_p - Table structure pointer from which we are getting the
- * element.
- *
- * linear_p - Pointer to a table linear structure from the array
- * returned by the table_order function.
- *
- * key_buf_p - Pointer which, if not NULL, will be set to the address
- * of the storage of this entry that is allocated in the table. If an
- * (int) is stored as this entry (for example) then key_buf_p should
- * be (int **) i.e. the address of a (int *).
- *
- * key_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the key that is stored in the table.
- *
- * data_buf_p - Pointer which, if not NULL, will be set to the address
- * of the data storage of this entry that is allocated in the table.
- * If a (long) is stored as this entry data (for example) then
- * data_buf_p should be (long **) i.e. the address of a (long *).
- *
- * data_size_p - Pointer to an integer which, if not NULL, will be set
- * to the size of the data that is stored in the table.
- */
-int table_entry_pos(table_t *table_p, table_linear_t *linear_p,
- void **key_buf_p, int *key_size_p,
- void **data_buf_p, int *data_size_p)
-{
- table_entry_t *entry_p;
- int ret;
-
- if (table_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
- if (table_p->ta_magic != TABLE_MAGIC) {
- return TABLE_ERROR_PNT;
- }
- if (linear_p == NULL) {
- return TABLE_ERROR_ARG_NULL;
- }
-
- /* find the associated entry */
- entry_p = this_entry(table_p, linear_p, &ret);
- if (entry_p == NULL) {
- return ret;
- }
-
- if (key_buf_p != NULL) {
- *key_buf_p = ENTRY_KEY_BUF(entry_p);
- }
- if (key_size_p != NULL) {
- *key_size_p = entry_p->te_key_size;
- }
- if (data_buf_p != NULL) {
- if (entry_p->te_data_size == 0) {
- *data_buf_p = NULL;
- }
- else {
- if (table_p->ta_data_align == 0) {
- *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p);
- }
- else {
- *data_buf_p = entry_data_buf(table_p, entry_p);
- }
- }
- }
- if (data_size_p != NULL) {
- *data_size_p = entry_p->te_data_size;
- }
-
- return TABLE_ERROR_NONE;
-}
-
-/*
- * const char *table_strerror
- *
- * DESCRIPTION:
- *
- * Return the corresponding string for the error number.
- *
- * RETURNS:
- *
- * Success - String equivalient of the error.
- *
- * Failure - String "invalid error code"
- *
- * ARGUMENTS:
- *
- * error - Error number that we are converting.
- */
-const char *table_strerror(const int error)
-{
- error_str_t *err_p;
-
- for (err_p = errors; err_p->es_error != 0; err_p++) {
- if (err_p->es_error == error) {
- return err_p->es_string;
- }
- }
-
- return INVALID_ERROR;
-}
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-/*
- * Hash table utility program.
- *
- * Copyright 2000 by Gray Watson
- *
- * This file is part of the table package.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose and without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies,
- * and that the name of Gray Watson not be used in advertising or
- * publicity pertaining to distribution of the document or software
- * without specific, written prior permission.
- *
- * Gray Watson makes no representations about the suitability of the
- * software described herein for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * The author may be reached via http://256.com/gray/
- *
- * $Id: table_util.c,v 1.5 2000/03/09 03:30:42 gray Exp $
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "table.h"
-
-static char *rcs_id =
- "$Id: table_util.c,v 1.5 2000/03/09 03:30:42 gray Exp $";
-
-#define WRITE_MODE 0640 /* mode to write out table */
-#define SPECIAL_CHARS "e\033^^\"\"''\\\\n\nr\rt\tb\bf\fa\007"
-
-/*
- * expand_chars
- *
- * DESCRIPTION:
- *
- * Copies a buffer into a output buffer while translates
- * non-printables into %03o octal values. If it can, it will also
- * translate certain \ characters (\r, \n, etc.) into \\%c. The
- * routine is useful for printing out binary values.
- *
- * NOTE: It does _not_ add a \0 at the end of the output buffer.
- *
- * RETURNS:
- *
- * Returns the number of characters added to the output buffer.
- *
- * ARGUMENTS:
- *
- * buf - the buffer to convert.
- *
- * buf_size - size of the buffer. If < 0 then it will expand till it
- * sees a \0 character.
- *
- * out - destination buffer for the convertion.
- *
- * out_size - size of the output buffer.
- */
-int expand_chars(const void *buf, const int buf_size,
- char *out, const int out_size)
-{
- int buf_c;
- const unsigned char *buf_p, *spec_p;
- char *max_p, *out_p = out;
-
- /* setup our max pointer */
- max_p = out + out_size;
-
- /* run through the input buffer, counting the characters as we go */
- for (buf_c = 0, buf_p = (const unsigned char *)buf;; buf_c++, buf_p++) {
-
- /* did we reach the end of the buffer? */
- if (buf_size < 0) {
- if (*buf_p == '\0') {
- break;
- }
- }
- else {
- if (buf_c >= buf_size) {
- break;
- }
- }
-
- /* search for special characters */
- for (spec_p = (unsigned char *)SPECIAL_CHARS + 1;
- *(spec_p - 1) != '\0';
- spec_p += 2) {
- if (*spec_p == *buf_p) {
- break;
- }
- }
-
- /* did we find one? */
- if (*(spec_p - 1) != '\0') {
- if (out_p + 2 >= max_p) {
- break;
- }
- (void)sprintf(out_p, "\\%c", *(spec_p - 1));
- out_p += 2;
- continue;
- }
-
- /* print out any 7-bit printable characters */
- if (*buf_p < 128 && isprint(*buf_p)) {
- if (out_p + 1 >= max_p) {
- break;
- }
- *out_p = *(char *)buf_p;
- out_p += 1;
- }
- else {
- if (out_p + 4 >= max_p) {
- break;
- }
- (void)sprintf(out_p, "\\%03o", *buf_p);
- out_p += 4;
- }
- }
-
- return out_p - out;
-}
-
-/*
- * dump_table
- *
- * DESCRIPTION:
- *
- * Dump a table file to the screen.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * tab_p - a table pointer that we are dumping.
- */
-static void dump_table(table_t *tab_p)
-{
- char buf[10240];
- void *key_p, *data_p;
- int ret, key_size, data_size, len, entry_c;
-
- for (ret = table_first(tab_p, (void **)&key_p, &key_size,
- (void **)&data_p, &data_size), entry_c = 0;
- ret == TABLE_ERROR_NONE;
- ret = table_next(tab_p, (void **)&key_p, &key_size,
- (void **)&data_p, &data_size), entry_c++) {
- /* expand the key */
- len = expand_chars(key_p, key_size, buf, sizeof(buf));
- (void)printf("%d: key '%.*s' (%d), ", entry_c, len, buf, len);
- /* now dump the data */
- len = expand_chars(data_p, data_size, buf, sizeof(buf));
- (void)printf("data '%.*s' (%d)\n", len, buf, len);
- }
-}
-
-/*
- * usage
- *
- * DESCRIPTION:
- *
- * Print the usage message to stderr.
- *
- * RETURNS:
- *
- * None.
- *
- * ARGUMENTS:
- *
- * tab_p - a table pointer that we are dumping.
- */
-static void usage(void)
-{
- (void)fprintf(stderr,
- "Usage: table_util\n"
- " [-b number] or --buckets num buckets to adjust table\n"
- " [-o file] or --out-file output filename\n"
- " [-v] or --verbose verbose messages\n"
- " file input table filename\n");
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- table_t *tab_p;
- char do_write = 0, verbose = 0;
- char *out_file = NULL, *in_file;
- int ret, entry_n, bucket_n, num_buckets = 0;
-
- /* process the args */
- for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
-
- switch (*(*argv + 1)) {
-
- case 'b':
- argc--, argv++;
- if (argc == 0) {
- usage();
- }
- num_buckets = atoi(*argv);
- break;
-
- case 'o':
- argc--, argv++;
- if (argc == 0) {
- usage();
- }
- out_file = *argv;
- break;
-
- case 'v':
- verbose = 1;
- break;
-
- default:
- usage();
- break;
- }
- }
-
- if (argc != 1) {
- usage();
- }
-
- /* take the last argument as the input file */
- in_file = *argv;
-
- /* read in the table from disk */
- tab_p = table_read(in_file, &ret);
- if (tab_p == NULL) {
- (void)fprintf(stderr, "table_util: unable to table_read from '%s': %s\n",
- in_file, table_strerror(ret));
- exit(1);
- }
-
- /* get info about the table */
- ret = table_info(tab_p, &bucket_n, &entry_n);
- if (ret != TABLE_ERROR_NONE) {
- (void)fprintf(stderr,
- "table_util: unable to get info on table in '%s': %s\n",
- in_file, table_strerror(ret));
- exit(1);
- }
-
- (void)printf("Read table of %d buckets and %d entries from '%s'\n",
- bucket_n, entry_n, in_file);
-
- if (verbose) {
- dump_table(tab_p);
- }
-
- if (num_buckets > 0) {
- /* adjust the table's buckets */
- ret = table_adjust(tab_p, num_buckets);
- if (ret != TABLE_ERROR_NONE) {
- (void)fprintf(stderr,
- "table_util: unable to adjust table to %d buckets: %s\n",
- num_buckets, table_strerror(ret));
- exit(1);
- }
- do_write = 1;
- }
-
- /* did we modify the table at all */
- if (do_write) {
- if (out_file == NULL) {
- out_file = in_file;
- }
-
- /* write out our table */
- ret = table_write(tab_p, out_file, WRITE_MODE);
- if (ret != TABLE_ERROR_NONE) {
- (void)fprintf(stderr, "table_util: unable to write table to '%s': %s\n",
- out_file, table_strerror(ret));
- exit(1);
- }
-
- (void)printf("Wrote table to '%s'\n", out_file);
- }
-
- /* free the table */
- ret = table_free(tab_p);
- if (ret != TABLE_ERROR_NONE) {
- (void)fprintf(stderr, "table_util: unable to free table: %s\n",
- table_strerror(ret));
- /* NOTE: not a critical error */
- }
-
- exit(0);
-}
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectGuid>{766F7FF4-CF39-4CDF-ABDC-4E9C88568F1F}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>testpools</RootNamespace>
- <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\include</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\include</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\include</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>$(ProjectDir)..\..\src\include</AdditionalIncludeDirectories>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup>
- <ClCompile Include="..\testpools.c" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\..\libks.vcxproj">
- <Project>{70d178d8-1100-4152-86c0-809a91cff832}</Project>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup>
- <Filter Include="Source Files">
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
- </Filter>
- <Filter Include="Header Files">
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
- <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
- </Filter>
- <Filter Include="Resource Files">
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
- </Filter>
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="..\testpools.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- </ItemGroup>
-</Project>
\ No newline at end of file