Fossil SCM
Fix a bug in error recovery logic in the 3-way merge. Added new comments to the 3-way merge code to hopefully make it easier to understand.
Commit
3e89b0c52648512790ae4c02101e2a25c520a502
Parent
26ab4f7012fb1bb…
1 file changed
+51
-9
+51
-9
| --- src/merge3.c | ||
| +++ src/merge3.c | ||
| @@ -37,13 +37,14 @@ | ||
| 37 | 37 | /* The minimum of two integers */ |
| 38 | 38 | #define min(A,B) (A<B?A:B) |
| 39 | 39 | |
| 40 | 40 | /* |
| 41 | 41 | ** Compare N lines of text from pV1 and pV2. If the lines |
| 42 | -** are the same, return true. Return false if they are different. | |
| 42 | +** are the same, return true. Return false if one or more of the N | |
| 43 | +** lines are different. | |
| 43 | 44 | ** |
| 44 | -** The cursor on both pV1 and pV2 is unchanged. | |
| 45 | +** The cursors on both pV1 and pV2 is unchanged by this comparison. | |
| 45 | 46 | */ |
| 46 | 47 | static int sameLines(Blob *pV1, Blob *pV2, int N){ |
| 47 | 48 | char *z1, *z2; |
| 48 | 49 | int i; |
| 49 | 50 | |
| @@ -58,15 +59,22 @@ | ||
| 58 | 59 | } |
| 59 | 60 | return 0; |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | 63 | /* |
| 63 | -** Look at the next edit triple in both aC1 and aC2. If they describe | |
| 64 | -** an identical edit, then return 1. If the edits are different, | |
| 65 | -** return 0. | |
| 64 | +** Look at the next edit triple in both aC1 and aC2. (An "edit triple" is | |
| 65 | +** three integers describing the number of copies, deletes, and inserts in | |
| 66 | +** moving from the original to the edited copy of the file.) If the three | |
| 67 | +** integers of the edit triples describe an identical edit, then return 1. | |
| 68 | +** If the edits are different, return 0. | |
| 66 | 69 | */ |
| 67 | -static int sameEdit(int *aC1, int *aC2, Blob *pV1, Blob *pV2){ | |
| 70 | +static int sameEdit( | |
| 71 | + int *aC1, /* Array of edit integers for file 1 */ | |
| 72 | + int *aC2, /* Array of edit integers for file 2 */ | |
| 73 | + Blob *pV1, /* Text of file 1 */ | |
| 74 | + Blob *pV2 /* Text of file 2 */ | |
| 75 | +){ | |
| 68 | 76 | if( aC1[0]!=aC2[0] ) return 0; |
| 69 | 77 | if( aC1[1]!=aC2[1] ) return 0; |
| 70 | 78 | if( aC1[2]!=aC2[2] ) return 0; |
| 71 | 79 | if( sameLines(pV1, pV2, aC1[2]) ) return 1; |
| 72 | 80 | return 0; |
| @@ -78,11 +86,11 @@ | ||
| 78 | 86 | ** |
| 79 | 87 | ** (0) The number of lines to copy |
| 80 | 88 | ** (1) The number of lines to delete |
| 81 | 89 | ** (2) The number of liens to insert |
| 82 | 90 | ** |
| 83 | -** Suppose we want to advance over sz lines of the pivot. This routine | |
| 91 | +** Suppose we want to advance over sz lines of the originl file. This routine | |
| 84 | 92 | ** returns true if that advance would land us on a copy operation. It |
| 85 | 93 | ** returns false if the advance would end on a delete. |
| 86 | 94 | */ |
| 87 | 95 | static int ends_at_CPY(int *aC, int sz){ |
| 88 | 96 | while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){ |
| @@ -98,10 +106,15 @@ | ||
| 98 | 106 | /* |
| 99 | 107 | ** pSrc contains an edited file where aC[] describes the edit. Part of |
| 100 | 108 | ** pSrc has already been output. This routine outputs additional lines |
| 101 | 109 | ** of pSrc - lines that correspond to the next sz lines of the original |
| 102 | 110 | ** unedited file. |
| 111 | +** | |
| 112 | +** Note that sz counts the number of lines of text in the original file. | |
| 113 | +** But text is output from the edited file. So the number of lines transfer | |
| 114 | +** to pOut might be different from sz. Fewer lines appear in pOut if there | |
| 115 | +** are deletes. More lines appear if there are inserts. | |
| 103 | 116 | ** |
| 104 | 117 | ** The aC[] array is updated and the new index into aC[] is returned. |
| 105 | 118 | */ |
| 106 | 119 | static int output_one_side( |
| 107 | 120 | Blob *pOut, /* Write to this blob */ |
| @@ -148,14 +161,21 @@ | ||
| 148 | 161 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 149 | 162 | static const char zBegin[] = ">>>>>>> BEGIN MERGE CONFLICT\n"; |
| 150 | 163 | static const char zMid[] = "============================\n"; |
| 151 | 164 | static const char zEnd[] = "<<<<<<< END MERGE CONFLICT\n"; |
| 152 | 165 | |
| 153 | - /* Compute the edits that occur from pPivot => pV1 and pPivot => pV2 */ | |
| 166 | + /* Compute the edits that occur from pPivot => pV1 (into aC1) | |
| 167 | + ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is | |
| 168 | + ** an array of integer triples. Within each triple, the first integer | |
| 169 | + ** is the number of lines of text to copy directly from the pivot, | |
| 170 | + ** the second integer is the number of lines of text to omit from the | |
| 171 | + ** pivot, and the third integer is the number of lines of text that are | |
| 172 | + ** inserted. The edit array ends with a triple of 0,0,0. | |
| 173 | + */ | |
| 154 | 174 | aC1 = text_diff(pPivot, pV1, 0, 0); |
| 155 | 175 | aC2 = text_diff(pPivot, pV2, 0, 0); |
| 156 | - if( aC2==0 || aC2==0 ){ | |
| 176 | + if( aC1==0 || aC2==0 ){ | |
| 157 | 177 | free(aC1); |
| 158 | 178 | free(aC2); |
| 159 | 179 | return -1; |
| 160 | 180 | } |
| 161 | 181 | |
| @@ -177,26 +197,33 @@ | ||
| 177 | 197 | for(i2=0; i2<limit2; i2+=3){ |
| 178 | 198 | printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); |
| 179 | 199 | } |
| 180 | 200 | ) |
| 181 | 201 | |
| 202 | + /* Loop over the two edit vectors and use them to compute merged text | |
| 203 | + ** which is written into pOut. i1 and i2 are multiples of 3 which are | |
| 204 | + ** indices into aC1[] and aC2[] to the edit triple currently being | |
| 205 | + ** processed | |
| 206 | + */ | |
| 182 | 207 | i1 = i2 = 0; |
| 183 | 208 | while( i1<limit1 && i2<limit2 ){ |
| 184 | 209 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 185 | 210 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 186 | 211 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 187 | 212 | |
| 188 | 213 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 214 | + /* Output text that is unchanged in both V1 and V2 */ | |
| 189 | 215 | nCpy = min(aC1[i1], aC2[i2]); |
| 190 | 216 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 191 | 217 | blob_copy_lines(pOut, pPivot, nCpy); |
| 192 | 218 | blob_copy_lines(0, pV1, nCpy); |
| 193 | 219 | blob_copy_lines(0, pV2, nCpy); |
| 194 | 220 | aC1[i1] -= nCpy; |
| 195 | 221 | aC2[i2] -= nCpy; |
| 196 | 222 | }else |
| 197 | 223 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 224 | + /* Output edits to V2 that occurs within unchanged regions of V1 */ | |
| 198 | 225 | nDel = aC2[i2+1]; |
| 199 | 226 | nIns = aC2[i2+2]; |
| 200 | 227 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 201 | 228 | blob_copy_lines(0, pPivot, nDel); |
| 202 | 229 | blob_copy_lines(0, pV1, nDel); |
| @@ -203,10 +230,11 @@ | ||
| 203 | 230 | blob_copy_lines(pOut, pV2, nIns); |
| 204 | 231 | aC1[i1] -= nDel; |
| 205 | 232 | i2 += 3; |
| 206 | 233 | }else |
| 207 | 234 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 235 | + /* Output edits to V1 that occur within unchanged regions of V2 */ | |
| 208 | 236 | nDel = aC1[i1+1]; |
| 209 | 237 | nIns = aC1[i1+2]; |
| 210 | 238 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 211 | 239 | blob_copy_lines(0, pPivot, nDel); |
| 212 | 240 | blob_copy_lines(0, pV2, nDel); |
| @@ -213,10 +241,11 @@ | ||
| 213 | 241 | blob_copy_lines(pOut, pV1, nIns); |
| 214 | 242 | aC2[i2] -= nDel; |
| 215 | 243 | i1 += 3; |
| 216 | 244 | }else |
| 217 | 245 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 246 | + /* Output edits that are identical in both V1 and V2. */ | |
| 218 | 247 | assert( aC1[i1]==0 ); |
| 219 | 248 | nDel = aC1[i1+1]; |
| 220 | 249 | nIns = aC1[i1+2]; |
| 221 | 250 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 222 | 251 | blob_copy_lines(0, pPivot, nDel); |
| @@ -224,10 +253,14 @@ | ||
| 224 | 253 | blob_copy_lines(0, pV2, nIns); |
| 225 | 254 | i1 += 3; |
| 226 | 255 | i2 += 3; |
| 227 | 256 | }else |
| 228 | 257 | { |
| 258 | + /* We have found a region where different edits to V1 and V2 overlap. | |
| 259 | + ** This is a merge conflict. Find the size of the conflict, then | |
| 260 | + ** output both possible edits separate by distinctive marks. | |
| 261 | + */ | |
| 229 | 262 | int sz = 1; /* Size of the conflict in lines */ |
| 230 | 263 | nConflict++; |
| 231 | 264 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 232 | 265 | sz++; |
| 233 | 266 | } |
| @@ -237,13 +270,22 @@ | ||
| 237 | 270 | blob_appendf(pOut, zMid); |
| 238 | 271 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 239 | 272 | blob_appendf(pOut, zEnd); |
| 240 | 273 | blob_copy_lines(0, pPivot, sz); |
| 241 | 274 | } |
| 275 | + | |
| 276 | + /* If we are finished with an edit triple, advance to the next | |
| 277 | + ** triple. | |
| 278 | + */ | |
| 242 | 279 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| 243 | 280 | if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3; |
| 244 | 281 | } |
| 282 | + | |
| 283 | + /* When one of the two edit vectors reaches its end, there might still | |
| 284 | + ** be an insert in the other edit vector. Output this remaining | |
| 285 | + ** insert. | |
| 286 | + */ | |
| 245 | 287 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 246 | 288 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 247 | 289 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 248 | 290 | if( i1<limit1 && aC1[i1+2]>0 ){ |
| 249 | 291 | DEBUG( printf("INSERT +%d left\n", aC1[i1+2]); ) |
| 250 | 292 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -37,13 +37,14 @@ | |
| 37 | /* The minimum of two integers */ |
| 38 | #define min(A,B) (A<B?A:B) |
| 39 | |
| 40 | /* |
| 41 | ** Compare N lines of text from pV1 and pV2. If the lines |
| 42 | ** are the same, return true. Return false if they are different. |
| 43 | ** |
| 44 | ** The cursor on both pV1 and pV2 is unchanged. |
| 45 | */ |
| 46 | static int sameLines(Blob *pV1, Blob *pV2, int N){ |
| 47 | char *z1, *z2; |
| 48 | int i; |
| 49 | |
| @@ -58,15 +59,22 @@ | |
| 58 | } |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | /* |
| 63 | ** Look at the next edit triple in both aC1 and aC2. If they describe |
| 64 | ** an identical edit, then return 1. If the edits are different, |
| 65 | ** return 0. |
| 66 | */ |
| 67 | static int sameEdit(int *aC1, int *aC2, Blob *pV1, Blob *pV2){ |
| 68 | if( aC1[0]!=aC2[0] ) return 0; |
| 69 | if( aC1[1]!=aC2[1] ) return 0; |
| 70 | if( aC1[2]!=aC2[2] ) return 0; |
| 71 | if( sameLines(pV1, pV2, aC1[2]) ) return 1; |
| 72 | return 0; |
| @@ -78,11 +86,11 @@ | |
| 78 | ** |
| 79 | ** (0) The number of lines to copy |
| 80 | ** (1) The number of lines to delete |
| 81 | ** (2) The number of liens to insert |
| 82 | ** |
| 83 | ** Suppose we want to advance over sz lines of the pivot. This routine |
| 84 | ** returns true if that advance would land us on a copy operation. It |
| 85 | ** returns false if the advance would end on a delete. |
| 86 | */ |
| 87 | static int ends_at_CPY(int *aC, int sz){ |
| 88 | while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){ |
| @@ -98,10 +106,15 @@ | |
| 98 | /* |
| 99 | ** pSrc contains an edited file where aC[] describes the edit. Part of |
| 100 | ** pSrc has already been output. This routine outputs additional lines |
| 101 | ** of pSrc - lines that correspond to the next sz lines of the original |
| 102 | ** unedited file. |
| 103 | ** |
| 104 | ** The aC[] array is updated and the new index into aC[] is returned. |
| 105 | */ |
| 106 | static int output_one_side( |
| 107 | Blob *pOut, /* Write to this blob */ |
| @@ -148,14 +161,21 @@ | |
| 148 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 149 | static const char zBegin[] = ">>>>>>> BEGIN MERGE CONFLICT\n"; |
| 150 | static const char zMid[] = "============================\n"; |
| 151 | static const char zEnd[] = "<<<<<<< END MERGE CONFLICT\n"; |
| 152 | |
| 153 | /* Compute the edits that occur from pPivot => pV1 and pPivot => pV2 */ |
| 154 | aC1 = text_diff(pPivot, pV1, 0, 0); |
| 155 | aC2 = text_diff(pPivot, pV2, 0, 0); |
| 156 | if( aC2==0 || aC2==0 ){ |
| 157 | free(aC1); |
| 158 | free(aC2); |
| 159 | return -1; |
| 160 | } |
| 161 | |
| @@ -177,26 +197,33 @@ | |
| 177 | for(i2=0; i2<limit2; i2+=3){ |
| 178 | printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); |
| 179 | } |
| 180 | ) |
| 181 | |
| 182 | i1 = i2 = 0; |
| 183 | while( i1<limit1 && i2<limit2 ){ |
| 184 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 185 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 186 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 187 | |
| 188 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 189 | nCpy = min(aC1[i1], aC2[i2]); |
| 190 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 191 | blob_copy_lines(pOut, pPivot, nCpy); |
| 192 | blob_copy_lines(0, pV1, nCpy); |
| 193 | blob_copy_lines(0, pV2, nCpy); |
| 194 | aC1[i1] -= nCpy; |
| 195 | aC2[i2] -= nCpy; |
| 196 | }else |
| 197 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 198 | nDel = aC2[i2+1]; |
| 199 | nIns = aC2[i2+2]; |
| 200 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 201 | blob_copy_lines(0, pPivot, nDel); |
| 202 | blob_copy_lines(0, pV1, nDel); |
| @@ -203,10 +230,11 @@ | |
| 203 | blob_copy_lines(pOut, pV2, nIns); |
| 204 | aC1[i1] -= nDel; |
| 205 | i2 += 3; |
| 206 | }else |
| 207 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 208 | nDel = aC1[i1+1]; |
| 209 | nIns = aC1[i1+2]; |
| 210 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 211 | blob_copy_lines(0, pPivot, nDel); |
| 212 | blob_copy_lines(0, pV2, nDel); |
| @@ -213,10 +241,11 @@ | |
| 213 | blob_copy_lines(pOut, pV1, nIns); |
| 214 | aC2[i2] -= nDel; |
| 215 | i1 += 3; |
| 216 | }else |
| 217 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 218 | assert( aC1[i1]==0 ); |
| 219 | nDel = aC1[i1+1]; |
| 220 | nIns = aC1[i1+2]; |
| 221 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 222 | blob_copy_lines(0, pPivot, nDel); |
| @@ -224,10 +253,14 @@ | |
| 224 | blob_copy_lines(0, pV2, nIns); |
| 225 | i1 += 3; |
| 226 | i2 += 3; |
| 227 | }else |
| 228 | { |
| 229 | int sz = 1; /* Size of the conflict in lines */ |
| 230 | nConflict++; |
| 231 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 232 | sz++; |
| 233 | } |
| @@ -237,13 +270,22 @@ | |
| 237 | blob_appendf(pOut, zMid); |
| 238 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 239 | blob_appendf(pOut, zEnd); |
| 240 | blob_copy_lines(0, pPivot, sz); |
| 241 | } |
| 242 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| 243 | if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3; |
| 244 | } |
| 245 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 246 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 247 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 248 | if( i1<limit1 && aC1[i1+2]>0 ){ |
| 249 | DEBUG( printf("INSERT +%d left\n", aC1[i1+2]); ) |
| 250 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -37,13 +37,14 @@ | |
| 37 | /* The minimum of two integers */ |
| 38 | #define min(A,B) (A<B?A:B) |
| 39 | |
| 40 | /* |
| 41 | ** Compare N lines of text from pV1 and pV2. If the lines |
| 42 | ** are the same, return true. Return false if one or more of the N |
| 43 | ** lines are different. |
| 44 | ** |
| 45 | ** The cursors on both pV1 and pV2 is unchanged by this comparison. |
| 46 | */ |
| 47 | static int sameLines(Blob *pV1, Blob *pV2, int N){ |
| 48 | char *z1, *z2; |
| 49 | int i; |
| 50 | |
| @@ -58,15 +59,22 @@ | |
| 59 | } |
| 60 | return 0; |
| 61 | } |
| 62 | |
| 63 | /* |
| 64 | ** Look at the next edit triple in both aC1 and aC2. (An "edit triple" is |
| 65 | ** three integers describing the number of copies, deletes, and inserts in |
| 66 | ** moving from the original to the edited copy of the file.) If the three |
| 67 | ** integers of the edit triples describe an identical edit, then return 1. |
| 68 | ** If the edits are different, return 0. |
| 69 | */ |
| 70 | static int sameEdit( |
| 71 | int *aC1, /* Array of edit integers for file 1 */ |
| 72 | int *aC2, /* Array of edit integers for file 2 */ |
| 73 | Blob *pV1, /* Text of file 1 */ |
| 74 | Blob *pV2 /* Text of file 2 */ |
| 75 | ){ |
| 76 | if( aC1[0]!=aC2[0] ) return 0; |
| 77 | if( aC1[1]!=aC2[1] ) return 0; |
| 78 | if( aC1[2]!=aC2[2] ) return 0; |
| 79 | if( sameLines(pV1, pV2, aC1[2]) ) return 1; |
| 80 | return 0; |
| @@ -78,11 +86,11 @@ | |
| 86 | ** |
| 87 | ** (0) The number of lines to copy |
| 88 | ** (1) The number of lines to delete |
| 89 | ** (2) The number of liens to insert |
| 90 | ** |
| 91 | ** Suppose we want to advance over sz lines of the originl file. This routine |
| 92 | ** returns true if that advance would land us on a copy operation. It |
| 93 | ** returns false if the advance would end on a delete. |
| 94 | */ |
| 95 | static int ends_at_CPY(int *aC, int sz){ |
| 96 | while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){ |
| @@ -98,10 +106,15 @@ | |
| 106 | /* |
| 107 | ** pSrc contains an edited file where aC[] describes the edit. Part of |
| 108 | ** pSrc has already been output. This routine outputs additional lines |
| 109 | ** of pSrc - lines that correspond to the next sz lines of the original |
| 110 | ** unedited file. |
| 111 | ** |
| 112 | ** Note that sz counts the number of lines of text in the original file. |
| 113 | ** But text is output from the edited file. So the number of lines transfer |
| 114 | ** to pOut might be different from sz. Fewer lines appear in pOut if there |
| 115 | ** are deletes. More lines appear if there are inserts. |
| 116 | ** |
| 117 | ** The aC[] array is updated and the new index into aC[] is returned. |
| 118 | */ |
| 119 | static int output_one_side( |
| 120 | Blob *pOut, /* Write to this blob */ |
| @@ -148,14 +161,21 @@ | |
| 161 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 162 | static const char zBegin[] = ">>>>>>> BEGIN MERGE CONFLICT\n"; |
| 163 | static const char zMid[] = "============================\n"; |
| 164 | static const char zEnd[] = "<<<<<<< END MERGE CONFLICT\n"; |
| 165 | |
| 166 | /* Compute the edits that occur from pPivot => pV1 (into aC1) |
| 167 | ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is |
| 168 | ** an array of integer triples. Within each triple, the first integer |
| 169 | ** is the number of lines of text to copy directly from the pivot, |
| 170 | ** the second integer is the number of lines of text to omit from the |
| 171 | ** pivot, and the third integer is the number of lines of text that are |
| 172 | ** inserted. The edit array ends with a triple of 0,0,0. |
| 173 | */ |
| 174 | aC1 = text_diff(pPivot, pV1, 0, 0); |
| 175 | aC2 = text_diff(pPivot, pV2, 0, 0); |
| 176 | if( aC1==0 || aC2==0 ){ |
| 177 | free(aC1); |
| 178 | free(aC2); |
| 179 | return -1; |
| 180 | } |
| 181 | |
| @@ -177,26 +197,33 @@ | |
| 197 | for(i2=0; i2<limit2; i2+=3){ |
| 198 | printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); |
| 199 | } |
| 200 | ) |
| 201 | |
| 202 | /* Loop over the two edit vectors and use them to compute merged text |
| 203 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| 204 | ** indices into aC1[] and aC2[] to the edit triple currently being |
| 205 | ** processed |
| 206 | */ |
| 207 | i1 = i2 = 0; |
| 208 | while( i1<limit1 && i2<limit2 ){ |
| 209 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 210 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 211 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 212 | |
| 213 | if( aC1[i1]>0 && aC2[i2]>0 ){ |
| 214 | /* Output text that is unchanged in both V1 and V2 */ |
| 215 | nCpy = min(aC1[i1], aC2[i2]); |
| 216 | DEBUG( printf("COPY %d\n", nCpy); ) |
| 217 | blob_copy_lines(pOut, pPivot, nCpy); |
| 218 | blob_copy_lines(0, pV1, nCpy); |
| 219 | blob_copy_lines(0, pV2, nCpy); |
| 220 | aC1[i1] -= nCpy; |
| 221 | aC2[i2] -= nCpy; |
| 222 | }else |
| 223 | if( aC1[i1] >= aC2[i2+1] && aC1[i1]>0 && aC2[i2+1]+aC2[i2+2]>0 ){ |
| 224 | /* Output edits to V2 that occurs within unchanged regions of V1 */ |
| 225 | nDel = aC2[i2+1]; |
| 226 | nIns = aC2[i2+2]; |
| 227 | DEBUG( printf("EDIT -%d+%d left\n", nDel, nIns); ) |
| 228 | blob_copy_lines(0, pPivot, nDel); |
| 229 | blob_copy_lines(0, pV1, nDel); |
| @@ -203,10 +230,11 @@ | |
| 230 | blob_copy_lines(pOut, pV2, nIns); |
| 231 | aC1[i1] -= nDel; |
| 232 | i2 += 3; |
| 233 | }else |
| 234 | if( aC2[i2] >= aC1[i1+1] && aC2[i2]>0 && aC1[i1+1]+aC1[i1+2]>0 ){ |
| 235 | /* Output edits to V1 that occur within unchanged regions of V2 */ |
| 236 | nDel = aC1[i1+1]; |
| 237 | nIns = aC1[i1+2]; |
| 238 | DEBUG( printf("EDIT -%d+%d right\n", nDel, nIns); ) |
| 239 | blob_copy_lines(0, pPivot, nDel); |
| 240 | blob_copy_lines(0, pV2, nDel); |
| @@ -213,10 +241,11 @@ | |
| 241 | blob_copy_lines(pOut, pV1, nIns); |
| 242 | aC2[i2] -= nDel; |
| 243 | i1 += 3; |
| 244 | }else |
| 245 | if( sameEdit(&aC1[i1], &aC2[i2], pV1, pV2) ){ |
| 246 | /* Output edits that are identical in both V1 and V2. */ |
| 247 | assert( aC1[i1]==0 ); |
| 248 | nDel = aC1[i1+1]; |
| 249 | nIns = aC1[i1+2]; |
| 250 | DEBUG( printf("EDIT -%d+%d both\n", nDel, nIns); ) |
| 251 | blob_copy_lines(0, pPivot, nDel); |
| @@ -224,10 +253,14 @@ | |
| 253 | blob_copy_lines(0, pV2, nIns); |
| 254 | i1 += 3; |
| 255 | i2 += 3; |
| 256 | }else |
| 257 | { |
| 258 | /* We have found a region where different edits to V1 and V2 overlap. |
| 259 | ** This is a merge conflict. Find the size of the conflict, then |
| 260 | ** output both possible edits separate by distinctive marks. |
| 261 | */ |
| 262 | int sz = 1; /* Size of the conflict in lines */ |
| 263 | nConflict++; |
| 264 | while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ |
| 265 | sz++; |
| 266 | } |
| @@ -237,13 +270,22 @@ | |
| 270 | blob_appendf(pOut, zMid); |
| 271 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 272 | blob_appendf(pOut, zEnd); |
| 273 | blob_copy_lines(0, pPivot, sz); |
| 274 | } |
| 275 | |
| 276 | /* If we are finished with an edit triple, advance to the next |
| 277 | ** triple. |
| 278 | */ |
| 279 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| 280 | if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3; |
| 281 | } |
| 282 | |
| 283 | /* When one of the two edit vectors reaches its end, there might still |
| 284 | ** be an insert in the other edit vector. Output this remaining |
| 285 | ** insert. |
| 286 | */ |
| 287 | DEBUG( printf("%d: %2d %2d %2d %d: %2d %2d %2d\n", |
| 288 | i1/3, aC1[i1], aC1[i1+1], aC1[i1+2], |
| 289 | i2/3, aC2[i2], aC2[i2+1], aC2[i2+2]); ) |
| 290 | if( i1<limit1 && aC1[i1+2]>0 ){ |
| 291 | DEBUG( printf("INSERT +%d left\n", aC1[i1+2]); ) |
| 292 |