home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / gdiff.zip / gdiff.for < prev    next >
Text File  |  1999-11-22  |  57KB  |  1,928 lines

  1. c program to compute a gdiff difference between two files
  2. c
  3. c  Error returns
  4. c 1- failed to specify input file
  5. c 2- problem computing md4 (oldfile)
  6. c 3- problem computing md4 (newfile)
  7. c 4 - bad -blocksize option 
  8. c 5 - verification requires an output file
  9. c 31 - could not open old file
  10. c 32 - problem rewinding old file
  11. c 33 - old file is empty
  12. c 34 - unable to read entire oldfile into memory
  13. c 35 - unable to allocate memory while creating synopsis
  14. c 36 - verification failure
  15. c 37 - unable to open temporary file
  16. c 41 - problem allocating memory to create diff file
  17. c 42 - problem opening newfile
  18. c 43 - internal write problem
  19. c 46 - error writing to ouptut file
  20. c 47 - problem allocating memory to read newfile 
  21. c 48 - problem reading newfile (possibly eof)
  22. c 49 - unable to open output file
  23. c 51 - unable to open "difference file" 
  24. c 52 - not a gdiff formatted difference file
  25. c 53 - unable to read from difference file
  26. c 54 - unimplemented "large move" gdiff command encountered
  27. c 55 - error in ungdiff procedure 
  28. c 56 - illegal gdiff code
  29.  
  30.         include 'fsublib.fi'
  31.  
  32.         character *140 oldfile,newfile,opt1,out_file
  33.         CHARACTER *80 MK_TEMPFILENAME,TMPNAME,version
  34.         character *32 comp_md4,amd4,bmd4,newmd4,newmd4b
  35.  
  36.         integer synsize,oldsize
  37.  
  38.         integer numargs,istat,do_gdiff,do_ungdiff
  39.         integer blocksize,nblocks
  40.         integer do_synopsis 
  41.         character *(*) synopsis         !allocated later
  42.         logical qgotold,q_domd4,qgotnew,q_ungdiff,qgotout,quiet,qverify
  43.         integer i36
  44.         common /cm36/i36,quiet
  45.  
  46.  
  47.  
  48. c ------ being user changeable parameters
  49.  
  50. c blocksize used in synopsis creation (0=program chooses         
  51. c note that blocksize can be overridded by a -blocksize=nnnn argument
  52.         blocksize=0      
  53.  
  54.         i36=6                   ! std output unit number
  55.  
  56.         quiet=.false.
  57.  
  58.         version='GDIFF ver. 1.01'
  59.  
  60. c ------- end of user changeable parameters
  61.  
  62. c read arguments from command line 
  63.  
  64.         numargs=iargc()
  65.          q_ungdiff=qgotold=q_domd4=qgotnew=qgotout=qverify=.false.
  66.         
  67.         oldfile=' '
  68.         newfile=' '
  69.         out_file=' '
  70.  
  71.         do jj=1, numargs-1
  72.             mm=igetarg(jj,opt1)
  73.             if (opt1(1:1).eq.'-') then
  74.                 call captaliz(opt1)
  75.                 if (opt1(1:4).eq.'-MD4') then
  76.                    q_domd4=.true.
  77.                 endif
  78.                 if (opt1(1:4).eq.'-V') then
  79.                    qverify=.true.
  80.                 endif
  81.                 if (opt1(1:8).eq.'-VERSION') then 
  82.                     print *,version
  83.                     call fexit(0)
  84.                     stop
  85.                 endif
  86.                 if (opt1(1:4).eq.'-U') then
  87.                    q_ungdiff=.true.
  88.                 endif
  89.  
  90.                 if (opt1(1:4).eq.'-Q') then
  91.                    quiet=.true.
  92.                 endif
  93.  
  94.                 if (opt1(1:3).eq.'-B=') then
  95.                     read(opt1(4:lentrim(opt1)),*,iostat=ierr)
  96.      1                  blocksize
  97.                     if (ierr.ne.0) then
  98.                         print *,'ERROR Bad blocksize option:',
  99.      1                  opt1(1:lentrim(opt1))
  100.                         call fexit(4)
  101.                         stop
  102.                     endif
  103.                 endif
  104.                 cycle                   ! get next argument
  105.             endif
  106.             if (.not.qgotold) then           !not an option, must be afilename 
  107.                   oldfile=opt1
  108.                   qgotold=.true.
  109.             elseif (.not.qgotnew) then
  110.                  newfile=opt1
  111.                  qgotnew=.true.
  112.             else                   !the output (difference) file
  113.                  out_file=opt1
  114.                  i36=36
  115.             endif
  116.         enddo
  117.  
  118.         if (oldfile.eq. ' ' .or. oldfile.eq.'?')
  119.      1           then 
  120.             print *,'GDiff -- compute a difference between two files'
  121.             print *,' '
  122.             print *,'Syntax:'
  123.             print *,'  x:>GDiff oldfile newfile [out_file]',
  124.      1                  ' [-options]'
  125.             print *,' '
  126.             print *,'Notes: '
  127.             print *,'    * If out_file is not specified, output ',
  128.      1                    'is written to stdout  '
  129.             print *,'    * Options: '
  130.             print *,'       -MD4   -- just compute an MD4 of oldfile ',
  131.      1            ' (and newfile)'
  132.             print *,'       -u     -- undiff (newfile should be',
  133.      1              ' a Gdiff difference file)'
  134.             print *,'       -b=nnn -- use a blocksize of nnn',
  135.      1           '  (0<nnn<2000, 0=program chooses). '
  136.             print *,'       -q     -- quiet (suppress status ',
  137.      1              ' messages)'
  138.             print *,'       -v     -- verify '
  139.             print *,'       -version -- display version info '
  140.  
  141.             print *, '    * GDiff will work on any kind of file',
  142.      1              ' (text or binary)'
  143.             print *,'    * GDiff uses the RSYNC algorithim to compute',
  144.      1              ' differences'
  145.             print *,'    * Specification of the GDIFF format can be',
  146.      1              ' found at: '
  147.             print *,
  148.      1       '         http://www.w3.org/TR/NOTE-gdiff-19970901.html '
  149.             print *,' '
  150.             print *,'Examples: '
  151.             print *,'   x:>GDIFF bigdoc.old bigdoc.new bigdoc.dif -v '
  152.             print *,'   x:>GDIFF -u bigdoc.old bigdoc.dif > bigdoc.nu2'
  153.  
  154.            call fexit(0)
  155.             stop
  156.         endif
  157.  
  158.         if (newfile.eq.' '.and.(.not.q_domd4)) then
  159.            print *,'ERROR you must specify a newfile, ',
  160.      1                  'or a difference file'            
  161.           call fexit(1)
  162.           stop
  163.         endif
  164.               
  165.         if (qverify.and.(.not.q_Ungdiff).and.i36.eq.6) then
  166.              print *,'ERROR to verify, you must specify an output file'
  167.              call fexit(5)
  168.              stop
  169.         endif
  170.  
  171. c just do an md4? 
  172.         if (q_domd4) then
  173.            amd4=comp_md4(oldfile,1)
  174.            if (amd4(1:5).eq.'ERROR') then
  175.                call fexit(2)
  176.                stop 'error'
  177.            endif
  178.            if (newfile.ne.' ') then 
  179.              bmd4=comp_md4(newfile,1)
  180.              if (bmd4(1:5).eq.'ERROR') then
  181.                  call fexit(3)
  182.                  stop 'error'
  183.              endif
  184.            endif
  185.            write(6,*)amd4,' ',bmd4
  186.            call fexit(0)
  187.            stop
  188.         endif
  189.  
  190.  
  191. c compute the GDIFF file, or the undiff file.
  192.  
  193. c in either case, open the oldfile
  194.  
  195. c open the "old" file
  196.         open(unit=41,file=oldfile,access='sequential',status='old',
  197.      1   form='unformatted',recordtype='fixed',iostat=ierr,
  198.      1   action='read')
  199.      
  200.         if (ierr.ne.0) then 
  201.            print *,'ERROR no such file: ',oldfile
  202.            call fexit(31)
  203.            stop
  204.         endif
  205.         rewind(unit=41,iostat=ierr) 
  206.         if (ierr.ne.0) then
  207.            print *,'ERROR unable to read: ',oldfile
  208.            call fexit(32)
  209.            stop
  210.         endif
  211.         oldsize=filesize(41)
  212.         if (oldsize.eq.0) then
  213.             print *,'ERROR empty ',oldfile
  214.             call fexit(33)
  215.             stop
  216.         endif
  217.  
  218. c possibly adjust blocksize 
  219.         if (blocksize.le.0.and. (.not.q_ungdiff)) then 
  220.            if (oldsize.lt.10000) then
  221.                  blocksize=50
  222.            elseif (oldsize.lt.25000) then
  223.                 blocksize=100
  224.            elseif (oldsize.lt.100000) then
  225.                 blocksize=250
  226.            elseif (oldsize.lt.2500000) then
  227.                 blocksize=500
  228.            else
  229.                 blocksize=1000
  230.            endif
  231.            if (.not.quiet.and.i36.ne.6) then
  232.                print *,'Using blocksize of ',blocksize                 
  233.            endif
  234.         endif
  235.  
  236. c Undifference?
  237.       if (q_ungdiff) then
  238.          istat=do_ungdiff(41,newfile,out_file,0)  
  239.          close(unit=41,iostat=ierr)
  240.          if (istat.ne.0) then         !some kind of error
  241.             call fexit(istat)           !write it as output status
  242.             WRITE(6,81)ISTAT
  243.  81         FORMAT('ERROR: ',I5)
  244.             call fexit(istat)
  245.             stop                        ! and give up
  246.         endif
  247.         call fexit(0)
  248.         stop
  249.       endif
  250.   
  251.  
  252. c --- IF here : compute a gdiff difference file
  253. c first, compute a rync synopsis
  254. c so let's allocate space for the synopsis
  255.  
  256.         nblocks=(float(oldsize)/float(blocksize))+0.99999
  257.         synsize=nblocks*20
  258.         allocate (synopsis*synsize,stat=ierr)
  259.         if (ierr.ne.0) then
  260.            call fexit(35)
  261.            stop
  262.         endif
  263.  
  264. c if here, file is open and ready to read
  265. C        print *,' pre dosyn ',nblocks,blocksize
  266.         istat=do_synopsis(41,oldsize,synopsis,blocksize,nblocks)
  267. C        print *,' post dosyn '
  268.         if (istat.ne.0) then       !some kind of error
  269.             call fexit(istat)           !write it as output status
  270.             stop                        ! and give up
  271.         endif
  272.  
  273.  
  274. c then use rsync to compute a gdiff formatted diference file
  275. c (write it to stdout)
  276.  
  277.         istat=do_gdiff(newfile,synopsis,out_file,blocksize,nblocks)
  278.         deallocate(synopsis,stat=ierr)
  279.  
  280.         if (istat.ne.0) then         !some kind of error
  281.             call fexit(istat)           !write it as output status
  282.             WRITE(6,181)ISTAT
  283.  181        FORMAT('ERROR: ',I5)
  284.             stop                        ! and give up
  285.         endif
  286.         
  287. c verify ?
  288.         if ((.not.qverify).or.(i36.eq.6)) then
  289.           close(unit=41,iostat=ierr)
  290.           call fexit(0)
  291.           stop
  292.         endif
  293.  
  294. c md4 of "newfile"
  295.         newmd4=comp_md4(newfile,1)
  296.  
  297. c md4 of "reconstruction"
  298.         TMPNAME=MK_TEMPFILENAME()
  299.         ii=do_ungdiff(41,out_file,TMPNAME,1)
  300.         if (ii.ne.0) then
  301.            call fexit(36)
  302.            stop
  303.         endif        
  304.         newmd4b=comp_md4(TMPNAME,1)
  305.         close(unit=41,iostat=ierr)
  306.  
  307.         if (newmd4.ne.newmd4b) then
  308.            print *,'ERROR verification failed! '
  309.            print *,'  (md4 hashes are: ',newmd4,newmd4b,')'
  310.            call fexit(36)
  311.            OPEN(UNIT=61,FILE=TMPNAME,IOSTAT=IERR)  !DELETE TEMPFILE
  312.            CLOSE(UNIT=61,STATUS='DELETE',IOSTAT=IERR)
  313.            STOP
  314.         ELSE
  315.            IF (.NOT.QUIET) THEN
  316.                 PRINT *,'Reconstructed file passes verification test'
  317.            ENDIF
  318.         endif
  319.         
  320.  
  321.         OPEN(UNIT=61,FILE=TMPNAME,IOSTAT=IERR)  !DELETE TEMPFILE
  322.         CLOSE(UNIT=61,STATUS='DELETE',IOSTAT=IERR)
  323.         call fexit(0)           !SUCCESS 
  324.  
  325.         end
  326.  
  327. C---------
  328. C CREATE A TEMPORARY FILE NAME
  329.         CHARACTER *(*) FUNCTION MK_TEMPFILENAME()
  330.         CHARACTER *80 ANAME,TMPDIR
  331.         CHARACTER *13 ANAME0
  332.         INCLUDE 'FSUBLIB.FI'
  333.         logical qexist
  334.         integer *2 ihr,imin,isec,ihsec
  335.         INTEGER MM,NN
  336.  
  337.         II=FGETENV('TEMP',TMPDIR)
  338.         IF (II.EQ.0) THEN
  339.             PRINT *,'ERROR no TEMP directory (can not verify)'
  340.             call fexit(37)
  341.             STOP
  342.         endif
  343.         if (tmpdir(lentrim(tmpdir):lentrim(tmpdir)).eq.'\') then
  344.            tmpdir=tmpdir(1:lentrim(tmpdir)-1)
  345.         endif
  346.         call gettim(ihr,imin,isec,ihsec)
  347.         do mm=11,99
  348.            nn=10000+imin*360+isec*60+ihsec
  349.            write(aname0,55)nn,mm
  350.  55        format('\GDF',I5,'.T',I2)
  351.            aname=tmpdir(1:lentrim(tmpdir))//aname0
  352.            inquire(file=aname,exist=qexist)
  353.            if (.NOT.qexist) EXIT
  354.         enddo
  355.         if (qexist) then
  356.             PRINT *,'ERROR could not find unused temp name ',
  357.      1          ' (can not verify)'
  358.             call fexit(37)
  359.             STOP
  360.         endif
  361.         
  362.         mk_tempfilename=aname
  363.         return
  364.         end
  365.                 
  366.  
  367.         
  368.  
  369. c=--------------------------------------
  370. c compute an rsync synopsis
  371.  
  372.         integer function do_synopsis(iunit,oldsize,synopsis,
  373.      1                         blocksize,nblocks)
  374.         
  375.         character *(*) synopsis,ablock
  376.         character *32 md1,comp_md4
  377.         character *20 ablock20
  378.         character *8 rs1,rsync32
  379.         integer oldsize,i1
  380.         integer blocksize,nblocks,inext,iunit
  381.         integer mm,jj,ith1
  382.  
  383.         allocate (ablock*blocksize,stat=ierr)
  384.         if (ierr.ne.0) then
  385.              do_synopsis=35
  386.             return
  387.         endif
  388.  
  389. c 20 character entries per block: 4 for rsync32, 16 for md4        
  390.         inext=1
  391.         do ii=1,nblocks
  392.             iget=min(blocksize,1+oldsize-inext)
  393.             read(iunit)ablock(1:iget)
  394.             inext=inext+blocksize
  395.             ith1=0
  396.             rs1=rsync32(ablock(1:iget))
  397.             do mm=1,7,2
  398.                read(rs1(mm:MM+1),99)jj
  399.                ith1=ith1+1
  400.                ablock20(ith1:ith1)=char(jj)
  401.             enddo
  402.  99         format(z2)
  403.  
  404.             md1=comp_md4(ablock(1:iget),0)
  405.             do mm=1,31,2
  406.                read(md1(mm:MM+1),99)jj
  407.                ith1=ith1+1
  408.                ablock20(ith1:ith1)=char(jj)
  409.             enddo
  410.             i1=(ii-1)*20
  411.             synopsis(i1+1:i1+20)=ablock20
  412.         enddo
  413.  
  414. c note: synopsis is returned as an argument
  415.  
  416.         do_synopsis=0           !no error
  417.         deallocate(ablock,stat=ierr)
  418.         return
  419.         end
  420.  
  421.  
  422.  
  423.  
  424. c------------------
  425. c compute a 32 bit rolling checksum 
  426.         character *(*) function rsync32(astring)
  427.  
  428.         character *(*) astring
  429.         character *8 chksum8
  430.         integer chksum,i2,isum,isumb,ilen
  431.  
  432.         ilen=len(astring)
  433.         isumb=isum=0
  434.  
  435.         do i1=1,ilen
  436.           i2=ichar(astring(i1:i1))
  437.           isum=isum+i2
  438.           isumb=((ilen-i1+1)*i2) + isumb
  439.         enddo 
  440.         isum=mod(isum,65536)
  441.         if (isum.lt.0)isum=isum+65536
  442.  
  443.         isumb=mod(isumb,65536)
  444.         if (isumb.lt.0)isumb=isumb+65536
  445.  
  446.         chksum=isum +  (65536*isumb)
  447.  
  448.         write(chksum8,883,iostat=ierr)chksum
  449.  
  450.  883    format(z8)
  451.         rsync32=chksum8
  452.         return
  453.  
  454.         END
  455.  
  456.  
  457. c=--------------------------------------
  458. c compute md4 of a file. Call it asL
  459. c           aa=comp_md4(contents,mode)
  460. c  where aa is character *32
  461. c  contents: filename, or string
  462. c  filemode: if 1, contents is read from filename.
  463. c            otherwise, contents contains the contents
  464.  
  465.     character *(*) function comp_MD4(contents,filemode)
  466.  
  467.         character *32 a32
  468.         character *(*)contents
  469.  
  470.         integer addme,lenorig,lenorig8,filemode
  471.  
  472.         integer *1 pads(64)
  473.         data pads/'80'x,63*'00'x/
  474.  
  475.         integer *1 i1a(4)               !use this for working with 
  476.         integer  i4a
  477.         equivalence (i4a,i1a)
  478.  
  479.         integer mess16(16),x(0:15)                 !16 word chunk to digest
  480.         integer *1 mess64(64)
  481.         equivalence(mess16,mess64,x)
  482.  
  483.         integer lenbits(2)              !# bits in message
  484.         integer *1 lenbits_1(8)
  485.         equivalence(lenbits,lenbits_1)
  486.        
  487.         character *32 ans
  488.         integer leftover,addbytes,dessize
  489.         integer a,b,c,d,aa,bb,cc,dd,il,icc,k,i16,i1,len2,len3,j
  490.  
  491.         integer s11,s12,s13,s14,s21,s22,s23,s24,s31,s32,s33,s34
  492.         integer inbuffer,endbuffer
  493.  
  494.         character *1 a1lc(6)
  495.         data a1lc/'a','b','c','d','e','f'/
  496.  
  497.         character *2048 buffer2048
  498.  
  499.         character *1 achar64(64)
  500.         integer ikk,ngrab
  501.  
  502.         include 'fsublib.fi'
  503.  
  504. c read the inputfile?
  505.         if (filemode.eq.1) then
  506.           open(unit=43,file=contents,access='sequential',status='old',
  507.      1     form='unformatted',recordtype='fixed',iostat=ierr,
  508.      1     action='read')
  509.      
  510.           if (ierr.ne.0) then 
  511.               write(a32,77)ierr
  512.  77           format('ERROR opening file: ',i6)
  513.               comp_md4=a32
  514.               return
  515.           endif
  516.           rewind(unit=43,iostat=ierr)
  517.           if (ierr.ne.0) then
  518.              comp_md4='ERROR could not rewind file'
  519.              return
  520.           endif
  521.           dessize=filesize(43)
  522.           if (dessize.eq.0) then
  523.              comp_md4='ERROR empty file'
  524.              return
  525.           endif
  526.  
  527.         else                            !use contents as is
  528.           dessize=len(contents)
  529.         endif        
  530.  
  531. c nb: md4 of '' is d41d8cd98f00b204e9800998ecf8427e
  532.     
  533.         lenorig=dessize
  534.         lenorig8=8*lenorig
  535.         lenbits(1)=lenorig8
  536.         
  537.         leftover=mod(lenorig8,512)
  538. c pad message to multiple of 512 bits. 
  539. c Last 2 words are 64 bit # bits in message
  540.         if (leftover.eq.448) addme=512
  541.         if (leftover.lt.448) addme=448-leftover
  542.         if (leftover.gt.448) addme=960-leftover
  543.         addBYTES=addme/8
  544.  
  545. c  starting values of registers   
  546.        a ='67452301'x 
  547.        b ='efcdab89'x 
  548.        c ='98badcfe'x 
  549.        d ='10325476'x 
  550.  
  551.        len2=lenorig+ADDBYTES
  552.        len3=len2+8              ! FINAL LENGTH IN BYTES, must be multiple of 64
  553.  
  554.        
  555. c load buffer
  556.        
  557.        if (filemode.eq.1.and.lenorig.gt.2048) then
  558.            read(43,iostat=ierr)buffer2048
  559.            inbuffer=1
  560.            endbuffer=2048
  561.        else
  562.             endbuffer=0
  563.        endif        
  564.  
  565. c  loop through entire message -- 16 words at a time   
  566.        do i1 = 0,((len3/64)-1)
  567.           i16=i1*64
  568.  
  569. c if file mode, load up achar64 buffer (possibly from 2k buffer) 
  570.           if (filemode.eq.1) then               ! read from file
  571.            if (i16+64.le.endbuffer) then  !use the buffer (perhaps refill it)
  572.               do ii1=inbuffer,inbuffer+63
  573.                   achar64(1+ii1-inbuffer)=buffer2048(ii1:ii1)
  574.               enddo
  575.               inbuffer=inbuffer+64
  576.               if (inbuffer.gt.1985.and.(endbuffer+2048.lt.lenorig))
  577.      1                   then
  578.                 read(43,iostat=ierr)buffer2048
  579.                 endbuffer=endbuffer+2048
  580.                 inbuffer=1
  581.               endif
  582.            else                  ! near the end of the file
  583.              if (i16.lt.lenorig) then
  584.                 ngrab=min(64,lenorig-i16)
  585.                 read(43)(achar64(ikk),ikk=1,ngrab) 
  586.              endif               !direct read of achar64
  587.             endif               ! read from buffer
  588.            endif              ! read from file
  589.  
  590.  
  591.           do j=1,64            ! start computing stuff for this 64byte 
  592.  
  593.              k=i16+j    !add this byte 
  594. C add byte from message, padding, or length 
  595.              if (k.le.lenorig) then
  596.                  if (filemode.eq.1) then
  597.                      mess64(j)=ichar(achar64(j))
  598.                   else
  599.                      mess64(j)=ichar(contents(k:k))
  600.                   endif
  601.              else
  602.                 if (k.le.len2) then
  603.                  mess64(j)=pads(k-lenorig)
  604.                 else
  605.                   mess64(j)=lenbits_1(k-len2)
  606.                 ENDIF
  607.              ENDIF
  608.           ENDDO                 !64 BYTES OF BLOCK
  609.  
  610. c  transform this block of 16 chars to 4 values. Save prior values first */
  611.         aa=a
  612.         bb=b
  613.         cc=c
  614.         dd=d
  615.  
  616.  
  617. c do 4 rounds, 16 operations per round (rounds differ in bit'ing functions 
  618.  
  619.         S11=3
  620.         S12=7 
  621.         S13=11
  622.         S14=19
  623.  
  624.           call round1_4(a, b, c, d, x( 0), S11)  ! /* 1 */
  625.           call round1_4(d, a, b, c, x( 1), S12) ! /* 2 */
  626.           call round1_4(c, d, a, b, x( 2), S13) !  /* 3 */
  627.           call round1_4(b, c, d, a, x( 3), S14) !  /* 4 */
  628.           call round1_4(a, b, c, d, x( 4), S11) !  /* 5 */
  629.           call round1_4(d, a, b, c, x( 5), S12) !  /* 6 */
  630.           call round1_4(c, d, a, b, x( 6), S13) !  /* 7 */
  631.           call round1_4(b, c, d, a, x( 7), S14) !  /* 8 */
  632.           call round1_4(a, b, c, d, x( 8), S11) !  /* 9 */
  633.           call round1_4(d, a, b, c, x( 9), S12) !  /* 10 */
  634.           call round1_4(c, d, a, b, x(10), S13) !  /* 11 */
  635.           call round1_4(b, c, d, a, x(11), S14) !  /* 12 */
  636.           call round1_4(a, b, c, d, x(12), S11) !  /* 13 */
  637.           call round1_4(d, a, b, c, x(13), S12) !  /* 14 */
  638.           call round1_4(c, d, a, b, x(14), S13) !  /* 15 */
  639.           call round1_4(b, c, d, a, x(15), S14) !  /* 16 */
  640.  
  641.  
  642.  
  643. c /* Round 2 */
  644.         S21=3
  645.         S22=5
  646.         S23=9 
  647.         S24=13
  648.  
  649.           call round2_4(a, b, c, d, x( 0), S21) !  /* 17 */
  650.           call round2_4(d, a, b, c, x( 4), S22) !  /* 18 */
  651.           call round2_4(c, d, a, b, x( 8), S23) !  /* 19 */
  652.           call round2_4(b, c, d, a, x(12), S24) !  /* 20 */
  653.           call round2_4(a, b, c, d, x( 1), S21) !  /* 21 */
  654.           call round2_4(d, a, b, c, x( 5), S22) !  /* 22 */
  655.           call round2_4(c, d, a, b, x( 9), S23) !  /* 23 */
  656.           call round2_4(b, c, d, a, x(13), S24) !  /* 24 */
  657.           call round2_4(a, b, c, d, x( 2), S21) !  /* 25 */
  658.           call round2_4(d, a, b, c, x( 6), S22) !  /* 26 */
  659.           call round2_4(c, d, a, b, x(10), S23) !  /* 27 */
  660.           call round2_4(b, c, d, a, x(14), S24) !  /* 28 */
  661.           call round2_4(a, b, c, d, x( 3), S21) !  /* 29 */
  662.           call round2_4(d, a, b, c, x( 7), S22) !  /* 30 */
  663.           call round2_4(c, d, a, b, x(11), S23) !  /* 31 */
  664.           call round2_4(b, c, d, a, x(15), S24)!  /* 32 */
  665.  
  666. c  /* Round 3 */
  667.         S31= 3
  668.         S32= 9 
  669.         S33= 11
  670.         S34= 15
  671.  
  672.           call round3_4(a, b, c, d, x( 0), S31) !  /* 33 */
  673.           call round3_4(d, a, b, c, x( 8), S32) !  /* 34 */
  674.           call round3_4(c, d, a, b, x( 4), S33) !  /* 35 */
  675.           call round3_4(b, c, d, a, x(12), S34) !  /* 36 */
  676.           call round3_4(a, b, c, d, x( 2), S31) !  /* 37 */
  677.           call round3_4(d, a, b, c, x(10), S32) !  /* 38 */
  678.           call round3_4(c, d, a, b, x( 6), S33) !  /* 39 */
  679.           call round3_4(b, c, d, a, x(14), S34) !  /* 40 */
  680.           call round3_4(a, b, c, d, x( 1), S31) !  /* 41 */
  681.           call round3_4(d, a, b, c, x( 9), S32) !  /* 42 */
  682.           call round3_4(c, d, a, b, x( 5), S33) !  /* 43 */
  683.           call round3_4(b, c, d, a, x(13), S34) !  /* 44 */
  684.           call round3_4(a, b, c, d, x( 3), S31) !  /* 45 */
  685.           call round3_4(d, a, b, c, x(11), S32) !  /* 46 */
  686.           call round3_4(c, d, a, b, x( 7), S33) !  /* 47 */
  687.           call round3_4(b, c, d, a, x(15), S34) !  /* 48 */
  688.  
  689.  
  690.         A=AA+A
  691.         B=BB+B
  692.         C=CC+C
  693.         D=D+DD
  694.  
  695.  
  696.       enddo
  697.  
  698.       i4a=a
  699.       write(ans(1:8),'(4(z2))')i1a
  700.    
  701.       i4a=b
  702.       write(ans(9:16),'(4(z2))')i1a
  703.  
  704.       i4a=c
  705.       write(ans(17:24),'(4(z2))')i1a
  706.  
  707.       i4a=d
  708.       write(ans(25:32),'(4(z2))')i1a
  709.  
  710. c convert to lower case
  711.        do il=1, 32
  712.           icc=index('ABCDEF',ANS(IL:il))
  713.           if (icc.gt.0) ans(il:il)=a1lc(icc)
  714.        enddo
  715.         
  716.       close(unit=43,iostat=ierr)
  717.       comp_md4=ans
  718.       return
  719.       end
  720.  
  721.  
  722. C  /* md4 round 1 to 4 functins */
  723.  
  724.         SUBROUTINE round1_4(a1,b1,c1,d1,kk,shift)
  725.         INTEGER A1,B1,C1,D1,Kk,SHIFT,T1,T2,f_4
  726.         
  727.         t1=a1+f_4(b1,c1,d1)+ kk 
  728.  
  729.         t2=ISHC(t1,shift)
  730.         A1=T2
  731.         return 
  732.         END
  733.  
  734.  
  735.         SUBROUTINE round2_4(a1,b1,c1,d1,kk,shift)
  736.         INTEGER A1,B1,C1,D1,Kk,SHIFT,T1,T2,g_4,aconst
  737.  
  738.         aconst='5a827999'x
  739.  
  740.         t1=a1+G_4(b1,c1,d1)+ kk + aconst
  741.         t2=ISHC(t1,shift)
  742.         A1=T2
  743.         return 
  744.         END
  745.  
  746.         SUBROUTINE round3_4(a1,b1,c1,d1,kk,shift)
  747.         INTEGER A1,B1,C1,D1,Kk,SHIFT,aconst,T1,T2,h_4
  748.  
  749.         aconst='6ed9eba1'x
  750.  
  751.         t1=a1+H_4(b1,c1,d1)+ kk + aconst
  752.         t2=ISHC(t1,shift)
  753.         A1=T2
  754.         return 
  755.         END
  756.  
  757.  
  758.  
  759.  
  760. c*********** Basic functions */
  761. c* F_4(x, y, z) == (((x) & (y)) | ((~x) & (z))) */
  762.         INTEGER FUNCTION f_4(X,Y,Z)
  763.         INTEGER X,Y,Z,T1,NOTX,t2
  764.         t1=Iand(x,y)
  765.         notx=NOT(x)
  766.         t2=Iand(notx,z)
  767.         t2=Ior(t1,t2)
  768.         f_4=t2
  769.         RETURN
  770.         END
  771.  
  772. c* G_4(x, y, z) == (((x) & (z)) | ((x) & (y)) | ((y) & (z)) ) */
  773.         INTEGER FUNCTION G_4(X,Y,Z)
  774.         INTEGER X,Y,Z,T1,T2,t3,t4
  775.  
  776.         T1=Iand(x,y)
  777.         t2=Iand(x,z)
  778.         t3=iand(y,z)
  779.         t4=Ior(t1,t2)
  780.         g_4=ior(t3,t4)
  781.         RETURN
  782.         END
  783.  
  784. c* H_4(x, y, z) == ((x) ^ (y) ^ (z)) */
  785.         INTEGER FUNCTION H_4(X,Y,Z)
  786.         INTEGER X,Y,Z,T1
  787.  
  788.         t1=IEor(x,y)
  789.         H_4=IEor(t1,z)
  790.         RETURN
  791.         END
  792.  
  793.  
  794.  
  795. c------------------------------
  796. c capitalize a string
  797.  
  798.         subroutine captaliz(sent)
  799.  
  800.         character *(*)sent
  801.         character *1 char
  802.  
  803.         do 100 ij=1,len(sent)
  804.             let=ichar(sent(ij:IJ))
  805.             if (let.ge.97.and.let.le.122) sent(ij:ij)=char(let-32)
  806.  100    continue
  807.         return
  808.         end
  809.  
  810.  
  811. c-----------------------
  812. c using synopsis, and the rsync algorithim, compute a difference and
  813. c output it as a gdiff file (to stdout)
  814.  
  815.         integer function do_gdiff(newfile,synopsis,out_file,
  816.      1                    blocksize,nblocks)
  817.  
  818.         include 'fsublib.fi'
  819.  
  820.     character *(*) synopsis,newfile,ablock,out_file
  821.  
  822.         character *4 ctmp4
  823.         character  *8 ctmp8
  824.         character *32 ctmp32,comp_md4
  825.         character *16 ctmp16
  826.  
  827.         character *20 aline20
  828.         integer mm,ierr,ierrout,ioerror,iserror
  829.         integer ierr1,ierr2,ierr3,ierr4
  830.  
  831.         integer i36
  832.         logical quiet
  833.         common /cm36/i36,quiet
  834.  
  835.         integer hasht(0:65535)
  836.  
  837.         character *10 t1     
  838.         character *5 t2      
  839.         character *1 ac1,ac1a
  840.                 
  841.         integer rsyncs16(:)
  842.         integer rsyncs(:)
  843.         integer index_rsyncs16(:)
  844.         character *16 md4s(:)
  845.  
  846.         integer nblocks,blocksize,ll
  847.         integer matchblock,read_new
  848.         integer ib1,ib2,ialpha,ibeta,chksum
  849.         integer rsync_increment_s
  850.         integer ihasht,i1,blklen,ifoo,gdiff_write,write_6
  851.  
  852.         logical qfirst_32
  853.  
  854.         character *1 wastype
  855.         integer was0,was1,newsize,def_blksiz
  856.         common /ccache/wastype,was0,was1,newsize,def_blksiz
  857.  
  858.  
  859. c the newfile buffer
  860.         character *96384 buffer
  861.         integer bufstart,bufend
  862.         common /ccache2/buffer,bufstart,bufend
  863.  
  864. c do some initializations
  865.         def_blksiz=blocksize            ! default blocksize, used by gdiff_write
  866.         qfirst_32=.false.
  867.         wastype=' '
  868.         do mm=0,65535
  869.            hasht(mm)=0
  870.         enddo
  871.  
  872. c create some storage space
  873.         allocate(rsyncs(1:nblocks),stat=ierr1)
  874.         allocate(index_rsyncs16(1:nblocks),stat=ierr2)
  875.         allocate(md4s(1:nblocks),stat=ierr3)
  876.         allocate(rsyncs16(1:nblocks),stat=ierr4)
  877.         if (ierr1+ierr2+ierr3+ierr4.ne.0) then
  878.           do_gdiff=41
  879.           return
  880.         endif
  881.  
  882. C        print *,' post allocate '
  883.  
  884. c read in nblocks from synopsis (rsync32~md4 pairs)
  885.         do mm=1,nblocks
  886.             i1=1+((mm-1)*20)
  887.             aline20=synopsis(i1:i1+19)
  888.             write(ctmp8,68,err=2024)aline20(1:4)
  889.             read(ctmp8,68,err=2024)rsyncs(mm)
  890.             md4s(mm)=aline20(5:20)
  891.             write(ctmp4,66,err=2024)aline20(1:2)
  892.  66         format(z4)
  893.  68         format(z8)
  894.             read(ctmp4,66,err=2024)rsyncs16(mm)
  895.         enddo
  896.  
  897. C        print *,' done reading synops8s '
  898. c sort each record (sort by leftmost 16 bit hash, as stored in rsyncs16) 
  899.         call quik_indexsort(rsyncs16,index_rsyncs16,nblocks)
  900. C        print *,' post quik '
  901. c  now make the 65k hash table 
  902.         call make_hashtable(nblocks,index_rsyncs16,rsyncs16,hasht)
  903. C        print *,' post hash '
  904. c now open the new version as unit 21  (will set newsize global)
  905.         ifoo=read_new(0,0,newfile)
  906.         if (ifoo.le.0) then     !problem
  907.              do_gdiff=42  
  908.              return
  909.         endif
  910.  
  911. c open output file and  write gdidff header
  912. c open output file
  913.        if (i36.ne.6) then
  914.          open(unit=i36,file=out_file,recordtype='FIXED',
  915.      1                access='sequential',
  916.      1               form='unformatted',iostat=ierr,action='WRITE')
  917.           if (ierr.ne.0) then
  918.               print *,'ERROR Unable to open output file:  ',out_file
  919.               do_gdiff=49
  920.               return
  921.           endif
  922.        endif
  923.  
  924.        t1='d1ffd1ff04'      
  925.        read(t1,13)t2        
  926. 13     format(z10)          
  927.        
  928.        ioerror=write_6(t2)
  929.        if (ioerror.ne.0) then
  930.             do_gdiff=46
  931.             return
  932.        endif
  933.  
  934. c set up stuff to prance through
  935.         ib1=1
  936.         ib2=ib1+blocksize
  937.  
  938.         allocate(ablock*blocksize,stat=ierr)
  939.         if (ierr.ne.0) then
  940.             do_gdiff=47
  941.             return
  942.         endif
  943.  
  944. c read first block (blocksize bytes) of data 
  945.         blklen=read_new(1,ib2-1,ablock)
  946.         if (BLKLEN.lt.0) then
  947.           PRINT *,'ERROR at first block read'
  948.             do_gdiff=48
  949.             return
  950.         endif
  951.  
  952. c compute the rsync for the first block..
  953.         call rsync32_compute(ablock,chksum,ialpha,ibeta)
  954.  
  955. C        print *,' rsync done '
  956.  
  957. c now start the waltz
  958. c from ith char, look for matching block
  959. c if not found, write the character
  960. c if found, write the character
  961. c note that writeit will "cache" results
  962.  
  963.         do while (ib1.le.newsize)  ! stop when all chars examined
  964.            matchblock=0
  965. c check the check16 against the hashtable, etc.
  966.           ihasht=hasht(ibeta)
  967.           if (ihasht.Ne.0) then
  968.               DO LL=IHASHT,NBLOCKS
  969.                  mm=index_rsyncs16(LL)
  970.                  IF (RSYNCS16(MM).NE.IBETA) EXIT  !NO MATCH
  971.                  IF (RSYNCS(MM).NE.CHKSUM) CYCLE  !TRY NEXT 32BIT HASH
  972.  
  973.                  blklen=read_new(ib1,ib2-1,ablock)        !now get actual block
  974.                  if (BLKLEN.lt.0) then            !to compute md4
  975.                    print *,'ERROR at block read pre md4 '
  976.                    do_gdiff=48
  977.                    return
  978.                  endif
  979.  
  980.                  ctmp32=comp_md4(ablock(1:blklen),0)
  981.                  read(ctmp32,133,err=2024)ctmp16      !try the 128 bit hash
  982.  133             format(z32)
  983.                  if (qfirst_32) then     ! just look at  first 32 bits?
  984.                      if (ctmp16(1:4).ne.md4s(mm)(1:4)) cycle
  985.                  else 
  986.                      if (ctmp16.ne.md4s(mm)) cycle    !look at 128 bits  
  987.                  endif
  988.                  matchblock=mm
  989.                  exit
  990.               enddo
  991.           endif                 !hash table match
  992.  
  993. c no match? record this character, and roll the rsync ...
  994.           if (matchblock.eq.0) then            !not a matching block 
  995.                iserror=gdiff_write('C',ib1,0)
  996.                if (iserror.ne.0) then
  997.                    rsync_gdiff=46
  998.                    return
  999.                endif
  1000.             
  1001. c COMPUTE ROLLING CHECKSUM (also save alpha,beta
  1002.             if (ib2.le.newsize) then            !increment 32bit checksum
  1003.                 ifoo=read_new(ib2,ib2,ac1)
  1004.                 if (ifoo.lt.0) then
  1005.                    print *,
  1006.      1      'ERROR reading last char (',ib2,') for rolling checksum'
  1007.                     do_gdif=48
  1008.                     return
  1009.                 endif
  1010.                 ifoo=read_new(ib1,ib1,ac1a)
  1011.                 if (ifoo.lt.0) then
  1012.                    print *,
  1013.      1      'ERROR reading first char (',ib1,') for rolling checksum'
  1014.                     do_gdif=48
  1015.                     return
  1016.                 endif
  1017.  
  1018.                  chksum=rsync_increment_s(ac1a,ac1,ialpha,   !compute rolling checksum
  1019.      1                                   ibeta,blocksize)
  1020.  
  1021.                ib1=ib1+1                   ! begin next block here 
  1022.                ib2=ib2+1
  1023.             else
  1024.                 if (ib1.ge.newsize) exit  !all done
  1025.                 ib1=ib1+1                   ! begin next block here
  1026.                 blklen=read_new(ib1,newsize,ablock)  !too messy to compute increment,
  1027.                 if (blklen.lt.0) then
  1028.                   do_gdiff=48
  1029.                   print *,'ERROR reading near end of file block '
  1030.                   return
  1031.                 endif
  1032.                 call rsync32_compute(ablock(1:blklen),chksum,     !so just compute using 
  1033.      1                               ialpha,ibeta)              !all characters
  1034.                 ib2=newsize+1
  1035.             endif
  1036.             cycle                       !get next block
  1037.          endif                          !  not a match
  1038.  
  1039. c if here, got a rsync16, 32, and md4 match. So write some results
  1040.  
  1041.          iserror=gdiff_write('B',matchblock,blklen)
  1042.          if (iserror.ne.0) then
  1043.               rsync_gdiff=49
  1044.               return
  1045.          endif
  1046.  
  1047.          if (ib2.gt.newsize) exit  ! done
  1048.          ib1=ib1+blocksize     ! skip past this block, and start searching again 
  1049.          ib2=ib1+blocksize      
  1050.          blklen=read_new(ib1,ib2-1,ablock)
  1051.          if (blklen.lt.0) then
  1052.                 print *,'ERROR reading skip to next block '
  1053.                 do_gdiff=48
  1054.                 return
  1055.         endif
  1056.          call rsync32_compute(ablock(1:blklen),chksum,ialpha,ibeta)
  1057.  
  1058.        enddo            !scan over all characters 
  1059.  
  1060. c add any "unmatched characters 
  1061.         iserror=gdiff_write('F',0,0)
  1062.         if (iserror.ne.0) then
  1063.             rsync_gdiff=46
  1064.             return
  1065.         endif
  1066.  
  1067.         call write_int(0,1)   ! close gdiff file
  1068.  
  1069.         close (unit=21,iostat=ierrout)  !close new file
  1070.         close (unit=36,iostat=ierrout)  ! close output file
  1071.  
  1072.         if (.not.quiet.and.i36.ne.6) then
  1073.           open(unit=i36,file=out_file,iostat=ierr,
  1074.      1         action='read',form='unformatted')
  1075.           if (ierr.ne.0) return
  1076.           iout=filesize(36)
  1077.           if (lentrim(out_File).lt.40) then
  1078.               write(6,51)iout,out_file(1:lentrim(out_file))
  1079.  51           format('OK ',i9,' bytes written to difference file ',a)
  1080.            else
  1081.               write(6,53)iout,out_file(1:lentrim(out_file))
  1082.  53           format('OK ',i9,' bytes written to difference file: '/a)
  1083.            endif
  1084.            close(unit=i36,iostat=ierr)
  1085.        endif
  1086.  
  1087.         deallocate(rsyncs,stat=ierr )
  1088.         deallocate(md4s,stat=ierr )
  1089.         deallocate(rsyncs16,stat=ierr )
  1090.         deallocate(index_rsyncs16,stat=ierr )
  1091.         deallocate(ablock,stat=ierr)
  1092.  
  1093.         do_gdiff=0
  1094.         return
  1095.  
  1096.  
  1097. c ------ status and errors
  1098.  2024   continue
  1099.         do_gdiff=43
  1100.         return
  1101.  
  1102.  
  1103.       end       
  1104.  
  1105. c-------------------------------------------
  1106. c write to an output device (on unit i36)
  1107.         integer function write_6(ac)
  1108.         character *(*)ac
  1109.  
  1110.         integer i36
  1111.         logical quiet
  1112.         common /cm36/i36,quiet
  1113.  
  1114.         if (i36.ne.6) then
  1115.             write(i36,iostat=ierr)ac
  1116.             write_6=ierr
  1117.             return
  1118.         else
  1119.         ill=len(ac)
  1120.            do mm=1,ill
  1121.              write(i36,55,iostat=ierr)ac(mm:mm)
  1122.              if (ierr.ne.0) then
  1123.                 write_6=ierr
  1124.                 return
  1125.              endif          
  1126.            enddo
  1127.            write_6=0
  1128.            return
  1129.          endif
  1130.  55     format(a1,$)
  1131.  
  1132.         end
  1133.         
  1134.  
  1135. c-------------------------------------------
  1136. c function to read from unit 21, into astring.
  1137. c start and end bytes of read are given, as well
  1138. c as file size (if end of read>filesize, read 
  1139. c until filesize).
  1140. c Returns astring in argument,
  1141. c function value is  length of astring (usually
  1142. c 1+end-start, but possibly 1+file_size-start read from 
  1143.  
  1144.         integer function read_new(istart,iend0,astring)
  1145.  
  1146.         include 'fsublib.fi'
  1147.  
  1148.         integer istart,iend,iend0
  1149.         character *(*) astring
  1150.  
  1151.         integer ido,ierr
  1152.         character *1 wastype
  1153.         integer was0,was1,newsize,def_blksiz
  1154.         common /ccache/wastype,was0,was1,newsize,def_blksiz
  1155.  
  1156. c the newfile buffer
  1157.         character *96384 buffer
  1158.         integer bufstart,bufend
  1159.         common /ccache2/buffer,bufstart,bufend
  1160.   
  1161.       
  1162. c initialize?
  1163.         if (istart+iend0.eq.0) then      
  1164.             open(unit=21,file=astring,
  1165.      1          access='SEQUENTIAL',
  1166.      1        status='old',form='unformatted',
  1167.      1        recordtype='fixed',iostat=ierr,action='read')
  1168.            if (ierr.ne.0) then 
  1169.                 print *,'ERROR unable to open ',
  1170.      1                  astring(1:lentrim(astring))
  1171.                 read_new=-1
  1172.                 return
  1173.            else
  1174.               newsize=filesize(21)   
  1175.               read_new=newsize
  1176.            endif
  1177.  
  1178. c  prime the buffer
  1179.  
  1180.            bufstart=1
  1181.            BUFEND=MIN(NEWSIZE,96384)
  1182.            read(21,iostat=ierr)buffer(1:BUFEND)
  1183.            if (ierr.ne.0) then          !error reading
  1184.                 read_new=-1
  1185.            endif
  1186.            return                       ! end of initialization
  1187.         endif
  1188.  
  1189.         iend=min(iend0,newsize)         !correct upper limit
  1190.         ido=1+iend-istart               ! characters to be returned
  1191.        
  1192. c check for bad range
  1193.         if (iend.lt.istart.or.istart.gt.newsize) then ! check for error
  1194.           PRINT *,'ERROR out of range ',ISTART,IEND,NEWSIZE
  1195.           read_new=-1
  1196.           return
  1197.         endif
  1198.  
  1199.  
  1200. c within buffer? don't do anything 
  1201.         if (istart.ge.bufstart.and.iend.le.bufend) then 
  1202.            continue
  1203.  
  1204. c otherwise, reload buffer
  1205. c  if (iend.lt.bufstart .or. istart.gt.bufend) then    !get fancy later 
  1206.  
  1207.         else
  1208.           II=SEEKUNIT(21,ISTART-1,0)
  1209.           IF (II.LT.0) THEN
  1210.               PRINT *,'ERROR BAD SEEKUNIT ',ISTART,II
  1211.               READ_NEW=-1
  1212.               RETURN
  1213.            ENDIF
  1214.            NRD=1+MIN(NEWSIZE,ISTART+96383)-ISTART
  1215.            read(21,iostat=ierr)buffer(1:NRD)
  1216.           IF (IERR.NE.0) THEN
  1217.               PRINT *,'ERROR BAD READ ',IERR,ISTART,NRD
  1218.               READ_NEW=-1
  1219.               RETURN
  1220.            ENDIF
  1221.  
  1222.            BUFSTART=ISTART
  1223.            BUFEND=BUFSTART+NRD-1
  1224.         ENDIF
  1225.  
  1226. c now we are ready to send back the info
  1227.        ioff1=1+istart-bufstart
  1228.        ioff2=ioff1+ido-1
  1229.        astring(1:ido)=buffer(ioff1:ioff2)
  1230.        read_new=ido
  1231.        return
  1232.        end
  1233.  
  1234.  
  1235. c-------------------------------------------
  1236. c write to stout using gdiff format
  1237. c if B (block found) call, then need to use "blksiz" (current
  1238. c blocksize) to find end (use def_blksize for beginning 
  1239.  
  1240.         integer function gdiff_write(atype,iat,blksiz)
  1241.  
  1242.         character *(*)atype
  1243.         integer iat,iserror ,blksiz
  1244.         integer ndo,ns1,blklen,read_new
  1245.         integer jas1,jassize
  1246.         character *1 wastype
  1247.  
  1248.         CHARACTER *4096 C4096
  1249.  
  1250.  
  1251.         integer was0,was1,newsize,def_blksiz,write_6
  1252.         common /ccache/wastype,was0,was1,newsize,def_blksiz
  1253.         COMMON /CSUM/KSUM
  1254.         DATA KSUM/0/
  1255.  
  1256.         iserror=0
  1257.  
  1258.         if (wastype.eq.' ') then          ! first call  
  1259.           if (atype.eq.'C') then
  1260.               was0=was1=iat
  1261.           else
  1262.               was0=((iat-1)*def_blksiz)+1
  1263.               was1=was0+blksiz-1
  1264.           endif
  1265.           wastype=atype
  1266.  
  1267.           gdiff_write=0
  1268.           return
  1269.         endif
  1270.  
  1271. c case 1: C,B
  1272.         if (atype.ne.'C'.and.wastype.eq.'C') then  ! flush chars, start new block 
  1273.           ndo=1+was1-was0    
  1274.           if (ndo.lt.247) then
  1275.              call write_int(ndo,1)
  1276.           else
  1277.              if (ndo.lt.65536) then      ! 2 bytes
  1278.                 call write_int(247,1)
  1279.                 call write_int(ndo,2)
  1280.              else
  1281.                 call write_int(248,1)
  1282.                 call write_int(ndo,4)
  1283.              endif
  1284.           endif
  1285.           do jj=was0,was1,4096
  1286.              blklen=read_new(JJ,MIN(JJ+4095,WAS1),C4096)
  1287.              if (blklen.GE.1) then
  1288.                 iserror=write_6(c4096(1:blklen))
  1289.              else
  1290.                  print *,'ERROR with ',Jj
  1291.              endif
  1292.              if (iserror.ne.0.or.blklen.lt.0) then
  1293.                 print *,'ERROR writing character run ',blklen,iserror
  1294.                   gdiff_write=-1
  1295.                   return
  1296.              endif
  1297.           enddo
  1298.           wastype=atype         !not strictly needed if "F"
  1299.           was0=((iat-1)*def_blksiz)+1
  1300.           was1=was0+blksiz-1
  1301.           gdiff_write=0
  1302.           return
  1303.       endif
  1304.  
  1305. c case 2: C,C
  1306.       if (atype.eq.'C'.and.wastype.eq.'C') then        !augment a characters run
  1307.              was1=iat
  1308.              gdiff_write=0
  1309.              return
  1310.       endif
  1311.         
  1312. c case 3: B,B
  1313.       if (atype.eq.'B'.and.wastype.eq.'B') then    !augment a block run, or flush 
  1314.          ns1=(iat-1)*def_blksiz
  1315.          if (ns1.eq.was1) then               !augment
  1316.              was1=was1+blksiz
  1317.              gdiff_write=0
  1318.              return
  1319.          endif
  1320.  
  1321.          jas1=was0       ! record a copy range
  1322.          jassize=1+was1-was0
  1323.          
  1324.          if (jas1.lt.65536) then
  1325.             if (jassize.lt.256) then 
  1326.                 call write_int(249,1)
  1327.                 call write_int(jas1,2)
  1328.                 call write_int(jassize,1)
  1329.             elseif (jassize.lt.65536) then
  1330.                 call write_int(250,1)
  1331.                 call write_int(jas1,2)
  1332.                 call write_int(jassize,2)
  1333.             else
  1334.                 call write_int(251,1)
  1335.                 call write_int(jas1,2)
  1336.                 call write_int(jassize,4)
  1337.             endif
  1338.          else                           !position > 65535
  1339.             if (jassize.lt.256) then 
  1340.                 call write_int(252,1)
  1341.                 call write_int(jas1,4)
  1342.                 call write_int(jassize,1)
  1343.             elseif (jassize.lt.65536) then
  1344.                 call write_int(253,1)
  1345.                 call write_int(jas1,4)
  1346.                 call write_int(jassize,2)
  1347.             else
  1348.                 call write_int(254,1)
  1349.                 call write_int(jas1,4)
  1350.                 call write_int(jassize,4)
  1351.             endif
  1352.          endif
  1353.  
  1354.          was0=ns1+1
  1355.          was1=was0+blksiz-1
  1356.  
  1357.          gdiff_write=0
  1358.          return
  1359.        endif
  1360.  
  1361. c case 4: B,C
  1362.       if (atype.ne.'B'.and.wastype.eq.'B') then    !flush a block run, start char run
  1363.  
  1364.          jas1=was0       ! record a copy range
  1365.          jassize=1+was1-was0
  1366.  
  1367.          if (jas1.lt.65536) then
  1368.             if (jassize.lt.256) then 
  1369.                 call write_int(249,1)
  1370.                 call write_int(jas1,2)
  1371.                 call write_int(jassize,1)
  1372.             elseif (jassize.lt.65536) then
  1373.                 call write_int(250,1)
  1374.                 call write_int(jas1,2)
  1375.                 call write_int(jassize,2)
  1376.             else
  1377.                 call write_int(251,1)
  1378.                 call write_int(jas1,2)
  1379.                 call write_int(jassize,4)
  1380.             endif
  1381.          else                           !position > 65536
  1382.             if (jassize.lt.256) then 
  1383.                 call write_int(252,1)
  1384.                 call write_int(jas1,4)
  1385.                 call write_int(jassize,1)
  1386.             elseif (jassize.lt.65536) then
  1387.                 call write_int(253,1)
  1388.                 call write_int(jas1,4)
  1389.                 call write_int(jassize,2)
  1390.             else
  1391.                 call write_int(254,1)
  1392.                 call write_int(jas1,4)
  1393.                 call write_int(jassize,4)
  1394.             endif
  1395.          endif
  1396.  
  1397.          was0=was1=iat
  1398.          wastype=atype          !not strictly needed if "F"
  1399.          gdiff_write=0
  1400.          return
  1401.  
  1402.         endif
  1403.  
  1404.  
  1405.  
  1406.          
  1407.         end
  1408.         
  1409. cc--------------
  1410. c write a 1, 2 or 4 byte integer to unit
  1411.         subroutine write_int(ival,nbytes)
  1412.         integer ival,iserror,nbytes
  1413.         character *1 c1
  1414.         character *2 c2
  1415.         character *4 c4
  1416.         character *8 c8
  1417.         integer write_6
  1418.  
  1419.  111       format(z4)
  1420.  1111       format(z8)
  1421.         if (nbytes.eq.1) then
  1422.              c1=char(ival)
  1423.              iserror=write_6(c1)
  1424.              if (iserror.gt.0) goto 10
  1425.              return
  1426.        endif
  1427.      
  1428.        if (nbytes.eq.2) then
  1429.             write(c4,111)ival
  1430.             read(c4,111)c2
  1431.             iserror=write_6(c2)
  1432.             if (iserror.gt.0) goto 10
  1433.  
  1434.            return
  1435.         endif
  1436.  
  1437. c otherwise use 4bytes (assume value < 2billion 
  1438.         write(c8,1111)ival
  1439.         read(c8,1111)c4
  1440.         iserror=write_6(c4)
  1441.         if (iserror.gt.0) goto 10
  1442.  
  1443.         return
  1444.  
  1445.  10     print *,'ERROR writing integer: ',ival
  1446.         stop
  1447.  
  1448.         end      
  1449.  
  1450.         subroutine make_hashtable(nblocks,index_rsyncs16, 
  1451.      1                     rsyncs16,hasht)
  1452.         integer rsyncs16(1)
  1453.         integer index_rsyncs16(1)
  1454.         integer  hasht(0:65535)
  1455.         integer ink,mm,ll,nblocks
  1456.  
  1457.         do mm=1,nblocks
  1458.            ink=index_rsyncs16(mm)
  1459.            ll=rsyncs16(ink)
  1460.            if (hasht(ll).eq.0) then
  1461.                  hasht(ll)=mm
  1462.            endif
  1463.         enddo
  1464.         return
  1465.         end
  1466.  
  1467.  
  1468. c---------------
  1469.         subroutine rsync32_compute(astring,chksum,ialpha,ibeta)
  1470.         integer chksum,ialpha,ibeta
  1471.         character *(*)astring
  1472.         integer isum,i2,i1,ilen
  1473.  
  1474.         ilen=len(astring)
  1475.  
  1476. c compute alpha
  1477.         isum=0
  1478.         do i1=1,ilen
  1479.           i2=ichar(astring(i1:i1))
  1480.           isum=isum+i2
  1481.         enddo 
  1482.         isum=mod(isum,65536)
  1483.         if (isum.lt.0)isum=isum+65536
  1484.         ialpha=isum
  1485.  
  1486.  
  1487. c compute beta     
  1488.         isum=0
  1489.         do i1=1,ilen
  1490.           i2=ichar(astring(i1:i1))
  1491.           isum=((ilen-i1+1)*i2) + isum
  1492.         enddo 
  1493.         isum=mod(isum,65536)
  1494.         if (isum.lt.0)isum=isum+65536
  1495.         ibeta=isum
  1496.  
  1497.         chksum=ialpha +  (65536*ibeta)
  1498.  
  1499.         return
  1500.         end
  1501.  
  1502.  
  1503. c----------------
  1504. c COMPUTE ROLLING CHECKSUM */
  1505.         integer function rsync_increment_s(oldchar,newchar,ialpha,
  1506.      1                          ibeta,ib)
  1507.         character *1 oldchar,newchar
  1508.         integer ialpha,ibeta,ioldchar,inewchar,ib
  1509.         IOLDCHAR=ichar(oldchar)
  1510.         INEWCHAR=ichar(newchar)
  1511.         ialpha=ialpha- Ioldchar + Inewchar
  1512.          ialpha=mod(ialpha,65536)
  1513.          if (ialpha.lt.0) ialpha=65536+ialpha
  1514.          ibeta=ibeta-(ib*ioldchar)+ialpha
  1515.          ibeta=mod(ibeta,65536)
  1516.         if (ibeta.lt.0) ibeta=65536+ibeta
  1517.         rsync_increment_s=ialpha+(ibeta*65536)
  1518.         return
  1519.         end
  1520.  
  1521. c==============================================================
  1522. c  sort to an index.  Index is integer, array to sort is integer
  1523. c Based on QUIKSORT
  1524.  
  1525.         SUBROUTINE quik_iNDEXSORT(X,xindex,nx)
  1526.  
  1527.         integer  x(1),pivotv
  1528.         integer    xindex(1),nx
  1529.         integer stack(5000)
  1530.         integer segbeg,segend,segsize,ep,bp,mid
  1531.         integer lenend,lenbeg,newpivot,nspt,ij
  1532.  
  1533.         logical QPopSort_rsync
  1534.  
  1535.         nspt=0
  1536.  
  1537. c initialize stack
  1538.         do 2 ij=1,5000
  1539.            stack(ij)=0
  1540.   2     continue
  1541.  
  1542.         do 3 ij=1,nx
  1543.            xindex(ij)=ij
  1544.  3      continue
  1545.         
  1546.         segbeg=1
  1547.         segend=nx
  1548.  
  1549. c  first "sort"
  1550.         call indqsort3_rsync(segbeg,mid,segend,pivotv,x,xindex)
  1551.         if (nx.le.3) goto 2000
  1552.  
  1553.  100    continue
  1554.         bp=segbeg
  1555.         ep=segend
  1556. C        print *,bp,MID,EP,':',
  1557. C     1       X(XINDEX(BP)),X(XINDEX(MID)),X(XINDEX(EP))
  1558.  
  1559.  200    continue
  1560.         if (x(xindex(bp)).le.pivotv .and.bp.lt.segend) then
  1561.           bp=bp+1
  1562. C         print *,'bp ',bp,SEGEND,X(XINDEX(BP))
  1563.  
  1564.           goto 200
  1565.         endif
  1566.  
  1567.  300    continue
  1568.         if (x(xindex(ep)).ge.pivotv.and.Ep.gt.segbeg) then
  1569.             ep=ep-1
  1570. C            PRINT *,' EP ',EP,SEGBEG,X(XINDEX(EP))
  1571.             goto 300
  1572.         endif
  1573.  
  1574.         if (ep.gt.bp) then
  1575.            call intswap_rsync(xindex(bp),xindex(ep))
  1576.            bp=bp+1
  1577.            ep=ep-1
  1578. C           PRINT *,' BP EP ',BP,EP
  1579.            goto 200
  1580.         endif
  1581.  
  1582.  
  1583.         if (bp.gt.mid) then
  1584.           if (ep.gt.mid) then
  1585.               call intswap_rsync(xindex(ep),xindex(mid))
  1586.               newpivot=ep
  1587.           else
  1588.               newpivot=mid
  1589.           endif
  1590.         else
  1591.            call intswap_rsync(xindex(bp),xindex(mid))
  1592.            newpivot=bp
  1593.         endif
  1594.  
  1595.         lenend=segend-newpivot
  1596.         lenbeg=newpivot-segbeg
  1597.  
  1598.         if (lenend.gt.lenbeg) then
  1599.            call pushsort_rsync(newpivot+1,segend,stack,nspt)
  1600.            segend=newpivot-1
  1601.            segsize=lenbeg
  1602.         else
  1603.            call pushsort_rsync(segbeg,newpivot-1,stack,nspt)
  1604.            segbeg=newpivot+1
  1605.            segsize=lenend
  1606.         endif
  1607.  
  1608.         call indqsort3_rsync(segbeg,mid,segend,pivotv,x,xindex)
  1609.  
  1610.         if (segsize.gt.3) goto 100
  1611.  
  1612.  1000   continue
  1613.         if (.not.QPopSort_rsync(segbeg,segend,stack,nspt)) then
  1614.             goto 2000
  1615.         else
  1616.            segsize=segend-segbeg+1
  1617.            call indqsort3_rsync(segbeg,mid,segend,pivotv,x,xindex)
  1618.            if (segsize.le.3) then
  1619.              goto 1000
  1620.            else
  1621.              goto 100
  1622.            endif
  1623.         endif
  1624.  
  1625.  2000   continue
  1626. C        print *,' endo quitk'
  1627.          return
  1628.         end
  1629.  
  1630.  
  1631.  
  1632.  
  1633.  
  1634. c--------
  1635.         subroutine indqsort3_rsync(segbeg,mid,segend,pivotv,x,xindex)
  1636.  
  1637.         integer x(1),pivotv
  1638.         integer segbeg,mid,segend
  1639.         integer xindex(1)
  1640.  
  1641.         mid=(segbeg+segend)/2
  1642.         if (segbeg+1.eq.segend) then
  1643.             if (x(xindex(segbeg)).gt.x(xindex(segend))) then
  1644.                call intswap_rsync(xindex(segbeg),xindex(segend))
  1645.             endif
  1646.             return
  1647.         endif
  1648.  
  1649.         if (x(xindex(segbeg)).gt.x(xindex(mid))) then
  1650.             if (x(xindex(segbeg)).gt.x(xindex(segend))) then
  1651.               call intswap_rsync(xindex(segbeg),xindex(segend))
  1652.               if (x(xindex(segbeg)).gt.x(xindex(mid))) then
  1653.                 call intswap_rsync(xindex(segbeg),xindex(mid))
  1654.               endif
  1655.             else
  1656.               call intswap_rsync(xindex(segbeg),xindex(mid))
  1657.             endif
  1658.         else
  1659.             if (x(xindex(mid)).gt.x(xindex(segend))) then
  1660.                call intswap_rsync(xindex(mid),xindex(segend))
  1661.                if (x(xindex(segbeg)).gt.x(xindex(mid))) then
  1662.                  call intswap_rsync(xindex(segbeg),xindex(mid))
  1663.                endif
  1664.             else
  1665.                continue
  1666.             endif
  1667.         endif
  1668.  
  1669.         pivotv=x(xindex(mid))
  1670.         return
  1671.         end
  1672.  
  1673.  
  1674.         subroutine intswap_rsync(ix,iy)
  1675.         integer it,ix,iy
  1676.         it=ix
  1677.         ix=iy
  1678.         iy=it
  1679.         return
  1680.         end
  1681.  
  1682.  
  1683.         subroutine pushsort_rsync(sb,se,stack,stackct)
  1684.         integer se,sb,stack(1),stackct
  1685.  
  1686.  
  1687.         if (stackct+2.gt.5000) then
  1688. c           print *,'ERROR in QUIKSORT: ARRAY TOO LONG '
  1689.            stop 0
  1690.         endif
  1691.  
  1692.         stackct=stackct+1
  1693.         stack(stackct)=sb
  1694.  
  1695.         stackct=stackct+1
  1696.         stack(stackct)=se
  1697.  
  1698.         return
  1699.         end
  1700.  
  1701.  
  1702.         logical function QPopSort_rsync(sb,se,stack,stkpoint)
  1703.         integer sb,se,stack(1),stkpoint
  1704.  
  1705.         if (stkpoint-1.le.0)then
  1706.            qpopsort_rsync=.false.
  1707.            return
  1708.         endif
  1709.  
  1710.         se=stack(stkpoint)
  1711.         stkpoint=stkpoint-1
  1712.         sb=stack(stkpoint)
  1713.         stkpoint=stkpoint-1
  1714.         qpopsort_rsync =.true.
  1715.         return
  1716.         end
  1717.  
  1718.  
  1719.  
  1720. c-----------------------
  1721. c using difference file, and old file, recreate "new file" (ungdiff)
  1722.  
  1723.         integer function do_ungdiff(iunit,dif_file,out_file,iquiet)
  1724.         character *(*) dif_file,out_file
  1725.         integer iunit,iquiet
  1726.         character *1 c1
  1727.         character *1000 c1000
  1728.         character *4 c4,c4a
  1729.         character *2 c2,c2a
  1730.         character *8 c8
  1731.         integer i4,iget,nget,c_to_int,write_6,iserror,ierr
  1732.  
  1733.         include 'fsublib.fi'
  1734.  
  1735.         integer i36
  1736.         logical quiet
  1737.         common /cm36/i36,quiet
  1738.  
  1739. c iunit points to the "old file"
  1740. c now open the "dif_file"
  1741.         open(unit=42,file=dif_file,access='sequential',status='old',
  1742.      1   form='unformatted',recordtype='fixed',iostat=ierr,
  1743.      1   action='read')
  1744.         if (ierr.ne.0) then
  1745.              do_ungdiff=51
  1746.              return
  1747.          endif
  1748.  
  1749. c is this a real difference file
  1750.         read(42,iostat=ierr)c1000(1:4),c1
  1751.  
  1752. c note: dif_file will be gone through sequentially. 41 (oldfile)
  1753. c will be jumped around in
  1754.  
  1755.        c8='d1ffd1ff'      
  1756.        read(c8,13)c4        
  1757.  13    format(z8)          
  1758.  
  1759.         if (c4.ne.c1000(1:4)) then
  1760.            do_ungdiff=52
  1761.            print *,'ERROR not a gdiff formatted difference file'
  1762.            return
  1763.         endif
  1764.  
  1765.  
  1766. c open output file?
  1767.        if (i36.ne.6) then
  1768.          open(unit=i36,file=out_file,recordtype='FIXED',
  1769.      1                access='sequential',
  1770.      1               form='unformatted',iostat=ierr,action='WRITE')
  1771.           if (ierr.ne.0) then
  1772.               print *,'ERROR Unable to open output file:  ',out_file
  1773.               do_gdiff=49
  1774.               return
  1775.           endif
  1776.        endif
  1777.  
  1778. c read codes from difference file, and write info accordingly
  1779.        do while (1.eq.1)               !do forever
  1780.         
  1781.         read(42,err=1010)c1
  1782.  
  1783.         itype=ichar(c1)   
  1784.  
  1785.         if (itype.eq.0) then
  1786.              exit                       !eof marker
  1787.  
  1788.         elseif (itype.eq.255) then
  1789.             do_ungdiff=54
  1790.             print *, 'ERROR gdiff copy operation too large'
  1791.             return
  1792.  
  1793.         elseif (itype.gt.0 .and. itype.lt.247) then ! 1 to 246 chars to write
  1794.             read(42,err=1010)c1000(1:itype)             !(from out_file)
  1795.             iserror=write_6(c1000(1:itype))
  1796.             if (iserror.ne.0) goto 1010
  1797.  
  1798.         elseif (itype.eq.247.or.itype.eq.248) then     ! get >255 bytes
  1799.            if (itype.eq.247) then                       ! from out_file
  1800.               read(42,err=1010)c2
  1801.               i4=c_to_int(c2)
  1802.            else
  1803.               read(42,err=1010)c4
  1804.               i4=c_to_int(c4)
  1805.            endif
  1806.  
  1807.            do jj=1,i4,1000
  1808.               nget=min(1000,1+i4-jj)
  1809.               read(42,err=1010)c1000(1:nget)
  1810.               iserror=write_6(c1000(1:nget))
  1811.               if (iserror.ne.0) goto 1010
  1812.  
  1813.            enddo
  1814.         
  1815.         else            !copy bytes from oldfile
  1816.  
  1817.           if (itype.eq.249) then
  1818.              read(42,err=1010)c2,c1
  1819.              istart=c_to_int(c2)
  1820.              iget=ichar(c1)
  1821.           elseif (itype.eq.250) then
  1822.              read(42,err=1010)c2,c2a
  1823.              istart=c_to_int(c2)
  1824.              iget=c_to_int(c2a)
  1825.  
  1826.           elseif (itype.eq.251) then
  1827.              read(42,err=1010)c2,c4
  1828.              istart=c_to_int(c2)
  1829.              iget=c_to_int(c4)
  1830.  
  1831.           elseif (itype.eq.252) then
  1832.              read(42,err=1010)c4,c1
  1833.              istart=c_to_int(c4)
  1834.              iget=ichar(c1)
  1835.           elseif (itype.eq.253) then
  1836.              read(42,err=1010)c4,c2
  1837.              istart=c_to_int(c4)
  1838.              iget=c_to_int(c2)
  1839.           elseif (itype.eq.254) then
  1840.              read(42,err=1010)c4,c4a
  1841.              istart=c_to_int(c4)
  1842.              iget=c_to_int(c4a)
  1843.           else
  1844.             do_ungdiff=56
  1845.             return
  1846.           endif                         !copy byte codes
  1847.  
  1848.           II=SEEKUNIT(iunit,istART-1,0)
  1849.           IF (II.LT.0)  goto 1010
  1850.          
  1851.           do mm=1,iget,1000
  1852.               nget=min(1000,1+iget-mm)
  1853.               read(iunit,err=1010)c1000(1:nget)
  1854.               iserror=write_6(c1000(1:nget))
  1855.               if (iserror.ne.0) goto 1010
  1856.  
  1857.           enddo
  1858.  
  1859.         endif             ! bytes code
  1860.        enddo               !scanning diff file 
  1861.  
  1862.        close(unit=iunit,iostat=ierr)            !oldfile
  1863.        close(unit=42,iostat=ierr)               !diff
  1864.        close(unit=36,iostat=ierr)               !output 
  1865.        do_ungdiff=0
  1866.  
  1867.         if (.not.quiet.and.i36.ne.6.and.iquiet.ne.1) then
  1868.           open(unit=i36,file=out_file,iostat=ierr,
  1869.      1         action='read',form='unformatted')
  1870.           if (ierr.ne.0) return
  1871.           iout=filesize(36)
  1872.           if (lentrim(out_File).lt.40) then
  1873.               write(6,51)iout,out_file(1:lentrim(out_file))
  1874.  51           format('OK ',i9,' bytes written to  ',a)
  1875.            else
  1876.               write(6,53)iout,out_file(1:lentrim(out_file))
  1877.  53           format('OK ',i9,' bytes written to  '/a)
  1878.            endif
  1879.            close(unit=i36,iostat=ierr)
  1880.         endif
  1881.  
  1882.  
  1883.  
  1884.        return
  1885.  
  1886.  
  1887.  1010   do_ungdiff=55   !unspecified io error
  1888.         return
  1889.  
  1890.         end
  1891.                 
  1892.  
  1893. c-------------------
  1894. c character to integer
  1895.         integer function c_to_int(cc)
  1896.         character *(*)cc
  1897.         INTEGER JJ
  1898.         CHARACTER *4 C4
  1899.         CHARaCTER *8 C8
  1900.  
  1901.  
  1902.         if (len(cc).eq.1) then
  1903.             c_to_int=ichar(cc)        
  1904.             return
  1905.         endif
  1906.  
  1907.         if (len(cc).eq.2) then
  1908.            write(c4,99)cc
  1909.  99        format(z4)
  1910.            read(c4,99)jj
  1911.            c_to_int=jj
  1912.            return
  1913.         endif
  1914.  
  1915.         if (len(cc).eq.4) then
  1916.            write(c8,199)cc
  1917.  199       format(z8)
  1918.            read(c8,199)jj
  1919.            c_to_int=jj
  1920.            return
  1921.         endif
  1922.  
  1923.         print *,'ERROR Overflow in c_to_int '
  1924.         stop
  1925.         end
  1926.  
  1927.