%!
% Copyright (C) 2001-2023 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
% CA 94129, USA, for further information.
%

% uninfo.ps: Utilities for "printing" PostScript items, especially dictionaries
% Usage:
% (prefix-string) dict unprint

% Maximum Print-Width
/HSpwidth 80 def

% any  HScvs string
/HScvs {
% Number-Syntax
  dup type % stack: any /anytype
  dup /integertype eq 1 index /realtype eq or { pop
    16 string cvs
  }{
% Logical-Type
    dup /booleantype eq { pop
      5 string cvs
    }{
% Identifiers
      dup /nametype eq { pop
        dup length 1 add string
        dup 0 (/) putinterval
        exch 1 index 1 1 index length 1 sub getinterval cvs pop
      }{
% Strings
        dup /stringtype eq { pop
% ------- Compute Length
          2 1 index { % stack: str len item
            dup 32 lt 1 index 126 gt or { % need 4
              pop 4 add
            }{
              dup 40 eq 1 index 41 eq or 1 index 92 eq or {
                pop 2 add
              }{
                pop 1 add
              } ifelse
            } ifelse
          } forall
% ------- Allocate & Fill String
          string dup 0 (\() putinterval 1
          3 -1 roll { % outstr pos item
            dup 32 lt 1 index 126 gt or {
              dup 7 le {
                2 index 2 index (\\00) putinterval
                8 3 index 3 index 3 add 1 getinterval cvrs
              }{
                dup 63 le {
                  2 index 2 index (\\0) putinterval
                  8 3 index 3 index 2 add 2 getinterval cvrs
                }{
                  2 index 2 index (\\) putinterval
                  8 3 index 3 index 1 add 3 getinterval cvrs
                } ifelse
              } ifelse
              pop 4 add
            }{
              dup 40 eq 1 index 41 eq or 1 index 92 eq or {
                2 index 2 index (\\) putinterval
                exch 1 add exch
              } if
              2 index exch 2 index exch put
              1 add
            } ifelse
          } forall
          1 index exch (\)) putinterval
        }{ exch pop
          dup length 1 add string
          dup 0 (-) putinterval
          exch 1 index 1 1 index length 1 sub getinterval cvs pop
          dup dup length 4 sub (-) putinterval
          0 1 index length 3 sub getinterval
        } ifelse
      } ifelse
    } ifelse
  } ifelse
} bind def

% int HSpindent - indent-spaces
/HSpindent {
  dup 0 gt {
    1 1 3 -1 roll { pop ( ) print } for
  }{
    pop
  } ifelse
} bind def

% indent array HSaprint -> Print an Array
/HSaprint {
  dup type /arraytype eq {
    ( [) print
    exch 1 add dup 1 add
    3 -1 roll { % rind pos item
      HScvs dup length % rind pos str len
      dup 3 index add HSpwidth ge {
        (\n) print
        3 index HSpindent
        3 -1 roll pop
        2 index add
        exch
      }{
        ( ) print
        2 index add 1 add
        3 -1 roll pop
        exch
      } ifelse
      print
    } forall
    ( ]) print
    pop pop
  }{
    ( ) print
    HScvs print pop
  } ifelse
  (\n) print
} bind def

% dict HSdnames dict names (creates sorted name-strings)
/HSdnames {
% Build namelist, stack: dic
  dup length 0 eq {
    []
  }{
    [ 1 index {
        pop dup type /nametype eq {
          dup length string cvs
        }{
          pop
        } ifelse
      } forall
    ]
% Sort the namelist, stack: dic nam
    0 1 2 index length 2 sub { % stack: dic nam I
      2 copy get % stack: pre dic nam I nam[I]
      1 index 1 add 1 4 index length 1 sub { % stack: dic nam I nam[I] J
        3 index 1 index get % dic nam I S[I] J S[J]
        2 index 1 index gt { % swap them
           4 index 2 index 4 index put
           4 index 4 index 2 index put
           3 1 roll
        } if
        pop pop
      } for
      pop pop
    } for
  } ifelse
} bind def

% string:prefix dict:which unprint
/unprint {
  HSdnames % pre dic nam
% compute the maximum length
  0 1 index { % pre dic nam maxlen nam[I]
    length 2 copy lt { exch } if pop
  } forall
% Print out all the items, stack: pre dic nam maxlen
  (\n) print
  exch { % pre dic maxlen nam[I]
% no prefix yet, -> flush right
    3 index length 0 eq {
      dup length 2 index exch sub HSpindent
    }{
      3 index print (/) print
    } ifelse
% print the name
    dup print
% prefix: fill up with blanks
    3 index length 0 ne {
      dup length 2 index exch sub HSpindent
    } if
% now print the item itself, stack: pre dic maxlen nam[I]
    2 index 1 index cvn get dup type % stack: pre dic maxlen nam[i] item typ
% Dict-Syntax
    dup /dicttype eq { pop % stack: pre dic maxlen nam[i] item
      ( ) print dup HScvs print
      4 index length 0 eq { % brand new prefix
        2 index string 0 1 5 index 1 sub { 1 index exch 32 put } for
        dup 4 index 4 index length sub 5 -1 roll putinterval
      }{
        4 index length 1 add 2 index length add string
        dup 0 7 index putinterval
        dup 6 index length (/) putinterval
        dup 6 index length 1 add 5 -1 roll putinterval
      } ifelse
      exch unprint
    }{
      3 -1 roll pop % tack: pre dic maxlen item typ
% Array-Syntax
      dup /arraytype eq { pop % stack: pre dic maxlen item
        3 index length dup 0 ne { 1 add } if 2 index add
        exch HSaprint
      }{ pop
        ( ) print
        HScvs print
        (\n) print
      } ifelse
    } ifelse
  } forall
  pop pop length -1 eq { (\n) print } if
} bind def

/currentpagedevice where { % check for currentpagedevice
   /currentpagedevice get exec () exch unprint
} if
