Fossil SCM

Enhance the verify-comment subroutine for "fossil commit" so that if the comment contains any of the special characters "\&<`[*_" it will display the formatted comment text and ask the user for confirmation before continuing, unless the --allow-suspect-comment flag is used or unless the [/help?cmd=verify-comments

drh 2025-03-18 15:14 trunk
Commit 6d05c66f877888fb1b45f16e6c3609e78769c95a8c04bcb3e081afa9a809555c
2 files changed +22 +20 -5
--- src/checkin.c
+++ src/checkin.c
@@ -2305,10 +2305,11 @@
23052305
char *z;
23062306
char *zEnd, *zEnd2;
23072307
char *zSep;
23082308
char cSave1;
23092309
int nIssue = 0;
2310
+ static const char zSpecial[] = "\\&<*_`[";
23102311
23112312
if( !db_get_boolean("verify-comments",1) ) return 0;
23122313
z = zStart;
23132314
blob_init(pSus, 0, 0);
23142315
while( (z = strchr(z,'['))!=0 ){
@@ -2341,10 +2342,31 @@
23412342
blob_init(pSus, 0, 0);
23422343
blob_appendf(pSus,
23432344
"Possible comment formatting error%s:%b\n",
23442345
nIssue>1 ? "s" : "", &tmp);
23452346
blob_reset(&tmp);
2347
+ return 1;
2348
+ }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2349
+ Blob html, txt;
2350
+ char zGot[16];
2351
+ int nGot = 0;
2352
+ int i;
2353
+ for(i=0; zSpecial[i]; i++){
2354
+ if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2355
+ }
2356
+ zGot[nGot] = 0;
2357
+ blob_init(&html, 0, 0);
2358
+ wiki_convert(pComment, &html, WIKI_INLINE);
2359
+ blob_init(&txt, 0, 0);
2360
+ html_to_plaintext(blob_str(&html), &txt);
2361
+ blob_reset(&html);
2362
+ fossil_print("The comment uses special character%s \"%s\". "
2363
+ "Does it render as you expect?\n\n ",
2364
+ nGot>1 ? "s" : "", zGot);
2365
+ comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2366
+ blob_init(pSus, 0, 0);
2367
+ blob_appendf(pSus, "\n");
23462368
return 1;
23472369
}else{
23482370
return 0;
23492371
}
23502372
}
23512373
--- src/checkin.c
+++ src/checkin.c
@@ -2305,10 +2305,11 @@
2305 char *z;
2306 char *zEnd, *zEnd2;
2307 char *zSep;
2308 char cSave1;
2309 int nIssue = 0;
 
