xref: /plan9/sys/src/cmd/gs/src/gsparam.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 1998, 1999 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: gsparam.c,v 1.7 2002/10/07 08:28:56 ghostgum Exp $ */
18 /* Support for parameter lists */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsparam.h"
24 #include "gsstruct.h"
25 
26 /* GC procedures */
27 ENUM_PTRS_WITH(gs_param_typed_value_enum_ptrs, gs_param_typed_value *pvalue) return 0;
28     case 0:
29     switch (pvalue->type) {
30     case gs_param_type_string:
31 	return ENUM_STRING(&pvalue->value.s);
32     case gs_param_type_name:
33 	return ENUM_STRING(&pvalue->value.n);
34     case gs_param_type_int_array:
35 	return ENUM_OBJ(pvalue->value.ia.data);
36     case gs_param_type_float_array:
37 	return ENUM_OBJ(pvalue->value.fa.data);
38     case gs_param_type_string_array:
39 	return ENUM_OBJ(pvalue->value.sa.data);
40     case gs_param_type_name_array:
41 	return ENUM_OBJ(pvalue->value.na.data);
42     default:
43 	return ENUM_OBJ(0);	/* don't stop early */
44     }
45 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_param_typed_value_reloc_ptrs,gs_param_typed_value * pvalue)46 RELOC_PTRS_WITH(gs_param_typed_value_reloc_ptrs, gs_param_typed_value *pvalue) {
47     switch (pvalue->type) {
48     case gs_param_type_string:
49     case gs_param_type_name: {
50 	gs_const_string str;
51 
52 	str.data = pvalue->value.s.data; /* n == s */
53 	str.size = pvalue->value.s.size;
54 	RELOC_CONST_STRING_VAR(str);
55 	pvalue->value.s.data = str.data;
56 	break;
57     }
58     case gs_param_type_int_array:
59 	RELOC_VAR(pvalue->value.ia.data);
60 	break;
61     case gs_param_type_float_array:
62 	RELOC_VAR(pvalue->value.fa.data);
63 	break;
64     case gs_param_type_string_array:
65 	RELOC_VAR(pvalue->value.sa.data);
66 	break;
67     case gs_param_type_name_array:
68 	RELOC_VAR(pvalue->value.na.data);
69 	break;
70     default:
71 	break;
72     }
73 }
74 RELOC_PTRS_END
75 
76 /* Internal procedure to initialize the common part of a parameter list. */
77 void
gs_param_list_init(gs_param_list * plist,const gs_param_list_procs * procs,gs_memory_t * mem)78 gs_param_list_init(gs_param_list *plist, const gs_param_list_procs *procs,
79 		   gs_memory_t *mem)
80 {
81     plist->procs = procs;
82     plist->memory = mem;
83     plist->persistent_keys = true;
84 }
85 
86 /* Set whether the keys for param_write_XXX are persistent. */
87 void
gs_param_list_set_persistent_keys(gs_param_list * plist,bool persistent)88 gs_param_list_set_persistent_keys(gs_param_list *plist, bool persistent)
89 {
90     plist->persistent_keys = persistent;
91 }
92 
93 /* Reset a gs_param_key_t enumerator to its initial state */
94 void
param_init_enumerator(gs_param_enumerator_t * enumerator)95 param_init_enumerator(gs_param_enumerator_t * enumerator)
96 {
97     memset(enumerator, 0, sizeof(*enumerator));
98 }
99 
100 /* Transfer a collection of parameters. */
101 private const byte xfer_item_sizes[] = {
102     GS_PARAM_TYPE_SIZES(0)
103 };
104 int
gs_param_read_items(gs_param_list * plist,void * obj,const gs_param_item_t * items)105 gs_param_read_items(gs_param_list * plist, void *obj,
106 		    const gs_param_item_t * items)
107 {
108     const gs_param_item_t *pi;
109     int ecode = 0;
110 
111     for (pi = items; pi->key != 0; ++pi) {
112 	const char *key = pi->key;
113 	void *pvalue = (void *)((char *)obj + pi->offset);
114 	gs_param_typed_value typed;
115 	int code;
116 
117 	typed.type = pi->type;
118 	code = param_read_requested_typed(plist, key, &typed);
119 	switch (code) {
120 	    default:		/* < 0 */
121 		ecode = code;
122 	    case 1:
123 		break;
124 	    case 0:
125 		if (typed.type != pi->type)	/* shouldn't happen! */
126 		    ecode = gs_note_error(gs_error_typecheck);
127 		else
128 		    memcpy(pvalue, &typed.value, xfer_item_sizes[pi->type]);
129 	}
130     }
131     return ecode;
132 }
133 int
gs_param_write_items(gs_param_list * plist,const void * obj,const void * default_obj,const gs_param_item_t * items)134 gs_param_write_items(gs_param_list * plist, const void *obj,
135 		     const void *default_obj, const gs_param_item_t * items)
136 {
137     const gs_param_item_t *pi;
138     int ecode = 0;
139 
140     for (pi = items; pi->key != 0; ++pi) {
141 	const char *key = pi->key;
142 	const void *pvalue = (const void *)((const char *)obj + pi->offset);
143 	int size = xfer_item_sizes[pi->type];
144 	gs_param_typed_value typed;
145 	int code;
146 
147 	if (default_obj != 0 &&
148 	    !memcmp((const void *)((const char *)default_obj + pi->offset),
149 		    pvalue, size)
150 	    )
151 	    continue;
152 	memcpy(&typed.value, pvalue, size);
153 	typed.type = pi->type;
154 	code = (*plist->procs->xmit_typed) (plist, key, &typed);
155 	if (code < 0)
156 	    ecode = code;
157     }
158     return ecode;
159 }
160 
161 /* Read a value, with coercion if requested, needed, and possible. */
162 /* If mem != 0, we can coerce int arrays to float arrays. */
163 int
param_coerce_typed(gs_param_typed_value * pvalue,gs_param_type req_type,gs_memory_t * mem)164 param_coerce_typed(gs_param_typed_value * pvalue, gs_param_type req_type,
165 		   gs_memory_t * mem)
166 {
167     if (req_type == gs_param_type_any || pvalue->type == req_type)
168 	return 0;
169     /*
170      * Look for coercion opportunities.  It would be wonderful if we
171      * could convert int/float arrays and name/string arrays, but
172      * right now we can't.  However, a 0-length heterogenous array
173      * will satisfy a request for any specific type.
174      */
175     switch (pvalue->type /* actual type */ ) {
176 	case gs_param_type_int:
177 	    switch (req_type) {
178 		case gs_param_type_long:
179 		    pvalue->value.l = pvalue->value.i;
180 		    goto ok;
181 		case gs_param_type_float:
182 		    pvalue->value.f = (float)pvalue->value.l;
183 		    goto ok;
184 		default:
185 		    break;
186 	    }
187 	    break;
188 	case gs_param_type_long:
189 	    switch (req_type) {
190 		case gs_param_type_int:
191 #if arch_sizeof_int < arch_sizeof_long
192 		    if (pvalue->value.l != (int)pvalue->value.l)
193 			return_error(gs_error_rangecheck);
194 #endif
195 		    pvalue->value.i = (int)pvalue->value.l;
196 		    goto ok;
197 		case gs_param_type_float:
198 		    pvalue->value.f = (float)pvalue->value.l;
199 		    goto ok;
200 		default:
201 		    break;
202 	    }
203 	    break;
204 	case gs_param_type_string:
205 	    if (req_type == gs_param_type_name)
206 		goto ok;
207 	    break;
208 	case gs_param_type_name:
209 	    if (req_type == gs_param_type_string)
210 		goto ok;
211 	    break;
212 	case gs_param_type_int_array:
213 	    switch (req_type) {
214 		case gs_param_type_float_array:{
215 			uint size = pvalue->value.ia.size;
216 			float *fv;
217 			uint i;
218 
219 			if (mem == 0)
220 			    break;
221 			fv = (float *)gs_alloc_byte_array(mem, size, sizeof(float),
222 						"int array => float array");
223 
224 			if (fv == 0)
225 			    return_error(gs_error_VMerror);
226 			for (i = 0; i < size; ++i)
227 			    fv[i] = (float)pvalue->value.ia.data[i];
228 			pvalue->value.fa.data = fv;
229 			pvalue->value.fa.persistent = false;
230 			goto ok;
231 		    }
232 		default:
233 		    break;
234 	    }
235 	    break;
236 	case gs_param_type_string_array:
237 	    if (req_type == gs_param_type_name_array)
238 		goto ok;
239 	    break;
240 	case gs_param_type_name_array:
241 	    if (req_type == gs_param_type_string_array)
242 		goto ok;
243 	    break;
244 	case gs_param_type_array:
245 	    if (pvalue->value.d.size == 0 &&
246 		(req_type == gs_param_type_int_array ||
247 		 req_type == gs_param_type_float_array ||
248 		 req_type == gs_param_type_string_array ||
249 		 req_type == gs_param_type_name_array)
250 		)
251 		goto ok;
252 	    break;
253 	default:
254 	    break;
255     }
256     return_error(gs_error_typecheck);
257   ok:pvalue->type = req_type;
258     return 0;
259 }
260 int
param_read_requested_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)261 param_read_requested_typed(gs_param_list * plist, gs_param_name pkey,
262 			   gs_param_typed_value * pvalue)
263 {
264     gs_param_type req_type = pvalue->type;
265     int code = (*plist->procs->xmit_typed) (plist, pkey, pvalue);
266 
267     if (code != 0)
268 	return code;
269     return param_coerce_typed(pvalue, req_type, plist->memory);
270 }
271 
272 
273 /* ---------------- Fixed-type reading procedures ---------------- */
274 
275 #define RETURN_READ_TYPED(alt, ptype)\
276   gs_param_typed_value typed;\
277   int code;\
278 \
279   typed.type = ptype;\
280   code = param_read_requested_typed(plist, pkey, &typed);\
281   if ( code == 0 )\
282     *pvalue = typed.value.alt;\
283   return code
284 
285 int
param_read_null(gs_param_list * plist,gs_param_name pkey)286 param_read_null(gs_param_list * plist, gs_param_name pkey)
287 {
288     gs_param_typed_value typed;
289 
290     typed.type = gs_param_type_null;
291     return param_read_requested_typed(plist, pkey, &typed);
292 }
293 int
param_read_bool(gs_param_list * plist,gs_param_name pkey,bool * pvalue)294 param_read_bool(gs_param_list * plist, gs_param_name pkey, bool * pvalue)
295 {
296     RETURN_READ_TYPED(b, gs_param_type_bool);
297 }
298 int
param_read_int(gs_param_list * plist,gs_param_name pkey,int * pvalue)299 param_read_int(gs_param_list * plist, gs_param_name pkey, int *pvalue)
300 {
301     RETURN_READ_TYPED(i, gs_param_type_int);
302 }
303 int
param_read_long(gs_param_list * plist,gs_param_name pkey,long * pvalue)304 param_read_long(gs_param_list * plist, gs_param_name pkey, long *pvalue)
305 {
306     RETURN_READ_TYPED(l, gs_param_type_long);
307 }
308 int
param_read_float(gs_param_list * plist,gs_param_name pkey,float * pvalue)309 param_read_float(gs_param_list * plist, gs_param_name pkey, float *pvalue)
310 {
311     RETURN_READ_TYPED(f, gs_param_type_float);
312 }
313 int
param_read_string(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)314 param_read_string(gs_param_list * plist, gs_param_name pkey,
315 		  gs_param_string * pvalue)
316 {
317     RETURN_READ_TYPED(s, gs_param_type_string);
318 }
319 int
param_read_name(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)320 param_read_name(gs_param_list * plist, gs_param_name pkey,
321 		gs_param_string * pvalue)
322 {
323     RETURN_READ_TYPED(n, gs_param_type_string);
324 }
325 int
param_read_int_array(gs_param_list * plist,gs_param_name pkey,gs_param_int_array * pvalue)326 param_read_int_array(gs_param_list * plist, gs_param_name pkey,
327 		     gs_param_int_array * pvalue)
328 {
329     RETURN_READ_TYPED(ia, gs_param_type_int_array);
330 }
331 int
param_read_float_array(gs_param_list * plist,gs_param_name pkey,gs_param_float_array * pvalue)332 param_read_float_array(gs_param_list * plist, gs_param_name pkey,
333 		       gs_param_float_array * pvalue)
334 {
335     RETURN_READ_TYPED(fa, gs_param_type_float_array);
336 }
337 int
param_read_string_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)338 param_read_string_array(gs_param_list * plist, gs_param_name pkey,
339 			gs_param_string_array * pvalue)
340 {
341     RETURN_READ_TYPED(sa, gs_param_type_string_array);
342 }
343 int
param_read_name_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)344 param_read_name_array(gs_param_list * plist, gs_param_name pkey,
345 		      gs_param_string_array * pvalue)
346 {
347     RETURN_READ_TYPED(na, gs_param_type_name_array);
348 }
349 
350 #undef RETURN_READ_TYPED
351 
352 /* ---------------- Default writing procedures ---------------- */
353 
354 #define RETURN_WRITE_TYPED(alt, ptype)\
355   gs_param_typed_value typed;\
356 \
357   typed.value.alt = *pvalue;\
358   typed.type = ptype;\
359   return param_write_typed(plist, pkey, &typed)
360 
361 int
param_write_null(gs_param_list * plist,gs_param_name pkey)362 param_write_null(gs_param_list * plist, gs_param_name pkey)
363 {
364     gs_param_typed_value typed;
365 
366     typed.type = gs_param_type_null;
367     return param_write_typed(plist, pkey, &typed);
368 }
369 int
param_write_bool(gs_param_list * plist,gs_param_name pkey,const bool * pvalue)370 param_write_bool(gs_param_list * plist, gs_param_name pkey, const bool * pvalue)
371 {
372     RETURN_WRITE_TYPED(b, gs_param_type_bool);
373 }
374 int
param_write_int(gs_param_list * plist,gs_param_name pkey,const int * pvalue)375 param_write_int(gs_param_list * plist, gs_param_name pkey, const int *pvalue)
376 {
377     RETURN_WRITE_TYPED(i, gs_param_type_int);
378 }
379 int
param_write_long(gs_param_list * plist,gs_param_name pkey,const long * pvalue)380 param_write_long(gs_param_list * plist, gs_param_name pkey, const long *pvalue)
381 {
382     RETURN_WRITE_TYPED(l, gs_param_type_long);
383 }
384 int
param_write_float(gs_param_list * plist,gs_param_name pkey,const float * pvalue)385 param_write_float(gs_param_list * plist, gs_param_name pkey,
386 		  const float *pvalue)
387 {
388     RETURN_WRITE_TYPED(f, gs_param_type_float);
389 }
390 int
param_write_string(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)391 param_write_string(gs_param_list * plist, gs_param_name pkey,
392 		   const gs_param_string * pvalue)
393 {
394     RETURN_WRITE_TYPED(s, gs_param_type_string);
395 }
396 int
param_write_name(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)397 param_write_name(gs_param_list * plist, gs_param_name pkey,
398 		 const gs_param_string * pvalue)
399 {
400     RETURN_WRITE_TYPED(n, gs_param_type_name);
401 }
402 int
param_write_int_array(gs_param_list * plist,gs_param_name pkey,const gs_param_int_array * pvalue)403 param_write_int_array(gs_param_list * plist, gs_param_name pkey,
404 		      const gs_param_int_array * pvalue)
405 {
406     RETURN_WRITE_TYPED(ia, gs_param_type_int_array);
407 }
408 int
param_write_int_values(gs_param_list * plist,gs_param_name pkey,const int * values,uint size,bool persistent)409 param_write_int_values(gs_param_list * plist, gs_param_name pkey,
410 		       const int *values, uint size, bool persistent)
411 {
412     gs_param_int_array ia;
413 
414     ia.data = values, ia.size = size, ia.persistent = persistent;
415     return param_write_int_array(plist, pkey, &ia);
416 }
417 int
param_write_float_array(gs_param_list * plist,gs_param_name pkey,const gs_param_float_array * pvalue)418 param_write_float_array(gs_param_list * plist, gs_param_name pkey,
419 			const gs_param_float_array * pvalue)
420 {
421     RETURN_WRITE_TYPED(fa, gs_param_type_float_array);
422 }
423 int
param_write_float_values(gs_param_list * plist,gs_param_name pkey,const float * values,uint size,bool persistent)424 param_write_float_values(gs_param_list * plist, gs_param_name pkey,
425 			 const float *values, uint size, bool persistent)
426 {
427     gs_param_float_array fa;
428 
429     fa.data = values, fa.size = size, fa.persistent = persistent;
430     return param_write_float_array(plist, pkey, &fa);
431 }
432 int
param_write_string_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)433 param_write_string_array(gs_param_list * plist, gs_param_name pkey,
434 			 const gs_param_string_array * pvalue)
435 {
436     RETURN_WRITE_TYPED(sa, gs_param_type_string_array);
437 }
438 int
param_write_name_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)439 param_write_name_array(gs_param_list * plist, gs_param_name pkey,
440 		       const gs_param_string_array * pvalue)
441 {
442     RETURN_WRITE_TYPED(na, gs_param_type_name_array);
443 }
444 
445 #undef RETURN_WRITE_TYPED
446 
447 /* ---------------- Default request implementation ---------------- */
448 
449 int
gs_param_request_default(gs_param_list * plist,gs_param_name pkey)450 gs_param_request_default(gs_param_list * plist, gs_param_name pkey)
451 {
452     return 0;
453 }
454 
455 int
gs_param_requested_default(const gs_param_list * plist,gs_param_name pkey)456 gs_param_requested_default(const gs_param_list * plist, gs_param_name pkey)
457 {
458     return -1;			/* requested by default */
459 }
460