ref: a31e4f61a4c9afb9696a7ff4ff09e02b3281a2f3
parent: e7df0daa66531eccb2d37f7b66e27d16c9ae4391
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Mon Sep 19 20:38:28 EDT 2011
uhtml: add html to unicode converter, used by mothra and page/html2ms
--- a/sys/src/cmd/html2ms.c
+++ b/sys/src/cmd/html2ms.c
@@ -296,79 +296,6 @@
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 @@
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 @@
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;
--- a/sys/src/cmd/mothra/html.h
+++ b/sys/src/cmd/mothra/html.h
@@ -192,8 +192,6 @@
ERR, /* tag must not occur */
};
Tag tag[];
-Entity pl_entity[];
-int pl_entities;
void rdform(Hglob *);
void endform(Hglob *);
char *pl_getattr(Pair *, char *);
--- a/sys/src/cmd/mothra/html.syntax.c
+++ b/sys/src/cmd/mothra/html.syntax.c
@@ -69,272 +69,3 @@
[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);
--- a/sys/src/cmd/mothra/mkfile
+++ b/sys/src/cmd/mothra/mkfile
@@ -11,7 +11,7 @@
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
--- a/sys/src/cmd/mothra/mothra.c
+++ b/sys/src/cmd/mothra/mothra.c
@@ -898,12 +898,15 @@
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);
--- a/sys/src/cmd/mothra/rdhtml.c
+++ b/sys/src/cmd/mothra/rdhtml.c
@@ -154,58 +154,6 @@
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 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,31 +265,23 @@
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;
+ *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{
- 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++='&';
- }
- }
}
else *t++=c;
}while(c);
@@ -644,7 +568,6 @@
g.spacc=0;
g.form=0;
strncpy(g.text, name, NTITLE);
- pl_applycharset(&g);
plaintext(&g);
dst->finished=1;
}
@@ -713,13 +636,6 @@
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 @@
g.state->indent=20;
break;
case Tag_body:
- pl_applycharset(&g);
+ break;
case Tag_head:
g.state->font=ROMAN;
g.state->size=NORMAL;
--- a/sys/src/cmd/page.c
+++ b/sys/src/cmd/page.c
@@ -626,7 +626,7 @@
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){
--- /dev/null
+++ b/sys/src/cmd/uhtml.c
@@ -1,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);
+}