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