Fossil SCM

Merge the diff enhancements into trunk.

drh 2011-10-21 21:34 trunk merge
Commit c24460586287cba2e65c51101be73eb5cac4488d
+207 -10
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
2121
#include "config.h"
2222
#include "diff.h"
2323
#include <assert.h>
2424
2525
26
+#if INTERFACE
27
+/*
28
+** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29
+*/
30
+#define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31
+#define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32
+#define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33
+#define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34
+#define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
35
+
36
+#endif /* INTERFACE */
37
+
2638
/*
2739
** Maximum length of a line in a text file. (8192)
2840
*/
2941
#define LENGTH_MASK_SZ 13
3042
#define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,176 @@
285297
for(j=0; j<m; j++){
286298
appendDiffLine(pOut, " ", &B[b+j]);
287299
}
288300
}
289301
}
302
+
303
+/*
304
+** Append spaces to a blob
305
+*/
306
+static void appendSpace(Blob *pOut, int n){
307
+ const char z100[101] =
308
+ " "
309
+ " ";
310
+ while( n>100 ){
311
+ blob_append(pOut, z100, 100); n -= 100;
312
+ }
313
+ if( n>0 ){
314
+ blob_append(pOut, z100, n);
315
+ }
316
+}
317
+
318
+/*
319
+** Append text to a sbs diff output
320
+*/
321
+static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){
322
+ int sz = pLine->h & LENGTH_MASK;
323
+ if( sz<width ){
324
+ blob_append(pOut, pLine->z, sz);
325
+ if( pad ) appendSpace(pOut, width-sz);
326
+ }else{
327
+ blob_append(pOut, pLine->z, width);
328
+ }
329
+}
330
+
331
+
332
+/*
333
+** Given a diff context in which the aEdit[] array has been filled
334
+** in, compute a side-by-side diff into pOut.
335
+*/
336
+static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
337
+ DLine *A; /* Left side of the diff */
338
+ DLine *B; /* Right side of the diff */
339
+ int a = 0; /* Index of next line in A[] */
340
+ int b = 0; /* Index of next line in B[] */
341
+ int *R; /* Array of COPY/DELETE/INSERT triples */
342
+ int r; /* Index into R[] */
343
+ int nr; /* Number of COPY/DELETE/INSERT triples to process */
344
+ int mxr; /* Maximum value for r */
345
+ int na, nb; /* Number of lines shown from A and B */
346
+ int i, j; /* Loop counters */
347
+ int m, ma, mb;/* Number of lines to output */
348
+ int skip; /* Number of lines to skip */
349
+ char zFormat[50]; /* Output format */
350
+
351
+ sqlite3_snprintf(sizeof(zFormat), zFormat,
352
+ "%%4d %%%d.%ds %%c %%4d %%.%ds\n",
353
+ width, width, width);
354
+ A = p->aFrom;
355
+ B = p->aTo;
356
+ R = p->aEdit;
357
+ mxr = p->nEdit;
358
+ while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
359
+ for(r=0; r<mxr; r += 3*nr){
360
+ /* Figure out how many triples to show in a single block */
361
+ for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
362
+ /* printf("r=%d nr=%d\n", r, nr); */
363
+
364
+ /* For the current block comprising nr triples, figure out
365
+ ** how many lines of A and B are to be displayed
366
+ */
367
+ if( R[r]>nContext ){
368
+ na = nb = nContext;
369
+ skip = R[r] - nContext;
370
+ }else{
371
+ na = nb = R[r];
372
+ skip = 0;
373
+ }
374
+ for(i=0; i<nr; i++){
375
+ na += R[r+i*3+1];
376
+ nb += R[r+i*3+2];
377
+ }
378
+ if( R[r+nr*3]>nContext ){
379
+ na += nContext;
380
+ nb += nContext;
381
+ }else{
382
+ na += R[r+nr*3];
383
+ nb += R[r+nr*3];
384
+ }
385
+ for(i=1; i<nr; i++){
386
+ na += R[r+i*3];
387
+ nb += R[r+i*3];
388
+ }
389
+ /*
390
+ * If the patch changes an empty file or results in an empty file,
391
+ * the block header must use 0,0 as position indicator and not 1,0.
392
+ * Otherwise, patch would be confused and may reject the diff.
393
+ */
394
+ blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n",
395
+ na ? a+skip+1 : 0, na,
396
+ nb ? b+skip+1 : 0, nb);
397
+
398
+ /* Show the initial common area */
399
+ a += skip;
400
+ b += skip;
401
+ m = R[r] - skip;
402
+ for(j=0; j<m; j++){
403
+ blob_appendf(pOut, "%6d ", a+j);
404
+ appendSbsLine(pOut, &A[a+j], width, 1);
405
+ blob_appendf(pOut, " %6d ", b+j);
406
+ appendSbsLine(pOut, &B[b+j], width, 0);
407
+ blob_append(pOut, "\n", 1);
408
+ }
409
+ a += m;
410
+ b += m;
411
+
412
+ /* Show the differences */
413
+ for(i=0; i<nr; i++){
414
+ ma = R[r+i*3+1];
415
+ mb = R[r+i*3+2];
416
+ m = ma<mb ? ma : mb;
417
+ for(j=0; j<m; j++){
418
+ blob_appendf(pOut, "%6d ", a+j);
419
+ appendSbsLine(pOut, &A[a+j], width, 1);
420
+ blob_appendf(pOut, " | %6d ", b+j);
421
+ appendSbsLine(pOut, &B[b+j], width, 0);
422
+ blob_append(pOut, "\n", 1);
423
+ }
424
+ a += m;
425
+ b += m;
426
+ ma -= m;
427
+ mb -= m;
428
+ for(j=0; j<ma; j++){
429
+ blob_appendf(pOut, "%6d ", a+j);
430
+ appendSbsLine(pOut, &A[a+j], width, 1);
431
+ blob_append(pOut, " <\n", 3);
432
+ }
433
+ a += ma;
434
+ for(j=0; j<mb; j++){
435
+ appendSpace(pOut, width+7);
436
+ blob_appendf(pOut, " > %6d", b+j);
437
+ appendSbsLine(pOut, &B[b+j], width, 0);
438
+ blob_append(pOut, "\n", 1);
439
+ }
440
+ b += mb;
441
+ if( i<nr-1 ){
442
+ m = R[r+i*3+3];
443
+ for(j=0; j<m; j++){
444
+ blob_appendf(pOut, "%6d ", a+j);
445
+ appendSbsLine(pOut, &A[a+j], width, 1);
446
+ blob_appendf(pOut, " %6d ", b+j);
447
+ appendSbsLine(pOut, &B[b+j], width, 0);
448
+ blob_append(pOut, "\n", 1);
449
+ }
450
+ b += m;
451
+ a += m;
452
+ }
453
+ }
454
+
455
+ /* Show the final common area */
456
+ assert( nr==i );
457
+ m = R[r+nr*3];
458
+ if( m>nContext ) m = nContext;
459
+ for(j=0; j<m; j++){
460
+ blob_appendf(pOut, "%6d ", a+j);
461
+ appendSbsLine(pOut, &A[a+j], width, 1);
462
+ blob_appendf(pOut, " %6d ", b+j);
463
+ appendSbsLine(pOut, &B[b+j], width, 0);
464
+ blob_append(pOut, "\n", 1);
465
+ }
466
+ }
467
+}
290468
291469
/*
292470
** Compute the optimal longest common subsequence (LCS) using an
293471
** exhaustive search. This version of the LCS is only used for
294472
** shorter input strings since runtime is O(N*N) where N is the
@@ -538,16 +716,21 @@
538716
** text "cannot compute difference between binary files".
539717
*/
540718
int *text_diff(
541719
Blob *pA_Blob, /* FROM file */
542720
Blob *pB_Blob, /* TO file */
543
- Blob *pOut, /* Write unified diff here if not NULL */
544
- int nContext, /* Amount of context to unified diff */
545
- int ignoreEolWs /* Ignore whitespace at the end of lines */
721
+ Blob *pOut, /* Write diff here if not NULL */
722
+ int diffFlags /* DIFF_* flags defined above */
546723
){
724
+ int ignoreEolWs; /* Ignore whitespace at the end of lines */
725
+ int nContext; /* Amount of context to display */
547726
DContext c;
548
-
727
+
728
+ nContext = diffFlags & DIFF_CONTEXT_MASK;
729
+ if( nContext==0 ) nContext = 5;
730
+ ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
731
+
549732
/* Prepare the input files */
550733
memset(&c, 0, sizeof(c));
551734
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
552735
&c.nFrom, ignoreEolWs);
553736
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +746,18 @@
563746
564747
/* Compute the difference */
565748
diff_all(&c);
566749
567750
if( pOut ){
568
- /* Compute a context diff if requested */
569
- contextDiff(&c, pOut, nContext);
751
+ /* Compute a context or side-by-side diff into pOut */
752
+ if( diffFlags & DIFF_SIDEBYSIDE ){
753
+ int width = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
754
+ if( width==0 ) width = 80;
755
+ sbsDiff(&c, pOut, nContext, width);
756
+ }else{
757
+ contextDiff(&c, pOut, nContext);
758
+ }
570759
free(c.aFrom);
571760
free(c.aTo);
572761
free(c.aEdit);
573762
return 0;
574763
}else{
@@ -660,11 +849,11 @@
660849
while( i<c.nEdit ){
661850
int j;
662851
/* Copied lines */
663852
for( j=0; j<c.aEdit[i]; j++){
664853
/* Hide lines which are copied and are further away from block boundaries
665
- ** than nConext lines. For each block with hidden lines, show a row
854
+ ** than nContext lines. For each block with hidden lines, show a row
666855
** notifying the user about the hidden rows.
667856
*/
668857
if( j<nContext || j>c.aEdit[i]-nContext-1 ){
669858
@ <tr>
670859
}else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,11 +965,11 @@
776965
if( g.argc<4 ) usage("FILE1 FILE2 ...");
777966
blob_read_from_file(&a, g.argv[2]);
778967
for(i=3; i<g.argc; i++){
779968
if( i>3 ) fossil_print("-------------------------------\n");
780969
blob_read_from_file(&b, g.argv[i]);
781
- R = text_diff(&a, &b, 0, 0, 0);
970
+ R = text_diff(&a, &b, 0, 0);
782971
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
783972
fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
784973
}
785974
/* free(R); */
786975
blob_reset(&b);
@@ -790,15 +979,23 @@
790979
/*
791980
** COMMAND: test-udiff
792981
*/
793982
void test_udiff_cmd(void){
794983
Blob a, b, out;
795
- if( g.argc!=4 ) usage("FILE1 FILE2");
984
+ int diffFlag = find_option("sbs",0,0)!=0 ? DIFF_SIDEBYSIDE : 0;
985
+ int nContext = 5;
986
+ const char *z;
987
+ if( (z = find_option("context","c",1))!=0 && atoi(z)>0 ){
988
+ nContext = atoi(z);
989
+ }
990
+ if( nContext<=0 ) nContext = 5;
991
+ if( (nContext&DIFF_CONTEXT_MASK)!=nContext ) nContext = DIFF_CONTEXT_MASK;
992
+ if( g.argc!=4 ) usage("[--sbs] [--context N] FILE1 FILE2");
796993
blob_read_from_file(&a, g.argv[2]);
797994
blob_read_from_file(&b, g.argv[3]);
798995
blob_zero(&out);
799
- text_diff(&a, &b, &out, 3, 0);
996
+ text_diff(&a, &b, &out, nContext | diffFlag);
800997
blob_write_to_file(&out, "-");
801998
}
802999
8031000
/**************************************************************************
8041001
** The basic difference engine is above. What follows is the annotation
8051002
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
21 #include "config.h"
22 #include "diff.h"
23 #include <assert.h>
24
25
 
 
 
 
 
 
 
 
 
 
 
 
26 /*
27 ** Maximum length of a line in a text file. (8192)
28 */
29 #define LENGTH_MASK_SZ 13
30 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,176 @@
285 for(j=0; j<m; j++){
286 appendDiffLine(pOut, " ", &B[b+j]);
287 }
288 }
289 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
291 /*
292 ** Compute the optimal longest common subsequence (LCS) using an
293 ** exhaustive search. This version of the LCS is only used for
294 ** shorter input strings since runtime is O(N*N) where N is the
@@ -538,16 +716,21 @@
538 ** text "cannot compute difference between binary files".
539 */
540 int *text_diff(
541 Blob *pA_Blob, /* FROM file */
542 Blob *pB_Blob, /* TO file */
543 Blob *pOut, /* Write unified diff here if not NULL */
544 int nContext, /* Amount of context to unified diff */
545 int ignoreEolWs /* Ignore whitespace at the end of lines */
546 ){
 
 
547 DContext c;
548
 
 
 
 
549 /* Prepare the input files */
550 memset(&c, 0, sizeof(c));
551 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
552 &c.nFrom, ignoreEolWs);
553 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +746,18 @@
563
564 /* Compute the difference */
565 diff_all(&c);
566
567 if( pOut ){
568 /* Compute a context diff if requested */
569 contextDiff(&c, pOut, nContext);
 
 
 
 
 
 
570 free(c.aFrom);
571 free(c.aTo);
572 free(c.aEdit);
573 return 0;
574 }else{
@@ -660,11 +849,11 @@
660 while( i<c.nEdit ){
661 int j;
662 /* Copied lines */
663 for( j=0; j<c.aEdit[i]; j++){
664 /* Hide lines which are copied and are further away from block boundaries
665 ** than nConext lines. For each block with hidden lines, show a row
666 ** notifying the user about the hidden rows.
667 */
668 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
669 @ <tr>
670 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,11 +965,11 @@
776 if( g.argc<4 ) usage("FILE1 FILE2 ...");
777 blob_read_from_file(&a, g.argv[2]);
778 for(i=3; i<g.argc; i++){
779 if( i>3 ) fossil_print("-------------------------------\n");
780 blob_read_from_file(&b, g.argv[i]);
781 R = text_diff(&a, &b, 0, 0, 0);
782 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
783 fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
784 }
785 /* free(R); */
786 blob_reset(&b);
@@ -790,15 +979,23 @@
790 /*
791 ** COMMAND: test-udiff
792 */
793 void test_udiff_cmd(void){
794 Blob a, b, out;
795 if( g.argc!=4 ) usage("FILE1 FILE2");
 
 
 
 
 
 
 
 
796 blob_read_from_file(&a, g.argv[2]);
797 blob_read_from_file(&b, g.argv[3]);
798 blob_zero(&out);
799 text_diff(&a, &b, &out, 3, 0);
800 blob_write_to_file(&out, "-");
801 }
802
803 /**************************************************************************
804 ** The basic difference engine is above. What follows is the annotation
805
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
21 #include "config.h"
22 #include "diff.h"
23 #include <assert.h>
24
25
26 #if INTERFACE
27 /*
28 ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29 */
30 #define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31 #define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32 #define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33 #define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34 #define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
35
36 #endif /* INTERFACE */
37
38 /*
39 ** Maximum length of a line in a text file. (8192)
40 */
41 #define LENGTH_MASK_SZ 13
42 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,176 @@
297 for(j=0; j<m; j++){
298 appendDiffLine(pOut, " ", &B[b+j]);
299 }
300 }
301 }
302
303 /*
304 ** Append spaces to a blob
305 */
306 static void appendSpace(Blob *pOut, int n){
307 const char z100[101] =
308 " "
309 " ";
310 while( n>100 ){
311 blob_append(pOut, z100, 100); n -= 100;
312 }
313 if( n>0 ){
314 blob_append(pOut, z100, n);
315 }
316 }
317
318 /*
319 ** Append text to a sbs diff output
320 */
321 static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){
322 int sz = pLine->h & LENGTH_MASK;
323 if( sz<width ){
324 blob_append(pOut, pLine->z, sz);
325 if( pad ) appendSpace(pOut, width-sz);
326 }else{
327 blob_append(pOut, pLine->z, width);
328 }
329 }
330
331
332 /*
333 ** Given a diff context in which the aEdit[] array has been filled
334 ** in, compute a side-by-side diff into pOut.
335 */
336 static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
337 DLine *A; /* Left side of the diff */
338 DLine *B; /* Right side of the diff */
339 int a = 0; /* Index of next line in A[] */
340 int b = 0; /* Index of next line in B[] */
341 int *R; /* Array of COPY/DELETE/INSERT triples */
342 int r; /* Index into R[] */
343 int nr; /* Number of COPY/DELETE/INSERT triples to process */
344 int mxr; /* Maximum value for r */
345 int na, nb; /* Number of lines shown from A and B */
346 int i, j; /* Loop counters */
347 int m, ma, mb;/* Number of lines to output */
348 int skip; /* Number of lines to skip */
349 char zFormat[50]; /* Output format */
350
351 sqlite3_snprintf(sizeof(zFormat), zFormat,
352 "%%4d %%%d.%ds %%c %%4d %%.%ds\n",
353 width, width, width);
354 A = p->aFrom;
355 B = p->aTo;
356 R = p->aEdit;
357 mxr = p->nEdit;
358 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
359 for(r=0; r<mxr; r += 3*nr){
360 /* Figure out how many triples to show in a single block */
361 for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
362 /* printf("r=%d nr=%d\n", r, nr); */
363
364 /* For the current block comprising nr triples, figure out
365 ** how many lines of A and B are to be displayed
366 */
367 if( R[r]>nContext ){
368 na = nb = nContext;
369 skip = R[r] - nContext;
370 }else{
371 na = nb = R[r];
372 skip = 0;
373 }
374 for(i=0; i<nr; i++){
375 na += R[r+i*3+1];
376 nb += R[r+i*3+2];
377 }
378 if( R[r+nr*3]>nContext ){
379 na += nContext;
380 nb += nContext;
381 }else{
382 na += R[r+nr*3];
383 nb += R[r+nr*3];
384 }
385 for(i=1; i<nr; i++){
386 na += R[r+i*3];
387 nb += R[r+i*3];
388 }
389 /*
390 * If the patch changes an empty file or results in an empty file,
391 * the block header must use 0,0 as position indicator and not 1,0.
392 * Otherwise, patch would be confused and may reject the diff.
393 */
394 blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n",
395 na ? a+skip+1 : 0, na,
396 nb ? b+skip+1 : 0, nb);
397
398 /* Show the initial common area */
399 a += skip;
400 b += skip;
401 m = R[r] - skip;
402 for(j=0; j<m; j++){
403 blob_appendf(pOut, "%6d ", a+j);
404 appendSbsLine(pOut, &A[a+j], width, 1);
405 blob_appendf(pOut, " %6d ", b+j);
406 appendSbsLine(pOut, &B[b+j], width, 0);
407 blob_append(pOut, "\n", 1);
408 }
409 a += m;
410 b += m;
411
412 /* Show the differences */
413 for(i=0; i<nr; i++){
414 ma = R[r+i*3+1];
415 mb = R[r+i*3+2];
416 m = ma<mb ? ma : mb;
417 for(j=0; j<m; j++){
418 blob_appendf(pOut, "%6d ", a+j);
419 appendSbsLine(pOut, &A[a+j], width, 1);
420 blob_appendf(pOut, " | %6d ", b+j);
421 appendSbsLine(pOut, &B[b+j], width, 0);
422 blob_append(pOut, "\n", 1);
423 }
424 a += m;
425 b += m;
426 ma -= m;
427 mb -= m;
428 for(j=0; j<ma; j++){
429 blob_appendf(pOut, "%6d ", a+j);
430 appendSbsLine(pOut, &A[a+j], width, 1);
431 blob_append(pOut, " <\n", 3);
432 }
433 a += ma;
434 for(j=0; j<mb; j++){
435 appendSpace(pOut, width+7);
436 blob_appendf(pOut, " > %6d", b+j);
437 appendSbsLine(pOut, &B[b+j], width, 0);
438 blob_append(pOut, "\n", 1);
439 }
440 b += mb;
441 if( i<nr-1 ){
442 m = R[r+i*3+3];
443 for(j=0; j<m; j++){
444 blob_appendf(pOut, "%6d ", a+j);
445 appendSbsLine(pOut, &A[a+j], width, 1);
446 blob_appendf(pOut, " %6d ", b+j);
447 appendSbsLine(pOut, &B[b+j], width, 0);
448 blob_append(pOut, "\n", 1);
449 }
450 b += m;
451 a += m;
452 }
453 }
454
455 /* Show the final common area */
456 assert( nr==i );
457 m = R[r+nr*3];
458 if( m>nContext ) m = nContext;
459 for(j=0; j<m; j++){
460 blob_appendf(pOut, "%6d ", a+j);
461 appendSbsLine(pOut, &A[a+j], width, 1);
462 blob_appendf(pOut, " %6d ", b+j);
463 appendSbsLine(pOut, &B[b+j], width, 0);
464 blob_append(pOut, "\n", 1);
465 }
466 }
467 }
468
469 /*
470 ** Compute the optimal longest common subsequence (LCS) using an
471 ** exhaustive search. This version of the LCS is only used for
472 ** shorter input strings since runtime is O(N*N) where N is the
@@ -538,16 +716,21 @@
716 ** text "cannot compute difference between binary files".
717 */
718 int *text_diff(
719 Blob *pA_Blob, /* FROM file */
720 Blob *pB_Blob, /* TO file */
721 Blob *pOut, /* Write diff here if not NULL */
722 int diffFlags /* DIFF_* flags defined above */
 
723 ){
724 int ignoreEolWs; /* Ignore whitespace at the end of lines */
725 int nContext; /* Amount of context to display */
726 DContext c;
727
728 nContext = diffFlags & DIFF_CONTEXT_MASK;
729 if( nContext==0 ) nContext = 5;
730 ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
731
732 /* Prepare the input files */
733 memset(&c, 0, sizeof(c));
734 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
735 &c.nFrom, ignoreEolWs);
736 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +746,18 @@
746
747 /* Compute the difference */
748 diff_all(&c);
749
750 if( pOut ){
751 /* Compute a context or side-by-side diff into pOut */
752 if( diffFlags & DIFF_SIDEBYSIDE ){
753 int width = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
754 if( width==0 ) width = 80;
755 sbsDiff(&c, pOut, nContext, width);
756 }else{
757 contextDiff(&c, pOut, nContext);
758 }
759 free(c.aFrom);
760 free(c.aTo);
761 free(c.aEdit);
762 return 0;
763 }else{
@@ -660,11 +849,11 @@
849 while( i<c.nEdit ){
850 int j;
851 /* Copied lines */
852 for( j=0; j<c.aEdit[i]; j++){
853 /* Hide lines which are copied and are further away from block boundaries
854 ** than nContext lines. For each block with hidden lines, show a row
855 ** notifying the user about the hidden rows.
856 */
857 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
858 @ <tr>
859 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,11 +965,11 @@
965 if( g.argc<4 ) usage("FILE1 FILE2 ...");
966 blob_read_from_file(&a, g.argv[2]);
967 for(i=3; i<g.argc; i++){
968 if( i>3 ) fossil_print("-------------------------------\n");
969 blob_read_from_file(&b, g.argv[i]);
970 R = text_diff(&a, &b, 0, 0);
971 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
972 fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
973 }
974 /* free(R); */
975 blob_reset(&b);
@@ -790,15 +979,23 @@
979 /*
980 ** COMMAND: test-udiff
981 */
982 void test_udiff_cmd(void){
983 Blob a, b, out;
984 int diffFlag = find_option("sbs",0,0)!=0 ? DIFF_SIDEBYSIDE : 0;
985 int nContext = 5;
986 const char *z;
987 if( (z = find_option("context","c",1))!=0 && atoi(z)>0 ){
988 nContext = atoi(z);
989 }
990 if( nContext<=0 ) nContext = 5;
991 if( (nContext&DIFF_CONTEXT_MASK)!=nContext ) nContext = DIFF_CONTEXT_MASK;
992 if( g.argc!=4 ) usage("[--sbs] [--context N] FILE1 FILE2");
993 blob_read_from_file(&a, g.argv[2]);
994 blob_read_from_file(&b, g.argv[3]);
995 blob_zero(&out);
996 text_diff(&a, &b, &out, nContext | diffFlag);
997 blob_write_to_file(&out, "-");
998 }
999
1000 /**************************************************************************
1001 ** The basic difference engine is above. What follows is the annotation
1002
+28 -23
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
1919
*/
2020
#include "config.h"
2121
#include "diffcmd.h"
2222
#include <assert.h>
2323
24
-/*
25
-** Diff option flags
26
-*/
27
-#define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */
28
-#define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */
29
-
3024
/*
3125
** Output the results of a diff. Output goes to stdout for command-line
3226
** or to the CGI/HTTP result buffer for web pages.
3327
*/
3428
static void diff_printf(const char *zFormat, ...){
@@ -62,11 +56,11 @@
6256
void diff_file(
6357
Blob *pFile1, /* In memory content to compare from */
6458
const char *zFile2, /* On disk content to compare to */
6559
const char *zName, /* Display name of the file */
6660
const char *zDiffCmd, /* Command for comparison */
67
- int ignoreEolWs /* Ignore whitespace at end of line */
61
+ int diffFlags /* Flags to control the diff */
6862
){
6963
if( zDiffCmd==0 ){
7064
Blob out; /* Diff output text */
7165
Blob file2; /* Content of zFile2 */
7266
const char *zName2; /* Name of zFile2 for display */
@@ -84,11 +78,11 @@
8478
zName2 = zName;
8579
}
8680
8781
/* Compute and output the differences */
8882
blob_zero(&out);
89
- text_diff(pFile1, &file2, &out, 5, ignoreEolWs);
83
+ text_diff(pFile1, &file2, &out, diffFlags);
9084
if( blob_size(&out) ){
9185
diff_printf("--- %s\n+++ %s\n", zName, zName2);
9286
diff_printf("%s\n", blob_str(&out));
9387
}
9488
@@ -138,17 +132,17 @@
138132
void diff_file_mem(
139133
Blob *pFile1, /* In memory content to compare from */
140134
Blob *pFile2, /* In memory content to compare to */
141135
const char *zName, /* Display name of the file */
142136
const char *zDiffCmd, /* Command for comparison */
143
- int ignoreEolWs /* Ignore whitespace at end of lines */
137
+ int diffFlags /* Diff flags */
144138
){
145139
if( zDiffCmd==0 ){
146140
Blob out; /* Diff output text */
147141
148142
blob_zero(&out);
149
- text_diff(pFile1, pFile2, &out, 5, ignoreEolWs);
143
+ text_diff(pFile1, pFile2, &out, diffFlags);
150144
diff_printf("--- %s\n+++ %s\n", zName, zName);
151145
diff_printf("%s\n", blob_str(&out));
152146
153147
/* Release memory resources */
154148
blob_reset(&out);
@@ -185,11 +179,11 @@
185179
** against the same file on disk.
186180
*/
187181
static void diff_one_against_disk(
188182
const char *zFrom, /* Name of file */
189183
const char *zDiffCmd, /* Use this "diff" command */
190
- int ignoreEolWs, /* Ignore whitespace changes at end of lines */
184
+ int diffFlags, /* Diff control flags */
191185
const char *zFileTreeName
192186
){
193187
Blob fname;
194188
Blob content;
195189
int isLink;
@@ -196,11 +190,11 @@
196190
file_tree_name(zFileTreeName, &fname, 1);
197191
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
198192
if( !isLink != !file_wd_islink(zFrom) ){
199193
diff_printf("cannot compute difference between symlink and regular file\n");
200194
}else{
201
- diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs);
195
+ diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
202196
}
203197
blob_reset(&content);
204198
blob_reset(&fname);
205199
}
206200
@@ -215,14 +209,12 @@
215209
int diffFlags /* Flags controlling diff output */
216210
){
217211
int vid;
218212
Blob sql;
219213
Stmt q;
220
- int ignoreEolWs; /* Ignore end-of-line whitespace */
221214
int asNewFile; /* Treat non-existant files as empty files */
222215
223
- ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0;
224216
asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
225217
vid = db_lget_int("checkout", 0);
226218
vfile_check_signature(vid, 1, 0);
227219
blob_zero(&sql);
228220
db_begin_transaction();
@@ -300,11 +292,11 @@
300292
content_get(srcid, &content);
301293
}else{
302294
blob_zero(&content);
303295
}
304296
diff_print_index(zPathname);
305
- diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs);
297
+ diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags);
306298
blob_reset(&content);
307299
}
308300
free(zToFree);
309301
}
310302
db_finalize(&q);
@@ -317,11 +309,11 @@
317309
*/
318310
static void diff_one_two_versions(
319311
const char *zFrom,
320312
const char *zTo,
321313
const char *zDiffCmd,
322
- int ignoreEolWs,
314
+ int diffFlags,
323315
const char *zFileTreeName
324316
){
325317
char *zName;
326318
Blob fname;
327319
Blob v1, v2;
@@ -332,11 +324,11 @@
332324
historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
333325
if( isLink1 != isLink2 ){
334326
diff_printf("--- %s\n+++ %s\n", zName, zName);
335327
diff_printf("cannot compute difference between symlink and regular file\n");
336328
}else{
337
- diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs);
329
+ diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
338330
}
339331
blob_reset(&v1);
340332
blob_reset(&v2);
341333
blob_reset(&fname);
342334
}
@@ -347,11 +339,11 @@
347339
*/
348340
static void diff_manifest_entry(
349341
struct ManifestFile *pFrom,
350342
struct ManifestFile *pTo,
351343
const char *zDiffCmd,
352
- int ignoreEolWs
344
+ int diffFlags
353345
){
354346
Blob f1, f2;
355347
int rid;
356348
const char *zName = pFrom ? pFrom->zName : pTo->zName;
357349
diff_print_index(zName);
@@ -365,11 +357,11 @@
365357
rid = uuid_to_rid(pTo->zUuid, 0);
366358
content_get(rid, &f2);
367359
}else{
368360
blob_zero(&f2);
369361
}
370
- diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs);
362
+ diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags);
371363
blob_reset(&f1);
372364
blob_reset(&f2);
373365
}
374366
375367
/*
@@ -381,11 +373,10 @@
381373
const char *zDiffCmd,
382374
int diffFlags
383375
){
384376
Manifest *pFrom, *pTo;
385377
ManifestFile *pFromFile, *pToFile;
386
- int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
387378
int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
388379
389380
pFrom = manifest_get_by_name(zFrom, 0);
390381
manifest_file_rewind(pFrom);
391382
pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +394,26 @@
403394
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
404395
}
405396
if( cmp<0 ){
406397
diff_printf("DELETED %s\n", pFromFile->zName);
407398
if( asNewFlag ){
408
- diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs);
399
+ diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
409400
}
410401
pFromFile = manifest_file_next(pFrom,0);
411402
}else if( cmp>0 ){
412403
diff_printf("ADDED %s\n", pToFile->zName);
413404
if( asNewFlag ){
414
- diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs);
405
+ diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
415406
}
416407
pToFile = manifest_file_next(pTo,0);
417408
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
418409
/* No changes */
419410
pFromFile = manifest_file_next(pFrom,0);
420411
pToFile = manifest_file_next(pTo,0);
421412
}else{
422413
/* diff_printf("CHANGED %s\n", pFromFile->zName); */
423
- diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs);
414
+ diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
424415
pFromFile = manifest_file_next(pFrom,0);
425416
pToFile = manifest_file_next(pTo,0);
426417
}
427418
}
428419
manifest_destroy(pFrom);
@@ -456,30 +447,44 @@
456447
**
457448
** The "-N" or "--new-file" option causes the complete text of added or
458449
** deleted files to be displayed.
459450
**
460451
** Options:
452
+** --context|-c N Use N lines of context
461453
** --from|-r VERSION select VERSION as source for the diff
462454
** --new-file|-N output complete text of added or deleted files
463455
** -i use internal diff logic
464456
** --to VERSION select VERSION as target for the diff
457
+** --side-by-side|-y side-by-side diff
458
+** --width|-W N Width of lines in side-by-side diff
465459
*/
466460
void diff_cmd(void){
467461
int isGDiff; /* True for gdiff. False for normal diff */
468462
int isInternDiff; /* True for internal diff */
469463
int hasNFlag; /* True if -N or --new-file flag is used */
470464
const char *zFrom; /* Source version number */
471465
const char *zTo; /* Target version number */
472466
const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
473467
int diffFlags = 0; /* Flags to control the DIFF */
468
+ const char *z;
474469
int f;
475470
476471
isGDiff = g.argv[1][0]=='g';
477472
isInternDiff = find_option("internal","i",0)!=0;
478473
zFrom = find_option("from", "r", 1);
479474
zTo = find_option("to", 0, 1);
480475
hasNFlag = find_option("new-file","N",0)!=0;
476
+ if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
477
+ if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){
478
+ if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;
479
+ diffFlags |= f;
480
+ }
481
+ if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
482
+ f *= DIFF_CONTEXT_MASK+1;
483
+ if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
484
+ diffFlags |= f;
485
+ }
481486
482487
483488
if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
484489
if( zTo==0 ){
485490
db_must_be_within_tree();
486491
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
24 /*
25 ** Diff option flags
26 */
27 #define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */
28 #define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */
29
30 /*
31 ** Output the results of a diff. Output goes to stdout for command-line
32 ** or to the CGI/HTTP result buffer for web pages.
33 */
34 static void diff_printf(const char *zFormat, ...){
@@ -62,11 +56,11 @@
62 void diff_file(
63 Blob *pFile1, /* In memory content to compare from */
64 const char *zFile2, /* On disk content to compare to */
65 const char *zName, /* Display name of the file */
66 const char *zDiffCmd, /* Command for comparison */
67 int ignoreEolWs /* Ignore whitespace at end of line */
68 ){
69 if( zDiffCmd==0 ){
70 Blob out; /* Diff output text */
71 Blob file2; /* Content of zFile2 */
72 const char *zName2; /* Name of zFile2 for display */
@@ -84,11 +78,11 @@
84 zName2 = zName;
85 }
86
87 /* Compute and output the differences */
88 blob_zero(&out);
89 text_diff(pFile1, &file2, &out, 5, ignoreEolWs);
90 if( blob_size(&out) ){
91 diff_printf("--- %s\n+++ %s\n", zName, zName2);
92 diff_printf("%s\n", blob_str(&out));
93 }
94
@@ -138,17 +132,17 @@
138 void diff_file_mem(
139 Blob *pFile1, /* In memory content to compare from */
140 Blob *pFile2, /* In memory content to compare to */
141 const char *zName, /* Display name of the file */
142 const char *zDiffCmd, /* Command for comparison */
143 int ignoreEolWs /* Ignore whitespace at end of lines */
144 ){
145 if( zDiffCmd==0 ){
146 Blob out; /* Diff output text */
147
148 blob_zero(&out);
149 text_diff(pFile1, pFile2, &out, 5, ignoreEolWs);
150 diff_printf("--- %s\n+++ %s\n", zName, zName);
151 diff_printf("%s\n", blob_str(&out));
152
153 /* Release memory resources */
154 blob_reset(&out);
@@ -185,11 +179,11 @@
185 ** against the same file on disk.
186 */
187 static void diff_one_against_disk(
188 const char *zFrom, /* Name of file */
189 const char *zDiffCmd, /* Use this "diff" command */
190 int ignoreEolWs, /* Ignore whitespace changes at end of lines */
191 const char *zFileTreeName
192 ){
193 Blob fname;
194 Blob content;
195 int isLink;
@@ -196,11 +190,11 @@
196 file_tree_name(zFileTreeName, &fname, 1);
197 historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
198 if( !isLink != !file_wd_islink(zFrom) ){
199 diff_printf("cannot compute difference between symlink and regular file\n");
200 }else{
201 diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs);
202 }
203 blob_reset(&content);
204 blob_reset(&fname);
205 }
206
@@ -215,14 +209,12 @@
215 int diffFlags /* Flags controlling diff output */
216 ){
217 int vid;
218 Blob sql;
219 Stmt q;
220 int ignoreEolWs; /* Ignore end-of-line whitespace */
221 int asNewFile; /* Treat non-existant files as empty files */
222
223 ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0;
224 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
225 vid = db_lget_int("checkout", 0);
226 vfile_check_signature(vid, 1, 0);
227 blob_zero(&sql);
228 db_begin_transaction();
@@ -300,11 +292,11 @@
300 content_get(srcid, &content);
301 }else{
302 blob_zero(&content);
303 }
304 diff_print_index(zPathname);
305 diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs);
306 blob_reset(&content);
307 }
308 free(zToFree);
309 }
310 db_finalize(&q);
@@ -317,11 +309,11 @@
317 */
318 static void diff_one_two_versions(
319 const char *zFrom,
320 const char *zTo,
321 const char *zDiffCmd,
322 int ignoreEolWs,
323 const char *zFileTreeName
324 ){
325 char *zName;
326 Blob fname;
327 Blob v1, v2;
@@ -332,11 +324,11 @@
332 historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
333 if( isLink1 != isLink2 ){
334 diff_printf("--- %s\n+++ %s\n", zName, zName);
335 diff_printf("cannot compute difference between symlink and regular file\n");
336 }else{
337 diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs);
338 }
339 blob_reset(&v1);
340 blob_reset(&v2);
341 blob_reset(&fname);
342 }
@@ -347,11 +339,11 @@
347 */
348 static void diff_manifest_entry(
349 struct ManifestFile *pFrom,
350 struct ManifestFile *pTo,
351 const char *zDiffCmd,
352 int ignoreEolWs
353 ){
354 Blob f1, f2;
355 int rid;
356 const char *zName = pFrom ? pFrom->zName : pTo->zName;
357 diff_print_index(zName);
@@ -365,11 +357,11 @@
365 rid = uuid_to_rid(pTo->zUuid, 0);
366 content_get(rid, &f2);
367 }else{
368 blob_zero(&f2);
369 }
370 diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs);
371 blob_reset(&f1);
372 blob_reset(&f2);
373 }
374
375 /*
@@ -381,11 +373,10 @@
381 const char *zDiffCmd,
382 int diffFlags
383 ){
384 Manifest *pFrom, *pTo;
385 ManifestFile *pFromFile, *pToFile;
386 int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
387 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
388
389 pFrom = manifest_get_by_name(zFrom, 0);
390 manifest_file_rewind(pFrom);
391 pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +394,26 @@
403 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
404 }
405 if( cmp<0 ){
406 diff_printf("DELETED %s\n", pFromFile->zName);
407 if( asNewFlag ){
408 diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs);
409 }
410 pFromFile = manifest_file_next(pFrom,0);
411 }else if( cmp>0 ){
412 diff_printf("ADDED %s\n", pToFile->zName);
413 if( asNewFlag ){
414 diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs);
415 }
416 pToFile = manifest_file_next(pTo,0);
417 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
418 /* No changes */
419 pFromFile = manifest_file_next(pFrom,0);
420 pToFile = manifest_file_next(pTo,0);
421 }else{
422 /* diff_printf("CHANGED %s\n", pFromFile->zName); */
423 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs);
424 pFromFile = manifest_file_next(pFrom,0);
425 pToFile = manifest_file_next(pTo,0);
426 }
427 }
428 manifest_destroy(pFrom);
@@ -456,30 +447,44 @@
456 **
457 ** The "-N" or "--new-file" option causes the complete text of added or
458 ** deleted files to be displayed.
459 **
460 ** Options:
 
