1//
2// "$Id: ppdc-source.cxx 11560 2014-02-06 20:10:19Z msweet $"
3//
4// Source class for the CUPS PPD Compiler.
5//
6// Copyright 2007-2014 by Apple Inc.
7// Copyright 2002-2007 by Easy Software Products.
8//
9// These coded instructions, statements, and computer programs are the
10// property of Apple Inc. and are protected by Federal copyright
11// law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12// which should have been included with this file.  If this file is
13// file is missing or damaged, see the license at "http://www.cups.org/".
14//
15
16//
17// Include necessary headers...
18//
19
20#include "ppdc-private.h"
21#include <limits.h>
22#include <math.h>
23#include <unistd.h>
24#include <cups/raster.h>
25#include "data/epson.h"
26#include "data/hp.h"
27#include "data/label.h"
28#ifndef WIN32
29#  include <sys/utsname.h>
30#endif // !WIN32
31
32
33//
34// Class globals...
35//
36
37ppdcArray	*ppdcSource::includes = 0;
38const char	*ppdcSource::driver_types[] =
39		{
40		  "custom",
41		  "ps",
42		  "escp",
43		  "pcl",
44		  "label",
45		  "epson",
46		  "hp"
47		};
48
49
50//
51// 'ppdcSource::ppdcSource()' - Load a driver source file.
52//
53
54ppdcSource::ppdcSource(const char  *f,	// I - File to read
55                       cups_file_t *ffp)// I - File pointer to use
56  : ppdcShared()
57{
58  PPDC_NEW;
59
60  filename      = new ppdcString(f);
61  base_fonts    = new ppdcArray();
62  drivers       = new ppdcArray();
63  po_files      = new ppdcArray();
64  sizes         = new ppdcArray();
65  vars          = new ppdcArray();
66  cond_state    = PPDC_COND_NORMAL;
67  cond_current  = cond_stack;
68  cond_stack[0] = PPDC_COND_NORMAL;
69
70  // Add standard #define variables...
71#define MAKE_STRING(x) #x
72
73  vars->add(new ppdcVariable("CUPS_VERSION", MAKE_STRING(CUPS_VERSION)));
74  vars->add(new ppdcVariable("CUPS_VERSION_MAJOR", MAKE_STRING(CUPS_VERSION_MAJOR)));
75  vars->add(new ppdcVariable("CUPS_VERSION_MINOR", MAKE_STRING(CUPS_VERSION_MINOR)));
76  vars->add(new ppdcVariable("CUPS_VERSION_PATCH", MAKE_STRING(CUPS_VERSION_PATCH)));
77
78#ifdef WIN32
79  vars->add(new ppdcVariable("PLATFORM_NAME", "Windows"));
80  vars->add(new ppdcVariable("PLATFORM_ARCH", "X86"));
81
82#else
83  struct utsname name;			// uname information
84
85  if (!uname(&name))
86  {
87    vars->add(new ppdcVariable("PLATFORM_NAME", name.sysname));
88    vars->add(new ppdcVariable("PLATFORM_ARCH", name.machine));
89  }
90  else
91  {
92    vars->add(new ppdcVariable("PLATFORM_NAME", "unknown"));
93    vars->add(new ppdcVariable("PLATFORM_ARCH", "unknown"));
94  }
95#endif // WIN32
96
97  if (f)
98    read_file(f, ffp);
99}
100
101
102//
103// 'ppdcSource::~ppdcSource()' - Free a driver source file.
104//
105
106ppdcSource::~ppdcSource()
107{
108  PPDC_DELETE;
109
110  filename->release();
111  base_fonts->release();
112  drivers->release();
113  po_files->release();
114  sizes->release();
115  vars->release();
116}
117
118
119//
120// 'ppdcSource::add_include()' - Add an include directory.
121//
122
123void
124ppdcSource::add_include(const char *d)	// I - Include directory
125{
126  if (!d)
127    return;
128
129  if (!includes)
130    includes = new ppdcArray();
131
132  includes->add(new ppdcString(d));
133}
134
135
136//
137// 'ppdcSource::find_driver()' - Find a driver.
138//
139
140ppdcDriver *				// O - Driver
141ppdcSource::find_driver(const char *f)	// I - Driver file name
142{
143  ppdcDriver	*d;			// Current driver
144
145
146  for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
147    if (!_cups_strcasecmp(f, d->pc_file_name->value))
148      return (d);
149
150  return (NULL);
151}
152
153
154//
155// 'ppdcSource::find_include()' - Find an include file.
156//
157
158char *					// O - Found path or NULL
159ppdcSource::find_include(
160    const char *f,			// I - Include filename
161    const char *base,			// I - Current directory
162    char       *n,			// I - Path buffer
163    int        nlen)			// I - Path buffer length
164{
165  ppdcString	*dir;			// Include directory
166  char		temp[1024],		// Temporary path
167		*ptr;			// Pointer to end of path
168
169
170  // Range check input...
171  if (!f || !*f || !n || nlen < 2)
172    return (0);
173
174  // Check the first character to see if we have <name> or "name"...
175  if (*f == '<')
176  {
177    // Remove the surrounding <> from the name...
178    strlcpy(temp, f + 1, sizeof(temp));
179    ptr = temp + strlen(temp) - 1;
180
181    if (*ptr != '>')
182    {
183      _cupsLangPrintf(stderr,
184                      _("ppdc: Invalid #include/#po filename \"%s\"."), n);
185      return (0);
186    }
187
188    *ptr = '\0';
189    f    = temp;
190  }
191  else
192  {
193    // Check for the local file relative to the current directory...
194    if (base && *base && f[0] != '/')
195      snprintf(n, (size_t)nlen, "%s/%s", base, f);
196    else
197      strlcpy(n, f, (size_t)nlen);
198
199    if (!access(n, 0))
200      return (n);
201    else if (*f == '/')
202    {
203      // Absolute path that doesn't exist...
204      return (0);
205    }
206  }
207
208  // Search the include directories, if any...
209  if (includes)
210  {
211    for (dir = (ppdcString *)includes->first(); dir; dir = (ppdcString *)includes->next())
212    {
213      snprintf(n, (size_t)nlen, "%s/%s", dir->value, f);
214      if (!access(n, 0))
215        return (n);
216    }
217  }
218
219  // Search the standard include directories...
220  _cups_globals_t *cg = _cupsGlobals();	// Global data
221
222  snprintf(n, (size_t)nlen, "%s/ppdc/%s", cg->cups_datadir, f);
223  if (!access(n, 0))
224    return (n);
225
226  snprintf(n, (size_t)nlen, "%s/po/%s", cg->cups_datadir, f);
227  if (!access(n, 0))
228    return (n);
229  else
230    return (0);
231}
232
233
234//
235// 'ppdcSource::find_po()' - Find a message catalog for the given locale.
236//
237
238ppdcCatalog *				// O - Message catalog or NULL
239ppdcSource::find_po(const char *l)	// I - Locale name
240{
241  ppdcCatalog	*cat;			// Current message catalog
242
243
244  for (cat = (ppdcCatalog *)po_files->first();
245       cat;
246       cat = (ppdcCatalog *)po_files->next())
247    if (!_cups_strcasecmp(l, cat->locale->value))
248      return (cat);
249
250  return (NULL);
251}
252
253
254//
255// 'ppdcSource::find_size()' - Find a media size.
256//
257
258ppdcMediaSize *				// O - Size
259ppdcSource::find_size(const char *s)	// I - Size name
260{
261  ppdcMediaSize	*m;			// Current media size
262
263
264  for (m = (ppdcMediaSize *)sizes->first(); m; m = (ppdcMediaSize *)sizes->next())
265    if (!_cups_strcasecmp(s, m->name->value))
266      return (m);
267
268  return (NULL);
269}
270
271
272//
273// 'ppdcSource::find_variable()' - Find a variable.
274//
275
276ppdcVariable *				// O - Variable
277ppdcSource::find_variable(const char *n)// I - Variable name
278{
279  ppdcVariable	*v;			// Current variable
280
281
282  for (v = (ppdcVariable *)vars->first(); v; v = (ppdcVariable *)vars->next())
283    if (!_cups_strcasecmp(n, v->name->value))
284      return (v);
285
286  return (NULL);
287}
288
289
290//
291// 'ppdcSource::get_attr()' - Get an attribute.
292//
293
294ppdcAttr *				// O - Attribute
295ppdcSource::get_attr(ppdcFile *fp, 	// I - File to read
296                     bool     loc)	// I - Localize this attribute?
297{
298  char	name[1024],			// Name string
299	selector[1024],			// Selector string
300	*text,				// Text string
301	value[1024];			// Value string
302
303
304  // Get the attribute parameters:
305  //
306  // Attribute name selector value
307  if (!get_token(fp, name, sizeof(name)))
308  {
309    _cupsLangPrintf(stderr,
310                    _("ppdc: Expected name after %s on line %d of %s."),
311		    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
312    return (0);
313  }
314
315  if (!get_token(fp, selector, sizeof(selector)))
316  {
317    _cupsLangPrintf(stderr,
318                    _("ppdc: Expected selector after %s on line %d of %s."),
319		    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
320    return (0);
321  }
322
323  if ((text = strchr(selector, '/')) != NULL)
324    *text++ = '\0';
325
326  if (!get_token(fp, value, sizeof(value)))
327  {
328    _cupsLangPrintf(stderr,
329                    _("ppdc: Expected value after %s on line %d of %s."),
330		    loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
331    return (0);
332  }
333
334  return (new ppdcAttr(name, selector, text, value, loc));
335}
336
337
338//
339// 'ppdcSource::get_boolean()' - Get a boolean value.
340//
341
342int					// O - Boolean value
343ppdcSource::get_boolean(ppdcFile *fp)	// I - File to read
344{
345  char	buffer[256];			// String buffer
346
347
348  if (!get_token(fp, buffer, sizeof(buffer)))
349  {
350    _cupsLangPrintf(stderr,
351                    _("ppdc: Expected boolean value on line %d of %s."),
352		    fp->line, fp->filename);
353    return (-1);
354  }
355
356  if (!_cups_strcasecmp(buffer, "on") ||
357      !_cups_strcasecmp(buffer, "yes") ||
358      !_cups_strcasecmp(buffer, "true"))
359    return (1);
360  else if (!_cups_strcasecmp(buffer, "off") ||
361	   !_cups_strcasecmp(buffer, "no") ||
362	   !_cups_strcasecmp(buffer, "false"))
363    return (0);
364  else
365  {
366    _cupsLangPrintf(stderr,
367                    _("ppdc: Bad boolean value (%s) on line %d of %s."),
368		    buffer, fp->line, fp->filename);
369    return (-1);
370  }
371}
372
373
374//
375// 'ppdcSource::get_choice()' - Get a choice.
376//
377
378ppdcChoice *				// O - Choice data
379ppdcSource::get_choice(ppdcFile *fp)	// I - File to read
380{
381  char	name[1024],			// Name
382	*text,				// Text
383	code[10240];			// Code
384
385
386  // Read a choice from the file:
387  //
388  // Choice name/text code
389  if (!get_token(fp, name, sizeof(name)))
390  {
391    _cupsLangPrintf(stderr,
392                    _("ppdc: Expected choice name/text on line %d of %s."),
393		    fp->line, fp->filename);
394    return (NULL);
395  }
396
397  if ((text = strchr(name, '/')) != NULL)
398    *text++ = '\0';
399  else
400    text = name;
401
402  if (!get_token(fp, code, sizeof(code)))
403  {
404    _cupsLangPrintf(stderr, _("ppdc: Expected choice code on line %d of %s."),
405		    fp->line, fp->filename);
406    return (NULL);
407  }
408
409  // Return the new choice
410  return (new ppdcChoice(name, text, code));
411}
412
413
414//
415// 'ppdcSource::get_color_model()' - Get an old-style color model option.
416//
417
418ppdcChoice *				// O - Choice data
419ppdcSource::get_color_model(ppdcFile *fp)
420					// I - File to read
421{
422  char		name[1024],		// Option name
423		*text,			// Text option
424		temp[256];		// Temporary string
425  int		color_space,		// Colorspace
426		color_order,		// Color order
427		compression;		// Compression mode
428
429
430  // Get the ColorModel parameters:
431  //
432  // ColorModel name/text colorspace colororder compression
433  if (!get_token(fp, name, sizeof(name)))
434  {
435    _cupsLangPrintf(stderr,
436                    _("ppdc: Expected name/text combination for ColorModel on "
437		      "line %d of %s."), fp->line, fp->filename);
438    return (NULL);
439  }
440
441  if ((text = strchr(name, '/')) != NULL)
442    *text++ = '\0';
443  else
444    text = name;
445
446  if (!get_token(fp, temp, sizeof(temp)))
447  {
448    _cupsLangPrintf(stderr,
449                    _("ppdc: Expected colorspace for ColorModel on line %d of "
450		      "%s."), fp->line, fp->filename);
451    return (NULL);
452  }
453
454  if ((color_space = get_color_space(temp)) < 0)
455    color_space = get_integer(temp);
456
457  if (!get_token(fp, temp, sizeof(temp)))
458  {
459    _cupsLangPrintf(stderr,
460                    _("ppdc: Expected color order for ColorModel on line %d of "
461		      "%s."), fp->line, fp->filename);
462    return (NULL);
463  }
464
465  if ((color_order = get_color_order(temp)) < 0)
466    color_order = get_integer(temp);
467
468  if (!get_token(fp, temp, sizeof(temp)))
469  {
470    _cupsLangPrintf(stderr,
471                    _("ppdc: Expected compression for ColorModel on line %d of "
472		      "%s."), fp->line, fp->filename);
473    return (NULL);
474  }
475
476  compression = get_integer(temp);
477
478  snprintf(temp, sizeof(temp),
479           "<</cupsColorSpace %d/cupsColorOrder %d/cupsCompression %d>>"
480	   "setpagedevice",
481           color_space, color_order, compression);
482
483  return (new ppdcChoice(name, text, temp));
484}
485
486
487//
488// 'ppdcSource::get_color_order()' - Get an old-style color order value.
489//
490
491int					// O - Color order value
492ppdcSource::get_color_order(
493    const char *co)			// I - Color order string
494{
495  if (!_cups_strcasecmp(co, "chunked") ||
496      !_cups_strcasecmp(co, "chunky"))
497    return (CUPS_ORDER_CHUNKED);
498  else if (!_cups_strcasecmp(co, "banded"))
499    return (CUPS_ORDER_BANDED);
500  else if (!_cups_strcasecmp(co, "planar"))
501    return (CUPS_ORDER_PLANAR);
502  else
503    return (-1);
504}
505
506
507//
508// 'ppdcSource::get_color_profile()' - Get a color profile definition.
509//
510
511ppdcProfile *				// O - Color profile
512ppdcSource::get_color_profile(
513    ppdcFile *fp)			// I - File to read
514{
515  char		resolution[1024],	// Resolution/media type
516		*media_type;		// Media type
517  int		i;			// Looping var
518  float		g,			// Gamma value
519		d,			// Density value
520		m[9];			// Transform matrix
521
522
523  // Get the ColorProfile parameters:
524  //
525  // ColorProfile resolution/mediatype gamma density m00 m01 m02 ... m22
526  if (!get_token(fp, resolution, sizeof(resolution)))
527  {
528    _cupsLangPrintf(stderr,
529                    _("ppdc: Expected resolution/mediatype following "
530		      "ColorProfile on line %d of %s."),
531		    fp->line, fp->filename);
532    return (NULL);
533  }
534
535  if ((media_type = strchr(resolution, '/')) != NULL)
536    *media_type++ = '\0';
537  else
538    media_type = resolution;
539
540  g = get_float(fp);
541  d = get_float(fp);
542  for (i = 0; i < 9; i ++)
543    m[i] = get_float(fp);
544
545  return (new ppdcProfile(resolution, media_type, g, d, m));
546}
547
548
549//
550// 'ppdcSource::get_color_space()' - Get an old-style colorspace value.
551//
552
553int					// O - Colorspace value
554ppdcSource::get_color_space(
555    const char *cs)			// I - Colorspace string
556{
557  if (!_cups_strcasecmp(cs, "w"))
558    return (CUPS_CSPACE_W);
559  else if (!_cups_strcasecmp(cs, "rgb"))
560    return (CUPS_CSPACE_RGB);
561  else if (!_cups_strcasecmp(cs, "rgba"))
562    return (CUPS_CSPACE_RGBA);
563  else if (!_cups_strcasecmp(cs, "k"))
564    return (CUPS_CSPACE_K);
565  else if (!_cups_strcasecmp(cs, "cmy"))
566    return (CUPS_CSPACE_CMY);
567  else if (!_cups_strcasecmp(cs, "ymc"))
568    return (CUPS_CSPACE_YMC);
569  else if (!_cups_strcasecmp(cs, "cmyk"))
570    return (CUPS_CSPACE_CMYK);
571  else if (!_cups_strcasecmp(cs, "ymck"))
572    return (CUPS_CSPACE_YMCK);
573  else if (!_cups_strcasecmp(cs, "kcmy"))
574    return (CUPS_CSPACE_KCMY);
575  else if (!_cups_strcasecmp(cs, "kcmycm"))
576    return (CUPS_CSPACE_KCMYcm);
577  else if (!_cups_strcasecmp(cs, "gmck"))
578    return (CUPS_CSPACE_GMCK);
579  else if (!_cups_strcasecmp(cs, "gmcs"))
580    return (CUPS_CSPACE_GMCS);
581  else if (!_cups_strcasecmp(cs, "white"))
582    return (CUPS_CSPACE_WHITE);
583  else if (!_cups_strcasecmp(cs, "gold"))
584    return (CUPS_CSPACE_GOLD);
585  else if (!_cups_strcasecmp(cs, "silver"))
586    return (CUPS_CSPACE_SILVER);
587  else if (!_cups_strcasecmp(cs, "CIEXYZ"))
588    return (CUPS_CSPACE_CIEXYZ);
589  else if (!_cups_strcasecmp(cs, "CIELab"))
590    return (CUPS_CSPACE_CIELab);
591  else if (!_cups_strcasecmp(cs, "RGBW"))
592    return (CUPS_CSPACE_RGBW);
593  else if (!_cups_strcasecmp(cs, "ICC1"))
594    return (CUPS_CSPACE_ICC1);
595  else if (!_cups_strcasecmp(cs, "ICC2"))
596    return (CUPS_CSPACE_ICC2);
597  else if (!_cups_strcasecmp(cs, "ICC3"))
598    return (CUPS_CSPACE_ICC3);
599  else if (!_cups_strcasecmp(cs, "ICC4"))
600    return (CUPS_CSPACE_ICC4);
601  else if (!_cups_strcasecmp(cs, "ICC5"))
602    return (CUPS_CSPACE_ICC5);
603  else if (!_cups_strcasecmp(cs, "ICC6"))
604    return (CUPS_CSPACE_ICC6);
605  else if (!_cups_strcasecmp(cs, "ICC7"))
606    return (CUPS_CSPACE_ICC7);
607  else if (!_cups_strcasecmp(cs, "ICC8"))
608    return (CUPS_CSPACE_ICC8);
609  else if (!_cups_strcasecmp(cs, "ICC9"))
610    return (CUPS_CSPACE_ICC9);
611  else if (!_cups_strcasecmp(cs, "ICCA"))
612    return (CUPS_CSPACE_ICCA);
613  else if (!_cups_strcasecmp(cs, "ICCB"))
614    return (CUPS_CSPACE_ICCB);
615  else if (!_cups_strcasecmp(cs, "ICCC"))
616    return (CUPS_CSPACE_ICCC);
617  else if (!_cups_strcasecmp(cs, "ICCD"))
618    return (CUPS_CSPACE_ICCD);
619  else if (!_cups_strcasecmp(cs, "ICCE"))
620    return (CUPS_CSPACE_ICCE);
621  else if (!_cups_strcasecmp(cs, "ICCF"))
622    return (CUPS_CSPACE_ICCF);
623  else
624    return (-1);
625}
626
627
628//
629// 'ppdcSource::get_constraint()' - Get a constraint.
630//
631
632ppdcConstraint *			// O - Constraint
633ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
634{
635  char		temp[1024],		// One string to rule them all
636		*ptr,			// Pointer into string
637		*option1,		// Constraint option 1
638		*choice1,		// Constraint choice 1
639		*option2,		// Constraint option 2
640		*choice2;		// Constraint choice 2
641
642
643  // Read the UIConstaints parameter in one of the following forms:
644  //
645  // UIConstraints "*Option1 *Option2"
646  // UIConstraints "*Option1 Choice1 *Option2"
647  // UIConstraints "*Option1 *Option2 Choice2"
648  // UIConstraints "*Option1 Choice1 *Option2 Choice2"
649  if (!get_token(fp, temp, sizeof(temp)))
650  {
651    _cupsLangPrintf(stderr,
652                    _("ppdc: Expected constraints string for UIConstraints on "
653		      "line %d of %s."), fp->line, fp->filename);
654    return (NULL);
655  }
656
657  for (ptr = temp; isspace(*ptr); ptr ++);
658
659  if (*ptr != '*')
660  {
661    _cupsLangPrintf(stderr,
662                    _("ppdc: Option constraint must *name on line %d of %s."),
663		    fp->line, fp->filename);
664    return (NULL);
665  }
666
667  option1 = ptr;
668
669  for (; *ptr && !isspace(*ptr); ptr ++);
670  for (; isspace(*ptr); *ptr++ = '\0');
671
672  if (*ptr != '*')
673  {
674    choice1 = ptr;
675
676    for (; *ptr && !isspace(*ptr); ptr ++);
677    for (; isspace(*ptr); *ptr++ = '\0');
678  }
679  else
680    choice1 = NULL;
681
682  if (*ptr != '*')
683  {
684    _cupsLangPrintf(stderr,
685                    _("ppdc: Expected two option names on line %d of %s."),
686		    fp->line, fp->filename);
687    return (NULL);
688  }
689
690  option2 = ptr;
691
692  for (; *ptr && !isspace(*ptr); ptr ++);
693  for (; isspace(*ptr); *ptr++ = '\0');
694
695  if (*ptr)
696    choice2 = ptr;
697  else
698    choice2 = NULL;
699
700  return (new ppdcConstraint(option1, choice1, option2, choice2));
701}
702
703
704//
705// 'ppdcSource::get_custom_size()' - Get a custom media size definition from a file.
706//
707
708ppdcMediaSize *				// O - Media size
709ppdcSource::get_custom_size(ppdcFile *fp)
710					// I - File to read
711{
712  char		name[1024],		// Name
713		*text,			// Text
714		size_code[10240],	// PageSize code
715		region_code[10240];	// PageRegion
716  float		width,			// Width
717		length,			// Length
718		left,			// Left margin
719		bottom,			// Bottom margin
720		right,			// Right margin
721		top;			// Top margin
722
723
724  // Get the name, text, width, length, margins, and code:
725  //
726  // CustomMedia name/text width length left bottom right top size-code region-code
727  if (!get_token(fp, name, sizeof(name)))
728    return (NULL);
729
730  if ((text = strchr(name, '/')) != NULL)
731    *text++ = '\0';
732  else
733    text = name;
734
735  if ((width = get_measurement(fp)) < 0.0f)
736    return (NULL);
737
738  if ((length = get_measurement(fp)) < 0.0f)
739    return (NULL);
740
741  if ((left = get_measurement(fp)) < 0.0f)
742    return (NULL);
743
744  if ((bottom = get_measurement(fp)) < 0.0f)
745    return (NULL);
746
747  if ((right = get_measurement(fp)) < 0.0f)
748    return (NULL);
749
750  if ((top = get_measurement(fp)) < 0.0f)
751    return (NULL);
752
753  if (!get_token(fp, size_code, sizeof(size_code)))
754    return (NULL);
755
756  if (!get_token(fp, region_code, sizeof(region_code)))
757    return (NULL);
758
759  // Return the new media size...
760  return (new ppdcMediaSize(name, text, width, length, left, bottom,
761                            right, top, size_code, region_code));
762}
763
764
765//
766// 'ppdcSource::get_duplex()' - Get a duplex option.
767//
768
769void
770ppdcSource::get_duplex(ppdcFile   *fp,	// I - File to read from
771                       ppdcDriver *d)	// I - Current driver
772{
773  char		temp[256];		// Duplex keyword
774  ppdcAttr	*attr;			// cupsFlipDuplex attribute
775  ppdcGroup	*g;			// Current group
776  ppdcOption	*o;			// Duplex option
777
778
779  // Duplex {boolean|none|normal|flip}
780  if (!get_token(fp, temp, sizeof(temp)))
781  {
782    _cupsLangPrintf(stderr,
783                    _("ppdc: Expected duplex type after Duplex on line %d of "
784		      "%s."), fp->line, fp->filename);
785    return;
786  }
787
788  if (cond_state)
789    return;
790
791  if (!_cups_strcasecmp(temp, "none") || !_cups_strcasecmp(temp, "false") ||
792      !_cups_strcasecmp(temp, "no") || !_cups_strcasecmp(temp, "off"))
793  {
794    g = d->find_group("General");
795    if ((o = g->find_option("Duplex")) != NULL)
796      g->options->remove(o);
797
798    for (attr = (ppdcAttr *)d->attrs->first();
799         attr;
800	 attr = (ppdcAttr *)d->attrs->next())
801      if (!strcmp(attr->name->value, "cupsFlipDuplex"))
802      {
803        d->attrs->remove(attr);
804	break;
805      }
806  }
807  else if (!_cups_strcasecmp(temp, "normal") || !_cups_strcasecmp(temp, "true") ||
808	   !_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "on") ||
809	   !_cups_strcasecmp(temp, "flip") || !_cups_strcasecmp(temp, "rotated") ||
810	   !_cups_strcasecmp(temp, "manualtumble"))
811  {
812    g = d->find_group("General");
813    o = g->find_option("Duplex");
814
815    if (!o)
816    {
817      o = new ppdcOption(PPDC_PICKONE, "Duplex", "2-Sided Printing",
818                	 !_cups_strcasecmp(temp, "flip") ? PPDC_SECTION_PAGE :
819			                             PPDC_SECTION_ANY, 10.0f);
820      o->add_choice(new ppdcChoice("None", "Off (1-Sided)",
821                        	   "<</Duplex false>>setpagedevice"));
822      o->add_choice(new ppdcChoice("DuplexNoTumble", "Long-Edge (Portrait)",
823                                   "<</Duplex true/Tumble false>>setpagedevice"));
824      o->add_choice(new ppdcChoice("DuplexTumble", "Short-Edge (Landscape)",
825                                   "<</Duplex true/Tumble true>>setpagedevice"));
826
827      g->add_option(o);
828    }
829
830    for (attr = (ppdcAttr *)d->attrs->first();
831         attr;
832	 attr = (ppdcAttr *)d->attrs->next())
833      if (!strcmp(attr->name->value, "cupsFlipDuplex"))
834      {
835        if (_cups_strcasecmp(temp, "flip"))
836          d->attrs->remove(attr);
837	break;
838      }
839
840    if (!_cups_strcasecmp(temp, "flip") && !attr)
841      d->add_attr(new ppdcAttr("cupsFlipDuplex", NULL, NULL, "true"));
842
843    for (attr = (ppdcAttr *)d->attrs->first();
844         attr;
845	 attr = (ppdcAttr *)d->attrs->next())
846      if (!strcmp(attr->name->value, "cupsBackSide"))
847      {
848        d->attrs->remove(attr);
849	break;
850      }
851
852    if (!_cups_strcasecmp(temp, "flip"))
853      d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Flipped"));
854    else if (!_cups_strcasecmp(temp, "rotated"))
855      d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Rotated"));
856    else if (!_cups_strcasecmp(temp, "manualtumble"))
857      d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "ManualTumble"));
858    else
859      d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Normal"));
860  }
861  else
862    _cupsLangPrintf(stderr,
863                    _("ppdc: Unknown duplex type \"%s\" on line %d of %s."),
864		    temp, fp->line, fp->filename);
865}
866
867
868//
869// 'ppdcSource::get_filter()' - Get a filter.
870//
871
872ppdcFilter *				// O - Filter
873ppdcSource::get_filter(ppdcFile *fp)	// I - File to read
874{
875  char	type[1024],			// MIME type
876	program[1024],			// Filter program
877	*ptr;				// Pointer into MIME type
878  int	cost;				// Relative cost
879
880
881  // Read filter parameters in one of the following formats:
882  //
883  // Filter "type cost program"
884  // Filter type cost program
885
886  if (!get_token(fp, type, sizeof(type)))
887  {
888    _cupsLangPrintf(stderr,
889                    _("ppdc: Expected a filter definition on line %d of %s."),
890		    fp->line, fp->filename);
891    return (NULL);
892  }
893
894  if ((ptr = strchr(type, ' ')) != NULL)
895  {
896    // Old-style filter definition in one string...
897    *ptr++ = '\0';
898    cost = strtol(ptr, &ptr, 10);
899
900    while (isspace(*ptr))
901      ptr ++;
902
903    strlcpy(program, ptr, sizeof(program));
904  }
905  else
906  {
907    cost = get_integer(fp);
908
909    if (!get_token(fp, program, sizeof(program)))
910    {
911      _cupsLangPrintf(stderr,
912                      _("ppdc: Expected a program name on line %d of %s."),
913		      fp->line, fp->filename);
914      return (NULL);
915    }
916  }
917
918  if (!type[0])
919  {
920    _cupsLangPrintf(stderr,
921                    _("ppdc: Invalid empty MIME type for filter on line %d of "
922		      "%s."), fp->line, fp->filename);
923    return (NULL);
924  }
925
926  if (cost < 0 || cost > 200)
927  {
928    _cupsLangPrintf(stderr,
929                    _("ppdc: Invalid cost for filter on line %d of %s."),
930		    fp->line, fp->filename);
931    return (NULL);
932  }
933
934  if (!program[0])
935  {
936    _cupsLangPrintf(stderr,
937                    _("ppdc: Invalid empty program name for filter on line %d "
938		      "of %s."), fp->line, fp->filename);
939    return (NULL);
940  }
941
942  return (new ppdcFilter(type, program, cost));
943}
944
945
946//
947// 'ppdcSource::get_float()' - Get a single floating-point number.
948//
949
950float					// O - Number
951ppdcSource::get_float(ppdcFile *fp)	// I - File to read
952{
953  char	temp[256],			// String buffer
954	*ptr;				// Pointer into buffer
955  float	val;				// Floating point value
956
957
958  // Get the number from the file and range-check...
959  if (!get_token(fp, temp, sizeof(temp)))
960  {
961    _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s."),
962		    fp->line, fp->filename);
963    return (-1.0f);
964  }
965
966  val = (float)strtod(temp, &ptr);
967
968  if (*ptr)
969  {
970    _cupsLangPrintf(stderr,
971                    _("ppdc: Unknown trailing characters in real number \"%s\" "
972		      "on line %d of %s."), temp, fp->line, fp->filename);
973    return (-1.0f);
974  }
975  else
976    return (val);
977}
978
979
980//
981// 'ppdcSource::get_font()' - Get a font definition.
982//
983
984ppdcFont *				// O - Font data
985ppdcSource::get_font(ppdcFile *fp)	// I - File to read
986{
987  char			name[256],	// Font name
988			encoding[256],	// Font encoding
989			version[256],	// Font version
990			charset[256],	// Font charset
991			temp[256];	// Font status string
992  ppdcFontStatus	status;		// Font status enumeration
993
994
995  // Read font parameters as follows:
996  //
997  // Font *
998  // Font name encoding version charset status
999  // %font name encoding version charset status
1000  //
1001  // "Name" is the PostScript font name.
1002  //
1003  // "Encoding" is the default encoding of the font: Standard, ISOLatin1,
1004  // Special, Expert, ExpertSubset, etc.
1005  //
1006  // "Version" is the version number string.
1007  //
1008  // "Charset" specifies the characters that are included in the font:
1009  // Standard, Special, Expert, Adobe-Identity, etc.
1010  //
1011  // "Status" is the keyword ROM or Disk.
1012  if (!get_token(fp, name, sizeof(name)))
1013  {
1014    _cupsLangPrintf(stderr,
1015                    _("ppdc: Expected name after Font on line %d of %s."),
1016		    fp->line, fp->filename);
1017    return (0);
1018  }
1019
1020  if (!strcmp(name, "*"))
1021  {
1022    // Include all base fonts...
1023    encoding[0] = '\0';
1024    version[0]  = '\0';
1025    charset[0]  = '\0';
1026    status      = PPDC_FONT_ROM;
1027  }
1028  else
1029  {
1030    // Load a full font definition...
1031    if (!get_token(fp, encoding, sizeof(encoding)))
1032    {
1033      _cupsLangPrintf(stderr,
1034                      _("ppdc: Expected encoding after Font on line %d of "
1035		        "%s."), fp->line, fp->filename);
1036      return (0);
1037    }
1038
1039    if (!get_token(fp, version, sizeof(version)))
1040    {
1041      _cupsLangPrintf(stderr,
1042                      _("ppdc: Expected version after Font on line %d of "
1043		        "%s."), fp->line, fp->filename);
1044      return (0);
1045    }
1046
1047    if (!get_token(fp, charset, sizeof(charset)))
1048    {
1049      _cupsLangPrintf(stderr,
1050                      _("ppdc: Expected charset after Font on line %d of "
1051		        "%s."), fp->line, fp->filename);
1052      return (0);
1053    }
1054
1055    if (!get_token(fp, temp, sizeof(temp)))
1056    {
1057      _cupsLangPrintf(stderr,
1058                      _("ppdc: Expected status after Font on line %d of %s."),
1059		      fp->line, fp->filename);
1060      return (0);
1061    }
1062
1063    if (!_cups_strcasecmp(temp, "ROM"))
1064      status = PPDC_FONT_ROM;
1065    else if (!_cups_strcasecmp(temp, "Disk"))
1066      status = PPDC_FONT_DISK;
1067    else
1068    {
1069      _cupsLangPrintf(stderr,
1070                      _("ppdc: Bad status keyword %s on line %d of %s."),
1071		      temp, fp->line, fp->filename);
1072      return (0);
1073    }
1074  }
1075
1076//  printf("Font %s %s %s %s %s\n", name, encoding, version, charset, temp);
1077
1078  return (new ppdcFont(name, encoding, version, charset, status));
1079}
1080
1081
1082//
1083// 'ppdcSource::get_generic()' - Get a generic old-style option.
1084//
1085
1086ppdcChoice *				// O - Choice data
1087ppdcSource::get_generic(ppdcFile   *fp,	// I - File to read
1088                        const char *keyword,
1089					// I - Keyword name
1090                        const char *tattr,
1091					// I - Text attribute
1092			const char *nattr)
1093					// I - Numeric attribute
1094{
1095  char		name[1024],		// Name
1096		*text,			// Text
1097		command[256];		// Command string
1098  int		val;			// Numeric value
1099
1100
1101  // Read one of the following parameters:
1102  //
1103  // Foo name/text
1104  // Foo integer name/text
1105  if (nattr)
1106    val = get_integer(fp);
1107  else
1108    val = 0;
1109
1110  if (!get_token(fp, name, sizeof(name)))
1111  {
1112    _cupsLangPrintf(stderr,
1113                    _("ppdc: Expected name/text after %s on line %d of %s."),
1114		    keyword, fp->line, fp->filename);
1115    return (NULL);
1116  }
1117
1118  if ((text = strchr(name, '/')) != NULL)
1119    *text++ = '\0';
1120  else
1121    text = name;
1122
1123  if (nattr)
1124  {
1125    if (tattr)
1126      snprintf(command, sizeof(command),
1127               "<</%s(%s)/%s %d>>setpagedevice",
1128               tattr, name, nattr, val);
1129    else
1130      snprintf(command, sizeof(command),
1131               "<</%s %d>>setpagedevice",
1132               nattr, val);
1133  }
1134  else
1135    snprintf(command, sizeof(command),
1136             "<</%s(%s)>>setpagedevice",
1137             tattr, name);
1138
1139  return (new ppdcChoice(name, text, command));
1140}
1141
1142
1143//
1144// 'ppdcSource::get_group()' - Get an option group.
1145//
1146
1147ppdcGroup *				// O - Group
1148ppdcSource::get_group(ppdcFile   *fp,	// I - File to read
1149                      ppdcDriver *d)	// I - Printer driver
1150{
1151  char		name[1024],		// UI name
1152		*text;			// UI text
1153  ppdcGroup	*g;			// Group
1154
1155
1156  // Read the Group parameters:
1157  //
1158  // Group name/text
1159  if (!get_token(fp, name, sizeof(name)))
1160  {
1161    _cupsLangPrintf(stderr,
1162                    _("ppdc: Expected group name/text on line %d of %s."),
1163		    fp->line, fp->filename);
1164    return (NULL);
1165  }
1166
1167  if ((text = strchr(name, '/')) != NULL)
1168    *text++ = '\0';
1169  else
1170    text = name;
1171
1172  // See if the group already exists...
1173  if ((g = d->find_group(name)) == NULL)
1174  {
1175    // Nope, add a new one...
1176    g = new ppdcGroup(name, text);
1177  }
1178
1179  return (g);
1180}
1181
1182
1183//
1184// 'ppdcSource::get_installable()' - Get an installable option.
1185//
1186
1187ppdcOption *				// O - Option
1188ppdcSource::get_installable(ppdcFile *fp)
1189					// I - File to read
1190{
1191  char		name[1024],		// Name for installable option
1192		*text;			// Text for installable option
1193  ppdcOption	*o;			// Option
1194
1195
1196  // Read the parameter for an installable option:
1197  //
1198  // Installable name/text
1199  if (!get_token(fp, name, sizeof(name)))
1200  {
1201    _cupsLangPrintf(stderr,
1202                    _("ppdc: Expected name/text after Installable on line %d "
1203		      "of %s."), fp->line, fp->filename);
1204    return (NULL);
1205  }
1206
1207  if ((text = strchr(name, '/')) != NULL)
1208    *text++ = '\0';
1209  else
1210    text = name;
1211
1212  // Create the option...
1213  o = new ppdcOption(PPDC_BOOLEAN, name, text, PPDC_SECTION_ANY, 10.0f);
1214
1215  // Add the false and true choices...
1216  o->add_choice(new ppdcChoice("False", "Not Installed", ""));
1217  o->add_choice(new ppdcChoice("True", "Installed", ""));
1218
1219  return (o);
1220}
1221
1222
1223//
1224// 'ppdcSource::get_integer()' - Get an integer value from a string.
1225//
1226
1227#define PPDC_XX	-1			// Bad
1228#define PPDC_EQ	0			// ==
1229#define PPDC_NE	1			// !=
1230#define PPDC_LT	2			// <
1231#define PPDC_LE	3			// <=
1232#define PPDC_GT	4			// >
1233#define PPDC_GE	5			// >=
1234
1235int					// O - Integer value
1236ppdcSource::get_integer(const char *v)	// I - Value string
1237{
1238  long		val;			// Value
1239  long		temp,			// Temporary value
1240		temp2;			// Second temporary value
1241  char		*newv,			// New value string pointer
1242		ch;			// Temporary character
1243  ppdcVariable	*var;			// #define variable
1244  int		compop;			// Comparison operator
1245
1246
1247  // Parse the value string...
1248  if (!v)
1249    return (-1);
1250
1251  if (isdigit(*v & 255) || *v == '-' || *v == '+')
1252  {
1253    // Return a simple integer value
1254    val = strtol(v, (char **)&v, 0);
1255    if (*v || val == LONG_MIN)
1256      return (-1);
1257    else
1258      return ((int)val);
1259  }
1260  else if (*v == '(')
1261  {
1262    // Evaluate and expression in any of the following formats:
1263    //
1264    // (number number ... number)   Bitwise OR of all numbers
1265    // (NAME == value)              1 if equal, 0 otherwise
1266    // (NAME != value)              1 if not equal, 0 otherwise
1267    // (NAME < value)               1 if less than, 0 otherwise
1268    // (NAME <= value)              1 if less than or equal, 0 otherwise
1269    // (NAME > value)               1 if greater than, 0 otherwise
1270    // (NAME >= value)              1 if greater than or equal, 0 otherwise
1271
1272    v ++;
1273    val = 0;
1274
1275    while (*v && *v != ')')
1276    {
1277      // Skip leading whitespace...
1278      while (*v && isspace(*v & 255))
1279        v ++;
1280
1281      if (!*v || *v == ')')
1282        break;
1283
1284      if (isdigit(*v & 255) || *v == '-' || *v == '+')
1285      {
1286        // Bitwise OR a number...
1287	temp = strtol(v, &newv, 0);
1288
1289	if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1290	    temp == LONG_MIN)
1291	  return (-1);
1292      }
1293      else
1294      {
1295        // NAME logicop value
1296	for (newv = (char *)v + 1;
1297	     *newv && (isalnum(*newv & 255) || *newv == '_');
1298	     newv ++)
1299	  /* do nothing */;
1300
1301        ch    = *newv;
1302	*newv = '\0';
1303
1304        if ((var = find_variable(v)) != NULL)
1305	{
1306	  if (!var->value || !var->value->value || !var->value->value[0])
1307	    temp = 0;
1308	  else if (isdigit(var->value->value[0] & 255) ||
1309	           var->value->value[0] == '-' ||
1310	           var->value->value[0] == '+')
1311            temp = strtol(var->value->value, NULL, 0);
1312	  else
1313	    temp = 1;
1314	}
1315	else
1316	  temp = 0;
1317
1318        *newv = ch;
1319	while (isspace(*newv & 255))
1320	  newv ++;
1321
1322        if (!strncmp(newv, "==", 2))
1323	{
1324	  compop = PPDC_EQ;
1325	  newv += 2;
1326	}
1327        else if (!strncmp(newv, "!=", 2))
1328        {
1329	  compop = PPDC_NE;
1330	  newv += 2;
1331	}
1332        else if (!strncmp(newv, "<=", 2))
1333        {
1334	  compop = PPDC_LE;
1335	  newv += 2;
1336	}
1337	else if (*newv == '<')
1338        {
1339	  compop = PPDC_LT;
1340	  newv ++;
1341	}
1342        else if (!strncmp(newv, ">=", 2))
1343        {
1344	  compop = PPDC_GE;
1345	  newv += 2;
1346	}
1347	else if (*newv == '>')
1348	{
1349	  compop = PPDC_GT;
1350	  newv ++;
1351	}
1352	else
1353	  compop = PPDC_XX;
1354
1355        if (compop != PPDC_XX)
1356	{
1357	  while (isspace(*newv & 255))
1358	    newv ++;
1359
1360          if (*newv == ')' || !*newv)
1361	    return (-1);
1362
1363	  if (isdigit(*newv & 255) || *newv == '-' || *newv == '+')
1364	  {
1365	    // Get the second number...
1366	    temp2 = strtol(newv, &newv, 0);
1367	    if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1368		temp == LONG_MIN)
1369	      return (-1);
1370          }
1371	  else
1372	  {
1373	    // Lookup the second name...
1374	    for (v = newv, newv ++;
1375		 *newv && (isalnum(*newv & 255) || *newv == '_');
1376		 newv ++);
1377
1378	    ch    = *newv;
1379	    *newv = '\0';
1380
1381	    if ((var = find_variable(v)) != NULL)
1382	    {
1383	      if (!var->value || !var->value->value || !var->value->value[0])
1384		temp2 = 0;
1385	      else if (isdigit(var->value->value[0] & 255) ||
1386		       var->value->value[0] == '-' ||
1387		       var->value->value[0] == '+')
1388		temp2 = strtol(var->value->value, NULL, 0);
1389	      else
1390		temp2 = 1;
1391	    }
1392	    else
1393	      temp2 = 0;
1394
1395	    *newv = ch;
1396          }
1397
1398	  // Do the comparison...
1399	  switch (compop)
1400	  {
1401	    case PPDC_EQ :
1402	        temp = temp == temp2;
1403		break;
1404	    case PPDC_NE :
1405	        temp = temp != temp2;
1406		break;
1407	    case PPDC_LT :
1408	        temp = temp < temp2;
1409		break;
1410	    case PPDC_LE :
1411	        temp = temp <= temp2;
1412		break;
1413	    case PPDC_GT :
1414	        temp = temp > temp2;
1415		break;
1416	    case PPDC_GE :
1417	        temp = temp >= temp2;
1418		break;
1419	  }
1420	}
1421      }
1422
1423      val |= temp;
1424      v   = newv;
1425    }
1426
1427    if (*v == ')' && !v[1])
1428      return ((int)val);
1429    else
1430      return (-1);
1431  }
1432  else if ((var = find_variable(v)) != NULL)
1433  {
1434    // NAME by itself returns 1 if the #define variable is not blank and
1435    // not "0"...
1436    return (var->value->value && var->value->value[0] &&
1437            strcmp(var->value->value, "0"));
1438  }
1439  else
1440  {
1441    // Anything else is an error...
1442    return (-1);
1443  }
1444}
1445
1446
1447//
1448// 'ppdcSource::get_integer()' - Get an integer value from a file.
1449//
1450
1451int					// O - Integer value
1452ppdcSource::get_integer(ppdcFile *fp)	// I - File to read
1453{
1454  char	temp[1024];			// String buffer
1455
1456
1457  if (!get_token(fp, temp, sizeof(temp)))
1458  {
1459    _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s."),
1460		    fp->line, fp->filename);
1461    return (-1);
1462  }
1463  else
1464    return (get_integer(temp));
1465}
1466
1467
1468//
1469// 'ppdcSource::get_measurement()' - Get a measurement value.
1470//
1471
1472float					// O - Measurement value in points
1473ppdcSource::get_measurement(ppdcFile *fp)
1474					// I - File to read
1475{
1476  char	buffer[256],			// Number buffer
1477	*ptr;				// Pointer into buffer
1478  float	val;				// Measurement value
1479
1480
1481  // Grab a token from the file...
1482  if (!get_token(fp, buffer, sizeof(buffer)))
1483    return (-1.0f);
1484
1485  // Get the floating point value of "s" and skip all digits and decimal points.
1486  val = (float)strtod(buffer, &ptr);
1487
1488  // Check for a trailing unit specifier...
1489  if (!_cups_strcasecmp(ptr, "mm"))
1490    val *= 72.0f / 25.4f;
1491  else if (!_cups_strcasecmp(ptr, "cm"))
1492    val *= 72.0f / 2.54f;
1493  else if (!_cups_strcasecmp(ptr, "m"))
1494    val *= 72.0f / 0.0254f;
1495  else if (!_cups_strcasecmp(ptr, "in"))
1496    val *= 72.0f;
1497  else if (!_cups_strcasecmp(ptr, "ft"))
1498    val *= 72.0f * 12.0f;
1499  else if (_cups_strcasecmp(ptr, "pt") && *ptr)
1500    return (-1.0f);
1501
1502  return (val);
1503}
1504
1505
1506//
1507// 'ppdcSource::get_option()' - Get an option definition.
1508//
1509
1510ppdcOption *				// O - Option
1511ppdcSource::get_option(ppdcFile   *fp,	// I - File to read
1512                       ppdcDriver *d,	// I - Printer driver
1513		       ppdcGroup  *g)	// I - Current group
1514{
1515  char		name[1024],		// UI name
1516		*text,			// UI text
1517		type[256];		// UI type string
1518  ppdcOptType	ot;			// Option type value
1519  ppdcOptSection section;		// Option section
1520  float		order;			// Option order
1521  ppdcOption	*o;			// Option
1522  ppdcGroup	*mg;			// Matching group, if any
1523
1524
1525  // Read the Option parameters:
1526  //
1527  // Option name/text type section order
1528  if (!get_token(fp, name, sizeof(name)))
1529  {
1530    _cupsLangPrintf(stderr,
1531                    _("ppdc: Expected option name/text on line %d of %s."),
1532		    fp->line, fp->filename);
1533    return (NULL);
1534  }
1535
1536  if ((text = strchr(name, '/')) != NULL)
1537    *text++ = '\0';
1538  else
1539    text = name;
1540
1541  if (!get_token(fp, type, sizeof(type)))
1542  {
1543    _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s."),
1544		    fp->line, fp->filename);
1545    return (NULL);
1546  }
1547
1548  if (!_cups_strcasecmp(type, "boolean"))
1549    ot = PPDC_BOOLEAN;
1550  else if (!_cups_strcasecmp(type, "pickone"))
1551    ot = PPDC_PICKONE;
1552  else if (!_cups_strcasecmp(type, "pickmany"))
1553    ot = PPDC_PICKMANY;
1554  else
1555  {
1556    _cupsLangPrintf(stderr,
1557                    _("ppdc: Invalid option type \"%s\" on line %d of %s."),
1558		    type, fp->line, fp->filename);
1559    return (NULL);
1560  }
1561
1562  if (!get_token(fp, type, sizeof(type)))
1563  {
1564    _cupsLangPrintf(stderr,
1565                    _("ppdc: Expected option section on line %d of %s."),
1566		    fp->line, fp->filename);
1567    return (NULL);
1568  }
1569
1570  if (!_cups_strcasecmp(type, "AnySetup"))
1571    section = PPDC_SECTION_ANY;
1572  else if (!_cups_strcasecmp(type, "DocumentSetup"))
1573    section = PPDC_SECTION_DOCUMENT;
1574  else if (!_cups_strcasecmp(type, "ExitServer"))
1575    section = PPDC_SECTION_EXIT;
1576  else if (!_cups_strcasecmp(type, "JCLSetup"))
1577    section = PPDC_SECTION_JCL;
1578  else if (!_cups_strcasecmp(type, "PageSetup"))
1579    section = PPDC_SECTION_PAGE;
1580  else if (!_cups_strcasecmp(type, "Prolog"))
1581    section = PPDC_SECTION_PROLOG;
1582  else
1583  {
1584    _cupsLangPrintf(stderr,
1585                    _("ppdc: Invalid option section \"%s\" on line %d of "
1586		      "%s."), type, fp->line, fp->filename);
1587    return (NULL);
1588  }
1589
1590  order = get_float(fp);
1591
1592  // See if the option already exists...
1593  if ((o = d->find_option_group(name, &mg)) == NULL)
1594  {
1595    // Nope, add a new one...
1596    o = new ppdcOption(ot, name, text, section, order);
1597  }
1598  else if (o->type != ot)
1599  {
1600    _cupsLangPrintf(stderr,
1601                    _("ppdc: Option %s redefined with a different type on line "
1602		      "%d of %s."), name, fp->line, fp->filename);
1603    return (NULL);
1604  }
1605  else if (g != mg)
1606  {
1607    _cupsLangPrintf(stderr,
1608                    _("ppdc: Option %s defined in two different groups on line "
1609		      "%d of %s."), name, fp->line, fp->filename);
1610    return (NULL);
1611  }
1612
1613  return (o);
1614}
1615
1616
1617//
1618// 'ppdcSource::get_po()' - Get a message catalog.
1619//
1620
1621ppdcCatalog *				// O - Message catalog
1622ppdcSource::get_po(ppdcFile *fp)	// I - File to read
1623{
1624  char		locale[32],		// Locale name
1625		poname[1024],		// Message catalog filename
1626		basedir[1024],		// Base directory
1627		*baseptr,		// Pointer into directory
1628		pofilename[1024];	// Full filename of message catalog
1629  ppdcCatalog	*cat;			// Message catalog
1630
1631
1632  // Read the #po parameters:
1633  //
1634  // #po locale "filename.po"
1635  if (!get_token(fp, locale, sizeof(locale)))
1636  {
1637    _cupsLangPrintf(stderr,
1638                    _("ppdc: Expected locale after #po on line %d of %s."),
1639		    fp->line, fp->filename);
1640    return (NULL);
1641  }
1642
1643  if (!get_token(fp, poname, sizeof(poname)))
1644  {
1645    _cupsLangPrintf(stderr,
1646                    _("ppdc: Expected filename after #po %s on line %d of "
1647		      "%s."), locale, fp->line, fp->filename);
1648    return (NULL);
1649  }
1650
1651  // See if the locale is already loaded...
1652  if (find_po(locale))
1653  {
1654    _cupsLangPrintf(stderr,
1655                    _("ppdc: Duplicate #po for locale %s on line %d of %s."),
1656		    locale, fp->line, fp->filename);
1657    return (NULL);
1658  }
1659
1660  // Figure out the current directory...
1661  strlcpy(basedir, fp->filename, sizeof(basedir));
1662
1663  if ((baseptr = strrchr(basedir, '/')) != NULL)
1664    *baseptr = '\0';
1665  else
1666    strlcpy(basedir, ".", sizeof(basedir));
1667
1668  // Find the po file...
1669  pofilename[0] = '\0';
1670
1671  if (!poname[0] ||
1672      find_include(poname, basedir, pofilename, sizeof(pofilename)))
1673  {
1674    // Found it, so load it...
1675    cat = new ppdcCatalog(locale, pofilename);
1676
1677    // Reset the filename to the name supplied by the user...
1678    cat->filename->release();
1679    cat->filename = new ppdcString(poname);
1680
1681    // Return the catalog...
1682    return (cat);
1683  }
1684  else
1685  {
1686    _cupsLangPrintf(stderr,
1687                    _("ppdc: Unable to find #po file %s on line %d of %s."),
1688		    poname, fp->line, fp->filename);
1689    return (NULL);
1690  }
1691}
1692
1693
1694//
1695// 'ppdcSource::get_resolution()' - Get an old-style resolution option.
1696//
1697
1698ppdcChoice *				// O - Choice data
1699ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
1700{
1701  char		name[1024],		// Name
1702		*text,			// Text
1703		temp[256],		// Temporary string
1704		command[256],		// Command string
1705		*commptr;		// Pointer into command
1706  int		xdpi, ydpi,		// X + Y resolution
1707		color_order,		// Color order
1708		color_space,		// Colorspace
1709		compression,		// Compression mode
1710		depth,			// Bits per color
1711		row_count,		// Row count
1712		row_feed,		// Row feed
1713		row_step;		// Row step/interval
1714
1715
1716  // Read the resolution parameters:
1717  //
1718  // Resolution colorspace bits row-count row-feed row-step name/text
1719  if (!get_token(fp, temp, sizeof(temp)))
1720  {
1721    _cupsLangPrintf(stderr,
1722                    _("ppdc: Expected override field after Resolution on line "
1723		      "%d of %s."), fp->line, fp->filename);
1724    return (NULL);
1725  }
1726
1727  color_order = get_color_order(temp);
1728  color_space = get_color_space(temp);
1729  compression = get_integer(temp);
1730
1731  depth       = get_integer(fp);
1732  row_count   = get_integer(fp);
1733  row_feed    = get_integer(fp);
1734  row_step    = get_integer(fp);
1735
1736  if (!get_token(fp, name, sizeof(name)))
1737  {
1738    _cupsLangPrintf(stderr,
1739		    _("ppdc: Expected name/text after Resolution on line %d of "
1740		      "%s."), fp->line, fp->filename);
1741    return (NULL);
1742  }
1743
1744  if ((text = strchr(name, '/')) != NULL)
1745    *text++ = '\0';
1746  else
1747    text = name;
1748
1749  switch (sscanf(name, "%dx%d", &xdpi, &ydpi))
1750  {
1751    case 0 :
1752        _cupsLangPrintf(stderr,
1753	                _("ppdc: Bad resolution name \"%s\" on line %d of "
1754			  "%s."), name, fp->line, fp->filename);
1755        break;
1756    case 1 :
1757        ydpi = xdpi;
1758	break;
1759  }
1760
1761  // Create the necessary PS commands...
1762  snprintf(command, sizeof(command),
1763           "<</HWResolution[%d %d]/cupsBitsPerColor %d/cupsRowCount %d"
1764           "/cupsRowFeed %d/cupsRowStep %d",
1765	   xdpi, ydpi, depth, row_count, row_feed, row_step);
1766  commptr = command + strlen(command);
1767
1768  if (color_order >= 0)
1769  {
1770    snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1771             "/cupsColorOrder %d", color_order);
1772    commptr += strlen(commptr);
1773  }
1774
1775  if (color_space >= 0)
1776  {
1777    snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1778             "/cupsColorSpace %d", color_space);
1779    commptr += strlen(commptr);
1780  }
1781
1782  if (compression >= 0)
1783  {
1784    snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1785             "/cupsCompression %d", compression);
1786    commptr += strlen(commptr);
1787  }
1788
1789  snprintf(commptr, sizeof(command) - (size_t)(commptr - command), ">>setpagedevice");
1790
1791  // Return the new choice...
1792  return (new ppdcChoice(name, text, command));
1793}
1794
1795
1796//
1797// 'ppdcSource::get_simple_profile()' - Get a simple color profile definition.
1798//
1799
1800ppdcProfile *				// O - Color profile
1801ppdcSource::get_simple_profile(ppdcFile *fp)
1802					// I - File to read
1803{
1804  char		resolution[1024],	// Resolution/media type
1805		*media_type;		// Media type
1806  float		m[9];			// Transform matrix
1807  float		kd, rd, g;		// Densities and gamma
1808  float		red, green, blue;	// RGB adjustments
1809  float		yellow;			// Yellow density
1810  float		color;			// Color density values
1811
1812
1813  // Get the SimpleColorProfile parameters:
1814  //
1815  // SimpleColorProfile resolution/mediatype black-density yellow-density
1816  //     red-density gamma red-adjust green-adjust blue-adjust
1817  if (!get_token(fp, resolution, sizeof(resolution)))
1818  {
1819    _cupsLangPrintf(stderr,
1820                    _("ppdc: Expected resolution/mediatype following "
1821		      "SimpleColorProfile on line %d of %s."),
1822		    fp->line, fp->filename);
1823    return (NULL);
1824  }
1825
1826  if ((media_type = strchr(resolution, '/')) != NULL)
1827    *media_type++ = '\0';
1828  else
1829    media_type = resolution;
1830
1831  // Collect the profile parameters...
1832  kd     = get_float(fp);
1833  yellow = get_float(fp);
1834  rd     = get_float(fp);
1835  g      = get_float(fp);
1836  red    = get_float(fp);
1837  green  = get_float(fp);
1838  blue   = get_float(fp);
1839
1840  // Build the color profile...
1841  color = 0.5f * rd / kd - kd;
1842  m[0]  = 1.0f;				// C
1843  m[1]  = color + blue;			// C + M (blue)
1844  m[2]  = color - green;		// C + Y (green)
1845  m[3]  = color - blue;			// M + C (blue)
1846  m[4]  = 1.0f;				// M
1847  m[5]  = color + red;			// M + Y (red)
1848  m[6]  = yellow * (color + green);	// Y + C (green)
1849  m[7]  = yellow * (color - red);	// Y + M (red)
1850  m[8]  = yellow;			// Y
1851
1852  if (m[1] > 0.0f)
1853  {
1854    m[3] -= m[1];
1855    m[1] = 0.0f;
1856  }
1857  else if (m[3] > 0.0f)
1858  {
1859    m[1] -= m[3];
1860    m[3] = 0.0f;
1861  }
1862
1863  if (m[2] > 0.0f)
1864  {
1865    m[6] -= m[2];
1866    m[2] = 0.0f;
1867  }
1868  else if (m[6] > 0.0f)
1869  {
1870    m[2] -= m[6];
1871    m[6] = 0.0f;
1872  }
1873
1874  if (m[5] > 0.0f)
1875  {
1876    m[7] -= m[5];
1877    m[5] = 0.0f;
1878  }
1879  else if (m[7] > 0.0f)
1880  {
1881    m[5] -= m[7];
1882    m[7] = 0.0f;
1883  }
1884
1885  // Return the new profile...
1886  return (new ppdcProfile(resolution, media_type, g, kd, m));
1887}
1888
1889
1890//
1891// 'ppdcSource::get_size()' - Get a media size definition from a file.
1892//
1893
1894ppdcMediaSize *				// O - Media size
1895ppdcSource::get_size(ppdcFile *fp)	// I - File to read
1896{
1897  char		name[1024],		// Name
1898		*text;			// Text
1899  float		width,			// Width
1900		length;			// Length
1901
1902
1903  // Get the name, text, width, and length:
1904  //
1905  // #media name/text width length
1906  if (!get_token(fp, name, sizeof(name)))
1907    return (NULL);
1908
1909  if ((text = strchr(name, '/')) != NULL)
1910    *text++ = '\0';
1911  else
1912    text = name;
1913
1914  if ((width = get_measurement(fp)) < 0.0f)
1915    return (NULL);
1916
1917  if ((length = get_measurement(fp)) < 0.0f)
1918    return (NULL);
1919
1920  // Return the new media size...
1921  return (new ppdcMediaSize(name, text, width, length, 0.0f, 0.0f, 0.0f, 0.0f));
1922}
1923
1924
1925//
1926// 'ppdcSource::get_token()' - Get a token from a file.
1927//
1928
1929char *					// O - Token string or NULL
1930ppdcSource::get_token(ppdcFile *fp,	// I - File to read
1931                      char     *buffer,	// I - Buffer
1932		      int      buflen)	// I - Length of buffer
1933{
1934  char		*bufptr,		// Pointer into string buffer
1935		*bufend;		// End of string buffer
1936  int		ch,			// Character from file
1937		nextch,			// Next char in file
1938		quote,			// Quote character used...
1939		empty,			// Empty input?
1940		startline;		// Start line for quote
1941  char		name[256],		// Name string
1942		*nameptr;		// Name pointer
1943  ppdcVariable	*var;			// Variable pointer
1944
1945
1946  // Mark the beginning and end of the buffer...
1947  bufptr = buffer;
1948  bufend = buffer + buflen - 1;
1949
1950  // Loop intil we've read a token...
1951  quote     = 0;
1952  startline = 0;
1953  empty     = 1;
1954
1955  while ((ch = fp->get()) != EOF)
1956  {
1957    if (isspace(ch) && !quote)
1958    {
1959      if (empty)
1960        continue;
1961      else
1962        break;
1963    }
1964    else if (ch == '$')
1965    {
1966      // Variable substitution
1967      empty = 0;
1968
1969      for (nameptr = name; (ch = fp->peek()) != EOF;)
1970      {
1971        if (!isalnum(ch) && ch != '_')
1972	  break;
1973	else if (nameptr < (name + sizeof(name) - 1))
1974	  *nameptr++ = (char)fp->get();
1975      }
1976
1977      if (nameptr == name)
1978      {
1979        // Just substitute this character...
1980	if (ch == '$')
1981	{
1982	  // $$ = $
1983	  if (bufptr < bufend)
1984	    *bufptr++ = (char)fp->get();
1985	}
1986	else
1987	{
1988	  // $ch = $ch
1989          _cupsLangPrintf(stderr,
1990	                  _("ppdc: Bad variable substitution ($%c) on line %d "
1991			    "of %s."), ch, fp->line, fp->filename);
1992
1993	  if (bufptr < bufend)
1994	    *bufptr++ = '$';
1995	}
1996      }
1997      else
1998      {
1999        // Substitute the variable value...
2000	*nameptr = '\0';
2001	var = find_variable(name);
2002	if (var)
2003	{
2004	  strlcpy(bufptr, var->value->value, (size_t)(bufend - bufptr + 1));
2005	  bufptr += strlen(bufptr);
2006	}
2007	else
2008	{
2009	  if (!(cond_state & PPDC_COND_SKIP))
2010	    _cupsLangPrintf(stderr,
2011			    _("ppdc: Undefined variable (%s) on line %d of "
2012			      "%s."), name, fp->line, fp->filename);
2013
2014	  snprintf(bufptr, (size_t)(bufend - bufptr + 1), "$%s", name);
2015	  bufptr += strlen(bufptr);
2016	}
2017      }
2018    }
2019    else if (ch == '/' && !quote)
2020    {
2021      // Possibly a comment...
2022      nextch = fp->peek();
2023
2024      if (nextch == '*')
2025      {
2026        // C comment...
2027	fp->get();
2028	ch = fp->get();
2029	while ((nextch = fp->get()) != EOF)
2030	{
2031	  if (ch == '*' && nextch == '/')
2032	    break;
2033
2034	  ch = nextch;
2035	}
2036
2037        if (nextch == EOF)
2038          break;
2039      }
2040      else if (nextch == '/')
2041      {
2042        // C++ comment...
2043        while ((nextch = fp->get()) != EOF)
2044          if (nextch == '\n')
2045	    break;
2046
2047        if (nextch == EOF)
2048          break;
2049      }
2050      else
2051      {
2052        // Not a comment...
2053        empty = 0;
2054
2055	if (bufptr < bufend)
2056	  *bufptr++ = (char)ch;
2057      }
2058    }
2059    else if (ch == '\'' || ch == '\"')
2060    {
2061      empty = 0;
2062
2063      if (quote == ch)
2064      {
2065        // Ending the current quoted string...
2066        quote = 0;
2067      }
2068      else if (quote)
2069      {
2070        // Insert the opposing quote char...
2071	if (bufptr < bufend)
2072          *bufptr++ = (char)ch;
2073      }
2074      else
2075      {
2076        // Start a new quoted string...
2077        startline = fp->line;
2078        quote     = ch;
2079      }
2080    }
2081    else if ((ch == '(' || ch == '<') && !quote)
2082    {
2083      empty     = 0;
2084      quote     = ch;
2085      startline = fp->line;
2086
2087      if (bufptr < bufend)
2088	*bufptr++ = (char)ch;
2089    }
2090    else if ((ch == ')' && quote == '(') || (ch == '>' && quote == '<'))
2091    {
2092      quote = 0;
2093
2094      if (bufptr < bufend)
2095	*bufptr++ = (char)ch;
2096    }
2097    else if (ch == '\\')
2098    {
2099      empty = 0;
2100
2101      if ((ch = fp->get()) == EOF)
2102        break;
2103
2104      if (bufptr < bufend)
2105        *bufptr++ = (char)ch;
2106    }
2107    else if (bufptr < bufend)
2108    {
2109      empty = 0;
2110
2111      *bufptr++ = (char)ch;
2112
2113      if ((ch == '{' || ch == '}') && !quote)
2114        break;
2115    }
2116  }
2117
2118  if (quote)
2119  {
2120    _cupsLangPrintf(stderr,
2121                    _("ppdc: Unterminated string starting with %c on line %d "
2122		      "of %s."), quote, startline, fp->filename);
2123    return (NULL);
2124  }
2125
2126  if (empty)
2127    return (NULL);
2128  else
2129  {
2130    *bufptr = '\0';
2131    return (buffer);
2132  }
2133}
2134
2135
2136//
2137// 'ppdcSource::get_variable()' - Get a variable definition.
2138//
2139
2140ppdcVariable *				// O - Variable
2141ppdcSource::get_variable(ppdcFile *fp)	// I - File to read
2142{
2143  char		name[1024],		// Name
2144		value[1024];		// Value
2145
2146
2147  // Get the name and value:
2148  //
2149  // #define name value
2150  if (!get_token(fp, name, sizeof(name)))
2151    return (NULL);
2152
2153  if (!get_token(fp, value, sizeof(value)))
2154    return (NULL);
2155
2156  // Set the variable...
2157  return (set_variable(name, value));
2158}
2159
2160
2161//
2162// 'ppdcSource::quotef()' - Write a formatted, quoted string...
2163//
2164
2165int					// O - Number bytes on success, -1 on failure
2166ppdcSource::quotef(cups_file_t *fp,	// I - File to write to
2167                   const char  *format,	// I - Printf-style format string
2168		   ...)			// I - Additional args as needed
2169{
2170  va_list	ap;			// Pointer to additional arguments
2171  int		bytes;			// Bytes written
2172  char		sign,			// Sign of format width
2173		size,			// Size character (h, l, L)
2174		type;			// Format type character
2175  const char	*bufformat;		// Start of format
2176  int		width,			// Width of field
2177		prec;			// Number of characters of precision
2178  char		tformat[100];		// Temporary format string for fprintf()
2179  char		*s;			// Pointer to string
2180  int		slen;			// Length of string
2181  int		i;			// Looping var
2182
2183
2184  // Range check input...
2185  if (!fp || !format)
2186    return (-1);
2187
2188  // Loop through the format string, formatting as needed...
2189  va_start(ap, format);
2190
2191  bytes = 0;
2192
2193  while (*format)
2194  {
2195    if (*format == '%')
2196    {
2197      bufformat = format;
2198      format ++;
2199
2200      if (*format == '%')
2201      {
2202        cupsFilePutChar(fp, *format++);
2203	bytes ++;
2204	continue;
2205      }
2206      else if (strchr(" -+#\'", *format))
2207        sign = *format++;
2208      else
2209        sign = 0;
2210
2211      width = 0;
2212      while (isdigit(*format))
2213        width = width * 10 + *format++ - '0';
2214
2215      if (*format == '.')
2216      {
2217        format ++;
2218	prec = 0;
2219
2220	while (isdigit(*format))
2221          prec = prec * 10 + *format++ - '0';
2222      }
2223      else
2224        prec = -1;
2225
2226      if (*format == 'l' && format[1] == 'l')
2227      {
2228        size = 'L';
2229	format += 2;
2230      }
2231      else if (*format == 'h' || *format == 'l' || *format == 'L')
2232        size = *format++;
2233      else
2234        size = '\0';
2235
2236      if (!*format)
2237        break;
2238
2239      type = *format++;
2240
2241      switch (type)
2242      {
2243	case 'E' : // Floating point formats
2244	case 'G' :
2245	case 'e' :
2246	case 'f' :
2247	case 'g' :
2248	    if ((format - bufformat + 1) > (int)sizeof(tformat))
2249	      break;
2250
2251	    memcpy(tformat, bufformat, (size_t)(format - bufformat));
2252	    tformat[format - bufformat] = '\0';
2253
2254	    bytes += cupsFilePrintf(fp, tformat, va_arg(ap, double));
2255	    break;
2256
2257        case 'B' : // Integer formats
2258	case 'X' :
2259	case 'b' :
2260        case 'd' :
2261	case 'i' :
2262	case 'o' :
2263	case 'u' :
2264	case 'x' :
2265	    if ((format - bufformat + 1) > (int)sizeof(tformat))
2266	      break;
2267
2268	    memcpy(tformat, bufformat, (size_t)(format - bufformat));
2269	    tformat[format - bufformat] = '\0';
2270
2271#  ifdef HAVE_LONG_LONG
2272            if (size == 'L')
2273	      bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long long));
2274	    else
2275#  endif /* HAVE_LONG_LONG */
2276            if (size == 'l')
2277	      bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long));
2278	    else
2279	      bytes += cupsFilePrintf(fp, tformat, va_arg(ap, int));
2280	    break;
2281
2282	case 'p' : // Pointer value
2283	    if ((format - bufformat + 1) > (int)sizeof(tformat))
2284	      break;
2285
2286	    memcpy(tformat, bufformat, (size_t)(format - bufformat));
2287	    tformat[format - bufformat] = '\0';
2288
2289	    bytes += cupsFilePrintf(fp, tformat, va_arg(ap, void *));
2290	    break;
2291
2292        case 'c' : // Character or character array
2293	    if (width <= 1)
2294	    {
2295	      bytes ++;
2296	      cupsFilePutChar(fp, va_arg(ap, int));
2297	    }
2298	    else
2299	    {
2300	      cupsFileWrite(fp, va_arg(ap, char *), (size_t)width);
2301	      bytes += width;
2302	    }
2303	    break;
2304
2305	case 's' : // String
2306	    if ((s = va_arg(ap, char *)) == NULL)
2307	      s = (char *)"(nil)";
2308
2309	    slen = (int)strlen(s);
2310	    if (slen > width && prec != width)
2311	      width = slen;
2312
2313            if (slen > width)
2314	      slen = width;
2315
2316            if (sign != '-')
2317	    {
2318	      for (i = width - slen; i > 0; i --, bytes ++)
2319	        cupsFilePutChar(fp, ' ');
2320	    }
2321
2322            for (i = slen; i > 0; i --, s ++, bytes ++)
2323	    {
2324	      if (*s == '\\' || *s == '\"')
2325	      {
2326	        cupsFilePutChar(fp, '\\');
2327		bytes ++;
2328	      }
2329
2330	      cupsFilePutChar(fp, *s);
2331	    }
2332
2333            if (sign == '-')
2334	    {
2335	      for (i = width - slen; i > 0; i --, bytes ++)
2336	        cupsFilePutChar(fp, ' ');
2337	    }
2338	    break;
2339      }
2340    }
2341    else
2342    {
2343      cupsFilePutChar(fp, *format++);
2344      bytes ++;
2345    }
2346  }
2347
2348  va_end(ap);
2349
2350  // Return the number of characters written.
2351  return (bytes);
2352}
2353
2354
2355//
2356// 'ppdcSource::read_file()' - Read a driver source file.
2357//
2358
2359void
2360ppdcSource::read_file(const char  *f,	// I - File to read
2361                      cups_file_t *ffp)	// I - File pointer to use
2362{
2363  ppdcFile *fp = new ppdcFile(f, ffp);
2364  scan_file(fp);
2365  delete fp;
2366
2367  if (cond_current != cond_stack)
2368    _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."), f);
2369}
2370
2371
2372//
2373// 'ppdcSource::scan_file()' - Scan a driver source file.
2374//
2375
2376void
2377ppdcSource::scan_file(ppdcFile   *fp,	// I - File to read
2378                      ppdcDriver *td,	// I - Driver template
2379		      bool       inc)	// I - Including?
2380{
2381  ppdcDriver	*d;			// Current driver
2382  ppdcGroup	*g,			// Current group
2383		*mg,			// Matching group
2384		*general,		// General options group
2385		*install;		// Installable options group
2386  ppdcOption	*o;			// Current option
2387  ppdcChoice	*c;			// Current choice
2388  char		temp[256],		// Token from file...
2389		*ptr;			// Pointer into token
2390  int		isdefault;		// Default option?
2391
2392
2393  // Initialize things as needed...
2394  if (inc && td)
2395  {
2396    d = td;
2397    d->retain();
2398  }
2399  else
2400    d = new ppdcDriver(td);
2401
2402  if ((general = d->find_group("General")) == NULL)
2403  {
2404    general = new ppdcGroup("General", NULL);
2405    d->add_group(general);
2406  }
2407
2408  if ((install = d->find_group("InstallableOptions")) == NULL)
2409  {
2410    install = new ppdcGroup("InstallableOptions", "Installable Options");
2411    d->add_group(install);
2412  }
2413
2414  // Loop until EOF or }
2415  o = 0;
2416  g = general;
2417
2418  while (get_token(fp, temp, sizeof(temp)))
2419  {
2420    if (temp[0] == '*')
2421    {
2422      // Mark the next choice as the default
2423      isdefault = 1;
2424
2425      for (ptr = temp; ptr[1]; ptr ++)
2426        *ptr = ptr[1];
2427
2428      *ptr = '\0';
2429    }
2430    else
2431    {
2432      // Don't mark the next choice as the default
2433      isdefault = 0;
2434    }
2435
2436    if (!_cups_strcasecmp(temp, "}"))
2437    {
2438      // Close this one out...
2439      break;
2440    }
2441    else if (!_cups_strcasecmp(temp, "{"))
2442    {
2443      // Open a new child...
2444      scan_file(fp, d);
2445    }
2446    else if (!_cups_strcasecmp(temp, "#if"))
2447    {
2448      if ((cond_current - cond_stack) >= 100)
2449      {
2450        _cupsLangPrintf(stderr,
2451	                _("ppdc: Too many nested #if's on line %d of %s."),
2452			fp->line, fp->filename);
2453	break;
2454      }
2455
2456      cond_current ++;
2457      if (get_integer(fp) > 0)
2458        *cond_current = PPDC_COND_SATISFIED;
2459      else
2460      {
2461        *cond_current = PPDC_COND_SKIP;
2462	cond_state    |= PPDC_COND_SKIP;
2463      }
2464    }
2465    else if (!_cups_strcasecmp(temp, "#elif"))
2466    {
2467      if (cond_current == cond_stack)
2468      {
2469        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2470	                fp->line, fp->filename);
2471        break;
2472      }
2473
2474      if (*cond_current & PPDC_COND_SATISFIED)
2475      {
2476        get_integer(fp);
2477	*cond_current |= PPDC_COND_SKIP;
2478      }
2479      else if (get_integer(fp) > 0)
2480      {
2481        *cond_current |= PPDC_COND_SATISFIED;
2482	*cond_current &= ~PPDC_COND_SKIP;
2483      }
2484      else
2485        *cond_current |= PPDC_COND_SKIP;
2486
2487      // Update the current state
2488      int *cond_temp = cond_current;	// Temporary stack pointer
2489
2490      cond_state = PPDC_COND_NORMAL;
2491      while (cond_temp > cond_stack)
2492        if (*cond_temp & PPDC_COND_SKIP)
2493	{
2494	  cond_state = PPDC_COND_SKIP;
2495	  break;
2496	}
2497	else
2498	  cond_temp --;
2499    }
2500    else if (!_cups_strcasecmp(temp, "#else"))
2501    {
2502      if (cond_current == cond_stack)
2503      {
2504        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2505		        fp->line, fp->filename);
2506        break;
2507      }
2508
2509      if (*cond_current & PPDC_COND_SATISFIED)
2510	*cond_current |= PPDC_COND_SKIP;
2511      else
2512      {
2513        *cond_current |= PPDC_COND_SATISFIED;
2514	*cond_current &= ~PPDC_COND_SKIP;
2515      }
2516
2517      // Update the current state
2518      int *cond_temp = cond_current;	// Temporary stack pointer
2519
2520      cond_state = PPDC_COND_NORMAL;
2521      while (cond_temp > cond_stack)
2522        if (*cond_temp & PPDC_COND_SKIP)
2523	{
2524	  cond_state = PPDC_COND_SKIP;
2525	  break;
2526	}
2527	else
2528	  cond_temp --;
2529    }
2530    else if (!_cups_strcasecmp(temp, "#endif"))
2531    {
2532      if (cond_current == cond_stack)
2533      {
2534        _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2535	                fp->line, fp->filename);
2536        break;
2537      }
2538
2539      cond_current --;
2540
2541      // Update the current state
2542      int *cond_temp = cond_current;	// Temporary stack pointer
2543
2544      cond_state = PPDC_COND_NORMAL;
2545      while (cond_temp > cond_stack)
2546        if (*cond_temp & PPDC_COND_SKIP)
2547	{
2548	  cond_state = PPDC_COND_SKIP;
2549	  break;
2550	}
2551	else
2552	  cond_temp --;
2553    }
2554    else if (!_cups_strcasecmp(temp, "#define"))
2555    {
2556      // Get the variable...
2557      get_variable(fp);
2558    }
2559    else if (!_cups_strcasecmp(temp, "#include"))
2560    {
2561      // #include filename
2562      char	basedir[1024],		// Base directory
2563		*baseptr,		// Pointer into directory
2564		inctemp[1024],		// Initial filename
2565		incname[1024];		// Include filename
2566      ppdcFile	*incfile;		// Include file
2567      int	*old_current = cond_current;
2568					// Previous current stack
2569
2570
2571      // Get the include name...
2572      if (!get_token(fp, inctemp, sizeof(inctemp)))
2573      {
2574        _cupsLangPrintf(stderr,
2575	                _("ppdc: Expected include filename on line %d of "
2576			  "%s."), fp->line, fp->filename);
2577        break;
2578      }
2579
2580      if (cond_state)
2581        continue;
2582
2583      // Figure out the current directory...
2584      strlcpy(basedir, fp->filename, sizeof(basedir));
2585
2586      if ((baseptr = strrchr(basedir, '/')) != NULL)
2587	*baseptr = '\0';
2588      else
2589	strlcpy(basedir, ".", sizeof(basedir));
2590
2591      // Find the include file...
2592      if (find_include(inctemp, basedir, incname, sizeof(incname)))
2593      {
2594	// Open the include file, scan it, and then close it...
2595	incfile = new ppdcFile(incname);
2596	scan_file(incfile, d, true);
2597	delete incfile;
2598
2599	if (cond_current != old_current)
2600	  _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."),
2601	                  incname);
2602      }
2603      else
2604      {
2605	// Can't find it!
2606	_cupsLangPrintf(stderr,
2607		        _("ppdc: Unable to find include file \"%s\" on line %d "
2608			  "of %s."), inctemp, fp->line, fp->filename);
2609	break;
2610      }
2611    }
2612    else if (!_cups_strcasecmp(temp, "#media"))
2613    {
2614      ppdcMediaSize	*m;		// Media size
2615
2616
2617      // Get a media size...
2618      m = get_size(fp);
2619      if (m)
2620      {
2621        if (cond_state)
2622	  m->release();
2623	else
2624          sizes->add(m);
2625      }
2626    }
2627    else if (!_cups_strcasecmp(temp, "#po"))
2628    {
2629      ppdcCatalog	*cat;		// Message catalog
2630
2631
2632      // Get a message catalog...
2633      cat = get_po(fp);
2634      if (cat)
2635      {
2636        if (cond_state)
2637	  cat->release();
2638	else
2639	  po_files->add(cat);
2640      }
2641    }
2642    else if (!_cups_strcasecmp(temp, "Attribute") ||
2643             !_cups_strcasecmp(temp, "LocAttribute"))
2644    {
2645      ppdcAttr	*a;			// Attribute
2646
2647
2648      // Get an attribute...
2649      a = get_attr(fp, !_cups_strcasecmp(temp, "LocAttribute"));
2650      if (a)
2651      {
2652        if (cond_state)
2653	  a->release();
2654	else
2655          d->add_attr(a);
2656      }
2657    }
2658    else if (!_cups_strcasecmp(temp, "Choice"))
2659    {
2660      // Get a choice...
2661      c = get_choice(fp);
2662      if (!c)
2663        break;
2664
2665      if (cond_state)
2666      {
2667        c->release();
2668        continue;
2669      }
2670
2671      // Add it to the current option...
2672      if (!o)
2673      {
2674        _cupsLangPrintf(stderr,
2675	                _("ppdc: Choice found on line %d of %s with no "
2676			  "Option."), fp->line, fp->filename);
2677        break;
2678      }
2679
2680      o->add_choice(c);
2681
2682      if (isdefault)
2683        o->set_defchoice(c);
2684    }
2685    else if (!_cups_strcasecmp(temp, "ColorDevice"))
2686    {
2687      // ColorDevice boolean
2688      if (cond_state)
2689        get_boolean(fp);
2690      else
2691        d->color_device = get_boolean(fp);
2692    }
2693    else if (!_cups_strcasecmp(temp, "ColorModel"))
2694    {
2695      // Get the color model
2696      c = get_color_model(fp);
2697      if (!c)
2698        continue;
2699
2700      if (cond_state)
2701      {
2702        c->release();
2703        continue;
2704      }
2705
2706      // Add the choice to the ColorModel option...
2707      if ((o = d->find_option("ColorModel")) == NULL)
2708      {
2709	// Create the ColorModel option...
2710	o = new ppdcOption(PPDC_PICKONE, "ColorModel", "Color Mode", PPDC_SECTION_ANY, 10.0f);
2711	g = general;
2712	g->add_option(o);
2713      }
2714
2715      o->add_choice(c);
2716
2717      if (isdefault)
2718	o->set_defchoice(c);
2719
2720      o = NULL;
2721    }
2722    else if (!_cups_strcasecmp(temp, "ColorProfile"))
2723    {
2724      ppdcProfile	*p;		// Color profile
2725
2726
2727      // Get the color profile...
2728      p = get_color_profile(fp);
2729
2730      if (p)
2731      {
2732        if (cond_state)
2733	  p->release();
2734	else
2735          d->profiles->add(p);
2736      }
2737    }
2738    else if (!_cups_strcasecmp(temp, "Copyright"))
2739    {
2740      // Copyright string
2741      char	copytemp[8192],		// Copyright string
2742		*copyptr,		// Pointer into string
2743		*copyend;		// Pointer to end of string
2744
2745
2746      // Get the copyright string...
2747      if (!get_token(fp, copytemp, sizeof(temp)))
2748      {
2749        _cupsLangPrintf(stderr,
2750	                _("ppdc: Expected string after Copyright on line %d "
2751			  "of %s."), fp->line, fp->filename);
2752	break;
2753      }
2754
2755      if (cond_state)
2756        continue;
2757
2758      // Break it up into individual lines...
2759      for (copyptr = copytemp; copyptr; copyptr = copyend)
2760      {
2761        if ((copyend = strchr(copyptr, '\n')) != NULL)
2762	  *copyend++ = '\0';
2763
2764        d->copyright->add(new ppdcString(copyptr));
2765      }
2766    }
2767    else if (!_cups_strcasecmp(temp, "CustomMedia"))
2768    {
2769      ppdcMediaSize	*m;		// Media size
2770
2771
2772      // Get a custom media size...
2773      m = get_custom_size(fp);
2774
2775      if (cond_state)
2776      {
2777        m->release();
2778        continue;
2779      }
2780
2781      if (m)
2782        d->sizes->add(m);
2783
2784      if (isdefault)
2785        d->set_default_size(m);
2786    }
2787    else if (!_cups_strcasecmp(temp, "Cutter"))
2788    {
2789      // Cutter boolean
2790      int	have_cutter;		// Have a paper cutter?
2791
2792
2793      have_cutter = get_boolean(fp);
2794      if (have_cutter <= 0 || cond_state)
2795        continue;
2796
2797      if ((o = d->find_option("CutMedia")) == NULL)
2798      {
2799        o = new ppdcOption(PPDC_BOOLEAN, "CutMedia", "Cut Media", PPDC_SECTION_ANY, 10.0f);
2800
2801	g = general;
2802	g->add_option(o);
2803
2804	c = new ppdcChoice("False", NULL, "<</CutMedia 0>>setpagedevice");
2805	o->add_choice(c);
2806	o->set_defchoice(c);
2807
2808	c = new ppdcChoice("True", NULL, "<</CutMedia 4>>setpagedevice");
2809	o->add_choice(c);
2810      }
2811
2812      o = NULL;
2813    }
2814    else if (!_cups_strcasecmp(temp, "Darkness"))
2815    {
2816      // Get the darkness choice...
2817      c = get_generic(fp, "Darkness", NULL, "cupsCompression");
2818      if (!c)
2819        continue;
2820
2821      if (cond_state)
2822      {
2823        c->release();
2824        continue;
2825      }
2826
2827      // Add the choice to the cupsDarkness option...
2828      if ((o = d->find_option_group("cupsDarkness", &mg)) == NULL)
2829      {
2830	// Create the cupsDarkness option...
2831	o = new ppdcOption(PPDC_PICKONE, "cupsDarkness", "Darkness", PPDC_SECTION_ANY, 10.0f);
2832	g = general;
2833	g->add_option(o);
2834      }
2835      else if (mg != general)
2836      {
2837	_cupsLangPrintf(stderr,
2838			_("ppdc: Option %s defined in two different groups on "
2839			  "line %d of %s."), "cupsDarkness", fp->line,
2840		        fp->filename);
2841	c->release();
2842	continue;
2843      }
2844
2845      o->add_choice(c);
2846
2847      if (isdefault)
2848	o->set_defchoice(c);
2849
2850      o = NULL;
2851    }
2852    else if (!_cups_strcasecmp(temp, "DriverType"))
2853    {
2854      int	i;			// Looping var
2855
2856
2857      // DriverType keyword
2858      if (!get_token(fp, temp, sizeof(temp)))
2859      {
2860        _cupsLangPrintf(stderr,
2861	                _("ppdc: Expected driver type keyword following "
2862			  "DriverType on line %d of %s."),
2863			fp->line, fp->filename);
2864        continue;
2865      }
2866
2867      if (cond_state)
2868        continue;
2869
2870      for (i = 0; i < (int)(sizeof(driver_types) / sizeof(driver_types[0])); i ++)
2871        if (!_cups_strcasecmp(temp, driver_types[i]))
2872	  break;
2873
2874      if (i < (int)(sizeof(driver_types) / sizeof(driver_types[0])))
2875        d->type = (ppdcDrvType)i;
2876      else if (!_cups_strcasecmp(temp, "dymo"))
2877        d->type = PPDC_DRIVER_LABEL;
2878      else
2879        _cupsLangPrintf(stderr,
2880	                _("ppdc: Unknown driver type %s on line %d of %s."),
2881			temp, fp->line, fp->filename);
2882    }
2883    else if (!_cups_strcasecmp(temp, "Duplex"))
2884      get_duplex(fp, d);
2885    else if (!_cups_strcasecmp(temp, "Filter"))
2886    {
2887      ppdcFilter	*f;		// Filter
2888
2889
2890      // Get the filter value...
2891      f = get_filter(fp);
2892      if (f)
2893      {
2894        if (cond_state)
2895	  f->release();
2896	else
2897          d->filters->add(f);
2898      }
2899    }
2900    else if (!_cups_strcasecmp(temp, "Finishing"))
2901    {
2902      // Get the finishing choice...
2903      c = get_generic(fp, "Finishing", "OutputType", NULL);
2904      if (!c)
2905        continue;
2906
2907      if (cond_state)
2908      {
2909        c->release();
2910        continue;
2911      }
2912
2913      // Add the choice to the cupsFinishing option...
2914      if ((o = d->find_option_group("cupsFinishing", &mg)) == NULL)
2915      {
2916	// Create the cupsFinishing option...
2917	o = new ppdcOption(PPDC_PICKONE, "cupsFinishing", "Finishing", PPDC_SECTION_ANY, 10.0f);
2918	g = general;
2919	g->add_option(o);
2920      }
2921      else if (mg != general)
2922      {
2923	_cupsLangPrintf(stderr,
2924			_("ppdc: Option %s defined in two different groups on "
2925			  "line %d of %s."), "cupsFinishing", fp->line,
2926		        fp->filename);
2927	c->release();
2928	continue;
2929      }
2930
2931      o->add_choice(c);
2932
2933      if (isdefault)
2934	o->set_defchoice(c);
2935
2936      o = NULL;
2937    }
2938    else if (!_cups_strcasecmp(temp, "Font") ||
2939             !_cups_strcasecmp(temp, "#font"))
2940    {
2941      ppdcFont	*f;			// Font
2942
2943
2944      // Get a font...
2945      f = get_font(fp);
2946      if (f)
2947      {
2948        if (cond_state)
2949	  f->release();
2950	else
2951	{
2952	  if (!_cups_strcasecmp(temp, "#font"))
2953	    base_fonts->add(f);
2954	  else
2955	    d->add_font(f);
2956
2957	  if (isdefault)
2958	    d->set_default_font(f);
2959	}
2960      }
2961    }
2962    else if (!_cups_strcasecmp(temp, "Group"))
2963    {
2964      // Get a group...
2965      ppdcGroup *tempg = get_group(fp, d);
2966
2967      if (!tempg)
2968        break;
2969
2970      if (cond_state)
2971      {
2972        if (!d->find_group(tempg->name->value))
2973          tempg->release();
2974      }
2975      else
2976      {
2977	if (!d->find_group(tempg->name->value))
2978	  d->add_group(tempg);
2979
2980        g = tempg;
2981      }
2982    }
2983    else if (!_cups_strcasecmp(temp, "HWMargins"))
2984    {
2985      // HWMargins left bottom right top
2986      d->left_margin   = get_measurement(fp);
2987      d->bottom_margin = get_measurement(fp);
2988      d->right_margin  = get_measurement(fp);
2989      d->top_margin    = get_measurement(fp);
2990    }
2991    else if (!_cups_strcasecmp(temp, "InputSlot"))
2992    {
2993      // Get the input slot choice...
2994      c = get_generic(fp, "InputSlot", NULL, "MediaPosition");
2995      if (!c)
2996        continue;
2997
2998      if (cond_state)
2999      {
3000        c->release();
3001        continue;
3002      }
3003
3004      // Add the choice to the InputSlot option...
3005
3006      if ((o = d->find_option_group("InputSlot", &mg)) == NULL)
3007      {
3008	// Create the InputSlot option...
3009	o = new ppdcOption(PPDC_PICKONE, "InputSlot", "Media Source",
3010	                   PPDC_SECTION_ANY, 10.0f);
3011	g = general;
3012	g->add_option(o);
3013      }
3014      else if (mg != general)
3015      {
3016	_cupsLangPrintf(stderr,
3017			_("ppdc: Option %s defined in two different groups on "
3018			  "line %d of %s."), "InputSlot", fp->line,
3019		        fp->filename);
3020	c->release();
3021	continue;
3022      }
3023
3024      o->add_choice(c);
3025
3026      if (isdefault)
3027	o->set_defchoice(c);
3028
3029      o = NULL;
3030    }
3031    else if (!_cups_strcasecmp(temp, "Installable"))
3032    {
3033      // Get the installable option...
3034      o = get_installable(fp);
3035
3036      // Add it as needed...
3037      if (o)
3038      {
3039        if (cond_state)
3040	  o->release();
3041	else
3042          install->add_option(o);
3043
3044        o = NULL;
3045      }
3046    }
3047    else if (!_cups_strcasecmp(temp, "ManualCopies"))
3048    {
3049      // ManualCopies boolean
3050      if (cond_state)
3051        get_boolean(fp);
3052      else
3053        d->manual_copies = get_boolean(fp);
3054    }
3055    else if (!_cups_strcasecmp(temp, "Manufacturer"))
3056    {
3057      // Manufacturer name
3058      char	name[256];		// Model name string
3059
3060
3061      if (!get_token(fp, name, sizeof(name)))
3062      {
3063        _cupsLangPrintf(stderr,
3064			_("ppdc: Expected name after Manufacturer on line %d "
3065			  "of %s."), fp->line, fp->filename);
3066	break;
3067      }
3068
3069      if (!cond_state)
3070        d->set_manufacturer(name);
3071    }
3072    else if (!_cups_strcasecmp(temp, "MaxSize"))
3073    {
3074      // MaxSize width length
3075      if (cond_state)
3076      {
3077        get_measurement(fp);
3078	get_measurement(fp);
3079      }
3080      else
3081      {
3082	d->max_width  = get_measurement(fp);
3083	d->max_length = get_measurement(fp);
3084      }
3085    }
3086    else if (!_cups_strcasecmp(temp, "MediaSize"))
3087    {
3088      // MediaSize keyword
3089      char		name[41];	// Media size name
3090      ppdcMediaSize	*m,		// Matching media size...
3091			*dm;		// Driver media size...
3092
3093
3094      if (get_token(fp, name, sizeof(name)) == NULL)
3095      {
3096        _cupsLangPrintf(stderr,
3097	                _("ppdc: Expected name after MediaSize on line %d of "
3098			  "%s."), fp->line, fp->filename);
3099	break;
3100      }
3101
3102      if (cond_state)
3103        continue;
3104
3105      m = find_size(name);
3106
3107      if (!m)
3108      {
3109        _cupsLangPrintf(stderr,
3110	                _("ppdc: Unknown media size \"%s\" on line %d of "
3111			  "%s."), name, fp->line, fp->filename);
3112	break;
3113      }
3114
3115      // Add this size to the driver...
3116      dm = new ppdcMediaSize(m->name->value, m->text->value,
3117                             m->width, m->length, d->left_margin,
3118			     d->bottom_margin, d->right_margin,
3119			     d->top_margin);
3120      d->sizes->add(dm);
3121
3122      if (isdefault)
3123        d->set_default_size(dm);
3124    }
3125    else if (!_cups_strcasecmp(temp, "MediaType"))
3126    {
3127      // Get the media type choice...
3128      c = get_generic(fp, "MediaType", "MediaType", "cupsMediaType");
3129      if (!c)
3130        continue;
3131
3132      if (cond_state)
3133      {
3134        c->release();
3135        continue;
3136      }
3137
3138      // Add the choice to the MediaType option...
3139      if ((o = d->find_option_group("MediaType", &mg)) == NULL)
3140      {
3141	// Create the MediaType option...
3142	o = new ppdcOption(PPDC_PICKONE, "MediaType", "Media Type",
3143	                   PPDC_SECTION_ANY, 10.0f);
3144	g = general;
3145	g->add_option(o);
3146      }
3147      else if (mg != general)
3148      {
3149	_cupsLangPrintf(stderr,
3150			_("ppdc: Option %s defined in two different groups on "
3151			  "line %d of %s."), "MediaType", fp->line,
3152		        fp->filename);
3153	c->release();
3154	continue;
3155      }
3156
3157      o->add_choice(c);
3158
3159      if (isdefault)
3160	o->set_defchoice(c);
3161
3162      o = NULL;
3163    }
3164    else if (!_cups_strcasecmp(temp, "MinSize"))
3165    {
3166      // MinSize width length
3167      if (cond_state)
3168      {
3169        get_measurement(fp);
3170	get_measurement(fp);
3171      }
3172      else
3173      {
3174	d->min_width  = get_measurement(fp);
3175	d->min_length = get_measurement(fp);
3176      }
3177    }
3178    else if (!_cups_strcasecmp(temp, "ModelName"))
3179    {
3180      // ModelName name
3181      char	name[256];		// Model name string
3182
3183
3184      if (!get_token(fp, name, sizeof(name)))
3185      {
3186        _cupsLangPrintf(stderr,
3187	                _("ppdc: Expected name after ModelName on line %d of "
3188			  "%s."), fp->line, fp->filename);
3189	break;
3190      }
3191
3192      if (!cond_state)
3193        d->set_model_name(name);
3194    }
3195    else if (!_cups_strcasecmp(temp, "ModelNumber"))
3196    {
3197      // ModelNumber number
3198      if (cond_state)
3199        get_integer(fp);
3200      else
3201        d->model_number = get_integer(fp);
3202    }
3203    else if (!_cups_strcasecmp(temp, "Option"))
3204    {
3205      // Get an option...
3206      ppdcOption *tempo = get_option(fp, d, g);
3207
3208      if (!tempo)
3209        break;
3210
3211      if (cond_state)
3212      {
3213        if (!g->find_option(tempo->name->value))
3214	  tempo->release();
3215      }
3216      else
3217      {
3218        if (!g->find_option(tempo->name->value))
3219	  g->add_option(tempo);
3220
3221        o = tempo;
3222      }
3223    }
3224    else if (!_cups_strcasecmp(temp, "FileName"))
3225    {
3226      // FileName name
3227      char	name[256];		// Filename string
3228
3229
3230      if (!get_token(fp, name, sizeof(name)))
3231      {
3232        _cupsLangPrintf(stderr,
3233	                _("ppdc: Expected name after FileName on line %d of "
3234			  "%s."), fp->line, fp->filename);
3235	break;
3236      }
3237
3238      if (!cond_state)
3239        d->set_file_name(name);
3240    }
3241    else if (!_cups_strcasecmp(temp, "PCFileName"))
3242    {
3243      // PCFileName name
3244      char	name[256];		// PC filename string
3245
3246
3247      if (!get_token(fp, name, sizeof(name)))
3248      {
3249        _cupsLangPrintf(stderr,
3250	                _("ppdc: Expected name after PCFileName on line %d of "
3251			  "%s."), fp->line, fp->filename);
3252	break;
3253      }
3254
3255      if (!cond_state)
3256        d->set_pc_file_name(name);
3257    }
3258    else if (!_cups_strcasecmp(temp, "Resolution"))
3259    {
3260      // Get the resolution choice...
3261      c = get_resolution(fp);
3262      if (!c)
3263        continue;
3264
3265      if (cond_state)
3266      {
3267        c->release();
3268        continue;
3269      }
3270
3271      // Add the choice to the Resolution option...
3272      if ((o = d->find_option_group("Resolution", &mg)) == NULL)
3273      {
3274	// Create the Resolution option...
3275	o = new ppdcOption(PPDC_PICKONE, "Resolution", NULL, PPDC_SECTION_ANY,
3276	                   10.0f);
3277	g = general;
3278	g->add_option(o);
3279      }
3280      else if (mg != general)
3281      {
3282	_cupsLangPrintf(stderr,
3283			_("ppdc: Option %s defined in two different groups on "
3284			  "line %d of %s."), "Resolution", fp->line,
3285		        fp->filename);
3286	c->release();
3287	continue;
3288      }
3289
3290      o->add_choice(c);
3291
3292      if (isdefault)
3293	o->set_defchoice(c);
3294
3295      o = NULL;
3296    }
3297    else if (!_cups_strcasecmp(temp, "SimpleColorProfile"))
3298    {
3299      ppdcProfile	*p;		// Color profile
3300
3301
3302      // Get the color profile...
3303      p = get_simple_profile(fp);
3304
3305      if (p)
3306      {
3307        if (cond_state)
3308	  p->release();
3309	else
3310          d->profiles->add(p);
3311      }
3312    }
3313    else if (!_cups_strcasecmp(temp, "Throughput"))
3314    {
3315      // Throughput number
3316      if (cond_state)
3317        get_integer(fp);
3318      else
3319        d->throughput = get_integer(fp);
3320    }
3321    else if (!_cups_strcasecmp(temp, "UIConstraints"))
3322    {
3323      ppdcConstraint	*con;		// Constraint
3324
3325
3326      con = get_constraint(fp);
3327
3328      if (con)
3329      {
3330        if (cond_state)
3331	  con->release();
3332	else
3333	  d->constraints->add(con);
3334      }
3335    }
3336    else if (!_cups_strcasecmp(temp, "VariablePaperSize"))
3337    {
3338      // VariablePaperSize boolean
3339      if (cond_state)
3340        get_boolean(fp);
3341      else
3342	d->variable_paper_size = get_boolean(fp);
3343    }
3344    else if (!_cups_strcasecmp(temp, "Version"))
3345    {
3346      // Version string
3347      char	name[256];		// Model name string
3348
3349
3350      if (!get_token(fp, name, sizeof(name)))
3351      {
3352        _cupsLangPrintf(stderr,
3353	                _("ppdc: Expected string after Version on line %d of "
3354			  "%s."), fp->line, fp->filename);
3355	break;
3356      }
3357
3358      if (!cond_state)
3359        d->set_version(name);
3360    }
3361    else
3362    {
3363      _cupsLangPrintf(stderr,
3364                      _("ppdc: Unknown token \"%s\" seen on line %d of %s."),
3365		      temp, fp->line, fp->filename);
3366      break;
3367    }
3368  }
3369
3370  // Done processing this block, is there anything to save?
3371  if (!inc)
3372  {
3373    if (!d->pc_file_name || !d->model_name || !d->manufacturer || !d->version ||
3374	!d->sizes->count)
3375    {
3376      // Nothing to save...
3377      d->release();
3378    }
3379    else
3380    {
3381      // Got a driver, save it...
3382      drivers->add(d);
3383    }
3384  }
3385  else if (inc && td)
3386    td->release();
3387}
3388
3389
3390//
3391// 'ppdcSource::set_variable()' - Set a variable.
3392//
3393
3394ppdcVariable *				// O - Variable
3395ppdcSource::set_variable(
3396    const char *name,			// I - Name
3397    const char *value)			// I - Value
3398{
3399  ppdcVariable	*v;			// Variable
3400
3401
3402  // See if the variable exists already...
3403  v = find_variable(name);
3404  if (v)
3405  {
3406    // Change the variable value...
3407    v->set_value(value);
3408  }
3409  else
3410  {
3411    // Create a new variable and add it...
3412    v = new ppdcVariable(name, value);
3413    vars->add(v);
3414  }
3415
3416  return (v);
3417}
3418
3419
3420//
3421// 'ppdcSource::write_file()' - Write the current source data to a file.
3422//
3423
3424int					// O - 0 on success, -1 on error
3425ppdcSource::write_file(const char *f)	// I - File to write
3426{
3427  cups_file_t	*fp;			// Output file
3428  char		bckname[1024];		// Backup file
3429  ppdcDriver	*d;			// Current driver
3430  ppdcString	*st;			// Current string
3431  ppdcAttr	*a;			// Current attribute
3432  ppdcConstraint *co;			// Current constraint
3433  ppdcFilter	*fi;			// Current filter
3434  ppdcFont	*fo;			// Current font
3435  ppdcGroup	*g;			// Current group
3436  ppdcOption	*o;			// Current option
3437  ppdcChoice	*ch;			// Current choice
3438  ppdcProfile	*p;			// Current color profile
3439  ppdcMediaSize	*si;			// Current media size
3440  float		left,			// Current left margin
3441		bottom,			// Current bottom margin
3442		right,			// Current right margin
3443		top;			// Current top margin
3444  int		dtused[PPDC_DRIVER_MAX];// Driver type usage...
3445
3446
3447  // Rename the current file, if any, to .bck...
3448  snprintf(bckname, sizeof(bckname), "%s.bck", f);
3449  rename(f, bckname);
3450
3451  // Open the output file...
3452  fp = cupsFileOpen(f, "w");
3453
3454  if (!fp)
3455  {
3456    // Can't create file; restore backup and return...
3457    rename(bckname, f);
3458    return (-1);
3459  }
3460
3461  cupsFilePuts(fp, "// CUPS PPD Compiler " CUPS_SVERSION "\n\n");
3462
3463  // Include standard files...
3464  cupsFilePuts(fp, "// Include necessary files...\n");
3465  cupsFilePuts(fp, "#include <font.defs>\n");
3466  cupsFilePuts(fp, "#include <media.defs>\n");
3467
3468  memset(dtused, 0, sizeof(dtused));
3469
3470  for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
3471    if (d->type > PPDC_DRIVER_PS && !dtused[d->type])
3472    {
3473      cupsFilePrintf(fp, "#include <%s.h>\n", driver_types[d->type]);
3474      dtused[d->type] = 1;
3475    }
3476
3477  // Output each driver...
3478  for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
3479  {
3480    // Start the driver...
3481    cupsFilePrintf(fp, "\n// %s %s\n", d->manufacturer->value,
3482                   d->model_name->value);
3483    cupsFilePuts(fp, "{\n");
3484
3485    // Write the copyright stings...
3486    for (st = (ppdcString *)d->copyright->first();
3487         st;
3488	 st = (ppdcString *)d->copyright->next())
3489      quotef(fp, "  Copyright \"%s\"\n", st->value);
3490
3491    // Write other strings and values...
3492    if (d->manufacturer && d->manufacturer->value)
3493      quotef(fp, "  Manufacturer \"%s\"\n", d->manufacturer->value);
3494    if (d->model_name->value)
3495      quotef(fp, "  ModelName \"%s\"\n", d->model_name->value);
3496    if (d->file_name && d->file_name->value)
3497      quotef(fp, "  FileName \"%s\"\n", d->file_name->value);
3498    if (d->pc_file_name && d->pc_file_name->value)
3499      quotef(fp, "  PCFileName \"%s\"\n", d->pc_file_name->value);
3500    if (d->version && d->version->value)
3501      quotef(fp, "  Version \"%s\"\n", d->version->value);
3502
3503    cupsFilePrintf(fp, "  DriverType %s\n", driver_types[d->type]);
3504
3505    if (d->model_number)
3506    {
3507      switch (d->type)
3508      {
3509	case PPDC_DRIVER_LABEL :
3510	    cupsFilePuts(fp, "  ModelNumber ");
3511
3512	    switch (d->model_number)
3513	    {
3514	      case DYMO_3x0 :
3515		  cupsFilePuts(fp, "$DYMO_3x0\n");
3516		  break;
3517
3518	      case ZEBRA_EPL_LINE :
3519		  cupsFilePuts(fp, "$ZEBRA_EPL_LINE\n");
3520		  break;
3521
3522	      case ZEBRA_EPL_PAGE :
3523		  cupsFilePuts(fp, "$ZEBRA_EPL_PAGE\n");
3524		  break;
3525
3526	      case ZEBRA_ZPL :
3527		  cupsFilePuts(fp, "$ZEBRA_ZPL\n");
3528		  break;
3529
3530	      case ZEBRA_CPCL :
3531		  cupsFilePuts(fp, "$ZEBRA_CPCL\n");
3532		  break;
3533
3534	      case INTELLITECH_PCL :
3535		  cupsFilePuts(fp, "$INTELLITECH_PCL\n");
3536		  break;
3537
3538	      default :
3539		  cupsFilePrintf(fp, "%d\n", d->model_number);
3540		  break;
3541	    }
3542	    break;
3543
3544	case PPDC_DRIVER_EPSON :
3545	    cupsFilePuts(fp, "  ModelNumber ");
3546
3547	    switch (d->model_number)
3548	    {
3549	      case EPSON_9PIN :
3550		  cupsFilePuts(fp, "$EPSON_9PIN\n");
3551		  break;
3552
3553	      case EPSON_24PIN :
3554		  cupsFilePuts(fp, "$EPSON_24PIN\n");
3555		  break;
3556
3557	      case EPSON_COLOR :
3558		  cupsFilePuts(fp, "$EPSON_COLOR\n");
3559		  break;
3560
3561	      case EPSON_PHOTO :
3562		  cupsFilePuts(fp, "$EPSON_PHOTO\n");
3563		  break;
3564
3565	      case EPSON_ICOLOR :
3566		  cupsFilePuts(fp, "$EPSON_ICOLOR\n");
3567		  break;
3568
3569	      case EPSON_IPHOTO :
3570		  cupsFilePuts(fp, "$EPSON_IPHOTO\n");
3571		  break;
3572
3573	      default :
3574		  cupsFilePrintf(fp, "%d\n", d->model_number);
3575	          break;
3576	    }
3577	    break;
3578
3579	case PPDC_DRIVER_HP :
3580	    cupsFilePuts(fp, "  ModelNumber ");
3581	    switch (d->model_number)
3582	    {
3583	      case HP_LASERJET :
3584	          cupsFilePuts(fp, "$HP_LASERJET\n");
3585		  break;
3586
3587	      case HP_DESKJET :
3588	          cupsFilePuts(fp, "$HP_DESKJET\n");
3589		  break;
3590
3591	      case HP_DESKJET2 :
3592	          cupsFilePuts(fp, "$HP_DESKJET2\n");
3593		  break;
3594
3595	      default :
3596		  cupsFilePrintf(fp, "%d\n", d->model_number);
3597		  break;
3598	    }
3599
3600	    cupsFilePuts(fp, ")\n");
3601	    break;
3602
3603        default :
3604            cupsFilePrintf(fp, "  ModelNumber %d\n", d->model_number);
3605	    break;
3606      }
3607    }
3608
3609    if (d->manual_copies)
3610      cupsFilePuts(fp, "  ManualCopies Yes\n");
3611
3612    if (d->color_device)
3613      cupsFilePuts(fp, "  ColorDevice Yes\n");
3614
3615    if (d->throughput)
3616      cupsFilePrintf(fp, "  Throughput %d\n", d->throughput);
3617
3618    // Output all of the attributes...
3619    for (a = (ppdcAttr *)d->attrs->first();
3620         a;
3621	 a = (ppdcAttr *)d->attrs->next())
3622      if (a->text->value && a->text->value[0])
3623	quotef(fp, "  Attribute \"%s\" \"%s/%s\" \"%s\"\n",
3624               a->name->value, a->selector->value ? a->selector->value : "",
3625	       a->text->value, a->value->value ? a->value->value : "");
3626      else
3627	quotef(fp, "  Attribute \"%s\" \"%s\" \"%s\"\n",
3628               a->name->value, a->selector->value ? a->selector->value : "",
3629	       a->value->value ? a->value->value : "");
3630
3631    // Output all of the constraints...
3632    for (co = (ppdcConstraint *)d->constraints->first();
3633         co;
3634	 co = (ppdcConstraint *)d->constraints->next())
3635    {
3636      if (co->option1->value[0] == '*')
3637	cupsFilePrintf(fp, "  UIConstraints \"%s %s", co->option1->value,
3638		       co->choice1->value ? co->choice1->value : "");
3639      else
3640	cupsFilePrintf(fp, "  UIConstraints \"*%s %s", co->option1->value,
3641		       co->choice1->value ? co->choice1->value : "");
3642
3643      if (co->option2->value[0] == '*')
3644	cupsFilePrintf(fp, " %s %s\"\n", co->option2->value,
3645		       co->choice2->value ? co->choice2->value : "");
3646      else
3647	cupsFilePrintf(fp, " *%s %s\"\n", co->option2->value,
3648		       co->choice2->value ? co->choice2->value : "");
3649    }
3650
3651    // Output all of the filters...
3652    for (fi = (ppdcFilter *)d->filters->first();
3653         fi;
3654	 fi = (ppdcFilter *)d->filters->next())
3655      cupsFilePrintf(fp, "  Filter \"%s %d %s\"\n",
3656                     fi->mime_type->value, fi->cost, fi->program->value);
3657
3658    // Output all of the fonts...
3659    for (fo = (ppdcFont *)d->fonts->first();
3660         fo;
3661	 fo = (ppdcFont *)d->fonts->next())
3662      if (!strcmp(fo->name->value, "*"))
3663        cupsFilePuts(fp, "  Font *\n");
3664      else
3665	cupsFilePrintf(fp, "  Font \"%s\" \"%s\" \"%s\" \"%s\" %s\n",
3666        	       fo->name->value, fo->encoding->value,
3667		       fo->version->value, fo->charset->value,
3668		       fo->status == PPDC_FONT_ROM ? "ROM" : "Disk");
3669
3670    // Output all options...
3671    for (g = (ppdcGroup *)d->groups->first();
3672         g;
3673	 g = (ppdcGroup *)d->groups->next())
3674    {
3675      if (g->options->count == 0)
3676        continue;
3677
3678      if (g->text->value && g->text->value[0])
3679        quotef(fp, "  Group \"%s/%s\"\n", g->name->value, g->text->value);
3680      else
3681        cupsFilePrintf(fp, "  Group \"%s\"\n", g->name->value);
3682
3683      for (o = (ppdcOption *)g->options->first();
3684           o;
3685	   o = (ppdcOption *)g->options->next())
3686      {
3687        if (o->choices->count == 0)
3688	  continue;
3689
3690	if (o->text->value && o->text->value[0])
3691          quotef(fp, "    Option \"%s/%s\"", o->name->value, o->text->value);
3692	else
3693          cupsFilePrintf(fp, "    Option \"%s\"", o->name->value);
3694
3695        cupsFilePrintf(fp, " %s %s %.1f\n",
3696		       o->type == PPDC_BOOLEAN ? "Boolean" :
3697			   o->type == PPDC_PICKONE ? "PickOne" : "PickMany",
3698		       o->section == PPDC_SECTION_ANY ? "AnySetup" :
3699			   o->section == PPDC_SECTION_DOCUMENT ? "DocumentSetup" :
3700			   o->section == PPDC_SECTION_EXIT ? "ExitServer" :
3701			   o->section == PPDC_SECTION_JCL ? "JCLSetup" :
3702			   o->section == PPDC_SECTION_PAGE ? "PageSetup" :
3703			   "Prolog",
3704		       o->order);
3705
3706        for (ch = (ppdcChoice *)o->choices->first();
3707	     ch;
3708	     ch = (ppdcChoice *)o->choices->next())
3709	{
3710	  if (ch->text->value && ch->text->value[0])
3711            quotef(fp, "      %sChoice \"%s/%s\" \"%s\"\n",
3712	    	   o->defchoice == ch->name ? "*" : "",
3713                   ch->name->value, ch->text->value,
3714		   ch->code->value ? ch->code->value : "");
3715	  else
3716            quotef(fp, "      %sChoice \"%s\" \"%s\"\n",
3717	           o->defchoice == ch->name ? "*" : "",
3718		   ch->name->value,
3719		   ch->code->value ? ch->code->value : "");
3720	}
3721      }
3722    }
3723
3724    // Output all of the color profiles...
3725    for (p = (ppdcProfile *)d->profiles->first();
3726         p;
3727	 p = (ppdcProfile *)d->profiles->next())
3728      cupsFilePrintf(fp, "  ColorProfile \"%s/%s\" %.3f %.3f "
3729                	 "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n",
3730        	     p->resolution->value, p->media_type->value,
3731		     p->density, p->gamma,
3732		     p->profile[0], p->profile[1], p->profile[2],
3733		     p->profile[3], p->profile[4], p->profile[5],
3734		     p->profile[6], p->profile[7], p->profile[8]);
3735
3736    // Output all of the media sizes...
3737    left   = 0.0;
3738    bottom = 0.0;
3739    right  = 0.0;
3740    top    = 0.0;
3741
3742    for (si = (ppdcMediaSize *)d->sizes->first();
3743         si;
3744	 si = (ppdcMediaSize *)d->sizes->next())
3745      if (si->size_code->value && si->region_code->value)
3746      {
3747        // Output a custom media size...
3748	quotef(fp, "  %sCustomMedia \"%s/%s\" %.2f %.2f %.2f %.2f %.2f %.2f \"%s\" \"%s\"\n",
3749	       si->name == d->default_size ? "*" : "", si->name->value,
3750	       si->text->value, si->width, si->length, si->left, si->bottom,
3751	       si->right, si->top, si->size_code->value,
3752	       si->region_code->value);
3753      }
3754      else
3755      {
3756        // Output a standard media size...
3757	if (fabs(left - si->left) > 0.1 ||
3758            fabs(bottom - si->bottom) > 0.1 ||
3759            fabs(right - si->right) > 0.1 ||
3760            fabs(top - si->top) > 0.1)
3761	{
3762          cupsFilePrintf(fp, "  HWMargins %.2f %.2f %.2f %.2f\n",
3763	        	 si->left, si->bottom, si->right, si->top);
3764
3765          left   = si->left;
3766	  bottom = si->bottom;
3767	  right  = si->right;
3768	  top    = si->top;
3769	}
3770
3771	cupsFilePrintf(fp, "  %sMediaSize %s\n",
3772	               si->name == d->default_size ? "*" : "",
3773        	       si->name->value);
3774      }
3775
3776    if (d->variable_paper_size)
3777    {
3778      cupsFilePuts(fp, "  VariablePaperSize Yes\n");
3779
3780      if (fabs(left - d->left_margin) > 0.1 ||
3781          fabs(bottom - d->bottom_margin) > 0.1 ||
3782          fabs(right - d->right_margin) > 0.1 ||
3783          fabs(top - d->top_margin) > 0.1)
3784      {
3785        cupsFilePrintf(fp, "  HWMargins %.2f %.2f %.2f %.2f\n",
3786	               d->left_margin, d->bottom_margin, d->right_margin,
3787		       d->top_margin);
3788      }
3789
3790      cupsFilePrintf(fp, "  MinSize %.2f %.2f\n", d->min_width, d->min_length);
3791      cupsFilePrintf(fp, "  MaxSize %.2f %.2f\n", d->max_width, d->max_length);
3792    }
3793
3794    // End the driver...
3795    cupsFilePuts(fp, "}\n");
3796  }
3797
3798  // Close the file and return...
3799  cupsFileClose(fp);
3800
3801  return (0);
3802}
3803
3804
3805//
3806// End of "$Id: ppdc-source.cxx 11560 2014-02-06 20:10:19Z msweet $".
3807//
3808