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