1/*
2 * "$Id: printers.c,v 1.89 2010/08/07 02:30:38 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 <gutenprint/gutenprint.h>
33#include "gutenprint-internal.h"
34#include <gutenprint/gutenprint-intl-internal.h>
35#include <math.h>
36#ifdef HAVE_LIMITS_H
37#include <limits.h>
38#endif
39#include <string.h>
40#include <stdlib.h>
41
42#define FMIN(a, b) ((a) < (b) ? (a) : (b))
43
44
45static void stpi_printvars_freefunc(void *item);
46static const char* stpi_printvars_namefunc(const void *item);
47
48static stp_list_t *printvars_list = NULL;
49
50typedef struct stp_printvars
51{
52  const char *name;
53  stp_vars_t *printvars;
54} stp_printvars_t;
55
56static void stpi_printer_freefunc(void *item);
57static const char* stpi_printer_namefunc(const void *item);
58static const char* stpi_printer_long_namefunc(const void *item);
59
60static stp_list_t *printer_list = NULL;
61
62struct stp_printer
63{
64  const char *driver;
65  char       *long_name;        /* Long name for UI */
66  char       *family;           /* Printer family */
67  char	     *manufacturer;	/* Printer manufacturer */
68  char	     *device_id; 	/* IEEE 1284 device ID */
69  char       *foomatic_id;	/* Foomatic printer ID */
70  int        model;             /* Model number */
71  int	     vars_initialized;
72  const stp_printfuncs_t *printfuncs;
73  stp_vars_t *printvars;
74};
75
76static void
77stpi_init_printvars_list(void)
78{
79  if (!printvars_list)
80    {
81      printvars_list = stp_list_create();
82      stp_list_set_freefunc(printvars_list, stpi_printvars_freefunc);
83      stp_list_set_namefunc(printvars_list, stpi_printvars_namefunc);
84      stp_list_set_long_namefunc(printvars_list, stpi_printvars_namefunc);
85    }
86}
87
88static int
89stpi_init_printer_list(void)
90{
91  if(printer_list)
92    stp_list_destroy(printer_list);
93  printer_list = stp_list_create();
94  stp_list_set_freefunc(printer_list, stpi_printer_freefunc);
95  stp_list_set_namefunc(printer_list, stpi_printer_namefunc);
96  stp_list_set_long_namefunc(printer_list, stpi_printer_long_namefunc);
97  /* stp_list_set_sortfunc(printer_list, stpi_printer_sortfunc); */
98  return 0;
99}
100
101int
102stp_printer_model_count(void)
103{
104  if (printer_list == NULL)
105    {
106      stp_erprintf("No printer drivers found: "
107		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
108      stpi_init_printer_list();
109    }
110  return stp_list_get_length(printer_list);
111}
112
113const stp_printer_t *
114stp_get_printer_by_index(int idx)
115{
116  stp_list_item_t *printer;
117  if (printer_list == NULL)
118    {
119      stp_erprintf("No printer drivers found: "
120		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
121      stpi_init_printer_list();
122    }
123  printer = stp_list_get_item_by_index(printer_list, idx);
124  if (printer == NULL)
125    return NULL;
126  return (const stp_printer_t *) stp_list_item_get_data(printer);
127}
128
129static void
130stpi_printer_freefunc(void *item)
131{
132  stp_printer_t *printer = (stp_printer_t *) item;
133  stp_free(printer->long_name);
134  stp_free(printer->family);
135  stp_free(printer);
136}
137
138/* ARGSUSED */
139static void
140stpi_printvars_freefunc(void *item)
141{
142}
143
144static const char *
145stpi_printvars_namefunc(const void *item)
146{
147  const stp_printvars_t *printvars = (const stp_printvars_t *) item;
148  return printvars->name;
149}
150
151const char *
152stp_printer_get_driver(const stp_printer_t *printer)
153{
154  return printer->driver;
155}
156
157static const char *
158stpi_printer_namefunc(const void *item)
159{
160  const stp_printer_t *printer = (const stp_printer_t *) item;
161  return printer->driver;
162}
163
164const char *
165stp_printer_get_long_name(const stp_printer_t *printer)
166{
167  return printer->long_name;
168}
169
170static const char *
171stpi_printer_long_namefunc(const void *item)
172{
173  const stp_printer_t *printer = (const stp_printer_t *) item;
174  return printer->long_name;
175}
176
177const char *
178stp_printer_get_device_id(const stp_printer_t *printer)
179{
180  return printer->device_id;
181}
182
183const char *
184stp_printer_get_family(const stp_printer_t *printer)
185{
186  return printer->family;
187}
188
189const char *
190stp_printer_get_manufacturer(const stp_printer_t *printer)
191{
192  return printer->manufacturer;
193}
194
195const char *
196stp_printer_get_foomatic_id(const stp_printer_t *printer)
197{
198  return printer->foomatic_id;
199}
200
201int
202stp_printer_get_model(const stp_printer_t *printer)
203{
204  return printer->model;
205}
206
207static inline const stp_printfuncs_t *
208stpi_get_printfuncs(const stp_printer_t *printer)
209{
210  return printer->printfuncs;
211}
212
213
214const stp_printer_t *
215stp_get_printer_by_long_name(const char *long_name)
216{
217  stp_list_item_t *printer_item;
218  if (printer_list == NULL)
219    {
220      stp_erprintf("No printer drivers found: "
221		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
222      stpi_init_printer_list();
223    }
224  printer_item = stp_list_get_item_by_long_name(printer_list, long_name);
225  if (!printer_item)
226    return NULL;
227  return (const stp_printer_t *) stp_list_item_get_data(printer_item);
228}
229
230const stp_printer_t *
231stp_get_printer_by_driver(const char *driver)
232{
233  stp_list_item_t *printer_item;
234  if (printer_list == NULL)
235    {
236      stp_erprintf("No printer drivers found: "
237		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
238      stpi_init_printer_list();
239    }
240  printer_item = stp_list_get_item_by_name(printer_list, driver);
241  if (!printer_item)
242    return NULL;
243  return (const stp_printer_t *) stp_list_item_get_data(printer_item);
244}
245
246const stp_printer_t *
247stp_get_printer_by_device_id(const char *device_id)
248{
249  stp_list_item_t *printer_item;
250  if (printer_list == NULL)
251    {
252      stp_erprintf("No printer drivers found: "
253		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
254      stpi_init_printer_list();
255    }
256  if (! device_id || strcmp(device_id, "") == 0)
257    return NULL;
258
259  printer_item = stp_list_get_start(printer_list);
260  while (printer_item)
261    {
262      if (strcmp(((const stp_printer_t *) stp_list_item_get_data(printer_item))->device_id,
263		 device_id) == 0)
264	return ((const stp_printer_t *) stp_list_item_get_data(printer_item));
265      printer_item = stp_list_item_next(printer_item);
266    }
267  return NULL;
268}
269
270const stp_printer_t *
271stp_get_printer_by_foomatic_id(const char *foomatic_id)
272{
273  stp_list_item_t *printer_item;
274  if (printer_list == NULL)
275    {
276      stp_erprintf("No printer drivers found: "
277		   "are STP_DATA_PATH and STP_MODULE_PATH correct?\n");
278      stpi_init_printer_list();
279    }
280  if (! foomatic_id || strcmp(foomatic_id, "") == 0)
281    return NULL;
282
283  printer_item = stp_list_get_start(printer_list);
284  while (printer_item)
285    {
286      if (strcmp(((const stp_printer_t *) stp_list_item_get_data(printer_item))->foomatic_id,
287		 foomatic_id) == 0)
288	return ((const stp_printer_t *) stp_list_item_get_data(printer_item));
289      printer_item = stp_list_item_next(printer_item);
290    }
291  return NULL;
292}
293
294int
295stp_get_printer_index_by_driver(const char *driver)
296{
297  /* There should be no need to ever know the index! */
298  int idx = 0;
299  for (idx = 0; idx < stp_printer_model_count(); idx++)
300    {
301      const stp_printer_t *printer = stp_get_printer_by_index(idx);
302      if (!strcmp(stp_printer_get_driver(printer), driver))
303	return idx;
304    }
305  return -1;
306}
307
308const stp_printer_t *
309stp_get_printer(const stp_vars_t *v)
310{
311  return stp_get_printer_by_driver(stp_get_driver(v));
312}
313
314int
315stp_get_model_id(const stp_vars_t *v)
316{
317  const stp_printer_t *printer = stp_get_printer_by_driver(stp_get_driver(v));
318  return printer->model;
319}
320
321stp_parameter_list_t
322stp_printer_list_parameters(const stp_vars_t *v)
323{
324  const stp_printfuncs_t *printfuncs =
325    stpi_get_printfuncs(stp_get_printer(v));
326  return (printfuncs->list_parameters)(v);
327}
328
329void
330stp_printer_describe_parameter(const stp_vars_t *v, const char *name,
331			       stp_parameter_t *description)
332{
333  const stp_printfuncs_t *printfuncs =
334    stpi_get_printfuncs(stp_get_printer(v));
335  (printfuncs->parameters)(v, name, description);
336}
337
338static void
339set_printer_defaults(stp_vars_t *v, int core_only, int soft)
340{
341  stp_parameter_list_t *params;
342  int count;
343  int i;
344  stp_parameter_t desc;
345  params = stp_get_parameter_list(v);
346  count = stp_parameter_list_count(params);
347  for (i = 0; i < count; i++)
348    {
349      const stp_parameter_t *p = stp_parameter_list_param(params, i);
350      if (p->is_mandatory &&
351	  (!core_only || p->p_class == STP_PARAMETER_CLASS_CORE))
352	{
353	  stp_describe_parameter(v, p->name, &desc);
354	  switch (p->p_type)
355	    {
356	    case STP_PARAMETER_TYPE_STRING_LIST:
357	      if (!soft ||
358		  !stp_check_string_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
359		{
360		  stp_set_string_parameter(v, p->name, desc.deflt.str);
361		  stp_set_string_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
362		}
363	      break;
364	    case STP_PARAMETER_TYPE_DOUBLE:
365	      if (!soft ||
366		  !stp_check_float_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
367		{
368		  stp_set_float_parameter(v, p->name, desc.deflt.dbl);
369		  stp_set_float_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
370		}
371	      break;
372	    case STP_PARAMETER_TYPE_INT:
373	      if (!soft ||
374		  !stp_check_int_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
375		{
376		  stp_set_int_parameter(v, p->name, desc.deflt.integer);
377		  stp_set_int_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
378		}
379	      break;
380	    case STP_PARAMETER_TYPE_DIMENSION:
381	      if (!soft ||
382		  !stp_check_dimension_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
383		{
384		  stp_set_dimension_parameter(v, p->name, desc.deflt.dimension);
385		  stp_set_dimension_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
386		}
387	      break;
388	    case STP_PARAMETER_TYPE_BOOLEAN:
389	      if (!soft ||
390		  !stp_check_boolean_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
391		{
392		  stp_set_boolean_parameter(v, p->name, desc.deflt.boolean);
393		  stp_set_boolean_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
394		}
395	      break;
396	    case STP_PARAMETER_TYPE_CURVE:
397	      if (!soft ||
398		  !stp_check_curve_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
399		{
400		  stp_set_curve_parameter(v, p->name, desc.deflt.curve);
401		  stp_set_curve_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
402		}
403	      break;
404	    case STP_PARAMETER_TYPE_ARRAY:
405	      if (!soft ||
406		  !stp_check_array_parameter(v, p->name, STP_PARAMETER_DEFAULTED))
407		{
408		  stp_set_array_parameter(v, p->name, desc.deflt.array);
409		  stp_set_array_parameter_active(v, p->name, STP_PARAMETER_ACTIVE);
410		}
411	      break;
412	    default:
413	      break;
414	    }
415	  stp_parameter_description_destroy(&desc);
416	}
417    }
418  stp_parameter_list_destroy(params);
419}
420
421void
422stp_set_printer_defaults(stp_vars_t *v, const stp_printer_t *printer)
423{
424  stp_set_driver(v, stp_printer_get_driver(printer));
425  set_printer_defaults(v, 0, 0);
426}
427
428void
429stp_set_printer_defaults_soft(stp_vars_t *v, const stp_printer_t *printer)
430{
431  stp_set_driver(v, stp_printer_get_driver(printer));
432  set_printer_defaults(v, 0, 1);
433}
434
435void
436stp_initialize_printer_defaults(void)
437{
438  if (printer_list == NULL)
439    {
440      stpi_init_printer_list();
441      stp_deprintf
442	(STP_DBG_PRINTERS,
443	 "stpi_family_register(): initialising printer_list...\n");
444    }
445}
446
447const stp_vars_t *
448stp_printer_get_defaults(const stp_printer_t *printer)
449{
450  if (! printer->vars_initialized)
451    {
452      stp_printer_t *nc_printer = (stp_printer_t *) printer;
453      stp_deprintf(STP_DBG_PRINTERS, "  ==>init %s\n", printer->driver);
454      set_printer_defaults (nc_printer->printvars, 1, 0);
455      nc_printer->vars_initialized = 1;
456    }
457  return printer->printvars;
458}
459
460void
461stp_get_media_size(const stp_vars_t *v, int *width, int *height)
462{
463  const stp_printfuncs_t *printfuncs =
464    stpi_get_printfuncs(stp_get_printer(v));
465  (printfuncs->media_size)(v, width, height);
466}
467
468void
469stp_get_imageable_area(const stp_vars_t *v,
470		       int *left, int *right, int *bottom, int *top)
471{
472  const stp_printfuncs_t *printfuncs =
473    stpi_get_printfuncs(stp_get_printer(v));
474  (printfuncs->imageable_area)(v, left, right, bottom, top);
475}
476
477void
478stp_get_maximum_imageable_area(const stp_vars_t *v,
479			       int *left, int *right, int *bottom, int *top)
480{
481  const stp_printfuncs_t *printfuncs =
482    stpi_get_printfuncs(stp_get_printer(v));
483  (printfuncs->maximum_imageable_area)(v, left, right, bottom, top);
484}
485
486void
487stp_get_size_limit(const stp_vars_t *v, int *max_width, int *max_height,
488		   int *min_width, int *min_height)
489{
490  const stp_printfuncs_t *printfuncs =
491    stpi_get_printfuncs(stp_get_printer(v));
492  (printfuncs->limit)(v, max_width, max_height, min_width,min_height);
493}
494
495void
496stp_describe_resolution(const stp_vars_t *v, int *x, int *y)
497{
498  const stp_printfuncs_t *printfuncs =
499    stpi_get_printfuncs(stp_get_printer(v));
500  (printfuncs->describe_resolution)(v, x, y);
501}
502
503const char *
504stp_describe_output(const stp_vars_t *v)
505{
506  const stp_printfuncs_t *printfuncs =
507    stpi_get_printfuncs(stp_get_printer(v));
508  return (printfuncs->describe_output)(v);
509}
510
511int
512stp_verify(stp_vars_t *v)
513{
514  const stp_printfuncs_t *printfuncs =
515    stpi_get_printfuncs(stp_get_printer(v));
516  stp_vars_t *nv = stp_vars_create_copy(v);
517  int status;
518  stp_prune_inactive_options(nv);
519  status = (printfuncs->verify)(nv);
520  stp_set_verified(v, stp_get_verified(nv));
521  stp_vars_destroy(nv);
522  return status;
523}
524
525int
526stp_print(const stp_vars_t *v, stp_image_t *image)
527{
528  const stp_printfuncs_t *printfuncs =
529    stpi_get_printfuncs(stp_get_printer(v));
530  return (printfuncs->print)(v, image);
531}
532
533int
534stp_start_job(const stp_vars_t *v, stp_image_t *image)
535{
536  const stp_printfuncs_t *printfuncs =
537    stpi_get_printfuncs(stp_get_printer(v));
538  if (!stp_get_string_parameter(v, "JobMode") ||
539      strcmp(stp_get_string_parameter(v, "JobMode"), "Page") == 0)
540    return 1;
541  if (printfuncs->start_job)
542    return (printfuncs->start_job)(v, image);
543  else
544    return 1;
545}
546
547int
548stp_end_job(const stp_vars_t *v, stp_image_t *image)
549{
550  const stp_printfuncs_t *printfuncs =
551    stpi_get_printfuncs(stp_get_printer(v));
552  if (!stp_get_string_parameter(v, "JobMode") ||
553      strcmp(stp_get_string_parameter(v, "JobMode"), "Page") == 0)
554    return 1;
555  if (printfuncs->end_job)
556    return (printfuncs->end_job)(v, image);
557  else
558    return 1;
559}
560
561stp_string_list_t *
562stp_get_external_options(const stp_vars_t *v)
563{
564  const stp_printfuncs_t *printfuncs =
565    stpi_get_printfuncs(stp_get_printer(v));
566  if (printfuncs->get_external_options)
567    return (printfuncs->get_external_options)(v);
568  else
569    return NULL;
570}
571
572static int
573verify_string_param(const stp_vars_t *v, const char *parameter,
574		    stp_parameter_t *desc, int quiet)
575{
576  stp_parameter_verify_t answer = PARAMETER_OK;
577  stp_dprintf(STP_DBG_VARS, v, "    Verifying string %s\n", parameter);
578  if (desc->is_mandatory ||
579      stp_check_string_parameter(v, parameter, STP_PARAMETER_ACTIVE))
580    {
581      const char *checkval = stp_get_string_parameter(v, parameter);
582      stp_string_list_t *vptr = desc->bounds.str;
583      size_t count = 0;
584      int i;
585      stp_dprintf(STP_DBG_VARS, v, "     value %s\n",
586		  checkval ? checkval : "(null)");
587      if (vptr)
588	count = stp_string_list_count(vptr);
589      answer = PARAMETER_BAD;
590      if (checkval == NULL)
591	{
592	  if (count == 0)
593	    answer = PARAMETER_OK;
594	  else
595	    {
596	      if (!quiet)
597		stp_eprintf(v, _("Value must be set for %s\n"), parameter);
598	      answer = PARAMETER_BAD;
599	    }
600	}
601      else if (count > 0)
602	{
603	  for (i = 0; i < count; i++)
604	    if (!strcmp(checkval, stp_string_list_param(vptr, i)->name))
605	      {
606		answer = PARAMETER_OK;
607		break;
608	      }
609	  if (!answer && !quiet)
610	    stp_eprintf(v, _("`%s' is not a valid %s\n"), checkval, parameter);
611	}
612      else if (strlen(checkval) == 0)
613	answer = PARAMETER_OK;
614      else if (!quiet)
615	stp_eprintf(v, _("`%s' is not a valid %s\n"), checkval, parameter);
616    }
617  stp_parameter_description_destroy(desc);
618  return answer;
619}
620
621static int
622verify_double_param(const stp_vars_t *v, const char *parameter,
623		    stp_parameter_t *desc, int quiet)
624{
625  stp_dprintf(STP_DBG_VARS, v, "    Verifying double %s\n", parameter);
626  if (desc->is_mandatory ||
627      stp_check_float_parameter(v, parameter, STP_PARAMETER_ACTIVE))
628    {
629      double checkval = stp_get_float_parameter(v, parameter);
630      if (checkval < desc->bounds.dbl.lower ||
631	  checkval > desc->bounds.dbl.upper)
632	{
633	  if (!quiet)
634	    stp_eprintf(v, _("%s must be between %f and %f (is %f)\n"),
635			parameter, desc->bounds.dbl.lower,
636			desc->bounds.dbl.upper, checkval);
637	  return PARAMETER_BAD;
638	}
639    }
640  return PARAMETER_OK;
641}
642
643static int
644verify_int_param(const stp_vars_t *v, const char *parameter,
645		 stp_parameter_t *desc, int quiet)
646{
647  stp_dprintf(STP_DBG_VARS, v, "    Verifying int %s\n", parameter);
648  if (desc->is_mandatory ||
649      stp_check_int_parameter(v, parameter, STP_PARAMETER_ACTIVE))
650    {
651      int checkval = stp_get_int_parameter(v, parameter);
652      if (checkval < desc->bounds.integer.lower ||
653	  checkval > desc->bounds.integer.upper)
654	{
655	  if (!quiet)
656	    stp_eprintf(v, _("%s must be between %d and %d (is %d)\n"),
657			parameter, desc->bounds.integer.lower,
658			desc->bounds.integer.upper, checkval);
659	  stp_parameter_description_destroy(desc);
660	  return PARAMETER_BAD;
661	}
662    }
663  stp_parameter_description_destroy(desc);
664  return PARAMETER_OK;
665}
666
667static int
668verify_dimension_param(const stp_vars_t *v, const char *parameter,
669		 stp_parameter_t *desc, int quiet)
670{
671  stp_dprintf(STP_DBG_VARS, v, "    Verifying dimension %s\n", parameter);
672  if (desc->is_mandatory ||
673      stp_check_dimension_parameter(v, parameter, STP_PARAMETER_ACTIVE))
674    {
675      int checkval = stp_get_dimension_parameter(v, parameter);
676      if (checkval < desc->bounds.dimension.lower ||
677	  checkval > desc->bounds.dimension.upper)
678	{
679	  if (!quiet)
680	    stp_eprintf(v, _("%s must be between %d and %d (is %d)\n"),
681			parameter, desc->bounds.dimension.lower,
682			desc->bounds.dimension.upper, checkval);
683	  stp_parameter_description_destroy(desc);
684	  return PARAMETER_BAD;
685	}
686    }
687  stp_parameter_description_destroy(desc);
688  return PARAMETER_OK;
689}
690
691static int
692verify_curve_param(const stp_vars_t *v, const char *parameter,
693		   stp_parameter_t *desc, int quiet)
694{
695  stp_parameter_verify_t answer = 1;
696  stp_dprintf(STP_DBG_VARS, v, "    Verifying curve %s\n", parameter);
697  if (desc->bounds.curve &&
698      (desc->is_mandatory ||
699       stp_check_curve_parameter(v, parameter, STP_PARAMETER_ACTIVE)))
700    {
701      const stp_curve_t *checkval = stp_get_curve_parameter(v, parameter);
702      if (checkval)
703	{
704	  double u0, l0;
705	  double u1, l1;
706	  stp_curve_get_bounds(checkval, &l0, &u0);
707	  stp_curve_get_bounds(desc->bounds.curve, &l1, &u1);
708	  if (u0 > u1 || l0 < l1)
709	    {
710	      if (!quiet)
711		stp_eprintf(v, _("%s bounds must be between %f and %f\n"),
712			    parameter, l1, u1);
713	      answer = PARAMETER_BAD;
714	    }
715	  if (stp_curve_get_wrap(checkval) !=
716	      stp_curve_get_wrap(desc->bounds.curve))
717	    {
718	      if (!quiet)
719		stp_eprintf(v, _("%s wrap mode must be %s\n"),
720			    parameter,
721			    (stp_curve_get_wrap(desc->bounds.curve) ==
722			     STP_CURVE_WRAP_NONE) ?
723			    _("no wrap") : _("wrap around"));
724	      answer = PARAMETER_BAD;
725	    }
726	}
727    }
728  stp_parameter_description_destroy(desc);
729  return answer;
730}
731
732stp_parameter_verify_t
733stp_verify_parameter(const stp_vars_t *v, const char *parameter,
734		     int quiet)
735{
736  stp_parameter_t desc;
737  quiet = 0;
738  stp_describe_parameter(v, parameter, &desc);
739  stp_dprintf(STP_DBG_VARS, v, "  Verifying %s %d %d\n", parameter,
740	      desc.is_active, desc.read_only);
741  if (!desc.is_active || desc.read_only)
742    {
743      stp_parameter_description_destroy(&desc);
744      return PARAMETER_INACTIVE;
745    }
746  switch (desc.p_type)
747    {
748    case STP_PARAMETER_TYPE_STRING_LIST:
749      return verify_string_param(v, parameter, &desc, quiet);
750    case STP_PARAMETER_TYPE_DOUBLE:
751      return verify_double_param(v, parameter, &desc, quiet);
752    case STP_PARAMETER_TYPE_INT:
753      return verify_int_param(v, parameter, &desc, quiet);
754    case STP_PARAMETER_TYPE_DIMENSION:
755      return verify_dimension_param(v, parameter, &desc, quiet);
756    case STP_PARAMETER_TYPE_CURVE:
757      return verify_curve_param(v, parameter, &desc, quiet);
758    case STP_PARAMETER_TYPE_RAW:
759    case STP_PARAMETER_TYPE_FILE:
760      stp_parameter_description_destroy(&desc);
761      return PARAMETER_OK;		/* No way to verify this here */
762    case STP_PARAMETER_TYPE_BOOLEAN:
763      stp_parameter_description_destroy(&desc);
764      return PARAMETER_OK;		/* Booleans always OK */
765    default:
766      if (!quiet)
767	stp_eprintf(v, _("Unknown type parameter %s (%d)\n"),
768		    parameter, desc.p_type);
769      stp_parameter_description_destroy(&desc);
770      return 0;
771    }
772}
773
774#define CHECK_INT_RANGE(v, component, min, max)				    \
775do									    \
776{									    \
777  if (stp_get_##component((v)) < (min) || stp_get_##component((v)) > (max)) \
778    {									    \
779      answer = 0;							    \
780      stp_eprintf(v, _("%s out of range (value %d, min %d, max %d)\n"),     \
781		  #component, stp_get_##component(v), min, max);	    \
782    }									    \
783} while (0)
784
785#define CHECK_INT_RANGE_INTERNAL(v, component, min, max)		      \
786do									      \
787{									      \
788  if (stpi_get_##component((v)) < (min) || stpi_get_##component((v)) > (max)) \
789    {									      \
790      answer = 0;							      \
791      stp_eprintf(v, _("%s out of range (value %d, min %d, max %d)\n"),       \
792		  #component, stpi_get_##component(v), min, max);	      \
793    }									      \
794} while (0)
795
796typedef struct
797{
798  char *data;
799  size_t bytes;
800} errbuf_t;
801
802static void
803fill_buffer_writefunc(void *priv, const char *buffer, size_t bytes)
804{
805  errbuf_t *errbuf = (errbuf_t *) priv;
806  if (errbuf->bytes == 0)
807    errbuf->data = stp_malloc(bytes + 1);
808  else
809    errbuf->data = stp_realloc(errbuf->data, errbuf->bytes + bytes + 1);
810  memcpy(errbuf->data + errbuf->bytes, buffer, bytes);
811  errbuf->bytes += bytes;
812  errbuf->data[errbuf->bytes] = '\0';
813}
814
815int
816stp_verify_printer_params(stp_vars_t *v)
817{
818  errbuf_t errbuf;
819  stp_outfunc_t ofunc = stp_get_errfunc(v);
820  void *odata = stp_get_errdata(v);
821  stp_parameter_list_t params;
822  int nparams;
823  int i;
824  int answer = 1;
825  int left, top, bottom, right;
826  const char *pagesize = stp_get_string_parameter(v, "PageSize");
827
828  stp_dprintf(STP_DBG_VARS, v, "** Entering stp_verify_printer_params(0x%p)\n",
829	      (void *) v);
830
831  stp_set_errfunc((stp_vars_t *) v, fill_buffer_writefunc);
832  stp_set_errdata((stp_vars_t *) v, &errbuf);
833
834  errbuf.data = NULL;
835  errbuf.bytes = 0;
836
837  if (pagesize && strlen(pagesize) > 0)
838    {
839      if (stp_verify_parameter(v, "PageSize", 0) == 0)
840	answer = 0;
841    }
842  else
843    {
844      int width, height, min_height, min_width;
845      stp_get_size_limit(v, &width, &height, &min_width, &min_height);
846      if (stp_get_page_height(v) <= min_height ||
847	  stp_get_page_height(v) > height ||
848	  stp_get_page_width(v) <= min_width || stp_get_page_width(v) > width)
849	{
850	  answer = 0;
851	  stp_eprintf(v, _("Page size is not valid\n"));
852	}
853      stp_dprintf(STP_DBG_PAPER, v,
854		  "page size max %d %d min %d %d actual %d %d\n",
855		  width, height, min_width, min_height,
856		  stp_get_page_width(v), stp_get_page_height(v));
857    }
858
859  stp_get_imageable_area(v, &left, &right, &bottom, &top);
860
861  stp_dprintf(STP_DBG_PAPER, v,
862	      "page      left %d top %d right %d bottom %d\n",
863	      left, top, right, bottom);
864  stp_dprintf(STP_DBG_PAPER, v,
865	      "requested left %d top %d width %d height %d\n",
866	      stp_get_left(v), stp_get_top(v),
867	      stp_get_width(v), stp_get_height(v));
868
869  if (stp_get_top(v) < top)
870    {
871      answer = 0;
872      stp_eprintf(v, _("Top margin must not be less than %d\n"), top);
873    }
874
875  if (stp_get_left(v) < left)
876    {
877      answer = 0;
878      stp_eprintf(v, _("Left margin must not be less than %d\n"), left);
879    }
880
881  if (stp_get_height(v) <= 0)
882    {
883      answer = 0;
884      stp_eprintf(v, _("Height must be greater than zero\n"));
885    }
886
887  if (stp_get_width(v) <= 0)
888    {
889      answer = 0;
890      stp_eprintf(v, _("Width must be greater than zero\n"));
891    }
892
893  if (stp_get_left(v) + stp_get_width(v) > right)
894    {
895      answer = 0;
896      stp_eprintf(v, _("Image is too wide for the page: left margin is %d, width %d, right edge is %d\n"),
897		  stp_get_left(v), stp_get_width(v), right);
898    }
899
900  if (stp_get_top(v) + stp_get_height(v) > bottom)
901    {
902      answer = 0;
903      stp_eprintf(v, _("Image is too long for the page: top margin is %d, height %d, bottom edge is %d\n"),
904		  stp_get_top(v), stp_get_height(v), bottom);
905    }
906
907  params = stp_get_parameter_list(v);
908  nparams = stp_parameter_list_count(params);
909  for (i = 0; i < nparams; i++)
910    {
911      const stp_parameter_t *param = stp_parameter_list_param(params, i);
912      stp_dprintf(STP_DBG_VARS, v, "Checking %s %d %d\n", param->name,
913		  param->is_active, param->verify_this_parameter);
914
915      if (strcmp(param->name, "PageSize") != 0 &&
916	  param->is_active && param->verify_this_parameter &&
917	  stp_verify_parameter(v, param->name, 0) == 0)
918	answer = 0;
919    }
920  stp_parameter_list_destroy(params);
921  stp_set_errfunc((stp_vars_t *) v, ofunc);
922  stp_set_errdata((stp_vars_t *) v, odata);
923  stp_set_verified((stp_vars_t *) v, answer);
924  if (errbuf.bytes > 0)
925    {
926      stp_eprintf(v, "%s", errbuf.data);
927      stp_free(errbuf.data);
928    }
929  stp_dprintf(STP_DBG_VARS, v, "** Exiting stp_verify_printer_params(0x%p) => %d\n",
930	      (void *) v, answer);
931  return answer;
932}
933
934static const stp_vars_t *
935stp_find_params(const char *name, const char *family)
936{
937  if (printvars_list)
938    {
939      char *stmp =
940	stp_malloc(strlen(family) + strlen("::") + strlen(name) + 1);
941      stp_list_item_t *item;
942      strcpy(stmp, family);
943      strcat(stmp, "::");
944      strcat(stmp, name);
945      item = stp_list_get_item_by_name(printvars_list, stmp);
946      if (item)
947	{
948	  stp_free(stmp);
949	  return ((const stp_printvars_t *)
950		  stp_list_item_get_data(item))->printvars;
951	}
952      strcpy(stmp, name);
953      item = stp_list_get_item_by_name(printvars_list, stmp);
954      stp_free(stmp);
955      if (item)
956	return ((const stp_printvars_t *)
957		stp_list_item_get_data(item))->printvars;
958    }
959  return NULL;
960}
961
962int
963stp_family_register(stp_list_t *family)
964{
965  stp_list_item_t *printer_item;
966  const stp_printer_t *printer;
967
968  if (printer_list == NULL)
969    {
970      stpi_init_printer_list();
971      stp_deprintf
972	(STP_DBG_PRINTERS,
973	 "stpi_family_register(): initialising printer_list...\n");
974    }
975
976  if (family)
977    {
978      printer_item = stp_list_get_start(family);
979
980      while(printer_item)
981	{
982	  printer = (const stp_printer_t *) stp_list_item_get_data(printer_item);
983	  if (!stp_list_get_item_by_name(printer_list, printer->driver))
984	    stp_list_item_create(printer_list, NULL, printer);
985	  printer_item = stp_list_item_next(printer_item);
986	}
987    }
988
989  return 0;
990}
991
992int
993stp_family_unregister(stp_list_t *family)
994{
995  stp_list_item_t *printer_item;
996  stp_list_item_t *old_printer_item;
997  const stp_printer_t *printer;
998
999  if (printer_list == NULL)
1000    {
1001      stpi_init_printer_list();
1002      stp_deprintf
1003	(STP_DBG_PRINTERS,
1004	 "stpi_family_unregister(): initialising printer_list...\n");
1005    }
1006
1007  if (family)
1008    {
1009      printer_item = stp_list_get_start(family);
1010
1011      while(printer_item)
1012	{
1013	  printer = (const stp_printer_t *) stp_list_item_get_data(printer_item);
1014	  old_printer_item =
1015	    stp_list_get_item_by_name(printer_list, printer->driver);
1016
1017	  if (old_printer_item)
1018	    stp_list_item_destroy(printer_list, old_printer_item);
1019	  printer_item = stp_list_item_next(printer_item);
1020	}
1021    }
1022  return 0;
1023}
1024
1025static stp_printvars_t *
1026stp_printvars_create_from_xmltree(stp_mxml_node_t *printer,
1027				  const char *family)
1028{
1029  stp_mxml_node_t *prop;	/* Temporary node pointer */
1030  const char *stmp;		/* Temporary string */
1031  char *sbuf;
1032  stp_printvars_t *outprintvars;
1033  outprintvars = stp_zalloc(sizeof(stp_printvars_t));
1034  if (!outprintvars)
1035    return NULL;
1036  outprintvars->printvars = stp_vars_create();
1037  if (outprintvars->printvars == NULL)
1038    {
1039      stp_free(outprintvars);
1040      return NULL;
1041    }
1042  stmp = stp_mxmlElementGetAttr(printer, "name");
1043  if (!stmp)
1044    {
1045      stp_vars_destroy(outprintvars->printvars);
1046      stp_free(outprintvars);
1047      return NULL;
1048    }
1049  sbuf = stp_malloc(strlen(family) + strlen("::") + strlen(stmp) + 1);
1050  strcpy(sbuf, family);
1051  strcat(sbuf, "::");
1052  strcat(sbuf, stmp);
1053  outprintvars->name = sbuf;
1054  prop = printer->child;
1055  stp_deprintf(STP_DBG_XML, ">>stp_printvars_create_from_xmltree: %p, %s\n",
1056	       (void *) (outprintvars->printvars), outprintvars->name);
1057  stp_vars_fill_from_xmltree(prop, outprintvars->printvars);
1058  stp_deprintf(STP_DBG_XML, "<<stp_printvars_create_from_xmltree: %p, %s\n",
1059	       (void *) (outprintvars->printvars), outprintvars->name);
1060  return outprintvars;
1061}
1062
1063
1064/*
1065 * Parse the printer node, and return the generated printer.  Returns
1066 * NULL on failure.
1067 */
1068static stp_printer_t*
1069stp_printer_create_from_xmltree(stp_mxml_node_t *printer, /* The printer node */
1070				const char *family,       /* Family name */
1071				const stp_printfuncs_t *printfuncs)
1072                                                       /* Family printfuncs */
1073{
1074  stp_mxml_node_t *prop;	/* Temporary node pointer */
1075  const char *stmp;		/* Temporary string */
1076  stp_printer_t *outprinter;	/* Generated printer */
1077  int
1078    driver = 0,			/* Check driver */
1079    long_name = 0;
1080
1081  outprinter = stp_zalloc(sizeof(stp_printer_t));
1082  if (!outprinter)
1083    return NULL;
1084  stmp = stp_mxmlElementGetAttr(printer, "parameters");
1085  if (stmp && !stp_find_params(stmp, family))
1086    stp_erprintf("stp_printer_create_from_xmltree: cannot find parameters %s::%s\n",
1087		 family, stmp);
1088  if (stmp && stp_find_params(stmp, family))
1089    outprinter->printvars = stp_vars_create_copy(stp_find_params(stmp, family));
1090  else
1091    outprinter->printvars = stp_vars_create();
1092  if (outprinter->printvars == NULL)
1093    {
1094      stp_free(outprinter);
1095      return NULL;
1096    }
1097
1098  stmp = stp_mxmlElementGetAttr(printer, "driver");
1099  stp_set_driver(outprinter->printvars, (const char *) stmp);
1100
1101  outprinter->long_name = stp_strdup(stp_mxmlElementGetAttr(printer, "name"));
1102  outprinter->manufacturer = stp_strdup(stp_mxmlElementGetAttr(printer, "manufacturer"));
1103  outprinter->model = stp_xmlstrtol(stp_mxmlElementGetAttr(printer, "model"));
1104  outprinter->family = stp_strdup((const char *) family);
1105  stmp = stp_mxmlElementGetAttr(printer, "deviceid");
1106  if (stmp)
1107    outprinter->device_id = stp_strdup(stmp);
1108  stmp = stp_mxmlElementGetAttr(printer, "foomaticid");
1109  if (stmp)
1110    outprinter->foomatic_id = stp_strdup(stmp);
1111
1112  if (stp_get_driver(outprinter->printvars))
1113    driver = 1;
1114  if (outprinter->long_name)
1115    long_name = 1;
1116
1117  outprinter->printfuncs = printfuncs;
1118
1119  prop = printer->child;
1120  stp_vars_fill_from_xmltree(prop, outprinter->printvars);
1121  if (driver && long_name && printfuncs)
1122    {
1123      if (stp_get_debug_level() & STP_DBG_XML)
1124	{
1125	  stmp = stp_mxmlElementGetAttr(printer, "driver");
1126	  stp_erprintf("stp_printer_create_from_xmltree: printer: %s\n", stmp);
1127	}
1128      outprinter->driver = stp_get_driver(outprinter->printvars);
1129      return outprinter;
1130    }
1131  stp_free(outprinter);
1132  return NULL;
1133}
1134
1135/*
1136 * Parse the <family> node.
1137 */
1138static void
1139stpi_xml_process_family(stp_mxml_node_t *family)     /* The family node */
1140{
1141  stp_list_t *family_module_list = NULL;      /* List of valid families */
1142  stp_list_item_t *family_module_item;        /* Current family */
1143  const char *family_name;                       /* Name of family */
1144  stp_mxml_node_t *printer;                         /* printer child node */
1145  stp_module_t *family_module_data;           /* Family module data */
1146  stp_family_t *family_data = NULL;  /* Family data */
1147  int family_valid = 0;                       /* Is family valid? */
1148
1149  family_module_list = stp_module_get_class(STP_MODULE_CLASS_FAMILY);
1150  if (!family_module_list)
1151    return;
1152
1153  family_name = stp_mxmlElementGetAttr(family, "name");
1154  family_module_item = stp_list_get_start(family_module_list);
1155  while (family_module_item)
1156    {
1157      family_module_data = (stp_module_t *)
1158	stp_list_item_get_data(family_module_item);
1159      if (!strcmp(family_name, family_module_data->name))
1160	{
1161	  stp_deprintf(STP_DBG_XML,
1162		       "stpi_xml_process_family: family module: %s\n",
1163		       family_module_data->name);
1164	  family_data = family_module_data->syms;
1165	  if (family_data->printer_list == NULL)
1166	    family_data->printer_list = stp_list_create();
1167	  family_valid = 1;
1168	}
1169      family_module_item = stp_list_item_next(family_module_item);
1170    }
1171
1172  printer = family->child;
1173  while (family_valid && printer)
1174    {
1175      if (printer->type == STP_MXML_ELEMENT)
1176	{
1177	  const char *printer_name = printer->value.element.name;
1178	  if (!strcmp(printer_name, "printer"))
1179	    {
1180	      stp_printer_t *outprinter =
1181		stp_printer_create_from_xmltree(printer, family_name,
1182						family_data->printfuncs);
1183	      if (outprinter)
1184		stp_list_item_create(family_data->printer_list, NULL,
1185				      outprinter);
1186	    }
1187	  else if (!strcmp(printer_name, "parameters"))
1188	    {
1189	      stp_printvars_t *printvars =
1190		stp_printvars_create_from_xmltree(printer, family_name);
1191	      if (printvars)
1192		{
1193		  stpi_init_printvars_list();
1194		  stp_list_item_create(printvars_list, NULL, printvars);
1195		}
1196	    }
1197	}
1198      printer = printer->next;
1199    }
1200
1201  stp_list_destroy(family_module_list);
1202  return;
1203}
1204
1205/*
1206 * Parse the <printdef> node.
1207 */
1208static int
1209stpi_xml_process_printdef(stp_mxml_node_t *printdef, const char *file) /* The printdef node */
1210{
1211  stp_mxml_node_t *family;                          /* Family child node */
1212
1213  family = printdef->child;
1214  while (family)
1215    {
1216      if (family->type == STP_MXML_ELEMENT)
1217	{
1218	  const char *family_name = family->value.element.name;
1219	  if (!strcmp(family_name, "family"))
1220	    {
1221	      stpi_xml_process_family(family);
1222	    }
1223	}
1224      family = family->next;
1225    }
1226  return 1;
1227}
1228
1229void
1230stpi_init_printer(void)
1231{
1232  stp_register_xml_parser("printdef", stpi_xml_process_printdef);
1233  stp_register_xml_preload("printers.xml");
1234}
1235