Fossil SCM

Internally, use the new DiffConfig object to pass around diff settings, rather than the legacy u64 bit array. This provides increased flexibility to the internals. There should be no user-visible changes (unless I made a mistake). Note that more parameters could be folded into the DiffConfig object. This check-in is just a start.

drh 2021-09-06 22:26 trunk merge
Commit 1347a1ddb9a565e93005f65cdfc6d773ab3b2e5292a38163972fe4c5c21c823a
+3 -1
--- src/ajax.c
+++ src/ajax.c
@@ -152,12 +152,14 @@
152152
** and pContent is the locally-edited (v2) content. diffFlags is any
153153
** set of flags suitable for passing to text_diff().
154154
*/
155155
void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){
156156
Blob out = empty_blob;
157
+ DiffConfig DCfg;
157158
158
- text_diff(pOrig, pContent, &out, 0, diffFlags);
159
+ diff_config_init(&DCfg, diffFlags);
160
+ text_diff(pOrig, pContent, &out, &DCfg);
159161
if(blob_size(&out)==0){
160162
/* nothing to do */
161163
}else if(DIFF_SIDEBYSIDE & diffFlags){
162164
CX("%b",&out);
163165
}else{
164166
--- src/ajax.c
+++ src/ajax.c
@@ -152,12 +152,14 @@
152 ** and pContent is the locally-edited (v2) content. diffFlags is any
153 ** set of flags suitable for passing to text_diff().
154 */
155 void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){
156 Blob out = empty_blob;
 
157
158 text_diff(pOrig, pContent, &out, 0, diffFlags);
 
159 if(blob_size(&out)==0){
160 /* nothing to do */
161 }else if(DIFF_SIDEBYSIDE & diffFlags){
162 CX("%b",&out);
163 }else{
164
--- src/ajax.c
+++ src/ajax.c
@@ -152,12 +152,14 @@
152 ** and pContent is the locally-edited (v2) content. diffFlags is any
153 ** set of flags suitable for passing to text_diff().
154 */
155 void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){
156 Blob out = empty_blob;
157 DiffConfig DCfg;
158
159 diff_config_init(&DCfg, diffFlags);
160 text_diff(pOrig, pContent, &out, &DCfg);
161 if(blob_size(&out)==0){
162 /* nothing to do */
163 }else if(DIFF_SIDEBYSIDE & diffFlags){
164 CX("%b",&out);
165 }else{
166
+4 -2
--- src/checkin.c
+++ src/checkin.c
@@ -1338,15 +1338,17 @@
13381338
"# All merged-in branches will be closed due to the --integrate flag\n"
13391339
"#\n", -1
13401340
);
13411341
}
13421342
if( p->verboseFlag ){
1343
+ DiffConfig DCfg;
13431344
blob_appendf(&prompt,
13441345
"#\n%.78c\n"
13451346
"# The following diff is excluded from the commit message:\n#\n",
13461347
'#'
13471348
);
1349
+ diff_config_init(&DCfg, DIFF_VERBOSE);
13481350
if( g.aCommitFile ){
13491351
FileDirList *diffFiles;
13501352
int i;
13511353
diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles));
13521354
for( i=0; g.aCommitFile[i]!=0; ++i ){
@@ -1360,19 +1362,19 @@
13601362
diffFiles[i].nName = strlen(diffFiles[i].zName);
13611363
diffFiles[i].nUsed = 0;
13621364
}
13631365
diff_against_disk(0, 0, diff_get_binary_glob(),
13641366
db_get_boolean("diff-binary", 1),
1365
- DIFF_VERBOSE, diffFiles, &prompt);
1367
+ &DCfg, diffFiles, &prompt);
13661368
for( i=0; diffFiles[i].zName; ++i ){
13671369
fossil_free(diffFiles[i].zName);
13681370
}
13691371
fossil_free(diffFiles);
13701372
}else{
13711373
diff_against_disk(0, 0, diff_get_binary_glob(),
13721374
db_get_boolean("diff-binary", 1),
1373
- DIFF_VERBOSE, 0, &prompt);
1375
+ &DCfg, 0, &prompt);
13741376
}
13751377
}
13761378
prompt_for_user_comment(pComment, &prompt);
13771379
blob_reset(&prompt);
13781380
}
13791381
--- src/checkin.c
+++ src/checkin.c
@@ -1338,15 +1338,17 @@
1338 "# All merged-in branches will be closed due to the --integrate flag\n"
1339 "#\n", -1
1340 );
1341 }
1342 if( p->verboseFlag ){
 
1343 blob_appendf(&prompt,
1344 "#\n%.78c\n"
1345 "# The following diff is excluded from the commit message:\n#\n",
1346 '#'
1347 );
 
1348 if( g.aCommitFile ){
1349 FileDirList *diffFiles;
1350 int i;
1351 diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles));
1352 for( i=0; g.aCommitFile[i]!=0; ++i ){
@@ -1360,19 +1362,19 @@
1360 diffFiles[i].nName = strlen(diffFiles[i].zName);
1361 diffFiles[i].nUsed = 0;
1362 }
1363 diff_against_disk(0, 0, diff_get_binary_glob(),
1364 db_get_boolean("diff-binary", 1),
1365 DIFF_VERBOSE, diffFiles, &prompt);
1366 for( i=0; diffFiles[i].zName; ++i ){
1367 fossil_free(diffFiles[i].zName);
1368 }
1369 fossil_free(diffFiles);
1370 }else{
1371 diff_against_disk(0, 0, diff_get_binary_glob(),
1372 db_get_boolean("diff-binary", 1),
1373 DIFF_VERBOSE, 0, &prompt);
1374 }
1375 }
1376 prompt_for_user_comment(pComment, &prompt);
1377 blob_reset(&prompt);
1378 }
1379
--- src/checkin.c
+++ src/checkin.c
@@ -1338,15 +1338,17 @@
1338 "# All merged-in branches will be closed due to the --integrate flag\n"
1339 "#\n", -1
1340 );
1341 }
1342 if( p->verboseFlag ){
1343 DiffConfig DCfg;
1344 blob_appendf(&prompt,
1345 "#\n%.78c\n"
1346 "# The following diff is excluded from the commit message:\n#\n",
1347 '#'
1348 );
1349 diff_config_init(&DCfg, DIFF_VERBOSE);
1350 if( g.aCommitFile ){
1351 FileDirList *diffFiles;
1352 int i;
1353 diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles));
1354 for( i=0; g.aCommitFile[i]!=0; ++i ){
@@ -1360,19 +1362,19 @@
1362 diffFiles[i].nName = strlen(diffFiles[i].zName);
1363 diffFiles[i].nUsed = 0;
1364 }
1365 diff_against_disk(0, 0, diff_get_binary_glob(),
1366 db_get_boolean("diff-binary", 1),
1367 &DCfg, diffFiles, &prompt);
1368 for( i=0; diffFiles[i].zName; ++i ){
1369 fossil_free(diffFiles[i].zName);
1370 }
1371 fossil_free(diffFiles);
1372 }else{
1373 diff_against_disk(0, 0, diff_get_binary_glob(),
1374 db_get_boolean("diff-binary", 1),
1375 &DCfg, 0, &prompt);
1376 }
1377 }
1378 prompt_for_user_comment(pComment, &prompt);
1379 blob_reset(&prompt);
1380 }
1381
+111 -75
--- src/diff.c
+++ src/diff.c
@@ -70,12 +70,47 @@
7070
/*
7171
** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes)
7272
*/
7373
#define LENGTH_MASK_SZ 15
7474
#define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
75
+
76
+/*
77
+** An instance of this object describes the formatting and processing
78
+** details desired of a "diff" operation.
79
+**
80
+** Conceptually, this object is as an encoding of the command-line options
81
+** for the "fossil diff" command. That is not a precise description, though,
82
+** because not all diff operations are started from the command-line. But
83
+** the idea is sound.
84
+**
85
+** Information encoded by this object includes but is not limited to:
86
+**
87
+** * The desired output format (unified vs. side-by-side,
88
+** TCL, JSON, HTML vs. plain-text).
89
+**
90
+** * Number of lines of context surrounding each difference block
91
+**
92
+** * Width of output columns for text side-by-side diffop
93
+*/
94
+struct DiffConfig {
95
+ u64 diffFlags; /* Diff flags */
96
+ u32 nFile; /* Number of files diffed so far */
97
+ const char *zDiffCmd; /* External diff command to use instead of builtin */
98
+ const char *zBinGlob; /* GLOB pattern for binary files */
99
+ ReCompiled *pRe; /* Show only changes matching this pattern */
100
+};
75101
76102
#endif /* INTERFACE */
103
+
104
+/*
105
+** Initialize memory for a DiffConfig based on just a diffFlags integer.
106
+*/
107
+DiffConfig *diff_config_init(DiffConfig *pCfg, u64 diffFlags){
108
+ memset(pCfg, 0, sizeof(*pCfg));
109
+ pCfg->diffFlags = diffFlags;
110
+ return pCfg;
111
+}
77112
78113
/*
79114
** Information about each line of a file being diffed.
80115
**
81116
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -332,11 +367,11 @@
332367
** Output a patch-style text diff.
333368
*/
334369
static void contextDiff(
335370
DContext *p, /* The difference */
336371
Blob *pOut, /* Output a context diff to here */
337
- u64 diffFlags /* Flags controlling the diff format */
372
+ DiffConfig *pCfg /* Configuration options */
338373
){
339374
DLine *A; /* Left side of the diff */
340375
DLine *B; /* Right side of the diff */
341376
int a = 0; /* Index of next line in A[] */
342377
int b = 0; /* Index of next line in B[] */
@@ -351,12 +386,12 @@
351386
static int nChunk = 0; /* Number of diff chunks seen so far */
352387
int nContext; /* Number of lines of context */
353388
int showLn; /* Show line numbers */
354389
int showDivider = 0; /* True to show the divider between diff blocks */
355390
356
- nContext = diff_context_lines(diffFlags);
357
- showLn = (diffFlags & DIFF_LINENO)!=0;
391
+ nContext = diff_context_lines(pCfg);
392
+ showLn = (pCfg->diffFlags & DIFF_LINENO)!=0;
358393
A = p->aFrom;
359394
B = p->aTo;
360395
R = p->aEdit;
361396
mxr = p->nEdit;
362397
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1119,11 +1154,11 @@
11191154
blob_append_char(p->pOut, ',');
11201155
blob_append_json_literal(p->pOut, pX->z + x, pX->n - x);
11211156
blob_append(p->pOut, "],\n",3);
11221157
}
11231158
static void dfjsonEnd(DiffBuilder *p){
1124
- blob_append(p->pOut, "0]", 2);
1159
+ blob_append(p->pOut, "0]}", 3);
11251160
fossil_free(p);
11261161
}
11271162
static DiffBuilder *dfjsonNew(Blob *pOut){
11281163
DiffBuilder *p = fossil_malloc(sizeof(*p));
11291164
p->xSkip = dfjsonSkip;
@@ -1631,21 +1666,21 @@
16311666
blob_append_char(p->pOut, '\n');
16321667
}
16331668
static void dfsbsEnd(DiffBuilder *p){
16341669
fossil_free(p);
16351670
}
1636
-static DiffBuilder *dfsbsNew(Blob *pOut, u64 diffFlags){
1671
+static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){
16371672
DiffBuilder *p = fossil_malloc(sizeof(*p));
16381673
p->xSkip = dfsbsSkip;
16391674
p->xCommon = dfsbsCommon;
16401675
p->xInsert = dfsbsInsert;
16411676
p->xDelete = dfsbsDelete;
16421677
p->xReplace = dfsbsEdit;
16431678
p->xEdit = dfsbsEdit;
16441679
p->xEnd = dfsbsEnd;
16451680
p->lnLeft = p->lnRight = 0;
1646
- p->width = diff_width(diffFlags);
1681
+ p->width = diff_width(pCfg);
16471682
p->pOut = pOut;
16481683
return p;
16491684
}
16501685
/****************************************************************************/
16511686
/*
@@ -1767,11 +1802,11 @@
17671802
** mismatch.
17681803
*/
17691804
static unsigned char *diffBlockAlignment(
17701805
const DLine *aLeft, int nLeft, /* Text on the left */
17711806
const DLine *aRight, int nRight, /* Text on the right */
1772
- u64 diffFlags, /* Flags passed into the original diff */
1807
+ DiffConfig *pCfg, /* Configuration options */
17731808
int *pNResult /* OUTPUT: Bytes of result */
17741809
){
17751810
int i, j, k; /* Loop counters */
17761811
int *a; /* One row of the Wagner matrix */
17771812
int *pToFree; /* Space that needs to be freed */
@@ -1795,11 +1830,11 @@
17951830
/* For large alignments, use a divide and conquer algorithm that is
17961831
** O(NlogN). The result is not as precise, but this whole thing is an
17971832
** approximation anyhow, and the faster response time is an acceptable
17981833
** trade-off for reduced precision.
17991834
*/
1800
- if( nLeft*nRight>DIFF_ALIGN_MX && (diffFlags & DIFF_SLOW_SBS)==0 ){
1835
+ if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
18011836
const DLine *aSmall; /* The smaller of aLeft and aRight */
18021837
const DLine *aBig; /* The larger of aLeft and aRight */
18031838
int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
18041839
int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
18051840
int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
@@ -1832,14 +1867,14 @@
18321867
iDivLeft = iDivBig;
18331868
}else{
18341869
iDivRight = iDivBig;
18351870
iDivLeft = iDivSmall;
18361871
}
1837
- a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,diffFlags,&n1);
1872
+ a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1);
18381873
a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft,
18391874
aRight+iDivRight, nRight-iDivRight,
1840
- diffFlags, &n2);
1875
+ pCfg, &n2);
18411876
a1 = fossil_realloc(a1, n1+n2 );
18421877
memcpy(a1+n1,a2,n2);
18431878
fossil_free(a2);
18441879
*pNResult = n1+n2;
18451880
return a1;
@@ -1938,12 +1973,11 @@
19381973
/*
19391974
** Format a diff using a DiffBuilder object
19401975
*/
19411976
static void formatDiff(
19421977
DContext *p, /* The computed diff */
1943
- ReCompiled *pRe, /* Only show changes that match this regex */
1944
- u64 diffFlags, /* Flags controlling the diff */
1978
+ DiffConfig *pCfg, /* Configuration options */
19451979
DiffBuilder *pBuilder /* The formatter object */
19461980
){
19471981
const DLine *A; /* Left side of the diff */
19481982
const DLine *B; /* Right side of the diff */
19491983
unsigned int a = 0; /* Index of next line in A[] */
@@ -1956,11 +1990,11 @@
19561990
unsigned int i, j; /* Loop counters */
19571991
unsigned int m, ma, mb;/* Number of lines to output */
19581992
signed int skip = 0; /* Number of lines to skip */
19591993
unsigned int nContext; /* Lines of context above and below each change */
19601994
1961
- nContext = diff_context_lines(diffFlags);
1995
+ nContext = diff_context_lines(pCfg);
19621996
A = p->aFrom;
19631997
B = p->aTo;
19641998
R = p->aEdit;
19651999
mxr = p->nEdit;
19662000
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1972,19 +2006,19 @@
19722006
/* If there is a regex, skip this block (generate no diff output)
19732007
** if the regex matches or does not match both insert and delete.
19742008
** Only display the block if one side matches but the other side does
19752009
** not.
19762010
*/
1977
- if( pRe ){
2011
+ if( pCfg->pRe ){
19782012
int hideBlock = 1;
19792013
int xa = a, xb = b;
19802014
for(i=0; hideBlock && i<nr; i++){
19812015
int c1, c2;
19822016
xa += R[r+i*3];
19832017
xb += R[r+i*3];
1984
- c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]);
1985
- c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]);
2018
+ c1 = re_dline_match(pCfg->pRe, &A[xa], R[r+i*3+1]);
2019
+ c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]);
19862020
hideBlock = c1==c2;
19872021
xa += R[r+i*3+1];
19882022
xb += R[r+i*3+2];
19892023
}
19902024
if( hideBlock ){
@@ -2050,11 +2084,11 @@
20502084
ma += R[r+i*3+1] + m;
20512085
mb += R[r+i*3+2] + m;
20522086
}
20532087
20542088
/* Try to find an alignment for the lines within this one block */
2055
- alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, diffFlags, &nAlign);
2089
+ alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign);
20562090
20572091
for(j=0; ma+mb>0; j++){
20582092
assert( j<nAlign );
20592093
switch( alignment[j] ){
20602094
case 1: {
@@ -2511,13 +2545,13 @@
25112545
25122546
/*
25132547
** Extract the number of lines of context from diffFlags. Supply an
25142548
** appropriate default if no context width is specified.
25152549
*/
2516
-int diff_context_lines(u64 diffFlags){
2517
- int n = diffFlags & DIFF_CONTEXT_MASK;
2518
- if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5;
2550
+int diff_context_lines(DiffConfig *pCfg){
2551
+ int n = pCfg->diffFlags & DIFF_CONTEXT_MASK;
2552
+ if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5;
25192553
return n;
25202554
}
25212555
25222556
/*
25232557
** Extract the width of columns for side-by-side diff. Supply an
@@ -2527,12 +2561,12 @@
25272561
** term-width = 2*diff-col + diff-marker + 1
25282562
** diff-col = lineno + lmargin + text-width + rmargin
25292563
**
25302564
** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin
25312565
*/
2532
-int diff_width(u64 diffFlags){
2533
- int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
2566
+int diff_width(DiffConfig *pCfg){
2567
+ int w = (pCfg->diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
25342568
if( w==0 ){
25352569
static struct {
25362570
unsigned int lineno, lmargin, text, rmargin, marker;
25372571
} sbsW = { 5, 2, 0, 0, 3 };
25382572
const unsigned int wMin = 24, wMax = 132;
@@ -2589,41 +2623,40 @@
25892623
*/
25902624
int *text_diff(
25912625
Blob *pA_Blob, /* FROM file */
25922626
Blob *pB_Blob, /* TO file */
25932627
Blob *pOut, /* Write diff here if not NULL */
2594
- ReCompiled *pRe, /* Only output changes where this Regexp matches */
2595
- u64 diffFlags /* DIFF_* flags defined above */
2628
+ DiffConfig *pCfg /* Configuration options */
25962629
){
25972630
int ignoreWs; /* Ignore whitespace */
25982631
DContext c;
25992632
2600
- if( diffFlags & DIFF_INVERT ){
2633
+ if( pCfg->diffFlags & DIFF_INVERT ){
26012634
Blob *pTemp = pA_Blob;
26022635
pA_Blob = pB_Blob;
26032636
pB_Blob = pTemp;
26042637
}
2605
- ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0;
2638
+ ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0;
26062639
blob_to_utf8_no_bom(pA_Blob, 0);
26072640
blob_to_utf8_no_bom(pB_Blob, 0);
26082641
26092642
/* Prepare the input files */
26102643
memset(&c, 0, sizeof(c));
2611
- if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2644
+ if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
26122645
c.xDiffer = compare_dline_ignore_allws;
26132646
}else{
26142647
c.xDiffer = compare_dline;
26152648
}
26162649
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
2617
- &c.nFrom, diffFlags);
2650
+ &c.nFrom, pCfg->diffFlags);
26182651
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
2619
- &c.nTo, diffFlags);
2652
+ &c.nTo, pCfg->diffFlags);
26202653
if( c.aFrom==0 || c.aTo==0 ){
26212654
fossil_free(c.aFrom);
26222655
fossil_free(c.aTo);
26232656
if( pOut ){
2624
- diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
2657
+ diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
26252658
}
26262659
return 0;
26272660
}
26282661
26292662
/* Compute the difference */
@@ -2630,32 +2663,32 @@
26302663
diff_all(&c);
26312664
if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
26322665
fossil_free(c.aFrom);
26332666
fossil_free(c.aTo);
26342667
fossil_free(c.aEdit);
2635
- if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
2668
+ if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags);
26362669
return 0;
26372670
}
2638
- if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2671
+ if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){
26392672
int i, m, n;
26402673
int *a = c.aEdit;
26412674
int mx = c.nEdit;
26422675
for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
26432676
if( n>10000 ){
26442677
fossil_free(c.aFrom);
26452678
fossil_free(c.aTo);
26462679
fossil_free(c.aEdit);
2647
- if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
2680
+ if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags);
26482681
return 0;
26492682
}
26502683
}
2651
- if( (diffFlags & DIFF_NOOPT)==0 ){
2684
+ if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
26522685
diff_optimize(&c);
26532686
}
26542687
26552688
if( pOut ){
2656
- if( diffFlags & DIFF_NUMSTAT ){
2689
+ if( pCfg->diffFlags & DIFF_NUMSTAT ){
26572690
int nDel = 0, nIns = 0, i;
26582691
for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
26592692
nDel += c.aEdit[i+1];
26602693
nIns += c.aEdit[i+2];
26612694
}
@@ -2663,40 +2696,40 @@
26632696
g.diffCnt[2] += nDel;
26642697
if( nIns+nDel ){
26652698
g.diffCnt[0]++;
26662699
blob_appendf(pOut, "%10d %10d", nIns, nDel);
26672700
}
2668
- }else if( diffFlags & DIFF_RAW ){
2701
+ }else if( pCfg->diffFlags & DIFF_RAW ){
26692702
const int *R = c.aEdit;
26702703
unsigned int r;
26712704
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
26722705
blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
26732706
R[r], R[r+1], R[r+2]);
26742707
}
2675
- }else if( diffFlags & DIFF_JSON ){
2708
+ }else if( pCfg->diffFlags & DIFF_JSON ){
26762709
DiffBuilder *pBuilder = dfjsonNew(pOut);
2677
- formatDiff(&c, pRe, diffFlags, pBuilder);
2710
+ formatDiff(&c, pCfg, pBuilder);
26782711
blob_append_char(pOut, '\n');
2679
- }else if( diffFlags & DIFF_TCL ){
2712
+ }else if( pCfg->diffFlags & DIFF_TCL ){
26802713
DiffBuilder *pBuilder = dftclNew(pOut);
2681
- formatDiff(&c, pRe, diffFlags, pBuilder);
2682
- }else if( diffFlags & DIFF_SIDEBYSIDE ){
2714
+ formatDiff(&c, pCfg, pBuilder);
2715
+ }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
26832716
DiffBuilder *pBuilder;
2684
- if( diffFlags & DIFF_HTML ){
2717
+ if( pCfg->diffFlags & DIFF_HTML ){
26852718
pBuilder = dfsplitNew(pOut);
26862719
}else{
2687
- pBuilder = dfsbsNew(pOut, diffFlags);
2720
+ pBuilder = dfsbsNew(pOut, pCfg);
26882721
}
2689
- formatDiff(&c, pRe, diffFlags, pBuilder);
2690
- }else if( diffFlags & DIFF_DEBUG ){
2722
+ formatDiff(&c, pCfg, pBuilder);
2723
+ }else if( pCfg->diffFlags & DIFF_DEBUG ){
26912724
DiffBuilder *pBuilder = dfdebugNew(pOut);
2692
- formatDiff(&c, pRe, diffFlags, pBuilder);
2693
- }else if( diffFlags & DIFF_HTML ){
2725
+ formatDiff(&c, pCfg, pBuilder);
2726
+ }else if( pCfg->diffFlags & DIFF_HTML ){
26942727
DiffBuilder *pBuilder = dfunifiedNew(pOut);
2695
- formatDiff(&c, pRe, diffFlags, pBuilder);
2728
+ formatDiff(&c, pCfg, pBuilder);
26962729
}else{
2697
- contextDiff(&c, pOut, diffFlags);
2730
+ contextDiff(&c, pOut, pCfg);
26982731
}
26992732
fossil_free(c.aFrom);
27002733
fossil_free(c.aTo);
27012734
fossil_free(c.aEdit);
27022735
return 0;
@@ -2709,31 +2742,35 @@
27092742
return c.aEdit;
27102743
}
27112744
}
27122745
27132746
/*
2747
+** Initialize the DiffConfig object using command-line options.
2748
+**
27142749
** Process diff-related command-line options and return an appropriate
27152750
** "diffFlags" integer.
27162751
**
2717
-** --brief Show filenames only DIFF_BRIEF
2718
-** -c|--context N N lines of context. DIFF_CONTEXT_MASK
2719
-** --html Format for HTML DIFF_HTML
2720
-** --invert Invert the diff DIFF_INVERT
2721
-** -n|--linenum Show line numbers DIFF_LINENO
2722
-** --noopt Disable optimization DIFF_NOOPT
2723
-** --numstat Show change counts DIFF_NUMSTAT
2724
-** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
2725
-** --unified Unified diff. ~DIFF_SIDEBYSIDE
2726
-** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
2727
-** -W|--width N N character lines. DIFF_WIDTH_MASK
2728
-** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
2729
-** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
2752
+** --brief Show filenames only DIFF_BRIEF
2753
+** -c|--context N N lines of context. DIFF_CONTEXT_MASK
2754
+** --html Format for HTML DIFF_HTML
2755
+** --invert Invert the diff DIFF_INVERT
2756
+** -n|--linenum Show line numbers DIFF_LINENO
2757
+** --noopt Disable optimization DIFF_NOOPT
2758
+** --numstat Show change counts DIFF_NUMSTAT
2759
+** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
2760
+** --unified Unified diff. ~DIFF_SIDEBYSIDE
2761
+** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
2762
+** -W|--width N N character lines. DIFF_WIDTH_MASK
2763
+** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
2764
+** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
27302765
*/
2731
-u64 diff_options(void){
2766
+void diff_options(DiffConfig *pCfg, int isGDiff){
27322767
u64 diffFlags = 0;
27332768
const char *z;
27342769
int f;
2770
+
2771
+ memset(pCfg, 0, sizeof(*pCfg));
27352772
if( find_option("ignore-trailing-space","Z",0)!=0 ){
27362773
diffFlags = DIFF_IGNORE_EOLWS;
27372774
}
27382775
if( find_option("ignore-all-space","w",0)!=0 ){
27392776
diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
@@ -2780,11 +2817,11 @@
27802817
27812818
/* Undocumented and unsupported flags used for development
27822819
** debugging and analysis: */
27832820
if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
27842821
if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
2785
- return diffFlags;
2822
+ pCfg->diffFlags = diffFlags;
27862823
}
27872824
27882825
/*
27892826
** COMMAND: test-diff
27902827
** COMMAND: xdiff
@@ -2802,39 +2839,38 @@
28022839
** See the "diff" command for a full list of command-line options.
28032840
**
28042841
** This command used to be called "test-diff". The older "test-diff" spelling
28052842
** still works, for compatibility.
28062843
*/
2807
-void test_diff_cmd(void){
2844
+void xdiff_cmd(void){
28082845
Blob a, b, out;
2809
- u64 diffFlag;
28102846
const char *zRe; /* Regex filter for diff output */
2811
- ReCompiled *pRe = 0; /* Regex filter for diff output */
2847
+ DiffConfig DCfg;
28122848
28132849
if( find_option("tk",0,0)!=0 ){
2814
- diff_tk("test-diff", 2);
2850
+ diff_tk("xdiff", 2);
28152851
return;
28162852
}
28172853
find_option("i",0,0);
28182854
find_option("v",0,0);
2855
+ diff_options(&DCfg, 0);
28192856
zRe = find_option("regexp","e",1);
28202857
if( zRe ){
2821
- const char *zErr = re_compile(&pRe, zRe, 0);
2858
+ const char *zErr = re_compile(&DCfg.pRe, zRe, 0);
28222859
if( zErr ) fossil_fatal("regex error: %s", zErr);
28232860
}
2824
- diffFlag = diff_options();
28252861
verify_all_options();
28262862
if( g.argc!=4 ) usage("FILE1 FILE2");
28272863
blob_zero(&out);
2828
- diff_begin(diffFlag);
2829
- diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out);
2864
+ diff_begin(&DCfg);
2865
+ diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
28302866
blob_read_from_file(&a, g.argv[2], ExtFILE);
28312867
blob_read_from_file(&b, g.argv[3], ExtFILE);
2832
- text_diff(&a, &b, &out, pRe, diffFlag);
2868
+ text_diff(&a, &b, &out, &DCfg);
28332869
blob_write_to_file(&out, "-");
2834
- diff_end(diffFlag, 0);
2835
- re_free(pRe);
2870
+ diff_end(&DCfg, 0);
2871
+ re_free(DCfg.pRe);
28362872
}
28372873
28382874
/**************************************************************************
28392875
** The basic difference engine is above. What follows is the annotation
28402876
** engine. Both are in the same file since they share many components.
28412877
--- src/diff.c
+++ src/diff.c
@@ -70,12 +70,47 @@
70 /*
71 ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes)
72 */
73 #define LENGTH_MASK_SZ 15
74 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
76 #endif /* INTERFACE */
 
 
 
 
 
 
 
 
 
77
78 /*
79 ** Information about each line of a file being diffed.
80 **
81 ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -332,11 +367,11 @@
332 ** Output a patch-style text diff.
333 */
334 static void contextDiff(
335 DContext *p, /* The difference */
336 Blob *pOut, /* Output a context diff to here */
337 u64 diffFlags /* Flags controlling the diff format */
338 ){
339 DLine *A; /* Left side of the diff */
340 DLine *B; /* Right side of the diff */
341 int a = 0; /* Index of next line in A[] */
342 int b = 0; /* Index of next line in B[] */
@@ -351,12 +386,12 @@
351 static int nChunk = 0; /* Number of diff chunks seen so far */
352 int nContext; /* Number of lines of context */
353 int showLn; /* Show line numbers */
354 int showDivider = 0; /* True to show the divider between diff blocks */
355
356 nContext = diff_context_lines(diffFlags);
357 showLn = (diffFlags & DIFF_LINENO)!=0;
358 A = p->aFrom;
359 B = p->aTo;
360 R = p->aEdit;
361 mxr = p->nEdit;
362 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1119,11 +1154,11 @@
1119 blob_append_char(p->pOut, ',');
1120 blob_append_json_literal(p->pOut, pX->z + x, pX->n - x);
1121 blob_append(p->pOut, "],\n",3);
1122 }
1123 static void dfjsonEnd(DiffBuilder *p){
1124 blob_append(p->pOut, "0]", 2);
1125 fossil_free(p);
1126 }
1127 static DiffBuilder *dfjsonNew(Blob *pOut){
1128 DiffBuilder *p = fossil_malloc(sizeof(*p));
1129 p->xSkip = dfjsonSkip;
@@ -1631,21 +1666,21 @@
1631 blob_append_char(p->pOut, '\n');
1632 }
1633 static void dfsbsEnd(DiffBuilder *p){
1634 fossil_free(p);
1635 }
1636 static DiffBuilder *dfsbsNew(Blob *pOut, u64 diffFlags){
1637 DiffBuilder *p = fossil_malloc(sizeof(*p));
1638 p->xSkip = dfsbsSkip;
1639 p->xCommon = dfsbsCommon;
1640 p->xInsert = dfsbsInsert;
1641 p->xDelete = dfsbsDelete;
1642 p->xReplace = dfsbsEdit;
1643 p->xEdit = dfsbsEdit;
1644 p->xEnd = dfsbsEnd;
1645 p->lnLeft = p->lnRight = 0;
1646 p->width = diff_width(diffFlags);
1647 p->pOut = pOut;
1648 return p;
1649 }
1650 /****************************************************************************/
1651 /*
@@ -1767,11 +1802,11 @@
1767 ** mismatch.
1768 */
1769 static unsigned char *diffBlockAlignment(
1770 const DLine *aLeft, int nLeft, /* Text on the left */
1771 const DLine *aRight, int nRight, /* Text on the right */
1772 u64 diffFlags, /* Flags passed into the original diff */
1773 int *pNResult /* OUTPUT: Bytes of result */
1774 ){
1775 int i, j, k; /* Loop counters */
1776 int *a; /* One row of the Wagner matrix */
1777 int *pToFree; /* Space that needs to be freed */
@@ -1795,11 +1830,11 @@
1795 /* For large alignments, use a divide and conquer algorithm that is
1796 ** O(NlogN). The result is not as precise, but this whole thing is an
1797 ** approximation anyhow, and the faster response time is an acceptable
1798 ** trade-off for reduced precision.
1799 */
1800 if( nLeft*nRight>DIFF_ALIGN_MX && (diffFlags & DIFF_SLOW_SBS)==0 ){
1801 const DLine *aSmall; /* The smaller of aLeft and aRight */
1802 const DLine *aBig; /* The larger of aLeft and aRight */
1803 int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
1804 int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
1805 int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
@@ -1832,14 +1867,14 @@
1832 iDivLeft = iDivBig;
1833 }else{
1834 iDivRight = iDivBig;
1835 iDivLeft = iDivSmall;
1836 }
1837 a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,diffFlags,&n1);
1838 a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft,
1839 aRight+iDivRight, nRight-iDivRight,
1840 diffFlags, &n2);
1841 a1 = fossil_realloc(a1, n1+n2 );
1842 memcpy(a1+n1,a2,n2);
1843 fossil_free(a2);
1844 *pNResult = n1+n2;
1845 return a1;
@@ -1938,12 +1973,11 @@
1938 /*
1939 ** Format a diff using a DiffBuilder object
1940 */
1941 static void formatDiff(
1942 DContext *p, /* The computed diff */
1943 ReCompiled *pRe, /* Only show changes that match this regex */
1944 u64 diffFlags, /* Flags controlling the diff */
1945 DiffBuilder *pBuilder /* The formatter object */
1946 ){
1947 const DLine *A; /* Left side of the diff */
1948 const DLine *B; /* Right side of the diff */
1949 unsigned int a = 0; /* Index of next line in A[] */
@@ -1956,11 +1990,11 @@
1956 unsigned int i, j; /* Loop counters */
1957 unsigned int m, ma, mb;/* Number of lines to output */
1958 signed int skip = 0; /* Number of lines to skip */
1959 unsigned int nContext; /* Lines of context above and below each change */
1960
1961 nContext = diff_context_lines(diffFlags);
1962 A = p->aFrom;
1963 B = p->aTo;
1964 R = p->aEdit;
1965 mxr = p->nEdit;
1966 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1972,19 +2006,19 @@
1972 /* If there is a regex, skip this block (generate no diff output)
1973 ** if the regex matches or does not match both insert and delete.
1974 ** Only display the block if one side matches but the other side does
1975 ** not.
1976 */
1977 if( pRe ){
1978 int hideBlock = 1;
1979 int xa = a, xb = b;
1980 for(i=0; hideBlock && i<nr; i++){
1981 int c1, c2;
1982 xa += R[r+i*3];
1983 xb += R[r+i*3];
1984 c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]);
1985 c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]);
1986 hideBlock = c1==c2;
1987 xa += R[r+i*3+1];
1988 xb += R[r+i*3+2];
1989 }
1990 if( hideBlock ){
@@ -2050,11 +2084,11 @@
2050 ma += R[r+i*3+1] + m;
2051 mb += R[r+i*3+2] + m;
2052 }
2053
2054 /* Try to find an alignment for the lines within this one block */
2055 alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, diffFlags, &nAlign);
2056
2057 for(j=0; ma+mb>0; j++){
2058 assert( j<nAlign );
2059 switch( alignment[j] ){
2060 case 1: {
@@ -2511,13 +2545,13 @@
2511
2512 /*
2513 ** Extract the number of lines of context from diffFlags. Supply an
2514 ** appropriate default if no context width is specified.
2515 */
2516 int diff_context_lines(u64 diffFlags){
2517 int n = diffFlags & DIFF_CONTEXT_MASK;
2518 if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5;
2519 return n;
2520 }
2521
2522 /*
2523 ** Extract the width of columns for side-by-side diff. Supply an
@@ -2527,12 +2561,12 @@
2527 ** term-width = 2*diff-col + diff-marker + 1
2528 ** diff-col = lineno + lmargin + text-width + rmargin
2529 **
2530 ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin
2531 */
2532 int diff_width(u64 diffFlags){
2533 int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
2534 if( w==0 ){
2535 static struct {
2536 unsigned int lineno, lmargin, text, rmargin, marker;
2537 } sbsW = { 5, 2, 0, 0, 3 };
2538 const unsigned int wMin = 24, wMax = 132;
@@ -2589,41 +2623,40 @@
2589 */
2590 int *text_diff(
2591 Blob *pA_Blob, /* FROM file */
2592 Blob *pB_Blob, /* TO file */
2593 Blob *pOut, /* Write diff here if not NULL */
2594 ReCompiled *pRe, /* Only output changes where this Regexp matches */
2595 u64 diffFlags /* DIFF_* flags defined above */
2596 ){
2597 int ignoreWs; /* Ignore whitespace */
2598 DContext c;
2599
2600 if( diffFlags & DIFF_INVERT ){
2601 Blob *pTemp = pA_Blob;
2602 pA_Blob = pB_Blob;
2603 pB_Blob = pTemp;
2604 }
2605 ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0;
2606 blob_to_utf8_no_bom(pA_Blob, 0);
2607 blob_to_utf8_no_bom(pB_Blob, 0);
2608
2609 /* Prepare the input files */
2610 memset(&c, 0, sizeof(c));
2611 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2612 c.xDiffer = compare_dline_ignore_allws;
2613 }else{
2614 c.xDiffer = compare_dline;
2615 }
2616 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
2617 &c.nFrom, diffFlags);
2618 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
2619 &c.nTo, diffFlags);
2620 if( c.aFrom==0 || c.aTo==0 ){
2621 fossil_free(c.aFrom);
2622 fossil_free(c.aTo);
2623 if( pOut ){
2624 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
2625 }
2626 return 0;
2627 }
2628
2629 /* Compute the difference */
@@ -2630,32 +2663,32 @@
2630 diff_all(&c);
2631 if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
2632 fossil_free(c.aFrom);
2633 fossil_free(c.aTo);
2634 fossil_free(c.aEdit);
2635 if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
2636 return 0;
2637 }
2638 if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
2639 int i, m, n;
2640 int *a = c.aEdit;
2641 int mx = c.nEdit;
2642 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2643 if( n>10000 ){
2644 fossil_free(c.aFrom);
2645 fossil_free(c.aTo);
2646 fossil_free(c.aEdit);
2647 if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
2648 return 0;
2649 }
2650 }
2651 if( (diffFlags & DIFF_NOOPT)==0 ){
2652 diff_optimize(&c);
2653 }
2654
2655 if( pOut ){
2656 if( diffFlags & DIFF_NUMSTAT ){
2657 int nDel = 0, nIns = 0, i;
2658 for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
2659 nDel += c.aEdit[i+1];
2660 nIns += c.aEdit[i+2];
2661 }
@@ -2663,40 +2696,40 @@
2663 g.diffCnt[2] += nDel;
2664 if( nIns+nDel ){
2665 g.diffCnt[0]++;
2666 blob_appendf(pOut, "%10d %10d", nIns, nDel);
2667 }
2668 }else if( diffFlags & DIFF_RAW ){
2669 const int *R = c.aEdit;
2670 unsigned int r;
2671 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
2672 blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
2673 R[r], R[r+1], R[r+2]);
2674 }
2675 }else if( diffFlags & DIFF_JSON ){
2676 DiffBuilder *pBuilder = dfjsonNew(pOut);
2677 formatDiff(&c, pRe, diffFlags, pBuilder);
2678 blob_append_char(pOut, '\n');
2679 }else if( diffFlags & DIFF_TCL ){
2680 DiffBuilder *pBuilder = dftclNew(pOut);
2681 formatDiff(&c, pRe, diffFlags, pBuilder);
2682 }else if( diffFlags & DIFF_SIDEBYSIDE ){
2683 DiffBuilder *pBuilder;
2684 if( diffFlags & DIFF_HTML ){
2685 pBuilder = dfsplitNew(pOut);
2686 }else{
2687 pBuilder = dfsbsNew(pOut, diffFlags);
2688 }
2689 formatDiff(&c, pRe, diffFlags, pBuilder);
2690 }else if( diffFlags & DIFF_DEBUG ){
2691 DiffBuilder *pBuilder = dfdebugNew(pOut);
2692 formatDiff(&c, pRe, diffFlags, pBuilder);
2693 }else if( diffFlags & DIFF_HTML ){
2694 DiffBuilder *pBuilder = dfunifiedNew(pOut);
2695 formatDiff(&c, pRe, diffFlags, pBuilder);
2696 }else{
2697 contextDiff(&c, pOut, diffFlags);
2698 }
2699 fossil_free(c.aFrom);
2700 fossil_free(c.aTo);
2701 fossil_free(c.aEdit);
2702 return 0;
@@ -2709,31 +2742,35 @@
2709 return c.aEdit;
2710 }
2711 }
2712
2713 /*
 
 
2714 ** Process diff-related command-line options and return an appropriate
2715 ** "diffFlags" integer.
2716 **
2717 ** --brief Show filenames only DIFF_BRIEF
2718 ** -c|--context N N lines of context. DIFF_CONTEXT_MASK
2719 ** --html Format for HTML DIFF_HTML
2720 ** --invert Invert the diff DIFF_INVERT
2721 ** -n|--linenum Show line numbers DIFF_LINENO
2722 ** --noopt Disable optimization DIFF_NOOPT
2723 ** --numstat Show change counts DIFF_NUMSTAT
2724 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
2725 ** --unified Unified diff. ~DIFF_SIDEBYSIDE
2726 ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
2727 ** -W|--width N N character lines. DIFF_WIDTH_MASK
2728 ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
2729 ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
2730 */
2731 u64 diff_options(void){
2732 u64 diffFlags = 0;
2733 const char *z;
2734 int f;
 
 
2735 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2736 diffFlags = DIFF_IGNORE_EOLWS;
2737 }
2738 if( find_option("ignore-all-space","w",0)!=0 ){
2739 diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
@@ -2780,11 +2817,11 @@
2780
2781 /* Undocumented and unsupported flags used for development
2782 ** debugging and analysis: */
2783 if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
2784 if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
2785 return diffFlags;
2786 }
2787
2788 /*
2789 ** COMMAND: test-diff
2790 ** COMMAND: xdiff
@@ -2802,39 +2839,38 @@
2802 ** See the "diff" command for a full list of command-line options.
2803 **
2804 ** This command used to be called "test-diff". The older "test-diff" spelling
2805 ** still works, for compatibility.
2806 */
2807 void test_diff_cmd(void){
2808 Blob a, b, out;
2809 u64 diffFlag;
2810 const char *zRe; /* Regex filter for diff output */
2811 ReCompiled *pRe = 0; /* Regex filter for diff output */
2812
2813 if( find_option("tk",0,0)!=0 ){
2814 diff_tk("test-diff", 2);
2815 return;
2816 }
2817 find_option("i",0,0);
2818 find_option("v",0,0);
 
2819 zRe = find_option("regexp","e",1);
2820 if( zRe ){
2821 const char *zErr = re_compile(&pRe, zRe, 0);
2822 if( zErr ) fossil_fatal("regex error: %s", zErr);
2823 }
2824 diffFlag = diff_options();
2825 verify_all_options();
2826 if( g.argc!=4 ) usage("FILE1 FILE2");
2827 blob_zero(&out);
2828 diff_begin(diffFlag);
2829 diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out);
2830 blob_read_from_file(&a, g.argv[2], ExtFILE);
2831 blob_read_from_file(&b, g.argv[3], ExtFILE);
2832 text_diff(&a, &b, &out, pRe, diffFlag);
2833 blob_write_to_file(&out, "-");
2834 diff_end(diffFlag, 0);
2835 re_free(pRe);
2836 }
2837
2838 /**************************************************************************
2839 ** The basic difference engine is above. What follows is the annotation
2840 ** engine. Both are in the same file since they share many components.
2841
--- src/diff.c
+++ src/diff.c
@@ -70,12 +70,47 @@
70 /*
71 ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes)
72 */
73 #define LENGTH_MASK_SZ 15
74 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
75
76 /*
77 ** An instance of this object describes the formatting and processing
78 ** details desired of a "diff" operation.
79 **
80 ** Conceptually, this object is as an encoding of the command-line options
81 ** for the "fossil diff" command. That is not a precise description, though,
82 ** because not all diff operations are started from the command-line. But
83 ** the idea is sound.
84 **
85 ** Information encoded by this object includes but is not limited to:
86 **
87 ** * The desired output format (unified vs. side-by-side,
88 ** TCL, JSON, HTML vs. plain-text).
89 **
90 ** * Number of lines of context surrounding each difference block
91 **
92 ** * Width of output columns for text side-by-side diffop
93 */
94 struct DiffConfig {
95 u64 diffFlags; /* Diff flags */
96 u32 nFile; /* Number of files diffed so far */
97 const char *zDiffCmd; /* External diff command to use instead of builtin */
98 const char *zBinGlob; /* GLOB pattern for binary files */
99 ReCompiled *pRe; /* Show only changes matching this pattern */
100 };
101
102 #endif /* INTERFACE */
103
104 /*
105 ** Initialize memory for a DiffConfig based on just a diffFlags integer.
106 */
107 DiffConfig *diff_config_init(DiffConfig *pCfg, u64 diffFlags){
108 memset(pCfg, 0, sizeof(*pCfg));
109 pCfg->diffFlags = diffFlags;
110 return pCfg;
111 }
112
113 /*
114 ** Information about each line of a file being diffed.
115 **
116 ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
@@ -332,11 +367,11 @@
367 ** Output a patch-style text diff.
368 */
369 static void contextDiff(
370 DContext *p, /* The difference */
371 Blob *pOut, /* Output a context diff to here */
372 DiffConfig *pCfg /* Configuration options */
373 ){
374 DLine *A; /* Left side of the diff */
375 DLine *B; /* Right side of the diff */
376 int a = 0; /* Index of next line in A[] */
377 int b = 0; /* Index of next line in B[] */
@@ -351,12 +386,12 @@
386 static int nChunk = 0; /* Number of diff chunks seen so far */
387 int nContext; /* Number of lines of context */
388 int showLn; /* Show line numbers */
389 int showDivider = 0; /* True to show the divider between diff blocks */
390
391 nContext = diff_context_lines(pCfg);
392 showLn = (pCfg->diffFlags & DIFF_LINENO)!=0;
393 A = p->aFrom;
394 B = p->aTo;
395 R = p->aEdit;
396 mxr = p->nEdit;
397 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1119,11 +1154,11 @@
1154 blob_append_char(p->pOut, ',');
1155 blob_append_json_literal(p->pOut, pX->z + x, pX->n - x);
1156 blob_append(p->pOut, "],\n",3);
1157 }
1158 static void dfjsonEnd(DiffBuilder *p){
1159 blob_append(p->pOut, "0]}", 3);
1160 fossil_free(p);
1161 }
1162 static DiffBuilder *dfjsonNew(Blob *pOut){
1163 DiffBuilder *p = fossil_malloc(sizeof(*p));
1164 p->xSkip = dfjsonSkip;
@@ -1631,21 +1666,21 @@
1666 blob_append_char(p->pOut, '\n');
1667 }
1668 static void dfsbsEnd(DiffBuilder *p){
1669 fossil_free(p);
1670 }
1671 static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){
1672 DiffBuilder *p = fossil_malloc(sizeof(*p));
1673 p->xSkip = dfsbsSkip;
1674 p->xCommon = dfsbsCommon;
1675 p->xInsert = dfsbsInsert;
1676 p->xDelete = dfsbsDelete;
1677 p->xReplace = dfsbsEdit;
1678 p->xEdit = dfsbsEdit;
1679 p->xEnd = dfsbsEnd;
1680 p->lnLeft = p->lnRight = 0;
1681 p->width = diff_width(pCfg);
1682 p->pOut = pOut;
1683 return p;
1684 }
1685 /****************************************************************************/
1686 /*
@@ -1767,11 +1802,11 @@
1802 ** mismatch.
1803 */
1804 static unsigned char *diffBlockAlignment(
1805 const DLine *aLeft, int nLeft, /* Text on the left */
1806 const DLine *aRight, int nRight, /* Text on the right */
1807 DiffConfig *pCfg, /* Configuration options */
1808 int *pNResult /* OUTPUT: Bytes of result */
1809 ){
1810 int i, j, k; /* Loop counters */
1811 int *a; /* One row of the Wagner matrix */
1812 int *pToFree; /* Space that needs to be freed */
@@ -1795,11 +1830,11 @@
1830 /* For large alignments, use a divide and conquer algorithm that is
1831 ** O(NlogN). The result is not as precise, but this whole thing is an
1832 ** approximation anyhow, and the faster response time is an acceptable
1833 ** trade-off for reduced precision.
1834 */
1835 if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
1836 const DLine *aSmall; /* The smaller of aLeft and aRight */
1837 const DLine *aBig; /* The larger of aLeft and aRight */
1838 int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
1839 int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
1840 int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
@@ -1832,14 +1867,14 @@
1867 iDivLeft = iDivBig;
1868 }else{
1869 iDivRight = iDivBig;
1870 iDivLeft = iDivSmall;
1871 }
1872 a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1);
1873 a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft,
1874 aRight+iDivRight, nRight-iDivRight,
1875 pCfg, &n2);
1876 a1 = fossil_realloc(a1, n1+n2 );
1877 memcpy(a1+n1,a2,n2);
1878 fossil_free(a2);
1879 *pNResult = n1+n2;
1880 return a1;
@@ -1938,12 +1973,11 @@
1973 /*
1974 ** Format a diff using a DiffBuilder object
1975 */
1976 static void formatDiff(
1977 DContext *p, /* The computed diff */
1978 DiffConfig *pCfg, /* Configuration options */
 
1979 DiffBuilder *pBuilder /* The formatter object */
1980 ){
1981 const DLine *A; /* Left side of the diff */
1982 const DLine *B; /* Right side of the diff */
1983 unsigned int a = 0; /* Index of next line in A[] */
@@ -1956,11 +1990,11 @@
1990 unsigned int i, j; /* Loop counters */
1991 unsigned int m, ma, mb;/* Number of lines to output */
1992 signed int skip = 0; /* Number of lines to skip */
1993 unsigned int nContext; /* Lines of context above and below each change */
1994
1995 nContext = diff_context_lines(pCfg);
1996 A = p->aFrom;
1997 B = p->aTo;
1998 R = p->aEdit;
1999 mxr = p->nEdit;
2000 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1972,19 +2006,19 @@
2006 /* If there is a regex, skip this block (generate no diff output)
2007 ** if the regex matches or does not match both insert and delete.
2008 ** Only display the block if one side matches but the other side does
2009 ** not.
2010 */
2011 if( pCfg->pRe ){
2012 int hideBlock = 1;
2013 int xa = a, xb = b;
2014 for(i=0; hideBlock && i<nr; i++){
2015 int c1, c2;
2016 xa += R[r+i*3];
2017 xb += R[r+i*3];
2018 c1 = re_dline_match(pCfg->pRe, &A[xa], R[r+i*3+1]);
2019 c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]);
2020 hideBlock = c1==c2;
2021 xa += R[r+i*3+1];
2022 xb += R[r+i*3+2];
2023 }
2024 if( hideBlock ){
@@ -2050,11 +2084,11 @@
2084 ma += R[r+i*3+1] + m;
2085 mb += R[r+i*3+2] + m;
2086 }
2087
2088 /* Try to find an alignment for the lines within this one block */
2089 alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign);
2090
2091 for(j=0; ma+mb>0; j++){
2092 assert( j<nAlign );
2093 switch( alignment[j] ){
2094 case 1: {
@@ -2511,13 +2545,13 @@
2545
2546 /*
2547 ** Extract the number of lines of context from diffFlags. Supply an
2548 ** appropriate default if no context width is specified.
2549 */
2550 int diff_context_lines(DiffConfig *pCfg){
2551 int n = pCfg->diffFlags & DIFF_CONTEXT_MASK;
2552 if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5;
2553 return n;
2554 }
2555
2556 /*
2557 ** Extract the width of columns for side-by-side diff. Supply an
@@ -2527,12 +2561,12 @@
2561 ** term-width = 2*diff-col + diff-marker + 1
2562 ** diff-col = lineno + lmargin + text-width + rmargin
2563 **
2564 ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin
2565 */
2566 int diff_width(DiffConfig *pCfg){
2567 int w = (pCfg->diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
2568 if( w==0 ){
2569 static struct {
2570 unsigned int lineno, lmargin, text, rmargin, marker;
2571 } sbsW = { 5, 2, 0, 0, 3 };
2572 const unsigned int wMin = 24, wMax = 132;
@@ -2589,41 +2623,40 @@
2623 */
2624 int *text_diff(
2625 Blob *pA_Blob, /* FROM file */
2626 Blob *pB_Blob, /* TO file */
2627 Blob *pOut, /* Write diff here if not NULL */
2628 DiffConfig *pCfg /* Configuration options */
 
2629 ){
2630 int ignoreWs; /* Ignore whitespace */
2631 DContext c;
2632
2633 if( pCfg->diffFlags & DIFF_INVERT ){
2634 Blob *pTemp = pA_Blob;
2635 pA_Blob = pB_Blob;
2636 pB_Blob = pTemp;
2637 }
2638 ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0;
2639 blob_to_utf8_no_bom(pA_Blob, 0);
2640 blob_to_utf8_no_bom(pB_Blob, 0);
2641
2642 /* Prepare the input files */
2643 memset(&c, 0, sizeof(c));
2644 if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2645 c.xDiffer = compare_dline_ignore_allws;
2646 }else{
2647 c.xDiffer = compare_dline;
2648 }
2649 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
2650 &c.nFrom, pCfg->diffFlags);
2651 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
2652 &c.nTo, pCfg->diffFlags);
2653 if( c.aFrom==0 || c.aTo==0 ){
2654 fossil_free(c.aFrom);
2655 fossil_free(c.aTo);
2656 if( pOut ){
2657 diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
2658 }
2659 return 0;
2660 }
2661
2662 /* Compute the difference */
@@ -2630,32 +2663,32 @@
2663 diff_all(&c);
2664 if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
2665 fossil_free(c.aFrom);
2666 fossil_free(c.aTo);
2667 fossil_free(c.aEdit);
2668 if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags);
2669 return 0;
2670 }
2671 if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){
2672 int i, m, n;
2673 int *a = c.aEdit;
2674 int mx = c.nEdit;
2675 for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
2676 if( n>10000 ){
2677 fossil_free(c.aFrom);
2678 fossil_free(c.aTo);
2679 fossil_free(c.aEdit);
2680 if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags);
2681 return 0;
2682 }
2683 }
2684 if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
2685 diff_optimize(&c);
2686 }
2687
2688 if( pOut ){
2689 if( pCfg->diffFlags & DIFF_NUMSTAT ){
2690 int nDel = 0, nIns = 0, i;
2691 for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
2692 nDel += c.aEdit[i+1];
2693 nIns += c.aEdit[i+2];
2694 }
@@ -2663,40 +2696,40 @@
2696 g.diffCnt[2] += nDel;
2697 if( nIns+nDel ){
2698 g.diffCnt[0]++;
2699 blob_appendf(pOut, "%10d %10d", nIns, nDel);
2700 }
2701 }else if( pCfg->diffFlags & DIFF_RAW ){
2702 const int *R = c.aEdit;
2703 unsigned int r;
2704 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
2705 blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
2706 R[r], R[r+1], R[r+2]);
2707 }
2708 }else if( pCfg->diffFlags & DIFF_JSON ){
2709 DiffBuilder *pBuilder = dfjsonNew(pOut);
2710 formatDiff(&c, pCfg, pBuilder);
2711 blob_append_char(pOut, '\n');
2712 }else if( pCfg->diffFlags & DIFF_TCL ){
2713 DiffBuilder *pBuilder = dftclNew(pOut);
2714 formatDiff(&c, pCfg, pBuilder);
2715 }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
2716 DiffBuilder *pBuilder;
2717 if( pCfg->diffFlags & DIFF_HTML ){
2718 pBuilder = dfsplitNew(pOut);
2719 }else{
2720 pBuilder = dfsbsNew(pOut, pCfg);
2721 }
2722 formatDiff(&c, pCfg, pBuilder);
2723 }else if( pCfg->diffFlags & DIFF_DEBUG ){
2724 DiffBuilder *pBuilder = dfdebugNew(pOut);
2725 formatDiff(&c, pCfg, pBuilder);
2726 }else if( pCfg->diffFlags & DIFF_HTML ){
2727 DiffBuilder *pBuilder = dfunifiedNew(pOut);
2728 formatDiff(&c, pCfg, pBuilder);
2729 }else{
2730 contextDiff(&c, pOut, pCfg);
2731 }
2732 fossil_free(c.aFrom);
2733 fossil_free(c.aTo);
2734 fossil_free(c.aEdit);
2735 return 0;
@@ -2709,31 +2742,35 @@
2742 return c.aEdit;
2743 }
2744 }
2745
2746 /*
2747 ** Initialize the DiffConfig object using command-line options.
2748 **
2749 ** Process diff-related command-line options and return an appropriate
2750 ** "diffFlags" integer.
2751 **
2752 ** --brief Show filenames only DIFF_BRIEF
2753 ** -c|--context N N lines of context. DIFF_CONTEXT_MASK
2754 ** --html Format for HTML DIFF_HTML
2755 ** --invert Invert the diff DIFF_INVERT
2756 ** -n|--linenum Show line numbers DIFF_LINENO
2757 ** --noopt Disable optimization DIFF_NOOPT
2758 ** --numstat Show change counts DIFF_NUMSTAT
2759 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
2760 ** --unified Unified diff. ~DIFF_SIDEBYSIDE
2761 ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS
2762 ** -W|--width N N character lines. DIFF_WIDTH_MASK
2763 ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE
2764 ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
2765 */
2766 void diff_options(DiffConfig *pCfg, int isGDiff){
2767 u64 diffFlags = 0;
2768 const char *z;
2769 int f;
2770
2771 memset(pCfg, 0, sizeof(*pCfg));
2772 if( find_option("ignore-trailing-space","Z",0)!=0 ){
2773 diffFlags = DIFF_IGNORE_EOLWS;
2774 }
2775 if( find_option("ignore-all-space","w",0)!=0 ){
2776 diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
@@ -2780,11 +2817,11 @@
2817
2818 /* Undocumented and unsupported flags used for development
2819 ** debugging and analysis: */
2820 if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
2821 if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW;
2822 pCfg->diffFlags = diffFlags;
2823 }
2824
2825 /*
2826 ** COMMAND: test-diff
2827 ** COMMAND: xdiff
@@ -2802,39 +2839,38 @@
2839 ** See the "diff" command for a full list of command-line options.
2840 **
2841 ** This command used to be called "test-diff". The older "test-diff" spelling
2842 ** still works, for compatibility.
2843 */
2844 void xdiff_cmd(void){
2845 Blob a, b, out;
 
2846 const char *zRe; /* Regex filter for diff output */
2847 DiffConfig DCfg;
2848
2849 if( find_option("tk",0,0)!=0 ){
2850 diff_tk("xdiff", 2);
2851 return;
2852 }
2853 find_option("i",0,0);
2854 find_option("v",0,0);
2855 diff_options(&DCfg, 0);
2856 zRe = find_option("regexp","e",1);
2857 if( zRe ){
2858 const char *zErr = re_compile(&DCfg.pRe, zRe, 0);
2859 if( zErr ) fossil_fatal("regex error: %s", zErr);
2860 }
 
2861 verify_all_options();
2862 if( g.argc!=4 ) usage("FILE1 FILE2");
2863 blob_zero(&out);
2864 diff_begin(&DCfg);
2865 diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
2866 blob_read_from_file(&a, g.argv[2], ExtFILE);
2867 blob_read_from_file(&b, g.argv[3], ExtFILE);
2868 text_diff(&a, &b, &out, &DCfg);
2869 blob_write_to_file(&out, "-");
2870 diff_end(&DCfg, 0);
2871 re_free(DCfg.pRe);
2872 }
2873
2874 /**************************************************************************
2875 ** The basic difference engine is above. What follows is the annotation
2876 ** engine. Both are in the same file since they share many components.
2877
+90 -68
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -113,13 +113,15 @@
113113
}
114114
115115
/*
116116
** Print the "Index:" message that patches wants to see at the top of a diff.
117117
*/
118
-void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){
119
- if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON|
120
- DIFF_WEBPAGE|DIFF_TCL))==0 ){
118
+void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *diffBlob){
119
+ if( (pCfg->diffFlags &
120
+ (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON|
121
+ DIFF_WEBPAGE|DIFF_TCL))==0
122
+ ){
121123
char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
122124
if( !diffBlob ){
123125
fossil_print("%s", z);
124126
}else{
125127
blob_appendf(diffBlob, "%s", z);
@@ -127,20 +129,22 @@
127129
fossil_free(z);
128130
}
129131
}
130132
131133
/*
132
-** Print the +++/--- filename lines for a diff operation.
134
+** Print the +++/--- filename lines or whatever filename information
135
+** is appropriate for the output format.
133136
*/
134137
void diff_print_filenames(
135
- const char *zLeft,
136
- const char *zRight,
137
- u64 diffFlags,
138
- Blob *diffBlob
138
+ const char *zLeft, /* Name of the left file */
139
+ const char *zRight, /* Name of the right file */
140
+ DiffConfig *pCfg, /* Diff configuration */
141
+ Blob *diffBlob /* Write to this blob, or stdout of this is NULL */
139142
){
140143
char *z = 0;
141
- if( diffFlags & (DIFF_BRIEF|DIFF_RAW|DIFF_JSON) ){
144
+ u64 diffFlags = pCfg->diffFlags;
145
+ if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
142146
/* no-op */
143147
}else if( diffFlags & DIFF_DEBUG ){
144148
fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n",
145149
zLeft, zRight);
146150
}else if( diffFlags & DIFF_WEBPAGE ){
@@ -147,31 +151,42 @@
147151
if( fossil_strcmp(zLeft,zRight)==0 ){
148152
z = mprintf("<h1>%h</h1>\n", zLeft);
149153
}else{
150154
z = mprintf("<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
151155
}
152
- }else if( diffFlags & DIFF_TCL ){
156
+ }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){
153157
Blob *pOut;
154158
Blob x;
155159
if( diffBlob ){
156160
pOut = diffBlob;
157161
}else{
158162
blob_init(&x, 0, 0);
159163
pOut = &x;
160164
}
161
- blob_append(pOut, "FILE ", 5);
162
- blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft));
163
- blob_append_char(pOut, ' ');
164
- blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight));
165
- blob_append_char(pOut, '\n');
165
+ if( diffFlags & DIFF_TCL ){
166
+ blob_append(pOut, "FILE ", 5);
167
+ blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft));
168
+ blob_append_char(pOut, ' ');
169
+ blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight));
170
+ blob_append_char(pOut, '\n');
171
+ }else{
172
+ blob_trim(pOut);
173
+ blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1);
174
+ pCfg->nFile++;
175
+ blob_append(pOut, "\n \"leftname\":", -1);
176
+ blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft));
177
+ blob_append(pOut, ",\n \"rightname\":", -1);
178
+ blob_append_json_literal(pOut, zRight, (int)strlen(zRight));
179
+ blob_append(pOut, ",\n \"diff\":\n", -1);
180
+ }
166181
if( !diffBlob ){
167182
fossil_print("%s", blob_str(pOut));
168183
blob_reset(&x);
169184
}
170185
return;
171186
}else if( diffFlags & DIFF_SIDEBYSIDE ){
172
- int w = diff_width(diffFlags);
187
+ int w = diff_width(pCfg);
173188
int n1 = strlen(zLeft);
174189
int n2 = strlen(zRight);
175190
int x;
176191
if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){
177192
if( n1>w*2 ) n1 = w*2;
@@ -282,11 +297,13 @@
282297
@ </body>
283298
@ </html>
284299
;
285300
286301
/*
287
-** State variables used by the --browser option for diff
302
+** State variables used by the --browser option for diff. These must
303
+** be static variables, not elements of DiffConfig, since they are
304
+** used by the interrupt handler.
288305
*/
289306
static char *tempDiffFilename; /* File holding the diff HTML */
290307
static FILE *diffOut; /* Open to write into tempDiffFilename */
291308
292309
/* Amount of delay (in milliseconds) between launching the
@@ -321,12 +338,12 @@
321338
** hold the result. Make arrangements to delete that temporary
322339
** file if the diff is interrupted.
323340
**
324341
** For --browser and --webpage, output the HTML header.
325342
*/
326
-void diff_begin(u64 diffFlags){
327
- if( (diffFlags & DIFF_BROWSER)!=0 ){
343
+void diff_begin(DiffConfig *pCfg){
344
+ if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){
328345
tempDiffFilename = fossil_temp_filename();
329346
tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
330347
diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
331348
if( diffOut==0 ){
332349
fossil_fatal("unable to create temporary file \"%s\"",
@@ -336,11 +353,11 @@
336353
signal(SIGINT, diff_www_interrupt);
337354
#else
338355
SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
339356
#endif
340357
}
341
- if( (diffFlags & DIFF_WEBPAGE)!=0 ){
358
+ if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
342359
fossil_print("%s",zWebpageHdr);
343360
fflush(stdout);
344361
}
345362
}
346363
@@ -352,19 +369,19 @@
352369
**
353370
** For --browser, close the connection to the temporary file, then
354371
** launch a web browser to view the file. After a delay
355372
** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file.
356373
*/
357
-void diff_end(u64 diffFlags, int nErr){
358
- if( (diffFlags & DIFF_WEBPAGE)!=0 ){
359
- if( diffFlags & DIFF_SIDEBYSIDE ){
374
+void diff_end(DiffConfig *pCfg, int nErr){
375
+ if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
376
+ if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
360377
const unsigned char *zJs = builtin_file("diff.js", 0);
361378
fossil_print("<script>\n%s</script>\n", zJs);
362379
}
363380
fossil_print("%s", zWebpageEnd);
364381
}
365
- if( (diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){
382
+ if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){
366383
char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename);
367384
fclose(diffOut);
368385
diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout);
369386
fossil_system(zCmd);
370387
fossil_free(zCmd);
@@ -371,10 +388,13 @@
371388
diffOut = 0;
372389
sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY);
373390
file_delete(tempDiffFilename);
374391
sqlite3_free(tempDiffFilename);
375392
tempDiffFilename = 0;
393
+ }
394
+ if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){
395
+ fossil_print("]\n");
376396
}
377397
}
378398
379399
/*
380400
** Show the difference between two files, one in memory and one on disk.
@@ -398,11 +418,11 @@
398418
const char *zFile2, /* On disk content to compare to */
399419
const char *zName, /* Display name of the file */
400420
const char *zDiffCmd, /* Command for comparison */
401421
const char *zBinGlob, /* Treat file names matching this as binary */
402422
int fIncludeBinary, /* Include binary files for external diff */
403
- u64 diffFlags, /* Flags to control the diff */
423
+ DiffConfig *pCfg, /* Flags to control the diff */
404424
int fSwapDiff, /* Diff from Zfile2 to Pfile1 */
405425
Blob *diffBlob /* Blob to store diff output */
406426
){
407427
if( zDiffCmd==0 ){
408428
Blob out; /* Diff output text */
@@ -417,34 +437,33 @@
417437
blob_read_from_file(&file2, zFile2, ExtFILE);
418438
zName2 = zName;
419439
}
420440
421441
/* Compute and output the differences */
422
- if( diffFlags & DIFF_BRIEF ){
442
+ if( pCfg->diffFlags & DIFF_BRIEF ){
423443
if( blob_compare(pFile1, &file2) ){
424444
fossil_print("CHANGED %s\n", zName);
425445
}
426446
}else{
427447
blob_zero(&out);
428448
if( fSwapDiff ){
429
- text_diff(&file2, pFile1, &out, 0, diffFlags);
449
+ text_diff(&file2, pFile1, &out, pCfg);
430450
}else{
431
- text_diff(pFile1, &file2, &out, 0, diffFlags);
451
+ text_diff(pFile1, &file2, &out, pCfg);
432452
}
433453
if( blob_size(&out) ){
434
- if( diffFlags & DIFF_NUMSTAT ){
454
+ if( pCfg->diffFlags & DIFF_NUMSTAT ){
435455
if( !diffBlob ){
436456
fossil_print("%s %s\n", blob_str(&out), zName);
437457
}else{
438458
blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName);
439459
}
440460
}else{
461
+ diff_print_filenames(zName, zName2, pCfg, diffBlob);
441462
if( !diffBlob ){
442
- diff_print_filenames(zName, zName2, diffFlags, 0);
443463
fossil_print("%s\n", blob_str(&out));
444464
}else{
445
- diff_print_filenames(zName, zName2, diffFlags, diffBlob);
446465
blob_appendf(diffBlob, "%s\n", blob_str(&out));
447466
}
448467
}
449468
}
450469
blob_reset(&out);
@@ -529,22 +548,22 @@
529548
int isBin2, /* Does the 'to' content appear to be binary */
530549
const char *zName, /* Display name of the file */
531550
const char *zDiffCmd, /* Command for comparison */
532551
const char *zBinGlob, /* Treat file names matching this as binary */
533552
int fIncludeBinary, /* Include binary files for external diff */
534
- u64 diffFlags /* Diff flags */
553
+ DiffConfig *pCfg /* Diff flags */
535554
){
536
- if( diffFlags & DIFF_BRIEF ) return;
555
+ if( pCfg->diffFlags & DIFF_BRIEF ) return;
537556
if( zDiffCmd==0 ){
538557
Blob out; /* Diff output text */
539558
540559
blob_zero(&out);
541
- text_diff(pFile1, pFile2, &out, 0, diffFlags);
542
- if( diffFlags & DIFF_NUMSTAT ){
560
+ text_diff(pFile1, pFile2, &out, pCfg);
561
+ if( pCfg->diffFlags & DIFF_NUMSTAT ){
543562
fossil_print("%s %s\n", blob_str(&out), zName);
544563
}else{
545
- diff_print_filenames(zName, zName, diffFlags, 0);
564
+ diff_print_filenames(zName, zName, pCfg, 0);
546565
fossil_print("%s\n", blob_str(&out));
547566
}
548567
549568
/* Release memory resources */
550569
blob_reset(&out);
@@ -609,22 +628,22 @@
609628
void diff_against_disk(
610629
const char *zFrom, /* Version to difference from */
611630
const char *zDiffCmd, /* Use this diff command. NULL for built-in */
612631
const char *zBinGlob, /* Treat file names matching this as binary */
613632
int fIncludeBinary, /* Treat file names matching this as binary */
614
- u64 diffFlags, /* Flags controlling diff output */
633
+ DiffConfig *pCfg, /* Flags controlling diff output */
615634
FileDirList *pFileDir, /* Which files to diff */
616635
Blob *diffBlob /* Blob to output diff instead of stdout */
617636
){
618637
int vid;
619638
Blob sql;
620639
Stmt q;
621640
int asNewFile; /* Treat non-existant files as empty files */
622641
int isNumStat; /* True for --numstat */
623642
624
- asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0;
625
- isNumStat = (diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0;
643
+ asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0;
644
+ isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0;
626645
vid = db_lget_int("checkout", 0);
627646
vfile_check_signature(vid, CKSIG_ENOTFILE);
628647
blob_zero(&sql);
629648
db_begin_transaction();
630649
if( zFrom ){
@@ -706,24 +725,24 @@
706725
}
707726
if( showDiff ){
708727
Blob content;
709728
int isBin;
710729
if( !isLink != !file_islink(zFullName) ){
711
- diff_print_index(zPathname, diffFlags, 0);
712
- diff_print_filenames(zPathname, zPathname, diffFlags, 0);
730
+ diff_print_index(zPathname, pCfg, 0);
731
+ diff_print_filenames(zPathname, zPathname, pCfg, 0);
713732
fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
714733
continue;
715734
}
716735
if( srcid>0 ){
717736
content_get(srcid, &content);
718737
}else{
719738
blob_zero(&content);
720739
}
721740
isBin = fIncludeBinary ? 0 : looks_like_binary(&content);
722
- diff_print_index(zPathname, diffFlags, diffBlob);
741
+ diff_print_index(zPathname, pCfg, diffBlob);
723742
diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
724
- zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob);
743
+ zBinGlob, fIncludeBinary, pCfg, 0, diffBlob);
725744
blob_reset(&content);
726745
}
727746
blob_reset(&fname);
728747
}
729748
db_finalize(&q);
@@ -742,11 +761,11 @@
742761
*/
743762
static void diff_against_undo(
744763
const char *zDiffCmd, /* Use this diff command. NULL for built-in */
745764
const char *zBinGlob, /* Treat file names matching this as binary */
746765
int fIncludeBinary, /* Treat file names matching this as binary */
747
- u64 diffFlags, /* Flags controlling diff output */
766
+ DiffConfig *pCfg, /* Flags controlling diff output */
748767
FileDirList *pFileDir /* List of files and directories to diff */
749768
){
750769
Stmt q;
751770
Blob content;
752771
db_prepare(&q, "SELECT pathname, content FROM undo");
@@ -756,11 +775,11 @@
756775
const char *zFile = (const char*)db_column_text(&q, 0);
757776
if( !file_dir_match(pFileDir, zFile) ) continue;
758777
zFullName = mprintf("%s%s", g.zLocalRoot, zFile);
759778
db_column_blob(&q, 1, &content);
760779
diff_file(&content, 0, zFullName, zFile,
761
- zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0);
780
+ zDiffCmd, zBinGlob, fIncludeBinary, pCfg, 0, 0);
762781
fossil_free(zFullName);
763782
blob_reset(&content);
764783
}
765784
db_finalize(&q);
766785
}
@@ -780,11 +799,11 @@
780799
struct ManifestFile *pFrom,
781800
struct ManifestFile *pTo,
782801
const char *zDiffCmd,
783802
const char *zBinGlob,
784803
int fIncludeBinary,
785
- u64 diffFlags
804
+ DiffConfig *pCfg
786805
){
787806
Blob f1, f2;
788807
int isBin1, isBin2;
789808
int rid;
790809
const char *zName;
@@ -793,12 +812,12 @@
793812
}else if( pTo ){
794813
zName = pTo->zName;
795814
}else{
796815
zName = DIFF_NO_NAME;
797816
}
798
- if( diffFlags & DIFF_BRIEF ) return;
799
- diff_print_index(zName, diffFlags, 0);
817
+ if( pCfg->diffFlags & DIFF_BRIEF ) return;
818
+ diff_print_index(zName, pCfg, 0);
800819
if( pFrom ){
801820
rid = uuid_to_rid(pFrom->zUuid, 0);
802821
content_get(rid, &f1);
803822
}else{
804823
blob_zero(&f1);
@@ -810,11 +829,11 @@
810829
blob_zero(&f2);
811830
}
812831
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1);
813832
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2);
814833
diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd,
815
- zBinGlob, fIncludeBinary, diffFlags);
834
+ zBinGlob, fIncludeBinary, pCfg);
816835
blob_reset(&f1);
817836
blob_reset(&f2);
818837
}
819838
820839
/*
@@ -831,16 +850,16 @@
831850
const char *zFrom,
832851
const char *zTo,
833852
const char *zDiffCmd,
834853
const char *zBinGlob,
835854
int fIncludeBinary,
836
- u64 diffFlags,
855
+ DiffConfig *pCfg,
837856
FileDirList *pFileDir
838857
){
839858
Manifest *pFrom, *pTo;
840859
ManifestFile *pFromFile, *pToFile;
841
- int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;
860
+ int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;
842861
843862
pFrom = manifest_get_by_name(zFrom, 0);
844863
manifest_file_rewind(pFrom);
845864
pFromFile = manifest_file_next(pFrom,0);
846865
pTo = manifest_get_by_name(zTo, 0);
@@ -856,27 +875,28 @@
856875
}else{
857876
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
858877
}
859878
if( cmp<0 ){
860879
if( file_dir_match(pFileDir, pFromFile->zName) ){
861
- if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
880
+ if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
862881
fossil_print("DELETED %s\n", pFromFile->zName);
863882
}
864883
if( asNewFlag ){
865884
diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob,
866
- fIncludeBinary, diffFlags);
885
+ fIncludeBinary, pCfg);
867886
}
868887
}
869888
pFromFile = manifest_file_next(pFrom,0);
870889
}else if( cmp>0 ){
871890
if( file_dir_match(pFileDir, pToFile->zName) ){
872
- if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
891
+ if( (pCfg->diffFlags &
892
+ (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
873893
fossil_print("ADDED %s\n", pToFile->zName);
874894
}
875895
if( asNewFlag ){
876896
diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob,
877
- fIncludeBinary, diffFlags);
897
+ fIncludeBinary, pCfg);
878898
}
879899
}
880900
pToFile = manifest_file_next(pTo,0);
881901
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
882902
/* No changes */
@@ -883,15 +903,15 @@
883903
(void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
884904
pFromFile = manifest_file_next(pFrom,0);
885905
pToFile = manifest_file_next(pTo,0);
886906
}else{
887907
if( file_dir_match(pFileDir, pToFile->zName) ){
888
- if( diffFlags & DIFF_BRIEF ){
908
+ if( pCfg->diffFlags & DIFF_BRIEF ){
889909
fossil_print("CHANGED %s\n", pFromFile->zName);
890910
}else{
891911
diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob,
892
- fIncludeBinary, diffFlags);
912
+ fIncludeBinary, pCfg);
893913
}
894914
}
895915
pFromFile = manifest_file_next(pFrom,0);
896916
pToFile = manifest_file_next(pTo,0);
897917
}
@@ -1107,12 +1127,12 @@
11071127
const char *zBranch; /* Branch to diff */
11081128
const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
11091129
const char *zBinGlob = 0; /* Treat file names matching this as binary */
11101130
int fIncludeBinary = 0; /* Include binary files for external diff */
11111131
int againstUndo = 0; /* Diff against files in the undo buffer */
1112
- u64 diffFlags = 0; /* Flags to control the DIFF */
11131132
FileDirList *pFileDir = 0; /* Restrict the diff to these files */
1133
+ DiffConfig DCfg; /* Diff configuration object */
11141134
11151135
if( find_option("tk",0,0)!=0 || has_option("tclsh") ){
11161136
diff_tk("diff", 2);
11171137
return;
11181138
}
@@ -1121,16 +1141,16 @@
11211141
zFrom = find_option("from", "r", 1);
11221142
zTo = find_option("to", 0, 1);
11231143
zCheckin = find_option("checkin", 0, 1);
11241144
zBranch = find_option("branch", 0, 1);
11251145
againstUndo = find_option("undo",0,0)!=0;
1126
- diffFlags = diff_options();
1146
+ diff_options(&DCfg, isGDiff);
11271147
verboseFlag = find_option("verbose","v",0)!=0;
11281148
if( !verboseFlag ){
11291149
verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */
11301150
}
1131
- if( verboseFlag ) diffFlags |= DIFF_VERBOSE;
1151
+ if( verboseFlag ) DCfg.diffFlags |= DIFF_VERBOSE;
11321152
if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
11331153
fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
11341154
" or --branch");
11351155
}
11361156
if( zBranch ){
@@ -1150,11 +1170,11 @@
11501170
fossil_fatal("must use --from if --to is present");
11511171
}else{
11521172
db_find_and_open_repository(0, 0);
11531173
}
11541174
if( !isInternDiff
1155
- && (diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */
1175
+ && (DCfg.diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */
11561176
){
11571177
zDiffCmd = find_option("command", 0, 1);
11581178
if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff);
11591179
}
11601180
zBinGlob = diff_get_binary_glob();
@@ -1188,24 +1208,24 @@
11881208
ridTo);
11891209
if( zFrom==0 ){
11901210
fossil_fatal("check-in %s has no parent", zTo);
11911211
}
11921212
}
1193
- diff_begin(diffFlags);
1213
+ diff_begin(&DCfg);
11941214
if( againstUndo ){
11951215
if( db_lget_int("undo_available",0)==0 ){
11961216
fossil_print("No undo or redo is available\n");
11971217
return;
11981218
}
11991219
diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary,
1200
- diffFlags, pFileDir);
1220
+ &DCfg, pFileDir);
12011221
}else if( zTo==0 ){
12021222
diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary,
1203
- diffFlags, pFileDir, 0);
1223
+ &DCfg, pFileDir, 0);
12041224
}else{
12051225
diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary,
1206
- diffFlags, pFileDir);
1226
+ &DCfg, pFileDir);
12071227
}
12081228
if( pFileDir ){
12091229
int i;
12101230
for(i=0; pFileDir[i].zName; i++){
12111231
if( pFileDir[i].nUsed==0
@@ -1216,12 +1236,12 @@
12161236
}
12171237
fossil_free(pFileDir[i].zName);
12181238
}
12191239
fossil_free(pFileDir);
12201240
}
1221
- diff_end(diffFlags, 0);
1222
- if ( diffFlags & DIFF_NUMSTAT ){
1241
+ diff_end(&DCfg, 0);
1242
+ if ( DCfg.diffFlags & DIFF_NUMSTAT ){
12231243
fossil_print("%10d %10d TOTAL over %d changed files\n",
12241244
g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
12251245
}
12261246
}
12271247
@@ -1232,12 +1252,14 @@
12321252
** Show a patch that goes from check-in FROM to check-in TO.
12331253
*/
12341254
void vpatch_page(void){
12351255
const char *zFrom = P("from");
12361256
const char *zTo = P("to");
1257
+ DiffConfig DCfg;
12371258
login_check_credentials();
12381259
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
12391260
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
12401261
12411262
cgi_set_content_type("text/plain");
1242
- diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
1263
+ diff_config_init(&DCfg, DIFF_VERBOSE);
1264
+ diff_two_versions(zFrom, zTo, 0, 0, 0, &DCfg, 0);
12431265
}
12441266
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -113,13 +113,15 @@
113 }
114
115 /*
116 ** Print the "Index:" message that patches wants to see at the top of a diff.
117 */
118 void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){
119 if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON|
120 DIFF_WEBPAGE|DIFF_TCL))==0 ){
 
 
121 char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
122 if( !diffBlob ){
123 fossil_print("%s", z);
124 }else{
125 blob_appendf(diffBlob, "%s", z);
@@ -127,20 +129,22 @@
127 fossil_free(z);
128 }
129 }
130
131 /*
132 ** Print the +++/--- filename lines for a diff operation.
 
133 */
134 void diff_print_filenames(
135 const char *zLeft,
136 const char *zRight,
137 u64 diffFlags,
138 Blob *diffBlob
139 ){
140 char *z = 0;
141 if( diffFlags & (DIFF_BRIEF|DIFF_RAW|DIFF_JSON) ){
 
142 /* no-op */
143 }else if( diffFlags & DIFF_DEBUG ){
144 fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n",
145 zLeft, zRight);
146 }else if( diffFlags & DIFF_WEBPAGE ){
@@ -147,31 +151,42 @@
147 if( fossil_strcmp(zLeft,zRight)==0 ){
148 z = mprintf("<h1>%h</h1>\n", zLeft);
149 }else{
150 z = mprintf("<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
151 }
152 }else if( diffFlags & DIFF_TCL ){
153 Blob *pOut;
154 Blob x;
155 if( diffBlob ){
156 pOut = diffBlob;
157 }else{
158 blob_init(&x, 0, 0);
159 pOut = &x;
160 }
161 blob_append(pOut, "FILE ", 5);
162 blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft));
163 blob_append_char(pOut, ' ');
164 blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight));
165 blob_append_char(pOut, '\n');
 
 
 
 
 
 
 
 
 
 
 
