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