Fossil SCM

Add the %j formatting directive to the customized printf() inside of Fossil. The %j format generates a string with appropriate backslash escapes so that the string can be part of a Javascript string literal.

drh 2019-05-17 13:53 trunk
Commit 5e9c1d5e049b09526ebb0519b5e6b1530a59e1d554ade8ebdbb564bb77a6a8e8
+8 -5
--- src/encode.c
+++ src/encode.c
@@ -376,13 +376,15 @@
376376
}
377377
return c;
378378
}
379379
380380
/*
381
-** Encode a UTF8 string for JSON. All special characters are escaped.
381
+** Encode a UTF8 string as a JSON string literal (without the surrounding
382
+** "...") and return a pointer to the encoding. Space to hold the encoding
383
+** is obtained from fossil_malloc() and must be freed by the caller.
382384
*/
383
-void blob_append_json_string(Blob *pBlob, const char *zStr){
385
+char *encode_json_string_literal(const char *zStr){
384386
const unsigned char *z;
385387
char *zOut;
386388
u32 c;
387389
int n, i, j;
388390
z = (const unsigned char*)zStr;
@@ -398,14 +400,14 @@
398400
}
399401
}else{
400402
n++;
401403
}
402404
}
403
- i = blob_size(pBlob);
404
- blob_resize(pBlob, i+n);
405
- zOut = blob_buffer(pBlob);
405
+ zOut = fossil_malloc(n+1);
406
+ if( zOut==0 ) return 0;
406407
z = (const unsigned char*)zStr;
408
+ i = 0;
407409
while( (c = fossil_utf8_read(&z))!=0 ){
408410
if( c=='\\' ){
409411
zOut[i++] = '\\';
410412
zOut[i++] = c;
411413
}else if( c<' ' || c>=0x7f ){
@@ -425,10 +427,11 @@
425427
}else{
426428
zOut[i++] = c;
427429
}
428430
}
429431
zOut[i] = 0;
432
+ return zOut;
430433
}
431434
432435
/*
433436
** The characters used for HTTP base64 encoding.
434437
*/
435438
--- src/encode.c
+++ src/encode.c
@@ -376,13 +376,15 @@
376 }
377 return c;
378 }
379
380 /*
381 ** Encode a UTF8 string for JSON. All special characters are escaped.
 
 
382 */
383 void blob_append_json_string(Blob *pBlob, const char *zStr){
384 const unsigned char *z;
385 char *zOut;
386 u32 c;
387 int n, i, j;
388 z = (const unsigned char*)zStr;
@@ -398,14 +400,14 @@
398 }
399 }else{
400 n++;
401 }
402 }
403 i = blob_size(pBlob);
404 blob_resize(pBlob, i+n);
405 zOut = blob_buffer(pBlob);
406 z = (const unsigned char*)zStr;
 
407 while( (c = fossil_utf8_read(&z))!=0 ){
408 if( c=='\\' ){
409 zOut[i++] = '\\';
410 zOut[i++] = c;
411 }else if( c<' ' || c>=0x7f ){
@@ -425,10 +427,11 @@
425 }else{
426 zOut[i++] = c;
427 }
428 }
429 zOut[i] = 0;
 
430 }
431
432 /*
433 ** The characters used for HTTP base64 encoding.
434 */
435
--- src/encode.c
+++ src/encode.c
@@ -376,13 +376,15 @@
376 }
377 return c;
378 }
379
380 /*
381 ** Encode a UTF8 string as a JSON string literal (without the surrounding
382 ** "...") and return a pointer to the encoding. Space to hold the encoding
383 ** is obtained from fossil_malloc() and must be freed by the caller.
384 */
385 char *encode_json_string_literal(const char *zStr){
386 const unsigned char *z;
387 char *zOut;
388 u32 c;
389 int n, i, j;
390 z = (const unsigned char*)zStr;
@@ -398,14 +400,14 @@
400 }
401 }else{
402 n++;
403 }
404 }
405 zOut = fossil_malloc(n+1);
406 if( zOut==0 ) return 0;
 
