1// 2// "$Id: ppdmerge.cxx 3277 2011-05-20 07:30:39Z msweet $" 3// 4// PPD file merge utility for the CUPS PPD Compiler. 5// 6// Copyright 2007-2011 by Apple Inc. 7// Copyright 2002-2007 by Easy Software Products. 8// 9// These coded instructions, statements, and computer programs are the 10// property of Apple Inc. and are protected by Federal copyright 11// law. Distribution and use rights are outlined in the file "LICENSE.txt" 12// which should have been included with this file. If this file is 13// file is missing or damaged, see the license at "http://www.cups.org/". 14// 15// Contents: 16// 17// main() - Main entry for the PPD merge utility. 18// ppd_locale() - Return the locale associated with a PPD file. 19// usage() - Show usage and exit. 20// 21 22// 23// Include necessary headers... 24// 25 26#include <cups/cups-private.h> 27#include <cups/ppd-private.h> 28#include <cups/array.h> 29 30 31// 32// Local functions... 33// 34 35static const char *ppd_locale(ppd_file_t *ppd); 36static void usage(void); 37 38 39// 40// 'main()' - Main entry for the PPD merge utility. 41// 42 43int // O - Exit status 44main(int argc, // I - Number of command-line arguments 45 char *argv[]) // I - Command-line arguments 46{ 47 int i; // Looping var 48 char *opt; // Current option 49 ppd_file_t *ppd; // PPD file 50 cups_array_t *ppds; // Array of PPD files 51 const char *inname, // First input filename 52 *outname; // Output filename (if any) 53 cups_file_t *infile, // Input file 54 *outfile; // Output file 55 cups_array_t *languages; // Languages in file 56 const char *locale; // Current locale 57 char line[1024]; // Line from file 58 59 60 _cupsSetLocale(argv); 61 62 // Scan the command-line... 63 inname = NULL; 64 outname = NULL; 65 outfile = NULL; 66 languages = NULL; 67 ppds = cupsArrayNew(NULL, NULL); 68 69 for (i = 1; i < argc; i ++) 70 if (argv[i][0] == '-') 71 { 72 for (opt = argv[i] + 1; *opt; opt ++) 73 switch (*opt) 74 { 75 case 'o' : // Output file 76 if (outname) 77 usage(); 78 79 i ++; 80 if (i >= argc) 81 usage(); 82 83 outname = argv[i]; 84 break; 85 86 default : // Unknown 87 usage(); 88 break; 89 } 90 } 91 else 92 { 93 // Open and load the PPD file... 94 if ((infile = cupsFileOpen(argv[i], "r")) == NULL) 95 { 96 _cupsLangPrintf(stderr, _("%s: Unable to open %s: %s"), "ppdmerge", 97 argv[i], strerror(errno)); 98 return (1); 99 } 100 101 // Open the PPD file... 102 if ((ppd = ppdOpen2(infile)) == NULL) 103 { 104 ppd_status_t status; // PPD open status 105 int curline, // Current line 106 linenum; // Line number 107 108 109 status = ppdLastError(&linenum); 110 111 _cupsLangPrintf(stderr, 112 _("%s: Unable to open PPD file: %s on line %d."), 113 "ppdmerge", ppdErrorString(status), linenum); 114 cupsFileRewind(infile); 115 116 line[0] = '\0'; 117 curline = 0; 118 119 while (cupsFileGets(infile, line, sizeof(line))) 120 { 121 curline ++; 122 if (curline >= linenum) 123 break; 124 } 125 126 _cupsLangPrintf(stderr, "%d: %s", linenum, line); 127 128 cupsFileClose(infile); 129 return (1); 130 } 131 132 // Figure out the locale... 133 if ((locale = ppd_locale(ppd)) == NULL) 134 { 135 _cupsLangPrintf(stderr, 136 _("ppdmerge: Bad LanguageVersion \"%s\" in %s."), 137 ppd->lang_version, argv[i]); 138 cupsFileClose(infile); 139 ppdClose(ppd); 140 return (1); 141 } 142 143 if (!strcmp(locale, "en") && !inname && !outfile) 144 { 145 // Set the English PPD's filename... 146 inname = argv[i]; 147 languages = _ppdGetLanguages(ppd); 148 149 if (outname && !strcmp(inname, outname)) 150 { 151 // Rename input filename so that we don't overwrite it... 152 char bckname[1024]; // Backup filename 153 154 155 snprintf(bckname, sizeof(bckname), "%s.bck", inname); 156 157 if (rename(inname, bckname)) 158 { 159 _cupsLangPrintf(stderr, 160 _("ppdmerge: Unable to backup %s to %s - %s"), 161 inname, bckname, strerror(errno)); 162 return (1); 163 } 164 165 inname = bckname; 166 } 167 } 168 else if (strcmp(locale, "en")) 169 { 170 // Save this PPD for later processing... 171 cupsArrayAdd(ppds, ppd); 172 } 173 else 174 { 175 // Don't need this PPD... 176 _cupsLangPrintf(stderr, _("ppdmerge: Ignoring PPD file %s."), 177 argv[i]); 178 ppdClose(ppd); 179 } 180 181 // Close and move on... 182 cupsFileClose(infile); 183 } 184 185 // If no PPDs have been loaded, display the program usage message. 186 if (!inname) 187 usage(); 188 189 // Loop through the PPD files we loaded to generate a new language list... 190 if (!languages) 191 languages = cupsArrayNew((cups_array_func_t)strcmp, NULL); 192 193 for (ppd = (ppd_file_t *)cupsArrayFirst(ppds); 194 ppd; 195 ppd = (ppd_file_t *)cupsArrayNext(ppds)) 196 { 197 locale = ppd_locale(ppd); 198 199 if (cupsArrayFind(languages, (void *)locale)) 200 { 201 // Already have this language, remove the PPD from the list. 202 ppdClose(ppd); 203 cupsArrayRemove(ppds, ppd); 204 } 205 else 206 cupsArrayAdd(languages, (void *)locale); 207 } 208 209 // Copy the English PPD starting with a cupsLanguages line... 210 infile = cupsFileOpen(inname, "r"); 211 212 if (outname) 213 { 214 const char *ext = strrchr(outname, '.'); 215 if (ext && !strcmp(ext, ".gz")) 216 outfile = cupsFileOpen(outname, "w9"); 217 else 218 outfile = cupsFileOpen(outname, "w"); 219 } 220 else 221 outfile = cupsFileStdout(); 222 223 cupsFileGets(infile, line, sizeof(line)); 224 cupsFilePrintf(outfile, "%s\n", line); 225 if ((locale = (char *)cupsArrayFirst(languages)) != NULL) 226 { 227 cupsFilePrintf(outfile, "*cupsLanguages: \"%s", locale); 228 while ((locale = (char *)cupsArrayNext(languages)) != NULL) 229 cupsFilePrintf(outfile, " %s", locale); 230 cupsFilePuts(outfile, "\"\n"); 231 } 232 233 while (cupsFileGets(infile, line, sizeof(line))) 234 { 235 if (strncmp(line, "*cupsLanguages:", 15)) 236 cupsFilePrintf(outfile, "%s\n", line); 237 } 238 239 // Loop through the other PPD files we loaded to provide the translations... 240 for (ppd = (ppd_file_t *)cupsArrayFirst(ppds); 241 ppd; 242 ppd = (ppd_file_t *)cupsArrayNext(ppds)) 243 { 244 // Output all of the UI text for this language... 245 int j, k, l; // Looping vars 246 ppd_group_t *g; // Option group 247 ppd_option_t *o; // Option 248 ppd_choice_t *c; // Choice 249 ppd_coption_t *co; // Custom option 250 ppd_cparam_t *cp; // Custom parameter 251 ppd_attr_t *attr; // PPD attribute 252 253 locale = ppd_locale(ppd); 254 255 cupsFilePrintf(outfile, "*%% %s localization\n", ppd->lang_version); 256 cupsFilePrintf(outfile, "*%s.Translation ModelName/%s: \"\"\n", locale, 257 ppd->modelname); 258 259 for (j = ppd->num_groups, g = ppd->groups; j > 0; j --, g ++) 260 { 261 cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale, 262 g->name, g->text); 263 264 for (k = g->num_options, o = g->options; k > 0; k --, o ++) 265 { 266 cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale, 267 o->keyword, o->text); 268 269 for (l = o->num_choices, c = o->choices; l > 0; l --, c ++) 270 cupsFilePrintf(outfile, "*%s.%s %s/%s: \"\"\n", locale, 271 o->keyword, c->choice, c->text); 272 273 if ((co = ppdFindCustomOption(ppd, o->keyword)) != NULL) 274 { 275 snprintf(line, sizeof(line), "Custom%s", o->keyword); 276 attr = ppdFindAttr(ppd, line, "True"); 277 cupsFilePrintf(outfile, "*%s.Custom%s True/%s: \"\"\n", locale, 278 o->keyword, attr->text); 279 for (cp = ppdFirstCustomParam(co); cp; cp = ppdNextCustomParam(co)) 280 cupsFilePrintf(outfile, "*%s.ParamCustom%s %s/%s: \"\"\n", locale, 281 o->keyword, cp->name, cp->text); 282 } 283 } 284 } 285 286 ppdClose(ppd); 287 } 288 289 cupsArrayDelete(ppds); 290 291 cupsFileClose(outfile); 292 293 // Return with no errors. 294 return (0); 295} 296 297 298// 299// 'ppd_locale()' - Return the locale associated with a PPD file. 300// 301 302static const char * // O - Locale string 303ppd_locale(ppd_file_t *ppd) // I - PPD file 304{ 305 int i, // Looping var 306 vlen; // Length of LanguageVersion string 307 static char locale[255]; // Locale string 308 static struct // LanguageVersion translation table 309 { 310 const char *version, // LanguageVersion string */ 311 *language; // Language code */ 312 } languages[] = 313 { 314 { "chinese", "zh" }, 315 { "czech", "cs" }, 316 { "danish", "da" }, 317 { "dutch", "nl" }, 318 { "english", "en" }, 319 { "finnish", "fi" }, 320 { "french", "fr" }, 321 { "german", "de" }, 322 { "greek", "el" }, 323 { "hungarian", "hu" }, 324 { "italian", "it" }, 325 { "japanese", "ja" }, 326 { "korean", "ko" }, 327 { "norwegian", "no" }, 328 { "polish", "pl" }, 329 { "portuguese", "pt" }, 330 { "russian", "ru" }, 331 { "simplified chinese", "zh_CN" }, 332 { "slovak", "sk" }, 333 { "spanish", "es" }, 334 { "swedish", "sv" }, 335 { "traditional chinese", "zh_TW" }, 336 { "turkish", "tr" } 337 }; 338 339 340 for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++) 341 { 342 vlen = strlen(languages[i].version); 343 344 if (!_cups_strncasecmp(ppd->lang_version, languages[i].version, vlen)) 345 { 346 if (ppd->lang_version[vlen] == '-' || 347 ppd->lang_version[vlen] == '_') 348 snprintf(locale, sizeof(locale), "%s_%s", languages[i].language, 349 ppd->lang_version + vlen + 1); 350 else 351 strlcpy(locale, languages[i].language, sizeof(locale)); 352 353 return (locale); 354 } 355 } 356 357 return (NULL); 358} 359 360// 361// 'usage()' - Show usage and exit. 362// 363 364static void 365usage(void) 366{ 367 _cupsLangPuts(stdout, _("Usage: ppdmerge [options] filename.ppd [ ... " 368 "filenameN.ppd ]")); 369 _cupsLangPuts(stdout, _("Options:")); 370 _cupsLangPuts(stdout, _(" -o filename.ppd[.gz] Set output file " 371 "(otherwise stdout).")); 372 373 exit(1); 374} 375 376 377// 378// End of "$Id: ppdmerge.cxx 3277 2011-05-20 07:30:39Z msweet $". 379// 380