166 if( !diffBlob ){
167 fossil_print("%s", blob_str(pOut));
168 blob_reset(&x);
169 }
170 return;
171 }else if( diffFlags & DIFF_SIDEBYSIDE ){
172 int w = diff_width(diffFlags);
173 int n1 = strlen(zLeft);
174 int n2 = strlen(zRight);
175 int x;
176 if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){
177 if( n1>w*2 ) n1 = w*2;
@@ -282,11 +297,13 @@
282 @ </body>
283 @ </html>
284 ;
285
286 /*
287 ** State variables used by the --browser option for diff
 
 
288 */
289 static char *tempDiffFilename; /* File holding the diff HTML */
290 static FILE *diffOut; /* Open to write into tempDiffFilename */
291
292 /* Amount of delay (in milliseconds) between launching the
@@ -321,12 +338,12 @@
321 ** hold the result. Make arrangements to delete that temporary
322 ** file if the diff is interrupted.
323 **
324 ** For --browser and --webpage, output the HTML header.
325 */
326 void diff_begin(u64 diffFlags){
327 if( (diffFlags & DIFF_BROWSER)!=0 ){
328 tempDiffFilename = fossil_temp_filename();
329 tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
330 diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
331 if( diffOut==0 ){
332 fossil_fatal("unable to create temporary file \"%s\"",
@@ -336,11 +353,11 @@
336 signal(SIGINT, diff_www_interrupt);
337 #else
338 SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
339 #endif
340 }
341 if( (diffFlags & DIFF_WEBPAGE)!=0 ){
342 fossil_print("%s",zWebpageHdr);
343 fflush(stdout);
344 }
345 }
346
@@ -352,19 +369,19 @@
352 **
353 ** For --browser, close the connection to the temporary file, then
354 ** launch a web browser to view the file. After a delay
355 ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file.
356 */
357 void diff_end(u64 diffFlags, int nErr){
358 if( (diffFlags & DIFF_WEBPAGE)!=0 ){
359 if( diffFlags & DIFF_SIDEBYSIDE ){
360 const unsigned char *zJs = builtin_file("diff.js", 0);
361 fossil_print("<script>\n%s</script>\n", zJs);
362 }
363 fossil_print("%s", zWebpageEnd);
364 }
365 if( (diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){
366 char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename);
367 fclose(diffOut);
368 diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout);
369 fossil_system(zCmd);
370 fossil_free(zCmd);
@@ -371,10 +388,13 @@
371 diffOut = 0;
372 sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY);
373 file_delete(tempDiffFilename);
374 sqlite3_free(tempDiffFilename);
375 tempDiffFilename = 0;
 
 
 
376 }
377 }
378
379 /*
380 ** Show the difference between two files, one in memory and one on disk.
@@ -398,11 +418,11 @@
398 const char *zFile2, /* On disk content to compare to */
399 const char *zName, /* Display name of the file */
400 const char *zDiffCmd, /* Command for comparison */
401 const char *zBinGlob, /* Treat file names matching this as binary */
402 int fIncludeBinary, /* Include binary files for external diff */
403 u64 diffFlags, /* Flags to control the diff */
404 int fSwapDiff, /* Diff from Zfile2 to Pfile1 */
405 Blob *diffBlob /* Blob to store diff output */
406 ){
407 if( zDiffCmd==0 ){
408 Blob out; /* Diff output text */
@@ -417,34 +437,33 @@
417 blob_read_from_file(&file2, zFile2, ExtFILE);
418 zName2 = zName;
419 }
420
421 /* Compute and output the differences */
422 if( diffFlags & DIFF_BRIEF ){
423 if( blob_compare(pFile1, &file2) ){
424 fossil_print("CHANGED %s\n", zName);
425 }
426 }else{
427 blob_zero(&out);
428 if( fSwapDiff ){
429 text_diff(&file2, pFile1, &out, 0, diffFlags);
430 }else{
431 text_diff(pFile1, &file2, &out, 0, diffFlags);
432 }
433 if( blob_size(&out) ){
434 if( diffFlags & DIFF_NUMSTAT ){
435 if( !diffBlob ){
436 fossil_print("%s %s\n", blob_str(&out), zName);
437 }else{
438 blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName);
439 }
440 }else{
 
441 if( !diffBlob ){
442 diff_print_filenames(zName, zName2, diffFlags, 0);
443 fossil_print("%s\n", blob_str(&out));
444 }else{
445 diff_print_filenames(zName, zName2, diffFlags, diffBlob);
446 blob_appendf(diffBlob, "%s\n", blob_str(&out));
447 }
448 }
449 }
450 blob_reset(&out);
@@ -529,22 +548,22 @@
529 int isBin2, /* Does the 'to' content appear to be binary */
530 const char *zName, /* Display name of the file */
531 const char *zDiffCmd, /* Command for comparison */
532 const char *zBinGlob, /* Treat file names matching this as binary */
533 int fIncludeBinary, /* Include binary files for external diff */
534 u64 diffFlags /* Diff flags */
535 ){
536 if( diffFlags & DIFF_BRIEF ) return;
537 if( zDiffCmd==0 ){
538 Blob out; /* Diff output text */
539
540 blob_zero(&out);
541 text_diff(pFile1, pFile2, &out, 0, diffFlags);
542 if( diffFlags & DIFF_NUMSTAT ){
543 fossil_print("%s %s\n", blob_str(&out), zName);
544 }else{
545 diff_print_filenames(zName, zName, diffFlags, 0);
546 fossil_print("%s\n", blob_str(&out));
547 }
548
549 /* Release memory resources */
550 blob_reset(&out);
@@ -609,22 +628,22 @@
609 void diff_against_disk(
610 const char *zFrom, /* Version to difference from */
611 const char *zDiffCmd, /* Use this diff command. NULL for built-in */
612 const char *zBinGlob, /* Treat file names matching this as binary */
613 int fIncludeBinary, /* Treat file names matching this as binary */
614 u64 diffFlags, /* Flags controlling diff output */
615 FileDirList *pFileDir, /* Which files to diff */
616 Blob *diffBlob /* Blob to output diff instead of stdout */
617 ){
618 int vid;
619 Blob sql;
620 Stmt q;
621 int asNewFile; /* Treat non-existant files as empty files */
622 int isNumStat; /* True for --numstat */
623
624 asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0;
625 isNumStat = (diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0;
626 vid = db_lget_int("checkout", 0);
627 vfile_check_signature(vid, CKSIG_ENOTFILE);
628 blob_zero(&sql);
629 db_begin_transaction();
630 if( zFrom ){
@@ -706,24 +725,24 @@
706 }
707 if( showDiff ){
708 Blob content;
709 int isBin;
710 if( !isLink != !file_islink(zFullName) ){
711 diff_print_index(zPathname, diffFlags, 0);
712 diff_print_filenames(zPathname, zPathname, diffFlags, 0);
713 fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
714 continue;
715 }
716 if( srcid>0 ){
717 content_get(srcid, &content);
718 }else{
719 blob_zero(&content);
720 }
721 isBin = fIncludeBinary ? 0 : looks_like_binary(&content);
722 diff_print_index(zPathname, diffFlags, diffBlob);
723 diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
724 zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob);
725 blob_reset(&content);
726 }
727 blob_reset(&fname);
728 }
729 db_finalize(&q);
@@ -742,11 +761,11 @@
742 */
743 static void diff_against_undo(
744 const char *zDiffCmd, /* Use this diff command. NULL for built-in */
745 const char *zBinGlob, /* Treat file names matching this as binary */
746 int fIncludeBinary, /* Treat file names matching this as binary */
747 u64 diffFlags, /* Flags controlling diff output */
748 FileDirList *pFileDir /* List of files and directories to diff */
749 ){
750 Stmt q;
751 Blob content;
752 db_prepare(&q, "SELECT pathname, content FROM undo");
@@ -756,11 +775,11 @@
756 const char *zFile = (const char*)db_column_text(&q, 0);
757 if( !file_dir_match(pFileDir, zFile) ) continue;
758 zFullName = mprintf("%s%s", g.zLocalRoot, zFile);
759 db_column_blob(&q, 1, &content);
760 diff_file(&content, 0, zFullName, zFile,
761 zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0);
762 fossil_free(zFullName);
763 blob_reset(&content);
764 }
765 db_finalize(&q);
766 }
@@ -780,11 +799,11 @@
780 struct ManifestFile *pFrom,
781 struct ManifestFile *pTo,
782 const char *zDiffCmd,
783 const char *zBinGlob,
784 int fIncludeBinary,
785 u64 diffFlags
786 ){
787 Blob f1, f2;
788 int isBin1, isBin2;
789 int rid;
790 const char *zName;
@@ -793,12 +812,12 @@
793 }else if( pTo ){
794 zName = pTo->zName;
795 }else{
796 zName = DIFF_NO_NAME;
797 }
798 if( diffFlags & DIFF_BRIEF ) return;
799 diff_print_index(zName, diffFlags, 0);
800 if( pFrom ){
801 rid = uuid_to_rid(pFrom->zUuid, 0);
802 content_get(rid, &f1);
803 }else{
804 blob_zero(&f1);
@@ -810,11 +829,11 @@
810 blob_zero(&f2);
811 }
812 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1);
813 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2);
814 diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd,
815 zBinGlob, fIncludeBinary, diffFlags);
816 blob_reset(&f1);
817 blob_reset(&f2);
818 }
819
820 /*
@@ -831,16 +850,16 @@
831 const char *zFrom,
832 const char *zTo,
833 const char *zDiffCmd,
834 const char *zBinGlob,
835 int fIncludeBinary,
836 u64 diffFlags,
837 FileDirList *pFileDir
838 ){
839 Manifest *pFrom, *pTo;
840 ManifestFile *pFromFile, *pToFile;
841 int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;
842
843 pFrom = manifest_get_by_name(zFrom, 0);
844 manifest_file_rewind(pFrom);
845 pFromFile = manifest_file_next(pFrom,0);
846 pTo = manifest_get_by_name(zTo, 0);
@@ -856,27 +875,28 @@
856 }else{
857 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
858 }
859 if( cmp<0 ){
860 if( file_dir_match(pFileDir, pFromFile->zName) ){
861 if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
862 fossil_print("DELETED %s\n", pFromFile->zName);
863 }
864 if( asNewFlag ){
865 diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob,
866 fIncludeBinary, diffFlags);
867 }
868 }
869 pFromFile = manifest_file_next(pFrom,0);
870 }else if( cmp>0 ){
871 if( file_dir_match(pFileDir, pToFile->zName) ){
872 if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
 
873 fossil_print("ADDED %s\n", pToFile->zName);
874 }
875 if( asNewFlag ){
876 diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob,
877 fIncludeBinary, diffFlags);
878 }
879 }
880 pToFile = manifest_file_next(pTo,0);
881 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
882 /* No changes */
@@ -883,15 +903,15 @@
883 (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
884 pFromFile = manifest_file_next(pFrom,0);
885 pToFile = manifest_file_next(pTo,0);
886 }else{
887 if( file_dir_match(pFileDir, pToFile->zName) ){
888 if( diffFlags & DIFF_BRIEF ){
889 fossil_print("CHANGED %s\n", pFromFile->zName);
890 }else{
891 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob,
892 fIncludeBinary, diffFlags);
893 }
894 }
895 pFromFile = manifest_file_next(pFrom,0);
896 pToFile = manifest_file_next(pTo,0);
897 }
@@ -1107,12 +1127,12 @@
1107 const char *zBranch; /* Branch to diff */
1108 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
1109 const char *zBinGlob = 0; /* Treat file names matching this as binary */
1110 int fIncludeBinary = 0; /* Include binary files for external diff */
1111 int againstUndo = 0; /* Diff against files in the undo buffer */
1112 u64 diffFlags = 0; /* Flags to control the DIFF */
1113 FileDirList *pFileDir = 0; /* Restrict the diff to these files */
 
