uhtml: add html to unicode converter, used by mothra and page/html2ms

This commit is contained in:
cinap_lenrek 2011-09-20 00:38:28 +02:00
parent e7df0daa66
commit a31e4f61a4
8 changed files with 154 additions and 458 deletions

View file

@ -296,79 +296,6 @@ parsetag(Tag *t)
return n > 0;
}
struct {
char *entity;
Rune rune;
} entities[] = {
"AElig", 198, "Aacute", 193, "Acirc", 194, "Agrave", 192,
"Alpha", 913, "Aring", 197, "Atilde", 195, "Auml", 196,
"Beta", 914, "Ccedil", 199, "Chi", 935, "Dagger", 8225,
"Delta", 916, "ETH", 208, "Eacute", 201, "Ecirc", 202,
"Egrave", 200, "Epsilon", 917, "Eta", 919, "Euml", 203,
"Gamma", 915, "Iacute", 205, "Icirc", 206, "Igrave", 204,
"Iota", 921, "Iuml", 207, "Kappa", 922, "Lambda", 923,
"Mu", 924, "Ntilde", 209, "Nu", 925, "OElig", 338,
"Oacute", 211, "Ocirc", 212, "Ograve", 210, "Omega", 937,
"Omicron", 927, "Oslash", 216, "Otilde", 213, "Ouml", 214,
"Phi", 934, "Pi", 928, "Prime", 8243, "Psi", 936,
"Rho", 929, "Scaron", 352, "Sigma", 931, "THORN", 222,
"Tau", 932, "Theta", 920, "Uacute", 218, "Ucirc", 219,
"Ugrave", 217, "Upsilon", 933, "Uuml", 220, "Xi", 926,
"Yacute", 221, "Yuml", 376, "Zeta", 918, "aacute", 225,
"acirc", 226, "acute", 180, "aelig", 230, "agrave", 224,
"alefsym", 8501,"alpha", 945, "amp", 38, "and", 8743,
"ang", 8736, "aring", 229, "asymp", 8776, "atilde", 227,
"auml", 228, "bdquo", 8222, "beta", 946, "brvbar", 166,
"bull", 8226, "cap", 8745, "ccedil", 231, "cdots", 8943,
"cedil", 184, "cent", 162, "chi", 967, "circ", 710,
"clubs", 9827, "cong", 8773, "copy", 169, "crarr", 8629,
"cup", 8746, "curren", 164, "dArr", 8659, "dagger", 8224,
"darr", 8595, "ddots", 8945, "deg", 176, "delta", 948,
"diams", 9830, "divide", 247, "eacute", 233, "ecirc", 234,
"egrave", 232, "emdash", 8212, "empty", 8709, "emsp", 8195,
"endash", 8211, "ensp", 8194, "epsilon", 949, "equiv", 8801,
"eta", 951, "eth", 240, "euml", 235, "euro", 8364,
"exist", 8707, "fnof", 402, "forall", 8704, "frac12", 189,
"frac14", 188, "frac34", 190, "frasl", 8260, "gamma", 947,
"ge", 8805, "gt", 62, "hArr", 8660, "harr", 8596,
"hearts", 9829, "hellip", 8230, "iacute", 237, "icirc", 238,
"iexcl", 161, "igrave", 236, "image", 8465, "infin", 8734,
"int", 8747, "iota", 953, "iquest", 191, "isin", 8712,
"iuml", 239, "kappa", 954, "lArr", 8656, "lambda", 955,
"lang", 9001, "laquo", 171, "larr", 8592, "lceil", 8968,
"ldots", 8230, "ldquo", 8220, "le", 8804, "lfloor", 8970,
"lowast", 8727, "loz", 9674, "lrm", 8206, "lsaquo", 8249,
"lsquo", 8216, "lt", 60, "macr", 175, "mdash", 8212,
"micro", 181, "middot", 183, "minus", 8722, "mu", 956,
"nabla", 8711, "nbsp", 160, "ndash", 8211, "ne", 8800,
"ni", 8715, "not", 172, "notin", 8713, "nsub", 8836,
"ntilde", 241, "nu", 957, "oacute", 243, "ocirc", 244,
"oelig", 339, "ograve", 242, "oline", 8254, "omega", 969,
"omicron", 959, "oplus", 8853, "or", 8744, "ordf", 170,
"ordm", 186, "oslash", 248, "otilde", 245, "otimes", 8855,
"ouml", 246, "para", 182, "part", 8706, "permil", 8240,
"perp", 8869, "phi", 966, "pi", 960, "piv", 982,
"plusmn", 177, "pound", 163, "prime", 8242, "prod", 8719,
"prop", 8733, "psi", 968, "quad", 8193, "quot", 34,
"rArr", 8658, "radic", 8730, "rang", 9002, "raquo", 187,
"rarr", 8594, "rceil", 8969, "rdquo", 8221, "real", 8476,
"reg", 174, "rfloor", 8971, "rho", 961, "rlm", 8207,
"rsaquo", 8250, "rsquo", 8217, "sbquo", 8218, "scaron", 353,
"sdot", 8901, "sect", 167, "shy", 173, "sigma", 963,
"sigmaf", 962, "sim", 8764, "sp", 8194, "spades", 9824,
"sub", 8834, "sube", 8838, "sum", 8721, "sup", 8835,
"sup1", 185, "sup2", 178, "sup3", 179, "supe", 8839,
"szlig", 223, "tau", 964, "there4", 8756, "theta", 952,
"thetasym", 977,"thinsp", 8201, "thorn", 254, "tilde", 732,
"times", 215, "trade", 8482, "uArr", 8657, "uacute", 250,
"uarr", 8593, "ucirc", 251, "ugrave", 249, "uml", 168,
"upsih", 978, "upsilon", 965, "uuml", 252, "varepsilon", 8712,
"varphi", 981, "varpi", 982, "varrho", 1009, "vdots", 8942,
"vsigma", 962, "vtheta", 977, "weierp", 8472, "xi", 958,
"yacute", 253, "yen", 165, "yuml", 255, "zeta", 950,
"zwj", 8205, "zwnj", 8204,
};
Rune
parserune(int c)
{
@ -379,7 +306,7 @@ parserune(int c)
n = 0;
if(c == '&'){
while((c = Bgetc(&in)) > 0){
if(strchr("\n\r\t ;</>", c)){
if(strchr(";&</>\n\r\t ", c)){
if(c != ';')
Bungetc(&in);
if(n == 0)
@ -391,15 +318,15 @@ parserune(int c)
buf[n++] = c;
}
buf[n] = 0;
if(buf[0] == '#')
return atoi(buf+1);
for(i=0; i<nelem(entities); i++){
n = strcmp(buf, entities[i].entity);
if(n == 0)
return entities[i].rune;
if(n < 0)
break;
}
if(strcmp(buf, "lt") == 0)
return '<';
if(strcmp(buf, "gt") == 0)
return '>';
if(strcmp(buf, "quot") == 0)
return '"';
if(strcmp(buf, "amp") == 0)
return '&';
/* use tcs -f html to handle the rest. */
} else {
do {
buf[n++] = c;

View file

@ -192,8 +192,6 @@ enum{
ERR, /* tag must not occur */
};
Tag tag[];
Entity pl_entity[];
int pl_entities;
void rdform(Hglob *);
void endform(Hglob *);
char *pl_getattr(Pair *, char *);

View file

@ -69,272 +69,3 @@ Tag tag[]={
[Tag_frame] "frame", NOEND,
[Tag_end] 0, ERR,
};
Entity pl_entity[]={
"AElig", L'Æ',
"Aacute", L'Á',
"Acirc", L'Â',
"Agrave", L'À',
"Alpha", L'Α',
"Aring", L'Å',
"Atilde", L'Ã',
"Auml", L'Ä',
"Beta", L'Β',
"Ccedil", L'Ç',
"Chi", L'Χ',
"Dagger", L'',
"Delta", L'Δ',
"ETH", L'Ð',
"Eacute", L'É',
"Ecirc", L'Ê',
"Egrave", L'È',
"Epsilon", L'Ε',
"Eta", L'Η',
"Euml", L'Ë',
"Gamma", L'Γ',
"Iacute", L'Í',
"Icirc", L'Î',
"Igrave", L'Ì',
"Iota", L'Ι',
"Iuml", L'Ï',
"Kappa", L'Κ',
"Lambda", L'Λ',
"Mu", L'Μ',
"Ntilde", L'Ñ',
"Nu", L'Ν',
"OElig", L'Œ',
"Oacute", L'Ó',
"Ocirc", L'Ô',
"Ograve", L'Ò',
"Omega", L'Ω',
"Omicron", L'Ο',
"Oslash", L'Ø',
"Otilde", L'Õ',
"Ouml", L'Ö',
"Phi", L'Φ',
"Pi", L'Π',
"Prime", L'',
"Psi", L'Ψ',
"Rho", L'Ρ',
"Scaron", L'Š',
"Sigma", L'Σ',
"THORN", L'Þ',
"Tau", L'Τ',
"Theta", L'Θ',
"Uacute", L'Ú',
"Ucirc", L'Û',
"Ugrave", L'Ù',
"Upsilon", L'Υ',
"Uuml", L'Ü',
"Xi", L'Ξ',
"Yacute", L'Ý',
"Yuml", L'Ÿ',
"Zeta", L'Ζ',
"aacute", L'á',
"acirc", L'â',
"acute", L'´',
"aelig", L'æ',
"agrave", L'à',
"alefsym", L'',
"alpha", L'α',
"amp", L'&',
"and", L'',
"ang", L'',
"aring", L'å',
"asymp", L'',
"atilde", L'ã',
"auml", L'ä',
"bdquo", L'',
"beta", L'β',
"brvbar", L'¦',
"bull", L'',
"cap", L'',
"ccedil", L'ç',
"cdots", L'',
"cedil", L'¸',
"cent", L'¢',
"chi", L'χ',
"circ", L'ˆ',
"clubs", L'',
"cong", L'',
"copy", L'©',
"crarr", L'',
"cup", L'',
"curren", L'¤',
"dArr", L'',
"dagger", L'',
"darr", L'',
"ddots", L'',
"deg", L'°',
"delta", L'δ',
"diams", L'',
"divide", L'÷',
"eacute", L'é',
"ecirc", L'ê',
"egrave", L'è',
"emdash", L'',
"empty", L'',
"emsp", L'',
"endash", L'',
"ensp", L'',
"epsilon", L'ε',
"equiv", L'',
"eta", L'η',
"eth", L'ð',
"euml", L'ë',
"euro", L'',
"exist", L'',
"fnof", L'ƒ',
"forall", L'',
"frac12", L'½',
"frac14", L'¼',
"frac34", L'¾',
"frasl", L'',
"gamma", L'γ',
"ge", L'',
"gt", L'>',
"hArr", L'',
"harr", L'',
"hearts", L'',
"hellip", L'',
"iacute", L'í',
"icirc", L'î',
"iexcl", L'¡',
"igrave", L'ì',
"image", L'',
"infin", L'',
"int", L'',
"iota", L'ι',
"iquest", L'¿',
"isin", L'',
"iuml", L'ï',
"kappa", L'κ',
"lArr", L'',
"lambda", L'λ',
"lang", L'',
"laquo", L'«',
"larr", L'',
"lceil", L'',
"ldots", L'',
"ldquo", L'',
"le", L'',
"lfloor", L'',
"lowast", L'',
"loz", L'',
"lrm", L'',
"lsaquo", L'',
"lsquo", L'',
"lt", L'<',
"macr", L'¯',
"mdash", L'',
"micro", L'µ',
"middot", L'·',
"minus", L'',
"mu", L'μ',
"nabla", L'',
"nbsp", L' ',
"ndash", L'',
"ne", L'',
"ni", L'',
"not", L'¬',
"notin", L'',
"nsub", L'',
"ntilde", L'ñ',
"nu", L'ν',
"oacute", L'ó',
"ocirc", L'ô',
"oelig", L'œ',
"ograve", L'ò',
"oline", L'',
"omega", L'ω',
"omicron", L'ο',
"oplus", L'',
"or", L'',
"ordf", L'ª',
"ordm", L'º',
"oslash", L'ø',
"otilde", L'õ',
"otimes", L'',
"ouml", L'ö',
"para", L'',
"part", L'',
"permil", L'',
"perp", L'',
"phi", L'φ',
"pi", L'π',
"piv", L'ϖ',
"plusmn", L'±',
"pound", L'£',
"prime", L'',
"prod", L'',
"prop", L'',
"psi", L'ψ',
"quad", L'',
"quot", L'"',
"rArr", L'',
"radic", L'',
"rang", L'',
"raquo", L'»',
"rarr", L'',
"rceil", L'',
"rdquo", L'',
"real", L'',
"reg", L'®',
"rfloor", L'',
"rho", L'ρ',
"rlm", L'',
"rsaquo", L'',
"rsquo", L'',
"sbquo", L'',
"scaron", L'š',
"sdot", L'',
"sect", L'§',
"shy", L'­',
"sigma", L'σ',
"sigmaf", L'ς',
"sim", L'',
"sp", L'',
"spades", L'',
"sub", L'',
"sube", L'',
"sum", L'',
"sup", L'',
"sup1", L'¹',
"sup2", L'²',
"sup3", L'³',
"supe", L'',
"szlig", L'ß',
"tau", L'τ',
"there4", L'',
"theta", L'θ',
"thetasym", L'ϑ',
"thinsp", L'',
"thorn", L'þ',
"tilde", L'˜',
"times", L'×',
"trade", L'',
"uArr", L'',
"uacute", L'ú',
"uarr", L'',
"ucirc", L'û',
"ugrave", L'ù',
"uml", L'¨',
"upsih", L'ϒ',
"upsilon", L'υ',
"uuml", L'ü',
"varepsilon", L'',
"varphi", L'ϕ',
"varpi", L'ϖ',
"varrho", L'ϱ',
"vdots", L'',
"vsigma", L'ς',
"vtheta", L'ϑ',
"weierp", L'',
"xi", L'ξ',
"yacute", L'ý',
"yen", L'¥',
"yuml", L'ÿ',
"zeta", L'ζ',
"zwj", L'',
"zwnj", L'',
};
int pl_entities = nelem(pl_entity);

View file

@ -11,7 +11,7 @@ CFILES= \
rdhtml.c \
OFILES=${CFILES:%.c=%.$O} version.$O
HFILES=mothra.h html.h tcs.h libpanel/panel.h libpanel/rtext.h
HFILES=mothra.h html.h libpanel/panel.h libpanel/rtext.h
BIN=/$objtype/bin
</sys/src/cmd/mkone

View file

@ -898,12 +898,15 @@ void geturl(char *urlname, int method, char *body, int cache, int map){
fd=pipeline("/bin/uncompress", fd);
else if(selection->type&GUNZIP)
fd=pipeline("/bin/gunzip", fd);
snprint(cmd, sizeof(cmd), selection->charset[0] ?
"/bin/uhtml -c %s" : "/bin/uhtml", selection->charset);
fd = pipeline(cmd, fd);
switch(selection->type&~COMPRESSION){
default:
message("Bad type %x in geturl", selection->type);
break;
case PLAIN:
case HTML:
case PLAIN:
w = www(i = wwwtop++);
if(i >= NWWW){
extern void freeform(void *p);

View file

@ -154,58 +154,6 @@ void pl_htmloutput(Hglob *g, int nsp, char *s, Field *field){
g->dst->changed=1;
}
void pl_applycharset(Hglob *g)
{
int fd, pfd[2], n;
char buf[NHBUF];
char **cs, *charset;
charset = nil;
for(cs = tcs; *cs; cs += 2){
if(cistrcmp(cs[0], g->charset) == 0){
charset = cs[1];
break;
}
}
/* make sure we dont convet multiple times */
g->charset[0]=0;
/* no match, dont convert */
if(charset == nil)
return;
fd = g->hfd;
n = g->ehbuf - g->hbufp;
memcpy(buf, g->hbufp, n);
if(pipe(pfd)==-1)
return;
switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
case -1:
close(pfd[0]);
close(pfd[1]);
return;
case 0:
dup(fd, 0);
dup(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
close(fd);
write(1, buf, n);
while((n=read(0, buf, sizeof(buf)))>0)
write(1, buf, n);
_exits("no exec!");
}
dup(pfd[0], fd);
close(pfd[0]);
close(pfd[1]);
g->hbufp = g->ehbuf;
snprint(buf, sizeof(buf), "tcs -s -f %s -t utf", charset);
if((fd=pipeline(buf, fd)) >= 0)
g->hfd = fd;
}
/*
* Buffered read, no translation
* Save in cache.
@ -297,22 +245,6 @@ int pl_nextc(Hglob *g){
int entchar(int c){
return c=='#' || 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9';
}
Entity *entsearch(char *s){
int i, m, n, r;
i=0;
n=pl_entities;
while ((n-i) > 0) {
m=i+(n-i)/2;
r=strcmp(s, pl_entity[m].name);
if (r > 0)
i=m+1;
else if (r < 0)
n=m;
else
return &pl_entity[m];
}
return 0;
}
/*
* remove entity references, in place.
* Potential bug:
@ -333,30 +265,22 @@ void pl_rmentities(Hglob *g, char *s){
u=s;
while(entchar(*s)) s++;
svc=*s;
if(svc!=';')
htmlerror(g->name, g->lineno, "entity syntax error");
*s++='\0';
if(*u=='#'){
if (u[1]=='X' || u[1]=='x')
r=strtol(u+2, 0, 16);
else
r=atoi(u+1);
t+=runetochar(t, &r);
if(svc!=';') *--s=svc;
}
else{
ep=entsearch(u);
if(ep && ep->name){
t+=runetochar(t, &ep->value);
if(svc!=';') *--s=svc;
}
else{
htmlerror(g->name, g->lineno,
"unknown entity %s", u);
s[-1]=svc;
s=u;
*t++='&';
}
*s = 0;
if(svc==';') s++;
if(strcmp(u, "lt") == 0)
*t++='<';
else if(strcmp(u, "gt") == 0)
*t++='>';
else if(strcmp(u, "quot") == 0)
*t++='"';
else if(strcmp(u, "amp") == 0)
*t++='&';
else {
if(svc==';') s--;
*s=svc;
*t++='&';
while(u<s)
*t++=*u++;
}
}
else *t++=c;
@ -644,7 +568,6 @@ void plrdplain(char *name, int fd, Www *dst){
g.spacc=0;
g.form=0;
strncpy(g.text, name, NTITLE);
pl_applycharset(&g);
plaintext(&g);
dst->finished=1;
}
@ -713,13 +636,6 @@ void plrdhtml(char *name, int fd, Www *dst){
case Tag_end: /* unrecognized start tag */
break;
case Tag_meta:
if((str=pl_getattr(g.attr, "http-equiv")) &&
(cistrcmp(str, "content-type"))==0 &&
(str=pl_getattr(g.attr, "content")) &&
(str=cistrstr(str, "charset="))){
strncpy(g.charset, str+8, sizeof(g.charset));
pl_applycharset(&g);
}
break;
case Tag_img:
if(str=pl_getattr(g.attr, "src"))
@ -805,7 +721,7 @@ void plrdhtml(char *name, int fd, Www *dst){
g.state->indent=20;
break;
case Tag_body:
pl_applycharset(&g);
break;
case Tag_head:
g.state->font=ROMAN;
g.state->size=NORMAL;

View file

@ -626,7 +626,7 @@ popenfile(Page *p)
else if(cistrncmp(buf, "<?xml", 5) == 0 ||
cistrncmp(buf, "<!DOCTYPE", 9) == 0 ||
cistrncmp(buf, "<HTML", 5) == 0){
p->data = "html2ms | troff -ms | lp -dstdout";
p->data = "uhtml | html2ms | troff -ms | lp -dstdout";
p->open = popengs;
}
else if(memcmp(buf, "\xF7\x02\x01\x83\x92\xC0\x1C;", 8) == 0){

121
sys/src/cmd/uhtml.c Normal file
View file

@ -0,0 +1,121 @@
#include <u.h>
#include <libc.h>
#include <ctype.h>
int nbuf;
char buf[4096+1];
char *cset = "utf";
void
usage(void)
{
fprint(2, "%s [ -h ] [ -c charset ] [ file ]\n", argv0);
exits("usage");
}
char*
strval(char *s)
{
char *e, q;
while(strchr("\t ", *s))
s++;
q = 0;
if(*s == '"' || *s == '\'')
q = *s++;
for(e = s; *e; e++){
if(*e == q)
break;
if(isalnum(*e))
continue;
if(*e == '-' || *e == '_')
continue;
break;
}
if(e - s > 1)
return smprint("%.*s", (int)(e-s), s);
return nil;
}
void
main(int argc, char *argv[])
{
int pfd[2], pflag = 0;
char *arg[4], *s;
ARGBEGIN {
case 'h':
usage();
case 'c':
cset = EARGF(usage());
break;
case 'p':
pflag = 1;
break;
} ARGEND;
if(*argv){
close(0);
if(open(*argv, OREAD) != 1)
sysfatal("open: %r");
}
if((nbuf = read(0, buf, sizeof(buf)-1)) < 0)
sysfatal("read: %r");
buf[nbuf] = 0;
for(;;){
if(s = cistrstr(buf, "encoding="))
if(s = strval(s+9)){
cset = s;
break;
}
if(s = cistrstr(buf, "charset="))
if(s = strval(s+8)){
cset = s;
break;
}
break;
}
if(pflag){
print("%s\n", cset);
exits(0);
}
if(pipe(pfd) < 0)
sysfatal("pipe: %r");
if(nbuf == 0){
write(1, buf, 0);
exits(0);
}
switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT)){
case -1:
sysfatal("fork: %r");
case 0:
dup(pfd[0], 0);
close(pfd[0]);
close(pfd[1]);
arg[0] = "rc";
arg[1] = "-c";
if(strcmp(cset, "utf"))
arg[2] = smprint("tcs -f %s -t utf | tcs -f html -t utf", cset);
else
arg[2] = "tcs -f html -t utf";
arg[3] = nil;
exec("/bin/rc", arg);
}
dup(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
while(nbuf > 0){
if(write(1, buf, nbuf) != nbuf)
sysfatal("write: %r");
if((nbuf = read(0, buf, sizeof(buf))) < 0)
sysfatal("read: %r");
}
exits(0);
}