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