#include <cups/ppd-private.h>
#include <cups/cups.h>
#include <cups/array.h>
#include <cups/string.h>
#include <cups/i18n.h>
#include <errno.h>
static const char *ppd_locale(ppd_file_t *ppd);
static void usage(void);
int main(int argc, char *argv[]) {
int i; char *opt; ppd_file_t *ppd; cups_array_t *ppds; const char *inname, *outname; cups_file_t *infile, *outfile; cups_array_t *languages; const char *locale; char line[1024];
_cupsSetLocale(argv);
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' : if (outname)
usage();
i ++;
if (i >= argc)
usage();
outname = argv[i];
break;
default : usage();
break;
}
}
else
{
if ((infile = cupsFileOpen(argv[i], "r")) == NULL)
{
_cupsLangPrintf(stderr, _("%s: Unable to open %s: %s\n"), "ppdmerge",
argv[i], strerror(errno));
return (1);
}
if ((ppd = ppdOpen2(infile)) == NULL)
{
ppd_status_t status; int linenum;
status = ppdLastError(&linenum);
_cupsLangPrintf(stderr, _("%s: Unable to open PPD file: %s on line %d.\n"),
"ppdmerge", ppdErrorString(status), linenum);
_cupsLangPrintf(stderr, "%d: ", linenum);
cupsFileRewind(infile);
line[0] = '\0';
while (cupsFileGets(infile, line, sizeof(line)))
{
linenum --;
if (!linenum)
break;
}
_cupsLangPrintf(stderr, "%s\n", line);
cupsFileClose(infile);
return (1);
}
if ((locale = ppd_locale(ppd)) == NULL)
{
_cupsLangPrintf(stderr,
_("ppdmerge: Bad LanguageVersion \"%s\" in %s!\n"),
ppd->lang_version, argv[i]);
cupsFileClose(infile);
ppdClose(ppd);
return (1);
}
if (!strcmp(locale, "en") && !inname && !outfile)
{
inname = argv[i];
languages = _ppdGetLanguages(ppd);
if (outname && !strcmp(inname, outname))
{
char bckname[1024];
snprintf(bckname, sizeof(bckname), "%s.bck", inname);
if (rename(inname, bckname))
{
_cupsLangPrintf(stderr,
_("ppdmerge: Unable to backup %s to %s- %s\n"),
inname, bckname, strerror(errno));
return (1);
}
inname = bckname;
}
}
else if (strcmp(locale, "en"))
{
cupsArrayAdd(ppds, ppd);
}
else
{
_cupsLangPrintf(stderr, _("ppdmerge: Ignoring PPD file %s...\n"),
argv[i]);
ppdClose(ppd);
}
cupsFileClose(infile);
}
if (!inname)
usage();
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))
{
ppdClose(ppd);
cupsArrayRemove(ppds, ppd);
}
else
cupsArrayAdd(languages, (void *)locale);
}
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);
}
for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
ppd;
ppd = (ppd_file_t *)cupsArrayNext(ppds))
{
int j, k, l; ppd_group_t *g; ppd_option_t *o; ppd_choice_t *c; ppd_coption_t *co; ppd_cparam_t *cp; ppd_attr_t *attr;
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 (0);
}
static const char * ppd_locale(ppd_file_t *ppd) {
int i, vlen; static char locale[255]; static struct {
const char *version, *language; } 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 (!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);
}
static void
usage(void)
{
_cupsLangPuts(stdout,
_("Usage: ppdmerge [options] filename.ppd "
"[ ... filenameN.ppd ]\n"
"Options:\n"
" -o filename.ppd[.gz]\n"));
exit(1);
}