Commit | Line | Data |
---|---|---|
354162ef 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 | /* zgeneric.c */ | |
21 | /* Array/string/dictionary generic operators for PostScript */ | |
22 | #include "memory_.h" | |
23 | #include "ghost.h" | |
24 | #include "errors.h" | |
25 | #include "oper.h" | |
26 | #include "dict.h" | |
27 | #include "estack.h" /* for forall */ | |
28 | #include "name.h" | |
29 | #include "packed.h" | |
30 | #include "store.h" | |
31 | ||
32 | /* This file implements copy, get, put, getinterval, putinterval, */ | |
33 | /* length, and forall, which apply generically to */ | |
34 | /* arrays, strings, and dictionaries. (Copy also has a special */ | |
35 | /* meaning for copying the top N elements of the stack.) */ | |
36 | ||
37 | /* Imported operators */ | |
38 | extern int zcopy_device(P1(os_ptr)); | |
39 | extern int zcopy_dict(P1(os_ptr)); | |
40 | ||
41 | /* Forward references */ | |
42 | int array_get(P3(ref *, long, ref *)); | |
43 | private int copy_interval(P4(os_ptr, uint, os_ptr, const char *)); | |
44 | ||
45 | /* copy */ | |
46 | /* Note that this implements copy for arrays and strings, */ | |
47 | /* but not for dictionaries (see zcopy_dict in zdict.c) */ | |
48 | /* or devices (see zcopy_device in zdevice.c). */ | |
49 | int | |
50 | zcopy(register os_ptr op) | |
51 | { os_ptr op1 = op - 1; | |
52 | int code; | |
53 | switch ( r_type(op) ) | |
54 | { | |
55 | case t_integer: | |
56 | { int count; | |
57 | if ( (ulong)op->value.intval > op - osbot ) | |
58 | return e_rangecheck; | |
59 | count = op->value.intval; | |
60 | if ( op1 + count > ostop ) | |
61 | return e_stackoverflow; | |
62 | memcpy((char *)op, (char *)(op - count), count * sizeof(ref)); | |
63 | push(count - 1); | |
64 | return 0; | |
65 | } | |
66 | case t_array: | |
67 | case t_string: | |
68 | code = copy_interval(op, 0, op1, "copy"); | |
69 | break; | |
70 | case t_device: | |
71 | return zcopy_device(op); | |
72 | case t_dictionary: | |
73 | return zcopy_dict(op); | |
74 | default: | |
75 | return e_typecheck; | |
76 | } | |
77 | if ( code ) return code; /* error */ | |
78 | r_set_size(op, r_size(op1)); | |
79 | *op1 = *op; | |
80 | pop(1); | |
81 | return 0; | |
82 | } | |
83 | ||
84 | /* length */ | |
85 | int | |
86 | zlength(register os_ptr op) | |
87 | { switch ( r_type(op) ) | |
88 | { | |
89 | case t_array: | |
90 | case t_string: | |
91 | case t_mixedarray: | |
92 | case t_shortarray: | |
93 | check_read(*op); | |
94 | make_int(op, r_size(op)); | |
95 | return 0; | |
96 | case t_dictionary: | |
97 | check_dict_read(*op); | |
98 | make_int(op, dict_length(op)); | |
99 | return 0; | |
100 | case t_name: | |
101 | { ref str; | |
102 | name_string_ref(op, &str); | |
103 | make_int(op, r_size(&str)); | |
104 | } | |
105 | return 0; | |
106 | default: | |
107 | return e_typecheck; | |
108 | } | |
109 | } | |
110 | ||
111 | /* get */ | |
112 | int | |
113 | zget(register os_ptr op) | |
114 | { os_ptr op1 = op - 1; | |
115 | ref *pvalue; | |
116 | switch ( r_type(op1) ) | |
117 | { | |
118 | case t_dictionary: | |
119 | check_dict_read(*op1); | |
120 | if ( dict_find(op1, op, &pvalue) <= 0 ) return e_undefined; | |
121 | op[-1] = *pvalue; | |
122 | break; | |
123 | case t_string: | |
124 | check_type(*op, t_integer); | |
125 | check_read(*op1); | |
126 | if ( (ulong)(op->value.intval) >= r_size(op1) ) { | |
127 | printf("Zget t_string %u >= %u\n", (ulong)(op->value.intval), r_size(op1) ); | |
128 | return e_rangecheck; | |
129 | } | |
130 | { int element = op1->value.bytes[(uint)op->value.intval]; | |
131 | make_int(op1, element); | |
132 | } | |
133 | pop(1); | |
134 | return 0; | |
135 | default: | |
136 | { int code; | |
137 | check_type(*op, t_integer); | |
138 | check_read(*op1); | |
139 | code = array_get(op1, op->value.intval, op1); | |
140 | if ( code < 0 ) return code; | |
141 | } | |
142 | } | |
143 | pop(1); | |
144 | return 0; | |
145 | } | |
146 | ||
147 | /* put */ | |
148 | int | |
149 | zput(register os_ptr op) | |
150 | { os_ptr op1 = op - 1; | |
151 | os_ptr op2 = op1 - 1; | |
152 | switch ( r_type(op2) ) | |
153 | { | |
154 | case t_dictionary: | |
155 | check_dict_write(*op2); | |
156 | { int code = dict_put(op2, op1, op); | |
157 | if ( code ) return code; /* error */ | |
158 | } | |
159 | break; | |
160 | case t_array: | |
161 | check_type(*op1, t_integer); | |
162 | check_write(*op2); | |
163 | if ( (ulong)(op1->value.intval) >= r_size(op2) ) | |
164 | return e_rangecheck; | |
165 | ref_assign_old(op2->value.refs + (uint)op1->value.intval, op, "put"); | |
166 | break; | |
167 | case t_mixedarray: /* packed arrays are read-only */ | |
168 | case t_shortarray: | |
169 | return e_invalidaccess; | |
170 | case t_string: | |
171 | check_type(*op1, t_integer); | |
172 | check_write(*op2); | |
173 | if ( (ulong)(op1->value.intval) >= r_size(op2) ) | |
174 | return e_rangecheck; | |
175 | check_type(*op, t_integer); | |
176 | if ( (ulong)op->value.intval > 0xff ) | |
177 | return e_rangecheck; | |
178 | op2->value.bytes[(uint)op1->value.intval] = (byte)op->value.intval; | |
179 | break; | |
180 | default: | |
181 | return e_typecheck; | |
182 | } | |
183 | pop(3); | |
184 | return 0; | |
185 | } | |
186 | ||
187 | /* getinterval */ | |
188 | int | |
189 | zgetinterval(register os_ptr op) | |
190 | { os_ptr op1 = op - 1; | |
191 | os_ptr op2 = op1 - 1; | |
192 | uint index; | |
193 | uint count; | |
194 | check_type(*op1, t_integer); | |
195 | check_type(*op, t_integer); | |
196 | switch ( r_type(op2) ) | |
197 | { | |
198 | default: | |
199 | return e_typecheck; | |
200 | case t_array: case t_string: | |
201 | case t_mixedarray: | |
202 | case t_shortarray: ; | |
203 | } | |
204 | check_read(*op2); | |
205 | if ( (ulong)op1->value.intval > r_size(op2) ) return e_rangecheck; | |
206 | index = op1->value.intval; | |
207 | if ( (ulong)op->value.intval > r_size(op2) - index ) return e_rangecheck; | |
208 | count = op->value.intval; | |
209 | switch ( r_type(op2) ) | |
210 | { | |
211 | case t_array: op2->value.refs += index; break; | |
212 | case t_string: op2->value.bytes += index; break; | |
213 | case t_mixedarray: | |
214 | { ushort *packed = op2->value.packed; | |
215 | for ( ; index--; ) packed = packed_next(packed); | |
216 | op2->value.packed = packed; | |
217 | } break; | |
218 | case t_shortarray: op2->value.packed += index; break; | |
219 | } | |
220 | r_set_size(op2, count); | |
221 | pop(2); | |
222 | return 0; | |
223 | } | |
224 | ||
225 | /* putinterval */ | |
226 | int | |
227 | zputinterval(register os_ptr op) | |
228 | { os_ptr opindex = op - 1; | |
229 | os_ptr opto = opindex - 1; | |
230 | int code; | |
231 | check_type(*opindex, t_integer); | |
232 | switch ( r_type(opto) ) | |
233 | { | |
234 | default: return e_typecheck; | |
235 | case t_mixedarray: case t_shortarray: return e_invalidaccess; | |
236 | case t_array: case t_string: ; | |
237 | } | |
238 | check_write(*opto); | |
239 | if ( (ulong)opindex->value.intval > r_size(opto) ) | |
240 | return e_rangecheck; | |
241 | code = copy_interval(opto, (uint)(opindex->value.intval), op, "putinterval"); | |
242 | if ( code >= 0 ) pop(3); | |
243 | return code; | |
244 | } | |
245 | ||
246 | /* forall */ | |
247 | private int | |
248 | array_continue(P1(os_ptr)), | |
249 | i_array_continue, | |
250 | dict_continue(P1(os_ptr)), | |
251 | i_dict_continue, | |
252 | string_continue(P1(os_ptr)), | |
253 | i_string_continue, | |
254 | packedarray_continue(P1(os_ptr)), | |
255 | i_packedarray_continue; | |
256 | int | |
257 | zforall(register os_ptr op) | |
258 | { int (*cproc)(P1(os_ptr)); | |
259 | os_ptr obj = op - 1; | |
260 | uint index = 0; /* only used for dictionaries */ | |
261 | switch ( r_type(obj) ) | |
262 | { | |
263 | default: | |
264 | return e_typecheck; | |
265 | case t_array: | |
266 | check_read(*obj); | |
267 | cproc = array_continue; | |
268 | break; | |
269 | case t_dictionary: | |
270 | check_dict_read(*obj); | |
271 | cproc = dict_continue; | |
272 | index = dict_first(obj); | |
273 | break; | |
274 | case t_string: | |
275 | check_read(*obj); | |
276 | cproc = string_continue; | |
277 | break; | |
278 | case t_mixedarray: | |
279 | case t_shortarray: | |
280 | check_read(*obj); | |
281 | cproc = packedarray_continue; | |
282 | break; | |
283 | } | |
284 | check_proc(*op); | |
285 | /* Push a mark, the composite object, the iteration index, */ | |
286 | /* and the procedure, and invoke the continuation operator. */ | |
287 | check_estack(6); | |
288 | mark_estack(es_for); | |
289 | *++esp = *obj; | |
290 | ++esp; | |
291 | make_int(esp, index); | |
292 | *++esp = *op; | |
293 | pop(2); op -= 2; | |
294 | return (*cproc)(op); | |
295 | } | |
296 | /* Continuation operator for arrays */ | |
297 | private int | |
298 | array_continue(register os_ptr op) | |
299 | { es_ptr obj = esp - 2; | |
300 | if ( r_size(obj) ) /* continue */ | |
301 | { r_inc_size(obj, -1); | |
302 | push(1); | |
303 | *op = *obj->value.refs; | |
304 | obj->value.refs++; | |
305 | push_op_estack(array_continue, i_array_continue); /* push continuation */ | |
306 | *++esp = obj[2]; | |
307 | return o_push_estack; | |
308 | } | |
309 | else /* done */ | |
310 | { esp -= 4; /* pop mark, object, index, proc */ | |
311 | return o_pop_estack; | |
312 | } | |
313 | } | |
314 | /* Continuation operator for dictionaries */ | |
315 | private int | |
316 | dict_continue(register os_ptr op) | |
317 | { es_ptr obj = esp - 2; | |
318 | int index = (int)esp[-1].value.intval; | |
319 | push(2); /* make room for key and value */ | |
320 | if ( (index = dict_next(obj, index, op - 1)) >= 0 ) /* continue */ | |
321 | { esp[-1].value.intval = index; | |
322 | push_op_estack(dict_continue, i_dict_continue); /* push continuation */ | |
323 | *++esp = obj[2]; | |
324 | return o_push_estack; | |
325 | } | |
326 | else /* done */ | |
327 | { pop(2); /* undo push */ | |
328 | esp -= 4; /* pop mark, object, index, proc */ | |
329 | return o_pop_estack; | |
330 | } | |
331 | } | |
332 | /* Continuation operator for strings */ | |
333 | private int | |
334 | string_continue(register os_ptr op) | |
335 | { es_ptr obj = esp - 2; | |
336 | if ( r_size(obj) ) /* continue */ | |
337 | { r_inc_size(obj, -1); | |
338 | push(1); | |
339 | make_int(op, *obj->value.bytes); | |
340 | obj->value.bytes++; | |
341 | push_op_estack(string_continue, i_string_continue); /* push continuation */ | |
342 | *++esp = obj[2]; | |
343 | return o_push_estack; | |
344 | } | |
345 | else /* done */ | |
346 | { esp -= 4; /* pop mark, object, index, proc */ | |
347 | return o_pop_estack; | |
348 | } | |
349 | } | |
350 | /* Continuation operator for packed arrays */ | |
351 | private int | |
352 | packedarray_continue(register os_ptr op) | |
353 | { es_ptr obj = esp - 2; | |
354 | if ( r_size(obj) ) /* continue */ | |
355 | { ushort *packed = obj->value.packed; | |
356 | r_inc_size(obj, -1); | |
357 | push(1); | |
358 | packed_get(packed, op); | |
359 | obj->value.packed = packed_next(packed); | |
360 | push_op_estack(packedarray_continue, i_packedarray_continue); /* push continuation */ | |
361 | *++esp = obj[2]; | |
362 | return o_push_estack; | |
363 | } | |
364 | else /* done */ | |
365 | { esp -= 4; /* pop mark, object, index, proc */ | |
366 | return o_pop_estack; | |
367 | } | |
368 | } | |
369 | ||
370 | /* ------ Initialization procedure ------ */ | |
371 | ||
372 | op_def zgeneric_op_defs[] = { | |
373 | {"1copy", zcopy}, | |
374 | {"2forall", zforall}, | |
375 | {"2get", zget}, | |
376 | {"3getinterval", zgetinterval}, | |
377 | {"1length", zlength}, | |
378 | {"3put", zput}, | |
379 | {"3putinterval", zputinterval}, | |
380 | /* Internal operators */ | |
381 | {"0%array_continue", array_continue, &i_array_continue}, | |
382 | {"0%dict_continue", dict_continue, &i_dict_continue}, | |
383 | {"0%packedarray_continue", packedarray_continue, &i_packedarray_continue}, | |
384 | {"0%string_continue", string_continue, &i_string_continue}, | |
385 | op_def_end(0) | |
386 | }; | |
387 | ||
388 | /* ------ Shared routines ------ */ | |
389 | ||
390 | /* Get an element from an array of some kind. */ | |
391 | /* This is also used to index into Encoding vectors, */ | |
392 | /* the error name vector, etc. */ | |
393 | int | |
394 | array_get(ref *aref, long index_long, ref *pref) | |
395 | { uint index = (uint)index_long; | |
396 | if ( (ulong)index_long >= r_size(aref) ) | |
397 | return e_rangecheck; | |
398 | switch ( r_type(aref) ) | |
399 | { | |
400 | case t_array: | |
401 | { ref *pvalue = aref->value.refs + index; | |
402 | ref_assign(pref, pvalue); | |
403 | } return 0; | |
404 | case t_mixedarray: | |
405 | { ushort *packed = aref->value.packed; | |
406 | for ( ; index--; ) packed = packed_next(packed); | |
407 | packed_get(packed, pref); | |
408 | } return 0; | |
409 | case t_shortarray: | |
410 | { ushort *packed = aref->value.packed + index; | |
411 | packed_get(packed, pref); | |
412 | } return 0; | |
413 | default: | |
414 | return e_typecheck; | |
415 | } | |
416 | } | |
417 | ||
418 | /* Copy an interval from one operand to another. */ | |
419 | /* This is used by both putinterval and string/array copy. */ | |
420 | /* One operand is known to be an array or string, */ | |
421 | /* and the starting index is known to be less than or equal to */ | |
422 | /* its length; nothing else has been checked. */ | |
423 | private int | |
424 | copy_interval(os_ptr prto, uint index, os_ptr prfrom, const char *cname) | |
425 | { int fromtype = r_type(prfrom); | |
426 | uint fromsize = r_size(prfrom); | |
427 | if ( !(fromtype == r_type(prto) || (fromtype == t_shortarray | |
428 | || fromtype == t_mixedarray) && r_type(prto) == t_array) | |
429 | ) | |
430 | return e_typecheck; | |
431 | check_read(*prfrom); | |
432 | check_write(*prto); | |
433 | if ( fromsize > r_size(prto) - index ) return e_rangecheck; | |
434 | switch ( fromtype ) | |
435 | { | |
436 | case t_array: | |
437 | refcpy_to_old(prto->value.refs + index, prfrom->value.refs, | |
438 | fromsize, cname); | |
439 | break; | |
440 | case t_string: | |
441 | memcpy(prto->value.bytes + index, prfrom->value.bytes, | |
442 | fromsize); | |
443 | break; | |
444 | case t_mixedarray: | |
445 | case t_shortarray: | |
446 | { int i; | |
447 | ushort *packed = prfrom->value.packed; | |
448 | ref *pdest = prto->value.refs + index; | |
449 | ref elt; | |
450 | for ( i = 0; i < fromsize; i++, pdest++ ) | |
451 | { packed_get(packed, &elt); | |
452 | ref_assign_old(pdest, &elt, cname); | |
453 | packed = packed_next(packed); | |
454 | } | |
455 | } break; | |
456 | } | |
457 | return 0; | |
458 | } |