Contents of file "btoa.4th"
( btoa.4th - use with a saved system from version 0.10 of postForth)
HIGHLEVEL BTOA ' DOCOMMAND , ' Z , ' OPEN , ' DUP , ' Z , ' > , IF
' INFILE1 , ' ! , ' Z , ' CREATEFILE , ' DUP , ' Z , ' > , IF
' OUTFILE1 , ' ! , ELSE " Output is to STDOUT" ' TYPE , ' CR ,
THEN ELSE " Input from STDIN, output to STDOUT" ' TYPE , ' CR ,
THEN ' CONVERT_BTOA , " ~>" ' OUTFILE1 , ' @ , ' >TYPE , ' BYE , ' ;S ,
( Ascii85 conversion is the process of changing a 32-bit word [4 bytes] into
a 5-digit base-85 character, where "!" is a zero and "u" is the highest
possible value. In both cases, the leftmost byte [lowest addressed] is taken
as the most significant bits. That is, if the bytes at offset 0 through 3
are, in order, 00 00 00 01, then btoa translation will make it !!!!" where
'!' is zero and '"' is 1. 00 00 00 55 will translate to !!!"! because 55
[85 decimal] is a "ten" in this base, so the '"' [one] is in the second
position from the right. A special case is when the 32-bit number is 0,
in which case it translates to a single 'z'. Another special case is when
less than 4 characters are being converted, as can happen at the end of a
file. In this case, N input characters are padded with 4-N null bytes and
converted into N+1 Ascii85 characters. Padding is done at the end, that is,
the LSBs, since the first characters received are more significant. Also,
if a group of chars is all null bytes and is padded, it does not become 'z'
because 'z' stands for 4 nulls. N+1 '!' characters must be output instead.)
VARIABLE ASCII85 055 055 * 055 055 * UM* SWAP , , ( 85 ^ 4, store LSBs first)
055 055 * 055 UM* SWAP , , ( 85^3) 055 055 * , Z , ( 85^2) 055 , Z ,
1 , Z , ( 85^0 = 1)
HIGHLEVEL NEXT4 ( - d count) ' Z , ' Z , ' SP@ , ' >R , ( buffer on stack)
' INFILE1 , ' @ , ' LIT , 04 , ' R> , ' READ , ' DUP , ' <0 , IF
" Read error" ' TYPE , ' CR , ' 1 , ' EXIT , THEN ( auto-padded!)
' >R , ' SWAPBYTES , ' SWAP , ' SWAPBYTES , ' SWAP , ' R> , ( reorder)
' ;S ,
VARIABLE BUF Z ,
HIGHLEVEL 85DIGIT ( d a - d' a') ( output next ascii85 digit, advance
pointer into table and return remainder for next digit conversion)
' >R , ( address of table entry) ' Z , ' BUF , ' ! , ( zero to start)
' DUP , ' <0 , IF ( test if high word of number is already negative)
BEGIN ' R , ' D@ , ' D- , ' BUF , ' BUMP , ' DUP , ' <0 , ' NOT , UNTIL
( now we have gotten it positive) THEN BEGIN ' R , ' D@ ,
' D- , ' BUF , ' BUMP , ' DUP , ' <0 , UNTIL ( loop until underflow)
' R , ' D@ , ' D+ , ( restore positive value) ' BUF , ' @ , ' BL , ' + ,
' OUTFILE1 , ' @ , ' >EMIT , ( was already +1, so add 32 [space])
' R> , ' LIT , 04 , ' + , ' ;S ,
HIGHLEVEL 85WORD ( d n -) ( output double as ASCII85 equivalent)
' >R , ' R , ' LIT , 04 , ' = , ' >R , ( count=4 and d=0, output z)
' OVER , ' OVER , ' OR , ' Z= , ' R> , ' AND , IF
ASCII z ' OUTFILE1 , ' @ , ' >EMIT , ELSE ( any count, any other value)
' ASCII85 , BEGIN ' 85DIGIT , ' R> , ' 1- , ' >R , ' R , ' <0 , UNTIL
' DROP , ( table addr) THEN ' R> , ' DROP , ( count)
' 2DROP , ( dword) ' ;S ,
HIGHLEVEL CONVERT_BTOA BEGIN ' NEXT4 , ' DUP , ' >R , ' R , IF ' 85WORD ,
THEN ' R> , ' Z= , UNTIL ' DROP , ' 2DROP , ' ;S ,
BTOA