1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-05 04:30:38 +03:00

Cleanup the printf code to make it smaller and more modular.

Fix a memory leak in the new OP_ContextPush opcode. (CVS 1258)

FossilOrigin-Name: 2756f7af3382fa9d186ab99cf76f469fb891a3c3
This commit is contained in:
drh
2004-02-21 19:02:30 +00:00
parent 8722318f3c
commit 5f968436e6
7 changed files with 140 additions and 240 deletions

View File

@@ -52,13 +52,6 @@
*/
#include "sqliteInt.h"
/*
** Undefine COMPATIBILITY to make some slight changes in the way things
** work. I think the changes are an improvement, but they are not
** backwards compatible.
*/
/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
@@ -78,6 +71,8 @@
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 14 /* a pointer to a Token structure */
#define etSRCLIST 15 /* a pointer to a SrcList */
/*
@@ -129,6 +124,8 @@ static et_info fmtinfo[] = {
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 10, 0, etRADIX, "0123456789", 0 },
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
};
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
@@ -192,10 +189,11 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** will run.
*/
static int vxprintf(
void (*func)(void*,char*,int),
void *arg,
const char *fmt,
va_list ap
void (*func)(void*,const char*,int), /* Consumer of text */
void *arg, /* First argument to the consumer */
int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
int c; /* Next character in the format string */
char *bufpt; /* Pointer to the conversion buffer */
@@ -284,10 +282,7 @@ static int vxprintf(
c = *++fmt;
if( c=='*' ){
precision = va_arg(ap,int);
#ifndef etCOMPATIBILITY
/* This is sensible, but SUN OS 4.1 doesn't do it. */
if( precision<0 ) precision = -precision;
#endif
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
@@ -313,7 +308,9 @@ static int vxprintf(
for(idx=0; idx<etNINFO; idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
xtype = infop->type;
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
}
break;
}
}
@@ -341,7 +338,7 @@ static int vxprintf(
case etRADIX:
if( flag_long ) longvalue = va_arg(ap,long);
else longvalue = va_arg(ap,int);
#ifdef etCOMPATIBILITY
#if 1
/* For the format %#x, the value zero is printed "0" not "0x0".
** I think this is stupid. */
if( longvalue==0 ) flag_alternateform = 0;
@@ -403,7 +400,7 @@ static int vxprintf(
}
if( infop->type==etGENERIC && precision>0 ) precision--;
rounder = 0.0;
#ifdef COMPATIBILITY
#if 0
/* 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
@@ -571,6 +568,25 @@ static int vxprintf(
if( precision>=0 && precision<length ) length = precision;
}
break;
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
(*func)(arg, pToken->z, pToken->n);
length = width = 0;
break;
}
case etSRCLIST: {
SrcList *pSrc = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
(*func)(arg, ".", 1);
}
(*func)(arg, pItem->zName, strlen(pItem->zName));
length = width = 0;
break;
}
case etERROR:
buf[0] = '%';
buf[1] = c;
@@ -615,11 +631,7 @@ static int vxprintf(
}
}
if( zExtra ){
if( xtype==etDYNSTRING ){
free(zExtra);
}else{
sqliteFree(zExtra);
}
sqliteFree(zExtra);
}
}/* End for loop over the format string */
return errorflag ? -1 : count;
@@ -633,7 +645,9 @@ struct sgMprintf {
char *zBase; /* A base allocation */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nTotal; /* Output size if unconstrained */
int nAlloc; /* Amount of space allocated in zText */
void *(*xRealloc)(void*,int); /* Function used to realloc memory */
};
/*
@@ -642,24 +656,25 @@ struct sgMprintf {
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg".
*/
static void mout(void *arg, char *zNewText, int nNewChar){
static void mout(void *arg, const char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
pM->nTotal += nNewChar;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = sqliteMalloc(pM->nAlloc);
if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
if( pM->xRealloc==0 ){
nNewChar = pM->nAlloc - pM->nChar - 1;
}else{
char *z = sqliteRealloc(pM->zText, pM->nAlloc);
if( z==0 ){
sqliteFree(pM->zText);
pM->nChar = 0;
pM->nAlloc = 0;
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = pM->xRealloc(0, pM->nAlloc);
if( pM->zText && pM->nChar ){
memcpy(pM->zText, pM->zBase, pM->nChar);
}
}else{
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
}
pM->zText = z;
}
}
if( pM->zText ){
if( pM->zText && nNewChar>0 ){
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
pM->zText[pM->nChar] = 0;
@@ -667,114 +682,104 @@ static void mout(void *arg, char *zNewText, int nNewChar){
}
/*
** sqlite_mprintf() works like printf(), but allocations memory to hold the
** resulting string and returns a pointer to the allocated memory. Use
** sqliteFree() to release the memory allocated.
** This routine is a wrapper around xprintf() that invokes mout() as
** the consumer.
*/
char *sqliteMPrintf(const char *zFormat, ...){
va_list ap;
struct sgMprintf sMprintf;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(mout,&sMprintf,zFormat,ap);
va_end(ap);
sMprintf.zText[sMprintf.nChar] = 0;
return sqliteRealloc(sMprintf.zText, sMprintf.nChar+1);
static char *base_vprintf(
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
int useInternal, /* Use internal %-conversions if true */
char *zInitBuf, /* Initially write here, before mallocing */
int nInitBuf, /* Size of zInitBuf[] */
const char *zFormat, /* format string */
va_list ap /* arguments */
){
struct sgMprintf sM;
sM.zBase = sM.zText = zInitBuf;
sM.nChar = sM.nTotal = 0;
sM.nAlloc = nInitBuf;
sM.xRealloc = xRealloc;
vxprintf(mout, &sM, useInternal, zFormat, ap);
if( xRealloc ){
if( sM.zText==sM.zBase ){
sM.zText = xRealloc(0, sM.nChar+1);
memcpy(sM.zText, sM.zBase, sM.nChar+1);
}else if( sM.nAlloc>sM.nChar+10 ){
sM.zText = xRealloc(sM.zText, sM.nChar+1);
}
}
return sM.zText;
}
/*
** sqlite_mprintf() works like printf(), but allocations memory to hold the
** resulting string and returns a pointer to the allocated memory. Use
** sqliteFree() to release the memory allocated.
** Realloc that is a real function, not a macro.
*/
static void *printf_realloc(void *old, int size){
return sqliteRealloc(old,size);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqliteVMPrintf(const char *zFormat, va_list ap){
char zBase[1000];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqliteMPrintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBase[1000];
va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
va_end(ap);
return z;
}
/*
** Print into memory obtained from malloc(). Do not use the internal
** %-conversion extensions. This routine is for use by external users.
*/
char *sqlite_mprintf(const char *zFormat, ...){
va_list ap;
struct sgMprintf sMprintf;
char *zNew;
char *z;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(mout,&sMprintf,zFormat,ap);
z = base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
sMprintf.zText[sMprintf.nChar] = 0;
zNew = malloc( sMprintf.nChar+1 );
if( zNew ) strcpy(zNew,sMprintf.zText);
if( sMprintf.zText!=sMprintf.zBase ){
sqliteFree(sMprintf.zText);
}
return zNew;
return z;
}
/* This is the varargs version of sqlite_mprintf.
*/
char *sqlite_vmprintf(const char *zFormat, va_list ap){
struct sgMprintf sMprintf;
char *zNew;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.zText = zBuf;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zBase = zBuf;
vxprintf(mout,&sMprintf,zFormat,ap);
sMprintf.zText[sMprintf.nChar] = 0;
zNew = malloc( sMprintf.nChar+1 );
if( zNew ) strcpy(zNew,sMprintf.zText);
if( sMprintf.zText!=sMprintf.zBase ){
sqliteFree(sMprintf.zText);
}
return zNew;
}
/*
** This function implements the callback from vxprintf.
**
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg". Unlike mout() above,
** this routine does not allocate new space when the buffer fills.
** It just truncates.
*/
static void sout(void *arg, char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
nNewChar = pM->nAlloc - pM->nChar - 1;
if( nNewChar<=0 ) return;
}
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
pM->zText[pM->nChar] = 0;
return base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
}
/*
** sqlite_sprintf() works like sprintf() except that it ignores the
** sqlite_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.
*/
int sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
struct sgMprintf sMprintf;
sMprintf.nChar = 0;
sMprintf.nAlloc = n;
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(sout,&sMprintf,zFormat,ap);
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
va_end(ap);
return sMprintf.nChar;
return z;
}
/*
** The following four routines implement the varargs versions of the
** sqlite_exec() and sqlite_get_table() interfaces. See the sqlite.h