2310
2311 if( !db_get_boolean("verify-comments",1) ) return 0;
2312 z = zStart;
2313 blob_init(pSus, 0, 0);
2314 while( (z = strchr(z,'['))!=0 ){
@@ -2341,10 +2342,31 @@
2341 blob_init(pSus, 0, 0);
2342 blob_appendf(pSus,
2343 "Possible comment formatting error%s:%b\n",
2344 nIssue>1 ? "s" : "", &tmp);
2345 blob_reset(&tmp);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2346 return 1;
2347 }else{
2348 return 0;
2349 }
2350 }
2351
--- src/checkin.c
+++ src/checkin.c
@@ -2305,10 +2305,11 @@
2305 char *z;
2306 char *zEnd, *zEnd2;
2307 char *zSep;
2308 char cSave1;
2309 int nIssue = 0;
2310 static const char zSpecial[] = "\\&<*_`[";
2311
2312 if( !db_get_boolean("verify-comments",1) ) return 0;
2313 z = zStart;
2314 blob_init(pSus, 0, 0);
2315 while( (z = strchr(z,'['))!=0 ){
@@ -2341,10 +2342,31 @@
2342 blob_init(pSus, 0, 0);
2343 blob_appendf(pSus,
2344 "Possible comment formatting error%s:%b\n",
2345 nIssue>1 ? "s" : "", &tmp);
2346 blob_reset(&tmp);
2347 return 1;
2348 }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2349 Blob html, txt;
2350 char zGot[16];
2351 int nGot = 0;
2352 int i;
2353 for(i=0; zSpecial[i]; i++){
2354 if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2355 }
2356 zGot[nGot] = 0;
2357 blob_init(&html, 0, 0);
2358 wiki_convert(pComment, &html, WIKI_INLINE);
2359 blob_init(&txt, 0, 0);
2360 html_to_plaintext(blob_str(&html), &txt);
2361 blob_reset(&html);
2362 fossil_print("The comment uses special character%s \"%s\". "
2363 "Does it render as you expect?\n\n ",
2364 nGot>1 ? "s" : "", zGot);
2365 comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2366 blob_init(pSus, 0, 0);
2367 blob_appendf(pSus, "\n");
2368 return 1;
2369 }else{
2370 return 0;
2371 }
2372 }
2373
+20 -5
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2489,20 +2489,21 @@
24892489
blob_append_char(pOut, nNL ? '\n' : ' ');
24902490
nWS = 1;
24912491
}
24922492
}
24932493
}else if( zIn[0]=='&' ){
2494
- char c = '?';
2494
+ u32 c = '?';
24952495
if( zIn[1]=='#' ){
2496
- int x = atoi(&zIn[1]);
2497
- if( x>0 && x<=127 ) c = x;
2496
+ c = atoi(&zIn[2]);
2497
+ if( c==0 ) c = '?';
24982498
}else{
2499
- static const struct { int n; char c; char *z; } aEntity[] = {
2499
+ static const struct { int n; u32 c; char *z; } aEntity[] = {
25002500
{ 5, '&', "&amp;" },
25012501
{ 4, '<', "&lt;" },
25022502
{ 4, '>', "&gt;" },
25032503
{ 6, ' ', "&nbsp;" },
2504
+ { 6, '"', "&quot;" },
25042505
};
25052506
int jj;
25062507
for(jj=0; jj<count(aEntity); jj++){
25072508
if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){
25082509
c = aEntity[jj].c;
@@ -2516,11 +2517,25 @@
25162517
nNL = c=='\n';
25172518
}else{
25182519
if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
25192520
seenText = 1;
25202521
nNL = nWS = 0;
2521
- blob_append_char(pOut, c);
2522
+ if( c<0x00080 ){
2523
+ blob_append_char(pOut, c & 0xff);
2524
+ }else if( c<0x00800 ){
2525
+ blob_append_char(pOut, 0xc0 + (u8)((c>>6)&0x1f));
2526
+ blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2527
+ }else if( c<0x10000 ){
2528
+ blob_append_char(pOut, 0xe0 + (u8)((c>>12)&0x0f));
2529
+ blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
2530
+ blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2531
+ }else{
2532
+ blob_append_char(pOut, 0xf0 + (u8)((c>>18)&0x07));
2533
+ blob_append_char(pOut, 0x80 + (u8)((c>>12)&0x3f));
2534
+ blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
2535
+ blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2536
+ }
25222537
}
25232538
}else{
25242539
if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
25252540
seenText = 1;
25262541
nNL = nWS = 0;
25272542
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2489,20 +2489,21 @@
2489 blob_append_char(pOut, nNL ? '\n' : ' ');
2490 nWS = 1;
2491 }
2492 }
2493 }else if( zIn[0]=='&' ){
2494 char c = '?';
2495 if( zIn[1]=='#' ){
2496 int x = atoi(&zIn[1]);
2497 if( x>0 && x<=127 ) c = x;
2498 }else{
2499 static const struct { int n; char c; char *z; } aEntity[] = {
2500 { 5, '&', "&amp;" },
2501 { 4, '<', "&lt;" },
2502 { 4, '>', "&gt;" },
2503 { 6, ' ', "&nbsp;" },
 
2504 };
2505 int jj;
2506 for(jj=0; jj<count(aEntity); jj++){
2507 if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){
2508 c = aEntity[jj].c;
@@ -2516,11 +2517,25 @@
2516 nNL = c=='\n';
2517 }else{
2518 if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
2519 seenText = 1;
2520 nNL = nWS = 0;
2521 blob_append_char(pOut, c);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2522 }
2523 }else{
2524 if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
2525 seenText = 1;
2526 nNL = nWS = 0;
2527
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -2489,20 +2489,21 @@
2489 blob_append_char(pOut, nNL ? '\n' : ' ');
2490 nWS = 1;
2491 }
2492 }
2493 }else if( zIn[0]=='&' ){
2494 u32 c = '?';
2495 if( zIn[1]=='#' ){
2496 c = atoi(&zIn[2]);
2497 if( c==0 ) c = '?';
2498 }else{
2499 static const struct { int n; u32 c; char *z; } aEntity[] = {
2500 { 5, '&', "&amp;" },
2501 { 4, '<', "&lt;" },
2502 { 4, '>', "&gt;" },
2503 { 6, ' ', "&nbsp;" },
2504 { 6, '"', "&quot;" },
2505 };
2506 int jj;
2507 for(jj=0; jj<count(aEntity); jj++){
2508 if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){
2509 c = aEntity[jj].c;
@@ -2516,11 +2517,25 @@
2517 nNL = c=='\n';
2518 }else{
2519 if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
2520 seenText = 1;
2521 nNL = nWS = 0;
2522 if( c<0x00080 ){
2523 blob_append_char(pOut, c & 0xff);
2524 }else if( c<0x00800 ){
2525 blob_append_char(pOut, 0xc0 + (u8)((c>>6)&0x1f));
2526 blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2527 }else if( c<0x10000 ){
2528 blob_append_char(pOut, 0xe0 + (u8)((c>>12)&0x0f));
2529 blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
2530 blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2531 }else{
2532 blob_append_char(pOut, 0xf0 + (u8)((c>>18)&0x07));
2533 blob_append_char(pOut, 0x80 + (u8)((c>>12)&0x3f));
2534 blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
2535 blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
2536 }
2537 }
2538 }else{
2539 if( !seenText && !inTitle ) blob_append_char(pOut, '\n');
2540 seenText = 1;
2541 nNL = nWS = 0;
2542

Keyboard Shortcuts

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