Fossil SCM

Add the Dline.nw field. Use it as a cache of the number of characters on a line with leading and trailing whitespace removed.

drh 2022-01-22 17:11 diff-improvement
Commit f6112b93e9bbb7e37f24d83fb322c48f9d113c4d35d4cab3d33c23d59e784933
1 file changed +103 -65
+103 -65
--- src/diff.c
+++ src/diff.c
@@ -121,12 +121,13 @@
121121
*/
122122
typedef struct DLine DLine;
123123
struct DLine {
124124
const char *z; /* The text of the line */
125125
u64 h; /* Hash of the line */
126
- unsigned short indent; /* Index of first non-space, non-control char */
126
+ unsigned short indent; /* Index of first non-space */
127127
unsigned short n; /* number of bytes */
128
+ unsigned short nw; /* number of bytes without leading/trailing space */
128129
unsigned int iNext; /* 1+(Index of next line with same the same hash) */
129130
130131
/* an array of DLine elements serves two purposes. The fields
131132
** above are one per line of input text. But each entry is also
132133
** a bucket in a hash table, as follows: */
@@ -163,12 +164,34 @@
163164
int nEditAlloc; /* Space allocated for aEdit[] */
164165
DLine *aFrom; /* File on left side of the diff */
165166
int nFrom; /* Number of lines in aFrom[] */
166167
DLine *aTo; /* File on right side of the diff */
167168
int nTo; /* Number of lines in aTo[] */
168
- int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
169
+ int (*xDiffer)(DLine*,DLine*); /* comparison function */
170
+};
171
+
172
+/* Fast isspace for use by diff */
173
+static const char diffIsSpace[] = {
174
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
175
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
177
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182
+
183
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
188
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
189
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
190
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169191
};
192
+#define diff_isspace(X) (diffIsSpace[(unsigned char)(X)])
170193
171194
/*
172195
** Count the number of lines in the input string. Include the last line
173196
** in the count even if it lacks the \n terminator. If an empty string
174197
** is specified, the number of lines is zero. For the purposes of this
@@ -246,29 +269,30 @@
246269
if( diffFlags & DIFF_STRIP_EOLCR ){
247270
if( k>0 && z[k-1]=='\r' ){ k--; }
248271
}
249272
a[i].n = k;
250273
if( diffFlags & DIFF_IGNORE_EOLWS ){
251
- while( k>0 && fossil_isspace(z[k-1]) ){ k--; }
274
+ while( k>0 && diff_isspace(z[k-1]) ){ k--; }
252275
}
253
- for(s=0; s<k && z[s]<=' '; s++){}
254
- a[i].indent = s;
255276
if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
256277
int numws = 0;
278
+ for(s=0; s<k && z[s]<=' '; s++){}
279
+ a[i].indent = s;
257280
for(h=0, x=s; x<k; x++){
258281
char c = z[x];
259
- if( fossil_isspace(c) ){
282
+ if( diff_isspace(c) ){
260283
++numws;
261284
}else{
262285
h = (h^c)*9000000000000000041LL;
263286
}
264287
}
265288
k -= numws;
289
+ a[i].nw = k - s;
266290
}else{
267291
int k2 = k & ~0x7;
268292
u64 m;
269
- for(h=x=0; x<k2; x += 8){
293
+ for(h=x=s=0; x<k2; x += 8){
270294
memcpy(&m, z+x, 8);
271295
h = (h^m)*9000000000000000041LL;
272296
}
273297
m = 0;
274298
memcpy(&m, z+x, k-k2);
@@ -289,11 +313,11 @@
289313
}
290314
291315
/*
292316
** Return zero if two DLine elements are identical.
293317
*/
294
-static int compare_dline(const DLine *pA, const DLine *pB){
318
+static int compare_dline(DLine *pA, DLine *pB){
295319
if( pA->h!=pB->h ) return 1;
296320
return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
297321
}
298322
299323
/*
@@ -300,17 +324,17 @@
300324
** Return zero if two DLine elements are identical, ignoring
301325
** all whitespace. The indent field of pA/pB already points
302326
** to the first non-space character in the string.
303327
*/
304328
305
-static int compare_dline_ignore_allws(const DLine *pA, const DLine *pB){
329
+static int compare_dline_ignore_allws(DLine *pA, DLine *pB){
306330
int a = pA->indent, b = pB->indent;
307331
if( pA->h==pB->h ){
308332
while( a<pA->n || b<pB->n ){
309333
if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
310
- while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
311
- while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
334
+ while( a<pA->n && diff_isspace(pA->z[a])) ++a;
335
+ while( b<pB->n && diff_isspace(pB->z[b])) ++b;
312336
}
313337
return pA->n-a != pB->n-b;
314338
}
315339
return 1;
316340
}
@@ -319,11 +343,11 @@
319343
** Return true if the regular expression *pRe matches any of the
320344
** N dlines
321345
*/
322346
static int re_dline_match(
323347
ReCompiled *pRe, /* The regular expression to be matched */
324
- const DLine *aDLine, /* First of N DLines to compare against */
348
+ DLine *aDLine, /* First of N DLines to compare against */
325349
int N /* Number of DLines to check */
326350
){
327351
while( N-- ){
328352
if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
329353
return 1;
@@ -618,11 +642,11 @@
618642
/*
619643
** Return true if the string starts with n spaces
620644
*/
621645
static int allSpaces(const char *z, int n){
622646
int i;
623
- for(i=0; i<n && fossil_isspace(z[i]); i++){}
647
+ for(i=0; i<n && diff_isspace(z[i]); i++){}
624648
return i==n;
625649
}
626650
627651
/*
628652
** Try to improve the human-readability of the LineChange p.
@@ -689,12 +713,12 @@
689713
**
690714
** The result is written into the LineChange object given by the
691715
** third parameter.
692716
*/
693717
static void oneLineChange(
694
- const DLine *pLeft, /* Left line of the change */
695
- const DLine *pRight, /* Right line of the change */
718
+ DLine *pLeft, /* Left line of the change */
719
+ DLine *pRight, /* Right line of the change */
696720
LineChange *p /* OUTPUT: Write the results here */
697721
){
698722
int nLeft; /* Length of left line in bytes */
699723
int nRight; /* Length of right line in bytes */
700724
int nShort; /* Shortest of left and right */
@@ -744,17 +768,17 @@
744768
int nLong = nLeft<nRight ? nRight : nLeft;
745769
int nGap = nLong - nShort;
746770
for(i=nShort-nSuffix; i<=nPrefix; i++){
747771
int iVal = 0;
748772
char c = zLeft[i];
749
- if( fossil_isspace(c) ){
773
+ if( diff_isspace(c) ){
750774
iVal += 5;
751775
}else if( !fossil_isalnum(c) ){
752776
iVal += 2;
753777
}
754778
c = zLeft[i+nGap-1];
755
- if( fossil_isspace(c) ){
779
+ if( diff_isspace(c) ){
756780
iVal += 5;
757781
}else if( !fossil_isalnum(c) ){
758782
iVal += 2;
759783
}
760784
if( iVal>iBestVal ){
@@ -885,15 +909,15 @@
885909
** in appropriate method implementations.
886910
*/
887911
typedef struct DiffBuilder DiffBuilder;
888912
struct DiffBuilder {
889913
void (*xSkip)(DiffBuilder*, unsigned int, int);
890
- void (*xCommon)(DiffBuilder*,const DLine*);
891
- void (*xInsert)(DiffBuilder*,const DLine*);
892
- void (*xDelete)(DiffBuilder*,const DLine*);
893
- void (*xReplace)(DiffBuilder*,const DLine*, const DLine*);
894
- void (*xEdit)(DiffBuilder*,const DLine*,const DLine*);
914
+ void (*xCommon)(DiffBuilder*,DLine*);
915
+ void (*xInsert)(DiffBuilder*,DLine*);
916
+ void (*xDelete)(DiffBuilder*,DLine*);
917
+ void (*xReplace)(DiffBuilder*,DLine*, DLine*);
918
+ void (*xEdit)(DiffBuilder*,DLine*,DLine*);
895919
void (*xEnd)(DiffBuilder*);
896920
unsigned int lnLeft; /* Lines seen on the left (delete) side */
897921
unsigned int lnRight; /* Lines seen on the right (insert) side */
898922
unsigned int nPending; /* Number of pending lines */
899923
int eState; /* State of the output */
@@ -915,35 +939,35 @@
915939
n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n,
916940
isFinal ? " FINAL" : "");
917941
p->lnLeft += n;
918942
p->lnRight += n;
919943
}
920
-static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){
944
+static void dfdebugCommon(DiffBuilder *p, DLine *pLine){
921945
p->lnLeft++;
922946
p->lnRight++;
923947
blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n",
924948
p->lnLeft, p->lnRight, (int)pLine->n, pLine->z);
925949
}
926
-static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){
950
+static void dfdebugInsert(DiffBuilder *p, DLine *pLine){
927951
p->lnRight++;
928952
blob_appendf(p->pOut, "INSERT %8d %.*s\n",
929953
p->lnRight, (int)pLine->n, pLine->z);
930954
}
931
-static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){
955
+static void dfdebugDelete(DiffBuilder *p, DLine *pLine){
932956
p->lnLeft++;
933957
blob_appendf(p->pOut, "DELETE %8u %.*s\n",
934958
p->lnLeft, (int)pLine->n, pLine->z);
935959
}
936
-static void dfdebugReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
960
+static void dfdebugReplace(DiffBuilder *p, DLine *pX, DLine *pY){
937961
p->lnLeft++;
938962
p->lnRight++;
939963
blob_appendf(p->pOut, "REPLACE %8u %.*s\n",
940964
p->lnLeft, (int)pX->n, pX->z);
941965
blob_appendf(p->pOut, " %8u %.*s\n",
942966
p->lnRight, (int)pY->n, pY->z);
943967
}
944
-static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
968
+static void dfdebugEdit(DiffBuilder *p, DLine *pX, DLine *pY){
945969
int i, j;
946970
int x;
947971
LineChange chng;
948972
p->lnLeft++;
949973
p->lnRight++;
@@ -1031,33 +1055,33 @@
10311055
** additional string which is a common suffix.
10321056
*/
10331057
static void dftclSkip(DiffBuilder *p, unsigned int n, int isFinal){
10341058
blob_appendf(p->pOut, "SKIP %u\n", n);
10351059
}
1036
-static void dftclCommon(DiffBuilder *p, const DLine *pLine){
1060
+static void dftclCommon(DiffBuilder *p, DLine *pLine){
10371061
blob_appendf(p->pOut, "COM ");
10381062
blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
10391063
blob_append_char(p->pOut, '\n');
10401064
}
1041
-static void dftclInsert(DiffBuilder *p, const DLine *pLine){
1065
+static void dftclInsert(DiffBuilder *p, DLine *pLine){
10421066
blob_append(p->pOut, "INS ", -1);
10431067
blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
10441068
blob_append_char(p->pOut, '\n');
10451069
}
1046
-static void dftclDelete(DiffBuilder *p, const DLine *pLine){
1070
+static void dftclDelete(DiffBuilder *p, DLine *pLine){
10471071
blob_append(p->pOut, "DEL ", -1);
10481072
blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
10491073
blob_append_char(p->pOut, '\n');
10501074
}
1051
-static void dftclReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1075
+static void dftclReplace(DiffBuilder *p, DLine *pX, DLine *pY){
10521076
blob_append(p->pOut, "EDIT \"\" ", -1);
10531077
blob_append_tcl_literal(p->pOut, pX->z, pX->n);
10541078
blob_append_char(p->pOut, ' ');
10551079
blob_append_tcl_literal(p->pOut, pY->z, pY->n);
10561080
blob_append_char(p->pOut, '\n');
10571081
}
1058
-static void dftclEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1082
+static void dftclEdit(DiffBuilder *p, DLine *pX, DLine *pY){
10591083
int i, x;
10601084
LineChange chng;
10611085
blob_append(p->pOut, "EDIT", 4);
10621086
oneLineChange(pX, pY, &chng);
10631087
for(i=x=0; i<chng.n; i++){
@@ -1115,33 +1139,33 @@
11151139
** not apply.
11161140
*/
11171141
static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){
11181142
blob_appendf(p->pOut, "1,%u,\n", n);
11191143
}
1120
-static void dfjsonCommon(DiffBuilder *p, const DLine *pLine){
1144
+static void dfjsonCommon(DiffBuilder *p, DLine *pLine){
11211145
blob_append(p->pOut, "2,",2);
11221146
blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
11231147
blob_append(p->pOut, ",\n",2);
11241148
}
1125
-static void dfjsonInsert(DiffBuilder *p, const DLine *pLine){
1149
+static void dfjsonInsert(DiffBuilder *p, DLine *pLine){
11261150
blob_append(p->pOut, "3,",2);
11271151
blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
11281152
blob_append(p->pOut, ",\n",2);
11291153
}
1130
-static void dfjsonDelete(DiffBuilder *p, const DLine *pLine){
1154
+static void dfjsonDelete(DiffBuilder *p, DLine *pLine){
11311155
blob_append(p->pOut, "4,",2);
11321156
blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
11331157
blob_append(p->pOut, ",\n",2);
11341158
}
1135
-static void dfjsonReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1159
+static void dfjsonReplace(DiffBuilder *p, DLine *pX, DLine *pY){
11361160
blob_append(p->pOut, "5,[\"\",",-1);
11371161
blob_append_json_literal(p->pOut, pX->z, (int)pX->n);
11381162
blob_append(p->pOut, ",",1);
11391163
blob_append_json_literal(p->pOut, pY->z, (int)pY->n);
11401164
blob_append(p->pOut, ",\"\"],\n",-1);
11411165
}
1142
-static void dfjsonEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1166
+static void dfjsonEdit(DiffBuilder *p, DLine *pX, DLine *pY){
11431167
int i, x;
11441168
LineChange chng;
11451169
blob_append(p->pOut, "5,[", 3);
11461170
oneLineChange(pX, pY, &chng);
11471171
for(i=x=0; i<chng.n; i++){
@@ -1270,11 +1294,11 @@
12701294
blob_append(p->pOut, "<td class=\"diffln difflne\">"
12711295
"&#xfe19;</td><td></td><td></td></tr>\n", -1);
12721296
p->lnLeft += n;
12731297
p->lnRight += n;
12741298
}
1275
-static void dfunifiedCommon(DiffBuilder *p, const DLine *pLine){
1299
+static void dfunifiedCommon(DiffBuilder *p, DLine *pLine){
12761300
dfunifiedStartRow(p);
12771301
dfunifiedFinishDelete(p);
12781302
dfunifiedFinishInsert(p);
12791303
p->lnLeft++;
12801304
p->lnRight++;
@@ -1282,20 +1306,20 @@
12821306
blob_appendf(&p->aCol[0],"%d\n",p->lnRight);
12831307
blob_append_char(&p->aCol[1], '\n');
12841308
htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
12851309
blob_append_char(&p->aCol[2], '\n');
12861310
}
1287
-static void dfunifiedInsert(DiffBuilder *p, const DLine *pLine){
1311
+static void dfunifiedInsert(DiffBuilder *p, DLine *pLine){
12881312
dfunifiedStartRow(p);
12891313
p->lnRight++;
12901314
blob_appendf(&p->aCol[3],"%d\n", p->lnRight);
12911315
blob_append(&p->aCol[4], "<ins>", 5);
12921316
htmlize_to_blob(&p->aCol[4], pLine->z, (int)pLine->n);
12931317
blob_append(&p->aCol[4], "</ins>\n", 7);
12941318
p->nPending++;
12951319
}
1296
-static void dfunifiedDelete(DiffBuilder *p, const DLine *pLine){
1320
+static void dfunifiedDelete(DiffBuilder *p, DLine *pLine){
12971321
dfunifiedStartRow(p);
12981322
dfunifiedFinishInsert(p);
12991323
if( p->eState==0 ){
13001324
dfunifiedFinishInsert(p);
13011325
blob_append(p->pOut, "<del>", 5);
@@ -1308,11 +1332,11 @@
13081332
blob_append(&p->aCol[1],"-\n",2);
13091333
blob_append(&p->aCol[2], "<del>", 5);
13101334
htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
13111335
blob_append(&p->aCol[2], "</del>\n", 7);
13121336
}
1313
-static void dfunifiedReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1337
+static void dfunifiedReplace(DiffBuilder *p, DLine *pX, DLine *pY){
13141338
dfunifiedStartRow(p);
13151339
if( p->eState==0 ){
13161340
dfunifiedFinishInsert(p);
13171341
blob_append(p->pOut, "<del>", 5);
13181342
blob_append(&p->aCol[2], "<del>", 5);
@@ -1331,11 +1355,11 @@
13311355
13321356
htmlize_to_blob(&p->aCol[4], pY->z, pY->n);
13331357
blob_append_char(&p->aCol[4], '\n');
13341358
p->nPending++;
13351359
}
1336
-static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1360
+static void dfunifiedEdit(DiffBuilder *p, DLine *pX, DLine *pY){
13371361
int i;
13381362
int x;
13391363
LineChange chng;
13401364
oneLineChange(pX, pY, &chng);
13411365
dfunifiedStartRow(p);
@@ -1500,11 +1524,11 @@
15001524
"<td class=\"diffln difflnr difflne\">&#xfe19;</td>"
15011525
"<td/td></tr>\n", -1);
15021526
p->lnLeft += n;
15031527
p->lnRight += n;
15041528
}
1505
-static void dfsplitCommon(DiffBuilder *p, const DLine *pLine){
1529
+static void dfsplitCommon(DiffBuilder *p, DLine *pLine){
15061530
dfsplitStartRow(p);
15071531
dfsplitChangeState(p, 0);
15081532
p->lnLeft++;
15091533
p->lnRight++;
15101534
blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1513,11 +1537,11 @@
15131537
blob_append_char(&p->aCol[1], '\n');
15141538
blob_appendf(&p->aCol[2],"%d\n",p->lnRight);
15151539
htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
15161540
blob_append_char(&p->aCol[3], '\n');
15171541
}
1518
-static void dfsplitInsert(DiffBuilder *p, const DLine *pLine){
1542
+static void dfsplitInsert(DiffBuilder *p, DLine *pLine){
15191543
dfsplitStartRow(p);
15201544
dfsplitChangeState(p, 2);
15211545
p->lnRight++;
15221546
blob_append_char(p->pOut, '\n');
15231547
blob_append_char(&p->aCol[0], '\n');
@@ -1525,11 +1549,11 @@
15251549
blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
15261550
blob_append(&p->aCol[3], "<ins>", 5);
15271551
htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
15281552
blob_append(&p->aCol[3], "</ins>\n", 7);
15291553
}
1530
-static void dfsplitDelete(DiffBuilder *p, const DLine *pLine){
1554
+static void dfsplitDelete(DiffBuilder *p, DLine *pLine){
15311555
dfsplitStartRow(p);
15321556
dfsplitChangeState(p, 1);
15331557
p->lnLeft++;
15341558
blob_appendf(p->pOut,"%d\n", p->lnLeft);
15351559
blob_append(&p->aCol[0], "<del>", 5);
@@ -1537,11 +1561,11 @@
15371561
blob_append(&p->aCol[0], "</del>\n", 7);
15381562
blob_append(&p->aCol[1], "&lt;\n", -1);
15391563
blob_append_char(&p->aCol[2],'\n');
15401564
blob_append_char(&p->aCol[3],'\n');
15411565
}
1542
-static void dfsplitReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1566
+static void dfsplitReplace(DiffBuilder *p, DLine *pX, DLine *pY){
15431567
dfsplitStartRow(p);
15441568
dfsplitChangeState(p, 3);
15451569
p->lnLeft++;
15461570
p->lnRight++;
15471571
blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1553,11 +1577,11 @@
15531577
blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
15541578
15551579
htmlize_to_blob(&p->aCol[3], pY->z, pY->n);
15561580
blob_append_char(&p->aCol[3], '\n');
15571581
}
1558
-static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1582
+static void dfsplitEdit(DiffBuilder *p, DLine *pX, DLine *pY){
15591583
int i;
15601584
int x;
15611585
LineChange chng;
15621586
oneLineChange(pX, pY, &chng);
15631587
dfsplitStartRow(p);
@@ -1655,11 +1679,11 @@
16551679
** from pX onto the into of p.
16561680
**
16571681
** This comment contains multibyte unicode characters (ü, Æ, ð) in order
16581682
** to test the ability of the diff code to handle such characters.
16591683
*/
1660
-static void sbs_append_chars(Blob *p, int iMin, int iMax, const DLine *pX){
1684
+static void sbs_append_chars(Blob *p, int iMin, int iMax, DLine *pX){
16611685
int i;
16621686
const char *z = pX->z;
16631687
for(i=0; i<iMax && i<pX->n; i++){
16641688
char c = z[i];
16651689
blob_append_char(p, c);
@@ -1669,33 +1693,33 @@
16691693
blob_append_char(p, ' ');
16701694
i++;
16711695
}
16721696
}
16731697
1674
-static void dfsbsCommon(DiffBuilder *p, const DLine *pLine){
1698
+static void dfsbsCommon(DiffBuilder *p, DLine *pLine){
16751699
p->lnLeft++;
16761700
p->lnRight++;
16771701
blob_appendf(p->pOut,"%6u ", p->lnLeft);
16781702
sbs_append_chars(p->pOut, p->width, p->width, pLine);
16791703
blob_appendf(p->pOut," %6u ", p->lnRight);
16801704
sbs_append_chars(p->pOut, 0, p->width, pLine);
16811705
blob_append_char(p->pOut, '\n');
16821706
}
1683
-static void dfsbsInsert(DiffBuilder *p, const DLine *pLine){
1707
+static void dfsbsInsert(DiffBuilder *p, DLine *pLine){
16841708
p->lnRight++;
16851709
blob_appendf(p->pOut,"%6s %*s > %6u ",
16861710
"", p->width, "", p->lnRight);
16871711
sbs_append_chars(p->pOut, 0, p->width, pLine);
16881712
blob_append_char(p->pOut, '\n');
16891713
}
1690
-static void dfsbsDelete(DiffBuilder *p, const DLine *pLine){
1714
+static void dfsbsDelete(DiffBuilder *p, DLine *pLine){
16911715
p->lnLeft++;
16921716
blob_appendf(p->pOut,"%6u ", p->lnLeft);
16931717
sbs_append_chars(p->pOut, p->width, p->width, pLine);
16941718
blob_append(p->pOut," <\n", 3);
16951719
}
1696
-static void dfsbsEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1720
+static void dfsbsEdit(DiffBuilder *p, DLine *pX, DLine *pY){
16971721
p->lnLeft++;
16981722
p->lnRight++;
16991723
blob_appendf(p->pOut,"%6u ", p->lnLeft);
17001724
sbs_append_chars(p->pOut, p->width, p->width, pX);
17011725
blob_appendf(p->pOut, " | %6u ", p->lnRight);
@@ -1732,11 +1756,11 @@
17321756
** (3) If the two strings have a common prefix, measure that prefix
17331757
** (4) Find the length of the longest common subsequence that is
17341758
** at least 150% longer than the common prefix.
17351759
** (5) Longer common subsequences yield lower scores.
17361760
*/
1737
-static int match_dline(const DLine *pA, const DLine *pB){
1761
+static int match_dline(DLine *pA, DLine *pB){
17381762
const char *zA; /* Left string */
17391763
const char *zB; /* right string */
17401764
int nA; /* Bytes in zA[] */
17411765
int nB; /* Bytes in zB[] */
17421766
int nMin;
@@ -1747,16 +1771,30 @@
17471771
int score; /* Final score. 0..100 */
17481772
unsigned char c; /* Character being examined */
17491773
unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
17501774
unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
17511775
1752
- zA = pA->z + pA->indent;
1753
- zB = pB->z + pB->indent;
1754
- nA = pA->n - pA->indent;
1755
- nB = pB->n - pB->indent;
1756
- while( nA>0 && (unsigned char)zA[nA-1]<=' ' ){ nA--; }
1757
- while( nB>0 && (unsigned char)zB[nB-1]<=' ' ){ nB--; }
1776
+ zA = pA->z;
1777
+ if( pA->nw==0 && pA->n ){
1778
+ for(i=0; i<pA->n && diff_isspace(zA[i]); i++){}
1779
+ pA->indent = i;
1780
+ for(j=pA->n-1; j>i && diff_isspace(zA[j]); j--){}
1781
+ pA->nw = j - i + 1;
1782
+ }
1783
+ zA += pA->indent;
1784
+ nA = pA->nw;
1785
+
1786
+ zB = pB->z;
1787
+ if( pB->nw==0 && pB->n ){
1788
+ for(i=0; i<pB->n && diff_isspace(zB[i]); i++){}
1789
+ pB->indent = i;
1790
+ for(j=pB->n-1; j>i && diff_isspace(zB[j]); j--){}
1791
+ pB->nw = j - i + 1;
1792
+ }
1793
+ zB += pB->indent;
1794
+ nB = pB->nw;
1795
+
17581796
if( nA>250 ) nA = 250;
17591797
if( nB>250 ) nB = 250;
17601798
avg = (nA+nB)/2;
17611799
if( avg==0 ) return 0;
17621800
nMin = nA;
@@ -1847,12 +1885,12 @@
18471885
** each other. Insertion and deletion costs are 50. Match costs
18481886
** are between 0 and 100 where 0 is a perfect match 100 is a complete
18491887
** mismatch.
18501888
*/
18511889
static unsigned char *diffBlockAlignment(
1852
- const DLine *aLeft, int nLeft, /* Text on the left */
1853
- const DLine *aRight, int nRight, /* Text on the right */
1890
+ DLine *aLeft, int nLeft, /* Text on the left */
1891
+ DLine *aRight, int nRight, /* Text on the right */
18541892
DiffConfig *pCfg, /* Configuration options */
18551893
int *pNResult /* OUTPUT: Bytes of result */
18561894
){
18571895
int i, j, k; /* Loop counters */
18581896
int *a; /* One row of the Wagner matrix */
@@ -1878,12 +1916,12 @@
18781916
** O(NlogN). The result is not as precise, but this whole thing is an
18791917
** approximation anyhow, and the faster response time is an acceptable
18801918
** trade-off for reduced precision.
18811919
*/
18821920
if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
1883
- const DLine *aSmall; /* The smaller of aLeft and aRight */
1884
- const DLine *aBig; /* The larger of aLeft and aRight */
1921
+ DLine *aSmall; /* The smaller of aLeft and aRight */
1922
+ DLine *aBig; /* The larger of aLeft and aRight */
18851923
int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
18861924
int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
18871925
int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
18881926
unsigned char *a1, *a2; /* Results of the alignments on two halves */
18891927
int n1, n2; /* Number of entries in a1 and a2 */
@@ -2023,12 +2061,12 @@
20232061
static void formatDiff(
20242062
DContext *p, /* The computed diff */
20252063
DiffConfig *pCfg, /* Configuration options */
20262064
DiffBuilder *pBuilder /* The formatter object */
20272065
){
2028
- const DLine *A; /* Left side of the diff */
2029
- const DLine *B; /* Right side of the diff */
2066
+ DLine *A; /* Left side of the diff */
2067
+ DLine *B; /* Right side of the diff */
20302068
unsigned int a = 0; /* Index of next line in A[] */
20312069
unsigned int b = 0; /* Index of next line in B[] */
20322070
const int *R; /* Array of COPY/DELETE/INSERT triples */
20332071
unsigned int r; /* Index into R[] */
20342072
unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */
20352073
--- src/diff.c
+++ src/diff.c
@@ -121,12 +121,13 @@
121 */
122 typedef struct DLine DLine;
123 struct DLine {
124 const char *z; /* The text of the line */
125 u64 h; /* Hash of the line */
126 unsigned short indent; /* Index of first non-space, non-control char */
127 unsigned short n; /* number of bytes */
 
128 unsigned int iNext; /* 1+(Index of next line with same the same hash) */
129
130 /* an array of DLine elements serves two purposes. The fields
131 ** above are one per line of input text. But each entry is also
132 ** a bucket in a hash table, as follows: */
@@ -163,12 +164,34 @@
163 int nEditAlloc; /* Space allocated for aEdit[] */
164 DLine *aFrom; /* File on left side of the diff */
165 int nFrom; /* Number of lines in aFrom[] */
166 DLine *aTo; /* File on right side of the diff */
167 int nTo; /* Number of lines in aTo[] */
168 int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169 };
 
170
171 /*
172 ** Count the number of lines in the input string. Include the last line
173 ** in the count even if it lacks the \n terminator. If an empty string
174 ** is specified, the number of lines is zero. For the purposes of this
@@ -246,29 +269,30 @@
246 if( diffFlags & DIFF_STRIP_EOLCR ){
247 if( k>0 && z[k-1]=='\r' ){ k--; }
248 }
249 a[i].n = k;
250 if( diffFlags & DIFF_IGNORE_EOLWS ){
251 while( k>0 && fossil_isspace(z[k-1]) ){ k--; }
252 }
253 for(s=0; s<k && z[s]<=' '; s++){}
254 a[i].indent = s;
255 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
256 int numws = 0;
 
 
257 for(h=0, x=s; x<k; x++){
258 char c = z[x];
259 if( fossil_isspace(c) ){
260 ++numws;
261 }else{
262 h = (h^c)*9000000000000000041LL;
263 }
264 }
265 k -= numws;
 
266 }else{
267 int k2 = k & ~0x7;
268 u64 m;
269 for(h=x=0; x<k2; x += 8){
270 memcpy(&m, z+x, 8);
271 h = (h^m)*9000000000000000041LL;
272 }
273 m = 0;
274 memcpy(&m, z+x, k-k2);
@@ -289,11 +313,11 @@
289 }
290
291 /*
292 ** Return zero if two DLine elements are identical.
293 */
294 static int compare_dline(const DLine *pA, const DLine *pB){
295 if( pA->h!=pB->h ) return 1;
296 return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
297 }
298
299 /*
@@ -300,17 +324,17 @@
300 ** Return zero if two DLine elements are identical, ignoring
301 ** all whitespace. The indent field of pA/pB already points
302 ** to the first non-space character in the string.
303 */
304
305 static int compare_dline_ignore_allws(const DLine *pA, const DLine *pB){
306 int a = pA->indent, b = pB->indent;
307 if( pA->h==pB->h ){
308 while( a<pA->n || b<pB->n ){
309 if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
310 while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
311 while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
312 }
313 return pA->n-a != pB->n-b;
314 }
315 return 1;
316 }
@@ -319,11 +343,11 @@
319 ** Return true if the regular expression *pRe matches any of the
320 ** N dlines
321 */
322 static int re_dline_match(
323 ReCompiled *pRe, /* The regular expression to be matched */
324 const DLine *aDLine, /* First of N DLines to compare against */
325 int N /* Number of DLines to check */
326 ){
327 while( N-- ){
328 if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
329 return 1;
@@ -618,11 +642,11 @@
618 /*
619 ** Return true if the string starts with n spaces
620 */
621 static int allSpaces(const char *z, int n){
622 int i;
623 for(i=0; i<n && fossil_isspace(z[i]); i++){}
624 return i==n;
625 }
626
627 /*
628 ** Try to improve the human-readability of the LineChange p.
@@ -689,12 +713,12 @@
689 **
690 ** The result is written into the LineChange object given by the
691 ** third parameter.
692 */
693 static void oneLineChange(
694 const DLine *pLeft, /* Left line of the change */
695 const DLine *pRight, /* Right line of the change */
696 LineChange *p /* OUTPUT: Write the results here */
697 ){
698 int nLeft; /* Length of left line in bytes */
699 int nRight; /* Length of right line in bytes */
700 int nShort; /* Shortest of left and right */
@@ -744,17 +768,17 @@
744 int nLong = nLeft<nRight ? nRight : nLeft;
745 int nGap = nLong - nShort;
746 for(i=nShort-nSuffix; i<=nPrefix; i++){
747 int iVal = 0;
748 char c = zLeft[i];
749 if( fossil_isspace(c) ){
750 iVal += 5;
751 }else if( !fossil_isalnum(c) ){
752 iVal += 2;
753 }
754 c = zLeft[i+nGap-1];
755 if( fossil_isspace(c) ){
756 iVal += 5;
757 }else if( !fossil_isalnum(c) ){
758 iVal += 2;
759 }
760 if( iVal>iBestVal ){
@@ -885,15 +909,15 @@
885 ** in appropriate method implementations.
886 */
887 typedef struct DiffBuilder DiffBuilder;
888 struct DiffBuilder {
889 void (*xSkip)(DiffBuilder*, unsigned int, int);
890 void (*xCommon)(DiffBuilder*,const DLine*);
891 void (*xInsert)(DiffBuilder*,const DLine*);
892 void (*xDelete)(DiffBuilder*,const DLine*);
893 void (*xReplace)(DiffBuilder*,const DLine*, const DLine*);
894 void (*xEdit)(DiffBuilder*,const DLine*,const DLine*);
895 void (*xEnd)(DiffBuilder*);
896 unsigned int lnLeft; /* Lines seen on the left (delete) side */
897 unsigned int lnRight; /* Lines seen on the right (insert) side */
898 unsigned int nPending; /* Number of pending lines */
899 int eState; /* State of the output */
@@ -915,35 +939,35 @@
915 n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n,
916 isFinal ? " FINAL" : "");
917 p->lnLeft += n;
918 p->lnRight += n;
919 }
920 static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){
921 p->lnLeft++;
922 p->lnRight++;
923 blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n",
924 p->lnLeft, p->lnRight, (int)pLine->n, pLine->z);
925 }
926 static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){
927 p->lnRight++;
928 blob_appendf(p->pOut, "INSERT %8d %.*s\n",
929 p->lnRight, (int)pLine->n, pLine->z);
930 }
931 static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){
932 p->lnLeft++;
933 blob_appendf(p->pOut, "DELETE %8u %.*s\n",
934 p->lnLeft, (int)pLine->n, pLine->z);
935 }
936 static void dfdebugReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
937 p->lnLeft++;
938 p->lnRight++;
939 blob_appendf(p->pOut, "REPLACE %8u %.*s\n",
940 p->lnLeft, (int)pX->n, pX->z);
941 blob_appendf(p->pOut, " %8u %.*s\n",
942 p->lnRight, (int)pY->n, pY->z);
943 }
944 static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
945 int i, j;
946 int x;
947 LineChange chng;
948 p->lnLeft++;
949 p->lnRight++;
@@ -1031,33 +1055,33 @@
1031 ** additional string which is a common suffix.
1032 */
1033 static void dftclSkip(DiffBuilder *p, unsigned int n, int isFinal){
1034 blob_appendf(p->pOut, "SKIP %u\n", n);
1035 }
1036 static void dftclCommon(DiffBuilder *p, const DLine *pLine){
1037 blob_appendf(p->pOut, "COM ");
1038 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1039 blob_append_char(p->pOut, '\n');
1040 }
1041 static void dftclInsert(DiffBuilder *p, const DLine *pLine){
1042 blob_append(p->pOut, "INS ", -1);
1043 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1044 blob_append_char(p->pOut, '\n');
1045 }
1046 static void dftclDelete(DiffBuilder *p, const DLine *pLine){
1047 blob_append(p->pOut, "DEL ", -1);
1048 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1049 blob_append_char(p->pOut, '\n');
1050 }
1051 static void dftclReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1052 blob_append(p->pOut, "EDIT \"\" ", -1);
1053 blob_append_tcl_literal(p->pOut, pX->z, pX->n);
1054 blob_append_char(p->pOut, ' ');
1055 blob_append_tcl_literal(p->pOut, pY->z, pY->n);
1056 blob_append_char(p->pOut, '\n');
1057 }
1058 static void dftclEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1059 int i, x;
1060 LineChange chng;
1061 blob_append(p->pOut, "EDIT", 4);
1062 oneLineChange(pX, pY, &chng);
1063 for(i=x=0; i<chng.n; i++){
@@ -1115,33 +1139,33 @@
1115 ** not apply.
1116 */
1117 static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){
1118 blob_appendf(p->pOut, "1,%u,\n", n);
1119 }
1120 static void dfjsonCommon(DiffBuilder *p, const DLine *pLine){
1121 blob_append(p->pOut, "2,",2);
1122 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1123 blob_append(p->pOut, ",\n",2);
1124 }
1125 static void dfjsonInsert(DiffBuilder *p, const DLine *pLine){
1126 blob_append(p->pOut, "3,",2);
1127 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1128 blob_append(p->pOut, ",\n",2);
1129 }
1130 static void dfjsonDelete(DiffBuilder *p, const DLine *pLine){
1131 blob_append(p->pOut, "4,",2);
1132 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1133 blob_append(p->pOut, ",\n",2);
1134 }
1135 static void dfjsonReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1136 blob_append(p->pOut, "5,[\"\",",-1);
1137 blob_append_json_literal(p->pOut, pX->z, (int)pX->n);
1138 blob_append(p->pOut, ",",1);
1139 blob_append_json_literal(p->pOut, pY->z, (int)pY->n);
1140 blob_append(p->pOut, ",\"\"],\n",-1);
1141 }
1142 static void dfjsonEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1143 int i, x;
1144 LineChange chng;
1145 blob_append(p->pOut, "5,[", 3);
1146 oneLineChange(pX, pY, &chng);
1147 for(i=x=0; i<chng.n; i++){
@@ -1270,11 +1294,11 @@
1270 blob_append(p->pOut, "<td class=\"diffln difflne\">"
1271 "&#xfe19;</td><td></td><td></td></tr>\n", -1);
1272 p->lnLeft += n;
1273 p->lnRight += n;
1274 }
1275 static void dfunifiedCommon(DiffBuilder *p, const DLine *pLine){
1276 dfunifiedStartRow(p);
1277 dfunifiedFinishDelete(p);
1278 dfunifiedFinishInsert(p);
1279 p->lnLeft++;
1280 p->lnRight++;
@@ -1282,20 +1306,20 @@
1282 blob_appendf(&p->aCol[0],"%d\n",p->lnRight);
1283 blob_append_char(&p->aCol[1], '\n');
1284 htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
1285 blob_append_char(&p->aCol[2], '\n');
1286 }
1287 static void dfunifiedInsert(DiffBuilder *p, const DLine *pLine){
1288 dfunifiedStartRow(p);
1289 p->lnRight++;
1290 blob_appendf(&p->aCol[3],"%d\n", p->lnRight);
1291 blob_append(&p->aCol[4], "<ins>", 5);
1292 htmlize_to_blob(&p->aCol[4], pLine->z, (int)pLine->n);
1293 blob_append(&p->aCol[4], "</ins>\n", 7);
1294 p->nPending++;
1295 }
1296 static void dfunifiedDelete(DiffBuilder *p, const DLine *pLine){
1297 dfunifiedStartRow(p);
1298 dfunifiedFinishInsert(p);
1299 if( p->eState==0 ){
1300 dfunifiedFinishInsert(p);
1301 blob_append(p->pOut, "<del>", 5);
@@ -1308,11 +1332,11 @@
1308 blob_append(&p->aCol[1],"-\n",2);
1309 blob_append(&p->aCol[2], "<del>", 5);
1310 htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
1311 blob_append(&p->aCol[2], "</del>\n", 7);
1312 }
1313 static void dfunifiedReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1314 dfunifiedStartRow(p);
1315 if( p->eState==0 ){
1316 dfunifiedFinishInsert(p);
1317 blob_append(p->pOut, "<del>", 5);
1318 blob_append(&p->aCol[2], "<del>", 5);
@@ -1331,11 +1355,11 @@
1331
1332 htmlize_to_blob(&p->aCol[4], pY->z, pY->n);
1333 blob_append_char(&p->aCol[4], '\n');
1334 p->nPending++;
1335 }
1336 static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1337 int i;
1338 int x;
1339 LineChange chng;
1340 oneLineChange(pX, pY, &chng);
1341 dfunifiedStartRow(p);
@@ -1500,11 +1524,11 @@
1500 "<td class=\"diffln difflnr difflne\">&#xfe19;</td>"
1501 "<td/td></tr>\n", -1);
1502 p->lnLeft += n;
1503 p->lnRight += n;
1504 }
1505 static void dfsplitCommon(DiffBuilder *p, const DLine *pLine){
1506 dfsplitStartRow(p);
1507 dfsplitChangeState(p, 0);
1508 p->lnLeft++;
1509 p->lnRight++;
1510 blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1513,11 +1537,11 @@
1513 blob_append_char(&p->aCol[1], '\n');
1514 blob_appendf(&p->aCol[2],"%d\n",p->lnRight);
1515 htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
1516 blob_append_char(&p->aCol[3], '\n');
1517 }
1518 static void dfsplitInsert(DiffBuilder *p, const DLine *pLine){
1519 dfsplitStartRow(p);
1520 dfsplitChangeState(p, 2);
1521 p->lnRight++;
1522 blob_append_char(p->pOut, '\n');
1523 blob_append_char(&p->aCol[0], '\n');
@@ -1525,11 +1549,11 @@
1525 blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
1526 blob_append(&p->aCol[3], "<ins>", 5);
1527 htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
1528 blob_append(&p->aCol[3], "</ins>\n", 7);
1529 }
1530 static void dfsplitDelete(DiffBuilder *p, const DLine *pLine){
1531 dfsplitStartRow(p);
1532 dfsplitChangeState(p, 1);
1533 p->lnLeft++;
1534 blob_appendf(p->pOut,"%d\n", p->lnLeft);
1535 blob_append(&p->aCol[0], "<del>", 5);
@@ -1537,11 +1561,11 @@
1537 blob_append(&p->aCol[0], "</del>\n", 7);
1538 blob_append(&p->aCol[1], "&lt;\n", -1);
1539 blob_append_char(&p->aCol[2],'\n');
1540 blob_append_char(&p->aCol[3],'\n');
1541 }
1542 static void dfsplitReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
1543 dfsplitStartRow(p);
1544 dfsplitChangeState(p, 3);
1545 p->lnLeft++;
1546 p->lnRight++;
1547 blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1553,11 +1577,11 @@
1553 blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
1554
1555 htmlize_to_blob(&p->aCol[3], pY->z, pY->n);
1556 blob_append_char(&p->aCol[3], '\n');
1557 }
1558 static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1559 int i;
1560 int x;
1561 LineChange chng;
1562 oneLineChange(pX, pY, &chng);
1563 dfsplitStartRow(p);
@@ -1655,11 +1679,11 @@
1655 ** from pX onto the into of p.
1656 **
1657 ** This comment contains multibyte unicode characters (ü, Æ, ð) in order
1658 ** to test the ability of the diff code to handle such characters.
1659 */
1660 static void sbs_append_chars(Blob *p, int iMin, int iMax, const DLine *pX){
1661 int i;
1662 const char *z = pX->z;
1663 for(i=0; i<iMax && i<pX->n; i++){
1664 char c = z[i];
1665 blob_append_char(p, c);
@@ -1669,33 +1693,33 @@
1669 blob_append_char(p, ' ');
1670 i++;
1671 }
1672 }
1673
1674 static void dfsbsCommon(DiffBuilder *p, const DLine *pLine){
1675 p->lnLeft++;
1676 p->lnRight++;
1677 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1678 sbs_append_chars(p->pOut, p->width, p->width, pLine);
1679 blob_appendf(p->pOut," %6u ", p->lnRight);
1680 sbs_append_chars(p->pOut, 0, p->width, pLine);
1681 blob_append_char(p->pOut, '\n');
1682 }
1683 static void dfsbsInsert(DiffBuilder *p, const DLine *pLine){
1684 p->lnRight++;
1685 blob_appendf(p->pOut,"%6s %*s > %6u ",
1686 "", p->width, "", p->lnRight);
1687 sbs_append_chars(p->pOut, 0, p->width, pLine);
1688 blob_append_char(p->pOut, '\n');
1689 }
1690 static void dfsbsDelete(DiffBuilder *p, const DLine *pLine){
1691 p->lnLeft++;
1692 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1693 sbs_append_chars(p->pOut, p->width, p->width, pLine);
1694 blob_append(p->pOut," <\n", 3);
1695 }
1696 static void dfsbsEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
1697 p->lnLeft++;
1698 p->lnRight++;
1699 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1700 sbs_append_chars(p->pOut, p->width, p->width, pX);
1701 blob_appendf(p->pOut, " | %6u ", p->lnRight);
@@ -1732,11 +1756,11 @@
1732 ** (3) If the two strings have a common prefix, measure that prefix
1733 ** (4) Find the length of the longest common subsequence that is
1734 ** at least 150% longer than the common prefix.
1735 ** (5) Longer common subsequences yield lower scores.
1736 */
1737 static int match_dline(const DLine *pA, const DLine *pB){
1738 const char *zA; /* Left string */
1739 const char *zB; /* right string */
1740 int nA; /* Bytes in zA[] */
1741 int nB; /* Bytes in zB[] */
1742 int nMin;
@@ -1747,16 +1771,30 @@
1747 int score; /* Final score. 0..100 */
1748 unsigned char c; /* Character being examined */
1749 unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
1750 unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
1751
1752 zA = pA->z + pA->indent;
1753 zB = pB->z + pB->indent;
1754 nA = pA->n - pA->indent;
1755 nB = pB->n - pB->indent;
1756 while( nA>0 && (unsigned char)zA[nA-1]<=' ' ){ nA--; }
1757 while( nB>0 && (unsigned char)zB[nB-1]<=' ' ){ nB--; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1758 if( nA>250 ) nA = 250;
1759 if( nB>250 ) nB = 250;
1760 avg = (nA+nB)/2;
1761 if( avg==0 ) return 0;
1762 nMin = nA;
@@ -1847,12 +1885,12 @@
1847 ** each other. Insertion and deletion costs are 50. Match costs
1848 ** are between 0 and 100 where 0 is a perfect match 100 is a complete
1849 ** mismatch.
1850 */
1851 static unsigned char *diffBlockAlignment(
1852 const DLine *aLeft, int nLeft, /* Text on the left */
1853 const DLine *aRight, int nRight, /* Text on the right */
1854 DiffConfig *pCfg, /* Configuration options */
1855 int *pNResult /* OUTPUT: Bytes of result */
1856 ){
1857 int i, j, k; /* Loop counters */
1858 int *a; /* One row of the Wagner matrix */
@@ -1878,12 +1916,12 @@
1878 ** O(NlogN). The result is not as precise, but this whole thing is an
1879 ** approximation anyhow, and the faster response time is an acceptable
1880 ** trade-off for reduced precision.
1881 */
1882 if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
1883 const DLine *aSmall; /* The smaller of aLeft and aRight */
1884 const DLine *aBig; /* The larger of aLeft and aRight */
1885 int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
1886 int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
1887 int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
1888 unsigned char *a1, *a2; /* Results of the alignments on two halves */
1889 int n1, n2; /* Number of entries in a1 and a2 */
@@ -2023,12 +2061,12 @@
2023 static void formatDiff(
2024 DContext *p, /* The computed diff */
2025 DiffConfig *pCfg, /* Configuration options */
2026 DiffBuilder *pBuilder /* The formatter object */
2027 ){
2028 const DLine *A; /* Left side of the diff */
2029 const DLine *B; /* Right side of the diff */
2030 unsigned int a = 0; /* Index of next line in A[] */
2031 unsigned int b = 0; /* Index of next line in B[] */
2032 const int *R; /* Array of COPY/DELETE/INSERT triples */
2033 unsigned int r; /* Index into R[] */
2034 unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */
2035
--- src/diff.c
+++ src/diff.c
@@ -121,12 +121,13 @@
121 */
122 typedef struct DLine DLine;
123 struct DLine {
124 const char *z; /* The text of the line */
125 u64 h; /* Hash of the line */
126 unsigned short indent; /* Index of first non-space */
127 unsigned short n; /* number of bytes */
128 unsigned short nw; /* number of bytes without leading/trailing space */
129 unsigned int iNext; /* 1+(Index of next line with same the same hash) */
130
131 /* an array of DLine elements serves two purposes. The fields
132 ** above are one per line of input text. But each entry is also
133 ** a bucket in a hash table, as follows: */
@@ -163,12 +164,34 @@
164 int nEditAlloc; /* Space allocated for aEdit[] */
165 DLine *aFrom; /* File on left side of the diff */
166 int nFrom; /* Number of lines in aFrom[] */
167 DLine *aTo; /* File on right side of the diff */
168 int nTo; /* Number of lines in aTo[] */
169 int (*xDiffer)(DLine*,DLine*); /* comparison function */
170 };
171
172 /* Fast isspace for use by diff */
173 static const char diffIsSpace[] = {
174 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
175 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
188 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 };
192 #define diff_isspace(X) (diffIsSpace[(unsigned char)(X)])
193
194 /*
195 ** Count the number of lines in the input string. Include the last line
196 ** in the count even if it lacks the \n terminator. If an empty string
197 ** is specified, the number of lines is zero. For the purposes of this
@@ -246,29 +269,30 @@
269 if( diffFlags & DIFF_STRIP_EOLCR ){
270 if( k>0 && z[k-1]=='\r' ){ k--; }
271 }
272 a[i].n = k;
273 if( diffFlags & DIFF_IGNORE_EOLWS ){
274 while( k>0 && diff_isspace(z[k-1]) ){ k--; }
275 }
 
 
276 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
277 int numws = 0;
278 for(s=0; s<k && z[s]<=' '; s++){}
279 a[i].indent = s;
280 for(h=0, x=s; x<k; x++){
281 char c = z[x];
282 if( diff_isspace(c) ){
283 ++numws;
284 }else{
285 h = (h^c)*9000000000000000041LL;
286 }
287 }
288 k -= numws;
289 a[i].nw = k - s;
290 }else{
291 int k2 = k & ~0x7;
292 u64 m;
293 for(h=x=s=0; x<k2; x += 8){
294 memcpy(&m, z+x, 8);
295 h = (h^m)*9000000000000000041LL;
296 }
297 m = 0;
298 memcpy(&m, z+x, k-k2);
@@ -289,11 +313,11 @@
313 }
314
315 /*
316 ** Return zero if two DLine elements are identical.
317 */
318 static int compare_dline(DLine *pA, DLine *pB){
319 if( pA->h!=pB->h ) return 1;
320 return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
321 }
322
323 /*
@@ -300,17 +324,17 @@
324 ** Return zero if two DLine elements are identical, ignoring
325 ** all whitespace. The indent field of pA/pB already points
326 ** to the first non-space character in the string.
327 */
328
329 static int compare_dline_ignore_allws(DLine *pA, DLine *pB){
330 int a = pA->indent, b = pB->indent;
331 if( pA->h==pB->h ){
332 while( a<pA->n || b<pB->n ){
333 if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
334 while( a<pA->n && diff_isspace(pA->z[a])) ++a;
335 while( b<pB->n && diff_isspace(pB->z[b])) ++b;
336 }
337 return pA->n-a != pB->n-b;
338 }
339 return 1;
340 }
@@ -319,11 +343,11 @@
343 ** Return true if the regular expression *pRe matches any of the
344 ** N dlines
345 */
346 static int re_dline_match(
347 ReCompiled *pRe, /* The regular expression to be matched */
348 DLine *aDLine, /* First of N DLines to compare against */
349 int N /* Number of DLines to check */
350 ){
351 while( N-- ){
352 if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
353 return 1;
@@ -618,11 +642,11 @@
642 /*
643 ** Return true if the string starts with n spaces
644 */
645 static int allSpaces(const char *z, int n){
646 int i;
647 for(i=0; i<n && diff_isspace(z[i]); i++){}
648 return i==n;
649 }
650
651 /*
652 ** Try to improve the human-readability of the LineChange p.
@@ -689,12 +713,12 @@
713 **
714 ** The result is written into the LineChange object given by the
715 ** third parameter.
716 */
717 static void oneLineChange(
718 DLine *pLeft, /* Left line of the change */
719 DLine *pRight, /* Right line of the change */
720 LineChange *p /* OUTPUT: Write the results here */
721 ){
722 int nLeft; /* Length of left line in bytes */
723 int nRight; /* Length of right line in bytes */
724 int nShort; /* Shortest of left and right */
@@ -744,17 +768,17 @@
768 int nLong = nLeft<nRight ? nRight : nLeft;
769 int nGap = nLong - nShort;
770 for(i=nShort-nSuffix; i<=nPrefix; i++){
771 int iVal = 0;
772 char c = zLeft[i];
773 if( diff_isspace(c) ){
774 iVal += 5;
775 }else if( !fossil_isalnum(c) ){
776 iVal += 2;
777 }
778 c = zLeft[i+nGap-1];
779 if( diff_isspace(c) ){
780 iVal += 5;
781 }else if( !fossil_isalnum(c) ){
782 iVal += 2;
783 }
784 if( iVal>iBestVal ){
@@ -885,15 +909,15 @@
909 ** in appropriate method implementations.
910 */
911 typedef struct DiffBuilder DiffBuilder;
912 struct DiffBuilder {
913 void (*xSkip)(DiffBuilder*, unsigned int, int);
914 void (*xCommon)(DiffBuilder*,DLine*);
915 void (*xInsert)(DiffBuilder*,DLine*);
916 void (*xDelete)(DiffBuilder*,DLine*);
917 void (*xReplace)(DiffBuilder*,DLine*, DLine*);
918 void (*xEdit)(DiffBuilder*,DLine*,DLine*);
919 void (*xEnd)(DiffBuilder*);
920 unsigned int lnLeft; /* Lines seen on the left (delete) side */
921 unsigned int lnRight; /* Lines seen on the right (insert) side */
922 unsigned int nPending; /* Number of pending lines */
923 int eState; /* State of the output */
@@ -915,35 +939,35 @@
939 n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n,
940 isFinal ? " FINAL" : "");
941 p->lnLeft += n;
942 p->lnRight += n;
943 }
944 static void dfdebugCommon(DiffBuilder *p, DLine *pLine){
945 p->lnLeft++;
946 p->lnRight++;
947 blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n",
948 p->lnLeft, p->lnRight, (int)pLine->n, pLine->z);
949 }
950 static void dfdebugInsert(DiffBuilder *p, DLine *pLine){
951 p->lnRight++;
952 blob_appendf(p->pOut, "INSERT %8d %.*s\n",
953 p->lnRight, (int)pLine->n, pLine->z);
954 }
955 static void dfdebugDelete(DiffBuilder *p, DLine *pLine){
956 p->lnLeft++;
957 blob_appendf(p->pOut, "DELETE %8u %.*s\n",
958 p->lnLeft, (int)pLine->n, pLine->z);
959 }
960 static void dfdebugReplace(DiffBuilder *p, DLine *pX, DLine *pY){
961 p->lnLeft++;
962 p->lnRight++;
963 blob_appendf(p->pOut, "REPLACE %8u %.*s\n",
964 p->lnLeft, (int)pX->n, pX->z);
965 blob_appendf(p->pOut, " %8u %.*s\n",
966 p->lnRight, (int)pY->n, pY->z);
967 }
968 static void dfdebugEdit(DiffBuilder *p, DLine *pX, DLine *pY){
969 int i, j;
970 int x;
971 LineChange chng;
972 p->lnLeft++;
973 p->lnRight++;
@@ -1031,33 +1055,33 @@
1055 ** additional string which is a common suffix.
1056 */
1057 static void dftclSkip(DiffBuilder *p, unsigned int n, int isFinal){
1058 blob_appendf(p->pOut, "SKIP %u\n", n);
1059 }
1060 static void dftclCommon(DiffBuilder *p, DLine *pLine){
1061 blob_appendf(p->pOut, "COM ");
1062 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1063 blob_append_char(p->pOut, '\n');
1064 }
1065 static void dftclInsert(DiffBuilder *p, DLine *pLine){
1066 blob_append(p->pOut, "INS ", -1);
1067 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1068 blob_append_char(p->pOut, '\n');
1069 }
1070 static void dftclDelete(DiffBuilder *p, DLine *pLine){
1071 blob_append(p->pOut, "DEL ", -1);
1072 blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
1073 blob_append_char(p->pOut, '\n');
1074 }
1075 static void dftclReplace(DiffBuilder *p, DLine *pX, DLine *pY){
1076 blob_append(p->pOut, "EDIT \"\" ", -1);
1077 blob_append_tcl_literal(p->pOut, pX->z, pX->n);
1078 blob_append_char(p->pOut, ' ');
1079 blob_append_tcl_literal(p->pOut, pY->z, pY->n);
1080 blob_append_char(p->pOut, '\n');
1081 }
1082 static void dftclEdit(DiffBuilder *p, DLine *pX, DLine *pY){
1083 int i, x;
1084 LineChange chng;
1085 blob_append(p->pOut, "EDIT", 4);
1086 oneLineChange(pX, pY, &chng);
1087 for(i=x=0; i<chng.n; i++){
@@ -1115,33 +1139,33 @@
1139 ** not apply.
1140 */
1141 static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){
1142 blob_appendf(p->pOut, "1,%u,\n", n);
1143 }
1144 static void dfjsonCommon(DiffBuilder *p, DLine *pLine){
1145 blob_append(p->pOut, "2,",2);
1146 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1147 blob_append(p->pOut, ",\n",2);
1148 }
1149 static void dfjsonInsert(DiffBuilder *p, DLine *pLine){
1150 blob_append(p->pOut, "3,",2);
1151 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1152 blob_append(p->pOut, ",\n",2);
1153 }
1154 static void dfjsonDelete(DiffBuilder *p, DLine *pLine){
1155 blob_append(p->pOut, "4,",2);
1156 blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
1157 blob_append(p->pOut, ",\n",2);
1158 }
1159 static void dfjsonReplace(DiffBuilder *p, DLine *pX, DLine *pY){
1160 blob_append(p->pOut, "5,[\"\",",-1);
1161 blob_append_json_literal(p->pOut, pX->z, (int)pX->n);
1162 blob_append(p->pOut, ",",1);
1163 blob_append_json_literal(p->pOut, pY->z, (int)pY->n);
1164 blob_append(p->pOut, ",\"\"],\n",-1);
1165 }
1166 static void dfjsonEdit(DiffBuilder *p, DLine *pX, DLine *pY){
1167 int i, x;
1168 LineChange chng;
1169 blob_append(p->pOut, "5,[", 3);
1170 oneLineChange(pX, pY, &chng);
1171 for(i=x=0; i<chng.n; i++){
@@ -1270,11 +1294,11 @@
1294 blob_append(p->pOut, "<td class=\"diffln difflne\">"
1295 "&#xfe19;</td><td></td><td></td></tr>\n", -1);
1296 p->lnLeft += n;
1297 p->lnRight += n;
1298 }
1299 static void dfunifiedCommon(DiffBuilder *p, DLine *pLine){
1300 dfunifiedStartRow(p);
1301 dfunifiedFinishDelete(p);
1302 dfunifiedFinishInsert(p);
1303 p->lnLeft++;
1304 p->lnRight++;
@@ -1282,20 +1306,20 @@
1306 blob_appendf(&p->aCol[0],"%d\n",p->lnRight);
1307 blob_append_char(&p->aCol[1], '\n');
1308 htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
1309 blob_append_char(&p->aCol[2], '\n');
1310 }
1311 static void dfunifiedInsert(DiffBuilder *p, DLine *pLine){
1312 dfunifiedStartRow(p);
1313 p->lnRight++;
1314 blob_appendf(&p->aCol[3],"%d\n", p->lnRight);
1315 blob_append(&p->aCol[4], "<ins>", 5);
1316 htmlize_to_blob(&p->aCol[4], pLine->z, (int)pLine->n);
1317 blob_append(&p->aCol[4], "</ins>\n", 7);
1318 p->nPending++;
1319 }
1320 static void dfunifiedDelete(DiffBuilder *p, DLine *pLine){
1321 dfunifiedStartRow(p);
1322 dfunifiedFinishInsert(p);
1323 if( p->eState==0 ){
1324 dfunifiedFinishInsert(p);
1325 blob_append(p->pOut, "<del>", 5);
@@ -1308,11 +1332,11 @@
1332 blob_append(&p->aCol[1],"-\n",2);
1333 blob_append(&p->aCol[2], "<del>", 5);
1334 htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
1335 blob_append(&p->aCol[2], "</del>\n", 7);
1336 }
1337 static void dfunifiedReplace(DiffBuilder *p, DLine *pX, DLine *pY){
1338 dfunifiedStartRow(p);
1339 if( p->eState==0 ){
1340 dfunifiedFinishInsert(p);
1341 blob_append(p->pOut, "<del>", 5);
1342 blob_append(&p->aCol[2], "<del>", 5);
@@ -1331,11 +1355,11 @@
1355
1356 htmlize_to_blob(&p->aCol[4], pY->z, pY->n);
1357 blob_append_char(&p->aCol[4], '\n');
1358 p->nPending++;
1359 }
1360 static void dfunifiedEdit(DiffBuilder *p, DLine *pX, DLine *pY){
1361 int i;
1362 int x;
1363 LineChange chng;
1364 oneLineChange(pX, pY, &chng);
1365 dfunifiedStartRow(p);
@@ -1500,11 +1524,11 @@
1524 "<td class=\"diffln difflnr difflne\">&#xfe19;</td>"
1525 "<td/td></tr>\n", -1);
1526 p->lnLeft += n;
1527 p->lnRight += n;
1528 }
1529 static void dfsplitCommon(DiffBuilder *p, DLine *pLine){
1530 dfsplitStartRow(p);
1531 dfsplitChangeState(p, 0);
1532 p->lnLeft++;
1533 p->lnRight++;
1534 blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1513,11 +1537,11 @@
1537 blob_append_char(&p->aCol[1], '\n');
1538 blob_appendf(&p->aCol[2],"%d\n",p->lnRight);
1539 htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
1540 blob_append_char(&p->aCol[3], '\n');
1541 }
1542 static void dfsplitInsert(DiffBuilder *p, DLine *pLine){
1543 dfsplitStartRow(p);
1544 dfsplitChangeState(p, 2);
1545 p->lnRight++;
1546 blob_append_char(p->pOut, '\n');
1547 blob_append_char(&p->aCol[0], '\n');
@@ -1525,11 +1549,11 @@
1549 blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
1550 blob_append(&p->aCol[3], "<ins>", 5);
1551 htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
1552 blob_append(&p->aCol[3], "</ins>\n", 7);
1553 }
1554 static void dfsplitDelete(DiffBuilder *p, DLine *pLine){
1555 dfsplitStartRow(p);
1556 dfsplitChangeState(p, 1);
1557 p->lnLeft++;
1558 blob_appendf(p->pOut,"%d\n", p->lnLeft);
1559 blob_append(&p->aCol[0], "<del>", 5);
@@ -1537,11 +1561,11 @@
1561 blob_append(&p->aCol[0], "</del>\n", 7);
1562 blob_append(&p->aCol[1], "&lt;\n", -1);
1563 blob_append_char(&p->aCol[2],'\n');
1564 blob_append_char(&p->aCol[3],'\n');
1565 }
1566 static void dfsplitReplace(DiffBuilder *p, DLine *pX, DLine *pY){
1567 dfsplitStartRow(p);
1568 dfsplitChangeState(p, 3);
1569 p->lnLeft++;
1570 p->lnRight++;
1571 blob_appendf(p->pOut,"%d\n", p->lnLeft);
@@ -1553,11 +1577,11 @@
1577 blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
1578
1579 htmlize_to_blob(&p->aCol[3], pY->z, pY->n);
1580 blob_append_char(&p->aCol[3], '\n');
1581 }
1582 static void dfsplitEdit(DiffBuilder *p, DLine *pX, DLine *pY){
1583 int i;
1584 int x;
1585 LineChange chng;
1586 oneLineChange(pX, pY, &chng);
1587 dfsplitStartRow(p);
@@ -1655,11 +1679,11 @@
1679 ** from pX onto the into of p.
1680 **
1681 ** This comment contains multibyte unicode characters (ü, Æ, ð) in order
1682 ** to test the ability of the diff code to handle such characters.
1683 */
1684 static void sbs_append_chars(Blob *p, int iMin, int iMax, DLine *pX){
1685 int i;
1686 const char *z = pX->z;
1687 for(i=0; i<iMax && i<pX->n; i++){
1688 char c = z[i];
1689 blob_append_char(p, c);
@@ -1669,33 +1693,33 @@
1693 blob_append_char(p, ' ');
1694 i++;
1695 }
1696 }
1697
1698 static void dfsbsCommon(DiffBuilder *p, DLine *pLine){
1699 p->lnLeft++;
1700 p->lnRight++;
1701 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1702 sbs_append_chars(p->pOut, p->width, p->width, pLine);
1703 blob_appendf(p->pOut," %6u ", p->lnRight);
1704 sbs_append_chars(p->pOut, 0, p->width, pLine);
1705 blob_append_char(p->pOut, '\n');
1706 }
1707 static void dfsbsInsert(DiffBuilder *p, DLine *pLine){
1708 p->lnRight++;
1709 blob_appendf(p->pOut,"%6s %*s > %6u ",
1710 "", p->width, "", p->lnRight);
1711 sbs_append_chars(p->pOut, 0, p->width, pLine);
1712 blob_append_char(p->pOut, '\n');
1713 }
1714 static void dfsbsDelete(DiffBuilder *p, DLine *pLine){
1715 p->lnLeft++;
1716 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1717 sbs_append_chars(p->pOut, p->width, p->width, pLine);
1718 blob_append(p->pOut," <\n", 3);
1719 }
1720 static void dfsbsEdit(DiffBuilder *p, DLine *pX, DLine *pY){
1721 p->lnLeft++;
1722 p->lnRight++;
1723 blob_appendf(p->pOut,"%6u ", p->lnLeft);
1724 sbs_append_chars(p->pOut, p->width, p->width, pX);
1725 blob_appendf(p->pOut, " | %6u ", p->lnRight);
@@ -1732,11 +1756,11 @@
1756 ** (3) If the two strings have a common prefix, measure that prefix
1757 ** (4) Find the length of the longest common subsequence that is
1758 ** at least 150% longer than the common prefix.
1759 ** (5) Longer common subsequences yield lower scores.
1760 */
1761 static int match_dline(DLine *pA, DLine *pB){
1762 const char *zA; /* Left string */
1763 const char *zB; /* right string */
1764 int nA; /* Bytes in zA[] */
1765 int nB; /* Bytes in zB[] */
1766 int nMin;
@@ -1747,16 +1771,30 @@
1771 int score; /* Final score. 0..100 */
1772 unsigned char c; /* Character being examined */
1773 unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
1774 unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */
1775
1776 zA = pA->z;
1777 if( pA->nw==0 && pA->n ){
1778 for(i=0; i<pA->n && diff_isspace(zA[i]); i++){}
1779 pA->indent = i;
1780 for(j=pA->n-1; j>i && diff_isspace(zA[j]); j--){}
1781 pA->nw = j - i + 1;
1782 }
1783 zA += pA->indent;
1784 nA = pA->nw;
1785
1786 zB = pB->z;
1787 if( pB->nw==0 && pB->n ){
1788 for(i=0; i<pB->n && diff_isspace(zB[i]); i++){}
1789 pB->indent = i;
1790 for(j=pB->n-1; j>i && diff_isspace(zB[j]); j--){}
1791 pB->nw = j - i + 1;
1792 }
1793 zB += pB->indent;
1794 nB = pB->nw;
1795
1796 if( nA>250 ) nA = 250;
1797 if( nB>250 ) nB = 250;
1798 avg = (nA+nB)/2;
1799 if( avg==0 ) return 0;
1800 nMin = nA;
@@ -1847,12 +1885,12 @@
1885 ** each other. Insertion and deletion costs are 50. Match costs
1886 ** are between 0 and 100 where 0 is a perfect match 100 is a complete
1887 ** mismatch.
1888 */
1889 static unsigned char *diffBlockAlignment(
1890 DLine *aLeft, int nLeft, /* Text on the left */
1891 DLine *aRight, int nRight, /* Text on the right */
1892 DiffConfig *pCfg, /* Configuration options */
1893 int *pNResult /* OUTPUT: Bytes of result */
1894 ){
1895 int i, j, k; /* Loop counters */
1896 int *a; /* One row of the Wagner matrix */
@@ -1878,12 +1916,12 @@
1916 ** O(NlogN). The result is not as precise, but this whole thing is an
1917 ** approximation anyhow, and the faster response time is an acceptable
1918 ** trade-off for reduced precision.
1919 */
1920 if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
1921 DLine *aSmall; /* The smaller of aLeft and aRight */
1922 DLine *aBig; /* The larger of aLeft and aRight */
1923 int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */
1924 int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */
1925 int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
1926 unsigned char *a1, *a2; /* Results of the alignments on two halves */
1927 int n1, n2; /* Number of entries in a1 and a2 */
@@ -2023,12 +2061,12 @@
2061 static void formatDiff(
2062 DContext *p, /* The computed diff */
2063 DiffConfig *pCfg, /* Configuration options */
2064 DiffBuilder *pBuilder /* The formatter object */
2065 ){
2066 DLine *A; /* Left side of the diff */
2067 DLine *B; /* Right side of the diff */
2068 unsigned int a = 0; /* Index of next line in A[] */
2069 unsigned int b = 0; /* Index of next line in B[] */
2070 const int *R; /* Array of COPY/DELETE/INSERT triples */
2071 unsigned int r; /* Index into R[] */
2072 unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */
2073

Keyboard Shortcuts

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