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