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