home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
-
- ┌───────────────────────┐
- │ E 3 C O M P . E │
- └───────────────────────┘
-
- By Dave Burton
- Modified by Bryan Lewis
-
- Modified to work in messy-desk mode as well as tiled, by calling
- pnextfile() instead of doing 'nextfile' for F10.
-
- This is a very useful file-compare utility written in E3 language.
- Searches two files for differences, centers the lines so you can easily
- flicker back and forth to see what's different. Fast! Dave Burton put a
- lot of effort into speed optimization, simplifying loops and the like. He
- is unable to spend any more time on this, but was happy to let me convert
- it to E3 (I needed it for myself!) and put it on PROCS. Don't expect
- support.
-
- Special features are: ability to get back in sync after being thrown off
- be an added or deleted line; and a LOOSEMATCH command to tell it not to
- consider leading / trailing spaces in the comparison.
-
- Modified by Larry Margolis to be slightly more efficient, and to work with
- EPM.
-
-
- Defines functions:
-
- COMPARE. Will scan through a pair of files looking for the first point
- where the two files differ. If they differ on the current lines (that
- is, after you've found a difference), pressing COMPARE repeatedly will
- "flicker" between the two files (do alternating next-file and
- previous-file operations). The current line in the two files will
- be centered in mid-screen so differences will be readily apparent.
-
- SYNC. Will attempt to resynchronize the two files, by looking ahead up to
- 11 lines in each file for a place where the two files are identical.
- Repeatedly pressing SYNC will "flicker" between the two files.
-
- FLICKER. Alternate between the compared files
-
- The two files to be compared should be the Current file and the "next"
- file in the ring (the "next" file is the one made active by a single F10
- keypress). Put the cursor on identical lines in the two files, then press
- the COMPARE key to skip to the first difference in each file.
-
- Press COMPARE a few times more to see the differences. You can then move
- the two cursors down to identical lines again "re-synchronize" with the
- SYNC key, and repeat the process.
-
- Note that COMPARE "remembers" which of the two files is currently being
- displayed; after you re-synchronize and compare again, you will again be
- looking at the "first" of the two files, no matter which one you were
- looking at when you started the compare. However, using the "NEXT-FILE"
- (F10) or the "LAST-FILE" (Alt-F10) key causes this recollection to be
- "forgotten".
-
- A faster way to re-synchronize (if you are within 11 lines of a pair of
- matching lines) is to simply press the SYNC key. Then press it again to
- see the other file (flicker).
-
- Defines:
- Ctrl-C
- As the COMPARE key
- Ctrl-S
- As the SYNC key
-
- LOOSEMATCH - Causes E3COMP to consider lines to be matching even if
- indented differently, or if one of them has trailing blanks.
-
- EXACTMATCH - Causes E3COMP to consider lines to be matching only if
- the lines are identical.
-
- Modifies the NEXT-FILE (F10) definition (adjust to suit)
- Modifies the LAST-FILE (Alt-F10) definition (adjust to suit)
-
- *****************************************************************************/
-
- ; Updated to add Compare and Sync to the action bar, and not use keys.
-
- compile if not defined(EPM)
- include 'STDCONST.E'
- compile endif
-
- definit /* 1=LOOSE matching as default. 0 for EXACT */
- universal c_inexact
- compile if defined(my_C_INEXACT)
- c_inexact=my_C_INEXACT
- compile else
- c_inexact=1
- compile endif
- menuname='default'
- buildsubmenu menuname, 30, 'Compare!', 'e3comp', 0, 0
- buildsubmenu menuname, 31, 'Sync!', 'sync', 0, 0
- showmenu menuname
-
- ;;def c_f10= /* define c_f10 to be the "compare" key */
- defc e3comp
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- c_saved_flicker_flag=c_flicker_flag
- call ppini_comp()
- if (c_line1<>c_line2) or ((not c_inexact)and(c_line1/==c_line2)) or (c_lineno1=.last) or (c_lineno2=c_last2) then
- if c_saved_flicker_flag=c_flicker_flag then
- call ppflicker() /* switch to other file */
- endif
- else
- ;compile if EPM
- ; sayatbox('comparing...')
- ;compile else
- sayerror 'comparing...'
- ;compile endif
- /* loop, looking for first difference */
- if (.last-c_lineno1) < (c_last2-c_lineno2) then
- /* trick to make loop faster by removing "c_lineno1<.last" test */
- c_last2=c_lineno2+.last-c_lineno1
- endif
- /*
- This function is an "unwound" version of the next loop; by adding
- this, we sped up the search substantially. You could, however, remove
- fast_compare_loop completely without affecting anything except speed.
- */
- call fast_compare_loop()
- /* here is the slow version of the loop, to finish up: */
- while (c_lineno2<c_last2) and ((c_line1==c_line2)or(c_inexact and(c_line1=c_line2))) do
- /* "and (c_lineno1<.last)" deleted due to trick, above */
- c_lineno1=c_lineno1+1
- c_lineno2=c_lineno2+1
- getline c_line1,c_lineno1,fileid1
- getline c_line2,c_lineno2,fileid2
- endwhile
- c_last2=fileid2.last /* done with loop, so restore to normal value */
- if (c_lineno1=.last) and (c_lineno2=c_last2) and ((c_line1==c_line2)or(c_inexact and(c_line1=c_line2))) then
- sayerror 'no differences'
- else
- sayerror 0
- endif
- call ppend_comp()
- endif
- call ppcenter_screen()
- /* end of compare key definition */
-
-
- /* inner loop for COMPARE definition -- unwound for maximum speed */
-
- defproc fast_compare_loop
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- if c_inexact then
- while ((c_last2-c_lineno2)>=4) and (c_line1=c_line2) do
- getline c_line1,c_lineno1+1,fileid1
- getline c_line2,c_lineno2+1,fileid2
- if c_line1<>c_line2 then
- c_lineno1=c_lineno1+1
- c_lineno2=c_lineno2+1
- else
- getline c_line1,c_lineno1+2,fileid1
- getline c_line2,c_lineno2+2,fileid2
- if c_line1<>c_line2 then
- c_lineno1=c_lineno1+2
- c_lineno2=c_lineno2+2
- else
- getline c_line1,c_lineno1+3,fileid1
- getline c_line2,c_lineno2+3,fileid2
- if c_line1<>c_line2 then
- c_lineno1=c_lineno1+3
- c_lineno2=c_lineno2+3
- else
- c_lineno1=c_lineno1+4
- c_lineno2=c_lineno2+4
- getline c_line1,c_lineno1,fileid1
- getline c_line2,c_lineno2,fileid2
- endif
- endif
- endif
- /* end of the unwound inexact-match while loop */
- endwhile
- else
- while ((c_last2-c_lineno2)>=4) and (c_line1==c_line2) do
- getline c_line1,c_lineno1+1,fileid1
- getline c_line2,c_lineno2+1,fileid2
- if c_line1/==c_line2 then
- c_lineno1=c_lineno1+1
- c_lineno2=c_lineno2+1
- else
- getline c_line1,c_lineno1+2,fileid1
- getline c_line2,c_lineno2+2,fileid2
- if c_line1/==c_line2 then
- c_lineno1=c_lineno1+2
- c_lineno2=c_lineno2+2
- else
- getline c_line1,c_lineno1+3,fileid1
- getline c_line2,c_lineno2+3,fileid2
- if c_line1/==c_line2 then
- c_lineno1=c_lineno1+3
- c_lineno2=c_lineno2+3
- else
- c_lineno1=c_lineno1+4
- c_lineno2=c_lineno2+4
- getline c_line1,c_lineno1,fileid1
- getline c_line2,c_lineno2,fileid2
- endif
- endif
- endif
- /* end of the unwound exact-match while loop */
- endwhile
- endif
-
-
-
- /****************************************************************************
- We have 7 private variables in this def, four of which have double uses:
- c_count1 & c_count2 = saved positions after a "no match" compare,
- line counter while scanning
- c_limit1 & c_limit2 = saved file sizes after a "no match" compare,
- limit to line counter while scanning
- c_got1 & c_got2 = "got a match" positions while scanning
- c_success "got one" flag while scanning
- ****************************************************************************/
-
- defc sync
- ;;def s_f10= /* define s-f10 to be the sync key */
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- c_saved_flicker_flag=c_flicker_flag
- call ppini_comp()
- if (c_count1=c_lineno1)and(c_count2=c_lineno2)and(c_limit1=.last)and(c_limit2=c_last2) then
- /* repeated "no match within 11 lines" flickers */
- if c_saved_flicker_flag=c_flicker_flag then
- call ppflicker() /* switch to other file */
- endif
- elseif (c_line1==c_line2) or (c_inexact and(c_line1=c_line2)) then
- /* if we are already synchronized, then flicker */
- c_count1=0 /* we have a match, so clear saved "not found" position */
- if c_saved_flicker_flag=c_flicker_flag then
- call ppflicker() /* switch to other file */
- endif
- else
- c_limit1=11 /* we look ahead only 11 lines (lest, it be too slow) */
- if (.last-c_lineno1) < c_limit1 then
- c_limit1=(.last-c_lineno1)
- endif
- c_got1=0
- c_got2=0
- c_count1=0
- c_success=0
- while c_count1 <= c_limit1 do
- c_count2=0
- if c_success then
- c_limit2=(c_got1+c_got2)-c_count1-1
- if c_limit2 > 11 then
- c_limit2=11
- endif
- else
- c_limit2=11
- endif
- if (c_last2-c_lineno2) < c_limit2 then
- c_limit2=(c_last2-c_lineno2)
- endif
- /* we've carefully calculated the limits so that we'll only find */
- /* "better" matches than those we've already found. A "better" */
- /* match is one which is nearer to the current lines (not as */
- /* far down). More precisely, the best match is the one with a */
- /* minimum sum of the two lines numbers. */
- if c_inexact then
- /* note: we move the "c_inexact" test outside the loop, for speed */
- while c_count2 <= c_limit2 do
- getline c_line1,c_lineno1+c_count1,fileid1
- getline c_line2,c_lineno2+c_count2,fileid2
- if c_line1=c_line2 then /*inexact*/
- if length(c_line1) > 0 then
- c_got1=c_count1
- c_got2=c_count2
- c_success=1
- c_limit2=c_count2 /* break out of the inner while */
- endif
- endif
- c_count2=(c_count2+1)
- endwhile
- else
- while c_count2 <= c_limit2 do
- getline c_line1,c_lineno1+c_count1,fileid1
- getline c_line2,c_lineno2+c_count2,fileid2
- if c_line1==c_line2 then /*exact*/
- if length(c_line1) > 0 then
- c_got1=c_count1
- c_got2=c_count2
- c_success=1
- c_limit2=c_count2 /* break out of the inner while */
- endif
- endif
- c_count2=(c_count2+1)
- endwhile
- endif
- c_count1=(c_count1+1)
- endwhile
- if c_success then
- c_lineno1=c_lineno1+c_got1
- c_lineno2=c_lineno2+c_got2
- c_count1=0 /* we found a match, so clear saved "no match" position */
- else
- /* save state (for flicker next time he presses c-F5 flickers) */
- c_count1=c_lineno1
- c_count2=c_lineno2
- c_limit1=.last
- c_limit2=c_last2
- sayerror 'No match within 11 lines'
- endif
- call ppend_comp()
- endif
- call ppcenter_screen()
- /* end of synchronize key definition */
-
-
- ;def c_f10= /* define Ctrl-F10 to be the "flicker" key */
- ;def a_f10= /* define Alt-F10 to be the "flicker" key */
- ;def c_w= /* define Ctrl-W to be the "flicker" key */
- ; universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- ; universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- ; universal c_limit1, c_limit2, c_got1, c_got2
- ; universal c_success, c_temp, c_inexact, fileid1, fileid2
- ; call ppflicker()
- ; c_count1=0 /* discard the saved "no match" state */
-
-
- /* modify the "NEXT-FILE" definition to reset the flicker-counter */
- def f10,f12,c_N
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- compile if EPM
- nextfile
- compile else
- call pnextfile() -- Do this instead of nextfile, so will work with messy-desk or tiled.
- compile endif
- c_flicker_flag=0 /* 1st file is current file */
- c_count1=0 /* discard the saved "no match" state */
-
-
- /* modify "LAST-FILE" definition to reset the flicker-counter */
- def a_f10,F11,c_P
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
- compile if EPM
- prevfile
- compile else
- call pprevfile()
- compile endif
- c_flicker_flag=0 /* 1st file is current file */
- c_count1=0 /* discard the saved "no match" state */
-
- /* Common stuff for compare and synchronize keys */
-
- defproc ppini_comp
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- /* if Ctrl-F10 was pressed an odd number of times, switch to 1st file */
-
- if c_flicker_flag then
- compile if EPM
- prevfile
- compile else
- call pprevfile()
- compile endif
- endif
- c_flicker_flag=0 /* 1st file is current file */
-
- /* get initial lines & file lengths to compare */
-
- getfileid fileid1
- if (not .line) and .last then 1; endif
- c_lineno1=.line
- getline c_line1
- compile if EPM
- nextfile
- compile else
- call pnextfile('Q')
- compile endif
- getfileid fileid2
- if (not .line) and .last then 1; endif
- c_lineno2=.line
- c_last2=.last
- getline c_line2
- compile if EPM
- prevfile
- compile else
- call pprevfile('Q')
- compile endif
- call ppcenter_screen()
-
-
- /* called after a compare, to set the current lines of the two files
- to c_lineno1 and c_lineno2, and center them on the screen */
-
- defproc ppend_comp
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- .line=c_lineno1
- compile if EPM
- nextfile
- compile else
- call pnextfile('Q')
- compile endif
- .line=c_lineno2
- call ppcenter_screen()
- compile if EPM
- prevfile
- compile else
- call pprevfile('Q')
- compile endif
- call ppcenter_screen()
-
-
- /* flicker procedure -- call to switch to other file */
-
- defproc ppflicker
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- if c_flicker_flag then
- c_lineno2=.line
- compile if EPM
- prevfile
- compile else
- call pprevfile()
- compile endif
- c_lineno1=.line
- call ppcenter_screen()
- c_flicker_flag=0 /* 1st file is current file */
- else
- c_lineno1=.line
- compile if EPM
- nextfile
- compile else
- call pnextfile()
- compile endif
- c_lineno2=.line
- call ppcenter_screen()
- c_flicker_flag=1 /* 2nd file is current file */
- endif
- /* end of flicker procedure definition */
-
-
- /***********************************************************************
- Procedure to center current line on screen, except that if either
- file is currently "at" a line number less than 1/2 of a screen,
- then the current position is set at that line (so they'll line up
- properly when you "flicker" with ctrl-F10). Note that I haven't
- been able to make this work for small files. Sigh.
-
- ************************************************************************/
- defproc ppcenter_screen
- universal c_flicker_flag, c_saved_flicker_flag, c_line1, c_line2
- universal c_lineno1, c_lineno2, c_last2, c_count1, c_count2
- universal c_limit1, c_limit2, c_got1, c_got2
- universal c_success, c_temp, c_inexact, fileid1, fileid2
-
- c_temp=.line
- .cursory=.windowheight%2 /* % for integer division */
- if (c_lineno1<.cursory) then
- .cursory=c_lineno1+1
- endif
- if (c_lineno2<.cursory) then
- .cursory=c_lineno2+1
- endif
- if (.cursory <= 1) then
- .cursory=2
- endif
- .cursorx=1
- c_temp
-
-
- defc loose, loosematch=
- universal c_inexact
- c_inexact=1
- sayerror 'COMPARE will use loose matching now.'
-
- defc exact, exactmatch=
- universal c_inexact
- c_inexact=0
- sayerror 'COMPARE will use exact matching now.'
-
-