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