461 ** --from|-r VERSION select VERSION as source for the diff
462 ** --new-file|-N output complete text of added or deleted files
463 ** -i use internal diff logic
464 ** --to VERSION select VERSION as target for the diff
 
 
465 */
466 void diff_cmd(void){
467 int isGDiff; /* True for gdiff. False for normal diff */
468 int isInternDiff; /* True for internal diff */
469 int hasNFlag; /* True if -N or --new-file flag is used */
470 const char *zFrom; /* Source version number */
471 const char *zTo; /* Target version number */
472 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
473 int diffFlags = 0; /* Flags to control the DIFF */
 
474 int f;
475
476 isGDiff = g.argv[1][0]=='g';
477 isInternDiff = find_option("internal","i",0)!=0;
478 zFrom = find_option("from", "r", 1);
479 zTo = find_option("to", 0, 1);
480 hasNFlag = find_option("new-file","N",0)!=0;
 
 
 
 
 
 
 
 
 
 
481
482
483 if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
484 if( zTo==0 ){
485 db_must_be_within_tree();
486
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
 
 
 
 
 
 
24 /*
25 ** Output the results of a diff. Output goes to stdout for command-line
26 ** or to the CGI/HTTP result buffer for web pages.
27 */
28 static void diff_printf(const char *zFormat, ...){
@@ -62,11 +56,11 @@
56 void diff_file(
57 Blob *pFile1, /* In memory content to compare from */
58 const char *zFile2, /* On disk content to compare to */
59 const char *zName, /* Display name of the file */
60 const char *zDiffCmd, /* Command for comparison */
61 int diffFlags /* Flags to control the diff */
62 ){
63 if( zDiffCmd==0 ){
64 Blob out; /* Diff output text */
65 Blob file2; /* Content of zFile2 */
66 const char *zName2; /* Name of zFile2 for display */
@@ -84,11 +78,11 @@
78 zName2 = zName;
79 }
80
81 /* Compute and output the differences */
82 blob_zero(&out);
83 text_diff(pFile1, &file2, &out, diffFlags);
84 if( blob_size(&out) ){
85 diff_printf("--- %s\n+++ %s\n", zName, zName2);
86 diff_printf("%s\n", blob_str(&out));
87 }
88
@@ -138,17 +132,17 @@
132 void diff_file_mem(
133 Blob *pFile1, /* In memory content to compare from */
134 Blob *pFile2, /* In memory content to compare to */
135 const char *zName, /* Display name of the file */
136 const char *zDiffCmd, /* Command for comparison */
137 int diffFlags /* Diff flags */
138 ){
139 if( zDiffCmd==0 ){
140 Blob out; /* Diff output text */
141
142 blob_zero(&out);
143 text_diff(pFile1, pFile2, &out, diffFlags);
144 diff_printf("--- %s\n+++ %s\n", zName, zName);
145 diff_printf("%s\n", blob_str(&out));
146
147 /* Release memory resources */
148 blob_reset(&out);
@@ -185,11 +179,11 @@
179 ** against the same file on disk.
180 */
181 static void diff_one_against_disk(
182 const char *zFrom, /* Name of file */
183 const char *zDiffCmd, /* Use this "diff" command */
184 int diffFlags, /* Diff control flags */
185 const char *zFileTreeName
186 ){
187 Blob fname;
188 Blob content;
189 int isLink;
@@ -196,11 +190,11 @@
190 file_tree_name(zFileTreeName, &fname, 1);
191 historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
192 if( !isLink != !file_wd_islink(zFrom) ){
193 diff_printf("cannot compute difference between symlink and regular file\n");
194 }else{
195 diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
196 }
197 blob_reset(&content);
198 blob_reset(&fname);
199 }
200
@@ -215,14 +209,12 @@
209 int diffFlags /* Flags controlling diff output */
210 ){
211 int vid;
212 Blob sql;
213 Stmt q;
 
214 int asNewFile; /* Treat non-existant files as empty files */
215
 
216 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
217 vid = db_lget_int("checkout", 0);
218 vfile_check_signature(vid, 1, 0);
219 blob_zero(&sql);
220 db_begin_transaction();
@@ -300,11 +292,11 @@
292 content_get(srcid, &content);
293 }else{
294 blob_zero(&content);
295 }
296 diff_print_index(zPathname);
297 diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags);
298 blob_reset(&content);
299 }
300 free(zToFree);
301 }
302 db_finalize(&q);
@@ -317,11 +309,11 @@
309 */
310 static void diff_one_two_versions(
311 const char *zFrom,
312 const char *zTo,
313 const char *zDiffCmd,
314 int diffFlags,
315 const char *zFileTreeName
316 ){
317 char *zName;
318 Blob fname;
319 Blob v1, v2;
@@ -332,11 +324,11 @@
324 historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
325 if( isLink1 != isLink2 ){
326 diff_printf("--- %s\n+++ %s\n", zName, zName);
327 diff_printf("cannot compute difference between symlink and regular file\n");
328 }else{
329 diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
330 }
331 blob_reset(&v1);
332 blob_reset(&v2);
333 blob_reset(&fname);
334 }
@@ -347,11 +339,11 @@
339 */
340 static void diff_manifest_entry(
341 struct ManifestFile *pFrom,
342 struct ManifestFile *pTo,
343 const char *zDiffCmd,
344 int diffFlags
345 ){
346 Blob f1, f2;
347 int rid;
348 const char *zName = pFrom ? pFrom->zName : pTo->zName;
349 diff_print_index(zName);
@@ -365,11 +357,11 @@
357 rid = uuid_to_rid(pTo->zUuid, 0);
358 content_get(rid, &f2);
359 }else{
360 blob_zero(&f2);
361 }
362 diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags);
363 blob_reset(&f1);
364 blob_reset(&f2);
365 }
366
367 /*
@@ -381,11 +373,10 @@
373 const char *zDiffCmd,
374 int diffFlags
375 ){
376 Manifest *pFrom, *pTo;
377 ManifestFile *pFromFile, *pToFile;
 
378 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
379
380 pFrom = manifest_get_by_name(zFrom, 0);
381 manifest_file_rewind(pFrom);
382 pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +394,26 @@
394 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
395 }
396 if( cmp<0 ){
397 diff_printf("DELETED %s\n", pFromFile->zName);
398 if( asNewFlag ){
399 diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
400 }
401 pFromFile = manifest_file_next(pFrom,0);
402 }else if( cmp>0 ){
403 diff_printf("ADDED %s\n", pToFile->zName);
404 if( asNewFlag ){
405 diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
406 }
407 pToFile = manifest_file_next(pTo,0);
408 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
409 /* No changes */
410 pFromFile = manifest_file_next(pFrom,0);
411 pToFile = manifest_file_next(pTo,0);
412 }else{
413 /* diff_printf("CHANGED %s\n", pFromFile->zName); */
414 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
415 pFromFile = manifest_file_next(pFrom,0);
416 pToFile = manifest_file_next(pTo,0);
417 }
418 }
419 manifest_destroy(pFrom);
@@ -456,30 +447,44 @@
447 **
448 ** The "-N" or "--new-file" option causes the complete text of added or
449 ** deleted files to be displayed.
450 **
451 ** Options:
452 ** --context|-c N Use N lines of context
453 ** --from|-r VERSION select VERSION as source for the diff
454 ** --new-file|-N output complete text of added or deleted files
455 ** -i use internal diff logic
456 ** --to VERSION select VERSION as target for the diff
457 ** --side-by-side|-y side-by-side diff
458 ** --width|-W N Width of lines in side-by-side diff
459 */
460 void diff_cmd(void){
461 int isGDiff; /* True for gdiff. False for normal diff */
462 int isInternDiff; /* True for internal diff */
463 int hasNFlag; /* True if -N or --new-file flag is used */
464 const char *zFrom; /* Source version number */
465 const char *zTo; /* Target version number */
466 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
467 int diffFlags = 0; /* Flags to control the DIFF */
468 const char *z;
469 int f;
470
471 isGDiff = g.argv[1][0]=='g';
472 isInternDiff = find_option("internal","i",0)!=0;
473 zFrom = find_option("from", "r", 1);
474 zTo = find_option("to", 0, 1);
475 hasNFlag = find_option("new-file","N",0)!=0;
476 if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
477 if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){
478 if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;
479 diffFlags |= f;
480 }
481 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
482 f *= DIFF_CONTEXT_MASK+1;
483 if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
484 diffFlags |= f;
485 }
486
487
488 if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
489 if( zTo==0 ){
490 db_must_be_within_tree();
491
+2 -2
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270270
content_get(toid, &to);
271271
}else{
272272
blob_zero(&to);
273273
}
274274
blob_zero(&out);
275
- text_diff(&from, &to, &out, 5, 1);
275
+ text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
276276
@ %h(blob_str(&out))
277277
blob_reset(&from);
278278
blob_reset(&to);
279279
blob_reset(&out);
280280
}
@@ -1091,11 +1091,11 @@
10911091
pOut = &diff;
10921092
}
10931093
if( !sideBySide || isPatch ){
10941094
content_get(v1, &c1);
10951095
content_get(v2, &c2);
1096
- text_diff(&c1, &c2, pOut, 4, 1);
1096
+ text_diff(&c1, &c2, pOut, 4 | 0);
10971097
blob_reset(&c1);
10981098
blob_reset(&c2);
10991099
}
11001100
if( !isPatch ){
11011101
style_header("Diff");
11021102
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270 content_get(toid, &to);
271 }else{
272 blob_zero(&to);
273 }
274 blob_zero(&out);
275 text_diff(&from, &to, &out, 5, 1);
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
@@ -1091,11 +1091,11 @@
1091 pOut = &diff;
1092 }
1093 if( !sideBySide || isPatch ){
1094 content_get(v1, &c1);
1095 content_get(v2, &c2);
1096 text_diff(&c1, &c2, pOut, 4, 1);
1097 blob_reset(&c1);
1098 blob_reset(&c2);
1099 }
1100 if( !isPatch ){
1101 style_header("Diff");
1102
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270 content_get(toid, &to);
271 }else{
272 blob_zero(&to);
273 }
274 blob_zero(&out);
275 text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
@@ -1091,11 +1091,11 @@
1091 pOut = &diff;
1092 }
1093 if( !sideBySide || isPatch ){
1094 content_get(v1, &c1);
1095 content_get(v2, &c2);
1096 text_diff(&c1, &c2, pOut, 4 | 0);
1097 blob_reset(&c1);
1098 blob_reset(&c2);
1099 }
1100 if( !isPatch ){
1101 style_header("Diff");
1102
+2 -2
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171171
** is the number of lines of text to copy directly from the pivot,
172172
** the second integer is the number of lines of text to omit from the
173173
** pivot, and the third integer is the number of lines of text that are
174174
** inserted. The edit array ends with a triple of 0,0,0.
175175
*/
176
- aC1 = text_diff(pPivot, pV1, 0, 0, 0);
177
- aC2 = text_diff(pPivot, pV2, 0, 0, 0);
176
+ aC1 = text_diff(pPivot, pV1, 0, 0);
177
+ aC2 = text_diff(pPivot, pV2, 0, 0);
178178
if( aC1==0 || aC2==0 ){
179179
free(aC1);
180180
free(aC2);
181181
return -1;
182182
}
183183
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171 ** is the number of lines of text to copy directly from the pivot,
172 ** the second integer is the number of lines of text to omit from the
173 ** pivot, and the third integer is the number of lines of text that are
174 ** inserted. The edit array ends with a triple of 0,0,0.
175 */
176 aC1 = text_diff(pPivot, pV1, 0, 0, 0);
177 aC2 = text_diff(pPivot, pV2, 0, 0, 0);
178 if( aC1==0 || aC2==0 ){
179 free(aC1);
180 free(aC2);
181 return -1;
182 }
183
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171 ** is the number of lines of text to copy directly from the pivot,
172 ** the second integer is the number of lines of text to omit from the
173 ** pivot, and the third integer is the number of lines of text that are
174 ** inserted. The edit array ends with a triple of 0,0,0.
175 */
176 aC1 = text_diff(pPivot, pV1, 0, 0);
177 aC2 = text_diff(pPivot, pV2, 0, 0);
178 if( aC1==0 || aC2==0 ){
179 free(aC1);
180 free(aC2);
181 return -1;
182 }
183
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621621
blob_zero(&w2);
622622
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623623
blob_init(&w2, pW2->zWiki, -1);
624624
}
625625
blob_zero(&d);
626
- text_diff(&w2, &w1, &d, 5, 1);
626
+ text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627627
@ <pre>
628628
@ %h(blob_str(&d))
629629
@ </pre>
630630
manifest_destroy(pW1);
631631
manifest_destroy(pW2);
632632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5, 1);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632

Keyboard Shortcuts

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