}
}
+/*
+** Escape the input string if it is needed and in accordance with
+** eEscape, which is either RESFMT_E_Ascii or RESFMT_E_Symbol.
+**
+** Escaping is needed if the string contains any control characters
+** other than \t, \n, and \r\n
+**
+** If no escaping is needed (the common case) then set *ppOut to NULL
+** and return 0. If escaping is needed, write the escaped string into
+** memory obtained from sqlite3_malloc64() and make *ppOut point to that
+** memory and return 0. If an error occurs, return non-zero.
+**
+** The caller is responsible for freeing *ppFree if it is non-NULL in order
+** to reclaim memory.
+*/
+static void resfmtEscape(
+ int eEscape, /* RESFMT_E_Ascii or RESFMT_E_Symbol */
+ sqlite3_str *pStr, /* String to be escaped */
+ int iStart /* Begin escapding on this byte of pStr */
+){
+ sqlite3_int64 i, j; /* Loop counters */
+ sqlite3_int64 sz; /* Size of the string prior to escaping */
+ sqlite3_int64 nCtrl = 0;/* Number of control characters to escape */
+ unsigned char *zIn; /* Text to be escaped */
+ unsigned char c; /* A single character of the text */
+ unsigned char *zOut; /* Where to write the results */
+
+ /* Find the text to be escaped */
+ zIn = (unsigned char*)sqlite3_str_value(pStr);
+ if( zIn==0 ) return;
+ zIn += iStart;
+
+ /* Count the control characters */
+ for(i=0; (c = zIn[i])!=0; i++){
+ if( c<=0x1f
+ && c!='\t'
+ && c!='\n'
+ && (c!='\r' || zIn[i+1]!='\n')
+ ){
+ nCtrl++;
+ }
+ }
+ if( nCtrl==0 ) return; /* Early out if no control characters */
+
+ /* Make space to hold the escapes. Copy the original text to the end
+ ** of the available space. */
+ sz = sqlite3_str_length(pStr) - iStart;
+ if( eEscape==RESFMT_E_Symbol ) nCtrl *= 2;
+ sqlite3_str_appendchar(pStr, nCtrl, ' ');
+ zOut = (unsigned char*)sqlite3_str_value(pStr);
+ if( zOut==0 ) return;
+ zOut += iStart;
+ zIn = zOut + nCtrl;
+ memmove(zIn,zOut,sz);
+
+ /* Convert the control characters */
+ for(i=j=0; (c = zIn[i])!=0; i++){
+ if( c>0x1f
+ || c=='\t'
+ || c=='\n'
+ || (c=='\r' && zIn[i+1]=='\n')
+ ){
+ continue;
+ }
+ if( i>0 ){
+ memmove(&zOut[j], zIn, i);
+ j += i;
+ }
+ zIn += i+1;
+ i = -1;
+ if( eEscape==RESFMT_E_Symbol ){
+ zOut[j++] = 0xe2;
+ zOut[j++] = 0x90;
+ zOut[j++] = 0x80+c;
+ }else{
+ zOut[j++] = '^';
+ zOut[j++] = 0x40+c;
+ }
+ }
+}
+
/*
** Encode text appropriately and append it to p->pOut.
*/
static void resfmtEncodeText(sqlite3_resfmt *p, const char *zTxt){
- if( p->spec.eQuote ){
- sqlite3_str_appendf(p->pOut, "%Q", zTxt);
- }else{
- sqlite3_str_appendall(p->pOut, zTxt);
+ int iStart = sqlite3_str_length(p->pOut);
+ switch( p->spec.eQuote ){
+ case RESFMT_Q_Sql: {
+ sqlite3_str_appendf(p->pOut, "%Q", zTxt);
+ break;
+ }
+ default: {
+ sqlite3_str_appendall(p->pOut, zTxt);
+ break;
+ }
+ }
+ if( p->spec.eEscape!=RESFMT_E_Off ){
+ resfmtEscape(p->spec.eEscape, p->pOut, iStart);
}
}
break;
}
case SQLITE_BLOB: {
- if( p->spec.eQuote ){
- int iStart = sqlite3_str_length(p->pOut);
- int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
- int i, j;
- char *zVal;
- const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
- sqlite3_str_append(p->pOut, "x'", 2);
- sqlite3_str_appendchar(p->pOut, nBlob, ' ');
- sqlite3_str_appendchar(p->pOut, nBlob, ' ');
- sqlite3_str_appendchar(p->pOut, 1, '\'');
- if( sqlite3_str_errcode(p->pOut) ) return;
- zVal = sqlite3_str_value(p->pOut);
- for(i=0, j=iStart+2; i<nBlob; i++, j+=2){
- unsigned char c = a[i];
- zVal[j] = "0123456789abcdef"[(c>>4)&0xf];
- zVal[j+1] = "0123456789abcdef"[(c)&0xf];
+ switch( p->spec.eQuote ){
+ case RESFMT_Q_Sql: {
+ int iStart = sqlite3_str_length(p->pOut);
+ int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
+ int i, j;
+ char *zVal;
+ const unsigned char *a = sqlite3_column_blob(p->pStmt,iCol);
+ sqlite3_str_append(p->pOut, "x'", 2);
+ sqlite3_str_appendchar(p->pOut, nBlob, ' ');
+ sqlite3_str_appendchar(p->pOut, nBlob, ' ');
+ sqlite3_str_appendchar(p->pOut, 1, '\'');
+ if( sqlite3_str_errcode(p->pOut) ) return;
+ zVal = sqlite3_str_value(p->pOut);
+ for(i=0, j=iStart+2; i<nBlob; i++, j+=2){
+ unsigned char c = a[i];
+ zVal[j] = "0123456789abcdef"[(c>>4)&0xf];
+ zVal[j+1] = "0123456789abcdef"[(c)&0xf];
+ }
+ break;
+ }
+ default: {
+ const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
+ resfmtEncodeText(p, zTxt);
}
- }else{
- const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
- sqlite3_str_appendall(p->pOut, zTxt);
}
break;
}
-C Recognize\sthe\svarious\squoting\sstyles\sand\sescape\smodes\sin\sthe\sresfmt-test\nprogram.
-D 2025-10-21T11:00:04.169
+C Control-character\sescaping
+D 2025-10-21T13:07:51.412
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/misc/randomjson.c ef835fc64289e76ac4873b85fe12f9463a036168d7683cf2b773e36e6262c4ed
F ext/misc/regexp.c 548151f3e57506fda678e6a65e85a763f4eece653287e1ad44e167f9485e0c6b
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
-F ext/misc/resfmt-tester.c 90a13ed2d4b61e147c0aa976c5b7c184c5e782ddbcfd6667a11431f26001cfc0
-F ext/misc/resfmt.c b12901db493acb62beb382f4174d66824f1311148b293f7736d74bfcfed0984d
-F ext/misc/resfmt.h da70079e9b543fbdd5bc2fef525b1d257f8e0e25d2550a0258540a377f42f4f3
+F ext/misc/resfmt-tester.c 1cb1dae3f31caa13e4b7ef635eec05a5b1981aaa2202a72ca74cd995ceb5c677
+F ext/misc/resfmt.c cae8cff21efa71d0779999f715023488e96739d690c1f5bff17f947b7f43a10a
+F ext/misc/resfmt.h 54937535c8d7bfda506ec3ecd9c9e6fe247f3621c0645d067809f2eb9d4bb70e
F ext/misc/resfmt.md 6f6cefd95fa11ce30e4f34ea84052e7a8291dd48b7e666352bd7cf2e22c22ec4
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 9adaf791f88875c5afeba7e7aa72efb59df42c6052898f8d7e2f83aede00a044
-R 41bf090f4cb07015b0636c2cbe7ec8eb
+P 3ee2a8775fcc557a53c36240ddc039024ff52e21d9ad9021d7cf5bf79f8b9ed4
+R 78c35db5d2e47632e3afeaff2a301639
U drh
-Z 6c096d7b8b0de8560d49dc8950bacfdd
+Z dd3d4f12786ad3019ddd480d2d6b5f14
# Remove this line to create a well-formed Fossil manifest.