xref: /plan9/sys/src/cmd/gs/src/gsparam.h (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: gsparam.h,v 1.13 2005/09/05 13:58:55 leonardo Exp $ */
18 /* Client interface to parameter dictionaries */
19 
20 #ifndef gsparam_INCLUDED
21 #  define gsparam_INCLUDED
22 
23 #include "gsstype.h"
24 
25 /*
26  * Several interfaces use parameter dictionaries to communicate sets of
27  * (key, value) pairs between a client and an object with complex state.
28  * (Several of these correspond directly to similar interfaces in the
29  * PostScript language.) This file defines the API for parameter dictionaries.
30  */
31 
32 /* ---------------- Generic interfaces ---------------- */
33 
34 /* Define the abstract type for a parameter list. */
35 #ifndef gs_param_list_DEFINED
36 #  define gs_param_list_DEFINED
37 typedef struct gs_param_list_s gs_param_list;
38 #endif
39 
40 /* Define the type for a parameter key name. */
41 typedef const char *gs_param_name;
42 
43 /*
44  * Parameter values fall into three categories:
45  *      - Scalar (null, Boolean, int, long, float);
46  *      - Homogenous collection (string/name, int array, float array,
47  *      string/name array);
48  *      - Heterogenous collection (dictionary, int-keyed dictionary, array).
49  * Each category has its own representation and memory management issues.
50  */
51 typedef enum {
52     /* Scalar */
53     gs_param_type_null, gs_param_type_bool, gs_param_type_int,
54     gs_param_type_long, gs_param_type_float,
55     /* Homogenous collection */
56     gs_param_type_string, gs_param_type_name,
57     gs_param_type_int_array, gs_param_type_float_array,
58     gs_param_type_string_array, gs_param_type_name_array,
59     /* Heterogenous collection */
60     gs_param_type_dict, gs_param_type_dict_int_keys, gs_param_type_array
61 } gs_param_type;
62 
63 /* Define a "don't care" type for reading typed values. */
64 #define gs_param_type_any ((gs_param_type)-1)
65 
66 /*
67  * Define the structures for homogenous collection values
68  * (string/name, integer array, or floating point array).
69  * The size is the number of elements, not the size in bytes.
70  * A value is persistent if it is defined as static const,
71  * or if it is allocated in garbage-collectable space and never freed.
72  */
73 
74 #define _param_array_struct(sname,etype)\
75   struct sname { const etype *data; uint size; bool persistent; }
76 typedef _param_array_struct(gs_param_int_array_s, int) gs_param_int_array;
77 typedef _param_array_struct(gs_param_float_array_s, float) gs_param_float_array;
78 typedef _param_array_struct(gs_param_string_array_s, gs_param_string) gs_param_string_array;
79 
80 #define param_string_from_string(ps, str)\
81   ((ps).data = (const byte *)(str),\
82    (ps).size = strlen((const char *)(ps).data),\
83    (ps).persistent = true)
84 
85 #define param_string_from_transient_string(ps, str)\
86   ((ps).data = (const byte *)(str),\
87    (ps).size = strlen((const char *)(ps).data),\
88    (ps).persistent = false)
89 
90 /*
91  * Define the structure for heterogenous collection values (dictionaries
92  * and heterogenous arrays).
93  */
94 typedef struct gs_param_collection_s {
95     gs_param_list *list;
96     uint size;
97 } gs_param_collection;
98 typedef gs_param_collection gs_param_dict;
99 typedef gs_param_collection gs_param_array;
100 
101 /*
102  * Define the sizes of the various parameter value types, indexed by type.
103  */
104 #define GS_PARAM_TYPE_SIZES(dict_size)\
105   0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
106   sizeof(gs_param_string), sizeof(gs_param_string),\
107   sizeof(gs_param_int_array), sizeof(gs_param_float_array),\
108   sizeof(gs_param_string_array), sizeof(gs_param_string_array),\
109   (dict_size), (dict_size), (dict_size)
110 /*
111  * Define the sizes of the underlying data types contained in or pointed
112  * to by the various value types.
113  */
114 #define GS_PARAM_TYPE_BASE_SIZES(dict_elt_size)\
115   0, sizeof(bool), sizeof(int), sizeof(long), sizeof(float),\
116   1, 1, sizeof(int), sizeof(float),\
117   sizeof(gs_param_string), sizeof(gs_param_string),\
118   (dict_elt_size), (dict_elt_size), (dict_elt_size)
119 
120 /* Define tables with 0 for the sizes of the heterogenous collections. */
121 extern const byte gs_param_type_sizes[];
122 extern const byte gs_param_type_base_sizes[];
123 
124 /* Define a union capable of holding any parameter value. */
125 #define GS_PARAM_VALUE_UNION(dict_type)\
126 	bool b;\
127 	int i;\
128 	long l;\
129 	float f;\
130 	gs_param_string s;\
131 	gs_param_string n;\
132 	gs_param_int_array ia;\
133 	gs_param_float_array fa;\
134 	gs_param_string_array sa;\
135 	gs_param_string_array na;\
136 	dict_type d
137 typedef union gs_param_value_s {
138     GS_PARAM_VALUE_UNION(gs_param_collection);
139 } gs_param_value;
140 
141 /*
142  * Define a structure containing a dynamically typed value (a value along
143  * with its type).
144  */
145 typedef struct gs_param_typed_value_s {
146     gs_param_value value;
147     gs_param_type type;
148 } gs_param_typed_value;
149 /*
150  * Garbage collection of gs_param_values depends on the value type and on
151  * the 'd' member of the union.  We provide enum_ptrs and reloc_ptrs
152  * procedures that handle all the other cases -- i.e., cases other than
153  * heterogenous collections.
154  */
155 struct_proc_enum_ptrs(gs_param_typed_value_enum_ptrs);
156 struct_proc_reloc_ptrs(gs_param_typed_value_reloc_ptrs);
157 #define gs_param_typed_value_max_ptrs 1
158 
159 /*
160  * Define the representation alternatives for heterogenous collections.
161  * _any must be 0, for Boolean testing.
162  */
163 typedef enum {
164 
165     /* Create or accept a general dictionary. */
166 
167     gs_param_collection_dict_any = 0,
168 
169     /* Create a dictionary with integer string keys ("0", "1", ...); */
170     /* accept a dictionary with integer string keys, or a heterogenous */
171     /* array. */
172 
173     gs_param_collection_dict_int_keys = 1,
174 
175     /* Create an array if possible, otherwise a dictionary with integer */
176     /* string keys; accept the same types as dict_int_keys. */
177 
178     gs_param_collection_array = 2
179 
180 } gs_param_collection_type_t;
181 
182 /*
183  * Define the 'policies' for handling out-of-range parameter values.
184  * This is not an enum, because some parameters may recognize other values.
185  */
186 #define gs_param_policy_signal_error 0
187 #define gs_param_policy_ignore 1
188 #define gs_param_policy_consult_user 2
189 
190 /*
191  * Define an enumerator used to iterate through the keys in a list.
192  *
193  * All the members of the union must be used such that memset(0) entire
194  * union means 'beginning of enumeration'.
195  */
196 typedef union gs_param_enumerator_s {
197     int intval;
198     long longval;
199     void *pvoid;
200     char *pchar;
201 } gs_param_enumerator_t;
202 typedef gs_param_string gs_param_key_t;
203 
204 /*
205  * Define the object procedures.  Note that the same interface is used
206  * both for getting and for setting parameter values.  (This is a bit
207  * of a hack, and we might change it someday.)  The procedures return
208  * as follows:
209  *      - 'reading' procedures ('put' operations from the client's viewpoint)
210  * return 1 for a missing parameter, 0 for a valid parameter, <0 on error.
211  *      - 'writing' procedures ('get' operations from the client's viewpoint)
212  * return 0 or 1 if successful, <0 on error.
213  *
214  * A lazy implementation can use the default procedures for scalar and
215  * homogenous collection types: these just called xmit_typed.
216  */
217 
218 /*
219  * Transmitting variable-size objects requires some extra care.
220  *      - When writing an array, string, name, or dictionary, the
221  * implementation (not the client) sets all the fields of the value.
222  *      - When reading an array, string, or name, the client must set
223  * all the fields of the value.
224  *      - When reading a dictionary, the client must set the size field
225  * before calling begin_write_dict; the implementation of begin_write_dict
226  * allocates the list.
227  */
228 
229 /*
230  * Setting parameters must use a "two-phase commit" policy.  Specifically,
231  * any put_params procedure must observe the following discipline:
232 
233  1. For each parameter known to the device, ask the parameter list if
234  there is a new value, and if so, make all necessary validity checks.  If any
235  check fails, call param_signal_error for that parameter, but continue to
236  check further parameters.  Normally, this step should not alter the state of
237  the device; however, if the device allows changing any parameters that are
238  read-only by default (for example, BitsPerPixel or ProcessColorModel), or if
239  it replaces the default put_params behavior for any parameter (for example,
240  if it handles MediaSize or Resolution itself to forestall the normal closing
241  of the device when these are set), step 1 of put_params must change the
242  parameters in the device state, and step 2 must undo the changes if
243  returning an error.
244 
245  2. Call the "superclass" put_params routine.  For printer devices,
246  this is gdev_prn_put_params; for other devices, it is gx_default_put_params.
247  Note that this must be done even if errors were detected in step 1.  If this
248  routine returns an error code, or if step 1 detected an error, undo any
249  changes that step 1 made in the device state, and return the error code.
250 
251  3. Install the new parameter values in the device.  If necessary,
252  close the device first; a higher-level routine (gs_putdeviceparams) will
253  reopen the device if necessary.
254 
255  */
256 
257 typedef struct gs_param_list_procs_s {
258 
259     /* Transmit a typed value. */
260     /*
261      * Note that read/write_typed do a begin_read/write_collection
262      * if the type is one of the heterogenous collection types.
263      * Note also that even for reading, the caller must set pvalue->type
264      * to the desired type or to gs_param_type_any.
265      */
266 
267 #define param_proc_xmit_typed(proc)\
268     int proc(gs_param_list *, gs_param_name, gs_param_typed_value *)
269 	 param_proc_xmit_typed((*xmit_typed));
270 	 /* See below for param_read_[requested_]typed */
271 #define param_write_typed(plist, pkey, pvalue)\
272 	 (*(plist)->procs->xmit_typed)(plist, pkey, pvalue)
273 
274 	 /* Start transmitting a dictionary or heterogenous value. */
275 
276 #define param_proc_begin_xmit_collection(proc)\
277 	 int proc(gs_param_list *, gs_param_name, gs_param_dict *,\
278 		     gs_param_collection_type_t)
279 	 param_proc_begin_xmit_collection((*begin_xmit_collection));
280 #define param_begin_read_collection(plist, pkey, pvalue, coll_type)\
281 	 (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type)
282 #define param_begin_read_dict(l, k, v, int_keys)\
283 	 param_begin_read_collection(l, k, v,\
284 				     (int_keys ? gs_param_collection_dict_int_keys :\
285 				      gs_param_collection_dict_any))
286 #define param_begin_write_collection(plist, pkey, pvalue, coll_type)\
287 	 (*(plist)->procs->begin_xmit_collection)(plist, pkey, pvalue, coll_type)
288 #define param_begin_write_dict(l, k, v, int_keys)\
289 	 param_begin_write_collection(l, k, v,\
290 				      (int_keys ? gs_param_collection_dict_int_keys :\
291 				       gs_param_collection_dict_any))
292 
293 	 /* Finish transmitting a collection value. */
294 
295 #define param_proc_end_xmit_collection(proc)\
296 	 int proc(gs_param_list *, gs_param_name, gs_param_dict *)
297 	 param_proc_end_xmit_collection((*end_xmit_collection));
298 #define param_end_read_collection(plist, pkey, pvalue)\
299 	 (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue)
300 #define param_end_read_dict(l, k, v) param_end_read_collection(l, k, v)
301 #define param_end_write_collection(plist, pkey, pvalue)\
302 	 (*(plist)->procs->end_xmit_collection)(plist, pkey, pvalue)
303 #define param_end_write_dict(l, k, v) param_end_write_collection(l, k, v)
304 
305 	 /*
306 	  * Get the next key in sequence.
307 	  * (Only used when reading.)
308 	  * Use param_init_enumerator(...) to reset to first key.
309 	  */
310 
311 #define param_proc_next_key(proc)\
312 	 int proc(gs_param_list *, gs_param_enumerator_t *, gs_param_key_t *)
313 	 param_proc_next_key((*next_key));
314 #define param_get_next_key(plist, penum, pkey)\
315 	 (*(plist)->procs->next_key)(plist, penum, pkey)
316 
317 	 /*
318 	  * Request a specific parameter. (Only used when writing, before
319 	  * writing any values.)  If no specific parameters are requested,
320 	  * param_requested always returns -1; if specific parameters
321 	  * are requested, param_requested will return 1 for those,
322 	  * and may return either 0 or 1 for others.
323 	  */
324 
325 #define param_proc_request(proc)\
326   int proc(gs_param_list *, gs_param_name)
327 	 param_proc_request((*request));
328 
329 #define param_request(plist, pkey)\
330   ((plist)->procs->request(plist, pkey))
331 
332 	 /*
333 	  * Determine whether a given key has been requested.  (Only used
334 	  * when writing.)  A return value of -1 means that no specific
335 	  * parameters have been requested; 0 means specific parameters have
336 	  * been requested, but not this one; 1 means this parameter has
337 	  * been requested specifically.
338 	  */
339 
340 #define param_proc_requested(proc)\
341 	 int proc(const gs_param_list *, gs_param_name)
342 	 param_proc_requested((*requested));
343 #define param_requested(plist, pkey)\
344 	 (*(plist)->procs->requested)(plist, pkey)
345 
346 	 /* Get the 'policy' associated with an out-of-range parameter value. */
347 	 /* (Only used when reading.) */
348 
349 #define param_proc_get_policy(proc)\
350 	 int proc(gs_param_list *, gs_param_name)
351 	 param_proc_get_policy((*get_policy));
352 #define param_get_policy(plist, pkey)\
353 	 (*(plist)->procs->get_policy)(plist, pkey)
354 
355 	 /*
356 	  * Signal an error.  (Only used when reading.)
357 	  * The procedure may return a different error code,
358 	  * or may return 0 indicating that the error is to be ignored.
359 	  */
360 
361 #define param_proc_signal_error(proc)\
362 	 int proc(gs_param_list *, gs_param_name, int)
363 	 param_proc_signal_error((*signal_error));
364 #define param_signal_error(plist, pkey, code)\
365 	 (*(plist)->procs->signal_error)(plist, pkey, code)
366 #define param_return_error(plist, pkey, code)\
367 	 return_error(param_signal_error(plist, pkey, code))
368 
369 	 /*
370 	  * "Commit" a set of changes.  (Only used when reading.)
371 	  * This is called at the end of the first phase.
372 	  */
373 
374 #define param_proc_commit(proc)\
375 	 int proc(gs_param_list *)
376 	 param_proc_commit((*commit));
377 #define param_commit(plist)\
378 	 (*(plist)->procs->commit)(plist)
379 
380 } gs_param_list_procs;
381 
382 /* Transmit typed parameters. */
383 int param_read_requested_typed(gs_param_list *, gs_param_name,
384 				  gs_param_typed_value *);
385 
386 #define param_read_typed(plist, pkey, pvalue)\
387   ((pvalue)->type = gs_param_type_any,\
388    param_read_requested_typed(plist, pkey, pvalue))
389 
390 /* Transmit parameters of specific types. */
391 int param_read_null(gs_param_list *, gs_param_name);
392 int param_write_null(gs_param_list *, gs_param_name);
393 int param_read_bool(gs_param_list *, gs_param_name, bool *);
394 int param_write_bool(gs_param_list *, gs_param_name, const bool *);
395 int param_read_int(gs_param_list *, gs_param_name, int *);
396 int param_write_int(gs_param_list *, gs_param_name, const int *);
397 int param_read_long(gs_param_list *, gs_param_name, long *);
398 int param_write_long(gs_param_list *, gs_param_name, const long *);
399 int param_read_float(gs_param_list *, gs_param_name, float *);
400 int param_write_float(gs_param_list *, gs_param_name, const float *);
401 int param_read_string(gs_param_list *, gs_param_name, gs_param_string *);
402 int param_write_string(gs_param_list *, gs_param_name,
403 		       const gs_param_string *);
404 int param_read_name(gs_param_list *, gs_param_name, gs_param_string *);
405 int param_write_name(gs_param_list *, gs_param_name,
406 		     const gs_param_string *);
407 int param_read_int_array(gs_param_list *, gs_param_name,
408 			 gs_param_int_array *);
409 int param_write_int_array(gs_param_list *, gs_param_name,
410 			  const gs_param_int_array *);
411 int param_write_int_values(gs_param_list *, gs_param_name,
412 			   const int *, uint, bool);
413 int param_read_float_array(gs_param_list *, gs_param_name,
414 			   gs_param_float_array *);
415 int param_write_float_array(gs_param_list *, gs_param_name,
416 			    const gs_param_float_array *);
417 int param_write_float_values(gs_param_list *, gs_param_name,
418 			     const float *, uint, bool);
419 int param_read_string_array(gs_param_list *, gs_param_name,
420 			    gs_param_string_array *);
421 int param_write_string_array(gs_param_list *, gs_param_name,
422 			     const gs_param_string_array *);
423 int param_read_name_array(gs_param_list *, gs_param_name,
424 			  gs_param_string_array *);
425 int param_write_name_array(gs_param_list *, gs_param_name,
426 			   const gs_param_string_array *);
427 
428 /*
429  * Define an abstract parameter list.  Implementations are concrete
430  * subclasses.
431  *
432  * The persisent_keys flag allows for both statically and dynamically
433  * allocated keys.  The default is static (the keys are normally C string
434  * literals).
435  */
436 #define gs_param_list_common\
437     const gs_param_list_procs *procs;\
438     gs_memory_t *memory;	/* for allocating coerced arrays */\
439     bool persistent_keys
440 struct gs_param_list_s {
441     gs_param_list_common;
442 };
443 
444 /* Set whether the keys for param_write_XXX are persistent. */
445 /* VMS limits procedure names to 31 characters. */
446 #define gs_param_list_set_persistent_keys gs_param_list_set_persist_keys
447 void gs_param_list_set_persistent_keys(gs_param_list *, bool);
448 
449 /* Initialize a parameter list key enumerator. */
450 void param_init_enumerator(gs_param_enumerator_t * penum);
451 
452 /*
453  * The following interface provides a convenient way to read and set
454  * collections of parameters of any type other than dictionaries.
455  */
456 
457 typedef struct gs_param_item_s {
458     const char *key;
459     byte /*gs_param_type */ type;
460     short offset;		/* offset of value in structure */
461 } gs_param_item_t;
462 #define gs_param_item_end { 0 }	/* list terminator */
463 /*
464  * Transfer a collection of parameters.
465  * For param_write_items, if a parameter value is equal to the value in
466  * the optional default_obj, the item isn't transferred.
467  */
468 int gs_param_read_items(gs_param_list * plist, void *obj,
469 			const gs_param_item_t * items);
470 int gs_param_write_items(gs_param_list * plist, const void *obj,
471 			 const void *default_obj,
472 			 const gs_param_item_t * items);
473 
474 /* Internal procedure to initialize the common part of a parameter list. */
475 void gs_param_list_init(gs_param_list *, const gs_param_list_procs *,
476 			gs_memory_t *);
477 
478 /*
479  * Internal procedure to read a value, with coercion if requested, needed,
480  * and possible.  If mem != 0, we can coerce int arrays to float arrays, and
481  * possibly do other coercions later.
482  */
483 int param_coerce_typed(gs_param_typed_value * pvalue,
484 		       gs_param_type req_type, gs_memory_t * mem);
485 
486 /* ---------------- Default implementation ---------------- */
487 
488 /*
489  * Provide default generic implementations of param_request and
490  * param_requested.
491  */
492 param_proc_request(gs_param_request_default);  /* does nothing */
493 param_proc_requested(gs_param_requested_default);  /* always returns true */
494 
495 /*
496  * Define a default implementation, intended to be usable easily
497  * from C code.  The intended usage pattern is:
498 	gs_c_param_list list;
499 	[... other code here ...]
500 	gs_c_param_list_write(&list, mem);
501 	[As many as needed:]
502 	code = param_write_XXX(&list, "ParamName", &param_value);
503 	[Check code for <0]
504 	gs_c_param_list_read(&list);
505 	code = gs_putdeviceparams(dev, &list);
506 	gs_c_param_list_release(&list);
507 	[Check code for <0]
508 	if ( code == 1 )
509 	{
510 	    code = (*dev_proc(dev, open_device))(dev);
511 	    [Check code for <0]
512 	}
513  *
514  * This implementation also has the special property that it can forward
515  * unrecognized param_read_ calls to another parameter list, called the
516  * target.  This allows constructing incrementally modified parameter lists.
517  * Note that this is only relevant for put_params (reading from the
518  * parameter list).
519  */
520 
521 typedef struct gs_c_param_s gs_c_param;	/* opaque here */
522 typedef struct gs_c_param_list_s {
523     gs_param_list_common;
524     gs_c_param *head;
525     gs_param_list *target;
526     uint count;
527     bool any_requested;
528     gs_param_collection_type_t coll_type;
529 } gs_c_param_list;
530 #define private_st_c_param_list()	/* in gsparam.c */\
531   gs_private_st_ptrs2(st_c_param_list, gs_c_param_list, "c_param_list",\
532     c_param_list_enum_ptrs, c_param_list_reloc_ptrs, head, target)
533 
534 /* Define a GC descriptor for gs_param_string. */
535 /* This structure descriptor is only for non persistent gs_param_strings. */
536 #define private_st_gs_param_string()	/* in gdevdevn.c */\
537   gs_private_st_composite(st_gs_param_string, gs_param_string, "gs_param_string",\
538 			param_string_enum_ptrs, param_string_reloc_ptrs)
539 
540 /* Set the target of a C parameter list. */
541 void gs_c_param_list_set_target(gs_c_param_list *, gs_param_list *);
542 
543 /*
544  * Clients normally allocate the gs_c_param_list on the stack, but we
545  * provide a procedure for allocating one in memory.
546  */
547 gs_c_param_list *gs_c_param_list_alloc(gs_memory_t *, client_name_t);
548 void gs_c_param_list_write(gs_c_param_list *, gs_memory_t *);
549 void gs_c_param_list_write_more(gs_c_param_list *); /* switch back to writing, no init */
550 void gs_c_param_list_read(gs_c_param_list *);	/* switch to reading */
551 void gs_c_param_list_release(gs_c_param_list *);
552 
553 #endif /* gsparam_INCLUDED */
554