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