Fossil SCM

Enhance the verify-comments subroutine in "fossil commit" so that if the comment text contains any of the special charaters "`*_\<&[" then the formatted text is previewed to the operator who must then confirm before continuing (unless --allow-suspect-comment is used or the verify-comments setting is off).

drh 2025-03-18 15:52 trunk merge
Commit 4ee3362aac8832aafa5414d5395679720b0f6709e815ab86cb9fa7672b23d087
2 files changed +28 -3 +20 -5
+28 -3
--- 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 ){
@@ -2325,26 +2326,50 @@
23252326
z = zEnd2;
23262327
continue;
23272328
}
23282329
zSep = strchr(z+1,'|');
23292330
if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2330
- cSave1 = zEnd[0];
2331
- zEnd[0] = 0;
2331
+ while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2332
+ cSave1 = zSep[0];
2333
+ zSep[0] = 0;
23322334
if( !wiki_valid_link_target(z+1) ){
23332335
blob_appendf(pSus,"\n (%d) ", ++nIssue);
23342336
blob_appendf(pSus, "Broken hyperlink: [%s]", z+1);
23352337
}
2336
- zEnd[0] = cSave1;
2338
+ zSep[0] = cSave1;
23372339
z = zEnd;
23382340
}
23392341
if( nIssue ){
23402342
Blob tmp = *pSus;
23412343
blob_init(pSus, 0, 0);
23422344
blob_appendf(pSus,
23432345
"Possible comment formatting error%s:%b\n",
23442346
nIssue>1 ? "s" : "", &tmp);
23452347
blob_reset(&tmp);
2348
+ return 1;
2349
+ }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2350
+ Blob in, html, txt;
2351
+ char zGot[16];
2352
+ int nGot = 0;
2353
+ int i;
2354
+ for(i=0; zSpecial[i]; i++){
2355
+ if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2356
+ }
2357
+ zGot[nGot] = 0;
2358
+ blob_init(&in, blob_str(pComment), -1);
2359
+ blob_init(&html, 0, 0);
2360
+ wiki_convert(&in, &html, WIKI_INLINE);
2361
+ blob_reset(&in);
2362
+ blob_init(&txt, 0, 0);
2363
+ html_to_plaintext(blob_str(&html), &txt);
2364
+ blob_reset(&html);
2365
+ fossil_print("The comment uses special character%s \"%s\". "
2366
+ "Does it render as you expect?\n\n ",
2367
+ nGot>1 ? "s" : "", zGot);
2368
+ comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2369
+ blob_init(pSus, 0, 0);
2370
+ blob_appendf(pSus, "\n");
23462371
return 1;
23472372
}else{
23482373
return 0;
23492374
}
23502375
}
23512376
--- 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 ){
@@ -2325,26 +2326,50 @@
2325 z = zEnd2;
2326 continue;
2327 }
2328 zSep = strchr(z+1,'|');
2329 if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2330 cSave1 = zEnd[0];
2331 zEnd[0] = 0;
 
2332 if( !wiki_valid_link_target(z+1) ){
2333 blob_appendf(pSus,"\n (%d) ", ++nIssue);
2334 blob_appendf(pSus, "Broken hyperlink: [%s]", z+1);
2335 }
2336 zEnd[0] = cSave1;
2337 z = zEnd;
2338 }
2339 if( nIssue ){
2340 Blob tmp = *pSus;
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 ){
@@ -2325,26 +2326,50 @@
2326 z = zEnd2;
2327 continue;
2328 }
2329 zSep = strchr(z+1,'|');
2330 if( zSep==0 || zSep>zEnd ) zSep = zEnd;
2331 while( zSep>z && fossil_isspace(zSep[-1]) ) zSep--;
2332 cSave1 = zSep[0];
2333 zSep[0] = 0;
2334 if( !wiki_valid_link_target(z+1) ){
2335 blob_appendf(pSus,"\n (%d) ", ++nIssue);
2336 blob_appendf(pSus, "Broken hyperlink: [%s]", z+1);
2337 }
2338 zSep[0] = cSave1;
2339 z = zEnd;
2340 }
2341 if( nIssue ){
2342 Blob tmp = *pSus;
2343 blob_init(pSus, 0, 0);
2344 blob_appendf(pSus,
2345 "Possible comment formatting error%s:%b\n",
2346 nIssue>1 ? "s" : "", &tmp);
2347 blob_reset(&tmp);
2348 return 1;
2349 }else if( strcspn(zStart,zSpecial)<strlen(zStart) ){
2350 Blob in, html, txt;
2351 char zGot[16];
2352 int nGot = 0;
2353 int i;
2354 for(i=0; zSpecial[i]; i++){
2355 if( strchr(zStart,zSpecial[i]) ) zGot[nGot++] = zSpecial[i];
2356 }
2357 zGot[nGot] = 0;
2358 blob_init(&in, blob_str(pComment), -1);
2359 blob_init(&html, 0, 0);
2360 wiki_convert(&in, &html, WIKI_INLINE);
2361 blob_reset(&in);
2362 blob_init(&txt, 0, 0);
2363 html_to_plaintext(blob_str(&html), &txt);
2364 blob_reset(&html);
2365 fossil_print("The comment uses special character%s \"%s\". "
2366 "Does it render as you expect?\n\n ",
2367 nGot>1 ? "s" : "", zGot);
2368 comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
2369 blob_init(pSus, 0, 0);
2370 blob_appendf(pSus, "\n");
2371 return 1;
2372 }else{
2373 return 0;
2374 }
2375 }
2376
+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