File Annotation

Not logged in
fc60825290 2011-04-18       stephan: #include "wh/whio/whio_amalgamation.h"
a7b8fa204a 2011-04-21       stephan: /* auto-generated on Thu Apr 21 12:23:04 CEST 2011. Do not edit! */
fc60825290 2011-04-18       stephan: #line 1 "whio_amalgamation_core.c"
fc60825290 2011-04-18       stephan: #if !defined(_POSIX_C_SOURCE)
fc60825290 2011-04-18       stephan: #define _POSIX_C_SOURCE 200112L /* needed for ftello() and friends */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: /* begin file src/whprintf.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whprintf.c"
fc60825290 2011-04-18       stephan: /************************************************************************
fc60825290 2011-04-18       stephan: The printf-like implementation in this file is based on the one found
fc60825290 2011-04-18       stephan: in the sqlite3 distribution is in the Public Domain.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: This copy was forked for use with the clob API in Feb 2008 by Stephan
fc60825290 2011-04-18       stephan: Beal (http://wanderinghorse.net/home/stephan/) and modified to send
fc60825290 2011-04-18       stephan: its output to arbitrary targets via a callback mechanism. Also
fc60825290 2011-04-18       stephan: refactored the %X specifier handlers a bit to make adding/removing
fc60825290 2011-04-18       stephan: specific handlers easier.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: All code in this file is released into the Public Domain.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: The printf implementation (whprintfv()) is pretty easy to extend
fc60825290 2011-04-18       stephan: (e.g. adding or removing %-specifiers for whprintfv()) if you're
fc60825290 2011-04-18       stephan: willing to poke around a bit and see how the specifiers are declared
fc60825290 2011-04-18       stephan: and dispatched. For an example, grep for 'etSTRING' and follow it
fc60825290 2011-04-18       stephan: through the process of declaration to implementation.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: See below for several WHPRINTF_OMIT_xxx macros which can be set to
fc60825290 2011-04-18       stephan: remove certain features/extensions.
fc60825290 2011-04-18       stephan: ************************************************************************/
fc60825290 2011-04-18       stephan: 
6e8c7e31b6 2011-04-20       stephan: #if 0
fc60825290 2011-04-18       stephan: #if !defined(_ISOC99_SOURCE)
fc60825290 2011-04-18       stephan: #define _ISOC99_SOURCE 1 /* needed for snprintf() */
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #include <stdio.h> /* FILE */
fc60825290 2011-04-18       stephan: #include <string.h> /* strlen() */
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* free/malloc() */
fc60825290 2011-04-18       stephan: #include <ctype.h>
fc60825290 2011-04-18       stephan: #include <stdint.h>
6e8c7e31b6 2011-04-20       stephan: 
fc60825290 2011-04-18       stephan: typedef long double LONGDOUBLE_TYPE;
6e8c7e31b6 2011-04-20       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    If WHPRINTF_OMIT_FLOATING_POINT is defined to a true value, then
fc60825290 2011-04-18       stephan:    floating point conversions are disabled.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #ifndef WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan: #  define WHPRINTF_OMIT_FLOATING_POINT 0
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    If WHPRINTF_OMIT_SIZE is defined to a true value, then
fc60825290 2011-04-18       stephan:    the %n specifier is disabled.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #ifndef WHPRINTF_OMIT_SIZE
fc60825290 2011-04-18       stephan: #  define WHPRINTF_OMIT_SIZE 0
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    If WHPRINTF_OMIT_SQL is defined to a true value, then
fc60825290 2011-04-18       stephan:    the %q and %Q specifiers are disabled.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #ifndef WHPRINTF_OMIT_SQL
6e8c7e31b6 2011-04-20       stephan: #  define WHPRINTF_OMIT_SQL 1 /* requires c99 */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    If WHPRINTF_OMIT_HTML is defined to a true value then the %h (HTML
fc60825290 2011-04-18       stephan:    escape), %t (URL escape), and %T (URL unescape) specifiers are
fc60825290 2011-04-18       stephan:    disabled.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #ifndef WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan: #  define WHPRINTF_OMIT_HTML 0
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: Most C compilers handle variable-sized arrays, so we enable
fc60825290 2011-04-18       stephan: that by default. Some (e.g. tcc) do not, so we provide a way
fc60825290 2011-04-18       stephan: to disable it: set WHPRINTF_HAVE_VARARRAY to 0
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: One approach would be to look at:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: but some compilers support variable-sized arrays even when not
fc60825290 2011-04-18       stephan: explicitly running in c99 mode.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #if !defined(WHPRINTF_HAVE_VARARRAY)
fc60825290 2011-04-18       stephan: #  if defined(__TINYC__)
fc60825290 2011-04-18       stephan: #    define WHPRINTF_HAVE_VARARRAY 0
fc60825290 2011-04-18       stephan: #  else
6e8c7e31b6 2011-04-20       stephan: #    if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
6e8c7e31b6 2011-04-20       stephan: #        define WHPRINTF_HAVE_VARARRAY 1 /*use 1 in C99 mode */
6e8c7e31b6 2011-04-20       stephan: #    else
6e8c7e31b6 2011-04-20       stephan: #        define WHPRINTF_HAVE_VARARRAY 0
6e8c7e31b6 2011-04-20       stephan: #    endif
fc60825290 2011-04-18       stephan: #  endif
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan: WHPRINTF_CHARARRAY is a helper to allocate variable-sized arrays.
fc60825290 2011-04-18       stephan: This exists mainly so this code can compile with the tcc compiler.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #if WHPRINTF_HAVE_VARARRAY
fc60825290 2011-04-18       stephan: #  define WHPRINTF_CHARARRAY(V,N) char V[N+1]; memset(V,0,N+1);
fc60825290 2011-04-18       stephan: #  define WHPRINTF_CHARARRAY_FREE(V)
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #  define WHPRINTF_CHARARRAY(V,N) char * V = (char *)malloc(N+1); memset(V,0,N+1);
fc60825290 2011-04-18       stephan: #  define WHPRINTF_CHARARRAY_FREE(V) free(V)
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    Conversion types fall into various categories as defined by the
fc60825290 2011-04-18       stephan:    following enumeration.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: enum PrintfCategory {etRADIX = 1, /* Integer types.  %d, %x, %o, and so forth */
fc60825290 2011-04-18       stephan: 		     etFLOAT = 2, /* Floating point.  %f */
fc60825290 2011-04-18       stephan: 		     etEXP = 3, /* Exponentional notation. %e and %E */
fc60825290 2011-04-18       stephan: 		     etGENERIC = 4, /* Floating or exponential, depending on exponent. %g */
fc60825290 2011-04-18       stephan: 		     etSIZE = 5, /* Return number of characters processed so far. %n */
fc60825290 2011-04-18       stephan: 		     etSTRING = 6, /* Strings. %s */
fc60825290 2011-04-18       stephan: 		     etDYNSTRING = 7, /* Dynamically allocated strings. %z */
fc60825290 2011-04-18       stephan: 		     etPERCENT = 8, /* Percent symbol. %% */
fc60825290 2011-04-18       stephan: 		     etCHARX = 9, /* Characters. %c */
fc60825290 2011-04-18       stephan: /* The rest are extensions, not normally found in printf() */
fc60825290 2011-04-18       stephan: 		     etCHARLIT = 10, /* Literal characters.  %' */
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_SQL
fc60825290 2011-04-18       stephan: 		     etSQLESCAPE = 11, /* Strings with '\'' doubled.  %q */
fc60825290 2011-04-18       stephan: 		     etSQLESCAPE2 = 12, /* Strings with '\'' doubled and enclosed in '',
fc60825290 2011-04-18       stephan:                           NULL pointers replaced by SQL NULL.  %Q */
fc60825290 2011-04-18       stephan: 		     etSQLESCAPE3 = 16, /* %w -> Strings with '\"' doubled */
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_SQL */
fc60825290 2011-04-18       stephan: 		     etPOINTER = 15, /* The %p conversion */
fc60825290 2011-04-18       stephan: 		     etORDINAL = 17, /* %r -> 1st, 2nd, 3rd, 4th, etc.  English only */
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan:                      etHTML = 18, /* %h -> basic HTML escaping. */
fc60825290 2011-04-18       stephan:                      etURLENCODE = 19, /* %t -> URL encoding. */
fc60825290 2011-04-18       stephan:                      etURLDECODE = 20, /* %T -> URL decoding. */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 		     etPLACEHOLDER = 100
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    An "etByte" is an 8-bit unsigned value.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef unsigned char etByte;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    Each builtin conversion character (ex: the 'd' in "%d") is described
fc60825290 2011-04-18       stephan:    by an instance of the following structure
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef struct et_info {   /* Information about each format field */
fc60825290 2011-04-18       stephan:   char fmttype;            /* The format field code letter */
fc60825290 2011-04-18       stephan:   etByte base;             /* The base for radix conversion */
fc60825290 2011-04-18       stephan:   etByte flags;            /* One or more of FLAG_ constants below */
fc60825290 2011-04-18       stephan:   etByte type;             /* Conversion paradigm */
fc60825290 2011-04-18       stephan:   etByte charset;          /* Offset into aDigits[] of the digits string */
fc60825290 2011-04-18       stephan:   etByte prefix;           /* Offset into aPrefix[] of the prefix string */
fc60825290 2011-04-18       stephan: } et_info;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    Allowed values for et_info.flags
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: enum et_info_flags { FLAG_SIGNED = 1,    /* True if the value to convert is signed */
fc60825290 2011-04-18       stephan: 		     FLAG_EXTENDED = 2,  /* True if for internal/extended use only. */
fc60825290 2011-04-18       stephan: 		     FLAG_STRING = 4     /* Allow infinity precision */
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   Historically, the following table was searched linearly, so the most
fc60825290 2011-04-18       stephan:   common conversions were kept at the front.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   Change 2008 Oct 31 by Stephan Beal: we reserve an array or ordered
fc60825290 2011-04-18       stephan:   entries for all chars in the range [32..126]. Format character
fc60825290 2011-04-18       stephan:   checks can now be done in constant time by addressing that array
fc60825290 2011-04-18       stephan:   directly.  This takes more static memory, but reduces the time and
fc60825290 2011-04-18       stephan:   per-call overhead costs of whprintfv().
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
fc60825290 2011-04-18       stephan: static const char aPrefix[] = "-x0\000X0";
fc60825290 2011-04-18       stephan: static const et_info fmtinfo[] = {
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    If WHPRINTF_FMTINFO_FIXED is 1 then we use the original
fc60825290 2011-04-18       stephan:    implementation: a linear list of entries. Search time is linear. If
fc60825290 2011-04-18       stephan:    WHPRINTF_FMTINFO_FIXED is 0 then we use a fixed-size array which
fc60825290 2011-04-18       stephan:    we index directly using the format char as the key.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define WHPRINTF_FMTINFO_FIXED 0
fc60825290 2011-04-18       stephan: #if WHPRINTF_FMTINFO_FIXED
fc60825290 2011-04-18       stephan:   {  'd', 10, FLAG_SIGNED, etRADIX,      0,  0 },
fc60825290 2011-04-18       stephan:   {  's',  0, FLAG_STRING, etSTRING,     0,  0 },
fc60825290 2011-04-18       stephan:   {  'g',  0, FLAG_SIGNED, etGENERIC,    30, 0 },
fc60825290 2011-04-18       stephan:   {  'z',  0, FLAG_STRING, etDYNSTRING,  0,  0 },
fc60825290 2011-04-18       stephan:   {  'c',  0, 0, etCHARX,      0,  0 },
fc60825290 2011-04-18       stephan:   {  'o',  8, 0, etRADIX,      0,  2 },
fc60825290 2011-04-18       stephan:   {  'u', 10, 0, etRADIX,      0,  0 },
fc60825290 2011-04-18       stephan:   {  'x', 16, 0, etRADIX,      16, 1 },
fc60825290 2011-04-18       stephan:   {  'X', 16, 0, etRADIX,      0,  4 },
fc60825290 2011-04-18       stephan:   {  'i', 10, FLAG_SIGNED, etRADIX,      0,  0 },
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan:   {  'f',  0, FLAG_SIGNED, etFLOAT,      0,  0 },
fc60825290 2011-04-18       stephan:   {  'e',  0, FLAG_SIGNED, etEXP,        30, 0 },
fc60825290 2011-04-18       stephan:   {  'E',  0, FLAG_SIGNED, etEXP,        14, 0 },
fc60825290 2011-04-18       stephan:   {  'G',  0, FLAG_SIGNED, etGENERIC,    14, 0 },
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_FLOATING_POINT */
fc60825290 2011-04-18       stephan:   {  '%',  0, 0, etPERCENT,    0,  0 },
fc60825290 2011-04-18       stephan:   {  'p', 16, 0, etPOINTER,    0,  1 },
fc60825290 2011-04-18       stephan:   {  'r', 10, (FLAG_EXTENDED|FLAG_SIGNED), etORDINAL,    0,  0 },
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_SQL
fc60825290 2011-04-18       stephan:   {  'q',  0, FLAG_STRING, etSQLESCAPE,  0,  0 },
fc60825290 2011-04-18       stephan:   {  'Q',  0, FLAG_STRING, etSQLESCAPE2, 0,  0 },
fc60825290 2011-04-18       stephan:   {  'w',  0, FLAG_STRING, etSQLESCAPE3, 0,  0 },
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_SQL */
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan:   {  'h',  0, FLAG_STRING, etHTML, 0, 0 },
fc60825290 2011-04-18       stephan:   {  't',  0, FLAG_STRING, etURLENCODE, 0, 0 },
fc60825290 2011-04-18       stephan:   {  'T',  0, FLAG_STRING, etURLDECODE, 0, 0 },
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_HTML */
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_SIZE
fc60825290 2011-04-18       stephan:   {  'n',  0, 0, etSIZE,       0,  0 },
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #else /* WHPRINTF_FMTINFO_FIXED */
fc60825290 2011-04-18       stephan:   /*
fc60825290 2011-04-18       stephan:     These entries MUST stay in ASCII order, sorted
fc60825290 2011-04-18       stephan:     on their fmttype member!
fc60825290 2011-04-18       stephan:   */
fc60825290 2011-04-18       stephan:   {' '/*32*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'!'/*33*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'"'/*34*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'#'/*35*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'$'/*36*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'%'/*37*/, 0, 0, etPERCENT, 0, 0 },
fc60825290 2011-04-18       stephan:   {'&'/*38*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'\''/*39*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'('/*40*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {')'/*41*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'*'/*42*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'+'/*43*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {','/*44*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'-'/*45*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'.'/*46*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'/'/*47*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'0'/*48*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'1'/*49*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'2'/*50*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'3'/*51*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'4'/*52*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'5'/*53*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'6'/*54*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'7'/*55*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'8'/*56*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'9'/*57*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {':'/*58*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {';'/*59*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'<'/*60*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'='/*61*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'>'/*62*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'?'/*63*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'@'/*64*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'A'/*65*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'B'/*66*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'C'/*67*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'D'/*68*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'E'/*69*/, 0, FLAG_SIGNED, etEXP, 14, 0 },
fc60825290 2011-04-18       stephan:   {'F'/*70*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'G'/*71*/, 0, FLAG_SIGNED, etGENERIC, 14, 0 },
fc60825290 2011-04-18       stephan:   {'H'/*72*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'I'/*73*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'J'/*74*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'K'/*75*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'L'/*76*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'M'/*77*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'N'/*78*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'O'/*79*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'P'/*80*/, 0, 0, 0, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #if WHPRINTF_OMIT_SQL
6e8c7e31b6 2011-04-20       stephan:   {'Q'/*81*/, 0, 0, 0, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #else
fc60825290 2011-04-18       stephan:   {'Q'/*81*/, 0, FLAG_STRING, etSQLESCAPE2, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan:   {'R'/*82*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'S'/*83*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'T'/*84*/,  0, FLAG_STRING, etURLDECODE, 0, 0 },
fc60825290 2011-04-18       stephan:   {'U'/*85*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'V'/*86*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'W'/*87*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'X'/*88*/, 16, 0, etRADIX,      0,  4 },
fc60825290 2011-04-18       stephan:   {'Y'/*89*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'Z'/*90*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'['/*91*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'\\'/*92*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {']'/*93*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'^'/*94*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'_'/*95*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'`'/*96*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'a'/*97*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'b'/*98*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'c'/*99*/, 0, 0, etCHARX,      0,  0 },
fc60825290 2011-04-18       stephan:   {'d'/*100*/, 10, FLAG_SIGNED, etRADIX,      0,  0 },
fc60825290 2011-04-18       stephan:   {'e'/*101*/, 0, FLAG_SIGNED, etEXP,        30, 0 },
fc60825290 2011-04-18       stephan:   {'f'/*102*/, 0, FLAG_SIGNED, etFLOAT,      0,  0},
fc60825290 2011-04-18       stephan:   {'g'/*103*/, 0, FLAG_SIGNED, etGENERIC,    30, 0 },
fc60825290 2011-04-18       stephan:   {'h'/*104*/, 0, FLAG_STRING, etHTML, 0, 0 },
fc60825290 2011-04-18       stephan:   {'i'/*105*/, 10, FLAG_SIGNED, etRADIX,      0,  0},
fc60825290 2011-04-18       stephan:   {'j'/*106*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'k'/*107*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'l'/*108*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'m'/*109*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'n'/*110*/, 0, 0, etSIZE, 0, 0 },
fc60825290 2011-04-18       stephan:   {'o'/*111*/, 8, 0, etRADIX,      0,  2 },
fc60825290 2011-04-18       stephan:   {'p'/*112*/, 16, 0, etPOINTER, 0, 1 },
6e8c7e31b6 2011-04-20       stephan: #if WHPRINTF_OMIT_SQL
6e8c7e31b6 2011-04-20       stephan:   {'q'/*113*/, 0, 0, 0, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #else
fc60825290 2011-04-18       stephan:   {'q'/*113*/, 0, FLAG_STRING, etSQLESCAPE,  0, 0 },
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan:   {'r'/*114*/, 10, (FLAG_EXTENDED|FLAG_SIGNED), etORDINAL,    0,  0},
fc60825290 2011-04-18       stephan:   {'s'/*115*/, 0, FLAG_STRING, etSTRING,     0,  0 },
fc60825290 2011-04-18       stephan:   {'t'/*116*/,  0, FLAG_STRING, etURLENCODE, 0, 0 },
fc60825290 2011-04-18       stephan:   {'u'/*117*/, 10, 0, etRADIX,      0,  0 },
fc60825290 2011-04-18       stephan:   {'v'/*118*/, 0, 0, 0, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #if WHPRINTF_OMIT_SQL
6e8c7e31b6 2011-04-20       stephan:   {'w'/*119*/, 0, 0, 0, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #else
fc60825290 2011-04-18       stephan:   {'w'/*119*/, 0, FLAG_STRING, etSQLESCAPE3, 0, 0 },
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan:   {'x'/*120*/, 16, 0, etRADIX,      16, 1  },
fc60825290 2011-04-18       stephan:   {'y'/*121*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'z'/*122*/, 0, FLAG_STRING, etDYNSTRING,  0,  0},
fc60825290 2011-04-18       stephan:   {'{'/*123*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'|'/*124*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'}'/*125*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan:   {'~'/*126*/, 0, 0, 0, 0, 0 },
fc60825290 2011-04-18       stephan: #endif /* WHPRINTF_FMTINFO_FIXED */
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: #define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    "*val" is a double such that 0.1 <= *val < 10.0
fc60825290 2011-04-18       stephan:    Return the ascii code for the leading digit of *val, then
fc60825290 2011-04-18       stephan:    multiply "*val" by 10.0 to renormalize.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan:    Example:
fc60825290 2011-04-18       stephan:        input:     *val = 3.14159
fc60825290 2011-04-18       stephan:        output:    *val = 1.4159    function return = '3'
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan:    The counter *cnt is incremented each time.  After counter exceeds
fc60825290 2011-04-18       stephan:    16 (the number of significant digits in a 64-bit float) '0' is
fc60825290 2011-04-18       stephan:    always returned.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
fc60825290 2011-04-18       stephan:   int digit;
fc60825290 2011-04-18       stephan:   LONGDOUBLE_TYPE d;
fc60825290 2011-04-18       stephan:   if( (*cnt)++ >= 16 ) return '0';
fc60825290 2011-04-18       stephan:   digit = (int)*val;
fc60825290 2011-04-18       stephan:   d = digit;
fc60825290 2011-04-18       stephan:   digit += '0';
fc60825290 2011-04-18       stephan:   *val = (*val - d)*10.0;
fc60825290 2011-04-18       stephan:   return digit;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_FLOATING_POINT */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    On machines with a small(?) stack size, you can redefine the
fc60825290 2011-04-18       stephan:    WHPRINTF_BUF_SIZE to be less than 350.  But beware - for smaller
fc60825290 2011-04-18       stephan:    values some %f conversions may go into an infinite loop.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #ifndef WHPRINTF_BUF_SIZE
fc60825290 2011-04-18       stephan: #  define WHPRINTF_BUF_SIZE 350  /* Size of the output buffer for numeric conversions */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if ! defined(__STDC__) && !defined(__TINYC__)
fc60825290 2011-04-18       stephan: #ifdef WHPRINTF_INT64_TYPE
fc60825290 2011-04-18       stephan:   typedef WHPRINTF_INT64_TYPE int64_t;
fc60825290 2011-04-18       stephan:   typedef unsigned WHPRINTF_INT64_TYPE uint64_t;
fc60825290 2011-04-18       stephan: #elif defined(_MSC_VER) || defined(__BORLANDC__)
fc60825290 2011-04-18       stephan:   typedef __int64 int64_t;
fc60825290 2011-04-18       stephan:   typedef unsigned __int64 uint64_t;
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:   typedef long long int int64_t;
fc60825290 2011-04-18       stephan:   typedef unsigned long long int uint64_t;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan: /   Not yet used. */
fc60825290 2011-04-18       stephan: enum PrintfArgTypes {
fc60825290 2011-04-18       stephan: TypeInt = 0,
fc60825290 2011-04-18       stephan: TypeIntP = 1,
fc60825290 2011-04-18       stephan: TypeFloat = 2,
fc60825290 2011-04-18       stephan: TypeFloatP = 3,
fc60825290 2011-04-18       stephan: TypeCString = 4
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan: /   Not yet used. */
fc60825290 2011-04-18       stephan: typedef struct whprintf_spec_handler_def
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	char letter; /   e.g. %s */
fc60825290 2011-04-18       stephan: 	int xtype; /* reference to the etXXXX values, or fmtinfo[*].type. */
fc60825290 2011-04-18       stephan: 	int ntype; /* reference to PrintfArgTypes enum. */
fc60825290 2011-04-18       stephan: } spec_handler;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    whprintf_spec_handler is an almost-generic interface for farming
fc60825290 2011-04-18       stephan:    work out of whprintfv()'s code into external functions.  It doesn't
fc60825290 2011-04-18       stephan:    actually save much (if any) overall code, but it makes the whprintfv()
fc60825290 2011-04-18       stephan:    code more manageable.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    REQUIREMENTS of implementations:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - Expects an implementation-specific vargp pointer.
fc60825290 2011-04-18       stephan:    whprintfv() passes a pointer to the converted value of
fc60825290 2011-04-18       stephan:    an entry from the format va_list. If it passes a type
fc60825290 2011-04-18       stephan:    other than the expected one, undefined results.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - If it calls pf then it must return the return value
fc60825290 2011-04-18       stephan:    from that function.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - If it calls pf it must do: pf( pfArg, D, N ), where D is
fc60825290 2011-04-18       stephan:    the data to export and N is the number of bytes to export.
fc60825290 2011-04-18       stephan:    It may call pf() an arbitrary number of times
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - If pf() successfully is called, the return value must be the
fc60825290 2011-04-18       stephan:    accumulated totals of its return value(s), plus (possibly, but
fc60825290 2011-04-18       stephan:    unlikely) an imnplementation-specific amount.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - If it does not call pf() then it must return 0 (success)
fc60825290 2011-04-18       stephan:    or a negative number (an error) or do all of the export
fc60825290 2011-04-18       stephan:    processing itself and return the number of bytes exported.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    SIGNIFICANT LIMITATIONS:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    - Has no way of iterating over the format string,
fc60825290 2011-04-18       stephan:    so handling precisions and such here can't work too
fc60825290 2011-04-18       stephan:    well.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef long (*whprintf_spec_handler)( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 				       void * pfArg,
fc60825290 2011-04-18       stephan: 				       void * vargp );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:   whprintf_spec_handler for etSTRING types. It assumes that varg is a
fc60825290 2011-04-18       stephan:   null-terminated (char [const] *)
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static long spech_string( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 			  void * pfArg,
fc60825290 2011-04-18       stephan: 			  void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	char const * ch = (char const *) varg;
fc60825290 2011-04-18       stephan: 	return ch ? pf( pfArg, ch, strlen(ch) ) : 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:   whprintf_spec_handler for etDYNSTRING types.  It assumes that varg
fc60825290 2011-04-18       stephan:   is a non-const (char *). It behaves identically to spec_string() and
fc60825290 2011-04-18       stephan:   then calls free() on that (char *).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static long spech_dynstring( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 			     void * pfArg,
fc60825290 2011-04-18       stephan: 			     void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:   long ret = spech_string( pf, pfArg, varg );
fc60825290 2011-04-18       stephan:   free( (char *) varg );
fc60825290 2011-04-18       stephan:   return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan: static long spech_string_to_html( whprintf_appender pf,
fc60825290 2011-04-18       stephan:                                   void * pfArg,
fc60825290 2011-04-18       stephan:                                   void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     char const * ch = (char const *) varg;
fc60825290 2011-04-18       stephan:     long ret = 0;
fc60825290 2011-04-18       stephan:     if( ! ch ) return 0;
fc60825290 2011-04-18       stephan:     ret = 0;
fc60825290 2011-04-18       stephan:     for( ; *ch; ++ch )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         switch( *ch )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:           case '<': ret += pf( pfArg, "&lt;", 4 );
fc60825290 2011-04-18       stephan:               break;
fc60825290 2011-04-18       stephan:           case '&': ret += pf( pfArg, "&amp;", 5 );
fc60825290 2011-04-18       stephan:               break;
fc60825290 2011-04-18       stephan:           default:
fc60825290 2011-04-18       stephan:               ret += pf( pfArg, ch, 1 );
fc60825290 2011-04-18       stephan:               break;
fc60825290 2011-04-18       stephan:         };
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int httpurl_needs_escape( int c )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /*
fc60825290 2011-04-18       stephan:       Definition of "safe" and "unsafe" chars
fc60825290 2011-04-18       stephan:       was taken from:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:       http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4029/
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     return ( (c >= 32 && c <=47)
fc60825290 2011-04-18       stephan:              || ( c>=58 && c<=64)
fc60825290 2011-04-18       stephan:              || ( c>=91 && c<=96)
fc60825290 2011-04-18       stephan:              || ( c>=123 && c<=126)
fc60825290 2011-04-18       stephan:              || ( c<32 || c>=127)
fc60825290 2011-04-18       stephan:              );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    The handler for the etURLENCODE specifier.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    It expects varg to be a string value, which it will preceed to
fc60825290 2011-04-18       stephan:    encode using an URL encoding algothrim (certain characters are
fc60825290 2011-04-18       stephan:    converted to %XX, where XX is their hex value) and passes the
fc60825290 2011-04-18       stephan:    encoded string to pf(). It returns the total length of the output
fc60825290 2011-04-18       stephan:    string.
fc60825290 2011-04-18       stephan:  */
fc60825290 2011-04-18       stephan: static long spech_urlencode( whprintf_appender pf,
fc60825290 2011-04-18       stephan:                              void * pfArg,
fc60825290 2011-04-18       stephan:                              void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     char const * str = (char const *) varg;
fc60825290 2011-04-18       stephan:     long ret = 0;
fc60825290 2011-04-18       stephan:     char ch = 0;
fc60825290 2011-04-18       stephan:     char const * hex = "0123456789ABCDEF";
fc60825290 2011-04-18       stephan: #define xbufsz 10
fc60825290 2011-04-18       stephan:     char xbuf[xbufsz];
fc60825290 2011-04-18       stephan:     int slen = 0;
fc60825290 2011-04-18       stephan:     if( ! str ) return 0;
fc60825290 2011-04-18       stephan:     memset( xbuf, 0, xbufsz );
fc60825290 2011-04-18       stephan:     ch = *str;
fc60825290 2011-04-18       stephan: #define xbufsz 10
fc60825290 2011-04-18       stephan:     slen = 0;
fc60825290 2011-04-18       stephan:     for( ; ch; ch = *(++str) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( ! httpurl_needs_escape( ch ) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             ret += pf( pfArg, str, 1 );
fc60825290 2011-04-18       stephan:             continue;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else {
6e8c7e31b6 2011-04-20       stephan:             xbuf[0] = '%';
6e8c7e31b6 2011-04-20       stephan:             xbuf[1] = hex[((ch>>4)&0xf)];
6e8c7e31b6 2011-04-20       stephan:             xbuf[2] = hex[(ch&0xf)];
6e8c7e31b6 2011-04-20       stephan:             xbuf[3] = 0;
6e8c7e31b6 2011-04-20       stephan:             slen = 3;
fc60825290 2011-04-18       stephan:             ret += pf( pfArg, xbuf, slen );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #undef xbufsz
fc60825290 2011-04-18       stephan:     return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    hexchar_to_int():
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    For 'a'-'f', 'A'-'F' and '0'-'9', returns the appropriate decimal
fc60825290 2011-04-18       stephan:    number.  For any other character it returns -1.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan: static int hexchar_to_int( int ch )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( (ch>='a' && ch<='f') ) return ch-'a'+10;
fc60825290 2011-04-18       stephan:     else if( (ch>='A' && ch<='F') ) return ch-'A'+10;
fc60825290 2011-04-18       stephan:     else if( (ch>='0' && ch<='9') ) return ch-'0';
fc60825290 2011-04-18       stephan:     return -1;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    The handler for the etURLDECODE specifier.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    It expects varg to be a ([const] char *), possibly encoded
fc60825290 2011-04-18       stephan:    with URL encoding. It decodes the string using a URL decode
fc60825290 2011-04-18       stephan:    algorithm and passes the decoded string to
fc60825290 2011-04-18       stephan:    pf(). It returns the total length of the output string.
fc60825290 2011-04-18       stephan:    If the input string contains malformed %XX codes then this
fc60825290 2011-04-18       stephan:    function will return prematurely.
fc60825290 2011-04-18       stephan:  */
fc60825290 2011-04-18       stephan: static long spech_urldecode( whprintf_appender pf,
fc60825290 2011-04-18       stephan:                              void * pfArg,
fc60825290 2011-04-18       stephan:                              void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     char const * str = (char const *) varg;
fc60825290 2011-04-18       stephan:     long ret = 0;
fc60825290 2011-04-18       stephan:     char ch = 0;
fc60825290 2011-04-18       stephan:     char ch2 = 0;
fc60825290 2011-04-18       stephan:     char xbuf[4];
fc60825290 2011-04-18       stephan:     int decoded;
6e8c7e31b6 2011-04-20       stephan:     if( ! str ) return 0;
fc60825290 2011-04-18       stephan:     ch = *str;
fc60825290 2011-04-18       stephan:     while( ch )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( ch == '%' )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             ch = *(++str);
fc60825290 2011-04-18       stephan:             ch2 = *(++str);
fc60825290 2011-04-18       stephan:             if( isxdigit(ch) &&
fc60825290 2011-04-18       stephan:                 isxdigit(ch2) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 decoded = (hexchar_to_int( ch ) * 16)
fc60825290 2011-04-18       stephan:                     + hexchar_to_int( ch2 );
fc60825290 2011-04-18       stephan:                 xbuf[0] = (char)decoded;
fc60825290 2011-04-18       stephan:                 xbuf[1] = 0;
fc60825290 2011-04-18       stephan:                 ret += pf( pfArg, xbuf, 1 );
fc60825290 2011-04-18       stephan:                 ch = *(++str);
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 xbuf[0] = '%';
fc60825290 2011-04-18       stephan:                 xbuf[1] = ch;
fc60825290 2011-04-18       stephan:                 xbuf[2] = ch2;
fc60825290 2011-04-18       stephan:                 xbuf[3] = 0;
fc60825290 2011-04-18       stephan:                 ret += pf( pfArg, xbuf, 3 );
fc60825290 2011-04-18       stephan:                 ch = *(++str);
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else if( ch == '+' )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             xbuf[0] = ' ';
fc60825290 2011-04-18       stephan:             xbuf[1] = 0;
fc60825290 2011-04-18       stephan:             ret += pf( pfArg, xbuf, 1 );
fc60825290 2011-04-18       stephan:             ch = *(++str);
fc60825290 2011-04-18       stephan:             continue;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         xbuf[0] = ch;
fc60825290 2011-04-18       stephan:         xbuf[1] = 0;
fc60825290 2011-04-18       stephan:         ret += pf( pfArg, xbuf, 1 );
fc60825290 2011-04-18       stephan:         ch = *(++str);
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_HTML */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_SQL
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Quotes the (char *) varg as an SQL string 'should'
fc60825290 2011-04-18       stephan:    be quoted. The exact type of the conversion
fc60825290 2011-04-18       stephan:    is specified by xtype, which must be one of
fc60825290 2011-04-18       stephan:    etSQLESCAPE, etSQLESCAPE2, or etSQLESCAPE3.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Search this file for those constants to find
fc60825290 2011-04-18       stephan:    the associated documentation.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static long spech_sqlstring_main( int xtype,
fc60825290 2011-04-18       stephan: 				  whprintf_appender pf,
fc60825290 2011-04-18       stephan: 				  void * pfArg,
fc60825290 2011-04-18       stephan: 				  void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:         int i, j, n, ch, isnull;
fc60825290 2011-04-18       stephan:         int needQuote;
fc60825290 2011-04-18       stephan:         char q = ((xtype==etSQLESCAPE3)?'"':'\'');   /* Quote character */
fc60825290 2011-04-18       stephan:         char const * escarg = (char const *) varg;
6e8c7e31b6 2011-04-20       stephan: 	char * bufpt = NULL;
6e8c7e31b6 2011-04-20       stephan:         long ret;
fc60825290 2011-04-18       stephan:         isnull = escarg==0;
fc60825290 2011-04-18       stephan:         if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
fc60825290 2011-04-18       stephan:         for(i=n=0; (ch=escarg[i])!=0; i++){
fc60825290 2011-04-18       stephan:           if( ch==q )  n++;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         needQuote = !isnull && xtype==etSQLESCAPE2;
fc60825290 2011-04-18       stephan:         n += i + 1 + needQuote*2;
6e8c7e31b6 2011-04-20       stephan: 	/* FIXME: use a static buffer here instead of malloc()! Shame on you! */
fc60825290 2011-04-18       stephan: 	bufpt = (char *)malloc( n );
fc60825290 2011-04-18       stephan: 	if( ! bufpt ) return -1;
fc60825290 2011-04-18       stephan:         j = 0;
fc60825290 2011-04-18       stephan:         if( needQuote ) bufpt[j++] = q;
fc60825290 2011-04-18       stephan:         for(i=0; (ch=escarg[i])!=0; i++){
fc60825290 2011-04-18       stephan:           bufpt[j++] = ch;
fc60825290 2011-04-18       stephan:           if( ch==q ) bufpt[j++] = ch;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( needQuote ) bufpt[j++] = q;
fc60825290 2011-04-18       stephan:         bufpt[j] = 0;
6e8c7e31b6 2011-04-20       stephan: 	ret = pf( pfArg, bufpt, j );
fc60825290 2011-04-18       stephan: 	free( bufpt );
fc60825290 2011-04-18       stephan: 	return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static long spech_sqlstring1( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 			      void * pfArg,
fc60825290 2011-04-18       stephan: 			      void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	return spech_sqlstring_main( etSQLESCAPE, pf, pfArg, varg );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static long spech_sqlstring2( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 			      void * pfArg,
fc60825290 2011-04-18       stephan: 			      void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	return spech_sqlstring_main( etSQLESCAPE2, pf, pfArg, varg );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static long spech_sqlstring3( whprintf_appender pf,
fc60825290 2011-04-18       stephan: 			      void * pfArg,
fc60825290 2011-04-18       stephan: 			      void * varg )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	return spech_sqlstring_main( etSQLESCAPE3, pf, pfArg, varg );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_SQL */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:    The root printf program.  All variations call this core.  It
fc60825290 2011-04-18       stephan:    implements most of the common printf behaviours plus (optionally)
fc60825290 2011-04-18       stephan:    some extended ones.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    INPUTS:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:      pfAppend : The is a whprintf_appender function which is responsible
fc60825290 2011-04-18       stephan:      for accumulating the output. If pfAppend returns a negative integer
fc60825290 2011-04-18       stephan:      then processing stops immediately.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:      pfAppendArg : is ignored by this function but passed as the first
fc60825290 2011-04-18       stephan:      argument to pfAppend. pfAppend will presumably use it as a data
fc60825290 2011-04-18       stephan:      store for accumulating its string.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:      fmt : This is the format string, as in the usual printf().
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:      ap : This is a pointer to a list of arguments.  Same as in
fc60825290 2011-04-18       stephan:      vprintf() and friends.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    OUTPUTS:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    The return value is the total number of characters sent to the
fc60825290 2011-04-18       stephan:    function "func".  Returns -1 on a error.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Note that the order in which automatic variables are declared below
fc60825290 2011-04-18       stephan:    seems to make a big difference in determining how fast this beast
fc60825290 2011-04-18       stephan:    will run.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Much of this code dates back to the early 1980's, supposedly.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Known change history (most historic info has been lost):
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    10 Feb 2008 by Stephan Beal: refactored to remove the 'useExtended'
fc60825290 2011-04-18       stephan:    flag (which is now always on). Added the whprintf_appender typedef to
fc60825290 2011-04-18       stephan:    make this function generic enough to drop into other source trees
fc60825290 2011-04-18       stephan:    without much work.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    31 Oct 2008 by Stephan Beal: refactored the et_info lookup to be
fc60825290 2011-04-18       stephan:    constant-time instead of linear.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: long whprintfv(
fc60825290 2011-04-18       stephan:   whprintf_appender pfAppend,          /* Accumulate results here */
fc60825290 2011-04-18       stephan:   void * pfAppendArg,                /* Passed as first arg to pfAppend. */
fc60825290 2011-04-18       stephan:   const char *fmt,                   /* Format string */
fc60825290 2011-04-18       stephan:   va_list ap                         /* arguments */
fc60825290 2011-04-18       stephan: ){
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        HISTORIC NOTE (author and year unknown):
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        Note that the order in which automatic variables are declared below
fc60825290 2011-04-18       stephan:        seems to make a big difference in determining how fast this beast
fc60825290 2011-04-18       stephan:        will run.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if WHPRINTF_FMTINFO_FIXED
fc60825290 2011-04-18       stephan:   const int useExtended = 1; /* Allow extended %-conversions */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:   long outCount = 0;          /* accumulated output count */
fc60825290 2011-04-18       stephan:   int pfrc = 0;              /* result from calling pfAppend */
fc60825290 2011-04-18       stephan:   int c;                     /* Next character in the format string */
fc60825290 2011-04-18       stephan:   char *bufpt = 0;           /* Pointer to the conversion buffer */
fc60825290 2011-04-18       stephan:   int precision;             /* Precision of the current field */
fc60825290 2011-04-18       stephan:   int length;                /* Length of the field */
fc60825290 2011-04-18       stephan:   int idx;                   /* A general purpose loop counter */
fc60825290 2011-04-18       stephan:   int width;                 /* Width of the current field */
fc60825290 2011-04-18       stephan:   etByte flag_leftjustify;   /* True if "-" flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_plussign;      /* True if "+" flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_blanksign;     /* True if " " flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_alternateform; /* True if "#" flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_altform2;      /* True if "!" flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_zeropad;       /* True if field width constant starts with zero */
fc60825290 2011-04-18       stephan:   etByte flag_long;          /* True if "l" flag is present */
fc60825290 2011-04-18       stephan:   etByte flag_longlong;      /* True if the "ll" flag is present */
fc60825290 2011-04-18       stephan:   etByte done;               /* Loop termination flag */
fc60825290 2011-04-18       stephan:   uint64_t longvalue;   /* Value for integer types */
fc60825290 2011-04-18       stephan:   LONGDOUBLE_TYPE realvalue; /* Value for real types */
fc60825290 2011-04-18       stephan:   const et_info *infop = 0;      /* Pointer to the appropriate info structure */
fc60825290 2011-04-18       stephan:   char buf[WHPRINTF_BUF_SIZE];       /* Conversion buffer */
fc60825290 2011-04-18       stephan:   char prefix;               /* Prefix character.  "+" or "-" or " " or '\0'. */
fc60825290 2011-04-18       stephan:   etByte errorflag = 0;      /* True if an error is encountered */
fc60825290 2011-04-18       stephan:   etByte xtype = 0;              /* Conversion paradigm */
fc60825290 2011-04-18       stephan:   char * zExtra = 0;              /* Extra memory used for etTCLESCAPE conversions */
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan:   int  exp, e2;              /* exponent of real numbers */
fc60825290 2011-04-18       stephan:   double rounder;            /* Used for rounding floating point values */
fc60825290 2011-04-18       stephan:   etByte flag_dp;            /* True if decimal point should be shown */
fc60825290 2011-04-18       stephan:   etByte flag_rtz;           /* True if trailing zeros should be removed */
fc60825290 2011-04-18       stephan:   etByte flag_exp;           /* True to force display of the exponent */
fc60825290 2011-04-18       stephan:   int nsd;                   /* Number of significant digits returned */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   /* WHPRINTF_RETURN, WHPRINTF_CHECKERR, and WHPRINTF_SPACES
fc60825290 2011-04-18       stephan:      are internal helpers.
fc60825290 2011-04-18       stephan:   */
fc60825290 2011-04-18       stephan: #define WHPRINTF_RETURN if( zExtra ) free(zExtra); return outCount;
fc60825290 2011-04-18       stephan: #define WHPRINTF_CHECKERR(FREEME) if( pfrc<0 ) { WHPRINTF_CHARARRAY_FREE(FREEME); WHPRINTF_RETURN; } else outCount += pfrc;
fc60825290 2011-04-18       stephan: #define WHPRINTF_SPACES(N) \
fc60825290 2011-04-18       stephan: if(1){				       \
fc60825290 2011-04-18       stephan:     WHPRINTF_CHARARRAY(zSpaces,N);		      \
fc60825290 2011-04-18       stephan:     memset( zSpaces,' ',N);			      \
fc60825290 2011-04-18       stephan:     pfrc = pfAppend(pfAppendArg, zSpaces, N);	      \
fc60825290 2011-04-18       stephan:     WHPRINTF_CHECKERR(zSpaces);			      \
fc60825290 2011-04-18       stephan:     WHPRINTF_CHARARRAY_FREE(zSpaces);		      \
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   length = 0;
fc60825290 2011-04-18       stephan:   bufpt = 0;
fc60825290 2011-04-18       stephan:   for(; (c=(*fmt))!=0; ++fmt){
fc60825290 2011-04-18       stephan:     if( c!='%' ){
fc60825290 2011-04-18       stephan:       int amt;
fc60825290 2011-04-18       stephan:       bufpt = (char *)fmt;
fc60825290 2011-04-18       stephan:       amt = 1;
fc60825290 2011-04-18       stephan:       while( (c=(*++fmt))!='%' && c!=0 ) amt++;
fc60825290 2011-04-18       stephan:       pfrc = pfAppend( pfAppendArg, bufpt, amt);
fc60825290 2011-04-18       stephan:       WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan:       if( c==0 ) break;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( (c=(*++fmt))==0 ){
fc60825290 2011-04-18       stephan:       errorflag = 1;
fc60825290 2011-04-18       stephan:       pfrc = pfAppend( pfAppendArg, "%", 1);
fc60825290 2011-04-18       stephan:       WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan:       break;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* Find out what flags are present */
fc60825290 2011-04-18       stephan:     flag_leftjustify = flag_plussign = flag_blanksign =
fc60825290 2011-04-18       stephan:      flag_alternateform = flag_altform2 = flag_zeropad = 0;
fc60825290 2011-04-18       stephan:     done = 0;
fc60825290 2011-04-18       stephan:     do{
fc60825290 2011-04-18       stephan:       switch( c ){
fc60825290 2011-04-18       stephan:         case '-':   flag_leftjustify = 1;     break;
fc60825290 2011-04-18       stephan:         case '+':   flag_plussign = 1;        break;
fc60825290 2011-04-18       stephan:         case ' ':   flag_blanksign = 1;       break;
fc60825290 2011-04-18       stephan:         case '#':   flag_alternateform = 1;   break;
fc60825290 2011-04-18       stephan:         case '!':   flag_altform2 = 1;        break;
fc60825290 2011-04-18       stephan:         case '0':   flag_zeropad = 1;         break;
fc60825290 2011-04-18       stephan:         default:    done = 1;                 break;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }while( !done && (c=(*++fmt))!=0 );
fc60825290 2011-04-18       stephan:     /* Get the field width */
fc60825290 2011-04-18       stephan:     width = 0;
fc60825290 2011-04-18       stephan:     if( c=='*' ){
fc60825290 2011-04-18       stephan:       width = va_arg(ap,int);
fc60825290 2011-04-18       stephan:       if( width<0 ){
fc60825290 2011-04-18       stephan:         flag_leftjustify = 1;
fc60825290 2011-04-18       stephan:         width = -width;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       c = *++fmt;
fc60825290 2011-04-18       stephan:     }else{
fc60825290 2011-04-18       stephan:       while( c>='0' && c<='9' ){
fc60825290 2011-04-18       stephan:         width = width*10 + c - '0';
fc60825290 2011-04-18       stephan:         c = *++fmt;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( width > WHPRINTF_BUF_SIZE-10 ){
fc60825290 2011-04-18       stephan:       width = WHPRINTF_BUF_SIZE-10;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* Get the precision */
fc60825290 2011-04-18       stephan:     if( c=='.' ){
fc60825290 2011-04-18       stephan:       precision = 0;
fc60825290 2011-04-18       stephan:       c = *++fmt;
fc60825290 2011-04-18       stephan:       if( c=='*' ){
fc60825290 2011-04-18       stephan:         precision = va_arg(ap,int);
fc60825290 2011-04-18       stephan:         if( precision<0 ) precision = -precision;
fc60825290 2011-04-18       stephan:         c = *++fmt;
fc60825290 2011-04-18       stephan:       }else{
fc60825290 2011-04-18       stephan:         while( c>='0' && c<='9' ){
fc60825290 2011-04-18       stephan:           precision = precision*10 + c - '0';
fc60825290 2011-04-18       stephan:           c = *++fmt;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }else{
fc60825290 2011-04-18       stephan:       precision = -1;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* Get the conversion type modifier */
fc60825290 2011-04-18       stephan:     if( c=='l' ){
fc60825290 2011-04-18       stephan:       flag_long = 1;
fc60825290 2011-04-18       stephan:       c = *++fmt;
fc60825290 2011-04-18       stephan:       if( c=='l' ){
fc60825290 2011-04-18       stephan:         flag_longlong = 1;
fc60825290 2011-04-18       stephan:         c = *++fmt;
fc60825290 2011-04-18       stephan:       }else{
fc60825290 2011-04-18       stephan:         flag_longlong = 0;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }else{
fc60825290 2011-04-18       stephan:       flag_long = flag_longlong = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* Fetch the info entry for the field */
fc60825290 2011-04-18       stephan:     infop = 0;
fc60825290 2011-04-18       stephan: #if WHPRINTF_FMTINFO_FIXED
fc60825290 2011-04-18       stephan:     for(idx=0; idx<etNINFO; idx++){
fc60825290 2011-04-18       stephan:       if( c==fmtinfo[idx].fmttype ){
fc60825290 2011-04-18       stephan:         infop = &fmtinfo[idx];
fc60825290 2011-04-18       stephan:         if( useExtended || (infop->flags & FLAG_EXTENDED)==0 ){
fc60825290 2011-04-18       stephan:           xtype = infop->type;
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan: 	    WHPRINTF_RETURN;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #define FMTNDX(N) (N - fmtinfo[0].fmttype)
fc60825290 2011-04-18       stephan: #define FMTINFO(N) (fmtinfo[ FMTNDX(N) ])
fc60825290 2011-04-18       stephan:     infop = ((c>=(fmtinfo[0].fmttype)) && (c<fmtinfo[etNINFO-1].fmttype))
fc60825290 2011-04-18       stephan: 	? &FMTINFO(c)
fc60825290 2011-04-18       stephan: 	: 0;
6e8c7e31b6 2011-04-20       stephan:     /*fprintf(stderr,"char '%c'/%d @ %d,  type=%c/%d\n",c,c,FMTNDX(c),infop->fmttype,infop->type);*/
fc60825290 2011-04-18       stephan:     if( infop ) xtype = infop->type;
fc60825290 2011-04-18       stephan: #undef FMTINFO
fc60825290 2011-04-18       stephan: #undef FMTNDX
fc60825290 2011-04-18       stephan: #endif /* WHPRINTF_FMTINFO_FIXED */
fc60825290 2011-04-18       stephan:     zExtra = 0;
fc60825290 2011-04-18       stephan:     if( (!infop) || (!infop->type) ){
fc60825290 2011-04-18       stephan: 	WHPRINTF_RETURN;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     /* Limit the precision to prevent overflowing buf[] during conversion */
fc60825290 2011-04-18       stephan:     if( precision>WHPRINTF_BUF_SIZE-40 && (infop->flags & FLAG_STRING)==0 ){
fc60825290 2011-04-18       stephan:       precision = WHPRINTF_BUF_SIZE-40;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     /*
fc60825290 2011-04-18       stephan:        At this point, variables are initialized as follows:
fc60825290 2011-04-18       stephan:     **
fc60825290 2011-04-18       stephan:          flag_alternateform          TRUE if a '#' is present.
fc60825290 2011-04-18       stephan:          flag_altform2               TRUE if a '!' is present.
fc60825290 2011-04-18       stephan:          flag_plussign               TRUE if a '+' is present.
fc60825290 2011-04-18       stephan:          flag_leftjustify            TRUE if a '-' is present or if the
fc60825290 2011-04-18       stephan:                                      field width was negative.
fc60825290 2011-04-18       stephan:          flag_zeropad                TRUE if the width began with 0.
fc60825290 2011-04-18       stephan:          flag_long                   TRUE if the letter 'l' (ell) prefixed
fc60825290 2011-04-18       stephan:                                      the conversion character.
fc60825290 2011-04-18       stephan:          flag_longlong               TRUE if the letter 'll' (ell ell) prefixed
fc60825290 2011-04-18       stephan:                                      the conversion character.
fc60825290 2011-04-18       stephan:          flag_blanksign              TRUE if a ' ' is present.
fc60825290 2011-04-18       stephan:          width                       The specified field width.  This is
fc60825290 2011-04-18       stephan:                                      always non-negative.  Zero is the default.
fc60825290 2011-04-18       stephan:          precision                   The specified precision.  The default
fc60825290 2011-04-18       stephan:                                      is -1.
fc60825290 2011-04-18       stephan:          xtype                       The class of the conversion.
fc60825290 2011-04-18       stephan:          infop                       Pointer to the appropriate info struct.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     switch( xtype ){
fc60825290 2011-04-18       stephan:       case etPOINTER:
fc60825290 2011-04-18       stephan:         flag_longlong = sizeof(char*)==sizeof(int64_t);
fc60825290 2011-04-18       stephan:         flag_long = sizeof(char*)==sizeof(long int);
fc60825290 2011-04-18       stephan:         /* Fall through into the next case */
fc60825290 2011-04-18       stephan:       case etORDINAL:
fc60825290 2011-04-18       stephan:       case etRADIX:
fc60825290 2011-04-18       stephan:         if( infop->flags & FLAG_SIGNED ){
fc60825290 2011-04-18       stephan:           int64_t v;
fc60825290 2011-04-18       stephan:           if( flag_longlong )   v = va_arg(ap,int64_t);
fc60825290 2011-04-18       stephan:           else if( flag_long )  v = va_arg(ap,long int);
fc60825290 2011-04-18       stephan:           else                  v = va_arg(ap,int);
fc60825290 2011-04-18       stephan:           if( v<0 ){
fc60825290 2011-04-18       stephan:             longvalue = -v;
fc60825290 2011-04-18       stephan:             prefix = '-';
fc60825290 2011-04-18       stephan:           }else{
fc60825290 2011-04-18       stephan:             longvalue = v;
fc60825290 2011-04-18       stephan:             if( flag_plussign )        prefix = '+';
fc60825290 2011-04-18       stephan:             else if( flag_blanksign )  prefix = ' ';
fc60825290 2011-04-18       stephan:             else                       prefix = 0;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           if( flag_longlong )   longvalue = va_arg(ap,uint64_t);
fc60825290 2011-04-18       stephan:           else if( flag_long )  longvalue = va_arg(ap,unsigned long int);
fc60825290 2011-04-18       stephan:           else                  longvalue = va_arg(ap,unsigned int);
fc60825290 2011-04-18       stephan:           prefix = 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( longvalue==0 ) flag_alternateform = 0;
fc60825290 2011-04-18       stephan:         if( flag_zeropad && precision<width-(prefix!=0) ){
fc60825290 2011-04-18       stephan:           precision = width-(prefix!=0);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         bufpt = &buf[WHPRINTF_BUF_SIZE-1];
fc60825290 2011-04-18       stephan:         if( xtype==etORDINAL ){
fc60825290 2011-04-18       stephan: 	    /** i sure would like to shake the hand of whoever figured this out: */
fc60825290 2011-04-18       stephan:           static const char zOrd[] = "thstndrd";
fc60825290 2011-04-18       stephan:           int x = longvalue % 10;
fc60825290 2011-04-18       stephan:           if( x>=4 || (longvalue/10)%10==1 ){
fc60825290 2011-04-18       stephan:             x = 0;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:           buf[WHPRINTF_BUF_SIZE-3] = zOrd[x*2];
fc60825290 2011-04-18       stephan:           buf[WHPRINTF_BUF_SIZE-2] = zOrd[x*2+1];
fc60825290 2011-04-18       stephan:           bufpt -= 2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:           const char *cset;
fc60825290 2011-04-18       stephan:           int base;
fc60825290 2011-04-18       stephan:           cset = &aDigits[infop->charset];
fc60825290 2011-04-18       stephan:           base = infop->base;
fc60825290 2011-04-18       stephan:           do{                                           /* Convert to ascii */
fc60825290 2011-04-18       stephan:             *(--bufpt) = cset[longvalue%base];
fc60825290 2011-04-18       stephan:             longvalue = longvalue/base;
fc60825290 2011-04-18       stephan:           }while( longvalue>0 );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         length = &buf[WHPRINTF_BUF_SIZE-1]-bufpt;
fc60825290 2011-04-18       stephan:         for(idx=precision-length; idx>0; idx--){
fc60825290 2011-04-18       stephan:           *(--bufpt) = '0';                             /* Zero pad */
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
fc60825290 2011-04-18       stephan:         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
fc60825290 2011-04-18       stephan:           const char *pre;
fc60825290 2011-04-18       stephan:           char x;
fc60825290 2011-04-18       stephan:           pre = &aPrefix[infop->prefix];
fc60825290 2011-04-18       stephan:           if( *bufpt!=pre[0] ){
fc60825290 2011-04-18       stephan:             for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         length = &buf[WHPRINTF_BUF_SIZE-1]-bufpt;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       case etFLOAT:
fc60825290 2011-04-18       stephan:       case etEXP:
fc60825290 2011-04-18       stephan:       case etGENERIC:
fc60825290 2011-04-18       stephan:         realvalue = va_arg(ap,double);
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan:         if( precision<0 ) precision = 6;         /* Set default precision */
fc60825290 2011-04-18       stephan:         if( precision>WHPRINTF_BUF_SIZE/2-10 ) precision = WHPRINTF_BUF_SIZE/2-10;
fc60825290 2011-04-18       stephan:         if( realvalue<0.0 ){
fc60825290 2011-04-18       stephan:           realvalue = -realvalue;
fc60825290 2011-04-18       stephan:           prefix = '-';
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           if( flag_plussign )          prefix = '+';
fc60825290 2011-04-18       stephan:           else if( flag_blanksign )    prefix = ' ';
fc60825290 2011-04-18       stephan:           else                         prefix = 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( xtype==etGENERIC && precision>0 ) precision--;
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:         /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
fc60825290 2011-04-18       stephan:         for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:         /* It makes more sense to use 0.5 */
fc60825290 2011-04-18       stephan:         for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         if( xtype==etFLOAT ) realvalue += rounder;
fc60825290 2011-04-18       stephan:         /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
fc60825290 2011-04-18       stephan:         exp = 0;
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan: 	if( (realvalue)!=(realvalue) ){
fc60825290 2011-04-18       stephan: 	    /* from sqlite3: #define sqlite3_isnan(X)  ((X)!=(X)) */
fc60825290 2011-04-18       stephan: 	    /* This weird array thing is to avoid constness violations
fc60825290 2011-04-18       stephan: 	       when assinging, e.g. "NaN" to bufpt.
fc60825290 2011-04-18       stephan: 	    */
fc60825290 2011-04-18       stephan: 	    static char NaN[4] = {'N','a','N','\0'};
fc60825290 2011-04-18       stephan: 	    bufpt = NaN;
fc60825290 2011-04-18       stephan:           length = 3;
fc60825290 2011-04-18       stephan:           break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         if( realvalue>0.0 ){
fc60825290 2011-04-18       stephan:           while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
fc60825290 2011-04-18       stephan:           while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
fc60825290 2011-04-18       stephan:           while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
fc60825290 2011-04-18       stephan:           while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
fc60825290 2011-04-18       stephan:           while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
fc60825290 2011-04-18       stephan:           if( exp>350 || exp<-350 ){
fc60825290 2011-04-18       stephan:             if( prefix=='-' ){
fc60825290 2011-04-18       stephan: 		static char Inf[5] = {'-','I','n','f','\0'};
fc60825290 2011-04-18       stephan: 		bufpt = Inf;
fc60825290 2011-04-18       stephan:             }else if( prefix=='+' ){
fc60825290 2011-04-18       stephan: 		static char Inf[5] = {'+','I','n','f','\0'};
fc60825290 2011-04-18       stephan: 		bufpt = Inf;
fc60825290 2011-04-18       stephan:             }else{
fc60825290 2011-04-18       stephan: 		static char Inf[4] = {'I','n','f','\0'};
fc60825290 2011-04-18       stephan: 		bufpt = Inf;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             length = strlen(bufpt);
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         bufpt = buf;
fc60825290 2011-04-18       stephan:         /*
fc60825290 2011-04-18       stephan:            If the field type is etGENERIC, then convert to either etEXP
fc60825290 2011-04-18       stephan:            or etFLOAT, as appropriate.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         flag_exp = xtype==etEXP;
fc60825290 2011-04-18       stephan:         if( xtype!=etFLOAT ){
fc60825290 2011-04-18       stephan:           realvalue += rounder;
fc60825290 2011-04-18       stephan:           if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( xtype==etGENERIC ){
fc60825290 2011-04-18       stephan:           flag_rtz = !flag_alternateform;
fc60825290 2011-04-18       stephan:           if( exp<-4 || exp>precision ){
fc60825290 2011-04-18       stephan:             xtype = etEXP;
fc60825290 2011-04-18       stephan:           }else{
fc60825290 2011-04-18       stephan:             precision = precision - exp;
fc60825290 2011-04-18       stephan:             xtype = etFLOAT;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           flag_rtz = 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( xtype==etEXP ){
fc60825290 2011-04-18       stephan:           e2 = 0;
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           e2 = exp;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         nsd = 0;
fc60825290 2011-04-18       stephan:         flag_dp = (precision>0) | flag_alternateform | flag_altform2;
fc60825290 2011-04-18       stephan:         /* The sign in front of the number */
fc60825290 2011-04-18       stephan:         if( prefix ){
fc60825290 2011-04-18       stephan:           *(bufpt++) = prefix;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* Digits prior to the decimal point */
fc60825290 2011-04-18       stephan:         if( e2<0 ){
fc60825290 2011-04-18       stephan:           *(bufpt++) = '0';
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           for(; e2>=0; e2--){
fc60825290 2011-04-18       stephan:             *(bufpt++) = et_getdigit(&realvalue,&nsd);
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* The decimal point */
fc60825290 2011-04-18       stephan:         if( flag_dp ){
fc60825290 2011-04-18       stephan:           *(bufpt++) = '.';
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* "0" digits after the decimal point but before the first
fc60825290 2011-04-18       stephan:            significant digit of the number */
fc60825290 2011-04-18       stephan:         for(e2++; e2<0 && precision>0; precision--, e2++){
fc60825290 2011-04-18       stephan:           *(bufpt++) = '0';
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* Significant digits after the decimal point */
fc60825290 2011-04-18       stephan:         while( (precision--)>0 ){
fc60825290 2011-04-18       stephan:           *(bufpt++) = et_getdigit(&realvalue,&nsd);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* Remove trailing zeros and the "." if no digits follow the "." */
fc60825290 2011-04-18       stephan:         if( flag_rtz && flag_dp ){
fc60825290 2011-04-18       stephan:           while( bufpt[-1]=='0' ) *(--bufpt) = 0;
fc60825290 2011-04-18       stephan:           /* assert( bufpt>buf ); */
fc60825290 2011-04-18       stephan:           if( bufpt[-1]=='.' ){
fc60825290 2011-04-18       stephan:             if( flag_altform2 ){
fc60825290 2011-04-18       stephan:               *(bufpt++) = '0';
fc60825290 2011-04-18       stephan:             }else{
fc60825290 2011-04-18       stephan:               *(--bufpt) = 0;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* Add the "eNNN" suffix */
fc60825290 2011-04-18       stephan:         if( flag_exp || (xtype==etEXP && exp) ){
fc60825290 2011-04-18       stephan:           *(bufpt++) = aDigits[infop->charset];
fc60825290 2011-04-18       stephan:           if( exp<0 ){
fc60825290 2011-04-18       stephan:             *(bufpt++) = '-'; exp = -exp;
fc60825290 2011-04-18       stephan:           }else{
fc60825290 2011-04-18       stephan:             *(bufpt++) = '+';
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:           if( exp>=100 ){
fc60825290 2011-04-18       stephan:             *(bufpt++) = (exp/100)+'0';                /* 100's digit */
fc60825290 2011-04-18       stephan:             exp %= 100;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:           *(bufpt++) = exp/10+'0';                     /* 10's digit */
fc60825290 2011-04-18       stephan:           *(bufpt++) = exp%10+'0';                     /* 1's digit */
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         *bufpt = 0;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         /* The converted number is in buf[] and zero terminated. Output it.
fc60825290 2011-04-18       stephan:            Note that the number is in the usual order, not reversed as with
fc60825290 2011-04-18       stephan:            integer conversions. */
fc60825290 2011-04-18       stephan:         length = bufpt-buf;
fc60825290 2011-04-18       stephan:         bufpt = buf;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         /* Special case:  Add leading zeros if the flag_zeropad flag is
fc60825290 2011-04-18       stephan:            set and we are not left justified */
fc60825290 2011-04-18       stephan:         if( flag_zeropad && !flag_leftjustify && length < width){
fc60825290 2011-04-18       stephan:           int i;
fc60825290 2011-04-18       stephan:           int nPad = width - length;
fc60825290 2011-04-18       stephan:           for(i=width; i>=nPad; i--){
fc60825290 2011-04-18       stephan:             bufpt[i] = bufpt[i-nPad];
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:           i = prefix!=0;
fc60825290 2011-04-18       stephan:           while( nPad-- ) bufpt[i++] = '0';
fc60825290 2011-04-18       stephan:           length = width;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_FLOATING_POINT */
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan: #if !WHPRINTF_OMIT_SIZE
fc60825290 2011-04-18       stephan:       case etSIZE:
fc60825290 2011-04-18       stephan:         *(va_arg(ap,int*)) = outCount;
fc60825290 2011-04-18       stephan:         length = width = 0;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:       case etPERCENT:
fc60825290 2011-04-18       stephan:         buf[0] = '%';
fc60825290 2011-04-18       stephan:         bufpt = buf;
fc60825290 2011-04-18       stephan:         length = 1;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       case etCHARLIT:
fc60825290 2011-04-18       stephan:       case etCHARX:
fc60825290 2011-04-18       stephan:         c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
fc60825290 2011-04-18       stephan:         if( precision>=0 ){
fc60825290 2011-04-18       stephan:           for(idx=1; idx<precision; idx++) buf[idx] = c;
fc60825290 2011-04-18       stephan:           length = precision;
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           length =1;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         bufpt = buf;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       case etSTRING:
fc60825290 2011-04-18       stephan:       case etDYNSTRING: {
fc60825290 2011-04-18       stephan: 	  whprintf_spec_handler spf = (xtype==etSTRING)
fc60825290 2011-04-18       stephan:               ? spech_string : spech_dynstring;
6e8c7e31b6 2011-04-20       stephan: 	  bufpt = va_arg(ap,char*);
fc60825290 2011-04-18       stephan: 	  pfrc = spf( pfAppend, pfAppendArg, bufpt );
fc60825290 2011-04-18       stephan: 	  WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan: 	  length = 0;
fc60825290 2011-04-18       stephan: 	  if( precision>=0 && precision<length ) length = precision;
fc60825290 2011-04-18       stephan: 	}
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan:       case etHTML:
fc60825290 2011-04-18       stephan: 	  bufpt = va_arg(ap,char*);
fc60825290 2011-04-18       stephan: 	  pfrc = spech_string_to_html( pfAppend, pfAppendArg, bufpt );
fc60825290 2011-04-18       stephan: 	  WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan: 	  length = 0;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       case etURLENCODE:
fc60825290 2011-04-18       stephan: 	  bufpt = va_arg(ap,char*);
fc60825290 2011-04-18       stephan: 	  pfrc = spech_urlencode( pfAppend, pfAppendArg, bufpt );
fc60825290 2011-04-18       stephan: 	  WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan: 	  length = 0;
fc60825290 2011-04-18       stephan:         break;
fc60825290 2011-04-18       stephan:       case etURLDECODE:
fc60825290 2011-04-18       stephan:           bufpt = va_arg(ap,char *);
fc60825290 2011-04-18       stephan: 	  pfrc = spech_urldecode( pfAppend, pfAppendArg, bufpt );
fc60825290 2011-04-18       stephan: 	  WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan:           length = 0;
fc60825290 2011-04-18       stephan:           break;
fc60825290 2011-04-18       stephan: #endif /* WHPRINTF_OMIT_HTML */
fc60825290 2011-04-18       stephan: #if ! WHPRINTF_OMIT_SQL
fc60825290 2011-04-18       stephan:       case etSQLESCAPE:
fc60825290 2011-04-18       stephan:       case etSQLESCAPE2:
fc60825290 2011-04-18       stephan:       case etSQLESCAPE3: {
fc60825290 2011-04-18       stephan: 	      whprintf_spec_handler spf =
fc60825290 2011-04-18       stephan: 		      (xtype==etSQLESCAPE)
fc60825290 2011-04-18       stephan: 		      ? spech_sqlstring1
fc60825290 2011-04-18       stephan: 		      : ((xtype==etSQLESCAPE2)
fc60825290 2011-04-18       stephan: 			 ? spech_sqlstring2
fc60825290 2011-04-18       stephan: 			 : spech_sqlstring3
fc60825290 2011-04-18       stephan: 			 );
fc60825290 2011-04-18       stephan: 	      bufpt = va_arg(ap,char*);
fc60825290 2011-04-18       stephan: 	      pfrc = spf( pfAppend, pfAppendArg, bufpt );
fc60825290 2011-04-18       stephan: 	      WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan: 	      length = 0;
fc60825290 2011-04-18       stephan: 	      if( precision>=0 && precision<length ) length = precision;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan: #endif /* !WHPRINTF_OMIT_SQL */
fc60825290 2011-04-18       stephan:     }/* End switch over the format type */
fc60825290 2011-04-18       stephan:     /*
fc60825290 2011-04-18       stephan:        The text of the conversion is pointed to by "bufpt" and is
fc60825290 2011-04-18       stephan:        "length" characters long.  The field width is "width".  Do
fc60825290 2011-04-18       stephan:        the output.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     if( !flag_leftjustify ){
fc60825290 2011-04-18       stephan:       int nspace;
fc60825290 2011-04-18       stephan:       nspace = width-length;
fc60825290 2011-04-18       stephan:       if( nspace>0 ){
fc60825290 2011-04-18       stephan: 	      WHPRINTF_SPACES(nspace);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( length>0 ){
fc60825290 2011-04-18       stephan:       pfrc = pfAppend( pfAppendArg, bufpt, length);
fc60825290 2011-04-18       stephan:       WHPRINTF_CHECKERR(0);
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( flag_leftjustify ){
fc60825290 2011-04-18       stephan:       int nspace;
fc60825290 2011-04-18       stephan:       nspace = width-length;
fc60825290 2011-04-18       stephan:       if( nspace>0 ){
fc60825290 2011-04-18       stephan: 	      WHPRINTF_SPACES(nspace);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( zExtra ){
fc60825290 2011-04-18       stephan:       free(zExtra);
fc60825290 2011-04-18       stephan:       zExtra = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:   }/* End for loop over the format string */
fc60825290 2011-04-18       stephan:   WHPRINTF_RETURN;
fc60825290 2011-04-18       stephan: } /* End of function */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef WHPRINTF_SPACES
fc60825290 2011-04-18       stephan: #undef WHPRINTF_CHECKERR
fc60825290 2011-04-18       stephan: #undef WHPRINTF_RETURN
fc60825290 2011-04-18       stephan: #undef WHPRINTF_OMIT_FLOATING_POINT
fc60825290 2011-04-18       stephan: #undef WHPRINTF_OMIT_SIZE
fc60825290 2011-04-18       stephan: #undef WHPRINTF_OMIT_SQL
fc60825290 2011-04-18       stephan: #undef WHPRINTF_BUF_SIZE
fc60825290 2011-04-18       stephan: #undef WHPRINTF_OMIT_HTML
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: long whprintf(whprintf_appender pfAppend,          /* Accumulate results here */
fc60825290 2011-04-18       stephan: 	    void * pfAppendArg,                /* Passed as first arg to pfAppend. */
fc60825290 2011-04-18       stephan: 	    const char *fmt,                   /* Format string */
fc60825290 2011-04-18       stephan: 	    ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	va_list vargs;
6e8c7e31b6 2011-04-20       stephan:         long ret;
fc60825290 2011-04-18       stephan: 	va_start( vargs, fmt );
6e8c7e31b6 2011-04-20       stephan: 	ret = whprintfv( pfAppend, pfAppendArg, fmt, vargs );
fc60825290 2011-04-18       stephan: 	va_end(vargs);
fc60825290 2011-04-18       stephan: 	return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: long whprintf_FILE_appender( void * a, char const * s, long n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	FILE * fp = (FILE *)a;
fc60825290 2011-04-18       stephan: 	if( ! fp ) return -1;
6e8c7e31b6 2011-04-20       stephan:         else
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             long ret = fwrite( s, sizeof(char), n, fp );
6e8c7e31b6 2011-04-20       stephan:             return (ret >= 0) ? ret : -2;
6e8c7e31b6 2011-04-20       stephan:         }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: long whprintf_file( FILE * fp, char const * fmt, ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 	va_list vargs;
6e8c7e31b6 2011-04-20       stephan:         int ret;
fc60825290 2011-04-18       stephan: 	va_start( vargs, fmt );
6e8c7e31b6 2011-04-20       stephan: 	ret = whprintfv( whprintf_FILE_appender, fp, fmt, vargs );
fc60825290 2011-04-18       stephan: 	va_end(vargs);
fc60825290 2011-04-18       stephan: 	return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Internal implementation details for whprintfv_appender_stringbuf.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef struct whprintfv_stringbuf
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /** dynamically allocated buffer */
fc60825290 2011-04-18       stephan:     char * buffer;
fc60825290 2011-04-18       stephan:     /** bytes allocated to buffer */
fc60825290 2011-04-18       stephan:     size_t alloced;
fc60825290 2011-04-18       stephan:     /** Current position within buffer. */
fc60825290 2011-04-18       stephan:     size_t pos;
fc60825290 2011-04-18       stephan: } whprintfv_stringbuf;
fc60825290 2011-04-18       stephan: static const whprintfv_stringbuf whprintfv_stringbuf_init = { 0, 0, 0 };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    A whprintfv_appender implementation which requires arg to be a
fc60825290 2011-04-18       stephan:    (whprintfv_stringbuf*). It appends n bytes of data to the
fc60825290 2011-04-18       stephan:    whprintfv_stringbuf object's buffer, reallocating it as
fc60825290 2011-04-18       stephan:    needed. Returns less than 0 on error, else the number of bytes
fc60825290 2011-04-18       stephan:    appended to the buffer. The buffer will always be null terminated.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static long whprintfv_appender_stringbuf( void * arg, char const * data, long n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whprintfv_stringbuf * sb = (whprintfv_stringbuf*)arg;
fc60825290 2011-04-18       stephan:     if( ! sb || (n<0) ) return -1;
6e8c7e31b6 2011-04-20       stephan:     else if( ! n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         long rc;
6e8c7e31b6 2011-04-20       stephan:         size_t npos = sb->pos + n;
6e8c7e31b6 2011-04-20       stephan:         if( npos >= sb->alloced )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             const size_t asz = (npos * 1.5) + 1;
6e8c7e31b6 2011-04-20       stephan:             if( asz < npos ) return -1; /* overflow */
6e8c7e31b6 2011-04-20       stephan:             else
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 char * buf = realloc( sb->buffer, asz );
6e8c7e31b6 2011-04-20       stephan:                 if( ! buf ) return -1;
6e8c7e31b6 2011-04-20       stephan:                 memset( buf + sb->pos, 0, (npos + 1 - sb->pos) ); /* the +1 adds our NUL for us*/
6e8c7e31b6 2011-04-20       stephan:                 sb->buffer = buf;
6e8c7e31b6 2011-04-20       stephan:                 sb->alloced = asz;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         rc = 0;
6e8c7e31b6 2011-04-20       stephan:         for( ; rc < n; ++rc, ++sb->pos )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             sb->buffer[sb->pos] = data[rc];
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         return rc;
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: char * whprintfv_str( char const * fmt, va_list vargs )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! fmt ) return 0;
6e8c7e31b6 2011-04-20       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         whprintfv_stringbuf sb = whprintfv_stringbuf_init;
6e8c7e31b6 2011-04-20       stephan:         long rc = whprintfv( whprintfv_appender_stringbuf, &sb, fmt, vargs );
6e8c7e31b6 2011-04-20       stephan:         if( rc <= 0 )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             free( sb.buffer );
6e8c7e31b6 2011-04-20       stephan:             sb.buffer = 0;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         return sb.buffer;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: char * whprintf_str( char const * fmt, ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     va_list vargs;
6e8c7e31b6 2011-04-20       stephan:     char * ret;
fc60825290 2011-04-18       stephan:     va_start( vargs, fmt );
6e8c7e31b6 2011-04-20       stephan:     ret = whprintfv_str( fmt, vargs );
fc60825290 2011-04-18       stephan:     va_end( vargs );
fc60825290 2011-04-18       stephan:     return ret;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /* end file src/whprintf.c */
fc60825290 2011-04-18       stephan: /* begin file src/whalloc_amalgamation.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whalloc_amalgamation.c"
fc60825290 2011-04-18       stephan: /* auto-generated on Thu Oct  7 02:09:01 CEST 2010. Do not edit! */
fc60825290 2011-04-18       stephan: #line 1 "whalloc_amalgamation.c"
fc60825290 2011-04-18       stephan: /* begin file whalloc.c */
fc60825290 2011-04-18       stephan: #line 8 "whalloc.c"
fc60825290 2011-04-18       stephan: #if !defined(__STDC_FORMAT_MACROS)
fc60825290 2011-04-18       stephan: #  define __STDC_FORMAT_MACROS 1 /* for PRIxNN specifiers*/
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #include <stdlib.h>
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /************************************************************************
fc60825290 2011-04-18       stephan: ************************************************************************/
fc60825290 2011-04-18       stephan: #if defined (_MSC_VER)
fc60825290 2011-04-18       stephan: /* warning C4116: unnamed type definition in parentheses */
fc60825290 2011-04-18       stephan: #  pragma warning (disable : 4116)
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Implements WHALLOC_API(realloc_f)() and returns realloc(m,n).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static void * WHALLOC_API(allocator_realloc_proxy)( void * m, unsigned int n, void * state )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return realloc(m, n);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(fallback) WHALLOC_API(fallback_empty) = whalloc_fallback_empty_m;
fc60825290 2011-04-18       stephan: const WHALLOC_API(fallback) WHALLOC_API(fallback_stdalloc) = {realloc,free};
fc60825290 2011-04-18       stephan: const WHALLOC_API(allocator) WHALLOC_API(allocator_realloc3) = {WHALLOC_API(allocator_realloc_proxy),NULL};
fc60825290 2011-04-18       stephan: const WHALLOC_API(allocator) WHALLOC_API(allocator_empty) = {NULL,NULL};
fc60825290 2011-04-18       stephan: const WHALLOC_API(allocator_base) WHALLOC_API(allocator_base_empty) = whalloc_allocator_base_empty_m;
fc60825290 2011-04-18       stephan: const WHALLOC_API(rc_t) WHALLOC_API(rc) =
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:     0/*OK*/,
fc60825290 2011-04-18       stephan:     1/*RangeError*/,
fc60825290 2011-04-18       stephan:     2/*ArgError*/,
fc60825290 2011-04-18       stephan:     3/*InternalError*/,
fc60825290 2011-04-18       stephan:     4/*HashingError*/,
fc60825290 2011-04-18       stephan:     5/*AllocError*/,
fc60825290 2011-04-18       stephan:     6/*UsageError*/,
fc60825290 2011-04-18       stephan:     7/*ConsistencyError*/,
fc60825290 2011-04-18       stephan:     8/*LockingError*/,
fc60825290 2011-04-18       stephan:     (WHALLOC_API(size_t))-1/*HashCodeError*/
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: typedef char static_assert[
fc60825290 2011-04-18       stephan:                            sizeof(uintptr_t) == sizeof(void*) ? 1 : -1
fc60825290 2011-04-18       stephan:                            ];
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(mutex) WHALLOC_API(mutex_empty) = whalloc_mutex_empty_m;
fc60825290 2011-04-18       stephan: const WHALLOC_API(mutex) WHALLOC_API(mutex_trace) = whalloc_mutex_trace_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(mutex_lock_trace)( void * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     fprintf(stderr,"WHALLOC_API(mutex)::lock(): mutex @%p\n",p);
fc60825290 2011-04-18       stephan:     return 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: int WHALLOC_API(mutex_unlock_trace)( void * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     fprintf(stderr,"WHALLOC_API(mutex)::unlock(): mutex @%p\n",p);
fc60825290 2011-04-18       stephan:     return 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whalloc_calc_mask( WHALLOC_API(size_t) number,
fc60825290 2011-04-18       stephan:                        uint8_t * bits,
fc60825290 2011-04-18       stephan:                        WHALLOC_API(size_t) * mask )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     uint8_t b;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) i;
fc60825290 2011-04-18       stephan:     if( !number || ! bits ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     b = 0;
fc60825290 2011-04-18       stephan:     i = 1;
fc60825290 2011-04-18       stephan:     for( ; i < number; i*=2 )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         ++b;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( b > (WHALLOC_BITNESS-1) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).RangeError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     *bits = b;
fc60825290 2011-04-18       stephan:     if( mask ) *mask = ((WHALLOC_API(size_t))WHALLOC_MASK >> (WHALLOC_BITNESS - b));
fc60825290 2011-04-18       stephan:     return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whalloc_calc_mask2( WHALLOC_API(size_t) size,
fc60825290 2011-04-18       stephan:                         WHALLOC_API(size_t) blockSize,
fc60825290 2011-04-18       stephan:                         uint8_t * bits,
fc60825290 2011-04-18       stephan:                         WHALLOC_API(size_t) * mask,
fc60825290 2011-04-18       stephan:                         WHALLOC_API(size_t) *blocks )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !size || !blockSize || ! bits || (size<(blockSize*2)) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) n;
fc60825290 2011-04-18       stephan:         n = size/blockSize;
fc60825290 2011-04-18       stephan:         if( blocks ) *blocks = n;
fc60825290 2011-04-18       stephan:         return whalloc_calc_mask( n, bits, mask );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Returns a hash value for the given offset (in bytes) in
fc60825290 2011-04-18       stephan:    self->uspace, which must be in the range [0,self->usize).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    If( off >= self->usize ) WHALLOC_API(rc).HashCodeError is returned, else
fc60825290 2011-04-18       stephan:    the hash value is returned.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: WHALLOC_API(size_t) whalloc_allocator_base_hash_offset( WHALLOC_API(allocator_base) const * self, WHALLOC_API(size_t) off )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan:     return ( off >= self->usize )
fc60825290 2011-04-18       stephan:         ? WHALLOC_API(rc).HashCodeError
fc60825290 2011-04-18       stephan:         : ((off/self->blockSize)&self->hashMask)
fc60825290 2011-04-18       stephan:         ;
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     return ((off)/self->blockSize) & self->hashMask;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Returns the hashcode for the given address. If addr
fc60825290 2011-04-18       stephan:    is outside of self's range then WHALLOC_API(rc).HashCodeError
fc60825290 2011-04-18       stephan:    is returned.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: WHALLOC_API(size_t) whalloc_allocator_base_hash_addr( WHALLOC_API(allocator_base) const * self, void const * addr_ )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     unsigned char const * addr;
fc60825290 2011-04-18       stephan:     addr = (unsigned char const *) addr_;
fc60825290 2011-04-18       stephan:     if( !addr || !self
fc60825290 2011-04-18       stephan:         || (addr < self->uspace)
fc60825290 2011-04-18       stephan:         || (addr >= self->end)
fc60825290 2011-04-18       stephan:         )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:         LOGBASE(("bad addr @%p/%u. uspace=%p/%u, limit=%p/%u\n",addr,(size_t)addr,
fc60825290 2011-04-18       stephan:                  self->uspace,(size_t)self->uspace,self->end,(size_t)self->end));
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         return
fc60825290 2011-04-18       stephan:             WHALLOC_API(rc).HashCodeError
fc60825290 2011-04-18       stephan:             ;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return whalloc_allocator_base_hash_offset( self, (WHALLOC_API(size_t))(addr - self->uspace) );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: uint8_t WHALLOC_API(bitness)()
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return WHALLOC_BITNESS;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /* end file whalloc.c */
fc60825290 2011-04-18       stephan: /* begin file whalloc_bt.c */
fc60825290 2011-04-18       stephan: #line 8 "whalloc_bt.c"
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Defined/documented in whalloc.c */
fc60825290 2011-04-18       stephan: extern WHALLOC_API(size_t) whalloc_allocator_base_hash_offset( WHALLOC_API(allocator_base) const * self, WHALLOC_API(size_t) off );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Defined/documented in whalloc.c */
fc60825290 2011-04-18       stephan: extern WHALLOC_API(size_t) whalloc_allocator_base_hash_addr( WHALLOC_API(allocator_base) const * self, void const * addr_ );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !defined(NDEBUG)
fc60825290 2011-04-18       stephan: #  define LOGBASE(mp_exp) if( self && self->log ) \
fc60825290 2011-04-18       stephan:     { self->log("%s:%d:%s(): ",__FILE__,__LINE__,__func__); \
fc60825290 2011-04-18       stephan:         self->log mp_exp; \
fc60825290 2011-04-18       stephan:     } else (void)0
fc60825290 2011-04-18       stephan: #  define LOGSELF(mp_exp) if( self && self->base.log )   \
fc60825290 2011-04-18       stephan:     { self->base.log("%s:%d:%s(): ",__FILE__,__LINE__,__func__); \
fc60825290 2011-04-18       stephan:         self->base.log mp_exp; \
fc60825290 2011-04-18       stephan:     } else (void)0
fc60825290 2011-04-18       stephan: #define MARKER(mp_exp) printf("MARKER: %s:%d:%s(): ",__FILE__,__LINE__,__func__); printf mp_exp
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #  define LOGSELF(mp_exp) (void)0
fc60825290 2011-04-18       stephan: #  define LOGBASE(mp_exp) (void)0
fc60825290 2011-04-18       stephan: #  define MARKER(mp_exp) ((void)0)
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define LOCK_OR(RC) if( self->base.mutex.lock ) if( 0 != self->base.mutex.lock(self->base.mutex.state) ) return RC
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define UNLOCK if( self->base.mutex.unlock ) self->base.mutex.unlock( self->base.mutex.state )
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define whalloc_bt_hash_offset(S,O) whalloc_allocator_base_hash_offset(&(S)->base,(O))
fc60825290 2011-04-18       stephan: #define whalloc_bt_hash_addr(S,O) whalloc_allocator_base_hash_addr(&(S)->base,(O))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(bt) WHALLOC_API(bt_empty) = whalloc_bt_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define BYTES_BYTEFOR(A,BIT) ((A)[ BIT / 8 ])
fc60825290 2011-04-18       stephan: #define BYTES_SET(A,BIT) ((BYTES_BYTEFOR(A,BIT) |= (0x01 << (BIT%8))),0x01)
fc60825290 2011-04-18       stephan: #define BYTES_UNSET(A,BIT) ((BYTES_BYTEFOR(A,BIT) &= ~(0x01 << (BIT%8))),0x00)
fc60825290 2011-04-18       stephan: #define BYTES_GET(A,BIT) ((BYTES_BYTEFOR(A,BIT) & (0x01 << (BIT%8))) ? 0x01 : 0x00)
fc60825290 2011-04-18       stephan: #define BYTES_TOGGLE(A,BIT) (BYTES_GET(A,BIT) ? (BYTES_UNSET(A,BIT)) : (BYTES_SET(B,BIT)))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define BITMAP_BYTEOF(ARRAY,BIT) ((self->bits.ARRAY)[ BIT / 8 ])
fc60825290 2011-04-18       stephan: #define BITMAP_IS_USED(BIT) BYTES_GET(self->bits.usage,(BIT))
fc60825290 2011-04-18       stephan: #define BITMAP_SET_USAGE(BIT,VAL) ((VAL)?BYTES_SET(self->bits.usage,BIT):BYTES_UNSET(self->bits.usage,BIT))
fc60825290 2011-04-18       stephan: #define BITMAP_USE(BIT) BITMAP_SET_USAGE(BIT,1)
fc60825290 2011-04-18       stephan: #define BITMAP_UNUSE(BIT) BITMAP_SET_USAGE(BIT,0)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define BITMAP_IS_LINKED(BIT) BYTES_GET(self->bits.links,(BIT))
fc60825290 2011-04-18       stephan: #define BITMAP_SET_LINK(BIT,VAL) ((VAL)?BYTES_SET(self->bits.links,BIT):BYTES_UNSET(self->bits.links,BIT))
fc60825290 2011-04-18       stephan: #define BITMAP_LINK(BIT) BITMAP_SET_LINK(BIT,1)
fc60825290 2011-04-18       stephan: #define BITMAP_UNLINK(BIT) BITMAP_SET_LINK(BIT,0)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Clears the internal bits table. Returns 0 on success.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static int WHALLOC_API(bt_clear_table)( WHALLOC_API(bt) * const self )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( self->bits.usage != self->bits.cache )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Clearing out %"WHALLOC_SIZE_T_PFMT" bytes from client-side cache.\n",self->bits.byteCount));
fc60825290 2011-04-18       stephan:             memset(self->bits.usage, 0, self->bits.byteCount );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Clearing out %"WHALLOC_SIZE_T_PFMT" bytes from internal cache.\n",sizeof(self->bits.cache)));
fc60825290 2011-04-18       stephan:             memset(self->bits.cache, 0, sizeof(self->bits.cache) );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         self->base.allocCount=0;
fc60825290 2011-04-18       stephan:         self->base.allocBlockCount=0;
fc60825290 2011-04-18       stephan:         self->base.freeIndexHint = 0;
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_init)( WHALLOC_API(bt) * const self,
fc60825290 2011-04-18       stephan:                          void * mem,
fc60825290 2011-04-18       stephan:                          WHALLOC_API(size_t) size,
fc60825290 2011-04-18       stephan:                          WHALLOC_API(size_t) blockSize )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     static const WHALLOC_API(size_t) MaxSize = (WHALLOC_MASK);
fc60825290 2011-04-18       stephan:     static const WHALLOC_API(size_t) MinSize = 64;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) blockCount;
fc60825290 2011-04-18       stephan:     unsigned char * bUsed;
fc60825290 2011-04-18       stephan:     unsigned char * bLink;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) tblBits;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) mbBytes;
fc60825290 2011-04-18       stephan:     int rc;
fc60825290 2011-04-18       stephan:     if( ! blockSize ) blockSize = 8;
fc60825290 2011-04-18       stephan:     if( ! self || ! mem || (size<(blockSize*2)) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( (size > MaxSize) || (size < MinSize) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Size %"WHALLOC_SIZE_T_PFMT" must be in the range (%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT")\n",size, MinSize, MaxSize));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     blockCount = 0;
fc60825290 2011-04-18       stephan:     rc = whalloc_calc_mask2( size, blockSize, &self->base.bitCount, &self->base.hashMask, &blockCount );
fc60825290 2011-04-18       stephan:     LOGSELF(("rc=%d from whalloc_calc_mask2(%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT",...) blockCount=%"WHALLOC_SIZE_T_PFMT"\n",rc,size, blockSize,blockCount));
fc60825290 2011-04-18       stephan:     if( rc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Error %d from whalloc_calc_mask2(%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT",...)\n",rc,self->base.usize, blockSize));
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     self->base.mem = (unsigned char *) mem;
fc60825290 2011-04-18       stephan:     self->base.size = self->base.usize = size;
fc60825290 2011-04-18       stephan:     self->base.uspace = self->base.mem;
fc60825290 2011-04-18       stephan:     self->base.end = self->base.mem + self->base.size;
fc60825290 2011-04-18       stephan:     self->base.blockSize = blockSize;
fc60825290 2011-04-18       stephan:     bUsed = 0;
fc60825290 2011-04-18       stephan:     bLink = 0;
fc60825290 2011-04-18       stephan:     tblBits = blockCount;
fc60825290 2011-04-18       stephan:     mbBytes = (tblBits/8)*2;/*  2==1 bit for is-used, 1 bit for is-linked */
fc60825290 2011-04-18       stephan:     /* if( ! mbBytes ) mbBytes = 2; */
fc60825290 2011-04-18       stephan:     if( mbBytes && (tblBits%8) ) ++mbBytes;
fc60825290 2011-04-18       stephan:     if( mbBytes%2 ) ++mbBytes; /*  round up to 2-byte boundary */
fc60825290 2011-04-18       stephan:     mbBytes += 2;
fc60825290 2011-04-18       stephan:     /** ^^^^^ maintenance reminder We need to add a padding byte
fc60825290 2011-04-18       stephan:         between each bitmap to ensure that the bitmaps do not align
fc60825290 2011-04-18       stephan:         directly with each other or the end of the bitmap. If the
fc60825290 2011-04-18       stephan:         bitmap has been perfectly sized, and all bits are used,
fc60825290 2011-04-18       stephan:         operations which crawl linked blocks can actually crawl into
fc60825290 2011-04-18       stephan:         the data bytes by mistake if the bitmaps are edge-to-edge,
fc60825290 2011-04-18       stephan:         causing corruption. Been there, done that.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         20100304: now that the bitsets have been moved to the end
fc60825290 2011-04-18       stephan:         of the memory, we really only need 1 padding byte between
fc60825290 2011-04-18       stephan:         the is-used and is-linked bitsets.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     if( (WHALLOC_API(bt_CacheLength))
fc60825290 2011-04-18       stephan:         && ((sizeof(self->bits.cache)>2) && (mbBytes < (sizeof(self->bits.cache))))
fc60825290 2011-04-18       stephan:         )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            If the bits will fit in our internal cache, use the cache space.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            TODO: if the cache is long enough to hold one of the bitsets,
fc60825290 2011-04-18       stephan:            relocate only one bitset into the reserved memory.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         LOGSELF(("Using internal bits cache for blockCount=%"WHALLOC_SIZE_T_PFMT", tblBits=%"WHALLOC_SIZE_T_PFMT", mbBytes=%"WHALLOC_SIZE_T_PFMT"! Stealing no memory!\n",
fc60825290 2011-04-18       stephan:                  blockCount, tblBits, mbBytes ));
fc60825290 2011-04-18       stephan:         bUsed = self->bits.cache;
fc60825290 2011-04-18       stephan:         bLink = self->bits.cache + (mbBytes/2);
fc60825290 2011-04-18       stephan:         self->bits.byteCount = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         self->base.usize -= mbBytes;
fc60825290 2011-04-18       stephan:         /*  adjust memory buffer size and re-calculate our bitmask... */
fc60825290 2011-04-18       stephan:         rc = whalloc_calc_mask2( self->base.usize, blockSize, &self->base.bitCount, &self->base.hashMask, &blockCount );
fc60825290 2011-04-18       stephan:         LOGSELF(("rc=%d from whalloc_calc_mask2(%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT",...) blockCount=%"WHALLOC_SIZE_T_PFMT"\n",rc,size, blockSize,blockCount));
fc60825290 2011-04-18       stephan:         if( rc )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Error %d from whalloc_calc_mask2(%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT",...)\n",rc,self->base.usize, blockSize));
fc60825290 2011-04-18       stephan:             return rc;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan:         /** Changed 20100304:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:             Locate the flag bits at the END of self->base.mem so that
fc60825290 2011-04-18       stephan:             we can ensure predictable alignment of allocated blocks.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         self->base.uspace = self->base.mem;
fc60825290 2011-04-18       stephan:         bUsed = self->base.mem + self->base.usize + 1 /*+1 need as a 0-pad byte, as explained above.*/;
fc60825290 2011-04-18       stephan:         bLink = bUsed + (mbBytes/2);
fc60825290 2011-04-18       stephan:         self->bits.byteCount = mbBytes;
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:         /** Store flag bits at the start of self->base.mem. This is
fc60825290 2011-04-18       stephan:             theoretically safer but makes it more difficult to ensure
fc60825290 2011-04-18       stephan:             predictable alignment of allocated blocks.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         self->base.uspace = self->base.mem + mbBytes;
fc60825290 2011-04-18       stephan:         bUsed = self->base.mem;
fc60825290 2011-04-18       stephan:         bLink = self->base.mem + (mbBytes/2);
fc60825290 2011-04-18       stephan:         self->bits.byteCount = mbBytes;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         LOGSELF(("blockCount=%"WHALLOC_SIZE_T_PFMT", usize=%"WHALLOC_SIZE_T_PFMT", tblBits=%"WHALLOC_SIZE_T_PFMT", mbBytes=%"WHALLOC_SIZE_T_PFMT", bits.byteCount=%"WHALLOC_SIZE_T_PFMT"\n",
fc60825290 2011-04-18       stephan:                  blockCount,self->base.usize,tblBits,mbBytes,self->bits.byteCount));
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     self->base.blockCount = self->bits.end = blockCount;
fc60825290 2011-04-18       stephan:     self->bits.usage = bUsed;
fc60825290 2011-04-18       stephan:     self->bits.links = bLink;
fc60825290 2011-04-18       stephan:     LOGSELF(("size=%"WHALLOC_SIZE_T_PFMT", usize=%"WHALLOC_SIZE_T_PFMT" (diff=-%"WHALLOC_SIZE_T_PFMT"), blockSize=%"WHALLOC_SIZE_T_PFMT", "
fc60825290 2011-04-18       stephan:              "maxBlocks=%"WHALLOC_SIZE_T_PFMT", tblBits=%"WHALLOC_SIZE_T_PFMT" (%"WHALLOC_SIZE_T_PFMT" per set), "
fc60825290 2011-04-18       stephan:              "mbBytes=%"WHALLOC_SIZE_T_PFMT" (fits %"WHALLOC_SIZE_T_PFMT" bits/set), self->bits.end\n",
fc60825290 2011-04-18       stephan:              size, self->base.usize, (size- self->base.usize), blockSize,
fc60825290 2011-04-18       stephan:              blockCount, tblBits, self->bits.end,
fc60825290 2011-04-18       stephan:              mbBytes, mbBytes*4));
fc60825290 2011-04-18       stephan:     LOGSELF(("bitCount=%"WHALLOC_SIZE_T_PFMT", hashMask=%08x\n",
fc60825290 2011-04-18       stephan:              self->base.bitCount, self->base.hashMask));
fc60825290 2011-04-18       stephan:     LOGSELF(("\nself->base.mem\t%p\nself->base.uspace\t%p\nDiff\t%"WHALLOC_SIZE_T_PFMT" bytes\nself->base.end\t%p\n",
fc60825290 2011-04-18       stephan:              self->base.mem, self->base.uspace, (uint32_t)(self->base.uspace - self->base.mem), self->base.end ));
fc60825290 2011-04-18       stephan:     /*  Test the hashing algo for no dupes: */
fc60825290 2011-04-18       stephan:     if( 1 )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) at;
fc60825290 2011-04-18       stephan:         unsigned char const * offset;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         at = 0;
fc60825290 2011-04-18       stephan:         offset = self->base.uspace;
fc60825290 2011-04-18       stephan:         hash = 0;
fc60825290 2011-04-18       stephan:         memset( mem, 0, size );
fc60825290 2011-04-18       stephan:         WHALLOC_API(bt_clear_table)(self);
fc60825290 2011-04-18       stephan:         for( ; at < self->bits.end; ++at, offset += self->base.blockSize )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             hash =
fc60825290 2011-04-18       stephan:                 /* whalloc_bt_hash_addr( self, offset ) */
fc60825290 2011-04-18       stephan:                 whalloc_bt_hash_offset( self, at * self->base.blockSize )
fc60825290 2011-04-18       stephan:                 ;
fc60825290 2011-04-18       stephan:             assert( hash == whalloc_bt_hash_offset( self, at * self->base.blockSize ) );
fc60825290 2011-04-18       stephan:             assert( hash == whalloc_bt_hash_addr( self, offset ) );
fc60825290 2011-04-18       stephan:             if( WHALLOC_API(rc).HashCodeError == hash )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Unexpected HashCodeError: Offset %p at=%"WHALLOC_SIZE_T_PFMT" hash=%"WHALLOC_SIZE_T_PFMT"\n",offset,at,hash));
fc60825290 2011-04-18       stephan:                 assert( 0 && "WHALLOC_API(rc).HashCodeError" );
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else if( BITMAP_IS_USED(hash) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Unexpected is-used while testing hashcodes (possibly hash collision): Offset %p at=%"WHALLOC_SIZE_T_PFMT" hash=%"WHALLOC_SIZE_T_PFMT"\n",offset,at,hash));
fc60825290 2011-04-18       stephan:                 assert( 0 && "BITMAP_IS_USED(hash)" );
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).ConsistencyError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else if( hash != at )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:                 LOGSELF(("Unexpected mismatch while testing hashcodes: Offset %p at=%"WHALLOC_SIZE_T_PFMT" hash=%"WHALLOC_SIZE_T_PFMT"\n",offset,at,hash));
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:                 LOGSELF(("Warning: (hash %"WHALLOC_SIZE_T_PFMT"!=pos %"WHALLOC_SIZE_T_PFMT") we ran out of hashcodes at %"WHALLOC_SIZE_T_PFMT" of %"WHALLOC_SIZE_T_PFMT" expected entries. "
fc60825290 2011-04-18       stephan:                          "Possibly caused by too-small of a blockSize (%"WHALLOC_SIZE_T_PFMT") for this size (%"WHALLOC_SIZE_T_PFMT").\n",
fc60825290 2011-04-18       stephan:                          hash,at,at,self->bits.end,self->base.blockSize, self->base.size));
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:                 assert( hash == at );
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             BITMAP_USE(at);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         offset += self->base.blockSize;
fc60825290 2011-04-18       stephan:         hash =
fc60825290 2011-04-18       stephan:             whalloc_bt_hash_addr( self, offset )
fc60825290 2011-04-18       stephan:             /* whalloc_bt_hash_offset( self, at ) */
fc60825290 2011-04-18       stephan:             ;
fc60825290 2011-04-18       stephan:         if( hash < self->bits.end )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             MARKER(("Unexpected final hash code: offset %p end=%p hash=%"WHALLOC_SIZE_T_PFMT"\n",offset,self->base.end,hash));
fc60825290 2011-04-18       stephan:             assert( (hash >= self->bits.end) );
fc60825290 2011-04-18       stephan:             return WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     memset( mem, 0, size );
fc60825290 2011-04-18       stephan:     WHALLOC_API(bt_clear_table)(self);
fc60825290 2011-04-18       stephan:     return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan:    Returns a pointer the memory associated with the given block index,
fc60825290 2011-04-18       stephan:    or null if !self or at is out of bounds.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static unsigned char *
fc60825290 2011-04-18       stephan: WHALLOC_API(bt_mem_for_hash)( WHALLOC_API(bt) const * const self,
fc60825290 2011-04-18       stephan:                              WHALLOC_API(size_t) at )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return !self
fc60825290 2011-04-18       stephan:         ? NULL
fc60825290 2011-04-18       stephan:         : ( (at >= self->bits.end)
fc60825290 2011-04-18       stephan:            ? NULL
fc60825290 2011-04-18       stephan:             : (self->base.uspace + ( self->base.blockSize * at )) )
fc60825290 2011-04-18       stephan:         ;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: Tries to find an unused range of memory in self. On success it marks
fc60825290 2011-04-18       stephan: the all blocks of the span as in-use and links all but the last one.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: startIndex = self->ht.head index to start at. It is a hint. If that
fc60825290 2011-04-18       stephan: block is in use then it will be skipped over.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: size = size, in bytes, to allocate. It must be greater than 0.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: self is assumed to already be locked - this function does
fc60825290 2011-04-18       stephan: not lock it.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: On success, returns the index of the chunk containing the memory
fc60825290 2011-04-18       stephan: record. On error it returns a value equal to or greater than
fc60825290 2011-04-18       stephan: self->bits.end (WHALLOC_API(rc).HashCodeError if !self or !size).  All
fc60825290 2011-04-18       stephan: blocks in the chain except the last one will be marked as in-use and
fc60825290 2011-04-18       stephan: linked. The last block will be marked as in-use and not linked.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: This function adjusts self->base.allocBlockCount and
fc60825290 2011-04-18       stephan: self->base.allocCount. It also possibly updates self->freeIndexHint.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static
fc60825290 2011-04-18       stephan: WHALLOC_API(size_t) WHALLOC_API(bt_mark_range)( WHALLOC_API(bt) * const self,
fc60825290 2011-04-18       stephan:                                       WHALLOC_API(size_t) startIndex,
fc60825290 2011-04-18       stephan:                                       WHALLOC_API(size_t) size )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) endex /* one-past-end */;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) stride;
fc60825290 2011-04-18       stephan:     if( ! self || ! size ) return WHALLOC_API(rc).HashCodeError;
fc60825290 2011-04-18       stephan:     LOGSELF(("trying to mark range of %"WHALLOC_SIZE_T_PFMT" bytes starting at index %"WHALLOC_SIZE_T_PFMT"...\n",
fc60825290 2011-04-18       stephan:              size, startIndex));
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Overall algorithm:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        endex = startIndex + (size/self->base.blockSize)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex>=self->bits.end return error
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex is in-use:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        - startIndex = endex+1
fc60825290 2011-04-18       stephan:        - If startIndex>=self->bits.end, return error
fc60825290 2011-04-18       stephan:        - Else try again
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex is unused:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        - Mark all blocks between (startIndex,endex) as used.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     if( startIndex >= self->bits.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return self->bits.end;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     endex = self->bits.end;
fc60825290 2011-04-18       stephan:     stride = (size/self->base.blockSize);
fc60825290 2011-04-18       stephan:     if( !stride || (size%self->base.blockSize) ) ++stride;
fc60825290 2011-04-18       stephan:     LOGSELF(("trying to mark range of %"WHALLOC_SIZE_T_PFMT" bytes starting at index %"WHALLOC_SIZE_T_PFMT", stride=%"WHALLOC_SIZE_T_PFMT"...\n",
fc60825290 2011-04-18       stephan:              size, startIndex, stride));
fc60825290 2011-04-18       stephan:     do
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) check;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) lastFree;
fc60825290 2011-04-18       stephan:         endex = startIndex + stride;
fc60825290 2011-04-18       stephan:         LOGSELF(("Checking range [%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT")"
fc60825290 2011-04-18       stephan:                  ", self->bits.end=%"WHALLOC_SIZE_T_PFMT"\n",
fc60825290 2011-04-18       stephan:                  startIndex, endex, self->bits.end));
fc60825290 2011-04-18       stephan:         if( endex > self->bits.end )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             return self->bits.end;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else if( endex != self->bits.end )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( BITMAP_IS_USED(endex) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("[%"WHALLOC_SIZE_T_PFMT" is used. Skipping.\n",startIndex,endex));
fc60825290 2011-04-18       stephan:                 startIndex = endex + 1;
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /* It looks like we're eking out the last block. */
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /*  ensure the whole range is not in use: */
fc60825290 2011-04-18       stephan:         /*
fc60825290 2011-04-18       stephan:             FIXME: when startIndex is on a byte boundary relative to
fc60825290 2011-04-18       stephan:             the bitsets, we can check a whole block of 8 (or 16, or
fc60825290 2011-04-18       stephan:             32) at once via a single mask check. If it's not on a byte
fc60825290 2011-04-18       stephan:             boundary, we'd have to shift that mask around quite trickily.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         check = endex-1;
fc60825290 2011-04-18       stephan:         lastFree = check;
fc60825290 2011-04-18       stephan:         for( ; (check != startIndex)
fc60825290 2011-04-18       stephan:                  && !BITMAP_IS_USED(check);
fc60825290 2011-04-18       stephan:              --check, --lastFree )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( check == startIndex ) break; /*  all blocks between (start,end) are free :-D */
fc60825290 2011-04-18       stephan:         startIndex = lastFree+1;
fc60825290 2011-04-18       stephan:         /*  try again. */
fc60825290 2011-04-18       stephan:     } while(1);
fc60825290 2011-04-18       stephan:     if( (endex > self->bits.end) || (startIndex >= self->bits.end) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return self->bits.end;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOGSELF(("Using range [%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT")\n",startIndex,endex));
fc60825290 2011-04-18       stephan:     for( pos = startIndex ; pos < endex; ++pos )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /*
fc60825290 2011-04-18       stephan:           FIXME: as above when checking ranges, we can,
fc60825290 2011-04-18       stephan:           if pos is on a byte boundary, mask whole
fc60825290 2011-04-18       stephan:           sets of 8 at once.
fc60825290 2011-04-18       stephan:          */
fc60825290 2011-04-18       stephan:         LOGSELF(("Marking #%"WHALLOC_SIZE_T_PFMT" as used.\n",pos));
fc60825290 2011-04-18       stephan:         BITMAP_USE(pos);
fc60825290 2011-04-18       stephan:         assert( BITMAP_IS_USED(pos) );
fc60825290 2011-04-18       stephan:         if( (endex-1) != pos )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             BITMAP_LINK(pos);
fc60825290 2011-04-18       stephan:             assert( BITMAP_IS_LINKED(pos) );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Not linking last item, #%"WHALLOC_SIZE_T_PFMT".\n",pos));
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         ++self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     ++self->base.allocCount;
fc60825290 2011-04-18       stephan:     if( self->base.freeIndexHint == startIndex )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         self->base.freeIndexHint = endex;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return startIndex;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**@ internal
fc60825290 2011-04-18       stephan:    The converse of WHALLOC_API(bt_mark_range)().
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Clears a range of blocks for re-use.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    startIndex must refer to an in-use block. That block,
fc60825290 2011-04-18       stephan:    plus any others to its right associated via a multi-block
fc60825290 2011-04-18       stephan:    allocation, are marked as free.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Returns 0 on success. If it returns WHALLOC_API(rc).InternalError
fc60825290 2011-04-18       stephan:    then the pool state is probably corrupt or unexpected. It returns
fc60825290 2011-04-18       stephan:    WHALLOC_API(rc).ArgError if !self and WHALLOC_API(rc).RangeError if
fc60825290 2011-04-18       stephan:    startIndex is not less than self->ht.end.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    This function adjusts self->base.allocBlockCount and
fc60825290 2011-04-18       stephan:    self->base.allocCount. It also possibly updates
fc60825290 2011-04-18       stephan:    self->freeIndexHint.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_clear_range)( WHALLOC_API(bt) * const self,
fc60825290 2011-04-18       stephan:                                  WHALLOC_API(size_t) startIndex )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     char hadLink;
fc60825290 2011-04-18       stephan:     unsigned char * mem;
fc60825290 2011-04-18       stephan:     if( ! self )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( startIndex >= self->bits.end)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).RangeError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     pos = startIndex;
fc60825290 2011-04-18       stephan:     LOGSELF(("Clearing range starting at %"WHALLOC_SIZE_T_PFMT"...\n",pos));
fc60825290 2011-04-18       stephan:     hadLink = 0;
fc60825290 2011-04-18       stephan:     for( ; pos < self->bits.end; ++pos )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            TODO:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            We can check the whole byte at once for used-ness and/or
fc60825290 2011-04-18       stephan:            linkedness. But we need to be careful to mask only the
fc60825290 2011-04-18       stephan:            pos-plus-right bits in the current byte of
fc60825290 2011-04-18       stephan:            self->bits.usage, and we have the special case of the final
fc60825290 2011-04-18       stephan:            block in a chain being used but not linked.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         if( startIndex == pos )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ! BITMAP_IS_USED(pos) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Internal error: we were expecting that entry #%"WHALLOC_SIZE_T_PFMT" was marked as used!\n",
fc60825290 2011-04-18       stephan:                          pos ));
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ! BITMAP_IS_USED(pos) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 break; /*  we've reached the next block. */
fc60825290 2011-04-18       stephan:                 LOGSELF(("Expecting a used entry at #%"WHALLOC_SIZE_T_PFMT"!\n",pos));
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         LOGSELF(("Marking entry #%"WHALLOC_SIZE_T_PFMT" as unused.\n",pos));
fc60825290 2011-04-18       stephan:         BITMAP_UNUSE(pos);
fc60825290 2011-04-18       stephan:         hadLink = BITMAP_IS_LINKED(pos);
fc60825290 2011-04-18       stephan:         BITMAP_UNLINK(pos);
fc60825290 2011-04-18       stephan:         --self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:         if( ! hadLink )
fc60825290 2011-04-18       stephan:         { /*  end of the block */
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     --self->base.allocCount;
fc60825290 2011-04-18       stephan:     mem = WHALLOC_API(bt_mem_for_hash)( self, startIndex );
fc60825290 2011-04-18       stephan:     assert(mem && "Internal memory reference error!");
fc60825290 2011-04-18       stephan:     if( self->base.freeIndexHint > startIndex )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         self->base.freeIndexHint = startIndex;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static WHALLOC_API(size_t) WHALLOC_API(bt_count_chain)( WHALLOC_API(bt) * const self,
fc60825290 2011-04-18       stephan:                                        WHALLOC_API(size_t) startIndex )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     if( ! self )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( startIndex >= self->bits.end)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     pos = startIndex;
fc60825290 2011-04-18       stephan:     for( ; pos < self->bits.end; ++pos )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( startIndex == pos )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ! BITMAP_IS_USED(pos) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Internal error: we were expecting that entry #%"WHALLOC_SIZE_T_PFMT" was marked as used!\n",
fc60825290 2011-04-18       stephan:                          pos ));
fc60825290 2011-04-18       stephan:                 return 0;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ! BITMAP_IS_USED(pos) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Expecting a used entry at #%"WHALLOC_SIZE_T_PFMT"!\n",pos));
fc60825290 2011-04-18       stephan:                 break; /*  we've reached the next block. */
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( ! BITMAP_IS_LINKED(pos) )
fc60825290 2011-04-18       stephan:         { /*  end of the block */
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return (pos - startIndex)+1;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Internal impl for WHALLOC_API(bt_alloc)() and WHALLOC_API(bt_realloc)().
fc60825290 2011-04-18       stephan:    If doLocking is true then self->mutex is respected, otherwise it
fc60825290 2011-04-18       stephan:    is assumed to already be locked.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static void*
fc60825290 2011-04-18       stephan: WHALLOC_API(bt_alloc_impl)( WHALLOC_API(bt) * const self, WHALLOC_API(size_t) size, char doLocking  )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:     unsigned char * mem;
fc60825290 2011-04-18       stephan:     void * fb;
fc60825290 2011-04-18       stephan:     if( ! self ) return 0;
fc60825290 2011-04-18       stephan:     if( doLocking )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOCK_OR(NULL);
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     fb = 0;
fc60825290 2011-04-18       stephan: #define FBALLOC if(self->base.fallback.realloc) do { fb = self->base.fallback.realloc(0,size); if(doLocking) UNLOCK; return fb; } while(0)
fc60825290 2011-04-18       stephan:     if (! size)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         size = self->base.blockSize;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOGSELF(("pool=@%p, alloc request size=%"WHALLOC_SIZE_T_PFMT"\n",(void const *)self, size));
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     if( (self->base.allocBlockCount>=self->bits.end /*we're full*/)
fc60825290 2011-04-18       stephan:         )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("pool=@%p cannot allocate %"WHALLOC_SIZE_T_PFMT" bytes.%s\n",
fc60825290 2011-04-18       stephan:                  (void const *)self,
fc60825290 2011-04-18       stephan:                  size,
fc60825290 2011-04-18       stephan:                  (self->base.fallback.realloc ? " Trying fallback." : "")
fc60825290 2011-04-18       stephan:                  ));
fc60825290 2011-04-18       stephan:         FBALLOC;
fc60825290 2011-04-18       stephan:         if(doLocking) UNLOCK;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     hash = 0;
fc60825290 2011-04-18       stephan:     hash = self->base.freeIndexHint;
fc60825290 2011-04-18       stephan:     LOGSELF(("self->base.freeIndexHint=%"WHALLOC_SIZE_T_PFMT"\n",hash));
fc60825290 2011-04-18       stephan:     if( hash >= self->bits.end ) hash = 0;
fc60825290 2011-04-18       stephan:     hash = WHALLOC_API(bt_mark_range)( self, hash, size );/*  FIXME: size+ALIGNMENT? */
fc60825290 2011-04-18       stephan:     if( hash >= self->bits.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Could not allocate %"WHALLOC_SIZE_T_PFMT" bytes!\n",size));
fc60825290 2011-04-18       stephan:         FBALLOC;
fc60825290 2011-04-18       stephan:         if(doLocking) UNLOCK;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     mem = WHALLOC_API(bt_mem_for_hash)( self, hash );
fc60825290 2011-04-18       stephan:     LOGSELF(("Allocated %"WHALLOC_SIZE_T_PFMT" bytes @%p\n",size,mem));
fc60825290 2011-04-18       stephan:     if(doLocking) UNLOCK;
fc60825290 2011-04-18       stephan:     assert( mem && "Internal memory handling error!" );
fc60825290 2011-04-18       stephan: #undef FBALLOC
fc60825290 2011-04-18       stephan:     return mem;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void *  WHALLOC_API(bt_realloc)( WHALLOC_API(bt) * const self, void * m, WHALLOC_API(size_t) size )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:     unsigned char * mem;
fc60825290 2011-04-18       stephan:     unsigned char * re;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) oldlen;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) bcount;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) blocksNeeded;
fc60825290 2011-04-18       stephan:     if( ! self ) return NULL;
fc60825290 2011-04-18       stephan:     else if( ! m ) return WHALLOC_API(bt_alloc)( self, size );
fc60825290 2011-04-18       stephan:     else if( ! size )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return (0 == WHALLOC_API(bt_free)( self, m ))
fc60825290 2011-04-18       stephan:             ? NULL
fc60825290 2011-04-18       stephan:             : m;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOCK_OR(NULL);
fc60825290 2011-04-18       stephan: #define FBALLOC if(self->base.fallback.realloc) do { void * fb = self->base.fallback.realloc(m,size); UNLOCK; return fb; } while(0)
fc60825290 2011-04-18       stephan:     hash = whalloc_bt_hash_addr( self, m );
fc60825290 2011-04-18       stephan:     if( hash >= self->bits.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         FBALLOC;
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         assert( 0 && "WHALLOC_API(bt_realloc)() was asked to realloc memory it doesn't manage!");
fc60825290 2011-04-18       stephan:         return NULL;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     mem = WHALLOC_API(bt_mem_for_hash)( self, hash );
fc60825290 2011-04-18       stephan:     assert( mem && "Internal error getting starting memory address for hash code.");
fc60825290 2011-04-18       stephan:     bcount = WHALLOC_API(bt_count_chain)( self, hash );
fc60825290 2011-04-18       stephan:     if( ! bcount )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         assert( 0 && "Internal error counting block chain length.");
fc60825290 2011-04-18       stephan:         return NULL;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     blocksNeeded = (size/self->base.blockSize);
fc60825290 2011-04-18       stephan:     if( !blocksNeeded || (size%self->base.blockSize) ) ++blocksNeeded;
fc60825290 2011-04-18       stephan:     oldlen = (bcount * self->base.blockSize);
fc60825290 2011-04-18       stephan:     if( (size <= oldlen) || (blocksNeeded<=bcount) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan:         if( blocksNeeded < bcount )
fc60825290 2011-04-18       stephan:         { /*
fc60825290 2011-04-18       stephan:             Shrink if needed. This could be optimized, but this approach
fc60825290 2011-04-18       stephan:             is easy...
fc60825290 2011-04-18       stephan:           */
fc60825290 2011-04-18       stephan:             WHALLOC_API(size_t) mark;
fc60825290 2011-04-18       stephan:             if( 0 != WHALLOC_API(bt_clear_range)( self, hash ) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 UNLOCK;
fc60825290 2011-04-18       stephan:                 assert(0 && "WHALLOC_API(bt_realloc)() internal error while clearing memory range!");
fc60825290 2011-04-18       stephan:                 return NULL;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             mark = WHALLOC_API(bt_mark_range)( self, hash, size );
fc60825290 2011-04-18       stephan:             assert( (mark == hash) && "WHALLOC_API(bt_realloc)() internal error: bt_mark_range() returned unexpected result!" );
fc60825290 2011-04-18       stephan:             mem = WHALLOC_API(bt_mem_for_hash)( self, mark );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         if( self->base.freeIndexHint >= hash)
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             self->base.freeIndexHint = hash+blocksNeeded;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         return mem;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     re = 0;
fc60825290 2011-04-18       stephan:     if(1) do
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            See if we can expand in the neighboring blocks
fc60825290 2011-04-18       stephan:            before falling back to WHALLOC_API(bt_alloc)().
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) endStart;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) endex /* at-end position, not one-past */;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) goal;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) x;
fc60825290 2011-04-18       stephan:         char isUsed;
fc60825290 2011-04-18       stephan:         isUsed = 0;
fc60825290 2011-04-18       stephan:         endStart= hash + bcount;
fc60825290 2011-04-18       stephan:         endex= endStart;
fc60825290 2011-04-18       stephan:         goal = hash + blocksNeeded - 1;
fc60825290 2011-04-18       stephan:         while( (endex < self->bits.end)
fc60825290 2011-04-18       stephan:                && (endex < goal)
fc60825290 2011-04-18       stephan:                &&  !(isUsed=BITMAP_IS_USED(endex)))
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             ++endex;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( (endex >= self->bits.end) || isUsed )
fc60825290 2011-04-18       stephan:         { /* we can't fit. Fall back to WHALLOC_API(bt_alloc)() for the new block...*/
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         assert( endex == goal );
fc60825290 2011-04-18       stephan:         /* mark [endStart,endex] as used/linked
fc60825290 2011-04-18       stephan:            and endex as used/unlinked.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         if(1)
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Expanding memory @%p range [%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT"] to "
fc60825290 2011-04-18       stephan:                      "[%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT"] "
fc60825290 2011-04-18       stephan:                      "= %"WHALLOC_SIZE_T_PFMT" blocks for %"WHALLOC_SIZE_T_PFMT" bytes.\n",
fc60825290 2011-04-18       stephan:                      mem, hash, (hash+bcount-1),
fc60825290 2011-04-18       stephan:                      hash, endex, blocksNeeded, size));
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( self->base.allocBlockCount ) --self->base.allocBlockCount;/*account for re-linking of previous tail item. */
fc60825290 2011-04-18       stephan:         for( x = endStart-1; x <= endex; ++x )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             ++self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:             if( endex == x )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 BITMAP_UNLINK(x);
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 BITMAP_LINK(x);
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             BITMAP_USE(x);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( (self->base.freeIndexHint >= hash)
fc60825290 2011-04-18       stephan:             && (self->base.freeIndexHint <= endex)
fc60825290 2011-04-18       stephan:             )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             self->base.freeIndexHint = endex+1;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         return mem;
fc60825290 2011-04-18       stephan:     } while(0);
fc60825290 2011-04-18       stephan:     if( ! re ) re = WHALLOC_API(bt_alloc_impl)( self, size, 0 );
fc60825290 2011-04-18       stephan:     if( re && (mem != re) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /*WHALLOC_API(size_t) end;*/
fc60825290 2011-04-18       stephan:         memcpy( re, mem, oldlen );
fc60825290 2011-04-18       stephan:         if(0) memset( mem, 0, oldlen ); /* arguable */
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan:         WHALLOC_API(bt_clear_range)( self, hash );
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:         assert( self->base.allocCount );
fc60825290 2011-04-18       stephan:         if( self->base.allocBlockCount ) --self->base.allocCount;
fc60825290 2011-04-18       stephan:         end = (hash+bcount);
fc60825290 2011-04-18       stephan:         for( ; hash < end; ++hash )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             --self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:             BITMAP_UNUSE(hash);
fc60825290 2011-04-18       stephan:             BITMAP_UNLINK(hash);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #undef FBALLOC
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return re;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(bt_alloc)( WHALLOC_API(bt) * const self, WHALLOC_API(size_t) size  )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return WHALLOC_API(bt_alloc_impl)( self, size, 1 );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_free)( WHALLOC_API(bt) * const self, void * m )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     unsigned char const * ucm;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:     int drc;
fc60825290 2011-04-18       stephan:     if( ! self || !m ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan: #define FBFREE if(self->base.fallback.free && self->base.fallback.realloc) { self->base.fallback.free(m); UNLOCK; return WHALLOC_API(rc).OK; }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     LOCK_OR(WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:     ucm = (unsigned char const *)m;
fc60825290 2011-04-18       stephan:     hash = whalloc_bt_hash_addr( self, m );
fc60825290 2011-04-18       stephan:     LOGSELF(("delloc @%p, hash=%"WHALLOC_SIZE_T_PFMT"\n",m,hash));
fc60825290 2011-04-18       stephan:     if( hash >= self->bits.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Cannot dealloc memory @%p.%s\n",
fc60825290 2011-04-18       stephan:                  m,(self->base.fallback.free ? " Trying fallback..." : "")));
fc60825290 2011-04-18       stephan:         FBFREE;
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         assert(0 && "WHALLOC_API(bt_free)() was asked to release memory it does not own!");
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).UsageError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     assert( ucm == WHALLOC_API(bt_mem_for_hash)( self, hash ) );
fc60825290 2011-04-18       stephan:     drc = WHALLOC_API(bt_clear_range)( self, hash );
fc60825290 2011-04-18       stephan:     if( WHALLOC_API(rc).OK != drc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Deallocation failed with rc %d!\n",drc));
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan: #undef FBFREE
fc60825290 2011-04-18       stephan:     return drc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Implements WHALLOC_API(realloc_f)() interface and requires that
fc60825290 2011-04-18       stephan:    allocState be-a (WHALLOC_API(bt)*).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static void * WHALLOC_API(bt_allocator_realloc)( void * mem, unsigned int n, void * allocState )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return allocState
fc60825290 2011-04-18       stephan:         ? WHALLOC_API(bt_realloc)( (WHALLOC_API(bt) *)allocState, mem, n )
fc60825290 2011-04-18       stephan:         : NULL;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_allocator)( WHALLOC_API(bt) * b, WHALLOC_API(allocator) * a )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b || !a ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         a->realloc = WHALLOC_API(bt_allocator_realloc);
fc60825290 2011-04-18       stephan:         a->state = b;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_drain)( WHALLOC_API(bt) * const self )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     LOCK_OR(WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:     memset( self->base.mem, 0, self->base.size );
fc60825290 2011-04-18       stephan:     WHALLOC_API(bt_clear_table)( self );
fc60825290 2011-04-18       stephan:     LOGSELF(("WHALLOC_API(bt_drain)(%p) {}\n",(void const*)self));
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(bt_dump_debug)( WHALLOC_API(bt) const * const self, FILE * out )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) at;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) count;
fc60825290 2011-04-18       stephan:     char isL;
fc60825290 2011-04-18       stephan:     char isU;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) inNode;
fc60825290 2011-04-18       stephan:     int rc;
fc60825290 2011-04-18       stephan:     if( ! self ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     LOCK_OR(WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan: #define NUM "%"WHALLOC_SIZE_T_PFMT
fc60825290 2011-04-18       stephan:     fprintf(out, "%s(): self=%p (sizeof="NUM")\n", __func__, (void const *)self, (WHALLOC_API(size_t))sizeof(WHALLOC_API(bt)) );
fc60825290 2011-04-18       stephan:     fprintf(out,"Allocator:\n");
fc60825290 2011-04-18       stephan:     fprintf(out,"\trealSize\t"NUM"\n\tusableSize\t"NUM"\n"
fc60825290 2011-04-18       stephan:             "\tblockSize\t"NUM"\n\thashBits\t%d\n\thashMask\t%08ux\n"
fc60825290 2011-04-18       stephan:             "\tbitmap is stealing "NUM" bytes (%1.2f%%) of the storage.\n",
fc60825290 2011-04-18       stephan:             self->base.size, self->base.usize,
fc60825290 2011-04-18       stephan:             self->base.blockSize, self->base.bitCount, (unsigned int)self->base.hashMask,
fc60825290 2011-04-18       stephan:             (WHALLOC_API(size_t))(self->base.size - self->base.usize),
fc60825290 2011-04-18       stephan: 	      ((1.0*(self->bits.byteCount))/(1.0*self->base.size))*100.0
fc60825290 2011-04-18       stephan:             );
fc60825290 2011-04-18       stephan:     fprintf(out,
fc60825290 2011-04-18       stephan:             "\tself->base.mem\t%p\n"
fc60825290 2011-04-18       stephan:             "\tself->base.uspace\t%p\n"
fc60825290 2011-04-18       stephan:             "\tself->base.end\t%p\n",
fc60825290 2011-04-18       stephan:             self->base.mem,
fc60825290 2011-04-18       stephan:             self->base.uspace,
fc60825290 2011-04-18       stephan:             self->base.end
fc60825290 2011-04-18       stephan:             );
fc60825290 2011-04-18       stephan:     fprintf(out, "Bitmap:\n\tbytes reserved\t"NUM"\n\tmax entries\t"NUM"\n"
fc60825290 2011-04-18       stephan:             "\tWHALLOC_API(bt_CacheLength)="NUM" bytes (enough for "NUM" entries)\n",
fc60825290 2011-04-18       stephan:             self->bits.byteCount, self->bits.end,
fc60825290 2011-04-18       stephan:             (WHALLOC_API(size_t)) WHALLOC_API(bt_CacheLength), (WHALLOC_API(size_t)) (WHALLOC_API(bt_CacheLength)*4)
fc60825290 2011-04-18       stephan:             );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     fprintf(out, "Used entries:\n"
fc60825290 2011-04-18       stephan:             "\t"NUM" of "NUM" block(s) alloced using "NUM" bytes from "NUM" allocation(s).\n",
fc60825290 2011-04-18       stephan:             self->base.allocBlockCount, self->bits.end,
fc60825290 2011-04-18       stephan:             self->base.allocBlockCount * self->base.blockSize,
fc60825290 2011-04-18       stephan:             self->base.allocCount );
fc60825290 2011-04-18       stephan:     fprintf(out, "Dump of used bitmap entries:\n");
fc60825290 2011-04-18       stephan:     at = 0;
fc60825290 2011-04-18       stephan:     count = 0;
fc60825290 2011-04-18       stephan:     inNode = WHALLOC_API(rc).HashCodeError;
fc60825290 2011-04-18       stephan:     for( ; at < self->bits.end; ++at )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         isL = BITMAP_IS_LINKED(at);
fc60825290 2011-04-18       stephan:         isU = BITMAP_IS_USED(at);
fc60825290 2011-04-18       stephan:         if( ! isL && !isU )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             inNode = WHALLOC_API(rc).HashCodeError;
fc60825290 2011-04-18       stephan:             pos = 0;
fc60825290 2011-04-18       stephan:             continue;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( WHALLOC_API(rc).HashCodeError == inNode )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( isU )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 if( isL )
fc60825290 2011-04-18       stephan:                 {
fc60825290 2011-04-18       stephan:                     inNode = at;
fc60825290 2011-04-18       stephan:                 }
fc60825290 2011-04-18       stephan:                 fprintf(out, "\t%s block #"NUM": addr=%p\n",
fc60825290 2011-04-18       stephan:                         (isL ? "Start" : "Single"),
fc60825290 2011-04-18       stephan:                         at,  WHALLOC_API(bt_mem_for_hash)(self,at) );
fc60825290 2011-04-18       stephan:                 pos = 1;
fc60825290 2011-04-18       stephan:                 ++count;
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             ++count;
fc60825290 2011-04-18       stephan:             ++pos;
fc60825290 2011-04-18       stephan:             if( isL )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 fprintf(out, "\t\tspan> #"NUM": addr=%p\n",
fc60825290 2011-04-18       stephan:                         at, WHALLOC_API(bt_mem_for_hash)(self,at) );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 fprintf(out, "\t\t end> #"NUM": addr=%p (%"WHALLOC_SIZE_T_PFMT" blocks)\n",
fc60825290 2011-04-18       stephan:                         at, WHALLOC_API(bt_mem_for_hash)(self,at), pos );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             if( ! isL )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 inNode = WHALLOC_API(rc).HashCodeError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( count != self->base.allocBlockCount )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         fprintf(out,"ERROR: allocated block count mismatch: expected "
fc60825290 2011-04-18       stephan:                 NUM" but got "NUM"!\n", self->base.allocBlockCount, count );
fc60825290 2011-04-18       stephan:         rc = WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #undef NUM
fc60825290 2011-04-18       stephan:     assert( count == self->base.allocBlockCount );
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef BITMAP_BYTE
fc60825290 2011-04-18       stephan: #undef BITMAP_IS_LINKED
fc60825290 2011-04-18       stephan: #undef BITMAP_IS_USED
fc60825290 2011-04-18       stephan: #undef BITMAP_LINK
fc60825290 2011-04-18       stephan: #undef BITMAP_SET_LINK
fc60825290 2011-04-18       stephan: #undef BITMAP_SET_USAGE
fc60825290 2011-04-18       stephan: #undef BITMAP_UNLINK
fc60825290 2011-04-18       stephan: #undef BITMAP_UNSET
fc60825290 2011-04-18       stephan: #undef BITMAP_UNUSE
fc60825290 2011-04-18       stephan: #undef BITMAP_USE
fc60825290 2011-04-18       stephan: #undef BYTES_BYTEFOR
fc60825290 2011-04-18       stephan: #undef BYTES_GET
fc60825290 2011-04-18       stephan: #undef BYTES_SET
fc60825290 2011-04-18       stephan: #undef BYTES_TOGGLE
fc60825290 2011-04-18       stephan: #undef BYTES_UNSET
fc60825290 2011-04-18       stephan: #undef LOGSELF
fc60825290 2011-04-18       stephan: #undef MARKER
fc60825290 2011-04-18       stephan: #undef whalloc_bt_hash_offset
fc60825290 2011-04-18       stephan: #undef whalloc_bt_hash_addr
fc60825290 2011-04-18       stephan: #undef UNLOCK
fc60825290 2011-04-18       stephan: #undef LOCK_OR
fc60825290 2011-04-18       stephan: /* end file whalloc_bt.c */
fc60825290 2011-04-18       stephan: /* begin file whalloc_ht.c */
fc60825290 2011-04-18       stephan: #line 8 "whalloc_ht.c"
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Defined/documented in whalloc.c */
fc60825290 2011-04-18       stephan: extern WHALLOC_API(size_t) whalloc_allocator_base_hash_offset( WHALLOC_API(allocator_base) const * self, WHALLOC_API(size_t) off );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Defined/documented in whalloc.c */
fc60825290 2011-04-18       stephan: extern WHALLOC_API(size_t) whalloc_allocator_base_hash_addr( WHALLOC_API(allocator_base) const * self, void const * addr_ );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(ht_entry) WHALLOC_API(ht_entry_empty) = whalloc_ht_entry_empty_m;
fc60825290 2011-04-18       stephan: const WHALLOC_API(ht) WHALLOC_API(ht_empty) = whalloc_ht_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #include <stdio.h>
fc60825290 2011-04-18       stephan: #if !defined(NDEBUG)
fc60825290 2011-04-18       stephan: #  define LOGBASE(mp_exp) if( self && self->log ) \
fc60825290 2011-04-18       stephan:     { self->log("%s:%d:%s(): ",__FILE__,__LINE__,__func__); \
fc60825290 2011-04-18       stephan:         self->log mp_exp; \
fc60825290 2011-04-18       stephan:     } else (void)0
fc60825290 2011-04-18       stephan: #  define LOGSELF(mp_exp) if( self && self->base.log )   \
fc60825290 2011-04-18       stephan:     { self->base.log("%s:%d:%s(): ",__FILE__,__LINE__,__func__); \
fc60825290 2011-04-18       stephan:         self->base.log mp_exp; \
fc60825290 2011-04-18       stephan:     } else (void)0
fc60825290 2011-04-18       stephan: #define MARKER(mp_exp) printf("MARKER: %s:%d:%s(): ",__FILE__,__LINE__,__func__); printf mp_exp
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #  define LOGSELF(mp_exp) (void)0
fc60825290 2011-04-18       stephan: #  define LOGBASE(mp_exp) (void)0
fc60825290 2011-04-18       stephan: #  define MARKER(mp_exp) ((void)0)
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define LOCK_OR(RC) if( self->base.mutex.lock ) if( 0 != self->base.mutex.lock(self->base.mutex.state) ) return RC
fc60825290 2011-04-18       stephan: #define UNLOCK if( self->base.mutex.unlock ) self->base.mutex.unlock( self->base.mutex.state )
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Internal masking macros:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    WHALLOC_MASK is the complete mask, with all usable bits set set.
fc60825290 2011-04-18       stephan:    Bits to the left of the usable space must explicitly be zeroed.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    WHALLOC_LENGTH_BITS = the number of bits which can be used for
fc60825290 2011-04-18       stephan:    storing the length of an allocated block. Normally
fc60825290 2011-04-18       stephan:    (WHALLOC_BITNESS-1). All non-length bits are assumed to be
fc60825290 2011-04-18       stephan:    flag bits.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    WHALLOC_FLAG_MASK is a mask of only the bits used as flags.
fc60825290 2011-04-18       stephan:    Currently the only flag is the in-use bit. Each additional flag
fc60825290 2011-04-18       stephan:    halves the maximum size of an allocation block, and
fc60825290 2011-04-18       stephan:    WHALLOC_LENGTH_BITS must be reduced by one for each flag bit.
fc60825290 2011-04-18       stephan:    Flag bits are assumed to be the left-most bits. All non-flag
fc60825290 2011-04-18       stephan:    bits are assumed to be length bits.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    WHALLOC_LEN_MASK is a mask of only the bit used as length
fc60825290 2011-04-18       stephan:    data. Length bits are assumed to be the right-most bits.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    WHALLOC_FLAG_USED is a mask of only the in-use bit.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #if 8 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan: #   define WHALLOC_LENGTH_BITS 7
fc60825290 2011-04-18       stephan: #   define WHALLOC_FLAG_MASK 0x80
fc60825290 2011-04-18       stephan: #elif 16 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan: #   define WHALLOC_LENGTH_BITS 15
fc60825290 2011-04-18       stephan: #   define WHALLOC_FLAG_MASK (WHALLOC_MASK & 0x8000)
fc60825290 2011-04-18       stephan: #elif 32 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan: #   define WHALLOC_LENGTH_BITS 31
fc60825290 2011-04-18       stephan: #   define WHALLOC_FLAG_MASK (0x01 << WHALLOC_LENGTH_BITS)
fc60825290 2011-04-18       stephan: #elif 64 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan: //#   error "UNTESTED CODE!"
fc60825290 2011-04-18       stephan: #   define WHALLOC_LENGTH_BITS 48
fc60825290 2011-04-18       stephan: #   define WHALLOC_FLAG_MASK (((uint64_t)0x01) << WHALLOC_LENGTH_BITS)
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #  error "All other values are untested!"
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Maintenance reminder: we need a per-BITNESS def of WHALLOC_FLAG_USED if we add more flag bits */
fc60825290 2011-04-18       stephan: #define WHALLOC_FLAG_USED WHALLOC_FLAG_MASK
fc60825290 2011-04-18       stephan: #define WHALLOC_LEN_MASK (WHALLOC_MASK & ~(WHALLOC_FLAG_MASK))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** Returns the LENGTH parts of integer I. */
fc60825290 2011-04-18       stephan: #define N_TO_ENTRYLEN(I) (((WHALLOC_API(size_t))(I)) & WHALLOC_LEN_MASK)
fc60825290 2011-04-18       stephan: /** Returns the LENGTH value of the (WHALLOC_API(ht_entry)*) E */
fc60825290 2011-04-18       stephan: #define ENTRY_GETLEN(E) N_TO_ENTRYLEN((E)->lenfl)
fc60825290 2011-04-18       stephan: /** Returns the FLAG parts of integer I. */
fc60825290 2011-04-18       stephan: #define N_TO_ENTRYFL(I) ((I) & WHALLOC_FLAG_MASK)
fc60825290 2011-04-18       stephan: /** Returns the FLAG value of the (WHALLOC_API(ht_entry)*) E */
fc60825290 2011-04-18       stephan: #define ENTRY_GETFL(E) N_TO_ENTRYFL((E)->lenfl)
fc60825290 2011-04-18       stephan: #define ENTRY_IS_USED(E) ((E)->lenfl & WHALLOC_FLAG_USED)
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Returns the given LENGTH value and FLAGS
fc60825290 2011-04-18       stephan:    values, encoded into a single value. LENGTH
fc60825290 2011-04-18       stephan:    and FLAGS must be fully masked.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define ENTRY_ENCODE(I,F) (N_TO_ENTRYLEN(I) | N_TO_ENTRYFL(F))
fc60825290 2011-04-18       stephan: #define ENTRY_SET_USE_ALLOC(E,I) (E)->lenfl = ENTRY_ENCODE(I,WHALLOC_FLAG_USED)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define whalloc_ht_hash_offset(S,O) whalloc_allocator_base_hash_offset(&(S)->base,(O))
fc60825290 2011-04-18       stephan: #define whalloc_ht_hash_addr(S,O) whalloc_allocator_base_hash_addr(&(S)->base,(O))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   Returns the address of the (not-necessarily-aligned) memory refered
fc60825290 2011-04-18       stephan:   to by the given hashcode (block index). at must be a valid hashcode
fc60825290 2011-04-18       stephan:   for self. Returns 0 on error (!self or 'at' out of range).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static unsigned char * WHALLOC_API(ht_mem_for_hash)( WHALLOC_API(ht) const * const self,
fc60825290 2011-04-18       stephan:                                            WHALLOC_API(size_t) at )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return !self
fc60825290 2011-04-18       stephan:         ? NULL
fc60825290 2011-04-18       stephan:         : ( (at >= self->ht.end)
fc60825290 2011-04-18       stephan:            ? NULL
fc60825290 2011-04-18       stephan:             : (self->base.uspace + ( self->base.blockSize * at )) )
fc60825290 2011-04-18       stephan:         ;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(ht_dump_debug)( WHALLOC_API(ht) const * const self, FILE * out )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) end;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) at;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) i;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) len;
fc60825290 2011-04-18       stephan:     WHALLOC_API(ht_entry) const * e;
fc60825290 2011-04-18       stephan:     if( ! self ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     end = self->ht.end;
fc60825290 2011-04-18       stephan:     fprintf(out, "%s(): self=%p (sizeof=%"WHALLOC_SIZE_T_PFMT")\n", __func__, (void const *)self,(WHALLOC_API(size_t))sizeof(WHALLOC_API(ht)) );
fc60825290 2011-04-18       stephan:     fprintf(out,"Allocator:\n\trealSize\t%"WHALLOC_SIZE_T_PFMT"\n\tusableSize\t%"WHALLOC_SIZE_T_PFMT""
fc60825290 2011-04-18       stephan:             "\n\tblockSize\t%"WHALLOC_SIZE_T_PFMT"\n\thashBits\t%d\n\thashMask\t%08ux\n",
fc60825290 2011-04-18       stephan:             self->base.size, self->base.usize,
fc60825290 2011-04-18       stephan:             self->base.blockSize, self->base.bitCount, (unsigned int) self->base.hashMask);
fc60825290 2011-04-18       stephan:     fprintf(out, "Hashtable:\n\tbytes\t%"WHALLOC_SIZE_T_PFMT"\n\tend\t%"WHALLOC_SIZE_T_PFMT" (%"WHALLOC_SIZE_T_PFMT" allocated)\n"
fc60825290 2011-04-18       stephan:             "\tis-initial entries\t%"WHALLOC_SIZE_T_PFMT"\n"
fc60825290 2011-04-18       stephan:             "\talloced blocks\t%"WHALLOC_SIZE_T_PFMT"\n"
fc60825290 2011-04-18       stephan:             "\tmemory usage (%1.2f%%)\n"
fc60825290 2011-04-18       stephan:             "Used entries:\n",
fc60825290 2011-04-18       stephan:             self->ht.sizeOf, end, self->ht.len,
fc60825290 2011-04-18       stephan:             self->base.allocCount,
fc60825290 2011-04-18       stephan:             self->base.allocBlockCount,
fc60825290 2011-04-18       stephan:             ((1.0*(self->ht.sizeOf))/(1.0*self->base.size))*100.0
fc60825290 2011-04-18       stephan:             );
fc60825290 2011-04-18       stephan:     at = 0;
fc60825290 2011-04-18       stephan:     i = 0;
fc60825290 2011-04-18       stephan:     len = 0;
fc60825290 2011-04-18       stephan:     e = 0;
fc60825290 2011-04-18       stephan:     for( ; at < self->ht.end; ++at, ++i )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         e = &self->ht.head[at];
fc60825290 2011-04-18       stephan:         if( ! ENTRY_IS_USED(e) ) continue;
fc60825290 2011-04-18       stephan:         len = ENTRY_GETLEN(e);
fc60825290 2011-04-18       stephan:         fprintf(out, "\t%s #%"WHALLOC_SIZE_T_PFMT": encoded=%08ux hash=%"WHALLOC_SIZE_T_PFMT" size=%"WHALLOC_SIZE_T_PFMT", addr=%p\n",
fc60825290 2011-04-18       stephan:                 (len ? "Entry" : "    span>"), i, (unsigned int)e->lenfl, at, len,
fc60825290 2011-04-18       stephan:                 WHALLOC_API(ht_mem_for_hash)(self,at) );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(ht_init)( WHALLOC_API(ht) * const self,
fc60825290 2011-04-18       stephan:               void* buffer,
fc60825290 2011-04-18       stephan:               WHALLOC_API(size_t) size,
fc60825290 2011-04-18       stephan:               WHALLOC_API(size_t) blockSize
fc60825290 2011-04-18       stephan:              )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     static const WHALLOC_API(size_t) MaxSize = (WHALLOC_MASK);
fc60825290 2011-04-18       stephan:     static const WHALLOC_API(size_t) MinSize = 64/*arbitrary!*/;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) i;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) maxItems;
fc60825290 2011-04-18       stephan:     size_t check;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) x;
fc60825290 2011-04-18       stephan:     int rc;
fc60825290 2011-04-18       stephan:     WHALLOC_API(ht_entry) * ht;
fc60825290 2011-04-18       stephan:     LOGSELF(("initializing...\n"));
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     LOGSELF(("WHALLOC_BITNESS=%"WHALLOC_SIZE_T_PFMT" WHALLOC_FLAG_MASK=%x WHALLOC_LEN_MASK=%x\n",
fc60825290 2011-04-18       stephan:              WHALLOC_BITNESS,WHALLOC_FLAG_MASK,WHALLOC_LEN_MASK));
fc60825290 2011-04-18       stephan:     LOGSELF(("WHALLOC_FLAG_USED=%04x/%"WHALLOC_SIZE_T_PFMT"\n",
fc60825290 2011-04-18       stephan:             WHALLOC_FLAG_USED,WHALLOC_FLAG_USED));
fc60825290 2011-04-18       stephan:     if( (size > MaxSize) || (size < MinSize) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Size %"WHALLOC_SIZE_T_PFMT" must be in the range %"WHALLOC_SIZE_T_PFMT" .. %"WHALLOC_SIZE_T_PFMT"\n",size, MinSize, MaxSize));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     if( ! blockSize ) blockSize = 8;
fc60825290 2011-04-18       stephan:     if( blockSize >= size )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Block size %"WHALLOC_SIZE_T_PFMT" must be smaller than the buffer size (%"WHALLOC_SIZE_T_PFMT")\n",blockSize,size));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( blockSize < (sizeof(WHALLOC_API(ht_entry))) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Block size of %"WHALLOC_SIZE_T_PFMT" is too small for this allocator.\n",blockSize));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).RangeError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     maxItems = 0;
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            Here we guestimate the maximum number of objects we can
fc60825290 2011-04-18       stephan:            handle.  The heuristic isn't 100% accurate - it can waste a
fc60825290 2011-04-18       stephan:            block or two - but does fairly well for most cases.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan: #if 8 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan:         maxItems = (size / blockSize);
fc60825290 2011-04-18       stephan: #elif 16 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan:         if( 4 == blockSize )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             maxItems = (WHALLOC_API(size_t))((size_t)size/6)+2;
fc60825290 2011-04-18       stephan:             /* works fairly well: (WHALLOC_API(size_t))((size_t)size/6)+blockSize;*/
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else /* this works well for 2/8/16+, but not 4:*/
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             maxItems = (size / (blockSize+2))+2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #elif 32 == WHALLOC_BITNESS
fc60825290 2011-04-18       stephan:         if( (4 == blockSize) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             maxItems = (WHALLOC_API(size_t))((size_t)size/8)+2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /* i haven't yet found one which works really well. This case
fc60825290 2011-04-18       stephan:                loses relatively many entries.
fc60825290 2011-04-18       stephan:             */
fc60825290 2011-04-18       stephan:             maxItems = (size / (blockSize+2))+2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: //#  error "Unhandled WHALLOC_BITNESS value!"
fc60825290 2011-04-18       stephan:         if( (4 == blockSize) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             maxItems = (WHALLOC_API(size_t))((size_t)size/8)+2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /* i haven't yet found one which works really well. This case
fc60825290 2011-04-18       stephan:                loses relatively many entries.
fc60825290 2011-04-18       stephan:             */
fc60825290 2011-04-18       stephan:             maxItems = (size / (blockSize+2))+2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* FIXME: refactor to use whalloc_calc_mask2(). See WHALLOC_API(bt_init)() for example. */
fc60825290 2011-04-18       stephan:     self->base.blockSize = blockSize;
fc60825290 2011-04-18       stephan:     self->base.bitCount = 0;
fc60825290 2011-04-18       stephan:     check = 1;
fc60825290 2011-04-18       stephan:     for( check = 1; check <= ((size_t)maxItems);
fc60825290 2011-04-18       stephan:          (check = check*2) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         ++self->base.bitCount;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( self->base.bitCount > (WHALLOC_BITNESS-1) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Some value is too high: self->base.bitCount(=%"WHALLOC_SIZE_T_PFMT") was pushed above the maximum value of %d!\n",
fc60825290 2011-04-18       stephan:                 self->base.bitCount,(WHALLOC_BITNESS-1)));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).RangeError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     self->base.hashMask = WHALLOC_MASK >> (WHALLOC_BITNESS - self->base.bitCount);
fc60825290 2011-04-18       stephan:     self->base.mem = buffer;
fc60825290 2011-04-18       stephan:     self->base.size = size;
fc60825290 2011-04-18       stephan:     self->base.end = self->base.mem + size;
fc60825290 2011-04-18       stephan:     self->ht.head = (WHALLOC_API(ht_entry)*)self->base.mem;
fc60825290 2011-04-18       stephan:     self->ht.len = maxItems;
fc60825290 2011-04-18       stephan:     self->ht.sizeOf = sizeof(WHALLOC_API(ht_entry)) * self->ht.len;
fc60825290 2011-04-18       stephan:     self->base.uspace = self->base.mem + self->ht.sizeOf;
fc60825290 2011-04-18       stephan:     self->base.usize = size - self->ht.sizeOf;
fc60825290 2011-04-18       stephan:     self->base.freeIndexHint = 0;
fc60825290 2011-04-18       stephan:     LOGSELF(("size=%"WHALLOC_SIZE_T_PFMT", maxItems=%"WHALLOC_SIZE_T_PFMT", blockSize=%"WHALLOC_SIZE_T_PFMT", check=%"WHALLOC_SIZE_T_PFMT", self->base.bitCount=%"WHALLOC_SIZE_T_PFMT", hashMask=0x%04x/%d\n",
fc60825290 2011-04-18       stephan:             size, maxItems, blockSize, check,self->base.bitCount,self->base.hashMask,self->base.hashMask));
fc60825290 2011-04-18       stephan:     LOGSELF(("mem=%p, uspace=%p, allocatable bytes=%"WHALLOC_SIZE_T_PFMT"\n",
fc60825290 2011-04-18       stephan:             self->base.mem, self->base.uspace,self->base.usize));
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:     /* FIXME: if we're wasting self->ht entries (that is, some are
fc60825290 2011-04-18       stephan:      unreachable in the memory range), shrink self->ht until we get
fc60825290 2011-04-18       stephan:      a nice fit. If we're wasting memory (entries which can never be
fc60825290 2011-04-18       stephan:      used), we should shrink the list and adjust self->base.uspace/self->base.usize
fc60825290 2011-04-18       stephan:      accordingly.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:      See WHALLOC_API(bt_init)() for how a similar problem is solved there.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:     ht = self->ht.head;
fc60825290 2011-04-18       stephan:     LOGSELF(("Hashtable@%p: %"WHALLOC_SIZE_T_PFMT" entries using %"WHALLOC_SIZE_T_PFMT" bytes (%1.2f%%).\n",
fc60825290 2011-04-18       stephan:             (void const *)ht,self->ht.len, self->ht.sizeOf,
fc60825290 2011-04-18       stephan:             (1.0*self->ht.sizeOf)/(size)*100));
fc60825290 2011-04-18       stephan:     for( i = 0; i < self->ht.len; ++i, ++ht )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         *ht = WHALLOC_API(ht_entry_empty);
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     i = 0;
fc60825290 2011-04-18       stephan:     rc = 0;
fc60825290 2011-04-18       stephan:     for( x = 0; (x < self->base.usize); x += blockSize, ++i )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            Try to hash all block boundaries:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            a) To ensure no hash collisions.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            b) Try to figure out how much space we might be wasting on
fc60825290 2011-04-18       stephan:            unused hash entries.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            c) To ensure we allocated enough hash entries.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         unsigned char const * addr;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:         WHALLOC_API(ht_entry) * e;
fc60825290 2011-04-18       stephan:         addr = self->base.uspace + x;
fc60825290 2011-04-18       stephan:         assert( whalloc_ht_hash_offset( self, x ) == whalloc_ht_hash_addr( self, addr ) );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         hash =
fc60825290 2011-04-18       stephan:             whalloc_ht_hash_offset( self, x )
fc60825290 2011-04-18       stephan:             /*whalloc_ht_hash_addr( self, addr )*/
fc60825290 2011-04-18       stephan:             ;
fc60825290 2011-04-18       stephan:         if( WHALLOC_API(rc).HashCodeError == hash )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Step #%"WHALLOC_SIZE_T_PFMT" Hash of addr offset %"WHALLOC_SIZE_T_PFMT" @ %p got unexpected hash value %"WHALLOC_SIZE_T_PFMT"!. self->ht.end=%"WHALLOC_SIZE_T_PFMT"\n",
fc60825290 2011-04-18       stephan:                      i, x, addr, hash, self->ht.end ));
fc60825290 2011-04-18       stephan:             rc = WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         e = &self->ht.head[hash];
fc60825290 2011-04-18       stephan:         if( WHALLOC_FLAG_USED & ENTRY_GETFL(e) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Step #%"WHALLOC_SIZE_T_PFMT" Hash of addr offset %"WHALLOC_SIZE_T_PFMT" @ %p = %"WHALLOC_SIZE_T_PFMT" got collision!\n",i, x, addr, hash ));
fc60825290 2011-04-18       stephan:             rc = WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         e->lenfl |= WHALLOC_FLAG_USED; /* just for checking for collisions, above. We'll undo this in a moment.*/
fc60825290 2011-04-18       stephan:         /*LOGSELF(("Step #%"WHALLOC_SIZE_T_PFMT" Hash of addr offset %"WHALLOC_SIZE_T_PFMT" @ %p = %"WHALLOC_SIZE_T_PFMT"\n",i, x, addr, hash ));*/
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     self->base.blockCount = self->ht.end = i;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     memset( self->ht.head, 0, self->ht.sizeOf ); /* Unset the USED flags we set above for testing purposes*/
fc60825290 2011-04-18       stephan:     if( i > self->ht.len )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("WARNING: overstepped table length by about %"WHALLOC_SIZE_T_PFMT" items.\n",
fc60825290 2011-04-18       stephan:                  (i-self->ht.len)));
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).HashingError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( i )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /**
fc60825290 2011-04-18       stephan:                FIXME: if we have enough space left, squeeze out the
fc60825290 2011-04-18       stephan:                extra ht entries, adjusting: self->base.uspace, self->base.usize,
fc60825290 2011-04-18       stephan:                ht->len until ht->len==(ht->end-1) or until we don't
fc60825290 2011-04-18       stephan:                have another full block.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:                Or calculate the number of hashtable entries more
fc60825290 2011-04-18       stephan:                accurately earlier on.
fc60825290 2011-04-18       stephan:             */
fc60825290 2011-04-18       stephan:             /*MARKER(("Wasted hash entries: %"WHALLOC_SIZE_T_PFMT".\n",(self->ht.len-i)));*/
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOGSELF(("ht.end=%"WHALLOC_SIZE_T_PFMT", ht.len=%"WHALLOC_SIZE_T_PFMT", ht.sizeOf=%"WHALLOC_SIZE_T_PFMT"\n",self->ht.end,self->ht.len,self->ht.sizeOf));
fc60825290 2011-04-18       stephan: #undef HASH
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: Tries to find an unused range of memory. On success it marks the all
fc60825290 2011-04-18       stephan: blocks of the span as in-use and marks the first element with the size
fc60825290 2011-04-18       stephan: of the range.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: startIndex = self->ht.head index to start at. It is a hint. if it's
fc60825290 2011-04-18       stephan: in use then it will be skipped over.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: size = size, in bytes, to allocate. It must be greater than 0.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: self is assumed to already be locked - this function does
fc60825290 2011-04-18       stephan: not lock it.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: On success, returns the index in self->ht.head of the page containing
fc60825290 2011-04-18       stephan: the memory record. On error it returns a value equal to or greater
fc60825290 2011-04-18       stephan: than self->ht.end (WHALLOC_API(rc).HashCodeError if !self or !size).
fc60825290 2011-04-18       stephan: The first record will contain the size parameter, and all subsequent
fc60825290 2011-04-18       stephan: blocks, if any, will be marked as in-use but having 0 bytes. That
fc60825290 2011-04-18       stephan: is a signal to the deallocator that those blocks "belong" to another
fc60825290 2011-04-18       stephan: block somewhere to the left of that block.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: This function adjusts self->base.allocBlockCount and
fc60825290 2011-04-18       stephan: self->base.allocCount. It also possibly updates self->freeIndexHint.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static WHALLOC_API(size_t) WHALLOC_API(ht_mark_range)( WHALLOC_API(ht) * const self,
fc60825290 2011-04-18       stephan:                                                WHALLOC_API(size_t) startIndex,
fc60825290 2011-04-18       stephan:                                                WHALLOC_API(size_t) size )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) endex;
fc60825290 2011-04-18       stephan:     WHALLOC_API(ht_entry) * e1;
fc60825290 2011-04-18       stephan:     WHALLOC_API(ht_entry) * e2;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) stride;
fc60825290 2011-04-18       stephan:     if( ! self || ! size ) return WHALLOC_API(rc).HashCodeError;
fc60825290 2011-04-18       stephan:     LOGSELF(("trying to mark range of %"WHALLOC_SIZE_T_PFMT" bytes starting at index %"WHALLOC_SIZE_T_PFMT"...\n",
fc60825290 2011-04-18       stephan:              size, startIndex));
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Overall algorithm:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        endex = startIndex + (size/self->base.blockSize)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex>=self->ht.end return error
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex is in-use:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        - startIndex = endex+1
fc60825290 2011-04-18       stephan:        - If startIndex>=self->ht.end, return error
fc60825290 2011-04-18       stephan:        - Else try again
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        If endex is unused:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        - Mark all blocks between (startIndex,endex) as used.
fc60825290 2011-04-18       stephan:        - Set self->ht[startIndex.lenfl length part] to size.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     if( startIndex >= self->ht.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return self->ht.end;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     endex = self->ht.end;
fc60825290 2011-04-18       stephan:     e1 = 0;
fc60825290 2011-04-18       stephan:     e2 = 0;
fc60825290 2011-04-18       stephan:     stride = (size/self->base.blockSize);
fc60825290 2011-04-18       stephan:     if( stride && !(size%self->base.blockSize) ) --stride;
fc60825290 2011-04-18       stephan:     do
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(ht_entry) * check;
fc60825290 2011-04-18       stephan:         WHALLOC_API(size_t) lastFree;
fc60825290 2011-04-18       stephan:         endex = startIndex + stride;
fc60825290 2011-04-18       stephan:         if( endex >= self->ht.end )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             return self->ht.end;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         e1 = &self->ht.head[startIndex];
fc60825290 2011-04-18       stephan:         e2 = &self->ht.head[endex];
fc60825290 2011-04-18       stephan:         LOGSELF(("Checking range [%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT"] ...\n",startIndex,endex));
fc60825290 2011-04-18       stephan:         if( ENTRY_IS_USED(e2) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             startIndex = endex + 1;
fc60825290 2011-04-18       stephan:             continue;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         /* ensure the whole range is not in use:*/
fc60825290 2011-04-18       stephan:         check = e2;
fc60825290 2011-04-18       stephan:         lastFree = endex;
fc60825290 2011-04-18       stephan:         for( ; (check != e1) && !ENTRY_IS_USED(check);
fc60825290 2011-04-18       stephan:              --check, --lastFree )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( check == e1 ) break; /* all blocks between [e1,e2] are free :-D*/
fc60825290 2011-04-18       stephan:         startIndex = lastFree+1;
fc60825290 2011-04-18       stephan:         /* try again.*/
fc60825290 2011-04-18       stephan:     } while(1);
fc60825290 2011-04-18       stephan:     if( (endex >= self->ht.end) || (startIndex >= self->ht.end) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return self->ht.end;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOGSELF(("Using range [%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT"]\n",startIndex,endex));
fc60825290 2011-04-18       stephan:     for( pos = startIndex ; pos <= endex; ++pos )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         e1 = &self->ht.head[pos];
fc60825290 2011-04-18       stephan:         ENTRY_SET_USE_ALLOC(e1,(pos==startIndex) ? size : 0);
fc60825290 2011-04-18       stephan:         LOGSELF(("Marking #%"WHALLOC_SIZE_T_PFMT" encoded=%08x, e->size=%"WHALLOC_SIZE_T_PFMT"\n",pos, e1->lenfl,ENTRY_GETLEN(e1)));
fc60825290 2011-04-18       stephan:         ++self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     /* e1 = &self->ht.head[startIndex]; */
fc60825290 2011-04-18       stephan:     ++self->base.allocCount;
fc60825290 2011-04-18       stephan:     if(1)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         unsigned char const * rawp;
fc60825290 2011-04-18       stephan:         rawp = WHALLOC_API(ht_mem_for_hash)( self, startIndex );
fc60825290 2011-04-18       stephan:         assert( rawp && "internal error in WHALLOC_API(ht_mark_range)!" );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     self->base.freeIndexHint = endex+1;
fc60825290 2011-04-18       stephan:     return startIndex;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**@ internal
fc60825290 2011-04-18       stephan:    The converse of WHALLOC_API(ht_mark_range)().
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Clears a range of blocks for re-use.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    startIndex must refer to an in-use hashtable entry. That block,
fc60825290 2011-04-18       stephan:    plus any others to its right associated via a multi-block
fc60825290 2011-04-18       stephan:    allocation, are marked as free.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Returns WHALLOC_API(rc).OK on error. If it returns WHALLOC_API(rc).InternalError
fc60825290 2011-04-18       stephan:    then the pool state is probably corrupt or unexpected. It returns
fc60825290 2011-04-18       stephan:    WHALLOC_API(rc).ArgError if !self and WHALLOC_API(rc).RangeError if
fc60825290 2011-04-18       stephan:    startIndex is not less than self->bits.end.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    This function adjusts self->base.allocBlockCount and
fc60825290 2011-04-18       stephan:    self->base.allocCount. It also possibly updates
fc60825290 2011-04-18       stephan:    self->freeIndexHint.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static int WHALLOC_API(ht_clear_range)( WHALLOC_API(ht) * const self,
fc60825290 2011-04-18       stephan:                                    WHALLOC_API(size_t) startIndex )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) pos;
fc60825290 2011-04-18       stephan:     WHALLOC_API(ht_entry) * e;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) xblocks;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) end;
fc60825290 2011-04-18       stephan:     if( ! self )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( startIndex >= self->ht.end)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).RangeError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     pos = startIndex;
fc60825290 2011-04-18       stephan:     e = &self->ht.head[pos];
fc60825290 2011-04-18       stephan:     /* WHALLOC_API(size_t) slots = (ENTRY_GETLEN(e) / self->base.blockSize); */
fc60825290 2011-04-18       stephan:     xblocks = (ENTRY_GETLEN(e) / self->base.blockSize);
fc60825290 2011-04-18       stephan:     if( xblocks && !(ENTRY_GETLEN(e) % self->base.blockSize) ) --xblocks;
fc60825290 2011-04-18       stephan:     end = pos + xblocks + 1;
fc60825290 2011-04-18       stephan:     LOGSELF(("Clearing range (%"WHALLOC_SIZE_T_PFMT",%"WHALLOC_SIZE_T_PFMT"]. Len=%"WHALLOC_SIZE_T_PFMT", blocks=%"WHALLOC_SIZE_T_PFMT", Block Size=%"WHALLOC_SIZE_T_PFMT"...\n",
fc60825290 2011-04-18       stephan:              pos,end,ENTRY_GETLEN(e),1+xblocks,self->base.blockSize));
fc60825290 2011-04-18       stephan:     for( ; pos < end; ++pos,
fc60825290 2011-04-18       stephan:              (e = &self->ht.head[pos]) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( ! ENTRY_IS_USED(e) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGSELF(("Internal error: we were expecting that hashtable entry #%"WHALLOC_SIZE_T_PFMT" was marked as used. encoded=%08x!\n",
fc60825290 2011-04-18       stephan:                      pos, e->lenfl ));
fc60825290 2011-04-18       stephan:             return WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( startIndex == pos )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ! ENTRY_GETLEN(e) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Expecting non-zero length at entry #%"WHALLOC_SIZE_T_PFMT"!\n",pos));
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( ENTRY_GETLEN(e) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGSELF(("Expecting zero length at entry #%"WHALLOC_SIZE_T_PFMT"!\n",pos));
fc60825290 2011-04-18       stephan:                 return WHALLOC_API(rc).InternalError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         LOGSELF(("Marking entry #%"WHALLOC_SIZE_T_PFMT" as unused. It says it owns %"WHALLOC_SIZE_T_PFMT" bytes.\n",
fc60825290 2011-04-18       stephan:                  pos, ENTRY_GETLEN(e)));
fc60825290 2011-04-18       stephan:         *e = WHALLOC_API(ht_entry_empty);
fc60825290 2011-04-18       stephan:         --self->base.allocBlockCount;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     --self->base.allocCount;
fc60825290 2011-04-18       stephan:     if( self->base.freeIndexHint > startIndex )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         self->base.freeIndexHint = startIndex;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return WHALLOC_API(rc).OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static void*
fc60825290 2011-04-18       stephan: WHALLOC_API(ht_alloc_ex)(
fc60825290 2011-04-18       stephan:                  WHALLOC_API(ht) * const self,
fc60825290 2011-04-18       stephan:                  WHALLOC_API(size_t) size,
fc60825290 2011-04-18       stephan:                  size_t align /* old artifact - not respected! */
fc60825290 2011-04-18       stephan:                  ) {
fc60825290 2011-04-18       stephan:     void * fb = 0;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:     unsigned char * rawp;
fc60825290 2011-04-18       stephan:     if( ! self ) return 0;
fc60825290 2011-04-18       stephan:     LOCK_OR(NULL);
fc60825290 2011-04-18       stephan: #define FBALLOC if(self->base.fallback.free && self->base.fallback.realloc) do { fb = self->base.fallback.realloc(0,size); UNLOCK; return fb; } while(0)
fc60825290 2011-04-18       stephan:     if (! size) {
fc60825290 2011-04-18       stephan:         size = self->base.blockSize;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     if (! align) {
fc60825290 2011-04-18       stephan: #if WHALLOC_USE_ALIGN
fc60825290 2011-04-18       stephan:         align = WHALLOC_ALIGN_MAX;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     LOGSELF(("pool=@%p, size=%"WHALLOC_SIZE_T_PFMT", align=%"WHALLOC_SIZE_T_PFMT"\n",(void const *)self, size, align));
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     if( (self->base.allocCount>=self->ht.end /*we're full*/)
fc60825290 2011-04-18       stephan:         /* || (self->base.blockSize < size) //FIXME: alloc > blockSize */
fc60825290 2011-04-18       stephan:         )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("pool=@%p cannot allocate %"WHALLOC_SIZE_T_PFMT" bytes. Trying fallback.\n",(void const *)self, size));
fc60825290 2011-04-18       stephan:         FBALLOC;
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     hash = 0;
fc60825290 2011-04-18       stephan:     hash =
fc60825290 2011-04-18       stephan:         whalloc_ht_hash_offset( self, self->base.freeIndexHint * self->base.blockSize )
fc60825290 2011-04-18       stephan:         ;
fc60825290 2011-04-18       stephan:     LOGSELF(("self->freeIndexHint=%"WHALLOC_SIZE_T_PFMT", hash=%"WHALLOC_SIZE_T_PFMT"\n",self->base.freeIndexHint,hash));
fc60825290 2011-04-18       stephan:     if( hash >= self->ht.end ) hash = 0;
fc60825290 2011-04-18       stephan:     hash = WHALLOC_API(ht_mark_range)( self, hash, size );/*  FIXME: size+ALIGNMENT? */
fc60825290 2011-04-18       stephan:     if( hash >= self->ht.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Could not allocate %"WHALLOC_SIZE_T_PFMT" bytes!\n",size));
fc60825290 2011-04-18       stephan:         FBALLOC;
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     rawp = WHALLOC_API(ht_mem_for_hash)( self, hash );
fc60825290 2011-04-18       stephan:     LOGSELF(("Allocating %"WHALLOC_SIZE_T_PFMT" bytes starting at @%p\n",size,rawp));
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return rawp;
fc60825290 2011-04-18       stephan: #undef FBALLOC
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(ht_alloc)( WHALLOC_API(ht) * const self, WHALLOC_API(size_t) size )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return WHALLOC_API(ht_alloc_ex)(self, size, WHALLOC_ALIGN_MAX);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int
fc60825290 2011-04-18       stephan: WHALLOC_API(ht_drain)( WHALLOC_API(ht) * const self )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     LOCK_OR(WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:     /* const size_t esz = sizeof(WHALLOC_API(ht_entry))*self->emax; */
fc60825290 2011-04-18       stephan:     self->base.allocCount = 0;
fc60825290 2011-04-18       stephan:     memset( self->base.mem, 0, self->base.size );
fc60825290 2011-04-18       stephan:     LOGSELF(("WHALLOC_API(ht_drain)(%p) {}\n",(void const*)self));
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(ht_free)( WHALLOC_API(ht) * const self, void * m )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     unsigned char const * ucm;
fc60825290 2011-04-18       stephan:     WHALLOC_API(size_t) hash;
fc60825290 2011-04-18       stephan:     int drc;
fc60825290 2011-04-18       stephan:     if( ! self || !m ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan: #define FBFREE if(self->base.fallback.free) { self->base.fallback.free(m); UNLOCK; return WHALLOC_API(rc).OK; }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     LOCK_OR(WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:     ucm = (unsigned char const *)m;
fc60825290 2011-04-18       stephan:     hash = whalloc_ht_hash_addr( self, m );
fc60825290 2011-04-18       stephan:     LOGSELF(("delloc @%p, hash=%"WHALLOC_SIZE_T_PFMT"\n",m,hash));
fc60825290 2011-04-18       stephan:     assert( ucm == WHALLOC_API(ht_mem_for_hash)( self, hash ) );
fc60825290 2011-04-18       stephan:     if( hash >= self->ht.end )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Cannot dealloc memory @%p.%s\n",
fc60825290 2011-04-18       stephan:                  m,(self->base.fallback.free ? " Trying fallback..." : "")));
fc60825290 2011-04-18       stephan:         FBFREE;
fc60825290 2011-04-18       stephan:         UNLOCK;
fc60825290 2011-04-18       stephan:         assert(0 && "Allocated was asked to release memory it does not own!");
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).UsageError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     drc = WHALLOC_API(ht_clear_range)( self, hash );
fc60825290 2011-04-18       stephan:     if( WHALLOC_API(rc).OK != drc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         LOGSELF(("Deallocation failed with rc %d!\n",drc));
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( self->base.freeIndexHint > hash )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         self->base.freeIndexHint = hash;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     UNLOCK;
fc60825290 2011-04-18       stephan:     return drc;
fc60825290 2011-04-18       stephan: #undef FBFREE
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef ENTRY_ENCODE
fc60825290 2011-04-18       stephan: #undef ENTRY_GETFL
fc60825290 2011-04-18       stephan: #undef ENTRY_GETLEN
fc60825290 2011-04-18       stephan: #undef ENTRY_LENGTH_BITS
fc60825290 2011-04-18       stephan: #undef LOGSELF
fc60825290 2011-04-18       stephan: #undef MARKER
fc60825290 2011-04-18       stephan: #undef N_TO_ENTRYFL
fc60825290 2011-04-18       stephan: #undef N_TO_ENTRYLEN
fc60825290 2011-04-18       stephan: #undef WHALLOC_ALIGN_MAX
fc60825290 2011-04-18       stephan: #undef WHALLOC_DEBUG
fc60825290 2011-04-18       stephan: #undef WHALLOC_FLAG_MASK
fc60825290 2011-04-18       stephan: #undef WHALLOC_FLAG_USED
fc60825290 2011-04-18       stephan: #undef WHALLOC_LEN_MASK
fc60825290 2011-04-18       stephan: #undef WHALLOC_LENGTH_BITS
fc60825290 2011-04-18       stephan: #undef UNLOCK
fc60825290 2011-04-18       stephan: #undef LOCK_OR
fc60825290 2011-04-18       stephan: /* end file whalloc_ht.c */
fc60825290 2011-04-18       stephan: /* begin file whalloc_pager.c */
fc60825290 2011-04-18       stephan: #line 8 "whalloc_pager.c"
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: #include <stdint.h> /* fixed-size integers. */
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* realloc() */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: enum WHALLOC_PAGER_FLAGS
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:     PAGER_BOOK_AUTO_VACUUM = 0x01
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !defined(NDEBUG)
fc60825290 2011-04-18       stephan: #  include <stdio.h> /* for debugging only */
fc60825290 2011-04-18       stephan: #  define LOGBOOK(B,mp_exp) if( (B) && (B)->log )              \
fc60825290 2011-04-18       stephan:     { (B)->log("%s:%d:%s(): ",__FILE__,__LINE__,__func__);     \
fc60825290 2011-04-18       stephan:         (B)->log mp_exp;                                       \
fc60825290 2011-04-18       stephan:     } else (void)0
fc60825290 2011-04-18       stephan: #  define MARKER(mp_exp) do{ printf("MARKER: %s:%d:%s(): ",__FILE__,__LINE__,__func__); printf mp_exp; } while(0)
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: #  define LOGBOOK(B,mp_exp) (void)0
fc60825290 2011-04-18       stephan: #  define MARKER(mp_exp) ((void)0)
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* Evalues to the number of bytes needed for N bits. */
fc60825290 2011-04-18       stephan: #define BITCOUNT_TO_BYTES(N) ( ((N)/8) + (((N)&&(!((N)%8))) ? 0 : 1) )
fc60825290 2011-04-18       stephan: /* Evalutes to the byte from array A storing the given BIT offset. */
fc60825290 2011-04-18       stephan: #define BYTES_BYTEFOR(A,BIT) ((A)[ BIT / 8 ])
fc60825290 2011-04-18       stephan: /* Sets the given bit in array A to 1. Evaluates to 1.*/
fc60825290 2011-04-18       stephan: #define BYTES_SET(A,BIT) ((BYTES_BYTEFOR(A,BIT) |= (0x01 << (BIT%8))),0x01)
fc60825290 2011-04-18       stephan: /* Sets the given bit in array A to 0. Evaluates to 0.*/
fc60825290 2011-04-18       stephan: #define BYTES_UNSET(A,BIT) ((BYTES_BYTEFOR(A,BIT) &= ~(0x01 << (BIT%8))),0x00)
fc60825290 2011-04-18       stephan: /* Gets the value (1 or 0) of the given BIT in array A. */
fc60825290 2011-04-18       stephan: #define BYTES_GET(A,BIT) ((BYTES_BYTEFOR(A,BIT) & (0x01 << (BIT%8))) ? 0x01 : 0x00)
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Toggles the given BIT in array A. Evaluates to the new value of
fc60825290 2011-04-18       stephan:    that bit (1 or 0).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define BYTES_TOGGLE(A,BIT) (BYTES_GET(A,BIT) ? (BYTES_UNSET(A,BIT)) : (BYTES_SET(B,BIT)))
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   #define BOOK_BYTEOF(P,BIT) ((P)->flags[ BIT / 8 ])
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define CHUNK_IS_USED(P,BIT) BYTES_GET((P)->flags,(BIT))
fc60825290 2011-04-18       stephan: /* Sets the given chunk (BIT) of page P to the given value (1 or 0).
fc60825290 2011-04-18       stephan:  Evaluates to 1 (if VAL) or 0. */
fc60825290 2011-04-18       stephan: #define CHUNK_SET_USAGE(P,BIT,VAL) ((VAL)?BYTES_SET((P)->flags,BIT):BYTES_UNSET((P)->flags,BIT))
fc60825290 2011-04-18       stephan: /* Sets the given chunk-as-used BIT in page P. Evaluates to 1.*/
fc60825290 2011-04-18       stephan: #define CHUNK_USE(P,BIT) CHUNK_SET_USAGE(P,BIT,1)
fc60825290 2011-04-18       stephan: /* Clears the given chunk-is-used BIT in page P. Evaluates to 0.*/
fc60825290 2011-04-18       stephan: #define CHUNK_UNUSE(P,BIT) CHUNK_SET_USAGE(P,BIT,0)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(page) WHALLOC_API(page_empty) = {
fc60825290 2011-04-18       stephan: 0/*length*/,
fc60825290 2011-04-18       stephan: 0/*chunkSize*/,
fc60825290 2011-04-18       stephan: 0/*useCount*/,
fc60825290 2011-04-18       stephan: 0/*nextFree*/,
fc60825290 2011-04-18       stephan: NULL/*flags*/,
fc60825290 2011-04-18       stephan: NULL/*pool*/,
fc60825290 2011-04-18       stephan: NULL/*next*/
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan:    Implements WHALLOC_API(realloc_f) interface. It ignores the allocState
fc60825290 2011-04-18       stephan:    argument and uses realloc(2).
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static void * WHALLOC_API(pager_realloc_default)( void * m, unsigned int n, void * allocState );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(book) WHALLOC_API(book_empty) = {
fc60825290 2011-04-18       stephan: 0/*pageLength*/,
fc60825290 2011-04-18       stephan: 0/*chunkSize*/,
fc60825290 2011-04-18       stephan: 0/*flags*/,
fc60825290 2011-04-18       stephan: NULL/*page*/,
fc60825290 2011-04-18       stephan: NULL/*log*/,
fc60825290 2011-04-18       stephan: whalloc_allocator_empty_m/*alloc*/,
fc60825290 2011-04-18       stephan: whalloc_allocator_empty_m/*pageAlloc*/,
fc60825290 2011-04-18       stephan: whalloc_mutex_empty_m/*mutex*/
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #define BOOK_LOCK_OR(B,COND,RC) if( (COND) && (B)->mutex.lock ) { if( 0 != (B)->mutex.lock( (B)->mutex.state ) ) return RC; }
fc60825290 2011-04-18       stephan: #define BOOK_UNLOCK(B,COND) if( (COND) && (B)->mutex.unlock ) (B)->mutex.unlock( (B)->mutex.state )
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(pager_realloc_default)( void * m, unsigned int n, void * _allocState )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return realloc( m, n );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     A realloc(3)-proxying WHALLOC_API(allocator) object.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static const WHALLOC_API(allocator) WHALLOC_API(pager_allocator_default) =
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: WHALLOC_API(pager_realloc_default),
fc60825290 2011-04-18       stephan: NULL
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: unsigned int WHALLOC_API(page_calc_size)( uint16_t n, uint16_t chunkSize )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !n || !chunkSize ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API_PAGE_CALC_SIZE( n, chunkSize );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: unsigned int WHALLOC_API(page_sizeof)( WHALLOC_API(page) const * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return p
fc60825290 2011-04-18       stephan:         ? WHALLOC_API(page_calc_size)( p->length, p->chunkSize )
fc60825290 2011-04-18       stephan:         : 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: WHALLOC_API(page) * WHALLOC_API(page_new2)( uint16_t n, uint16_t chunkSize,
fc60825290 2011-04-18       stephan:                                            WHALLOC_API(allocator) const * alloc)
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     const uint16_t sz = WHALLOC_API(page_calc_size)(n, chunkSize);
fc60825290 2011-04-18       stephan:     unsigned char * mem = NULL;
fc60825290 2011-04-18       stephan:     WHALLOC_API(page) * page = NULL;
fc60825290 2011-04-18       stephan:     if( ! sz ) return NULL;
fc60825290 2011-04-18       stephan:     if( (NULL == alloc) || (NULL == alloc->realloc) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         alloc = &WHALLOC_API(pager_allocator_default);
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     mem = (unsigned char *) alloc->realloc( NULL, sz, alloc->state );
fc60825290 2011-04-18       stephan:     if( ! mem ) return NULL;
fc60825290 2011-04-18       stephan:     memset( mem, 0, sz ); /* valgrind bitches without this! */
fc60825290 2011-04-18       stephan:     page = (WHALLOC_API(page)*) mem;
fc60825290 2011-04-18       stephan:     *page = WHALLOC_API(page_empty);
fc60825290 2011-04-18       stephan:     page->alloc = *alloc;
fc60825290 2011-04-18       stephan:     page->length = n;
fc60825290 2011-04-18       stephan:     page->chunkSize = chunkSize;
fc60825290 2011-04-18       stephan:     page->useCount = 0;
fc60825290 2011-04-18       stephan:     /* FIXME: move flags to end so we can guarany alignment of page->pool. */
fc60825290 2011-04-18       stephan:     page->flags = mem + sizeof(WHALLOC_API(page));
fc60825290 2011-04-18       stephan:     page->pool = page->flags + BITCOUNT_TO_BYTES(n);
fc60825290 2011-04-18       stephan:     page->next = page->prev = NULL;
fc60825290 2011-04-18       stephan:     return page;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: WHALLOC_API(page) * WHALLOC_API(page_new)( uint16_t n, uint16_t chunkSize,
fc60825290 2011-04-18       stephan:                                            WHALLOC_API(realloc_f) alloc, void * allocState)
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) A = WHALLOC_API(allocator_empty);
fc60825290 2011-04-18       stephan:     A.realloc = alloc;
fc60825290 2011-04-18       stephan:     A.state = allocState;
fc60825290 2011-04-18       stephan:     return WHALLOC_API(page_new2)( n, chunkSize, &A );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void WHALLOC_API(page_finalize)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( p )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         void * ignored;
fc60825290 2011-04-18       stephan:         ignored = p->alloc.realloc( p, 0, p->alloc.state );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(page_alloc)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! p ) return NULL;
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:     else if( p->useCount >= p->length ) return NULL;
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     else if( p->nextFree >= p->length ) return NULL;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         uint16_t i = p->nextFree;
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:         if( p->nextFree >= 8 )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( (p->length > 8) && (p->useCount > 8) )
fc60825290 2011-04-18       stephan:             { /* Optimization to check if sets of 8
fc60825290 2011-04-18       stephan:                  (one byte in p->flags) are set. Cuts
fc60825290 2011-04-18       stephan:                  down the looping on full large pages.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:                  But only works as-is if i starts at 0,
fc60825290 2011-04-18       stephan:                  which invalidates any effect of using
fc60825290 2011-04-18       stephan:                  p->nextFree. :/
fc60825290 2011-04-18       stephan:               */
fc60825290 2011-04-18       stephan:                 uint16_t x = 0;
fc60825290 2011-04-18       stephan:                 for( ; x < BITCOUNT_TO_BYTES(p->length); ++x )
fc60825290 2011-04-18       stephan:                 {
fc60825290 2011-04-18       stephan:                     if( 0xFF == p->flags[x] )
fc60825290 2011-04-18       stephan:                     {
fc60825290 2011-04-18       stephan:                         i += 8;
fc60825290 2011-04-18       stephan:                     }
fc60825290 2011-04-18       stephan:                     else if( 0xF0 == p->flags[x] )
fc60825290 2011-04-18       stephan:                     {
fc60825290 2011-04-18       stephan:                         i += 4;
fc60825290 2011-04-18       stephan:                     }
fc60825290 2011-04-18       stephan:                     else break;
fc60825290 2011-04-18       stephan:                 }
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         for( ; i < p->length; ++i )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( CHUNK_IS_USED(p,i) ) continue;
fc60825290 2011-04-18       stephan:             CHUNK_USE(p,i);
fc60825290 2011-04-18       stephan:             if( p->nextFree == i )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 ++p->nextFree;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             ++p->useCount;
fc60825290 2011-04-18       stephan:             return p->pool + (p->chunkSize * i);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         MARKER(("You shouldn't have gotten this far: page@%p, i=%"PRIu16", p->length=%"PRIu16", p->used=%"PRIu16"\n",
fc60825290 2011-04-18       stephan:                 (void const *)p, i, p->length,p->useCount));
fc60825290 2011-04-18       stephan:         assert( 0 && "This theoretically cannot be reached!" );
fc60825290 2011-04-18       stephan:         return NULL;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: char WHALLOC_API(page_owns_mem)( WHALLOC_API(page) const * p, void const * m )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if(!p || !m ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         unsigned char const * mc = (unsigned char const *)m;
fc60825290 2011-04-18       stephan:         if( (mc < p->pool)
fc60825290 2011-04-18       stephan:             || (mc > ((p->pool + (p->chunkSize * p->length))))
fc60825290 2011-04-18       stephan:             )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             return 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             return 1;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_free)( WHALLOC_API(page) * p, void * mem )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     unsigned char const * mc = (unsigned char const *)mem;
fc60825290 2011-04-18       stephan:     /*MARKER(("mc=@%p\n",(void const *)mc));*/
fc60825290 2011-04-18       stephan:     if( ! p ) return -1;
fc60825290 2011-04-18       stephan:     else if( ! WHALLOC_API(page_owns_mem)(p,mem) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return -1;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         const uint16_t pos = (mc - p->pool) / p->chunkSize;
fc60825290 2011-04-18       stephan:         /*MARKER(("pos=%u"\n",pos));*/
fc60825290 2011-04-18       stephan:         CHUNK_UNUSE(p,pos);
fc60825290 2011-04-18       stephan:         --p->useCount;
fc60825290 2011-04-18       stephan:         if( p->nextFree > pos )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             p->nextFree = pos;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_erase)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! p ) return -1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         memset( p->flags, 0, BITCOUNT_TO_BYTES(p->length) );
fc60825290 2011-04-18       stephan: #if 0 /* highly arguable. */
fc60825290 2011-04-18       stephan:         memset( p->pool, 0, p->length * p->chunkSize );
fc60825290 2011-04-18       stephan: #error "Re-add the API docs in the following comment lines to the public API!"
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            This routine effectively performs a memset() on the page's entire
fc60825290 2011-04-18       stephan:            contents, and thus has O(N) performance, where N is a function of
fc60825290 2011-04-18       stephan:            (but not exactly equal to) (p->length * p->chunkSize). This is
fc60825290 2011-04-18       stephan:            highly arguably, but is there to help avoid mis-use of deallocated
fc60825290 2011-04-18       stephan:            memory.
fc60825290 2011-04-18       stephan:          */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         p->nextFree = p->useCount = 0;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: char WHALLOC_API(page_is_full)( WHALLOC_API(page) const * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return p
fc60825290 2011-04-18       stephan:         ? ((p->nextFree >= p->length) ? 1 : 0)
fc60825290 2011-04-18       stephan:         : 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_insert_after)( WHALLOC_API(page) * p, WHALLOC_API(page) * after )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !p || !after ) return -1;
fc60825290 2011-04-18       stephan:     else if( p->prev || p->next ) return 1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( after->next )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             after->next->prev = p;
fc60825290 2011-04-18       stephan:             p->next = after->next;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         after->next = p;
fc60825290 2011-04-18       stephan:         p->prev = after;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_insert_before)( WHALLOC_API(page) * p, WHALLOC_API(page) * before )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !p || !before ) return -1;
fc60825290 2011-04-18       stephan:     else if( p->prev || p->next ) return 1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( before->prev )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             before->prev->next = p;
fc60825290 2011-04-18       stephan:             p->prev = before->prev;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         before->prev = p;
fc60825290 2011-04-18       stephan:         p->next = before;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: WHALLOC_API(page)* WHALLOC_API(page_snip)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !p ) return NULL;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(page)* rc = NULL;
fc60825290 2011-04-18       stephan:         if( p->prev )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             p->prev->next = p->next;
fc60825290 2011-04-18       stephan:             rc = p->prev;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( p->next )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             p->next->prev = p->prev;
fc60825290 2011-04-18       stephan:             rc = p->next;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         p->prev = p->next = NULL;
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_move_right)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !p ) return -1;
fc60825290 2011-04-18       stephan:     else if( ! p->next ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: #if !defined(NDEBUG)
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) const * pr = p->next;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * s = WHALLOC_API(page_snip)( p );
fc60825290 2011-04-18       stephan:         assert( s == pr );
fc60825290 2011-04-18       stephan:         WHALLOC_API(page_insert_after)( p, s );
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(page_move_left)( WHALLOC_API(page) * p )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !p ) return -1;
fc60825290 2011-04-18       stephan:     else if( ! p->prev ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * pr = p->prev;
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * ignored;
fc60825290 2011-04-18       stephan:         ignored = WHALLOC_API(page_snip)( p );
fc60825290 2011-04-18       stephan:         WHALLOC_API(page_insert_before)( p, pr );
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: WHALLOC_API(book) * WHALLOC_API(book_open2)( uint16_t n, uint16_t chunkSize,
fc60825290 2011-04-18       stephan:                                              WHALLOC_API(allocator) const * alloc,
fc60825290 2011-04-18       stephan:                                              WHALLOC_API(allocator) const * pageAlloc )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     const size_t sz = sizeof(WHALLOC_API(book));
fc60825290 2011-04-18       stephan:     WHALLOC_API(book) * b = NULL;
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) const * AB =
fc60825290 2011-04-18       stephan:         (alloc && alloc->realloc)
fc60825290 2011-04-18       stephan:         ? alloc
fc60825290 2011-04-18       stephan:         : &WHALLOC_API(pager_allocator_default);
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) const * AP =
fc60825290 2011-04-18       stephan:         (pageAlloc && pageAlloc->realloc)
fc60825290 2011-04-18       stephan:         ? pageAlloc
fc60825290 2011-04-18       stephan:         : &WHALLOC_API(pager_allocator_default);
fc60825290 2011-04-18       stephan:     if( !chunkSize || !n ) return NULL;
fc60825290 2011-04-18       stephan:     b = (WHALLOC_API(book)*) AB->realloc( NULL, sz, AB->state );
fc60825290 2011-04-18       stephan:     if( ! b ) return NULL;
fc60825290 2011-04-18       stephan:     memset( b, 0, sz ); /* valgrind bitches without this, even though the next line does the same thing! */
fc60825290 2011-04-18       stephan:     *b = WHALLOC_API(book_empty);
fc60825290 2011-04-18       stephan:     b->pageLength = n;
fc60825290 2011-04-18       stephan:     b->chunkSize = chunkSize;
fc60825290 2011-04-18       stephan:     b->alloc = *AB;
fc60825290 2011-04-18       stephan:     b->pageAlloc = *AP;
fc60825290 2011-04-18       stephan:     return b;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: WHALLOC_API(book) * WHALLOC_API(book_open)( uint16_t n, uint16_t chunkSize,
fc60825290 2011-04-18       stephan:                                             WHALLOC_API(realloc_f) alloc, void * allocState,
fc60825290 2011-04-18       stephan:                                             WHALLOC_API(realloc_f) pageAlloc, void * pageAllocState
fc60825290 2011-04-18       stephan:                                             )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: #if 1
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) ab;
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) ap;
fc60825290 2011-04-18       stephan:     ab.realloc = alloc;
fc60825290 2011-04-18       stephan:     ab.state = allocState;
fc60825290 2011-04-18       stephan:     ap.realloc = pageAlloc;
fc60825290 2011-04-18       stephan:     ap.state = pageAllocState;
fc60825290 2011-04-18       stephan:     return WHALLOC_API(book_open2)( n, chunkSize, &ab, &ap );
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     const size_t sz = sizeof(WHALLOC_API(book));
fc60825290 2011-04-18       stephan:     WHALLOC_API(book) * b = NULL;
fc60825290 2011-04-18       stephan:     if( NULL == alloc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         alloc = WHALLOC_API(pager_realloc_default);
fc60825290 2011-04-18       stephan:         allocState = NULL;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( NULL == pageAlloc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         pageAlloc = WHALLOC_API(pager_realloc_default);
fc60825290 2011-04-18       stephan:         pageAllocState = NULL;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( !chunkSize || !n ) return NULL;
fc60825290 2011-04-18       stephan:     b = (WHALLOC_API(book)*) alloc( NULL, sz, allocState );
fc60825290 2011-04-18       stephan:     if( ! b ) return NULL;
fc60825290 2011-04-18       stephan:     memset( b, 0, sz ); /* valgrind bitches without this, even though the next line does the same thing! */
fc60825290 2011-04-18       stephan:     *b = WHALLOC_API(book_empty);
fc60825290 2011-04-18       stephan:     b->pageLength = n;
fc60825290 2011-04-18       stephan:     b->chunkSize = chunkSize;
fc60825290 2011-04-18       stephan:     b->alloc.realloc = alloc;
fc60825290 2011-04-18       stephan:     b->alloc.state = allocState;
fc60825290 2011-04-18       stephan:     b->pageAlloc.realloc = pageAlloc;
fc60825290 2011-04-18       stephan:     b->pageAlloc.state = pageAllocState;
fc60825290 2011-04-18       stephan:     return b;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(book_close)( WHALLOC_API(book) * b )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(mutex) mutex;
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * p = NULL;
fc60825290 2011-04-18       stephan:         void * allocState = NULL;
fc60825290 2011-04-18       stephan:         WHALLOC_API(realloc_f) balloc = NULL;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,1,WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:         mutex = b->mutex;
fc60825290 2011-04-18       stephan:         allocState = b->alloc.state;
fc60825290 2011-04-18       stephan:         balloc = b->alloc.realloc;
fc60825290 2011-04-18       stephan:         p = b->page;
fc60825290 2011-04-18       stephan:         *b = WHALLOC_API(book_empty) /* helps avoid mis-use after freeing. */;
fc60825290 2011-04-18       stephan:         balloc( b, 0, allocState );
fc60825290 2011-04-18       stephan:         while( p && p->prev ) p = p->prev;
fc60825290 2011-04-18       stephan:         while( p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             WHALLOC_API(page) * x = WHALLOC_API(page_snip)( p );
fc60825290 2011-04-18       stephan:             WHALLOC_API(page_finalize)( p );
fc60825290 2011-04-18       stephan:             p = x;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if(mutex.unlock) mutex.unlock(mutex.state);
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(book_open_alloc_reuse)( void * m, unsigned int n, void * allocState )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return n ? allocState : NULL;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Internal impl for WHALLOC_API(book_add_page). If doLock is 1 then
fc60825290 2011-04-18       stephan:    this function will lock/unlock b->mutex IF b->mutex.lock is
fc60825290 2011-04-18       stephan:    non-null.  If doLock is 0, the caller is assumed to have locked and
fc60825290 2011-04-18       stephan:    no locking is done.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static WHALLOC_API(page) * WHALLOC_API(book_add_page_impl)( WHALLOC_API(book) * b, char doLock )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return NULL;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            In theory...
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            we could move the lock to after the allocation (and only
fc60825290 2011-04-18       stephan:            lock if allocation succeeds). This implies, however, that:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            a) b->pageAlloc/pageAllocState are not modified (their API
fc60825290 2011-04-18       stephan:            docs specify that they must not be modified, so doing so is
fc60825290 2011-04-18       stephan:            blatant mis-use).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            b) b->pageAlloc.realloc does its own locking.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            If in fact b->pageAlloc.realloc does its own locking AND
fc60825290 2011-04-18       stephan:            its using the same mutex as b, then us indirectly locking
fc60825290 2011-04-18       stephan:            it here will cause a deadlock if the mutex is not
fc60825290 2011-04-18       stephan:            recursive.
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * np = NULL;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b, doLock,NULL);
fc60825290 2011-04-18       stephan:         np = WHALLOC_API(page_new2)( b->pageLength,
fc60825290 2011-04-18       stephan:                                      b->chunkSize,
fc60825290 2011-04-18       stephan:                                      &b->pageAlloc );
fc60825290 2011-04-18       stephan:         if( np )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( b->page )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page_insert_before)( np, b->page );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             b->page = np;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         LOGBOOK(b,("Added new page @%p to the book.\n",(void const *)np));
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b, doLock);
fc60825290 2011-04-18       stephan:         return np;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: WHALLOC_API(page) * WHALLOC_API(book_add_page)( WHALLOC_API(book) * b )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return WHALLOC_API(book_add_page_impl)( b, 1 );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(book_alloc)( WHALLOC_API(book) * b )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return NULL;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         /**
fc60825290 2011-04-18       stephan:            Walk each page until we find space.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:            Each time we allocate from a page, move it to the right if
fc60825290 2011-04-18       stephan:            it has more allocations than page->next. The point being to
fc60825290 2011-04-18       stephan:            keep pages with free slots up front in the list. This
fc60825290 2011-04-18       stephan:            speeds up allocation but can have the opposite effect on
fc60825290 2011-04-18       stephan:            deallocation if objects are destructed in the same order as
fc60825290 2011-04-18       stephan:            they are created (which is not unusual, but not the norm, i
fc60825290 2011-04-18       stephan:            think).
fc60825290 2011-04-18       stephan:         */
fc60825290 2011-04-18       stephan:         void * rc = NULL;
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * p = NULL;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,1,NULL);
fc60825290 2011-04-18       stephan:         p = b->page;
fc60825290 2011-04-18       stephan:         if( ! p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             p = WHALLOC_API(book_add_page_impl)( b, 0 );
fc60825290 2011-04-18       stephan:             if( !p )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Adding new page failed! Out of memory?\n"));
fc60825290 2011-04-18       stephan:                 BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:                 return NULL;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         while( p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /**
fc60825290 2011-04-18       stephan:                Actually... the next page is guaranteed to be NULL
fc60825290 2011-04-18       stephan:                or full due to the list-reordering. Thus if the first
fc60825290 2011-04-18       stephan:                page is full we could skip to the end. However, it'd
fc60825290 2011-04-18       stephan:                still be O(N).
fc60825290 2011-04-18       stephan:             */
fc60825290 2011-04-18       stephan:             if( WHALLOC_API(page_is_full)( p ) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Skipping full page @%p.\n",(void const *)p));
fc60825290 2011-04-18       stephan:                 p = p->next;
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             rc = WHALLOC_API(page_alloc)(p);
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( !rc )
fc60825290 2011-04-18       stephan:         { /* (most likely) all pages were full */
fc60825290 2011-04-18       stephan:             p = WHALLOC_API(book_add_page)( b );
fc60825290 2011-04-18       stephan:             if( ! p )
fc60825290 2011-04-18       stephan:             { /* OOM. */
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Page allocation failed!\n"));
fc60825290 2011-04-18       stephan:                 BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:                 return NULL;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             rc = WHALLOC_API(page_alloc)(p);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( ! rc )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGBOOK(b,("This shouldn't be able to happen: allocation failed but we have free page slots!\n"));
fc60825290 2011-04-18       stephan:             BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:             assert( rc && "This shouldn't be able to happen!");
fc60825290 2011-04-18       stephan:             return NULL;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( p->next )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             while( p->useCount > p->next->useCount )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Moving page @%p to the right.\n",(void const *)p));
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page_move_right)( p );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( p->prev )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             while( p->prev && (p->useCount < p->prev->useCount) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Moving page @%p to the left.\n",(void const *)p));
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page_move_right)( p->prev );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         while( b->page->prev )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             /* kludge to ensure b->page is the head, until i work out
fc60825290 2011-04-18       stephan:                some list-organization details. */
fc60825290 2011-04-18       stephan:             b->page = b->page->prev;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         LOGBOOK(b,("Allocated object @%p from page @%p!\n",(void const *)rc,(void const *)p));
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(book_free)( WHALLOC_API(book) * b, void * mem )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return -1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * p = NULL;
fc60825290 2011-04-18       stephan:         int rc = 0;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,1,WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:         p = b->page;
fc60825290 2011-04-18       stephan:         while( p && ! WHALLOC_API(page_owns_mem)(p, mem) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             p = p->next;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( ! p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:             return 1;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         rc = WHALLOC_API(page_free)(p, mem);
fc60825290 2011-04-18       stephan:         if( 0 == rc )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGBOOK(b,("Deallocated object @%p from page @%p!\n",(void const *)mem,(void const *)p));
fc60825290 2011-04-18       stephan:             if( !p->useCount
fc60825290 2011-04-18       stephan:                 && (b->flags & PAGER_BOOK_AUTO_VACUUM)
fc60825290 2011-04-18       stephan:                 )
fc60825290 2011-04-18       stephan:             { /** Deallocate p. */
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page) * s = WHALLOC_API(page_snip)( p );
fc60825290 2011-04-18       stephan:                 if( b->page == p )
fc60825290 2011-04-18       stephan:                 {
fc60825290 2011-04-18       stephan:                     b->page = s ? (s->prev ? s->prev : s) : s;
fc60825290 2011-04-18       stephan:                 }
fc60825290 2011-04-18       stephan:                 LOGBOOK(b,("Auto-vacuuming page @%p.\n",(void const *)p));
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page_finalize)(p);
fc60825290 2011-04-18       stephan:                 p = 0;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             if( p )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 while( p->prev && (p->prev->useCount > p->useCount) )
fc60825290 2011-04-18       stephan:                 {
fc60825290 2011-04-18       stephan:                     WHALLOC_API( page_move_left(p) );
fc60825290 2011-04-18       stephan:                 }
fc60825290 2011-04-18       stephan:                 if( ! p->prev )
fc60825290 2011-04-18       stephan:                 {
fc60825290 2011-04-18       stephan:                     b->page = p;
fc60825290 2011-04-18       stephan:                 }
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             LOGBOOK(b,("Deallocation of object @%p from page @%p failed!\n",(void const *)mem,(void const *)p));
fc60825290 2011-04-18       stephan:             assert(0 && "DEallocation of object from page failed!");
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan: #undef UNLOCK
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Internal impl of WHALLOC_API(book_vacuum)(). If doLock is 1 then this
fc60825290 2011-04-18       stephan:    function uses b->mutex (if set) to lock/unlock b. If doLock is 0
fc60825290 2011-04-18       stephan:    then the caller is assumed to have locked b.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static unsigned int WHALLOC_API(book_vacuum_impl)( WHALLOC_API(book) * b,
fc60825290 2011-04-18       stephan:                                                    char doLock )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b || !b->page ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         size_t rc = 0;
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * p = NULL;
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * x = NULL;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,doLock,0);
fc60825290 2011-04-18       stephan:         p = b->page;;
fc60825290 2011-04-18       stephan:         while( p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( p->useCount )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 p = p->next;
fc60825290 2011-04-18       stephan:                 continue;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             ++rc;
fc60825290 2011-04-18       stephan:             x = WHALLOC_API(page_snip)( p );
fc60825290 2011-04-18       stephan:             LOGBOOK(b,("Vacuuming page @%p\n",(void const *)p));
fc60825290 2011-04-18       stephan:             if( b->page == p )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 b->page = x;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             WHALLOC_API(page_finalize)( p );
fc60825290 2011-04-18       stephan:             p = x;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         while( b->page && b->page->prev )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             b->page = b->page->prev;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b,doLock);
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: unsigned int WHALLOC_API(book_vacuum)( WHALLOC_API(book) * b )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return WHALLOC_API(book_vacuum_impl)( b, 1 );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(book_vacuum_auto)( WHALLOC_API(book) * b, char autoVac )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return -1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,1,WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:         b->flags |= PAGER_BOOK_AUTO_VACUUM;
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(book_erase)( WHALLOC_API(book) * b, char alsoDeallocPages )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! b ) return -1;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         WHALLOC_API(page) * p = NULL;
fc60825290 2011-04-18       stephan:         unsigned int count = 0;
fc60825290 2011-04-18       stephan:         BOOK_LOCK_OR(b,1,WHALLOC_API(rc).LockingError);
fc60825290 2011-04-18       stephan:         p = b->page;
fc60825290 2011-04-18       stephan:         if( NULL != p )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             while( p->prev ) p = p->prev;
fc60825290 2011-04-18       stephan:             b->page = p;
fc60825290 2011-04-18       stephan:             for( ; p ;)
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 WHALLOC_API(page_erase)( p );
fc60825290 2011-04-18       stephan:                 p = p->next;
fc60825290 2011-04-18       stephan:                 ++count;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             if( alsoDeallocPages )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 const unsigned int check = WHALLOC_API(book_vacuum_impl)( b, 0 );
fc60825290 2011-04-18       stephan:                 if(!check){/*avoid unused var warning.*/}
fc60825290 2011-04-18       stephan:                 assert( (check == count) && ! b->page );
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         BOOK_UNLOCK(b,1);
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: WHALLOC_API(book) * WHALLOC_API(book_from_bt)( WHALLOC_API(bt) * src,
fc60825290 2011-04-18       stephan:                                                uint16_t pageLength,
fc60825290 2011-04-18       stephan:                                                uint16_t chunkSize )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     WHALLOC_API(book) * b = NULL;
fc60825290 2011-04-18       stephan:     WHALLOC_API(allocator) A = WHALLOC_API(allocator_empty);
fc60825290 2011-04-18       stephan:     if( ! src || ! pageLength || ! chunkSize ) return 0;
fc60825290 2011-04-18       stephan:     WHALLOC_API(bt_allocator)( src, &A );
fc60825290 2011-04-18       stephan:     b = WHALLOC_API(book_open2)( pageLength, chunkSize,
fc60825290 2011-04-18       stephan:                                  &A, &A );
fc60825290 2011-04-18       stephan:     if( b && src->base.mutex.lock)
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         b->mutex = src->base.mutex;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return b;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef LOGBOOK
fc60825290 2011-04-18       stephan: #undef MARKER
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef BITCOUNT_TO_BYTES
fc60825290 2011-04-18       stephan: #undef BYTES_BYTEFOR
fc60825290 2011-04-18       stephan: #undef BYTES_SET
fc60825290 2011-04-18       stephan: #undef BYTES_UNSET
fc60825290 2011-04-18       stephan: #undef BYTES_GET
fc60825290 2011-04-18       stephan: #undef BYTES_TOGGLE
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   #undef BOOK_BYTEOF
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #undef CHUNK_IS_USED
fc60825290 2011-04-18       stephan: #undef CHUNK_SET_USAGE
fc60825290 2011-04-18       stephan: #undef CHUNK_USE
fc60825290 2011-04-18       stephan: #undef CHUNK_UNUSE
fc60825290 2011-04-18       stephan: #undef BOOK_LOCK_OR
fc60825290 2011-04-18       stephan: #undef BOOK_UNLOCK
fc60825290 2011-04-18       stephan: /* end file whalloc_pager.c */
fc60825290 2011-04-18       stephan: /* begin file whalloc_region.c */
fc60825290 2011-04-18       stephan: #line 8 "whalloc_region.c"
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const WHALLOC_API(region) WHALLOC_API(region_empty) = {
fc60825290 2011-04-18       stephan: NULL/*mem*/,
fc60825290 2011-04-18       stephan: NULL/*pos*/,
fc60825290 2011-04-18       stephan: 0/*length*/
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(region_init)( WHALLOC_API(region) * r, void * mem, WHALLOC_API(size_t) length )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! r || ! mem || !length ) return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         r->mem = r->pos = mem;
fc60825290 2011-04-18       stephan:         r->end = r->mem + length;
fc60825290 2011-04-18       stephan:         memset( r->mem, 0, length );
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void * WHALLOC_API(region_alloc)( WHALLOC_API(region) * r, WHALLOC_API(size_t) n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! r || ! n ) return NULL;
fc60825290 2011-04-18       stephan:     else if( (r->pos + n) > r->end ) return NULL;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         void * rc = r->pos;
fc60825290 2011-04-18       stephan:         r->pos += n;
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int WHALLOC_API(region_free)( WHALLOC_API(region) * r )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! r )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return WHALLOC_API(rc).ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         r->pos = r->mem;
fc60825290 2011-04-18       stephan:         memset( r->pos, 0, r->end - r->pos );
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* end file whalloc_region.c */
fc60825290 2011-04-18       stephan: /* end file src/whalloc_amalgamation.c */
fc60825290 2011-04-18       stephan: /* begin file src/whglob.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whglob.c"
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #ifdef __cplusplus
fc60825290 2011-04-18       stephan: extern "C" {
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Globbing implementation extracted from the sqlite3 source tree.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Original author: D. Richard Hipp (http://sqlite.org)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    Maintainer of this copy: Stephan Beal
fc60825290 2011-04-18       stephan:    (http://wanderinghorse.net/home/stephan)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    License: Public Domain
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: typedef unsigned char u8;
fc60825290 2011-04-18       stephan: #define SQLITE_ASCII 1
fc60825290 2011-04-18       stephan: /* An array to map all upper-case characters into their corresponding
fc60825290 2011-04-18       stephan: ** lower-case character.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** SQLite only considers US-ASCII (or EBCDIC) characters.  We do not
fc60825290 2011-04-18       stephan: ** handle case conversions for the UTF character set since the tables
fc60825290 2011-04-18       stephan: ** involved are nearly as big or bigger than SQLite itself.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static const unsigned char sqlite3UpperToLower[] = {
fc60825290 2011-04-18       stephan: #ifdef SQLITE_ASCII
fc60825290 2011-04-18       stephan:       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
fc60825290 2011-04-18       stephan:      18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
fc60825290 2011-04-18       stephan:      36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
fc60825290 2011-04-18       stephan:      54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
fc60825290 2011-04-18       stephan:     104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
fc60825290 2011-04-18       stephan:     122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
fc60825290 2011-04-18       stephan:     108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
fc60825290 2011-04-18       stephan:     126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
fc60825290 2011-04-18       stephan:     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
fc60825290 2011-04-18       stephan:     162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
fc60825290 2011-04-18       stephan:     180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
fc60825290 2011-04-18       stephan:     198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
fc60825290 2011-04-18       stephan:     216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
fc60825290 2011-04-18       stephan:     234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
fc60825290 2011-04-18       stephan:     252,253,254,255
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #ifdef SQLITE_EBCDIC
fc60825290 2011-04-18       stephan:       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 0x */
fc60825290 2011-04-18       stephan:      16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
fc60825290 2011-04-18       stephan:      32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
fc60825290 2011-04-18       stephan:      48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
fc60825290 2011-04-18       stephan:      64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
fc60825290 2011-04-18       stephan:      80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
fc60825290 2011-04-18       stephan:      96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
fc60825290 2011-04-18       stephan:     112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
fc60825290 2011-04-18       stephan:     128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
fc60825290 2011-04-18       stephan:     144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
fc60825290 2011-04-18       stephan:     160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
fc60825290 2011-04-18       stephan:     176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
fc60825290 2011-04-18       stephan:     192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
fc60825290 2011-04-18       stephan:     208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
fc60825290 2011-04-18       stephan:     224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
fc60825290 2011-04-18       stephan:     239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** This lookup table is used to help decode the first byte of
fc60825290 2011-04-18       stephan: ** a multi-byte UTF8 character.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static const unsigned char sqlite3UtfTrans1[] = {
fc60825290 2011-04-18       stephan:   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
fc60825290 2011-04-18       stephan:   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
fc60825290 2011-04-18       stephan:   0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
fc60825290 2011-04-18       stephan:   0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
fc60825290 2011-04-18       stephan:   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
fc60825290 2011-04-18       stephan:   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
fc60825290 2011-04-18       stephan:   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
fc60825290 2011-04-18       stephan:   0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** For LIKE and GLOB matching on EBCDIC machines, assume that every
fc60825290 2011-04-18       stephan: ** character is exactly one byte in size.  Also, all characters are
fc60825290 2011-04-18       stephan: ** able to participate in upper-case-to-lower-case mappings in EBCDIC
fc60825290 2011-04-18       stephan: ** whereas only characters less than 0x80 do in ASCII.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #if defined(SQLITE_EBCDIC)
fc60825290 2011-04-18       stephan: # define sqlite3Utf8Read(A,B,C)  (*(A++))
fc60825290 2011-04-18       stephan: # define GlogUpperToLower(A)     A = sqlite3UpperToLower[A]
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan: # define GlogUpperToLower(A)     if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** Assuming zIn points to the first byte of a UTF-8 character,
fc60825290 2011-04-18       stephan: ** advance zIn to point to the first byte of the next UTF-8 character.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define SQLITE_SKIP_UTF8(zIn) {                        \
fc60825290 2011-04-18       stephan:   if( (*(zIn++))>=0xc0 ){                              \
fc60825290 2011-04-18       stephan:     while( (*zIn & 0xc0)==0x80 ){ zIn++; }             \
fc60825290 2011-04-18       stephan:   }                                                    \
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** Translate a single UTF-8 character.  Return the unicode value.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** During translation, assume that the byte that zTerm points
fc60825290 2011-04-18       stephan: ** is a 0x00.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** Write a pointer to the next unread byte back into *pzNext.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** Notes On Invalid UTF-8:
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **  *  This routine never allows a 7-bit character (0x00 through 0x7f) to
fc60825290 2011-04-18       stephan: **     be encoded as a multi-byte character.  Any multi-byte character that
fc60825290 2011-04-18       stephan: **     attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **  *  This routine never allows a UTF16 surrogate value to be encoded.
fc60825290 2011-04-18       stephan: **     If a multi-byte character attempts to encode a value between
fc60825290 2011-04-18       stephan: **     0xd800 and 0xe000 then it is rendered as 0xfffd.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **  *  Bytes in the range of 0x80 through 0xbf which occur as the first
fc60825290 2011-04-18       stephan: **     byte of a character are interpreted as single-byte characters
fc60825290 2011-04-18       stephan: **     and rendered as themselves even though they are technically
fc60825290 2011-04-18       stephan: **     invalid characters.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **  *  This routine accepts an infinite number of different UTF8 encodings
fc60825290 2011-04-18       stephan: **     for unicode values 0x80 and greater.  It do not change over-length
fc60825290 2011-04-18       stephan: **     encodings to 0xfffd as some systems recommend.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define READ_UTF8(zIn, zTerm, c)                           \
fc60825290 2011-04-18       stephan:   c = *(zIn++);                                            \
fc60825290 2011-04-18       stephan:   if( c>=0xc0 ){                                           \
fc60825290 2011-04-18       stephan:     c = sqlite3UtfTrans1[c-0xc0];                          \
fc60825290 2011-04-18       stephan:     while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){            \
fc60825290 2011-04-18       stephan:       c = (c<<6) + (0x3f & *(zIn++));                      \
fc60825290 2011-04-18       stephan:     }                                                      \
fc60825290 2011-04-18       stephan:     if( c<0x80                                             \
fc60825290 2011-04-18       stephan:         || (c&0xFFFFF800)==0xD800                          \
fc60825290 2011-04-18       stephan:         || (c&0xFFFFFFFE)==0xFFFE ){  c = 0xFFFD; }        \
fc60825290 2011-04-18       stephan:   }
fc60825290 2011-04-18       stephan: static int sqlite3Utf8Read(
fc60825290 2011-04-18       stephan:   const unsigned char *z,         /* First byte of UTF-8 character */
fc60825290 2011-04-18       stephan:   const unsigned char *zTerm,     /* Pretend this byte is 0x00 */
fc60825290 2011-04-18       stephan:   const unsigned char **pzNext    /* Write first byte past UTF-8 char here */
fc60825290 2011-04-18       stephan: ){
fc60825290 2011-04-18       stephan:   int c;
fc60825290 2011-04-18       stephan:   READ_UTF8(z, zTerm, c);
fc60825290 2011-04-18       stephan:   *pzNext = z;
fc60825290 2011-04-18       stephan:   return c;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** A structure defining how to do GLOB-style comparisons.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef struct sqlite3CompareInfo
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:   u8 matchAll;
fc60825290 2011-04-18       stephan:   u8 matchOne;
fc60825290 2011-04-18       stephan:   u8 matchSet;
fc60825290 2011-04-18       stephan:   u8 noCase;
fc60825290 2011-04-18       stephan: } sqlite3CompareInfo;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan: ** Compare two UTF-8 strings for equality where the first string can
fc60825290 2011-04-18       stephan: ** potentially be a "glob" expression.  Return true (1) if they
fc60825290 2011-04-18       stephan: ** are the same and false (0) if they are different.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** Globbing rules:
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **      '*'       Matches any sequence of zero or more characters.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **      '?'       Matches exactly one character.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **     [...]      Matches one character from the enclosed list of
fc60825290 2011-04-18       stephan: **                characters.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **     [^...]     Matches one character not in the enclosed list.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** With the [...] and [^...] matching, a ']' character can be included
fc60825290 2011-04-18       stephan: ** in the list by making it the first character after '[' or '^'.  A
fc60825290 2011-04-18       stephan: ** range of characters can be specified using '-'.  Example:
fc60825290 2011-04-18       stephan: ** "[a-z]" matches any single lower-case letter.  To match a '-', make
fc60825290 2011-04-18       stephan: ** it the last character in the list.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** This routine is usually quick, but can be N**2 in the worst case.
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: ** Hints: to match '*' or '?', put them in "[]".  Like this:
fc60825290 2011-04-18       stephan: **
fc60825290 2011-04-18       stephan: **         abc[*]xyz        Matches "abc*xyz" only
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static int patternCompare(
fc60825290 2011-04-18       stephan:   const u8 *zPattern,              /* The glob pattern */
fc60825290 2011-04-18       stephan:   const u8 *zString,               /* The string to compare against the glob */
fc60825290 2011-04-18       stephan:   const sqlite3CompareInfo *pInfo, /* Information about how to do the compare */
fc60825290 2011-04-18       stephan:   const int esc                    /* The escape character */
fc60825290 2011-04-18       stephan: ){
fc60825290 2011-04-18       stephan:   int c, c2;
fc60825290 2011-04-18       stephan:   int invert;
fc60825290 2011-04-18       stephan:   int seen;
fc60825290 2011-04-18       stephan:   u8 matchOne = pInfo->matchOne;
fc60825290 2011-04-18       stephan:   u8 matchAll = pInfo->matchAll;
fc60825290 2011-04-18       stephan:   u8 matchSet = pInfo->matchSet;
fc60825290 2011-04-18       stephan:   u8 noCase = pInfo->noCase;
fc60825290 2011-04-18       stephan:   int prevEscape = 0;     /* True if the previous character was 'escape' */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   if( ! zPattern || !zString ) return 0;
fc60825290 2011-04-18       stephan:   while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){
fc60825290 2011-04-18       stephan:     if( !prevEscape && c==matchAll ){
fc60825290 2011-04-18       stephan:       while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll
fc60825290 2011-04-18       stephan:                || c == matchOne ){
fc60825290 2011-04-18       stephan:         if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){
fc60825290 2011-04-18       stephan:           return 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       if( c==0 ){
fc60825290 2011-04-18       stephan:         return 1;
fc60825290 2011-04-18       stephan:       }else if( c==esc ){
fc60825290 2011-04-18       stephan:         c = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:         if( c==0 ){
fc60825290 2011-04-18       stephan:           return 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:       }else if( c==matchSet ){
6e8c7e31b6 2011-04-20       stephan: #if 0
6e8c7e31b6 2011-04-20       stephan: 	  assert( esc==0 );         /* This is GLOB, not LIKE */
6e8c7e31b6 2011-04-20       stephan: 	  assert( matchSet<0x80 );  /* '[' is a single-byte character */
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan: 	  if( (esc==0) || (matchSet<0x80) ) return 0;
fc60825290 2011-04-18       stephan:         while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
fc60825290 2011-04-18       stephan:           SQLITE_SKIP_UTF8(zString);
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         return *zString!=0;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){
fc60825290 2011-04-18       stephan:         if( noCase ){
fc60825290 2011-04-18       stephan:           GlogUpperToLower(c2);
fc60825290 2011-04-18       stephan:           GlogUpperToLower(c);
fc60825290 2011-04-18       stephan:           while( c2 != 0 && c2 != c ){
fc60825290 2011-04-18       stephan:             c2 = sqlite3Utf8Read(zString, 0, &zString);
fc60825290 2011-04-18       stephan:             GlogUpperToLower(c2);
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           while( c2 != 0 && c2 != c ){
fc60825290 2011-04-18       stephan:             c2 = sqlite3Utf8Read(zString, 0, &zString);
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         if( c2==0 ) return 0;
fc60825290 2011-04-18       stephan:         if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       return 0;
fc60825290 2011-04-18       stephan:     }else if( !prevEscape && c==matchOne ){
fc60825290 2011-04-18       stephan:       if( sqlite3Utf8Read(zString, 0, &zString)==0 ){
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }else if( c==matchSet ){
fc60825290 2011-04-18       stephan:       int prior_c = 0;
6e8c7e31b6 2011-04-20       stephan: #if 0
6e8c7e31b6 2011-04-20       stephan:       assert( esc==0 );    /* This only occurs for GLOB, not LIKE */
6e8c7e31b6 2011-04-20       stephan: #endif
fc60825290 2011-04-18       stephan:       if( esc == 0 ) return 0;
fc60825290 2011-04-18       stephan:       seen = 0;
fc60825290 2011-04-18       stephan:       invert = 0;
fc60825290 2011-04-18       stephan:       c = sqlite3Utf8Read(zString, 0, &zString);
fc60825290 2011-04-18       stephan:       if( c==0 ) return 0;
fc60825290 2011-04-18       stephan:       c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:       if( c2=='^' ){
fc60825290 2011-04-18       stephan:         invert = 1;
fc60825290 2011-04-18       stephan:         c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       if( c2==']' ){
fc60825290 2011-04-18       stephan:         if( c==']' ) seen = 1;
fc60825290 2011-04-18       stephan:         c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       while( c2 && c2!=']' ){
fc60825290 2011-04-18       stephan:         if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
fc60825290 2011-04-18       stephan:           c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:           if( c>=prior_c && c<=c2 ) seen = 1;
fc60825290 2011-04-18       stephan:           prior_c = 0;
fc60825290 2011-04-18       stephan:         }else{
fc60825290 2011-04-18       stephan:           if( c==c2 ){
fc60825290 2011-04-18       stephan:             seen = 1;
fc60825290 2011-04-18       stephan:           }
fc60825290 2011-04-18       stephan:           prior_c = c2;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       if( c2==0 || (seen ^ invert)==0 ){
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:     }else if( esc==c && !prevEscape ){
fc60825290 2011-04-18       stephan:       prevEscape = 1;
fc60825290 2011-04-18       stephan:     }else{
fc60825290 2011-04-18       stephan:       c2 = sqlite3Utf8Read(zString, 0, &zString);
fc60825290 2011-04-18       stephan:       if( noCase ){
fc60825290 2011-04-18       stephan:         GlogUpperToLower(c);
fc60825290 2011-04-18       stephan:         GlogUpperToLower(c2);
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       if( c!=c2 ){
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:       }
fc60825290 2011-04-18       stephan:       prevEscape = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:   }
fc60825290 2011-04-18       stephan:   return *zString==0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whglob_matches( char const * pattern, char const * str )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     static const sqlite3CompareInfo cinfo = { '*', '?', '[', 0 };
fc60825290 2011-04-18       stephan:     return patternCompare( (unsigned char *)pattern, (unsigned char *) str, &cinfo, '\\' );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whglob_matches_like( char const *pattern, char const * str, char caseSensitive )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /* The correct SQL-92 behavior is for the LIKE operator to ignore
fc60825290 2011-04-18       stephan:     ** case.  Thus  'a' LIKE 'A' would be true. */
fc60825290 2011-04-18       stephan:     static const sqlite3CompareInfo likeInfoNorm = { '%', '_',   0, 1 };
fc60825290 2011-04-18       stephan:     /* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
fc60825290 2011-04-18       stephan:     ** is case sensitive causing 'a' LIKE 'A' to be false */
fc60825290 2011-04-18       stephan:     static const sqlite3CompareInfo likeInfoAlt = { '%', '_',   0, 0 };
fc60825290 2011-04-18       stephan:     return patternCompare( (unsigned char *)pattern, (unsigned char *) str,
fc60825290 2011-04-18       stephan: 			   caseSensitive ? &likeInfoAlt : &likeInfoNorm,
fc60825290 2011-04-18       stephan: 			   '%' );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef SQLITE_ASCII
fc60825290 2011-04-18       stephan: #undef SQLITE_SKIP_UTF8
fc60825290 2011-04-18       stephan: #undef READ_UTF8
fc60825290 2011-04-18       stephan: #if defined(GlogUpperToLower)
fc60825290 2011-04-18       stephan: #  undef GlogUpperToLower
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #if defined(sqlite3Utf8Read)
fc60825290 2011-04-18       stephan: #  define sqlite3Utf8Read
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #ifdef __cplusplus
fc60825290 2011-04-18       stephan: } /* extern "C" */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: /* end file src/whglob.c */
fc60825290 2011-04-18       stephan: /* begin file src/whio.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whio.c"
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   License: Public Domain
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #include <stdlib.h>
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <memory.h>
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const whio_mutex whio_mutex_empty = whio_mutex_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Maintenance reminder: keep the member-name comments in the same
fc60825290 2011-04-18       stephan:    order as declared in the class!
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: const whio_rc_t whio_rc =
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:     0, /* OK */
fc60825290 2011-04-18       stephan:     /* -1 is reserved to avoid potential confusion with SizeTError. */
fc60825290 2011-04-18       stephan:     -2, /* ArgError */
fc60825290 2011-04-18       stephan:     -3, /* IOError */
fc60825290 2011-04-18       stephan:     -4, /* AllocError */
fc60825290 2011-04-18       stephan:     -5, /* InternalError */
fc60825290 2011-04-18       stephan:     -6, /* RangeError */
fc60825290 2011-04-18       stephan:     -7, /* InterruptedError */
fc60825290 2011-04-18       stephan:     -8, /* AccessError */
fc60825290 2011-04-18       stephan:     -9, /* ConsistencyError */
fc60825290 2011-04-18       stephan:     -10, /* NYIError */
fc60825290 2011-04-18       stephan:     -11, /* UnsupportedError */
fc60825290 2011-04-18       stephan:     -12, /* TypeError */
fc60825290 2011-04-18       stephan:     -13, /* DeviceFullError */
fc60825290 2011-04-18       stephan:     -14, /* LockingError */
fc60825290 2011-04-18       stephan:     -15, /* HashingError */
fc60825290 2011-04-18       stephan:     -16, /* NotFoundError */
fc60825290 2011-04-18       stephan:     -17, /* ConcurrentModificationError */
fc60825290 2011-04-18       stephan:     -18, /* WTFError */
fc60825290 2011-04-18       stephan:     (whio_size_t)-1 /* SizeTError */
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: char const * whio_rc_string( int rc )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /* can't use switch(rc) here b/c we can't use
fc60825290 2011-04-18       stephan:        whio_rc.XXX in a case label.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     if( ! rc ) return "whio_rc.OK";
fc60825290 2011-04-18       stephan: #define C(X) else if( whio_rc.X == rc ) return "whio_rc."#X
fc60825290 2011-04-18       stephan:     C(ArgError);
fc60825290 2011-04-18       stephan:     C(IOError);
fc60825290 2011-04-18       stephan:     C(AllocError);
fc60825290 2011-04-18       stephan:     C(InternalError);
fc60825290 2011-04-18       stephan:     C(RangeError);
fc60825290 2011-04-18       stephan:     C(InterruptedError);
fc60825290 2011-04-18       stephan:     C(AccessError);
fc60825290 2011-04-18       stephan:     C(ConsistencyError);
fc60825290 2011-04-18       stephan:     C(NYIError);
fc60825290 2011-04-18       stephan:     C(UnsupportedError);
fc60825290 2011-04-18       stephan:     C(TypeError);
fc60825290 2011-04-18       stephan:     C(DeviceFullError);
fc60825290 2011-04-18       stephan:     C(LockingError);
fc60825290 2011-04-18       stephan:     C(HashingError);
fc60825290 2011-04-18       stephan:     C(NotFoundError);
fc60825290 2011-04-18       stephan:     C(ConcurrentModificationError);
fc60825290 2011-04-18       stephan:     C(WTFError);
fc60825290 2011-04-18       stephan: #undef C
fc60825290 2011-04-18       stephan:     else return NULL;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void whio_noop_printf(char const * fmt, ...)
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: static void * whio_realloc_default( void * m, unsigned int n, void * state )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return realloc( m, n );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const whio_allocator whio_allocator_stdalloc = {whio_realloc_default,NULL};
fc60825290 2011-04-18       stephan: whio_allocator whio_memory_source = {whio_realloc_default,NULL};
fc60825290 2011-04-18       stephan: void * whio_realloc( void * m, unsigned int n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return whio_memory_source.realloc( m, n, whio_memory_source.state );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: void * whio_malloc( unsigned int n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return whio_realloc( NULL, n );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void whio_free( void * m )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if(NULL != m) whio_realloc( m, 0 );
fc60825290 2011-04-18       stephan:     return;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /* end file src/whio.c */
fc60825290 2011-04-18       stephan: /* begin file src/whio_common.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whio_common.c"
fc60825290 2011-04-18       stephan: #include <string.h> /* strchr() */
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* malloc()/free() */
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: const whio_client_data whio_client_data_empty = whio_client_data_empty_m;
fc60825290 2011-04-18       stephan: const whio_impl_data whio_impl_data_empty = whio_impl_data_empty_m;
fc60825290 2011-04-18       stephan: const whio_buffer whio_buffer_empty = whio_buffer_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_iomodes whio_mode_to_iomode( char const * mode )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_iomodes rc = WHIO_MODE_INVALID;
fc60825290 2011-04-18       stephan:     bool gotR = false;
fc60825290 2011-04-18       stephan:     bool gotW = false;
fc60825290 2011-04-18       stephan:     bool gotA = false;
fc60825290 2011-04-18       stephan:     if( ! mode || !*mode ) return rc;
fc60825290 2011-04-18       stephan:     for( ; *mode; ++mode )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	if( ('+'==*mode) || ('w'==*mode) || ('W'==*mode) ) gotW = true;
fc60825290 2011-04-18       stephan: 	else if( ('r'==*mode) || ('R'==*mode) ) gotR = true;
fc60825290 2011-04-18       stephan:         else if( ('a'==*mode) || ('A'==*mode) ) gotA = true;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     if( gotR ) rc |= WHIO_MODE_READ;
fc60825290 2011-04-18       stephan:     if( gotW ) rc |= WHIO_MODE_WRITE;
fc60825290 2011-04-18       stephan:     if( gotA ) rc |= WHIO_MODE_FLAG_APPEND;
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_buffer_reserve( whio_buffer * buf, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! buf ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     else if( 0 == n )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         free(buf->mem);
fc60825290 2011-04-18       stephan:         *buf = whio_buffer_empty;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( buf->capacity >= n )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         void * x = realloc( buf->mem, n );
fc60825290 2011-04-18       stephan:         if( ! x ) return whio_rc.AllocError;
fc60825290 2011-04-18       stephan:         buf->mem = x;
fc60825290 2011-04-18       stephan:         buf->capacity = n;
fc60825290 2011-04-18       stephan:         ++buf->timesExpanded;
fc60825290 2011-04-18       stephan:         return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_buffer_fill( whio_buffer * buf, char c )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( !buf || !buf->capacity || !buf->mem ) return 0;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         memset( buf->mem, c, buf->capacity );
fc60825290 2011-04-18       stephan:         return buf->capacity;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Implementation detail for whio_buffer_vprintf().
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    arg MUST be a (whio_buffer*). This function starts appending n
fc60825290 2011-04-18       stephan:    bytes at position arg->used, expanding the buffer as necessary.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static long whprintf_appender_whio_buffer( void * arg, char const * data, long n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_buffer * sb = (whio_buffer*)arg;
6e8c7e31b6 2011-04-20       stephan:     whio_size_t npos;
6e8c7e31b6 2011-04-20       stephan:     long rc = 0;
fc60825290 2011-04-18       stephan:     if( ! sb || (n<0) ) return -1;
fc60825290 2011-04-18       stephan:     if( ! n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     npos = sb->used + n;
fc60825290 2011-04-18       stephan:     if( npos >= sb->capacity )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         const whio_size_t asz = npos * 2;
fc60825290 2011-04-18       stephan:         const whio_size_t oldCap = sb->capacity;
6e8c7e31b6 2011-04-20       stephan:         int rrc;
6e8c7e31b6 2011-04-20       stephan:         if( asz < npos ) return -1; /* overflow */
6e8c7e31b6 2011-04-20       stephan:         rrc = whio_buffer_reserve( sb, asz );
6e8c7e31b6 2011-04-20       stephan:         if( rrc ) return -1 /* reminder: whio_rc.AllocError MIGHT
fc60825290 2011-04-18       stephan:                               be a negative number and it might not,
fc60825290 2011-04-18       stephan:                               so we can't use it here.
fc60825290 2011-04-18       stephan:                            */
fc60825290 2011-04-18       stephan:             ;
fc60825290 2011-04-18       stephan:         assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
fc60825290 2011-04-18       stephan:         /* make sure it gets NULL terminated. */
fc60825290 2011-04-18       stephan:         memset( ((char *)sb->mem) + oldCap, 0, (sb->capacity - oldCap) );
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     for( ; rc < n; ++rc, ++sb->used )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         ((char *)sb->mem)[sb->used] = data[rc];
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_buffer_vprintf( whio_buffer * buf, char const * fmt, va_list vargs )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! buf || ! fmt ) return whio_rc.ArgError;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         long rc = whprintfv( whprintf_appender_whio_buffer, buf, fmt, vargs );
6e8c7e31b6 2011-04-20       stephan:         return (rc < 0) ? whio_rc.WTFError : 0;
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_buffer_printf( whio_buffer * buf, char const * fmt, ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     va_list vargs;
6e8c7e31b6 2011-04-20       stephan:     int rc;
fc60825290 2011-04-18       stephan:     va_start( vargs, fmt );
6e8c7e31b6 2011-04-20       stephan:     rc = whio_buffer_vprintf( buf, fmt, vargs );
fc60825290 2011-04-18       stephan:     va_end( vargs );
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /* end file src/whio_common.c */
fc60825290 2011-04-18       stephan: /* begin file src/whio_dev.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whio_dev.c"
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   License: Public Domain
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS)
fc60825290 2011-04-18       stephan: #  define __STDC_LIMIT_MACROS
fc60825290 2011-04-18       stephan: /* A comment from the Linux stdint.h:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:    The ISO C99 standard specifies that in C++ implementations these
fc60825290 2011-04-18       stephan:    macros should only be defined if explicitly requested.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #include <stdint.h>
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* calloc() and friends */
fc60825290 2011-04-18       stephan: #include <inttypes.h> /* PRIuXX */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const whio_dev whio_dev_empty = whio_dev_empty_m;
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_empty = whio_lock_request_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_test_r =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_READ,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_TEST,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 1};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_test_w =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_WRITE,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_TEST,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 1};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_set_w =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_WRITE,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_NOWAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_set_r =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_READ,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_NOWAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_setw_w =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_WRITE,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_WAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_setw_r =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_READ,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_WAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_set_u =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_UNLOCK,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_NOWAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: const whio_lock_request whio_lock_request_setw_u =
fc60825290 2011-04-18       stephan:     { whio_lock_TYPE_UNLOCK,
fc60825290 2011-04-18       stephan:       whio_lock_CMD_SET_WAIT,
fc60825290 2011-04-18       stephan:       SEEK_SET,
fc60825290 2011-04-18       stephan:       0, 0};
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan: enum {
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    The number of elements to statically allocate
fc60825290 2011-04-18       stephan:    in the whio_dev_alloc_slots object.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: whio_dev_alloc_count = 15
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: struct
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_dev devs[whio_dev_alloc_count]; /* Flawfinder: ignore  this is intentional. */
fc60825290 2011-04-18       stephan:     char used[whio_dev_alloc_count]; /* Flawfinder: ignore  this is intentional. */
fc60825290 2011-04-18       stephan:     whio_size_t next;
fc60825290 2011-04-18       stephan: } whio_dev_alloc_slots = { {whio_dev_empty_m}, {0}, 0 };
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_dev * whio_dev_alloc()
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_dev * dev = 0;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     size_t i = whio_dev_alloc_slots.next;
fc60825290 2011-04-18       stephan:     for( ; i < whio_dev_alloc_count; ++i )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	if( whio_dev_alloc_slots.used[i] ) continue;
fc60825290 2011-04-18       stephan: 	whio_dev_alloc_slots.next = i+1;
fc60825290 2011-04-18       stephan: 	whio_dev_alloc_slots.used[i] = 1;
fc60825290 2011-04-18       stephan: 	dev = &whio_dev_alloc_slots.devs[i];
fc60825290 2011-04-18       stephan: 	//WHIO_DEBUG("Allocated device #%u @0x%p\n", i, (void const *)dev );
fc60825290 2011-04-18       stephan: 	break;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan:     if( ! dev ) dev = (whio_dev *) whio_malloc( sizeof(whio_dev) );
fc60825290 2011-04-18       stephan:     if( dev ) *dev = whio_dev_empty;
fc60825290 2011-04-18       stephan:     return dev;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void whio_dev_free( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( dev ) *dev = whio_dev_empty;
fc60825290 2011-04-18       stephan:     else return;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     if( (dev < &whio_dev_alloc_slots.devs[0]) ||
fc60825290 2011-04-18       stephan: 	(dev > &whio_dev_alloc_slots.devs[whio_dev_alloc_count-1]) )
fc60825290 2011-04-18       stephan:     { /* doesn't belong to us. */
fc60825290 2011-04-18       stephan: 	whio_free(dev);
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	size_t ndx = dev - &whio_dev_alloc_slots.devs[0];
fc60825290 2011-04-18       stephan: 	if( 0 )
fc60825290 2011-04-18       stephan: 	{
fc60825290 2011-04-18       stephan: 	    WHIO_DEBUG("Address range = 0x%p to 0x%p, ndx=%u\n",
fc60825290 2011-04-18       stephan: 		       (void const *)&whio_dev_alloc_slots.devs[0],
fc60825290 2011-04-18       stephan: 		       (void const *)&whio_dev_alloc_slots.devs[whio_dev_alloc_count-1],
fc60825290 2011-04-18       stephan: 		       ndx
fc60825290 2011-04-18       stephan: 		       );
fc60825290 2011-04-18       stephan: 	    WHIO_DEBUG("Freeing object @0x%p from static pool index %u (@0x%p)\n",
fc60825290 2011-04-18       stephan: 		       (void const *)dev,
fc60825290 2011-04-18       stephan: 		       ndx,
fc60825290 2011-04-18       stephan: 		       (void const *)&whio_dev_alloc_slots.devs[ndx] );
fc60825290 2011-04-18       stephan: 	}
fc60825290 2011-04-18       stephan: 	whio_dev_alloc_slots.used[ndx] = 0;
fc60825290 2011-04-18       stephan: 	if( ndx < whio_dev_alloc_slots.next ) whio_dev_alloc_slots.next = ndx;
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     whio_free(dev);
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_ioctl( whio_dev * dev, int operation, ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev ) return whio_rc.ArgError;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         va_list vargs;
6e8c7e31b6 2011-04-20       stephan:         int rc;
6e8c7e31b6 2011-04-20       stephan:         va_start( vargs, operation );
6e8c7e31b6 2011-04-20       stephan:         rc = dev->api->ioctl( dev, operation, vargs );
6e8c7e31b6 2011-04-20       stephan:         va_end(vargs);
6e8c7e31b6 2011-04-20       stephan:         return rc;
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_write( whio_dev * dev, void const * data, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev->api->write( dev, data, n );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_writeat( whio_dev * dev, whio_size_t pos, void const * data, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev || ! data || !n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         /*WHIO_DEBUG("Writing %u bytes at pos %u\n", n, pos );*/
6e8c7e31b6 2011-04-20       stephan:         whio_size_t const rc = dev->api->seek( dev, pos, SEEK_SET );
6e8c7e31b6 2011-04-20       stephan:         return (whio_rc.SizeTError == rc)
6e8c7e31b6 2011-04-20       stephan:             ? rc
6e8c7e31b6 2011-04-20       stephan:             : whio_dev_write( dev, data, n );
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_readat( whio_dev * dev, whio_size_t pos, void * data, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev || ! data || !n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         /*WHIO_DEBUG("Writing %u bytes at pos %u\n", n, pos );*/
6e8c7e31b6 2011-04-20       stephan:         whio_size_t const rc = dev->api->seek( dev, pos, SEEK_SET );
6e8c7e31b6 2011-04-20       stephan:         return (whio_rc.SizeTError == rc)
6e8c7e31b6 2011-04-20       stephan:             ? rc
6e8c7e31b6 2011-04-20       stephan:             : whio_dev_read( dev, data, n );
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_size( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev ) return whio_rc.SizeTError;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         whio_size_t const pos = dev->api->tell( dev );
6e8c7e31b6 2011-04-20       stephan:         if( whio_rc.SizeTError == pos ) return pos;
6e8c7e31b6 2011-04-20       stephan:         else
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             whio_size_t const rc = dev->api->seek( dev, 0L, SEEK_END );
6e8c7e31b6 2011-04-20       stephan:             dev->api->seek( dev, pos, SEEK_SET );
6e8c7e31b6 2011-04-20       stephan:             return rc;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_rewind( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     return (whio_rc.SizeTError != dev->api->seek( dev, 0, SEEK_SET ))
fc60825290 2011-04-18       stephan: 	? whio_rc.OK
fc60825290 2011-04-18       stephan: 	: whio_rc.IOError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_copy( whio_dev * src, whio_dev * dest )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! src || ! dest ) return whio_rc.ArgError;
6e8c7e31b6 2011-04-20       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         int rc = whio_rc.OK;
6e8c7e31b6 2011-04-20       stephan:         enum { bufSize = (1024 * 4) };
6e8c7e31b6 2011-04-20       stephan:         unsigned char buf[bufSize];  /* Flawfinder: ignore This is intentional and used correctly in the loop below. */
6e8c7e31b6 2011-04-20       stephan:         whio_size_t rlen = 0;
6e8c7e31b6 2011-04-20       stephan:         if( 0 != src->api->seek( src, 0L, SEEK_SET ) )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             return whio_rc.RangeError;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         while( (rlen = src->api->read( src, buf /*Flawfinder: ignore  This is safe in conjunction with bufSize*/, bufSize ) ) )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             if( rlen != dest->api->write( dest, buf, rlen ) )
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 rc = whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:                 break;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_copy_n( whio_dev * src, whio_size_t n, whio_dev * dest, whio_size_t * outCount )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( outCount ) *outCount = 0;
fc60825290 2011-04-18       stephan:     if( ! src || ! dest ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     else if( ! n ) return whio_rc.RangeError;
6e8c7e31b6 2011-04-20       stephan:     else if( ! (WHIO_MODE_WRITE & dest->api->iomode(dest) ) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     }
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         enum { BufLen = (1024 * 4) };
6e8c7e31b6 2011-04-20       stephan:         unsigned char buf[BufLen];
6e8c7e31b6 2011-04-20       stephan:         whio_size_t total = 0;
6e8c7e31b6 2011-04-20       stephan:         whio_size_t iorc = 0;
6e8c7e31b6 2011-04-20       stephan:         int rc = whio_rc.OK;
6e8c7e31b6 2011-04-20       stephan:         whio_size_t iosz = 0;
6e8c7e31b6 2011-04-20       stephan:         whio_size_t x = 0;
6e8c7e31b6 2011-04-20       stephan:         while( total < n )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             x = n - total;
6e8c7e31b6 2011-04-20       stephan:             iosz = (BufLen>x) ? x : BufLen;
6e8c7e31b6 2011-04-20       stephan:             iorc = src->api->read( src, buf, iosz);
6e8c7e31b6 2011-04-20       stephan:             if( iosz != iorc )
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 rc = whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:                 break;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:             iorc = dest->api->write( dest, buf, iosz );
6e8c7e31b6 2011-04-20       stephan:             if( iosz != iorc )
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 rc = whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:                 break;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:             total += iorc;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         if(outCount) *outCount = total;
6e8c7e31b6 2011-04-20       stephan:         return rc;
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static long whio_dev_printf_appender( void * arg, char const * data, long n )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     size_t sz = (size_t)n;
6e8c7e31b6 2011-04-20       stephan:     whio_dev * dev = NULL;
fc60825290 2011-04-18       stephan:     if( ! arg || !data || (n<1) ) return -1;
fc60825290 2011-04-18       stephan:     if( n < sz ) return -1; /* negative n */
6e8c7e31b6 2011-04-20       stephan:     dev = (whio_dev*)arg;
fc60825290 2011-04-18       stephan:     sz = dev->api->write( dev, data, sz );
6e8c7e31b6 2011-04-20       stephan:     return (sz == whio_rc.SizeTError) ? 0 : (long) sz; /* FIXME: check for overflow! */
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: size_t whio_dev_writefv( whio_dev * dev, const char *fmt, va_list ap )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     long const rc = whprintfv( whio_dev_printf_appender, dev, fmt, ap );
fc60825290 2011-04-18       stephan:     return (rc < 0) ? 0 : (size_t)rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: size_t whio_dev_writef( whio_dev * dev, const char *fmt, ... )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     va_list vargs;
6e8c7e31b6 2011-04-20       stephan:     size_t rc;
fc60825290 2011-04-18       stephan:     va_start( vargs, fmt );
6e8c7e31b6 2011-04-20       stephan:     rc = whio_dev_writefv( dev, fmt, vargs );
fc60825290 2011-04-18       stephan:     va_end(vargs);
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_read( whio_dev * dev, void * dest, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->read( dev, dest, n ) : 0; /*Flawfinder: ignore  Bounds check is done in proxied function (cannot be done here). */
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_eof( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->eof( dev ) : whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_tell( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->tell( dev ) : whio_rc.SizeTError;;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_size_t whio_dev_seek( whio_dev * dev, whio_off_t pos, int whence )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->seek( dev, pos, whence ) : whio_rc.SizeTError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_flush( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->flush( dev ) : whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_truncate( whio_dev * dev, whio_off_t size )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->truncate( dev, size ) : whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void whio_dev_finalize( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( dev ) dev->api->finalize( dev );
fc60825290 2011-04-18       stephan:     return;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: bool whio_dev_close( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return dev ? dev->api->close( dev ) : false;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_lock( whio_dev * dev, whio_lock_request * lock )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev || !lock ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     /** This check is _also_ left up to device impls because
fc60825290 2011-04-18       stephan:         they might get locks requested through a different
fc60825290 2011-04-18       stephan:         interface (i.e. directly over ioctl()).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:         We perform this check _here_ mainly as a fail-fast case before
fc60825290 2011-04-18       stephan:         delving into ioctl().
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     else if( (lock->type == whio_lock_TYPE_WRITE)
fc60825290 2011-04-18       stephan:              && !(dev->api->iomode(dev) & WHIO_MODE_WRITE)
fc60825290 2011-04-18       stephan:              )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return whio_dev_ioctl( dev, whio_dev_ioctl_WHIO_LOCK, lock );
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_fetch_result * whio_dev_fetch( whio_dev * dev, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev ) return 0;
6e8c7e31b6 2011-04-20       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         whio_fetch_result * rc = (whio_fetch_result*)whio_malloc(sizeof(whio_fetch_result));
6e8c7e31b6 2011-04-20       stephan:         whio_size_t sza;
6e8c7e31b6 2011-04-20       stephan:         if( ! rc ) return 0;
6e8c7e31b6 2011-04-20       stephan:         rc->alloced = 0;
6e8c7e31b6 2011-04-20       stephan:         rc->requested = n;
6e8c7e31b6 2011-04-20       stephan:         rc->read = 0;
6e8c7e31b6 2011-04-20       stephan:         if( ! n ) return rc;
6e8c7e31b6 2011-04-20       stephan:         sza = n+1 /* the +1 is necessary so we can ensure nulls for script-side strings. */;
6e8c7e31b6 2011-04-20       stephan:         rc->data = (char *)malloc(sza);
6e8c7e31b6 2011-04-20       stephan:         if( ! rc->data )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             whio_free(rc);
6e8c7e31b6 2011-04-20       stephan:             return 0;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         rc->alloced = sza;
6e8c7e31b6 2011-04-20       stephan:         memset( rc->data, 0, sza );
6e8c7e31b6 2011-04-20       stephan:         rc->read = dev->api->read( dev, rc->data, n ); /*Flawfinder: ignore rc->data will always be longer than (see above). */
6e8c7e31b6 2011-04-20       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_fetch_r( whio_dev * dev, whio_size_t n, whio_fetch_result * tgt )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev || !tgt ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     if( ! n )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	tgt->requested = tgt->read = n;
fc60825290 2011-04-18       stephan: 	return whio_rc.OK;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     tgt->read = 0;
fc60825290 2011-04-18       stephan:     if( !tgt->data || (tgt->alloced < n) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	whio_size_t sza = n + 1;
fc60825290 2011-04-18       stephan: 	void * p = realloc( tgt->data, sza );
fc60825290 2011-04-18       stephan: 	if( ! p ) return whio_rc.AllocError;
fc60825290 2011-04-18       stephan: 	memset( p, 0, sza );
fc60825290 2011-04-18       stephan: 	tgt->data = p;
fc60825290 2011-04-18       stephan: 	tgt->alloced = sza;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     tgt->requested = n;
fc60825290 2011-04-18       stephan:     memset( tgt->data, 0, n );
fc60825290 2011-04-18       stephan:     tgt->read = dev->api->read( dev, tgt->data, n );  /*Flawfinder: ignore  tgt->data will always be  longer than n as long as tgt->allocated is set properly. */
fc60825290 2011-04-18       stephan:     return whio_rc.OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_fetch_free( whio_fetch_result * r )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( r )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         whio_dev_fetch_free_data(r);
fc60825290 2011-04-18       stephan: 	whio_free(r);
fc60825290 2011-04-18       stephan: 	return whio_rc.OK;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: int whio_dev_fetch_free_data( whio_fetch_result * r )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( r )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( r->data )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             free(r->data);
fc60825290 2011-04-18       stephan:             r->alloced = 0;
fc60825290 2011-04-18       stephan:             r->data = 0;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: 	return whio_rc.OK;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: const whio_blockdev whio_blockdev_empty = whio_blockdev_empty_m;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan: enum {
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    The number of elements to statically allocate
fc60825290 2011-04-18       stephan:    in the whio_blockdev_alloc_slots object.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: whio_blockdev_alloc_count = 10
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: #define whio_blockdev_alloc_slots_whio_blockdev_INIT {0 /* FILL THIS OUT FOR whio_blockdev OBJECTS! */}
fc60825290 2011-04-18       stephan: static struct
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_blockdev objs[whio_blockdev_alloc_count]; /* Flawfinder: ignore This is intentional. */
fc60825290 2011-04-18       stephan:     char used[whio_blockdev_alloc_count]; /* Flawfinder: ignore This is intentional. */
fc60825290 2011-04-18       stephan: } whio_blockdev_alloc_slots = { { whio_blockdev_empty_m }, {0} };
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_blockdev * whio_blockdev_alloc()
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_blockdev * obj = 0;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     size_t i = 0;
fc60825290 2011-04-18       stephan:     for( ; i < whio_blockdev_alloc_count; ++i )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	if( whio_blockdev_alloc_slots.used[i] ) continue;
fc60825290 2011-04-18       stephan: 	whio_blockdev_alloc_slots.used[i] = 1;
fc60825290 2011-04-18       stephan: 	obj = &whio_blockdev_alloc_slots.objs[i];
fc60825290 2011-04-18       stephan: 	break;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan:     if( ! obj ) obj = (whio_blockdev *) whio_malloc( sizeof(whio_blockdev) );
fc60825290 2011-04-18       stephan:     if( obj ) *obj = whio_blockdev_empty;
fc60825290 2011-04-18       stephan:     return obj;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: void whio_blockdev_free( whio_blockdev * obj )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! obj ) return;
fc60825290 2011-04-18       stephan:     whio_blockdev_cleanup( obj );
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     if( (obj < &whio_blockdev_alloc_slots.objs[0]) ||
fc60825290 2011-04-18       stephan: 	(obj > &whio_blockdev_alloc_slots.objs[whio_blockdev_alloc_count-1]) )
fc60825290 2011-04-18       stephan:     { /* it does not belong to us */
fc60825290 2011-04-18       stephan: 	whio_free(obj);
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	const size_t ndx = (obj - &whio_blockdev_alloc_slots.objs[0]);
fc60825290 2011-04-18       stephan: 	whio_blockdev_alloc_slots.objs[ndx] = whio_blockdev_empty;
fc60825290 2011-04-18       stephan: 	whio_blockdev_alloc_slots.used[ndx] = 0;
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     whio_free(obj);
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: bool whio_blockdev_cleanup( whio_blockdev * self )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self ) return false;
fc60825290 2011-04-18       stephan:     if( self->impl.fence )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         if( self->blocks.count )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             self->impl.fence->api->finalize( self->impl.fence );
fc60825290 2011-04-18       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         /* else fence was pointing back to the parent device. */
fc60825290 2011-04-18       stephan: 	self->impl.fence = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     *self = whio_blockdev_empty;
fc60825290 2011-04-18       stephan:     return true;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_blockdev_setup( whio_blockdev * self, whio_dev * parent, whio_size_t parent_offset,
fc60825290 2011-04-18       stephan:                          whio_size_t block_size, whio_size_t count, void const * prototype )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self || ! parent || ! count || ! block_size ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     *self = whio_blockdev_empty;
fc60825290 2011-04-18       stephan:     self->impl.fence = whio_dev_subdev_create( parent, parent_offset, parent_offset + (count * block_size) );
fc60825290 2011-04-18       stephan:     if( ! self->impl.fence ) return whio_rc.AllocError;
fc60825290 2011-04-18       stephan:     self->blocks.prototype = prototype;
fc60825290 2011-04-18       stephan:     self->blocks.size = block_size;
fc60825290 2011-04-18       stephan:     self->blocks.count = count;
fc60825290 2011-04-18       stephan:     return whio_rc.OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_blockdev_setup2( whio_blockdev * self, whio_dev * parent, whio_size_t block_size, void const * prototype )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! self || ! parent || ! block_size ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     *self = whio_blockdev_empty;
fc60825290 2011-04-18       stephan:     self->impl.fence = parent;
fc60825290 2011-04-18       stephan:     self->blocks.prototype = prototype;
fc60825290 2011-04-18       stephan:     self->blocks.size = block_size;
fc60825290 2011-04-18       stephan:     self->blocks.count = 0;
fc60825290 2011-04-18       stephan:     return whio_rc.OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_blockdev_wipe( whio_blockdev * self, whio_size_t id )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return (self && self->blocks.prototype)
fc60825290 2011-04-18       stephan:         ? whio_blockdev_write( self, id, self->blocks.prototype )
fc60825290 2011-04-18       stephan:         : whio_rc.ArgError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: bool whio_blockdev_in_range( whio_blockdev const * self, whio_size_t id )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return !self
fc60825290 2011-04-18       stephan: 	? false
fc60825290 2011-04-18       stephan: 	: (self->blocks.count ? (id < self->blocks.count) : true);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Returns the on-disk position of the given block ID, relative to
fc60825290 2011-04-18       stephan:    self, or whio_rc.SizeTError if !self or if id is not in range for
fc60825290 2011-04-18       stephan:    self.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static whio_size_t whio_block_offset_for_id( whio_blockdev * self, whio_size_t id )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     return ( ! self || !whio_blockdev_in_range( self, id ) )
fc60825290 2011-04-18       stephan: 	? whio_rc.SizeTError
fc60825290 2011-04-18       stephan: 	: (id * self->blocks.size);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_blockdev_write( whio_blockdev * self, whio_size_t id, void const * src )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! src ) return whio_rc.ArgError;
6e8c7e31b6 2011-04-20       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         whio_size_t const pos = whio_block_offset_for_id( self, id );
6e8c7e31b6 2011-04-20       stephan:         if( whio_rc.SizeTError == pos )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             WHIO_DEBUG("id #%"WHIO_SIZE_T_PFMT" is not valid for this whio_blockdev. block count=%"WHIO_SIZE_T_PFMT"\n",id,self->blocks.count);
6e8c7e31b6 2011-04-20       stephan:             return whio_rc.RangeError;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         if( ! src ) return false;
6e8c7e31b6 2011-04-20       stephan:         if( pos != self->impl.fence->api->seek( self->impl.fence, pos, SEEK_SET ) ) return whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:         return (self->blocks.size == self->impl.fence->api->write( self->impl.fence, src, self->blocks.size ))
6e8c7e31b6 2011-04-20       stephan:             ? whio_rc.OK
6e8c7e31b6 2011-04-20       stephan:             : whio_rc.IOError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_blockdev_read( whio_blockdev * self, whio_size_t id, void * dest )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     whio_size_t const pos = whio_block_offset_for_id( self, id );
fc60825290 2011-04-18       stephan:     if( whio_rc.SizeTError == pos ) return whio_rc.RangeError;
6e8c7e31b6 2011-04-20       stephan:     else if( pos != self->impl.fence->api->seek( self->impl.fence, pos, SEEK_SET ) ) return whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:     else return (self->blocks.size == self->impl.fence->api->read( self->impl.fence, dest, self->blocks.size ))  /*Flawfinder: ignore  Bounds check is mostly done in self->impl.fence->api->read(). Bounds of dest must be ensured by the caller. */
6e8c7e31b6 2011-04-20       stephan:         ? whio_rc.OK
6e8c7e31b6 2011-04-20       stephan:         : whio_rc.IOError;
fc60825290 2011-04-18       stephan: }
6e8c7e31b6 2011-04-20       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: int whio_dev_fill( whio_dev * dev, unsigned char ch, whio_size_t n )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     if( ! dev ) return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     else if( ! n ) return whio_rc.RangeError;
fc60825290 2011-04-18       stephan:     else if( ! (WHIO_MODE_WRITE & dev->api->iomode(dev) ) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     }
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         enum { BufLen = 2048 };
6e8c7e31b6 2011-04-20       stephan:         whio_size_t buf[BufLen];
6e8c7e31b6 2011-04-20       stephan:         whio_size_t wrc = 0;
6e8c7e31b6 2011-04-20       stephan:         whio_size_t total = 0;
6e8c7e31b6 2011-04-20       stephan:         int rc = 0;
6e8c7e31b6 2011-04-20       stephan:         memset( buf, 0, (n < BufLen) ? n : BufLen );
6e8c7e31b6 2011-04-20       stephan:         while( total < n )
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             const whio_size_t x = n - total;
6e8c7e31b6 2011-04-20       stephan:             const whio_size_t wsz = (BufLen>x) ? x : BufLen;
6e8c7e31b6 2011-04-20       stephan:             wrc = dev->api->write( dev, buf, wsz);
6e8c7e31b6 2011-04-20       stephan:             if( wsz != wrc )
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 rc = whio_rc.IOError;
6e8c7e31b6 2011-04-20       stephan:                 break;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:             total += wrc;
6e8c7e31b6 2011-04-20       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         return rc;
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: /* end file src/whio_dev.c */
fc60825290 2011-04-18       stephan: /* begin file src/whio_dev_FILE.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whio_dev_FILE.c"
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   License: Public Domain
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: /************************************************************************
fc60825290 2011-04-18       stephan: Implementations for a whio_dev type for wrapping a FILE handle.
fc60825290 2011-04-18       stephan: It complies with the whio_dev interface, and all
fc60825290 2011-04-18       stephan: implementation-specified behaviours of the interface are documented
fc60825290 2011-04-18       stephan: along with the factory functions for creating the device objects.
fc60825290 2011-04-18       stephan: ************************************************************************/
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !defined(_POSIX_C_SOURCE)
fc60825290 2011-04-18       stephan: /* required for for fileno(), ftello(), maybe others */
fc60825290 2011-04-18       stephan: #  define _POSIX_C_SOURCE 200112L
6e8c7e31b6 2011-04-20       stephan: /*#  define _POSIX_C_SOURCE 199309L */
6e8c7e31b6 2011-04-20       stephan: /*#  define _POSIX_C_SOURCE 199506L */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #include <unistd.h> /* ftruncate() */
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* malloc()/free() */
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
6e8c7e31b6 2011-04-20       stephan: /*#include <stdio.h> */
fc60825290 2011-04-18       stephan: #if defined(__GNUC__) || defined(__TINYC__)
fc60825290 2011-04-18       stephan: #if !defined(GCC_VERSION) || (GCC_VERSION < 40100)
fc60825290 2011-04-18       stephan: /* i don't actually know which versions need this, but 4.0.2 does. */
fc60825290 2011-04-18       stephan:     extern int ftruncate(int , off_t);
fc60825290 2011-04-18       stephan:     extern int fsync(int fd);
6e8c7e31b6 2011-04-20       stephan: /*#  warning "Kludging ftruncate() and fsync() declartions." */
6e8c7e31b6 2011-04-20       stephan: /*#else */
6e8c7e31b6 2011-04-20       stephan: /*#  warning "Hoping ftruncate() and fsync() are declared." */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #endif /* __GNUC__ */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_USE_FCNTL
fc60825290 2011-04-18       stephan: #  include <fcntl.h>
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Internal implementation details for the whio_dev FILE wrapper.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef struct whio_dev_FILE
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Underlying FILE handle. Owned by this
fc60825290 2011-04-18       stephan:        object.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     FILE * fp;
fc60825290 2011-04-18       stephan:     int fileno;
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Flags whether we need to do a flush (i.e. if any writes
fc60825290 2011-04-18       stephan:        have been called since the last flush).
fc60825290 2011-04-18       stephan:      */
fc60825290 2011-04-18       stephan:     short needsFlush;
fc60825290 2011-04-18       stephan:     bool ownsFile;
fc60825290 2011-04-18       stephan:     whio_iomodes iomode;
fc60825290 2011-04-18       stephan:     /** We use this to allow us to combine two mallocs into one. */
fc60825290 2011-04-18       stephan:     whio_dev dev;
fc60825290 2011-04-18       stephan: } whio_dev_FILE;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Initialization object for whio_dev_FILE objects. Also used as
fc60825290 2011-04-18       stephan:    whio_dev::typeID for such objects.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define WHIO_DEV_FILE_INIT { \
fc60825290 2011-04-18       stephan:     0, /* fp */ \
fc60825290 2011-04-18       stephan:     0, /* fileno */ \
fc60825290 2011-04-18       stephan:     0, /* needsFlush */ \
fc60825290 2011-04-18       stephan:     0, /* ownsFile */                       \
fc60825290 2011-04-18       stephan:     WHIO_MODE_INVALID /*iomode*/,                      \
fc60825290 2011-04-18       stephan:     whio_dev_empty_m/*dev*/ \
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: static const whio_dev_FILE whio_dev_FILE_meta_init = WHIO_DEV_FILE_INIT;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan: enum {
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    The number of elements to statically allocate
fc60825290 2011-04-18       stephan:    in the whio_dev_FILE_alloc_slots object.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: whio_dev_FILE_alloc_count = 5
fc60825290 2011-04-18       stephan: };
fc60825290 2011-04-18       stephan: struct
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_dev_FILE objs[whio_dev_FILE_alloc_count];
fc60825290 2011-04-18       stephan:     char used[whio_dev_FILE_alloc_count];
fc60825290 2011-04-18       stephan: } whio_dev_FILE_alloc_slots = { {WHIO_DEV_FILE_INIT}, {0} };
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #undef WHIO_DEV_FILE_INIT
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_dev_FILE * whio_dev_FILE_alloc()
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_dev_FILE * obj = 0;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     size_t i = 0;
fc60825290 2011-04-18       stephan:     for( ; i < whio_dev_FILE_alloc_count; ++i )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	if( whio_dev_FILE_alloc_slots.used[i] ) continue;
fc60825290 2011-04-18       stephan: 	whio_dev_FILE_alloc_slots.used[i] = 1;
fc60825290 2011-04-18       stephan: 	obj = &whio_dev_FILE_alloc_slots.objs[i];
fc60825290 2011-04-18       stephan: 	break;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan:     if( ! obj ) obj = (whio_dev_FILE *) whio_malloc( sizeof(whio_dev_FILE) );
fc60825290 2011-04-18       stephan:     if( obj ) *obj = whio_dev_FILE_meta_init;
fc60825290 2011-04-18       stephan:     return obj;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static void whio_dev_FILE_free( whio_dev_FILE * obj )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_ENABLE_STATIC_MALLOC
fc60825290 2011-04-18       stephan:     if( (obj < &whio_dev_FILE_alloc_slots.objs[0]) ||
fc60825290 2011-04-18       stephan: 	(obj > &whio_dev_FILE_alloc_slots.objs[whio_dev_FILE_alloc_count-1]) )
fc60825290 2011-04-18       stephan:     { /* it does not belong to us */
fc60825290 2011-04-18       stephan: 	whio_free(obj);
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	const size_t ndx = (obj - &whio_dev_FILE_alloc_slots.objs[0]);
fc60825290 2011-04-18       stephan: 	whio_dev_FILE_alloc_slots.objs[ndx] = whio_dev_FILE_meta_init;
fc60825290 2011-04-18       stephan: 	whio_dev_FILE_alloc_slots.used[ndx] = 0;
fc60825290 2011-04-18       stephan: 	return;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #else
fc60825290 2011-04-18       stephan:     whio_free(obj);
fc60825290 2011-04-18       stephan: #endif /* WHIO_CONFIG_ENABLE_STATIC_MALLOC */
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    A helper for the whio_dev_FILE API. Requires that the 'dev'
fc60825290 2011-04-18       stephan:    parameter be-a whio_dev and that that device is-a whio_dev_FILE.
fc60825290 2011-04-18       stephan:  */
fc60825290 2011-04-18       stephan: #define WHIO_FILE_DECL(RV) whio_dev_FILE * f = (dev ? (whio_dev_FILE*)dev->impl.data : 0); \
fc60825290 2011-04-18       stephan:     if( !f || !f->fp || ((void const *)&whio_dev_FILE_meta_init != dev->impl.typeID) ) return RV
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_FILE_read( whio_dev * dev, void * dest, whio_size_t n )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     whio_size_t rc;
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.SizeTError);
fc60825290 2011-04-18       stephan:     if( f->needsFlush ) dev->api->flush(dev);
6e8c7e31b6 2011-04-20       stephan:     rc = (dev && dest)
6e8c7e31b6 2011-04-20       stephan:         ? fread( dest, sizeof(char), n, f->fp )
6e8c7e31b6 2011-04-20       stephan:         : 0;
fc60825290 2011-04-18       stephan:     if( rc == n ) f->iomode |= WHIO_MODE_READ;
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_FILE_write( whio_dev * dev, void const * src, whio_size_t n )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     whio_size_t rc;
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(0);
fc60825290 2011-04-18       stephan:     f->needsFlush = (n ? 1 : 0);
6e8c7e31b6 2011-04-20       stephan:     rc = (dev && src && n)
fc60825290 2011-04-18       stephan: 	? fwrite( src, sizeof(char), n, f->fp )
fc60825290 2011-04-18       stephan: 	: 0;
fc60825290 2011-04-18       stephan:     if( rc == n ) f->iomode |= WHIO_MODE_WRITE;
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_error( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     return ferror(f->fp);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_clear_error( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     clearerr(f->fp);
fc60825290 2011-04-18       stephan:     return whio_rc.OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_eof( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     return feof(f->fp);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_FILE_tell( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     off_t rc;
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.SizeTError);
6e8c7e31b6 2011-04-20       stephan:     rc = ftello(f->fp);
fc60825290 2011-04-18       stephan:     return (rc>=0) ? (whio_size_t)rc : whio_rc.SizeTError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_FILE_seek( whio_dev * dev, whio_off_t pos, int whence )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.SizeTError);
fc60825290 2011-04-18       stephan:     if( 0 == fseeko( f->fp, pos, whence ) )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	off_t t = ftello( f->fp );
fc60825290 2011-04-18       stephan: 	return (t >= 0) ? (whio_size_t)t : whio_rc.SizeTError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return whio_rc.SizeTError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_flush( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     if( ! (WHIO_MODE_WRITE & f->iomode) ) return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         f->needsFlush = 0;
fc60825290 2011-04-18       stephan:         return (0 == fflush( f->fp ))
fc60825290 2011-04-18       stephan:             ? whio_rc.OK
fc60825290 2011-04-18       stephan:             : whio_rc.IOError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_trunc( whio_dev * dev, whio_off_t len )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     if( !(WHIO_MODE_WRITE & f->iomode) ) return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return (0 == ftruncate( f->fileno, len ))
fc60825290 2011-04-18       stephan:             ? whio_rc.OK
fc60825290 2011-04-18       stephan:             : whio_rc.IOError;
fc60825290 2011-04-18       stephan:         /** ^^^ is there a way to truncate a FILE handle without using fileno()? */
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
6e8c7e31b6 2011-04-20       stephan: /* internal func defined and documented in whio_dev_fileno.c: */
fc60825290 2011-04-18       stephan: extern int whio_dev_ioctl_fcntl_proxy( whio_iomodes iomode, int fileno, int ctl, void * lockObj );
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_FILE_ioctl( whio_dev * dev, int arg, va_list vargs )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     int rc = whio_rc.UnsupportedError;
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        The standard ioctl() looks like:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        int ioctl(int d, int request, ...);
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        which means there's no way for us to pass our ... directly to
fc60825290 2011-04-18       stephan:        it.  So it appears to be impossible to emulate the system's
fc60825290 2011-04-18       stephan:        ioctl() without literally checking every possible ioctl and
fc60825290 2011-04-18       stephan:        casting the first ... arg to the proper type (which is likely
fc60825290 2011-04-18       stephan:        platform-dependent).
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     switch( arg )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_FILE_fd:
fc60825290 2011-04-18       stephan: 	  rc = whio_rc.OK;
fc60825290 2011-04-18       stephan: 	  *(va_arg(vargs,int*)) = f->fileno;
fc60825290 2011-04-18       stephan: 	  break;
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_USE_FCNTL
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_mask_FCNTL_LOCKING:
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_mask_WHIO_LOCKING:
fc60825290 2011-04-18       stephan:           rc = whio_rc.OK;
fc60825290 2011-04-18       stephan:           break;
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_FCNTL_lock_nowait:
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_FCNTL_lock_wait:
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_FCNTL_lock_get:
fc60825290 2011-04-18       stephan:       case whio_dev_ioctl_WHIO_LOCK:
fc60825290 2011-04-18       stephan:           rc = whio_dev_ioctl_fcntl_proxy( f->iomode, f->fileno, arg, va_arg(vargs,void *) );
fc60825290 2011-04-18       stephan:           break;
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:       default: break;
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_iomodes whio_dev_FILE_iomode( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(WHIO_MODE_INVALID);
fc60825290 2011-04-18       stephan:     return f->iomode;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static bool whio_dev_FILE_close( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_FILE_DECL(false);
fc60825290 2011-04-18       stephan:     dev->api->flush(dev);
fc60825290 2011-04-18       stephan:     if( dev->client.dtor ) dev->client.dtor( dev->client.data );
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Reminder: we want it to be (and stay) legal for client.data to
fc60825290 2011-04-18       stephan:        refer to f->fp and client.dtor to destroy f->fp IFF
fc60825290 2011-04-18       stephan:        !f->ownsFile. This allows us to attach (e.g.) popen()-opened
fc60825290 2011-04-18       stephan:        handles as the client data of the device and clean them up
fc60825290 2011-04-18       stephan:        properly when the device is closed.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:        So... don't touch f->fp below unless f->ownsFile.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     dev->client = whio_client_data_empty;
fc60825290 2011-04-18       stephan:     dev->impl.data = 0;
fc60825290 2011-04-18       stephan:     if( f->fp && f->ownsFile ) fclose( f->fp );
fc60825290 2011-04-18       stephan:     f->fileno = 0;
fc60825290 2011-04-18       stephan:     return true;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static void whio_dev_FILE_finalize( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     whio_dev_FILE * f = (dev ? (whio_dev_FILE*)dev->impl.data : 0);
6e8c7e31b6 2011-04-20       stephan:     if( !f || !f->fp || ((void const *)&whio_dev_FILE_meta_init != dev->impl.typeID) ) return;
6e8c7e31b6 2011-04-20       stephan:     else
6e8c7e31b6 2011-04-20       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         dev->api->close( dev );
6e8c7e31b6 2011-04-20       stephan:         whio_dev_FILE_free( f );
6e8c7e31b6 2011-04-20       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: #undef WHIO_FILE_DECL
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static const whio_dev_api whio_dev_FILE_api =
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:     whio_dev_FILE_read,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_write,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_close,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_finalize,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_error,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_clear_error,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_eof,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_tell,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_seek,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_flush,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_trunc,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_ioctl,
fc60825290 2011-04-18       stephan:     whio_dev_FILE_iomode
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static const whio_dev whio_dev_FILE_init =
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:     &whio_dev_FILE_api,
fc60825290 2011-04-18       stephan:     { /* impl */
fc60825290 2011-04-18       stephan:     0, /* data. Must be-a (whio_dev_FILE*) */
fc60825290 2011-04-18       stephan:     (void const *)&whio_dev_FILE_meta_init /* typeID */
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     };
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_dev * whio_dev_for_FILE( FILE * F, bool takeOwnership )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: #if 0
6e8c7e31b6 2011-04-20       stephan:     /* TODO: test this, and enable it if it really does what i think it should do: */
fc60825290 2011-04-18       stephan:     if( (off_t)-1 == lseek( fileno(F), 0L, SEEK_CUR ) )
fc60825290 2011-04-18       stephan:     {/* device does not seem to be seekable (not random-access). */
fc60825290 2011-04-18       stephan: 	return 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: #endif
6e8c7e31b6 2011-04-20       stephan:     whio_dev_FILE * meta = NULL;
6e8c7e31b6 2011-04-20       stephan:     whio_dev * dev = NULL;
6e8c7e31b6 2011-04-20       stephan:     if( ! F ) return NULL;
6e8c7e31b6 2011-04-20       stephan:     meta = whio_dev_FILE_alloc();
fc60825290 2011-04-18       stephan:     if( ! meta ) return NULL;
fc60825290 2011-04-18       stephan:     *meta = whio_dev_FILE_meta_init;
6e8c7e31b6 2011-04-20       stephan:     dev = &meta->dev;
fc60825290 2011-04-18       stephan:     *dev = whio_dev_FILE_init;
fc60825290 2011-04-18       stephan:     dev->impl.data = meta;
fc60825290 2011-04-18       stephan:     meta->fp = F;
fc60825290 2011-04-18       stephan:     meta->ownsFile = takeOwnership;
fc60825290 2011-04-18       stephan:     meta->fileno = fileno(F);
fc60825290 2011-04-18       stephan:     meta->iomode = WHIO_MODE_UNKNOWN;
fc60825290 2011-04-18       stephan:     return dev;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if 0 /* now implemented in whio_dev_fileno.c, but this may be interesting for later. */
fc60825290 2011-04-18       stephan: whio_dev * whio_dev_for_filename( char const * fname, char const * mode )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     if( ! fname || !mode ) return NULL;
6e8c7e31b6 2011-04-20       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         FILE * f = fopen( fname, mode );
6e8c7e31b6 2011-04-20       stephan:         if( ! f ) return NULL;
6e8c7e31b6 2011-04-20       stephan:         else
6e8c7e31b6 2011-04-20       stephan:         {
6e8c7e31b6 2011-04-20       stephan:             whio_dev * d = whio_dev_for_FILE( f, true );
6e8c7e31b6 2011-04-20       stephan:             if( ! d )
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 fclose(f);
6e8c7e31b6 2011-04-20       stephan:                 return NULL;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:             else
6e8c7e31b6 2011-04-20       stephan:             {
6e8c7e31b6 2011-04-20       stephan:                 whio_dev_FILE * meta = (whio_dev_FILE*)d->impl.data;
6e8c7e31b6 2011-04-20       stephan:                 meta->iomode = whio_mode_to_iomode( mode );
6e8c7e31b6 2011-04-20       stephan:                 return d;
6e8c7e31b6 2011-04-20       stephan:             }
6e8c7e31b6 2011-04-20       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /* end file src/whio_dev_FILE.c */
fc60825290 2011-04-18       stephan: /* begin file src/whio_dev_fileno.c */
fc60825290 2011-04-18       stephan: #line 8 "src/whio_dev_fileno.c"
fc60825290 2011-04-18       stephan: /*
fc60825290 2011-04-18       stephan:   Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   License: Public Domain
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   Many thanks to Lew Pitcher for his tips on implementing this:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:   http://groups.google.com/group/comp.unix.programmer/browse_thread/thread/9ffb66c1d0a4f7f3/7c28cd32b63d99a4
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: /************************************************************************
fc60825290 2011-04-18       stephan: Implementations for a whio_dev type for wrapping a file descriptor
fc60825290 2011-04-18       stephan: handle.  This is almost a 100% copy/paste of the code from
fc60825290 2011-04-18       stephan: whio_dev_FILE.c, but it uses the lower-level read()/write() API
fc60825290 2011-04-18       stephan: instead of the fXXX(FILE*,...) API. Simple tests in libwhefs show this
fc60825290 2011-04-18       stephan: to provide dramatic speed increases.
fc60825290 2011-04-18       stephan: ************************************************************************/
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if !defined(_POSIX_C_SOURCE)
fc60825290 2011-04-18       stephan: /* required for for fileno(), ftello(), fdatasync(), maybe others */
fc60825290 2011-04-18       stephan: #  define _POSIX_C_SOURCE 200112L
6e8c7e31b6 2011-04-20       stephan: /*#  define _POSIX_C_SOURCE 199309L */
6e8c7e31b6 2011-04-20       stephan: /*#  define _POSIX_C_SOURCE 199506L */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #include <assert.h>
fc60825290 2011-04-18       stephan: #include <stdlib.h> /* malloc()/free() */
fc60825290 2011-04-18       stephan: #include <string.h> /* memset() */
fc60825290 2011-04-18       stephan: #include <unistd.h> /* ftruncate(), fdatasync() */
fc60825290 2011-04-18       stephan: #include <errno.h>
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if defined(__GNUC__) || defined(__TINYC__)
fc60825290 2011-04-18       stephan: #if !defined(GCC_VERSION) || (GCC_VERSION < 40100)
fc60825290 2011-04-18       stephan: /* i don't actually know which versions need this, but 4.0.2 does. */
fc60825290 2011-04-18       stephan:     extern int ftruncate(int, off_t);
fc60825290 2011-04-18       stephan:     extern int fsync(int fd);
6e8c7e31b6 2011-04-20       stephan: /*#  warning "Kludging ftruncate() and fsync() declartions." */
6e8c7e31b6 2011-04-20       stephan: /*#else */
6e8c7e31b6 2011-04-20       stephan: /*#  warning "Hoping ftruncate() and fsync() are declared." */
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: #endif /* __GNUC__ */
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: #if WHIO_CONFIG_USE_FCNTL
fc60825290 2011-04-18       stephan: #  include <fcntl.h>
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Internal implementation details for the whio_dev file descriptor
fc60825290 2011-04-18       stephan:    wrapper.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: typedef struct whio_dev_fileno
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:        Underlying FILE handle. Owned by this
fc60825290 2011-04-18       stephan:        object.
fc60825290 2011-04-18       stephan:     */
fc60825290 2011-04-18       stephan:     FILE * fp;
fc60825290 2011-04-18       stephan:     int fileno;
fc60825290 2011-04-18       stephan:     char * filename;
fc60825290 2011-04-18       stephan:     bool atEOF;
fc60825290 2011-04-18       stephan:     int errstate;
fc60825290 2011-04-18       stephan:     whio_iomodes iomode;
fc60825290 2011-04-18       stephan:     /** We use this to allow us to combine two mallocs into one. */
fc60825290 2011-04-18       stephan:     whio_dev * dev;
fc60825290 2011-04-18       stephan:     whio_dev devMem;
fc60825290 2011-04-18       stephan: } whio_dev_fileno;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Initialization object for whio_dev_fileno objects. Also used as
fc60825290 2011-04-18       stephan:    whio_dev::typeID for such objects.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: #define whio_dev_fileno_empty_m { \
fc60825290 2011-04-18       stephan:     0, /* fp */ \
fc60825290 2011-04-18       stephan:     -1, /* fileno */ \
fc60825290 2011-04-18       stephan:     0, /* filename */ \
fc60825290 2011-04-18       stephan:     false, /* atEOF */ \
fc60825290 2011-04-18       stephan:     0, /* errstate */                       \
fc60825290 2011-04-18       stephan:     WHIO_MODE_INVALID /*iomode*/,                      \
fc60825290 2011-04-18       stephan:         NULL/*dev*/,                            \
fc60825290 2011-04-18       stephan:         whio_dev_empty_m/*devMem*/              \
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: static const whio_dev_fileno whio_dev_fileno_meta_empty = whio_dev_fileno_empty_m;
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    Allocates (sizeof(whio_dev_fileno)+plus) bytes. If plus is not 0
fc60825290 2011-04-18       stephan:    then the 'filename' member if the allocated object is pointed to
fc60825290 2011-04-18       stephan:    that memory, which lies just beyond the whio_dev_fileno object.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: static whio_dev_fileno * whio_dev_fileno_alloc( whio_size_t plus )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     unsigned char * m = (unsigned char *)whio_malloc( sizeof(whio_dev_fileno) + plus );
fc60825290 2011-04-18       stephan:     whio_dev_fileno * obj = 0;
fc60825290 2011-04-18       stephan:     if( m )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         obj = (whio_dev_fileno*)m;
fc60825290 2011-04-18       stephan:         *obj = whio_dev_fileno_meta_empty;
fc60825290 2011-04-18       stephan:         if( plus )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             obj->filename = (char *) (m+sizeof(whio_dev_fileno));
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return obj;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static void whio_dev_fileno_free( whio_dev_fileno * obj )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     whio_free(obj);
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /**
fc60825290 2011-04-18       stephan:    A helper for the whio_dev_fileno API. Requires that the 'dev'
fc60825290 2011-04-18       stephan:    parameter be-a whio_dev and that that device is-a whio_dev_fileno.
fc60825290 2011-04-18       stephan:  */
6e8c7e31b6 2011-04-20       stephan: #define WHIO_fileno_DECL(RV) whio_dev_fileno * f = (dev ? (whio_dev_fileno*)dev->impl.data : NULL); \
fc60825290 2011-04-18       stephan:     if( !f || (f->fileno<0) || ((void const *)&whio_dev_fileno_meta_empty != dev->impl.typeID) ) return RV
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_fileno_read( whio_dev * dev, void * dest, whio_size_t n )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     ssize_t rc;
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.SizeTError);
fc60825290 2011-04-18       stephan:     if( ! dest || !n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     rc = read( f->fileno, dest, n );
fc60825290 2011-04-18       stephan:     if( 0 == rc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	f->atEOF = true;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( (ssize_t)-1 == rc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	f->errstate = errno;
fc60825290 2011-04-18       stephan: 	rc = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return (whio_size_t)rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_fileno_write( whio_dev * dev, void const * src, whio_size_t n )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     ssize_t rc;
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(0);
fc60825290 2011-04-18       stephan:     if( ! src || !n ) return 0;
6e8c7e31b6 2011-04-20       stephan:     rc = write( f->fileno, src, n );
fc60825290 2011-04-18       stephan:     if( (ssize_t)-1 == rc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	f->errstate = errno;
fc60825290 2011-04-18       stephan: 	rc = 0;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return rc;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_fileno_error( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     /**
fc60825290 2011-04-18       stephan:       ferror(f->fp) is not likely to be valid b/c we're
fc60825290 2011-04-18       stephan:       using the low-level i/o API, but what the heck...
fc60825290 2011-04-18       stephan:     */
6e8c7e31b6 2011-04-20       stephan:     /*return ferror(f->fp); */
fc60825290 2011-04-18       stephan:     return f->errstate;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_fileno_clear_error( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     /** Because we use the low-level read/write() API instead of fread()/fwrite()
fc60825290 2011-04-18       stephan: 	and friends, using clearerr(f->fp) isn't really going to give us anything.
fc60825290 2011-04-18       stephan: 	We'll go ahead and call it and assume the best.
fc60825290 2011-04-18       stephan:     */
6e8c7e31b6 2011-04-20       stephan:     /*clearerr(f->fp); */
fc60825290 2011-04-18       stephan:     f->errstate = 0;
fc60825290 2011-04-18       stephan:     f->atEOF = false;
fc60825290 2011-04-18       stephan:     return whio_rc.OK;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_fileno_eof( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     return  f->atEOF ? 1 : 0;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_fileno_tell( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     off_t rc;
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.SizeTError);
6e8c7e31b6 2011-04-20       stephan:     rc = lseek( f->fileno, 0L, SEEK_CUR );
fc60825290 2011-04-18       stephan:     return (rc>=0) ? (whio_size_t)rc : whio_rc.SizeTError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static whio_size_t whio_dev_fileno_seek( whio_dev * dev, whio_off_t pos, int whence )
fc60825290 2011-04-18       stephan: {
6e8c7e31b6 2011-04-20       stephan:     off_t rc;
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.SizeTError);
6e8c7e31b6 2011-04-20       stephan:     rc = lseek( f->fileno, pos, whence );
fc60825290 2011-04-18       stephan:     if( pos == rc )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: 	/**
fc60825290 2011-04-18       stephan: 	   The man page for fseek() says (on my system):
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 	   "A successful call to the fseek() function clears the
fc60825290 2011-04-18       stephan: 	   end-of-file indicator for the stream."
fc60825290 2011-04-18       stephan: 	*/
fc60825290 2011-04-18       stephan: 	f->atEOF = false;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     return (rc>=0) ? (whio_size_t) rc : whio_rc.SizeTError;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_fileno_flush( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     if( !(WHIO_MODE_WRITE & f->iomode) ) return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         int const rc = fsync( f->fileno );
fc60825290 2011-04-18       stephan:         /* reminder: i realy want fdatasync(), but some platforms
fc60825290 2011-04-18       stephan:          *cough* Solaris *cough* don't appear to have it. */
6e8c7e31b6 2011-04-20       stephan:         return (0 == rc)
6e8c7e31b6 2011-04-20       stephan:             ? 0
6e8c7e31b6 2011-04-20       stephan:             : whio_rc.IOError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: static int whio_dev_fileno_trunc( whio_dev * dev, whio_off_t len )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(whio_rc.ArgError);
fc60825290 2011-04-18       stephan:     if( !(WHIO_MODE_WRITE & f->iomode) ) return whio_rc.AccessError;
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         int rc = whio_rc.OK;
fc60825290 2011-04-18       stephan:         if( 0 == ftruncate( f->fileno, len ) )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             whio_dev_fileno_flush( dev );
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             rc = whio_rc.IOError;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         return rc;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: whio_iomodes whio_dev_fileno_iomode( whio_dev * dev )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan:     WHIO_fileno_DECL(WHIO_MODE_INVALID);
fc60825290 2011-04-18       stephan:     return f->iomode;
fc60825290 2011-04-18       stephan: }
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: /** @internal
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     Helper for use by whio_dev impls which use fcntl() locks. This
fc60825290 2011-04-18       stephan:     function implements the whio_dev_ioctl_FCNTL family of locking
fc60825290 2011-04-18       stephan:     ioctls, as well as whio_dev_ioctl_WHIO_LOCKING (by translating the
fc60825290 2011-04-18       stephan:     request to an fcntl() lock).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     If WHIO_CONFIG_USE_FCNTL is false then this function does nothing
fc60825290 2011-04-18       stephan:     and returns whio_rc.UnsupportedError.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     The args:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - iomode is the whio_dev::iomode()-compatible value describing the
fc60825290 2011-04-18       stephan:     over-lying whio_dev object's i/o mode. whio_rc.AccessError is
fc60825290 2011-04-18       stephan:     returned if iomode is zero and a write lock is
fc60825290 2011-04-18       stephan:     attempted. (iomode<0) is treated as writable b/c FILE proxy
fc60825290 2011-04-18       stephan:     devices (and possibly others) cannot know their access mode, and
fc60825290 2011-04-18       stephan:     they have a negative iomode.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - ctl is the whio_dev ioctl command. Only the following are
fc60825290 2011-04-18       stephan:     supported:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     whio_dev_ioctl_WHIO_LOCK, whio_dev_ioctl_FCNTL_lock_nowait,
fc60825290 2011-04-18       stephan:     whio_dev_ioctl_FCNTL_lock_wait, whio_dev_ioctl_FCNTL_lock_get.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - fileno is the file descriptor, which is presumably associated
fc60825290 2011-04-18       stephan:     with dev.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - lockObj must be either a populated (whio_lock_request*) if
fc60825290 2011-04-18       stephan:     (ctl==whio_dev_ioctl_WHIO_LOCK), else it must be a populated
fc60825290 2011-04-18       stephan:     ((struct flock *), for all other ctl values). It may not be null.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     Returns zero on success, or one of several different errors on error:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - whio_rc.LockingError = a lock was attempted but fcntl() returned
fc60825290 2011-04-18       stephan:     an error code.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - whio_rc.ArgError = one or more of the arguments is not correct (e.g. lockObj
fc60825290 2011-04-18       stephan:     is null or ctl is out of range).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - whio_rc.AccessError = iomode is 0 and the request is for a write
fc60825290 2011-04-18       stephan:     lock.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     If the lock request is a F_GETLK/whio_lock_CMD_TEST and it
fc60825290 2011-04-18       stephan:     succeeds, the lockObj may be modified:
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - flock::l_type will be changed to F_UNLCK to signify that the
fc60825290 2011-04-18       stephan:     lock _could_ have been placed but wansn't.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - whio_lock::command will be changed to whio_lock_CMD_TEST_PASSED
fc60825290 2011-04-18       stephan:     to signify that the lock _could_ have been placed but wansn't.
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     - whio_rc.InterruptedError if EINTR is returned from fcntl() (lock
fc60825290 2011-04-18       stephan:     was interrupted by a signal).
fc60825290 2011-04-18       stephan: 
fc60825290 2011-04-18       stephan:     Maintenance reminder: this function is used by the whio_dev_FILE
fc60825290 2011-04-18       stephan:     implementation as well.
fc60825290 2011-04-18       stephan: */
fc60825290 2011-04-18       stephan: int whio_dev_ioctl_fcntl_proxy( whio_iomodes iomode, int fileno, int ctl, void * lockObj )
fc60825290 2011-04-18       stephan: {
fc60825290 2011-04-18       stephan: #if ! WHIO_CONFIG_USE_FCNTL
fc60825290 2011-04-18       stephan:     return whio_rc.UnsupportedError;
fc60825290 2011-04-18       stephan: #else
6e8c7e31b6 2011-04-20       stephan:     int rc = 0;
fc60825290 2011-04-18       stephan:     whio_lock_request * wli = NULL;
fc60825290 2011-04-18       stephan:     struct flock * fl = NULL;
fc60825290 2011-04-18       stephan:     if( ! lockObj )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if( whio_dev_ioctl_WHIO_LOCK == ctl )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         wli = (whio_lock_request*)lockObj;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else if(
fc60825290 2011-04-18       stephan:             (ctl == whio_dev_ioctl_FCNTL_lock_nowait)
fc60825290 2011-04-18       stephan:             || (ctl == whio_dev_ioctl_FCNTL_lock_wait)
fc60825290 2011-04-18       stephan:             || (ctl == whio_dev_ioctl_FCNTL_lock_get)
fc60825290 2011-04-18       stephan:             )
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan: #if 0
fc60825290 2011-04-18       stephan:         if( ! fileno )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan: #endif
fc60825290 2011-04-18       stephan:         fl = (struct flock *)lockObj;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     else
fc60825290 2011-04-18       stephan:     {
6e8c7e31b6 2011-04-20       stephan:         /*assert(0 && "Shouldn't ever happen."); */
fc60825290 2011-04-18       stephan:         return whio_rc.ArgError;
fc60825290 2011-04-18       stephan:     }
fc60825290 2011-04-18       stephan:     do
fc60825290 2011-04-18       stephan:     {
fc60825290 2011-04-18       stephan:         struct flock flo /* only used if (wli). */;
fc60825290 2011-04-18       stephan:         int lockCmd = 0;
fc60825290 2011-04-18       stephan:         if( wli )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             fl = &flo;
fc60825290 2011-04-18       stephan:             memset(&flo,0,sizeof(flo));
fc60825290 2011-04-18       stephan:             flo.l_type = (whio_lock_TYPE_UNLOCK == wli->type)
fc60825290 2011-04-18       stephan:                 ? F_UNLCK
fc60825290 2011-04-18       stephan:                 : ((wli->type==whio_lock_TYPE_WRITE) ? F_WRLCK : F_RDLCK)
fc60825290 2011-04-18       stephan:                 ;
fc60825290 2011-04-18       stephan:             flo.l_start = (off_t)wli->start;
fc60825290 2011-04-18       stephan:             flo.l_len = (off_t)wli->length;
fc60825290 2011-04-18       stephan:             flo.l_whence = (short)wli->whence;
fc60825290 2011-04-18       stephan:             lockCmd = (whio_lock_CMD_TEST == wli->command)
fc60825290 2011-04-18       stephan:                 ? F_GETLK
fc60825290 2011-04-18       stephan:                 : ((wli->command==whio_lock_CMD_SET_WAIT) ? F_SETLKW : F_SETLK);
fc60825290 2011-04-18       stephan:             if( (wli->whence == SEEK_SET)
fc60825290 2011-04-18       stephan:                 && (wli->start < 0) )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 rc = whio_rc.RangeError;
fc60825290 2011-04-18       stephan:                 break;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:         }
fc60825290 2011-04-18       stephan:         else
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             lockCmd = (whio_dev_ioctl_FCNTL_lock_get == ctl)
fc60825290 2011-04-18       stephan:                 ? F_GETLK
fc60825290 2011-04-18       stephan:                 : ((whio_dev_ioctl_FCNTL_lock_nowait == ctl)
fc60825290 2011-04-18       stephan:                    ? F_SETLK
fc60825290 2011-04-18       stephan:                    : F_SETLKW
fc60825290 2011-04-18       stephan:                    )
fc60825290 2011-04-18       stephan:                 ;
fc60825290 2011-04-18       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         /* almost there... */
fc60825290 2011-04-18       stephan:         if( !(WHIO_MODE_WRITE & iomode)
fc60825290 2011-04-18       stephan:             && (F_WRLCK == fl->l_type)
fc60825290 2011-04-18       stephan:             )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             rc = whio_rc.AccessError;
fc60825290 2011-04-18       stephan:             break;
fc60825290 2011-04-18       stephan:         }
6e8c7e31b6 2011-04-20       stephan:         /* Finally... */
6e8c7e31b6 2011-04-20       stephan:         /*retry_lock: */
fc60825290 2011-04-18       stephan:         errno = 0;
fc60825290 2011-04-18       stephan:         rc = fcntl( fileno, lockCmd, fl );
fc60825290 2011-04-18       stephan:         if( 0 != rc )
fc60825290 2011-04-18       stephan:         {
fc60825290 2011-04-18       stephan:             if( EINTR == errno)
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 rc = whio_rc.InterruptedError;
6e8c7e31b6 2011-04-20       stephan:                 /* arguable: goto retry_lock; */
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else if( EINVAL == errno )
fc60825290 2011-04-18       stephan:             {
fc60825290 2011-04-18       stephan:                 rc = whio_rc.RangeError;
fc60825290 2011-04-18       stephan:             }
fc60825290 2011-04-18       stephan:             else