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