xref: /titanic_50/usr/src/cmd/ast/msgcc/msgcvt.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
1*da2e3ebdSchin /***********************************************************************
2*da2e3ebdSchin *                                                                      *
3*da2e3ebdSchin *               This software is part of the ast package               *
4*da2e3ebdSchin *           Copyright (c) 2000-2007 AT&T Knowledge Ventures            *
5*da2e3ebdSchin *                      and is licensed under the                       *
6*da2e3ebdSchin *                  Common Public License, Version 1.0                  *
7*da2e3ebdSchin *                      by AT&T Knowledge Ventures                      *
8*da2e3ebdSchin *                                                                      *
9*da2e3ebdSchin *                A copy of the License is available at                 *
10*da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*da2e3ebdSchin *                                                                      *
13*da2e3ebdSchin *              Information and Software Systems Research               *
14*da2e3ebdSchin *                            AT&T Research                             *
15*da2e3ebdSchin *                           Florham Park NJ                            *
16*da2e3ebdSchin *                                                                      *
17*da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18*da2e3ebdSchin *                                                                      *
19*da2e3ebdSchin ***********************************************************************/
20*da2e3ebdSchin #pragma prototyped
21*da2e3ebdSchin /*
22*da2e3ebdSchin  * Glenn Fowler
23*da2e3ebdSchin  * AT&T Research
24*da2e3ebdSchin  */
25*da2e3ebdSchin 
26*da2e3ebdSchin static const char usage[] =
27*da2e3ebdSchin "[-?\n@(#)$Id: msgcvt (AT&T Research) 2000-05-01 $\n]"
28*da2e3ebdSchin USAGE_LICENSE
29*da2e3ebdSchin "[+NAME?msgcvt - convert message file to/from html]"
30*da2e3ebdSchin "[+DESCRIPTION?\bmsgcvt\b reads a \bgencat\b(1) format file on the standard"
31*da2e3ebdSchin "	input and converts it to \bhtml\b on the standard output. The input"
32*da2e3ebdSchin "	file must contain the control statement \b$quote \"\b and use the \""
33*da2e3ebdSchin "	character to quote message text. The output is in a form suitable for"
34*da2e3ebdSchin "	automatic translation by web sites like"
35*da2e3ebdSchin "	\bhttp://babelfish.altavista.com/\b or filters like"
36*da2e3ebdSchin "	\btranslate\b(1).]"
37*da2e3ebdSchin "[h:html?Generate \bhtml\b from \bgencat\b(1) input. This is the default.]"
38*da2e3ebdSchin "[m:msg?Generate a \bgencat\b(1) message file from (presumably translated)"
39*da2e3ebdSchin "	\bhtml\b. Wide characters are UTF-8 encoded.]"
40*da2e3ebdSchin "[r:raw?The message file is raw message text, one message per line, with no"
41*da2e3ebdSchin "	quoting or line numbering.]"
42*da2e3ebdSchin "[+SEE ALSO?\bgencat\b(1), \bmsgcc\b(1), \bmsggen\b(1), \btranslate\b(1)]"
43*da2e3ebdSchin ;
44*da2e3ebdSchin 
45*da2e3ebdSchin #include <ast.h>
46*da2e3ebdSchin #include <ctype.h>
47*da2e3ebdSchin #include <error.h>
48*da2e3ebdSchin 
49*da2e3ebdSchin #define MSG_RAW		(1<<0)
50*da2e3ebdSchin #define MSG_SPLICE	(1<<1)
51*da2e3ebdSchin 
52*da2e3ebdSchin #define SPACE(s)	(isspace(*s)&&(s+=1)||*s=='\\'&&(*(s+1)=='n'||*(s+1)=='t')&&(s+=2))
53*da2e3ebdSchin 
54*da2e3ebdSchin typedef void (*Convert_f)(Sfio_t*, Sfio_t*, int);
55*da2e3ebdSchin 
56*da2e3ebdSchin typedef struct
57*da2e3ebdSchin {
58*da2e3ebdSchin 	const char*	name;
59*da2e3ebdSchin 	int		code;
60*da2e3ebdSchin } Code_t;
61*da2e3ebdSchin 
62*da2e3ebdSchin static const Code_t	codes[] =
63*da2e3ebdSchin {
64*da2e3ebdSchin 	"aacute",	225,
65*da2e3ebdSchin 	"Aacute",	193,
66*da2e3ebdSchin 	"acirc",	226,
67*da2e3ebdSchin 	"Acirc",	194,
68*da2e3ebdSchin 	"aelig",	230,
69*da2e3ebdSchin 	"AElig",	198,
70*da2e3ebdSchin 	"agrave",	224,
71*da2e3ebdSchin 	"Agrave",	192,
72*da2e3ebdSchin 	"amp",		'&',
73*da2e3ebdSchin 	"aring",	229,
74*da2e3ebdSchin 	"Aring",	197,
75*da2e3ebdSchin 	"atilde",	227,
76*da2e3ebdSchin 	"Atilde",	195,
77*da2e3ebdSchin 	"auml",		228,
78*da2e3ebdSchin 	"Auml",		196,
79*da2e3ebdSchin 	"ccedil",	231,
80*da2e3ebdSchin 	"Ccedil",	199,
81*da2e3ebdSchin 	"copy",		169,
82*da2e3ebdSchin 	"eacute",	233,
83*da2e3ebdSchin 	"Eacute",	201,
84*da2e3ebdSchin 	"ecirc",	234,
85*da2e3ebdSchin 	"Ecirc",	202,
86*da2e3ebdSchin 	"egrave",	232,
87*da2e3ebdSchin 	"Egrave",	200,
88*da2e3ebdSchin 	"euml",		235,
89*da2e3ebdSchin 	"Euml",		203,
90*da2e3ebdSchin 	"gt",		'>',
91*da2e3ebdSchin 	"iacute",	237,
92*da2e3ebdSchin 	"Iacute",	205,
93*da2e3ebdSchin 	"icirc",	238,
94*da2e3ebdSchin 	"Icirc",	206,
95*da2e3ebdSchin 	"igrave",	236,
96*da2e3ebdSchin 	"Igrave",	204,
97*da2e3ebdSchin 	"iuml",		239,
98*da2e3ebdSchin 	"Iuml",		207,
99*da2e3ebdSchin 	"lt",		'<',
100*da2e3ebdSchin 	"nbsp",		' ',
101*da2e3ebdSchin 	"ntilde",	241,
102*da2e3ebdSchin 	"Ntilde",	209,
103*da2e3ebdSchin 	"oacute",	243,
104*da2e3ebdSchin 	"Oacute",	211,
105*da2e3ebdSchin 	"ocirc",	244,
106*da2e3ebdSchin 	"Ocirc",	212,
107*da2e3ebdSchin 	"ograve",	242,
108*da2e3ebdSchin 	"Ograve",	210,
109*da2e3ebdSchin 	"oslash",	248,
110*da2e3ebdSchin 	"Oslash",	216,
111*da2e3ebdSchin 	"otilde",	245,
112*da2e3ebdSchin 	"Otilde",	213,
113*da2e3ebdSchin 	"ouml",		246,
114*da2e3ebdSchin 	"Ouml",		214,
115*da2e3ebdSchin 	"quot",		'"',
116*da2e3ebdSchin 	"reg",		174,
117*da2e3ebdSchin 	"szlig",	223,
118*da2e3ebdSchin 	"uacute",	250,
119*da2e3ebdSchin 	"Uacute",	218,
120*da2e3ebdSchin 	"ucirc",	251,
121*da2e3ebdSchin 	"Ucirc",	219,
122*da2e3ebdSchin 	"ugrave",	249,
123*da2e3ebdSchin 	"Ugrave",	217,
124*da2e3ebdSchin 	"uuml",		252,
125*da2e3ebdSchin 	"Uuml",		220,
126*da2e3ebdSchin 	"yuml",		255,
127*da2e3ebdSchin };
128*da2e3ebdSchin 
129*da2e3ebdSchin static int
130*da2e3ebdSchin decode(Sfio_t* ip)
131*da2e3ebdSchin {
132*da2e3ebdSchin 	register int	c;
133*da2e3ebdSchin 	register int	i;
134*da2e3ebdSchin 	char		name[32];
135*da2e3ebdSchin 
136*da2e3ebdSchin 	if ((c = sfgetc(ip)) == EOF)
137*da2e3ebdSchin 		return '&';
138*da2e3ebdSchin 	name[0] = c;
139*da2e3ebdSchin 	i = 1;
140*da2e3ebdSchin 	if (c != '#' && !isalpha(c))
141*da2e3ebdSchin 		goto bad;
142*da2e3ebdSchin 	while ((c = sfgetc(ip)) != EOF && c != ';')
143*da2e3ebdSchin 	{
144*da2e3ebdSchin 		if (c == '&')
145*da2e3ebdSchin 			i = 0;
146*da2e3ebdSchin 		else
147*da2e3ebdSchin 		{
148*da2e3ebdSchin 			name[i++] = c;
149*da2e3ebdSchin 			if (!isalnum(c) && (i > 1 || c != '#') || i >= (elementsof(name) - 1))
150*da2e3ebdSchin 				goto bad;
151*da2e3ebdSchin 		}
152*da2e3ebdSchin 	}
153*da2e3ebdSchin 	name[i] = 0;
154*da2e3ebdSchin 	if (name[0] == '#')
155*da2e3ebdSchin 	{
156*da2e3ebdSchin 		switch (c = strtol(name + 1, NiL, 10))
157*da2e3ebdSchin 		{
158*da2e3ebdSchin 		case 91:
159*da2e3ebdSchin 			c = '[';
160*da2e3ebdSchin 			break;
161*da2e3ebdSchin 		case 93:
162*da2e3ebdSchin 			c = ']';
163*da2e3ebdSchin 			break;
164*da2e3ebdSchin 		}
165*da2e3ebdSchin 	}
166*da2e3ebdSchin 	else
167*da2e3ebdSchin 	{
168*da2e3ebdSchin 		for (i = 0; i < elementsof(codes); i++)
169*da2e3ebdSchin 			if (streq(codes[i].name, name))
170*da2e3ebdSchin 			{
171*da2e3ebdSchin 				c = codes[i].code;
172*da2e3ebdSchin 				break;
173*da2e3ebdSchin 			}
174*da2e3ebdSchin 		if (i >= elementsof(codes))
175*da2e3ebdSchin 			goto bad;
176*da2e3ebdSchin 	}
177*da2e3ebdSchin 	return c;
178*da2e3ebdSchin  bad:
179*da2e3ebdSchin 	name[i] = 0;
180*da2e3ebdSchin 	if (c == ';')
181*da2e3ebdSchin 		error(1, "&%s: unknown HTML special character -- & assumed", name);
182*da2e3ebdSchin 	else
183*da2e3ebdSchin 		error(1, "&%s: invalid HTML special character -- & assumed", name);
184*da2e3ebdSchin 	while (i--)
185*da2e3ebdSchin 		sfungetc(ip, name[i]);
186*da2e3ebdSchin 	return '&';
187*da2e3ebdSchin }
188*da2e3ebdSchin 
189*da2e3ebdSchin static int
190*da2e3ebdSchin sfpututf(Sfio_t* op, register int w)
191*da2e3ebdSchin {
192*da2e3ebdSchin 	if (!(w & ~0x7F))
193*da2e3ebdSchin 		return sfputc(op, w);
194*da2e3ebdSchin 	else if (!(w & ~0x7FF))
195*da2e3ebdSchin 		sfputc(op, 0xC0 + (w >> 6));
196*da2e3ebdSchin 	else if (!(w & ~0xFFFF))
197*da2e3ebdSchin 	{
198*da2e3ebdSchin 		sfputc(op, 0xE0 + (w >> 12));
199*da2e3ebdSchin 		sfputc(op, 0x80 + (w >> 6 ) & 0x3F);
200*da2e3ebdSchin 	}
201*da2e3ebdSchin 	else
202*da2e3ebdSchin 		return sfputc(op, '?');
203*da2e3ebdSchin 	return sfputc(op, 0x80 + (w & 0x3F));
204*da2e3ebdSchin }
205*da2e3ebdSchin 
206*da2e3ebdSchin static int
207*da2e3ebdSchin sfnext(Sfio_t* ip)
208*da2e3ebdSchin {
209*da2e3ebdSchin 	register int	c;
210*da2e3ebdSchin 
211*da2e3ebdSchin 	while (isspace(c = sfgetc(ip)));
212*da2e3ebdSchin 	return c;
213*da2e3ebdSchin }
214*da2e3ebdSchin 
215*da2e3ebdSchin static void
216*da2e3ebdSchin html2msg(register Sfio_t* ip, register Sfio_t* op, int flags)
217*da2e3ebdSchin {
218*da2e3ebdSchin 	register int	c;
219*da2e3ebdSchin 	register int	q;
220*da2e3ebdSchin 
221*da2e3ebdSchin  again:
222*da2e3ebdSchin 	while ((c = sfgetc(ip)) != EOF)
223*da2e3ebdSchin 		if (c == '<')
224*da2e3ebdSchin 		{
225*da2e3ebdSchin 			if ((c = sfnext(ip)) == 'O' &&
226*da2e3ebdSchin 			    (c = sfnext(ip)) == 'L' &&
227*da2e3ebdSchin 			    isspace(c = sfgetc(ip)) &&
228*da2e3ebdSchin 			    (c = sfnext(ip)) == 'S' &&
229*da2e3ebdSchin 			    (c = sfnext(ip)) == 'T' &&
230*da2e3ebdSchin 			    (c = sfnext(ip)) == 'A' &&
231*da2e3ebdSchin 			    (c = sfnext(ip)) == 'R' &&
232*da2e3ebdSchin 			    (c = sfnext(ip)) == 'T' &&
233*da2e3ebdSchin 			    (c = sfnext(ip)) == '=' &&
234*da2e3ebdSchin 			    (c = sfnext(ip)) == '"' &&
235*da2e3ebdSchin 			    (c = sfnext(ip)) == '5' &&
236*da2e3ebdSchin 			    (c = sfnext(ip)) == '5' &&
237*da2e3ebdSchin 			    (c = sfnext(ip)) == '0' &&
238*da2e3ebdSchin 			    (c = sfnext(ip)) == '7' &&
239*da2e3ebdSchin 			    (c = sfnext(ip)) == '1' &&
240*da2e3ebdSchin 			    (c = sfnext(ip)) == '7' &&
241*da2e3ebdSchin 			    (c = sfnext(ip)) == '"' &&
242*da2e3ebdSchin 			    (c = sfnext(ip)) == '>')
243*da2e3ebdSchin 				break;
244*da2e3ebdSchin 			while (c != EOF && c != '>')
245*da2e3ebdSchin 				c = sfgetc(ip);
246*da2e3ebdSchin 		}
247*da2e3ebdSchin 	if ((c = sfnext(ip)) != EOF)
248*da2e3ebdSchin 		sfungetc(ip, c);
249*da2e3ebdSchin 	q = 0;
250*da2e3ebdSchin 	for (;;)
251*da2e3ebdSchin 	{
252*da2e3ebdSchin 		switch (c = sfgetc(ip))
253*da2e3ebdSchin 		{
254*da2e3ebdSchin 		case EOF:
255*da2e3ebdSchin 			break;
256*da2e3ebdSchin 		case '&':
257*da2e3ebdSchin 			c = decode(ip);
258*da2e3ebdSchin 			sfpututf(op, c);
259*da2e3ebdSchin 			if (isspace(c))
260*da2e3ebdSchin 			{
261*da2e3ebdSchin 				while (isspace(c = sfgetc(ip)));
262*da2e3ebdSchin 				if (c == EOF)
263*da2e3ebdSchin 					break;
264*da2e3ebdSchin 				sfungetc(ip, c);
265*da2e3ebdSchin 			}
266*da2e3ebdSchin 			continue;
267*da2e3ebdSchin 		case '<':
268*da2e3ebdSchin 			switch (c = sfnext(ip))
269*da2e3ebdSchin 			{
270*da2e3ebdSchin 			case '/':
271*da2e3ebdSchin 				if ((c = sfnext(ip)) == 'O' &&
272*da2e3ebdSchin 				    (c = sfgetc(ip)) == 'L' &&
273*da2e3ebdSchin 				    (c = sfnext(ip)) == '>')
274*da2e3ebdSchin 				{
275*da2e3ebdSchin 					if (q)
276*da2e3ebdSchin 					{
277*da2e3ebdSchin 						sfputc(op, q);
278*da2e3ebdSchin 						q = '"';
279*da2e3ebdSchin 					}
280*da2e3ebdSchin 					goto again;
281*da2e3ebdSchin 				}
282*da2e3ebdSchin 				break;
283*da2e3ebdSchin 			case 'B':
284*da2e3ebdSchin 				if ((c = sfgetc(ip)) == 'R' &&
285*da2e3ebdSchin 				    (c = sfnext(ip)) == '>')
286*da2e3ebdSchin 					sfputc(op, ' ');
287*da2e3ebdSchin 				break;
288*da2e3ebdSchin 			case 'L':
289*da2e3ebdSchin 				if ((c = sfgetc(ip)) == 'I' &&
290*da2e3ebdSchin 				    (c = sfnext(ip)) == '>' &&
291*da2e3ebdSchin 				     isdigit(c = sfnext(ip)))
292*da2e3ebdSchin 				{
293*da2e3ebdSchin 					if (q)
294*da2e3ebdSchin 						sfputc(op, q);
295*da2e3ebdSchin 					else
296*da2e3ebdSchin 						q = '"';
297*da2e3ebdSchin 					sfputc(op, '\n');
298*da2e3ebdSchin 					do
299*da2e3ebdSchin 					{
300*da2e3ebdSchin 						sfputc(op, c);
301*da2e3ebdSchin 					} while (isdigit(c = sfgetc(ip)));
302*da2e3ebdSchin 					if (c == EOF)
303*da2e3ebdSchin 						break;
304*da2e3ebdSchin 					sfputc(op, ' ');
305*da2e3ebdSchin 					sfputc(op, '"');
306*da2e3ebdSchin 					if (isspace(c))
307*da2e3ebdSchin 						c = sfnext(ip);
308*da2e3ebdSchin 					if (c == '<' &&
309*da2e3ebdSchin 					    (c = sfnext(ip)) == 'L' &&
310*da2e3ebdSchin 					    (c = sfgetc(ip)) == 'I' &&
311*da2e3ebdSchin 					    (c = sfnext(ip)) == '>')
312*da2e3ebdSchin 						/* great */;
313*da2e3ebdSchin 					continue;
314*da2e3ebdSchin 				}
315*da2e3ebdSchin 				break;
316*da2e3ebdSchin 			case 'P':
317*da2e3ebdSchin 				if ((c = sfnext(ip)) == '>')
318*da2e3ebdSchin 					sfputc(op, '\n');
319*da2e3ebdSchin 				else if (c == 'C' &&
320*da2e3ebdSchin 					 (c = sfgetc(ip)) == 'L' &&
321*da2e3ebdSchin 					 (c = sfgetc(ip)) == 'A' &&
322*da2e3ebdSchin 					 (c = sfgetc(ip)) == 'S' &&
323*da2e3ebdSchin 					 (c = sfgetc(ip)) == 'S' &&
324*da2e3ebdSchin 					 (c = sfnext(ip)) == '=' &&
325*da2e3ebdSchin 					 (c = sfnext(ip)) == '"')
326*da2e3ebdSchin 					for (;;)
327*da2e3ebdSchin 					{
328*da2e3ebdSchin 						switch (c = sfgetc(ip))
329*da2e3ebdSchin 						{
330*da2e3ebdSchin 						case EOF:
331*da2e3ebdSchin 						case '"':
332*da2e3ebdSchin 							break;
333*da2e3ebdSchin 						case '&':
334*da2e3ebdSchin 							c = decode(ip);
335*da2e3ebdSchin 							sfpututf(op, c);
336*da2e3ebdSchin 							continue;
337*da2e3ebdSchin 						default:
338*da2e3ebdSchin 							sfpututf(op, c);
339*da2e3ebdSchin 							continue;
340*da2e3ebdSchin 						}
341*da2e3ebdSchin 						break;
342*da2e3ebdSchin 					}
343*da2e3ebdSchin 				break;
344*da2e3ebdSchin 			}
345*da2e3ebdSchin 			while (c != EOF && c != '>')
346*da2e3ebdSchin 				c = sfgetc(ip);
347*da2e3ebdSchin 			if (c == EOF || (c = sfgetc(ip)) == EOF)
348*da2e3ebdSchin 				break;
349*da2e3ebdSchin 			sfungetc(ip, c);
350*da2e3ebdSchin 			continue;
351*da2e3ebdSchin 		case '"':
352*da2e3ebdSchin 			if (!flags)
353*da2e3ebdSchin 				sfputc(op, '\\');
354*da2e3ebdSchin 			sfputc(op, c);
355*da2e3ebdSchin 			continue;
356*da2e3ebdSchin 		case '\n':
357*da2e3ebdSchin 			if (flags)
358*da2e3ebdSchin 			{
359*da2e3ebdSchin 				sfputc(op, c);
360*da2e3ebdSchin 				continue;
361*da2e3ebdSchin 			}
362*da2e3ebdSchin 			/*FALLTHROUGH*/
363*da2e3ebdSchin 		case ' ':
364*da2e3ebdSchin 		case '\t':
365*da2e3ebdSchin 			while ((c = sfgetc(ip)) != EOF)
366*da2e3ebdSchin 				if (c == '&')
367*da2e3ebdSchin 				{
368*da2e3ebdSchin 					c = decode(ip);
369*da2e3ebdSchin 					if (!isspace(c))
370*da2e3ebdSchin 						sfputc(op, ' ');
371*da2e3ebdSchin 					sfpututf(op, c);
372*da2e3ebdSchin 					break;
373*da2e3ebdSchin 				}
374*da2e3ebdSchin 				else if (!isspace(c))
375*da2e3ebdSchin 				{
376*da2e3ebdSchin 					if (c == '<')
377*da2e3ebdSchin 					{
378*da2e3ebdSchin 						c = sfgetc(ip);
379*da2e3ebdSchin 						if (c == EOF)
380*da2e3ebdSchin 							break;
381*da2e3ebdSchin 						sfungetc(ip, c);
382*da2e3ebdSchin 						sfungetc(ip, '<');
383*da2e3ebdSchin 						if (c != 'L' && c != '/')
384*da2e3ebdSchin 							sfputc(op, ' ');
385*da2e3ebdSchin 					}
386*da2e3ebdSchin 					else
387*da2e3ebdSchin 					{
388*da2e3ebdSchin 						if (c != EOF)
389*da2e3ebdSchin 							sfungetc(ip, c);
390*da2e3ebdSchin 						sfputc(op, ' ');
391*da2e3ebdSchin 					}
392*da2e3ebdSchin 					break;
393*da2e3ebdSchin 				}
394*da2e3ebdSchin 			continue;
395*da2e3ebdSchin 		case '\r':
396*da2e3ebdSchin 		case '[':
397*da2e3ebdSchin 		case ']':
398*da2e3ebdSchin 			continue;
399*da2e3ebdSchin 		default:
400*da2e3ebdSchin 			sfpututf(op, c);
401*da2e3ebdSchin 			continue;
402*da2e3ebdSchin 		}
403*da2e3ebdSchin 		break;
404*da2e3ebdSchin 	}
405*da2e3ebdSchin 	if (q)
406*da2e3ebdSchin 		sfputc(op, q);
407*da2e3ebdSchin 	sfputc(op, '\n');
408*da2e3ebdSchin }
409*da2e3ebdSchin 
410*da2e3ebdSchin static void
411*da2e3ebdSchin encode(Sfio_t* op, register int c)
412*da2e3ebdSchin {
413*da2e3ebdSchin 	if (c == '<')
414*da2e3ebdSchin 		sfprintf(op, "&lt;");
415*da2e3ebdSchin 	else if (c == '>')
416*da2e3ebdSchin 		sfprintf(op, "&gt;");
417*da2e3ebdSchin 	else if (c == '"')
418*da2e3ebdSchin 		sfprintf(op, "&quot;");
419*da2e3ebdSchin 	else if (c == '&')
420*da2e3ebdSchin 		sfprintf(op, "&amp;");
421*da2e3ebdSchin 	else if (c == '[')
422*da2e3ebdSchin 		sfprintf(op, "&#091;");
423*da2e3ebdSchin 	else if (c == ']')
424*da2e3ebdSchin 		sfprintf(op, "&#093;");
425*da2e3ebdSchin 	else
426*da2e3ebdSchin 		sfputc(op, c);
427*da2e3ebdSchin }
428*da2e3ebdSchin 
429*da2e3ebdSchin static void
430*da2e3ebdSchin msg2html(register Sfio_t* ip, register Sfio_t* op, register int flags)
431*da2e3ebdSchin {
432*da2e3ebdSchin 	register char*	s;
433*da2e3ebdSchin 	register int	c;
434*da2e3ebdSchin 	register int	q;
435*da2e3ebdSchin 	register int	p;
436*da2e3ebdSchin 
437*da2e3ebdSchin 	sfprintf(op, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><HTML><HEAD><!-- text massaged for external translation --></HEAD><BODY>\n");
438*da2e3ebdSchin 	sfprintf(op, "<OL START=\"550717\">\n");
439*da2e3ebdSchin 	p = q = 0;
440*da2e3ebdSchin 	while (s = sfgetr(ip, '\n', 1))
441*da2e3ebdSchin 	{
442*da2e3ebdSchin 		error_info.line++;
443*da2e3ebdSchin 		if (flags)
444*da2e3ebdSchin 			sfprintf(op, "<P>");
445*da2e3ebdSchin 		else
446*da2e3ebdSchin 		{
447*da2e3ebdSchin 			if (*s == '$')
448*da2e3ebdSchin 			{
449*da2e3ebdSchin 				if (p)
450*da2e3ebdSchin 					sfprintf(op, "<P>");
451*da2e3ebdSchin 				else
452*da2e3ebdSchin 					p = 1;
453*da2e3ebdSchin 				sfprintf(op, "<P CLASS=\"", s);
454*da2e3ebdSchin 				while (c = *s++)
455*da2e3ebdSchin 					encode(op, c);
456*da2e3ebdSchin 				sfprintf(op, "\">\n");
457*da2e3ebdSchin 				continue;
458*da2e3ebdSchin 			}
459*da2e3ebdSchin 			p = 0;
460*da2e3ebdSchin 			if (!isdigit(*s))
461*da2e3ebdSchin 				continue;
462*da2e3ebdSchin 			sfprintf(op, "<LI>");
463*da2e3ebdSchin 			while (isdigit(c = *s++))
464*da2e3ebdSchin 				sfputc(op, c);
465*da2e3ebdSchin 			sfprintf(op, "<LI>");
466*da2e3ebdSchin 			while (c && c != '"')
467*da2e3ebdSchin 				c = *s++;
468*da2e3ebdSchin 			if (!c)
469*da2e3ebdSchin 				s--;
470*da2e3ebdSchin 			else if (isspace(*s))
471*da2e3ebdSchin 			{
472*da2e3ebdSchin 				s++;
473*da2e3ebdSchin 				sfprintf(op, "<BR>");
474*da2e3ebdSchin 			}
475*da2e3ebdSchin 		}
476*da2e3ebdSchin 		for (;;)
477*da2e3ebdSchin 		{
478*da2e3ebdSchin 			switch (c = *s++)
479*da2e3ebdSchin 			{
480*da2e3ebdSchin 			case 0:
481*da2e3ebdSchin 				flags &= ~MSG_SPLICE;
482*da2e3ebdSchin 				if (q)
483*da2e3ebdSchin 				{
484*da2e3ebdSchin 					q = 0;
485*da2e3ebdSchin 					sfprintf(op, "\">");
486*da2e3ebdSchin 				}
487*da2e3ebdSchin 				sfputc(op, '\n');
488*da2e3ebdSchin 				break;
489*da2e3ebdSchin 			case '<':
490*da2e3ebdSchin 				sfprintf(op, "&lt;");
491*da2e3ebdSchin 				continue;
492*da2e3ebdSchin 			case '>':
493*da2e3ebdSchin 				sfprintf(op, "&gt;");
494*da2e3ebdSchin 				continue;
495*da2e3ebdSchin 			case '&':
496*da2e3ebdSchin 				sfprintf(op, "&amp;");
497*da2e3ebdSchin 				continue;
498*da2e3ebdSchin 			case '[':
499*da2e3ebdSchin 				sfprintf(op, "&#091;");
500*da2e3ebdSchin 				continue;
501*da2e3ebdSchin 			case ']':
502*da2e3ebdSchin 				sfprintf(op, "&#093;");
503*da2e3ebdSchin 				continue;
504*da2e3ebdSchin 			case '$':
505*da2e3ebdSchin 				if (!q)
506*da2e3ebdSchin 				{
507*da2e3ebdSchin 					q = 1;
508*da2e3ebdSchin 					sfprintf(op, "<P CLASS=\"");
509*da2e3ebdSchin 				}
510*da2e3ebdSchin 				sfputc(op, c);
511*da2e3ebdSchin 				while (isalnum(c = *s++))
512*da2e3ebdSchin 					sfputc(op, c);
513*da2e3ebdSchin 				s--;
514*da2e3ebdSchin 				continue;
515*da2e3ebdSchin 			case '%':
516*da2e3ebdSchin 				if (!q)
517*da2e3ebdSchin 				{
518*da2e3ebdSchin 					q = 1;
519*da2e3ebdSchin 					sfprintf(op, "<P CLASS=\"");
520*da2e3ebdSchin 				}
521*da2e3ebdSchin 				sfputc(op, c);
522*da2e3ebdSchin 				if (*s == '%')
523*da2e3ebdSchin 					sfputc(op, *s++);
524*da2e3ebdSchin 				else
525*da2e3ebdSchin 					do
526*da2e3ebdSchin 					{
527*da2e3ebdSchin 						if (!(c = *s++) || c == '"')
528*da2e3ebdSchin 						{
529*da2e3ebdSchin 							s--;
530*da2e3ebdSchin 							break;
531*da2e3ebdSchin 						}
532*da2e3ebdSchin 						encode(op, c);
533*da2e3ebdSchin 					} while (!isalpha(c) || (!islower(c) || c == 'h' || c == 'l') && isalpha(*s));
534*da2e3ebdSchin 				if (SPACE(s))
535*da2e3ebdSchin 					sfprintf(op, "&nbsp;");
536*da2e3ebdSchin 				continue;
537*da2e3ebdSchin 			case '"':
538*da2e3ebdSchin 				if (!(flags & MSG_RAW))
539*da2e3ebdSchin 				{
540*da2e3ebdSchin 					s = "";
541*da2e3ebdSchin 					continue;
542*da2e3ebdSchin 				}
543*da2e3ebdSchin 				/*FALLTHROUGH*/
544*da2e3ebdSchin 			case '\'':
545*da2e3ebdSchin 			case ':':
546*da2e3ebdSchin 			case '/':
547*da2e3ebdSchin 			case '+':
548*da2e3ebdSchin 			case '@':
549*da2e3ebdSchin 				if (!q)
550*da2e3ebdSchin 				{
551*da2e3ebdSchin 					q = 1;
552*da2e3ebdSchin 					sfprintf(op, "<P CLASS=\"");
553*da2e3ebdSchin 				}
554*da2e3ebdSchin 				/*FALLTHROUGH*/
555*da2e3ebdSchin 			case '.':
556*da2e3ebdSchin 			case ',':
557*da2e3ebdSchin 				sfputc(op, c);
558*da2e3ebdSchin 				if (SPACE(s))
559*da2e3ebdSchin 					sfprintf(op, "&nbsp;");
560*da2e3ebdSchin 				continue;
561*da2e3ebdSchin 			case '\\':
562*da2e3ebdSchin 				if (!(c = *s++))
563*da2e3ebdSchin 				{
564*da2e3ebdSchin 					flags |= MSG_SPLICE;
565*da2e3ebdSchin 					break;
566*da2e3ebdSchin 				}
567*da2e3ebdSchin 				if (c != 'n' && c != 't')
568*da2e3ebdSchin 				{
569*da2e3ebdSchin 					if (!q)
570*da2e3ebdSchin 					{
571*da2e3ebdSchin 						q = 1;
572*da2e3ebdSchin 						sfprintf(op, "<P CLASS=\"");
573*da2e3ebdSchin 					}
574*da2e3ebdSchin 					sfputc(op, '\\');
575*da2e3ebdSchin 					encode(op, c);
576*da2e3ebdSchin 					if (c == 'b')
577*da2e3ebdSchin 					{
578*da2e3ebdSchin 						for (;;)
579*da2e3ebdSchin 						{
580*da2e3ebdSchin 							if (!(c = *s++) || c == '"')
581*da2e3ebdSchin 							{
582*da2e3ebdSchin 								s--;
583*da2e3ebdSchin 								break;
584*da2e3ebdSchin 							}
585*da2e3ebdSchin 							if (c == '?')
586*da2e3ebdSchin 							{
587*da2e3ebdSchin 								if (*s != '?')
588*da2e3ebdSchin 								{
589*da2e3ebdSchin 									s--;
590*da2e3ebdSchin 									break;
591*da2e3ebdSchin 								}
592*da2e3ebdSchin 								sfputc(op, c);
593*da2e3ebdSchin 								sfputc(op, *s++);
594*da2e3ebdSchin 								continue;
595*da2e3ebdSchin 							}
596*da2e3ebdSchin 							if (c == '\\')
597*da2e3ebdSchin 							{
598*da2e3ebdSchin 								if (!*s)
599*da2e3ebdSchin 									break;
600*da2e3ebdSchin 								sfputc(op, c);
601*da2e3ebdSchin 								if (*s == 'a' || *s == 'b' || *s == '0')
602*da2e3ebdSchin 								{
603*da2e3ebdSchin 									sfputc(op, *s++);
604*da2e3ebdSchin 									break;
605*da2e3ebdSchin 								}
606*da2e3ebdSchin 								c = *s++;
607*da2e3ebdSchin 							}
608*da2e3ebdSchin 							encode(op, c);
609*da2e3ebdSchin 						}
610*da2e3ebdSchin 					}
611*da2e3ebdSchin 					else if (isdigit(c) && isdigit(*s))
612*da2e3ebdSchin 					{
613*da2e3ebdSchin 						sfputc(op, *s++);
614*da2e3ebdSchin 						if (isdigit(*s))
615*da2e3ebdSchin 							sfputc(op, *s++);
616*da2e3ebdSchin 					}
617*da2e3ebdSchin 					if (SPACE(s))
618*da2e3ebdSchin 						sfprintf(op, "&nbsp;");
619*da2e3ebdSchin 					continue;
620*da2e3ebdSchin 				}
621*da2e3ebdSchin 				/*FALLTHROUGH*/
622*da2e3ebdSchin 			case ' ':
623*da2e3ebdSchin 			case '\t':
624*da2e3ebdSchin 				while (isspace(*s) || *s == '\\' && (*(s + 1) == 'n' || *(s + 1) == 't') && s++)
625*da2e3ebdSchin 					s++;
626*da2e3ebdSchin 				if (*s == '"')
627*da2e3ebdSchin 				{
628*da2e3ebdSchin 					if (q)
629*da2e3ebdSchin 					{
630*da2e3ebdSchin 						q = 0;
631*da2e3ebdSchin 						sfprintf(op, " \">");
632*da2e3ebdSchin 					}
633*da2e3ebdSchin 					else
634*da2e3ebdSchin 						sfprintf(op, "<BR>");
635*da2e3ebdSchin 					continue;
636*da2e3ebdSchin 				}
637*da2e3ebdSchin 				c = ' ';
638*da2e3ebdSchin 				/*FALLTHROUGH*/
639*da2e3ebdSchin 			default:
640*da2e3ebdSchin 				if (q)
641*da2e3ebdSchin 				{
642*da2e3ebdSchin 					q = 0;
643*da2e3ebdSchin 					sfprintf(op, "\">");
644*da2e3ebdSchin 				}
645*da2e3ebdSchin 				sfputc(op, c);
646*da2e3ebdSchin 				continue;
647*da2e3ebdSchin 			}
648*da2e3ebdSchin 			break;
649*da2e3ebdSchin 		}
650*da2e3ebdSchin 	}
651*da2e3ebdSchin 	sfprintf(op, "</OL>\n");
652*da2e3ebdSchin 	sfprintf(op, "</BODY></HTML>\n");
653*da2e3ebdSchin 	error_info.line = 0;
654*da2e3ebdSchin }
655*da2e3ebdSchin 
656*da2e3ebdSchin int
657*da2e3ebdSchin main(int argc, char** argv)
658*da2e3ebdSchin {
659*da2e3ebdSchin 	int		flags = 0;
660*da2e3ebdSchin 	Convert_f	convert = msg2html;
661*da2e3ebdSchin 
662*da2e3ebdSchin 	NoP(argc);
663*da2e3ebdSchin 	error_info.id = "msgcvt";
664*da2e3ebdSchin 	for (;;)
665*da2e3ebdSchin 	{
666*da2e3ebdSchin 		switch (optget(argv, usage))
667*da2e3ebdSchin 		{
668*da2e3ebdSchin 		case 'h':
669*da2e3ebdSchin 			convert = msg2html;
670*da2e3ebdSchin 			continue;
671*da2e3ebdSchin 		case 'm':
672*da2e3ebdSchin 			convert = html2msg;
673*da2e3ebdSchin 			continue;
674*da2e3ebdSchin 		case 'r':
675*da2e3ebdSchin 			flags |= MSG_RAW;
676*da2e3ebdSchin 			continue;
677*da2e3ebdSchin 		case '?':
678*da2e3ebdSchin 			error(ERROR_USAGE|4, "%s", opt_info.arg);
679*da2e3ebdSchin 			continue;
680*da2e3ebdSchin 		case ':':
681*da2e3ebdSchin 			error(2, "%s", opt_info.arg);
682*da2e3ebdSchin 			continue;
683*da2e3ebdSchin 		}
684*da2e3ebdSchin 		break;
685*da2e3ebdSchin 	}
686*da2e3ebdSchin 	argv += opt_info.index;
687*da2e3ebdSchin 	if (error_info.errors)
688*da2e3ebdSchin 		error(ERROR_USAGE|4, "%s", optusage(NiL));
689*da2e3ebdSchin 	(*convert)(sfstdin, sfstdout, flags);
690*da2e3ebdSchin 	return error_info.errors != 0;
691*da2e3ebdSchin }
692