home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
epm603a.zip
/
EPMSMP.ZIP
/
E3COMP.E
< prev
next >
Wrap
Text File
|
1995-01-16
|
19KB
|
528 lines
/****************************************************************************
┌───────────────────────┐
│ 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 optionally add Compare and Sync to the action bar, and not use keys.
compile if not defined(EPM)
include 'stdconst.e'
tryinclude 'mycnf.e'
compile endif
compile if not defined(USE_MENU_FOR_E3COMP)
const USE_MENU_FOR_E3COMP = 1
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
compile if USE_MENU_FOR_E3COMP
menuname='default'
buildsubmenu menuname, 30, 'Compare!', 'e3comp', 0, 0
buildsubmenu menuname, 31, 'Sync!', 'sync', 0, 0
showmenu menuname
compile endif
compile if not USE_MENU_FOR_E3COMP
def c_c='e3comp' /* define C-C to be the "compare" key */
compile endif
defc e3comp
universal c_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_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
sayerror 'comparing...'
/* 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 1
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_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_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
****************************************************************************/
compile if not USE_MENU_FOR_E3COMP
def c_s='sync' /* Define C-S to be the sync key */
compile endif
defc sync
universal c_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_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_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_inexact, fileid1, fileid2
; call ppflicker()
; c_count1=0 /* discard the saved "no match" state */
/* modify the "NEXT-FILE" definition to reset the flicker-counter */
compile if EVERSION < '4.10' -- Early E doesn't support enh. kbd.
def f10,c_N
compile else
def f10,f12,c_N
compile endif
universal c_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_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 */
compile if EVERSION < '4.10' -- Early E doesn't support enh. kbd.
def a_f10,c_P=
compile else
def a_f10,F11,c_P= -- a_F10 is usual E default; F11 for enh. kbd, c_P for EPM.
compile endif
universal c_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_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_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_inexact, fileid1, fileid2
/* if Ctrl-F10 was pressed an odd number of times, switch to 1st file */
getfileid fileid
if fileid<>fileid1 & fileid <> fileid2 then -- Neither of the original files; reset.
c_flicker_flag=0 /* 1st file is current file */
c_count1=0 /* discard the saved "no match" state */
endif
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_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_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_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_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_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_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.'