407 z = (const unsigned char*)zStr;
408 i = 0;
409 while( (c = fossil_utf8_read(&z))!=0 ){
410 if( c=='\\' ){
411 zOut[i++] = '\\';
412 zOut[i++] = c;
413 }else if( c<' ' || c>=0x7f ){
@@ -425,10 +427,11 @@
427 }else{
428 zOut[i++] = c;
429 }
430 }
431 zOut[i] = 0;
432 return zOut;
433 }
434
435 /*
436 ** The characters used for HTTP base64 encoding.
437 */
438
+11
--- src/printf.c
+++ src/printf.c
@@ -99,10 +99,11 @@
9999
#define etFOSSILIZE 20 /* The fossil header encoding format. */
100100
#define etPATH 21 /* Path type */
101101
#define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102102
#define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
103103
#define etROOT 24 /* String value of g.zTop: %R */
104
+#define etJSONSTR 25 /* String encoded as a JSON string literal: %j */
104105
105106
106107
/*
107108
** An "etByte" is an 8-bit unsigned value.
108109
*/
@@ -150,10 +151,11 @@
150151
{ 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
151152
{ 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
152153
{ 'w', 0, 4, etSQLESCAPE3, 0, 0 },
153154
{ 'F', 0, 4, etFOSSILIZE, 0, 0 },
154155
{ 'S', 0, 4, etSTRINGID, 0, 0 },
156
+ { 'j', 0, 0, etJSONSTR, 0, 0 },
155157
{ 'c', 0, 0, etCHARX, 0, 0 },
156158
{ 'o', 8, 0, etRADIX, 0, 2 },
157159
{ 'u', 10, 0, etRADIX, 0, 0 },
158160
{ 'x', 16, 0, etRADIX, 16, 1 },
159161
{ 'X', 16, 0, etRADIX, 0, 4 },
@@ -779,10 +781,19 @@
779781
case etFOSSILIZE: {
780782
int limit = flag_alternateform ? va_arg(ap,int) : -1;
781783
char *zMem = va_arg(ap,char*);
782784
if( zMem==0 ) zMem = "";
783785
zExtra = bufpt = fossilize(zMem, limit);
786
+ length = strlen(bufpt);
787
+ if( precision>=0 && precision<length ) length = precision;
788
+ break;
789
+ }
790
+ case etJSONSTR: {
791
+ int limit = flag_alternateform ? va_arg(ap,int) : -1;
792
+ char *zMem = va_arg(ap,char*);
793
+ if( zMem==0 ) zMem = "";
794
+ zExtra = bufpt = encode_json_string_literal(zMem);
784795
length = strlen(bufpt);
785796
if( precision>=0 && precision<length ) length = precision;
786797
break;
787798
}
788799
case etWIKISTR: {
789800
--- src/printf.c
+++ src/printf.c
@@ -99,10 +99,11 @@
99 #define etFOSSILIZE 20 /* The fossil header encoding format. */
100 #define etPATH 21 /* Path type */
101 #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
103 #define etROOT 24 /* String value of g.zTop: %R */
 
104
105
106 /*
107 ** An "etByte" is an 8-bit unsigned value.
108 */
@@ -150,10 +151,11 @@
150 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
151 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
152 { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
153 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
154 { 'S', 0, 4, etSTRINGID, 0, 0 },
 
155 { 'c', 0, 0, etCHARX, 0, 0 },
156 { 'o', 8, 0, etRADIX, 0, 2 },
157 { 'u', 10, 0, etRADIX, 0, 0 },
158 { 'x', 16, 0, etRADIX, 16, 1 },
159 { 'X', 16, 0, etRADIX, 0, 4 },
@@ -779,10 +781,19 @@
779 case etFOSSILIZE: {
780 int limit = flag_alternateform ? va_arg(ap,int) : -1;
781 char *zMem = va_arg(ap,char*);
782 if( zMem==0 ) zMem = "";
783 zExtra = bufpt = fossilize(zMem, limit);
 
 
 
 
 
 
 
 
 
784 length = strlen(bufpt);
785 if( precision>=0 && precision<length ) length = precision;
786 break;
787 }
788 case etWIKISTR: {
789
--- src/printf.c
+++ src/printf.c
@@ -99,10 +99,11 @@
99 #define etFOSSILIZE 20 /* The fossil header encoding format. */
100 #define etPATH 21 /* Path type */
101 #define etWIKISTR 22 /* Timeline comment text rendered from a char*: %W */
102 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
103 #define etROOT 24 /* String value of g.zTop: %R */
104 #define etJSONSTR 25 /* String encoded as a JSON string literal: %j */
105
106
107 /*
108 ** An "etByte" is an 8-bit unsigned value.
109 */
@@ -150,10 +151,11 @@
151 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
152 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
153 { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
154 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
155 { 'S', 0, 4, etSTRINGID, 0, 0 },
156 { 'j', 0, 0, etJSONSTR, 0, 0 },
157 { 'c', 0, 0, etCHARX, 0, 0 },
158 { 'o', 8, 0, etRADIX, 0, 2 },
159 { 'u', 10, 0, etRADIX, 0, 0 },
160 { 'x', 16, 0, etRADIX, 16, 1 },
161 { 'X', 16, 0, etRADIX, 0, 4 },
@@ -779,10 +781,19 @@
781 case etFOSSILIZE: {
782 int limit = flag_alternateform ? va_arg(ap,int) : -1;
783 char *zMem = va_arg(ap,char*);
784 if( zMem==0 ) zMem = "";
785 zExtra = bufpt = fossilize(zMem, limit);
786 length = strlen(bufpt);
787 if( precision>=0 && precision<length ) length = precision;
788 break;
789 }
790 case etJSONSTR: {
791 int limit = flag_alternateform ? va_arg(ap,int) : -1;
792 char *zMem = va_arg(ap,char*);
793 if( zMem==0 ) zMem = "";
794 zExtra = bufpt = encode_json_string_literal(zMem);
795 length = strlen(bufpt);
796 if( precision>=0 && precision<length ) length = precision;
797 break;
798 }
799 case etWIKISTR: {
800
--- src/unversioned.c
+++ src/unversioned.c
@@ -619,18 +619,16 @@
619619
sqlite3_int64 mtime = db_column_int(&q, 1);
620620
const char *zHash = db_column_text(&q, 2);
621621
int fullSize = db_column_int(&q, 3);
622622
const char *zLogin = db_column_text(&q, 4);
623623
if( zLogin==0 ) zLogin = "";
624
- blob_appendf(&json, "%s{\"name\":\"", zSep);
624
+ blob_appendf(&json, "%s{\"name\":\"%j\",\n", zSep, zName);
625625
zSep = ",\n ";
626
- blob_append_json_string(&json, zName);
627
- blob_appendf(&json, "\",\n \"mtime\":%lld,\n \"hash\":\"", mtime);
628
- blob_append_json_string(&json, zHash);
629
- blob_appendf(&json, "\",\n \"size\":%d,\n \"user\":\"", fullSize);
630
- blob_append_json_string(&json, zLogin);
631
- blob_appendf(&json, "\"}");
626
+ blob_appendf(&json, " \"mtime\":%lld,\n", mtime);
627
+ blob_appendf(&json, " \"hash\":\"%j\",\n", zHash);
628
+ blob_appendf(&json, " \"size\":%d,\n", fullSize);
629
+ blob_appendf(&json, " \"user\":\"%j\"}", zLogin);
632630
}
633631
db_finalize(&q);
634632
blob_appendf(&json,"]\n");
635633
cgi_set_content(&json);
636634
}
637635
--- src/unversioned.c
+++ src/unversioned.c
@@ -619,18 +619,16 @@
619 sqlite3_int64 mtime = db_column_int(&q, 1);
620 const char *zHash = db_column_text(&q, 2);
621 int fullSize = db_column_int(&q, 3);
622 const char *zLogin = db_column_text(&q, 4);
623 if( zLogin==0 ) zLogin = "";
624 blob_appendf(&json, "%s{\"name\":\"", zSep);
625 zSep = ",\n ";
626 blob_append_json_string(&json, zName);
627 blob_appendf(&json, "\",\n \"mtime\":%lld,\n \"hash\":\"", mtime);
628 blob_append_json_string(&json, zHash);
629 blob_appendf(&json, "\",\n \"size\":%d,\n \"user\":\"", fullSize);
630 blob_append_json_string(&json, zLogin);
631 blob_appendf(&json, "\"}");
632 }
633 db_finalize(&q);
634 blob_appendf(&json,"]\n");
635 cgi_set_content(&json);
636 }
637
--- src/unversioned.c
+++ src/unversioned.c
@@ -619,18 +619,16 @@
619 sqlite3_int64 mtime = db_column_int(&q, 1);
620 const char *zHash = db_column_text(&q, 2);
621 int fullSize = db_column_int(&q, 3);
622 const char *zLogin = db_column_text(&q, 4);
623 if( zLogin==0 ) zLogin = "";
624 blob_appendf(&json, "%s{\"name\":\"%j\",\n", zSep, zName);
625 zSep = ",\n ";
626 blob_appendf(&json, " \"mtime\":%lld,\n", mtime);
627 blob_appendf(&json, " \"hash\":\"%j\",\n", zHash);
628 blob_appendf(&json, " \"size\":%d,\n", fullSize);
629 blob_appendf(&json, " \"user\":\"%j\"}", zLogin);
 
 
630 }
631 db_finalize(&q);
632 blob_appendf(&json,"]\n");
633 cgi_set_content(&json);
634 }
635

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button