Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 */
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
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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 */
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
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
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
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
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
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
}