liam@cs.qmc.ac.uk (William Roberts) (10/22/87)
Expires:
Sender:
Followup-To:
Distribution:
You have other problems to worry about besides operators: there
are also strings and dictionaries. You can handle dictionaries
and operators by using the ability to have arbitrary objects as
keys in PostScript dictionaries. The strings are a bit harder
and you just have to work you way through them, handling the
special cases.
I spent this afternoon writing the following, which finishes up
with these useful routines:
Print any_object => - % prints the object
PrintDef /name => - % prints a definition
FileOut dict (filename) => - % writes procedures to a file
The output of PrintDef looks a bit stilted, e.g.
---------------------------------
%
/Print{ dup type /arraytype eq{ PrintArray}
{ dup type /stringtype eq{ PrintString}
{ PrintItem}
ifelse}
ifelse pause}
def
---------------------------------
but it is legal and it is human-readable (almost). The Print and
PrintDef routines write to a file object which is called
/OutputFile and must be accessible on the dict stack. This
defaults to (%stderr) just like == and so on. The FileOut
method writes all the procedures in the given dictionary into
the filename of your choice.
The main thing that still doesn't work is dictionaries: if you
register a name for the dictionary it will be identified, e.g.
/Object AddIndexItem
Object Print
gives
Object
but otherwise you just get the obscure
dictionary[72]
which is of course not very useful. Here is the code (it uses a
few useful things like fprintf which are supplied with NeWS):
------------------------------------------------
%!NeWS-1.0
%%
%% Write PostScript Objects to a file
%% STAGE 1:
%%
%% The index of known names - you supply the object and that
%% is used as a key in MyIndex to find the associated name.
%% Pre-fill this with things from systemdict and a few
%% well-known dictionary names
/MyIndex 500 dict def
/AddIndexItem { % name => -
MyIndex exch dup load exch cvx put
} def
% Load up with all systemdict operators
systemdict {
dup dup
type /operatortype eq exch
type /dicttype eq or
{ exch MyIndex 3 1 roll cvx put }
{ pop pop }
ifelse
} forall
% Fix a couple of stupidities
MyIndex systemdict /systemdict cvx put
MyIndex userdict /userdict cvx put
%% STAGE 2:
%%
%% Lowest level print stuff
/FPrint { % string => - (write string to OutputFile)
OutputFile exch (%) fprintf
} def
% Default OutputFile is stderr
/OutputFile (%stderr)(w) file def
%% STAGE 3:
%%
%% Various print procedures of increasing complexity
/PrintItem { % object => - (fprints object to OutputFile)
dup MyIndex exch known
{ MyIndex exch get } if
OutputFile exch ( %) fprintf
} def
/PrintArray { % array => - (FPrint it to OutputFile)
dup xcheck { (}\n) ({) } { (]\n) ([) } ifelse
FPrint exch
/Print load forall
FPrint
} def
/PrintString { % string => - (FPrint string to OutputFile)
(\() FPrint /PrintChar load forall (\)) FPrint
} def
% Chars are somewhat harder - use a dictionary to record
% some of the more common ones
/StringSpecials 35 dict begin
(\n) 0 get (\\n) def
(\r) 0 get (\\r) def
(\t) 0 get (\\t) def
(\b) 0 get (\\b) def
(\f) 0 get (\\f) def
(\\) 0 get (\\\\) def
(\() 0 get (\\() def
(\)) 0 get (\\)) def
currentdict end
def
/PrintChar { % int => - (FPrint equivalent char string)
dup
StringSpecials exch known
{ StringSpecials exch get }
{ dup 127 gt
{ (\\) FPrint 8 (000) cvrs }
{ dup 32 lt
{ 8 (00) cvrs (\\0xx) dup 2 4 -1 roll putinterval}
{ (x) dup 0 4 -1 roll put } ifelse
} ifelse
} ifelse
FPrint
} def
%% STAGE 4:
%%
%% The interesting print procedures
/Print { % anything => - (FPrint it to OutputFile)
dup type /arraytype eq {PrintArray} {
dup type /stringtype eq {PrintString} {PrintItem} ifelse
} ifelse
pause
} def
/PrintDef { % name => - (FPrint definition to OutputFile)
(%\n) FPrint
dup Print load Print ( def\n\n) FPrint
} def
% FileOut preserves the original OutputFile and restores
% it at the end. Be warned, this takes a fair while if you
% decide to FileOut the systemdict....
/FileOut { % dict name => - (write dict procs to file)
OutputFile 3 1 roll
/OutputFile exch (w) file store
dup begin
{ dup xcheck
{ type /operatortype ne { PrintDef} { pop } ifelse }
{ pop pop } ifelse
} forall
end
OutputFile closefile
/OutputFile exch store
(Done\n) print
} def
------------------------------------------------
Here is the result of typing
lhc1% psh
executive
(fileproc.ps) run
currentdict (fileout) FileOut
------------------------------------------------
%
/Print{ dup type /arraytype eq{ PrintArray}
{ dup type /stringtype eq{ PrintString}
{ PrintItem}
ifelse}
ifelse pause}
def
%
/AddIndexItem{ MyIndex exch dup load exch cvx put}
def
%
/FileOut{ OutputFile 3 1 roll /OutputFile exch(w) file store dup begin{ dup xcheck{ type /operatortype ne{ PrintDef}
{ pop}
ifelse}
{ pop pop}
ifelse}
forall end OutputFile closefile /OutputFile exch store(Done\n) print}
def
%
/PrintString{(\() def
()) 0 get (\)) FPrint /PrintChar load forall()) FPrint}
def
%
/FPrint{ OutputFile exch(%) fprintf}
def
%
/PrintDef{(%\n) FPrint dup Print load Print( def\n\n) FPrint}
def
%
/execfile file(?,W,R) def
%
/PrintItem{ dup MyIndex exch known{ MyIndex exch get}
if OutputFile exch( %) fprintf}
def
%
/PrintChar{ dup StringSpecials exch known{ StringSpecials exch get}
{ dup 127 gt{(\\) FPrint 8(000) cvrs}
{ dup 32 lt{ 8(00) cvrs(\\0xx) dup 2 4 -1 roll putinterval}
{(x) dup 0 4 -1 roll put}
ifelse}
ifelse}
ifelse FPrint}
def
%
/PrintArray{ dup xcheck{(}\n)({)}
{(]\n)([)}
ifelse FPrint exch /Print load forall FPrint}
def
%
/bye{ quit}
def
--
William Roberts ARPA: liam@cs.qmc.ac.uk (gw: cs.ucl.edu)
Queen Mary College UUCP: liam@qmc-cs.UUCP
LONDON, UK Tel: 01-980 4811 ext 3900