1// 2// "$Id: ppdc.cxx 3796 2012-04-23 22:54:48Z msweet $" 3// 4// PPD file compiler main entry for the CUPS PPD Compiler. 5// 6// Copyright 2007-2012 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 compiler. 18// usage() - Show usage and exit. 19// 20 21// 22// Include necessary headers... 23// 24 25#include "ppdc-private.h" 26#include <unistd.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29 30 31// 32// Local functions... 33// 34 35static void usage(void); 36 37 38// 39// 'main()' - Main entry for the PPD compiler. 40// 41 42int // O - Exit status 43main(int argc, // I - Number of command-line arguments 44 char *argv[]) // I - Command-line arguments 45{ 46 int i, j; // Looping vars 47 ppdcCatalog *catalog; // Message catalog 48 const char *outdir; // Output directory 49 ppdcSource *src; // PPD source file data 50 ppdcDriver *d; // Current driver 51 cups_file_t *fp; // PPD file 52 char *opt, // Current option 53 *value, // Value in option 54 *outname, // Output filename 55 make_model[1024], 56 // Make and model 57 pcfilename[1024], 58 // Lowercase pcfilename 59 filename[1024]; // PPD filename 60 int comp, // Compress 61 do_test, // Test PPD files 62 single_language,// Generate single-language files 63 use_model_name, // Use ModelName for filename 64 verbose; // Verbosity 65 ppdcLineEnding le; // Line ending to use 66 ppdcArray *locales; // List of locales 67 cups_array_t *filenames; // List of generated filenames 68 69 70 _cupsSetLocale(argv); 71 72 // Scan the command-line... 73 catalog = NULL; 74 comp = 0; 75 do_test = 0; 76 le = PPDC_LFONLY; 77 locales = NULL; 78 outdir = "ppd"; 79 single_language = 0; 80 src = new ppdcSource(); 81 use_model_name = 0; 82 verbose = 0; 83 filenames = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); 84 85 for (i = 1; i < argc; i ++) 86 if (argv[i][0] == '-') 87 { 88 for (opt = argv[i] + 1; *opt; opt ++) 89 switch (*opt) 90 { 91 case 'D' : // Define variable 92 i ++; 93 if (i >= argc) 94 usage(); 95 96 if ((value = strchr(argv[i], '=')) != NULL) 97 { 98 *value++ = '\0'; 99 100 src->set_variable(argv[i], value); 101 } 102 else 103 src->set_variable(argv[i], "1"); 104 break; 105 106 case 'I' : // Include directory... 107 i ++; 108 if (i >= argc) 109 usage(); 110 111 if (verbose > 1) 112 _cupsLangPrintf(stdout, 113 _("ppdc: Adding include directory \"%s\"."), 114 argv[i]); 115 116 ppdcSource::add_include(argv[i]); 117 break; 118 119 case 'c' : // Message catalog... 120 i ++; 121 if (i >= argc) 122 usage(); 123 124 if (verbose > 1) 125 _cupsLangPrintf(stdout, 126 _("ppdc: Loading messages from \"%s\"."), 127 argv[i]); 128 129 if (!catalog) 130 catalog = new ppdcCatalog("en"); 131 132 if (catalog->load_messages(argv[i])) 133 { 134 _cupsLangPrintf(stderr, 135 _("ppdc: Unable to load localization file " 136 "\"%s\" - %s"), argv[i], strerror(errno)); 137 return (1); 138 } 139 break; 140 141 case 'd' : // Output directory... 142 i ++; 143 if (i >= argc) 144 usage(); 145 146 if (verbose > 1) 147 _cupsLangPrintf(stdout, 148 _("ppdc: Writing PPD files to directory " 149 "\"%s\"."), argv[i]); 150 151 outdir = argv[i]; 152 break; 153 154 case 'l' : // Language(s)... 155 i ++; 156 if (i >= argc) 157 usage(); 158 159 if (strchr(argv[i], ',')) 160 { 161 // Comma-delimited list of languages... 162 char temp[1024], // Copy of language list 163 *start, // Start of current locale name 164 *end; // End of current locale name 165 166 167 locales = new ppdcArray(); 168 169 strlcpy(temp, argv[i], sizeof(temp)); 170 for (start = temp; *start; start = end) 171 { 172 if ((end = strchr(start, ',')) != NULL) 173 *end++ = '\0'; 174 else 175 end = start + strlen(start); 176 177 if (end > start) 178 locales->add(new ppdcString(start)); 179 } 180 } 181 else 182 { 183 single_language = 1; 184 185 if (verbose > 1) 186 _cupsLangPrintf(stdout, 187 _("ppdc: Loading messages for locale " 188 "\"%s\"."), argv[i]); 189 190 if (catalog) 191 catalog->release(); 192 193 catalog = new ppdcCatalog(argv[i]); 194 195 if (catalog->messages->count == 0) 196 { 197 _cupsLangPrintf(stderr, 198 _("ppdc: Unable to find localization for " 199 "\"%s\" - %s"), argv[i], strerror(errno)); 200 return (1); 201 } 202 } 203 break; 204 205 case 'm' : // Use ModelName for filename 206 use_model_name = 1; 207 break; 208 209 case 't' : // Test PPDs instead of generating them 210 do_test = 1; 211 break; 212 213 case 'v' : // Be verbose... 214 verbose ++; 215 break; 216 217 case 'z' : // Compress files... 218 comp = 1; 219 break; 220 221 case '-' : // --option 222 if (!strcmp(opt, "-lf")) 223 { 224 le = PPDC_LFONLY; 225 opt += strlen(opt) - 1; 226 break; 227 } 228 else if (!strcmp(opt, "-cr")) 229 { 230 le = PPDC_CRONLY; 231 opt += strlen(opt) - 1; 232 break; 233 } 234 else if (!strcmp(opt, "-crlf")) 235 { 236 le = PPDC_CRLF; 237 opt += strlen(opt) - 1; 238 break; 239 } 240 241 default : // Unknown 242 usage(); 243 break; 244 } 245 } 246 else 247 { 248 // Open and load the driver info file... 249 if (verbose > 1) 250 _cupsLangPrintf(stdout, 251 _("ppdc: Loading driver information file \"%s\"."), 252 argv[i]); 253 254 src->read_file(argv[i]); 255 } 256 257 258 if (src->drivers->count > 0) 259 { 260 // Create the output directory... 261 if (mkdir(outdir, 0777)) 262 { 263 if (errno != EEXIST) 264 { 265 _cupsLangPrintf(stderr, 266 _("ppdc: Unable to create output directory %s: %s"), 267 outdir, strerror(errno)); 268 return (1); 269 } 270 } 271 272 // Write PPD files... 273 for (d = (ppdcDriver *)src->drivers->first(); 274 d; 275 d = (ppdcDriver *)src->drivers->next()) 276 { 277 if (do_test) 278 { 279 // Test the PPD file for this driver... 280 int pid, // Process ID 281 fds[2]; // Pipe file descriptors 282 283 284 if (pipe(fds)) 285 { 286 _cupsLangPrintf(stderr, 287 _("ppdc: Unable to create output pipes: %s"), 288 strerror(errno)); 289 return (1); 290 } 291 292 if ((pid = fork()) == 0) 293 { 294 // Child process comes here... 295 dup2(fds[0], 0); 296 297 close(fds[0]); 298 close(fds[1]); 299 300 execlp("cupstestppd", "cupstestppd", "-", (char *)0); 301 302 _cupsLangPrintf(stderr, 303 _("ppdc: Unable to execute cupstestppd: %s"), 304 strerror(errno)); 305 return (errno); 306 } 307 else if (pid < 0) 308 { 309 _cupsLangPrintf(stderr, _("ppdc: Unable to execute cupstestppd: %s"), 310 strerror(errno)); 311 return (errno); 312 } 313 314 close(fds[0]); 315 fp = cupsFileOpenFd(fds[1], "w"); 316 } 317 else 318 { 319 // Write the PPD file for this driver... 320 if (use_model_name) 321 { 322 if (!_cups_strncasecmp(d->model_name->value, d->manufacturer->value, 323 strlen(d->manufacturer->value))) 324 { 325 // Model name already starts with the manufacturer... 326 outname = d->model_name->value; 327 } 328 else 329 { 330 // Add manufacturer to the front of the model name... 331 snprintf(make_model, sizeof(make_model), "%s %s", 332 d->manufacturer->value, d->model_name->value); 333 outname = make_model; 334 } 335 } 336 else if (d->file_name) 337 outname = d->file_name->value; 338 else 339 outname = d->pc_file_name->value; 340 341 if (strstr(outname, ".PPD")) 342 { 343 // Convert PCFileName to lowercase... 344 for (j = 0; 345 outname[j] && j < (int)(sizeof(pcfilename) - 1); 346 j ++) 347 pcfilename[j] = tolower(outname[j] & 255); 348 349 pcfilename[j] = '\0'; 350 } 351 else 352 { 353 // Leave PCFileName as-is... 354 strlcpy(pcfilename, outname, sizeof(pcfilename)); 355 } 356 357 // Open the PPD file for writing... 358 if (comp) 359 snprintf(filename, sizeof(filename), "%s/%s.gz", outdir, pcfilename); 360 else 361 snprintf(filename, sizeof(filename), "%s/%s", outdir, pcfilename); 362 363 if (cupsArrayFind(filenames, filename)) 364 _cupsLangPrintf(stderr, 365 _("ppdc: Warning - overlapping filename \"%s\"."), 366 filename); 367 else 368 cupsArrayAdd(filenames, strdup(filename)); 369 370 fp = cupsFileOpen(filename, comp ? "w9" : "w"); 371 if (!fp) 372 { 373 _cupsLangPrintf(stderr, 374 _("ppdc: Unable to create PPD file \"%s\" - %s."), 375 filename, strerror(errno)); 376 return (1); 377 } 378 379 if (verbose) 380 _cupsLangPrintf(stdout, _("ppdc: Writing %s."), filename); 381 } 382 383 /* 384 * Write the PPD file... 385 */ 386 387 ppdcArray *templocales = locales; 388 389 if (!templocales && !single_language) 390 { 391 templocales = new ppdcArray(); 392 for (ppdcCatalog *tempcatalog = (ppdcCatalog *)src->po_files->first(); 393 tempcatalog; 394 tempcatalog = (ppdcCatalog *)src->po_files->next()) 395 { 396 tempcatalog->locale->retain(); 397 templocales->add(tempcatalog->locale); 398 } 399 } 400 401 if (d->write_ppd_file(fp, catalog, templocales, src, le)) 402 { 403 cupsFileClose(fp); 404 return (1); 405 } 406 407 if (templocales != locales) 408 templocales->release(); 409 410 cupsFileClose(fp); 411 } 412 } 413 else 414 usage(); 415 416 // Delete the printer driver information... 417 src->release(); 418 419 // Message catalog... 420 if (catalog) 421 catalog->release(); 422 423 // Return with no errors. 424 return (0); 425} 426 427 428// 429// 'usage()' - Show usage and exit. 430// 431 432static void 433usage(void) 434{ 435 _cupsLangPuts(stdout, _("Usage: ppdc [options] filename.drv [ ... " 436 "filenameN.drv ]")); 437 _cupsLangPuts(stdout, _("Options:")); 438 _cupsLangPuts(stdout, _(" -D name=value Set named variable to " 439 "value.")); 440 _cupsLangPuts(stdout, _(" -I include-dir Add include directory to " 441 "search path.")); 442 _cupsLangPuts(stdout, _(" -c catalog.po Load the specified " 443 "message catalog.")); 444 _cupsLangPuts(stdout, _(" -d output-dir Specify the output " 445 "directory.")); 446 _cupsLangPuts(stdout, _(" -l lang[,lang,...] Specify the output " 447 "language(s) (locale).")); 448 _cupsLangPuts(stdout, _(" -m Use the ModelName value " 449 "as the filename.")); 450 _cupsLangPuts(stdout, _(" -t Test PPDs instead of " 451 "generating them.")); 452 _cupsLangPuts(stdout, _(" -v Be verbose.")); 453 _cupsLangPuts(stdout, _(" -z Compress PPD files using " 454 "GNU zip.")); 455 _cupsLangPuts(stdout, _(" --cr End lines with CR (Mac " 456 "OS 9).")); 457 _cupsLangPuts(stdout, _(" --crlf End lines with CR + LF " 458 "(Windows).")); 459 _cupsLangPuts(stdout, _(" --lf End lines with LF " 460 "(UNIX/Linux/OS X).")); 461 462 exit(1); 463} 464 465 466// 467// End of "$Id: ppdc.cxx 3796 2012-04-23 22:54:48Z msweet $". 468// 469