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.
Commit
f6112b93e9bbb7e37f24d83fb322c48f9d113c4d35d4cab3d33c23d59e784933
Parent
2dad4158dbf0d92…
1 file changed
+103
-65
+103
-65
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -121,12 +121,13 @@ | ||
| 121 | 121 | */ |
| 122 | 122 | typedef struct DLine DLine; |
| 123 | 123 | struct DLine { |
| 124 | 124 | const char *z; /* The text of the line */ |
| 125 | 125 | 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 */ | |
| 127 | 127 | unsigned short n; /* number of bytes */ |
| 128 | + unsigned short nw; /* number of bytes without leading/trailing space */ | |
| 128 | 129 | unsigned int iNext; /* 1+(Index of next line with same the same hash) */ |
| 129 | 130 | |
| 130 | 131 | /* an array of DLine elements serves two purposes. The fields |
| 131 | 132 | ** above are one per line of input text. But each entry is also |
| 132 | 133 | ** a bucket in a hash table, as follows: */ |
| @@ -163,12 +164,34 @@ | ||
| 163 | 164 | int nEditAlloc; /* Space allocated for aEdit[] */ |
| 164 | 165 | DLine *aFrom; /* File on left side of the diff */ |
| 165 | 166 | int nFrom; /* Number of lines in aFrom[] */ |
| 166 | 167 | DLine *aTo; /* File on right side of the diff */ |
| 167 | 168 | 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, | |
| 169 | 191 | }; |
| 192 | +#define diff_isspace(X) (diffIsSpace[(unsigned char)(X)]) | |
| 170 | 193 | |
| 171 | 194 | /* |
| 172 | 195 | ** Count the number of lines in the input string. Include the last line |
| 173 | 196 | ** in the count even if it lacks the \n terminator. If an empty string |
| 174 | 197 | ** is specified, the number of lines is zero. For the purposes of this |
| @@ -246,29 +269,30 @@ | ||
| 246 | 269 | if( diffFlags & DIFF_STRIP_EOLCR ){ |
| 247 | 270 | if( k>0 && z[k-1]=='\r' ){ k--; } |
| 248 | 271 | } |
| 249 | 272 | a[i].n = k; |
| 250 | 273 | 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--; } | |
| 252 | 275 | } |
| 253 | - for(s=0; s<k && z[s]<=' '; s++){} | |
| 254 | - a[i].indent = s; | |
| 255 | 276 | if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 256 | 277 | int numws = 0; |
| 278 | + for(s=0; s<k && z[s]<=' '; s++){} | |
| 279 | + a[i].indent = s; | |
| 257 | 280 | for(h=0, x=s; x<k; x++){ |
| 258 | 281 | char c = z[x]; |
| 259 | - if( fossil_isspace(c) ){ | |
| 282 | + if( diff_isspace(c) ){ | |
| 260 | 283 | ++numws; |
| 261 | 284 | }else{ |
| 262 | 285 | h = (h^c)*9000000000000000041LL; |
| 263 | 286 | } |
| 264 | 287 | } |
| 265 | 288 | k -= numws; |
| 289 | + a[i].nw = k - s; | |
| 266 | 290 | }else{ |
| 267 | 291 | int k2 = k & ~0x7; |
| 268 | 292 | u64 m; |
| 269 | - for(h=x=0; x<k2; x += 8){ | |
| 293 | + for(h=x=s=0; x<k2; x += 8){ | |
| 270 | 294 | memcpy(&m, z+x, 8); |
| 271 | 295 | h = (h^m)*9000000000000000041LL; |
| 272 | 296 | } |
| 273 | 297 | m = 0; |
| 274 | 298 | memcpy(&m, z+x, k-k2); |
| @@ -289,11 +313,11 @@ | ||
| 289 | 313 | } |
| 290 | 314 | |
| 291 | 315 | /* |
| 292 | 316 | ** Return zero if two DLine elements are identical. |
| 293 | 317 | */ |
| 294 | -static int compare_dline(const DLine *pA, const DLine *pB){ | |
| 318 | +static int compare_dline(DLine *pA, DLine *pB){ | |
| 295 | 319 | if( pA->h!=pB->h ) return 1; |
| 296 | 320 | return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK); |
| 297 | 321 | } |
| 298 | 322 | |
| 299 | 323 | /* |
| @@ -300,17 +324,17 @@ | ||
| 300 | 324 | ** Return zero if two DLine elements are identical, ignoring |
| 301 | 325 | ** all whitespace. The indent field of pA/pB already points |
| 302 | 326 | ** to the first non-space character in the string. |
| 303 | 327 | */ |
| 304 | 328 | |
| 305 | -static int compare_dline_ignore_allws(const DLine *pA, const DLine *pB){ | |
| 329 | +static int compare_dline_ignore_allws(DLine *pA, DLine *pB){ | |
| 306 | 330 | int a = pA->indent, b = pB->indent; |
| 307 | 331 | if( pA->h==pB->h ){ |
| 308 | 332 | while( a<pA->n || b<pB->n ){ |
| 309 | 333 | 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; | |
| 312 | 336 | } |
| 313 | 337 | return pA->n-a != pB->n-b; |
| 314 | 338 | } |
| 315 | 339 | return 1; |
| 316 | 340 | } |
| @@ -319,11 +343,11 @@ | ||
| 319 | 343 | ** Return true if the regular expression *pRe matches any of the |
| 320 | 344 | ** N dlines |
| 321 | 345 | */ |
| 322 | 346 | static int re_dline_match( |
| 323 | 347 | 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 */ | |
| 325 | 349 | int N /* Number of DLines to check */ |
| 326 | 350 | ){ |
| 327 | 351 | while( N-- ){ |
| 328 | 352 | if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){ |
| 329 | 353 | return 1; |
| @@ -618,11 +642,11 @@ | ||
| 618 | 642 | /* |
| 619 | 643 | ** Return true if the string starts with n spaces |
| 620 | 644 | */ |
| 621 | 645 | static int allSpaces(const char *z, int n){ |
| 622 | 646 | int i; |
| 623 | - for(i=0; i<n && fossil_isspace(z[i]); i++){} | |
| 647 | + for(i=0; i<n && diff_isspace(z[i]); i++){} | |
| 624 | 648 | return i==n; |
| 625 | 649 | } |
| 626 | 650 | |
| 627 | 651 | /* |
| 628 | 652 | ** Try to improve the human-readability of the LineChange p. |
| @@ -689,12 +713,12 @@ | ||
| 689 | 713 | ** |
| 690 | 714 | ** The result is written into the LineChange object given by the |
| 691 | 715 | ** third parameter. |
| 692 | 716 | */ |
| 693 | 717 | 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 */ | |
| 696 | 720 | LineChange *p /* OUTPUT: Write the results here */ |
| 697 | 721 | ){ |
| 698 | 722 | int nLeft; /* Length of left line in bytes */ |
| 699 | 723 | int nRight; /* Length of right line in bytes */ |
| 700 | 724 | int nShort; /* Shortest of left and right */ |
| @@ -744,17 +768,17 @@ | ||
| 744 | 768 | int nLong = nLeft<nRight ? nRight : nLeft; |
| 745 | 769 | int nGap = nLong - nShort; |
| 746 | 770 | for(i=nShort-nSuffix; i<=nPrefix; i++){ |
| 747 | 771 | int iVal = 0; |
| 748 | 772 | char c = zLeft[i]; |
| 749 | - if( fossil_isspace(c) ){ | |
| 773 | + if( diff_isspace(c) ){ | |
| 750 | 774 | iVal += 5; |
| 751 | 775 | }else if( !fossil_isalnum(c) ){ |
| 752 | 776 | iVal += 2; |
| 753 | 777 | } |
| 754 | 778 | c = zLeft[i+nGap-1]; |
| 755 | - if( fossil_isspace(c) ){ | |
| 779 | + if( diff_isspace(c) ){ | |
| 756 | 780 | iVal += 5; |
| 757 | 781 | }else if( !fossil_isalnum(c) ){ |
| 758 | 782 | iVal += 2; |
| 759 | 783 | } |
| 760 | 784 | if( iVal>iBestVal ){ |
| @@ -885,15 +909,15 @@ | ||
| 885 | 909 | ** in appropriate method implementations. |
| 886 | 910 | */ |
| 887 | 911 | typedef struct DiffBuilder DiffBuilder; |
| 888 | 912 | struct DiffBuilder { |
| 889 | 913 | 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*); | |
| 895 | 919 | void (*xEnd)(DiffBuilder*); |
| 896 | 920 | unsigned int lnLeft; /* Lines seen on the left (delete) side */ |
| 897 | 921 | unsigned int lnRight; /* Lines seen on the right (insert) side */ |
| 898 | 922 | unsigned int nPending; /* Number of pending lines */ |
| 899 | 923 | int eState; /* State of the output */ |
| @@ -915,35 +939,35 @@ | ||
| 915 | 939 | n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n, |
| 916 | 940 | isFinal ? " FINAL" : ""); |
| 917 | 941 | p->lnLeft += n; |
| 918 | 942 | p->lnRight += n; |
| 919 | 943 | } |
| 920 | -static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){ | |
| 944 | +static void dfdebugCommon(DiffBuilder *p, DLine *pLine){ | |
| 921 | 945 | p->lnLeft++; |
| 922 | 946 | p->lnRight++; |
| 923 | 947 | blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n", |
| 924 | 948 | p->lnLeft, p->lnRight, (int)pLine->n, pLine->z); |
| 925 | 949 | } |
| 926 | -static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){ | |
| 950 | +static void dfdebugInsert(DiffBuilder *p, DLine *pLine){ | |
| 927 | 951 | p->lnRight++; |
| 928 | 952 | blob_appendf(p->pOut, "INSERT %8d %.*s\n", |
| 929 | 953 | p->lnRight, (int)pLine->n, pLine->z); |
| 930 | 954 | } |
| 931 | -static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){ | |
| 955 | +static void dfdebugDelete(DiffBuilder *p, DLine *pLine){ | |
| 932 | 956 | p->lnLeft++; |
| 933 | 957 | blob_appendf(p->pOut, "DELETE %8u %.*s\n", |
| 934 | 958 | p->lnLeft, (int)pLine->n, pLine->z); |
| 935 | 959 | } |
| 936 | -static void dfdebugReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 960 | +static void dfdebugReplace(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 937 | 961 | p->lnLeft++; |
| 938 | 962 | p->lnRight++; |
| 939 | 963 | blob_appendf(p->pOut, "REPLACE %8u %.*s\n", |
| 940 | 964 | p->lnLeft, (int)pX->n, pX->z); |
| 941 | 965 | blob_appendf(p->pOut, " %8u %.*s\n", |
| 942 | 966 | p->lnRight, (int)pY->n, pY->z); |
| 943 | 967 | } |
| 944 | -static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 968 | +static void dfdebugEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 945 | 969 | int i, j; |
| 946 | 970 | int x; |
| 947 | 971 | LineChange chng; |
| 948 | 972 | p->lnLeft++; |
| 949 | 973 | p->lnRight++; |
| @@ -1031,33 +1055,33 @@ | ||
| 1031 | 1055 | ** additional string which is a common suffix. |
| 1032 | 1056 | */ |
| 1033 | 1057 | static void dftclSkip(DiffBuilder *p, unsigned int n, int isFinal){ |
| 1034 | 1058 | blob_appendf(p->pOut, "SKIP %u\n", n); |
| 1035 | 1059 | } |
| 1036 | -static void dftclCommon(DiffBuilder *p, const DLine *pLine){ | |
| 1060 | +static void dftclCommon(DiffBuilder *p, DLine *pLine){ | |
| 1037 | 1061 | blob_appendf(p->pOut, "COM "); |
| 1038 | 1062 | blob_append_tcl_literal(p->pOut, pLine->z, pLine->n); |
| 1039 | 1063 | blob_append_char(p->pOut, '\n'); |
| 1040 | 1064 | } |
| 1041 | -static void dftclInsert(DiffBuilder *p, const DLine *pLine){ | |
| 1065 | +static void dftclInsert(DiffBuilder *p, DLine *pLine){ | |
| 1042 | 1066 | blob_append(p->pOut, "INS ", -1); |
| 1043 | 1067 | blob_append_tcl_literal(p->pOut, pLine->z, pLine->n); |
| 1044 | 1068 | blob_append_char(p->pOut, '\n'); |
| 1045 | 1069 | } |
| 1046 | -static void dftclDelete(DiffBuilder *p, const DLine *pLine){ | |
| 1070 | +static void dftclDelete(DiffBuilder *p, DLine *pLine){ | |
| 1047 | 1071 | blob_append(p->pOut, "DEL ", -1); |
| 1048 | 1072 | blob_append_tcl_literal(p->pOut, pLine->z, pLine->n); |
| 1049 | 1073 | blob_append_char(p->pOut, '\n'); |
| 1050 | 1074 | } |
| 1051 | -static void dftclReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1075 | +static void dftclReplace(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1052 | 1076 | blob_append(p->pOut, "EDIT \"\" ", -1); |
| 1053 | 1077 | blob_append_tcl_literal(p->pOut, pX->z, pX->n); |
| 1054 | 1078 | blob_append_char(p->pOut, ' '); |
| 1055 | 1079 | blob_append_tcl_literal(p->pOut, pY->z, pY->n); |
| 1056 | 1080 | blob_append_char(p->pOut, '\n'); |
| 1057 | 1081 | } |
| 1058 | -static void dftclEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1082 | +static void dftclEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1059 | 1083 | int i, x; |
| 1060 | 1084 | LineChange chng; |
| 1061 | 1085 | blob_append(p->pOut, "EDIT", 4); |
| 1062 | 1086 | oneLineChange(pX, pY, &chng); |
| 1063 | 1087 | for(i=x=0; i<chng.n; i++){ |
| @@ -1115,33 +1139,33 @@ | ||
| 1115 | 1139 | ** not apply. |
| 1116 | 1140 | */ |
| 1117 | 1141 | static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){ |
| 1118 | 1142 | blob_appendf(p->pOut, "1,%u,\n", n); |
| 1119 | 1143 | } |
| 1120 | -static void dfjsonCommon(DiffBuilder *p, const DLine *pLine){ | |
| 1144 | +static void dfjsonCommon(DiffBuilder *p, DLine *pLine){ | |
| 1121 | 1145 | blob_append(p->pOut, "2,",2); |
| 1122 | 1146 | blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n); |
| 1123 | 1147 | blob_append(p->pOut, ",\n",2); |
| 1124 | 1148 | } |
| 1125 | -static void dfjsonInsert(DiffBuilder *p, const DLine *pLine){ | |
| 1149 | +static void dfjsonInsert(DiffBuilder *p, DLine *pLine){ | |
| 1126 | 1150 | blob_append(p->pOut, "3,",2); |
| 1127 | 1151 | blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n); |
| 1128 | 1152 | blob_append(p->pOut, ",\n",2); |
| 1129 | 1153 | } |
| 1130 | -static void dfjsonDelete(DiffBuilder *p, const DLine *pLine){ | |
| 1154 | +static void dfjsonDelete(DiffBuilder *p, DLine *pLine){ | |
| 1131 | 1155 | blob_append(p->pOut, "4,",2); |
| 1132 | 1156 | blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n); |
| 1133 | 1157 | blob_append(p->pOut, ",\n",2); |
| 1134 | 1158 | } |
| 1135 | -static void dfjsonReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1159 | +static void dfjsonReplace(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1136 | 1160 | blob_append(p->pOut, "5,[\"\",",-1); |
| 1137 | 1161 | blob_append_json_literal(p->pOut, pX->z, (int)pX->n); |
| 1138 | 1162 | blob_append(p->pOut, ",",1); |
| 1139 | 1163 | blob_append_json_literal(p->pOut, pY->z, (int)pY->n); |
| 1140 | 1164 | blob_append(p->pOut, ",\"\"],\n",-1); |
| 1141 | 1165 | } |
| 1142 | -static void dfjsonEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1166 | +static void dfjsonEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1143 | 1167 | int i, x; |
| 1144 | 1168 | LineChange chng; |
| 1145 | 1169 | blob_append(p->pOut, "5,[", 3); |
| 1146 | 1170 | oneLineChange(pX, pY, &chng); |
| 1147 | 1171 | for(i=x=0; i<chng.n; i++){ |
| @@ -1270,11 +1294,11 @@ | ||
| 1270 | 1294 | blob_append(p->pOut, "<td class=\"diffln difflne\">" |
| 1271 | 1295 | "︙</td><td></td><td></td></tr>\n", -1); |
| 1272 | 1296 | p->lnLeft += n; |
| 1273 | 1297 | p->lnRight += n; |
| 1274 | 1298 | } |
| 1275 | -static void dfunifiedCommon(DiffBuilder *p, const DLine *pLine){ | |
| 1299 | +static void dfunifiedCommon(DiffBuilder *p, DLine *pLine){ | |
| 1276 | 1300 | dfunifiedStartRow(p); |
| 1277 | 1301 | dfunifiedFinishDelete(p); |
| 1278 | 1302 | dfunifiedFinishInsert(p); |
| 1279 | 1303 | p->lnLeft++; |
| 1280 | 1304 | p->lnRight++; |
| @@ -1282,20 +1306,20 @@ | ||
| 1282 | 1306 | blob_appendf(&p->aCol[0],"%d\n",p->lnRight); |
| 1283 | 1307 | blob_append_char(&p->aCol[1], '\n'); |
| 1284 | 1308 | htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n); |
| 1285 | 1309 | blob_append_char(&p->aCol[2], '\n'); |
| 1286 | 1310 | } |
| 1287 | -static void dfunifiedInsert(DiffBuilder *p, const DLine *pLine){ | |
| 1311 | +static void dfunifiedInsert(DiffBuilder *p, DLine *pLine){ | |
| 1288 | 1312 | dfunifiedStartRow(p); |
| 1289 | 1313 | p->lnRight++; |
| 1290 | 1314 | blob_appendf(&p->aCol[3],"%d\n", p->lnRight); |
| 1291 | 1315 | blob_append(&p->aCol[4], "<ins>", 5); |
| 1292 | 1316 | htmlize_to_blob(&p->aCol[4], pLine->z, (int)pLine->n); |
| 1293 | 1317 | blob_append(&p->aCol[4], "</ins>\n", 7); |
| 1294 | 1318 | p->nPending++; |
| 1295 | 1319 | } |
| 1296 | -static void dfunifiedDelete(DiffBuilder *p, const DLine *pLine){ | |
| 1320 | +static void dfunifiedDelete(DiffBuilder *p, DLine *pLine){ | |
| 1297 | 1321 | dfunifiedStartRow(p); |
| 1298 | 1322 | dfunifiedFinishInsert(p); |
| 1299 | 1323 | if( p->eState==0 ){ |
| 1300 | 1324 | dfunifiedFinishInsert(p); |
| 1301 | 1325 | blob_append(p->pOut, "<del>", 5); |
| @@ -1308,11 +1332,11 @@ | ||
| 1308 | 1332 | blob_append(&p->aCol[1],"-\n",2); |
| 1309 | 1333 | blob_append(&p->aCol[2], "<del>", 5); |
| 1310 | 1334 | htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n); |
| 1311 | 1335 | blob_append(&p->aCol[2], "</del>\n", 7); |
| 1312 | 1336 | } |
| 1313 | -static void dfunifiedReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1337 | +static void dfunifiedReplace(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1314 | 1338 | dfunifiedStartRow(p); |
| 1315 | 1339 | if( p->eState==0 ){ |
| 1316 | 1340 | dfunifiedFinishInsert(p); |
| 1317 | 1341 | blob_append(p->pOut, "<del>", 5); |
| 1318 | 1342 | blob_append(&p->aCol[2], "<del>", 5); |
| @@ -1331,11 +1355,11 @@ | ||
| 1331 | 1355 | |
| 1332 | 1356 | htmlize_to_blob(&p->aCol[4], pY->z, pY->n); |
| 1333 | 1357 | blob_append_char(&p->aCol[4], '\n'); |
| 1334 | 1358 | p->nPending++; |
| 1335 | 1359 | } |
| 1336 | -static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1360 | +static void dfunifiedEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1337 | 1361 | int i; |
| 1338 | 1362 | int x; |
| 1339 | 1363 | LineChange chng; |
| 1340 | 1364 | oneLineChange(pX, pY, &chng); |
| 1341 | 1365 | dfunifiedStartRow(p); |
| @@ -1500,11 +1524,11 @@ | ||
| 1500 | 1524 | "<td class=\"diffln difflnr difflne\">︙</td>" |
| 1501 | 1525 | "<td/td></tr>\n", -1); |
| 1502 | 1526 | p->lnLeft += n; |
| 1503 | 1527 | p->lnRight += n; |
| 1504 | 1528 | } |
| 1505 | -static void dfsplitCommon(DiffBuilder *p, const DLine *pLine){ | |
| 1529 | +static void dfsplitCommon(DiffBuilder *p, DLine *pLine){ | |
| 1506 | 1530 | dfsplitStartRow(p); |
| 1507 | 1531 | dfsplitChangeState(p, 0); |
| 1508 | 1532 | p->lnLeft++; |
| 1509 | 1533 | p->lnRight++; |
| 1510 | 1534 | blob_appendf(p->pOut,"%d\n", p->lnLeft); |
| @@ -1513,11 +1537,11 @@ | ||
| 1513 | 1537 | blob_append_char(&p->aCol[1], '\n'); |
| 1514 | 1538 | blob_appendf(&p->aCol[2],"%d\n",p->lnRight); |
| 1515 | 1539 | htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n); |
| 1516 | 1540 | blob_append_char(&p->aCol[3], '\n'); |
| 1517 | 1541 | } |
| 1518 | -static void dfsplitInsert(DiffBuilder *p, const DLine *pLine){ | |
| 1542 | +static void dfsplitInsert(DiffBuilder *p, DLine *pLine){ | |
| 1519 | 1543 | dfsplitStartRow(p); |
| 1520 | 1544 | dfsplitChangeState(p, 2); |
| 1521 | 1545 | p->lnRight++; |
| 1522 | 1546 | blob_append_char(p->pOut, '\n'); |
| 1523 | 1547 | blob_append_char(&p->aCol[0], '\n'); |
| @@ -1525,11 +1549,11 @@ | ||
| 1525 | 1549 | blob_appendf(&p->aCol[2],"%d\n", p->lnRight); |
| 1526 | 1550 | blob_append(&p->aCol[3], "<ins>", 5); |
| 1527 | 1551 | htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n); |
| 1528 | 1552 | blob_append(&p->aCol[3], "</ins>\n", 7); |
| 1529 | 1553 | } |
| 1530 | -static void dfsplitDelete(DiffBuilder *p, const DLine *pLine){ | |
| 1554 | +static void dfsplitDelete(DiffBuilder *p, DLine *pLine){ | |
| 1531 | 1555 | dfsplitStartRow(p); |
| 1532 | 1556 | dfsplitChangeState(p, 1); |
| 1533 | 1557 | p->lnLeft++; |
| 1534 | 1558 | blob_appendf(p->pOut,"%d\n", p->lnLeft); |
| 1535 | 1559 | blob_append(&p->aCol[0], "<del>", 5); |
| @@ -1537,11 +1561,11 @@ | ||
| 1537 | 1561 | blob_append(&p->aCol[0], "</del>\n", 7); |
| 1538 | 1562 | blob_append(&p->aCol[1], "<\n", -1); |
| 1539 | 1563 | blob_append_char(&p->aCol[2],'\n'); |
| 1540 | 1564 | blob_append_char(&p->aCol[3],'\n'); |
| 1541 | 1565 | } |
| 1542 | -static void dfsplitReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1566 | +static void dfsplitReplace(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1543 | 1567 | dfsplitStartRow(p); |
| 1544 | 1568 | dfsplitChangeState(p, 3); |
| 1545 | 1569 | p->lnLeft++; |
| 1546 | 1570 | p->lnRight++; |
| 1547 | 1571 | blob_appendf(p->pOut,"%d\n", p->lnLeft); |
| @@ -1553,11 +1577,11 @@ | ||
| 1553 | 1577 | blob_appendf(&p->aCol[2],"%d\n", p->lnRight); |
| 1554 | 1578 | |
| 1555 | 1579 | htmlize_to_blob(&p->aCol[3], pY->z, pY->n); |
| 1556 | 1580 | blob_append_char(&p->aCol[3], '\n'); |
| 1557 | 1581 | } |
| 1558 | -static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1582 | +static void dfsplitEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1559 | 1583 | int i; |
| 1560 | 1584 | int x; |
| 1561 | 1585 | LineChange chng; |
| 1562 | 1586 | oneLineChange(pX, pY, &chng); |
| 1563 | 1587 | dfsplitStartRow(p); |
| @@ -1655,11 +1679,11 @@ | ||
| 1655 | 1679 | ** from pX onto the into of p. |
| 1656 | 1680 | ** |
| 1657 | 1681 | ** This comment contains multibyte unicode characters (ü, Æ, ð) in order |
| 1658 | 1682 | ** to test the ability of the diff code to handle such characters. |
| 1659 | 1683 | */ |
| 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){ | |
| 1661 | 1685 | int i; |
| 1662 | 1686 | const char *z = pX->z; |
| 1663 | 1687 | for(i=0; i<iMax && i<pX->n; i++){ |
| 1664 | 1688 | char c = z[i]; |
| 1665 | 1689 | blob_append_char(p, c); |
| @@ -1669,33 +1693,33 @@ | ||
| 1669 | 1693 | blob_append_char(p, ' '); |
| 1670 | 1694 | i++; |
| 1671 | 1695 | } |
| 1672 | 1696 | } |
| 1673 | 1697 | |
| 1674 | -static void dfsbsCommon(DiffBuilder *p, const DLine *pLine){ | |
| 1698 | +static void dfsbsCommon(DiffBuilder *p, DLine *pLine){ | |
| 1675 | 1699 | p->lnLeft++; |
| 1676 | 1700 | p->lnRight++; |
| 1677 | 1701 | blob_appendf(p->pOut,"%6u ", p->lnLeft); |
| 1678 | 1702 | sbs_append_chars(p->pOut, p->width, p->width, pLine); |
| 1679 | 1703 | blob_appendf(p->pOut," %6u ", p->lnRight); |
| 1680 | 1704 | sbs_append_chars(p->pOut, 0, p->width, pLine); |
| 1681 | 1705 | blob_append_char(p->pOut, '\n'); |
| 1682 | 1706 | } |
| 1683 | -static void dfsbsInsert(DiffBuilder *p, const DLine *pLine){ | |
| 1707 | +static void dfsbsInsert(DiffBuilder *p, DLine *pLine){ | |
| 1684 | 1708 | p->lnRight++; |
| 1685 | 1709 | blob_appendf(p->pOut,"%6s %*s > %6u ", |
| 1686 | 1710 | "", p->width, "", p->lnRight); |
| 1687 | 1711 | sbs_append_chars(p->pOut, 0, p->width, pLine); |
| 1688 | 1712 | blob_append_char(p->pOut, '\n'); |
| 1689 | 1713 | } |
| 1690 | -static void dfsbsDelete(DiffBuilder *p, const DLine *pLine){ | |
| 1714 | +static void dfsbsDelete(DiffBuilder *p, DLine *pLine){ | |
| 1691 | 1715 | p->lnLeft++; |
| 1692 | 1716 | blob_appendf(p->pOut,"%6u ", p->lnLeft); |
| 1693 | 1717 | sbs_append_chars(p->pOut, p->width, p->width, pLine); |
| 1694 | 1718 | blob_append(p->pOut," <\n", 3); |
| 1695 | 1719 | } |
| 1696 | -static void dfsbsEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ | |
| 1720 | +static void dfsbsEdit(DiffBuilder *p, DLine *pX, DLine *pY){ | |
| 1697 | 1721 | p->lnLeft++; |
| 1698 | 1722 | p->lnRight++; |
| 1699 | 1723 | blob_appendf(p->pOut,"%6u ", p->lnLeft); |
| 1700 | 1724 | sbs_append_chars(p->pOut, p->width, p->width, pX); |
| 1701 | 1725 | blob_appendf(p->pOut, " | %6u ", p->lnRight); |
| @@ -1732,11 +1756,11 @@ | ||
| 1732 | 1756 | ** (3) If the two strings have a common prefix, measure that prefix |
| 1733 | 1757 | ** (4) Find the length of the longest common subsequence that is |
| 1734 | 1758 | ** at least 150% longer than the common prefix. |
| 1735 | 1759 | ** (5) Longer common subsequences yield lower scores. |
| 1736 | 1760 | */ |
| 1737 | -static int match_dline(const DLine *pA, const DLine *pB){ | |
| 1761 | +static int match_dline(DLine *pA, DLine *pB){ | |
| 1738 | 1762 | const char *zA; /* Left string */ |
| 1739 | 1763 | const char *zB; /* right string */ |
| 1740 | 1764 | int nA; /* Bytes in zA[] */ |
| 1741 | 1765 | int nB; /* Bytes in zB[] */ |
| 1742 | 1766 | int nMin; |
| @@ -1747,16 +1771,30 @@ | ||
| 1747 | 1771 | int score; /* Final score. 0..100 */ |
| 1748 | 1772 | unsigned char c; /* Character being examined */ |
| 1749 | 1773 | unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */ |
| 1750 | 1774 | unsigned char aNext[252]; /* aNext[i] = index in zB[] of next zB[i] char */ |
| 1751 | 1775 | |
| 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 | + | |
| 1758 | 1796 | if( nA>250 ) nA = 250; |
| 1759 | 1797 | if( nB>250 ) nB = 250; |
| 1760 | 1798 | avg = (nA+nB)/2; |
| 1761 | 1799 | if( avg==0 ) return 0; |
| 1762 | 1800 | nMin = nA; |
| @@ -1847,12 +1885,12 @@ | ||
| 1847 | 1885 | ** each other. Insertion and deletion costs are 50. Match costs |
| 1848 | 1886 | ** are between 0 and 100 where 0 is a perfect match 100 is a complete |
| 1849 | 1887 | ** mismatch. |
| 1850 | 1888 | */ |
| 1851 | 1889 | 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 */ | |
| 1854 | 1892 | DiffConfig *pCfg, /* Configuration options */ |
| 1855 | 1893 | int *pNResult /* OUTPUT: Bytes of result */ |
| 1856 | 1894 | ){ |
| 1857 | 1895 | int i, j, k; /* Loop counters */ |
| 1858 | 1896 | int *a; /* One row of the Wagner matrix */ |
| @@ -1878,12 +1916,12 @@ | ||
| 1878 | 1916 | ** O(NlogN). The result is not as precise, but this whole thing is an |
| 1879 | 1917 | ** approximation anyhow, and the faster response time is an acceptable |
| 1880 | 1918 | ** trade-off for reduced precision. |
| 1881 | 1919 | */ |
| 1882 | 1920 | 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 */ | |
| 1885 | 1923 | int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */ |
| 1886 | 1924 | int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */ |
| 1887 | 1925 | int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */ |
| 1888 | 1926 | unsigned char *a1, *a2; /* Results of the alignments on two halves */ |
| 1889 | 1927 | int n1, n2; /* Number of entries in a1 and a2 */ |
| @@ -2023,12 +2061,12 @@ | ||
| 2023 | 2061 | static void formatDiff( |
| 2024 | 2062 | DContext *p, /* The computed diff */ |
| 2025 | 2063 | DiffConfig *pCfg, /* Configuration options */ |
| 2026 | 2064 | DiffBuilder *pBuilder /* The formatter object */ |
| 2027 | 2065 | ){ |
| 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 */ | |
| 2030 | 2068 | unsigned int a = 0; /* Index of next line in A[] */ |
| 2031 | 2069 | unsigned int b = 0; /* Index of next line in B[] */ |
| 2032 | 2070 | const int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 2033 | 2071 | unsigned int r; /* Index into R[] */ |
| 2034 | 2072 | unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| 2035 | 2073 |
| --- 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 | "︙</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\">︙</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], "<\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 | "︙</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\">︙</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], "<\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 |