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