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.
453 lines
11 KiB
453 lines
11 KiB
//
|
|
// PPD file compiler main entry for the CUPS PPD Compiler.
|
|
//
|
|
// Copyright 2007-2014 by Apple Inc.
|
|
// Copyright 2002-2007 by Easy Software Products.
|
|
//
|
|
// Licensed under Apache License v2.0. See the file "LICENSE" for more information.
|
|
//
|
|
|
|
//
|
|
// Include necessary headers...
|
|
//
|
|
|
|
#include "ppdc-private.h"
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
|
|
//
|
|
// Local functions...
|
|
//
|
|
|
|
static void usage(void);
|
|
|
|
|
|
//
|
|
// 'main()' - Main entry for the PPD compiler.
|
|
//
|
|
|
|
int // O - Exit status
|
|
main(int argc, // I - Number of command-line arguments
|
|
char *argv[]) // I - Command-line arguments
|
|
{
|
|
int i, j; // Looping vars
|
|
ppdcCatalog *catalog; // Message catalog
|
|
const char *outdir; // Output directory
|
|
ppdcSource *src; // PPD source file data
|
|
ppdcDriver *d; // Current driver
|
|
cups_file_t *fp; // PPD file
|
|
char *opt, // Current option
|
|
*value, // Value in option
|
|
*outname, // Output filename
|
|
make_model[1024],
|
|
// Make and model
|
|
pcfilename[1024],
|
|
// Lowercase pcfilename
|
|
filename[1024]; // PPD filename
|
|
int comp, // Compress
|
|
do_test, // Test PPD files
|
|
single_language,// Generate single-language files
|
|
use_model_name, // Use ModelName for filename
|
|
verbose; // Verbosity
|
|
ppdcLineEnding le; // Line ending to use
|
|
ppdcArray *locales; // List of locales
|
|
cups_array_t *filenames; // List of generated filenames
|
|
|
|
|
|
_cupsSetLocale(argv);
|
|
|
|
// Scan the command-line...
|
|
catalog = NULL;
|
|
comp = 0;
|
|
do_test = 0;
|
|
le = PPDC_LFONLY;
|
|
locales = NULL;
|
|
outdir = "ppd";
|
|
single_language = 0;
|
|
src = new ppdcSource();
|
|
use_model_name = 0;
|
|
verbose = 0;
|
|
filenames = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
|
|
|
|
for (i = 1; i < argc; i ++)
|
|
if (argv[i][0] == '-')
|
|
{
|
|
for (opt = argv[i] + 1; *opt; opt ++)
|
|
switch (*opt)
|
|
{
|
|
case 'D' : // Define variable
|
|
i ++;
|
|
if (i >= argc)
|
|
usage();
|
|
|
|
if ((value = strchr(argv[i], '=')) != NULL)
|
|
{
|
|
*value++ = '\0';
|
|
|
|
src->set_variable(argv[i], value);
|
|
}
|
|
else
|
|
src->set_variable(argv[i], "1");
|
|
break;
|
|
|
|
case 'I' : // Include directory...
|
|
i ++;
|
|
if (i >= argc)
|
|
usage();
|
|
|
|
if (verbose > 1)
|
|
_cupsLangPrintf(stdout,
|
|
_("ppdc: Adding include directory \"%s\"."),
|
|
argv[i]);
|
|
|
|
ppdcSource::add_include(argv[i]);
|
|
break;
|
|
|
|
case 'c' : // Message catalog...
|
|
i ++;
|
|
if (i >= argc)
|
|
usage();
|
|
|
|
if (verbose > 1)
|
|
_cupsLangPrintf(stdout,
|
|
_("ppdc: Loading messages from \"%s\"."),
|
|
argv[i]);
|
|
|
|
if (!catalog)
|
|
catalog = new ppdcCatalog("en");
|
|
|
|
if (catalog->load_messages(argv[i]))
|
|
{
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to load localization file "
|
|
"\"%s\" - %s"), argv[i], strerror(errno));
|
|
return (1);
|
|
}
|
|
break;
|
|
|
|
case 'd' : // Output directory...
|
|
i ++;
|
|
if (i >= argc)
|
|
usage();
|
|
|
|
if (verbose > 1)
|
|
_cupsLangPrintf(stdout,
|
|
_("ppdc: Writing PPD files to directory "
|
|
"\"%s\"."), argv[i]);
|
|
|
|
outdir = argv[i];
|
|
break;
|
|
|
|
case 'l' : // Language(s)...
|
|
i ++;
|
|
if (i >= argc)
|
|
usage();
|
|
|
|
if (strchr(argv[i], ','))
|
|
{
|
|
// Comma-delimited list of languages...
|
|
char temp[1024], // Copy of language list
|
|
*start, // Start of current locale name
|
|
*end; // End of current locale name
|
|
|
|
|
|
locales = new ppdcArray();
|
|
|
|
strlcpy(temp, argv[i], sizeof(temp));
|
|
for (start = temp; *start; start = end)
|
|
{
|
|
if ((end = strchr(start, ',')) != NULL)
|
|
*end++ = '\0';
|
|
else
|
|
end = start + strlen(start);
|
|
|
|
if (end > start)
|
|
locales->add(new ppdcString(start));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
single_language = 1;
|
|
|
|
if (verbose > 1)
|
|
_cupsLangPrintf(stdout,
|
|
_("ppdc: Loading messages for locale "
|
|
"\"%s\"."), argv[i]);
|
|
|
|
if (catalog)
|
|
catalog->release();
|
|
|
|
catalog = new ppdcCatalog(argv[i]);
|
|
|
|
if (catalog->messages->count == 0 && strcmp(argv[i], "en"))
|
|
{
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to find localization for "
|
|
"\"%s\" - %s"), argv[i], strerror(errno));
|
|
return (1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'm' : // Use ModelName for filename
|
|
use_model_name = 1;
|
|
break;
|
|
|
|
case 't' : // Test PPDs instead of generating them
|
|
do_test = 1;
|
|
break;
|
|
|
|
case 'v' : // Be verbose...
|
|
verbose ++;
|
|
break;
|
|
|
|
case 'z' : // Compress files...
|
|
comp = 1;
|
|
break;
|
|
|
|
case '-' : // --option
|
|
if (!strcmp(opt, "-lf"))
|
|
{
|
|
le = PPDC_LFONLY;
|
|
opt += strlen(opt) - 1;
|
|
break;
|
|
}
|
|
else if (!strcmp(opt, "-cr"))
|
|
{
|
|
le = PPDC_CRONLY;
|
|
opt += strlen(opt) - 1;
|
|
break;
|
|
}
|
|
else if (!strcmp(opt, "-crlf"))
|
|
{
|
|
le = PPDC_CRLF;
|
|
opt += strlen(opt) - 1;
|
|
break;
|
|
}
|
|
|
|
default : // Unknown
|
|
usage();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Open and load the driver info file...
|
|
if (verbose > 1)
|
|
_cupsLangPrintf(stdout,
|
|
_("ppdc: Loading driver information file \"%s\"."),
|
|
argv[i]);
|
|
|
|
src->read_file(argv[i]);
|
|
}
|
|
|
|
|
|
if (src->drivers->count > 0)
|
|
{
|
|
// Create the output directory...
|
|
if (mkdir(outdir, 0777))
|
|
{
|
|
if (errno != EEXIST)
|
|
{
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to create output directory %s: %s"),
|
|
outdir, strerror(errno));
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
// Write PPD files...
|
|
for (d = (ppdcDriver *)src->drivers->first();
|
|
d;
|
|
d = (ppdcDriver *)src->drivers->next())
|
|
{
|
|
if (do_test)
|
|
{
|
|
// Test the PPD file for this driver...
|
|
int pid, // Process ID
|
|
fds[2]; // Pipe file descriptors
|
|
|
|
|
|
if (pipe(fds))
|
|
{
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to create output pipes: %s"),
|
|
strerror(errno));
|
|
return (1);
|
|
}
|
|
|
|
if ((pid = fork()) == 0)
|
|
{
|
|
// Child process comes here...
|
|
dup2(fds[0], 0);
|
|
|
|
close(fds[0]);
|
|
close(fds[1]);
|
|
|
|
execlp("cupstestppd", "cupstestppd", "-", (char *)0);
|
|
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to execute cupstestppd: %s"),
|
|
strerror(errno));
|
|
return (errno);
|
|
}
|
|
else if (pid < 0)
|
|
{
|
|
_cupsLangPrintf(stderr, _("ppdc: Unable to execute cupstestppd: %s"),
|
|
strerror(errno));
|
|
return (errno);
|
|
}
|
|
|
|
close(fds[0]);
|
|
fp = cupsFileOpenFd(fds[1], "w");
|
|
}
|
|
else
|
|
{
|
|
// Write the PPD file for this driver...
|
|
if (use_model_name)
|
|
{
|
|
if (!_cups_strncasecmp(d->model_name->value, d->manufacturer->value,
|
|
strlen(d->manufacturer->value)))
|
|
{
|
|
// Model name already starts with the manufacturer...
|
|
outname = d->model_name->value;
|
|
}
|
|
else
|
|
{
|
|
// Add manufacturer to the front of the model name...
|
|
snprintf(make_model, sizeof(make_model), "%s %s",
|
|
d->manufacturer->value, d->model_name->value);
|
|
outname = make_model;
|
|
}
|
|
}
|
|
else if (d->file_name)
|
|
outname = d->file_name->value;
|
|
else
|
|
outname = d->pc_file_name->value;
|
|
|
|
if (strstr(outname, ".PPD"))
|
|
{
|
|
// Convert PCFileName to lowercase...
|
|
for (j = 0;
|
|
outname[j] && j < (int)(sizeof(pcfilename) - 1);
|
|
j ++)
|
|
pcfilename[j] = (char)tolower(outname[j] & 255);
|
|
|
|
pcfilename[j] = '\0';
|
|
}
|
|
else
|
|
{
|
|
// Leave PCFileName as-is...
|
|
strlcpy(pcfilename, outname, sizeof(pcfilename));
|
|
}
|
|
|
|
// Open the PPD file for writing...
|
|
if (comp)
|
|
snprintf(filename, sizeof(filename), "%s/%s.gz", outdir, pcfilename);
|
|
else
|
|
snprintf(filename, sizeof(filename), "%s/%s", outdir, pcfilename);
|
|
|
|
if (cupsArrayFind(filenames, filename))
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Warning - overlapping filename \"%s\"."),
|
|
filename);
|
|
else
|
|
cupsArrayAdd(filenames, strdup(filename));
|
|
|
|
fp = cupsFileOpen(filename, comp ? "w9" : "w");
|
|
if (!fp)
|
|
{
|
|
_cupsLangPrintf(stderr,
|
|
_("ppdc: Unable to create PPD file \"%s\" - %s."),
|
|
filename, strerror(errno));
|
|
return (1);
|
|
}
|
|
|
|
if (verbose)
|
|
_cupsLangPrintf(stdout, _("ppdc: Writing %s."), filename);
|
|
}
|
|
|
|
/*
|
|
* Write the PPD file...
|
|
*/
|
|
|
|
ppdcArray *templocales = locales;
|
|
|
|
if (!templocales && !single_language)
|
|
{
|
|
templocales = new ppdcArray();
|
|
for (ppdcCatalog *tempcatalog = (ppdcCatalog *)src->po_files->first();
|
|
tempcatalog;
|
|
tempcatalog = (ppdcCatalog *)src->po_files->next())
|
|
{
|
|
tempcatalog->locale->retain();
|
|
templocales->add(tempcatalog->locale);
|
|
}
|
|
}
|
|
|
|
if (d->write_ppd_file(fp, catalog, templocales, src, le))
|
|
{
|
|
cupsFileClose(fp);
|
|
return (1);
|
|
}
|
|
|
|
if (templocales != locales)
|
|
templocales->release();
|
|
|
|
cupsFileClose(fp);
|
|
}
|
|
}
|
|
else
|
|
usage();
|
|
|
|
// Delete the printer driver information...
|
|
src->release();
|
|
|
|
// Message catalog...
|
|
if (catalog)
|
|
catalog->release();
|
|
|
|
// Return with no errors.
|
|
return (0);
|
|
}
|
|
|
|
|
|
//
|
|
// 'usage()' - Show usage and exit.
|
|
//
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
_cupsLangPuts(stdout, _("Usage: ppdc [options] filename.drv [ ... "
|
|
"filenameN.drv ]"));
|
|
_cupsLangPuts(stdout, _("Options:"));
|
|
_cupsLangPuts(stdout, _(" -D name=value Set named variable to "
|
|
"value."));
|
|
_cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
|
|
"search path."));
|
|
_cupsLangPuts(stdout, _(" -c catalog.po Load the specified "
|
|
"message catalog."));
|
|
_cupsLangPuts(stdout, _(" -d output-dir Specify the output "
|
|
"directory."));
|
|
_cupsLangPuts(stdout, _(" -l lang[,lang,...] Specify the output "
|
|
"language(s) (locale)."));
|
|
_cupsLangPuts(stdout, _(" -m Use the ModelName value "
|
|
"as the filename."));
|
|
_cupsLangPuts(stdout, _(" -t Test PPDs instead of "
|
|
"generating them."));
|
|
_cupsLangPuts(stdout, _(" -v Be verbose."));
|
|
_cupsLangPuts(stdout, _(" -z Compress PPD files using "
|
|
"GNU zip."));
|
|
_cupsLangPuts(stdout, _(" --cr End lines with CR (Mac "
|
|
"OS 9)."));
|
|
_cupsLangPuts(stdout, _(" --crlf End lines with CR + LF "
|
|
"(Windows)."));
|
|
_cupsLangPuts(stdout, _(" --lf End lines with LF "
|
|
"(UNIX/Linux/macOS)."));
|
|
|
|
exit(1);
|
|
}
|