mirror of https://gitee.com/openkylin/cups.git
361 lines
8.9 KiB
C++
361 lines
8.9 KiB
C++
//
|
||
// PPD file merge utility for the CUPS PPD Compiler.
|
||
//
|
||
// Copyright © 2007-2018 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 <cups/cups-private.h>
|
||
#include <cups/ppd-private.h>
|
||
#include <cups/array.h>
|
||
|
||
|
||
//
|
||
// Local functions...
|
||
//
|
||
|
||
static const char *ppd_locale(ppd_file_t *ppd);
|
||
static void usage(void) _CUPS_NORETURN;
|
||
|
||
|
||
//
|
||
// 'main()' - Main entry for the PPD merge utility.
|
||
//
|
||
|
||
int // O - Exit status
|
||
main(int argc, // I - Number of command-line arguments
|
||
char *argv[]) // I - Command-line arguments
|
||
{
|
||
int i; // Looping var
|
||
char *opt; // Current option
|
||
ppd_file_t *ppd; // PPD file
|
||
cups_array_t *ppds; // Array of PPD files
|
||
const char *inname, // First input filename
|
||
*outname; // Output filename (if any)
|
||
char bckname[1024]; // Backup filename
|
||
cups_file_t *infile, // Input file
|
||
*outfile; // Output file
|
||
cups_array_t *languages; // Languages in file
|
||
const char *locale; // Current locale
|
||
char line[1024]; // Line from file
|
||
|
||
|
||
_cupsSetLocale(argv);
|
||
|
||
// Scan the command-line...
|
||
inname = NULL;
|
||
outname = NULL;
|
||
outfile = NULL;
|
||
languages = NULL;
|
||
ppds = cupsArrayNew(NULL, NULL);
|
||
|
||
for (i = 1; i < argc; i ++)
|
||
if (argv[i][0] == '-')
|
||
{
|
||
for (opt = argv[i] + 1; *opt; opt ++)
|
||
switch (*opt)
|
||
{
|
||
case 'o' : // Output file
|
||
if (outname)
|
||
usage();
|
||
|
||
i ++;
|
||
if (i >= argc)
|
||
usage();
|
||
|
||
outname = argv[i];
|
||
break;
|
||
|
||
default : // Unknown
|
||
usage();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Open and load the PPD file...
|
||
if ((infile = cupsFileOpen(argv[i], "r")) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Unable to open %s: %s"), "ppdmerge",
|
||
argv[i], strerror(errno));
|
||
return (1);
|
||
}
|
||
|
||
// Open the PPD file...
|
||
if ((ppd = ppdOpen2(infile)) == NULL)
|
||
{
|
||
ppd_status_t status; // PPD open status
|
||
int curline, // Current line
|
||
linenum; // Line number
|
||
|
||
|
||
status = ppdLastError(&linenum);
|
||
|
||
_cupsLangPrintf(stderr,
|
||
_("%s: Unable to open PPD file: %s on line %d."),
|
||
"ppdmerge", ppdErrorString(status), linenum);
|
||
cupsFileRewind(infile);
|
||
|
||
line[0] = '\0';
|
||
curline = 0;
|
||
|
||
while (cupsFileGets(infile, line, sizeof(line)))
|
||
{
|
||
curline ++;
|
||
if (curline >= linenum)
|
||
break;
|
||
}
|
||
|
||
_cupsLangPrintf(stderr, "%d: %s", linenum, line);
|
||
|
||
cupsFileClose(infile);
|
||
return (1);
|
||
}
|
||
|
||
// Figure out the locale...
|
||
if ((locale = ppd_locale(ppd)) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("ppdmerge: Bad LanguageVersion \"%s\" in %s."),
|
||
ppd->lang_version, argv[i]);
|
||
cupsFileClose(infile);
|
||
ppdClose(ppd);
|
||
return (1);
|
||
}
|
||
|
||
if (!strcmp(locale, "en") && !inname && !outfile)
|
||
{
|
||
// Set the English PPD's filename...
|
||
inname = argv[i];
|
||
languages = _ppdGetLanguages(ppd);
|
||
|
||
if (outname && !strcmp(inname, outname))
|
||
{
|
||
// Rename input filename so that we don't overwrite it...
|
||
snprintf(bckname, sizeof(bckname), "%s.bck", inname);
|
||
|
||
if (rename(inname, bckname))
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("ppdmerge: Unable to backup %s to %s - %s"),
|
||
inname, bckname, strerror(errno));
|
||
return (1);
|
||
}
|
||
|
||
inname = bckname;
|
||
}
|
||
}
|
||
else if (strcmp(locale, "en"))
|
||
{
|
||
// Save this PPD for later processing...
|
||
cupsArrayAdd(ppds, ppd);
|
||
}
|
||
else
|
||
{
|
||
// Don't need this PPD...
|
||
_cupsLangPrintf(stderr, _("ppdmerge: Ignoring PPD file %s."),
|
||
argv[i]);
|
||
ppdClose(ppd);
|
||
}
|
||
|
||
// Close and move on...
|
||
cupsFileClose(infile);
|
||
}
|
||
|
||
// If no PPDs have been loaded, display the program usage message.
|
||
if (!inname)
|
||
usage();
|
||
|
||
// Loop through the PPD files we loaded to generate a new language list...
|
||
if (!languages)
|
||
languages = cupsArrayNew((cups_array_func_t)strcmp, NULL);
|
||
|
||
for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
|
||
ppd;
|
||
ppd = (ppd_file_t *)cupsArrayNext(ppds))
|
||
{
|
||
locale = ppd_locale(ppd);
|
||
|
||
if (cupsArrayFind(languages, (void *)locale))
|
||
{
|
||
// Already have this language, remove the PPD from the list.
|
||
ppdClose(ppd);
|
||
cupsArrayRemove(ppds, ppd);
|
||
}
|
||
else
|
||
cupsArrayAdd(languages, (void *)locale);
|
||
}
|
||
|
||
// Copy the English PPD starting with a cupsLanguages line...
|
||
infile = cupsFileOpen(inname, "r");
|
||
|
||
if (outname)
|
||
{
|
||
const char *ext = strrchr(outname, '.');
|
||
if (ext && !strcmp(ext, ".gz"))
|
||
outfile = cupsFileOpen(outname, "w9");
|
||
else
|
||
outfile = cupsFileOpen(outname, "w");
|
||
}
|
||
else
|
||
outfile = cupsFileStdout();
|
||
|
||
cupsFileGets(infile, line, sizeof(line));
|
||
cupsFilePrintf(outfile, "%s\n", line);
|
||
if ((locale = (char *)cupsArrayFirst(languages)) != NULL)
|
||
{
|
||
cupsFilePrintf(outfile, "*cupsLanguages: \"%s", locale);
|
||
while ((locale = (char *)cupsArrayNext(languages)) != NULL)
|
||
cupsFilePrintf(outfile, " %s", locale);
|
||
cupsFilePuts(outfile, "\"\n");
|
||
}
|
||
|
||
while (cupsFileGets(infile, line, sizeof(line)))
|
||
{
|
||
if (strncmp(line, "*cupsLanguages:", 15))
|
||
cupsFilePrintf(outfile, "%s\n", line);
|
||
}
|
||
|
||
// Loop through the other PPD files we loaded to provide the translations...
|
||
for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
|
||
ppd;
|
||
ppd = (ppd_file_t *)cupsArrayNext(ppds))
|
||
{
|
||
// Output all of the UI text for this language...
|
||
int j, k, l; // Looping vars
|
||
ppd_group_t *g; // Option group
|
||
ppd_option_t *o; // Option
|
||
ppd_choice_t *c; // Choice
|
||
ppd_coption_t *co; // Custom option
|
||
ppd_cparam_t *cp; // Custom parameter
|
||
ppd_attr_t *attr; // PPD attribute
|
||
|
||
locale = ppd_locale(ppd);
|
||
|
||
cupsFilePrintf(outfile, "*%% %s localization\n", ppd->lang_version);
|
||
cupsFilePrintf(outfile, "*%s.Translation ModelName/%s: \"\"\n", locale,
|
||
ppd->modelname);
|
||
|
||
for (j = ppd->num_groups, g = ppd->groups; j > 0; j --, g ++)
|
||
{
|
||
cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
|
||
g->name, g->text);
|
||
|
||
for (k = g->num_options, o = g->options; k > 0; k --, o ++)
|
||
{
|
||
cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
|
||
o->keyword, o->text);
|
||
|
||
for (l = o->num_choices, c = o->choices; l > 0; l --, c ++)
|
||
cupsFilePrintf(outfile, "*%s.%s %s/%s: \"\"\n", locale,
|
||
o->keyword, c->choice, c->text);
|
||
|
||
if ((co = ppdFindCustomOption(ppd, o->keyword)) != NULL)
|
||
{
|
||
snprintf(line, sizeof(line), "Custom%s", o->keyword);
|
||
attr = ppdFindAttr(ppd, line, "True");
|
||
cupsFilePrintf(outfile, "*%s.Custom%s True/%s: \"\"\n", locale,
|
||
o->keyword, attr->text);
|
||
for (cp = ppdFirstCustomParam(co); cp; cp = ppdNextCustomParam(co))
|
||
cupsFilePrintf(outfile, "*%s.ParamCustom%s %s/%s: \"\"\n", locale,
|
||
o->keyword, cp->name, cp->text);
|
||
}
|
||
}
|
||
}
|
||
|
||
ppdClose(ppd);
|
||
}
|
||
|
||
cupsArrayDelete(ppds);
|
||
|
||
cupsFileClose(outfile);
|
||
|
||
// Return with no errors.
|
||
return (0);
|
||
}
|
||
|
||
|
||
//
|
||
// 'ppd_locale()' - Return the locale associated with a PPD file.
|
||
//
|
||
|
||
static const char * // O - Locale string
|
||
ppd_locale(ppd_file_t *ppd) // I - PPD file
|
||
{
|
||
int i; // Looping var
|
||
size_t vlen; // Length of LanguageVersion string
|
||
static char locale[255]; // Locale string
|
||
static struct // LanguageVersion translation table
|
||
{
|
||
const char *version, // LanguageVersion string */
|
||
*language; // Language code */
|
||
} languages[] =
|
||
{
|
||
{ "chinese", "zh" },
|
||
{ "czech", "cs" },
|
||
{ "danish", "da" },
|
||
{ "dutch", "nl" },
|
||
{ "english", "en" },
|
||
{ "finnish", "fi" },
|
||
{ "french", "fr" },
|
||
{ "german", "de" },
|
||
{ "greek", "el" },
|
||
{ "hungarian", "hu" },
|
||
{ "italian", "it" },
|
||
{ "japanese", "ja" },
|
||
{ "korean", "ko" },
|
||
{ "norwegian", "no" },
|
||
{ "polish", "pl" },
|
||
{ "portuguese", "pt" },
|
||
{ "russian", "ru" },
|
||
{ "simplified chinese", "zh_CN" },
|
||
{ "slovak", "sk" },
|
||
{ "spanish", "es" },
|
||
{ "swedish", "sv" },
|
||
{ "traditional chinese", "zh_TW" },
|
||
{ "turkish", "tr" }
|
||
};
|
||
|
||
|
||
for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
|
||
{
|
||
vlen = strlen(languages[i].version);
|
||
|
||
if (!_cups_strncasecmp(ppd->lang_version, languages[i].version, vlen))
|
||
{
|
||
if (ppd->lang_version[vlen] == '-' ||
|
||
ppd->lang_version[vlen] == '_')
|
||
snprintf(locale, sizeof(locale), "%s_%s", languages[i].language,
|
||
ppd->lang_version + vlen + 1);
|
||
else
|
||
strlcpy(locale, languages[i].language, sizeof(locale));
|
||
|
||
return (locale);
|
||
}
|
||
}
|
||
|
||
return (NULL);
|
||
}
|
||
|
||
//
|
||
// 'usage()' - Show usage and exit.
|
||
//
|
||
|
||
static void
|
||
usage(void)
|
||
{
|
||
_cupsLangPuts(stdout, _("Usage: ppdmerge [options] filename.ppd [ ... "
|
||
"filenameN.ppd ]"));
|
||
_cupsLangPuts(stdout, _("Options:"));
|
||
_cupsLangPuts(stdout, _(" -o filename.ppd[.gz] Set output file "
|
||
"(otherwise stdout)."));
|
||
|
||
exit(1);
|
||
}
|