]> git.ipfire.org Git - thirdparty/cups.git/blame - ppdc/ppdmerge.cxx
Don't generate certificates that expire on Feb 29th (Issue #5643)
[thirdparty/cups.git] / ppdc / ppdmerge.cxx
CommitLineData
ac884b6a 1//
7e86f2f6 2// PPD file merge utility for the CUPS PPD Compiler.
ac884b6a 3//
70bdce16
MS
4// Copyright © 2007-2018 by Apple Inc.
5// Copyright © 2002-2007 by Easy Software Products.
ac884b6a 6//
70bdce16
MS
7// Licensed under Apache License v2.0. See the file "LICENSE" for more
8// information.
ac884b6a
MS
9//
10
11//
12// Include necessary headers...
13//
14
71e16022 15#include <cups/cups-private.h>
61cf44e2 16#include <cups/ppd-private.h>
ac884b6a 17#include <cups/array.h>
ac884b6a
MS
18
19
20//
21// Local functions...
22//
23
24static const char *ppd_locale(ppd_file_t *ppd);
25static void usage(void);
26
27
28//
29// 'main()' - Main entry for the PPD merge utility.
30//
31
32int // O - Exit status
33main(int argc, // I - Number of command-line arguments
34 char *argv[]) // I - Command-line arguments
35{
36 int i; // Looping var
37 char *opt; // Current option
38 ppd_file_t *ppd; // PPD file
39 cups_array_t *ppds; // Array of PPD files
40 const char *inname, // First input filename
41 *outname; // Output filename (if any)
70bdce16 42 char bckname[1024]; // Backup filename
ac884b6a
MS
43 cups_file_t *infile, // Input file
44 *outfile; // Output file
61cf44e2
MS
45 cups_array_t *languages; // Languages in file
46 const char *locale; // Current locale
47 char line[1024]; // Line from file
ac884b6a
MS
48
49
61cf44e2
MS
50 _cupsSetLocale(argv);
51
ac884b6a 52 // Scan the command-line...
61cf44e2
MS
53 inname = NULL;
54 outname = NULL;
55 outfile = NULL;
56 languages = NULL;
57 ppds = cupsArrayNew(NULL, NULL);
ac884b6a
MS
58
59 for (i = 1; i < argc; i ++)
60 if (argv[i][0] == '-')
61 {
62 for (opt = argv[i] + 1; *opt; opt ++)
63 switch (*opt)
64 {
65 case 'o' : // Output file
66 if (outname)
67 usage();
68
69 i ++;
70 if (i >= argc)
71 usage();
72
73 outname = argv[i];
74 break;
75
76 default : // Unknown
77 usage();
78 break;
79 }
80 }
81 else
82 {
61cf44e2 83 // Open and load the PPD file...
ac884b6a
MS
84 if ((infile = cupsFileOpen(argv[i], "r")) == NULL)
85 {
0837b7e8 86 _cupsLangPrintf(stderr, _("%s: Unable to open %s: %s"), "ppdmerge",
61cf44e2
MS
87 argv[i], strerror(errno));
88 return (1);
ac884b6a
MS
89 }
90
91 // Open the PPD file...
92 if ((ppd = ppdOpen2(infile)) == NULL)
93 {
94 ppd_status_t status; // PPD open status
0837b7e8
MS
95 int curline, // Current line
96 linenum; // Line number
88f9aafc
MS
97
98
ac884b6a 99 status = ppdLastError(&linenum);
88f9aafc 100
0837b7e8
MS
101 _cupsLangPrintf(stderr,
102 _("%s: Unable to open PPD file: %s on line %d."),
f0ab5bff 103 "ppdmerge", ppdErrorString(status), linenum);
ac884b6a 104 cupsFileRewind(infile);
88f9aafc 105
ac884b6a 106 line[0] = '\0';
0837b7e8 107 curline = 0;
88f9aafc 108
ac884b6a
MS
109 while (cupsFileGets(infile, line, sizeof(line)))
110 {
0837b7e8
MS
111 curline ++;
112 if (curline >= linenum)
ac884b6a
MS
113 break;
114 }
0837b7e8
MS
115
116 _cupsLangPrintf(stderr, "%d: %s", linenum, line);
117
ac884b6a 118 cupsFileClose(infile);
61cf44e2 119 return (1);
ac884b6a 120 }
88f9aafc 121
ac884b6a 122 // Figure out the locale...
61cf44e2 123 if ((locale = ppd_locale(ppd)) == NULL)
ac884b6a 124 {
61cf44e2 125 _cupsLangPrintf(stderr,
0837b7e8 126 _("ppdmerge: Bad LanguageVersion \"%s\" in %s."),
61cf44e2 127 ppd->lang_version, argv[i]);
ac884b6a
MS
128 cupsFileClose(infile);
129 ppdClose(ppd);
61cf44e2 130 return (1);
ac884b6a 131 }
61cf44e2 132
ac884b6a
MS
133 if (!strcmp(locale, "en") && !inname && !outfile)
134 {
135 // Set the English PPD's filename...
61cf44e2
MS
136 inname = argv[i];
137 languages = _ppdGetLanguages(ppd);
138
ac884b6a 139 if (outname && !strcmp(inname, outname))
88f9aafc 140 {
ac884b6a 141 // Rename input filename so that we don't overwrite it...
ac884b6a 142 snprintf(bckname, sizeof(bckname), "%s.bck", inname);
88f9aafc 143
ac884b6a
MS
144 if (rename(inname, bckname))
145 {
61cf44e2 146 _cupsLangPrintf(stderr,
0837b7e8 147 _("ppdmerge: Unable to backup %s to %s - %s"),
61cf44e2 148 inname, bckname, strerror(errno));
ac884b6a
MS
149 return (1);
150 }
ac884b6a 151
61cf44e2 152 inname = bckname;
ac884b6a
MS
153 }
154 }
61cf44e2 155 else if (strcmp(locale, "en"))
ac884b6a
MS
156 {
157 // Save this PPD for later processing...
158 cupsArrayAdd(ppds, ppd);
159 }
160 else
161 {
162 // Don't need this PPD...
0837b7e8 163 _cupsLangPrintf(stderr, _("ppdmerge: Ignoring PPD file %s."),
61cf44e2 164 argv[i]);
ac884b6a
MS
165 ppdClose(ppd);
166 }
88f9aafc 167
ac884b6a
MS
168 // Close and move on...
169 cupsFileClose(infile);
170 }
171
172 // If no PPDs have been loaded, display the program usage message.
173 if (!inname)
174 usage();
61cf44e2
MS
175
176 // Loop through the PPD files we loaded to generate a new language list...
177 if (!languages)
178 languages = cupsArrayNew((cups_array_func_t)strcmp, NULL);
179
180 for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
181 ppd;
182 ppd = (ppd_file_t *)cupsArrayNext(ppds))
183 {
184 locale = ppd_locale(ppd);
185
186 if (cupsArrayFind(languages, (void *)locale))
187 {
188 // Already have this language, remove the PPD from the list.
189 ppdClose(ppd);
190 cupsArrayRemove(ppds, ppd);
191 }
192 else
193 cupsArrayAdd(languages, (void *)locale);
194 }
195
196 // Copy the English PPD starting with a cupsLanguages line...
197 infile = cupsFileOpen(inname, "r");
198
199 if (outname)
200 {
201 const char *ext = strrchr(outname, '.');
202 if (ext && !strcmp(ext, ".gz"))
203 outfile = cupsFileOpen(outname, "w9");
204 else
205 outfile = cupsFileOpen(outname, "w");
206 }
207 else
208 outfile = cupsFileStdout();
209
210 cupsFileGets(infile, line, sizeof(line));
211 cupsFilePrintf(outfile, "%s\n", line);
212 if ((locale = (char *)cupsArrayFirst(languages)) != NULL)
213 {
214 cupsFilePrintf(outfile, "*cupsLanguages: \"%s", locale);
215 while ((locale = (char *)cupsArrayNext(languages)) != NULL)
216 cupsFilePrintf(outfile, " %s", locale);
217 cupsFilePuts(outfile, "\"\n");
218 }
219
220 while (cupsFileGets(infile, line, sizeof(line)))
221 {
222 if (strncmp(line, "*cupsLanguages:", 15))
223 cupsFilePrintf(outfile, "%s\n", line);
224 }
225
226 // Loop through the other PPD files we loaded to provide the translations...
ac884b6a
MS
227 for (ppd = (ppd_file_t *)cupsArrayFirst(ppds);
228 ppd;
229 ppd = (ppd_file_t *)cupsArrayNext(ppds))
230 {
231 // Output all of the UI text for this language...
232 int j, k, l; // Looping vars
233 ppd_group_t *g; // Option group
234 ppd_option_t *o; // Option
235 ppd_choice_t *c; // Choice
61cf44e2
MS
236 ppd_coption_t *co; // Custom option
237 ppd_cparam_t *cp; // Custom parameter
238 ppd_attr_t *attr; // PPD attribute
239
240 locale = ppd_locale(ppd);
ac884b6a 241
ac884b6a 242 cupsFilePrintf(outfile, "*%% %s localization\n", ppd->lang_version);
ac884b6a
MS
243 cupsFilePrintf(outfile, "*%s.Translation ModelName/%s: \"\"\n", locale,
244 ppd->modelname);
61cf44e2 245
ac884b6a
MS
246 for (j = ppd->num_groups, g = ppd->groups; j > 0; j --, g ++)
247 {
248 cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
249 g->name, g->text);
61cf44e2 250
ac884b6a
MS
251 for (k = g->num_options, o = g->options; k > 0; k --, o ++)
252 {
253 cupsFilePrintf(outfile, "*%s.Translation %s/%s: \"\"\n", locale,
254 o->keyword, o->text);
61cf44e2 255
ac884b6a
MS
256 for (l = o->num_choices, c = o->choices; l > 0; l --, c ++)
257 cupsFilePrintf(outfile, "*%s.%s %s/%s: \"\"\n", locale,
258 o->keyword, c->choice, c->text);
61cf44e2
MS
259
260 if ((co = ppdFindCustomOption(ppd, o->keyword)) != NULL)
261 {
262 snprintf(line, sizeof(line), "Custom%s", o->keyword);
263 attr = ppdFindAttr(ppd, line, "True");
264 cupsFilePrintf(outfile, "*%s.Custom%s True/%s: \"\"\n", locale,
265 o->keyword, attr->text);
266 for (cp = ppdFirstCustomParam(co); cp; cp = ppdNextCustomParam(co))
267 cupsFilePrintf(outfile, "*%s.ParamCustom%s %s/%s: \"\"\n", locale,
268 o->keyword, cp->name, cp->text);
269 }
ac884b6a
MS
270 }
271 }
ac884b6a
MS
272
273 ppdClose(ppd);
274 }
275
276 cupsArrayDelete(ppds);
277
ac884b6a
MS
278 cupsFileClose(outfile);
279
280 // Return with no errors.
281 return (0);
ac884b6a
MS
282}
283
284
285//
286// 'ppd_locale()' - Return the locale associated with a PPD file.
287//
288
289static const char * // O - Locale string
290ppd_locale(ppd_file_t *ppd) // I - PPD file
291{
7e86f2f6
MS
292 int i; // Looping var
293 size_t vlen; // Length of LanguageVersion string
ac884b6a
MS
294 static char locale[255]; // Locale string
295 static struct // LanguageVersion translation table
296 {
297 const char *version, // LanguageVersion string */
298 *language; // Language code */
299 } languages[] =
300 {
dd1abb6b
MS
301 { "chinese", "zh" },
302 { "czech", "cs" },
303 { "danish", "da" },
304 { "dutch", "nl" },
305 { "english", "en" },
306 { "finnish", "fi" },
307 { "french", "fr" },
308 { "german", "de" },
309 { "greek", "el" },
310 { "hungarian", "hu" },
311 { "italian", "it" },
312 { "japanese", "ja" },
313 { "korean", "ko" },
314 { "norwegian", "no" },
315 { "polish", "pl" },
316 { "portuguese", "pt" },
317 { "russian", "ru" },
318 { "simplified chinese", "zh_CN" },
319 { "slovak", "sk" },
320 { "spanish", "es" },
321 { "swedish", "sv" },
322 { "traditional chinese", "zh_TW" },
323 { "turkish", "tr" }
ac884b6a
MS
324 };
325
326
327 for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
328 {
329 vlen = strlen(languages[i].version);
330
88f9aafc 331 if (!_cups_strncasecmp(ppd->lang_version, languages[i].version, vlen))
ac884b6a
MS
332 {
333 if (ppd->lang_version[vlen] == '-' ||
334 ppd->lang_version[vlen] == '_')
335 snprintf(locale, sizeof(locale), "%s_%s", languages[i].language,
336 ppd->lang_version + vlen + 1);
337 else
338 strlcpy(locale, languages[i].language, sizeof(locale));
339
340 return (locale);
341 }
342 }
343
344 return (NULL);
345}
346
347//
348// 'usage()' - Show usage and exit.
349//
350
351static void
352usage(void)
353{
0837b7e8
MS
354 _cupsLangPuts(stdout, _("Usage: ppdmerge [options] filename.ppd [ ... "
355 "filenameN.ppd ]"));
356 _cupsLangPuts(stdout, _("Options:"));
84315f46
MS
357 _cupsLangPuts(stdout, _(" -o filename.ppd[.gz] Set output file "
358 "(otherwise stdout)."));
ac884b6a
MS
359
360 exit(1);
361}