From: drh <> Date: Wed, 6 May 2026 20:48:34 +0000 (+0000) Subject: Experimental prototype of the %J conversion in printf(). X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=3ece90420dac4c05ac9d15a9523d52849411999c;p=thirdparty%2Fsqlite.git Experimental prototype of the %J conversion in printf(). FossilOrigin-Name: 7f6b1bae0849f0a840b95ae95aa6fdc6d51b72fdd50493649f584ad7829a3060 --- diff --git a/manifest b/manifest index 0effdc537c..5559936a02 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sminor\stypo\sin\sa\scomment\sin\sthe\sjson\smodule. -D 2026-05-06T19:13:21.357 +C Experimental\sprototype\sof\sthe\s%J\sconversion\sin\sprintf(). +D 2026-05-06T20:48:34.700 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -731,7 +731,7 @@ F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd F src/pragma.c 789ef67117b74b5be0a2db6681f7f0c55e6913791b9da309aefd280de2c8a74d F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d -F src/printf.c 50be92de0725e88c8b38978775ab46f9b42d74e21f65045c3423503173eb0566 +F src/printf.c 56069e56e6cf34ce54169ad26621c379e086a64dadf33a17bdb9d7a9350973ab F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c fcc406bfb055bee9954ee77c023f4a2a66a24bcdf1573516a72280811a269c20 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 @@ -2203,8 +2203,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d588680240a7f4395f2ef52dd78635de66120a677a41a28ceb96921b3333973d -R 0496dadfbf0d51d742a60ee63be334df +P 5c6d3e9d83af94234f67b06bd23c4eb0178a80c74c39be4945b3282244630020 +R a21480506f85a37cbc3d8c2a9355b050 +T *branch * format-json +T *sym-format-json * +T -sym-trunk * U drh -Z 93465120da68ecf990bab50fe9969894 +Z 3fa145bffe9be1127d94257e2ad01c6e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..85fc5126a2 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch format-json +tag format-json diff --git a/manifest.uuid b/manifest.uuid index 99be39db19..7ee69f5912 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c6d3e9d83af94234f67b06bd23c4eb0178a80c74c39be4945b3282244630020 +7f6b1bae0849f0a840b95ae95aa6fdc6d51b72fdd50493649f584ad7829a3060 diff --git a/src/printf.c b/src/printf.c index 4596cc10fe..1ee7ce5945 100644 --- a/src/printf.c +++ b/src/printf.c @@ -34,8 +34,9 @@ #define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etDECIMAL 16 /* %d or %u, but not %x, %o */ +#define etJSONSTR 17 /* %J -> generate a JSON string literal */ -#define etINVALID 17 /* Any unrecognized conversion type */ +#define etINVALID 18 /* Any unrecognized conversion type */ /* @@ -65,13 +66,13 @@ typedef struct et_info { /* Information about each format field */ /* ** The table is searched by hash. In the case of %C where C is the character -** and that character has ASCII value j, then the hash is j%23. +** and that character has ASCII value j, then the hash is j%24. ** ** The order of the entries in fmtinfo[] and the hash chain was entered ** manually, but based on the output of the following TCL script: */ #if 0 /***** Beginning of script ******/ -foreach c {d s g z q Q w c o u x X f e E G i n % p T S r} { +foreach c {d s g z q Q w c o u x X f e E G i n % p T S r J} { scan $c %c x set n($c) $x } @@ -90,31 +91,33 @@ for {set r 0} {$r<$mx} {incr r} { #endif /***** End of script ********/ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; +static const char aHex[] = "0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; -static const et_info fmtinfo[23] = { - /* 0 */ { 's', 0, 4, etSTRING, 0, 0, 1 }, - /* 1 */ { 'E', 0, 1, etEXP, 14, 0, 0 }, /* Hash: 0 */ - /* 2 */ { 'u', 10, 0, etDECIMAL, 0, 0, 3 }, - /* 3 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, /* Hash: 2 */ - /* 4 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, - /* 5 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, - /* 6 */ { 'c', 0, 0, etCHARX, 0, 0, 0 }, /* Hash: 7 */ - /* 7 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 6 }, - /* 8 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, - /* 9 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, - /* 10 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, - /* 11 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, - /* 12 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 0 }, - /* 13 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, - /* 14 */ { '%', 0, 0, etPERCENT, 0, 0, 16 }, - /* 15 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, - /* 16 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, /* Hash: 14 */ - /* 17 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 19 */ - /* 18 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, - /* 19 */ { 'o', 8, 0, etRADIX, 0, 2, 17 }, - /* 20 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, - /* 21 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 0 }, - /* 22 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 } +static const et_info fmtinfo[24] = { + /* 0 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, + /* 1 */ { 'J', 0, 0, etJSONSTR, 0, 0, 0 }, /* Hash: 2 */ + /* 2 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 1 }, + /* 3 */ { 'c', 0, 0, etCHARX, 0, 0, 0 }, + /* 4 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, + /* 5 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, + /* 6 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, + /* 7 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, + /* 8 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, /* Hash: 9 */ + /* 9 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 8 }, + /* 10 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 16 */ + /* 11 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, + /* 12 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, + /* 13 */ { '%', 0, 0, etPERCENT, 0, 0, 0 }, + /* 14 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, + /* 15 */ { 'o', 8, 0, etRADIX, 0, 2, 0 }, + /* 16 */ { 'p', 16, 0, etPOINTER, 0, 1, 10 }, + /* 17 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 0 }, + /* 18 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 }, + /* 19 */ { 's', 0, 4, etSTRING, 0, 0, 0 }, + /* 20 */ { 'E', 0, 1, etEXP, 14, 0, 0 }, /* Hash: 21 */ + /* 21 */ { 'u', 10, 0, etDECIMAL, 0, 0, 20 }, + /* 22 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, /* Hash: 23 */ + /* 23 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 22 } }; /* Additional Notes: @@ -375,8 +378,8 @@ void sqlite3_str_vappendf( } #else /* Fast hash-table lookup */ - assert( ArraySize(fmtinfo)==23 ); - idx = ((unsigned)c) % 23; + assert( ArraySize(fmtinfo)==24 ); + idx = ((unsigned)c) % 24; if( fmtinfo[idx].fmttype==c || fmtinfo[idx = fmtinfo[idx].iNxt].fmttype==c ){ @@ -747,7 +750,7 @@ void sqlite3_str_vappendf( if( zExtra==0 ){ /* The result is being rendered directory into pAccum. This - ** is the command and fast case */ + ** is the common and fast case */ pAccum->nChar += length; zOut[length] = 0; continue; @@ -867,6 +870,44 @@ void sqlite3_str_vappendf( while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; + case etJSONSTR: { /* %J: Generate a JSON string literal */ + char *escarg; + int i, j; + unsigned char ch; + + if( bArgList ){ + escarg = getTextArg(pArgList); + }else{ + escarg = va_arg(ap,char*); + } + if( escarg==0 ){ + sqlite3_str_append(pAccum, "null", 4); + }else{ + sqlite3_str_append(pAccum, "\"", 1); + for(i=j=0; 1; i++){ + if( (ch = ((u8*)escarg)[i])<0x1f || ch=='"' || ch=='\\' ){ + if( j0x1f ){ + sqlite3_str_appendchar(pAccum, 1, ch); + }else if( ((1<>4]); + sqlite3_str_appendchar(pAccum, 1, aHex[ch&0xf]); + } + } + } + sqlite3_str_append(pAccum, "\"", 1); + } + length = 0; + width = 0; + break; + } case etESCAPE_q: /* %q: Escape ' characters */ case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ case etESCAPE_w: { /* %w: Escape " characters */ @@ -958,7 +999,7 @@ void sqlite3_str_vappendf( bufpt[j++] = '0'; bufpt[j++] = '0'; bufpt[j++] = ch>=0x10 ? '1' : '0'; - bufpt[j++] = "0123456789abcdef"[ch&0xf]; + bufpt[j++] = aHex[ch&0xf]; } } }else{