xref: /aosp_15_r20/external/libcups/locale/po2strings.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
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