386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / zgeneric.c
CommitLineData
354162ef
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
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 */
38extern int zcopy_device(P1(os_ptr));
39extern int zcopy_dict(P1(os_ptr));
40
41/* Forward references */
42int array_get(P3(ref *, long, ref *));
43private 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). */
49int
50zcopy(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 */
85int
86zlength(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 */
112int
113zget(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) ) {
127printf("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 */
148int
149zput(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 */
188int
189zgetinterval(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 */
226int
227zputinterval(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 */
247private 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;
256int
257zforall(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 */
297private int
298array_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 */
315private int
316dict_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 */
333private int
334string_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 */
351private int
352packedarray_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
372op_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. */
393int
394array_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. */
423private int
424copy_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}