]> git.ipfire.org Git - thirdparty/cups.git/blob - ppdc/ppdc.cxx
Don't create the full name twice (<rdar://problem/23144358>)
[thirdparty/cups.git] / ppdc / ppdc.cxx
1 //
2 // "$Id$"
3 //
4 // PPD file compiler main entry for the CUPS PPD Compiler.
5 //
6 // Copyright 2007-2014 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
16 //
17 // Include necessary headers...
18 //
19
20 #include "ppdc-private.h"
21 #include <unistd.h>
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
49 *outname, // Output filename
50 make_model[1024],
51 // Make and model
52 pcfilename[1024],
53 // Lowercase pcfilename
54 filename[1024]; // PPD filename
55 int comp, // Compress
56 do_test, // Test PPD files
57 single_language,// Generate single-language files
58 use_model_name, // Use ModelName for filename
59 verbose; // Verbosity
60 ppdcLineEnding le; // Line ending to use
61 ppdcArray *locales; // List of locales
62 cups_array_t *filenames; // List of generated filenames
63
64
65 _cupsSetLocale(argv);
66
67 // Scan the command-line...
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;
78 filenames = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
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 {
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)
107 _cupsLangPrintf(stdout,
108 _("ppdc: Adding include directory \"%s\"."),
109 argv[i]);
110
111 ppdcSource::add_include(argv[i]);
112 break;
113
114 case 'c' : // Message catalog...
115 i ++;
116 if (i >= argc)
117 usage();
118
119 if (verbose > 1)
120 _cupsLangPrintf(stdout,
121 _("ppdc: Loading messages from \"%s\"."),
122 argv[i]);
123
124 if (!catalog)
125 catalog = new ppdcCatalog("en");
126
127 if (catalog->load_messages(argv[i]))
128 {
129 _cupsLangPrintf(stderr,
130 _("ppdc: Unable to load localization file "
131 "\"%s\" - %s"), argv[i], strerror(errno));
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)
142 _cupsLangPrintf(stdout,
143 _("ppdc: Writing PPD files to directory "
144 "\"%s\"."), argv[i]);
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 {
178 single_language = 1;
179
180 if (verbose > 1)
181 _cupsLangPrintf(stdout,
182 _("ppdc: Loading messages for locale "
183 "\"%s\"."), argv[i]);
184
185 if (catalog)
186 catalog->release();
187
188 catalog = new ppdcCatalog(argv[i]);
189
190 if (catalog->messages->count == 0 && strcmp(argv[i], "en"))
191 {
192 _cupsLangPrintf(stderr,
193 _("ppdc: Unable to find localization for "
194 "\"%s\" - %s"), argv[i], strerror(errno));
195 return (1);
196 }
197 }
198 break;
199
200 case 'm' : // Use ModelName for filename
201 use_model_name = 1;
202 break;
203
204 case 't' : // Test PPDs instead of generating them
205 do_test = 1;
206 break;
207
208 case 'v' : // Be verbose...
209 verbose ++;
210 break;
211
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 }
235
236 default : // Unknown
237 usage();
238 break;
239 }
240 }
241 else
242 {
243 // Open and load the driver info file...
244 if (verbose > 1)
245 _cupsLangPrintf(stdout,
246 _("ppdc: Loading driver information file \"%s\"."),
247 argv[i]);
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 {
260 _cupsLangPrintf(stderr,
261 _("ppdc: Unable to create output directory %s: %s"),
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 {
272 if (do_test)
273 {
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 {
281 _cupsLangPrintf(stderr,
282 _("ppdc: Unable to create output pipes: %s"),
283 strerror(errno));
284 return (1);
285 }
286
287 if ((pid = fork()) == 0)
288 {
289 // Child process comes here...
290 dup2(fds[0], 0);
291
292 close(fds[0]);
293 close(fds[1]);
294
295 execlp("cupstestppd", "cupstestppd", "-", (char *)0);
296
297 _cupsLangPrintf(stderr,
298 _("ppdc: Unable to execute cupstestppd: %s"),
299 strerror(errno));
300 return (errno);
301 }
302 else if (pid < 0)
303 {
304 _cupsLangPrintf(stderr, _("ppdc: Unable to execute cupstestppd: %s"),
305 strerror(errno));
306 return (errno);
307 }
308
309 close(fds[0]);
310 fp = cupsFileOpenFd(fds[1], "w");
311 }
312 else
313 {
314 // Write the PPD file for this driver...
315 if (use_model_name)
316 {
317 if (!_cups_strncasecmp(d->model_name->value, d->manufacturer->value,
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 }
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 ++)
342 pcfilename[j] = (char)tolower(outname[j] & 255);
343
344 pcfilename[j] = '\0';
345 }
346 else
347 {
348 // Leave PCFileName as-is...
349 strlcpy(pcfilename, outname, sizeof(pcfilename));
350 }
351
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
358 if (cupsArrayFind(filenames, filename))
359 _cupsLangPrintf(stderr,
360 _("ppdc: Warning - overlapping filename \"%s\"."),
361 filename);
362 else
363 cupsArrayAdd(filenames, strdup(filename));
364
365 fp = cupsFileOpen(filename, comp ? "w9" : "w");
366 if (!fp)
367 {
368 _cupsLangPrintf(stderr,
369 _("ppdc: Unable to create PPD file \"%s\" - %s."),
370 filename, strerror(errno));
371 return (1);
372 }
373
374 if (verbose)
375 _cupsLangPrintf(stdout, _("ppdc: Writing %s."), filename);
376 }
377
378 /*
379 * Write the PPD file...
380 */
381
382 ppdcArray *templocales = locales;
383
384 if (!templocales && !single_language)
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))
397 {
398 cupsFileClose(fp);
399 return (1);
400 }
401
402 if (templocales != locales)
403 templocales->release();
404
405 cupsFileClose(fp);
406 }
407 }
408 else
409 usage();
410
411 // Delete the printer driver information...
412 src->release();
413
414 // Message catalog...
415 if (catalog)
416 catalog->release();
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 {
430 _cupsLangPuts(stdout, _("Usage: ppdc [options] filename.drv [ ... "
431 "filenameN.drv ]"));
432 _cupsLangPuts(stdout, _("Options:"));
433 _cupsLangPuts(stdout, _(" -D name=value Set named variable to "
434 "value."));
435 _cupsLangPuts(stdout, _(" -I include-dir Add include directory to "
436 "search path."));
437 _cupsLangPuts(stdout, _(" -c catalog.po Load the specified "
438 "message catalog."));
439 _cupsLangPuts(stdout, _(" -d output-dir Specify the output "
440 "directory."));
441 _cupsLangPuts(stdout, _(" -l lang[,lang,...] Specify the output "
442 "language(s) (locale)."));
443 _cupsLangPuts(stdout, _(" -m Use the ModelName value "
444 "as the filename."));
445 _cupsLangPuts(stdout, _(" -t Test PPDs instead of "
446 "generating them."));
447 _cupsLangPuts(stdout, _(" -v Be verbose."));
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 "
453 "(Windows)."));
454 _cupsLangPuts(stdout, _(" --lf End lines with LF "
455 "(UNIX/Linux/OS X)."));
456
457 exit(1);
458 }
459
460
461 //
462 // End of "$Id$".
463 //