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