]> git.ipfire.org Git - thirdparty/cups.git/blame - ppdc/ppdc.cxx
Don't create the full name twice (<rdar://problem/23144358>)
[thirdparty/cups.git] / ppdc / ppdc.cxx
CommitLineData
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
30static void usage(void);
31
32
33//
34// 'main()' - Main entry for the PPD compiler.
35//
36
37int // O - Exit status
38main(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
427static void
428usage(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//