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