using System; using System.Diagnostics; using System.Text; namespace Community.CsharpSqlite { using etByte = System.Boolean; using i64 = System.Int64; using LONGDOUBLE_TYPE = System.Double; using u64 = System.UInt64; using va_list = System.Object; public partial class Sqlite3 { /* ** The "printf" code that follows dates from the 1980's. It is in ** the public domain. The original comments are included here for ** completeness. They are very out-of-date but might be useful as ** an historical reference. Most of the "enhancements" have been backed ** out so that the functionality is now the same as standard printf(). ** ************************************************************************** ** ** The following modules is an enhanced replacement for the "printf" subroutines ** found in the standard C library. The following enhancements are ** supported: ** ** + Additional functions. The standard set of "printf" functions ** includes printf, fprintf, sprintf, vprintf, vfprintf, and ** vsprintf. This module adds the following: ** ** * snprintf -- Works like sprintf, but has an extra argument ** which is the size of the buffer written to. ** ** * mprintf -- Similar to sprintf. Writes output to memory ** obtained from malloc. ** ** * xprintf -- Calls a function to dispose of output. ** ** * nprintf -- No output, but returns the number of characters ** that would have been output by printf. ** ** * A v- version (ex: vsnprintf) of every function is also ** supplied. ** ** + A few extensions to the formatting notation are supported: ** ** * The "=" flag (similar to "-") causes the output to be ** be centered in the appropriately sized field. ** ** * The %b field outputs an integer in binary notation. ** ** * The %c field now accepts a precision. The character output ** is repeated by the number of times the precision specifies. ** ** * The %' field works like %c, but takes as its character the ** next character of the format string, instead of the next ** argument. For example, printf("%.78'-") prints 78 minus ** signs, the same as printf("%.78c",'-'). ** ** + When compiled using GCC on a SPARC, this version of printf is ** faster than the library printf for SUN OS 4.1. ** ** + All functions are fully reentrant. ** ************************************************************************* ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart ** C#-SQLite is an independent reimplementation of the SQLite software library ** ** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e ** ************************************************************************* */ //#include "sqliteInt.h" /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ //#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ //#define etFLOAT 2 /* Floating point. %f */ //#define etEXP 3 /* Exponentional notation. %e and %E */ //#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */ //#define etSIZE 5 /* Return number of characters processed so far. %n */ //#define etSTRING 6 /* Strings. %s */ //#define etDYNSTRING 7 /* Dynamically allocated strings. %z */ //#define etPERCENT 8 /* Percent symbol. %% */ //#define etCHARX 9 /* Characters. %c */ ///* The rest are extensions, not normally found in printf() */ //#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */ //#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '', // NULL pointers replaced by SQL NULL. %Q */ //#define etTOKEN 12 /* a pointer to a Token structure */ //#define etSRCLIST 13 /* a pointer to a SrcList */ //#define etPOINTER 14 /* The %p conversion */ //#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */ //#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ //#define etINVALID 0 /* Any unrecognized conversion type */ private const int etRADIX = 1; /* Integer types. %d, %x, %o, and so forth */ private const int etFLOAT = 2; /* Floating point. %f */ private const int etEXP = 3; /* Exponentional notation. %e and %E */ private const int etGENERIC = 4; /* Floating or exponential, depending on exponent. %g */ private const int etSIZE = 5; /* Return number of characters processed so far. %n */ private const int etSTRING = 6; /* Strings. %s */ private const int etDYNSTRING = 7; /* Dynamically allocated strings. %z */ private const int etPERCENT = 8; /* Percent symbol. %% */ private const int etCHARX = 9; /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ private const int etSQLESCAPE = 10; /* Strings with '\'' doubled. %q */ private const int etSQLESCAPE2 = 11; /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ private const int etTOKEN = 12; /* a pointer to a Token structure */ private const int etSRCLIST = 13; /* a pointer to a SrcList */ private const int etPOINTER = 14; /* The %p conversion */ private const int etSQLESCAPE3 = 15; /* %w . Strings with '\"' doubled */ private const int etORDINAL = 16; /* %r . 1st, 2nd, 3rd, 4th, etc. English only */ private const int etINVALID = 0; /* Any unrecognized conversion type */ /* ** An "etByte" is an 8-bit unsigned value. */ //typedef unsigned char etByte; /* ** Each builtin conversion character (ex: the 'd' in "%d") is described ** by an instance of the following structure */ public class et_info { /* Information about each format field */ public char fmttype; /* The format field code letter */ public byte _base; /* The _base for radix conversion */ public byte flags; /* One or more of FLAG_ constants below */ public byte type; /* Conversion paradigm */ public byte charset; /* Offset into aDigits[] of the digits string */ public byte prefix; /* Offset into aPrefix[] of the prefix string */ /* * Constructor */ public et_info(char fmttype, byte _base, byte flags, byte type, byte charset, byte prefix ) { this.fmttype = fmttype; this._base = _base; this.flags = flags; this.type = type; this.charset = charset; this.prefix = prefix; } } /* ** Allowed values for et_info.flags */ private const byte FLAG_SIGNED = 1; /* True if the value to convert is signed */ private const byte FLAG_INTERN = 2; /* True if for internal use only */ private const byte FLAG_STRING = 4; /* Allow infinity precision */ /* ** The following table is searched linearly, so it is good to put the ** most frequently used conversion types first. */ private static string aDigits = "0123456789ABCDEF0123456789abcdef"; private static string aPrefix = "-x0\000X0"; private static et_info[] fmtinfo = new et_info[] { new et_info( 'd', 10, 1, etRADIX, 0, 0 ), new et_info( 's', 0, 4, etSTRING, 0, 0 ), new et_info( 'g', 0, 1, etGENERIC, 30, 0 ), new et_info( 'z', 0, 4, etDYNSTRING, 0, 0 ), new et_info( 'q', 0, 4, etSQLESCAPE, 0, 0 ), new et_info( 'Q', 0, 4, etSQLESCAPE2, 0, 0 ), new et_info( 'w', 0, 4, etSQLESCAPE3, 0, 0 ), new et_info( 'c', 0, 0, etCHARX, 0, 0 ), new et_info( 'o', 8, 0, etRADIX, 0, 2 ), new et_info( 'u', 10, 0, etRADIX, 0, 0 ), new et_info( 'x', 16, 0, etRADIX, 16, 1 ), new et_info( 'X', 16, 0, etRADIX, 0, 4 ), #if !SQLITE_OMIT_FLOATING_POINT new et_info( 'f', 0, 1, etFLOAT, 0, 0 ), new et_info( 'e', 0, 1, etEXP, 30, 0 ), new et_info( 'E', 0, 1, etEXP, 14, 0 ), new et_info( 'G', 0, 1, etGENERIC, 14, 0 ), #endif new et_info( 'i', 10, 1, etRADIX, 0, 0 ), new et_info( 'n', 0, 0, etSIZE, 0, 0 ), new et_info( '%', 0, 0, etPERCENT, 0, 0 ), new et_info( 'p', 16, 0, etPOINTER, 0, 1 ), /* All the rest have the FLAG_INTERN bit set and are thus for internal ** use only */ new et_info( 'T', 0, 2, etTOKEN, 0, 0 ), new et_info( 'S', 0, 2, etSRCLIST, 0, 0 ), new et_info( 'r', 10, 3, etORDINAL, 0, 0 ), }; /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. */ #if !SQLITE_OMIT_FLOATING_POINT /* ** "*val" is a double such that 0.1 <= *val < 10.0 ** Return the ascii code for the leading digit of *val, then ** multiply "*val" by 10.0 to renormalize. ** ** Example: ** input: *val = 3.14159 ** output: *val = 1.4159 function return = '3' ** ** The counter *cnt is incremented each time. After counter exceeds ** 16 (the number of significant digits in a 64-bit float) '0' is ** always returned. */ private static char et_getdigit(ref LONGDOUBLE_TYPE val, ref int cnt) { int digit; LONGDOUBLE_TYPE d; if (cnt++ >= 16) return '\0'; digit = (int)val; d = digit; //digit += '0'; val = (val - d) * 10.0; return (char)digit; } #endif // * SQLITE_OMIT_FLOATING_POINT */ /* ** Append N space characters to the given string buffer. */ private static void appendSpace(StrAccum pAccum, int N) { //static const char zSpaces[] = " "; //while( N>=zSpaces.Length-1 ){ // sqlite3StrAccumAppend(pAccum, zSpaces, zSpaces.Length-1); // N -= zSpaces.Length-1; //} //if( N>0 ){ // sqlite3StrAccumAppend(pAccum, zSpaces, N); //} pAccum.zText.AppendFormat("{0," + N + "}", ""); } /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be less than 350. */ #if !SQLITE_PRINT_BUF_SIZE # if (SQLITE_SMALL_STACK) const int SQLITE_PRINT_BUF_SIZE = 50; # else private const int SQLITE_PRINT_BUF_SIZE = 350; #endif #endif private const int etBUFSIZE = SQLITE_PRINT_BUF_SIZE; /* Size of the output buffer */ /* ** The root program. All variations call this core. ** ** INPUTS: ** func This is a pointer to a function taking three arguments ** 1. A pointer to anything. Same as the "arg" parameter. ** 2. A pointer to the list of characters to be output ** (Note, this list is NOT null terminated.) ** 3. An integer number of characters to be output. ** (Note: This number might be zero.) ** ** arg This is the pointer to anything which will be passed as the ** first argument to "func". Use it for whatever you like. ** ** fmt This is the format string, as in the usual print. ** ** ap This is a pointer to a list of arguments. Same as in ** vfprint. ** ** OUTPUTS: ** The return value is the total number of characters sent to ** the function "func". Returns -1 on a error. ** ** Note that the order in which automatic variables are declared below ** seems to make a big difference in determining how fast this beast ** will run. */ private static char[] buf = new char[etBUFSIZE]; /* Conversion buffer */ private static void sqlite3VXPrintf( StrAccum pAccum, /* Accumulate results here */ int useExtended, /* Allow extended %-conversions */ string fmt, /* Format string */ va_list[] ap /* arguments */ ) { int c; /* Next character in the format string */ int bufpt; /* Pointer to the conversion buffer */ int precision; /* Precision of the current field */ int length; /* Length of the field */ int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ etByte flag_plussign; /* True if "+" flag is present */ etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ i64 longvalue; LONGDOUBLE_TYPE realvalue; /* Value for real types */ et_info infop; /* Pointer to the appropriate info structure */ char[] buf = new char[etBUFSIZE]; /* Conversion buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ byte xtype = 0; /* Conversion paradigm */ // Not used in C# -- string zExtra; /* Extra memory used for etTCLESCAPE conversions */ #if !SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ int nsd; /* Number of significant digits returned */ #endif length = 0; bufpt = 0; int _fmt = 0; // Work around string pointer fmt += '\0'; for (; _fmt <= fmt.Length && (c = fmt[_fmt]) != 0; ++_fmt) { if (c != '%') { int amt; bufpt = _fmt; amt = 1; while (_fmt < fmt.Length && (c = (fmt[++_fmt])) != '%' && c != 0) amt++; sqlite3StrAccumAppend(pAccum, fmt.Substring(bufpt, amt), amt); if (c == 0) break; } if (_fmt < fmt.Length && (c = (fmt[++_fmt])) == 0) { sqlite3StrAccumAppend(pAccum, "%", 1); break; } /* Find out what flags are present */ flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_altform2 = flag_zeropad = false; done = false; do { switch (c) { case '-': flag_leftjustify = true; break; case '+': flag_plussign = true; break; case ' ': flag_blanksign = true; break; case '#': flag_alternateform = true; break; case '!': flag_altform2 = true; break; case '0': flag_zeropad = true; break; default: done = true; break; } } while (!done && _fmt < fmt.Length - 1 && (c = (fmt[++_fmt])) != 0); /* Get the field width */ width = 0; if (c == '*') { width = va_arg(ap, (Int32)0); if (width < 0) { flag_leftjustify = true; width = -width; } c = fmt[++_fmt]; } else { while (c >= '0' && c <= '9') { width = width * 10 + c - '0'; c = fmt[++_fmt]; } } if (width > etBUFSIZE - 10) { width = etBUFSIZE - 12; } /* Get the precision */ if (c == '.') { precision = 0; c = fmt[++_fmt]; if (c == '*') { precision = va_arg(ap, (Int32)0); if (precision < 0) precision = -precision; c = fmt[++_fmt]; } else { while (c >= '0' && c <= '9') { precision = precision * 10 + c - '0'; c = fmt[++_fmt]; } } } else { precision = -1; } /* Get the conversion type modifier */ if (c == 'l') { flag_long = true; c = fmt[++_fmt]; if (c == 'l') { flag_longlong = true; c = fmt[++_fmt]; } else { flag_longlong = false; } } else { flag_long = flag_longlong = false; } /* Fetch the info entry for the field */ infop = fmtinfo[0]; xtype = etINVALID; for (idx = 0; idx < ArraySize(fmtinfo); idx++) { if (c == fmtinfo[idx].fmttype) { infop = fmtinfo[idx]; if (useExtended != 0 || (infop.flags & FLAG_INTERN) == 0) { xtype = infop.type; } else { return; } break; } } //zExtra = null; /* Limit the precision to prevent overflowing buf[] during conversion */ if (precision > etBUFSIZE - 40 && (infop.flags & FLAG_STRING) == 0) { precision = etBUFSIZE - 40; } /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. ** flag_plussign TRUE if a '+' is present. ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. ** flag_long TRUE if the letter 'l' (ell) prefixed ** the conversion character. ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed ** the conversion character. ** flag_blanksign TRUE if a ' ' is present. ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default ** is -1. ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ switch (xtype) { case etPOINTER: flag_longlong = true;// char*.Length == sizeof(i64); flag_long = false;// char*.Length == sizeof(long); /* Fall through into the next case */ goto case etRADIX; case etORDINAL: case etRADIX: if ((infop.flags & FLAG_SIGNED) != 0) { i64 v; if (flag_longlong) { v = (Int64)va_arg(ap, (Int64)0); } else if (flag_long) { v = (Int64)va_arg(ap, (Int64)0); } else { v = (Int32)va_arg(ap, (Int32)0); } if (v < 0) { if (v == SMALLEST_INT64) { longvalue = ((long)((u64)1) << 63); } else { longvalue = -v; } prefix = '-'; } else { longvalue = v; if (flag_plussign) prefix = '+'; else if (flag_blanksign) prefix = ' '; else prefix = '\0'; } } else { if (flag_longlong) { longvalue = va_arg(ap, (Int64)0); } else if (flag_long) { longvalue = va_arg(ap, (Int64)0); } else { longvalue = va_arg(ap, (Int64)0); } prefix = '\0'; } if (longvalue == 0) flag_alternateform = false; if (flag_zeropad && precision < width - ((prefix != '\0') ? 1 : 0)) { precision = width - ((prefix != '\0') ? 1 : 0); } bufpt = buf.Length;//[etBUFSIZE-1]; char[] _bufOrd = null; if (xtype == etORDINAL) { char[] zOrd = "thstndrd".ToCharArray(); int x = (int)(longvalue % 10); if (x >= 4 || (longvalue / 10) % 10 == 1) { x = 0; } _bufOrd = new char[2]; _bufOrd[0] = zOrd[x * 2]; _bufOrd[1] = zOrd[x * 2 + 1]; //bufpt -= 2; } { char[] _buf; switch (infop._base) { case 16: _buf = longvalue.ToString("x").ToCharArray(); break; case 8: _buf = Convert.ToString((long)longvalue, 8).ToCharArray(); break; default: { if (flag_zeropad) _buf = longvalue.ToString(new string('0', width - ((prefix != '\0') ? 1 : 0))).ToCharArray(); else _buf = longvalue.ToString().ToCharArray(); } break; } bufpt = buf.Length - _buf.Length - (_bufOrd == null ? 0 : 2); Array.Copy(_buf, 0, buf, bufpt, _buf.Length); if (_bufOrd != null) { buf[buf.Length - 1] = _bufOrd[1]; buf[buf.Length - 2] = _bufOrd[0]; } //char* cset; /* Use registers for speed */ //int _base; //cset = aDigits[infop.charset]; //_base = infop._base; //do //{ /* Convert to ascii */ // *(--bufpt) = cset[longvalue % (ulong)_base]; // longvalue = longvalue / (ulong)_base; //} while (longvalue > 0); } length = buf.Length - bufpt;//length = (int)(&buf[etBUFSIZE-1]-bufpt); for (idx = precision - length; idx > 0; idx--) { buf[(--bufpt)] = '0'; /* Zero pad */ } if (prefix != '\0') buf[--bufpt] = prefix; /* Add sign */ if (flag_alternateform && infop.prefix != 0) { /* Add "0" or "0x" */ int pre; char x; pre = infop.prefix; for (; (x = aPrefix[pre]) != 0; pre++) buf[--bufpt] = x; } length = buf.Length - bufpt;//length = (int)(&buf[etBUFSIZE-1]-bufpt); break; case etFLOAT: case etEXP: case etGENERIC: realvalue = va_arg(ap, (Double)0); #if SQLITE_OMIT_FLOATING_POINT length = 0; #else if (precision < 0) precision = 6; /* Set default precision */ if (precision > etBUFSIZE / 2 - 10) precision = etBUFSIZE / 2 - 10; if (realvalue < 0.0) { realvalue = -realvalue; prefix = '-'; } else { if (flag_plussign) prefix = '+'; else if (flag_blanksign) prefix = ' '; else prefix = '\0'; } if (xtype == etGENERIC && precision > 0) precision--; #if FALSE /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); #else /* It makes more sense to use 0.5 */ for (idx = precision, rounder = 0.5; idx > 0; idx--, rounder *= 0.1) { } #endif if (xtype == etFLOAT) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; double d = 0; #if WINDOWS_MOBILE //alxwest: Tryparse doesn't exist on Windows Moble and what will Tryparsing a double do? if ( Double.IsNaN( realvalue )) #else if (Double.IsNaN(realvalue) || !(Double.TryParse(Convert.ToString(realvalue), out d)))//if( sqlite3IsNaN((double)realvalue) ) #endif { buf[0] = 'N'; buf[1] = 'a'; buf[2] = 'N';// "NaN" length = 3; break; } if (realvalue > 0.0) { while (realvalue >= 1e32 && exp <= 350) { realvalue *= 1e-32; exp += 32; } while (realvalue >= 1e8 && exp <= 350) { realvalue *= 1e-8; exp += 8; } while (realvalue >= 10.0 && exp <= 350) { realvalue *= 0.1; exp++; } while (realvalue < 1e-8) { realvalue *= 1e8; exp -= 8; } while (realvalue < 1.0) { realvalue *= 10.0; exp--; } if (exp > 350) { if (prefix == '-') { buf[0] = '-'; buf[1] = 'I'; buf[2] = 'n'; buf[3] = 'f';// "-Inf" bufpt = 4; } else if (prefix == '+') { buf[0] = '+'; buf[1] = 'I'; buf[2] = 'n'; buf[3] = 'f';// "+Inf" bufpt = 4; } else { buf[0] = 'I'; buf[1] = 'n'; buf[2] = 'f';// "Inf" bufpt = 3; } length = sqlite3Strlen30(bufpt);// sqlite3Strlen30(bufpt); bufpt = 0; break; } } bufpt = 0; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ flag_exp = xtype == etEXP; if (xtype != etFLOAT) { realvalue += rounder; if (realvalue >= 10.0) { realvalue *= 0.1; exp++; } } if (xtype == etGENERIC) { flag_rtz = !flag_alternateform; if (exp < -4 || exp > precision) { xtype = etEXP; } else { precision = precision - exp; xtype = etFLOAT; } } else { flag_rtz = false; } if (xtype == etEXP) { e2 = 0; } else { e2 = exp; } nsd = 0; flag_dp = (precision > 0 ? true : false) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if (prefix != '\0') { buf[bufpt++] = prefix; } /* Digits prior to the decimal point */ if (e2 < 0) { buf[bufpt++] = '0'; } else { for (; e2 >= 0; e2--) { buf[bufpt++] = (char)(et_getdigit(ref realvalue, ref nsd) + '0'); // *(bufpt++) = et_getdigit(ref realvalue, ref nsd); } } /* The decimal point */ if (flag_dp) { buf[bufpt++] = '.'; } /* "0" digits after the decimal point but before the first ** significant digit of the number */ for (e2++; e2 < 0; precision--, e2++) { Debug.Assert(precision > 0); buf[bufpt++] = '0'; } /* Significant digits after the decimal point */ while ((precision--) > 0) { buf[bufpt++] = (char)(et_getdigit(ref realvalue, ref nsd) + '0'); // *(bufpt++) = et_getdigit(&realvalue, nsd); } /* Remove trailing zeros and the "." if no digits follow the "." */ if (flag_rtz && flag_dp) { while (buf[bufpt - 1] == '0') buf[--bufpt] = '\0'; Debug.Assert(bufpt > 0); if (buf[bufpt - 1] == '.') { if (flag_altform2) { buf[(bufpt++)] = '0'; } else { buf[(--bufpt)] = '0'; } } } /* Add the "eNNN" suffix */ if (flag_exp || xtype == etEXP) { buf[bufpt++] = aDigits[infop.charset]; if (exp < 0) { buf[bufpt++] = '-'; exp = -exp; } else { buf[bufpt++] = '+'; } if (exp >= 100) { buf[bufpt++] = (char)(exp / 100 + '0'); /* 100's digit */ exp %= 100; } buf[bufpt++] = (char)(exp / 10 + '0'); /* 10's digit */ buf[bufpt++] = (char)(exp % 10 + '0'); /* 1's digit */ } //bufpt = 0; /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ length = bufpt;//length = (int)(bufpt-buf); bufpt = 0; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ if (flag_zeropad && !flag_leftjustify && length < width) { int i; int nPad = width - length; for (i = width; i >= nPad; i--) { buf[bufpt + i] = buf[bufpt + i - nPad]; } i = (prefix != '\0' ? 1 : 0); while (nPad-- != 0) buf[(bufpt++) + i] = '0'; length = width; bufpt = 0; } #endif //* !defined(SQLITE_OMIT_FLOATING_POINT) */ break; case etSIZE: ap[0] = pAccum.nChar; // *(va_arg(ap,int)) = pAccum.nChar; length = width = 0; break; case etPERCENT: buf[0] = '%'; bufpt = 0; length = 1; break; case etCHARX: c = va_arg(ap, (Char)0); buf[0] = (char)c; if (precision >= 0) { for (idx = 1; idx < precision; idx++) buf[idx] = (char)c; length = precision; } else { length = 1; } bufpt = 0; break; case etSTRING: case etDYNSTRING: bufpt = 0;// string bufStr = (string)va_arg(ap, "string"); if (bufStr.Length > buf.Length) buf = new char[bufStr.Length]; bufStr.ToCharArray().CopyTo(buf, 0); bufpt = bufStr.Length; if (bufpt == 0) { buf[0] = '\0'; } else if (xtype == etDYNSTRING) { // zExtra = bufpt; } if (precision >= 0) { for (length = 0; length < precision && length < bufStr.Length && buf[length] != 0; length++) { } //length += precision; } else { length = sqlite3Strlen30(bufpt); } bufpt = 0; break; case etSQLESCAPE: case etSQLESCAPE2: case etSQLESCAPE3: { int i; int j; int k; int n; bool isnull; bool needQuote; char ch; char q = ((xtype == etSQLESCAPE3) ? '"' : '\''); /* Quote character */ string escarg = (string)va_arg(ap, "char*") + '\0'; isnull = (escarg == "" || escarg == "NULL\0"); if (isnull) escarg = (xtype == etSQLESCAPE2) ? "NULL\0" : "(NULL)\0"; k = precision; for (i = n = 0; k != 0 && (ch = escarg[i]) != 0; i++, k--) { if (ch == q) n++; } needQuote = !isnull && (xtype == etSQLESCAPE2); n += i + 1 + (needQuote ? 2 : 0); if (n > etBUFSIZE) { buf = new char[n];//bufpt = zExtra = sqlite3Malloc(n); //if ( bufpt == 0 ) //{ // pAccum->mallocFailed = 1; // return; //} bufpt = 0; //Start of Buffer } else { //bufpt = buf; bufpt = 0; //Start of Buffer } j = 0; if (needQuote) buf[bufpt + j++] = q; k = i; for (i = 0; i < k; i++) { buf[bufpt + j++] = ch = escarg[i]; if (ch == q) buf[bufpt + j++] = ch; } if (needQuote) buf[bufpt + j++] = q; buf[bufpt + j] = '\0'; length = j; /* The precision in %q and %Q means how many input characters to ** consume, not the length of the output... ** if( precision>=0 && precision= 0 && k < pSrc.nSrc); if (pItem.zDatabase != null) { sqlite3StrAccumAppend(pAccum, pItem.zDatabase, -1); sqlite3StrAccumAppend(pAccum, ".", 1); } sqlite3StrAccumAppend(pAccum, pItem.zName, -1); length = width = 0; break; } default: { Debug.Assert(xtype == etINVALID); return; } }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. */ if (!flag_leftjustify) { int nspace; nspace = width - length;// -2; if (nspace > 0) { appendSpace(pAccum, nspace); } } if (length > 0) { sqlite3StrAccumAppend(pAccum, new string(buf, bufpt, length), length); } if (flag_leftjustify) { int nspace; nspace = width - length; if (nspace > 0) { appendSpace(pAccum, nspace); } } //if( zExtra ){ // sqlite3DbFree(db,ref zExtra); //} }/* End for loop over the format string */ } /* End of function */ /* ** Append N bytes of text from z to the StrAccum object. */ private static void sqlite3StrAccumAppend(StrAccum p, string z, int N) { Debug.Assert(z != null || N == 0); if (p.tooBig)//|| p.mallocFailed != 0 ) { testcase(p.tooBig); //testcase( p.mallocFailed ); return; } if (N < 0) { N = sqlite3Strlen30(z); } if (N == 0 || NEVER(z == null)) { return; } //if( p->nChar+N >= p->nAlloc ){ // string zNew; // if( null==p->useMalloc ){ // p->tooBig = 1; // N = p->nAlloc - p->nChar - 1; // if( N<=0 ){ // return; // } // }else{ // string zOld = (p->zText==p->zBase ? 0 : p->zText); // i64 szNew = p->nChar; // szNew += N + 1; // if( szNew > p->mxAlloc ){ // sqlite3StrAccumReset(p); // p->tooBig = 1; // return; // }else{ // p->nAlloc = (int)szNew; // } // if( p->useMalloc==1 ){ // zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); // }else{ // zNew = sqlite3_realloc(zOld, p->nAlloc); // } // if( zNew ){ // if( zOld==0 ) memcpy(zNew, p->zText, p->nChar); // p->zText = zNew; // }else{ // p->mallocFailed = 1; // sqlite3StrAccumReset(p); // return; // } // } //} //memcpy(&p->zText[p->nChar], z, N); p.zText.Append(z.Substring(0, N <= z.Length ? N : z.Length)); //p.nChar += N; } /* ** Finish off a string by making sure it is zero-terminated. ** Return a pointer to the resulting string. Return a NULL ** pointer if any kind of error was encountered. */ private static string sqlite3StrAccumFinish(StrAccum p) { //if ( p->zText ) //{ // p->zText[p->nChar] = 0; // if ( p->useMalloc && p->zText == p->zBase ) // { // if ( p->useMalloc == 1 ) // { // p->zText = sqlite3DbMallocRaw( p->db, p->nChar + 1 ); // } // else // { // p->zText = sqlite3_malloc( p->nChar + 1 ); // } // if ( p->zText ) // { // memcpy( p->zText, p->zBase, p->nChar + 1 ); // } // else // { // p->mallocFailed = 1; // } // } //} return p.zText.ToString(); } /* ** Reset an StrAccum string. Reclaim all malloced memory. */ private static void sqlite3StrAccumReset(StrAccum p) { //if ( p.zText.ToString() != p.zBase.ToString() ) //{ // if ( p.useMalloc == 1 ) // { // sqlite3DbFree( p.db, ref p.zText ); // } // else // { // sqlite3_free( ref p.zText ); // } //} p.zText.Length = 0; } /* ** Initialize a string accumulator */ private static void sqlite3StrAccumInit(StrAccum p, StringBuilder zBase, int n, int mx) { //p.zBase.Length = 0; //if ( p.zBase.Capacity < n ) // p.zBase.Capacity = n; p.zText.Length = 0; if (p.zText.Capacity < n) p.zText.Capacity = n; p.db = null; //p.nChar = 0; //p.nAlloc = n; p.mxAlloc = mx; //p.useMalloc = 1; //p.tooBig = 0; //p.mallocFailed = 0; } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ private static StrAccum acc = new StrAccum(SQLITE_PRINT_BUF_SIZE); private static string sqlite3VMPrintf(sqlite3 db, string zFormat, params va_list[] ap) { if (zFormat == null) return null; if (ap.Length == 0) return zFormat; //string z; Debug.Assert(db != null); sqlite3StrAccumInit(acc, null, SQLITE_PRINT_BUF_SIZE, db.aLimit[SQLITE_LIMIT_LENGTH]); acc.db = db; acc.zText.Length = 0; sqlite3VXPrintf(acc, 1, zFormat, ap); // if ( acc.mallocFailed != 0 ) // { ////// db.mallocFailed = 1; // } return sqlite3StrAccumFinish(acc); } /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. */ private static string sqlite3MPrintf(sqlite3 db, string zFormat, params va_list[] ap) { string z; //va_list ap; lock (lock_va_list) { va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ref ap); } return z; } /* ** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting ** the string and before returnning. This routine is intended to be used ** to modify an existing string. For example: ** ** x = sqlite3MPrintf(db, x, "prefix %s suffix", x); ** */ private static string sqlite3MAppendf(sqlite3 db, string zStr, string zFormat, params va_list[] ap) { string z; //va_list ap; lock (lock_va_list) { va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ref ap); sqlite3DbFree(db, ref zStr); } return z; } /* ** Print into memory obtained from sqlite3Malloc(). Omit the internal ** %-conversion extensions. */ private static string sqlite3_vmprintf(string zFormat, params va_list[] ap) { //StrAccum acc = new StrAccum( SQLITE_PRINT_BUF_SIZE ); #if !SQLITE_OMIT_AUTOINIT if (sqlite3_initialize() != 0) return ""; #endif sqlite3StrAccumInit(acc, null, SQLITE_PRINT_BUF_SIZE, SQLITE_PRINT_BUF_SIZE);//zBase).Length; //acc.useMalloc = 2; sqlite3VXPrintf(acc, 0, zFormat, ap); return sqlite3StrAccumFinish(acc); } /* ** Print into memory obtained from sqlite3Malloc()(). Omit the internal ** %-conversion extensions. */ static public string sqlite3_mprintf(string zFormat, params va_list[] ap) { //, ...){ string z; #if !SQLITE_OMIT_AUTOINIT if (sqlite3_initialize() != 0) return ""; #endif //va_list ap; lock (lock_va_list) { va_start(ap, zFormat); z = sqlite3_vmprintf(zFormat, ap); va_end(ref ap); } return z; } /* ** sqlite3_snprintf() works like snprintf() except that it ignores the ** current locale settings. This is important for SQLite because we ** are not able to use a "," as the decimal point in place of "." as ** specified by some locales. ** ** Oops: The first two arguments of sqlite3_snprintf() are backwards ** from the snprintf() standard. Unfortunately, it is too late to change ** this without breaking compatibility, so we just have to live with the ** mistake. ** ** sqlite3_vsnprintf() is the varargs version. */ static public void sqlite3_vsnprintf(int n, StringBuilder zBuf, string zFormat, params va_list[] ap) { //StrAccum acc = new StrAccum( SQLITE_PRINT_BUF_SIZE ); if (n <= 0) return; sqlite3StrAccumInit(acc, null, n, 0); //acc.useMalloc = 0; sqlite3VXPrintf(acc, 0, zFormat, ap); zBuf.Length = 0; if (n > 1 && n <= acc.zText.Length) acc.zText.Length = n - 1; zBuf.Append(sqlite3StrAccumFinish(acc)); return; } static public void sqlite3_snprintf(int n, StringBuilder zBuf, string zFormat, params va_list[] ap) { //string z; //va_list ap; lock (lock_va_list) {//StrAccum acc = new StrAccum( SQLITE_PRINT_BUF_SIZE ); zBuf.EnsureCapacity(SQLITE_PRINT_BUF_SIZE); va_start(ap, zFormat); sqlite3_vsnprintf(n, zBuf, zFormat, ap); va_end(ref ap); } return; } //static public string sqlite3_snprintf( int n, ref string zBuf, string zFormat, params va_list[] ap ) //{ // string z; // //va_list ap; // StrAccum acc = new StrAccum( SQLITE_PRINT_BUF_SIZE ); // if ( n <= 0 ) // { // return zBuf; // } // sqlite3StrAccumInit( acc, null, n, 0 ); // //acc.useMalloc = 0; // va_start( ap, zFormat ); // sqlite3VXPrintf( acc, 0, zFormat, ap ); // va_end( ap ); // z = sqlite3StrAccumFinish( acc ); // return ( zBuf = z ); //} /* ** This is the routine that actually formats the sqlite3_log() message. ** We house it in a separate routine from sqlite3_log() to avoid using ** stack space on small-stack systems when logging is disabled. ** ** sqlite3_log() must render into a static buffer. It cannot dynamically ** allocate memory because it might be called while the memory allocator ** mutex is held. */ private static void renderLogMsg(int iErrCode, string zFormat, params object[] ap) { //StrAccum acc; /* String accumulator */ //char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ sqlite3StrAccumInit(acc, null, SQLITE_PRINT_BUF_SIZE * 3, 0); //acc.useMalloc = 0; sqlite3VXPrintf(acc, 0, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(acc)); } /* ** Format and write a message to the log if logging is enabled. */ private static void sqlite3_log(int iErrCode, string zFormat, params va_list[] ap) { if (sqlite3GlobalConfig != null && sqlite3GlobalConfig.xLog != null) { //va_list ap; /* Vararg list */ lock (lock_va_list) { va_start(ap, zFormat); renderLogMsg(iErrCode, zFormat, ap); va_end(ref ap); } } } #if SQLITE_DEBUG || DEBUG || TRACE /* ** A version of printf() that understands %lld. Used for debugging. ** The printf() built into some versions of windows does not understand %lld ** and segfaults if you give it a long long int. */ private static void sqlite3DebugPrintf(string zFormat, params va_list[] ap) { //va_list ap; lock (lock_va_list) { //StrAccum acc = new StrAccum( SQLITE_PRINT_BUF_SIZE ); sqlite3StrAccumInit(acc, null, SQLITE_PRINT_BUF_SIZE, 0); //acc.useMalloc = 0; va_start(ap, zFormat); sqlite3VXPrintf(acc, 0, zFormat, ap); va_end(ref ap); } #if !SQLITE_WINRT Console.Write(sqlite3StrAccumFinish(acc)); #endif //fflush(stdout); } #endif #if !SQLITE_OMIT_TRACE /* ** variable-argument wrapper around sqlite3VXPrintf(). */ private static void sqlite3XPrintf(StrAccum p, string zFormat, params object[] ap) { //va_list ap; lock (lock_va_list) { va_start(ap, zFormat); sqlite3VXPrintf(p, 1, zFormat, ap); va_end(ref ap); } } #endif } }