From 6885390791d74b2915e10c7542607225f93c64af Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 May 2007 11:24:30 +0000 Subject: [PATCH] Change sqlite3_snprintf() so that it does not write a zero-terminator if the buffer size argument is less than 1. Ticket #2341. Added documentation about the sqlite3_snprintf() function. (CVS 3935) FossilOrigin-Name: f3ae4ac5fe0bfa2f91e76a6def86c444e51fe80b --- main.mk | 4 ---- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/printf.c | 4 ++++ src/test1.c | 30 +++++++++++++++++++++++++++++- test/printf.test | 11 ++++++++++- www/capi3ref.tcl | 29 ++++++++++++++++++++++++++++- 7 files changed, 83 insertions(+), 19 deletions(-) diff --git a/main.mk b/main.mk index af6a8fd7a1..2596722096 100644 --- a/main.mk +++ b/main.mk @@ -65,8 +65,6 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \ vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \ where.o utf.o legacy.o vtab.o -LIBOBJ += icu.o - # All of the source code files. # SRC = \ @@ -143,8 +141,6 @@ SRC += \ $(TOP)/ext/fts2/fts2_porter.c \ $(TOP)/ext/fts2/fts2_tokenizer.h \ $(TOP)/ext/fts2/fts2_tokenizer1.c -SRC += \ - $(TOP)/ext/icu/icu.c # Generated source code files # diff --git a/manifest b/manifest index 4fe782c25a..7bbff81533 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sexperimental\screate_collation_x()\sapi.\s(CVS\s3934) -D 2007-05-07T09:32:45 +C Change\ssqlite3_snprintf()\sso\sthat\sit\sdoes\snot\swrite\sa\szero-terminator\sif\nthe\sbuffer\ssize\sargument\sis\sless\sthan\s1.\s\sTicket\s#2341.\s\sAdded\sdocumentation\nabout\sthe\ssqlite3_snprintf()\sfunction.\s(CVS\s3935) +D 2007-05-07T11:24:30 F Makefile.in ea8888bdcf53313d26576fcabcb6d0a10ecd35cd F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -46,7 +46,7 @@ F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977 F ext/icu/icu.c a30999ba467749ed6232d02cc8c4b5a0e62cd727 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 -F main.mk 6298bd3fcbc590fe05354f7d962c57ac202d7bcd +F main.mk 09c19ae05ac9e5654d5fd866a980b21ad9df8f30 F mkdll.sh ed62756baf44babf562a7843588790c02fee2106 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -96,7 +96,7 @@ F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c F src/parse.y a5bdc301e970ceb3826b56a84898b8966d5353f8 F src/pragma.c 3f16c1274bc25afb630b61a3630ea19a2fd0b5dc F src/prepare.c 03277063bc4f5860efbf23548fa0123ac0f6eaec -F src/printf.c 0c6f40648770831341ac45ab32423a80b4c87f05 +F src/printf.c 67de0dcb40ef3297f4a047b434b81585c0f7062d F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88 F src/select.c a306d03fc7d8365055bef70c3563e8fca897460f F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 @@ -106,7 +106,7 @@ F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 F src/sqliteInt.h 5e1cf645ef1bf8b43c5d020adbeed43746df24ed F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b -F src/test1.c a91c84e903e3a59ad3bf6c10bd5b93e74d631ea2 +F src/test1.c 84e78efa05a6d36a1868912b84cc5009d990f49d F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 @@ -309,7 +309,7 @@ F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pageropt.test b4b38eb3cf76be2be444326856248898bb0e3fc9 F test/pagesize.test e0a8b3fe80f8b8e808d94a00734c7a18c76c407e F test/pragma.test fecb7085f58d9fb5172a5c0b63fd3b25c7bfb414 -F test/printf.test 483b9fe75ffae1fb27328bdce5560b452ba83577 +F test/printf.test 71047b5fe8e2adfbe514e0d56e10adf12d84deff F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x F test/ptrchng.test 1c712dd6516e1377471744fa765e41c79a357da6 F test/quick.test afa4339d08800d8aa3625df6cc2f059cc505f4c3 @@ -437,7 +437,7 @@ F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0 F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06 F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716 -F www/capi3ref.tcl 0d742d6bd59bc51bbb4be014e7ea47e97786d318 +F www/capi3ref.tcl be09756d8b9aebd2d7b597fb910eed66fb4480e6 F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58 F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084 @@ -481,7 +481,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 2d1348dda2cbdf958a15267432063f359550c303 -R cb3c4e9539473867932a2c5f74528890 -U danielk1977 -Z eaa2b3011ed3cbd2140fcff678e040f6 +P ff49d48f2f025898a0f4ace1fc227e1d367ea89f +R d693f630962da031deefd4769c7a8268 +U drh +Z ff527a494f455c458a9191e7c78f4220 diff --git a/manifest.uuid b/manifest.uuid index 53affad84b..ed94877353 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff49d48f2f025898a0f4ace1fc227e1d367ea89f \ No newline at end of file +f3ae4ac5fe0bfa2f91e76a6def86c444e51fe80b \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 17809b11eb..612cae6e52 100644 --- a/src/printf.c +++ b/src/printf.c @@ -837,6 +837,10 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ char *z; va_list ap; + if( n<=0 ){ + return zBuf; + } + zBuf[0] = 0; va_start(ap,zFormat); z = base_vprintf(0, 0, zBuf, n, zFormat, ap); va_end(ap); diff --git a/src/test1.c b/src/test1.c index 479390dead..69f5112d74 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.248 2007/05/07 09:32:45 danielk1977 Exp $ +** $Id: test1.c,v 1.249 2007/05/07 11:24:30 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -426,6 +426,33 @@ static int test_mprintf_n( return TCL_OK; } +/* +** Usage: sqlite3_snprintf_int SIZE FORMAT INT +** +** Test the of sqlite3_snprintf() routine. SIZE is the size of the +** output buffer in bytes. The maximum size is 100. FORMAT is the +** format string. INT is a single integer argument. The FORMAT +** string must require no more than this one integer argument. If +** You pass in a format string that requires more than one argument, +** bad things will happen. +*/ +static int test_snprintf_int( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + char zStr[100]; + int n = atoi(argv[1]); + if( n>sizeof(zStr) ) n = sizeof(zStr); + const char *zFormat = argv[2]; + int a1 = atoi(argv[3]); + strcpy(zStr, "abcdefghijklmnopqrstuvwxyz"); + sqlite3_snprintf(n, zStr, zFormat, a1); + Tcl_AppendResult(interp, zStr, 0); + return TCL_OK; +} + /* ** Usage: sqlite3_get_table_printf DB FORMAT STRING ** @@ -4609,6 +4636,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble}, { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, { "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n }, + { "sqlite3_snprintf_int", (Tcl_CmdProc*)test_snprintf_int }, { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, { "sqlite3_exec", (Tcl_CmdProc*)test_exec }, diff --git a/test/printf.test b/test/printf.test index 70283bc123..2c6671f29b 100644 --- a/test/printf.test +++ b/test/printf.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_*_printf() interface. # -# $Id: printf.test,v 1.22 2007/03/31 15:02:50 drh Exp $ +# $Id: printf.test,v 1.23 2007/05/07 11:24:31 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -268,5 +268,14 @@ do_test printf-14.3 { sqlite3_mprintf_str {abc-%T-123} 0 0 {not used} } {abc-} +do_test printf-15.1 { + sqlite3_snprintf_int 5 {12345} 0 +} {1234} +do_test printf-15.2 { + sqlite3_snprintf_int 5 {} 0 +} {} +do_test printf-15.3 { + sqlite3_snprintf_int 0 {} 0 +} {abcdefghijklmnopqrstuvwxyz} finish_test diff --git a/www/capi3ref.tcl b/www/capi3ref.tcl index aaa88ea1ed..07fca4c06a 100644 --- a/www/capi3ref.tcl +++ b/www/capi3ref.tcl @@ -1,4 +1,4 @@ -set rcsid {$Id: capi3ref.tcl,v 1.56 2007/04/27 17:16:22 drh Exp $} +set rcsid {$Id: capi3ref.tcl,v 1.57 2007/05/07 11:24:31 drh Exp $} source common.tcl header {C/C++ Interface For SQLite Version 3} puts { @@ -1134,6 +1134,33 @@ char *sqlite3_vmprintf(const char*, va_list); literal. } {} +api {} { +char *sqlite3_snprintf(int bufSize, char *buf, const char *zFormat, ...); +} { + This routine works like "sprintf()", writing a formatted string into + the buf[]. However, no more than bufSize characters will be written + into buf[]. This routine returns a pointer to buf[]. If bufSize is + greater than zero, then buf[] is guaranteed to be zero-terminated. + + This routine uses the same extended formatting options as + sqlite3_mprintf() and sqlite3_vmprintf(). + + Note these differences with the snprintf() function found in many + standard libraries: (1) sqlite3_snprintf() returns a pointer to the + buffer rather than the number of characters written. (It would, + arguably, be more useful to return the number of characters written, + but we discovered that after the interface had been published and + are unwilling to break backwards compatibility.) (2) The order + of the bufSize and buf parameter is reversed from snprintf(). + And (3) sqlite3_snprintf() always writes a zero-terminator if bufSize + is positive. + + Please do not use the return value of this routine. We may + decide to make the minor compatibility break and change this routine + to return the number of characters written rather than a pointer to + the buffer in a future minor version increment. +} + api {} { int sqlite3_open( const char *filename, /* Database filename (UTF-8) */