1114
1115 if( find_option("tk",0,0)!=0 || has_option("tclsh") ){
1116 diff_tk("diff", 2);
1117 return;
1118 }
@@ -1121,16 +1141,16 @@
1121 zFrom = find_option("from", "r", 1);
1122 zTo = find_option("to", 0, 1);
1123 zCheckin = find_option("checkin", 0, 1);
1124 zBranch = find_option("branch", 0, 1);
1125 againstUndo = find_option("undo",0,0)!=0;
1126 diffFlags = diff_options();
1127 verboseFlag = find_option("verbose","v",0)!=0;
1128 if( !verboseFlag ){
1129 verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */
1130 }
1131 if( verboseFlag ) diffFlags |= DIFF_VERBOSE;
1132 if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
1133 fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
1134 " or --branch");
1135 }
1136 if( zBranch ){
@@ -1150,11 +1170,11 @@
1150 fossil_fatal("must use --from if --to is present");
1151 }else{
1152 db_find_and_open_repository(0, 0);
1153 }
1154 if( !isInternDiff
1155 && (diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */
1156 ){
1157 zDiffCmd = find_option("command", 0, 1);
1158 if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff);
1159 }
1160 zBinGlob = diff_get_binary_glob();
@@ -1188,24 +1208,24 @@
1188 ridTo);
1189 if( zFrom==0 ){
1190 fossil_fatal("check-in %s has no parent", zTo);
1191 }
1192 }
1193 diff_begin(diffFlags);
1194 if( againstUndo ){
1195 if( db_lget_int("undo_available",0)==0 ){
1196 fossil_print("No undo or redo is available\n");
1197 return;
1198 }
1199 diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary,
1200 diffFlags, pFileDir);
1201 }else if( zTo==0 ){
1202 diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary,
1203 diffFlags, pFileDir, 0);
1204 }else{
1205 diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary,
1206 diffFlags, pFileDir);
1207 }
1208 if( pFileDir ){
1209 int i;
1210 for(i=0; pFileDir[i].zName; i++){
1211 if( pFileDir[i].nUsed==0
@@ -1216,12 +1236,12 @@
1216 }
1217 fossil_free(pFileDir[i].zName);
1218 }
1219 fossil_free(pFileDir);
1220 }
1221 diff_end(diffFlags, 0);
1222 if ( diffFlags & DIFF_NUMSTAT ){
1223 fossil_print("%10d %10d TOTAL over %d changed files\n",
1224 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
1225 }
1226 }
1227
@@ -1232,12 +1252,14 @@
1232 ** Show a patch that goes from check-in FROM to check-in TO.
1233 */
1234 void vpatch_page(void){
1235 const char *zFrom = P("from");
1236 const char *zTo = P("to");
 
1237 login_check_credentials();
1238 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1239 if( zFrom==0 || zTo==0 ) fossil_redirect_home();
1240
1241 cgi_set_content_type("text/plain");
1242 diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
 
1243 }
1244
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -113,13 +113,15 @@
113 }
114
115 /*
116 ** Print the "Index:" message that patches wants to see at the top of a diff.
117 */
118 void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *diffBlob){
119 if( (pCfg->diffFlags &
120 (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON|
121 DIFF_WEBPAGE|DIFF_TCL))==0
122 ){
123 char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
124 if( !diffBlob ){
125 fossil_print("%s", z);
126 }else{
127 blob_appendf(diffBlob, "%s", z);
@@ -127,20 +129,22 @@
129 fossil_free(z);
130 }
131 }
132
133 /*
134 ** Print the +++/--- filename lines or whatever filename information
135 ** is appropriate for the output format.
136 */
137 void diff_print_filenames(
138 const char *zLeft, /* Name of the left file */
139 const char *zRight, /* Name of the right file */
140 DiffConfig *pCfg, /* Diff configuration */
141 Blob *diffBlob /* Write to this blob, or stdout of this is NULL */
142 ){
143 char *z = 0;
144 u64 diffFlags = pCfg->diffFlags;
145 if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
146 /* no-op */
147 }else if( diffFlags & DIFF_DEBUG ){
148 fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n",
149 zLeft, zRight);
150 }else if( diffFlags & DIFF_WEBPAGE ){
@@ -147,31 +151,42 @@
151 if( fossil_strcmp(zLeft,zRight)==0 ){
152 z = mprintf("<h1>%h</h1>\n", zLeft);
153 }else{
154 z = mprintf("<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
155 }
156 }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){
157 Blob *pOut;
158 Blob x;
159 if( diffBlob ){
160 pOut = diffBlob;
161 }else{
162 blob_init(&x, 0, 0);
163 pOut = &x;
164 }
165 if( diffFlags & DIFF_TCL ){
166 blob_append(pOut, "FILE ", 5);
167 blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft));
168 blob_append_char(pOut, ' ');
169 blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight));
170 blob_append_char(pOut, '\n');
171 }else{
172 blob_trim(pOut);
173 blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1);
174 pCfg->nFile++;
175 blob_append(pOut, "\n \"leftname\":", -1);
176 blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft));
177 blob_append(pOut, ",\n \"rightname\":", -1);
178 blob_append_json_literal(pOut, zRight, (int)strlen(zRight));
179 blob_append(pOut, ",\n \"diff\":\n", -1);
180 }
181 if( !diffBlob ){
182 fossil_print("%s", blob_str(pOut));
183 blob_reset(&x);
184 }
185 return;
186 }else if( diffFlags & DIFF_SIDEBYSIDE ){
187 int w = diff_width(pCfg);
188 int n1 = strlen(zLeft);
189 int n2 = strlen(zRight);
190 int x;
191 if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){
192 if( n1>w*2 ) n1 = w*2;
@@ -282,11 +297,13 @@
297 @ </body>
298 @ </html>
299 ;
300
301 /*
302 ** State variables used by the --browser option for diff. These must
303 ** be static variables, not elements of DiffConfig, since they are
304 ** used by the interrupt handler.
305 */
306 static char *tempDiffFilename; /* File holding the diff HTML */
307 static FILE *diffOut; /* Open to write into tempDiffFilename */
308
309 /* Amount of delay (in milliseconds) between launching the
@@ -321,12 +338,12 @@
338 ** hold the result. Make arrangements to delete that temporary
339 ** file if the diff is interrupted.
340 **
341 ** For --browser and --webpage, output the HTML header.
342 */
343 void diff_begin(DiffConfig *pCfg){
344 if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){
345 tempDiffFilename = fossil_temp_filename();
346 tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
347 diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
348 if( diffOut==0 ){
349 fossil_fatal("unable to create temporary file \"%s\"",
@@ -336,11 +353,11 @@
353 signal(SIGINT, diff_www_interrupt);
354 #else
355 SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
356 #endif
357 }
358 if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
359 fossil_print("%s",zWebpageHdr);
360 fflush(stdout);
361 }
362 }
363
@@ -352,19 +369,19 @@
369 **
370 ** For --browser, close the connection to the temporary file, then
371 ** launch a web browser to view the file. After a delay
372 ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file.
373 */
374 void diff_end(DiffConfig *pCfg, int nErr){
375 if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
376 if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
377 const unsigned char *zJs = builtin_file("diff.js", 0);
378 fossil_print("<script>\n%s</script>\n", zJs);
379 }
380 fossil_print("%s", zWebpageEnd);
381 }
382 if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){
383 char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename);
384 fclose(diffOut);
385 diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout);
386 fossil_system(zCmd);
387 fossil_free(zCmd);
@@ -371,10 +388,13 @@
388 diffOut = 0;
389 sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY);
390 file_delete(tempDiffFilename);
391 sqlite3_free(tempDiffFilename);
392 tempDiffFilename = 0;
393 }
394 if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){
395 fossil_print("]\n");
396 }
397 }
398
399 /*
400 ** Show the difference between two files, one in memory and one on disk.
@@ -398,11 +418,11 @@
418 const char *zFile2, /* On disk content to compare to */
419 const char *zName, /* Display name of the file */
420 const char *zDiffCmd, /* Command for comparison */
421 const char *zBinGlob, /* Treat file names matching this as binary */
422 int fIncludeBinary, /* Include binary files for external diff */
423 DiffConfig *pCfg, /* Flags to control the diff */
424 int fSwapDiff, /* Diff from Zfile2 to Pfile1 */
425 Blob *diffBlob /* Blob to store diff output */
426 ){
427 if( zDiffCmd==0 ){
428 Blob out; /* Diff output text */
@@ -417,34 +437,33 @@
437 blob_read_from_file(&file2, zFile2, ExtFILE);
438 zName2 = zName;
439 }
440
441 /* Compute and output the differences */
442 if( pCfg->diffFlags & DIFF_BRIEF ){
443 if( blob_compare(pFile1, &file2) ){
444 fossil_print("CHANGED %s\n", zName);
445 }
446 }else{
447 blob_zero(&out);
448 if( fSwapDiff ){
449 text_diff(&file2, pFile1, &out, pCfg);
450 }else{
451 text_diff(pFile1, &file2, &out, pCfg);
452 }
453 if( blob_size(&out) ){
454 if( pCfg->diffFlags & DIFF_NUMSTAT ){
455 if( !diffBlob ){
456 fossil_print("%s %s\n", blob_str(&out), zName);
457 }else{
458 blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName);
459 }
460 }else{
461 diff_print_filenames(zName, zName2, pCfg, diffBlob);
462 if( !diffBlob ){
 
463 fossil_print("%s\n", blob_str(&out));
464 }else{
 
465 blob_appendf(diffBlob, "%s\n", blob_str(&out));
466 }
467 }
468 }
469 blob_reset(&out);
@@ -529,22 +548,22 @@
548 int isBin2, /* Does the 'to' content appear to be binary */
549 const char *zName, /* Display name of the file */
550 const char *zDiffCmd, /* Command for comparison */
551 const char *zBinGlob, /* Treat file names matching this as binary */
552 int fIncludeBinary, /* Include binary files for external diff */
553 DiffConfig *pCfg /* Diff flags */
554 ){
555 if( pCfg->diffFlags & DIFF_BRIEF ) return;
556 if( zDiffCmd==0 ){
557 Blob out; /* Diff output text */
558
559 blob_zero(&out);
560 text_diff(pFile1, pFile2, &out, pCfg);
561 if( pCfg->diffFlags & DIFF_NUMSTAT ){
562 fossil_print("%s %s\n", blob_str(&out), zName);
563 }else{
564 diff_print_filenames(zName, zName, pCfg, 0);
565 fossil_print("%s\n", blob_str(&out));
566 }
567
568 /* Release memory resources */
569 blob_reset(&out);
@@ -609,22 +628,22 @@
628 void diff_against_disk(
629 const char *zFrom, /* Version to difference from */
630 const char *zDiffCmd, /* Use this diff command. NULL for built-in */
631 const char *zBinGlob, /* Treat file names matching this as binary */
632 int fIncludeBinary, /* Treat file names matching this as binary */
633 DiffConfig *pCfg, /* Flags controlling diff output */
634 FileDirList *pFileDir, /* Which files to diff */
635 Blob *diffBlob /* Blob to output diff instead of stdout */
636 ){
637 int vid;
638 Blob sql;
639 Stmt q;
640 int asNewFile; /* Treat non-existant files as empty files */
641 int isNumStat; /* True for --numstat */
642
643 asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0;
644 isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0;
645 vid = db_lget_int("checkout", 0);
646 vfile_check_signature(vid, CKSIG_ENOTFILE);
647 blob_zero(&sql);
648 db_begin_transaction();
649 if( zFrom ){
@@ -706,24 +725,24 @@
725 }
726 if( showDiff ){
727 Blob content;
728 int isBin;
729 if( !isLink != !file_islink(zFullName) ){
730 diff_print_index(zPathname, pCfg, 0);
731 diff_print_filenames(zPathname, zPathname, pCfg, 0);
732 fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
733 continue;
734 }
735 if( srcid>0 ){
736 content_get(srcid, &content);
737 }else{
738 blob_zero(&content);
739 }
740 isBin = fIncludeBinary ? 0 : looks_like_binary(&content);
741 diff_print_index(zPathname, pCfg, diffBlob);
742 diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
743 zBinGlob, fIncludeBinary, pCfg, 0, diffBlob);
744 blob_reset(&content);
745 }
746 blob_reset(&fname);
747 }
748 db_finalize(&q);
@@ -742,11 +761,11 @@
761 */
762 static void diff_against_undo(
763 const char *zDiffCmd, /* Use this diff command. NULL for built-in */
764 const char *zBinGlob, /* Treat file names matching this as binary */
765 int fIncludeBinary, /* Treat file names matching this as binary */
766 DiffConfig *pCfg, /* Flags controlling diff output */
767 FileDirList *pFileDir /* List of files and directories to diff */
768 ){
769 Stmt q;
770 Blob content;
771 db_prepare(&q, "SELECT pathname, content FROM undo");
@@ -756,11 +775,11 @@
775 const char *zFile = (const char*)db_column_text(&q, 0);
776 if( !file_dir_match(pFileDir, zFile) ) continue;
777 zFullName = mprintf("%s%s", g.zLocalRoot, zFile);
778 db_column_blob(&q, 1, &content);
779 diff_file(&content, 0, zFullName, zFile,
780 zDiffCmd, zBinGlob, fIncludeBinary, pCfg, 0, 0);
781 fossil_free(zFullName);
782 blob_reset(&content);
783 }
784 db_finalize(&q);
785 }
@@ -780,11 +799,11 @@
799 struct ManifestFile *pFrom,
800 struct ManifestFile *pTo,
801 const char *zDiffCmd,
802 const char *zBinGlob,
803 int fIncludeBinary,
804 DiffConfig *pCfg
805 ){
806 Blob f1, f2;
807 int isBin1, isBin2;
808 int rid;
809 const char *zName;
@@ -793,12 +812,12 @@
812 }else if( pTo ){
813 zName = pTo->zName;
814 }else{
815 zName = DIFF_NO_NAME;
816 }
817 if( pCfg->diffFlags & DIFF_BRIEF ) return;
818 diff_print_index(zName, pCfg, 0);
819 if( pFrom ){
820 rid = uuid_to_rid(pFrom->zUuid, 0);
821 content_get(rid, &f1);
822 }else{
823 blob_zero(&f1);
@@ -810,11 +829,11 @@
829 blob_zero(&f2);
830 }
831 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1);
832 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2);
833 diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd,
834 zBinGlob, fIncludeBinary, pCfg);
835 blob_reset(&f1);
836 blob_reset(&f2);
837 }
838
839 /*
@@ -831,16 +850,16 @@
850 const char *zFrom,
851 const char *zTo,
852 const char *zDiffCmd,
853 const char *zBinGlob,
854 int fIncludeBinary,
855 DiffConfig *pCfg,
856 FileDirList *pFileDir
857 ){
858 Manifest *pFrom, *pTo;
859 ManifestFile *pFromFile, *pToFile;
860 int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;
861
862 pFrom = manifest_get_by_name(zFrom, 0);
863 manifest_file_rewind(pFrom);
864 pFromFile = manifest_file_next(pFrom,0);
865 pTo = manifest_get_by_name(zTo, 0);
@@ -856,27 +875,28 @@
875 }else{
876 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
877 }
878 if( cmp<0 ){
879 if( file_dir_match(pFileDir, pFromFile->zName) ){
880 if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
881 fossil_print("DELETED %s\n", pFromFile->zName);
882 }
883 if( asNewFlag ){
884 diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob,
885 fIncludeBinary, pCfg);
886 }
887 }
888 pFromFile = manifest_file_next(pFrom,0);
889 }else if( cmp>0 ){
890 if( file_dir_match(pFileDir, pToFile->zName) ){
891 if( (pCfg->diffFlags &
892 (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
893 fossil_print("ADDED %s\n", pToFile->zName);
894 }
895 if( asNewFlag ){
896 diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob,
897 fIncludeBinary, pCfg);
898 }
899 }
900 pToFile = manifest_file_next(pTo,0);
901 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
902 /* No changes */
@@ -883,15 +903,15 @@
903 (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
904 pFromFile = manifest_file_next(pFrom,0);
905 pToFile = manifest_file_next(pTo,0);
906 }else{
907 if( file_dir_match(pFileDir, pToFile->zName) ){
908 if( pCfg->diffFlags & DIFF_BRIEF ){
909 fossil_print("CHANGED %s\n", pFromFile->zName);
910 }else{
911 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob,
912 fIncludeBinary, pCfg);
913 }
914 }
915 pFromFile = manifest_file_next(pFrom,0);
916 pToFile = manifest_file_next(pTo,0);
917 }
@@ -1107,12 +1127,12 @@
1127 const char *zBranch; /* Branch to diff */
1128 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */
1129 const char *zBinGlob = 0; /* Treat file names matching this as binary */
1130 int fIncludeBinary = 0; /* Include binary files for external diff */
1131 int againstUndo = 0; /* Diff against files in the undo buffer */
 
