home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxrsync.zip / rxsync.cmd < prev   
OS/2 REXX Batch file  |  1999-11-15  |  18KB  |  617 lines

  1. /* The ALL rexx rsync.  This is a lot slower then the OS/2 mixed
  2.  versions that use rxsync.dll (as demoed in rsynctst.cmd and rsyncts2.cmd),
  3.  but it should run on most rexx systems */
  4.  
  5. /*********  USER changeable parameters  ************/
  6. /* (larger blocksizes mean less info sent in c1, but  more in s1. */
  7. blocksize=500
  8.  
  9. afile='tst\dir.doc'             
  10.  
  11. bfile='tst\dirnew.doc'             /* the client's old version */
  12.  
  13. verbose=1                      /* status messages: 0-terse, 1=normal, 2=verbose */
  14.  
  15. reportat=250000                 /* how often to report some status messages */
  16.  
  17.  
  18. /**** END of USER changeable parameters  ************/
  19.  
  20. parse arg infile outfile
  21.  
  22.  
  23.  
  24. if infile<>'' then afile=infile
  25. if outfile<>'' then bfile=outfile
  26.  
  27. s1file='rxsync.dif'         /* server's response */
  28. c1file='rxsync.syn'         /* clients requeset */
  29. B1file='rxsync.out'         /* client side reconstruction of B1 (i.e.; a copy of B */
  30.  
  31. numeric digits 11
  32.  
  33. if infile='?' then do
  34.     say "RxSYNC: an all REXX rsync (for demonstration purposes). "
  35.     say "Usage: x:>rxsync infile outfile  "
  36.     say " Will generate: "
  37.     say "   Client side 'synopsis': "c1file
  38.     say "   Server side 'difference':" s1file
  39.     say "   Client side duplicate of outfile: "b1file
  40.     exit
  41. end /* do */
  42.  
  43.  
  44.  
  45. /* Load up advanced REXX functions -- for non os/2 systems, you
  46. may have to provide a different library name */
  47. call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  48. call SysLoadFuncs
  49.  
  50.  
  51.  
  52.  
  53. /******** The client's request, along with the c1 message ***/
  54.  
  55. a=time('r')
  56. /* read "Afile" */
  57. isize=stream(afile,'c','query size')
  58. if isize='' | isize=0 then do
  59.     say 'Rsync Client: 'afile " is unaccessible"
  60.     exit
  61. end
  62.  
  63. astuff=charin(afile,1,isize)
  64. say "Rsync Client: read "isize" bytes from "afile
  65. say " ... computing md4 "
  66. amd4=rexx_md4(astuff)
  67.  
  68. crlf='0d0a'x
  69. /* break into chunks of size blocksize, and compute "adler" and md4 checksums */
  70. ifoo=trunc(isize/blocksize+0.999999)
  71.  
  72. /* Structure of client request file
  73.    Comment  -- 80 characters (i.e.; requested file name)
  74.    1 space
  75.    Blocksize  -- 6 digit integer
  76.    1 space
  77.    #Blocks    -- 8 digit character
  78.    1 space
  79.    md4        -- 32 digit md4
  80.    3 spaces
  81.    rsync1||md41||..||rsyncN||md4||N -- rsync and md4 values (machine format)
  82. */
  83.  
  84.  
  85. ac1=left(bfile,80)||' '||left(blocksize,6)||' '||left(ifoo,8)||' '||amd4||' '
  86. ctcs='  '               /* may use this "parameter" later */
  87. ac1=ac1||ctcs
  88. iat=1
  89. do mm=1 to ifoo
  90.   if mm=ifoo then
  91.      ablock=substr(astuff,iat)
  92.   else
  93.      ablock=substr(astuff,iat,blocksize)
  94.   foo=rsync32_md4(ablock)
  95.   ac1=ac1||foo
  96.   iat=iat+blocksize
  97.   if (iat//20000)=1 then say "processing " iat
  98. end
  99. foo=time('e')
  100. say 'Rsync Client: Done creating hashes for  'ifoo' blocks'
  101.  
  102. foo=sysfiledelete(c1file)
  103. foo=charout(c1file,ac1,1)          /* create the message the client send to the server*/
  104. foo=stream(c1file,'c','close')
  105. b=time('e')
  106. say 'Rsync client: Saving client request to 'c1file' [elapsed time='||strip(b,'t','0')
  107. drop ac1
  108.  
  109. /***************** This is the server's action ***/
  110. /* Read in in C1 */
  111. aaa:
  112.  
  113. b=time('r')
  114.  
  115. csz=stream(c1file,'c','query size')
  116. foo=stream(c1file,'c','open read')
  117. in1=charin(c1file,1,132)
  118. parse var in1 getfile iblock numblocks amd4 gotcts .
  119.  
  120. say ' '
  121. say "Rsync Server: reads "c1file", and sees that client requested: "
  122. say "     "getfile
  123. say "     (client used blocksize=" iblock ', and sent 'numblocks' blocks '
  124.  
  125. /* read in Bfile */
  126. isize=stream(bfile,'c','query size')
  127. if isize='' | isize=0 then do
  128.     say 'Rsync server: ' bfile " is unaccessible"
  129.     exit
  130. end
  131. astuff=charin(bfile,1,isize)
  132. bmd4=rexx_md4(astuff)
  133. say 'Rsync server: 'isize' bytes from requested file read '
  134. if strip(translate(amd4))=translate(strip(bmd4)) then do
  135.    say "Rsync Server: Files have not changed."
  136.    saveb=0
  137.    signal jump1
  138. end /* do */
  139.  
  140. /* store 32bit hashes in stem.
  141.   Note that the rsync specs suggest a 16 bit hash table, which
  142.   provides an index into a sorted (by 32 bit checksum) array.  
  143.   However, here we take advantage of the balanced tree architecture
  144.   uses in rexx stem variables */
  145. hasht.=0
  146. mxlen=1
  147. nhash=0
  148. do mm=1 to numblocks
  149.    aline=charin(c1file,,20)
  150.    adler=left(aline,4) ; md4=right(aline,16)
  151.    akey='!'||adler
  152.    ijk=hasht.akey+1
  153.    if ijk=1 then nhash=nhash+1
  154.    hasht.akey=ijk
  155.    hasht.akey.!m.ijk=md4
  156.    hasht.akey.!i.ijk=mm
  157.    mxlen=max(mxlen,ijk)
  158. end /* do */
  159.  
  160. say 'Rsync server: created ' nhash||' entries in hash table with max keys= 'mxlen
  161.  
  162.  
  163. /* commence rolling through astuff, starting from first character */
  164. /* for now, if not 500 chars left in file, then stop */
  165.  
  166. nom1=0      /* last character accounted for (explicitily, or as a block */
  167. nom2=0     /* last character unmatched, and not written to s1 */
  168. lenstuff=length(astuff)
  169.  
  170. ib1=1 ; ib2=ib1+iblock          /* start of this block, first char after this block */
  171. ablock=substr(astuff,ib1,iblock)         /* initialize Bfile stuff */
  172. adler=rsync32(ablock)         /* alpha and beta are expose */
  173. adler=d2c(adler)
  174.  
  175. s1=bmd4' 'iblock||crlf                /* the server's report --start with md4 of Bfile */
  176. blockwrites=0; charwrites=0
  177.  
  178. noted=0
  179. bad32s=0
  180. saveb=0
  181. do while ib1 <= 1+lenstuff-iblock   /* stop when can't grab a block */
  182.  
  183.   if ib1-noted>reportat=1 then do
  184.     if verbose>0 then say " ... Rsync server: At character # " ib1 '('charwrites','blockwrites')'
  185.     noted=ib1
  186.   end
  187.    
  188.   akey='!'||adler            /* check hash table */
  189.   matchblock=0                          /* assume no matching block */
  190.   do jkk=1 to hasht.akey                /* check all entries with this 32bit hash */
  191.      if jkk=1 then ablock=substr(astuff,ib1,iblock)
  192.      tmd4=x2c(strip(rexx_md4(ablock)))
  193.      if tmd4=hasht.akey.!m.jkk then do       /* md4 match. use this block */
  194.          matchblock=hasht.akey.!i.jkk
  195.          blockwrites=blockwrites+1
  196.          leave
  197.      end             /* md4 check */
  198.      else do
  199.          bad32s=bad32s+1
  200.      end /* do */
  201.  
  202.   end                   /* all matches of 16 bit hash of adler 32 */
  203.  
  204. /* if no match, slide block over 1, compute it's adler, and back to top of loop */
  205.   if matchblock=0 then do         /* no match....try next block of Bfile */
  206.       nom2=ib1                    /* "end" of current set of unmatched characters*/
  207.       newchar=substr(astuff,ib2,1)   /* character to add to create next block */
  208.  
  209.       oldchar=substr(astuff,ib1,1)
  210.       ib1=ib1+1                     /* begin next block here */
  211.       ib2=ib2+1                     /* first char after this block */
  212. /* COMPUTE ROLLING CHECKSUM */
  213.       IOLDCHAR=C2D(OLDCHAR); INEWCHAR=C2D(NEWCHAR)
  214.       alpha=alpha- Ioldchar + Inewchar
  215.       if alpha<0 then  alpha=65536+alpha
  216.       xalpha=right(d2x(alpha),4,0)
  217.       alpha=x2d(xalpha)
  218.       beta=beta-(iblock*ioldchar)+alpha
  219.       if beta<0 then  beta=65536+(beta//65536)
  220.       iadler=right(d2x(beta),4,0)||xalpha
  221.       ADLER=right(x2c(iadler),4)
  222.  
  223. /*      adler=rexx_add_sync(c2d(oldchar),c2d(newchar))  alpha beta exposed */
  224.  
  225.       iterate                   /* try next comparision, using new adler checksum */
  226.  
  227.   end /* do */
  228.  
  229. /* if here, got a match. */
  230. /* Record set of unmatched chars (that precede this  block) */
  231.    if nom2>0 then do    /* there are some unmatched character before this matching block */
  232.       ndo=nom2-nom1
  233.       charwrites=charwrites+ndo
  234.       if verbose> 1 then say "... Rsync server: record "ndo " chars starting after "nom1
  235.       saveb=saveb+1
  236.       saves.saveb.1='C'
  237.       saves.saveb=ndo':'||substr(astuff,nom1+1,ndo)  /* record unmatched chars */
  238.    end
  239. /* record this matching block */
  240.    saveb=saveb+1
  241.    saves.saveb.1='B'
  242.    saves.saveb=matchblock                     /* record matching block id */
  243.    if verbose>1 then say "... Rsync server: recording block: "matchblock '(with adler 'adler
  244. /* skip past this block, and start searching again */
  245.    ib1=ib1+iblock
  246.    nom1=ib1-1                   /* last "matched" character */
  247.    nom2=0                       /* end of "unmatched characters */
  248.    ablock=substr(astuff,ib1,iblock)         /* get block after */
  249.    adler=rsync32(ablock)         
  250.    adler=d2c(strip(adler))
  251.    ib2=ib1+iblock         
  252.  
  253. end /* do */
  254.  
  255. say 'Rsync server:  done comparing blocks '
  256. /* add any "unmatched characters */
  257. if nom1<lenstuff then do
  258.      ndo=lenstuff-nom1
  259.      charwrites=charwrites+ndo
  260.      saveb=saveb+1
  261.      saves.saveb.1='C'
  262.      saves.saveb=ndo':'||substr(astuff,nom1+1)  /* record unmatched chars */
  263. end
  264.  
  265. say "Rsync server: "charwrites "characters, "blockwrites " blocks"
  266. if verbose>1 then say "Rsync server: # of nonmatching 32bit checksums: "bad32s
  267.  
  268. jump1: nop
  269. foo=sysfiledelete(s1file)
  270.  
  271. /* now write saves. array to output file; possibly appending B blocks */
  272. mm=0
  273. foo=stream(s1file,'c','open write')
  274. oout=bmd4' 'iblock||crlf
  275. foo=charout(s1file,oout,1)
  276. do until mm >= saveb
  277.   mm=mm+1
  278.   if saves.mm.1='C' then do
  279.      oout='C'||saves.mm||crlf
  280.      foo=charout(s1file,oout)
  281.   end
  282.   if saves.mm.1='B' then do 
  283.      ib1=saves.mm ; ib2=ib1 
  284.      imm0=mm+1
  285.      do mm2=imm0 to saveb
  286.         if saves.mm2.1<>'B'  then leave
  287.         if saves.mm2-1<>ib2 then leave   /* not next in squesnce */
  288.         ib2=saves.mm2 
  289.         mm=mm2
  290.      end
  291.      oout='B'||ib1':'ib2||crlf
  292.      foo=charout(s1file,oout)
  293.   end /* if */
  294. end /* do */
  295.  
  296. foo=stream(s1file,'c','close')
  297. b=time('e')
  298.  
  299. say 'Rsync server: Writing the 's1file ' server response file [elapsed time='||strip(b,'t','0')
  300. drop astuff
  301. drop saves.
  302.  
  303. /*********** Client recieves response, and assembles Bfile */
  304.  
  305. b=time('r')
  306.  
  307. say " "
  308. /* read in s1 */
  309. cisize=stream(s1file,'c','query size')
  310. if isize='' | isize=0 then do
  311.     say 'Rsync Client: Server response file ('s1file' is unaccessible'
  312.     exit
  313. end
  314. s1=charin(s1file,1,cisize)
  315.  
  316. say "Rsync Client: read "cisize" bytes of server response "
  317. /* read "Afile" */
  318. iasize=stream(afile,'c','query size')
  319. if isize='' | isize=0 then do
  320.     say afile "Rsync Client: (the client's 'A' file) is unaccessible!"
  321.     exit
  322. end
  323. astuff=charin(afile,1,iasize)
  324. amd4=rexx_md4(astuff)
  325.  
  326. /* get md4 and blocksize from s1 */
  327. parse var s1 smd4 bsize (crlf) s1
  328.  
  329. if strip(translate(amd4))=strip(translate(smd4)) then do
  330.    say "Rsync Client: file has not changed "
  331.    exit
  332. end /* do */
  333.  
  334.  
  335. /* start building. Each records starts with a single character identifier,
  336. either a B or a C. Following the identifier is:
  337.    B: a block start: block end number, and then a crlf
  338.    C: a count of bytes (nnn), a ":", a string of length nnn, and a crlf
  339. */
  340. bstuff=''
  341. noted=0
  342. do forever
  343.    if length(s1)=0 | s1='' then leave
  344.    mbl=lengtH(bstuff)
  345.    if  mbl-noted> reportat then do
  346.       if verbose>0 then say "... Rsync client: # characters recovered "mbl
  347.       noted=mbl
  348.    end /* do */
  349.    parse var s1 atype +1 s1  ; atype=translate(atype)
  350.    select
  351.       when atype='C' then do
  352.          parse var s1 nnn ':' s1
  353.          parse var s1 ccs +(nnn) (crlf) s1
  354.          bstuff=bstuff||ccs
  355.       end /* do */
  356.       when atype='B' then do
  357.          parse var s1 idb1 ':' idb2 (crlf)  s1
  358.          i1=((idb1-1)*bsize)+1
  359.          i2=idb2*bsize
  360.          i2=min(i2,iasize)
  361.          bstuff=bstuff||substr(astuff,i1,1+i2-i1)
  362.       end /* do */
  363.       otherwise do
  364.          say "ERROR in rsync response: unknown type= "atype
  365.          exit
  366.      end
  367.    end  /* select */
  368. end /* do */
  369.  
  370. /* compute md4 of this constructed file */
  371. b2md4=rexx_md4(bstuff)
  372. if strip(translate(b2md4)) <> strip(translate(smd4)) then do
  373.    say "Rsync Client: ERROR: md4 does not match: "b2md4', 'smd4
  374. end /* do */
  375. foo=sysfiledelete(bb1file)
  376. foo=charout(b1file,bstuff,1)          /* save the computed Afile */
  377. foo=stream(b1file,'c','close')
  378. b=time('e')
  379. say 'Rsync client: ' length(bstuff) ' bytes written to  'b1file ' [elapsed time='||strip(b,'t','0')
  380. exit
  381.  
  382.  
  383. /**********************************/
  384. /* some useful procedures */
  385.  
  386.  
  387. /*  ------------------------------ */
  388. /* this is an "all rexx" md4 procedure. It works, but it is slow */
  389. rexx_md4:procedure             /* if called externally, remove the "procedure" */
  390. parse arg stuff
  391. lenstuff=length(stuff)
  392.  
  393. c0=d2c(0)
  394. c1=d2c(128)
  395. c1a=d2c(255)
  396. c1111=c1a||c1a||c1a||c1a
  397. slen=length(stuff)*8
  398. slen512=slen//512
  399.  
  400. const1=c2d('5a827999'x)
  401. const2=c2d('6ed9eba1'x)
  402.  
  403.  
  404. /* pad message to multiple of 512 bits.  Last 2 words are 64 bit # bits in message*/
  405. if slen512=448 then  addme=512
  406. if slen512<448 then addme=448-slen512
  407. if slen512>448 then addme=960-slen512
  408. addwords=addme/8
  409.  
  410. apad=c1||copies(c0,addwords-1)
  411.  
  412. xlen=reverse(right(d2c(lenstuff*8),4,c0))||c0||c0||c0||c0  /* 2**32 max bytes in message */
  413.  
  414. /* NEWSTUFF is the message to be md4'ed */
  415. newstuff=stuff||apad||xlen
  416.  
  417. /* starting values of registers */
  418.  a ='67452301'x;
  419.  b ='efcdab89'x;
  420.  c ='98badcfe'x;
  421.  d ='10325476'x;
  422.  
  423. lennews=length(newstuff)/4
  424.  
  425. /* loop through entire message */
  426. do i1 = 0 to ((lennews/16)-1)
  427.   i16=i1*64
  428.   do j=1 to 16
  429.      j4=((j-1)*4)+1
  430.      jj=i16+j4
  431.      m.j=reverse(substr(newstuff,jj,4))
  432.   end /* do */
  433.  
  434. /* transform this block of 16 chars to 4 values. Save prior values first */
  435.  aa=a;bb=b;cc=c;dd=d
  436.  
  437. /* do 3 rounds, 16 operations per round (rounds differ in bit'ing functions */
  438. S11=3
  439. S12=7 
  440. S13=11
  441. S14=19
  442.   a=round1( a, b, c, d,   0 , S11); /* 1 */
  443.   d=round1( d, a, b, c,   1 , S12); /* 2 */
  444.   c=round1( c, d, a, b,   2 , S13); /* 3 */
  445.   b=round1( b, c, d, a,   3 , S14); /* 4 */
  446.   a=round1( a, b, c, d,   4 , S11); /* 5 */
  447.   d=round1( d, a, b, c,   5 , S12); /* 6 */
  448.   c=round1( c, d, a, b,   6 , S13); /* 7 */
  449.   b=round1( b, c, d, a,   7 , S14); /* 8 */
  450.   a=round1( a, b, c, d,   8 , S11); /* 9 */
  451.   d=round1( d, a, b, c,   9 , S12); /* 10 */
  452.   c=round1( c, d, a, b,  10 , S13); /* 11 */
  453.   b=round1( b, c, d, a,  11 , S14); /* 12 */
  454.   a=round1( a, b, c, d,  12 , S11); /* 13 */
  455.   d=round1( d, a, b, c,  13 , S12); /* 14 */
  456.   c=round1( c, d, a, b,  14 , S13); /* 15 */
  457.   b=round1( b, c, d, a,  15 , S14); /* 16 */
  458.  
  459.   /* Round 2 */
  460. S21=3
  461. S22=5
  462. S23=9 
  463. S24=13
  464. a= round2( a, b, c, d,   0 ,  S21 ); /* 17 */
  465. d= round2( d, a, b, c,   4 ,  S22 ); /* 18 */
  466. c=  round2( c, d, a, b,  8 , S23); /* 19 */
  467. b=  round2( b, c, d, a,  12 , S24); /* 20 */
  468. a=  round2( a, b, c, d,   1 , S21); /* 21 */
  469. d=  round2( d, a, b, c,  5  , S22); /* 22 */
  470. c=  round2( c, d, a, b,  9  , S23); /* 23 */
  471.  b= round2( b, c, d, a,   13,  S24); /* 24 */
  472. a= round2( a, b, c, d,   2 ,  S21); /* 25 */
  473. d= round2( d, a, b, c,  6  ,  S22); /* 26 */
  474. c=  round2( c, d, a, b,  10 , S23); /* 27 */
  475. b=  round2( b, c, d, a,  14 , S24); /* 28 */
  476. a=  round2( a, b, c, d,   3 , S21); /* 29 */
  477. d=  round2( d, a, b, c,   7 , S22); /* 30 */
  478. c=  round2( c, d, a, b,  11 , S23); /* 31 */
  479. b= round2( b, c, d, a,  15 ,  S24) ; /* 32 */
  480.  
  481.   /* Round 3 */
  482. S31= 3
  483. S32= 9 
  484. S33= 11
  485. S34= 15
  486. a= round3( a, b, c, d,   0 , S31) ; /* 33 */
  487. d=  round3( d, a, b, c,   8 , S32); /* 34 */
  488. c=  round3( c, d, a, b,  4  , S33); /* 35 */
  489. b=  round3( b, c, d, a,  12 , S34); /* 36 */
  490. a=  round3( a, b, c, d,   2 , S31); /* 37 */
  491. d=  round3( d, a, b, c,  10 , S32); /* 38 */
  492. c=  round3( c, d, a, b,   6 , S33); /* 39 */
  493. b=  round3( b, c, d, a,  14 , S34); /* 40 */
  494. a=  round3( a, b, c, d,  1  , S31); /* 41 */
  495. d=  round3( d, a, b, c,   9 , S32); /* 42 */
  496. c=  round3( c, d, a, b,   5 , S33); /* 43 */
  497. b=  round3( b, c, d, a,  13 , S34); /* 44 */
  498. a=  round3( a, b, c, d,   3 , S31); /* 45 */
  499. d=  round3( d, a, b, c,  11 , S32); /* 46 */
  500. c=  round3( c, d, a, b,   7 , S33); /* 47 */
  501. b=  round3( b, c, d, a,  15 , S34); /* 48 */
  502.  
  503.  
  504. a=m32add(aa,a) ; b=m32add(bb,b) ; c=m32add(cc,c) ; d=m32add(dd,d)
  505.  
  506. end
  507.  
  508. aa=c2x(reverse(a))||c2x(reverse(b))||c2x(reverse(C))||c2x(reverse(D))
  509. return aa
  510.  
  511. /* round 1 to 3 functins */
  512.  
  513. round1:procedure expose m. c1111 c0 c1
  514. parse arg a1,b1,c1,d1,kth,shift
  515. kth=kth+1
  516. t1=c2d(a1)+c2d(f(b1,c1,d1))+ c2d(m.kth) 
  517. t1a=right(d2c(t1),4,c0)
  518. t2=rotleft(t1a,shift)
  519. return t2
  520.  
  521. round2:procedure expose m. c1111 c0 c1 const1
  522. parse arg a1,b1,c1,d1,kth,shift
  523. kth=kth+1
  524. t1=c2d(a1)+c2d(g(b1,c1,d1))+ c2d(m.kth) + const1
  525. t1a=right(d2c(t1),4,c0)
  526. t2=rotleft(t1a,shift)
  527. return t2
  528.  
  529. round3:procedure expose m. c1111 c0 c1 const2
  530. parse arg a1,b1,c1,d1,kth,shift
  531. kth=kth+1
  532. t1=c2d(a1)+c2d(h(b1,c1,d1))+ c2d(m.kth) + const2 
  533. t1a=right(d2c(t1),4,c0)
  534. t2=rotleft(t1a,shift)
  535. return t2
  536.  
  537. /* add to "char" numbers, modulo 2**32, return as char */
  538. m32add:procedure expose c0 c1 c1111
  539. parse arg v1,v2
  540. t1=c2d(v1)+c2d(v2)
  541. t2=d2c(t1)
  542. t3=right(t2,4,c0)
  543. return t3
  544.  
  545.  
  546.  
  547. /*********** Basic functions */
  548. /* F(x, y, z) == (((x) & (y)) | ((~x) & (z))) */
  549. f:procedure expose c0 c1 c1111 
  550. parse arg x,y,z
  551. t1=bitand(x,y)
  552. notx=bitxor(x,c1111)
  553. t2=bitand(notx,z)
  554. return bitor(t1,t2)
  555.  
  556. /* G(x, y, z) == (((x) & (y)) | ((x) & (Z))|  ((y) & (z)) */
  557. g:procedure expose c0 c1 c1111
  558. parse arg x,y,z
  559. t1=bitand(x,y)
  560. t2=bitand(x,z)
  561. t3=bitand(y,z)
  562. t4=bitor(t1,t2)
  563. return bitor(t4,t3)
  564.  
  565. /* H(x, y, z) == ((x) ^ (y) ^ (z)) */
  566. h:procedure expose c0 c1 c1111
  567. parse arg x,y,z
  568. t1=bitxor(x,y)
  569. return bitxor(t1,z)
  570.  
  571.  
  572. /* bit rotate to the left by s positions */
  573. rotleft:procedure 
  574. parse arg achar,s
  575. if s=0 then return achar
  576.  
  577. bits=x2b(c2x(achar))
  578. lb=length(bits)
  579. t1=left(bits,s)
  580. t2=bits||t1
  581. yib=right(t2,lb)
  582. return x2c(b2x(yib))
  583.  
  584.  
  585. /***/
  586. /* comupte checksum using alpha and beta */
  587. rsync32:procedure expose alpha beta 
  588. parse arg mess
  589. asum=0 ; asum2=0
  590. l=length(mess)
  591. do i=1 to l
  592.    v1=c2d(substr(mess,i,1))
  593.    asum=asum+v1
  594.    asum2=((1+l-i)*v1) + asum2
  595. end /* do */
  596. alpha=asum // 65536
  597. beta=asum2 // 65536
  598. chek=alpha+ (65536*beta)
  599.  
  600. return chek
  601.  
  602.  
  603. /*********************/
  604. /* return checksum|md4, in character format */
  605. rsync32_md4:procedure 
  606. parse arg ablock
  607.  
  608. aa=rsync32(ablocK)
  609. aa=d2c(aa)
  610. c32=right(aa,4)
  611.  
  612. cmd4=x2c(rexx_md4(ablock))
  613.  
  614. return c32||cmd4
  615.  
  616.  
  617.