xref: /plan9/sys/src/cmd/gs/src/iparam.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 2000 Aladdin Enterprises.  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 
17 /* $Id: iparam.c,v 1.10 2004/08/04 19:36:13 stefan Exp $ */
18 /* Interpreter implementations of parameter dictionaries */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "ghost.h"
22 #include "ierrors.h"
23 #include "oper.h"		/* for check_type */
24 #include "opcheck.h"
25 #include "ialloc.h"
26 #include "idict.h"
27 #include "imemory.h"		/* for iutil.h */
28 #include "iname.h"
29 #include "istack.h"
30 #include "iparam.h"
31 #include "iutil.h"		/* for num_params */
32 #include "ivmspace.h"
33 #include "store.h"
34 
35 /* ================ Utilities ================ */
36 
37 /* Convert a key to a ref. */
38 private int
ref_param_key(const iparam_list * plist,gs_param_name pkey,ref * pkref)39 ref_param_key(const iparam_list * plist, gs_param_name pkey, ref * pkref)
40 {
41     if (plist->int_keys) {
42 	long key;
43 
44 	if (sscanf(pkey, "%ld", &key) != 1)
45 	    return_error(e_rangecheck);
46 	make_int(pkref, key);
47 	return 0;
48     } else
49         return name_ref(plist->memory, (const byte *)pkey, strlen(pkey), pkref, 0);
50 }
51 
52 /* Fill in a gs_param_key_t from a name or int ref. */
53 private int
ref_to_key(const ref * pref,gs_param_key_t * key,iparam_list * plist)54 ref_to_key(const ref * pref, gs_param_key_t * key, iparam_list *plist)
55 {
56     if (r_has_type(pref, t_name)) {
57 	ref nref;
58 
59 	name_string_ref(plist->memory, pref, &nref);
60 	key->data = nref.value.const_bytes;
61 	key->size = r_size(&nref);
62 	key->persistent = false; /* names may be freed */
63     } else if (r_has_type(pref, t_integer)) {
64 	char istr[sizeof(long) * 8 / 3 + 2];
65 	int len;
66 	byte *buf;
67 
68 	sprintf(istr, "%ld", pref->value.intval);
69 	len = strlen(istr);
70 	/* GC will take care of freeing this: */
71 	buf = gs_alloc_string(plist->memory, len, "ref_to_key");
72 	if (!buf)
73 	    return_error(e_VMerror);
74 	key->data = buf;
75 	key->size = len;
76 	key->persistent = true;
77     } else
78 	return_error(e_typecheck);
79     return 0;
80 }
81 
82 /* ================ Writing parameters to refs ================ */
83 
84 /* Forward references */
85 private int array_new_indexed_plist_write(dict_param_list *plist,
86 					  ref *parray, const ref *pwanted,
87 					  gs_ref_memory_t *imem);
88 
89 /* ---------------- Generic writing procedures ---------------- */
90 
91 private param_proc_begin_xmit_collection(ref_param_begin_write_collection);
92 private param_proc_end_xmit_collection(ref_param_end_write_collection);
93 private param_proc_xmit_typed(ref_param_write_typed);
94 private param_proc_next_key(ref_param_get_next_key);
95 private param_proc_requested(ref_param_requested);
96 private const gs_param_list_procs ref_write_procs =
97 {
98     ref_param_write_typed,
99     ref_param_begin_write_collection,
100     ref_param_end_write_collection,
101     ref_param_get_next_key,
102     NULL,			/* request */
103     ref_param_requested
104 };
105 private int ref_array_param_requested(const iparam_list *, gs_param_name,
106 				      ref *, uint, client_name_t);
107 private int ref_param_write(iparam_list *, gs_param_name, const ref *);
108 private int ref_param_write_string_value(ref *, const gs_param_string *,
109 					 gs_ref_memory_t *);
110 private int ref_param_write_name_value(const gs_memory_t *mem, ref *, const gs_param_string *);
111 private int
ref_param_make_int(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)112 ref_param_make_int(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
113 {
114     make_tav(pe, t_integer, imemory_new_mask(imem), intval,
115 	     ((const gs_param_int_array *)pvalue)->data[i]);
116     return 0;
117 }
118 private int
ref_param_make_float(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)119 ref_param_make_float(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
120 {
121     make_tav(pe, t_real, imemory_new_mask(imem), realval,
122 	     ((const gs_param_float_array *)pvalue)->data[i]);
123     return 0;
124 }
125 private int
ref_param_make_string(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)126 ref_param_make_string(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
127 {
128     return ref_param_write_string_value(pe,
129 			 &((const gs_param_string_array *)pvalue)->data[i],
130 					imem);
131 }
132 private int
ref_param_make_name(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)133 ref_param_make_name(ref * pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
134 {
135     return ref_param_write_name_value((const gs_memory_t *)imem, pe,
136 			 &((const gs_param_string_array *)pvalue)->data[i]);
137 }
138 private int
ref_param_write_typed_array(gs_param_list * plist,gs_param_name pkey,void * pvalue,uint count,int (* make)(ref *,const void *,uint,gs_ref_memory_t *))139 ref_param_write_typed_array(gs_param_list * plist, gs_param_name pkey,
140 			    void *pvalue, uint count,
141 			    int (*make)(ref *, const void *, uint,
142 					gs_ref_memory_t *))
143 {
144     iparam_list *const iplist = (iparam_list *) plist;
145     ref value;
146     uint i;
147     ref *pe;
148     int code;
149 
150     if ((code = ref_array_param_requested(iplist, pkey, &value, count,
151 				       "ref_param_write_typed_array")) <= 0)
152 	return code;
153     for (i = 0, pe = value.value.refs; i < count; ++i, ++pe)
154 	if ((code = (*make) (pe, pvalue, i, iplist->ref_memory)) < 0)
155 	    return code;
156     return ref_param_write(iplist, pkey, &value);
157 }
158 private int
ref_param_begin_write_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue,gs_param_collection_type_t coll_type)159 ref_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
160 				 gs_param_dict * pvalue,
161 				 gs_param_collection_type_t coll_type)
162 {
163     iparam_list *const iplist = (iparam_list *) plist;
164     gs_ref_memory_t *imem = iplist->ref_memory;
165     dict_param_list *dlist = (dict_param_list *)
166 	gs_alloc_bytes(plist->memory, size_of(dict_param_list),
167 		       "ref_param_begin_write_collection");
168     int code;
169 
170     if (dlist == 0)
171 	return_error(e_VMerror);
172     if (coll_type != gs_param_collection_array) {
173 	ref dref;
174 
175 	code = dict_alloc(imem, pvalue->size, &dref);
176 	if (code >= 0) {
177 	    code = dict_param_list_write(dlist, &dref, NULL, imem);
178 	    dlist->int_keys = coll_type == gs_param_collection_dict_int_keys;
179 	}
180     } else {
181 	ref aref;
182 
183 	code = gs_alloc_ref_array(imem, &aref, a_all, pvalue->size,
184 				  "ref_param_begin_write_collection");
185 	if (code >= 0)
186 	    code = array_new_indexed_plist_write(dlist, &aref, NULL, imem);
187     }
188     if (code < 0)
189 	gs_free_object(plist->memory, dlist, "ref_param_begin_write_collection");
190     else
191 	pvalue->list = (gs_param_list *) dlist;
192     return code;
193 }
194 private int
ref_param_end_write_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue)195 ref_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
196 			       gs_param_dict * pvalue)
197 {
198     iparam_list *const iplist = (iparam_list *) plist;
199     int code = ref_param_write(iplist, pkey,
200 			       &((dict_param_list *) pvalue->list)->dict);
201 
202     gs_free_object(plist->memory, pvalue->list, "ref_param_end_write_collection");
203     return code;
204 }
205 private int
ref_param_write_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)206 ref_param_write_typed(gs_param_list * plist, gs_param_name pkey,
207 		      gs_param_typed_value * pvalue)
208 {
209     iparam_list *const iplist = (iparam_list *) plist;
210     ref value;
211     int code = 0;
212 
213     switch (pvalue->type) {
214 	case gs_param_type_null:
215 	    make_null(&value);
216 	    break;
217 	case gs_param_type_bool:
218 	    make_bool(&value, pvalue->value.b);
219 	    break;
220 	case gs_param_type_int:
221 	    make_int(&value, pvalue->value.i);
222 	    break;
223 	case gs_param_type_long:
224 	    make_int(&value, pvalue->value.l);
225 	    break;
226 	case gs_param_type_float:
227 	    make_real(&value, pvalue->value.f);
228 	    break;
229 	case gs_param_type_string:
230 	    if (!ref_param_requested(plist, pkey))
231 		return 0;
232 	    code = ref_param_write_string_value(&value, &pvalue->value.s,
233 						iplist->ref_memory);
234 	    break;
235 	case gs_param_type_name:
236 	    if (!ref_param_requested(plist, pkey))
237 		return 0;
238 	    code = ref_param_write_name_value(iplist->memory, &value, &pvalue->value.n);
239 	    break;
240 	case gs_param_type_int_array:
241 	    return ref_param_write_typed_array(plist, pkey, &pvalue->value.ia,
242 					       pvalue->value.ia.size,
243 					       ref_param_make_int);
244 	case gs_param_type_float_array:
245 	    return ref_param_write_typed_array(plist, pkey, &pvalue->value.fa,
246 					       pvalue->value.fa.size,
247 					       ref_param_make_float);
248 	case gs_param_type_string_array:
249 	    return ref_param_write_typed_array(plist, pkey, &pvalue->value.sa,
250 					       pvalue->value.sa.size,
251 					       ref_param_make_string);
252 	case gs_param_type_name_array:
253 	    return ref_param_write_typed_array(plist, pkey, &pvalue->value.na,
254 					       pvalue->value.na.size,
255 					       ref_param_make_name);
256 	case gs_param_type_dict:
257 	case gs_param_type_dict_int_keys:
258 	case gs_param_type_array:
259 	    return ref_param_begin_write_collection(plist, pkey,
260 						    &pvalue->value.d,
261 	      (gs_param_collection_type_t)(pvalue->type - gs_param_type_dict));
262 	default:
263 	    return_error(e_typecheck);
264     }
265     if (code < 0)
266 	return code;
267     return ref_param_write(iplist, pkey, &value);
268 }
269 
270 /* Check whether a given parameter was requested. */
271 private int
ref_param_requested(const gs_param_list * plist,gs_param_name pkey)272 ref_param_requested(const gs_param_list * plist, gs_param_name pkey)
273 {
274     const iparam_list *const ciplist = (const iparam_list *)plist;
275     ref kref;
276     ref *ignore_value;
277 
278     if (!r_has_type(&ciplist->u.w.wanted, t_dictionary))
279 	return -1;
280     if (ref_param_key(ciplist, pkey, &kref) < 0)
281 	return -1;		/* catch it later */
282     return (dict_find(&ciplist->u.w.wanted, &kref, &ignore_value) > 0);
283 }
284 
285 /* Check whether an array parameter is wanted, and allocate it if so. */
286 /* Return <0 on error, 0 if not wanted, 1 if wanted. */
287 private int
ref_array_param_requested(const iparam_list * iplist,gs_param_name pkey,ref * pvalue,uint size,client_name_t cname)288 ref_array_param_requested(const iparam_list *iplist, gs_param_name pkey,
289 			  ref *pvalue, uint size, client_name_t cname)
290 {
291     int code;
292 
293     if (!ref_param_requested((const gs_param_list *)iplist, pkey))
294 	return 0;
295     code = gs_alloc_ref_array(iplist->ref_memory, pvalue, a_all, size, cname);
296     return (code < 0 ? code : 1);
297 }
298 
299 /* ---------------- Internal routines ---------------- */
300 
301 /* Prepare to write a string value. */
302 private int
ref_param_write_string_value(ref * pref,const gs_param_string * pvalue,gs_ref_memory_t * imem)303 ref_param_write_string_value(ref * pref, const gs_param_string * pvalue,
304 			     gs_ref_memory_t *imem)
305 {
306     const byte *pdata = pvalue->data;
307     uint n = pvalue->size;
308 
309     if (pvalue->persistent)
310 	make_const_string(pref, a_readonly | avm_foreign, n, pdata);
311     else {
312 	byte *pstr = gs_alloc_string((gs_memory_t *)imem, n,
313 				     "ref_param_write_string");
314 
315 	if (pstr == 0)
316 	    return_error(e_VMerror);
317 	memcpy(pstr, pdata, n);
318 	make_string(pref, a_readonly | imemory_space(imem), n, pstr);
319     }
320     return 0;
321 }
322 
323 /* Prepare to write a name value. */
324 private int
ref_param_write_name_value(const gs_memory_t * mem,ref * pref,const gs_param_string * pvalue)325 ref_param_write_name_value(const gs_memory_t *mem, ref * pref, const gs_param_string * pvalue)
326 {
327     return name_ref(mem, pvalue->data, pvalue->size, pref,
328 		    (pvalue->persistent ? 0 : 1));
329 }
330 
331 /* Generic routine for writing a ref parameter. */
332 private int
ref_param_write(iparam_list * plist,gs_param_name pkey,const ref * pvalue)333 ref_param_write(iparam_list * plist, gs_param_name pkey, const ref * pvalue)
334 {
335     ref kref;
336     int code;
337 
338     if (!ref_param_requested((gs_param_list *) plist, pkey))
339 	return 0;
340     code = ref_param_key(plist, pkey, &kref);
341     if (code < 0)
342 	return code;
343     return (*plist->u.w.write) (plist, &kref, pvalue);
344 }
345 
346 /* ---------------- Implementations ---------------- */
347 
348 /* Initialize for writing parameters. */
349 private void
ref_param_write_init(iparam_list * plist,const ref * pwanted,gs_ref_memory_t * imem)350 ref_param_write_init(iparam_list * plist, const ref * pwanted,
351 		     gs_ref_memory_t *imem)
352 {
353     gs_param_list_init((gs_param_list *)plist, &ref_write_procs,
354 		       (gs_memory_t *)imem);
355     plist->ref_memory = imem;
356     if (pwanted == 0)
357 	make_null(&plist->u.w.wanted);
358     else
359 	plist->u.w.wanted = *pwanted;
360     plist->results = 0;
361     plist->int_keys = false;
362 }
363 
364 /* Implementation for getting parameters to a stack. */
365 private int
stack_param_write(iparam_list * plist,const ref * pkey,const ref * pvalue)366 stack_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
367 {
368     stack_param_list *const splist = (stack_param_list *) plist;
369     ref_stack_t *pstack = splist->pstack;
370     s_ptr p = pstack->p;
371 
372     if (pstack->top - p < 2) {
373 	int code = ref_stack_push(pstack, 2);
374 
375 	if (code < 0)
376 	    return code;
377 	*ref_stack_index(pstack, 1) = *pkey;
378 	p = pstack->p;
379     } else {
380 	pstack->p = p += 2;
381 	p[-1] = *pkey;
382     }
383     *p = *pvalue;
384     splist->count++;
385     return 0;
386 }
387 
388 /* Implementation for enumerating parameters on a stack */
389 private int			/* ret 0 ok, 1 if EOF, or -ve err */
stack_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)390 stack_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
391 		      gs_param_key_t * key, ref_type * type)
392 {
393     int code;
394     stack_param_list *const splist = (stack_param_list *) plist;
395     long index = penum->intval;
396     ref *stack_element;
397 
398     do {
399 	stack_element =
400 	    ref_stack_index(splist->pstack, index + 1 + splist->skip);
401 	if (!stack_element)
402 	    return 1;
403     } while (index += 2, !r_has_type(stack_element, t_name));
404     *type = r_type(stack_element);
405     code = ref_to_key(stack_element, key, plist);
406     penum->intval = index;
407     return code;
408 }
409 
410 int
stack_param_list_write(stack_param_list * plist,ref_stack_t * pstack,const ref * pwanted,gs_ref_memory_t * imem)411 stack_param_list_write(stack_param_list * plist, ref_stack_t * pstack,
412 		       const ref * pwanted, gs_ref_memory_t *imem)
413 {
414     plist->u.w.write = stack_param_write;
415     ref_param_write_init((iparam_list *) plist, pwanted, imem);
416     plist->enumerate = stack_param_enumerate;
417     plist->pstack = pstack;
418     plist->skip = 0;
419     plist->count = 0;
420     return 0;
421 }
422 
423 /* Implementation for getting parameters to a dictionary. */
424 private int
dict_param_write(iparam_list * plist,const ref * pkey,const ref * pvalue)425 dict_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
426 {
427     int code =
428 	dict_put(&((dict_param_list *) plist)->dict, pkey, pvalue, NULL);
429 
430     return min(code, 0);
431 }
432 
433 /* Implementation for enumerating parameters in a dictionary */
434 private int			/* ret 0 ok, 1 if EOF, or -ve err */
dict_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)435 dict_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
436 		     gs_param_key_t * key, ref_type * type)
437 {
438     ref elt[2];
439     int code;
440     dict_param_list *const pdlist = (dict_param_list *) plist;
441     int index =
442     (penum->intval != 0 ? penum->intval : dict_first(&pdlist->dict));
443 
444     index = dict_next(&pdlist->dict, index, elt);
445     if (index < 0)
446 	return 1;
447     *type = r_type(&elt[1]);
448     code = ref_to_key(&elt[0], key, plist);
449     penum->intval = index;
450     return code;
451 }
452 
453 int
dict_param_list_write(dict_param_list * plist,ref * pdict,const ref * pwanted,gs_ref_memory_t * imem)454 dict_param_list_write(dict_param_list *plist, ref *pdict, const ref *pwanted,
455 		      gs_ref_memory_t *imem)
456 {
457     check_dict_write(*pdict);
458     plist->u.w.write = dict_param_write;
459     plist->enumerate = dict_param_enumerate;
460     ref_param_write_init((iparam_list *) plist, pwanted, imem);
461     plist->dict = *pdict;
462     return 0;
463 }
464 
465 /* Implementation for getting parameters to an indexed array. */
466 /* Note that this is now internal, since it only handles "new" arrays. */
467 private int
array_new_indexed_param_write(iparam_list * iplist,const ref * pkey,const ref * pvalue)468 array_new_indexed_param_write(iparam_list * iplist, const ref * pkey,
469 			  const ref * pvalue)
470 {
471     const ref *const arr = &((dict_param_list *)iplist)->dict;
472     ref *eltp;
473 
474     if (!r_has_type(pkey, t_integer))
475 	return_error(e_typecheck);
476     check_int_ltu(*pkey, r_size(arr));
477     store_check_dest(arr, pvalue);
478     eltp = arr->value.refs + pkey->value.intval;
479     /* ref_assign_new(eltp, pvalue); */
480     ref_assign(eltp, pvalue);
481     r_set_attrs(eltp, imemory_new_mask(iplist->ref_memory));
482     return 0;
483 }
484 private int
array_new_indexed_plist_write(dict_param_list * plist,ref * parray,const ref * pwanted,gs_ref_memory_t * imem)485 array_new_indexed_plist_write(dict_param_list * plist, ref * parray,
486 			      const ref * pwanted, gs_ref_memory_t *imem)
487 {
488     check_array(*parray);
489     check_write(*parray);
490     plist->u.w.write = array_new_indexed_param_write;
491     ref_param_write_init((iparam_list *) plist, pwanted, imem);
492     plist->dict = *parray;
493     plist->int_keys = true;
494     return 0;
495 }
496 
497 /* ================ Reading refs to parameters ================ */
498 
499 /* ---------------- Generic reading procedures ---------------- */
500 
501 private param_proc_begin_xmit_collection(ref_param_begin_read_collection);
502 private param_proc_end_xmit_collection(ref_param_end_read_collection);
503 private param_proc_xmit_typed(ref_param_read_typed);
504 
505 /*private param_proc_next_key(ref_param_get_next_key); already dec'ld above */
506 private param_proc_get_policy(ref_param_read_get_policy);
507 private param_proc_signal_error(ref_param_read_signal_error);
508 private param_proc_commit(ref_param_read_commit);
509 private const gs_param_list_procs ref_read_procs =
510 {
511     ref_param_read_typed,
512     ref_param_begin_read_collection,
513     ref_param_end_read_collection,
514     ref_param_get_next_key,
515     NULL,			/* request */
516     NULL,			/* requested */
517     ref_param_read_get_policy,
518     ref_param_read_signal_error,
519     ref_param_read_commit
520 };
521 private int ref_param_read(iparam_list *, gs_param_name,
522 			   iparam_loc *, int);
523 private int ref_param_read_string_value(const gs_memory_t *mem,
524 					const iparam_loc *,
525 					gs_param_string *);
526 private int ref_param_read_array(iparam_list *, gs_param_name,
527 				 iparam_loc *);
528 
529 #define iparam_note_error(loc, code)\
530   gs_note_error(*(loc).presult = code)
531 #define iparam_check_type(loc, typ)\
532   if ( !r_has_type((loc).pvalue, typ) )\
533     return iparam_note_error(loc, e_typecheck)
534 #define iparam_check_read(loc)\
535   if ( !r_has_attr((loc).pvalue, a_read) )\
536     return iparam_note_error(loc, e_invalidaccess)
537 
538 private int
ref_param_read_int_array(gs_param_list * plist,gs_param_name pkey,gs_param_int_array * pvalue)539 ref_param_read_int_array(gs_param_list * plist, gs_param_name pkey,
540 			 gs_param_int_array * pvalue)
541 {
542     iparam_list *const iplist = (iparam_list *) plist;
543     iparam_loc loc;
544     int code = ref_param_read_array(iplist, pkey, &loc);
545     int *piv;
546     uint size;
547     long i;
548 
549     if (code != 0)
550 	return code;
551     size = r_size(loc.pvalue);
552     piv = (int *)gs_alloc_byte_array(plist->memory, size, sizeof(int),
553 				     "ref_param_read_int_array");
554 
555     if (piv == 0)
556 	return_error(e_VMerror);
557     for (i = 0; i < size; i++) {
558 	ref elt;
559 
560 	array_get(plist->memory, loc.pvalue, i, &elt);
561 	if (!r_has_type(&elt, t_integer)) {
562 	    code = gs_note_error(e_typecheck);
563 	    break;
564 	}
565 #if arch_sizeof_int < arch_sizeof_long
566 	if (elt.value.intval != (int)elt.value.intval) {
567 	    code = gs_note_error(e_rangecheck);
568 	    break;
569 	}
570 #endif
571 	piv[i] = (int)elt.value.intval;
572     }
573     if (code < 0) {
574 	gs_free_object(plist->memory, piv, "ref_param_read_int_array");
575 	return (*loc.presult = code);
576     }
577     pvalue->data = piv;
578     pvalue->size = size;
579     pvalue->persistent = true;
580     return 0;
581 }
582 private int
ref_param_read_float_array(gs_param_list * plist,gs_param_name pkey,gs_param_float_array * pvalue)583 ref_param_read_float_array(gs_param_list * plist, gs_param_name pkey,
584 			   gs_param_float_array * pvalue)
585 {
586     iparam_list *const iplist = (iparam_list *) plist;
587     iparam_loc loc;
588     ref aref, elt;
589     int code = ref_param_read_array(iplist, pkey, &loc);
590     float *pfv;
591     uint size;
592     long i;
593 
594     if (code != 0)
595 	return code;
596     size = r_size(loc.pvalue);
597     pfv = (float *)gs_alloc_byte_array(plist->memory, size, sizeof(float),
598 				       "ref_param_read_float_array");
599 
600     if (pfv == 0)
601 	return_error(e_VMerror);
602     aref = *loc.pvalue;
603     loc.pvalue = &elt;
604     for (i = 0; code >= 0 && i < size; i++) {
605         array_get(plist->memory, &aref, i, &elt);
606 	code = float_param(&elt, pfv + i);
607     }
608     if (code < 0) {
609 	gs_free_object(plist->memory, pfv, "ref_read_float_array_param");
610 	return (*loc.presult = code);
611     }
612     pvalue->data = pfv;
613     pvalue->size = size;
614     pvalue->persistent = true;
615     return 0;
616 }
617 private int
ref_param_read_string_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)618 ref_param_read_string_array(gs_param_list * plist, gs_param_name pkey,
619 			    gs_param_string_array * pvalue)
620 {
621     iparam_list *const iplist = (iparam_list *) plist;
622     iparam_loc loc;
623     ref aref;
624     int code = ref_param_read_array(iplist, pkey, &loc);
625     gs_param_string *psv;
626     uint size;
627     long i;
628 
629     if (code != 0)
630 	return code;
631     size = r_size(loc.pvalue);
632     psv = (gs_param_string *)
633 	gs_alloc_byte_array(plist->memory, size, sizeof(gs_param_string),
634 			    "ref_param_read_string_array");
635     if (psv == 0)
636 	return_error(e_VMerror);
637     aref = *loc.pvalue;
638     if (r_has_type(&aref, t_array)) {
639 	for (i = 0; code >= 0 && i < size; i++) {
640 	    loc.pvalue = aref.value.refs + i;
641 	    code = ref_param_read_string_value(plist->memory, &loc, psv + i);
642 	}
643     } else {
644 	ref elt;
645 
646 	loc.pvalue = &elt;
647 	for (i = 0; code >= 0 && i < size; i++) {
648 	    array_get(plist->memory, &aref, i, &elt);
649 	    code = ref_param_read_string_value(plist->memory, &loc, psv + i);
650 	}
651     }
652     if (code < 0) {
653 	gs_free_object(plist->memory, psv, "ref_param_read_string_array");
654 	return (*loc.presult = code);
655     }
656     pvalue->data = psv;
657     pvalue->size = size;
658     pvalue->persistent = true;
659     return 0;
660 }
661 private int
ref_param_begin_read_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue,gs_param_collection_type_t coll_type)662 ref_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
663 				gs_param_dict * pvalue,
664 				gs_param_collection_type_t coll_type)
665 {
666     iparam_list *const iplist = (iparam_list *) plist;
667     iparam_loc loc;
668     bool int_keys = coll_type != 0;
669     int code = ref_param_read(iplist, pkey, &loc, -1);
670     dict_param_list *dlist;
671 
672     if (code != 0)
673 	return code;
674     dlist = (dict_param_list *)
675 	gs_alloc_bytes(plist->memory, size_of(dict_param_list),
676 		       "ref_param_begin_read_collection");
677     if (dlist == 0)
678 	return_error(e_VMerror);
679     if (r_has_type(loc.pvalue, t_dictionary)) {
680 	code = dict_param_list_read(dlist, loc.pvalue, NULL, false,
681 				    iplist->ref_memory);
682 	dlist->int_keys = int_keys;
683 	if (code >= 0)
684 	    pvalue->size = dict_length(loc.pvalue);
685     } else if (int_keys && r_is_array(loc.pvalue)) {
686 	code = array_indexed_param_list_read(dlist, loc.pvalue, NULL, false,
687 					     iplist->ref_memory);
688 	if (code >= 0)
689 	    pvalue->size = r_size(loc.pvalue);
690     } else
691 	code = gs_note_error(e_typecheck);
692     if (code < 0) {
693 	gs_free_object(plist->memory, dlist, "ref_param_begin_write_collection");
694 	return iparam_note_error(loc, code);
695     }
696     pvalue->list = (gs_param_list *) dlist;
697     return 0;
698 }
699 private int
ref_param_end_read_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue)700 ref_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
701 			      gs_param_dict * pvalue)
702 {
703     iparam_list_release((dict_param_list *) pvalue->list);
704     gs_free_object(plist->memory, pvalue->list,
705 		   "ref_param_end_read_collection");
706     return 0;
707 }
708 private int
ref_param_read_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)709 ref_param_read_typed(gs_param_list * plist, gs_param_name pkey,
710 		     gs_param_typed_value * pvalue)
711 {
712     iparam_list *const iplist = (iparam_list *) plist;
713     iparam_loc loc;
714     ref elt;
715     int code = ref_param_read(iplist, pkey, &loc, -1);
716 
717     if (code != 0)
718 	return code;
719     switch (r_type(loc.pvalue)) {
720 	case t_array:
721 	case t_mixedarray:
722 	case t_shortarray:
723 	    iparam_check_read(loc);
724 	    if (r_size(loc.pvalue) <= 0) {
725 		/* 0-length array; can't get type info */
726 		pvalue->type = gs_param_type_array;
727 		pvalue->value.d.list = 0;
728 		pvalue->value.d.size = 0;
729 		return 0;
730 	    }
731 	    /*
732 	     * We have to guess at the array type.  First we guess based
733 	     * on the type of the first element of the array.  If that
734 	     * fails, we try again with more general types.
735 	     */
736 	    array_get(plist->memory, loc.pvalue, 0, &elt);
737 	    switch (r_type(&elt)) {
738 		case t_integer:
739 		    pvalue->type = gs_param_type_int_array;
740 		    code = ref_param_read_int_array(plist, pkey,
741 						    &pvalue->value.ia);
742 		    if (code != e_typecheck)
743 			return code;
744 		    /* This might be a float array.  Fall through. */
745 		    *loc.presult = 0;  /* reset error */
746 		case t_real:
747 		    pvalue->type = gs_param_type_float_array;
748 		    return ref_param_read_float_array(plist, pkey,
749 						      &pvalue->value.fa);
750 		case t_string:
751 		    pvalue->type = gs_param_type_string_array;
752 		    return ref_param_read_string_array(plist, pkey,
753 						       &pvalue->value.sa);
754 		case t_name:
755 		    pvalue->type = gs_param_type_name_array;
756 		    return ref_param_read_string_array(plist, pkey,
757 						       &pvalue->value.na);
758 		default:
759 		    break;
760 	    }
761 	    return gs_note_error(e_typecheck);
762 	case t_boolean:
763 	    pvalue->type = gs_param_type_bool;
764 	    pvalue->value.b = loc.pvalue->value.boolval;
765 	    return 0;
766 	case t_dictionary:
767 	    code = ref_param_begin_read_collection(plist, pkey,
768 			    &pvalue->value.d, gs_param_collection_dict_any);
769 	    if (code < 0)
770 		return code;
771 	    pvalue->type = gs_param_type_dict;
772 
773 	    /* fixup new dict's type & int_keys field if contents have int keys */
774 	    {
775 		gs_param_enumerator_t enumr;
776 		gs_param_key_t key;
777 		ref_type keytype;
778 
779 		param_init_enumerator(&enumr);
780 		if (!(*((iparam_list *) plist)->enumerate)
781 		    ((iparam_list *) pvalue->value.d.list, &enumr, &key, &keytype)
782 		    && keytype == t_integer) {
783 		    ((dict_param_list *) pvalue->value.d.list)->int_keys = 1;
784 		    pvalue->type = gs_param_type_dict_int_keys;
785 		}
786 	    }
787 	    return 0;
788 	case t_integer:
789 	    pvalue->type = gs_param_type_long;
790 	    pvalue->value.l = loc.pvalue->value.intval;
791 	    return 0;
792 	case t_name:
793 	    pvalue->type = gs_param_type_name;
794 	    return ref_param_read_string_value(plist->memory, &loc, &pvalue->value.n);
795 	case t_null:
796 	    pvalue->type = gs_param_type_null;
797 	    return 0;
798 	case t_real:
799 	    pvalue->value.f = loc.pvalue->value.realval;
800 	    pvalue->type = gs_param_type_float;
801 	    return 0;
802 	case t_string:
803 	    pvalue->type = gs_param_type_string;
804 	    return ref_param_read_string_value(plist->memory, &loc, &pvalue->value.s);
805 	default:
806 	    break;
807     }
808     return gs_note_error(e_typecheck);
809 }
810 
811 private int
ref_param_read_get_policy(gs_param_list * plist,gs_param_name pkey)812 ref_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
813 {
814     iparam_list *const iplist = (iparam_list *) plist;
815     ref *pvalue;
816 
817     if (!(r_has_type(&iplist->u.r.policies, t_dictionary) &&
818 	  dict_find_string(&iplist->u.r.policies, pkey, &pvalue) > 0 &&
819 	  r_has_type(pvalue, t_integer))
820 	)
821 	return gs_param_policy_ignore;
822     return (int)pvalue->value.intval;
823 }
824 private int
ref_param_read_signal_error(gs_param_list * plist,gs_param_name pkey,int code)825 ref_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
826 {
827     iparam_list *const iplist = (iparam_list *) plist;
828     iparam_loc loc;
829 
830     ref_param_read(iplist, pkey, &loc, -1);	/* can't fail */
831     *loc.presult = code;
832     switch (ref_param_read_get_policy(plist, pkey)) {
833 	case gs_param_policy_ignore:
834 	    return 0;
835 	case gs_param_policy_consult_user:
836 	    return_error(e_configurationerror);
837 	default:
838 	    return code;
839     }
840 }
841 private int
ref_param_read_commit(gs_param_list * plist)842 ref_param_read_commit(gs_param_list * plist)
843 {
844     iparam_list *const iplist = (iparam_list *) plist;
845     int i;
846     int ecode = 0;
847 
848     if (!iplist->u.r.require_all)
849 	return 0;
850     /* Check to make sure that all parameters were actually read. */
851     for (i = 0; i < iplist->count; ++i)
852 	if (iplist->results[i] == 0)
853 	    iplist->results[i] = ecode = gs_note_error(e_undefined);
854     return ecode;
855 }
856 private int
ref_param_get_next_key(gs_param_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key)857 ref_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
858 		       gs_param_key_t * key)
859 {
860     ref_type keytype;		/* result not needed here */
861     iparam_list *const pilist = (iparam_list *) plist;
862 
863     return (*pilist->enumerate) (pilist, penum, key, &keytype);
864 }
865 
866 /* ---------------- Internal routines ---------------- */
867 
868 /* Read a string value. */
869 private int
ref_param_read_string_value(const gs_memory_t * mem,const iparam_loc * ploc,gs_param_string * pvalue)870 ref_param_read_string_value(const gs_memory_t *mem, const iparam_loc * ploc, gs_param_string * pvalue)
871 {
872     const ref *pref = ploc->pvalue;
873 
874     switch (r_type(pref)) {
875 	case t_name: {
876 	    ref nref;
877 
878 	    name_string_ref(mem, pref, &nref);
879 	    pvalue->data = nref.value.const_bytes;
880 	    pvalue->size = r_size(&nref);
881 	    pvalue->persistent = true;
882 	}
883 	    break;
884 	case t_string:
885 	    iparam_check_read(*ploc);
886 	    pvalue->data = pref->value.const_bytes;
887 	    pvalue->size = r_size(pref);
888 	    pvalue->persistent = false;
889 	    break;
890 	default:
891 	    return iparam_note_error(*ploc, e_typecheck);
892     }
893     return 0;
894 }
895 
896 /* Read an array (or packed array) parameter. */
897 private int
ref_param_read_array(iparam_list * plist,gs_param_name pkey,iparam_loc * ploc)898 ref_param_read_array(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc)
899 {
900     int code = ref_param_read(plist, pkey, ploc, -1);
901 
902     if (code != 0)
903 	return code;
904     if (!r_is_array(ploc->pvalue))
905 	return iparam_note_error(*ploc, e_typecheck);
906     iparam_check_read(*ploc);
907     return 0;
908 }
909 
910 /* Generic routine for reading a ref parameter. */
911 private int
ref_param_read(iparam_list * plist,gs_param_name pkey,iparam_loc * ploc,int type)912 ref_param_read(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc,
913 	       int type)
914 {
915     iparam_list *const iplist = (iparam_list *) plist;
916     ref kref;
917     int code = ref_param_key(plist, pkey, &kref);
918 
919     if (code < 0)
920 	return code;
921     code = (*plist->u.r.read) (iplist, &kref, ploc);
922     if (code != 0)
923 	return code;
924     if (type >= 0)
925 	iparam_check_type(*ploc, type);
926     return 0;
927 }
928 
929 /* ---------------- Implementations ---------------- */
930 
931 /* Implementation for putting parameters from an empty collection. */
932 private int
empty_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)933 empty_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
934 {
935     return 1;
936 }
937 
938 /* Initialize for reading parameters. */
939 private int
ref_param_read_init(iparam_list * plist,uint count,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)940 ref_param_read_init(iparam_list * plist, uint count, const ref * ppolicies,
941 		    bool require_all, gs_ref_memory_t *imem)
942 {
943     gs_param_list_init((gs_param_list *)plist, &ref_read_procs,
944 		       (gs_memory_t *)imem);
945     plist->ref_memory = imem;
946     if (ppolicies == 0)
947 	make_null(&plist->u.r.policies);
948     else
949 	plist->u.r.policies = *ppolicies;
950     plist->u.r.require_all = require_all;
951     plist->count = count;
952     plist->results = (int *)
953 	gs_alloc_byte_array(plist->memory, count, sizeof(int),
954 			    "ref_param_read_init");
955 
956     if (plist->results == 0)
957 	return_error(e_VMerror);
958     memset(plist->results, 0, count * sizeof(int));
959 
960     plist->int_keys = false;
961     return 0;
962 }
963 
964 /* Implementation for putting parameters from an indexed array. */
965 private int
array_indexed_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)966 array_indexed_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
967 {
968     ref *const arr = &((dict_param_list *) plist)->dict;
969 
970     check_type(*pkey, t_integer);
971     if (pkey->value.intval < 0 || pkey->value.intval >= r_size(arr))
972 	return 1;
973     ploc->pvalue = arr->value.refs + pkey->value.intval;
974     ploc->presult = &plist->results[pkey->value.intval];
975     *ploc->presult = 1;
976     return 0;
977 }
978 int
array_indexed_param_list_read(dict_param_list * plist,const ref * parray,const ref * ppolicies,bool require_all,gs_ref_memory_t * ref_memory)979 array_indexed_param_list_read(dict_param_list * plist, const ref * parray,
980 			      const ref * ppolicies, bool require_all,
981 			      gs_ref_memory_t *ref_memory)
982 {
983     iparam_list *const iplist = (iparam_list *) plist;
984     int code;
985 
986     check_read_type(*parray, t_array);
987     plist->u.r.read = array_indexed_param_read;
988     plist->dict = *parray;
989     code = ref_param_read_init(iplist, r_size(parray), ppolicies,
990 			       require_all, ref_memory);
991     plist->int_keys = true;
992     return code;
993 }
994 
995 /* Implementation for putting parameters from an array. */
996 private int
array_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)997 array_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
998 {
999     ref *bot = ((array_param_list *) plist)->bot;
1000     ref *ptr = bot;
1001     ref *top = ((array_param_list *) plist)->top;
1002 
1003     for (; ptr < top; ptr += 2) {
1004 	if (r_has_type(ptr, t_name) && name_eq(ptr, pkey)) {
1005 	    ploc->pvalue = ptr + 1;
1006 	    ploc->presult = &plist->results[ptr - bot];
1007 	    *ploc->presult = 1;
1008 	    return 0;
1009 	}
1010     }
1011     return 1;
1012 }
1013 
1014 /* Implementation for enumerating parameters in an array */
1015 private int			/* ret 0 ok, 1 if EOF, or -ve err */
array_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)1016 array_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
1017 		      gs_param_key_t * key, ref_type * type)
1018 {
1019     int index = penum->intval;
1020     ref *bot = ((array_param_list *) plist)->bot;
1021     ref *ptr = bot + index;
1022     ref *top = ((array_param_list *) plist)->top;
1023 
1024     for (; ptr < top; ptr += 2) {
1025 	index += 2;
1026 
1027 	if (r_has_type(ptr, t_name)) {
1028 	    int code = ref_to_key(ptr, key, plist);
1029 
1030 	    *type = r_type(ptr);
1031 	    penum->intval = index;
1032 	    return code;
1033 	}
1034     }
1035     return 1;
1036 }
1037 
1038 int
array_param_list_read(array_param_list * plist,ref * bot,uint count,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1039 array_param_list_read(array_param_list * plist, ref * bot, uint count,
1040 		      const ref * ppolicies, bool require_all,
1041 		      gs_ref_memory_t *imem)
1042 {
1043     iparam_list *const iplist = (iparam_list *) plist;
1044 
1045     if (count & 1)
1046 	return_error(e_rangecheck);
1047     plist->u.r.read = array_param_read;
1048     plist->enumerate = array_param_enumerate;
1049     plist->bot = bot;
1050     plist->top = bot + count;
1051     return ref_param_read_init(iplist, count, ppolicies, require_all, imem);
1052 }
1053 
1054 /* Implementation for putting parameters from a stack. */
1055 private int
stack_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)1056 stack_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
1057 {
1058     stack_param_list *const splist = (stack_param_list *) plist;
1059     ref_stack_t *pstack = splist->pstack;
1060 
1061     /* This implementation is slow, but it probably doesn't matter. */
1062     uint index = splist->skip + 1;
1063     uint count = splist->count;
1064 
1065     for (; count; count--, index += 2) {
1066 	const ref *p = ref_stack_index(pstack, index);
1067 
1068 	if (r_has_type(p, t_name) && name_eq(p, pkey)) {
1069 	    ploc->pvalue = ref_stack_index(pstack, index - 1);
1070 	    ploc->presult = &plist->results[count - 1];
1071 	    *ploc->presult = 1;
1072 	    return 0;
1073 	}
1074     }
1075     return 1;
1076 }
1077 int
stack_param_list_read(stack_param_list * plist,ref_stack_t * pstack,uint skip,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1078 stack_param_list_read(stack_param_list * plist, ref_stack_t * pstack,
1079 		      uint skip, const ref * ppolicies, bool require_all,
1080 		      gs_ref_memory_t *imem)
1081 {
1082     iparam_list *const iplist = (iparam_list *) plist;
1083     uint count = ref_stack_counttomark(pstack);
1084 
1085     if (count == 0)
1086 	return_error(e_unmatchedmark);
1087     count -= skip + 1;
1088     if (count & 1)
1089 	return_error(e_rangecheck);
1090     plist->u.r.read = stack_param_read;
1091     plist->enumerate = stack_param_enumerate;
1092     plist->pstack = pstack;
1093     plist->skip = skip;
1094     return ref_param_read_init(iplist, count >> 1, ppolicies, require_all, imem);
1095 }
1096 
1097 /* Implementation for putting parameters from a dictionary. */
1098 private int
dict_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)1099 dict_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
1100 {
1101     ref const *spdict = &((dict_param_list *) plist)->dict;
1102     int code = dict_find(spdict, pkey, &ploc->pvalue);
1103 
1104     if (code != 1)
1105 	return 1;
1106     ploc->presult =
1107 	&plist->results[dict_value_index(spdict, ploc->pvalue)];
1108     *ploc->presult = 1;
1109     return 0;
1110 }
1111 int
dict_param_list_read(dict_param_list * plist,const ref * pdict,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1112 dict_param_list_read(dict_param_list * plist, const ref * pdict,
1113 		     const ref * ppolicies, bool require_all,
1114 		     gs_ref_memory_t *imem)
1115 {
1116     iparam_list *const iplist = (iparam_list *) plist;
1117     uint count;
1118 
1119     if (pdict == 0) {
1120 	plist->u.r.read = empty_param_read;
1121 	count = 0;
1122     } else {
1123 	check_dict_read(*pdict);
1124 	plist->u.r.read = dict_param_read;
1125 	plist->dict = *pdict;
1126 	count = dict_max_index(pdict) + 1;
1127     }
1128     plist->enumerate = dict_param_enumerate;
1129     return ref_param_read_init(iplist, count, ppolicies, require_all, imem);
1130 }
1131