1132 FileDirList *pFileDir = 0; /* Restrict the diff to these files */
1133 DiffConfig DCfg; /* Diff configuration object */
1134
1135 if( find_option("tk",0,0)!=0 || has_option("tclsh") ){
1136 diff_tk("diff", 2);
1137 return;
1138 }
@@ -1121,16 +1141,16 @@
1141 zFrom = find_option("from", "r", 1);
1142 zTo = find_option("to", 0, 1);
1143 zCheckin = find_option("checkin", 0, 1);
1144 zBranch = find_option("branch", 0, 1);
1145 againstUndo = find_option("undo",0,0)!=0;
1146 diff_options(&DCfg, isGDiff);
1147 verboseFlag = find_option("verbose","v",0)!=0;
1148 if( !verboseFlag ){
1149 verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */
1150 }
1151 if( verboseFlag ) DCfg.diffFlags |= DIFF_VERBOSE;
1152 if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
1153 fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
1154 " or --branch");
1155 }
1156 if( zBranch ){
@@ -1150,11 +1170,11 @@
1170 fossil_fatal("must use --from if --to is present");
1171 }else{
1172 db_find_and_open_repository(0, 0);
1173 }
1174 if( !isInternDiff
1175 && (DCfg.diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */
1176 ){
1177 zDiffCmd = find_option("command", 0, 1);
1178 if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff);
1179 }
1180 zBinGlob = diff_get_binary_glob();
@@ -1188,24 +1208,24 @@
1208 ridTo);
1209 if( zFrom==0 ){
1210 fossil_fatal("check-in %s has no parent", zTo);
1211 }
1212 }
1213 diff_begin(&DCfg);
1214 if( againstUndo ){
1215 if( db_lget_int("undo_available",0)==0 ){
1216 fossil_print("No undo or redo is available\n");
1217 return;
1218 }
1219 diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary,
1220 &DCfg, pFileDir);
1221 }else if( zTo==0 ){
1222 diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary,
1223 &DCfg, pFileDir, 0);
1224 }else{
1225 diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary,
1226 &DCfg, pFileDir);
1227 }
1228 if( pFileDir ){
1229 int i;
1230 for(i=0; pFileDir[i].zName; i++){
1231 if( pFileDir[i].nUsed==0
@@ -1216,12 +1236,12 @@
1236 }
1237 fossil_free(pFileDir[i].zName);
1238 }
1239 fossil_free(pFileDir);
1240 }
1241 diff_end(&DCfg, 0);
1242 if ( DCfg.diffFlags & DIFF_NUMSTAT ){
1243 fossil_print("%10d %10d TOTAL over %d changed files\n",
1244 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
1245 }
1246 }
1247
@@ -1232,12 +1252,14 @@
1252 ** Show a patch that goes from check-in FROM to check-in TO.
1253 */
1254 void vpatch_page(void){
1255 const char *zFrom = P("from");
1256 const char *zTo = P("to");
1257 DiffConfig DCfg;
1258 login_check_credentials();
1259 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1260 if( zFrom==0 || zTo==0 ) fossil_redirect_home();
1261
1262 cgi_set_content_type("text/plain");
1263 diff_config_init(&DCfg, DIFF_VERBOSE);
1264 diff_two_versions(zFrom, zTo, 0, 0, 0, &DCfg, 0);
1265 }
1266
+41 -31
--- src/info.c
+++ src/info.c
@@ -330,12 +330,11 @@
330330
** Append the difference between artifacts to the output
331331
*/
332332
static void append_diff(
333333
const char *zFrom, /* Diff from this artifact */
334334
const char *zTo, /* ... to this artifact */
335
- u64 diffFlags, /* Diff formatting flags */
336
- ReCompiled *pRe /* Only show change matching this regex */
335
+ DiffConfig *pCfg /* The diff configuration */
337336
){
338337
int fromid;
339338
int toid;
340339
Blob from, to;
341340
if( zFrom ){
@@ -348,16 +347,16 @@
348347
toid = uuid_to_rid(zTo, 0);
349348
content_get(toid, &to);
350349
}else{
351350
blob_zero(&to);
352351
}
353
- if( diffFlags & DIFF_SIDEBYSIDE ){
354
- diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
352
+ if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
353
+ pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
355354
}else{
356
- diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
355
+ pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
357356
}
358
- text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags);
357
+ text_diff(&from, &to, cgi_output_blob(), pCfg);
359358
blob_reset(&from);
360359
blob_reset(&to);
361360
}
362361
363362
/*
@@ -368,12 +367,11 @@
368367
const char *zCkin, /* The checkin on which the change occurs */
369368
const char *zName, /* Name of the file that has changed */
370369
const char *zOld, /* blob.uuid before change. NULL for added files */
371370
const char *zNew, /* blob.uuid after change. NULL for deletes */
372371
const char *zOldName, /* Prior name. NULL if no name change. */
373
- u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
374
- ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
372
+ DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
375373
int mperm /* executable or symlink permission for zNew */
376374
){
377375
@ <p>
378376
if( !g.perm.Hyperlink ){
379377
if( zNew==0 ){
@@ -391,12 +389,12 @@
391389
@ %h(zName) became a regular file.
392390
}
393391
}else{
394392
@ Changes to %h(zName).
395393
}
396
- if( diffFlags ){
397
- append_diff(zOld, zNew, diffFlags, pRe);
394
+ if( pCfg ){
395
+ append_diff(zOld, zNew, pCfg);
398396
}
399397
}else{
400398
if( zOld && zNew ){
401399
if( fossil_strcmp(zOld, zNew)!=0 ){
402400
@ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@@ -426,12 +424,12 @@
426424
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
427425
}else{
428426
@ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
429427
@ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
430428
}
431
- if( diffFlags ){
432
- append_diff(zOld, zNew, diffFlags, pRe);
429
+ if( pCfg ){
430
+ append_diff(zOld, zNew, pCfg);
433431
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
434432
@ &nbsp;&nbsp;
435433
@ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
436434
}
437435
}
@@ -448,11 +446,11 @@
448446
449447
/*
450448
** Construct an appropriate diffFlag for text_diff() based on query
451449
** parameters and the to boolean arguments.
452450
*/
453
-u64 construct_diff_flags(int diffType){
451
+DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){
454452
u64 diffFlags = 0; /* Zero means do not show any diff */
455453
if( diffType>0 ){
456454
int x;
457455
if( diffType==2 ){
458456
diffFlags = DIFF_SIDEBYSIDE;
@@ -472,12 +470,16 @@
472470
diffFlags += x;
473471
474472
/* The "noopt" parameter disables diff optimization */
475473
if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
476474
diffFlags |= DIFF_STRIP_EOLCR;
475
+ diff_config_init(pCfg, diffFlags);
476
+ return pCfg;
477
+ }else{
478
+ diff_config_init(pCfg, 0);
479
+ return 0;
477480
}
478
- return diffFlags;
479481
}
480482
481483
/*
482484
** WEBPAGE: ci_tags
483485
** URL: /ci_tags?name=ARTIFACTID
@@ -614,20 +616,20 @@
614616
void ci_page(void){
615617
Stmt q1, q2, q3;
616618
int rid;
617619
int isLeaf;
618620
int diffType; /* 0: no diff, 1: unified, 2: side-by-side */
619
- u64 diffFlags; /* Flag parameter for text_diff() */
620621
const char *zName; /* Name of the check-in to be displayed */
621622
const char *zUuid; /* Hash of zName, found via blob.uuid */
622623
const char *zParent; /* Hash of the parent check-in (if any) */
623624
const char *zRe; /* regex parameter */
624625
ReCompiled *pRe = 0; /* regex */
625
- const char *zW; /* URL param for ignoring whitespace */
626
+ const char *zW; /* URL param for ignoring whitespace */
626627
const char *zPage = "vinfo"; /* Page that shows diffs */
627628
const char *zPageHide = "ci"; /* Page that hides diffs */
628
- const char *zBrName; /* Branch name */
629
+ const char *zBrName; /* Branch name */
630
+ DiffConfig DCfg,*pCfg; /* Type of diff */
629631
630632
login_check_credentials();
631633
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
632634
style_set_current_feature("vinfo");
633635
zName = P("name");
@@ -878,12 +880,13 @@
878880
render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
879881
@ <div class="section">Context</div>
880882
render_checkin_context(rid, 0, 0, 0);
881883
@ <div class="section">Changes</div>
882884
@ <div class="sectionmenu">
883
- diffFlags = construct_diff_flags(diffType);
884
- zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
885
+ pCfg = construct_diff_flags(diffType, &DCfg);
886
+ DCfg.pRe = pRe;
887
+ zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
885888
if( diffType!=0 ){
886889
@ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
887890
@ Hide&nbsp;Diffs</a>
888891
}
889892
if( diffType!=1 ){
@@ -933,14 +936,14 @@
933936
int mperm = db_column_int(&q3, 1);
934937
const char *zOld = db_column_text(&q3,2);
935938
const char *zNew = db_column_text(&q3,3);
936939
const char *zOldName = db_column_text(&q3, 4);
937940
append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
938
- diffFlags,pRe,mperm);
941
+ pCfg,mperm);
939942
}
940943
db_finalize(&q3);
941
- append_diff_javascript(diffType==2);
944
+ append_diff_javascript(diffType);
942945
builtin_fossil_js_bundle_or("info-diff",NULL);
943946
style_finish_page();
944947
}
945948
946949
/*
@@ -1167,20 +1170,20 @@
11671170
** Show all differences between two check-ins.
11681171
*/
11691172
void vdiff_page(void){
11701173
int ridFrom, ridTo;
11711174
int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */
1172
- u64 diffFlags = 0;
11731175
Manifest *pFrom, *pTo;
11741176
ManifestFile *pFileFrom, *pFileTo;
11751177
const char *zBranch;
11761178
const char *zFrom;
11771179
const char *zTo;
11781180
const char *zRe;
11791181
const char *zGlob;
11801182
char *zMergeOrigin = 0;
11811183
ReCompiled *pRe = 0;
1184
+ DiffConfig DCfg, *pCfg = 0;
11821185
int graphFlags = 0;
11831186
Blob qp;
11841187
int bInvert = PB("inv");
11851188
11861189
login_check_credentials();
@@ -1229,12 +1232,12 @@
12291232
}
12301233
if( PB("nc") ){
12311234
graphFlags |= TIMELINE_NOCOLOR;
12321235
blob_appendf(&qp, "&nc");
12331236
}
1234
- diffFlags = construct_diff_flags(diffType);
1235
- if( diffFlags & DIFF_IGNORE_ALLWS ){
1237
+ pCfg = construct_diff_flags(diffType, &DCfg);
1238
+ if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){
12361239
blob_appendf(&qp, "&w");
12371240
}
12381241
style_set_current_feature("vdiff");
12391242
if( zBranch==0 ){
12401243
style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
@@ -1253,11 +1256,11 @@
12531256
}
12541257
if( zGlob ){
12551258
style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
12561259
}else{
12571260
style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
1258
- (diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
1261
+ (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
12591262
}
12601263
if( diffType!=0 ){
12611264
style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
12621265
}
12631266
if( zBranch ){
@@ -1301,10 +1304,11 @@
13011304
13021305
manifest_file_rewind(pFrom);
13031306
pFileFrom = manifest_file_next(pFrom, 0);
13041307
manifest_file_rewind(pTo);
13051308
pFileTo = manifest_file_next(pTo, 0);
1309
+ DCfg.pRe = pRe;
13061310
while( pFileFrom || pFileTo ){
13071311
int cmp;
13081312
if( pFileFrom==0 ){
13091313
cmp = +1;
13101314
}else if( pFileTo==0 ){
@@ -1313,17 +1317,17 @@
13131317
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
13141318
}
13151319
if( cmp<0 ){
13161320
if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
13171321
append_file_change_line(zFrom, pFileFrom->zName,
1318
- pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0);
1322
+ pFileFrom->zUuid, 0, 0, pCfg, 0);
13191323
}
13201324
pFileFrom = manifest_file_next(pFrom, 0);
13211325
}else if( cmp>0 ){
13221326
if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
13231327
append_file_change_line(zTo, pFileTo->zName,
1324
- 0, pFileTo->zUuid, 0, diffFlags, pRe,
1328
+ 0, pFileTo->zUuid, 0, pCfg,
13251329
manifest_file_mperm(pFileTo));
13261330
}
13271331
pFileTo = manifest_file_next(pTo, 0);
13281332
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
13291333
pFileFrom = manifest_file_next(pFrom, 0);
@@ -1331,11 +1335,11 @@
13311335
}else{
13321336
if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
13331337
|| sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
13341338
append_file_change_line(zFrom, pFileFrom->zName,
13351339
pFileFrom->zUuid,
1336
- pFileTo->zUuid, 0, diffFlags, pRe,
1340
+ pFileTo->zUuid, 0, pCfg,
13371341
manifest_file_mperm(pFileTo));
13381342
}
13391343
pFileFrom = manifest_file_next(pFrom, 0);
13401344
pFileTo = manifest_file_next(pTo, 0);
13411345
}
@@ -1722,10 +1726,11 @@
17221726
const char *zRe;
17231727
ReCompiled *pRe = 0;
17241728
u64 diffFlags;
17251729
u32 objdescFlags = 0;
17261730
int verbose = PB("verbose");
1731
+ DiffConfig DCfg;
17271732
17281733
login_check_credentials();
17291734
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
17301735
diffType = preferred_diff_type();
17311736
if( P("from") && P("to") ){
@@ -1768,24 +1773,28 @@
17681773
zRe = P("regex");
17691774
if( zRe ) re_compile(&pRe, zRe, 0);
17701775
if( verbose ) objdescFlags |= OBJDESC_DETAIL;
17711776
if( isPatch ){
17721777
Blob c1, c2, *pOut;
1778
+ DiffConfig DCfg;
17731779
pOut = cgi_output_blob();
17741780
cgi_set_content_type("text/plain");
17751781
diffFlags = 4;
17761782
content_get(v1, &c1);
17771783
content_get(v2, &c2);
1778
- text_diff(&c1, &c2, pOut, pRe, diffFlags);
1784
+ diff_config_init(&DCfg, diffFlags);
1785
+ DCfg.pRe = pRe;
1786
+ text_diff(&c1, &c2, pOut, &DCfg);
17791787
blob_reset(&c1);
17801788
blob_reset(&c2);
17811789
return;
17821790
}
17831791
17841792
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
17851793
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1786
- diffFlags = construct_diff_flags(diffType) | DIFF_HTML;
1794
+ construct_diff_flags(diffType, &DCfg);
1795
+ DCfg.diffFlags |= DIFF_HTML;
17871796
17881797
style_set_current_feature("fdiff");
17891798
style_header("Diff");
17901799
style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
17911800
if( diffType==2 ){
@@ -1811,13 +1820,14 @@
18111820
object_description(v2, objdescFlags,0, 0);
18121821
}
18131822
if( pRe ){
18141823
@ <b>Only differences that match regular expression "%h(zRe)"
18151824
@ are shown.</b>
1825
+ DCfg.pRe = pRe;
18161826
}
18171827
@ <hr />
1818
- append_diff(zV1, zV2, diffFlags, pRe);
1828
+ append_diff(zV1, zV2, &DCfg);
18191829
append_diff_javascript(diffType);
18201830
style_finish_page();
18211831
}
18221832
18231833
/*
18241834
--- src/info.c
+++ src/info.c
@@ -330,12 +330,11 @@
330 ** Append the difference between artifacts to the output
331 */
332 static void append_diff(
333 const char *zFrom, /* Diff from this artifact */
334 const char *zTo, /* ... to this artifact */
335 u64 diffFlags, /* Diff formatting flags */
336 ReCompiled *pRe /* Only show change matching this regex */
337 ){
338 int fromid;
339 int toid;
340 Blob from, to;
341 if( zFrom ){
@@ -348,16 +347,16 @@
348 toid = uuid_to_rid(zTo, 0);
349 content_get(toid, &to);
350 }else{
351 blob_zero(&to);
352 }
353 if( diffFlags & DIFF_SIDEBYSIDE ){
354 diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
355 }else{
356 diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
357 }
358 text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags);
359 blob_reset(&from);
360 blob_reset(&to);
361 }
362
363 /*
@@ -368,12 +367,11 @@
368 const char *zCkin, /* The checkin on which the change occurs */
369 const char *zName, /* Name of the file that has changed */
370 const char *zOld, /* blob.uuid before change. NULL for added files */
371 const char *zNew, /* blob.uuid after change. NULL for deletes */
372 const char *zOldName, /* Prior name. NULL if no name change. */
373 u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
374 ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
375 int mperm /* executable or symlink permission for zNew */
376 ){
377 @ <p>
378 if( !g.perm.Hyperlink ){
379 if( zNew==0 ){
@@ -391,12 +389,12 @@
391 @ %h(zName) became a regular file.
392 }
393 }else{
394 @ Changes to %h(zName).
395 }
396 if( diffFlags ){
397 append_diff(zOld, zNew, diffFlags, pRe);
398 }
399 }else{
400 if( zOld && zNew ){
401 if( fossil_strcmp(zOld, zNew)!=0 ){
402 @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@@ -426,12 +424,12 @@
426 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
427 }else{
428 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
429 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
430 }
431 if( diffFlags ){
432 append_diff(zOld, zNew, diffFlags, pRe);
433 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
434 @ &nbsp;&nbsp;
435 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
436 }
437 }
@@ -448,11 +446,11 @@
448
449 /*
450 ** Construct an appropriate diffFlag for text_diff() based on query
451 ** parameters and the to boolean arguments.
452 */
453 u64 construct_diff_flags(int diffType){
454 u64 diffFlags = 0; /* Zero means do not show any diff */
455 if( diffType>0 ){
456 int x;
457 if( diffType==2 ){
458 diffFlags = DIFF_SIDEBYSIDE;
@@ -472,12 +470,16 @@
472 diffFlags += x;
473
474 /* The "noopt" parameter disables diff optimization */
475 if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
476 diffFlags |= DIFF_STRIP_EOLCR;
 
 
 
 
 
477 }
478 return diffFlags;
479 }
480
481 /*
482 ** WEBPAGE: ci_tags
483 ** URL: /ci_tags?name=ARTIFACTID
@@ -614,20 +616,20 @@
614 void ci_page(void){
615 Stmt q1, q2, q3;
616 int rid;
617 int isLeaf;
618 int diffType; /* 0: no diff, 1: unified, 2: side-by-side */
619 u64 diffFlags; /* Flag parameter for text_diff() */
620 const char *zName; /* Name of the check-in to be displayed */
621 const char *zUuid; /* Hash of zName, found via blob.uuid */
622 const char *zParent; /* Hash of the parent check-in (if any) */
623 const char *zRe; /* regex parameter */
624 ReCompiled *pRe = 0; /* regex */
625 const char *zW; /* URL param for ignoring whitespace */
626 const char *zPage = "vinfo"; /* Page that shows diffs */
627 const char *zPageHide = "ci"; /* Page that hides diffs */
628 const char *zBrName; /* Branch name */
 
629
630 login_check_credentials();
631 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
632 style_set_current_feature("vinfo");
633 zName = P("name");
@@ -878,12 +880,13 @@
878 render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
879 @ <div class="section">Context</div>
880 render_checkin_context(rid, 0, 0, 0);
881 @ <div class="section">Changes</div>
882 @ <div class="sectionmenu">
883 diffFlags = construct_diff_flags(diffType);
884 zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
 
885 if( diffType!=0 ){
886 @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
887 @ Hide&nbsp;Diffs</a>
888 }
889 if( diffType!=1 ){
@@ -933,14 +936,14 @@
933 int mperm = db_column_int(&q3, 1);
934 const char *zOld = db_column_text(&q3,2);
935 const char *zNew = db_column_text(&q3,3);
936 const char *zOldName = db_column_text(&q3, 4);
937 append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
938 diffFlags,pRe,mperm);
939 }
940 db_finalize(&q3);
941 append_diff_javascript(diffType==2);
942 builtin_fossil_js_bundle_or("info-diff",NULL);
943 style_finish_page();
944 }
945
946 /*
@@ -1167,20 +1170,20 @@
1167 ** Show all differences between two check-ins.
1168 */
1169 void vdiff_page(void){
1170 int ridFrom, ridTo;
1171 int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */
1172 u64 diffFlags = 0;
1173 Manifest *pFrom, *pTo;
1174 ManifestFile *pFileFrom, *pFileTo;
1175 const char *zBranch;
1176 const char *zFrom;
1177 const char *zTo;
1178 const char *zRe;
1179 const char *zGlob;
1180 char *zMergeOrigin = 0;
1181 ReCompiled *pRe = 0;
 
1182 int graphFlags = 0;
1183 Blob qp;
1184 int bInvert = PB("inv");
1185
1186 login_check_credentials();
@@ -1229,12 +1232,12 @@
1229 }
1230 if( PB("nc") ){
1231 graphFlags |= TIMELINE_NOCOLOR;
1232 blob_appendf(&qp, "&nc");
1233 }
1234 diffFlags = construct_diff_flags(diffType);
1235 if( diffFlags & DIFF_IGNORE_ALLWS ){
1236 blob_appendf(&qp, "&w");
1237 }
1238 style_set_current_feature("vdiff");
1239 if( zBranch==0 ){
1240 style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
@@ -1253,11 +1256,11 @@
1253 }
1254 if( zGlob ){
1255 style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
1256 }else{
1257 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
1258 (diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
1259 }
1260 if( diffType!=0 ){
1261 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
1262 }
1263 if( zBranch ){
@@ -1301,10 +1304,11 @@
1301
1302 manifest_file_rewind(pFrom);
1303 pFileFrom = manifest_file_next(pFrom, 0);
1304 manifest_file_rewind(pTo);
1305 pFileTo = manifest_file_next(pTo, 0);
 
1306 while( pFileFrom || pFileTo ){
1307 int cmp;
1308 if( pFileFrom==0 ){
1309 cmp = +1;
1310 }else if( pFileTo==0 ){
@@ -1313,17 +1317,17 @@
1313 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1314 }
1315 if( cmp<0 ){
1316 if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
1317 append_file_change_line(zFrom, pFileFrom->zName,
1318 pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0);
1319 }
1320 pFileFrom = manifest_file_next(pFrom, 0);
1321 }else if( cmp>0 ){
1322 if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
1323 append_file_change_line(zTo, pFileTo->zName,
1324 0, pFileTo->zUuid, 0, diffFlags, pRe,
1325 manifest_file_mperm(pFileTo));
1326 }
1327 pFileTo = manifest_file_next(pTo, 0);
1328 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1329 pFileFrom = manifest_file_next(pFrom, 0);
@@ -1331,11 +1335,11 @@
1331 }else{
1332 if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
1333 || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
1334 append_file_change_line(zFrom, pFileFrom->zName,
1335 pFileFrom->zUuid,
1336 pFileTo->zUuid, 0, diffFlags, pRe,
1337 manifest_file_mperm(pFileTo));
1338 }
1339 pFileFrom = manifest_file_next(pFrom, 0);
1340 pFileTo = manifest_file_next(pTo, 0);
1341 }
@@ -1722,10 +1726,11 @@
1722 const char *zRe;
1723 ReCompiled *pRe = 0;
1724 u64 diffFlags;
1725 u32 objdescFlags = 0;
1726 int verbose = PB("verbose");
 
