[comp.lang.postscript] Exploring PostScript's dictionaries

debruyne@prles3.prl.philips.nl (10/04/89)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
if test -f 'psdicts'
then	rm 'psdicts'
fi
if test -d 'psdicts'
then	:
else	echo 'Making     psdicts/'
	mkdir 'psdicts'
fi
chmod 'u=rwx,g=rx,o=rx' 'psdicts'
echo 'Extracting psdicts/README'
sed 's/^X//' > psdicts/README << '+ END-OF-FILE psdicts/README'
XHi there,
X
XWhile I was playing with PostScript a few weeks ago, I found out
Xthat it is possible to list the names of the keywords in PostScript's
Xdictionaries.
X
XBecause we're going to swich from an Apple LaserWriter to an
XAgfa P3400PS Laser Printer, I thought it might be nice to have a way
Xto compare the internal dictionaries of these printers.
X
XThis resulted in a recursive PostScript program, systemdict.ps, that 
Xlists the total contents of the printer's dicts.
X
XThe output is as follows (in regular expression syntax):
X  level keyword type value
X  where:
X    level 	= (.   )*
X    keyword 	= <The human readable keyword>
X    type	= "(" ((typeId ( access | none )) | none) ")"
X    typeId	= (array|boolean|dict|file|fontId|integer|mark|name|
X		   null|operator|packedarray|real|save|string)
X    access	= (","(r|-)(w|-)(x|-))
X    value	= (( "=" <the keyword's value>) | none )
X    none	= ""		     
X
X  which means:
X    level gives the level of the dictionary:
X      "" 	   means the upper level
X      ".   "	   means one level below the upper level
X      ".   .   "   means two levels below the upper level
X    and so on
X
X    Each time a dictionary is encountered the program descends a level
X    and that dictionary is then listed.
X    An empty line indicates that the program is ascending one level.
X    For instance, a part of the systemdict might look like:
X	type (operator)			% upper level (systemdict)
X	userdict (dict,rw-)		% userdict is encountered
X	.   #copies (integer) = 1	% #copies is a keyword in userdict
X	.   $IdleTimeDict (dict,rw-)	% a new dict is encountered
X	.   .   ROMnames (array,r--)	% an entry in $IdleTimeDict
X					% empty line: ascending one level
X	.   LocalDict (dict,rw-)	% LocalDict is a keyword in userdict..
X	.   .   Dlen (integer) = 24	% .. which is again a dict
X					% empty line: ascending
X	.   start (packedarray,r-x)	% a keyword in userdict
X					% empty line: back to systemdict
X	usertime (operator)		% a keyword in systemdict
X	version (string,r--) = 38.0	%   ...
X
X
X    In the latter example the keywords are: 
X      type, userdict, #copies, $IdleTimeDict, ROMnames, LocalDict, Dlen, 
X      start, usertime and version.
X
X    The types are:
X      operator, dict, integer, array, packedarray and string.
X
X    The accesses are:
X      r = read
X      w = write
X      x = execute
X    so rw- means: read access, write access, not executable 
X
X    If the keyword's value is of the type integer, string, name, boolean
X    or real, then the value of the keyword is listed if the ascii 
X    representation doesn't exeed 19 characters. If it exeeds 19 characters 
X    then the representation is clipped, which is indicated by three dots.
X    For instance:
X	Notice (string,r--) = Helvetica is a ...
X
X    
XThe font dictionaries, located in the FontDictionary, contain a dictionary
Xcalled CharStrings. See the Red Book page 92 for a description of this
Xdictionary. The contents of these dictionaries is not listed (it would
Xproduce many many pages of identical information). Instead, three dots 
Xindicate that there is more...
XFor instance:
X	FontDirectory (dict,r--)
X	.   Courier (dict,r--)
X	.   .   CharStrings (dict,r--)
X	.   .   .   ...
X
X	.   .   Encoding (array,r--)
X	.   .   FID (fontId)
X	and so on
X
X
XEvery dictionary is first sorted in alphabetically ascending order by the 
Xprocedure qsort, written August 31, 1989  by Scott Hemphill, who posted 
Xhis routine to comp.lang.postscript a while ago as an addition to the 
XPostScript toolkit.
X
X
XLine 265 in the file systemdict.ps is:
X/DictName (systemdict) def
X
XThe string systemdict can be changed to anything else that results in a 
Xdictionary on the stack. 
XFor instance:
X	/DictName (userdict) def
Xor:
X	/DictName (systemdict /statusdict get) def
X
XIf you do so, be sure to modify line 74 (starting level information) as well.
X
X
XIf you have any comments or if you encounter any bugs, please let me know.
X
XJos de Bruijne
XPhilips Research Laboratories
XEindhoven, The Netherlands
XEmail: debruyne@prles3.prl.philips.nl
X
+ END-OF-FILE psdicts/README
chmod 'u=rw,g=r,o=r' 'psdicts/README'
echo 'SENT: -rw-r--r--  1 debruyne     3990 Oct  3 13:09 psdicts/README'
echo -n 'RCVD: '
/bin/ls -l psdicts/README
echo 'Extracting psdicts/systemdict.ps'
sed 's/^X//' > psdicts/systemdict.ps << '+ END-OF-FILE psdicts/systemdict.ps'
X%!
X
X/qsortdict 7 dict def
Xqsortdict begin
X   /q-compare 0 def		% user-supplied comparison procedure
X   /q-array 1 def		% current sub-array being sorted by qsortsub
X   /q-length 2 def		% length of q-array
X   /q-left 3 def		% left scan index
X   /q-right 4 def		% right scan index
X   /q-last 5 def		% partitioning element
X   /q-temp 6 def		% temporary array element
Xend
X
X/qsort
X{
X   qsortdict begin
X   /q-compare exch def
X   qsortsub
X   end
X}
Xbind def
X
X/qsortsub
X{
X   /q-array exch def
X   /q-length q-array length def
X   q-length 1 gt
X   {
X      /q-left 0 def
X      /q-right q-length 1 sub def
X      /q-last q-array q-right get def
X      {
X         {
X            q-array q-left get q-last q-compare
X            {/q-left q-left 1 add def}
X            {exit}
X            ifelse
X         }
X         loop
X         {
X            q-left q-right eq {exit} if
X            q-array q-right get q-last q-compare
X            {exit}
X            {/q-right q-right 1 sub def}
X            ifelse
X         }
X         loop
X         q-left q-right eq {exit} if
X         /q-temp q-array q-left get def
X         q-array q-left q-array q-right get put
X         q-array q-right q-temp put
X      }
X      loop
X      q-array q-length 1 sub q-array q-left get put
X      q-array q-left q-last put
X      q-array q-left 1 add q-length q-left sub 1 sub getinterval
X         q-array 0 q-left getinterval
X         qsortsub
X      qsortsub
X   }
X   if
X}
Xbind def
X
Xgsave
X
Xserverdict begin
Xstatusdict begin
X/Times-Roman findfont 20 scalefont setfont 
X72 730 moveto 
X/Str 80 string def 
XStr printername show
X/Times-Roman findfont 12 scalefont setfont
X(\'s dictionaries  \(starting level: systemdict\)) show
Xend end
X
X/LocalDict 27 dict def
XLocalDict begin
X  /X 			0 def
X  /Y 			1 def
X  /row 			2 def
X  /col 			3 def
X  /crlf 		4 def
X  /showln 		5 def
X  /s 			6 def
X  /ShowOperandType 	7 def
X  /Oper 		8 def
X  /NewStr 		9 def
X  /loopvar 		10 def
X  /rwxcheck 		11 def
X  /showarr 		12 def
X  /Keyword 		13 def
X  /Operand 		14 def
X  /OperandType 		15 def
X  /arr 			16 def
X  /Str 			17 def
X  /NewLine		18 def
X  /Spaces		19 def
X  /DictName		20 def
X  /OldDictName		21 def
X  /Dlen			22 def
X  /TmpStr		23 def
X  /shw			24 def
X  /ShowContents		25 def
X  /PageNo		26 def
Xend
X
XLocalDict begin
X
X/X 72 def /Y 700 def /row 1 def /col 1 def
X/crlf { /Y Y 10 sub def X Y moveto /row row 1 add def } def
X
X/shw { % <any> "shw" -  (NOTE: string shown is at most 19 chars long)
X  dup type (                    ) cvs (stringtype) ne 
X    { /TmpStr 128 string def TmpStr cvs cvlit /TmpStr exch def }
X    { cvlit /TmpStr exch def } 
X  ifelse
X  TmpStr length 19 gt 
X    { /NewStr 19 string def
X      0 1 14 {
X	/loopvar exch def
X	TmpStr loopvar get NewStr exch loopvar exch put 
X      } for
X      16 1 18 { 
X	NewStr exch 46 put
X      } for
X      /TmpStr NewStr def
X    } if
X    TmpStr show
X} def % shw
X
X/showln { % <any> "showln" -
X  X Y moveto shw crlf 
X} def
X/s { % <any> "s" -
X  X Y moveto shw 
X} def
X
X/NewLine { 
X  crlf
X  row 60 eq {
X    /row 1 def
X    /Y 700 def
X    /X X 170 add def
X    /col col 1 add def
X    col 3 gt {
X      gsave
X      291 70 moveto
X      /Times-Roman findfont 9 scalefont setfont
X      (\-  ) show PageNo (   ) cvs show (  \-) show
X      showpage 
X      grestore
X      /PageNo PageNo 1 add def
X      /col 1 def
X      /X 72 def
X    } if
X  } if
X} def % NewLine
X
X/ShowOperandType { % <OperandTypeString> "ShowOperandType" -
X  /Oper exch def
X  Oper (fonttype) eq { (fontId) show }
X  {
X    /NewStr Oper length 4 sub string def
X    0 1 Oper length 5 sub {
X      /loopvar exch def
X      Oper loopvar get NewStr exch loopvar exch put
X    } for
X    NewStr show
X  } ifelse
X} def % ShowOperandType
X
X/rwxcheck { % <array|dict|file|string> "rwxcheck" -
X  (,) show
X  dup rcheck {(r) show} {(-) show} ifelse
X  dup wcheck {(w) show} {(-) show} ifelse
X  xcheck {(x) show} {(-) show} ifelse
X} def % rwxcheck
X
X/ShowContents { % - "ShowContents" -
X  /Times-Italic findfont 8 scalefont setfont
X  OperandType (integertype) eq    OperandType (stringtype) eq or 
X  OperandType (booleantype) eq or OperandType (nametype) eq or    
X  OperandType (realtype) eq or
X  { mark
X    { DictName cvx exec Keyword get } stopped 
X    { ( = \(\?\)) show }
X    { ( = ) show shw } ifelse
X    cleartomark
X  } if
X} def % ShowContents
X
X/showarr { % - showarr -
X  gsave
X  arr {
X    /Times-Bold findfont 8 scalefont setfont
X    /Keyword exch def
X    Spaces s Keyword shw 
X    /Times-Roman findfont 8 scalefont setfont
X    (  \() show 
X    { DictName cvx exec Keyword get } stopped 
X    {( ) show /OperandType (undef) def}
X    {
X      type (                         ) cvs
X      /OperandType exch def
X      OperandType ShowOperandType 
X      DictName cvx exec Keyword get 
X      OperandType (arraytype)  eq { rwxcheck }
X      { OperandType (packedarraytype)   eq { rwxcheck }
X	{ OperandType (dicttype)   eq { rwxcheck }
X    	  { OperandType (filetype)   eq { rwxcheck }
X      	    { OperandType (stringtype) eq { rwxcheck }
X              { pop
X	      } ifelse
X	    } ifelse
X	  } ifelse
X	} ifelse
X      } ifelse
X    } ifelse
X    (\)) show 
X    OperandType (dicttype) ne ShowContents
X    NewLine
X    OperandType (dicttype) eq Keyword (systemdict) ne and 
X      { Keyword (CharStrings) eq 
X	{ /Times-Bold findfont 8 scalefont setfont
X	  Spaces s (.   ...) show NewLine NewLine 
X	}
X	{ DictName cvx exec Keyword get rcheck 
X	  { DictName dup /OldDictName exch def
X	    /Dlen DictName length def
X 	    /DictName Dlen 6 add Keyword length add string def
X	    DictName 0 OldDictName putinterval
X	    DictName Dlen 1 add (\/) putinterval
X	    DictName Dlen 2 add Keyword putinterval
X	    DictName Dlen Keyword length add 3 add (get) putinterval
X	    Spaces
X	    /Spaces Spaces length 4 add string def
X	    1 4 Spaces length 1 sub {
X	      Spaces exch 46 put
X	    } for
X	    arr
X	    mark
X	    {/arr 
X	      [DictName cvx exec {pop /Str 80 string def Str cvs} forall] 
X	    def} stopped {} {
X	      arr /lt load qsort
X	      showarr
X	    } ifelse
X	    cleartomark
X	    /arr exch def
X	    /Spaces exch def
X	    /DictName exch def
X	    NewLine
X	  } if
X	} ifelse
X      } if
X  } forall
X  grestore
X} def
X
X/Times-Roman findfont 8 scalefont setfont
X
X/PageNo 1 def
X/Spaces 1 string def
X/DictName (systemdict) def
X/arr [DictName cvx exec {pop /Str 80 string def Str cvs} forall] def
Xarr /lt load qsort
Xshowarr
X
Xrow 1 ne col 1 ne or 
X  { 291 70 moveto
X    /Times-Roman findfont 9 scalefont setfont
X    (\-  ) show PageNo (   ) cvs show (  \-) show
X    showpage 
X  } if
X
X
Xgrestore
Xend % LocalDict
+ END-OF-FILE psdicts/systemdict.ps
chmod 'u=rw,g=r,o=r' 'psdicts/systemdict.ps'
echo 'SENT: -rw-r--r--  1 debruyne     6482 Oct  3 08:44 psdicts/systemdict.ps'
echo -n 'RCVD: '
/bin/ls -l psdicts/systemdict.ps
exit 0

philip@xilinx.UUCP (Philip Freidin) (10/06/89)

In article <723@prles2.UUCP> debruyne@prles3.prl.philips.nl () writes:
>
> ..... Really Neat program that does EXACTLY what I have wanted to do
> ..... ever since I got my new PostScript printer a week ago!!!!

1) bug 1:   the "'s" after the printers name printed on the first page
	    is in the wrong point size.  (I may know enough about
	    postscript to fix this my self :-)  )

2) bug 2:   When run on my printer (Jasmine Direct print (which is
            actually a Qume CrystalPrint, with new labels stuck on.)
	    Memory is 3 MB, CPU is Weitek 8200, engine is ??? LCD
	    shutter, PS interpreter is a clone with version number
	    3.02) with systemdict as the starting level, it prints 10
	    pages beautifully, and then dies with a VMERROR. Except for
	    the first dozen or so lines in the first column on page 1,
	    the rest is all font info (about 4 columns of info per
	    font, so it dies during the 7th font). What is all this
	    gunk it is printing out about each font? how do I get
	    around the VMerror (The available VM memory does meet the
	    required minimum as specified in the red book, where it
	    details the minimum requirements for VM is 240000 bytes).
	    How do I findout how to use commands that are listed in
	    the various dictionaries, but not in any of the Adobe
	    books?

