You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1325 lines
40 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

//
// PPD file compiler definitions for the CUPS PPD Compiler.
//
// Copyright © 2007-2019 by Apple Inc.
// Copyright © 2002-2006 by Easy Software Products.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
//
// Include necessary headers...
//
#include "ppdc-private.h"
//
// 'ppdcDriver::ppdcDriver()' - Create a new printer driver.
//
ppdcDriver::ppdcDriver(ppdcDriver *d) // I - Printer driver template
: ppdcShared()
{
ppdcGroup *g; // Current group
PPDC_NEW;
if (d)
{
// Bump the use count of any strings we inherit...
if (d->manufacturer)
d->manufacturer->retain();
if (d->version)
d->version->retain();
if (d->default_font)
d->default_font->retain();
if (d->default_size)
d->default_size->retain();
if (d->custom_size_code)
d->custom_size_code->retain();
// Copy all of the data from the driver template...
copyright = new ppdcArray(d->copyright);
manufacturer = d->manufacturer;
model_name = 0;
file_name = 0;
pc_file_name = 0;
type = d->type;
version = d->version;
model_number = d->model_number;
manual_copies = d->manual_copies;
color_device = d->color_device;
throughput = d->throughput;
attrs = new ppdcArray(d->attrs);
constraints = new ppdcArray(d->constraints);
filters = new ppdcArray(d->filters);
fonts = new ppdcArray(d->fonts);
profiles = new ppdcArray(d->profiles);
sizes = new ppdcArray(d->sizes);
default_font = d->default_font;
default_size = d->default_size;
variable_paper_size = d->variable_paper_size;
custom_size_code = d->custom_size_code;
left_margin = d->left_margin;
bottom_margin = d->bottom_margin;
right_margin = d->right_margin;
top_margin = d->top_margin;
max_width = d->max_width;
max_length = d->max_length;
min_width = d->min_width;
min_length = d->min_length;
// Then copy the groups manually, since we want separate copies
// of the groups and options...
groups = new ppdcArray();
for (g = (ppdcGroup *)d->groups->first(); g; g = (ppdcGroup *)d->groups->next())
groups->add(new ppdcGroup(g));
}
else
{
// Zero all of the data in the driver...
copyright = new ppdcArray();
manufacturer = 0;
model_name = 0;
file_name = 0;
pc_file_name = 0;
version = 0;
type = PPDC_DRIVER_CUSTOM;
model_number = 0;
manual_copies = 0;
color_device = 0;
throughput = 1;
attrs = new ppdcArray();
constraints = new ppdcArray();
fonts = new ppdcArray();
filters = new ppdcArray();
groups = new ppdcArray();
profiles = new ppdcArray();
sizes = new ppdcArray();
default_font = 0;
default_size = 0;
variable_paper_size = 0;
custom_size_code = 0;
left_margin = 0;
bottom_margin = 0;
right_margin = 0;
top_margin = 0;
max_width = 0;
max_length = 0;
min_width = 0;
min_length = 0;
}
}
//
// 'ppdcDriver::~ppdcDriver()' - Destroy a printer driver.
//
ppdcDriver::~ppdcDriver()
{
PPDC_DELETE;
copyright->release();
if (manufacturer)
manufacturer->release();
if (model_name)
model_name->release();
if (file_name)
file_name->release();
if (pc_file_name)
pc_file_name->release();
if (version)
version->release();
if (default_font)
default_font->release();
if (default_size)
default_size->release();
if (custom_size_code)
custom_size_code->release();
attrs->release();
constraints->release();
filters->release();
fonts->release();
groups->release();
profiles->release();
sizes->release();
}
//
// 'ppdcDriver::find_attr()' - Find an attribute.
//
ppdcAttr * // O - Attribute or NULL
ppdcDriver::find_attr(const char *k, // I - Keyword string
const char *s) // I - Spec string
{
ppdcAttr *a; // Current attribute
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
if (!strcmp(a->name->value, k) &&
((!s && (!a->selector->value || !a->selector->value[0])) ||
(s && a->selector->value && !strcmp(a->selector->value, s))))
return (a);
return (NULL);
}
//
// 'ppdcDriver::find_group()' - Find a group.
//
ppdcGroup * // O - Matching group or NULL
ppdcDriver::find_group(const char *n) // I - Group name
{
ppdcGroup *g; // Current group
for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
if (!_cups_strcasecmp(n, g->name->value))
return (g);
return (0);
}
//
// 'ppdcDriver::find_option()' - Find an option.
//
ppdcOption * // O - Matching option or NULL
ppdcDriver::find_option(const char *n) // I - Option name
{
return (find_option_group(n, (ppdcGroup **)0));
}
//
// 'ppdcDriver::find_option_group()' - Find an option and its group.
//
ppdcOption * // O - Matching option or NULL
ppdcDriver::find_option_group(
const char *n, // I - Option name
ppdcGroup **mg) // O - Matching group or NULL
{
ppdcGroup *g; // Current group
ppdcOption *o; // Current option
for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
for (o = (ppdcOption *)g->options->first(); o; o = (ppdcOption *)g->options->next())
if (!_cups_strcasecmp(n, o->name->value))
{
if (mg)
*mg = g;
return (o);
}
if (mg)
*mg = (ppdcGroup *)0;
return (0);
}
//
// 'ppdcDriver::set_custom_size_code()' - Set the custom page size code.
//
void
ppdcDriver::set_custom_size_code(
const char *c) // I - CustomPageSize code
{
if (custom_size_code)
custom_size_code->release();
custom_size_code = new ppdcString(c);
}
//
// 'ppdcDriver::set_default_font()' - Set the default font name.
//
void
ppdcDriver::set_default_font(
ppdcFont *f) // I - Font
{
if (default_font)
default_font->release();
if (f)
{
f->name->retain();
default_font = f->name;
}
else
default_font = 0;
}
//
// 'ppdcDriver::set_default_size()' - Set the default size name.
//
void
ppdcDriver::set_default_size(
ppdcMediaSize *m) // I - Media size
{
if (default_size)
default_size->release();
if (m)
{
m->name->retain();
default_size = m->name;
}
else
default_size = 0;
}
//
// 'ppdcDriver::set_file_name()' - Set the full filename.
//
void
ppdcDriver::set_file_name(const char *f)// I - Filename
{
if (file_name)
file_name->release();
file_name = new ppdcString(f);
}
//
// 'ppdcDriver::set_manufacturer()' - Set the manufacturer name.
//
void
ppdcDriver::set_manufacturer(
const char *m) // I - Model name
{
if (manufacturer)
manufacturer->release();
manufacturer = new ppdcString(m);
}
//
// 'ppdcDriver::set_model_name()' - Set the model name.
//
void
ppdcDriver::set_model_name(
const char *m) // I - Model name
{
if (model_name)
model_name->release();
model_name = new ppdcString(m);
}
//
// 'ppdcDriver::set_pc_file_name()' - Set the PC filename.
//
void
ppdcDriver::set_pc_file_name(
const char *f) // I - Filename
{
if (pc_file_name)
pc_file_name->release();
pc_file_name = new ppdcString(f);
}
//
// 'ppdcDriver::set_version()' - Set the version string.
//
void
ppdcDriver::set_version(const char *v) // I - Version
{
if (version)
version->release();
version = new ppdcString(v);
}
//
// 'ppdcDriver::write_ppd_file()' - Write a PPD file...
//
int // O - 0 on success, -1 on failure
ppdcDriver::write_ppd_file(
cups_file_t *fp, // I - PPD file
ppdcCatalog *catalog, // I - Message catalog
ppdcArray *locales, // I - Additional languages to add
ppdcSource *src, // I - Driver source
ppdcLineEnding le) // I - Line endings to use
{
bool delete_cat; // Delete the catalog when we are done?
char query[42], // Query attribute
custom[42]; // Custom attribute
ppdcString *s; // Copyright string
ppdcGroup *g; // Current group
ppdcOption *o; // Current option
ppdcChoice *c; // Current choice
ppdcMediaSize *m; // Current media size
ppdcProfile *p; // Current color profile
ppdcFilter *f; // Current filter
ppdcFont *fn, // Current font
*bfn; // Current base font
ppdcConstraint *cn; // Current constraint
ppdcAttr *a; // Current attribute
const char *lf; // Linefeed character to use
// If we don't have a message catalog, use an empty (English) one...
if (!catalog)
{
catalog = new ppdcCatalog(NULL);
delete_cat = true;
}
else
delete_cat = false;
// Figure out the end-of-line string...
if (le == PPDC_LFONLY)
lf = "\n";
else if (le == PPDC_CRONLY)
lf = "\r";
else
lf = "\r\n";
// Write the standard header stuff...
cupsFilePrintf(fp, "*PPD-Adobe: \"4.3\"%s", lf);
cupsFilePrintf(fp, "*%%%%%%%% PPD file for %s with CUPS.%s",
model_name->value, lf);
cupsFilePrintf(fp,
"*%%%%%%%% Created by the CUPS PPD Compiler " CUPS_SVERSION
".%s", lf);
for (s = (ppdcString *)copyright->first();
s;
s = (ppdcString *)copyright->next())
cupsFilePrintf(fp, "*%% %s%s", catalog->find_message(s->value), lf);
cupsFilePrintf(fp, "*FormatVersion: \"4.3\"%s", lf);
cupsFilePrintf(fp, "*FileVersion: \"%s\"%s", version->value, lf);
a = find_attr("LanguageVersion", NULL);
cupsFilePrintf(fp, "*LanguageVersion: %s%s",
catalog->find_message(a ? a->value->value : "English"), lf);
a = find_attr("LanguageEncoding", NULL);
cupsFilePrintf(fp, "*LanguageEncoding: %s%s",
catalog->find_message(a ? a->value->value : "ISOLatin1"), lf);
cupsFilePrintf(fp, "*PCFileName: \"%s\"%s", pc_file_name->value, lf);
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
if (!strcmp(a->name->value, "Product"))
break;
if (a)
{
for (; a; a = (ppdcAttr *)attrs->next())
if (!strcmp(a->name->value, "Product"))
cupsFilePrintf(fp, "*Product: \"%s\"%s", a->value->value, lf);
}
else
cupsFilePrintf(fp, "*Product: \"(%s)\"%s", model_name->value, lf);
cupsFilePrintf(fp, "*Manufacturer: \"%s\"%s",
catalog->find_message(manufacturer->value), lf);
if ((a = find_attr("ModelName", NULL)) != NULL)
cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
catalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*ModelName: \"%s %s\"%s",
catalog->find_message(manufacturer->value),
catalog->find_message(model_name->value), lf);
else
cupsFilePrintf(fp, "*ModelName: \"%s\"%s",
catalog->find_message(model_name->value), lf);
if ((a = find_attr("ShortNickName", NULL)) != NULL)
cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
catalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*ShortNickName: \"%s %s\"%s",
catalog->find_message(manufacturer->value),
catalog->find_message(model_name->value), lf);
else
cupsFilePrintf(fp, "*ShortNickName: \"%s\"%s",
catalog->find_message(model_name->value), lf);
if ((a = find_attr("NickName", NULL)) != NULL)
cupsFilePrintf(fp, "*NickName: \"%s\"%s",
catalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*NickName: \"%s %s, %s\"%s",
catalog->find_message(manufacturer->value),
catalog->find_message(model_name->value), version->value,
lf);
else
cupsFilePrintf(fp, "*NickName: \"%s, %s\"%s",
catalog->find_message(model_name->value), version->value,
lf);
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
if (!strcmp(a->name->value, "PSVersion"))
break;
if (a)
{
for (; a; a = (ppdcAttr *)attrs->next())
if (!strcmp(a->name->value, "PSVersion"))
cupsFilePrintf(fp, "*PSVersion: \"%s\"%s", a->value->value, lf);
}
else
cupsFilePrintf(fp, "*PSVersion: \"(3010.000) 0\"%s", lf);
if ((a = find_attr("LanguageLevel", NULL)) != NULL)
cupsFilePrintf(fp, "*LanguageLevel: \"%s\"%s", a->value->value, lf);
else
cupsFilePrintf(fp, "*LanguageLevel: \"3\"%s", lf);
cupsFilePrintf(fp, "*ColorDevice: %s%s", color_device ? "True" : "False", lf);
if ((a = find_attr("DefaultColorSpace", NULL)) != NULL)
cupsFilePrintf(fp, "*DefaultColorSpace: %s%s", a->value->value, lf);
else
cupsFilePrintf(fp, "*DefaultColorSpace: %s%s",
color_device ? "RGB" : "Gray", lf);
if ((a = find_attr("FileSystem", NULL)) != NULL)
cupsFilePrintf(fp, "*FileSystem: %s%s", a->value->value, lf);
else
cupsFilePrintf(fp, "*FileSystem: False%s", lf);
cupsFilePrintf(fp, "*Throughput: \"%d\"%s", throughput, lf);
if ((a = find_attr("LandscapeOrientation", NULL)) != NULL)
cupsFilePrintf(fp, "*LandscapeOrientation: %s%s", a->value->value, lf);
else
cupsFilePrintf(fp, "*LandscapeOrientation: Plus90%s", lf);
if ((a = find_attr("TTRasterizer", NULL)) != NULL)
cupsFilePrintf(fp, "*TTRasterizer: %s%s", a->value->value, lf);
else if (type != PPDC_DRIVER_PS)
cupsFilePrintf(fp, "*TTRasterizer: Type42%s", lf);
struct lconv *loc = localeconv();
if (attrs->count)
{
// Write driver-defined attributes...
cupsFilePrintf(fp, "*%% Driver-defined attributes...%s", lf);
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
{
if (!strcmp(a->name->value, "Product") ||
!strcmp(a->name->value, "PSVersion") ||
!strcmp(a->name->value, "LanguageLevel") ||
!strcmp(a->name->value, "DefaultColorSpace") ||
!strcmp(a->name->value, "FileSystem") ||
!strcmp(a->name->value, "LandscapeOrientation") ||
!strcmp(a->name->value, "TTRasterizer") ||
!strcmp(a->name->value, "LanguageVersion") ||
!strcmp(a->name->value, "LanguageEncoding") ||
!strcmp(a->name->value, "ModelName") ||
!strcmp(a->name->value, "NickName") ||
!strcmp(a->name->value, "ShortNickName") ||
!strcmp(a->name->value, "cupsVersion"))
continue;
if (a->name->value[0] == '?' &&
(find_option(a->name->value + 1) ||
!strcmp(a->name->value, "?ImageableArea") ||
!strcmp(a->name->value, "?PageRegion") ||
!strcmp(a->name->value, "?PageSize") ||
!strcmp(a->name->value, "?PaperDimension")))
continue;
if (!strncmp(a->name->value, "Custom", 6) &&
find_option(a->name->value + 6))
continue;
if (!strncmp(a->name->value, "ParamCustom", 11) &&
find_option(a->name->value + 11))
continue;
if (!a->selector->value || !a->selector->value[0])
cupsFilePrintf(fp, "*%s", a->name->value);
else if (!a->text->value || !a->text->value[0])
cupsFilePrintf(fp, "*%s %s", a->name->value, a->selector->value);
else
cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
a->text->value);
if (strcmp(a->value->value, "False") &&
strcmp(a->value->value, "True") &&
strcmp(a->name->value, "1284Modes") &&
strcmp(a->name->value, "InkName") &&
strcmp(a->name->value, "PageStackOrder") &&
strncmp(a->name->value, "ParamCustom", 11) &&
strcmp(a->name->value, "Protocols") &&
strcmp(a->name->value, "ReferencePunch") &&
strncmp(a->name->value, "Default", 7))
{
cupsFilePrintf(fp, ": \"%s\"%s", a->value->value, lf);
if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
else
cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
}
}
if (type != PPDC_DRIVER_PS || filters->count)
{
if ((a = find_attr("cupsVersion", NULL)) != NULL)
cupsFilePrintf(fp, "*cupsVersion: %s%s", a->value->value, lf);
else
cupsFilePrintf(fp, "*cupsVersion: %d.%d%s", CUPS_VERSION_MAJOR,
CUPS_VERSION_MINOR, lf);
cupsFilePrintf(fp, "*cupsModelNumber: %d%s", model_number, lf);
cupsFilePrintf(fp, "*cupsManualCopies: %s%s",
manual_copies ? "True" : "False", lf);
if (filters->count)
{
for (f = (ppdcFilter *)filters->first();
f;
f = (ppdcFilter *)filters->next())
cupsFilePrintf(fp, "*cupsFilter: \"%s %d %s\"%s", f->mime_type->value,
f->cost, f->program->value, lf);
}
else
{
switch (type)
{
case PPDC_DRIVER_LABEL :
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
"rastertolabel\"%s", lf);
break;
case PPDC_DRIVER_EPSON :
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
"rastertoepson\"%s", lf);
break;
case PPDC_DRIVER_ESCP :
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
"commandtoescpx\"%s", lf);
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
"rastertoescpx\"%s", lf);
break;
case PPDC_DRIVER_HP :
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
"rastertohp\"%s", lf);
break;
case PPDC_DRIVER_PCL :
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-command 50 "
"commandtopclx\"%s", lf);
cupsFilePrintf(fp, "*cupsFilter: \"application/vnd.cups-raster 50 "
"rastertopclx\"%s", lf);
break;
default :
break;
}
}
for (p = (ppdcProfile *)profiles->first();
p;
p = (ppdcProfile *)profiles->next())
{
char density[255], gamma[255], profile[9][255];
_cupsStrFormatd(density, density + sizeof(density), p->density, loc);
_cupsStrFormatd(gamma, gamma + sizeof(gamma), p->gamma, loc);
for (int i = 0; i < 9; i ++)
_cupsStrFormatd(profile[i], profile[i] + sizeof(profile[0]),
p->profile[i], loc);
cupsFilePrintf(fp,
"*cupsColorProfile %s/%s: \"%s %s %s %s %s %s %s %s %s %s "
"%s\"%s", p->resolution->value, p->media_type->value,
density, gamma, profile[0], profile[1], profile[2],
profile[3], profile[4], profile[5], profile[6], profile[7],
profile[8], lf);
}
}
if (locales)
{
// Add localizations for additional languages...
ppdcString *locale; // Locale name
ppdcCatalog *locatalog; // Message catalog for locale
// Write the list of languages...
cupsFilePrintf(fp, "*cupsLanguages: \"en");
for (locale = (ppdcString *)locales->first();
locale;
locale = (ppdcString *)locales->next())
{
// Skip (US) English...
if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
continue;
// See if we have a po file for this language...
if (!src->find_po(locale->value))
{
// No, see if we can use the base file?
locatalog = new ppdcCatalog(locale->value);
if (locatalog->messages->count == 0)
{
// No, skip this one...
_cupsLangPrintf(stderr,
_("ppdc: No message catalog provided for locale "
"%s."), locale->value);
delete locatalog;
continue;
}
// Add the base file to the list...
src->po_files->add(locatalog);
}
cupsFilePrintf(fp, " %s", locale->value);
}
cupsFilePrintf(fp, "\"%s", lf);
}
for (cn = (ppdcConstraint *)constraints->first();
cn;
cn = (ppdcConstraint *)constraints->next())
{
// First constrain 1 against 2...
if (!strncmp(cn->option1->value, "*Custom", 7) ||
!strncmp(cn->option2->value, "*Custom", 7))
cupsFilePuts(fp, "*NonUIConstraints: ");
else
cupsFilePuts(fp, "*UIConstraints: ");
if (cn->option1->value[0] != '*')
cupsFilePutChar(fp, '*');
cupsFilePuts(fp, cn->option1->value);
if (cn->choice1->value)
cupsFilePrintf(fp, " %s", cn->choice1->value);
cupsFilePutChar(fp, ' ');
if (cn->option2->value[0] != '*')
cupsFilePutChar(fp, '*');
cupsFilePuts(fp, cn->option2->value);
if (cn->choice2->value)
cupsFilePrintf(fp, " %s", cn->choice2->value);
cupsFilePuts(fp, lf);
// Then constrain 2 against 1...
if (!strncmp(cn->option1->value, "*Custom", 7) ||
!strncmp(cn->option2->value, "*Custom", 7))
cupsFilePuts(fp, "*NonUIConstraints: ");
else
cupsFilePuts(fp, "*UIConstraints: ");
if (cn->option2->value[0] != '*')
cupsFilePutChar(fp, '*');
cupsFilePuts(fp, cn->option2->value);
if (cn->choice2->value)
cupsFilePrintf(fp, " %s", cn->choice2->value);
cupsFilePutChar(fp, ' ');
if (cn->option1->value[0] != '*')
cupsFilePutChar(fp, '*');
cupsFilePuts(fp, cn->option1->value);
if (cn->choice1->value)
cupsFilePrintf(fp, " %s", cn->choice1->value);
cupsFilePuts(fp, lf);
}
// PageSize option...
cupsFilePrintf(fp, "*OpenUI *PageSize/Media Size: PickOne%s", lf);
cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageSize%s", lf);
cupsFilePrintf(fp, "*DefaultPageSize: %s%s",
default_size ? default_size->value : "Letter", lf);
for (m = (ppdcMediaSize *)sizes->first();
m;
m = (ppdcMediaSize *)sizes->next())
if (m->size_code->value)
{
cupsFilePrintf(fp, "*PageSize %s/%s: \"%s\"%s",
m->name->value, catalog->find_message(m->text->value),
m->size_code->value, lf);
if (strchr(m->size_code->value, '\n') ||
strchr(m->size_code->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
else
cupsFilePrintf(fp,
"*PageSize %s/%s: \"<</PageSize[%.0f %.0f]"
"/ImagingBBox null>>setpagedevice\"%s",
m->name->value, catalog->find_message(m->text->value),
m->width, m->length, lf);
if ((a = find_attr("?PageSize", NULL)) != NULL)
{
cupsFilePrintf(fp, "*?PageSize: \"%s\"%s", a->value->value, lf);
if (strchr(a->value->value, '\n') ||
strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
cupsFilePrintf(fp, "*CloseUI: *PageSize%s", lf);
// PageRegion option...
cupsFilePrintf(fp, "*OpenUI *PageRegion/Media Size: PickOne%s", lf);
cupsFilePrintf(fp, "*OrderDependency: 10 AnySetup *PageRegion%s", lf);
cupsFilePrintf(fp, "*DefaultPageRegion: %s%s",
default_size ? default_size->value : "Letter", lf);
for (m = (ppdcMediaSize *)sizes->first();
m;
m = (ppdcMediaSize *)sizes->next())
if (m->region_code->value)
{
cupsFilePrintf(fp, "*PageRegion %s/%s: \"%s\"%s",
m->name->value, catalog->find_message(m->text->value),
m->region_code->value, lf);
if (strchr(m->region_code->value, '\n') ||
strchr(m->region_code->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
else
cupsFilePrintf(fp,
"*PageRegion %s/%s: \"<</PageSize[%.0f %.0f]"
"/ImagingBBox null>>setpagedevice\"%s",
m->name->value, catalog->find_message(m->text->value),
m->width, m->length, lf);
if ((a = find_attr("?PageRegion", NULL)) != NULL)
{
cupsFilePrintf(fp, "*?PageRegion: \"%s\"%s", a->value->value, lf);
if (strchr(a->value->value, '\n') ||
strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
cupsFilePrintf(fp, "*CloseUI: *PageRegion%s", lf);
// ImageableArea info...
cupsFilePrintf(fp, "*DefaultImageableArea: %s%s",
default_size ? default_size->value : "Letter", lf);
char left[255], right[255], bottom[255], top[255];
for (m = (ppdcMediaSize *)sizes->first();
m;
m = (ppdcMediaSize *)sizes->next())
{
_cupsStrFormatd(left, left + sizeof(left), m->left, loc);
_cupsStrFormatd(bottom, bottom + sizeof(bottom), m->bottom, loc);
_cupsStrFormatd(right, right + sizeof(right), m->width - m->right, loc);
_cupsStrFormatd(top, top + sizeof(top), m->length - m->top, loc);
cupsFilePrintf(fp, "*ImageableArea %s/%s: \"%s %s %s %s\"%s",
m->name->value, catalog->find_message(m->text->value),
left, bottom, right, top, lf);
}
if ((a = find_attr("?ImageableArea", NULL)) != NULL)
{
cupsFilePrintf(fp, "*?ImageableArea: \"%s\"%s", a->value->value, lf);
if (strchr(a->value->value, '\n') ||
strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
// PaperDimension info...
cupsFilePrintf(fp, "*DefaultPaperDimension: %s%s",
default_size ? default_size->value : "Letter", lf);
char width[255], length[255];
for (m = (ppdcMediaSize *)sizes->first();
m;
m = (ppdcMediaSize *)sizes->next())
{
_cupsStrFormatd(width, width + sizeof(width), m->width, loc);
_cupsStrFormatd(length, length + sizeof(length), m->length, loc);
cupsFilePrintf(fp, "*PaperDimension %s/%s: \"%s %s\"%s",
m->name->value, catalog->find_message(m->text->value),
width, length, lf);
}
if ((a = find_attr("?PaperDimension", NULL)) != NULL)
{
cupsFilePrintf(fp, "*?PaperDimension: \"%s\"%s", a->value->value, lf);
if (strchr(a->value->value, '\n') ||
strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
// Custom size support...
if (variable_paper_size)
{
_cupsStrFormatd(width, width + sizeof(width), max_width, loc);
_cupsStrFormatd(length, length + sizeof(length), max_length, loc);
_cupsStrFormatd(left, left + sizeof(left), left_margin, loc);
_cupsStrFormatd(bottom, bottom + sizeof(bottom), bottom_margin, loc);
_cupsStrFormatd(right, right + sizeof(right), right_margin, loc);
_cupsStrFormatd(top, top + sizeof(top), top_margin, loc);
cupsFilePrintf(fp, "*MaxMediaWidth: \"%s\"%s", width, lf);
cupsFilePrintf(fp, "*MaxMediaHeight: \"%s\"%s", length, lf);
cupsFilePrintf(fp, "*HWMargins: %s %s %s %s%s", left, bottom, right, top,
lf);
if (custom_size_code && custom_size_code->value)
{
cupsFilePrintf(fp, "*CustomPageSize True: \"%s\"%s",
custom_size_code->value, lf);
if (strchr(custom_size_code->value, '\n') ||
strchr(custom_size_code->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
else
cupsFilePrintf(fp,
"*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]"
"/ImagingBBox null>>setpagedevice\"%s", lf);
if ((a = find_attr("ParamCustomPageSize", "Width")) != NULL)
cupsFilePrintf(fp, "*ParamCustomPageSize Width: %s%s", a->value->value,
lf);
else
{
char width0[255];
_cupsStrFormatd(width0, width0 + sizeof(width0), min_width, loc);
_cupsStrFormatd(width, width + sizeof(width), max_width, loc);
cupsFilePrintf(fp, "*ParamCustomPageSize Width: 1 points %s %s%s",
width0, width, lf);
}
if ((a = find_attr("ParamCustomPageSize", "Height")) != NULL)
cupsFilePrintf(fp, "*ParamCustomPageSize Height: %s%s", a->value->value,
lf);
else
{
char length0[255];
_cupsStrFormatd(length0, length0 + sizeof(length0), min_length, loc);
_cupsStrFormatd(length, length + sizeof(length), max_length, loc);
cupsFilePrintf(fp, "*ParamCustomPageSize Height: 2 points %s %s%s",
length0, length, lf);
}
if ((a = find_attr("ParamCustomPageSize", "WidthOffset")) != NULL)
cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: %s%s",
a->value->value, lf);
else
cupsFilePrintf(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0%s", lf);
if ((a = find_attr("ParamCustomPageSize", "HeightOffset")) != NULL)
cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: %s%s",
a->value->value, lf);
else
cupsFilePrintf(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0%s", lf);
if ((a = find_attr("ParamCustomPageSize", "Orientation")) != NULL)
cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: %s%s",
a->value->value, lf);
else
cupsFilePrintf(fp, "*ParamCustomPageSize Orientation: 5 int 0 0%s", lf);
}
// All other options...
for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
{
if (!g->options->count)
continue;
if (_cups_strcasecmp(g->name->value, "General"))
cupsFilePrintf(fp, "*OpenGroup: %s/%s%s", g->name->value,
catalog->find_message(g->text->value), lf);
for (o = (ppdcOption *)g->options->first();
o;
o = (ppdcOption *)g->options->next())
{
if (!o->choices->count)
continue;
if (o->section == PPDC_SECTION_JCL)
{
if (!o->text->value)
cupsFilePrintf(fp, "*JCLOpenUI *%s/%s: ", o->name->value,
catalog->find_message(o->name->value));
else
cupsFilePrintf(fp, "*JCLOpenUI *%s/%s: ", o->name->value,
catalog->find_message(o->text->value));
}
else if (!o->text->value)
cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
catalog->find_message(o->name->value));
else
cupsFilePrintf(fp, "*OpenUI *%s/%s: ", o->name->value,
catalog->find_message(o->text->value));
switch (o->type)
{
case PPDC_BOOLEAN :
cupsFilePrintf(fp, "Boolean%s", lf);
break;
default :
cupsFilePrintf(fp, "PickOne%s", lf);
break;
case PPDC_PICKMANY :
cupsFilePrintf(fp, "PickMany%s", lf);
break;
}
char order[255];
_cupsStrFormatd(order, order + sizeof(order), o->order, loc);
cupsFilePrintf(fp, "*OrderDependency: %s ", order);
switch (o->section)
{
default :
cupsFilePrintf(fp, "AnySetup");
break;
case PPDC_SECTION_DOCUMENT :
cupsFilePrintf(fp, "DocumentSetup");
break;
case PPDC_SECTION_EXIT :
cupsFilePrintf(fp, "ExitServer");
break;
case PPDC_SECTION_JCL :
cupsFilePrintf(fp, "JCLSetup");
break;
case PPDC_SECTION_PAGE :
cupsFilePrintf(fp, "PageSetup");
break;
case PPDC_SECTION_PROLOG :
cupsFilePrintf(fp, "Prolog");
break;
}
cupsFilePrintf(fp, " *%s%s", o->name->value, lf);
if (o->defchoice)
{
// Use the programmer-supplied default...
cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value,
o->defchoice->value, lf);
}
else
{
// Make the first choice the default...
c = (ppdcChoice *)o->choices->first();
cupsFilePrintf(fp, "*Default%s: %s%s", o->name->value, c->name->value,
lf);
}
for (c = (ppdcChoice *)o->choices->first();
c;
c = (ppdcChoice *)o->choices->next())
{
// Write this choice...
if (!c->text->value)
cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
c->name->value, catalog->find_message(c->name->value),
c->code->value, lf);
else
cupsFilePrintf(fp, "*%s %s/%s: \"%s\"%s", o->name->value,
c->name->value, catalog->find_message(c->text->value),
c->code->value, lf);
// Multi-line commands need a *End line to terminate them.
if (strchr(c->code->value, '\n') ||
strchr(c->code->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
snprintf(query, sizeof(query), "?%s", o->name->value);
if ((a = find_attr(query, NULL)) != NULL)
{
cupsFilePrintf(fp, "*%s: \"%s\"%s", query, a->value->value, lf);
if (strchr(a->value->value, '\n') ||
strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
}
if (o->section == PPDC_SECTION_JCL)
cupsFilePrintf(fp, "*JCLCloseUI: *%s%s", o->name->value, lf);
else
cupsFilePrintf(fp, "*CloseUI: *%s%s", o->name->value, lf);
snprintf(custom, sizeof(custom), "Custom%s", o->name->value);
if ((a = find_attr(custom, "True")) != NULL)
{
// Output custom option information...
cupsFilePrintf(fp, "*%s True: \"%s\"%s", custom, a->value->value, lf);
if (strchr(a->value->value, '\n') || strchr(a->value->value, '\r'))
cupsFilePrintf(fp, "*End%s", lf);
snprintf(custom, sizeof(custom), "ParamCustom%s", o->name->value);
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
{
if (strcmp(a->name->value, custom))
continue;
if (!a->selector->value || !a->selector->value[0])
cupsFilePrintf(fp, "*%s", a->name->value);
else if (!a->text->value || !a->text->value[0])
cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
catalog->find_message(a->selector->value));
else
cupsFilePrintf(fp, "*%s %s/%s", a->name->value, a->selector->value,
catalog->find_message(a->text->value));
cupsFilePrintf(fp, ": %s%s", a->value->value, lf);
}
}
}
if (_cups_strcasecmp(g->name->value, "General"))
cupsFilePrintf(fp, "*CloseGroup: %s%s", g->name->value, lf);
}
if (locales)
{
// Add localizations for additional languages...
ppdcString *locale; // Locale name
ppdcCatalog *locatalog; // Message catalog for locale
// Write the translation strings for each language...
for (locale = (ppdcString *)locales->first();
locale;
locale = (ppdcString *)locales->next())
{
// Skip (US) English...
if (!strcmp(locale->value, "en") || !strcmp(locale->value, "en_US"))
continue;
// Skip missing languages...
if ((locatalog = src->find_po(locale->value)) == NULL)
continue;
// Do the core stuff first...
cupsFilePrintf(fp, "*%s.Translation Manufacturer/%s: \"\"%s",
locale->value,
locatalog->find_message(manufacturer->value), lf);
if ((a = find_attr("ModelName", NULL)) != NULL)
cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
locale->value,
locatalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*%s.Translation ModelName/%s %s: \"\"%s",
locale->value,
locatalog->find_message(manufacturer->value),
locatalog->find_message(model_name->value), lf);
else
cupsFilePrintf(fp, "*%s.Translation ModelName/%s: \"\"%s",
locale->value,
locatalog->find_message(model_name->value), lf);
if ((a = find_attr("ShortNickName", NULL)) != NULL)
cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
locale->value,
locatalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s %s: \"\"%s",
locale->value,
locatalog->find_message(manufacturer->value),
locatalog->find_message(model_name->value), lf);
else
cupsFilePrintf(fp, "*%s.Translation ShortNickName/%s: \"\"%s",
locale->value,
locatalog->find_message(model_name->value), lf);
if ((a = find_attr("NickName", NULL)) != NULL)
cupsFilePrintf(fp, "*%s.Translation NickName/%s: \"\"%s",
locale->value,
locatalog->find_message(a->value->value), lf);
else if (_cups_strncasecmp(model_name->value, manufacturer->value,
strlen(manufacturer->value)))
cupsFilePrintf(fp, "*%s.Translation NickName/%s %s, %s: \"\"%s",
locale->value,
locatalog->find_message(manufacturer->value),
locatalog->find_message(model_name->value),
version->value, lf);
else
cupsFilePrintf(fp, "*%s.Translation NickName/%s, %s: \"\"%s",
locale->value,
locatalog->find_message(model_name->value),
version->value, lf);
// Then the page sizes...
cupsFilePrintf(fp, "*%s.Translation PageSize/%s: \"\"%s", locale->value,
locatalog->find_message("Media Size"), lf);
for (m = (ppdcMediaSize *)sizes->first();
m;
m = (ppdcMediaSize *)sizes->next())
{
cupsFilePrintf(fp, "*%s.PageSize %s/%s: \"\"%s", locale->value,
m->name->value, locatalog->find_message(m->text->value),
lf);
}
// Next the groups and options...
for (g = (ppdcGroup *)groups->first(); g; g = (ppdcGroup *)groups->next())
{
if (!g->options->count)
continue;
if (_cups_strcasecmp(g->name->value, "General"))
cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
g->name->value,
locatalog->find_message(g->text->value), lf);
for (o = (ppdcOption *)g->options->first();
o;
o = (ppdcOption *)g->options->next())
{
if (!o->choices->count)
continue;
cupsFilePrintf(fp, "*%s.Translation %s/%s: \"\"%s", locale->value,
o->name->value,
locatalog->find_message(o->text->value ?
o->text->value :
o->name->value), lf);
for (c = (ppdcChoice *)o->choices->first();
c;
c = (ppdcChoice *)o->choices->next())
{
// Write this choice...
cupsFilePrintf(fp, "*%s.%s %s/%s: \"\"%s", locale->value,
o->name->value, c->name->value,
locatalog->find_message(c->text->value ?
c->text->value :
c->name->value), lf);
}
}
}
// Finally the localizable attributes...
for (a = (ppdcAttr *)attrs->first(); a; a = (ppdcAttr *)attrs->next())
{
if (!a->localizable &&
(!a->text || !a->text->value || !a->text->value[0]) &&
strcmp(a->name->value, "APCustomColorMatchingName") &&
strcmp(a->name->value, "APPrinterPreset") &&
strcmp(a->name->value, "cupsICCProfile") &&
strcmp(a->name->value, "cupsIPPReason") &&
strcmp(a->name->value, "cupsMarkerName") &&
strncmp(a->name->value, "Custom", 6) &&
strncmp(a->name->value, "ParamCustom", 11))
continue;
cupsFilePrintf(fp, "*%s.%s %s/%s: \"%s\"%s", locale->value,
a->name->value, a->selector->value,
locatalog->find_message(a->text && a->text->value ?
a->text->value : a->name->value),
((a->localizable && a->value->value[0]) ||
!strcmp(a->name->value, "cupsIPPReason")) ?
locatalog->find_message(a->value->value) : "",
lf);
}
}
}
if (default_font && default_font->value)
cupsFilePrintf(fp, "*DefaultFont: %s%s", default_font->value, lf);
else
cupsFilePrintf(fp, "*DefaultFont: Courier%s", lf);
for (fn = (ppdcFont *)fonts->first(); fn; fn = (ppdcFont *)fonts->next())
if (!strcmp(fn->name->value, "*"))
{
for (bfn = (ppdcFont *)src->base_fonts->first();
bfn;
bfn = (ppdcFont *)src->base_fonts->next())
cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
bfn->name->value, bfn->encoding->value,
bfn->version->value, bfn->charset->value,
bfn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
}
else
cupsFilePrintf(fp, "*Font %s: %s \"%s\" %s %s%s",
fn->name->value, fn->encoding->value, fn->version->value,
fn->charset->value,
fn->status == PPDC_FONT_ROM ? "ROM" : "Disk", lf);
cupsFilePrintf(fp, "*%% End of %s, %05d bytes.%s", pc_file_name->value,
(int)((size_t)cupsFileTell(fp) + 25 + strlen(pc_file_name->value)),
lf);
if (delete_cat)
catalog->release();
return (0);
}