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
Commit
6d05c66f877888fb1b45f16e6c3609e78769c95a8c04bcb3e081afa9a809555c
Parent
3f30abc80ae4b19…
2 files changed
+22
+20
-5
+22
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -2305,10 +2305,11 @@ | ||
| 2305 | 2305 | char *z; |
| 2306 | 2306 | char *zEnd, *zEnd2; |
| 2307 | 2307 | char *zSep; |
| 2308 | 2308 | char cSave1; |
| 2309 | 2309 | int nIssue = 0; |
| 2310 | + static const char zSpecial[] = "\\&<*_`["; | |
| 2310 | 2311 | |
| 2311 | 2312 | if( !db_get_boolean("verify-comments",1) ) return 0; |
| 2312 | 2313 | z = zStart; |
| 2313 | 2314 | blob_init(pSus, 0, 0); |
| 2314 | 2315 | while( (z = strchr(z,'['))!=0 ){ |
| @@ -2341,10 +2342,31 @@ | ||
| 2341 | 2342 | blob_init(pSus, 0, 0); |
| 2342 | 2343 | blob_appendf(pSus, |
| 2343 | 2344 | "Possible comment formatting error%s:%b\n", |
| 2344 | 2345 | nIssue>1 ? "s" : "", &tmp); |
| 2345 | 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"); | |
| 2346 | 2368 | return 1; |
| 2347 | 2369 | }else{ |
| 2348 | 2370 | return 0; |
| 2349 | 2371 | } |
| 2350 | 2372 | } |
| 2351 | 2373 |
| --- 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 @@ | ||
| 2489 | 2489 | blob_append_char(pOut, nNL ? '\n' : ' '); |
| 2490 | 2490 | nWS = 1; |
| 2491 | 2491 | } |
| 2492 | 2492 | } |
| 2493 | 2493 | }else if( zIn[0]=='&' ){ |
| 2494 | - char c = '?'; | |
| 2494 | + u32 c = '?'; | |
| 2495 | 2495 | 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 = '?'; | |
| 2498 | 2498 | }else{ |
| 2499 | - static const struct { int n; char c; char *z; } aEntity[] = { | |
| 2499 | + static const struct { int n; u32 c; char *z; } aEntity[] = { | |
| 2500 | 2500 | { 5, '&', "&" }, |
| 2501 | 2501 | { 4, '<', "<" }, |
| 2502 | 2502 | { 4, '>', ">" }, |
| 2503 | 2503 | { 6, ' ', " " }, |
| 2504 | + { 6, '"', """ }, | |
| 2504 | 2505 | }; |
| 2505 | 2506 | int jj; |
| 2506 | 2507 | for(jj=0; jj<count(aEntity); jj++){ |
| 2507 | 2508 | if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){ |
| 2508 | 2509 | c = aEntity[jj].c; |
| @@ -2516,11 +2517,25 @@ | ||
| 2516 | 2517 | nNL = c=='\n'; |
| 2517 | 2518 | }else{ |
| 2518 | 2519 | if( !seenText && !inTitle ) blob_append_char(pOut, '\n'); |
| 2519 | 2520 | seenText = 1; |
| 2520 | 2521 | 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 | + } | |
| 2522 | 2537 | } |
| 2523 | 2538 | }else{ |
| 2524 | 2539 | if( !seenText && !inTitle ) blob_append_char(pOut, '\n'); |
| 2525 | 2540 | seenText = 1; |
| 2526 | 2541 | nNL = nWS = 0; |
| 2527 | 2542 |
| --- 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, '&', "&" }, |
| 2501 | { 4, '<', "<" }, |
| 2502 | { 4, '>', ">" }, |
| 2503 | { 6, ' ', " " }, |
| 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, '&', "&" }, |
| 2501 | { 4, '<', "<" }, |
| 2502 | { 4, '>', ">" }, |
| 2503 | { 6, ' ', " " }, |
| 2504 | { 6, '"', """ }, |
| 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 |