Philip Freidin    uunet!xilinx!philip
		  pyramid!xilinx!philip



-- 
Philip Freidin: Product Planning Manager, Xilinx, INC
(rest of clever .sig still under construction....
		coming to a terminal near you, Real Soon Now (tm))

debruyne@prles3a.prl.philips.nl (Jos de Bruijne) (10/09/89)

Last Thursday, when I switched form an Apple Laserwriter to an Agfa P3400PS
Laserprinter I encountered some problems with my program "systemdict.ps"
that I posted a few days ago.

1. The statusdict-integer waittimeout was too small (30): The printer ended 
   with an error-message "timeout".
   To solve this problem I added some lines to my program that increase this
   timeout during the job to 120.

2. When the program encountered a "no access" string, i.e.:
	FontDirectory (dict,r--)
	.   Courier (dict,r--)
	.   .   CharData (string,---)			
   the printerjob ended with:
	%%[ Error: invalidaccess; OffendingCommand: length ]%%
   
   The printer was right about that (isn't he always?): it is illegal to
   read a string that has *no* access at all !
   This problem was solved by adding a few lines that first check the
   keyword to see if it has read-access.


The end of this file is the diff(1) output of the changes I made to 
systemdict.ps . 


One other problem
-----------------
There is one known problem that I wasn't able to solve right now:
The printer might stop the job with an error that looks something like:
	%%[ Fatal system error.... ]%%
I think that is because the printer's memory is full. This might be so for
instance when you use permanently downloaded fonts from TeX (or LaTeX).
Switching the printer off and on again might solve this problem, BUT then
all of your donwloaded stuff is also gone !


If you still find any bugs after you have updated systemdict.ps please
let me know.

			Jos. 


***** the rest of the file is diff(1) output for the systemdict.ps update. *****

77c77
< /LocalDict 27 dict def
---
> /LocalDict 28 dict def
105a106
>   /wto			27 def
186,188c187,191
<     { DictName cvx exec Keyword get } stopped 
<     { ( = \(\?\)) show }
<     { ( = ) show shw } ifelse
---
>     OperandType (stringtype) eq {
>       DictName cvx exec Keyword get rcheck
>       { ( = ) show DictName cvx exec Keyword get shw } if
>     } 
>     { ( = ) show DictName cvx exec Keyword get shw } ifelse
260a264,268
> statusdict begin
>   defaulttimeouts /wto exch def pop pop
>   /waittimeout 120 def
> end
> 
276a285,287
> statusdict begin
>   /waittimeout wto def
> end
279a291,292
> 
>