fc60825290 2011-04-18 stephan: #include "wh/whio/whio_amalgamation.h" 45f8d4be63 2012-02-27 stephan: /* auto-generated on Mon Feb 20 11:49:24 CET 2012. Do not edit! */ 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: /************************************************************************ 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, "<", 4 ); fc60825290 2011-04-18 stephan: break; fc60825290 2011-04-18 stephan: case '&': ret += pf( pfArg, "&", 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 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: 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: { 45f8d4be63 2012-02-27 stephan: const size_t asz = (3 * npos / 2) + 1; 6e8c7e31b6 2011-04-20 stephan: if( asz < npos ) return -1; /* overflow */ 6e8c7e31b6 2011-04-20 stephan: else 6e8c7e31b6 2011-04-20 stephan: { 45f8d4be63 2012-02-27 stephan: char * buf = (char *)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 */ 45f8d4be63 2012-02-27 stephan: /* auto-generated on Tue Feb 14 23:25:42 CET 2012. Do not edit! */ fc60825290 2011-04-18 stephan: /* begin file 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 45f8d4be63 2012-02-27 stephan: : ( 45f8d4be63 2012-02-27 stephan: (WHALLOC_API(size_t))((off/self->blockSize) 45f8d4be63 2012-02-27 stephan: &self->hashMask) 45f8d4be63 2012-02-27 stephan: ) 45f8d4be63 2012-02-27 stephan: 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: #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) 45f8d4be63 2012-02-27 stephan: #define BYTES_GET(A,BIT) (BYTES_BYTEFOR(A,BIT) & (0x01 << (BIT%8))) 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)) 45f8d4be63 2012-02-27 stephan: #define BITMAP_USE(BIT) (void)BITMAP_SET_USAGE(BIT,1) 45f8d4be63 2012-02-27 stephan: #define BITMAP_UNUSE(BIT) (void)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)) 45f8d4be63 2012-02-27 stephan: #define BITMAP_LINK(BIT) (void)BITMAP_SET_LINK(BIT,1) 45f8d4be63 2012-02-27 stephan: #define BITMAP_UNLINK(BIT) (void)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; 45f8d4be63 2012-02-27 stephan: for( ; (check != startIndex); fc60825290 2011-04-18 stephan: --check, --lastFree ) fc60825290 2011-04-18 stephan: { 45f8d4be63 2012-02-27 stephan: if( BITMAP_IS_USED(check) ) break; 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 ); 45f8d4be63 2012-02-27 stephan: if( self->base.freeIndexHint >= hash) 45f8d4be63 2012-02-27 stephan: { 45f8d4be63 2012-02-27 stephan: self->base.freeIndexHint = hash+blocksNeeded; 45f8d4be63 2012-02-27 stephan: } fc60825290 2011-04-18 stephan: } fc60825290 2011-04-18 stephan: #endif 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; 45f8d4be63 2012-02-27 stephan: if(0) do /* this code is broken, it seems, and i'm too tired to debugger it */ 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: { 45f8d4be63 2012-02-27 stephan: WHALLOC_API(size_t) at = 0; 45f8d4be63 2012-02-27 stephan: WHALLOC_API(size_t) pos = 0; 45f8d4be63 2012-02-27 stephan: WHALLOC_API(size_t) count = 0; fc60825290 2011-04-18 stephan: char isL; fc60825290 2011-04-18 stephan: char isU; fc60825290 2011-04-18 stephan: WHALLOC_API(size_t) inNode; 45f8d4be63 2012-02-27 stephan: int rc = 0; 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: #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: # 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: 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: #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.*/ 45f8d4be63 2012-02-27 stephan: #define CHUNK_USE(P,BIT) (void)CHUNK_SET_USAGE(P,BIT,1) fc60825290 2011-04-18 stephan: /* Clears the given chunk-is-used BIT in page P. Evaluates to 0.*/ 45f8d4be63 2012-02-27 stephan: #define CHUNK_UNUSE(P,BIT) (void)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 ); 45f8d4be63 2012-02-27 stephan: if(NULL == ignored){/*kludge for pedantic gcc*/} 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 ); 45f8d4be63 2012-02-27 stephan: if(NULL == ignored){/*kludge for pedantic gcc*/} 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 */ 45f8d4be63 2012-02-27 stephan: p = WHALLOC_API(book_add_page_impl)( b, 0 ); 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: #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: #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: #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: /* 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: } 45f8d4be63 2012-02-27 stephan: 45f8d4be63 2012-02-27 stephan: char whio_zlib_enabled() 45f8d4be63 2012-02-27 stephan: { 45f8d4be63 2012-02-27 stephan: return WHIO_CONFIG_ENABLE_ZLIB ? 1 : 0; 45f8d4be63 2012-02-27 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: #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: 45f8d4be63 2012-02-27 stephan: whio_iomode_mask whio_mode_to_iomode( char const * mode ) fc60825290 2011-04-18 stephan: { 45f8d4be63 2012-02-27 stephan: whio_iomode_mask 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: /* 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: 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 45f8d4be63 2012-02-27 stephan: { 45f8d4be63 2012-02-27 stephan: whio_size_t sz = (whio_size_t)-1; 45f8d4be63 2012-02-27 stephan: int const rc = whio_dev_ioctl( dev, whio_dev_ioctl_GENERAL_size, &sz ); 45f8d4be63 2012-02-27 stephan: if( 0 == rc ) return sz; 6e8c7e31b6 2011-04-20 stephan: else 45f8d4be63 2012-02-27 stephan: { 45f8d4be63 2012-02-27 stephan: whio_size_t const pos = dev->api->tell( dev ); 45f8d4be63 2012-02-27 stephan: if( whio_rc.SizeTError == pos ) return pos; 45f8d4be63 2012-02-27 stephan: else 45f8d4be63 2012-02-27 stephan: { 45f8d4be63 2012-02-27 stephan: whio_size_t const rc = dev->api->seek( dev, 0L, SEEK_END ); 45f8d4be63 2012-02-27 stephan: dev->api->seek( dev, (whio_off_t)pos, SEEK_SET ); 45f8d4be63 2012-02-27 stephan: return rc; 45f8d4be63 2012-02-27 stephan: } 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) ) ) 6e8c7e31b6 2011-04-20 stephan: { 6e8c7e31b6 2011-04-20 stephan: return whio_rc.AccessError; 6e8c7e31b6 2011-04-20 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; 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: /* 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 <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: 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); 45f8d4be63 2012-02-27 stephan: if( 0 == fseeko( f->fp, WHIO_OFF_TO_STD_OFF_T(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: { 45f8d4be63 2012-02-27 stephan: return (0 == ftruncate( f->fileno, WHIO_OFF_TO_STD_OFF_T(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: 45f8d4be63 2012-02-27 stephan: whio_iomode_mask 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: /* 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 <errno.h> 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; 45f8d4be63 2012-02-27 stephan: whio_iomode_mask 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); 45f8d4be63 2012-02-27 stephan: rc = lseek( f->fileno, WHIO_OFF_TO_STD_OFF_T(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; 45f8d4be63 2012-02-27 stephan: if( 0 == ftruncate( f->fileno, WHIO_OFF_TO_STD_OFF_T(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: 45f8d4be63 2012-02-27 stephan: whio_iomode_mask 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 fc60825290 2011-04-18 stephan: { fc60825290 2011-04-18 stephan: rc = whio_rc.LockingError; fc60825290 2011-04-18 stephan: } fc60825290 2011-04-18 stephan: } fc60825290 2011-04-18 stephan: else if( wli fc60825290 2011-04-18 stephan: && (whio_lock_CMD_TEST == wli->command) fc60825290 2011-04-18 stephan: && (F_UNLCK == fl->l_type) ) fc60825290 2011-04-18 stephan: { fc60825290 2011-04-18 stephan: wli->command = whio_lock_CMD_TEST_PASSED; fc60825290 2011-04-18 stephan: } fc60825290 2011-04-18 stephan: } while(0); fc60825290 2011-04-18 stephan: return rc; fc60825290 2011-04-18 stephan: #endif /* WHIO_CONFIG_USE_FCNTL */ fc60825290 2011-04-18 stephan: } fc60825290 2011-04-18 stephan: fc60825290 2011-04-18 stephan: static int whio_dev_fileno_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_fileno_DECL(whio_rc.ArgError); fc60825290 2011-04-18 stephan: /** fc60825290 2011-04-18 stephan: The