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