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, "<"); 415*da2e3ebdSchin else if (c == '>') 416*da2e3ebdSchin sfprintf(op, ">"); 417*da2e3ebdSchin else if (c == '"') 418*da2e3ebdSchin sfprintf(op, """); 419*da2e3ebdSchin else if (c == '&') 420*da2e3ebdSchin sfprintf(op, "&"); 421*da2e3ebdSchin else if (c == '[') 422*da2e3ebdSchin sfprintf(op, "["); 423*da2e3ebdSchin else if (c == ']') 424*da2e3ebdSchin sfprintf(op, "]"); 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, "<"); 491*da2e3ebdSchin continue; 492*da2e3ebdSchin case '>': 493*da2e3ebdSchin sfprintf(op, ">"); 494*da2e3ebdSchin continue; 495*da2e3ebdSchin case '&': 496*da2e3ebdSchin sfprintf(op, "&"); 497*da2e3ebdSchin continue; 498*da2e3ebdSchin case '[': 499*da2e3ebdSchin sfprintf(op, "["); 500*da2e3ebdSchin continue; 501*da2e3ebdSchin case ']': 502*da2e3ebdSchin sfprintf(op, "]"); 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, " "); 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, " "); 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, " "); 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