1//
2// "$Id: ppdc-driver.cxx 3942 2012-10-15 21:05:33Z msweet $"
3//
4//   PPD file compiler definitions for the CUPS PPD Compiler.
5//
6//   Copyright 2007-2011 by Apple Inc.
7//   Copyright 2002-2006 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// Contents:
16//
17//   ppdcDriver::ppdcDriver()           - Create a new printer driver.
18//   ppdcDriver::~ppdcDriver()          - Destroy a printer driver.
19//   ppdcDriver::find_attr()            - Find an attribute.
20//   ppdcDriver::find_group()           - Find a group.
21//   ppdcDriver::find_option()          - Find an option.
22//   ppdcDriver::find_option_group()    - Find an option and its group.
23//   ppdcDriver::set_custom_size_code() - Set the custom page size code.
24//   ppdcDriver::set_default_font()     - Set the default font name.
25//   ppdcDriver::set_default_size()     - Set the default size name.
26//   ppdcDriver::set_file_name()        - Set the full filename.
27//   ppdcDriver::set_manufacturer()     - Set the manufacturer name.
28//   ppdcDriver::set_model_name()       - Set the model name.
29//   ppdcDriver::set_pc_file_name()     - Set the PC filename.
30//   ppdcDriver::set_version()          - Set the version string.
31//   ppdcDriver::write_ppd_file()       - Write a PPD file...
32//
33
34//
35// Include necessary headers...
36//
37
38#include "ppdc-private.h"
39
40
41//
42// 'ppdcDriver::ppdcDriver()' - Create a new printer driver.
43//
44
45ppdcDriver::ppdcDriver(ppdcDriver *d)	// I - Printer driver template
46  : ppdcShared()
47{
48  ppdcGroup	*g;			// Current group
49
50
51  PPDC_NEW;
52
53  if (d)
54  {
55    // Bump the use count of any strings we inherit...
56    if (d->manufacturer)
57      d->manufacturer->retain();
58    if (d->version)
59      d->version->retain();
60    if (d->default_font)
61      d->default_font->retain();
62    if (d->default_size)
63      d->default_size->retain();
64    if (d->custom_size_code)
65      d->custom_size_code->retain();
66
67    // Copy all of the data from the driver template...
68    copyright           = new ppdcArray(d->copyright);
69    manufacturer        = d->manufacturer;
70    model_name          = 0;
71    file_name           = 0;
72    pc_file_name        = 0;
73    type                = d->type;
74    version             = d->version;
75    model_number        = d->model_number;
76    manual_copies       = d->manual_copies;
77    color_device        = d->color_device;
78    throughput          = d->throughput;
79    attrs               = new ppdcArray(d->attrs);
80    constraints         = new ppdcArray(d->constraints);
81    filters             = new ppdcArray(d->filters);
82    fonts               = new ppdcArray(d->fonts);
83    profiles            = new ppdcArray(d->profiles);
84    sizes               = new ppdcArray(d->sizes);
85    default_font        = d->default_font;
86    default_size        = d->default_size;
87    variable_paper_size = d->variable_paper_size;
88    custom_size_code    = d->custom_size_code;
89    left_margin         = d->left_margin;
90    bottom_margin       = d->bottom_margin;
91    right_margin        = d->right_margin;
92    top_margin          = d->top_margin;
93    max_width           = d->max_width;
94    max_length          = d->max_length;
95    min_width           = d->min_width;
96    min_length          = d->min_length;
97
98    // Then copy the groups manually, since we want separate copies
99    // of the groups and options...
100    groups = new ppdcArray();
101
102    for (g = (ppdcGroup *)d->groups->first(); g; g = (ppdcGroup *)d->groups->next())
103      groups->add(new ppdcGroup(g));
104  }
105  else
106  {
107    // Zero all of the data in the driver...
108    copyright           = new ppdcArray();
109    manufacturer        = 0;
110    model_name          = 0;
111    file_name           = 0;
112    pc_file_name        = 0;
113    version             = 0;
114    type                = PPDC_DRIVER_CUSTOM;
115    model_number        = 0;
116    manual_copies       = 0;
117    color_device        = 0;
118    throughput          = 1;
119    attrs               = new ppdcArray();
120    constraints         = new ppdcArray();
121    fonts               = new ppdcArray();
122    filters             = new ppdcArray();
123    groups              = new ppdcArray();
124    profiles            = new ppdcArray();
125    sizes               = new ppdcArray();
126    default_font        = 0;
127    default_size        = 0;
128    variable_paper_size = 0;
129    custom_size_code    = 0;
130    left_margin         = 0;
131    bottom_margin       = 0;
132    right_margin        = 0;
133    top_margin          = 0;
134    max_width           = 0;
135    max_length          = 0;
136    min_width           = 0;
137    min_length          = 0;
138  }
139}
140
141
142//
143// 'ppdcDriver::~ppdcDriver()' - Destroy a printer driver.
144//
145
146ppdcDriver::~ppdcDriver()
147{
148  PPDC_DELETE;
149
150  copyright->release();
151
152  if (manufacturer)
153    manufacturer->release();
154  if (model_name)
155    model_name->release();
156  if (file_name)
157    file_name->release();
158  if (pc_file_name)
159    pc_file_name->release();
160  if (version)
161    version->release();
162  if (default_font)
163    default_font->release();
164  if (default_size)
165    default_size->release();
166  if (custom_size_code)
167    custom_size_code->release();
168
169  attrs->release();
170  constraints->release();
171  filters->release();
172  fonts->release();
173  groups->release();
174  profiles->release();
175  sizes->release();
176}
177
178
179//
180// 'ppdcDriver::find_attr()' - Find an attribute.
181//
182
183ppdcAttr *				// O - Attribute or NULL
184ppdcDriver::find_attr(const char *k,	// I - Keyword string
185                      const char *s)	// I - Spec string
186{
187  ppdcAttr	*a;			// Current attribute
188
189
190  for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
191    if (!strcmp(a->name->value, k) &&
192        ((!s && (!a->selector->value || !a->selector->value[0])) ||
193	 (s && a->selector->value && !strcmp(a->selector->value, s))))
194      return (a);
195
196  return (NULL);
197}
198
199
200//
201// 'ppdcDriver::find_group()' - Find a group.
202//
203
204ppdcGroup *				// O - Matching group or NULL
205ppdcDriver::find_group(const char *n)	// I - Group name
206{
207  ppdcGroup	*g;			// Current group
208
209
210  for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
211    if (!_cups_strcasecmp(n, g->name->value))
212      return (g);
213
214  return (0);
215}
216
217
218//
219// 'ppdcDriver::find_option()' - Find an option.
220//
221
222ppdcOption *				// O - Matching option or NULL
223ppdcDriver::find_option(const char *n)	// I - Option name
224{
225  return (find_option_group(n, (ppdcGroup **)0));
226}
227
228
229//
230// 'ppdcDriver::find_option_group()' - Find an option and its group.
231//
232
233ppdcOption *				// O - Matching option or NULL
234ppdcDriver::find_option_group(
235    const char *n,			// I - Option name
236    ppdcGroup  **mg)			// O - Matching group or NULL
237{
238  ppdcGroup	*g;			// Current group
239  ppdcOption	*o;			// Current option
240
241
242  for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
243    for (o = (ppdcOption *)g->options->first(); o; o = (ppdcOption *)g->options->next())
244      if (!_cups_strcasecmp(n, o->name->value))
245      {
246        if (mg)
247	  *mg = g;
248
249        return (o);
250      }
251
252  if (mg)
253    *mg = (ppdcGroup *)0;
254
255  return (0);
256}
257
258
259//
260// 'ppdcDriver::set_custom_size_code()' - Set the custom page size code.
261//
262
263void
264ppdcDriver::set_custom_size_code(
265    const char *c)			// I - CustomPageSize code
266{
267  if (custom_size_code)
268    custom_size_code->release();
269
270  custom_size_code = new ppdcString(c);
271}
272
273
274//
275// 'ppdcDriver::set_default_font()' - Set the default font name.
276//
277
278void
279ppdcDriver::set_default_font(
280    ppdcFont *f)			// I - Font
281{
282  if (default_font)
283    default_font->release();
284
285  if (f)
286  {
287    f->name->retain();
288    default_font = f->name;
289  }
290  else
291    default_font = 0;
292}
293
294
295//
296// 'ppdcDriver::set_default_size()' - Set the default size name.
297//
298
299void
300ppdcDriver::set_default_size(
301    ppdcMediaSize *m)			// I - Media size
302{
303  if (default_size)
304    default_size->release();
305
306  if (m)
307  {
308    m->name->retain();
309    default_size = m->name;
310  }
311  else
312    default_size = 0;
313}
314
315
316//
317// 'ppdcDriver::set_file_name()' - Set the full filename.
318//
319
320void
321ppdcDriver::set_file_name(const char *f)// I - Filename
322{
323  if (file_name)
324    file_name->release();
325
326  file_name = new ppdcString(f);
327}
328
329
330//
331// 'ppdcDriver::set_manufacturer()' - Set the manufacturer name.
332//
333
334void
335ppdcDriver::set_manufacturer(
336    const char *m)			// I - Model name
337{
338  if (manufacturer)
339    manufacturer->release();
340
341  manufacturer = new ppdcString(m);
342}
343
344
345//
346// 'ppdcDriver::set_model_name()' - Set the model name.
347//
348
349void
350ppdcDriver::set_model_name(
351    const char *m)			// I - Model name
352{
353  if (model_name)
354    model_name->release();
355
356  model_name = new ppdcString(m);
357}
358
359
360//
361// 'ppdcDriver::set_pc_file_name()' - Set the PC filename.
362//
363
364void
365ppdcDriver::set_pc_file_name(
366    const char *f)			// I - Filename
367{
368  if (pc_file_name)
369    pc_file_name->release();
370
371  pc_file_name = new ppdcString(f);
372}
373
374
375//
376// 'ppdcDriver::set_version()' - Set the version string.
377//
378
379void
380ppdcDriver::set_version(const char *v)	// I - Version
381{
382  if (version)
383    version->release();
384
385  version = new ppdcString(v);
386}
387
388
389//
390// 'ppdcDriver::write_ppd_file()' - Write a PPD file...
391//
392
393int					// O - 0 on success, -1 on failure
394ppdcDriver::write_ppd_file(
395    cups_file_t    *fp,			// I - PPD file
396    ppdcCatalog    *catalog,		// I - Message catalog
397    ppdcArray      *locales,		// I - Additional languages to add
398    ppdcSource     *src,		// I - Driver source
399    ppdcLineEnding le)			// I - Line endings to use
400{
401  bool			delete_cat;	// Delete the catalog when we are done?
402  char			query[42],	// Query attribute
403			custom[42];	// Custom attribute
404  ppdcString		*s;		// Copyright string
405  ppdcGroup		*g;		// Current group
406  ppdcOption		*o;		// Current option
407  ppdcChoice		*c;		// Current choice
408  ppdcMediaSize		*m;		// Current media size
409  ppdcProfile		*p;		// Current color profile
410  ppdcFilter		*f;		// Current filter
411  ppdcFont		*fn,		// Current font
412			*bfn;		// Current base font
413  ppdcConstraint	*cn;		// Current constraint
414  ppdcAttr		*a;		// Current attribute
415  const char		*lf;		// Linefeed character to use
416
417
418  // If we don't have a message catalog, use an empty (English) one...
419  if (!catalog)
420  {
421    catalog    = new ppdcCatalog("en");
422    delete_cat = true;
423  }
424  else
425    delete_cat = false;
426
427  // Figure out the end-of-line string...
428  if (le == PPDC_LFONLY)
429    lf = "\n";
430  else if (le == PPDC_CRONLY)
431    lf = "\r";
432  else
433    lf = "\r\n";
434
435  // Write the standard header stuff...
436  cupsFilePrintf(fp, "*PPD-Adobe: \"4.3\"%s", lf);
437  cupsFilePrintf(fp, "*%%%%%%%% PPD file for %s with CUPS.%s",
438                 model_name->value, lf);
439  cupsFilePrintf(fp,
440                 "*%%%%%%%% Created by the CUPS PPD Compiler " CUPS_SVERSION
441		 ".%s", lf);
442  for (s = (ppdcString *)copyright->first();
443       s;
444       s = (ppdcString *)copyright->next())
445    cupsFilePrintf(fp, "*%% %s%s", catalog->find_message(s->value), lf);
446  cupsFilePrintf(fp, "*FormatVersion: \"4.3\"%s", lf);
447  cupsFilePrintf(fp, "*FileVersion: \"%s\"%s", version->value, lf);
448
449  a = find_attr("LanguageVersion", NULL);
450  cupsFilePrintf(fp, "*LanguageVersion: %s%s",
451        	 catalog->find_message(a ? a->value->value : "English"), lf);
452
453  a = find_attr("LanguageEncoding", NULL);
454  cupsFilePrintf(fp, "*LanguageEncoding: %s%s",
455        	 catalog->find_message(a ? a->value->value : "ISOLatin1"), lf);
456
457  cupsFilePrintf(fp, "*PCFileName: \"%s\"%s", pc_file_name->value, lf);
458
459  for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
460    if (!strcmp(a->name->value, "Product"))
461      break;
462
463  if (a)
464  {
465    for (; a; a = (ppdcAttr *)attrs->next())
466      if (!strcmp(a->name->value, "Product"))
467	cupsFilePrintf(fp, "*Product: \"%s\"%s", a->value->value, lf);
468  }
469  else
470    cupsFilePrintf(fp, "*Product: \"(%s)\"%s", model_name->value, lf);
471
472  cupsFilePrintf(fp, "*Manufacturer: \"%s\"%s",
473        	 catalog->find_message(manufacturer->value), lf);
474
475  if ((a = find_attr("ModelName", NULL)) != NULL)
476    cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
477        	   catalog->find_message(a->value->value), lf);
478  else if (_cups_strncasecmp(model_name->value, manufacturer->value,
479                       strlen(manufacturer->value)))
480    cupsFilePrintf(fp, "*ModelName: \"%s %s\"%s",
481        	   catalog->find_message(manufacturer->value),
482        	   catalog->find_message(model_name->value), lf);
483  else
484    cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
485        	   catalog->find_message(model_name->value), lf);
486
487  if ((a = find_attr("ShortNickName", NULL)) != NULL)
488    cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
489        	   catalog->find_message(a->value->value), lf);
490  else if (_cups_strncasecmp(model_name->value, manufacturer->value,
491                       strlen(manufacturer->value)))
492    cupsFilePrintf(fp, "*ShortNickName: \"%s %s\"%s",
493        	   catalog->find_message(manufacturer->value),
494        	   catalog->find_message(model_name->value), lf);
495  else
496    cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
497        	   catalog->find_message(model_name->value), lf);
498
499  if ((a = find_attr("NickName", NULL)) != NULL)
500    cupsFilePrintf(fp, "*NickName: \"%s\"%s",
501        	   catalog->find_message(a->value->value), lf);
502  else if (_cups_strncasecmp(model_name->value, manufacturer->value,
503                       strlen(manufacturer->value)))
504    cupsFilePrintf(fp, "*NickName: \"%s %s, %s\"%s",
505        	   catalog->find_message(manufacturer->value),
506        	   catalog->find_message(model_name->value), version->value,
507		   lf);
508  else
509    cupsFilePrintf(fp, "*NickName: \"%s, %s\"%s",
510        	   catalog->find_message(model_name->value), version->value,
511		   lf);
512
513  for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
514    if (!strcmp(a->name->value, "PSVersion"))
515      break;
516
517  if (a)
518  {
519    for (; a; a = (ppdcAttr *)attrs->next())
520      if (!strcmp(a->name->value, "PSVersion"))
521	cupsFilePrintf(fp, "*PSVersion: \"%s\"%s", a->value->value, lf);
522  }
523  else
524    cupsFilePrintf(fp, "*PSVersion: \"(3010.000) 0\"%s", lf);
525
526  if ((a = find_attr("LanguageLevel", NULL)) != NULL)
527    cupsFilePrintf(fp, "*LanguageLevel: \"%s\"%s", a->value->value, lf);
528  else
529    cupsFilePrintf(fp, "*LanguageLevel: \"3\"%s", lf);
530
531  cupsFilePrintf(fp, "*ColorDevice: %s%s", color_device ? "True" : "False", lf);
532
533  if ((a = find_attr("DefaultColorSpace", NULL)) != NULL)
534    cupsFilePrintf(fp, "*DefaultColorSpace: %s%s", a->value->value, lf);
535  else
536    cupsFilePrintf(fp, "*DefaultColorSpace: %s%s",
537                   color_device ? "RGB" : "Gray", lf);
538
539  if ((a = find_attr("FileSystem", NULL)) != NULL)
540    cupsFilePrintf(fp, "*FileSystem: %s%s", a->value->value, lf);
541  else
542    cupsFilePrintf(fp, "*FileSystem: False%s", lf);
543
544  cupsFilePrintf(fp, "*Throughput: \"%d\"%s", throughput, lf);
545
546  if ((a = find_attr("LandscapeOrientation", NULL)) != NULL)
547    cupsFilePrintf(fp, "*LandscapeOrientation: %s%s", a->value->value, lf);
548  else
549    cupsFilePrintf(fp, "*LandscapeOrientation: Plus90%s", lf);
550
551  if ((a = find_attr("TTRasterizer", NULL)) != NULL)
552    cupsFilePrintf(fp, "*TTRasterizer: %s%s", a->value->value, lf);
553  else if (type != PPDC_DRIVER_PS)
554    cupsFilePrintf(fp, "*TTRasterizer: Type42%s", lf);
555
556  struct lconv *loc = localeconv();
557
558  if (attrs->count)
559  {
560    // Write driver-defined attributes...
561    cupsFilePrintf(fp, "*%% Driver-defined attributes...%s", lf);
562    for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
563    {
564      if (!strcmp(a->name->value, "Product") ||
565          !strcmp(a->name->value, "PSVersion") ||
566          !strcmp(a->name->value, "LanguageLevel") ||
567          !strcmp(a->name->value, "DefaultColorSpace") ||
568          !strcmp(a->name->value, "FileSystem") ||
569          !strcmp(a->name->value, "LandscapeOrientation") ||
570          !strcmp(a->name->value, "TTRasterizer") ||
571          !strcmp(a->name->value, "LanguageVersion") ||
572          !strcmp(a->name->value, "LanguageEncoding") ||
573          !strcmp(a->name->value, "ModelName") ||
574          !strcmp(a->name->value, "NickName") ||
575          !strcmp(a->name->value, "ShortNickName") ||
576	  !strcmp(a->name->value, "cupsVersion"))
577	continue;
578
579      if (a->name->value[0] == '?' &&
580          (find_option(a->name->value + 1) ||
581	   !strcmp(a->name->value, "?ImageableArea") ||
582	   !strcmp(a->name->value, "?PageRegion") ||
583	   !strcmp(a->name->value, "?PageSize") ||
584	   !strcmp(a->name->value, "?PaperDimension")))
585        continue;
586
587      if (!strncmp(a->name->value, "Custom", 6) &&
588          find_option(a->name->value + 6))
589	continue;
590
591      if (!strncmp(a->name->value, "ParamCustom", 11) &&
592          find_option(a->name->value + 11))
593	continue;
594
595      if (!a->selector->value || !a->selector->value[0])
596	cupsFilePrintf(fp, "*%s", a->name->value);
597      else if (!a->text->value || !a->text->value[0])
598	cupsFilePrintf(fp, "*%s %s", a->name->value, a->selector->value);
599      else
600	cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
601        	       a->text->value);
602
603      if (strcmp(a->value->value, "False") &&
604          strcmp(a->value->value, "True") &&
605	  strcmp(a->name->value, "1284Modes") &&
606	  strcmp(a->name->value, "InkName") &&
607	  strcmp(a->name->value, "PageStackOrder") &&
608	  strncmp(a->name->value, "ParamCustom", 11) &&
609	  strcmp(a->name->value, "Protocols") &&
610	  strcmp(a->name->value, "ReferencePunch") &&
611	  strncmp(a->name->value, "Default", 7))
612      {
613	cupsFilePrintf(fp, ": \"%s\"%s", a->value->value, lf);
614
615	if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
616          cupsFilePrintf(fp, "*End%s", lf);
617      }
618      else
619	cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
620    }
621  }
622
623  if (type != PPDC_DRIVER_PS || filters->count)
624  {
625    if ((a = find_attr("cupsVersion", NULL)) != NULL)
626      cupsFilePrintf(fp, "*cupsVersion: %s%s", a->value->value, lf);
627    else
628      cupsFilePrintf(fp, "*cupsVersion: %d.%d%s", CUPS_VERSION_MAJOR,
629		     CUPS_VERSION_MINOR, lf);
630    cupsFilePrintf(fp, "*cupsModelNumber: %d%s", model_number, lf);
631    cupsFilePrintf(fp, "*cupsManualCopies: %s%s",
632                   manual_copies ? "True" : "False", lf);
633
634    if (filters->count)
635    {
636      for (f = (ppdcFilter *)filters->first();
637           f;
638	   f = (ppdcFilter *)filters->next())
639	cupsFilePrintf(fp, "*cupsFilter: \"%s %d %s\"%s", f->mime_type->value,
640	               f->cost, f->program->value, lf);
641    }
642    else
643    {
644      switch (type)
645      {
646        case PPDC_DRIVER_LABEL :
647	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
648	        	     "rastertolabel\"%s", lf);
649	    break;
650
651        case PPDC_DRIVER_EPSON :
652	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
653	        	     "rastertoepson\"%s", lf);
654	    break;
655
656        case PPDC_DRIVER_ESCP :
657	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
658	        	     "commandtoescpx\"%s", lf);
659	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
660	        	     "rastertoescpx\"%s", lf);
661	    break;
662
663        case PPDC_DRIVER_HP :
664	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
665	        	     "rastertohp\"%s", lf);
666	    break;
667
668        case PPDC_DRIVER_PCL :
669	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
670	        	     "commandtopclx\"%s", lf);
671	    cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
672	        	     "rastertopclx\"%s", lf);
673	    break;
674
675	default :
676	    break;
677      }
678    }
679
680    for (p = (ppdcProfile *)profiles->first();
681         p;
682	 p = (ppdcProfile *)profiles->next())
683    {
684      char density[255], gamma[255], profile[9][255];
685
686      _cupsStrFormatd(density, density + sizeof(density), p->density, loc);
687      _cupsStrFormatd(gamma, gamma + sizeof(gamma), p->gamma, loc);
688
689      for (int i = 0; i < 9; i ++)
690	_cupsStrFormatd(profile[i], profile[i] + sizeof(profile[0]),
691	                p->profile[i], loc);
692
693      cupsFilePrintf(fp,
694                     "*cupsColorProfile %s/%s: \"%s %s %s %s %s %s %s %s %s %s "
695		     "%s\"%s", p->resolution->value, p->media_type->value,
696		     density, gamma, profile[0], profile[1], profile[2],
697		     profile[3], profile[4], profile[5], profile[6], profile[7],
698		     profile[8], lf);
699    }
700  }
701
702  if (locales)
703  {
704    // Add localizations for additional languages...
705    ppdcString	*locale;		// Locale name
706    ppdcCatalog	*locatalog;		// Message catalog for locale
707
708
709    // Write the list of languages...
710    cupsFilePrintf(fp, "*cupsLanguages: \"en");
711
712    for (locale = (ppdcString *)locales->first();
713         locale;
714	 locale = (ppdcString *)locales->next())
715    {
716      // Skip (US) English...
717      if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
718        continue;
719
720      // See if we have a po file for this language...
721      if (!src->find_po(locale->value))
722      {
723        // No, see if we can use the base file?
724        locatalog = new ppdcCatalog(locale->value);
725
726	if (locatalog->messages->count == 0)
727	{
728	  // No, skip this one...
729          _cupsLangPrintf(stderr,
730	                  _("ppdc: No message catalog provided for locale "
731			    "%s."), locale->value);
732          continue;
733	}
734
735        // Add the base file to the list...
736	src->po_files->add(locatalog);
737      }
738
739      cupsFilePrintf(fp, " %s", locale->value);
740    }
741
742    cupsFilePrintf(fp, "\"%s", lf);
743  }
744
745  for (cn = (ppdcConstraint *)constraints->first();
746       cn;
747       cn = (ppdcConstraint *)constraints->next())
748  {
749    // First constrain 1 against 2...
750    if (!strncmp(cn->option1->value, "*Custom", 7) ||
751        !strncmp(cn->option2->value, "*Custom", 7))
752      cupsFilePuts(fp, "*NonUIConstraints: ");
753    else
754      cupsFilePuts(fp, "*UIConstraints: ");
755
756    if (cn->option1->value[0] != '*')
757      cupsFilePutChar(fp, '*');
758
759    cupsFilePuts(fp, cn->option1->value);
760
761    if (cn->choice1->value)
762      cupsFilePrintf(fp, " %s", cn->choice1->value);
763
764    cupsFilePutChar(fp, ' ');
765
766    if (cn->option2->value[0] != '*')
767      cupsFilePutChar(fp, '*');
768
769    cupsFilePuts(fp, cn->option2->value);
770
771    if (cn->choice2->value)
772      cupsFilePrintf(fp, " %s", cn->choice2->value);
773
774    cupsFilePuts(fp, lf);
775
776    // Then constrain 2 against 1...
777    if (!strncmp(cn->option1->value, "*Custom", 7) ||
778        !strncmp(cn->option2->value, "*Custom", 7))
779      cupsFilePuts(fp, "*NonUIConstraints: ");
780    else
781      cupsFilePuts(fp, "*UIConstraints: ");
782
783    if (cn->option2->value[0] != '*')
784      cupsFilePutChar(fp, '*');
785
786    cupsFilePuts(fp, cn->option2->value);
787
788    if (cn->choice2->value)
789      cupsFilePrintf(fp, " %s", cn->choice2->value);
790
791    cupsFilePutChar(fp, ' ');
792
793    if (cn->option1->value[0] != '*')
794      cupsFilePutChar(fp, '*');
795
796    cupsFilePuts(fp, cn->option1->value);
797
798    if (cn->choice1->value)
799      cupsFilePrintf(fp, " %s", cn->choice1->value);
800
801    cupsFilePuts(fp, lf);
802  }
803
804  // PageSize option...
805  cupsFilePrintf(fp, "*OpenUI *PageSize/Media Size: PickOne%s", lf);
806  cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageSize%s", lf);
807  cupsFilePrintf(fp, "*DefaultPageSize: %s%s",
808                 default_size ? default_size->value : "Letter", lf);
809
810  for (m = (ppdcMediaSize *)sizes->first();
811       m;
812       m = (ppdcMediaSize *)sizes->next())
813    if (m->size_code->value)
814    {
815      cupsFilePrintf(fp, "*PageSize %s/%s: \"%s\"%s",
816        	     m->name->value, catalog->find_message(m->text->value),
817		     m->size_code->value, lf);
818
819      if (strchr(m->size_code->value, '\n') ||
820          strchr(m->size_code->value, '\r'))
821        cupsFilePrintf(fp, "*End%s", lf);
822    }
823    else
824      cupsFilePrintf(fp,
825                     "*PageSize %s/%s: \"<</PageSize[%.0f %.0f]"
826		     "/ImagingBBox null>>setpagedevice\"%s",
827        	     m->name->value, catalog->find_message(m->text->value),
828		     m->width, m->length, lf);
829
830  if ((a = find_attr("?PageSize", NULL)) != NULL)
831  {
832    cupsFilePrintf(fp, "*?PageSize: \"%s\"%s", a->value->value, lf);
833
834    if (strchr(a->value->value, '\n') ||
835        strchr(a->value->value, '\r'))
836      cupsFilePrintf(fp, "*End%s", lf);
837  }
838
839  cupsFilePrintf(fp, "*CloseUI: *PageSize%s", lf);
840
841  // PageRegion option...
842  cupsFilePrintf(fp, "*OpenUI *PageRegion/Media Size: PickOne%s", lf);
843  cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageRegion%s", lf);
844  cupsFilePrintf(fp, "*DefaultPageRegion: %s%s",
845                 default_size ? default_size->value : "Letter", lf);
846
847  for (m = (ppdcMediaSize *)sizes->first();
848       m;
849       m = (ppdcMediaSize *)sizes->next())
850    if (m->region_code->value)
851    {
852      cupsFilePrintf(fp, "*PageRegion %s/%s: \"%s\"%s",
853        	     m->name->value, catalog->find_message(m->text->value),
854		     m->region_code->value, lf);
855
856      if (strchr(m->region_code->value, '\n') ||
857          strchr(m->region_code->value, '\r'))
858        cupsFilePrintf(fp, "*End%s", lf);
859    }
860    else
861      cupsFilePrintf(fp,
862                     "*PageRegion %s/%s: \"<</PageSize[%.0f %.0f]"
863		     "/ImagingBBox null>>setpagedevice\"%s",
864        	     m->name->value, catalog->find_message(m->text->value),
865		     m->width, m->length, lf);
866
867  if ((a = find_attr("?PageRegion", NULL)) != NULL)
868  {
869    cupsFilePrintf(fp, "*?PageRegion: \"%s\"%s", a->value->value, lf);
870
871    if (strchr(a->value->value, '\n') ||
872        strchr(a->value->value, '\r'))
873      cupsFilePrintf(fp, "*End%s", lf);
874  }
875
876  cupsFilePrintf(fp, "*CloseUI: *PageRegion%s", lf);
877
878  // ImageableArea info...
879  cupsFilePrintf(fp, "*DefaultImageableArea: %s%s",
880                 default_size ? default_size->value : "Letter", lf);
881
882  char left[255], right[255], bottom[255], top[255];
883
884  for (m = (ppdcMediaSize *)sizes->first();
885       m;
886       m = (ppdcMediaSize *)sizes->next())
887  {
888    _cupsStrFormatd(left, left + sizeof(left), m->left, loc);
889    _cupsStrFormatd(bottom, bottom + sizeof(bottom), m->bottom, loc);
890    _cupsStrFormatd(right, right + sizeof(right), m->width - m->right, loc);
891    _cupsStrFormatd(top, top + sizeof(top), m->length - m->top, loc);
892
893    cupsFilePrintf(fp, "*ImageableArea %s/%s: \"%s %s %s %s\"%s",
894                   m->name->value, catalog->find_message(m->text->value),
895		   left, bottom, right, top, lf);
896  }
897
898  if ((a = find_attr("?ImageableArea", NULL)) != NULL)
899  {
900    cupsFilePrintf(fp, "*?ImageableArea: \"%s\"%s", a->value->value, lf);
901
902    if (strchr(a->value->value, '\n') ||
903        strchr(a->value->value, '\r'))
904      cupsFilePrintf(fp, "*End%s", lf);
905  }
906
907  // PaperDimension info...
908  cupsFilePrintf(fp, "*DefaultPaperDimension: %s%s",
909                 default_size ? default_size->value : "Letter", lf);
910
911  char width[255], length[255];
912
913  for (m = (ppdcMediaSize *)sizes->first();
914       m;
915       m = (ppdcMediaSize *)sizes->next())
916  {
917    _cupsStrFormatd(width, width + sizeof(width), m->width, loc);
918    _cupsStrFormatd(length, length + sizeof(length), m->length, loc);
919
920    cupsFilePrintf(fp, "*PaperDimension %s/%s: \"%s %s\"%s",
921                   m->name->value, catalog->find_message(m->text->value),
922		   width, length, lf);
923  }
924
925  if ((a = find_attr("?PaperDimension", NULL)) != NULL)
926  {
927    cupsFilePrintf(fp, "*?PaperDimension: \"%s\"%s", a->value->value, lf);
928
929    if (strchr(a->value->value, '\n') ||
930        strchr(a->value->value, '\r'))
931      cupsFilePrintf(fp, "*End%s", lf);
932  }
933
934  // Custom size support...
935  if (variable_paper_size)
936  {
937    _cupsStrFormatd(width, width + sizeof(width), max_width, loc);
938    _cupsStrFormatd(length, length + sizeof(length), max_length, loc);
939
940    _cupsStrFormatd(left, left + sizeof(left), left_margin, loc);
941    _cupsStrFormatd(bottom, bottom + sizeof(bottom), bottom_margin, loc);
942    _cupsStrFormatd(right, right + sizeof(right), right_margin, loc);
943    _cupsStrFormatd(top, top + sizeof(top), top_margin, loc);
944
945    cupsFilePrintf(fp, "*MaxMediaWidth: \"%s\"%s", width, lf);
946    cupsFilePrintf(fp, "*MaxMediaHeight: \"%s\"%s", length, lf);
947    cupsFilePrintf(fp, "*HWMargins: %s %s %s %s%s", left, bottom, right, top,
948                   lf);
949
950    if (custom_size_code && custom_size_code->value)
951    {
952      cupsFilePrintf(fp, "*CustomPageSize True: \"%s\"%s",
953                     custom_size_code->value, lf);
954
955      if (strchr(custom_size_code->value, '\n') ||
956          strchr(custom_size_code->value, '\r'))
957        cupsFilePrintf(fp, "*End%s", lf);
958    }
959    else
960      cupsFilePrintf(fp,
961		     "*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]"
962		     "/ImagingBBox null>>setpagedevice\"%s", lf);
963
964    if ((a = find_attr("ParamCustomPageSize", "Width")) != NULL)
965      cupsFilePrintf(fp, "*ParamCustomPageSize Width: %s%s", a->value->value,
966		     lf);
967    else
968    {
969      char width0[255];
970
971      _cupsStrFormatd(width0, width0 + sizeof(width0), min_width, loc);
972      _cupsStrFormatd(width, width + sizeof(width), max_width, loc);
973
974      cupsFilePrintf(fp, "*ParamCustomPageSize Width: 1 points %s %s%s",
975                     width0, width, lf);
976    }
977
978    if ((a = find_attr("ParamCustomPageSize", "Height")) != NULL)
979      cupsFilePrintf(fp, "*ParamCustomPageSize Height: %s%s", a->value->value,
980		     lf);
981    else
982    {
983      char length0[255];
984
985      _cupsStrFormatd(length0, length0 + sizeof(length0), min_length, loc);
986      _cupsStrFormatd(length, length + sizeof(length), max_length, loc);
987
988      cupsFilePrintf(fp, "*ParamCustomPageSize Height: 2 points %s %s%s",
989                     length0, length, lf);
990    }
991
992    if ((a = find_attr("ParamCustomPageSize", "WidthOffset")) != NULL)
993      cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: %s%s",
994                     a->value->value, lf);
995    else
996      cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0%s", lf);
997
998    if ((a = find_attr("ParamCustomPageSize", "HeightOffset")) != NULL)
999      cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: %s%s",
1000                     a->value->value, lf);
1001    else
1002      cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0%s", lf);
1003
1004    if ((a = find_attr("ParamCustomPageSize", "Orientation")) != NULL)
1005      cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: %s%s",
1006                     a->value->value, lf);
1007    else
1008      cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: 5 int 0 0%s", lf);
1009  }
1010
1011  // All other options...
1012  for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
1013  {
1014    if (!g->options->count)
1015      continue;
1016
1017    if (_cups_strcasecmp(g->name->value, "General"))
1018      cupsFilePrintf(fp, "*OpenGroup: %s/%s%s", g->name->value,
1019                     catalog->find_message(g->text->value), lf);
1020
1021    for (o = (ppdcOption *)g->options->first();
1022         o;
1023	 o = (ppdcOption *)g->options->next())
1024    {
1025      if (!o->choices->count)
1026        continue;
1027
1028      if (o->section == PPDC_SECTION_JCL)
1029      {
1030	if (!o->text->value)
1031	  cupsFilePrintf(fp, "*JCLOpenUI *%s/%s: ", o->name->value,
1032			 catalog->find_message(o->name->value));
1033	else
1034	  cupsFilePrintf(fp, "*JCLOpenUI *%s/%s: ", o->name->value,
1035			 catalog->find_message(o->text->value));
1036      }
1037      else if (!o->text->value)
1038	cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
1039	               catalog->find_message(o->name->value));
1040      else
1041	cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
1042	               catalog->find_message(o->text->value));
1043
1044      switch (o->type)
1045      {
1046        case PPDC_BOOLEAN :
1047	    cupsFilePrintf(fp, "Boolean%s", lf);
1048	    break;
1049        default :
1050	    cupsFilePrintf(fp, "PickOne%s", lf);
1051	    break;
1052        case PPDC_PICKMANY :
1053	    cupsFilePrintf(fp, "PickMany%s", lf);
1054	    break;
1055      }
1056
1057      char order[255];
1058      _cupsStrFormatd(order, order + sizeof(order), o->order, loc);
1059
1060      cupsFilePrintf(fp, "*OrderDependency: %s ", order);
1061      switch (o->section)
1062      {
1063        default :
1064	    cupsFilePrintf(fp, "AnySetup");
1065	    break;
1066        case PPDC_SECTION_DOCUMENT :
1067	    cupsFilePrintf(fp, "DocumentSetup");
1068	    break;
1069        case PPDC_SECTION_EXIT :
1070	    cupsFilePrintf(fp, "ExitServer");
1071	    break;
1072        case PPDC_SECTION_JCL :
1073	    cupsFilePrintf(fp, "JCLSetup");
1074	    break;
1075        case PPDC_SECTION_PAGE :
1076	    cupsFilePrintf(fp, "PageSetup");
1077	    break;
1078        case PPDC_SECTION_PROLOG :
1079	    cupsFilePrintf(fp, "Prolog");
1080	    break;
1081      }
1082
1083      cupsFilePrintf(fp, " *%s%s", o->name->value, lf);
1084
1085      if (o->defchoice)
1086      {
1087        // Use the programmer-supplied default...
1088        cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value,
1089	               o->defchoice->value, lf);
1090      }
1091      else
1092      {
1093        // Make the first choice the default...
1094        c = (ppdcChoice *)o->choices->first();
1095        cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value, c->name->value,
1096		       lf);
1097      }
1098
1099      for (c = (ppdcChoice *)o->choices->first();
1100           c;
1101	   c = (ppdcChoice *)o->choices->next())
1102      {
1103        // Write this choice...
1104	if (!c->text->value)
1105          cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
1106                         c->name->value, catalog->find_message(c->name->value),
1107	        	 c->code->value, lf);
1108        else
1109          cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
1110	                 c->name->value, catalog->find_message(c->text->value),
1111			 c->code->value, lf);
1112
1113	// Multi-line commands need a *End line to terminate them.
1114        if (strchr(c->code->value, '\n') ||
1115	    strchr(c->code->value, '\r'))
1116	  cupsFilePrintf(fp, "*End%s", lf);
1117      }
1118
1119      snprintf(query, sizeof(query), "?%s", o->name->value);
1120
1121      if ((a = find_attr(query, NULL)) != NULL)
1122      {
1123	cupsFilePrintf(fp, "*%s: \"%s\"%s", query, a->value->value, lf);
1124
1125	if (strchr(a->value->value, '\n') ||
1126            strchr(a->value->value, '\r'))
1127	  cupsFilePrintf(fp, "*End%s", lf);
1128      }
1129
1130      cupsFilePrintf(fp, "*CloseUI: *%s%s", o->name->value, lf);
1131
1132      snprintf(custom, sizeof(custom), "Custom%s", o->name->value);
1133      if ((a = find_attr(custom, "True")) != NULL)
1134      {
1135        // Output custom option information...
1136        cupsFilePrintf(fp, "*%s True: \"%s\"%s", custom, a->value->value, lf);
1137	if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
1138	  cupsFilePrintf(fp, "*End%s", lf);
1139
1140        snprintf(custom, sizeof(custom), "ParamCustom%s", o->name->value);
1141	for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
1142	{
1143	  if (strcmp(a->name->value, custom))
1144	    continue;
1145
1146	  if (!a->selector->value || !a->selector->value[0])
1147	    cupsFilePrintf(fp, "*%s", a->name->value);
1148	  else if (!a->text->value || !a->text->value[0])
1149	    cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
1150	                   catalog->find_message(a->selector->value));
1151	  else
1152	    cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
1153			   catalog->find_message(a->text->value));
1154
1155          cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
1156	}
1157      }
1158    }
1159
1160    if (_cups_strcasecmp(g->name->value, "General"))
1161      cupsFilePrintf(fp, "*CloseGroup: %s%s", g->name->value, lf);
1162  }
1163
1164  if (locales)
1165  {
1166    // Add localizations for additional languages...
1167    ppdcString	*locale;		// Locale name
1168    ppdcCatalog	*locatalog;		// Message catalog for locale
1169
1170
1171    // Write the translation strings for each language...
1172    for (locale = (ppdcString *)locales->first();
1173         locale;
1174	 locale = (ppdcString *)locales->next())
1175    {
1176      // Skip (US) English...
1177      if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
1178        continue;
1179
1180      // Skip missing languages...
1181      if ((locatalog = src->find_po(locale->value)) == NULL)
1182        continue;
1183
1184      // Do the core stuff first...
1185      cupsFilePrintf(fp, "*%s.Translation Manufacturer/%s: \"\"%s",
1186                     locale->value,
1187        	     locatalog->find_message(manufacturer->value), lf);
1188
1189      if ((a = find_attr("ModelName", NULL)) != NULL)
1190	cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
1191                       locale->value,
1192        	       locatalog->find_message(a->value->value), lf);
1193      else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1194                	   strlen(manufacturer->value)))
1195	cupsFilePrintf(fp, "*%s.Translation ModelName/%s %s: \"\"%s",
1196                       locale->value,
1197        	       locatalog->find_message(manufacturer->value),
1198        	       locatalog->find_message(model_name->value), lf);
1199      else
1200	cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
1201                       locale->value,
1202        	       locatalog->find_message(model_name->value), lf);
1203
1204      if ((a = find_attr("ShortNickName", NULL)) != NULL)
1205	cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
1206                       locale->value,
1207        	       locatalog->find_message(a->value->value), lf);
1208      else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1209                	   strlen(manufacturer->value)))
1210	cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s %s: \"\"%s",
1211                       locale->value,
1212        	       locatalog->find_message(manufacturer->value),
1213        	       locatalog->find_message(model_name->value), lf);
1214      else
1215	cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
1216                       locale->value,
1217        	       locatalog->find_message(model_name->value), lf);
1218
1219      if ((a = find_attr("NickName", NULL)) != NULL)
1220	cupsFilePrintf(fp, "*%s.Translation NickName/%s: \"\"%s",
1221                       locale->value,
1222        	       locatalog->find_message(a->value->value), lf);
1223      else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1224                	   strlen(manufacturer->value)))
1225	cupsFilePrintf(fp, "*%s.Translation NickName/%s %s, %s: \"\"%s",
1226                       locale->value,
1227        	       locatalog->find_message(manufacturer->value),
1228        	       locatalog->find_message(model_name->value),
1229		       version->value, lf);
1230      else
1231	cupsFilePrintf(fp, "*%s.Translation NickName/%s, %s: \"\"%s",
1232                       locale->value,
1233        	       locatalog->find_message(model_name->value),
1234		       version->value, lf);
1235
1236      // Then the page sizes...
1237      cupsFilePrintf(fp, "*%s.Translation PageSize/%s: \"\"%s", locale->value,
1238                     locatalog->find_message("Media Size"), lf);
1239
1240      for (m = (ppdcMediaSize *)sizes->first();
1241	   m;
1242	   m = (ppdcMediaSize *)sizes->next())
1243      {
1244        cupsFilePrintf(fp, "*%s.PageSize %s/%s: \"\"%s", locale->value,
1245        	       m->name->value, locatalog->find_message(m->text->value),
1246		       lf);
1247      }
1248
1249      // Next the groups and options...
1250      for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
1251      {
1252	if (!g->options->count)
1253	  continue;
1254
1255	if (_cups_strcasecmp(g->name->value, "General"))
1256	  cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
1257	                 g->name->value,
1258                	 locatalog->find_message(g->text->value), lf);
1259
1260	for (o = (ppdcOption *)g->options->first();
1261             o;
1262	     o = (ppdcOption *)g->options->next())
1263	{
1264	  if (!o->choices->count)
1265            continue;
1266
1267          cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
1268	                 o->name->value,
1269			 locatalog->find_message(o->text->value ?
1270			                         o->text->value :
1271						 o->name->value), lf);
1272
1273	  for (c = (ppdcChoice *)o->choices->first();
1274               c;
1275	       c = (ppdcChoice *)o->choices->next())
1276	  {
1277            // Write this choice...
1278            cupsFilePrintf(fp, "*%s.%s %s/%s: \"\"%s", locale->value,
1279	                   o->name->value, c->name->value,
1280			   locatalog->find_message(c->text->value ?
1281			                           c->text->value :
1282						   c->name->value), lf);
1283	  }
1284	}
1285      }
1286
1287      // Finally the localizable attributes...
1288      for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
1289      {
1290        if (!a->localizable &&
1291	    (!a->text || !a->text->value || !a->text->value[0]) &&
1292	    strcmp(a->name->value, "APCustomColorMatchingName") &&
1293	    strcmp(a->name->value, "APPrinterPreset") &&
1294	    strcmp(a->name->value, "cupsICCProfile") &&
1295	    strcmp(a->name->value, "cupsIPPReason") &&
1296	    strcmp(a->name->value, "cupsMarkerName") &&
1297	    strncmp(a->name->value, "Custom", 6) &&
1298	    strncmp(a->name->value, "ParamCustom", 11))
1299	  continue;
1300
1301        cupsFilePrintf(fp, "*%s.%s %s/%s: \"%s\"%s", locale->value,
1302	               a->name->value, a->selector->value,
1303		       locatalog->find_message(a->text && a->text->value ?
1304		                               a->text->value : a->name->value),
1305		       ((a->localizable && a->value->value[0]) ||
1306		        !strcmp(a->name->value, "cupsIPPReason")) ?
1307		           locatalog->find_message(a->value->value) : "",
1308		       lf);
1309      }
1310    }
1311  }
1312
1313  if (default_font && default_font->value)
1314    cupsFilePrintf(fp, "*DefaultFont: %s%s", default_font->value, lf);
1315  else
1316    cupsFilePrintf(fp, "*DefaultFont: Courier%s", lf);
1317
1318  for (fn = (ppdcFont *)fonts->first(); fn; fn = (ppdcFont *)fonts->next())
1319    if (!strcmp(fn->name->value, "*"))
1320    {
1321      for (bfn = (ppdcFont *)src->base_fonts->first();
1322	   bfn;
1323	   bfn = (ppdcFont *)src->base_fonts->next())
1324	cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
1325		       bfn->name->value, bfn->encoding->value,
1326		       bfn->version->value, bfn->charset->value,
1327		       bfn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
1328    }
1329    else
1330      cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
1331        	     fn->name->value, fn->encoding->value, fn->version->value,
1332		     fn->charset->value,
1333		     fn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
1334
1335  cupsFilePrintf(fp, "*%% End of %s, %05d bytes.%s", pc_file_name->value,
1336        	 (int)(cupsFileTell(fp) + 25 + strlen(pc_file_name->value)),
1337		 lf);
1338
1339  if (delete_cat)
1340    catalog->release();
1341
1342  return (0);
1343}
1344
1345
1346//
1347// End of "$Id: ppdc-driver.cxx 3942 2012-10-15 21:05:33Z msweet $".
1348//
1349