1727
1728 login_check_credentials();
1729 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1730 diffType = preferred_diff_type();
1731 if( P("from") && P("to") ){
@@ -1768,24 +1773,28 @@
1768 zRe = P("regex");
1769 if( zRe ) re_compile(&pRe, zRe, 0);
1770 if( verbose ) objdescFlags |= OBJDESC_DETAIL;
1771 if( isPatch ){
1772 Blob c1, c2, *pOut;
 
1773 pOut = cgi_output_blob();
1774 cgi_set_content_type("text/plain");
1775 diffFlags = 4;
1776 content_get(v1, &c1);
1777 content_get(v2, &c2);
1778 text_diff(&c1, &c2, pOut, pRe, diffFlags);
 
 
1779 blob_reset(&c1);
1780 blob_reset(&c2);
1781 return;
1782 }
1783
1784 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1785 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1786 diffFlags = construct_diff_flags(diffType) | DIFF_HTML;
 
1787
1788 style_set_current_feature("fdiff");
1789 style_header("Diff");
1790 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
1791 if( diffType==2 ){
@@ -1811,13 +1820,14 @@
1811 object_description(v2, objdescFlags,0, 0);
1812 }
1813 if( pRe ){
1814 @ <b>Only differences that match regular expression "%h(zRe)"
1815 @ are shown.</b>
 
1816 }
1817 @ <hr />
1818 append_diff(zV1, zV2, diffFlags, pRe);
1819 append_diff_javascript(diffType);
1820 style_finish_page();
1821 }
1822
1823 /*
1824
--- src/info.c
+++ src/info.c
@@ -330,12 +330,11 @@
330 ** Append the difference between artifacts to the output
331 */
332 static void append_diff(
333 const char *zFrom, /* Diff from this artifact */
334 const char *zTo, /* ... to this artifact */
335 DiffConfig *pCfg /* The diff configuration */
 
336 ){
337 int fromid;
338 int toid;
339 Blob from, to;
340 if( zFrom ){
@@ -348,16 +347,16 @@
347 toid = uuid_to_rid(zTo, 0);
348 content_get(toid, &to);
349 }else{
350 blob_zero(&to);
351 }
352 if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
353 pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
354 }else{
355 pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
356 }
357 text_diff(&from, &to, cgi_output_blob(), pCfg);
358 blob_reset(&from);
359 blob_reset(&to);
360 }
361
362 /*
@@ -368,12 +367,11 @@
367 const char *zCkin, /* The checkin on which the change occurs */
368 const char *zName, /* Name of the file that has changed */
369 const char *zOld, /* blob.uuid before change. NULL for added files */
370 const char *zNew, /* blob.uuid after change. NULL for deletes */
371 const char *zOldName, /* Prior name. NULL if no name change. */
372 DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */
 
