Subject: Re: saving procedures from NeWS

From: [email-masked] (William Roberts)
Date: Mon, 26 Oct 87 01:14:48 EST

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: [email-masked]  (gw: cs.ucl.edu)
Queen Mary College      UUCP: [email-masked]
LONDON, UK              Tel:  01-980 4811 ext 3900