1/*
2 * "$Id: print-vars.c,v 1.91 2010/12/05 21:38:15 rlk Exp $"
3 *
4 *   Print plug-in driver utility functions for the GIMP.
5 *
6 *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
7 *	Robert Krawitz (rlk@alum.mit.edu)
8 *
9 *   This program is free software; you can redistribute it and/or modify it
10 *   under the terms of the GNU General Public License as published by the Free
11 *   Software Foundation; either version 2 of the License, or (at your option)
12 *   any later version.
13 *
14 *   This program is distributed in the hope that it will be useful, but
15 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *   for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/*
25 * This file must include only standard C header files.  The core code must
26 * compile on generic platforms that don't support glib, gimp, gtk, etc.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <math.h>
33#ifdef HAVE_LIMITS_H
34#include <limits.h>
35#endif
36#include <string.h>
37#include <gutenprint/gutenprint.h>
38#include "gutenprint-internal.h"
39#include <gutenprint/gutenprint-intl-internal.h>
40#include "generic-options.h"
41
42typedef struct
43{
44  char *name;
45  stp_parameter_type_t typ;
46  stp_parameter_activity_t active;
47  union
48  {
49    int ival;
50    int bval;
51    double dval;
52    stp_curve_t *cval;
53    stp_array_t *aval;
54    stp_raw_t rval;
55  } value;
56} value_t;
57
58struct stp_compdata
59{
60  char *name;
61  stp_copy_data_func_t copyfunc;
62  stp_free_data_func_t freefunc;
63  void *data;
64};
65
66struct stp_vars			/* Plug-in variables */
67{
68  char *driver;			/* Name of printer "driver" */
69  char *color_conversion;       /* Color module in use */
70  int	left;			/* Offset from left-upper corner, points */
71  int	top;			/* ... */
72  int	width;			/* Width of the image, points */
73  int	height;			/* ... */
74  int	page_width;		/* Width of page in points */
75  int	page_height;		/* Height of page in points */
76  stp_list_t *params[STP_PARAMETER_TYPE_INVALID];
77  stp_list_t *internal_data;
78  void (*outfunc)(void *data, const char *buffer, size_t bytes);
79  void *outdata;
80  void (*errfunc)(void *data, const char *buffer, size_t bytes);
81  void *errdata;
82  int verified;			/* Ensure that params are OK! */
83};
84
85static int standard_vars_initialized = 0;
86
87
88void
89stp_parameter_description_destroy(stp_parameter_t *desc)
90{
91  switch (desc->p_type)
92    {
93    case STP_PARAMETER_TYPE_CURVE:
94      if (desc->bounds.curve)
95	stp_curve_destroy(desc->bounds.curve);
96      desc->bounds.curve = NULL;
97      break;
98    case STP_PARAMETER_TYPE_ARRAY:
99      if (desc->bounds.array)
100	stp_array_destroy(desc->bounds.array);
101      desc->bounds.array = NULL;
102      break;
103    case STP_PARAMETER_TYPE_STRING_LIST:
104      if (desc->bounds.str)
105	stp_string_list_destroy(desc->bounds.str);
106      desc->bounds.str = NULL;
107      break;
108    default:
109      break;
110    }
111}
112static stp_vars_t default_vars;
113
114#define CHECK_VARS(v) STPI_ASSERT(v, NULL)
115
116static const char *
117value_namefunc(const void *item)
118{
119  const value_t *v = (const value_t *) (item);
120  return v->name;
121}
122
123static void
124value_freefunc(void *item)
125{
126  value_t *v = (value_t *) (item);
127  switch (v->typ)
128    {
129    case STP_PARAMETER_TYPE_STRING_LIST:
130    case STP_PARAMETER_TYPE_FILE:
131    case STP_PARAMETER_TYPE_RAW:
132      stp_free((void *) v->value.rval.data);
133      break;
134    case STP_PARAMETER_TYPE_CURVE:
135      if (v->value.cval)
136	stp_curve_destroy(v->value.cval);
137      break;
138    case STP_PARAMETER_TYPE_ARRAY:
139      stp_array_destroy(v->value.aval);
140      break;
141    default:
142      break;
143    }
144  stp_free(v->name);
145  stp_free(v);
146}
147
148static stp_list_t *
149create_vars_list(void)
150{
151  stp_list_t *ret = stp_list_create();
152  stp_list_set_freefunc(ret, value_freefunc);
153  stp_list_set_namefunc(ret, value_namefunc);
154  return ret;
155}
156
157static void
158copy_to_raw(stp_raw_t *raw, const void *data, size_t bytes)
159{
160  char *ndata = NULL;
161  if (data)
162    {
163      ndata = stp_malloc(bytes + 1);
164      memcpy(ndata, data, bytes);
165      ndata[bytes] = '\0';
166    }
167  else
168    bytes = 0;
169  raw->data = (void *) ndata;
170  raw->bytes = bytes;
171}
172
173static value_t *
174value_copy(const void *item)
175{
176  value_t *ret = stp_malloc(sizeof(value_t));
177  const value_t *v = (const value_t *) (item);
178  ret->name = stp_strdup(v->name);
179  ret->typ = v->typ;
180  ret->active = v->active;
181  switch (v->typ)
182    {
183    case STP_PARAMETER_TYPE_CURVE:
184      ret->value.cval = stp_curve_create_copy(v->value.cval);
185      break;
186    case STP_PARAMETER_TYPE_ARRAY:
187      ret->value.aval = stp_array_create_copy(v->value.aval);
188      break;
189    case STP_PARAMETER_TYPE_STRING_LIST:
190    case STP_PARAMETER_TYPE_FILE:
191    case STP_PARAMETER_TYPE_RAW:
192      copy_to_raw(&(ret->value.rval), v->value.rval.data, v->value.rval.bytes);
193      break;
194    case STP_PARAMETER_TYPE_INT:
195    case STP_PARAMETER_TYPE_DIMENSION:
196    case STP_PARAMETER_TYPE_BOOLEAN:
197      ret->value.ival = v->value.ival;
198      break;
199    case STP_PARAMETER_TYPE_DOUBLE:
200      ret->value.dval = v->value.dval;
201      break;
202    default:
203      break;
204    }
205  return ret;
206}
207
208static stp_list_t *
209copy_value_list(const stp_list_t *src)
210{
211  stp_list_t *ret = create_vars_list();
212  const stp_list_item_t *item = stp_list_get_start((const stp_list_t *)src);
213  while (item)
214    {
215      stp_list_item_create(ret, NULL, value_copy(stp_list_item_get_data(item)));
216      item = stp_list_item_next(item);
217    }
218  return ret;
219}
220
221static const char *
222compdata_namefunc(const void *item)
223{
224  const compdata_t *cd = (const compdata_t *) (item);
225  return cd->name;
226}
227
228static void
229compdata_freefunc(void *item)
230{
231  compdata_t *cd = (compdata_t *) (item);
232  if (cd->freefunc)
233    (cd->freefunc)(cd->data);
234  stp_free(cd->name);
235  stp_free(cd);
236}
237
238static void *
239compdata_copyfunc(const void *item)
240{
241  const compdata_t *cd = (const compdata_t *) (item);
242  if (cd->copyfunc)
243    return (cd->copyfunc)(cd->data);
244  else
245    return cd->data;
246}
247
248void
249stp_allocate_component_data(stp_vars_t *v,
250			     const char *name,
251			     stp_copy_data_func_t copyfunc,
252			     stp_free_data_func_t freefunc,
253			     void *data)
254{
255  compdata_t *cd;
256  stp_list_item_t *item;
257  CHECK_VARS(v);
258  cd = stp_malloc(sizeof(compdata_t));
259  item = stp_list_get_item_by_name(v->internal_data, name);
260  if (item)
261    stp_list_item_destroy(v->internal_data, item);
262  cd->name = stp_strdup(name);
263  cd->copyfunc = copyfunc;
264  cd->freefunc = freefunc;
265  cd->data = data;
266  stp_list_item_create(v->internal_data, NULL, cd);
267}
268
269void
270stp_destroy_component_data(stp_vars_t *v, const char *name)
271{
272  stp_list_item_t *item;
273  CHECK_VARS(v);
274  item = stp_list_get_item_by_name(v->internal_data, name);
275  if (item)
276    stp_list_item_destroy(v->internal_data, item);
277}
278
279void *
280stp_get_component_data(const stp_vars_t *v, const char *name)
281{
282  stp_list_item_t *item;
283  CHECK_VARS(v);
284  item = stp_list_get_item_by_name(v->internal_data, name);
285  if (item)
286    return ((compdata_t *) stp_list_item_get_data(item))->data;
287  else
288    return NULL;
289}
290
291static stp_list_t *
292create_compdata_list(void)
293{
294  stp_list_t *ret = stp_list_create();
295  stp_list_set_freefunc(ret, compdata_freefunc);
296  stp_list_set_namefunc(ret, compdata_namefunc);
297  return ret;
298}
299
300static stp_list_t *
301copy_compdata_list(const stp_list_t *src)
302{
303  stp_list_t *ret = create_compdata_list();
304  const stp_list_item_t *item = stp_list_get_start(src);
305  while (item)
306    {
307      stp_list_item_create(ret, NULL, compdata_copyfunc(item));
308      item = stp_list_item_next(item);
309    }
310  return ret;
311}
312
313static void
314initialize_standard_vars(void)
315{
316  if (!standard_vars_initialized)
317    {
318      int i;
319      for (i = 0; i < STP_PARAMETER_TYPE_INVALID; i++)
320	default_vars.params[i] = create_vars_list();
321      default_vars.driver = stp_strdup("ps2");
322      default_vars.color_conversion = stp_strdup("traditional");
323      default_vars.internal_data = create_compdata_list();
324      standard_vars_initialized = 1;
325    }
326}
327
328const stp_vars_t *
329stp_default_settings(void)
330{
331  initialize_standard_vars();
332  return (stp_vars_t *) &default_vars;
333}
334
335stp_vars_t *
336stp_vars_create(void)
337{
338  int i;
339  stp_vars_t *retval = stp_zalloc(sizeof(stp_vars_t));
340  initialize_standard_vars();
341  for (i = 0; i < STP_PARAMETER_TYPE_INVALID; i++)
342    retval->params[i] = create_vars_list();
343  retval->internal_data = create_compdata_list();
344  stp_vars_copy(retval, (stp_vars_t *)&default_vars);
345  return (retval);
346}
347
348void
349stp_vars_destroy(stp_vars_t *v)
350{
351  int i;
352  CHECK_VARS(v);
353  for (i = 0; i < STP_PARAMETER_TYPE_INVALID; i++)
354    stp_list_destroy(v->params[i]);
355  stp_list_destroy(v->internal_data);
356  STP_SAFE_FREE(v->driver);
357  STP_SAFE_FREE(v->color_conversion);
358  stp_free(v);
359}
360
361#define DEF_STRING_FUNCS(s, pre)					\
362void									\
363pre##_set_##s(stp_vars_t *v, const char *val)				\
364{									\
365  CHECK_VARS(v);							\
366  if (val)								\
367    stp_deprintf(STP_DBG_VARS, "set %s to %s (0x%p)\n", #s, val,	\
368                 (const void *) v);					\
369  else									\
370    stp_deprintf(STP_DBG_VARS, "clear %s (0x%p)\n", #s,			\
371                 (const void *) v);					\
372  if (v->s == val)							\
373    return;								\
374  STP_SAFE_FREE(v->s);							\
375  v->s = stp_strdup(val);						\
376  v->verified = 0;							\
377}									\
378									\
379void									\
380pre##_set_##s##_n(stp_vars_t *v, const char *val, int n)		\
381{									\
382  CHECK_VARS(v);							\
383  if (v->s == val)							\
384    return;								\
385  STP_SAFE_FREE(v->s);							\
386  v->s = stp_strndup(val, n);						\
387  v->verified = 0;							\
388}									\
389									\
390const char *								\
391pre##_get_##s(const stp_vars_t *v)					\
392{									\
393  CHECK_VARS(v);							\
394  return v->s;								\
395}
396
397#define DEF_FUNCS(s, t, pre)				\
398void							\
399pre##_set_##s(stp_vars_t *v, t val)			\
400{							\
401  CHECK_VARS(v);                                        \
402  v->verified = 0;					\
403  v->s = val;						\
404}							\
405							\
406t							\
407pre##_get_##s(const stp_vars_t *v)			\
408{							\
409  CHECK_VARS(v);                                        \
410  return v->s;						\
411}
412
413DEF_STRING_FUNCS(driver, stp)
414DEF_STRING_FUNCS(color_conversion, stp)
415DEF_FUNCS(left, int, stp)
416DEF_FUNCS(top, int, stp)
417DEF_FUNCS(width, int, stp)
418DEF_FUNCS(height, int, stp)
419DEF_FUNCS(page_width, int, stp)
420DEF_FUNCS(page_height, int, stp)
421DEF_FUNCS(outdata, void *, stp)
422DEF_FUNCS(errdata, void *, stp)
423DEF_FUNCS(outfunc, stp_outfunc_t, stp)
424DEF_FUNCS(errfunc, stp_outfunc_t, stp)
425
426void
427stp_set_verified(stp_vars_t *v, int val)
428{
429  CHECK_VARS(v);
430  v->verified = val;
431}
432
433int
434stp_get_verified(const stp_vars_t *v)
435{
436  CHECK_VARS(v);
437  return v->verified;
438}
439
440static void
441set_default_raw_parameter(stp_list_t *list, const char *parameter,
442			  const char *value, size_t bytes, int typ)
443{
444  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
445  if (value && !item)
446    {
447      value_t *val = stp_malloc(sizeof(value_t));
448      val->name = stp_strdup(parameter);
449      val->typ = typ;
450      val->active = STP_PARAMETER_DEFAULTED;
451      stp_list_item_create(list, NULL, val);
452      copy_to_raw(&(val->value.rval), value, bytes);
453    }
454}
455
456static void
457set_raw_parameter(stp_list_t *list, const char *parameter, const char *value,
458		  size_t bytes, int typ)
459{
460  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
461  if (value)
462    {
463      value_t *val;
464      if (item)
465	{
466	  val = (value_t *) stp_list_item_get_data(item);
467	  if (val->active == STP_PARAMETER_DEFAULTED)
468	    val->active = STP_PARAMETER_ACTIVE;
469	  stp_free((void *) val->value.rval.data);
470	}
471      else
472	{
473	  val = stp_malloc(sizeof(value_t));
474	  val->name = stp_strdup(parameter);
475	  val->typ = typ;
476	  val->active = STP_PARAMETER_ACTIVE;
477	  stp_list_item_create(list, NULL, val);
478	}
479      copy_to_raw(&(val->value.rval), value, bytes);
480    }
481  else if (item)
482    stp_list_item_destroy(list, item);
483}
484
485void
486stp_set_string_parameter_n(stp_vars_t *v, const char *parameter,
487			   const char *value, size_t bytes)
488{
489  stp_list_t *list = v->params[STP_PARAMETER_TYPE_STRING_LIST];
490  if (value)
491    stp_deprintf(STP_DBG_VARS, "stp_set_string_parameter(0x%p, %s, %s)\n",
492		 (const void *) v, parameter, value);
493  else
494    stp_deprintf(STP_DBG_VARS, "stp_set_string_parameter(0x%p, %s)\n",
495		 (const void *) v, parameter);
496  set_raw_parameter(list, parameter, value, bytes,
497		    STP_PARAMETER_TYPE_STRING_LIST);
498  stp_set_verified(v, 0);
499}
500
501void
502stp_set_string_parameter(stp_vars_t *v, const char *parameter,
503			 const char *value)
504{
505  int byte_count = 0;
506  if (value)
507      byte_count = strlen(value);
508  stp_deprintf(STP_DBG_VARS, "stp_set_string_parameter(0x%p, %s, %s)\n",
509	       (const void *) v, parameter, value ? value : "NULL");
510  stp_set_string_parameter_n(v, parameter, value, byte_count);
511  stp_set_verified(v, 0);
512}
513
514void
515stp_set_default_string_parameter_n(stp_vars_t *v, const char *parameter,
516				   const char *value, size_t bytes)
517{
518  stp_list_t *list = v->params[STP_PARAMETER_TYPE_STRING_LIST];
519  stp_deprintf(STP_DBG_VARS, "stp_set_default_string_parameter(0x%p, %s, %s)\n",
520	       (const void *) v, parameter, value ? value : "NULL");
521  set_default_raw_parameter(list, parameter, value, bytes,
522			    STP_PARAMETER_TYPE_STRING_LIST);
523  stp_set_verified(v, 0);
524}
525
526void
527stp_set_default_string_parameter(stp_vars_t *v, const char *parameter,
528				 const char *value)
529{
530  int byte_count = 0;
531  if (value)
532    byte_count = strlen(value);
533  stp_set_default_string_parameter_n(v, parameter, value, byte_count);
534  stp_set_verified(v, 0);
535}
536
537void
538stp_clear_string_parameter(stp_vars_t *v, const char *parameter)
539{
540  stp_set_string_parameter(v, parameter, NULL);
541}
542
543const char *
544stp_get_string_parameter(const stp_vars_t *v, const char *parameter)
545{
546  stp_list_t *list = v->params[STP_PARAMETER_TYPE_STRING_LIST];
547  value_t *val;
548  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
549  if (item)
550    {
551      val = (value_t *) stp_list_item_get_data(item);
552      return val->value.rval.data;
553    }
554  else
555    return NULL;
556}
557
558void
559stp_set_raw_parameter(stp_vars_t *v, const char *parameter,
560		      const void *value, size_t bytes)
561{
562  stp_list_t *list = v->params[STP_PARAMETER_TYPE_RAW];
563  set_raw_parameter(list, parameter, value, bytes, STP_PARAMETER_TYPE_RAW);
564  stp_set_verified(v, 0);
565}
566
567void
568stp_set_default_raw_parameter(stp_vars_t *v, const char *parameter,
569			      const void *value, size_t bytes)
570{
571  stp_list_t *list = v->params[STP_PARAMETER_TYPE_RAW];
572  set_default_raw_parameter(list, parameter, value, bytes,
573			    STP_PARAMETER_TYPE_RAW);
574  stp_set_verified(v, 0);
575}
576
577void
578stp_clear_raw_parameter(stp_vars_t *v, const char *parameter)
579{
580  stp_set_raw_parameter(v, parameter, NULL, 0);
581}
582
583const stp_raw_t *
584stp_get_raw_parameter(const stp_vars_t *v, const char *parameter)
585{
586  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_RAW];
587  const value_t *val;
588  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
589  if (item)
590    {
591      val = (const value_t *) stp_list_item_get_data(item);
592      return &(val->value.rval);
593    }
594  else
595    return NULL;
596}
597
598void
599stp_set_file_parameter(stp_vars_t *v, const char *parameter,
600		       const char *value)
601{
602  stp_list_t *list = v->params[STP_PARAMETER_TYPE_FILE];
603  size_t byte_count = 0;
604  if (value)
605    byte_count = strlen(value);
606  stp_deprintf(STP_DBG_VARS, "stp_set_file_parameter(0x%p, %s, %s)\n",
607	       (const void *) v, parameter, value ? value : "NULL");
608  set_raw_parameter(list, parameter, value, byte_count,
609		    STP_PARAMETER_TYPE_FILE);
610  stp_set_verified(v, 0);
611}
612
613void
614stp_set_file_parameter_n(stp_vars_t *v, const char *parameter,
615			 const char *value, size_t byte_count)
616{
617  stp_list_t *list = v->params[STP_PARAMETER_TYPE_FILE];
618  stp_deprintf(STP_DBG_VARS, "stp_set_file_parameter(0x%p, %s, %s)\n",
619	       (const void *) v, parameter, value ? value : "NULL");
620  set_raw_parameter(list, parameter, value, byte_count,
621		    STP_PARAMETER_TYPE_FILE);
622  stp_set_verified(v, 0);
623}
624
625void
626stp_set_default_file_parameter(stp_vars_t *v, const char *parameter,
627			       const char *value)
628{
629  stp_list_t *list = v->params[STP_PARAMETER_TYPE_FILE];
630  size_t byte_count = 0;
631  if (value)
632    byte_count = strlen(value);
633  stp_deprintf(STP_DBG_VARS, "stp_set_default_file_parameter(0x%p, %s, %s)\n",
634	       (const void *) v, parameter, value ? value : "NULL");
635  set_default_raw_parameter(list, parameter, value, byte_count,
636			    STP_PARAMETER_TYPE_FILE);
637  stp_set_verified(v, 0);
638}
639
640void
641stp_set_default_file_parameter_n(stp_vars_t *v, const char *parameter,
642				 const char *value, size_t byte_count)
643{
644  stp_list_t *list = v->params[STP_PARAMETER_TYPE_FILE];
645  stp_deprintf(STP_DBG_VARS, "stp_set_default_file_parameter(0x%p, %s, %s)\n",
646	       (const void *) v, parameter, value ? value : "NULL");
647  set_default_raw_parameter(list, parameter, value, byte_count,
648			    STP_PARAMETER_TYPE_FILE);
649  stp_set_verified(v, 0);
650}
651
652void
653stp_clear_file_parameter(stp_vars_t *v, const char *parameter)
654{
655  stp_set_file_parameter(v, parameter, NULL);
656}
657
658const char *
659stp_get_file_parameter(const stp_vars_t *v, const char *parameter)
660{
661  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_FILE];
662  const value_t *val;
663  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
664  if (item)
665    {
666      val = (const value_t *) stp_list_item_get_data(item);
667      return val->value.rval.data;
668    }
669  else
670    return NULL;
671}
672
673void
674stp_set_curve_parameter(stp_vars_t *v, const char *parameter,
675			const stp_curve_t *curve)
676{
677  stp_list_t *list = v->params[STP_PARAMETER_TYPE_CURVE];
678  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
679  stp_deprintf(STP_DBG_VARS, "stp_set_curve_parameter(0x%p, %s)\n",
680	       (const void *) v, parameter);
681  if (curve)
682    {
683      value_t *val;
684      if (item)
685	{
686	  val = (value_t *) stp_list_item_get_data(item);
687	  if (val->active == STP_PARAMETER_DEFAULTED)
688	    val->active = STP_PARAMETER_ACTIVE;
689	  if (val->value.cval)
690	    stp_curve_destroy(val->value.cval);
691	}
692      else
693	{
694	  val = stp_malloc(sizeof(value_t));
695	  val->name = stp_strdup(parameter);
696	  val->typ = STP_PARAMETER_TYPE_CURVE;
697	  val->active = STP_PARAMETER_ACTIVE;
698	  stp_list_item_create(list, NULL, val);
699	}
700      val->value.cval = stp_curve_create_copy(curve);
701    }
702  else if (item)
703    stp_list_item_destroy(list, item);
704  stp_set_verified(v, 0);
705}
706
707void
708stp_set_default_curve_parameter(stp_vars_t *v, const char *parameter,
709				const stp_curve_t *curve)
710{
711  stp_list_t *list = v->params[STP_PARAMETER_TYPE_CURVE];
712  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
713  stp_deprintf(STP_DBG_VARS, "stp_set_default_curve_parameter(0x%p, %s)\n",
714	       (const void *) v, parameter);
715  if (!item)
716    {
717      if (curve)
718	{
719	  value_t *val;
720	  val = stp_malloc(sizeof(value_t));
721	  val->name = stp_strdup(parameter);
722	  val->typ = STP_PARAMETER_TYPE_CURVE;
723	  val->active = STP_PARAMETER_DEFAULTED;
724	  stp_list_item_create(list, NULL, val);
725	  val->value.cval = stp_curve_create_copy(curve);
726	}
727    }
728  stp_set_verified(v, 0);
729}
730
731void
732stp_clear_curve_parameter(stp_vars_t *v, const char *parameter)
733{
734  stp_set_curve_parameter(v, parameter, NULL);
735}
736
737const stp_curve_t *
738stp_get_curve_parameter(const stp_vars_t *v, const char *parameter)
739{
740  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_CURVE];
741  const value_t *val;
742  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
743  if (item)
744    {
745      val = (value_t *) stp_list_item_get_data(item);
746      return val->value.cval;
747    }
748  else
749    return NULL;
750}
751
752void
753stp_set_array_parameter(stp_vars_t *v, const char *parameter,
754			const stp_array_t *array)
755{
756  stp_list_t *list = v->params[STP_PARAMETER_TYPE_ARRAY];
757  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
758  stp_deprintf(STP_DBG_VARS, "stp_set_array_parameter(0x%p, %s)\n",
759	       (const void *) v, parameter);
760  if (array)
761    {
762      value_t *val;
763      if (item)
764	{
765	  val = (value_t *) stp_list_item_get_data(item);
766	  if (val->active == STP_PARAMETER_DEFAULTED)
767	    val->active = STP_PARAMETER_ACTIVE;
768	  stp_array_destroy(val->value.aval);
769	}
770      else
771	{
772	  val = stp_malloc(sizeof(value_t));
773	  val->name = stp_strdup(parameter);
774	  val->typ = STP_PARAMETER_TYPE_ARRAY;
775	  val->active = STP_PARAMETER_ACTIVE;
776	  stp_list_item_create(list, NULL, val);
777	}
778      val->value.aval = stp_array_create_copy(array);
779    }
780  else if (item)
781    stp_list_item_destroy(list, item);
782  stp_set_verified(v, 0);
783}
784
785void
786stp_set_default_array_parameter(stp_vars_t *v, const char *parameter,
787				const stp_array_t *array)
788{
789  stp_list_t *list = v->params[STP_PARAMETER_TYPE_ARRAY];
790  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
791  stp_deprintf(STP_DBG_VARS, "stp_set_default_array_parameter(0x%p, %s)\n",
792	       (const void *) v, parameter);
793  if (!item)
794    {
795      if (array)
796	{
797	  value_t *val;
798	  val = stp_malloc(sizeof(value_t));
799	  val->name = stp_strdup(parameter);
800	  val->typ = STP_PARAMETER_TYPE_ARRAY;
801	  val->active = STP_PARAMETER_DEFAULTED;
802	  stp_list_item_create(list, NULL, val);
803	  val->value.aval = stp_array_create_copy(array);
804	}
805    }
806  stp_set_verified(v, 0);
807}
808
809void
810stp_clear_array_parameter(stp_vars_t *v, const char *parameter)
811{
812  stp_set_array_parameter(v, parameter, NULL);
813}
814
815const stp_array_t *
816stp_get_array_parameter(const stp_vars_t *v, const char *parameter)
817{
818  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_ARRAY];
819  const value_t *val;
820  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
821  if (item)
822    {
823      val = (const value_t *) stp_list_item_get_data(item);
824      return val->value.aval;
825    }
826  else
827    return NULL;
828}
829
830void
831stp_set_int_parameter(stp_vars_t *v, const char *parameter, int ival)
832{
833  stp_list_t *list = v->params[STP_PARAMETER_TYPE_INT];
834  value_t *val;
835  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
836  stp_deprintf(STP_DBG_VARS, "stp_set_int_parameter(0x%p, %s, %d)\n",
837	       (const void *) v, parameter, ival);
838  if (item)
839    {
840      val = (value_t *) stp_list_item_get_data(item);
841      if (val->active == STP_PARAMETER_DEFAULTED)
842	val->active = STP_PARAMETER_ACTIVE;
843    }
844  else
845    {
846      val = stp_malloc(sizeof(value_t));
847      val->name = stp_strdup(parameter);
848      val->typ = STP_PARAMETER_TYPE_INT;
849      val->active = STP_PARAMETER_ACTIVE;
850      stp_list_item_create(list, NULL, val);
851    }
852  val->value.ival = ival;
853  stp_set_verified(v, 0);
854}
855
856void
857stp_set_default_int_parameter(stp_vars_t *v, const char *parameter, int ival)
858{
859  stp_list_t *list = v->params[STP_PARAMETER_TYPE_INT];
860  value_t *val;
861  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
862  stp_deprintf(STP_DBG_VARS, "stp_set_default_int_parameter(0x%p, %s, %d)\n",
863	       (const void *) v, parameter, ival);
864  if (!item)
865    {
866      val = stp_malloc(sizeof(value_t));
867      val->name = stp_strdup(parameter);
868      val->typ = STP_PARAMETER_TYPE_INT;
869      val->active = STP_PARAMETER_DEFAULTED;
870      stp_list_item_create(list, NULL, val);
871      val->value.ival = ival;
872    }
873  stp_set_verified(v, 0);
874}
875
876void
877stp_clear_int_parameter(stp_vars_t *v, const char *parameter)
878{
879  stp_list_t *list = v->params[STP_PARAMETER_TYPE_INT];
880  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
881  stp_deprintf(STP_DBG_VARS, "stp_clear_int_parameter(0x%p, %s)\n",
882	       (const void *) v, parameter);
883  if (item)
884    stp_list_item_destroy(list, item);
885  stp_set_verified(v, 0);
886}
887
888int
889stp_get_int_parameter(const stp_vars_t *v, const char *parameter)
890{
891  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_INT];
892  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
893  if (item)
894    {
895      const value_t *val = (const value_t *) stp_list_item_get_data(item);
896      return val->value.ival;
897    }
898  else
899    {
900      stp_parameter_t desc;
901      stp_describe_parameter(v, parameter, &desc);
902      if (desc.p_type == STP_PARAMETER_TYPE_INT)
903	{
904	  int intval = desc.deflt.integer;
905	  stp_parameter_description_destroy(&desc);
906	  return intval;
907	}
908      else
909	{
910	  stp_parameter_description_destroy(&desc);
911	  stp_erprintf
912	    ("Gutenprint: Attempt to retrieve unset integer parameter %s\n",
913	     parameter);
914	  return 0;
915	}
916    }
917}
918
919void
920stp_set_boolean_parameter(stp_vars_t *v, const char *parameter, int ival)
921{
922  stp_list_t *list = v->params[STP_PARAMETER_TYPE_BOOLEAN];
923  value_t *val;
924  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
925  stp_deprintf(STP_DBG_VARS, "stp_set_boolean_parameter(0x%p, %s, %d)\n",
926	       (const void *) v, parameter, ival);
927  if (item)
928    {
929      val = (value_t *) stp_list_item_get_data(item);
930      if (val->active == STP_PARAMETER_DEFAULTED)
931	val->active = STP_PARAMETER_ACTIVE;
932    }
933  else
934    {
935      val = stp_malloc(sizeof(value_t));
936      val->name = stp_strdup(parameter);
937      val->typ = STP_PARAMETER_TYPE_BOOLEAN;
938      val->active = STP_PARAMETER_ACTIVE;
939      stp_list_item_create(list, NULL, val);
940    }
941  if (ival)
942    val->value.ival = 1;
943  else
944    val->value.ival = 0;
945  stp_set_verified(v, 0);
946}
947
948void
949stp_set_default_boolean_parameter(stp_vars_t *v, const char *parameter,
950				  int ival)
951{
952  stp_list_t *list = v->params[STP_PARAMETER_TYPE_BOOLEAN];
953  value_t *val;
954  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
955  stp_deprintf(STP_DBG_VARS, "stp_set_default_boolean_parameter(0x%p, %s, %d)\n",
956	       (const void *) v, parameter, ival);
957  if (!item)
958    {
959      val = stp_malloc(sizeof(value_t));
960      val->name = stp_strdup(parameter);
961      val->typ = STP_PARAMETER_TYPE_BOOLEAN;
962      val->active = STP_PARAMETER_DEFAULTED;
963      stp_list_item_create(list, NULL, val);
964      if (ival)
965	val->value.ival = 1;
966      else
967	val->value.ival = 0;
968    }
969  stp_set_verified(v, 0);
970}
971
972void
973stp_clear_boolean_parameter(stp_vars_t *v, const char *parameter)
974{
975  stp_list_t *list = v->params[STP_PARAMETER_TYPE_BOOLEAN];
976  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
977  stp_deprintf(STP_DBG_VARS, "stp_clear_boolean_parameter(0x%p, %s)\n",
978	       (const void *) v, parameter);
979  if (item)
980    stp_list_item_destroy(list, item);
981  stp_set_verified(v, 0);
982}
983
984int
985stp_get_boolean_parameter(const stp_vars_t *v, const char *parameter)
986{
987  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_BOOLEAN];
988  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
989  if (item)
990    {
991      const value_t *val = (const value_t *) stp_list_item_get_data(item);
992      return val->value.ival;
993    }
994  else
995    {
996      stp_parameter_t desc;
997      stp_describe_parameter(v, parameter, &desc);
998      if (desc.p_type == STP_PARAMETER_TYPE_BOOLEAN)
999	{
1000	  int boolean = desc.deflt.boolean;
1001	  stp_parameter_description_destroy(&desc);
1002	  return boolean;
1003	}
1004      else
1005	{
1006	  stp_parameter_description_destroy(&desc);
1007	  stp_erprintf
1008	    ("Gutenprint: Attempt to retrieve unset boolean parameter %s\n",
1009	     parameter);
1010	  return 0;
1011	}
1012    }
1013}
1014
1015void
1016stp_set_dimension_parameter(stp_vars_t *v, const char *parameter, int ival)
1017{
1018  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DIMENSION];
1019  value_t *val;
1020  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1021  stp_deprintf(STP_DBG_VARS, "stp_set_dimension_parameter(0x%p, %s, %d)\n",
1022	       (const void *) v, parameter, ival);
1023  if (item)
1024    {
1025      val = (value_t *) stp_list_item_get_data(item);
1026      if (val->active == STP_PARAMETER_DEFAULTED)
1027	val->active = STP_PARAMETER_ACTIVE;
1028    }
1029  else
1030    {
1031      val = stp_malloc(sizeof(value_t));
1032      val->name = stp_strdup(parameter);
1033      val->typ = STP_PARAMETER_TYPE_DIMENSION;
1034      val->active = STP_PARAMETER_ACTIVE;
1035      stp_list_item_create(list, NULL, val);
1036    }
1037  val->value.ival = ival;
1038  stp_set_verified(v, 0);
1039}
1040
1041void
1042stp_set_default_dimension_parameter(stp_vars_t *v, const char *parameter, int ival)
1043{
1044  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DIMENSION];
1045  value_t *val;
1046  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1047  stp_deprintf(STP_DBG_VARS, "stp_set_default_dimension_parameter(0x%p, %s, %d)\n",
1048	       (const void *) v, parameter, ival);
1049  if (!item)
1050    {
1051      val = stp_malloc(sizeof(value_t));
1052      val->name = stp_strdup(parameter);
1053      val->typ = STP_PARAMETER_TYPE_DIMENSION;
1054      val->active = STP_PARAMETER_DEFAULTED;
1055      stp_list_item_create(list, NULL, val);
1056      val->value.ival = ival;
1057    }
1058  stp_set_verified(v, 0);
1059}
1060
1061void
1062stp_clear_dimension_parameter(stp_vars_t *v, const char *parameter)
1063{
1064  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DIMENSION];
1065  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1066  stp_deprintf(STP_DBG_VARS, "stp_clear_dimension_parameter(0x%p, %s)\n",
1067	       (const void *) v, parameter);
1068  if (item)
1069    stp_list_item_destroy(list, item);
1070  stp_set_verified(v, 0);
1071}
1072
1073int
1074stp_get_dimension_parameter(const stp_vars_t *v, const char *parameter)
1075{
1076  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_DIMENSION];
1077  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1078  if (item)
1079    {
1080      const value_t *val = (const value_t *) stp_list_item_get_data(item);
1081      return val->value.ival;
1082    }
1083  else
1084    {
1085      stp_parameter_t desc;
1086      stp_describe_parameter(v, parameter, &desc);
1087      if (desc.p_type == STP_PARAMETER_TYPE_DIMENSION)
1088	{
1089	  int intval = desc.deflt.integer;
1090	  stp_parameter_description_destroy(&desc);
1091	  return intval;
1092	}
1093      else
1094	{
1095	  stp_parameter_description_destroy(&desc);
1096	  stp_erprintf
1097	    ("Gutenprint: Attempt to retrieve unset dimension parameter %s\n",
1098	     parameter);
1099	  return 0;
1100	}
1101    }
1102}
1103
1104void
1105stp_set_float_parameter(stp_vars_t *v, const char *parameter, double dval)
1106{
1107  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DOUBLE];
1108  value_t *val;
1109  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1110  stp_deprintf(STP_DBG_VARS, "stp_set_float_parameter(0x%p, %s, %f)\n",
1111	       (const void *) v, parameter, dval);
1112  if (item)
1113    {
1114      val = (value_t *) stp_list_item_get_data(item);
1115      if (val->active == STP_PARAMETER_DEFAULTED)
1116	val->active = STP_PARAMETER_ACTIVE;
1117    }
1118  else
1119    {
1120      val = stp_malloc(sizeof(value_t));
1121      val->name = stp_strdup(parameter);
1122      val->typ = STP_PARAMETER_TYPE_DOUBLE;
1123      val->active = STP_PARAMETER_ACTIVE;
1124      stp_list_item_create(list, NULL, val);
1125    }
1126  val->value.dval = dval;
1127  stp_set_verified(v, 0);
1128}
1129
1130void
1131stp_set_default_float_parameter(stp_vars_t *v, const char *parameter,
1132				double dval)
1133{
1134  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DOUBLE];
1135  value_t *val;
1136  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1137  stp_deprintf(STP_DBG_VARS, "stp_set_default_float_parameter(0x%p, %s, %f)\n",
1138	       (const void *) v, parameter, dval);
1139  if (!item)
1140    {
1141      val = stp_malloc(sizeof(value_t));
1142      val->name = stp_strdup(parameter);
1143      val->typ = STP_PARAMETER_TYPE_DOUBLE;
1144      val->active = STP_PARAMETER_DEFAULTED;
1145      stp_list_item_create(list, NULL, val);
1146      val->value.dval = dval;
1147    }
1148  stp_set_verified(v, 0);
1149}
1150
1151void
1152stp_clear_float_parameter(stp_vars_t *v, const char *parameter)
1153{
1154  stp_list_t *list = v->params[STP_PARAMETER_TYPE_DOUBLE];
1155  stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1156  stp_deprintf(STP_DBG_VARS, "stp_clear_float_parameter(0x%p, %s)\n",
1157	       (const void *) v, parameter);
1158  if (item)
1159    stp_list_item_destroy(list, item);
1160  stp_set_verified(v, 0);
1161}
1162
1163double
1164stp_get_float_parameter(const stp_vars_t *v, const char *parameter)
1165{
1166  const stp_list_t *list = v->params[STP_PARAMETER_TYPE_DOUBLE];
1167  const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1168  if (item)
1169    {
1170      const value_t *val = (value_t *) stp_list_item_get_data(item);
1171      return val->value.dval;
1172    }
1173  else
1174    {
1175      stp_parameter_t desc;
1176      stp_describe_parameter(v, parameter, &desc);
1177      if (desc.p_type == STP_PARAMETER_TYPE_DOUBLE)
1178	{
1179	  double dbl = desc.deflt.dbl;
1180	  stp_parameter_description_destroy(&desc);
1181	  return dbl;
1182	}
1183      else
1184	{
1185	  stp_parameter_description_destroy(&desc);
1186	  stp_erprintf
1187	    ("Gutenprint: Attempt to retrieve unset float parameter %s\n",
1188	     parameter);
1189	  return 1.0;
1190	}
1191    }
1192}
1193
1194void
1195stp_scale_float_parameter(stp_vars_t *v, const char *parameter,
1196			  double scale)
1197{
1198  double val;
1199  if (stp_check_float_parameter(v, parameter, STP_PARAMETER_DEFAULTED))
1200    val = stp_get_float_parameter(v, parameter);
1201  else
1202    {
1203      stp_parameter_t desc;
1204      stp_describe_parameter(v, parameter, &desc);
1205      if (desc.p_type != STP_PARAMETER_TYPE_DOUBLE)
1206	{
1207	  stp_parameter_description_destroy(&desc);
1208	  return;
1209	}
1210      val = desc.deflt.dbl;
1211      stp_parameter_description_destroy(&desc);
1212    }
1213  stp_deprintf(STP_DBG_VARS, "stp_scale_float_parameter(%p, %s, %f*%f)\n",
1214	       (const void *) v, parameter, val, scale);
1215  stp_set_float_parameter(v, parameter, val * scale);
1216}
1217
1218void
1219stp_clear_parameter(stp_vars_t *v, const char *parameter, stp_parameter_type_t type)
1220{
1221  switch (type)
1222    {
1223    case STP_PARAMETER_TYPE_STRING_LIST:
1224      stp_clear_string_parameter(v, parameter);
1225      break;
1226    case STP_PARAMETER_TYPE_FILE:
1227      stp_clear_file_parameter(v, parameter);
1228      break;
1229    case STP_PARAMETER_TYPE_DOUBLE:
1230      stp_clear_float_parameter(v, parameter);
1231      break;
1232    case STP_PARAMETER_TYPE_INT:
1233      stp_clear_int_parameter(v, parameter);
1234      break;
1235    case STP_PARAMETER_TYPE_DIMENSION:
1236      stp_clear_dimension_parameter(v, parameter);
1237      break;
1238    case STP_PARAMETER_TYPE_BOOLEAN:
1239      stp_clear_boolean_parameter(v, parameter);
1240      break;
1241    case STP_PARAMETER_TYPE_CURVE:
1242      stp_clear_curve_parameter(v, parameter);
1243      break;
1244    case STP_PARAMETER_TYPE_ARRAY:
1245      stp_clear_array_parameter(v, parameter);
1246      break;
1247    case STP_PARAMETER_TYPE_RAW:
1248      stp_clear_raw_parameter(v, parameter);
1249      break;
1250    default:
1251      stp_eprintf(v, "Attempt to clear unknown type parameter!\n");
1252    }
1253}
1254
1255
1256int
1257stp_check_parameter(const stp_vars_t *v,
1258		    const char *parameter,
1259		    stp_parameter_activity_t active,
1260		    stp_parameter_type_t p_type)
1261{
1262  if (p_type >= STP_PARAMETER_TYPE_STRING_LIST &&
1263      p_type < STP_PARAMETER_TYPE_INVALID)
1264    {
1265      const stp_list_t *list = v->params[p_type];
1266      const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1267      if (item &&
1268	  active <= ((const value_t *) stp_list_item_get_data(item))->active)
1269	return 1;
1270      else
1271	return 0;
1272    }
1273  return 0;
1274}
1275
1276#define CHECK_FUNCTION(type, index)					\
1277int									\
1278stp_check_##type##_parameter(const stp_vars_t *v, const char *parameter, \
1279			     stp_parameter_activity_t active)		\
1280{									\
1281  return stp_check_parameter(v, parameter, active, index);		\
1282}
1283
1284CHECK_FUNCTION(string, STP_PARAMETER_TYPE_STRING_LIST)
1285CHECK_FUNCTION(file, STP_PARAMETER_TYPE_FILE)
1286CHECK_FUNCTION(float, STP_PARAMETER_TYPE_DOUBLE)
1287CHECK_FUNCTION(int, STP_PARAMETER_TYPE_INT)
1288CHECK_FUNCTION(dimension, STP_PARAMETER_TYPE_DIMENSION)
1289CHECK_FUNCTION(boolean, STP_PARAMETER_TYPE_BOOLEAN)
1290CHECK_FUNCTION(curve, STP_PARAMETER_TYPE_CURVE)
1291CHECK_FUNCTION(array, STP_PARAMETER_TYPE_ARRAY)
1292CHECK_FUNCTION(raw, STP_PARAMETER_TYPE_RAW)
1293
1294stp_string_list_t *
1295stp_list_parameters(const stp_vars_t *v, stp_parameter_type_t p_type)
1296{
1297  if (p_type >= STP_PARAMETER_TYPE_STRING_LIST &&
1298      p_type < STP_PARAMETER_TYPE_INVALID)
1299    {
1300      const stp_list_t *list = v->params[p_type];
1301      stp_string_list_t *answer = stp_string_list_create();
1302      const stp_list_item_t *li = stp_list_get_start(list);
1303      while (li)
1304	{
1305	  const value_t *val = (value_t *) stp_list_item_get_data(li);
1306	  stp_string_list_add_string(answer, val->name, val->name);
1307	  li = stp_list_item_next(li);
1308	}
1309      return answer;
1310    }
1311  return NULL;
1312}
1313
1314#define LIST_FUNCTION(type, index)			\
1315stp_string_list_t *					\
1316stp_list_##type##_parameters(const stp_vars_t *v)	\
1317{							\
1318  return stp_list_parameters(v, index);			\
1319}
1320
1321LIST_FUNCTION(string, STP_PARAMETER_TYPE_STRING_LIST)
1322LIST_FUNCTION(file, STP_PARAMETER_TYPE_FILE)
1323LIST_FUNCTION(float, STP_PARAMETER_TYPE_DOUBLE)
1324LIST_FUNCTION(int, STP_PARAMETER_TYPE_INT)
1325LIST_FUNCTION(dimension, STP_PARAMETER_TYPE_DIMENSION)
1326LIST_FUNCTION(boolean, STP_PARAMETER_TYPE_BOOLEAN)
1327LIST_FUNCTION(curve, STP_PARAMETER_TYPE_CURVE)
1328LIST_FUNCTION(array, STP_PARAMETER_TYPE_ARRAY)
1329LIST_FUNCTION(raw, STP_PARAMETER_TYPE_RAW)
1330
1331stp_parameter_activity_t
1332stp_get_parameter_active(const stp_vars_t *v, const char *parameter,
1333			 stp_parameter_type_t p_type)
1334{
1335  if (p_type >= STP_PARAMETER_TYPE_STRING_LIST &&
1336      p_type < STP_PARAMETER_TYPE_INVALID)
1337    {
1338      const stp_list_t *list = v->params[p_type];
1339      const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1340      if (item)
1341	return ((const value_t *) stp_list_item_get_data(item))->active;
1342      else
1343	return 0;
1344    }
1345  return 0;
1346}
1347
1348#define GET_PARAMETER_ACTIVE_FUNCTION(type, index)			\
1349stp_parameter_activity_t						\
1350stp_get_##type##_parameter_active(const stp_vars_t *v, const char *parameter) \
1351{									\
1352  return stp_get_parameter_active(v, parameter, index);			\
1353}
1354
1355GET_PARAMETER_ACTIVE_FUNCTION(string, STP_PARAMETER_TYPE_STRING_LIST)
1356GET_PARAMETER_ACTIVE_FUNCTION(file, STP_PARAMETER_TYPE_FILE)
1357GET_PARAMETER_ACTIVE_FUNCTION(float, STP_PARAMETER_TYPE_DOUBLE)
1358GET_PARAMETER_ACTIVE_FUNCTION(int, STP_PARAMETER_TYPE_INT)
1359GET_PARAMETER_ACTIVE_FUNCTION(dimension, STP_PARAMETER_TYPE_DIMENSION)
1360GET_PARAMETER_ACTIVE_FUNCTION(boolean, STP_PARAMETER_TYPE_BOOLEAN)
1361GET_PARAMETER_ACTIVE_FUNCTION(curve, STP_PARAMETER_TYPE_CURVE)
1362GET_PARAMETER_ACTIVE_FUNCTION(array, STP_PARAMETER_TYPE_ARRAY)
1363GET_PARAMETER_ACTIVE_FUNCTION(raw, STP_PARAMETER_TYPE_RAW)
1364
1365void
1366stp_set_parameter_active(stp_vars_t *v,
1367			 const char *parameter,
1368			 stp_parameter_activity_t active,
1369			 stp_parameter_type_t p_type)
1370{
1371  if (p_type >= STP_PARAMETER_TYPE_STRING_LIST &&
1372      p_type < STP_PARAMETER_TYPE_INVALID)
1373    {
1374      const stp_list_t *list = v->params[p_type];
1375      const stp_list_item_t *item = stp_list_get_item_by_name(list, parameter);
1376      if (item && (active == STP_PARAMETER_ACTIVE ||
1377		   active == STP_PARAMETER_INACTIVE))
1378	((value_t *) stp_list_item_get_data(item))->active = active;
1379    }
1380}
1381
1382#define SET_PARAMETER_ACTIVE_FUNCTION(type, index)			\
1383void									\
1384stp_set_##type##_parameter_active(stp_vars_t *v, const char *parameter, \
1385				  stp_parameter_activity_t active)	\
1386{									\
1387  stp_deprintf(STP_DBG_VARS,						\
1388	       "stp_set_%s_parameter_active(0x%p, %s, %d)\n",		\
1389	       #type, (const void *) v, parameter, active);		\
1390  stp_set_parameter_active(v, parameter, active, index);		\
1391}
1392
1393SET_PARAMETER_ACTIVE_FUNCTION(string, STP_PARAMETER_TYPE_STRING_LIST)
1394SET_PARAMETER_ACTIVE_FUNCTION(file, STP_PARAMETER_TYPE_FILE)
1395SET_PARAMETER_ACTIVE_FUNCTION(float, STP_PARAMETER_TYPE_DOUBLE)
1396SET_PARAMETER_ACTIVE_FUNCTION(int, STP_PARAMETER_TYPE_INT)
1397SET_PARAMETER_ACTIVE_FUNCTION(dimension, STP_PARAMETER_TYPE_DIMENSION)
1398SET_PARAMETER_ACTIVE_FUNCTION(boolean, STP_PARAMETER_TYPE_BOOLEAN)
1399SET_PARAMETER_ACTIVE_FUNCTION(curve, STP_PARAMETER_TYPE_CURVE)
1400SET_PARAMETER_ACTIVE_FUNCTION(array, STP_PARAMETER_TYPE_ARRAY)
1401SET_PARAMETER_ACTIVE_FUNCTION(raw, STP_PARAMETER_TYPE_RAW)
1402
1403void
1404stp_fill_parameter_settings(stp_parameter_t *desc,
1405			    const stp_parameter_t *param)
1406{
1407  if (param)
1408    {
1409      desc->p_type = param->p_type;
1410      desc->p_level = param->p_level;
1411      desc->p_class = param->p_class;
1412      desc->is_mandatory = param->is_mandatory;
1413      desc->is_active = param->is_active;
1414      desc->channel = param->channel;
1415      desc->verify_this_parameter = param->verify_this_parameter;
1416      desc->read_only = param->read_only;
1417      desc->name = param->name;
1418      STPI_ASSERT(param->text, NULL);
1419      desc->text = gettext(param->text);
1420      STPI_ASSERT(param->category, NULL);
1421      desc->category = gettext(param->category);
1422      desc->help = param->help ? gettext(param->help) : NULL;
1423      return;
1424    }
1425}
1426
1427void
1428stp_vars_copy(stp_vars_t *vd, const stp_vars_t *vs)
1429{
1430  int i;
1431
1432  if (vs == vd)
1433    return;
1434  stp_set_driver(vd, stp_get_driver(vs));
1435  stp_set_color_conversion(vd, stp_get_color_conversion(vs));
1436  stp_set_left(vd, stp_get_left(vs));
1437  stp_set_top(vd, stp_get_top(vs));
1438  stp_set_width(vd, stp_get_width(vs));
1439  stp_set_height(vd, stp_get_height(vs));
1440  stp_set_page_width(vd, stp_get_page_width(vs));
1441  stp_set_page_height(vd, stp_get_page_height(vs));
1442  stp_set_outdata(vd, stp_get_outdata(vs));
1443  stp_set_errdata(vd, stp_get_errdata(vs));
1444  stp_set_outfunc(vd, stp_get_outfunc(vs));
1445  stp_set_errfunc(vd, stp_get_errfunc(vs));
1446  for (i = 0; i < STP_PARAMETER_TYPE_INVALID; i++)
1447    {
1448      stp_list_destroy(vd->params[i]);
1449      vd->params[i] = copy_value_list(vs->params[i]);
1450    }
1451  stp_list_destroy(vd->internal_data);
1452  vd->internal_data = copy_compdata_list(vs->internal_data);
1453  stp_set_verified(vd, stp_get_verified(vs));
1454}
1455
1456void
1457stp_prune_inactive_options(stp_vars_t *v)
1458{
1459  stp_parameter_list_t params = stp_get_parameter_list(v);
1460  int i;
1461  for (i = 0; i < STP_PARAMETER_TYPE_INVALID; i++)
1462    {
1463      stp_list_t *list = v->params[i];
1464      stp_list_item_t *item = stp_list_get_start(list);
1465      while (item)
1466	{
1467	  stp_list_item_t *next = stp_list_item_next(item);
1468	  value_t *var = (value_t *)stp_list_item_get_data(item);
1469	  if (var->active < STP_PARAMETER_DEFAULTED ||
1470	      !(stp_parameter_find(params, var->name)))
1471	    stp_list_item_destroy(list, item);
1472	  item = next;
1473	}
1474    }
1475  stp_parameter_list_destroy(params);
1476}
1477
1478stp_vars_t *
1479stp_vars_create_copy(const stp_vars_t *vs)
1480{
1481  stp_vars_t *vd = stp_vars_create();
1482  stp_vars_copy(vd, vs);
1483  return (vd);
1484}
1485
1486static const char *
1487param_namefunc(const void *item)
1488{
1489  const stp_parameter_t *param = (const stp_parameter_t *)(item);
1490  return param->name;
1491}
1492
1493static const char *
1494param_longnamefunc(const void *item)
1495{
1496  const stp_parameter_t *param = (const stp_parameter_t *) (item);
1497  return param->text;
1498}
1499
1500stp_parameter_list_t
1501stp_parameter_list_create(void)
1502{
1503  stp_list_t *ret = stp_list_create();
1504  stp_list_set_namefunc(ret, param_namefunc);
1505  stp_list_set_long_namefunc(ret, param_longnamefunc);
1506  return (stp_parameter_list_t) ret;
1507}
1508
1509void
1510stp_parameter_list_add_param(stp_parameter_list_t list,
1511			     const stp_parameter_t *item)
1512{
1513  stp_list_t *ilist = (stp_list_t *) list;
1514  stp_list_item_create(ilist, NULL, item);
1515}
1516
1517static void
1518debug_print_parameter_description(const stp_parameter_t *desc, const char *who,
1519				  const stp_vars_t *v)
1520{
1521  int i;
1522  char *curve;
1523  if (! (stp_get_debug_level() & STP_DBG_VARS))
1524    return;
1525  stp_deprintf(STP_DBG_VARS, "Describe %s: vars 0x%p from %s type %d class %d level %d\n",
1526	       desc->name, (const void *) v, who,
1527	       desc->p_type, desc->p_class, desc->p_level);
1528  stp_deprintf(STP_DBG_VARS, "   driver %s mandatory %d active %d channel %d verify %d ro %d\n",
1529	       stp_get_driver(v), desc->is_mandatory, desc->is_active,
1530	       desc->channel, desc->verify_this_parameter, desc->read_only);
1531  switch (desc->p_type)
1532    {
1533    case STP_PARAMETER_TYPE_STRING_LIST:
1534      stp_deprintf(STP_DBG_VARS,
1535		   "   String default: %s\n",
1536		   desc->deflt.str ? desc->deflt.str : "(null)");
1537      if (desc->bounds.str)
1538	for (i = 0; i < stp_string_list_count(desc->bounds.str); i++)
1539	  {
1540	    if (i == 0)
1541	      stp_deprintf(STP_DBG_VARS, "          Choices: %s\n",
1542			   stp_string_list_param(desc->bounds.str, i)->name);
1543	    else
1544	      stp_deprintf(STP_DBG_VARS, "                 : %s\n",
1545			   stp_string_list_param(desc->bounds.str, i)->name);
1546	  }
1547      break;
1548    case STP_PARAMETER_TYPE_INT:
1549      stp_deprintf(STP_DBG_VARS,
1550		   "   Integer default: %d Bounds: %d %d\n",
1551		   desc->deflt.integer,
1552		   desc->bounds.integer.lower, desc->bounds.integer.upper);
1553      break;
1554    case STP_PARAMETER_TYPE_DIMENSION:
1555      stp_deprintf(STP_DBG_VARS,
1556		   "   Dimension default: %d Bounds: %d %d\n",
1557		   desc->deflt.dimension,
1558		   desc->bounds.dimension.lower, desc->bounds.dimension.upper);
1559      break;
1560    case STP_PARAMETER_TYPE_BOOLEAN:
1561      stp_deprintf(STP_DBG_VARS,
1562		   "   Boolean default: %d\n", desc->deflt.boolean);
1563      break;
1564    case STP_PARAMETER_TYPE_DOUBLE:
1565      stp_deprintf(STP_DBG_VARS,
1566		   "   Double default: %f Bounds: %f %f\n",
1567		   desc->deflt.dbl,
1568		   desc->bounds.dbl.lower, desc->bounds.dbl.upper);
1569      break;
1570    case STP_PARAMETER_TYPE_FILE:
1571      stp_deprintf(STP_DBG_VARS, "   File (no default)\n");
1572      break;
1573    case STP_PARAMETER_TYPE_RAW:
1574      stp_deprintf(STP_DBG_VARS, "   Raw (no default)\n");
1575      break;
1576    case STP_PARAMETER_TYPE_CURVE:
1577      curve = stp_curve_write_string(desc->deflt.curve);
1578      stp_deprintf(STP_DBG_VARS,
1579		   "   Curve default: %s\n", curve);
1580      stp_free(curve);
1581      curve = stp_curve_write_string(desc->bounds.curve);
1582      stp_deprintf(STP_DBG_VARS,
1583		   "          bounds: %s\n", curve);
1584      stp_free(curve);
1585      break;
1586    case STP_PARAMETER_TYPE_ARRAY:
1587      stp_deprintf(STP_DBG_VARS, "   Array\n");
1588      break;
1589    case STP_PARAMETER_TYPE_INVALID:
1590      stp_deprintf(STP_DBG_VARS, "   *** Invalid ***\n");
1591      break;
1592    default:
1593      stp_deprintf(STP_DBG_VARS, "   Unknown type!\n");
1594    }
1595}
1596
1597void
1598stp_describe_parameter(const stp_vars_t *v, const char *name,
1599		       stp_parameter_t *description)
1600{
1601  description->p_type = STP_PARAMETER_TYPE_INVALID;
1602/* Set these to NULL in case stpi_*_describe_parameter() doesn't */
1603  description->bounds.str = NULL;
1604  description->deflt.str = NULL;
1605  stp_printer_describe_parameter(v, name, description);
1606  if (description->p_type != STP_PARAMETER_TYPE_INVALID)
1607    {
1608      debug_print_parameter_description(description, "driver", v);
1609      return;
1610    }
1611  stp_color_describe_parameter(v, name, description);
1612  if (description->p_type != STP_PARAMETER_TYPE_INVALID)
1613    {
1614      debug_print_parameter_description(description, "color", v);
1615      return;
1616    }
1617  stp_dither_describe_parameter(v, name, description);
1618  if (description->p_type != STP_PARAMETER_TYPE_INVALID)
1619    {
1620      debug_print_parameter_description(description, "dither", v);
1621      return;
1622    }
1623  stpi_describe_generic_parameter(v, name, description);
1624  if (description->p_type != STP_PARAMETER_TYPE_INVALID)
1625    debug_print_parameter_description(description, "generic", v);
1626  else
1627    stp_deprintf(STP_DBG_VARS, "Describing invalid parameter %s\n", name);
1628}
1629
1630stp_string_list_t *
1631stp_parameter_get_categories(const stp_vars_t *v, const stp_parameter_t *desc)
1632{
1633  const char *dptr;
1634  stp_string_list_t *answer;
1635  int count = 0;
1636  if (!v || !desc || !(desc->category))
1637    return NULL;
1638  answer = stp_string_list_create();
1639  dptr = desc->category;
1640  while (dptr)
1641    {
1642      const char *xptr = strchr(dptr, '=');
1643      if (xptr)
1644	{
1645	  char *name = stp_strndup(dptr, xptr - dptr);
1646	  char *text;
1647	  dptr = xptr + 1;
1648	  xptr = strchr(dptr, ',');
1649	  if (xptr)
1650	    {
1651	      text = stp_strndup(dptr, xptr - dptr);
1652	      dptr = xptr + 1;
1653	    }
1654	  else
1655	    {
1656	      text = stp_strdup(dptr);
1657	      dptr = NULL;
1658	    }
1659	  stp_string_list_add_string(answer, name, text);
1660	  stp_free(name);
1661	  stp_free(text);
1662	  count++;
1663	}
1664      else
1665	dptr = NULL;
1666    }
1667  if (count == 0)
1668    {
1669      stp_string_list_destroy(answer);
1670      return NULL;
1671    }
1672  else
1673    return answer;
1674}
1675
1676char *
1677stp_parameter_get_category(const stp_vars_t *v, const stp_parameter_t *desc,
1678			   const char *category)
1679{
1680  const char *dptr;
1681  char *cptr;
1682  int len;
1683  if (!v || !desc || !(desc->category) || !category)
1684    return NULL;
1685  dptr = desc->category;
1686  stp_asprintf(&cptr, "%s=", category);
1687  len = stp_strlen(cptr);
1688  while (dptr)
1689    {
1690      if (strncmp(dptr, cptr, len) == 0)
1691	{
1692	  const char *xptr;
1693	  char *answer;
1694	  dptr += len;
1695	  xptr = strchr(dptr, ',');
1696	  if (xptr)
1697	    answer = stp_strndup(dptr, xptr - dptr);
1698	  else
1699	    answer = stp_strdup(dptr);
1700	  stp_free(cptr);
1701	  return answer;
1702	}
1703      dptr = strchr(dptr, ',');
1704      if (dptr)
1705	dptr++;
1706    }
1707  return NULL;
1708}
1709
1710int
1711stp_parameter_has_category_value(const stp_vars_t *v,
1712				 const stp_parameter_t *desc,
1713				 const char *category, const char *value)
1714{
1715  const char *dptr;
1716  char *cptr;
1717  int answer = 0;
1718  if (!v || !desc || !category)
1719    return -1;
1720  cptr = stp_parameter_get_category(v, desc, category);
1721  if (cptr == NULL)
1722    return 0;
1723  if (value == NULL || strcmp(value, cptr) == 0)
1724    answer = 1;
1725  stp_free(cptr);
1726  return answer;
1727}
1728
1729const stp_parameter_t *
1730stp_parameter_find_in_settings(const stp_vars_t *v, const char *name)
1731{
1732  stp_parameter_list_t param_list = stp_get_parameter_list(v);
1733  const stp_parameter_t *param = stp_parameter_find(param_list, name);
1734  stp_parameter_list_destroy(param_list);
1735  return param;
1736}
1737
1738size_t
1739stp_parameter_list_count(stp_const_parameter_list_t list)
1740{
1741  const stp_list_t *ilist = (const stp_list_t *)list;
1742  return stp_list_get_length(ilist);
1743}
1744
1745const stp_parameter_t *
1746stp_parameter_find(stp_const_parameter_list_t list, const char *name)
1747{
1748  const stp_list_t *ilist = (const stp_list_t *)list;
1749  const stp_list_item_t *item = stp_list_get_item_by_name(ilist, name);
1750  if (item)
1751    return (const stp_parameter_t *) stp_list_item_get_data(item);
1752  else
1753    return NULL;
1754}
1755
1756const stp_parameter_t *
1757stp_parameter_list_param(stp_const_parameter_list_t list, size_t item)
1758{
1759  const stp_list_t *ilist = (const stp_list_t *)list;
1760  if (item >= stp_list_get_length(ilist))
1761    return NULL;
1762  else
1763    return (const stp_parameter_t *)
1764      stp_list_item_get_data(stp_list_get_item_by_index(ilist, item));
1765}
1766
1767void
1768stp_parameter_list_destroy(stp_parameter_list_t list)
1769{
1770  stp_list_destroy((stp_list_t *)list);
1771}
1772
1773stp_parameter_list_t
1774stp_parameter_list_copy(stp_const_parameter_list_t list)
1775{
1776  stp_list_t *ret = stp_parameter_list_create();
1777  int i;
1778  size_t count = stp_parameter_list_count(list);
1779  for (i = 0; i < count; i++)
1780    stp_list_item_create(ret, NULL, stp_parameter_list_param(list, i));
1781  return (stp_parameter_list_t) ret;
1782}
1783
1784void
1785stp_parameter_list_append(stp_parameter_list_t list,
1786			  stp_const_parameter_list_t append)
1787{
1788  int i;
1789  stp_list_t *ilist = (stp_list_t *)list;
1790  size_t count = stp_parameter_list_count(append);
1791  for (i = 0; i < count; i++)
1792    {
1793      const stp_parameter_t *param = stp_parameter_list_param(append, i);
1794      if (!stp_list_get_item_by_name(ilist, param->name))
1795	stp_list_item_create(ilist, NULL, param);
1796    }
1797}
1798
1799static void
1800fill_vars_from_xmltree(stp_mxml_node_t *prop, stp_mxml_node_t *root,
1801		       stp_vars_t *v)
1802{
1803#ifdef HAVE_LOCALE_H
1804  char *locale = stp_strdup(setlocale(LC_ALL, NULL));
1805  setlocale(LC_ALL, "C");
1806#endif
1807  while (prop)
1808    {
1809      if (prop->type == STP_MXML_ELEMENT &&
1810	  !strcmp(prop->value.element.name, "parameter") &&
1811	  (prop->child || stp_mxmlElementGetAttr(prop, "name")))
1812	{
1813	  stp_mxml_node_t *child = prop->child;
1814	  const char *prop_name = prop->value.element.name;
1815	  const char *p_type = stp_mxmlElementGetAttr(prop, "type");
1816	  const char *p_name = stp_mxmlElementGetAttr(prop, "name");
1817	  if (!strcmp(prop_name, "parameter") && (!p_type || !p_name))
1818	    stp_erprintf("Bad property found!\n");
1819	  else if (!strcmp(prop_name, "parameter"))
1820	    {
1821	      const char *active = stp_mxmlElementGetAttr(prop, "active");
1822	      const char *cref = stp_mxmlElementGetAttr(prop, "ref");
1823	      stp_mxml_node_t *cnode = child;
1824	      stp_parameter_type_t type = STP_PARAMETER_TYPE_INVALID;
1825	      if (cref && root)
1826		{
1827		  cnode = stp_mxmlFindElement(root, root, "namedParam",
1828					      "name", cref,
1829					      STP_MXML_DESCEND);
1830		  STPI_ASSERT(cnode && cnode->type == STP_MXML_ELEMENT &&
1831			 cnode->child, v);
1832		  stp_deprintf(STP_DBG_XML, "Found parameter ref %s\n", cref);
1833		  cnode = cnode->child;
1834		}
1835	      if (strcmp(p_type, "float") == 0)
1836		{
1837		  if (cnode->type == STP_MXML_TEXT)
1838		    {
1839		      stp_set_float_parameter
1840			(v, p_name, stp_xmlstrtod(cnode->value.text.string));
1841		      type = STP_PARAMETER_TYPE_DOUBLE;
1842		      if (stp_get_debug_level() & STP_DBG_XML)
1843			stp_deprintf(STP_DBG_XML, "  Set float '%s' to '%s' (%f)\n",
1844				     p_name, cnode->value.text.string,
1845				     stp_get_float_parameter(v, p_name));
1846		    }
1847		}
1848	      else if (strcmp(p_type, "integer") == 0)
1849		{
1850		  if (cnode->type == STP_MXML_TEXT)
1851		    {
1852		      stp_set_int_parameter
1853			(v, p_name, (int) stp_xmlstrtol(cnode->value.text.string));
1854		      type = STP_PARAMETER_TYPE_DOUBLE;
1855		      if (stp_get_debug_level() & STP_DBG_XML)
1856			stp_deprintf(STP_DBG_XML, "  Set int '%s' to '%s' (%d)\n",
1857				     p_name, cnode->value.text.string,
1858				     stp_get_int_parameter(v, p_name));
1859		    }
1860		}
1861	      else if (strcmp(p_type, "dimension") == 0)
1862		{
1863		  if (cnode->type == STP_MXML_TEXT)
1864		    {
1865		      stp_set_dimension_parameter
1866			(v, p_name, (int) stp_xmlstrtol(cnode->value.text.string));
1867		      type = STP_PARAMETER_TYPE_DOUBLE;
1868		      if (stp_get_debug_level() & STP_DBG_XML)
1869			stp_deprintf(STP_DBG_XML, "  Set dimension '%s' to '%s' (%d)\n",
1870				     p_name, cnode->value.text.string,
1871				     stp_get_dimension_parameter(v, p_name));
1872		    }
1873		}
1874	      else if (strcmp(p_type, "boolean") == 0)
1875		{
1876		  if (cnode->type == STP_MXML_TEXT)
1877		    {
1878		      stp_set_boolean_parameter
1879			(v, p_name, (int) stp_xmlstrtol(cnode->value.text.string));
1880		      type = STP_PARAMETER_TYPE_DOUBLE;
1881		      if (stp_get_debug_level() & STP_DBG_XML)
1882			stp_deprintf(STP_DBG_XML, "  Set bool '%s' to '%s' (%d)\n",
1883				     p_name, cnode->value.text.string,
1884				     stp_get_boolean_parameter(v, p_name));
1885		    }
1886		}
1887	      else if (strcmp(p_type, "string") == 0)
1888		{
1889		  if (cnode->type == STP_MXML_TEXT)
1890		    {
1891		      stp_set_string_parameter
1892			(v, p_name, cnode->value.text.string);
1893		      type = STP_PARAMETER_TYPE_DOUBLE;
1894		      if (stp_get_debug_level() & STP_DBG_XML)
1895			stp_deprintf(STP_DBG_XML, "  Set string '%s' to '%s' (%s)\n",
1896				     p_name, cnode->value.text.string,
1897				     stp_get_string_parameter(v, p_name));
1898		    }
1899		}
1900	      else if (strcmp(p_type, "file") == 0)
1901		{
1902		  if (cnode->type == STP_MXML_TEXT)
1903		    {
1904		      stp_set_file_parameter
1905			(v, p_name, cnode->value.text.string);
1906		      type = STP_PARAMETER_TYPE_DOUBLE;
1907		      if (stp_get_debug_level() & STP_DBG_XML)
1908			stp_deprintf(STP_DBG_XML, "  Set file '%s' to '%s' (%s)\n",
1909				     p_name, cnode->value.text.string,
1910				     stp_get_file_parameter(v, p_name));
1911		    }
1912		}
1913	      else if (strcmp(p_type, "raw") == 0)
1914		{
1915		  if (cnode->type == STP_MXML_TEXT)
1916		    {
1917		      stp_raw_t *raw = stp_xmlstrtoraw(cnode->value.text.string);
1918		      if (raw)
1919			{
1920			  stp_set_raw_parameter(v, p_name, raw->data,raw->bytes);
1921			  type = STP_PARAMETER_TYPE_DOUBLE;
1922			  stp_deprintf(STP_DBG_XML, "  Set raw '%s' to '%s'\n",
1923				       p_name, cnode->value.text.string);
1924			  stp_free((void *) raw->data);
1925			  stp_free(raw);
1926			}
1927		    }
1928		}
1929	      else if (strcmp(p_type, "curve") == 0)
1930		{
1931		  stp_curve_t *curve;
1932		  while (cnode->type != STP_MXML_ELEMENT && cnode->next)
1933		    cnode = cnode->next;
1934		  STPI_ASSERT(cnode, v);
1935		  curve = stp_curve_create_from_xmltree(cnode);
1936		  STPI_ASSERT(curve, v);
1937		  stp_set_curve_parameter(v, p_name, curve);
1938		  type = STP_PARAMETER_TYPE_DOUBLE;
1939		  if (stp_get_debug_level() & STP_DBG_XML)
1940		    {
1941		      char *cv = stp_curve_write_string(curve);
1942		      stp_deprintf(STP_DBG_XML, "  Set curve '%s' (%s)\n",
1943				   p_name, cv);
1944		      stp_free(cv);
1945		    }
1946		  stp_curve_destroy(curve);
1947		}
1948	      else if (strcmp(p_type, "array") == 0)
1949		{
1950		  stp_array_t *array;
1951		  while (cnode->type != STP_MXML_ELEMENT && cnode->next)
1952		    cnode = cnode->next;
1953		  STPI_ASSERT(cnode, v);
1954		  array = stp_array_create_from_xmltree(cnode);
1955		  STPI_ASSERT(array, v);
1956		  type = STP_PARAMETER_TYPE_DOUBLE;
1957		  stp_set_array_parameter(v, p_name, array);
1958		  stp_deprintf(STP_DBG_XML, "  Set array '%s'\n", p_name);
1959		  stp_array_destroy(array);
1960		}
1961	      else
1962		{
1963		  stp_erprintf("Bad property %s type %s\n", p_name, p_type);
1964		}
1965	      if (active && type != STP_PARAMETER_TYPE_INVALID)
1966		{
1967		  if (strcmp(active, "active") == 0)
1968		    stp_set_parameter_active(v, p_name, STP_PARAMETER_ACTIVE, type);
1969		  else if (strcmp(active, "inactive") == 0)
1970		    stp_set_parameter_active(v, p_name, STP_PARAMETER_INACTIVE, type);
1971		  else if (strcmp(active, "default") == 0)
1972		    stp_set_parameter_active(v, p_name, STP_PARAMETER_DEFAULTED, type);
1973		}
1974
1975	    }
1976	  else if (child->type == STP_MXML_TEXT)
1977	    {
1978	      if (!strcmp(prop_name, "driver"))
1979		stp_set_driver(v, child->value.text.string);
1980	      else if (!strcmp(prop_name, "color_conversion"))
1981		stp_set_color_conversion(v, child->value.text.string);
1982	      else if (!strcmp(prop_name, "left"))
1983		stp_set_left(v, stp_xmlstrtol(child->value.text.string));
1984	      else if (!strcmp(prop_name, "top"))
1985		stp_set_top(v, stp_xmlstrtol(child->value.text.string));
1986	      else if (!strcmp(prop_name, "width"))
1987		stp_set_width(v, stp_xmlstrtol(child->value.text.string));
1988	      else if (!strcmp(prop_name, "height"))
1989		stp_set_height(v, stp_xmlstrtol(child->value.text.string));
1990	      else if (!strcmp(prop_name, "page_width"))
1991		stp_set_page_width(v, stp_xmlstrtol(child->value.text.string));
1992	      else if (!strcmp(prop_name, "page_height"))
1993		stp_set_page_height(v, stp_xmlstrtol(child->value.text.string));
1994	    }
1995	}
1996      prop = prop->next;
1997    }
1998#ifdef HAVE_LOCALE_H
1999  setlocale(LC_ALL, locale);
2000  stp_free(locale);
2001#endif
2002}
2003
2004void
2005stp_vars_fill_from_xmltree(stp_mxml_node_t *prop, stp_vars_t *v)
2006{
2007  fill_vars_from_xmltree(prop, NULL, v);
2008}
2009
2010stp_vars_t *
2011stp_vars_create_from_xmltree(stp_mxml_node_t *da)
2012{
2013  stp_vars_t *v = stp_vars_create();
2014  fill_vars_from_xmltree(da, NULL, v);
2015  return v;
2016}
2017
2018void
2019stp_vars_fill_from_xmltree_ref(stp_mxml_node_t *prop, stp_mxml_node_t *root,
2020			       stp_vars_t *v)
2021{
2022  fill_vars_from_xmltree(prop, root, v);
2023}
2024
2025stp_vars_t *
2026stp_vars_create_from_xmltree_ref(stp_mxml_node_t *da, stp_mxml_node_t *root)
2027{
2028  stp_vars_t *v = stp_vars_create();
2029  fill_vars_from_xmltree(da, root, v);
2030  return v;
2031}
2032
2033static void
2034add_text_node(stp_mxml_node_t *node, const char *element, const char *value)
2035{
2036  if (value)
2037    stp_mxmlNewOpaque(stp_mxmlNewElement(node, element), value);
2038}
2039
2040stp_mxml_node_t *
2041stp_xmltree_create_from_vars(const stp_vars_t *v)
2042{
2043  stp_mxml_node_t *varnode;
2044  int i;
2045  if (!v)
2046    return NULL;
2047  varnode = stp_mxmlNewElement(NULL, "vars");
2048  add_text_node(varnode, "driver", stp_get_driver(v));
2049  add_text_node(varnode, "color_conversion", stp_get_color_conversion(v));
2050  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "left"), stp_get_left(v));
2051  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "top"), stp_get_top(v));
2052  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "width"), stp_get_width(v));
2053  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "height"), stp_get_height(v));
2054  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "page_width"), stp_get_page_width(v));
2055  stp_mxmlNewInteger(stp_mxmlNewElement(varnode, "page_height"), stp_get_page_height(v));
2056  for (i = STP_PARAMETER_TYPE_STRING_LIST; i < STP_PARAMETER_TYPE_INVALID; i++)
2057    {
2058      stp_string_list_t *list = stp_list_parameters(v, i);
2059      if (list)
2060	{
2061	  int j;
2062	  int count = stp_string_list_count(list);
2063	  for (j = 0; j < count; j++)
2064	    {
2065	      const stp_param_string_t *pstr = stp_string_list_param(list, j);
2066	      const char *name = pstr->name;
2067	      char *data;
2068	      stp_mxml_node_t *node = stp_mxmlNewElement(varnode, "parameter");
2069	      stp_parameter_activity_t active =
2070		stp_get_parameter_active(v, name, i);
2071	      stp_mxmlElementSetAttr(node, "name", name);
2072	      stp_mxmlElementSetAttr(node, "active",
2073				     (active == STP_PARAMETER_INACTIVE ?
2074				      "inactive" :
2075				      (active == STP_PARAMETER_DEFAULTED ?
2076				       "default" : "active")));
2077	      switch (i)
2078		{
2079		case STP_PARAMETER_TYPE_STRING_LIST:
2080		  stp_mxmlElementSetAttr(node, "type", "string");
2081		  data = stp_strtoxmlstr(stp_get_string_parameter(v, name));
2082		  if (data)
2083		    {
2084		      stp_mxmlNewOpaque(node, data);
2085		      stp_free(data);
2086		    }
2087		  break;
2088		case STP_PARAMETER_TYPE_INT:
2089		  stp_mxmlElementSetAttr(node, "type", "integer");
2090		  stp_mxmlNewInteger(node, stp_get_int_parameter(v, name));
2091		  break;
2092		case STP_PARAMETER_TYPE_BOOLEAN:
2093		  stp_mxmlElementSetAttr(node, "type", "boolean");
2094		  stp_mxmlNewInteger(node, stp_get_boolean_parameter(v, name));
2095		  break;
2096		case STP_PARAMETER_TYPE_DOUBLE:
2097		  stp_mxmlElementSetAttr(node, "type", "float");
2098		  stp_mxmlNewReal(node, stp_get_float_parameter(v, name));
2099		  break;
2100		case STP_PARAMETER_TYPE_CURVE:
2101		  stp_mxmlElementSetAttr(node, "type", "curve");
2102		  stp_mxmlAdd(node, STP_MXML_ADD_AFTER, NULL,
2103			      stp_xmltree_create_from_curve(stp_get_curve_parameter(v, name)));
2104		  break;
2105		case STP_PARAMETER_TYPE_FILE:
2106		  stp_mxmlElementSetAttr(node, "type", "file");
2107		  data = stp_strtoxmlstr(stp_get_file_parameter(v, name));
2108		  if (data)
2109		    {
2110		      stp_mxmlNewOpaque(node, data);
2111		      stp_free(data);
2112		    }
2113		  break;
2114		case STP_PARAMETER_TYPE_RAW:
2115		  stp_mxmlElementSetAttr(node, "type", "raw");
2116		  data = stp_rawtoxmlstr(stp_get_raw_parameter(v, name));
2117		  if (data)
2118		    {
2119		      stp_mxmlNewOpaque(node, data);
2120		      stp_free(data);
2121		    }
2122		  break;
2123		case STP_PARAMETER_TYPE_ARRAY:
2124		  stp_mxmlElementSetAttr(node, "type", "array");
2125		  stp_mxmlAdd(node, STP_MXML_ADD_AFTER, NULL,
2126			      stp_xmltree_create_from_array(stp_get_array_parameter(v, name)));
2127		  break;
2128		case STP_PARAMETER_TYPE_DIMENSION:
2129		  stp_mxmlElementSetAttr(node, "type", "dimension");
2130		  stp_mxmlNewInteger(node, stp_get_dimension_parameter(v, name));
2131		  break;
2132		default:
2133		  stp_mxmlElementSetAttr(node, "type", "INVALID!");
2134		  break;
2135		}
2136	    }
2137	  stp_string_list_destroy(list);
2138	}
2139    }
2140  return varnode;
2141}
2142