373 int mperm /* executable or symlink permission for zNew */
374 ){
375 @ <p>
376 if( !g.perm.Hyperlink ){
377 if( zNew==0 ){
@@ -391,12 +389,12 @@
389 @ %h(zName) became a regular file.
390 }
391 }else{
392 @ Changes to %h(zName).
393 }
394 if( pCfg ){
395 append_diff(zOld, zNew, pCfg);
396 }
397 }else{
398 if( zOld && zNew ){
399 if( fossil_strcmp(zOld, zNew)!=0 ){
400 @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
@@ -426,12 +424,12 @@
424 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
425 }else{
426 @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
427 @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
428 }
429 if( pCfg ){
430 append_diff(zOld, zNew, pCfg);
431 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
432 @ &nbsp;&nbsp;
433 @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
434 }
435 }
@@ -448,11 +446,11 @@
446
447 /*
448 ** Construct an appropriate diffFlag for text_diff() based on query
449 ** parameters and the to boolean arguments.
450 */
451 DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){
452 u64 diffFlags = 0; /* Zero means do not show any diff */
453 if( diffType>0 ){
454 int x;
455 if( diffType==2 ){
456 diffFlags = DIFF_SIDEBYSIDE;
@@ -472,12 +470,16 @@
470 diffFlags += x;
471
472 /* The "noopt" parameter disables diff optimization */
473 if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
474 diffFlags |= DIFF_STRIP_EOLCR;
475 diff_config_init(pCfg, diffFlags);
476 return pCfg;
477 }else{
478 diff_config_init(pCfg, 0);
479 return 0;
480 }
 
481 }
482
483 /*
484 ** WEBPAGE: ci_tags
485 ** URL: /ci_tags?name=ARTIFACTID
@@ -614,20 +616,20 @@
616 void ci_page(void){
617 Stmt q1, q2, q3;
618 int rid;
619 int isLeaf;
620 int diffType; /* 0: no diff, 1: unified, 2: side-by-side */
 
621 const char *zName; /* Name of the check-in to be displayed */
622 const char *zUuid; /* Hash of zName, found via blob.uuid */
623 const char *zParent; /* Hash of the parent check-in (if any) */
624 const char *zRe; /* regex parameter */
625 ReCompiled *pRe = 0; /* regex */
626 const char *zW; /* URL param for ignoring whitespace */
627 const char *zPage = "vinfo"; /* Page that shows diffs */
628 const char *zPageHide = "ci"; /* Page that hides diffs */
629 const char *zBrName; /* Branch name */
630 DiffConfig DCfg,*pCfg; /* Type of diff */
631
632 login_check_credentials();
633 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
634 style_set_current_feature("vinfo");
635 zName = P("name");
@@ -878,12 +880,13 @@
880 render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
881 @ <div class="section">Context</div>
882 render_checkin_context(rid, 0, 0, 0);
883 @ <div class="section">Changes</div>
884 @ <div class="sectionmenu">
885 pCfg = construct_diff_flags(diffType, &DCfg);
886 DCfg.pRe = pRe;
887 zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
888 if( diffType!=0 ){
889 @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
890 @ Hide&nbsp;Diffs</a>
891 }
892 if( diffType!=1 ){
@@ -933,14 +936,14 @@
936 int mperm = db_column_int(&q3, 1);
937 const char *zOld = db_column_text(&q3,2);
938 const char *zNew = db_column_text(&q3,3);
939 const char *zOldName = db_column_text(&q3, 4);
940 append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
941 pCfg,mperm);
942 }
943 db_finalize(&q3);
944 append_diff_javascript(diffType);
945 builtin_fossil_js_bundle_or("info-diff",NULL);
946 style_finish_page();
947 }
948
949 /*
@@ -1167,20 +1170,20 @@
1170 ** Show all differences between two check-ins.
1171 */
1172 void vdiff_page(void){
1173 int ridFrom, ridTo;
1174 int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */
 
1175 Manifest *pFrom, *pTo;
1176 ManifestFile *pFileFrom, *pFileTo;
1177 const char *zBranch;
1178 const char *zFrom;
1179 const char *zTo;
1180 const char *zRe;
1181 const char *zGlob;
1182 char *zMergeOrigin = 0;
1183 ReCompiled *pRe = 0;
1184 DiffConfig DCfg, *pCfg = 0;
1185 int graphFlags = 0;
1186 Blob qp;
1187 int bInvert = PB("inv");
1188
1189 login_check_credentials();
@@ -1229,12 +1232,12 @@
1232 }
1233 if( PB("nc") ){
1234 graphFlags |= TIMELINE_NOCOLOR;
1235 blob_appendf(&qp, "&nc");
1236 }
1237 pCfg = construct_diff_flags(diffType, &DCfg);
1238 if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){
1239 blob_appendf(&qp, "&w");
1240 }
1241 style_set_current_feature("vdiff");
1242 if( zBranch==0 ){
1243 style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
@@ -1253,11 +1256,11 @@
1256 }
1257 if( zGlob ){
1258 style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
1259 }else{
1260 style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
1261 (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
1262 }
1263 if( diffType!=0 ){
1264 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
1265 }
1266 if( zBranch ){
@@ -1301,10 +1304,11 @@
1304
1305 manifest_file_rewind(pFrom);
1306 pFileFrom = manifest_file_next(pFrom, 0);
1307 manifest_file_rewind(pTo);
1308 pFileTo = manifest_file_next(pTo, 0);
1309 DCfg.pRe = pRe;
1310 while( pFileFrom || pFileTo ){
1311 int cmp;
1312 if( pFileFrom==0 ){
1313 cmp = +1;
1314 }else if( pFileTo==0 ){
@@ -1313,17 +1317,17 @@
1317 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
1318 }
1319 if( cmp<0 ){
1320 if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
1321 append_file_change_line(zFrom, pFileFrom->zName,
1322 pFileFrom->zUuid, 0, 0, pCfg, 0);
1323 }
1324 pFileFrom = manifest_file_next(pFrom, 0);
1325 }else if( cmp>0 ){
1326 if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
1327 append_file_change_line(zTo, pFileTo->zName,
1328 0, pFileTo->zUuid, 0, pCfg,
1329 manifest_file_mperm(pFileTo));
1330 }
1331 pFileTo = manifest_file_next(pTo, 0);
1332 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
1333 pFileFrom = manifest_file_next(pFrom, 0);
@@ -1331,11 +1335,11 @@
1335 }else{
1336 if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
1337 || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
1338 append_file_change_line(zFrom, pFileFrom->zName,
1339 pFileFrom->zUuid,
1340 pFileTo->zUuid, 0, pCfg,
1341 manifest_file_mperm(pFileTo));
1342 }
1343 pFileFrom = manifest_file_next(pFrom, 0);
1344 pFileTo = manifest_file_next(pTo, 0);
1345 }
@@ -1722,10 +1726,11 @@
1726 const char *zRe;
1727 ReCompiled *pRe = 0;
1728 u64 diffFlags;
1729 u32 objdescFlags = 0;
1730 int verbose = PB("verbose");
1731 DiffConfig DCfg;
1732
1733 login_check_credentials();
1734 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1735 diffType = preferred_diff_type();
1736 if( P("from") && P("to") ){
@@ -1768,24 +1773,28 @@
1773 zRe = P("regex");
1774 if( zRe ) re_compile(&pRe, zRe, 0);
1775 if( verbose ) objdescFlags |= OBJDESC_DETAIL;
1776 if( isPatch ){
1777 Blob c1, c2, *pOut;
1778 DiffConfig DCfg;
1779 pOut = cgi_output_blob();
1780 cgi_set_content_type("text/plain");
1781 diffFlags = 4;
1782 content_get(v1, &c1);
1783 content_get(v2, &c2);
1784 diff_config_init(&DCfg, diffFlags);
1785 DCfg.pRe = pRe;
1786 text_diff(&c1, &c2, pOut, &DCfg);
1787 blob_reset(&c1);
1788 blob_reset(&c2);
1789 return;
1790 }
1791
1792 zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
1793 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1794 construct_diff_flags(diffType, &DCfg);
1795 DCfg.diffFlags |= DIFF_HTML;
1796
1797 style_set_current_feature("fdiff");
1798 style_header("Diff");
1799 style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
1800 if( diffType==2 ){
@@ -1811,13 +1820,14 @@
1820 object_description(v2, objdescFlags,0, 0);
1821 }
1822 if( pRe ){
1823 @ <b>Only differences that match regular expression "%h(zRe)"
1824 @ are shown.</b>
1825 DCfg.pRe = pRe;
1826 }
1827 @ <hr />
1828 append_diff(zV1, zV2, &DCfg);
1829 append_diff_javascript(diffType);
1830 style_finish_page();
1831 }
1832
1833 /*
1834
+3 -1
--- src/json_diff.c
+++ src/json_diff.c
@@ -38,10 +38,11 @@
3838
int nContext, char fSbs,
3939
char fHtml){
4040
int fromid;
4141
int toid;
4242
int outLen;
43
+ DiffConfig DCfg;
4344
Blob from = empty_blob, to = empty_blob, out = empty_blob;
4445
cson_value * rc = NULL;
4546
int flags = (DIFF_CONTEXT_MASK & nContext)
4647
| (fSbs ? DIFF_SIDEBYSIDE : 0)
4748
| (fHtml ? DIFF_HTML : 0);
@@ -58,11 +59,12 @@
5859
return NULL;
5960
}
6061
content_get(fromid, &from);
6162
content_get(toid, &to);
6263
blob_zero(&out);
63
- text_diff(&from, &to, &out, 0, flags);
64
+ diff_config_init(&DCfg, flags);
65
+ text_diff(&from, &to, &out, &DCfg);
6466
blob_reset(&from);
6567
blob_reset(&to);
6668
outLen = blob_size(&out);
6769
if(outLen>=0){
6870
rc = cson_value_new_string(blob_buffer(&out),
6971
--- src/json_diff.c
+++ src/json_diff.c
@@ -38,10 +38,11 @@
38 int nContext, char fSbs,
39 char fHtml){
40 int fromid;
41 int toid;
42 int outLen;
 
43 Blob from = empty_blob, to = empty_blob, out = empty_blob;
44 cson_value * rc = NULL;
45 int flags = (DIFF_CONTEXT_MASK & nContext)
46 | (fSbs ? DIFF_SIDEBYSIDE : 0)
47 | (fHtml ? DIFF_HTML : 0);
@@ -58,11 +59,12 @@
58 return NULL;
59 }
60 content_get(fromid, &from);
61 content_get(toid, &to);
62 blob_zero(&out);
63 text_diff(&from, &to, &out, 0, flags);
 
64 blob_reset(&from);
65 blob_reset(&to);
66 outLen = blob_size(&out);
67 if(outLen>=0){
68 rc = cson_value_new_string(blob_buffer(&out),
69
--- src/json_diff.c
+++ src/json_diff.c
@@ -38,10 +38,11 @@
38 int nContext, char fSbs,
39 char fHtml){
40 int fromid;
41 int toid;
42 int outLen;
43 DiffConfig DCfg;
44 Blob from = empty_blob, to = empty_blob, out = empty_blob;
45 cson_value * rc = NULL;
46 int flags = (DIFF_CONTEXT_MASK & nContext)
47 | (fSbs ? DIFF_SIDEBYSIDE : 0)
48 | (fHtml ? DIFF_HTML : 0);
@@ -58,11 +59,12 @@
59 return NULL;
60 }
61 content_get(fromid, &from);
62 content_get(toid, &to);
63 blob_zero(&out);
64 diff_config_init(&DCfg, flags);
65 text_diff(&from, &to, &out, &DCfg);
66 blob_reset(&from);
67 blob_reset(&to);
68 outLen = blob_size(&out);
69 if(outLen>=0){
70 rc = cson_value_new_string(blob_buffer(&out),
71
+3 -3
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -519,11 +519,11 @@
519519
int argPos = g.json.dispatchDepth;
520520
int r1 = 0, r2 = 0;
521521
Manifest * pW1 = NULL, *pW2 = NULL;
522522
Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
523523
char const * zErrTag = NULL;
524
- u64 diffFlags;
524
+ DiffConfig DCfg;
525525
char * zUuid = NULL;
526526
if( !g.perm.Hyperlink ){
527527
json_set_err(FSL_JSON_E_DENIED,
528528
"Requires 'h' permissions.");
529529
return NULL;
@@ -567,12 +567,12 @@
567567
568568
blob_init(&w1, pW1->zWiki, -1);
569569
blob_zero(&w2);
570570
blob_init(&w2, pW2->zWiki, -1);
571571
blob_zero(&d);
572
- diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR;
573
- text_diff(&w1, &w2, &d, 0, diffFlags);
572
+ diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR);
573
+ text_diff(&w1, &w2, &d, &DCfg);
574574
blob_reset(&w1);
575575
blob_reset(&w2);
576576
577577
pay = cson_new_object();
578578
579579
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -519,11 +519,11 @@
519 int argPos = g.json.dispatchDepth;
520 int r1 = 0, r2 = 0;
521 Manifest * pW1 = NULL, *pW2 = NULL;
522 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
523 char const * zErrTag = NULL;
524 u64 diffFlags;
525 char * zUuid = NULL;
526 if( !g.perm.Hyperlink ){
527 json_set_err(FSL_JSON_E_DENIED,
528 "Requires 'h' permissions.");
529 return NULL;
@@ -567,12 +567,12 @@
567
568 blob_init(&w1, pW1->zWiki, -1);
569 blob_zero(&w2);
570 blob_init(&w2, pW2->zWiki, -1);
571 blob_zero(&d);
572 diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR;
573 text_diff(&w1, &w2, &d, 0, diffFlags);
574 blob_reset(&w1);
575 blob_reset(&w2);
576
577 pay = cson_new_object();
578
579
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -519,11 +519,11 @@
519 int argPos = g.json.dispatchDepth;
520 int r1 = 0, r2 = 0;
521 Manifest * pW1 = NULL, *pW2 = NULL;
522 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
523 char const * zErrTag = NULL;
524 DiffConfig DCfg;
525 char * zUuid = NULL;
526 if( !g.perm.Hyperlink ){
527 json_set_err(FSL_JSON_E_DENIED,
528 "Requires 'h' permissions.");
529 return NULL;
@@ -567,12 +567,12 @@
567
568 blob_init(&w1, pW1->zWiki, -1);
569 blob_zero(&w2);
570 blob_init(&w2, pW2->zWiki, -1);
571 blob_zero(&d);
572 diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR);
573 text_diff(&w1, &w2, &d, &DCfg);
574 blob_reset(&w1);
575 blob_reset(&w2);
576
577 pay = cson_new_object();
578
579
+4 -2
--- src/merge3.c
+++ src/merge3.c
@@ -196,10 +196,11 @@
196196
int i1, i2; /* Index into aC1[] and aC2[] */
197197
int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
198198
int limit1, limit2; /* Sizes of aC1[] and aC2[] */
199199
int nConflict = 0; /* Number of merge conflicts seen so far */
200200
int useCrLf = 0;
201
+ DiffConfig DCfg;
201202
202203
blob_zero(pOut); /* Merge results stored in pOut */
203204
204205
/* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
205206
** keep it in the output. This should be secure enough not to cause
@@ -224,12 +225,13 @@
224225
** is the number of lines of text to copy directly from the pivot,
225226
** the second integer is the number of lines of text to omit from the
226227
** pivot, and the third integer is the number of lines of text that are
227228
** inserted. The edit array ends with a triple of 0,0,0.
228229
*/
229
- aC1 = text_diff(pPivot, pV1, 0, 0, 0);
230
- aC2 = text_diff(pPivot, pV2, 0, 0, 0);
230
+ diff_config_init(&DCfg, 0);
231
+ aC1 = text_diff(pPivot, pV1, 0, &DCfg);
232
+ aC2 = text_diff(pPivot, pV2, 0, &DCfg);
231233
if( aC1==0 || aC2==0 ){
232234
free(aC1);
233235
free(aC2);
234236
return -1;
235237
}
236238
--- src/merge3.c
+++ src/merge3.c
@@ -196,10 +196,11 @@
196 int i1, i2; /* Index into aC1[] and aC2[] */
197 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
198 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
199 int nConflict = 0; /* Number of merge conflicts seen so far */
200 int useCrLf = 0;
 
