[ Index ]
 

Code source de WikiNi 0.4.4

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/handlers/page/ -> diff.php (source)

   1  <?php
   2  /*
   3  diff.php
   4  
   5  Copyright (C) 1992 Free Software Foundation, Inc. Francois Pinard <pinard@iro.umontreal.ca>.
   6  Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
   7  Copyright 2002,2003,2004  David DELON
   8  Copyright 2002  Patrick PAUL
   9  Copyright 2003  Eric FELDSTEIN
  10  
  11  This program is free software; you can redistribute it and/or modify
  12  it under the terms of the GNU General Public License as published by
  13  the Free Software Foundation; either version 2 of the License, or
  14  (at your option) any later version.
  15  
  16  This program is distributed in the hope that it will be useful,
  17  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19  GNU General Public License for more details.
  20  
  21  You should have received a copy of the GNU General Public License
  22  along with this program; if not, write to the Free Software
  23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24  
  25  original diff.php
  26  Copyright (c) 2002, Hendrik Mans <hendrik@mans.de>
  27  All rights reserved.
  28  Redistribution and use in source and binary forms, with or without
  29  modification, are permitted provided that the following conditions
  30  are met:
  31  1. Redistributions of source code must retain the above copyright
  32  notice, this list of conditions and the following disclaimer.
  33  2. Redistributions in binary form must reproduce the above copyright
  34  notice, this list of conditions and the following disclaimer in the
  35  documentation and/or other materials provided with the distribution.
  36  3. The name of the author may not be used to endorse or promote products
  37  derived from this software without specific prior written permission.
  38  
  39  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  40  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  41  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  42  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  43  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  44  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  45  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  46  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  47  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  48  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  49  */
  50  
  51  
  52  //vérification de sécurité
  53  if (!eregi("wakka.php", $_SERVER['PHP_SELF'])) {
  54      die ("acc&egrave;s direct interdit");
  55  }
  56  echo $this->Header();
  57  ?>
  58  <div class="page">
  59  <?php
  60  
  61  if ($this->HasAccess("read")) 
  62  {
  63  
  64  // If asked, call original diff 
  65  
  66      if (!empty($_REQUEST["fastdiff"])) {
  67         
  68          /* NOTE: This is a really cheap way to do it. I think it may be more intelligent to write the two pages to temporary files and run /usr/bin/diff over them. Then again, maybe not.        */ 
  69          // load pages
  70            $pageA = $this->LoadPageById($_REQUEST["a"]);
  71            $pageB = $this->LoadPageById($_REQUEST["b"]);
  72      
  73          // prepare bodies
  74            $bodyA = explode("\n", $pageA["body"]);
  75            $bodyB = explode("\n", $pageB["body"]);
  76      
  77            $added = array_diff($bodyA, $bodyB);
  78            $deleted = array_diff($bodyB, $bodyA);
  79      
  80            $output .= "<b>Comparaison de <a href=\"".$this->href("", "", "time=".urlencode($pageA["time"]))."\">".$pageA["time"]."</a> &agrave; <a href=\"".$this->href("", "", "time=".urlencode($pageB["time"]))."\">".$pageB["time"]."</a></b><br />\n";
  81      
  82            if ($added)
  83            {
  84              // remove blank lines
  85              $output .= "<br />\n<b>Ajouts:</b><br />\n";
  86              $output .= "<div class=\"additions\">".$this->Format(implode("\n", $added))."</div>";
  87            }
  88      
  89            if ($deleted)
  90            {
  91              $output .= "<br />\n<b>Suppressions:</b><br />\n";
  92              $output .= "<div class=\"deletions\">".$this->Format(implode("\n", $deleted))."</div>";
  93            }
  94      
  95            if (!$added && !$deleted)
  96            {
  97              $output .= "<br />\nPas de diff&eacute;rences.";
  98            }
  99            echo $output;
 100      
 101      }
 102      
 103      else {
 104      
 105      // load pages
 106      
 107          $pageA = $this->LoadPageById($_REQUEST["b"]);
 108          $pageB = $this->LoadPageById($_REQUEST["a"]);
 109      
 110          // extract text from bodies
 111          $textA = $pageA["body"];
 112          $textB = $pageB["body"];
 113      
 114          $sideA = new Side($textA);
 115          $sideB = new Side($textB);
 116      
 117          $bodyA='';
 118          $sideA->split_file_into_words($bodyA);
 119      
 120          $bodyB='';
 121          $sideB->split_file_into_words($bodyB);
 122      
 123          // diff on these two file
 124          $diff = new Diff(split("\n",$bodyA),split("\n",$bodyB));
 125      
 126          // format output
 127          $fmt = new DiffFormatter();
 128      
 129          $sideO = new Side($fmt->format($diff));
 130      
 131          $resync_left=0;
 132          $resync_right=0;
 133      
 134          $count_total_right=$sideB->getposition() ;
 135      
 136          $sideA->init();
 137          $sideB->init();
 138      
 139          $output='';
 140      
 141            while (1) {
 142                 
 143                $sideO->skip_line();
 144                if ($sideO->isend()) {
 145                break;
 146                }
 147      
 148                if ($sideO->decode_directive_line()) {
 149              $argument=$sideO->getargument();
 150              $letter=$sideO->getdirective();
 151                switch ($letter) {
 152                  case 'a':
 153                    $resync_left = $argument[0];
 154                    $resync_right = $argument[2] - 1;
 155                    break;
 156      
 157                  case 'd':
 158                    $resync_left = $argument[0] - 1;
 159                    $resync_right = $argument[2];
 160                    break;
 161      
 162                  case 'c':
 163                    $resync_left = $argument[0] - 1;
 164                    $resync_right = $argument[2] - 1;
 165                    break;
 166      
 167                  }
 168      
 169                  $sideA->skip_until_ordinal($resync_left);
 170                  $sideB->copy_until_ordinal($resync_right,$output);
 171        
 172      // deleted word
 173      
 174                  if (($letter=='d') || ($letter=='c')) {
 175                    $sideA->copy_whitespace($output);
 176                    $output .="@@";
 177                    $sideA->copy_word($output);
 178                    $sideA->copy_until_ordinal($argument[1],$output);
 179                    $output .="@@";
 180                  }
 181      
 182      // inserted word
 183                  if ($letter == 'a' || $letter == 'c') {
 184                  $sideB->copy_whitespace($output);
 185                  $output .="££";
 186                  $sideB->copy_word($output);
 187                  $sideB->copy_until_ordinal($argument[3],$output);
 188                  $output .="££";
 189                  }
 190      
 191            }
 192      
 193          }
 194      
 195            $sideB->copy_until_ordinal($count_total_right,$output);
 196            $sideB->copy_whitespace($output);
 197            $out=$this->Format($output);
 198            echo $out;
 199      
 200      }
 201  
 202  }
 203  else{
 204      echo "<i>Vous n'&ecirc;tes pas autoris&eacute; &agrave; lire cette page.</i>" ;
 205  }
 206      
 207      // Side : a string for wdiff
 208      
 209      class Side {
 210          var $position;
 211          var $cursor;
 212          var $content;
 213          var $character;
 214          var $directive;
 215          var $argument;
 216          var $length;
 217  
 218  	    function Side($content) {
 219             $this->content=$content;
 220             $this->position=0;
 221             $this->cursor=0;
 222             $this->directive='';
 223             $this->argument=array();
 224             $this->length=strlen($this->content);
 225             $this->character=substr($this->content,0,1);
 226             
 227          }
 228  
 229  	    function getposition() {
 230             return $this->position;
 231          }
 232  
 233  	    function getcharacter() {
 234             return $this->character;
 235          }
 236  
 237  	    function getdirective() {
 238             return $this->directive;
 239          }
 240  
 241  	    function getargument() {
 242             return $this->argument;
 243          }
 244  
 245  	    function nextchar() {
 246             $this->cursor++; 
 247             $this->character=substr($this->content,$this->cursor,1);
 248          }
 249  
 250  	    function copy_until_ordinal($ordinal,&$out)  {
 251             while ($this->position < $ordinal) {
 252            $this->copy_whitespace($out);
 253            $this->copy_word($out);
 254             }
 255          }
 256  
 257  	    function skip_until_ordinal($ordinal) {
 258             while ($this->position < $ordinal) {
 259            $this->skip_whitespace();
 260            $this->skip_word();
 261             }
 262          }
 263  
 264  	    function split_file_into_words (&$out) {
 265             while (!$this->isend()) {
 266           $this->skip_whitespace();
 267           if ($this->isend()) {
 268             break;
 269           }
 270           $this->copy_word($out);
 271           $out .="\n";
 272             }
 273          }
 274          
 275  	    function init() {
 276             $this->position=0;
 277             $this->cursor=0;
 278             $this->directive='';
 279             $this->argument=array();
 280             $this->character=substr($this->content,0,1);
 281          }     
 282  
 283  	    function isspace($char) {
 284             if (ereg('[[:space:]]',$char)) {
 285            return true;
 286             }
 287             else {
 288            return false;
 289             }
 290          }
 291  
 292  	    function isdigit($char) {
 293             if (ereg('[[:digit:]]',$char)) {
 294            return true;
 295             }
 296             else {
 297            return false;
 298             }
 299          }
 300  
 301  	    function isend() {
 302             if (($this->cursor)>=($this->length)) {
 303            return true;
 304             }
 305             else {
 306            return false;
 307             }
 308          }
 309  
 310  
 311  
 312  	    function copy_whitespace(&$out)  {
 313           while (!$this->isend() && $this->isspace($this->character)) {
 314              $out .=$this->character;
 315              $this->nextchar();
 316           }
 317          }
 318  
 319  	    function skip_whitespace()  {
 320           while (!$this->isend() && $this->isspace($this->character)) {
 321              $this->nextchar();
 322           }
 323          }
 324  
 325  	    function skip_line()  {
 326            while (!$this->isend() && !$this->isdigit($this->character)) {
 327            while (!$this->isend() && $this->character!="\n")
 328            $this->nextchar();
 329            if($this->character=="\n")
 330                $this->nextchar();
 331             }
 332           }
 333  
 334  
 335  
 336  	     function copy_word(&$out) {
 337           while (!$this->isend() && !($this->isspace($this->character))) {
 338              $out.=$this->character;
 339              $this->nextchar();
 340           }
 341           $this->position++;
 342           }
 343  
 344  	     function skip_word() {
 345  
 346           while (!$this->isend() && !($this->isspace($this->character))) {
 347              $this->nextchar();
 348           }
 349           $this->position++;
 350           }
 351  
 352  
 353  	 function decode_directive_line() {
 354  
 355        $value=0;                    
 356        $state=0;                   
 357        $error=0;                  
 358  
 359        while (!$error && $state < 4) {
 360            if ($this->isdigit($this->character)) {
 361            $value = 0;
 362            while($this->isdigit($this->character)) {
 363                $value = 10 * $value + $this->character - '0';
 364                $this->nextchar(); 
 365            }
 366            }
 367            else if ($state != 1 && $state != 3)
 368            $error = 1;
 369  
 370            /* Assign the proper value.  */
 371  
 372            $this->argument[$state] = $value;
 373  
 374            /* Skip the following character.  */
 375  
 376            switch ($state) {
 377          case 0:
 378          case 2:
 379            if ($this->character == ',')
 380               $this->nextchar();
 381            break;
 382  
 383          case 1:
 384            if ($this->character == 'a' || $this->character == 'd' || $this->character == 'c') {
 385                $this->directive = $this->character;
 386                $this->nextchar();
 387              }
 388            else
 389              $error = 1;
 390            break;
 391  
 392            case 3:
 393            if ($this->character != "\n")
 394              $error = 1;
 395              break;
 396            }
 397           $state++;
 398            }
 399  
 400        /* Complete reading of the line and return success value.  */
 401  
 402        while ((!$this->isend()) && ($this->character != "\n")) {
 403            $this->nextchar();
 404        }
 405        if ($this->character == "\n")
 406            $this->nextchar();
 407  
 408        return !$error;
 409      }
 410  
 411  
 412  
 413      }
 414  
 415      // difflib
 416      //
 417      // A PHP diff engine for phpwiki.
 418      //
 419      // Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
 420      // You may copy this code freely under the conditions of the GPL.
 421      //
 422  
 423      class _DiffOp {
 424          var $type;
 425          var $orig;
 426          var $final;
 427          
 428  
 429  	    function norig() {
 430          return $this->orig ? sizeof($this->orig) : 0;
 431          }
 432  
 433  	    function nfinal() {
 434          return $this->final ? sizeof($this->final) : 0;
 435          }
 436      }
 437  
 438      class _DiffOp_Copy extends _DiffOp {
 439          var $type = 'copy';
 440          
 441  	    function _DiffOp_Copy ($orig, $final = false) {
 442          if (!is_array($final))
 443              $final = $orig;
 444          $this->orig = $orig;
 445          $this->final = $final;
 446          }
 447  
 448      }
 449  
 450      class _DiffOp_Delete extends _DiffOp {
 451          var $type = 'delete';
 452          
 453  	    function _DiffOp_Delete ($lines) {
 454          $this->orig = $lines;
 455          $this->final = false;
 456          }
 457  
 458      }
 459  
 460      class _DiffOp_Add extends _DiffOp {
 461          var $type = 'add';
 462          
 463  	    function _DiffOp_Add ($lines) {
 464          $this->final = $lines;
 465          $this->orig = false;
 466          }
 467  
 468      }
 469  
 470      class _DiffOp_Change extends _DiffOp {
 471          var $type = 'change';
 472          
 473  	    function _DiffOp_Change ($orig, $final) {
 474          $this->orig = $orig;
 475          $this->final = $final;
 476          }
 477  
 478      }
 479          
 480            
 481      /**
 482       * Class used internally by Diff to actually compute the diffs.
 483       *
 484       * The algorithm used here is mostly lifted from the perl module
 485       * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
 486       *   http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
 487       *
 488       * More ideas are taken from:
 489       *   http://www.ics.uci.edu/~eppstein/161/960229.html
 490       *
 491       * Some ideas are (and a bit of code) are from from analyze.c, from GNU
 492       * diffutils-2.7, which can be found at:
 493       *   ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
 494       *
 495       * Finally, some ideas (subdivision by NCHUNKS > 2, and some optimizations)
 496       * are my own.
 497       *
 498       * @author Geoffrey T. Dairiki
 499       * @access private
 500       */
 501      class _DiffEngine
 502      {
 503  	    function diff ($from_lines, $to_lines) {
 504          $n_from = sizeof($from_lines);
 505          $n_to = sizeof($to_lines);
 506  
 507          $this->xchanged = $this->ychanged = array();
 508          $this->xv = $this->yv = array();
 509          $this->xind = $this->yind = array();
 510          unset($this->seq);
 511          unset($this->in_seq);
 512          unset($this->lcs);
 513           
 514          // Skip leading common lines.
 515          for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
 516              if ($from_lines[$skip] != $to_lines[$skip])
 517              break;
 518              $this->xchanged[$skip] = $this->ychanged[$skip] = false;
 519          }
 520          // Skip trailing common lines.
 521          $xi = $n_from; $yi = $n_to;
 522          for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
 523              if ($from_lines[$xi] != $to_lines[$yi])
 524              break;
 525              $this->xchanged[$xi] = $this->ychanged[$yi] = false;
 526          }
 527          
 528          // Ignore lines which do not exist in both files.
 529          for ($xi = $skip; $xi < $n_from - $endskip; $xi++)
 530              $xhash[$from_lines[$xi]] = 1;
 531          for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
 532              $line = $to_lines[$yi];
 533              if ( ($this->ychanged[$yi] = empty($xhash[$line])) )
 534              continue;
 535              $yhash[$line] = 1;
 536              $this->yv[] = $line;
 537              $this->yind[] = $yi;
 538          }
 539          for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
 540              $line = $from_lines[$xi];
 541              if ( ($this->xchanged[$xi] = empty($yhash[$line])) )
 542              continue;
 543              $this->xv[] = $line;
 544              $this->xind[] = $xi;
 545          }
 546  
 547          // Find the LCS.
 548          $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
 549  
 550          // Merge edits when possible
 551          $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
 552          $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
 553  
 554          // Compute the edit operations.
 555          $edits = array();
 556          $xi = $yi = 0;
 557          while ($xi < $n_from || $yi < $n_to) {
 558              assert($yi < $n_to || $this->xchanged[$xi]);
 559              assert($xi < $n_from || $this->ychanged[$yi]);
 560  
 561              // Skip matching "snake".
 562              $copy = array();
 563              while ( $xi < $n_from && $yi < $n_to
 564                  && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
 565              $copy[] = $from_lines[$xi++];
 566              ++$yi;
 567              }
 568              if ($copy)
 569              $edits[] = new _DiffOp_Copy($copy);
 570  
 571              // Find deletes & adds.
 572              $delete = array();
 573              while ($xi < $n_from && $this->xchanged[$xi])
 574              $delete[] = $from_lines[$xi++];
 575  
 576              $add = array();
 577              while ($yi < $n_to && $this->ychanged[$yi])
 578              $add[] = $to_lines[$yi++];
 579              
 580              if ($delete && $add)
 581              $edits[] = new _DiffOp_Change($delete, $add);
 582              elseif ($delete)
 583              $edits[] = new _DiffOp_Delete($delete);
 584              elseif ($add)
 585              $edits[] = new _DiffOp_Add($add);
 586          }
 587          return $edits;
 588          }
 589          
 590  
 591          /* Divide the Largest Common Subsequence (LCS) of the sequences
 592           * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
 593           * sized segments.
 594           *
 595           * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an
 596           * array of NCHUNKS+1 (X, Y) indexes giving the diving points between
 597           * sub sequences.  The first sub-sequence is contained in [X0, X1),
 598           * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on.  Note
 599           * that (X0, Y0) == (XOFF, YOFF) and
 600           * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
 601           *
 602           * This function assumes that the first lines of the specified portions
 603           * of the two files do not match, and likewise that the last lines do not
 604           * match.  The caller must trim matching lines from the beginning and end
 605           * of the portions it is going to specify.
 606           */
 607  	    function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) {
 608          $flip = false;
 609          
 610          if ($xlim - $xoff > $ylim - $yoff) {
 611              // Things seems faster (I'm not sure I understand why)
 612              // when the shortest sequence in X.
 613              $flip = true;
 614              list ($xoff, $xlim, $yoff, $ylim)
 615              = array( $yoff, $ylim, $xoff, $xlim);
 616          }
 617  
 618          if ($flip)
 619              for ($i = $ylim - 1; $i >= $yoff; $i--)
 620              $ymatches[$this->xv[$i]][] = $i;
 621          else
 622              for ($i = $ylim - 1; $i >= $yoff; $i--)
 623              $ymatches[$this->yv[$i]][] = $i;
 624  
 625          $this->lcs = 0;
 626          $this->seq[0]= $yoff - 1;
 627          $this->in_seq = array();
 628          $ymids[0] = array();
 629          
 630          $numer = $xlim - $xoff + $nchunks - 1;
 631          $x = $xoff;
 632          for ($chunk = 0; $chunk < $nchunks; $chunk++) {
 633              if ($chunk > 0)
 634              for ($i = 0; $i <= $this->lcs; $i++)
 635                  $ymids[$i][$chunk-1] = $this->seq[$i];
 636  
 637              $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
 638              for ( ; $x < $x1; $x++) {
 639              $line = $flip ? $this->yv[$x] : $this->xv[$x];
 640              if (empty($ymatches[$line]))
 641                  continue;
 642              $matches = $ymatches[$line];
 643              reset($matches);
 644              while (list ($junk, $y) = each($matches))
 645                  if (empty($this->in_seq[$y])) {
 646                  $k = $this->_lcs_pos($y);
 647                  assert($k > 0);
 648                  $ymids[$k] = $ymids[$k-1];
 649                  break;
 650                  }
 651              while (list ($junk, $y) = each($matches)) {
 652                  if ($y > $this->seq[$k-1]) {
 653                  assert($y < $this->seq[$k]);
 654                  // Optimization: this is a common case:
 655                  //  next match is just replacing previous match.
 656                  $this->in_seq[$this->seq[$k]] = false;
 657                  $this->seq[$k] = $y;
 658                  $this->in_seq[$y] = 1;
 659                  }
 660                  else if (empty($this->in_seq[$y])) {
 661                  $k = $this->_lcs_pos($y);
 662                  assert($k > 0);
 663                  $ymids[$k] = $ymids[$k-1];
 664                  }
 665              }
 666              }
 667          }
 668  
 669          $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
 670          $ymid = $ymids[$this->lcs];
 671          for ($n = 0; $n < $nchunks - 1; $n++) {
 672              $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
 673              $y1 = $ymid[$n] + 1;
 674              $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
 675          }
 676          $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
 677  
 678          return array($this->lcs, $seps);
 679          }
 680  
 681  	    function _lcs_pos ($ypos) {
 682          $end = $this->lcs;
 683          if ($end == 0 || $ypos > $this->seq[$end]) {
 684              $this->seq[++$this->lcs] = $ypos;
 685              $this->in_seq[$ypos] = 1;
 686              return $this->lcs;
 687          }
 688  
 689          $beg = 1;
 690          while ($beg < $end) {
 691              $mid = (int)(($beg + $end) / 2);
 692              if ( $ypos > $this->seq[$mid] )
 693              $beg = $mid + 1;
 694              else
 695              $end = $mid;
 696          }
 697  
 698          assert($ypos != $this->seq[$end]);
 699  
 700          $this->in_seq[$this->seq[$end]] = false;
 701          $this->seq[$end] = $ypos;
 702          $this->in_seq[$ypos] = 1;
 703          return $end;
 704          }
 705  
 706          /* Find LCS of two sequences.
 707           *
 708           * The results are recorded in the vectors $this->{x,y}changed[], by
 709           * storing a 1 in the element for each line that is an insertion
 710           * or deletion (ie. is not in the LCS).
 711           *
 712           * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
 713           *
 714           * Note that XLIM, YLIM are exclusive bounds.
 715           * All line numbers are origin-0 and discarded lines are not counted.
 716           */
 717  	    function _compareseq ($xoff, $xlim, $yoff, $ylim) {
 718          // Slide down the bottom initial diagonal.
 719          while ($xoff < $xlim && $yoff < $ylim
 720                 && $this->xv[$xoff] == $this->yv[$yoff]) {
 721              ++$xoff;
 722              ++$yoff;
 723          }
 724  
 725          // Slide up the top initial diagonal.
 726          while ($xlim > $xoff && $ylim > $yoff
 727                 && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
 728              --$xlim;
 729              --$ylim;
 730          }
 731  
 732          if ($xoff == $xlim || $yoff == $ylim)
 733              $lcs = 0;
 734          else {
 735              // This is ad hoc but seems to work well.
 736              //$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
 737              //$nchunks = max(2,min(8,(int)$nchunks));
 738              $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
 739              list ($lcs, $seps)
 740              = $this->_diag($xoff,$xlim,$yoff, $ylim,$nchunks);
 741          }
 742  
 743          if ($lcs == 0) {
 744              // X and Y sequences have no common subsequence:
 745              // mark all changed.
 746              while ($yoff < $ylim)
 747              $this->ychanged[$this->yind[$yoff++]] = 1;
 748              while ($xoff < $xlim)
 749              $this->xchanged[$this->xind[$xoff++]] = 1;
 750          }
 751          else {
 752              // Use the partitions to split this problem into subproblems.
 753              reset($seps);
 754              $pt1 = $seps[0];
 755              while ($pt2 = next($seps)) {
 756              $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
 757              $pt1 = $pt2;
 758              }
 759          }
 760          }
 761  
 762          /* Adjust inserts/deletes of identical lines to join changes
 763           * as much as possible.
 764           *
 765           * We do something when a run of changed lines include a
 766           * line at one end and has an excluded, identical line at the other.
 767           * We are free to choose which identical line is included.
 768           * `compareseq' usually chooses the one at the beginning,
 769           * but usually it is cleaner to consider the following identical line
 770           * to be the "change".
 771           *
 772           * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
 773           */
 774  	    function _shift_boundaries ($lines, &$changed, $other_changed) {
 775          $i = 0;
 776          $j = 0;
 777  
 778          assert('sizeof($lines) == sizeof($changed)');
 779          $len = sizeof($lines);
 780          $other_len = sizeof($other_changed);
 781  
 782          while (1) {
 783              /*
 784               * Scan forwards to find beginning of another run of changes.
 785               * Also keep track of the corresponding point in the other file.
 786               *
 787               * Throughout this code, $i and $j are adjusted together so that
 788               * the first $i elements of $changed and the first $j elements
 789               * of $other_changed both contain the same number of zeros
 790               * (unchanged lines).
 791               * Furthermore, $j is always kept so that $j == $other_len or
 792               * $other_changed[$j] == false.
 793               */
 794              while ($j < $other_len && $other_changed[$j])
 795              $j++;
 796              
 797              while ($i < $len && ! $changed[$i]) {
 798              assert('$j < $other_len && ! $other_changed[$j]');
 799              $i++; $j++;
 800              while ($j < $other_len && $other_changed[$j])
 801                  $j++;
 802              }
 803              
 804              if ($i == $len)
 805              break;
 806  
 807              $start = $i;
 808  
 809              // Find the end of this run of changes.
 810              while (++$i < $len && $changed[$i])
 811              continue;
 812  
 813              do {
 814              /*
 815               * Record the length of this run of changes, so that
 816               * we can later determine whether the run has grown.
 817               */
 818              $runlength = $i - $start;
 819  
 820              /*
 821               * Move the changed region back, so long as the
 822               * previous unchanged line matches the last changed one.
 823               * This merges with previous changed regions.
 824               */
 825              while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
 826                  $changed[--$start] = 1;
 827                  $changed[--$i] = false;
 828                  while ($start > 0 && $changed[$start - 1])
 829                  $start--;
 830                  assert('$j > 0');
 831                  while ($other_changed[--$j])
 832                  continue;
 833                  assert('$j >= 0 && !$other_changed[$j]');
 834              }
 835  
 836              /*
 837               * Set CORRESPONDING to the end of the changed run, at the last
 838               * point where it corresponds to a changed run in the other file.
 839               * CORRESPONDING == LEN means no such point has been found.
 840               */
 841              $corresponding = $j < $other_len ? $i : $len;
 842  
 843              /*
 844               * Move the changed region forward, so long as the
 845               * first changed line matches the following unchanged one.
 846               * This merges with following changed regions.
 847               * Do this second, so that if there are no merges,
 848               * the changed region is moved forward as far as possible.
 849               */
 850              while ($i < $len && $lines[$start] == $lines[$i]) {
 851                  $changed[$start++] = false;
 852                  $changed[$i++] = 1;
 853                  while ($i < $len && $changed[$i])
 854                  $i++;
 855  
 856                  assert('$j < $other_len && ! $other_changed[$j]');
 857                  $j++;
 858                  if ($j < $other_len && $other_changed[$j]) {
 859                  $corresponding = $i;
 860                  while ($j < $other_len && $other_changed[$j])
 861                      $j++;
 862                  }
 863              }
 864              } while ($runlength != $i - $start);
 865  
 866              /*
 867               * If possible, move the fully-merged run of changes
 868               * back to a corresponding run in the other file.
 869               */
 870              while ($corresponding < $i) {
 871              $changed[--$start] = 1;
 872              $changed[--$i] = 0;
 873              assert('$j > 0');
 874              while ($other_changed[--$j])
 875                  continue;
 876              assert('$j >= 0 && !$other_changed[$j]');
 877              }
 878          }
 879          }
 880      }
 881  
 882      /**
 883       * Class representing a 'diff' between two sequences of strings.
 884       */
 885      class Diff 
 886      {
 887          var $edits;
 888  
 889          /**
 890           * Constructor.
 891           * Computes diff between sequences of strings.
 892           *
 893           * @param $from_lines array An array of strings.
 894           *        (Typically these are lines from a file.)
 895           * @param $to_lines array An array of strings.
 896           */
 897  	    function Diff($from_lines, $to_lines) {
 898          $eng = new _DiffEngine;
 899          $this->edits = $eng->diff($from_lines, $to_lines);
 900          }
 901  
 902      }
 903  
 904              
 905  
 906      /**
 907       * A class to format Diffs
 908       *
 909       * This class formats the diff in classic diff format.
 910       * It is intended that this class be customized via inheritance,
 911       * to obtain fancier outputs.
 912       */
 913      class DiffFormatter
 914      {
 915  
 916          /**
 917           * Format a diff.
 918           *
 919           * @param $diff object A Diff object.
 920           * @return string The formatted output.
 921           */
 922  	    function format($diff) {
 923  
 924          $xi = $yi = 1;
 925          $block = false;
 926          $context = array();
 927  
 928          $this->_start_diff();
 929  
 930          foreach ($diff->edits as $edit) {
 931              if ($edit->type == 'copy') {
 932              if (is_array($block)) {
 933                  if (sizeof($edit->orig) <= 0) {
 934                  $block[] = $edit;
 935                  }
 936                  else{
 937                  $this->_block($x0, + $xi - $x0,
 938                            $y0, + $yi - $y0,
 939                            $block);
 940                  $block = false;
 941                  }
 942              }
 943              }
 944              else {
 945              if (! is_array($block)) {
 946                  $x0 = $xi;
 947                  $y0 = $yi;
 948                  $block = array();
 949              }
 950              $block[] = $edit;
 951              }
 952  
 953              if ($edit->orig)
 954              $xi += sizeof($edit->orig);
 955              if ($edit->final)
 956              $yi += sizeof($edit->final);
 957          }
 958  
 959          if (is_array($block))
 960              $this->_block($x0, $xi - $x0,
 961                    $y0, $yi - $y0,
 962                    $block);
 963  
 964          return $this->_end_diff();
 965          }
 966  
 967  	    function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
 968          $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
 969          }
 970  
 971  	    function _start_diff() {
 972          ob_start();
 973          }
 974  
 975  	    function _end_diff() {
 976          $val = ob_get_contents();
 977          ob_end_clean();
 978          return $val;
 979          }
 980  
 981  	    function _block_header($xbeg, $xlen, $ybeg, $ylen) {
 982          if ($xlen > 1)
 983              $xbeg .= "," . ($xbeg + $xlen - 1);
 984          if ($ylen > 1)
 985              $ybeg .= "," . ($ybeg + $ylen - 1);
 986  
 987          return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
 988          }
 989          
 990  	    function _start_block($header) {
 991          echo $header."\n";
 992          }
 993  
 994      }
 995      
 996  
 997  ?>
 998  </div>
 999  <?php echo $this->Footer(); ?>


Généré le : Mon Nov 26 12:05:46 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics