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