201
202 blob_zero(pOut); /* Merge results stored in pOut */
203
204 /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
205 ** keep it in the output. This should be secure enough not to cause
@@ -224,12 +225,13 @@
224 ** is the number of lines of text to copy directly from the pivot,
225 ** the second integer is the number of lines of text to omit from the
226 ** pivot, and the third integer is the number of lines of text that are
227 ** inserted. The edit array ends with a triple of 0,0,0.
228 */
229 aC1 = text_diff(pPivot, pV1, 0, 0, 0);
230 aC2 = text_diff(pPivot, pV2, 0, 0, 0);
 
231 if( aC1==0 || aC2==0 ){
232 free(aC1);
233 free(aC2);
234 return -1;
235 }
236
--- src/merge3.c
+++ src/merge3.c
@@ -196,10 +196,11 @@
196 int i1, i2; /* Index into aC1[] and aC2[] */
197 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
198 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
199 int nConflict = 0; /* Number of merge conflicts seen so far */
200 int useCrLf = 0;
201 DiffConfig DCfg;
202
203 blob_zero(pOut); /* Merge results stored in pOut */
204
205 /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
206 ** keep it in the output. This should be secure enough not to cause
@@ -224,12 +225,13 @@
225 ** is the number of lines of text to copy directly from the pivot,
226 ** the second integer is the number of lines of text to omit from the
227 ** pivot, and the third integer is the number of lines of text that are
228 ** inserted. The edit array ends with a triple of 0,0,0.
229 */
230 diff_config_init(&DCfg, 0);
231 aC1 = text_diff(pPivot, pV1, 0, &DCfg);
232 aC2 = text_diff(pPivot, pV2, 0, &DCfg);
233 if( aC1==0 || aC2==0 ){
234 free(aC1);
235 free(aC2);
236 return -1;
237 }
238
+14 -14
--- src/patch.c
+++ src/patch.c
@@ -720,15 +720,15 @@
720720
static void patch_diff(
721721
unsigned mFlags, /* Patch flags. only -f is allowed */
722722
const char *zDiffCmd, /* Command used for diffing */
723723
const char *zBinGlob, /* GLOB pattern to determine binary files */
724724
int fIncludeBinary, /* Do diffs against binary files */
725
- u64 diffFlags /* Other diff flags */
725
+ DiffConfig *pCfg /* Diff options */
726726
){
727727
int nErr = 0;
728728
Stmt q;
729
- int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
729
+ int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0;
730730
Blob empty;
731731
blob_zero(&empty);
732732
733733
if( (mFlags & PATCH_FORCE)==0 ){
734734
/* Check to ensure that the patch is against the repository that
@@ -764,11 +764,11 @@
764764
"in the %s repository", zBaseline, g.zRepositoryName);
765765
}
766766
}
767767
}
768768
769
- diff_begin(diffFlags);
769
+ diff_begin(pCfg);
770770
db_prepare(&q,
771771
"SELECT"
772772
" (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
773773
" pathname," /* 1: new pathname */
774774
" origname," /* 2: original pathname. Null if not renamed */
@@ -804,25 +804,25 @@
804804
zName = db_column_text(&q, 1);
805805
rid = db_column_int(&q, 0);
806806
807807
if( db_column_type(&q,3)==SQLITE_NULL ){
808808
if( !bWebpage ) fossil_print("DELETE %s\n", zName);
809
- diff_print_index(zName, diffFlags, 0);
809
+ diff_print_index(zName, pCfg, 0);
810810
isBin2 = 0;
811811
content_get(rid, &a);
812812
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
813813
diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
814
- zBinGlob, fIncludeBinary, diffFlags);
814
+ zBinGlob, fIncludeBinary, pCfg);
815815
}else if( rid==0 ){
816816
db_ephemeral_blob(&q, 3, &a);
817817
blob_uncompress(&a, &a);
818818
if( !bWebpage ) fossil_print("ADDED %s\n", zName);
819
- diff_print_index(zName, diffFlags, 0);
819
+ diff_print_index(zName, pCfg, 0);
820820
isBin1 = 0;
821821
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
822822
diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
823
- zBinGlob, fIncludeBinary, diffFlags);
823
+ zBinGlob, fIncludeBinary, pCfg);
824824
blob_reset(&a);
825825
}else if( db_column_bytes(&q, 3)>0 ){
826826
Blob delta;
827827
db_ephemeral_blob(&q, 3, &delta);
828828
blob_uncompress(&delta, &delta);
@@ -829,18 +829,18 @@
829829
content_get(rid, &a);
830830
blob_delta_apply(&a, &delta, &b);
831831
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
832832
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
833833
diff_file_mem(&a, &b, isBin1, isBin2, zName,
834
- zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
834
+ zDiffCmd, zBinGlob, fIncludeBinary, pCfg);
835835
blob_reset(&a);
836836
blob_reset(&b);
837837
blob_reset(&delta);
838838
}
839839
}
840840
db_finalize(&q);
841
- diff_end(diffFlags, nErr);
841
+ diff_end(pCfg, nErr);
842842
if( nErr ) fossil_fatal("abort due to prior errors");
843843
}
844844
845845
846846
/*
@@ -949,36 +949,36 @@
949949
}else
950950
if( strncmp(zCmd, "diff", n)==0 ){
951951
const char *zDiffCmd = 0;
952952
const char *zBinGlob = 0;
953953
int fIncludeBinary = 0;
954
- u64 diffFlags;
955954
char *zIn;
956955
unsigned flags = 0;
956
+ DiffConfig DCfg;
957957
958958
if( find_option("tk",0,0)!=0 ){
959959
db_close(0);
960960
diff_tk("patch diff", 3);
961961
return;
962962
}
963
- diffFlags = diff_options();
963
+ diff_options(&DCfg, zCmd[0]=='g');
964964
if( find_option("internal","i",0)==0
965
- && (diffFlags & DIFF_HTML)==0
965
+ && (DCfg.diffFlags & DIFF_HTML)==0
966966
){
967967
zDiffCmd = diff_command_external(zCmd[0]=='g');
968968
}
969
- if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
969
+ if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE;
970970
if( zDiffCmd ){
971971
zBinGlob = diff_get_binary_glob();
972972
fIncludeBinary = diff_include_binary_files();
973973
}
974974
db_find_and_open_repository(0, 0);
975975
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
976976
verify_all_options();
977977
zIn = patch_find_patch_filename("apply");
978978
patch_attach(zIn, stdin);
979
- patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
979
+ patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, &DCfg);
980980
fossil_free(zIn);
981981
}else
982982
if( strncmp(zCmd, "pull", n)==0 ){
983983
FILE *pIn = 0;
984984
unsigned flags = 0;
985985
--- src/patch.c
+++ src/patch.c
@@ -720,15 +720,15 @@
720 static void patch_diff(
721 unsigned mFlags, /* Patch flags. only -f is allowed */
722 const char *zDiffCmd, /* Command used for diffing */
723 const char *zBinGlob, /* GLOB pattern to determine binary files */
724 int fIncludeBinary, /* Do diffs against binary files */
725 u64 diffFlags /* Other diff flags */
726 ){
727 int nErr = 0;
728 Stmt q;
729 int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
730 Blob empty;
731 blob_zero(&empty);
732
733 if( (mFlags & PATCH_FORCE)==0 ){
734 /* Check to ensure that the patch is against the repository that
@@ -764,11 +764,11 @@
764 "in the %s repository", zBaseline, g.zRepositoryName);
765 }
766 }
767 }
768
769 diff_begin(diffFlags);
770 db_prepare(&q,
771 "SELECT"
772 " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
773 " pathname," /* 1: new pathname */
774 " origname," /* 2: original pathname. Null if not renamed */
@@ -804,25 +804,25 @@
804 zName = db_column_text(&q, 1);
805 rid = db_column_int(&q, 0);
806
807 if( db_column_type(&q,3)==SQLITE_NULL ){
808 if( !bWebpage ) fossil_print("DELETE %s\n", zName);
809 diff_print_index(zName, diffFlags, 0);
810 isBin2 = 0;
811 content_get(rid, &a);
812 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
813 diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
814 zBinGlob, fIncludeBinary, diffFlags);
815 }else if( rid==0 ){
816 db_ephemeral_blob(&q, 3, &a);
817 blob_uncompress(&a, &a);
818 if( !bWebpage ) fossil_print("ADDED %s\n", zName);
819 diff_print_index(zName, diffFlags, 0);
820 isBin1 = 0;
821 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
822 diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
823 zBinGlob, fIncludeBinary, diffFlags);
824 blob_reset(&a);
825 }else if( db_column_bytes(&q, 3)>0 ){
826 Blob delta;
827 db_ephemeral_blob(&q, 3, &delta);
828 blob_uncompress(&delta, &delta);
@@ -829,18 +829,18 @@
829 content_get(rid, &a);
830 blob_delta_apply(&a, &delta, &b);
831 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
832 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
833 diff_file_mem(&a, &b, isBin1, isBin2, zName,
834 zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
835 blob_reset(&a);
836 blob_reset(&b);
837 blob_reset(&delta);
838 }
839 }
840 db_finalize(&q);
841 diff_end(diffFlags, nErr);
842 if( nErr ) fossil_fatal("abort due to prior errors");
843 }
844
845
846 /*
@@ -949,36 +949,36 @@
949 }else
950 if( strncmp(zCmd, "diff", n)==0 ){
951 const char *zDiffCmd = 0;
952 const char *zBinGlob = 0;
953 int fIncludeBinary = 0;
954 u64 diffFlags;
955 char *zIn;
956 unsigned flags = 0;
 
957
958 if( find_option("tk",0,0)!=0 ){
959 db_close(0);
960 diff_tk("patch diff", 3);
961 return;
962 }
963 diffFlags = diff_options();
964 if( find_option("internal","i",0)==0
965 && (diffFlags & DIFF_HTML)==0
966 ){
967 zDiffCmd = diff_command_external(zCmd[0]=='g');
968 }
969 if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
970 if( zDiffCmd ){
971 zBinGlob = diff_get_binary_glob();
972 fIncludeBinary = diff_include_binary_files();
973 }
974 db_find_and_open_repository(0, 0);
975 if( find_option("force","f",0) ) flags |= PATCH_FORCE;
976 verify_all_options();
977 zIn = patch_find_patch_filename("apply");
978 patch_attach(zIn, stdin);
979 patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
980 fossil_free(zIn);
981 }else
982 if( strncmp(zCmd, "pull", n)==0 ){
983 FILE *pIn = 0;
984 unsigned flags = 0;
985
--- src/patch.c
+++ src/patch.c
@@ -720,15 +720,15 @@
720 static void patch_diff(
721 unsigned mFlags, /* Patch flags. only -f is allowed */
722 const char *zDiffCmd, /* Command used for diffing */
723 const char *zBinGlob, /* GLOB pattern to determine binary files */
724 int fIncludeBinary, /* Do diffs against binary files */
725 DiffConfig *pCfg /* Diff options */
726 ){
727 int nErr = 0;
728 Stmt q;
729 int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0;
730 Blob empty;
731 blob_zero(&empty);
732
733 if( (mFlags & PATCH_FORCE)==0 ){
734 /* Check to ensure that the patch is against the repository that
@@ -764,11 +764,11 @@
764 "in the %s repository", zBaseline, g.zRepositoryName);
765 }
766 }
767 }
768
769 diff_begin(pCfg);
770 db_prepare(&q,
771 "SELECT"
772 " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
773 " pathname," /* 1: new pathname */
774 " origname," /* 2: original pathname. Null if not renamed */
@@ -804,25 +804,25 @@
804 zName = db_column_text(&q, 1);
805 rid = db_column_int(&q, 0);
806
807 if( db_column_type(&q,3)==SQLITE_NULL ){
808 if( !bWebpage ) fossil_print("DELETE %s\n", zName);
809 diff_print_index(zName, pCfg, 0);
810 isBin2 = 0;
811 content_get(rid, &a);
812 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
813 diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
814 zBinGlob, fIncludeBinary, pCfg);
815 }else if( rid==0 ){
816 db_ephemeral_blob(&q, 3, &a);
817 blob_uncompress(&a, &a);
818 if( !bWebpage ) fossil_print("ADDED %s\n", zName);
819 diff_print_index(zName, pCfg, 0);
820 isBin1 = 0;
821 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
822 diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
823 zBinGlob, fIncludeBinary, pCfg);
824 blob_reset(&a);
825 }else if( db_column_bytes(&q, 3)>0 ){
826 Blob delta;
827 db_ephemeral_blob(&q, 3, &delta);
828 blob_uncompress(&delta, &delta);
@@ -829,18 +829,18 @@
829 content_get(rid, &a);
830 blob_delta_apply(&a, &delta, &b);
831 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
832 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
833 diff_file_mem(&a, &b, isBin1, isBin2, zName,
834 zDiffCmd, zBinGlob, fIncludeBinary, pCfg);
835 blob_reset(&a);
836 blob_reset(&b);
837 blob_reset(&delta);
838 }
839 }
840 db_finalize(&q);
841 diff_end(pCfg, nErr);
842 if( nErr ) fossil_fatal("abort due to prior errors");
843 }
844
845
846 /*
@@ -949,36 +949,36 @@
949 }else
950 if( strncmp(zCmd, "diff", n)==0 ){
951 const char *zDiffCmd = 0;
952 const char *zBinGlob = 0;
953 int fIncludeBinary = 0;
 
954 char *zIn;
955 unsigned flags = 0;
956 DiffConfig DCfg;
957
958 if( find_option("tk",0,0)!=0 ){
959 db_close(0);
960 diff_tk("patch diff", 3);
961 return;
962 }
963 diff_options(&DCfg, zCmd[0]=='g');
964 if( find_option("internal","i",0)==0
965 && (DCfg.diffFlags & DIFF_HTML)==0
966 ){
967 zDiffCmd = diff_command_external(zCmd[0]=='g');
968 }
969 if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE;
970 if( zDiffCmd ){
971 zBinGlob = diff_get_binary_glob();
972 fIncludeBinary = diff_include_binary_files();
973 }
974 db_find_and_open_repository(0, 0);
975 if( find_option("force","f",0) ) flags |= PATCH_FORCE;
976 verify_all_options();
977 zIn = patch_find_patch_filename("apply");
978 patch_attach(zIn, stdin);
979 patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, &DCfg);
980 fossil_free(zIn);
981 }else
982 if( strncmp(zCmd, "pull", n)==0 ){
983 FILE *pIn = 0;
984 unsigned flags = 0;
985
+9 -6
--- src/skins.c
+++ src/skins.c
@@ -867,22 +867,25 @@
867867
@ Baseline: \
868868
skin_emit_skin_selector("basis", zBasis, zDraft);
869869
@ <input type="submit" name="diff" value="Unified Diff" />
870870
@ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" />
871871
if( P("diff")!=0 || P("sbsdiff")!=0 ){
872
- u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR;
873872
Blob from, to, out;
874
- if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
873
+ DiffConfig DCfg;
874
+ construct_diff_flags(1, &DCfg);
875
+ DCfg.diffFlags |= DIFF_STRIP_EOLCR;
876
+ if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE;
875877
blob_init(&to, zContent, -1);
876878
blob_init(&from, skin_file_content(zBasis, zFile), -1);
877879
blob_zero(&out);
878
- if( diffFlags & DIFF_SIDEBYSIDE ){
879
- text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
880
+ DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
881
+ if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
882
+ text_diff(&from, &to, &out, &DCfg);
880883
@ %s(blob_str(&out))
881884
}else{
882
- text_diff(&from, &to, &out, 0,
883
- diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
885
+ DCfg.diffFlags |= DIFF_LINENO;
886
+ text_diff(&from, &to, &out, &DCfg);
884887
@ <pre class="udiff">
885888
@ %s(blob_str(&out))
886889
@ </pre>
887890
}
888891
blob_reset(&from);
889892
--- src/skins.c
+++ src/skins.c
@@ -867,22 +867,25 @@
867 @ Baseline: \
868 skin_emit_skin_selector("basis", zBasis, zDraft);
869 @ <input type="submit" name="diff" value="Unified Diff" />
870 @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" />
871 if( P("diff")!=0 || P("sbsdiff")!=0 ){
872 u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR;
873 Blob from, to, out;
874 if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
 
 
 
875 blob_init(&to, zContent, -1);
876 blob_init(&from, skin_file_content(zBasis, zFile), -1);
877 blob_zero(&out);
878 if( diffFlags & DIFF_SIDEBYSIDE ){
879 text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
 
880 @ %s(blob_str(&out))
881 }else{
882 text_diff(&from, &to, &out, 0,
883 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
884 @ <pre class="udiff">
885 @ %s(blob_str(&out))
886 @ </pre>
887 }
888 blob_reset(&from);
889
--- src/skins.c
+++ src/skins.c
@@ -867,22 +867,25 @@
867 @ Baseline: \
868 skin_emit_skin_selector("basis", zBasis, zDraft);
869 @ <input type="submit" name="diff" value="Unified Diff" />
870 @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" />
871 if( P("diff")!=0 || P("sbsdiff")!=0 ){
 
872 Blob from, to, out;
873 DiffConfig DCfg;
874 construct_diff_flags(1, &DCfg);
875 DCfg.diffFlags |= DIFF_STRIP_EOLCR;
876 if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE;
877 blob_init(&to, zContent, -1);
878 blob_init(&from, skin_file_content(zBasis, zFile), -1);
879 blob_zero(&out);
880 DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
881 if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
882 text_diff(&from, &to, &out, &DCfg);
883 @ %s(blob_str(&out))
884 }else{
885 DCfg.diffFlags |= DIFF_LINENO;
886 text_diff(&from, &to, &out, &DCfg);
887 @ <pre class="udiff">
888 @ %s(blob_str(&out))
889 @ </pre>
890 }
891 blob_reset(&from);
892
+17 -18
--- src/stash.c
+++ src/stash.c
@@ -406,17 +406,17 @@
406406
int stashid, /* The stash entry to diff */
407407
const char *zDiffCmd, /* Command used for diffing */
408408
const char *zBinGlob, /* GLOB pattern to determine binary files */
409409
int fBaseline, /* Diff against original baseline check-in if true */
410410
int fIncludeBinary, /* Do diffs against binary files */
411
- u64 diffFlags /* Other diff flags */
411
+ DiffConfig *pCfg /* Diff formatting options */
412412
){
413413
Stmt q;
414414
Blob empty;
415
- int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
415
+ int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0;
416416
blob_zero(&empty);
417
- diff_begin(diffFlags);
417
+ diff_begin(pCfg);
418418
db_prepare(&q,
419419
"SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
420420
" FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
421421
stashid
422422
);
@@ -430,56 +430,56 @@
430430
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
431431
Blob a, b;
432432
if( rid==0 ){
433433
db_ephemeral_blob(&q, 6, &a);
434434
if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
435
- diff_print_index(zNew, diffFlags, 0);
435
+ diff_print_index(zNew, pCfg, 0);
436436
isBin1 = 0;
437437
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
438438
diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
439
- zBinGlob, fIncludeBinary, diffFlags);
439
+ zBinGlob, fIncludeBinary, pCfg);
440440
}else if( isRemoved ){
441441
if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
442
- diff_print_index(zNew, diffFlags, 0);
442
+ diff_print_index(zNew, pCfg, 0);
443443
isBin2 = 0;
444444
if( fBaseline ){
445445
content_get(rid, &a);
446446
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
447447
diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
448
- zBinGlob, fIncludeBinary, diffFlags);
448
+ zBinGlob, fIncludeBinary, pCfg);
449449
}
450450
}else{
451451
Blob delta;
452452
int isOrigLink = file_islink(zOPath);
453453
db_ephemeral_blob(&q, 6, &delta);
454454
if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
455455
if( !isOrigLink != !isLink ){
456
- diff_print_index(zNew, diffFlags, 0);
457
- diff_print_filenames(zOrig, zNew, diffFlags, 0);
456
+ diff_print_index(zNew, pCfg, 0);
457
+ diff_print_filenames(zOrig, zNew, pCfg, 0);
458458
printf(DIFF_CANNOT_COMPUTE_SYMLINK);
459459
}else{
460460
content_get(rid, &a);
461461
blob_delta_apply(&a, &delta, &b);
462462
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
463463
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
464464
if( fBaseline ){
465465
diff_file_mem(&a, &b, isBin1, isBin2, zNew,
466
- zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
466
+ zDiffCmd, zBinGlob, fIncludeBinary, pCfg);
467467
}else{
468468
/*Diff with file on disk using fSwapDiff=1 to show the diff in the
469469
same direction as if fBaseline=1.*/
470470
diff_file(&b, isBin2, zOPath, zNew, zDiffCmd,
471
- zBinGlob, fIncludeBinary, diffFlags, 1, 0);
471
+ zBinGlob, fIncludeBinary, pCfg, 1, 0);
472472
}
473473
blob_reset(&a);
474474
blob_reset(&b);
475475
}
476476
blob_reset(&delta);
477477
}
478478
}
479479
db_finalize(&q);
480
- diff_end(diffFlags, 0);
480
+ diff_end(pCfg, 0);
481481
}
482482
483483
/*
484484
** Drop the indicated stash
485485
*/
@@ -744,35 +744,34 @@
744744
){
745745
const char *zDiffCmd = 0;
746746
const char *zBinGlob = 0;
747747
int fIncludeBinary = 0;
748748
int fBaseline = 0;
749
- u64 diffFlags;
749
+ DiffConfig DCfg;
750750
751751
if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
752752
fBaseline = 1;
753753
}
754754
if( find_option("tk",0,0)!=0 ){
755755
db_close(0);
756756
diff_tk(fBaseline ? "stash show" : "stash diff", 3);
757757
return;
758758
}
759
- diffFlags = diff_options();
759
+ diff_options(&DCfg, zCmd[0]=='g');
760760
if( find_option("internal","i",0)==0
761
- && (diffFlags & DIFF_HTML)==0
761
+ && (DCfg.diffFlags & DIFF_HTML)==0
762762
){
763763
zDiffCmd = diff_command_external(zCmd[0]=='g');
764764
}
765
- if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
765
+ if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE;
766766
if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd));
767767
if( zDiffCmd ){
768768
zBinGlob = diff_get_binary_glob();
769769
fIncludeBinary = diff_include_binary_files();
770770
}
771771
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
772
- stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary,
773
- diffFlags);
772
+ stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, &DCfg);
774773
}else
775774
if( memcmp(zCmd, "help", nCmd)==0 ){
776775
g.argv[1] = "help";
777776
g.argv[2] = "stash";
778777
g.argc = 3;
779778
--- src/stash.c
+++ src/stash.c
@@ -406,17 +406,17 @@
406 int stashid, /* The stash entry to diff */
407 const char *zDiffCmd, /* Command used for diffing */
408 const char *zBinGlob, /* GLOB pattern to determine binary files */
409 int fBaseline, /* Diff against original baseline check-in if true */
410 int fIncludeBinary, /* Do diffs against binary files */
411 u64 diffFlags /* Other diff flags */
412 ){
413 Stmt q;
414 Blob empty;
415 int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
416 blob_zero(&empty);
417 diff_begin(diffFlags);
418 db_prepare(&q,
419 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
420 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
421 stashid
422 );
@@ -430,56 +430,56 @@
430 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
431 Blob a, b;
432 if( rid==0 ){
433 db_ephemeral_blob(&q, 6, &a);
434 if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
435 diff_print_index(zNew, diffFlags, 0);
436 isBin1 = 0;
437 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
438 diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
439 zBinGlob, fIncludeBinary, diffFlags);
440 }else if( isRemoved ){
441 if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
442 diff_print_index(zNew, diffFlags, 0);
443 isBin2 = 0;
444 if( fBaseline ){
445 content_get(rid, &a);
446 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
447 diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
448 zBinGlob, fIncludeBinary, diffFlags);
449 }
450 }else{
451 Blob delta;
452 int isOrigLink = file_islink(zOPath);
453 db_ephemeral_blob(&q, 6, &delta);
454 if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
455 if( !isOrigLink != !isLink ){
456 diff_print_index(zNew, diffFlags, 0);
457 diff_print_filenames(zOrig, zNew, diffFlags, 0);
458 printf(DIFF_CANNOT_COMPUTE_SYMLINK);
459 }else{
460 content_get(rid, &a);
461 blob_delta_apply(&a, &delta, &b);
462 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
463 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
464 if( fBaseline ){
465 diff_file_mem(&a, &b, isBin1, isBin2, zNew,
466 zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
467 }else{
468 /*Diff with file on disk using fSwapDiff=1 to show the diff in the
469 same direction as if fBaseline=1.*/
470 diff_file(&b, isBin2, zOPath, zNew, zDiffCmd,
471 zBinGlob, fIncludeBinary, diffFlags, 1, 0);
472 }
473 blob_reset(&a);
474 blob_reset(&b);
475 }
476 blob_reset(&delta);
477 }
478 }
479 db_finalize(&q);
480 diff_end(diffFlags, 0);
481 }
482
483 /*
484 ** Drop the indicated stash
485 */
@@ -744,35 +744,34 @@
744 ){
745 const char *zDiffCmd = 0;
746 const char *zBinGlob = 0;
747 int fIncludeBinary = 0;
748 int fBaseline = 0;
749 u64 diffFlags;
750
751 if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
752 fBaseline = 1;
753 }
754 if( find_option("tk",0,0)!=0 ){
755 db_close(0);
756 diff_tk(fBaseline ? "stash show" : "stash diff", 3);
757 return;
758 }
759 diffFlags = diff_options();
760 if( find_option("internal","i",0)==0
761 && (diffFlags & DIFF_HTML)==0
762 ){
763 zDiffCmd = diff_command_external(zCmd[0]=='g');
764 }
765 if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
766 if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd));
767 if( zDiffCmd ){
768 zBinGlob = diff_get_binary_glob();
769 fIncludeBinary = diff_include_binary_files();
770 }
771 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
772 stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary,
773 diffFlags);
774 }else
775 if( memcmp(zCmd, "help", nCmd)==0 ){
776 g.argv[1] = "help";
777 g.argv[2] = "stash";
778 g.argc = 3;
779
--- src/stash.c
+++ src/stash.c
@@ -406,17 +406,17 @@
406 int stashid, /* The stash entry to diff */
407 const char *zDiffCmd, /* Command used for diffing */
408 const char *zBinGlob, /* GLOB pattern to determine binary files */
409 int fBaseline, /* Diff against original baseline check-in if true */
410 int fIncludeBinary, /* Do diffs against binary files */
411 DiffConfig *pCfg /* Diff formatting options */
412 ){
413 Stmt q;
414 Blob empty;
415 int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0;
416 blob_zero(&empty);
417 diff_begin(pCfg);
418 db_prepare(&q,
419 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
420 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
421 stashid
422 );
@@ -430,56 +430,56 @@
430 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
431 Blob a, b;
432 if( rid==0 ){
433 db_ephemeral_blob(&q, 6, &a);
434 if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
435 diff_print_index(zNew, pCfg, 0);
436 isBin1 = 0;
437 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
438 diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
439 zBinGlob, fIncludeBinary, pCfg);
440 }else if( isRemoved ){
441 if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
442 diff_print_index(zNew, pCfg, 0);
443 isBin2 = 0;
444 if( fBaseline ){
445 content_get(rid, &a);
446 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
447 diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
448 zBinGlob, fIncludeBinary, pCfg);
449 }
450 }else{
451 Blob delta;
452 int isOrigLink = file_islink(zOPath);
453 db_ephemeral_blob(&q, 6, &delta);
454 if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
455 if( !isOrigLink != !isLink ){
456 diff_print_index(zNew, pCfg, 0);
457 diff_print_filenames(zOrig, zNew, pCfg, 0);
458 printf(DIFF_CANNOT_COMPUTE_SYMLINK);
459 }else{
460 content_get(rid, &a);
461 blob_delta_apply(&a, &delta, &b);
462 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
463 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
464 if( fBaseline ){
465 diff_file_mem(&a, &b, isBin1, isBin2, zNew,
466 zDiffCmd, zBinGlob, fIncludeBinary, pCfg);
467 }else{
468 /*Diff with file on disk using fSwapDiff=1 to show the diff in the
469 same direction as if fBaseline=1.*/
470 diff_file(&b, isBin2, zOPath, zNew, zDiffCmd,
471 zBinGlob, fIncludeBinary, pCfg, 1, 0);
472 }
473 blob_reset(&a);
474 blob_reset(&b);
475 }
476 blob_reset(&delta);
477 }
478 }
479 db_finalize(&q);
480 diff_end(pCfg, 0);
481 }
482
483 /*
484 ** Drop the indicated stash
485 */
@@ -744,35 +744,34 @@
744 ){
745 const char *zDiffCmd = 0;
746 const char *zBinGlob = 0;
747 int fIncludeBinary = 0;
748 int fBaseline = 0;
749 DiffConfig DCfg;
750
751 if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
752 fBaseline = 1;
753 }
754 if( find_option("tk",0,0)!=0 ){
755 db_close(0);
756 diff_tk(fBaseline ? "stash show" : "stash diff", 3);
757 return;
758 }
759 diff_options(&DCfg, zCmd[0]=='g');
760 if( find_option("internal","i",0)==0
761 && (DCfg.diffFlags & DIFF_HTML)==0
762 ){
763 zDiffCmd = diff_command_external(zCmd[0]=='g');
764 }
765 if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE;
766 if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd));
767 if( zDiffCmd ){
768 zBinGlob = diff_get_binary_glob();
769 fIncludeBinary = diff_include_binary_files();
770 }
771 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
772 stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, &DCfg);
 
