]> git.ipfire.org Git - thirdparty/cups.git/blame - ppdc/ppdc.cxx
Merge changes from CUPS 1.5b1-r9774.
[thirdparty/cups.git] / ppdc / ppdc.cxx
CommitLineData
ac884b6a
MS
1//
2// "$Id$"
3//
4// PPD file compiler main entry for the CUPS PPD Compiler.
5//
84315f46 6// Copyright 2007-2011 by Apple Inc.
ac884b6a
MS
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
38e73f87 25#include "ppdc-private.h"
bdd6c45b 26#include <unistd.h>
ac884b6a
MS
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
bdd6c45b 54 *outname, // Output filename
41681883
MS
55 make_model[1024],
56 // Make and model
ac884b6a
MS
57 pcfilename[1024],
58 // Lowercase pcfilename
59 filename[1024]; // PPD filename
bdd6c45b
MS
60 int comp, // Compress
61 do_test, // Test PPD files
5a6b583a 62 single_language,// Generate single-language files
bdd6c45b
MS
63 use_model_name, // Use ModelName for filename
64 verbose; // Verbosity
ac884b6a 65 ppdcLineEnding le; // Line ending to use
bdd6c45b 66 ppdcArray *locales; // List of locales
18ecb428 67 cups_array_t *filenames; // List of generated filenames
ac884b6a
MS
68
69
61cf44e2
MS
70 _cupsSetLocale(argv);
71
ac884b6a 72 // Scan the command-line...
5a6b583a
MS
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)strcasecmp, NULL);
ac884b6a
MS
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 {
bdd6c45b
MS
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)
61cf44e2 112 _cupsLangPrintf(stdout,
0837b7e8 113 _("ppdc: Adding include directory \"%s\"."),
61cf44e2 114 argv[i]);
bdd6c45b
MS
115
116 ppdcSource::add_include(argv[i]);
117 break;
118
ac884b6a
MS
119 case 'c' : // Message catalog...
120 i ++;
121 if (i >= argc)
122 usage();
123
124 if (verbose > 1)
61cf44e2 125 _cupsLangPrintf(stdout,
0837b7e8 126 _("ppdc: Loading messages from \"%s\"."),
61cf44e2 127 argv[i]);
ac884b6a
MS
128
129 if (!catalog)
130 catalog = new ppdcCatalog("en");
131
132 if (catalog->load_messages(argv[i]))
133 {
61cf44e2
MS
134 _cupsLangPrintf(stderr,
135 _("ppdc: Unable to load localization file "
0837b7e8 136 "\"%s\" - %s"), argv[i], strerror(errno));
ac884b6a
MS
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)
61cf44e2
MS
147 _cupsLangPrintf(stdout,
148 _("ppdc: Writing PPD files to directory "
0837b7e8 149 "\"%s\"."), argv[i]);
ac884b6a
MS
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 {
5a6b583a
MS
183 single_language = 1;
184
ac884b6a 185 if (verbose > 1)
61cf44e2
MS
186 _cupsLangPrintf(stdout,
187 _("ppdc: Loading messages for locale "
0837b7e8 188 "\"%s\"."), argv[i]);
ac884b6a
MS
189
190 if (catalog)
e4572d57 191 catalog->release();
ac884b6a
MS
192
193 catalog = new ppdcCatalog(argv[i]);
194
195 if (catalog->messages->count == 0)
196 {
61cf44e2
MS
197 _cupsLangPrintf(stderr,
198 _("ppdc: Unable to find localization for "
0837b7e8 199 "\"%s\" - %s"), argv[i], strerror(errno));
ac884b6a
MS
200 return (1);
201 }
202 }
203 break;
204
bdd6c45b
MS
205 case 'm' : // Use ModelName for filename
206 use_model_name = 1;
207 break;
ac884b6a 208
bdd6c45b
MS
209 case 't' : // Test PPDs instead of generating them
210 do_test = 1;
ac884b6a
MS
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)
61cf44e2 250 _cupsLangPrintf(stdout,
0837b7e8 251 _("ppdc: Loading driver information file \"%s\"."),
61cf44e2 252 argv[i]);
ac884b6a
MS
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 {
61cf44e2 265 _cupsLangPrintf(stderr,
0837b7e8 266 _("ppdc: Unable to create output directory %s: %s"),
ac884b6a
MS
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 {
bdd6c45b 277 if (do_test)
ac884b6a 278 {
bdd6c45b
MS
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 {
61cf44e2 286 _cupsLangPrintf(stderr,
0837b7e8 287 _("ppdc: Unable to create output pipes: %s"),
61cf44e2 288 strerror(errno));
bdd6c45b
MS
289 return (1);
290 }
291
292 if ((pid = fork()) == 0)
293 {
294 // Child process comes here...
97c9a8d7 295 dup2(fds[0], 0);
bdd6c45b
MS
296
297 close(fds[0]);
298 close(fds[1]);
299
300 execlp("cupstestppd", "cupstestppd", "-", (char *)0);
301
61cf44e2 302 _cupsLangPrintf(stderr,
0837b7e8 303 _("ppdc: Unable to execute cupstestppd: %s"),
61cf44e2 304 strerror(errno));
bdd6c45b
MS
305 return (errno);
306 }
307 else if (pid < 0)
308 {
0837b7e8 309 _cupsLangPrintf(stderr, _("ppdc: Unable to execute cupstestppd: %s"),
61cf44e2 310 strerror(errno));
bdd6c45b
MS
311 return (errno);
312 }
ac884b6a 313
bdd6c45b
MS
314 close(fds[0]);
315 fp = cupsFileOpenFd(fds[1], "w");
ac884b6a
MS
316 }
317 else
318 {
bdd6c45b
MS
319 // Write the PPD file for this driver...
320 if (use_model_name)
41681883
MS
321 {
322 if (!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 }
bdd6c45b
MS
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);
ac884b6a 348
bdd6c45b
MS
349 pcfilename[j] = '\0';
350 }
351 else
352 {
353 // Leave PCFileName as-is...
354 strlcpy(pcfilename, outname, sizeof(pcfilename));
355 }
ac884b6a 356
bdd6c45b
MS
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
18ecb428
MS
363 if (cupsArrayFind(filenames, filename))
364 _cupsLangPrintf(stderr,
0837b7e8 365 _("ppdc: Warning - overlapping filename \"%s\"."),
18ecb428
MS
366 filename);
367 else
368 cupsArrayAdd(filenames, strdup(filename));
369
bdd6c45b
MS
370 fp = cupsFileOpen(filename, comp ? "w9" : "w");
371 if (!fp)
372 {
61cf44e2 373 _cupsLangPrintf(stderr,
0837b7e8 374 _("ppdc: Unable to create PPD file \"%s\" - %s."),
61cf44e2 375 filename, strerror(errno));
bdd6c45b
MS
376 return (1);
377 }
378
379 if (verbose)
0837b7e8 380 _cupsLangPrintf(stdout, _("ppdc: Writing %s."), filename);
ac884b6a
MS
381 }
382
bdd6c45b
MS
383 /*
384 * Write the PPD file...
385 */
ac884b6a 386
97c9a8d7
MS
387 ppdcArray *templocales = locales;
388
5a6b583a 389 if (!templocales && !single_language)
97c9a8d7
MS
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))
ac884b6a
MS
402 {
403 cupsFileClose(fp);
404 return (1);
405 }
406
97c9a8d7
MS
407 if (templocales != locales)
408 templocales->release();
409
ac884b6a
MS
410 cupsFileClose(fp);
411 }
412 }
413 else
414 usage();
415
416 // Delete the printer driver information...
e4572d57 417 src->release();
ac884b6a
MS
418
419 // Message catalog...
420 if (catalog)
e4572d57 421 catalog->release();
ac884b6a
MS
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{
0837b7e8
MS
435 _cupsLangPuts(stdout, _("Usage: ppdc [options] filename.drv [ ... "
436 "filenameN.drv ]"));
437 _cupsLangPuts(stdout, _("Options:"));
84315f46 438 _cupsLangPuts(stdout, _(" -D name=value Set named variable to "
0837b7e8 439 "value."));
84315f46 440 _cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
0837b7e8 441 "search path."));
84315f46
MS
442 _cupsLangPuts(stdout, _(" -c catalog.po Load the specified "
443 "message catalog."));
444 _cupsLangPuts(stdout, _(" -d output-dir Specify the output "
0837b7e8 445 "directory."));
84315f46 446 _cupsLangPuts(stdout, _(" -l lang[,lang,...] Specify the output "
0837b7e8 447 "language(s) (locale)."));
84315f46
MS
448 _cupsLangPuts(stdout, _(" -m Use the ModelName value "
449 "as the filename."));
450 _cupsLangPuts(stdout, _(" -t Test PPDs instead of "
0837b7e8 451 "generating them."));
84315f46 452 _cupsLangPuts(stdout, _(" -v Be verbose (more v's for "
0837b7e8 453 "more verbosity)."));
84315f46
MS
454 _cupsLangPuts(stdout, _(" -z Compress PPD files using "
455 "GNU zip."));
456 _cupsLangPuts(stdout, _(" --cr End lines with CR (Mac "
457 "OS 9)."));
458 _cupsLangPuts(stdout, _(" --crlf End lines with CR + LF "
0837b7e8 459 "(Windows)."));
84315f46
MS
460 _cupsLangPuts(stdout, _(" --lf End lines with LF "
461 "(UNIX/Linux/Mac OS X)."));
ac884b6a
MS
462
463 exit(1);
464}
465
466
467//
468// End of "$Id$".
469//