home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / editor / epmtools / epmsmp / e3comp.e < prev    next >
Encoding:
Text File  |  1992-08-26  |  18.5 KB  |  506 lines

  1. /****************************************************************************
  2.  
  3.                         ┌───────────────────────┐
  4.                         │  E 3 C O M P . E      │
  5.                         └───────────────────────┘
  6.  
  7.                                     By Dave Burton
  8.                                     Modified by Bryan Lewis
  9.  
  10.   Modified  to work  in messy-desk  mode as  well as  tiled, by calling
  11.   pnextfile() instead of doing 'nextfile' for F10.
  12.  
  13.   This  is  a  very  useful  file-compare  utility  written  in E3 language.
  14.   Searches two files for differences, centers  the lines  so you  can easily
  15.   flicker back and forth to see what's different.  Fast!  Dave  Burton put a
  16.   lot of effort into speed optimization, simplifying loops and the like.  He
  17.   is unable to spend any more time on this, but was happy to let  me convert
  18.   it to E3 (I  needed it  for myself!)  and put  it on  PROCS.  Don't expect
  19.   support.
  20.  
  21.   Special features are: ability to get back in  sync after  being thrown off
  22.   be an added or deleted line; and a LOOSEMATCH  command to  tell it  not to
  23.   consider leading / trailing spaces in the comparison.
  24.  
  25.   Modified by Larry Margolis to be slightly more efficient, and to work with
  26.   EPM.
  27.  
  28.  
  29.   Defines functions:
  30.  
  31.   COMPARE.  Will scan through a pair  of files  looking for  the first point
  32.       where the two files differ.  If they differ on the current lines (that
  33.       is, after you've found a difference), pressing COMPARE repeatedly will
  34.       "flicker"   between the   two files   (do alternating   next-file  and
  35.       previous-file operations).  The current line in the two  files will
  36.   be centered in mid-screen so differences will be readily apparent.
  37.  
  38.   SYNC.  Will attempt to resynchronize the two files, by looking ahead up to
  39.       11 lines in each file for a place where  the two  files are identical.
  40.       Repeatedly pressing SYNC will "flicker" between the two files.
  41.  
  42.   FLICKER.  Alternate between the compared files
  43.  
  44.   The two files to be  compared should  be the  Current file  and the "next"
  45.   file in the ring (the "next" file is the one made active  by a  single F10
  46.   keypress).  Put the cursor on identical lines in the two files, then press
  47.   the COMPARE key to skip to the first difference in each file.
  48.  
  49.   Press COMPARE a few times more to see the differences.  You  can then move
  50.   the two cursors down to  identical lines  again "re-synchronize"  with the
  51.   SYNC key, and repeat the process.
  52.  
  53.   Note that COMPARE "remembers" which  of the  two files  is currently being
  54.   displayed; after you re-synchronize and compare again,  you will  again be
  55.   looking at the  "first" of  the two  files, no  matter which  one you were
  56.   looking at when you started the compare.  However, using  the  "NEXT-FILE"
  57.   (F10) or  the "LAST-FILE" (Alt-F10)  key  causes this  recollection  to be
  58.   "forgotten".
  59.  
  60.   A faster way to re-synchronize (if you are  within 11  lines of  a pair of
  61.   matching lines) is to simply press the SYNC key.  Then  press it  again to
  62.   see the other file (flicker).
  63.  
  64.   Defines:
  65.      Ctrl-C
  66.         As the COMPARE key
  67.      Ctrl-S
  68.         As the SYNC key
  69.  
  70.       LOOSEMATCH - Causes E3COMP to  consider lines  to be  matching even if
  71.           indented differently, or if one of them has trailing blanks.
  72.  
  73.       EXACTMATCH - Causes E3COMP to  consider lines  to be  matching only if
  74.           the lines are identical.
  75.  
  76.      Modifies the NEXT-FILE (F10) definition        (adjust to suit)
  77.      Modifies the LAST-FILE (Alt-F10) definition    (adjust to suit)
  78.  
  79. *****************************************************************************/
  80.  
  81. ; Updated to add Compare and Sync to the action bar, and not use keys.
  82.  
  83. compile if not defined(EPM)
  84.    include 'STDCONST.E'
  85. compile endif
  86.  
  87. definit                     /* 1=LOOSE matching as default. 0 for EXACT  */
  88.    universal c_inexact
  89. compile if defined(my_C_INEXACT)
  90.    c_inexact=my_C_INEXACT
  91. compile else
  92.    c_inexact=1
  93. compile endif
  94.    menuname='default'
  95.    buildsubmenu menuname, 30, 'Compare!', 'e3comp',     0, 0
  96.    buildsubmenu menuname, 31, 'Sync!', 'sync',       0, 0
  97.    showmenu menuname
  98.  
  99. ;;def c_f10=                 /* define c_f10 to be the "compare" key */
  100. defc e3comp
  101.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  102.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  103.    universal c_limit1, c_limit2, c_got1, c_got2
  104.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  105.  
  106.   c_saved_flicker_flag=c_flicker_flag
  107.   call ppini_comp()
  108.   if (c_line1<>c_line2) or ((not c_inexact)and(c_line1/==c_line2)) or (c_lineno1=.last) or (c_lineno2=c_last2) then
  109.       if c_saved_flicker_flag=c_flicker_flag then
  110.           call ppflicker()  /* switch to other file */
  111.       endif
  112.   else
  113. ;compile if EPM
  114. ;      sayatbox('comparing...')
  115. ;compile else
  116.       sayerror 'comparing...'
  117. ;compile endif
  118.       /* loop, looking for first difference */
  119.       if (.last-c_lineno1) < (c_last2-c_lineno2) then
  120.           /* trick to make loop faster by removing "c_lineno1<.last" test */
  121.           c_last2=c_lineno2+.last-c_lineno1
  122.       endif
  123.       /*
  124.          This function is an "unwound" version of the next loop; by adding
  125.          this, we sped up the search substantially.  You could, however, remove
  126.          fast_compare_loop completely without affecting anything except speed.
  127.       */
  128.       call fast_compare_loop()
  129.       /* here is the slow version of the loop, to finish up: */
  130.       while (c_lineno2<c_last2) and ((c_line1==c_line2)or(c_inexact and(c_line1=c_line2))) do
  131.          /* "and (c_lineno1<.last)" deleted due to trick, above */
  132.          c_lineno1=c_lineno1+1
  133.          c_lineno2=c_lineno2+1
  134.          getline c_line1,c_lineno1,fileid1
  135.          getline c_line2,c_lineno2,fileid2
  136.       endwhile
  137.       c_last2=fileid2.last /* done with loop, so restore to normal value */
  138.       if (c_lineno1=.last) and (c_lineno2=c_last2) and ((c_line1==c_line2)or(c_inexact and(c_line1=c_line2))) then
  139.          sayerror 'no differences'
  140.       else
  141.          sayerror 0
  142.       endif
  143.       call ppend_comp()
  144.   endif
  145.   call ppcenter_screen()
  146. /* end of compare key definition */
  147.  
  148.  
  149. /* inner loop for COMPARE definition -- unwound for maximum speed */
  150.  
  151. defproc fast_compare_loop
  152.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  153.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  154.    universal c_limit1, c_limit2, c_got1, c_got2
  155.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  156.  
  157.    if c_inexact then
  158.       while ((c_last2-c_lineno2)>=4) and (c_line1=c_line2) do
  159.         getline c_line1,c_lineno1+1,fileid1
  160.         getline c_line2,c_lineno2+1,fileid2
  161.         if c_line1<>c_line2 then
  162.             c_lineno1=c_lineno1+1
  163.             c_lineno2=c_lineno2+1
  164.         else
  165.             getline c_line1,c_lineno1+2,fileid1
  166.             getline c_line2,c_lineno2+2,fileid2
  167.             if c_line1<>c_line2 then
  168.                 c_lineno1=c_lineno1+2
  169.                 c_lineno2=c_lineno2+2
  170.             else
  171.                 getline c_line1,c_lineno1+3,fileid1
  172.                 getline c_line2,c_lineno2+3,fileid2
  173.                 if c_line1<>c_line2 then
  174.                     c_lineno1=c_lineno1+3
  175.                     c_lineno2=c_lineno2+3
  176.                 else
  177.                     c_lineno1=c_lineno1+4
  178.                     c_lineno2=c_lineno2+4
  179.                     getline c_line1,c_lineno1,fileid1
  180.                     getline c_line2,c_lineno2,fileid2
  181.                 endif
  182.             endif
  183.         endif
  184.         /* end of the unwound inexact-match while loop */
  185.       endwhile
  186.    else
  187.       while ((c_last2-c_lineno2)>=4) and (c_line1==c_line2) do
  188.         getline c_line1,c_lineno1+1,fileid1
  189.         getline c_line2,c_lineno2+1,fileid2
  190.         if c_line1/==c_line2 then
  191.             c_lineno1=c_lineno1+1
  192.             c_lineno2=c_lineno2+1
  193.         else
  194.             getline c_line1,c_lineno1+2,fileid1
  195.             getline c_line2,c_lineno2+2,fileid2
  196.             if c_line1/==c_line2 then
  197.                 c_lineno1=c_lineno1+2
  198.                 c_lineno2=c_lineno2+2
  199.             else
  200.                 getline c_line1,c_lineno1+3,fileid1
  201.                 getline c_line2,c_lineno2+3,fileid2
  202.                 if c_line1/==c_line2 then
  203.                     c_lineno1=c_lineno1+3
  204.                     c_lineno2=c_lineno2+3
  205.                 else
  206.                     c_lineno1=c_lineno1+4
  207.                     c_lineno2=c_lineno2+4
  208.                     getline c_line1,c_lineno1,fileid1
  209.                     getline c_line2,c_lineno2,fileid2
  210.                 endif
  211.             endif
  212.         endif
  213.         /* end of the unwound exact-match while loop */
  214.       endwhile
  215.    endif
  216.  
  217.  
  218.  
  219. /****************************************************************************
  220. We have 7 private variables in this def, four of which have double uses:
  221.      c_count1 & c_count2  =  saved positions after a "no match" compare,
  222.                              line counter while scanning
  223.      c_limit1 & c_limit2  =  saved file sizes after a "no match" compare,
  224.                              limit to line counter while scanning
  225.      c_got1 & c_got2      =  "got a match" positions while scanning
  226.      c_success               "got one" flag while scanning
  227. ****************************************************************************/
  228.  
  229. defc sync
  230. ;;def s_f10=                    /* define s-f10 to be the sync key */
  231.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  232.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  233.    universal c_limit1, c_limit2, c_got1, c_got2
  234.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  235.  
  236.   c_saved_flicker_flag=c_flicker_flag
  237.   call ppini_comp()
  238.   if (c_count1=c_lineno1)and(c_count2=c_lineno2)and(c_limit1=.last)and(c_limit2=c_last2) then
  239.       /* repeated "no match within 11 lines" flickers */
  240.       if c_saved_flicker_flag=c_flicker_flag then
  241.           call ppflicker()  /* switch to other file */
  242.       endif
  243.   elseif (c_line1==c_line2) or (c_inexact and(c_line1=c_line2)) then
  244.       /* if we are already synchronized, then flicker */
  245.       c_count1=0  /* we have a match, so clear saved "not found" position */
  246.       if c_saved_flicker_flag=c_flicker_flag then
  247.           call ppflicker()  /* switch to other file */
  248.       endif
  249.   else
  250.       c_limit1=11 /* we look ahead only 11 lines (lest, it be too slow) */
  251.       if (.last-c_lineno1) < c_limit1 then
  252.           c_limit1=(.last-c_lineno1)
  253.       endif
  254.       c_got1=0
  255.       c_got2=0
  256.       c_count1=0
  257.       c_success=0
  258.       while c_count1 <= c_limit1 do
  259.           c_count2=0
  260.           if c_success then
  261.               c_limit2=(c_got1+c_got2)-c_count1-1
  262.               if c_limit2 > 11 then
  263.                   c_limit2=11
  264.               endif
  265.           else
  266.               c_limit2=11
  267.           endif
  268.           if (c_last2-c_lineno2) < c_limit2 then
  269.               c_limit2=(c_last2-c_lineno2)
  270.           endif
  271.           /* we've carefully calculated the limits so that we'll only find */
  272.           /* "better" matches than those we've already found.  A "better"  */
  273.           /* match is one which is nearer to the current lines (not as     */
  274.           /* far down).  More precisely, the best match is the one with a  */
  275.           /* minimum sum of the two lines numbers.                         */
  276.           if c_inexact then
  277.            /* note: we move the "c_inexact" test outside the loop, for speed */
  278.               while c_count2 <= c_limit2 do
  279.                   getline c_line1,c_lineno1+c_count1,fileid1
  280.                   getline c_line2,c_lineno2+c_count2,fileid2
  281.                   if c_line1=c_line2 then /*inexact*/
  282.                       if length(c_line1) > 0 then
  283.                           c_got1=c_count1
  284.                           c_got2=c_count2
  285.                           c_success=1
  286.                           c_limit2=c_count2 /* break out of the inner while */
  287.                       endif
  288.                   endif
  289.                   c_count2=(c_count2+1)
  290.               endwhile
  291.           else
  292.               while c_count2 <= c_limit2 do
  293.                   getline c_line1,c_lineno1+c_count1,fileid1
  294.                   getline c_line2,c_lineno2+c_count2,fileid2
  295.                   if c_line1==c_line2 then /*exact*/
  296.                       if length(c_line1) > 0 then
  297.                           c_got1=c_count1
  298.                           c_got2=c_count2
  299.                           c_success=1
  300.                           c_limit2=c_count2 /* break out of the inner while */
  301.                       endif
  302.                   endif
  303.                   c_count2=(c_count2+1)
  304.               endwhile
  305.           endif
  306.           c_count1=(c_count1+1)
  307.       endwhile
  308.       if c_success then
  309.           c_lineno1=c_lineno1+c_got1
  310.           c_lineno2=c_lineno2+c_got2
  311.           c_count1=0 /* we found a match, so clear saved "no match" position */
  312.       else
  313.           /* save state (for flicker next time he presses c-F5 flickers) */
  314.           c_count1=c_lineno1
  315.           c_count2=c_lineno2
  316.           c_limit1=.last
  317.           c_limit2=c_last2
  318.           sayerror 'No match within 11 lines'
  319.       endif
  320.       call ppend_comp()
  321.   endif
  322.   call ppcenter_screen()
  323. /* end of synchronize key definition */
  324.  
  325.  
  326. ;def c_f10=            /*     define Ctrl-F10 to be the "flicker" key  */
  327. ;def a_f10=            /*     define Alt-F10 to be the "flicker" key   */
  328. ;def c_w=             /*     define Ctrl-W to be the "flicker" key    */
  329. ;   universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  330. ;   universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  331. ;   universal c_limit1, c_limit2, c_got1, c_got2
  332. ;   universal c_success, c_temp, c_inexact, fileid1, fileid2
  333. ;   call ppflicker()
  334. ;   c_count1=0  /* discard the saved "no match" state */
  335.  
  336.  
  337. /* modify the "NEXT-FILE" definition to reset the flicker-counter */
  338. def f10,f12,c_N
  339.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  340.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  341.    universal c_limit1, c_limit2, c_got1, c_got2
  342.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  343.  
  344. compile if EPM
  345.    nextfile
  346. compile else
  347.    call pnextfile() -- Do this instead of nextfile, so will work with messy-desk or tiled.
  348. compile endif
  349.    c_flicker_flag=0  /* 1st file is current file */
  350.    c_count1=0  /* discard the saved "no match" state */
  351.  
  352.  
  353. /* modify "LAST-FILE" definition to reset the flicker-counter */
  354. def a_f10,F11,c_P
  355.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  356.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  357.    universal c_limit1, c_limit2, c_got1, c_got2
  358.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  359. compile if EPM
  360.    prevfile
  361. compile else
  362.    call pprevfile()
  363. compile endif
  364.    c_flicker_flag=0  /* 1st file is current file */
  365.    c_count1=0  /* discard the saved "no match" state */
  366.  
  367.      /* Common stuff for compare and synchronize keys */
  368.  
  369. defproc ppini_comp
  370.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  371.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  372.    universal c_limit1, c_limit2, c_got1, c_got2
  373.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  374.  
  375.     /* if Ctrl-F10 was pressed an odd number of times, switch to 1st file */
  376.  
  377.    if c_flicker_flag then
  378. compile if EPM
  379.       prevfile
  380. compile else
  381.       call pprevfile()
  382. compile endif
  383.    endif
  384.    c_flicker_flag=0  /* 1st file is current file */
  385.  
  386.      /* get initial lines & file lengths to compare */
  387.  
  388.    getfileid fileid1
  389.    if (not .line) and .last then 1; endif
  390.    c_lineno1=.line
  391.    getline c_line1
  392. compile if EPM
  393.    nextfile
  394. compile else
  395.    call pnextfile('Q')
  396. compile endif
  397.    getfileid fileid2
  398.    if (not .line) and .last then 1; endif
  399.    c_lineno2=.line
  400.    c_last2=.last
  401.    getline c_line2
  402. compile if EPM
  403.    prevfile
  404. compile else
  405.    call pprevfile('Q')
  406. compile endif
  407.    call ppcenter_screen()
  408.  
  409.  
  410. /* called after a compare, to set the current lines of the two files
  411.    to c_lineno1 and c_lineno2, and center them on the screen */
  412.  
  413. defproc ppend_comp
  414.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  415.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  416.    universal c_limit1, c_limit2, c_got1, c_got2
  417.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  418.  
  419.    .line=c_lineno1
  420. compile if EPM
  421.    nextfile
  422. compile else
  423.    call pnextfile('Q')
  424. compile endif
  425.    .line=c_lineno2
  426.    call ppcenter_screen()
  427. compile if EPM
  428.    prevfile
  429. compile else
  430.    call pprevfile('Q')
  431. compile endif
  432.    call ppcenter_screen()
  433.  
  434.  
  435. /* flicker procedure -- call to switch to other file */
  436.  
  437. defproc ppflicker
  438.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  439.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  440.    universal c_limit1, c_limit2, c_got1, c_got2
  441.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  442.  
  443.    if c_flicker_flag then
  444.       c_lineno2=.line
  445. compile if EPM
  446.       prevfile
  447. compile else
  448.       call pprevfile()
  449. compile endif
  450.       c_lineno1=.line
  451.       call ppcenter_screen()
  452.       c_flicker_flag=0  /* 1st file is current file */
  453.    else
  454.       c_lineno1=.line
  455. compile if EPM
  456.       nextfile
  457. compile else
  458.       call pnextfile()
  459. compile endif
  460.       c_lineno2=.line
  461.       call ppcenter_screen()
  462.       c_flicker_flag=1  /* 2nd file is current file */
  463.    endif
  464. /* end of flicker procedure definition */
  465.  
  466.  
  467. /***********************************************************************
  468. Procedure to center current line on screen, except that if either
  469.    file is currently "at" a line number less than 1/2 of a screen,
  470.    then the current position is set at that line (so they'll line up
  471.    properly when you "flicker" with ctrl-F10).  Note that I haven't
  472.    been able to make this work for small files.  Sigh.
  473.  
  474. ************************************************************************/
  475. defproc ppcenter_screen
  476.    universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
  477.    universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
  478.    universal c_limit1, c_limit2, c_got1, c_got2
  479.    universal c_success, c_temp, c_inexact, fileid1, fileid2
  480.  
  481.    c_temp=.line
  482.    .cursory=.windowheight%2   /* % for integer division */
  483.    if (c_lineno1<.cursory) then
  484.       .cursory=c_lineno1+1
  485.    endif
  486.    if (c_lineno2<.cursory) then
  487.       .cursory=c_lineno2+1
  488.    endif
  489.    if (.cursory <= 1) then
  490.       .cursory=2
  491.    endif
  492.    .cursorx=1
  493.    c_temp
  494.  
  495.  
  496. defc loose, loosematch=
  497.    universal c_inexact
  498.    c_inexact=1
  499.    sayerror 'COMPARE will use loose matching now.'
  500.  
  501. defc exact, exactmatch=
  502.    universal c_inexact
  503.    c_inexact=0
  504.    sayerror 'COMPARE will use exact matching now.'
  505.  
  506.