Fossil SCM

Add a --tcl option to the 3-way-merge command.

drh 2024-11-28 19:13 merge-enhancements
Commit 97ab5604ea9fbde58c3d320fc6ef5b9a08637152c1b2ccb00d62863d7c3420bc
2 files changed +1 -1 +187 -7
+1 -1
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
11
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
22
# to this file, then runs this file using "tclsh" in order to display the
33
# graphical diff in a separate window. A typical "set fossilcmd" line
44
# looks like this:
55
#
6
-# set fossilcmd {| "./fossil" diff --html -y -i -v}
6
+# set fossilcmd {| "./fossil" diff --tcl -i -v}
77
#
88
# This header comment is stripped off by the "mkbuiltin.c" program.
99
#
1010
set prog {
1111
package require Tk
1212
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
1 # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2 # to this file, then runs this file using "tclsh" in order to display the
3 # graphical diff in a separate window. A typical "set fossilcmd" line
4 # looks like this:
5 #
6 # set fossilcmd {| "./fossil" diff --html -y -i -v}
7 #
8 # This header comment is stripped off by the "mkbuiltin.c" program.
9 #
10 set prog {
11 package require Tk
12
--- src/diff.tcl
+++ src/diff.tcl
@@ -1,11 +1,11 @@
1 # The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
2 # to this file, then runs this file using "tclsh" in order to display the
3 # graphical diff in a separate window. A typical "set fossilcmd" line
4 # looks like this:
5 #
6 # set fossilcmd {| "./fossil" diff --tcl -i -v}
7 #
8 # This header comment is stripped off by the "mkbuiltin.c" program.
9 #
10 set prog {
11 package require Tk
12
+187 -7
--- src/merge3.c
+++ src/merge3.c
@@ -277,11 +277,10 @@
277277
p->xConflict = dbgConflict;
278278
p->xEnd = dbgStartEnd;
279279
p->xDestroy = dbgDestroy;
280280
}
281281
282
-
283282
/************************* MergeBuilderText **********************************/
284283
/* This version of MergeBuilder actually performs a merge on file and puts
285284
** the result in pOut
286285
*/
287286
static void txtStart(MergeBuilder *p){
@@ -341,10 +340,188 @@
341340
p->xChngV1 = txtChngV1;
342341
p->xChngV2 = txtChngV2;
343342
p->xChngBoth = txtChngBoth;
344343
p->xConflict = txtConflict;
345344
}
345
+
346
+/************************* MergeBuilderTcl **********************************/
347
+/* Generate merge output formatted for reading by a TCL script.
348
+**
349
+** The output consists of lines of text, each with 4 tokens. The tokens
350
+** represent the content for one line from baseline, v1, v2, and output
351
+** respectively. The first character of each token provides auxiliary
352
+** information:
353
+**
354
+** . This line is omitted.
355
+** T Literal text follows that should have a \n terminator.
356
+** R Literal text follows that needs a \r\n terminator.
357
+** Z Literal text without a line terminator.
358
+** 1 Text is a copy of token 1
359
+** 2 Use data from data-token 2
360
+** 3 Use data from data-token 3
361
+*/
362
+
363
+/* Copy one line of text from pIn and append to pOut, encoded as TCL */
364
+static void tclLineOfText(Blob *pOut, Blob *pIn){
365
+ int i, j, k;
366
+ for(i=pIn->iCursor; i<pIn->nUsed && pIn->aData[i]!='\n'; i++){}
367
+ if( i==pIn->nUsed ){
368
+ blob_append(pOut, "\"Z", 2);
369
+ k = i;
370
+ }else if( i>pIn->iCursor && pIn->aData[i-1]=='\r' ){
371
+ blob_append(pOut, "\"R", 2);
372
+ k = i-1;
373
+ i++;
374
+ }else{
375
+ blob_append(pOut, "\"T", 2);
376
+ k = i;
377
+ i++;
378
+ }
379
+ for(j=pIn->iCursor; j<k; j++){
380
+ char c = pIn->aData[j];
381
+ if( c=='\\' ){
382
+ blob_append(pOut, "\\\\", 2);
383
+ }else if( c=='"' ){
384
+ blob_append(pOut, "\\\"", 2);
385
+ }else if( c<' ' || c>0x7e ){
386
+ char z[5];
387
+ z[0] = '\\';
388
+ z[1] = "01234567"[(c>>6)&0x3];
389
+ z[2] = "01234567"[(c>>3)&0x7];
390
+ z[3] = "01234567"[c&0x7];
391
+ z[4] = 0;
392
+ blob_append(pOut, z, 4);
393
+ }else{
394
+ blob_append_char(pOut, c);
395
+ }
396
+ }
397
+ pIn->iCursor = i;
398
+ blob_append_char(pOut, '"');
399
+}
400
+static void tclSame(MergeBuilder *p, unsigned int N){
401
+ int i;
402
+ for(i=0; i<N; i++){
403
+ tclLineOfText(p->pOut, p->pPivot);
404
+ blob_append(p->pOut, " 1 1 1\n", 7);
405
+ }
406
+ p->lnPivot += N;
407
+ p->lnV1 += N;
408
+ p->lnV2 += N;
409
+ blob_copy_lines(0, p->pV1, N);
410
+ blob_copy_lines(0, p->pV2, N);
411
+}
412
+static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
413
+ int i;
414
+ for(i=0; i<nPivot && i<nV1; i++){
415
+ tclLineOfText(p->pOut, p->pPivot);
416
+ blob_append_char(p->pOut, ' ');
417
+ tclLineOfText(p->pOut, p->pV1);
418
+ blob_append(p->pOut, " 1 2\n", 5);
419
+ }
420
+ while( i<nPivot ){
421
+ tclLineOfText(p->pOut, p->pPivot);
422
+ blob_append(p->pOut, " . 1 .\n", 7);
423
+ i++;
424
+ }
425
+ while( i<nV1 ){
426
+ blob_append(p->pOut, ". ", 2);
427
+ tclLineOfText(p->pOut, p->pV1);
428
+ blob_append(p->pOut, " . 2\n", 5);
429
+ i++;
430
+ }
431
+ p->lnPivot += nPivot;
432
+ p->lnV1 += nV1;
433
+ p->lnV2 += nPivot;
434
+ blob_copy_lines(0, p->pV2, nPivot);
435
+}
436
+static void tclChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
437
+ int i;
438
+ for(i=0; i<nPivot && i<nV2; i++){
439
+ tclLineOfText(p->pOut, p->pPivot);
440
+ blob_append(p->pOut, " 1 ", 3);
441
+ tclLineOfText(p->pOut, p->pV2);
442
+ blob_append(p->pOut, " 3\n", 3);
443
+ }
444
+ while( i<nPivot ){
445
+ tclLineOfText(p->pOut, p->pPivot);
446
+ blob_append(p->pOut, " 1 . .\n", 7);
447
+ i++;
448
+ }
449
+ while( i<nV2 ){
450
+ blob_append(p->pOut, ". . ", 4);
451
+ tclLineOfText(p->pOut, p->pV2);
452
+ blob_append(p->pOut, " 3\n", 3);
453
+ i++;
454
+ }
455
+ p->lnPivot += nPivot;
456
+ p->lnV1 += nPivot;
457
+ p->lnV2 += nV2;
458
+ blob_copy_lines(0, p->pV1, nPivot);
459
+}
460
+static void tclChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
461
+ int i;
462
+ for(i=0; i<nPivot && i<nV; i++){
463
+ tclLineOfText(p->pOut, p->pPivot);
464
+ blob_append_char(p->pOut, ' ');
465
+ tclLineOfText(p->pOut, p->pV1);
466
+ blob_append(p->pOut, " 2 2\n", 5);
467
+ }
468
+ while( i<nPivot ){
469
+ tclLineOfText(p->pOut, p->pPivot);
470
+ blob_append(p->pOut, " . . .\n", 7);
471
+ i++;
472
+ }
473
+ while( i<nV ){
474
+ blob_append(p->pOut, ". ", 2);
475
+ tclLineOfText(p->pOut, p->pV1);
476
+ blob_append(p->pOut, " 2 2\n", 5);
477
+ i++;
478
+ }
479
+ p->lnPivot += nPivot;
480
+ p->lnV1 += nV;
481
+ p->lnV2 += nV;
482
+ blob_copy_lines(0, p->pV2, nV);
483
+}
484
+static void tclConflict(
485
+ MergeBuilder *p,
486
+ unsigned int nPivot,
487
+ unsigned int nV1,
488
+ unsigned int nV2
489
+){
490
+ int mx = nPivot;
491
+ int i;
492
+ if( nV1>mx ) mx = nV1;
493
+ if( nV2>mx ) mx = nV2;
494
+ for(i=0; i<mx; i++){
495
+ if( i<nPivot ){
496
+ tclLineOfText(p->pOut, p->pPivot);
497
+ }else{
498
+ blob_append_char(p->pOut, '.');
499
+ }
500
+ blob_append_char(p->pOut, ' ');
501
+ if( i<nV1 ){
502
+ tclLineOfText(p->pOut, p->pV1);
503
+ }else{
504
+ blob_append_char(p->pOut, '.');
505
+ }
506
+ blob_append_char(p->pOut, ' ');
507
+ if( i<nV2 ){
508
+ tclLineOfText(p->pOut, p->pV2);
509
+ }else{
510
+ blob_append_char(p->pOut, '.');
511
+ }
512
+ blob_append(p->pOut, " X\n", 3);
513
+ }
514
+}
515
+static void mergebuilder_init_tcl(MergeBuilder *p){
516
+ mergebuilder_init(p);
517
+ p->xSame = tclSame;
518
+ p->xChngV1 = tclChngV1;
519
+ p->xChngV2 = tclChngV2;
520
+ p->xChngBoth = tclChngBoth;
521
+ p->xConflict = tclConflict;
522
+}
346523
/*****************************************************************************/
347524
348525
/*
349526
** aC[] is an "edit triple" for changes from A to B. Advance through
350527
** this triple to determine the number of lines to bypass on B in order
@@ -381,11 +558,11 @@
381558
** The return is 0 upon complete success. If any input file is binary,
382559
** -1 is returned and pOut is unmodified. If there are merge
383560
** conflicts, the merge proceeds as best as it can and the number
384561
** of conflicts is returns
385562
*/
386
-static int blob_merge(MergeBuilder *p){
563
+static int merge_three_blobs(MergeBuilder *p){
387564
int *aC1; /* Changes from pPivot to pV1 */
388565
int *aC2; /* Changes from pPivot to pV2 */
389566
int i1, i2; /* Index into aC1[] and aC2[] */
390567
int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
391568
int limit1, limit2; /* Sizes of aC1[] and aC2[] */
@@ -573,10 +750,13 @@
573750
Blob pivot, v1, v2, out;
574751
575752
mergebuilder_init_text(&s);
576753
if( find_option("debug", 0, 0) ){
577754
mergebuilder_init(&s);
755
+ }
756
+ if( find_option("tcl", 0, 0) ){
757
+ mergebuilder_init_tcl(&s);
578758
}
579759
blob_zero(&pivot); s.pPivot = &pivot;
580760
blob_zero(&v1); s.pV1 = &v1;
581761
blob_zero(&v2); s.pV2 = &v2;
582762
blob_zero(&out); s.pOut = &out;
@@ -594,11 +774,11 @@
594774
fossil_fatal("cannot read %s", g.argv[3]);
595775
}
596776
if( blob_read_from_file(s.pV2, g.argv[4], ExtFILE)<0 ){
597777
fossil_fatal("cannot read %s", g.argv[4]);
598778
}
599
- nConflict = blob_merge(&s);
779
+ nConflict = merge_three_blobs(&s);
600780
if( g.argc==6 ){
601781
blob_write_to_file(s.pOut, g.argv[5]);
602782
}else{
603783
blob_write_to_file(s.pOut, "-");
604784
}
@@ -658,21 +838,21 @@
658838
#define MERGE_KEEP_FILES 0x0002
659839
#endif
660840
661841
662842
/*
663
-** This routine is a wrapper around blob_merge() with the following
843
+** This routine is a wrapper around merge_three_blobs() with the following
664844
** enhancements:
665845
**
666846
** (1) If the merge-command is defined, then use the external merging
667847
** program specified instead of the built-in blob-merge to do the
668848
** merging. Panic if the external merger fails.
669849
** ** Not currently implemented **
670850
**
671851
** (2) If gmerge-command is defined and there are merge conflicts in
672
-** blob_merge() then invoke the external graphical merger to resolve
673
-** the conflicts.
852
+** merge_three_blobs() then invoke the external graphical merger
853
+** to resolve the conflicts.
674854
**
675855
** (3) If a merge conflict occurs and gmerge-command is not defined,
676856
** then write the pivot, original, and merge-in files to the
677857
** filesystem.
678858
*/
@@ -693,11 +873,11 @@
693873
s.pV1 = &v1;
694874
s.pV2 = pV2;
695875
blob_zero(pOut);
696876
s.pOut = pOut;
697877
blob_read_from_file(s.pV1, zV1, ExtFILE);
698
- rc = blob_merge(&s);
878
+ rc = merge_three_blobs(&s);
699879
zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
700880
if( (mergeFlags & MERGE_DRYRUN)==0
701881
&& ((zGMerge!=0 && zGMerge[0]!=0)
702882
|| (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
703883
char *zPivot; /* Name of the pivot file */
704884
--- src/merge3.c
+++ src/merge3.c
@@ -277,11 +277,10 @@
277 p->xConflict = dbgConflict;
278 p->xEnd = dbgStartEnd;
279 p->xDestroy = dbgDestroy;
280 }
281
282
283 /************************* MergeBuilderText **********************************/
284 /* This version of MergeBuilder actually performs a merge on file and puts
285 ** the result in pOut
286 */
287 static void txtStart(MergeBuilder *p){
@@ -341,10 +340,188 @@
341 p->xChngV1 = txtChngV1;
342 p->xChngV2 = txtChngV2;
343 p->xChngBoth = txtChngBoth;
344 p->xConflict = txtConflict;
345 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346 /*****************************************************************************/
347
348 /*
349 ** aC[] is an "edit triple" for changes from A to B. Advance through
350 ** this triple to determine the number of lines to bypass on B in order
@@ -381,11 +558,11 @@
381 ** The return is 0 upon complete success. If any input file is binary,
382 ** -1 is returned and pOut is unmodified. If there are merge
383 ** conflicts, the merge proceeds as best as it can and the number
384 ** of conflicts is returns
385 */
386 static int blob_merge(MergeBuilder *p){
387 int *aC1; /* Changes from pPivot to pV1 */
388 int *aC2; /* Changes from pPivot to pV2 */
389 int i1, i2; /* Index into aC1[] and aC2[] */
390 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
391 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
@@ -573,10 +750,13 @@
573 Blob pivot, v1, v2, out;
574
575 mergebuilder_init_text(&s);
576 if( find_option("debug", 0, 0) ){
577 mergebuilder_init(&s);
 
 
 
578 }
579 blob_zero(&pivot); s.pPivot = &pivot;
580 blob_zero(&v1); s.pV1 = &v1;
581 blob_zero(&v2); s.pV2 = &v2;
582 blob_zero(&out); s.pOut = &out;
@@ -594,11 +774,11 @@
594 fossil_fatal("cannot read %s", g.argv[3]);
595 }
596 if( blob_read_from_file(s.pV2, g.argv[4], ExtFILE)<0 ){
597 fossil_fatal("cannot read %s", g.argv[4]);
598 }
599 nConflict = blob_merge(&s);
600 if( g.argc==6 ){
601 blob_write_to_file(s.pOut, g.argv[5]);
602 }else{
603 blob_write_to_file(s.pOut, "-");
604 }
@@ -658,21 +838,21 @@
658 #define MERGE_KEEP_FILES 0x0002
659 #endif
660
661
662 /*
663 ** This routine is a wrapper around blob_merge() with the following
664 ** enhancements:
665 **
666 ** (1) If the merge-command is defined, then use the external merging
667 ** program specified instead of the built-in blob-merge to do the
668 ** merging. Panic if the external merger fails.
669 ** ** Not currently implemented **
670 **
671 ** (2) If gmerge-command is defined and there are merge conflicts in
672 ** blob_merge() then invoke the external graphical merger to resolve
673 ** the conflicts.
674 **
675 ** (3) If a merge conflict occurs and gmerge-command is not defined,
676 ** then write the pivot, original, and merge-in files to the
677 ** filesystem.
678 */
@@ -693,11 +873,11 @@
693 s.pV1 = &v1;
694 s.pV2 = pV2;
695 blob_zero(pOut);
696 s.pOut = pOut;
697 blob_read_from_file(s.pV1, zV1, ExtFILE);
698 rc = blob_merge(&s);
699 zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
700 if( (mergeFlags & MERGE_DRYRUN)==0
701 && ((zGMerge!=0 && zGMerge[0]!=0)
702 || (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
703 char *zPivot; /* Name of the pivot file */
704
--- src/merge3.c
+++ src/merge3.c
@@ -277,11 +277,10 @@
277 p->xConflict = dbgConflict;
278 p->xEnd = dbgStartEnd;
279 p->xDestroy = dbgDestroy;
280 }
281
 
282 /************************* MergeBuilderText **********************************/
283 /* This version of MergeBuilder actually performs a merge on file and puts
284 ** the result in pOut
285 */
286 static void txtStart(MergeBuilder *p){
@@ -341,10 +340,188 @@
340 p->xChngV1 = txtChngV1;
341 p->xChngV2 = txtChngV2;
342 p->xChngBoth = txtChngBoth;
343 p->xConflict = txtConflict;
344 }
345
346 /************************* MergeBuilderTcl **********************************/
347 /* Generate merge output formatted for reading by a TCL script.
348 **
349 ** The output consists of lines of text, each with 4 tokens. The tokens
350 ** represent the content for one line from baseline, v1, v2, and output
351 ** respectively. The first character of each token provides auxiliary
352 ** information:
353 **
354 ** . This line is omitted.
355 ** T Literal text follows that should have a \n terminator.
356 ** R Literal text follows that needs a \r\n terminator.
357 ** Z Literal text without a line terminator.
358 ** 1 Text is a copy of token 1
359 ** 2 Use data from data-token 2
360 ** 3 Use data from data-token 3
361 */
362
363 /* Copy one line of text from pIn and append to pOut, encoded as TCL */
364 static void tclLineOfText(Blob *pOut, Blob *pIn){
365 int i, j, k;
366 for(i=pIn->iCursor; i<pIn->nUsed && pIn->aData[i]!='\n'; i++){}
367 if( i==pIn->nUsed ){
368 blob_append(pOut, "\"Z", 2);
369 k = i;
370 }else if( i>pIn->iCursor && pIn->aData[i-1]=='\r' ){
371 blob_append(pOut, "\"R", 2);
372 k = i-1;
373 i++;
374 }else{
375 blob_append(pOut, "\"T", 2);
376 k = i;
377 i++;
378 }
379 for(j=pIn->iCursor; j<k; j++){
380 char c = pIn->aData[j];
381 if( c=='\\' ){
382 blob_append(pOut, "\\\\", 2);
383 }else if( c=='"' ){
384 blob_append(pOut, "\\\"", 2);
385 }else if( c<' ' || c>0x7e ){
386 char z[5];
387 z[0] = '\\';
388 z[1] = "01234567"[(c>>6)&0x3];
389 z[2] = "01234567"[(c>>3)&0x7];
390 z[3] = "01234567"[c&0x7];
391 z[4] = 0;
392 blob_append(pOut, z, 4);
393 }else{
394 blob_append_char(pOut, c);
395 }
396 }
397 pIn->iCursor = i;
398 blob_append_char(pOut, '"');
399 }
400 static void tclSame(MergeBuilder *p, unsigned int N){
401 int i;
402 for(i=0; i<N; i++){
403 tclLineOfText(p->pOut, p->pPivot);
404 blob_append(p->pOut, " 1 1 1\n", 7);
405 }
406 p->lnPivot += N;
407 p->lnV1 += N;
408 p->lnV2 += N;
409 blob_copy_lines(0, p->pV1, N);
410 blob_copy_lines(0, p->pV2, N);
411 }
412 static void tclChngV1(MergeBuilder *p, unsigned int nPivot, unsigned int nV1){
413 int i;
414 for(i=0; i<nPivot && i<nV1; i++){
415 tclLineOfText(p->pOut, p->pPivot);
416 blob_append_char(p->pOut, ' ');
417 tclLineOfText(p->pOut, p->pV1);
418 blob_append(p->pOut, " 1 2\n", 5);
419 }
420 while( i<nPivot ){
421 tclLineOfText(p->pOut, p->pPivot);
422 blob_append(p->pOut, " . 1 .\n", 7);
423 i++;
424 }
425 while( i<nV1 ){
426 blob_append(p->pOut, ". ", 2);
427 tclLineOfText(p->pOut, p->pV1);
428 blob_append(p->pOut, " . 2\n", 5);
429 i++;
430 }
431 p->lnPivot += nPivot;
432 p->lnV1 += nV1;
433 p->lnV2 += nPivot;
434 blob_copy_lines(0, p->pV2, nPivot);
435 }
436 static void tclChngV2(MergeBuilder *p, unsigned int nPivot, unsigned int nV2){
437 int i;
438 for(i=0; i<nPivot && i<nV2; i++){
439 tclLineOfText(p->pOut, p->pPivot);
440 blob_append(p->pOut, " 1 ", 3);
441 tclLineOfText(p->pOut, p->pV2);
442 blob_append(p->pOut, " 3\n", 3);
443 }
444 while( i<nPivot ){
445 tclLineOfText(p->pOut, p->pPivot);
446 blob_append(p->pOut, " 1 . .\n", 7);
447 i++;
448 }
449 while( i<nV2 ){
450 blob_append(p->pOut, ". . ", 4);
451 tclLineOfText(p->pOut, p->pV2);
452 blob_append(p->pOut, " 3\n", 3);
453 i++;
454 }
455 p->lnPivot += nPivot;
456 p->lnV1 += nPivot;
457 p->lnV2 += nV2;
458 blob_copy_lines(0, p->pV1, nPivot);
459 }
460 static void tclChngBoth(MergeBuilder *p, unsigned int nPivot, unsigned int nV){
461 int i;
462 for(i=0; i<nPivot && i<nV; i++){
463 tclLineOfText(p->pOut, p->pPivot);
464 blob_append_char(p->pOut, ' ');
465 tclLineOfText(p->pOut, p->pV1);
466 blob_append(p->pOut, " 2 2\n", 5);
467 }
468 while( i<nPivot ){
469 tclLineOfText(p->pOut, p->pPivot);
470 blob_append(p->pOut, " . . .\n", 7);
471 i++;
472 }
473 while( i<nV ){
474 blob_append(p->pOut, ". ", 2);
475 tclLineOfText(p->pOut, p->pV1);
476 blob_append(p->pOut, " 2 2\n", 5);
477 i++;
478 }
479 p->lnPivot += nPivot;
480 p->lnV1 += nV;
481 p->lnV2 += nV;
482 blob_copy_lines(0, p->pV2, nV);
483 }
484 static void tclConflict(
485 MergeBuilder *p,
486 unsigned int nPivot,
487 unsigned int nV1,
488 unsigned int nV2
489 ){
490 int mx = nPivot;
491 int i;
492 if( nV1>mx ) mx = nV1;
493 if( nV2>mx ) mx = nV2;
494 for(i=0; i<mx; i++){
495 if( i<nPivot ){
496 tclLineOfText(p->pOut, p->pPivot);
497 }else{
498 blob_append_char(p->pOut, '.');
499 }
500 blob_append_char(p->pOut, ' ');
501 if( i<nV1 ){
502 tclLineOfText(p->pOut, p->pV1);
503 }else{
504 blob_append_char(p->pOut, '.');
505 }
506 blob_append_char(p->pOut, ' ');
507 if( i<nV2 ){
508 tclLineOfText(p->pOut, p->pV2);
509 }else{
510 blob_append_char(p->pOut, '.');
511 }
512 blob_append(p->pOut, " X\n", 3);
513 }
514 }
515 static void mergebuilder_init_tcl(MergeBuilder *p){
516 mergebuilder_init(p);
517 p->xSame = tclSame;
518 p->xChngV1 = tclChngV1;
519 p->xChngV2 = tclChngV2;
520 p->xChngBoth = tclChngBoth;
521 p->xConflict = tclConflict;
522 }
523 /*****************************************************************************/
524
525 /*
526 ** aC[] is an "edit triple" for changes from A to B. Advance through
527 ** this triple to determine the number of lines to bypass on B in order
@@ -381,11 +558,11 @@
558 ** The return is 0 upon complete success. If any input file is binary,
559 ** -1 is returned and pOut is unmodified. If there are merge
560 ** conflicts, the merge proceeds as best as it can and the number
561 ** of conflicts is returns
562 */
563 static int merge_three_blobs(MergeBuilder *p){
564 int *aC1; /* Changes from pPivot to pV1 */
565 int *aC2; /* Changes from pPivot to pV2 */
566 int i1, i2; /* Index into aC1[] and aC2[] */
567 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */
568 int limit1, limit2; /* Sizes of aC1[] and aC2[] */
@@ -573,10 +750,13 @@
750 Blob pivot, v1, v2, out;
751
752 mergebuilder_init_text(&s);
753 if( find_option("debug", 0, 0) ){
754 mergebuilder_init(&s);
755 }
756 if( find_option("tcl", 0, 0) ){
757 mergebuilder_init_tcl(&s);
758 }
759 blob_zero(&pivot); s.pPivot = &pivot;
760 blob_zero(&v1); s.pV1 = &v1;
761 blob_zero(&v2); s.pV2 = &v2;
762 blob_zero(&out); s.pOut = &out;
@@ -594,11 +774,11 @@
774 fossil_fatal("cannot read %s", g.argv[3]);
775 }
776 if( blob_read_from_file(s.pV2, g.argv[4], ExtFILE)<0 ){
777 fossil_fatal("cannot read %s", g.argv[4]);
778 }
779 nConflict = merge_three_blobs(&s);
780 if( g.argc==6 ){
781 blob_write_to_file(s.pOut, g.argv[5]);
782 }else{
783 blob_write_to_file(s.pOut, "-");
784 }
@@ -658,21 +838,21 @@
838 #define MERGE_KEEP_FILES 0x0002
839 #endif
840
841
842 /*
843 ** This routine is a wrapper around merge_three_blobs() with the following
844 ** enhancements:
845 **
846 ** (1) If the merge-command is defined, then use the external merging
847 ** program specified instead of the built-in blob-merge to do the
848 ** merging. Panic if the external merger fails.
849 ** ** Not currently implemented **
850 **
851 ** (2) If gmerge-command is defined and there are merge conflicts in
852 ** merge_three_blobs() then invoke the external graphical merger
853 ** to resolve the conflicts.
854 **
855 ** (3) If a merge conflict occurs and gmerge-command is not defined,
856 ** then write the pivot, original, and merge-in files to the
857 ** filesystem.
858 */
@@ -693,11 +873,11 @@
873 s.pV1 = &v1;
874 s.pV2 = pV2;
875 blob_zero(pOut);
876 s.pOut = pOut;
877 blob_read_from_file(s.pV1, zV1, ExtFILE);
878 rc = merge_three_blobs(&s);
879 zGMerge = rc<=0 ? 0 : db_get("gmerge-command", 0);
880 if( (mergeFlags & MERGE_DRYRUN)==0
881 && ((zGMerge!=0 && zGMerge[0]!=0)
882 || (rc!=0 && (mergeFlags & MERGE_KEEP_FILES)!=0)) ){
883 char *zPivot; /* Name of the pivot file */
884

Keyboard Shortcuts

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