]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/gs_resmp.ps
etherbcm: handle 64-bit host addresses, use PCIWADDR() instead of PADDR()
[plan9front.git] / sys / lib / ghostscript / gs_resmp.ps
1 %    Copyright (C) 2000 artofcode LLC.  All rights reserved.
2
3 % This software is provided AS-IS with no warranty, either express or
4 % implied.
5
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
9
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
16 % $Id: gs_resmp.ps,v 1.11 2004/10/25 15:11:37 igor Exp $
17 % A procset to redefine a resource category with a resource map.
18
19 % Public entries :
20  
21 % Redefine - a procedure for redefining a resource category with a map.
22 %    Methods for interpreting the resource map to be provided by client 
23 %    in the argument dictionary.
24 %
25 %    Note that the procedure Redefine is idempotential :
26 %    consequtive calls to it will not replace the category methods,
27 %    but will merge resource maps. If an interleaving redefinition
28 %    needs to cancel the idempotentity, it must remove the entry
29 %    /.IsRedefinedWithMap from the category dictionary.
30
31 % MakeResourceEnumerator - this procedure is useful for
32 %    redefining any category. It provides a proper order of instances
33 %    and proper stacks during resourceforall.
34
35 % BindWithCurrentdict - a procedure for generating temporary procedures 
36 %    from templates, binding them with a local dictionary.
37
38 % execstack_lookup - a procedure for communicating through the execution stack.
39 %    It allows for a callee to get an information from an indirect caller.
40
41 % The procedures are designed for exeution witout putting
42 % the procset instance onto the dictionary stack.
43
44 languagelevel 2 .setlanguagelevel
45 currentglobal true setglobal
46
47 /MappedCategoryRedefiner 10 dict begin % The procset.
48
49 currentpacking false setpacking
50
51 /InstanceEnumeratorPattern   %  - InstanceEnumeratorPattern ...
52 {  
53   % This is a pattern for enumeration procedure to be built dynamically,
54   % applying BindWithCurrentdict with a temporary dictionary.
55   % The following names will be replaced with specific objects
56   % during BindWithCurrentdict :
57   % en_local_dict - a dictionary for storing the local integer variable 'status'.
58   % scr - the scratch string argument of resourceforall;
59   % proc - the procedure argument of resourceforall;
60   % InstancesStatus - a dictionary that maps resource instance names to their status value;
61   % Category - the category to be enumerated.
62
63   % When this procedure is called from ResourceForAll, the category is the current dictionary.
64   % We remove it from the dictionary stack before performing the enumeration
65   % to provide the <proc> to write to the underlying dictionary,
66   % and put it back after the enumeration is completed.
67   end
68   { 
69     0 1 2 {
70       en_local_dict exch /status exch put
71       InstancesStatus {                                            
72         en_local_dict /status get eq {
73           scr cvs                           % ... (Font)
74           proc exec                         %
75         } {
76           pop
77         } ifelse                            % ...
78       } forall
79     } for                                   % ...
80   } stopped
81   Category begin
82   { stop } if
83 } bind def
84
85 % An auxiliary proc for BindWithCurrentdict :
86 /.BindAux    % <proc> BindAux <proc>
87 { 0 exec
88 } bind def
89
90 setpacking
91
92 /BindWithCurrentdict     % <proc> BindWithCurrentdict <proc>
93 {  
94   % Make a copy of the given procedure, binding in the values of all names
95   % defined in currentdict.
96   % Caution1 : this code cannot handle procedures that were already
97   %            bound recursively.
98   % Caution2 : this code don't bind packedarrays. This was done
99   %            intentionally for a termination of the procedure tree.
100
101   dup length array copy
102   dup length 1 sub -1 0 {                      
103     2 copy get                            % {precopy} i {elem}
104     dup dup type /arraytype eq exch xcheck and {
105                                           % {precopy} i {elem}
106       //.BindAux exec                     % {precopy} i {elem_copy}
107       2 index 3 1 roll put                % {precopy}
108     } {
109       dup dup type /nametype eq exch xcheck and {
110                                           % {precopy} i {elem}
111         currentdict exch .knownget {            
112           2 index 3 1 roll put            % {precopy}
113         } {                                            
114           pop
115         } ifelse
116       } {
117         pop pop
118       } ifelse
119     } ifelse                              % {precopy}
120   } for                                   % {copy}
121   cvx
122 } bind def
123
124 //.BindAux 0 //BindWithCurrentdict put   % bind the recursive call in 'Bind'.
125
126 /MakeResourceEnumerator   % <proc> <scr> <InstancesStatus> MakeResourceEnumerator <Enumerator>
127 {
128   % Build the enumeration procedure :
129
130   % Since the resourceforall procedure may leave values on the operand stack,
131   % we cannot simply store the enumerator's local data on the stack.
132   % We also cannot use a static dictionary to store local variables,
133   % because of possible recursion in the resourceforall procedure.
134   % To work around this, we create a copy of the enumeration procedure and
135   % bind it dynamically with a temporary dictionary, which contains
136   % local variables for the currently executing instance of resourceforall.
137
138   currentdict                    % Category
139   6 dict begin % the temporary dictionary
140     /Category exch def           %
141     /InstancesStatus exch def
142     /scr exch def
143     /proc exch def
144     /en_local_dict currentdict def
145     //InstanceEnumeratorPattern //BindWithCurrentdict exec     % Enumerator
146     /status 0 def % variable for the current status to enumerate - do not bind with it !
147   end
148
149 } bind def
150
151 /execstack_lookup     % <object> execstack_lookup <object1>
152                       % <object> execstack_lookup null
153 { % Checks whether execution stack contains a procedure starting with <object>,
154   % and retrives the 2nd element of the procedure,
155   % or null if the procedure was not found.
156   %
157   % Since 'execstack' actually renders subarrays of procedures,
158   % the pattern for recognition must be like this :
159   %
160   %   { <object> <object1>
161   %     CallSomething
162   %   } loop
163   %
164   % The solution with 'loop' depends on how GS implements cycles,
165   % so it must not appear in documents, which are required to be interpreter independent.
166   % Any other type of cycles are also acceptable.
167   % If no repitition is really needed, just insert 'exit' into its body.
168   % If <object> <object1> are not needed for the caller, insert "pop pop" after them.
169   % If <object1> is really unuseful, the pattern may be simplified :
170   %
171   %   { <object> pop
172   %     CallSomething
173   %     exit
174   %   } loop
175   %
176   % It will retrieve 'pop' or 'null'.
177   %
178   % Note that 2 topmost execstack elements are the execstack_lookup procedure and its caller.
179   % We don't check them.
180
181   currentglobal false setglobal                    % <object> bGlobal
182   countexecstack array execstack                   % <object> bGlobal [execstack]
183   dup null exch                                    % <object> bGlobal [execstack] null [execstack]
184   length 3 sub -1 0 {                              % <object> bGlobal [execstack] null i
185     2 index exch get                               % <object> bGlobal [execstack] null proc
186     dup type dup /packedarraytype eq exch /arraytype eq or {
187       dup length 1 gt {                            % <object> bGlobal [execstack] null proc
188         dup 0 get                                  % <object> bGlobal [execstack] null proc elem0
189         5 index eq {                               % <object> bGlobal [execstack] null proc
190           1 get                                    % <object> bGlobal [execstack] null object1
191           exch pop exit                            % <object> bGlobal [execstack] object1
192         } {
193           pop
194         } ifelse
195       } {
196         pop                                        % <object> bGlobal [execstack] false
197       } ifelse
198     } {
199       pop                                          % <object> bGlobal [execstack] false
200     } ifelse
201   } for                                            % <object> bGlobal [execstack] bResult
202   exch pop exch setglobal exch pop                 % bResult
203 } bind def
204
205 currentpacking false setpacking
206 /MethodsToRedefine 5 dict begin
207
208     % Procedures in this dictionary really are patterns for new category methods.
209     % The following names will be replaced with specific objects during BindWithCurrentdict :
210     %   .map - the map dictionary;
211     %   DefineResource, ResourceStatus, ResourceFileName, FindResource, ResourceForAll 
212     %        - procedures from the original resource category.
213
214     /FindResource  % <Name> FindResource <dict>
215     { RESMPDEBUG { (resmp FindResource beg ) print dup = } if
216       dup ResourceStatus exec {
217         pop 2 lt
218       } {
219         false
220       } ifelse                             % bInVirtualMemory
221       { FindResource exec
222       } {
223         dup dup .map exch .knownget {      % /Name /Name <<record>>
224           dup dup /RecordVirtualMethods get /IsActive get exec {
225             1 index .getvminstance {       % /Name /Name <<record>> holder
226               1 get 1 eq
227             } {
228               true
229             } ifelse                       % /Name /Name <<record>> bStatusIs1
230             4 1 roll                       % bStatusIs1 /Name /Name <<record>>
231             dup /RecordVirtualMethods get /MakeInstance get exec
232                                            % bStatusIs1 /Name /Name Instance size
233             5 1 roll                       % size bStatusIs1 /Name /Name Instance
234             DefineResource exec            % size bStatusIs1 /Name Instance
235             % Make ResourceStatus to return correct values for this instance :
236             % Hack: we replace status values in the instance holder :
237             exch .getvminstance pop        % size bStatusIs1 Instance holder
238             dup 5 -1 roll 2 exch put       % bStatusIs1 Instance holder
239             3 2 roll {                     % Instance holder
240               1 1 put                      % Instance
241             } {
242               pop
243             } ifelse                       % Instance
244           } {                              % /Name /Name <<record>>
245             pop pop FindResource exec            
246           } ifelse
247         } {                                % /Name /Name
248           pop FindResource exec            
249         } ifelse
250       } ifelse
251       RESMPDEBUG { (resmp FindResource end) = } if
252     } bind def
253
254     /ResourceStatus   % <Name> ResourceStatus <status> <size> true
255                       % <Name> ResourceStatus false
256     { RESMPDEBUG { (resmp ResourceStatus beg ) print dup == } if
257       dup ResourceStatus exec {            % /Name status size
258         1 index 2 lt {
259           % In VM - return with it.
260           3 2 roll pop true
261         } {
262           % Not in VM.
263           exch pop exch                    % size /Name
264           dup .map exch .knownget {        % size /Name <<record>>
265             dup dup /RecordVirtualMethods get /IsActive get exec {
266               3 2 roll pop                 % /Name <<record>>
267               dup /RecordVirtualMethods get /GetSize get exec 2 exch true
268             } {                            % size /Name <<record>>
269               pop pop 2 exch true
270             } ifelse
271           } {                              % size /Name
272             pop 2 exch true
273           } ifelse
274         } ifelse
275       } {                                  % /Name
276         dup .map exch .knownget {          % /Name <<record>>
277           dup dup /RecordVirtualMethods get /IsActive get exec {
278             dup /RecordVirtualMethods get /GetSize get exec 2 exch true
279           } {                              % /Name <<record>>
280             pop pop false
281           } ifelse
282         } {                                % /Name
283           pop false
284         } ifelse
285       } ifelse
286       RESMPDEBUG { (resmp ResourceStatus end) = } if
287     } bind def
288
289     /ResourceFileName  % <Name> <scratch> ResourceFileName <string>
290     { RESMPDEBUG { (resmp ResourceFileName beg ) print 1 index = } if
291       exch                                                    % (scratch) /Name
292       .map 1 index .knownget {                                % (scratch) /Name <<record>>
293         RESMPDEBUG { (resmp ResourceFileName : have a map record.) = } if
294         dup dup /RecordVirtualMethods get /IsActive get exec {
295           RESMPDEBUG { (resmp ResourceFileName : record is active.) = } if
296           dup /RecordVirtualMethods get /GetFilePath get exec % (string)
297           RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
298         } {                                                   % (scratch) /Name <<record>>
299           RESMPDEBUG { (resmp ResourceFileName : record is NOT active.) = } if
300           pop exch ResourceFileName exec
301           RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
302         } ifelse
303       } { 
304         RESMPDEBUG { (resmp ResourceFileName : have NO map record.) = } if
305         exch ResourceFileName exec
306         RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
307       } ifelse
308       RESMPDEBUG { (resmp ResourceFileName end) = } if
309     } bind def
310
311     /ResourceForAll  % <template> <proc> <scratch> ResourceForAll -
312     { RESMPDEBUG { (resmp ResourceForAll beg ) print 2 index = } if
313       % Create InstancesStatus dictionary :
314       20 dict % IS - Instances Status
315       4 1 roll                            % <<IS>> (templ) {proc} (sctarch)
316                                           % <<IS>> bOrder (templ) {proc} (sctarch)
317       % Check if we are under another ResourceForAll :
318       /.DisableResourceOrdering //execstack_lookup exec null eq 4 1 roll
319
320       % Put underlying resources to the InstancesStatus dictionary :
321       currentdict % the category
322       begin % ResourceForAll removes it locally.
323       2 index
324       { cvn                               % <<IS>> bOrder (templ) {proc} (sctarch) /Name
325         4 index {
326           dup ResourceStatus exec {pop 6 index 3 1 roll put} {pop} ifelse
327         } {
328           5 index exch 2 put % Don't need the ordering, put '2' as a scratch.
329         } ifelse
330       }
331       2 index ResourceForAll exec         % <<IS>> bOrder (templ) {proc} (sctarch)
332       4 3 roll pop                        % <<IS>> (templ) {proc} (sctarch)
333       end
334
335       % Put .map entries to the InstancesStatus dictionary :
336       4 -1 roll begin                     % (templ) {proc} (sctarch)
337       .map {                              % (templ) {proc} (sctarch) /Name record
338          dup dup /RecordVirtualMethods get /IsActive get exec {
339            pop                            % (templ) {proc} (sctarch) /Name
340            dup currentdict exch known {
341              pop
342            } {
343              dup 2 index cvs              % (templ) {proc} (sctarch) /Name (Name)
344              4 index .stringmatch {       % (templ) {proc} (sctarch) /Name
345                2 def % It is not in VM.
346              } {
347                pop
348              } ifelse
349            } ifelse
350         } {                               % (templ) {proc} (sctarch) /Name record
351           pop pop
352         } ifelse
353       } forall                            % (templ) {proc} (sctarch)
354
355       % prepare stacks for the enumeration :
356       3 2 roll pop                        % {proc} (sctarch)
357       currentdict end                     % {proc} (scratch) <<IS>>
358
359       % Make the enumerator and apply it :
360       //MakeResourceEnumerator exec exec
361       RESMPDEBUG { (resmp ResourceForAll end)= } if
362     } bind def
363
364     /GetCIDSystemInfoFromMap   % <Name> GetCIDSystemInfoFromMap <Name>
365                                % <Name> GetCIDSystemInfoFromMap <dict>
366     { RESMPDEBUG { (resmp GetCIDSystemInfoFromMap beg ) print dup = } if
367       % This is a special function for communicating with GetCIDSystemInfo in gs_cidcm.ps .
368       dup .map exch .knownget {
369         RESMPDEBUG { (resmp GetCIDSystemInfoFromMap : have a map record.) = } if
370         dup /RecordVirtualMethods get /GetCSI get exec
371         dup null ne {
372           RESMPDEBUG { (resmp GetCIDSystemInfoFromMap : retrieving a dict.) = } if
373           exch
374         } if
375         pop
376       } if
377       RESMPDEBUG { (resmp GetCIDSystemInfoFromMap end) = } if
378     } bind def
379
380 currentdict end def
381 setpacking
382
383 /Redefine     % <OptionsDict> Redefine -
384 { % Before calling this proc, the OptionsDict must specify options for
385   % the catregory to be redefined :
386   % CategoryName - a name of category to redefine;
387   % MapFileName - a string for the resource map file name;
388   % VerifyMap - a procedure :
389   %   <raw_map> VerifyMap -
390   %   - checks the map for consistency
391   % PreprocessRecord  - a procedure :
392   %   <map> <Name> <raw_record> PreprocessRecord <map> <Name> <record> true
393   %   <map> <Name> <raw_record> PreprocessRecord <map> <Name> <raw_record> false
394   %   - converts a map record into a dictionary;
395   %   It must add RecordVirtualMethods dictionary to the record :
396   %     MakeInstance - a procedure :
397   %         <Name> <record> MakeInstance <Name> <Instance> <size>
398   %         - converts the record to resource instance;
399   %     GetFilePath - a procedure for ResourceFileName :
400   %         <scratch> <Name> <record> GetFilePath <filepath>
401   %     GetSize - a procedure for ResourceStatus :
402   %         <Name> <record> GetSize <size>
403   %     GetCSI - a procedure for obtaining CIDSystemInfo dictionary from the record :
404   %         <record> GetCSI <CSI>
405   %         <record> GetCSI null
406   %     IsActive - a procedure for skipping records depending on the current device :
407   %         <record> IsActive <bool>
408   %     Also it is allowed to contain additional entries for client's needs.
409   % The OptionsDict is also used for storing some local variables.
410
411   % If a category is being redefined several times with this function,
412   % each redefinition must either use an unique map file,
413   % or the map file should be scanned by the last redefinition
414   % (and must be defined in the last one with /MapFileName).
415   % This happens so because we must accumulate all variants of
416   % methods before scanning the map. We would like to delay
417   % the scanning until all redefinitions are done, but it requires
418   % to implement a queue of "refinish" methods and execute it
419   % at very end of the prelude.
420
421   begin % OptionsDict
422   CategoryName /Category findresource /OldCategory exch def
423   OldCategory /.IsRedefinedWithMap known {
424     % Already redefined with map - don't redefine, but enhance the map.
425     OldCategory /NewCategory exch def
426   } {
427     % Redefine with a new category instance.
428     OldCategory dup length dict 
429     dup /.PreprocessRecord 4 dict put
430     copy /NewCategory exch def
431   } ifelse
432
433   % Provide the 'or' logic for PreprocessRecord,
434   % to allow different record types to be mixed in a single map file.
435   % We do this with building a dictionary of PreprocessRecord procedures,
436   % which come from different calls to Redefine :
437   NewCategory /.PreprocessRecord get dup length % <<pr>> l  
438   currentdict /PreprocessRecord get .growput
439
440   currentdict /MapFileName known {
441     MapFileName .libfile {
442       1 dict begin
443       /; {} def
444       mark exch cvx exec .dicttomark           % <<map>>
445       end
446       dup VerifyMap                            % <<map>>
447     } {
448       QUIET not {
449         currentdict /IsMapFileOptional .knownget not { false } if not {
450           (Warning: the map file ) print dup =string cvs print ( was not found.) =
451         } if
452       } if
453       pop 0 dict                               % <<map>>
454     } ifelse
455   } {
456     currentdict /.map .knownget not { 
457       0 dict                                   % <<map>>
458     } if
459   } ifelse
460
461   % Preprocess entries :
462   dup NewCategory /.PreprocessRecord get       % <<map>> <<map>> <<pr>>
463   3 1 roll {                                   % <<pr>> <<map>> /Name raw_record
464     false 3 1 roll                             % <<pr>> <<map>> false /Name raw_record 
465     4 index {                                  % <<pr>> <<map>> false /Name raw_record i {pr}
466       exch pop                                 % <<pr>> <<map>> false /Name raw_record {pr}
467       exec {                                   % <<pr>> <<map>> false /Name record
468         3 -1 roll pop true 3 1 roll            % <<pr>> <<map>> true /Name record
469         exit
470       } if                                     % <<pr>> <<map>> false /Name raw_record
471     } forall
472     3 2 roll {                                 % <<pr>> <<map>> /Name record
473       2 index 3 1 roll put                     % <<pr>> <<map>>
474     } {
475       exch                                     % <<pr>> <<map>> raw_record /Name
476       (Incorrect record ) print =string cvs print ( of the map file ) print MapFileName =string cvs print (.) =
477       end % Pops OptionsDict from dstack.
478       pop pop pop                              %
479       /Redefine cvx /undefinedresource signalerror
480     } ifelse
481   } forall                                     % <<pr>> <<map>>
482   exch pop                                     % <<map>>
483
484
485   % Add the map :
486   OldCategory /.IsRedefinedWithMap known {     % <<map>>
487     % Just add to the old map :
488     OldCategory /.map get copy pop             %
489   } {                                          % <<map>>
490     % Store the map to both the category and OptionsDict :
491     dup NewCategory exch /.map exch put
492     /.map exch def                             %
493   } ifelse
494   OldCategory /.IsRedefinedWithMap known not {
495     % Copy old methods to OptionsDict :
496     [ /DefineResource /ResourceStatus /ResourceFileName 
497       /FindResource /ResourceForAll
498     ] {
499       dup OldCategory exch get def
500     } forall
501     
502     % Build new methods :
503     //MethodsToRedefine {
504       //BindWithCurrentdict exec NewCategory 3 1 roll put  
505     } forall
506     CategoryName /CIDFont ne {
507       NewCategory /GetCIDSystemInfoFromMap undef
508       % This is some ugly, sorry.
509     } if
510     % Redefine the category :
511     NewCategory /.IsRedefinedWithMap true put
512     CategoryName NewCategory /Category defineresource pop
513   } if
514   end % OptionsDict
515 } bind executeonly def
516
517 currentdict /PutPreprocessRecord .undef
518
519 currentdict end
520 /ProcSet defineresource pop
521
522 setglobal .setlanguagelevel