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