Revert manifest to default one
[external/cups.git] / ppdc / ppdc-driver.cxx
1 //
2 // "$Id: ppdc-driver.cxx 9793 2011-05-20 03:49:49Z mike $"
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
45 ppdcDriver::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
146 ppdcDriver::~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
183 ppdcAttr *                              // O - Attribute or NULL
184 ppdcDriver::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
204 ppdcGroup *                             // O - Matching group or NULL
205 ppdcDriver::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
222 ppdcOption *                            // O - Matching option or NULL
223 ppdcDriver::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
233 ppdcOption *                            // O - Matching option or NULL
234 ppdcDriver::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
263 void
264 ppdcDriver::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
278 void
279 ppdcDriver::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
299 void
300 ppdcDriver::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
320 void
321 ppdcDriver::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
334 void
335 ppdcDriver::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
349 void
350 ppdcDriver::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
364 void
365 ppdcDriver::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
379 void
380 ppdcDriver::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
393 int                                     // O - 0 on success, -1 on failure
394 ppdcDriver::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->text->value)
1029         cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
1030                        catalog->find_message(o->name->value));
1031       else
1032         cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
1033                        catalog->find_message(o->text->value));
1034
1035       switch (o->type)
1036       {
1037         case PPDC_BOOLEAN :
1038             cupsFilePrintf(fp, "Boolean%s", lf);
1039             break;
1040         default :
1041             cupsFilePrintf(fp, "PickOne%s", lf);
1042             break;
1043         case PPDC_PICKMANY :
1044             cupsFilePrintf(fp, "PickMany%s", lf);
1045             break;
1046       }
1047
1048       char order[255];
1049       _cupsStrFormatd(order, order + sizeof(order), o->order, loc);
1050
1051       cupsFilePrintf(fp, "*OrderDependency: %s ", order);
1052       switch (o->section)
1053       {
1054         default :
1055             cupsFilePrintf(fp, "AnySetup");
1056             break;
1057         case PPDC_SECTION_DOCUMENT :
1058             cupsFilePrintf(fp, "DocumentSetup");
1059             break;
1060         case PPDC_SECTION_EXIT :
1061             cupsFilePrintf(fp, "ExitServer");
1062             break;
1063         case PPDC_SECTION_JCL :
1064             cupsFilePrintf(fp, "JCLSetup");
1065             break;
1066         case PPDC_SECTION_PAGE :
1067             cupsFilePrintf(fp, "PageSetup");
1068             break;
1069         case PPDC_SECTION_PROLOG :
1070             cupsFilePrintf(fp, "Prolog");
1071             break;
1072       }
1073
1074       cupsFilePrintf(fp, " *%s%s", o->name->value, lf);
1075
1076       if (o->defchoice)
1077       {
1078         // Use the programmer-supplied default...
1079         cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value,
1080                        o->defchoice->value, lf);
1081       }
1082       else
1083       {
1084         // Make the first choice the default...
1085         c = (ppdcChoice *)o->choices->first();
1086         cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value, c->name->value,
1087                        lf);
1088       }
1089
1090       for (c = (ppdcChoice *)o->choices->first();
1091            c;
1092            c = (ppdcChoice *)o->choices->next())
1093       {
1094         // Write this choice...
1095         if (!c->text->value)
1096           cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
1097                          c->name->value, catalog->find_message(c->name->value),
1098                          c->code->value, lf);
1099         else
1100           cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
1101                          c->name->value, catalog->find_message(c->text->value),
1102                          c->code->value, lf);
1103
1104         // Multi-line commands need a *End line to terminate them.
1105         if (strchr(c->code->value, '\n') ||
1106             strchr(c->code->value, '\r'))
1107           cupsFilePrintf(fp, "*End%s", lf);
1108       }
1109
1110       snprintf(query, sizeof(query), "?%s", o->name->value);
1111
1112       if ((a = find_attr(query, NULL)) != NULL)
1113       {
1114         cupsFilePrintf(fp, "*%s: \"%s\"%s", query, a->value->value, lf);
1115
1116         if (strchr(a->value->value, '\n') ||
1117             strchr(a->value->value, '\r'))
1118           cupsFilePrintf(fp, "*End%s", lf);
1119       }
1120
1121       cupsFilePrintf(fp, "*CloseUI: *%s%s", o->name->value, lf);
1122
1123       snprintf(custom, sizeof(custom), "Custom%s", o->name->value);
1124       if ((a = find_attr(custom, "True")) != NULL)
1125       {
1126         // Output custom option information...
1127         cupsFilePrintf(fp, "*%s True: \"%s\"%s", custom, a->value->value, lf);
1128         if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
1129           cupsFilePrintf(fp, "*End%s", lf);
1130
1131         snprintf(custom, sizeof(custom), "ParamCustom%s", o->name->value);
1132         for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
1133         {
1134           if (strcmp(a->name->value, custom))
1135             continue;
1136
1137           if (!a->selector->value || !a->selector->value[0])
1138             cupsFilePrintf(fp, "*%s", a->name->value);
1139           else if (!a->text->value || !a->text->value[0])
1140             cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
1141                            catalog->find_message(a->selector->value));
1142           else
1143             cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
1144                            catalog->find_message(a->text->value));
1145
1146           cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
1147         }
1148       }
1149     }
1150
1151     if (_cups_strcasecmp(g->name->value, "General"))
1152       cupsFilePrintf(fp, "*CloseGroup: %s%s", g->name->value, lf);
1153   }
1154
1155   if (locales)
1156   {
1157     // Add localizations for additional languages...
1158     ppdcString  *locale;                // Locale name
1159     ppdcCatalog *locatalog;             // Message catalog for locale
1160
1161
1162     // Write the translation strings for each language...
1163     for (locale = (ppdcString *)locales->first();
1164          locale;
1165          locale = (ppdcString *)locales->next())
1166     {
1167       // Skip (US) English...
1168       if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
1169         continue;
1170
1171       // Skip missing languages...
1172       if ((locatalog = src->find_po(locale->value)) == NULL)
1173         continue;
1174
1175       // Do the core stuff first...
1176       cupsFilePrintf(fp, "*%s.Translation Manufacturer/%s: \"\"%s",
1177                      locale->value,
1178                      locatalog->find_message(manufacturer->value), lf);
1179
1180       if ((a = find_attr("ModelName", NULL)) != NULL)
1181         cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
1182                        locale->value,
1183                        locatalog->find_message(a->value->value), lf);
1184       else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1185                            strlen(manufacturer->value)))
1186         cupsFilePrintf(fp, "*%s.Translation ModelName/%s %s: \"\"%s",
1187                        locale->value,
1188                        locatalog->find_message(manufacturer->value),
1189                        locatalog->find_message(model_name->value), lf);
1190       else
1191         cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
1192                        locale->value,
1193                        locatalog->find_message(model_name->value), lf);
1194
1195       if ((a = find_attr("ShortNickName", NULL)) != NULL)
1196         cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
1197                        locale->value,
1198                        locatalog->find_message(a->value->value), lf);
1199       else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1200                            strlen(manufacturer->value)))
1201         cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s %s: \"\"%s",
1202                        locale->value,
1203                        locatalog->find_message(manufacturer->value),
1204                        locatalog->find_message(model_name->value), lf);
1205       else
1206         cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
1207                        locale->value,
1208                        locatalog->find_message(model_name->value), lf);
1209
1210       if ((a = find_attr("NickName", NULL)) != NULL)
1211         cupsFilePrintf(fp, "*%s.Translation NickName/%s: \"\"%s",
1212                        locale->value,
1213                        locatalog->find_message(a->value->value), lf);
1214       else if (_cups_strncasecmp(model_name->value, manufacturer->value,
1215                            strlen(manufacturer->value)))
1216         cupsFilePrintf(fp, "*%s.Translation NickName/%s %s, %s: \"\"%s",
1217                        locale->value,
1218                        locatalog->find_message(manufacturer->value),
1219                        locatalog->find_message(model_name->value),
1220                        version->value, lf);
1221       else
1222         cupsFilePrintf(fp, "*%s.Translation NickName/%s, %s: \"\"%s",
1223                        locale->value,
1224                        locatalog->find_message(model_name->value),
1225                        version->value, lf);
1226
1227       // Then the page sizes...
1228       cupsFilePrintf(fp, "*%s.Translation PageSize/%s: \"\"%s", locale->value,
1229                      locatalog->find_message("Media Size"), lf);
1230
1231       for (m = (ppdcMediaSize *)sizes->first();
1232            m;
1233            m = (ppdcMediaSize *)sizes->next())
1234       {
1235         cupsFilePrintf(fp, "*%s.PageSize %s/%s: \"\"%s", locale->value,
1236                        m->name->value, locatalog->find_message(m->text->value),
1237                        lf);
1238       }
1239
1240       // Next the groups and options...
1241       for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
1242       {
1243         if (!g->options->count)
1244           continue;
1245
1246         if (_cups_strcasecmp(g->name->value, "General"))
1247           cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
1248                          g->name->value,
1249                          locatalog->find_message(g->text->value), lf);
1250
1251         for (o = (ppdcOption *)g->options->first();
1252              o;
1253              o = (ppdcOption *)g->options->next())
1254         {
1255           if (!o->choices->count)
1256             continue;
1257
1258           cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
1259                          o->name->value,
1260                          locatalog->find_message(o->text->value ?
1261                                                  o->text->value :
1262                                                  o->name->value), lf);
1263
1264           for (c = (ppdcChoice *)o->choices->first();
1265                c;
1266                c = (ppdcChoice *)o->choices->next())
1267           {
1268             // Write this choice...
1269             cupsFilePrintf(fp, "*%s.%s %s/%s: \"\"%s", locale->value,
1270                            o->name->value, c->name->value,
1271                            locatalog->find_message(c->text->value ?
1272                                                    c->text->value :
1273                                                    c->name->value), lf);
1274           }
1275         }
1276       }
1277
1278       // Finally the localizable attributes...
1279       for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
1280       {
1281         if (!a->localizable &&
1282             (!a->text || !a->text->value || !a->text->value[0]) &&
1283             strcmp(a->name->value, "APCustomColorMatchingName") &&
1284             strcmp(a->name->value, "APPrinterPreset") &&
1285             strcmp(a->name->value, "cupsICCProfile") &&
1286             strcmp(a->name->value, "cupsIPPReason") &&
1287             strcmp(a->name->value, "cupsMarkerName") &&
1288             strncmp(a->name->value, "Custom", 6) &&
1289             strncmp(a->name->value, "ParamCustom", 11))
1290           continue;
1291
1292         cupsFilePrintf(fp, "*%s.%s %s/%s: \"%s\"%s", locale->value,
1293                        a->name->value, a->selector->value,
1294                        locatalog->find_message(a->text && a->text->value ?
1295                                                a->text->value : a->name->value),
1296                        ((a->localizable && a->value->value[0]) ||
1297                         !strcmp(a->name->value, "cupsIPPReason")) ?
1298                            locatalog->find_message(a->value->value) : "",
1299                        lf);
1300       }
1301     }
1302   }
1303
1304   if (default_font && default_font->value)
1305     cupsFilePrintf(fp, "*DefaultFont: %s%s", default_font->value, lf);
1306   else
1307     cupsFilePrintf(fp, "*DefaultFont: Courier%s", lf);
1308
1309   for (fn = (ppdcFont *)fonts->first(); fn; fn = (ppdcFont *)fonts->next())
1310     if (!strcmp(fn->name->value, "*"))
1311     {
1312       for (bfn = (ppdcFont *)src->base_fonts->first();
1313            bfn;
1314            bfn = (ppdcFont *)src->base_fonts->next())
1315         cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
1316                        bfn->name->value, bfn->encoding->value,
1317                        bfn->version->value, bfn->charset->value,
1318                        bfn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
1319     }
1320     else
1321       cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
1322                      fn->name->value, fn->encoding->value, fn->version->value,
1323                      fn->charset->value,
1324                      fn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
1325
1326   cupsFilePrintf(fp, "*%% End of %s, %05d bytes.%s", pc_file_name->value,
1327                  (int)(cupsFileTell(fp) + 25 + strlen(pc_file_name->value)),
1328                  lf);
1329
1330   if (delete_cat)
1331     catalog->release();
1332
1333   return (0);
1334 }
1335
1336
1337 //
1338 // End of "$Id: ppdc-driver.cxx 9793 2011-05-20 03:49:49Z mike $".
1339 //