[mod.computers.laser-printers] Flaw in Postscript?

seiler@HUDSON.DEC.COM ("LARRY SEILER") (01/15/86)

There's something that's bothered me since I first heard of Postscript,
and now that people are doing fancy stuff like N-up headers, it might
actually start biting people.  

Early criticisms of Postscript pointed out things like the absence of
any built in accounting, bugs in ROM'd code, and so forth.  To each of 
the criticisms, the reply was that Postscript allows builtin operations
to be redefined, so that a piece of patch code can be downloaded to
correct known bugs, a site that wants per-page accounting can define
a new ShowPage that provides this, and so forth.

For bug fixes, this is great.  But when it is used to add new features
to an existing function, there is trouble.  Say that the system redefines
ShowPage to include per-page accounting, and I use a header that redefines
ShowPage to do 2-up printing.  Either I've just defeated the accounting,
or else the definition of ShowPage was locked in and my 2-up header fails
on this machine.

Can any Postscript gurus out there point out a way around this problem?
It would suffice in this case to allow ShowPage to be redefined by an N-up 
header that itself calls the previous definition of ShowPage (not the original 
version, which might be buggy or might not include desired accounting).
Is that possible in PostScript?  Can anyone come up with other examples
like this where nesting of function redefinitions causes trouble?

	Larry

PS - Please, no straw men: don't say "but you have the same problem in
page description languages X, Y, and Z as well."  The question is, can
PostScript cope with it.
------

evan@SU-CSLI.ARPA (Evan Kirshenbaum) (01/15/86)

>It would suffice in this case to allow ShowPage to be redefined by an N-up
>header that itself calls the previous definition of ShowPage (not the
>original version, which might be buggy or might not include desired
>accounting).  Is that possible in PostScript?  

This is exactly what is done.  You do something like:

mydict begin
  /OLDSHOWPAGE /showpage load def
  ...
end

/showpage {
  mydict begin
  ... OLDSHOWPAGE ...
  end } def

Thus the newly defined version of showpage calls the version most recently
defined (at the time of definition).  This allows bugfixes to rom code and
even allows such redefinitions to be nested.

Evan Kirshenbaum
-------

reid@SU-GLACIER.ARPA (Brian Reid) (01/15/86)

This is the sort of issue that can be difficult to understand until you
fully understand PostScript. Let me offer a brief explanation.

  (1) PostScript implementations come with a barrier, namely the server
loop boundary, inside which the system manager can change things, but
the user cannot. So the system manager can redefine "showpage" inside
the server loop so that it does whatever kind of accounting he wants,
in such a way that nobody can access the original definition of
showpage, and therefore there is no way to print a page without calling
his redefined version of showpage. This is accomplished by exiting the
server loop, retrieving the value of the name "showpage", then defining
a new symbol named "showpage" whose contents is some form of accounting
followed by an execution of the value that was retrieved from the old
showpage operator before it was redefined. If the resulting definition
is marked "execute-only", then it cannot be picked apart, and the
old value cannot be extracted from it.

Once the server loop is re-entered, the new showpage is
indistinguishable from the old showpage--it is a "built in" operator,
because the user cannot execute a restore that will un-do the
redefinition, and cannot get his hands on the old version of the
operator.

 (2) Referring to things like the 2-up header as "redefining" showpage
is a bit misleading. It doesn't really redefine the showpage operator,
it redefines the meaning of the name "showpage". It does this by
stacking a new dictionary on top of the existing dictionary stack, and
putting in that new dictionary a function named "showpage". That
function will do the necessary 2-up trickery, and then call the
"original" showpage. The "original" showpage here means the definition
of the operator that was in force at the time the 2-up header
dictionary was stacked. This can be accomplished in several different
ways; my favorite is for each kind of header (such as the 2-up header)
to extract the old definition of showpage and put it in a safe place,
then stack a new definition; and at the end pop back to the previous
definition. In this way it is easy to take a header that throws
decorative borders around the page and combine it with a header that
prints in 2-up, each of which relies on a redefinition of the name
"showpage", in such a way that the resulting combination prints
decorated pages in 2-up, or so that it prints 2-up pages with a
combined decorative border, by reversing the order of the two header
files.

Summary: page accounting changes are done by redefining the OPERATOR
that is called "showpage". 2-up printing and other such headers are
done by stacking a new definition for the NAME "showpage", regardless
of its contents. As long as the 2-up header works by stacking the new
definition, rather than overwriting the old one, then it can be
arbitrarily combined with other headers. In no event can a header undo
the effect of an operator redefinition by the system manager.

Brian Reid
Stanford

laser-lovers@ucbvax.UUCP (01/16/86)

This is in response to a message from LARRY SEILER <seiler@hudson.dec.com>
regarding the PostScript language and the redefining operators, and to some
of the subsequent replies.

The problem:

You want to redefine the `showpage' operator in such a way that a user
job downloaded to the PostScript printer will use your version of
`showpage' instead of the one in /systemdict, thereby allowing for N-up
output, page accounting, etc.  You also want to make sure that your
version of `showpage' does not replace any existing re-definition of
`showpage', but augments it.

A solution:

The version of /showpage that is in systemdict CANNOT be altered by
the user, and will always be the bottom line.  Anyone who redefines
/showpage in userdict will need to essentially rename the existing
/showpage as something else, and then call it.  If /showpage has been
redefined already, then this routine should be called by the new
/showpage as if it were the real showpage.  The `exitserver' operator
will allow the user (or system manager) to make the operator
definition persist from one user job to another, because the
definition will take place inside the save/restore construct in the
serverloop.  There is no other privilege afforded by the `exitserver'
operator; the routines in systemdict are in ROM and cannot be
altered.  If /showpage has not been redefined, then the /showpage in
systemdict should be called directly.  In order to allow for
aribtrary levels of redefinition, a scheme should be used to generate
a unique name for the old /showpage (which can be done using the page
count, for example, but that is a bit beyond this discussion), then
to copy the old showpage under the new name, and call it from the new
/showpage you are defining.  Below is an example which does not
bother to make sure that the name is unique, but otherwise satisfies
the problem posed above:

%!PS-Adobe-1.0
%%For: redefining the showpage operator

/realshowpage /showpage load def
/showpage {
    90 rotate
    0 -612 translate
    .5 .5 scale
    realshowpage
} def

The use of the `load' operator here will look downward through the
dictionary stack (in case there are added levels of dictionaries,
redefinition, etc. already there) until it finds the `showpage' name,
and will push the procedure body onto the stack.  In the event that
the /showpage routine has not been redefined, then /realshowpage will
get the /showpage routine that is in systemdict, which it should.  If
another job comes along and redefines /showpage again, then it should
rename my /realshowpage to something different, and call it the same
way:

%!PS-Adobe-1.0
%%For: re-redefining the showpage operator

/realshowpage.$$ /showpage load def
/showpage {
    90 rotate
    0 -612 translate
    .5 .5 scale
    realshowpage.$$
} def

In this case, the `/showpage load' will retrieve my version of
/showpage from above, which in turn will call /realshowpage, which is
actually the /showpage from systemdict.

This can go on indefinitely, if you are willing to clutter up
userdict with strange names.  It basically boils down to a naming
problem, not a PostScript problem.

Glenn Reid
Adobe Systems Incorporated