%!PS % This version 18:00 Saturday 4th February 2023 % Copyright 2021-2023 Julian D. A. Wiseman of www.jdawiseman.com. % This sofware is licensed under the GNU General Public License v3.0. % Permissions of this strong copyleft license are conditioned on making available complete source code of % licensed works and modifications, which include larger works using a licensed work, under the same license. % Copyright and license notices must be preserved. Contributors provide an express grant of patent rights. % http://github.com/jdaw1/placemat/blob/main/PostScript/glyph_log.ps % http://github.com/jdaw1/placemat/blob/main/Documentation/compound_strings_characters.md#readme /Gotham-Book % Chosen font true % true => A4; false => US Letter {/PageWidth 595.27559 def /PageHeight 841.88976 def} % A4 = 210mm by 297mm {/PageWidth 612 def /PageHeight 792 def} % US Letter = 8.5" by 11" ifelse % Page size: A4 or US Letter? /FontName exch def /Margin 36 def /ColumnsNum 3 def /FontSize 12 def /TabSize FontSize 1.5 mul def /LineStep FontSize 1.5 mul def () = FontName == () = /usertimeStart usertime def /DeBugLevel 65535 def /SuppressANN % http://groups.google.com/g/comp.lang.postscript/c/8V9XFDwuLPg /currentdistillerparams where { pop currentdistillerparams /CheckCompliance 2 copy known {get //false exch {dup /PDFX1a:2001 eq exch /PDFX3:2002 eq or or} forall} {pop pop //false} ifelse currentdistillerparams /PDFX1aCheck 2 copy known {get or} {pop pop} ifelse currentdistillerparams /PDFX3Check 2 copy known {get or} {pop pop} ifelse } {false} ifelse def % /SuppressANN /pdfmark where { false % Use testing routine? In user-distributed code should be false. {pop /pdfmark {dup == pdfmark} bind def} {pop /pdfmark {dup /ANN eq //SuppressANN and {cleartomark} {pdfmark} ifelse} bind def} ifelse % Use testing routine } {/globaldict where {pop globaldict} {userdict} ifelse /pdfmark /cleartomark load put} ifelse % /pdfmark where /ShellSortGaps [ % ShellSort is very fast at short arrays, but QuickSort's segregation helps multi-CPU with long arrays. % PostScript's max array size usually 65535 (PLRM3, p739, table B.1), but an implementation could allow longer. % Included are those up to PostScript's max integer = 2^31 - 1, subsequent being commented out. % From http://en.wikipedia.org/wiki/Shellsort % > Gonnet and Baeza-Yates observed that Shellsort makes the fewest comparisons on average when the ratios of successive gaps are % > roughly equal to 2.2. This is why their sequence with ratio 2.2 and Tokuda's sequence with ratio 2.25 prove efficient. However, % > it is not known why this is so. Sedgewick recommends using gaps which have low greatest common divisors or are pairwise coprime. % Here each is closest to immediately previous * Sqrt5 that is coprime to all smaller, % so ratios tend to ~=2.236. From values of 83 the ratios >2.2358 and <2.2531. 1 3 7 16 37 83 187 419 937 2099 4693 10499 23479 52501 % Below 2^16 = 65536, so sufficient for PostScript. 117391 262495 586961 1312481 2934793 6562397 14673961 32811973 73369801 164059859 366848983 820299269 1834244921 % Below 2^31 ~= 2 billion % 4101496331 9171224603 20507481647 45856123009 102537408229 229280615033 512687041133 1146403075157 2563435205663 5732015375783 % 12817176028331 28660076878933 64085880141667 143300384394667 320429400708323 716501921973329 1602147003541613 3582509609866643 % 8010735017708063 17912548049333207 40053675088540303 89562740246666023 200268375442701509 447813701233330109 % 1001341877213507537 2239068506166650537 5006709386067537661 11195342530833252689 % Below 2^64 ~= 18 quintillion ] readonly def % /ShellSortGaps /ShellSortGapsLength1Sub ShellSortGaps length 1 sub def % Immediate dependencies: DeBugLevel; ShellSortGaps; ShellSortGapsLength1Sub. % [ thing thing ... ] {comparison code that takes two things and returns a boolean} ShellSort - % Sorts array such that for elements i and i+1 the comparison code returns true (or equal). % E.g., [1 2 3 4 5 2. 3. 4. 5. 3 4 5 4. 5. 5] dup {le} ShellSort == outputs [1 2 2.0 3 3 3.0 4 4.0 4 4.0 5 5 5.0 5.0 5] % Based on http://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm /ShellSort { //DeBugLevel 25 le {(+ShellSort) OutputToLog} if 8 dict begin /ComparisonCode exch def /Things exch def /n Things length def n 2 ge { 1 1 //ShellSortGapsLength1Sub { /gapNum exch def //ShellSortGaps gapNum get n gt {/gapNum gapNum 1 sub def exit} if } for % gapNum up gapNum -1 0 { //ShellSortGaps exch get /gap exch def gap 1 n 1 sub { /outer exch def /valueToInsert Things outer get def /inner outer def { inner gap lt {exit} if Things inner gap sub get valueToInsert ComparisonCode {exit} if Things inner Things inner gap sub get put /inner inner gap sub def } loop % inner Things inner valueToInsert put } for % outer } for % gap down } if % n 2 ge end //DeBugLevel 25 le {(-ShellSort) OutputToLog} if } bind def % /ShellSort currentdict /ShellSortGaps undef currentdict /ShellSortGapsLength1Subs undef /AlphaSortDict << ( ) 0 32 0 (0) 1 48 1 (1) 2 49 2 (2) 3 50 3 (3) 4 51 4 (4) 5 52 5 (5) 6 53 6 (6) 7 54 7 (7) 8 55 8 (8) 9 56 9 (9) 10 57 10 (a) 11 97 11 (A) 12 65 12 (b) 13 98 13 (B) 14 66 14 (c) 15 99 15 (C) 16 67 16 (d) 17 100 17 (D) 18 68 18 (e) 19 101 19 (E) 20 69 20 (f) 21 102 21 (F) 22 70 22 (g) 23 103 23 (G) 24 71 24 (h) 25 104 25 (H) 26 72 26 (i) 27 105 27 (I) 28 73 28 (j) 29 106 29 (J) 30 74 30 (k) 31 107 31 (K) 32 75 32 (l) 33 108 33 (L) 34 76 34 (m) 35 109 35 (M) 36 77 36 (n) 37 110 37 (N) 38 78 38 (o) 39 111 39 (O) 40 79 40 (p) 41 112 41 (P) 42 80 42 (q) 43 113 43 (Q) 44 81 44 (r) 45 114 45 (R) 46 82 46 (s) 47 115 47 (S) 48 83 48 (t) 49 116 49 (T) 50 84 50 (u) 51 117 51 (U) 52 85 52 (v) 53 118 53 (V) 54 86 54 (w) 55 119 55 (W) 56 87 56 (x) 57 120 57 (X) 58 88 58 (y) 59 121 59 (Y) 60 89 60 (z) 61 122 61 (Z) 62 90 62 (!) 63 33 63 (") 64 34 64 (#) 65 35 65 ($) 66 36 66 (%) 67 37 67 (&) 68 38 68 (') 69 39 69 (\() 70 40 70 (\)) 71 41 71 (*) 72 42 72 (+) 73 43 73 (,) 74 44 74 (-) 75 45 75 (.) 76 46 76 (/) 77 47 77 (:) 78 58 78 (;) 79 59 79 (<) 80 60 80 (=) 81 61 81 (>) 82 62 82 (?) 83 63 83 (@) 84 64 84 ([) 85 91 85 (\\) 86 92 86 (]) 87 93 87 (^) 88 94 88 (_) 89 95 89 (`) 90 96 90 ({) 91 123 91 (|) 92 124 92 (}) 93 125 93 (~) 94 126 94 127 95 >> readonly def % /AlphaSortDict /NamesOrdered { 4 dict begin 2 get /Name2 exch def 2 get /Name1 exch def /NoAnswerYet % Used if Name2 longer than Name1, or if identical [ //false //true ] { /CaseSensitive exch def 0 1 Name1 length 1 sub { /i exch def i Name2 length ge {pop //false exit} if % Name2 shorter, identical to here //AlphaSortDict Name1 i get CaseSensitive not {dup dup 65 ge exch 90 le and {32 add} if} if get //AlphaSortDict Name2 i get CaseSensitive not {dup dup 65 ge exch 90 le and {32 add} if} if get 2 copy eq {pop pop} {lt exch pop exit} ifelse } for % i dup type /booleantype eq {exit} if Name1 length Name2 length lt {pop //true exit} if } forall % CaseSensitive end dup type /nametype eq {pop //true} if } bind def % /NamesOrdered [ 0 0 (banana)] [0 0 (apple)] NamesOrdered = /Fonts [ FontName findfont /CharStrings get {[ 3 1 roll 1 index 256 string cvs ]} bind forall ] dup /NamesOrdered load ShellSort def % /Fonts << /PageSize [PageWidth PageHeight] >> setpagedevice /Xs [ ColumnsNum -1 1 {dup Margin mul exch ColumnsNum exch sub PageWidth Margin sub mul add ColumnsNum div} for ] def % /Xs /Yadj 0 def 0 setgray /Y PageHeight Margin sub LineStep 2 mul sub def FontName FontSize 3 mul selectfont FontName 256 string cvs dup stringwidth pop PageWidth exch sub 2 div Y moveto show FontName FontSize selectfont /Top_D gsave 0 0 moveto 1024 dup scale (D) true charpath flattenpath pathbbox 4 1 roll pop pop pop grestore def /Y Y LineStep sub def [ Fonts length 10 string cvs ( characters, shown at ) FontSize 10 string cvs (pt, grey from baseline to top of D) ] 0 1 index {stringwidth pop add} forall PageWidth exch sub 2 div dup Margin lt {pop Margin} if Y moveto {show} forall [ (THE FIVE BOXING WIZARDS JUMP QUICKLY !"#$%&'\(\)*+,-./:;<=>?@[\\]^_`{|}~) % all ASCII characters (the quick brown fox jumps over a lazy dog 0123456789) (S97 K47 D78 Mz96 Ck12 Ni27 Cr45 TSQ47 W55 SW63 G66 D70 F85 T92 RP97 N00 V03 Qv11) (http://github.com/jdaw1/placemat/blob/main/PostScript/glyph_log.ps) (http://github.com/jdaw1/placemat/blob/main/Documentation/compound_strings_characters.md#readme) ]{ /Y Y LineStep sub def dup 0 4 getinterval (http) eq { FontName FontSize 2 div selectfont Xs 0 get Xs 1 get add 2 div Y Yadj add moveto /Yadj Yadj FontSize 0.7 mul add def }{ 0.9 setgray //Margin Y PageWidth Margin 2 mul sub Top_D rectfill 0 setgray % Grey box goes from baseline to top of capital D FontName FontSize selectfont Xs 0 get Y moveto } ifelse % http show } bind forall FontName FontSize selectfont /Y Y LineStep 1.25 mul sub def /Ystart Y def /Any false def /PageDested false def /iX 0 def Fonts { aload pop /GlyphNameString exch def /GlyphNum exch def /GlyphName exch def 256 string 0 1 9 {1 index exch 32 put} for % Spaces dup 10 47 put % "/" GlyphNum 1 index cvs pop % Number GlyphNameString 1 index 11 245 getinterval copy length 11 add 0 exch getinterval = Xs iX get Y moveto GlyphName glyphshow Xs iX get //TabSize add Y moveto GlyphNameString show /Any //true def /Y Y LineStep sub def PageDested not { GlyphNameString 0 get dup dup dup 65 ge exch 90 le and 3 1 roll 97 ge exch 122 le and or { mark /Dest GlyphName /DEST pdfmark mark /Action /GoTo /Dest GlyphName /Title GlyphNameString /OUT pdfmark /PageDested true def } if % A...Z or a...z } if % first on page Y //Margin le { /iX iX 1 add ColumnsNum mod def iX 0 eq {showpage /Any //false def /PageDested false def /Ystart //PageHeight //Margin sub //LineStep sub def} if /Y Ystart def } if % Y //Margin le } bind forall % Fonts Any {showpage} if mark /Color [0.6 0.6 0.6] /F 2 /Title (\273 PostScript original) /Action << /Subtype /URI /URI (http://github.com/jdaw1/placemat/blob/main/PostScript/glyph_log.ps) >> /OUT pdfmark mark /Color [0.6 0.6 0.6] /F 2 /Title (\273 Non-ASCII chars in placemat software) /Action << /Subtype /URI /URI (http://github.com/jdaw1/placemat/blob/main/Documentation/compound_strings_characters.md#readme) >> /OUT pdfmark mark /Color [0.6 0.6 0.6] /F 2 /Title (\273 Author=J.D.A.Wiseman) /Action << /Subtype /URI /URI (http://www.jdawiseman.com/author.html) >> /OUT pdfmark (\n\n\nExecution time ~= ) dup dup 21 10 getinterval usertime usertimeStart sub 1000 div exch cvs length 21 add (s) 0 get put = % Bug check count dup 0 gt { (Problem!) = (count = ) exch 1 index 8 10 getinterval cvs pop = () = (+pstack) = pstack (-pstack) = } {pop (Stack correctly empty.) =} ifelse