Commit | Line | Data |
---|---|---|
abc63828 WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zvmem.c */ | |
21 | /* "Virtual memory" operators for Ghostscript */ | |
22 | #include "ghost.h" | |
23 | #include "errors.h" | |
24 | #include "oper.h" | |
25 | #include "alloc.h" | |
26 | #include "estack.h" /* for checking in restore */ | |
27 | #include "dict.h" /* ditto */ | |
28 | #include "dstack.h" | |
29 | #include "save.h" | |
30 | #include "state.h" | |
31 | #include "store.h" | |
32 | #include "gsmatrix.h" /* for gsstate.h */ | |
33 | #include "gsstate.h" | |
34 | ||
35 | /* Imported operators */ | |
36 | extern int zgsave(P1(os_ptr)); | |
37 | extern int zgrestore(P1(os_ptr)); | |
38 | ||
39 | /* Import the routine for setting the attributes of the identity matrix. */ | |
40 | extern void init_identity_matrix(P0()); | |
41 | ||
42 | /* 'Save' structure */ | |
43 | typedef struct vm_save_s vm_save; | |
44 | struct vm_save_s { | |
45 | alloc_save *asave; /* allocator save */ | |
46 | int_gstate isave; /* old interpreter state */ | |
47 | gs_state *gsave; /* old graphics state */ | |
48 | }; | |
49 | ||
50 | /* save */ | |
51 | int | |
52 | zsave(register os_ptr op) | |
53 | { vm_save *vmsave = (vm_save *)alloc(1, sizeof(vm_save), "zsave"); | |
54 | alloc_save *asave; | |
55 | int code; | |
56 | gs_state *prev, *prev2; | |
57 | if ( vmsave == 0 ) return_error(e_VMerror); | |
58 | asave = alloc_save_state(); | |
59 | if ( asave == 0 ) | |
60 | { alloc_free((char *)vmsave, 1, sizeof(vm_save), "zsave"); | |
61 | return_error(e_VMerror); | |
62 | } | |
63 | vmsave->asave = asave; | |
64 | /* Save the old interpreter state, */ | |
65 | /* and cut the chains so we can't grestore past here. */ | |
66 | vmsave->isave = istate; | |
67 | code = zgsave(op); | |
68 | if ( code < 0 ) return code; | |
69 | /* Swap the contents of the old and new states, */ | |
70 | /* so the new state points to the newly allocated components. */ | |
71 | prev = gs_state_swap_saved(igs, (gs_state *)0); | |
72 | prev2 = gs_state_swap_saved(prev, (gs_state *)0); | |
73 | gs_state_swap_saved(igs, prev2); | |
74 | gs_state_swap(igs, prev); | |
75 | vmsave->gsave = igs; | |
76 | igs = prev; | |
77 | istate.saved = 0; | |
78 | push(1); | |
79 | make_tv(op, t_save, psave, vmsave); | |
80 | init_identity_matrix(); /* update l_new attribute */ | |
81 | return zgsave(op); | |
82 | } | |
83 | ||
84 | /* restore */ | |
85 | private int restore_check_stack(P3(ref *, ref *, alloc_save *)); | |
86 | private void restore_fix_stack(P3(ref *, ref *, alloc_save *)); | |
87 | int | |
88 | zrestore(register os_ptr op) | |
89 | { vm_save *vmsave; | |
90 | alloc_save *asave; | |
91 | check_type(*op, t_save); | |
92 | vmsave = op->value.psave; | |
93 | if ( vmsave == 0 ) /* invalidated save */ | |
94 | return_error(e_invalidrestore); | |
95 | asave = vmsave->asave; | |
96 | /* Check the contents of the stacks. */ | |
97 | { int code; | |
98 | if ( (code = restore_check_stack(osbot, op, asave)) < 0 || | |
99 | (code = restore_check_stack(esbot, esp + 1, asave)) < 0 || | |
100 | (code = restore_check_stack(dstack, dsp + 1, asave)) < 0 | |
101 | ) | |
102 | return code; | |
103 | } | |
104 | if ( alloc_restore_state_check(asave) < 0 ) | |
105 | return_error(e_invalidrestore); | |
106 | /* Invalidate any other copies of this save object on the stacks, */ | |
107 | /* and reset l_new in all stack entries if the new restore level */ | |
108 | /* is zero. */ | |
109 | restore_fix_stack(osbot, op, asave); | |
110 | restore_fix_stack(esbot, esp + 1, asave); | |
111 | restore_fix_stack(dstack, dsp + 1, asave); | |
112 | /* Now it's safe to restore the state of memory. */ | |
113 | alloc_restore_state(asave); | |
114 | /* Restore the interpreter and graphics state. */ | |
115 | istate = vmsave->isave; | |
116 | igs = vmsave->gsave; | |
117 | alloc_free((char *)vmsave, 1, sizeof(vm_save), "zrestore"); | |
118 | pop(1); | |
119 | init_identity_matrix(); /* update l_new attribute */ | |
120 | return 0; | |
121 | } | |
122 | /* Check a stack to make sure all its elements are older than a save. */ | |
123 | private int | |
124 | restore_check_stack(ref *bot, ref *top, alloc_save *asave) | |
125 | { ref *stkp; | |
126 | for ( stkp = bot; stkp < top; stkp++ ) | |
127 | { char *ptr; | |
128 | switch ( r_type(stkp) ) | |
129 | { | |
130 | case t_array: ptr = (char *)stkp->value.refs; break; | |
131 | case t_condition: ptr = (char *)stkp->value.pcond; break; | |
132 | case t_dictionary: ptr = (char *)stkp->value.pdict; break; | |
133 | case t_fontID: ptr = (char *)stkp->value.pfont; break; | |
134 | case t_gstate: ptr = (char *)stkp->value.pgstate; break; | |
135 | /* case t_file: ****** WHAT? ****** */ | |
136 | case t_lock: ptr = (char *)stkp->value.plock; break; | |
137 | case t_name: | |
138 | /* Names are special because of how they are allocated. */ | |
139 | if ( alloc_name_is_since_save(stkp, asave) ) | |
140 | return_error(e_invalidrestore); | |
141 | continue; | |
142 | case t_save: ptr = (char *)stkp->value.psave; break; | |
143 | case t_string: ptr = (char *)stkp->value.bytes; break; | |
144 | case t_mixedarray: case t_shortarray: | |
145 | ptr = (char *)stkp->value.packed; break; | |
146 | case t_color: ptr = (char *)stkp->value.pcolor; break; | |
147 | case t_device: ptr = (char *)stkp->value.pdevice; break; | |
148 | default: continue; | |
149 | } | |
150 | if ( alloc_is_since_save(ptr, asave) ) | |
151 | return_error(e_invalidrestore); | |
152 | } | |
153 | ||
154 | return 0; /* OK */ | |
155 | } | |
156 | /* Fix up the contents of a stack by invalidating */ | |
157 | /* any save objects newer than the save being restored, */ | |
158 | /* and, if the new save level is zero, clearing the l_new */ | |
159 | /* bit in all the entries (since we can't tolerate values with */ | |
160 | /* l_new set if the save level is zero). */ | |
161 | private void | |
162 | restore_fix_stack(ref *bot, ref *top, alloc_save *asave) | |
163 | { ref *stkp; | |
164 | for ( stkp = bot; stkp < top; stkp++ ) | |
165 | { if ( r_type(stkp) == t_save && | |
166 | stkp->value.psave != 0 && | |
167 | (stkp->value.psave->asave == asave || | |
168 | alloc_is_since_save((char *)stkp->value.psave, asave)) | |
169 | ) | |
170 | stkp->value.psave = 0; | |
171 | r_clear_attrs(stkp, l_new); /* always do it, no harm */ | |
172 | } | |
173 | } | |
174 | ||
175 | /* vmstatus */ | |
176 | int | |
177 | zvmstatus(register os_ptr op) | |
178 | { long used, total; | |
179 | alloc_status(&used, &total); | |
180 | push(3); | |
181 | make_int(op - 2, alloc_save_level()); | |
182 | make_int(op - 1, used); | |
183 | make_int(op, total); | |
184 | return 0; | |
185 | } | |
186 | ||
187 | /* ------ Initialization procedure ------ */ | |
188 | ||
189 | op_def zvmem_op_defs[] = { | |
190 | {"1restore", zrestore}, | |
191 | {"0save", zsave}, | |
192 | {"0vmstatus", zvmstatus}, | |
193 | op_def_end(0) | |
194 | }; |