Contents of file "btoa.pf"
#! /usr/local/postforth/pf
: BTOA
' ARGC , ' 2 , ' > ,
IF ( infile specified)
' 0 , ' CLOSEFILE , ' 2 , ' ARGV , ' 0 , ' 0 , ' OPEN ,
IF ( nonzero handle returned)
" Cannot redirect STDIN" ' 2 , ' TYPE , ' 2 , ' CR , ' 1 , ' EXIT ,
ENDIF
ENDIF
' ARGC , ' LIT , 16# 3 , ' > ,
IF ( outfile specified)
' 1 , ' CLOSEFILE , ' LIT , 16# 3 , ' ARGV ,
' LIT , 16# 1FF , ' UMASK , ' ~ , ' & , ' FCREATE ,
' 1 , ' = , ' ~ ,
IF ( handle not 1)
" Cannot redirect STDOUT" ' 2 , ' TYPE , ' 2 , ' CR , ' 1 , ' EXIT ,
ENDIF
ENDIF
' CONVERT_BTOA , " ~>" ' 1 , ' TYPE , ' 1 , ' CR , ' 0 , ' EXIT , ' ;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.
Some filters, such as postscript's, expect the Ascii85 stream to end in ~>
or it will not process it correctly. Strictly speaking it should also begin
with <~ but for some reason the postscript interpreters I've used don't
enforce this.)
VARIABLE ASCII85 16# 55 DUP DUP DUP DUP * * * ( 85 ^ 4) ,
DUP DUP DUP * * ( 85 ^ 3) ,
DUP DUP * ( 85 ^ 2) ,
( 85 ^ 1) ,
1 ( 85 ^ 0) ,
: SWAPS ( n -n2) ( swap 16-bit words in a 32-bit word)
' DUP , ' LIT , 16# 10 , ' >> , ( make a copy, and shift it down)
' SWAP , ' LIT , 16# 10 , ' << , ( shift original up)
' + , ' ;S , ( merge them with + or OR)
: NEXT4 ( - d count) ' 0 , ' SP@ , ' >R , ( buffer on stack)
' 0 , ' LIT , 16# 4 , ' R> , ' READ , ' DUP , ' 0< , IF
" Read error" ' 2 , ' TYPE , ' 2 , ' CR , ' 1 , ' EXIT , ENDIF
' >R , ' SWAB , ' SWAPS , ' SWAB , ' R> , ( reorder)
' ;S ,
: 85DIGIT ( n a - n' a') ( output next ascii85 digit, advance
pointer into table and return remainder for next digit conversion)
' SWAP , ' OVER , ' @ , ' 0 , ' SWAP , ' U/M , ( divide n by *a)
' LIT , ASCII ! , ' + , ' 1 , ' EMIT , ( convert to ASCII85 and output)
' SWAP , ' LIT , 16# 4 , ' + , ' ;S , ( replace n with remainder, update a)
: 85WORD ( n1 n2 -) ( output n1, count n2 as ASCII85 equivalent)
' >R , ' R , ' LIT , 16# 4 , ' = , ( count=4 and n=0, output z)
' OVER , ' 0= , ' & ,
IF ' LIT , ASCII z , ' 1 , ' EMIT ,
ELSE ( any count, any other value)
' ASCII85 ,
BEGIN ' 85DIGIT , ' R> , ' 1- , ' >R , ' R , ' 0< ,
UNTIL
' DROP , ( table addr)
ENDIF ' R> , ' DROP , ( count)
' DROP , ' ;S ,
: CONVERT_BTOA
BEGIN ' NEXT4 , ' DUP , ' >R , ' R ,
IF ' 85WORD ,
ENDIF ' R> , ' 0= ,
UNTIL ' DROP , ' DROP , ' ;S ,
BTOA ( run BTOA - comment out until debugged)