]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experimental prototype of the %J conversion in printf().
authordrh <>
Wed, 6 May 2026 20:48:34 +0000 (20:48 +0000)
committerdrh <>
Wed, 6 May 2026 20:48:34 +0000 (20:48 +0000)
FossilOrigin-Name: 7f6b1bae0849f0a840b95ae95aa6fdc6d51b72fdd50493649f584ad7829a3060

manifest
manifest.tags
manifest.uuid
src/printf.c

index 0effdc537cdea7205b732fb558911c8783293064..5559936a02c0bdbbdbdaab048a522de309e8f203 100644 (file)
--- 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.
index bec971799ff1b8ee641c166c7aeb22d12c785393..85fc5126a2bcd4444e2050f0ace036007d08b18c 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch format-json
+tag format-json
index 99be39db190c9381e36012af874f425d349cb1ed..7ee69f5912bf8ea40b2430f94d17463d2aa7026d 100644 (file)
@@ -1 +1 @@
-5c6d3e9d83af94234f67b06bd23c4eb0178a80c74c39be4945b3282244630020
+7f6b1bae0849f0a840b95ae95aa6fdc6d51b72fdd50493649f584ad7829a3060
index 4596cc10fefbba350cce506a07857a20af3cb191..1ee7ce594537561be1e06bfdd6bf13d60cd2c17c 100644 (file)
@@ -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( j<i-1 ) sqlite3_str_append(pAccum, &escarg[j], i-j);
+              j = i+1;
+              if( ch==0 ) break;
+              sqlite3_str_appendchar(pAccum, 1, '\\');
+              if( ch>0x1f ){
+                sqlite3_str_appendchar(pAccum, 1, ch);
+              }else if( ((1<<ch)&0x3700)!=0 ){
+                ch = "btn?fr"[ch-8];
+                sqlite3_str_appendchar(pAccum, 1, ch);
+              }else{
+                sqlite3_str_append(pAccum, "u00", 3);
+                sqlite3_str_appendchar(pAccum, 1, aHex[ch>>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{