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.

362 lines
8.9 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 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);
//
// '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();
break;
}
}
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);
}