]> git.ipfire.org Git - thirdparty/cups.git/blame - locale/po2strings.c
Fix curley quotes.
[thirdparty/cups.git] / locale / po2strings.c
CommitLineData
bc44d920 1/*
f2d18633 2 * "$Id$"
bc44d920 3 *
7e86f2f6 4 * Convert a GNU gettext .po file to an Apple .strings file.
71e16022 5 *
3b20f9f5 6 * Copyright 2007-2015 by Apple Inc.
71e16022 7 *
7e86f2f6
MS
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
bc44d920 13 *
14 * Usage:
15 *
16 * po2strings filename.strings filename.po
17 *
18 * Compile with:
19 *
20 * gcc -o po2strings po2strings.c `cups-config --libs`
bc44d920 21 */
22
71e16022 23#include <cups/cups-private.h>
bc44d920 24
25
26/*
27 * The .strings file format is simple:
28 *
29 * // comment
0837b7e8 30 * "msgid" = "msgstr";
bc44d920 31 *
0837b7e8
MS
32 * The GNU gettext .po format is also fairly simple:
33 *
34 * #. comment
35 * msgid "some text"
36 * msgstr "localized text"
37 *
38 * The comment, msgid, and msgstr text can span multiple lines using the form:
39 *
40 * #. comment
41 * #. more comments
42 * msgid ""
43 * "some long text"
44 * msgstr ""
45 * "localized text spanning "
46 * "multiple lines"
47 *
48 * Both the msgid and msgstr strings use standard C quoting for special
49 * characters like newline and the double quote character.
bc44d920 50 */
51
3b20f9f5
MS
52static char *normalize_string(const char *idstr, char *buffer, size_t bufsize);
53
54
bc44d920 55/*
56 * main() - Convert .po file to .strings.
57 */
58
59int /* O - Exit code */
60main(int argc, /* I - Number of command-line args */
61 char *argv[]) /* I - Command-line arguments */
62{
745129be 63 int i; /* Looping var */
0837b7e8
MS
64 const char *pofile, /* .po filename */
65 *stringsfile; /* .strings filename */
66 cups_file_t *po, /* .po file */
67 *strings; /* .strings file */
68 char s[4096], /* String buffer */
69 *ptr, /* Pointer into buffer */
70 *temp, /* New string */
71 *msgid, /* msgid string */
3b20f9f5
MS
72 *msgstr, /* msgstr string */
73 normalized[8192];/* Normalized msgid string */
7e86f2f6 74 size_t length; /* Length of combined strings */
745129be 75 int use_msgid; /* Use msgid strings for msgstr? */
bc44d920 76
77
0837b7e8
MS
78 /*
79 * Process command-line arguments...
80 */
745129be 81
0837b7e8
MS
82 pofile = NULL;
83 stringsfile = NULL;
84 use_msgid = 0;
745129be
MS
85
86 for (i = 1; i < argc; i ++)
0837b7e8 87 {
745129be
MS
88 if (!strcmp(argv[i], "-m"))
89 use_msgid = 1;
90 else if (argv[i][0] == '-')
91 {
92 puts("Usage: po2strings [-m] filename.po filename.strings");
93 return (1);
94 }
0837b7e8
MS
95 else if (!pofile)
96 pofile = argv[i];
97 else if (!stringsfile)
98 stringsfile = argv[i];
745129be
MS
99 else
100 {
101 puts("Usage: po2strings [-m] filename.po filename.strings");
102 return (1);
103 }
0837b7e8 104 }
745129be 105
0837b7e8 106 if (!pofile || !stringsfile)
bc44d920 107 {
745129be 108 puts("Usage: po2strings [-m] filename.po filename.strings");
bc44d920 109 return (1);
110 }
111
112 /*
0837b7e8 113 * Read strings from the .po file and write to the .strings file...
bc44d920 114 */
115
0837b7e8 116 if ((po = cupsFileOpen(pofile, "r")) == NULL)
bc44d920 117 {
0837b7e8 118 perror(pofile);
bc44d920 119 return (1);
120 }
121
0837b7e8 122 if ((strings = cupsFileOpen(stringsfile, "w")) == NULL)
bc44d920 123 {
0837b7e8
MS
124 perror(stringsfile);
125 cupsFileClose(po);
bc44d920 126 return (1);
127 }
128
0837b7e8
MS
129 msgid = msgstr = NULL;
130
131 while (cupsFileGets(po, s, sizeof(s)) != NULL)
bc44d920 132 {
84315f46 133 if (s[0] == '#' && s[1] == '.')
0837b7e8
MS
134 {
135 /*
84315f46 136 * Copy comment string...
0837b7e8 137 */
bc44d920 138
84315f46
MS
139 if (msgid && msgstr)
140 {
141 /*
142 * First output the last localization string...
143 */
144
145 if (*msgid)
146 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid,
147 (use_msgid || !*msgstr) ? msgid : msgstr);
148
149 free(msgid);
150 free(msgstr);
151 msgid = msgstr = NULL;
152 }
153
154 cupsFilePrintf(strings, "//%s\n", s + 2);
0837b7e8 155 }
84315f46 156 else if (s[0] == '#' || !s[0])
0837b7e8
MS
157 {
158 /*
84315f46 159 * Skip blank and file comment lines...
0837b7e8 160 */
bc44d920 161
84315f46 162 continue;
0837b7e8
MS
163 }
164 else
165 {
166 /*
167 * Strip the trailing quote...
168 */
bc44d920 169
0837b7e8
MS
170 if ((ptr = strrchr(s, '\"')) == NULL)
171 continue;
bc44d920 172
0837b7e8 173 *ptr = '\0';
bc44d920 174
0837b7e8
MS
175 /*
176 * Find start of value...
177 */
82cc1f9a 178
0837b7e8
MS
179 if ((ptr = strchr(s, '\"')) == NULL)
180 continue;
bc44d920 181
0837b7e8 182 ptr ++;
bc44d920 183
0837b7e8
MS
184 /*
185 * Create or add to a message...
186 */
187
188 if (!strncmp(s, "msgid", 5))
189 {
190 /*
191 * Output previous message as needed...
192 */
193
194 if (msgid && msgstr)
195 {
196 if (*msgid)
3b20f9f5 197 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, normalize_string((use_msgid || !*msgstr) ? msgid : msgstr, normalized, sizeof(normalized)));
82cc1f9a 198 }
0837b7e8 199
82cc1f9a 200 if (msgid)
0837b7e8 201 free(msgid);
82cc1f9a
MS
202
203 if (msgstr)
0837b7e8 204 free(msgstr);
0837b7e8
MS
205
206 msgid = strdup(ptr);
207 msgstr = NULL;
208 }
82cc1f9a 209 else if (s[0] == '\"' && (msgid || msgstr))
0837b7e8
MS
210 {
211 /*
212 * Append to current string...
213 */
214
5a9febac
MS
215 size_t ptrlen = strlen(ptr); /* Length of string */
216
7e86f2f6 217 length = strlen(msgstr ? msgstr : msgid);
0837b7e8
MS
218
219 if ((temp = realloc(msgstr ? msgstr : msgid,
5a9febac 220 length + ptrlen + 1)) == NULL)
0837b7e8 221 {
82cc1f9a
MS
222 free(msgid);
223 if (msgstr)
224 free(msgstr);
0837b7e8
MS
225 perror("Unable to allocate string");
226 return (1);
227 }
228
229 if (msgstr)
230 {
231 /*
232 * Copy the new portion to the end of the msgstr string - safe
233 * to use strcpy because the buffer is allocated to the correct
234 * size...
235 */
236
237 msgstr = temp;
238
5a9febac 239 memcpy(msgstr + length, ptr, ptrlen + 1);
0837b7e8
MS
240 }
241 else
242 {
243 /*
244 * Copy the new portion to the end of the msgid string - safe
245 * to use strcpy because the buffer is allocated to the correct
246 * size...
247 */
248
249 msgid = temp;
250
5a9febac 251 memcpy(msgid + length, ptr, ptrlen + 1);
0837b7e8
MS
252 }
253 }
254 else if (!strncmp(s, "msgstr", 6) && msgid)
255 {
256 /*
257 * Set the string...
258 */
259
82cc1f9a
MS
260 if (msgstr)
261 free(msgstr);
262
0837b7e8
MS
263 if ((msgstr = strdup(ptr)) == NULL)
264 {
82cc1f9a 265 free(msgid);
0837b7e8
MS
266 perror("Unable to allocate msgstr");
267 return (1);
268 }
269 }
bc44d920 270 }
0837b7e8
MS
271 }
272
273 if (msgid && msgstr)
274 {
275 if (*msgid)
3b20f9f5 276 cupsFilePrintf(strings, "\"%s\" = \"%s\";\n", msgid, normalize_string((use_msgid || !*msgstr) ? msgid : msgstr, normalized, sizeof(normalized)));
82cc1f9a 277 }
bc44d920 278
82cc1f9a 279 if (msgid)
0837b7e8 280 free(msgid);
82cc1f9a
MS
281
282 if (msgstr)
0837b7e8 283 free(msgstr);
bc44d920 284
0837b7e8
MS
285 cupsFileClose(po);
286 cupsFileClose(strings);
287
288 return (0);
bc44d920 289}
290
291
3b20f9f5
MS
292/*
293 * 'normalize_string()' - Normalize a msgid string.
294 *
295 * This function converts ASCII ellipsis and double quotes to their Unicode
296 * counterparts.
297 */
298
299static char * /* O - Normalized string */
300normalize_string(const char *idstr, /* I - msgid string */
301 char *buffer, /* I - Normalized string buffer */
302 size_t bufsize) /* I - Size of string buffer */
303{
304 char *bufptr = buffer, /* Pointer into buffer */
305 *bufend = buffer + bufsize - 3; /* End of buffer */
306 int quote = 0; /* Quote direction */
307
308
309 while (*idstr && bufptr < bufend)
310 {
311 if (*idstr == '.' && idstr[1] == '.' && idstr[2] == '.')
312 {
313 /*
71936a32 314 * Convert ... to Unicode ellipsis...
3b20f9f5
MS
315 */
316
317 *bufptr++ = (char)0xE2;
318 *bufptr++ = (char)0x80;
319 *bufptr++ = (char)0xA6;
320 idstr += 2;
321 }
71936a32 322 else if (*idstr == '\\' && idstr[1] == '\"')
3b20f9f5
MS
323 {
324 if (quote)
325 {
326 /*
71936a32 327 * Convert \" to Unicode right (curley) double quote.
3b20f9f5
MS
328 */
329
330 *bufptr++ = (char)0xE2;
331 *bufptr++ = (char)0x80;
332 *bufptr++ = (char)0x9D;
333 }
334 else
335 {
336 /*
71936a32 337 * Convert \" to Unicode left (curley) double quote.
3b20f9f5
MS
338 */
339
340 *bufptr++ = (char)0xE2;
341 *bufptr++ = (char)0x80;
342 *bufptr++ = (char)0x9C;
343 }
344
345 quote = !quote;
71936a32 346 idstr ++;
3b20f9f5
MS
347 }
348 else
349 *bufptr++ = *idstr;
350
351 idstr ++;
352 }
353
354 *bufptr = '\0';
355
356 return (buffer);
357}
358
359
bc44d920 360/*
f2d18633 361 * End of "$Id$".
bc44d920 362 */