Blame ppdc/ppdmerge.cxx

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