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