/framework/Text_Diff/lib/Horde/Text/Diff/ThreeWay.php

https://github.com/finger2000/horde · PHP · 137 lines · 91 code · 14 blank · 32 comment · 25 complexity · f17ea6fd5864f4b7208336db2403bb74 MD5 · raw file

  1. <?php
  2. /**
  3. * A class for computing three way diffs.
  4. *
  5. * Copyright 2007-2011 Horde LLC (http://www.horde.org/)
  6. *
  7. * See the enclosed file COPYING for license information (LGPL). If you did
  8. * not receive this file, see http://www.horde.org/licenses/lgpl21.
  9. *
  10. * @package Text_Diff
  11. * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
  12. */
  13. class Horde_Text_Diff_ThreeWay extends Horde_Text_Diff
  14. {
  15. /**
  16. * Conflict counter.
  17. *
  18. * @var integer
  19. */
  20. protected $_conflictingBlocks = 0;
  21. /**
  22. * Computes diff between 3 sequences of strings.
  23. *
  24. * @param array $orig The original lines to use.
  25. * @param array $final1 The first version to compare to.
  26. * @param array $final2 The second version to compare to.
  27. */
  28. public function __construct($orig, $final1, $final2)
  29. {
  30. if (extension_loaded('xdiff')) {
  31. $engine = new Horde_Text_Diff_Engine_xdiff();
  32. } else {
  33. $engine = new Horde_Text_Diff_Engine_native();
  34. }
  35. $this->_edits = $this->_diff3($engine->diff($orig, $final1),
  36. $engine->diff($orig, $final2));
  37. }
  38. /**
  39. */
  40. public function mergedOutput($label1 = false, $label2 = false)
  41. {
  42. $lines = array();
  43. foreach ($this->_edits as $edit) {
  44. if ($edit->isConflict()) {
  45. /* FIXME: this should probably be moved somewhere else. */
  46. $lines = array_merge($lines,
  47. array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')),
  48. $edit->final1,
  49. array("======="),
  50. $edit->final2,
  51. array('>>>>>>>' . ($label2 ? ' ' . $label2 : '')));
  52. $this->_conflictingBlocks++;
  53. } else {
  54. $lines = array_merge($lines, $edit->merged());
  55. }
  56. }
  57. return $lines;
  58. }
  59. /**
  60. * @access private
  61. */
  62. protected function _diff3($edits1, $edits2)
  63. {
  64. $edits = array();
  65. $bb = new Horde_Text_Diff_ThreeWay_BlockBuilder();
  66. $e1 = current($edits1);
  67. $e2 = current($edits2);
  68. while ($e1 || $e2) {
  69. if ($e1 && $e2 &&
  70. $e1 instanceof Horde_Text_Diff_Op_Copy &&
  71. $e2 instanceof Horde_Text_Diff_Op_Copy) {
  72. /* We have copy blocks from both diffs. This is the (only)
  73. * time we want to emit a diff3 copy block. Flush current
  74. * diff3 diff block, if any. */
  75. if ($edit = $bb->finish()) {
  76. $edits[] = $edit;
  77. }
  78. $ncopy = min($e1->norig(), $e2->norig());
  79. assert($ncopy > 0);
  80. $edits[] = new Horde_Text_Diff_ThreeWay_Op_Copy(array_slice($e1->orig, 0, $ncopy));
  81. if ($e1->norig() > $ncopy) {
  82. array_splice($e1->orig, 0, $ncopy);
  83. array_splice($e1->final, 0, $ncopy);
  84. } else {
  85. $e1 = next($edits1);
  86. }
  87. if ($e2->norig() > $ncopy) {
  88. array_splice($e2->orig, 0, $ncopy);
  89. array_splice($e2->final, 0, $ncopy);
  90. } else {
  91. $e2 = next($edits2);
  92. }
  93. } else {
  94. if ($e1 && $e2) {
  95. if ($e1->orig && $e2->orig) {
  96. $norig = min($e1->norig(), $e2->norig());
  97. $orig = array_splice($e1->orig, 0, $norig);
  98. array_splice($e2->orig, 0, $norig);
  99. $bb->input($orig);
  100. }
  101. if ($e1 instanceof Horde_Text_Diff_Op_Copy) {
  102. $bb->out1(array_splice($e1->final, 0, $norig));
  103. }
  104. if ($e2 instanceof Horde_Text_Diff_Op_Copy) {
  105. $bb->out2(array_splice($e2->final, 0, $norig));
  106. }
  107. }
  108. if ($e1 && ! $e1->orig) {
  109. $bb->out1($e1->final);
  110. $e1 = next($edits1);
  111. }
  112. if ($e2 && ! $e2->orig) {
  113. $bb->out2($e2->final);
  114. $e2 = next($edits2);
  115. }
  116. }
  117. }
  118. if ($edit = $bb->finish()) {
  119. $edits[] = $edit;
  120. }
  121. return $edits;
  122. }
  123. }