773 }else
774 if( memcmp(zCmd, "help", nCmd)==0 ){
775 g.argv[1] = "help";
776 g.argv[2] = "stash";
777 g.argc = 3;
778
+4 -3
--- src/wiki.c
+++ src/wiki.c
@@ -1815,11 +1815,11 @@
18151815
const char *zId;
18161816
const char *zPid;
18171817
Manifest *pW1, *pW2 = 0;
18181818
int rid1, rid2, nextRid;
18191819
Blob w1, w2, d;
1820
- u64 diffFlags;
1820
+ DiffConfig DCfg;
18211821
18221822
login_check_credentials();
18231823
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
18241824
zId = P("id");
18251825
if( zId==0 ){
@@ -1858,12 +1858,13 @@
18581858
style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid);
18591859
}
18601860
style_set_current_feature("wiki");
18611861
style_header("Changes To %s", pW1->zWikiTitle);
18621862
blob_zero(&d);
1863
- diffFlags = construct_diff_flags(1);
1864
- text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
1863
+ construct_diff_flags(1, &DCfg);
1864
+ DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
1865
+ text_diff(&w2, &w1, &d, &DCfg);
18651866
@ <pre class="udiff">
18661867
@ %s(blob_str(&d))
18671868
@ <pre>
18681869
manifest_destroy(pW1);
18691870
manifest_destroy(pW2);
18701871
--- src/wiki.c
+++ src/wiki.c
@@ -1815,11 +1815,11 @@
1815 const char *zId;
1816 const char *zPid;
1817 Manifest *pW1, *pW2 = 0;
1818 int rid1, rid2, nextRid;
1819 Blob w1, w2, d;
1820 u64 diffFlags;
1821
1822 login_check_credentials();
1823 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1824 zId = P("id");
1825 if( zId==0 ){
@@ -1858,12 +1858,13 @@
1858 style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid);
1859 }
1860 style_set_current_feature("wiki");
1861 style_header("Changes To %s", pW1->zWikiTitle);
1862 blob_zero(&d);
1863 diffFlags = construct_diff_flags(1);
1864 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
 
1865 @ <pre class="udiff">
1866 @ %s(blob_str(&d))
1867 @ <pre>
1868 manifest_destroy(pW1);
1869 manifest_destroy(pW2);
1870
--- src/wiki.c
+++ src/wiki.c
@@ -1815,11 +1815,11 @@
1815 const char *zId;
1816 const char *zPid;
1817 Manifest *pW1, *pW2 = 0;
1818 int rid1, rid2, nextRid;
1819 Blob w1, w2, d;
1820 DiffConfig DCfg;
1821
1822 login_check_credentials();
1823 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1824 zId = P("id");
1825 if( zId==0 ){
@@ -1858,12 +1858,13 @@
1858 style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid);
1859 }
1860 style_set_current_feature("wiki");
1861 style_header("Changes To %s", pW1->zWikiTitle);
1862 blob_zero(&d);
1863 construct_diff_flags(1, &DCfg);
1864 DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
1865 text_diff(&w2, &w1, &d, &DCfg);
1866 @ <pre class="udiff">
1867 @ %s(blob_str(&d))
1868 @ <pre>
1869 manifest_destroy(pW1);
1870 manifest_destroy(pW2);
1871

Keyboard Shortcuts

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