2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <bio.h>
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
typedef struct Tag Tag;
|
|
|
|
typedef struct Attr Attr;
|
|
|
|
typedef struct Text Text;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
struct Attr {
|
|
|
|
char attr[64];
|
|
|
|
char val[256-64];
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
struct Tag {
|
|
|
|
Tag *up;
|
|
|
|
char tag[32];
|
|
|
|
Attr attr[16];
|
|
|
|
int nattr;
|
|
|
|
int opening;
|
|
|
|
int closing;
|
|
|
|
|
|
|
|
void (*close)(Text *, Tag *);
|
|
|
|
union {
|
|
|
|
void *aux;
|
|
|
|
int restore;
|
|
|
|
};
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
struct Text {
|
2011-09-20 00:21:54 +00:00
|
|
|
char* font;
|
2011-09-18 18:35:57 +00:00
|
|
|
int pre;
|
|
|
|
int pos;
|
|
|
|
int space;
|
|
|
|
int output;
|
2011-09-20 00:21:54 +00:00
|
|
|
int underline;
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
void eatwhite(void);
|
|
|
|
Tag *parsetext(Text *, Tag *);
|
|
|
|
int parsetag(Tag *);
|
|
|
|
int parseattr(Attr *);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
Biobuf in, out;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
void
|
|
|
|
emit(Text *text, char *fmt, ...)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
va_list a;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
if(text->pos > 0){
|
|
|
|
text->pos = 0;
|
|
|
|
Bputc(&out, '\n');
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-09-18 18:35:57 +00:00
|
|
|
va_start(a, fmt);
|
|
|
|
Bvprint(&out, fmt, a);
|
|
|
|
va_end(a);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
restoreoutput(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
text->output = tag->restore;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
ongarbage(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
tag->restore = text->output;
|
|
|
|
tag->close = restoreoutput;
|
|
|
|
text->output = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onp(Text *text, Tag *)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
emit(text, ".LP\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
restorepre(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
text->pre = tag->restore;
|
|
|
|
emit(text, ".DE\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onpre(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
tag->restore = text->pre;
|
|
|
|
tag->close = restorepre;
|
|
|
|
text->pre = 1;
|
|
|
|
emit(text, ".DS L\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onli(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
if(tag->up && cistrcmp(tag->up->tag, "ol") == 0)
|
|
|
|
emit(text, ".IP\n");
|
|
|
|
else
|
|
|
|
emit(text, ".IP \\(bu\n");
|
|
|
|
if(tag->up)
|
|
|
|
tag->up->close = onp;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onh(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
emit(text, ".SH %c\n", tag->tag[1]);
|
|
|
|
tag->close = onp;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onbr(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
tag->closing = 1;
|
|
|
|
emit(text, ".br\n");
|
|
|
|
if(cistrcmp(tag->tag, "hr") == 0)
|
|
|
|
emit(text, "\\l'5i'\n.br\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
restorefont(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-20 00:21:54 +00:00
|
|
|
text->font = tag->aux;
|
|
|
|
text->pos += Bprint(&out, "\\f%s", text->font);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
onfont(Text *text, Tag *tag)
|
|
|
|
{
|
|
|
|
if(text->font == 0)
|
2011-09-20 00:21:54 +00:00
|
|
|
text->font = "R";
|
|
|
|
tag->aux = text->font;
|
2011-09-18 18:35:57 +00:00
|
|
|
tag->close = restorefont;
|
|
|
|
if(cistrcmp(tag->tag, "i") == 0)
|
2011-09-20 00:21:54 +00:00
|
|
|
text->font = "I";
|
2011-09-18 18:35:57 +00:00
|
|
|
else if(cistrcmp(tag->tag, "b") == 0)
|
2011-09-20 00:21:54 +00:00
|
|
|
text->font = "B";
|
|
|
|
text->pos += Bprint(&out, "\\f%s", text->font);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-20 02:14:29 +00:00
|
|
|
restoreunderline(Text *text, Tag *tag)
|
2011-09-20 00:21:54 +00:00
|
|
|
{
|
2011-09-20 02:14:29 +00:00
|
|
|
text->underline = tag->restore;
|
|
|
|
emit(text, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ona(Text *text, Tag *tag)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<tag->nattr; i++)
|
|
|
|
if(cistrcmp(tag->attr[i].attr, "href") == 0)
|
|
|
|
break;
|
|
|
|
if(i == tag->nattr)
|
|
|
|
return;
|
|
|
|
tag->restore = text->underline;
|
|
|
|
tag->close = restoreunderline;
|
2011-09-20 00:21:54 +00:00
|
|
|
text->underline = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
struct {
|
|
|
|
char *tag;
|
|
|
|
void (*open)(Text *, Tag *);
|
|
|
|
} ontag[] = {
|
2011-09-20 00:21:54 +00:00
|
|
|
"a", ona,
|
2011-09-18 18:35:57 +00:00
|
|
|
"br", onbr,
|
|
|
|
"hr", onbr,
|
|
|
|
"b", onfont,
|
|
|
|
"i", onfont,
|
|
|
|
"p", onp,
|
|
|
|
"h1", onh,
|
|
|
|
"h2", onh,
|
|
|
|
"h3", onh,
|
|
|
|
"h4", onh,
|
|
|
|
"h5", onh,
|
2011-09-20 00:21:54 +00:00
|
|
|
"h6", onh,
|
2011-09-18 18:35:57 +00:00
|
|
|
"li", onli,
|
|
|
|
"pre", onpre,
|
|
|
|
"head", ongarbage,
|
|
|
|
"style", ongarbage,
|
|
|
|
"script", ongarbage,
|
|
|
|
};
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
eatwhite(void)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
int c;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(strchr("\n\r\t ", c) == nil){
|
|
|
|
Bungetc(&in);
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
parsecomment(void)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
char buf[64];
|
|
|
|
int n, c;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
n = 0;
|
|
|
|
eatwhite();
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(c == '>')
|
|
|
|
return;
|
|
|
|
if(n == 0 && c == '-'){
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(c == '-')
|
|
|
|
if(Bgetc(&in) == '-')
|
|
|
|
if(Bgetc(&in) == '>')
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(n+1 < sizeof(buf)){
|
|
|
|
buf[n++] = c;
|
|
|
|
if(n != 7 || cistrncmp(buf, "[CDATA[", 7))
|
|
|
|
continue;
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
2011-09-20 02:14:29 +00:00
|
|
|
if(c == ']'){
|
|
|
|
if(Bgetc(&in) == ']'){
|
|
|
|
if(Bgetc(&in) != '>')
|
|
|
|
Bungetc(&in);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-09-18 18:35:57 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
int
|
|
|
|
parseattr(Attr *a)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
int q, c, n;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
n = 0;
|
|
|
|
eatwhite();
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(strchr("</>=?!", c)){
|
|
|
|
Bungetc(&in);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(strchr("\n\r\t ", c))
|
|
|
|
break;
|
|
|
|
if(n < sizeof(a->attr)-1)
|
|
|
|
a->attr[n++] = c;
|
|
|
|
}
|
|
|
|
if(n == 0)
|
|
|
|
return 0;
|
|
|
|
a->attr[n] = 0;
|
|
|
|
n = 0;
|
|
|
|
eatwhite();
|
|
|
|
if(Bgetc(&in) == '='){
|
|
|
|
eatwhite();
|
|
|
|
c = Bgetc(&in);
|
|
|
|
if(strchr("'\"", c)){
|
|
|
|
q = c;
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(c == q)
|
|
|
|
break;
|
|
|
|
if(n < sizeof(a->val)-1)
|
|
|
|
a->val[n++] = c;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Bungetc(&in);
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(strchr("\n\r\t </>?!", c)){
|
|
|
|
Bungetc(&in);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(n < sizeof(a->val)-1)
|
|
|
|
a->val[n++] = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
Bungetc(&in);
|
|
|
|
a->val[n] = 0;
|
|
|
|
return 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
int
|
|
|
|
parsetag(Tag *t)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
int n, c;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
t->nattr = 0;
|
|
|
|
t->opening = 1;
|
|
|
|
t->closing = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
n = 0;
|
|
|
|
eatwhite();
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(c == '>')
|
|
|
|
break;
|
|
|
|
if(strchr("\n\r\t ", c)){
|
|
|
|
if(parseattr(t->attr + t->nattr))
|
|
|
|
if(t->nattr < nelem(t->attr)-1)
|
|
|
|
t->nattr++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(n == 0 && strchr("?!", c)){
|
|
|
|
parsecomment();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(c == '/'){
|
|
|
|
if(n == 0){
|
|
|
|
t->opening = 0;
|
|
|
|
t->closing = 1;
|
|
|
|
} else
|
|
|
|
t->closing = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(n < sizeof(t->tag)-1)
|
|
|
|
t->tag[n++] = c;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2011-09-18 18:35:57 +00:00
|
|
|
t->tag[n] = 0;
|
|
|
|
return n > 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
Rune
|
|
|
|
parserune(int c)
|
|
|
|
{
|
|
|
|
char buf[10];
|
2011-09-20 00:21:54 +00:00
|
|
|
int n;
|
2011-09-18 18:35:57 +00:00
|
|
|
Rune r;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
if(c == '&'){
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
2011-09-19 22:38:28 +00:00
|
|
|
if(strchr(";&</>\n\r\t ", c)){
|
2011-09-18 18:35:57 +00:00
|
|
|
if(c != ';')
|
|
|
|
Bungetc(&in);
|
|
|
|
if(n == 0)
|
|
|
|
return '&';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(n == sizeof(buf)-1)
|
|
|
|
break;
|
|
|
|
buf[n++] = c;
|
|
|
|
}
|
|
|
|
buf[n] = 0;
|
2011-09-19 22:38:28 +00:00
|
|
|
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. */
|
2011-09-18 18:35:57 +00:00
|
|
|
} else {
|
|
|
|
do {
|
|
|
|
buf[n++] = c;
|
|
|
|
if(fullrune(buf, n)){
|
|
|
|
chartorune(&r, buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if(n >= UTFmax)
|
|
|
|
break;
|
|
|
|
} while((c = Bgetc(&in)) > 0);
|
|
|
|
}
|
|
|
|
return 0xFFFD;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
Rune
|
|
|
|
substrune(Rune r)
|
|
|
|
{
|
|
|
|
switch(r){
|
|
|
|
case 0x2019:
|
|
|
|
case 0x2018:
|
|
|
|
return '\'';
|
|
|
|
case 0x201c:
|
|
|
|
case 0x201d:
|
|
|
|
return '"';
|
|
|
|
default:
|
|
|
|
return r;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
debugtag(Tag *tag, char *dbg)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
if(1) return;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
if(tag == nil)
|
|
|
|
return;
|
|
|
|
debugtag(tag->up, nil);
|
|
|
|
fprint(2, "%s %s%s", tag->tag, dbg ? dbg : " > ", dbg ? "\n" : "");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
Tag*
|
|
|
|
parsetext(Text *text, Tag *tag)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
Tag *rtag;
|
|
|
|
Rune r;
|
|
|
|
int c;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
rtag = tag;
|
|
|
|
debugtag(tag, "open");
|
|
|
|
if(tag == nil || tag->closing == 0){
|
|
|
|
while((c = Bgetc(&in)) > 0){
|
|
|
|
if(c == '<'){
|
|
|
|
Tag t;
|
|
|
|
|
|
|
|
memset(&t, 0, sizeof(t));
|
|
|
|
if(parsetag(&t)){
|
|
|
|
if(t.opening){
|
|
|
|
t.up = tag;
|
|
|
|
for(c = 0; c < nelem(ontag); c++){
|
|
|
|
if(cistrcmp(t.tag, ontag[c].tag) == 0){
|
|
|
|
ontag[c].open(text, &t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rtag = parsetext(text, &t);
|
|
|
|
if(rtag == &t)
|
|
|
|
rtag = tag;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
} else if(t.closing){
|
|
|
|
while(rtag && cistrcmp(rtag->tag, t.tag))
|
|
|
|
rtag = rtag->up;
|
|
|
|
if(rtag == nil)
|
|
|
|
rtag = tag;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(!text->output)
|
|
|
|
continue;
|
|
|
|
r = substrune(parserune(c));
|
|
|
|
switch(r){
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
2011-09-20 02:14:29 +00:00
|
|
|
text->space = 1;
|
|
|
|
if(text->pre == 0)
|
2011-09-18 18:35:57 +00:00
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
if(r == '\n' || r == '\r')
|
|
|
|
text->pos = 0;
|
|
|
|
if(text->space){
|
|
|
|
text->space = 0;
|
2011-09-20 00:21:54 +00:00
|
|
|
if(text->underline){
|
2011-09-20 02:14:29 +00:00
|
|
|
emit(text, ".UL ");
|
|
|
|
text->pos = 1;
|
2011-09-20 00:21:54 +00:00
|
|
|
} else if(text->pos >= 70){
|
2011-09-18 18:35:57 +00:00
|
|
|
text->pos = 0;
|
|
|
|
Bputc(&out, '\n');
|
|
|
|
} else if(text->pos > 0){
|
|
|
|
text->pos++;
|
|
|
|
Bputc(&out, ' ');
|
|
|
|
}
|
|
|
|
}
|
2011-09-20 02:14:29 +00:00
|
|
|
if(text->pos == 0 && r == '.')
|
|
|
|
text->pos += Bprint(&out, "\\&");
|
|
|
|
else if(r == '\\')
|
|
|
|
text->pos += Bprint(&out, "\\&\\");
|
|
|
|
else if(r == 0xA0){
|
2011-09-18 18:35:57 +00:00
|
|
|
r = ' ';
|
2011-09-20 02:14:29 +00:00
|
|
|
text->pos += Bprint(&out, "\\");
|
2011-09-18 18:35:57 +00:00
|
|
|
}
|
2011-09-20 02:14:29 +00:00
|
|
|
text->pos += Bprint(&out, "%C", r);
|
2011-09-18 18:35:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debugtag(tag, "close");
|
|
|
|
if(tag && tag->close)
|
|
|
|
tag->close(text, tag);
|
|
|
|
return rtag;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-09-18 18:35:57 +00:00
|
|
|
main(void)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-09-18 18:35:57 +00:00
|
|
|
Text text;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
Binit(&in, 0, OREAD);
|
|
|
|
Binit(&out, 1, OWRITE);
|
|
|
|
|
|
|
|
memset(&text, 0, sizeof(text));
|
2011-09-20 02:14:29 +00:00
|
|
|
|
|
|
|
text.font = "R";
|
2011-09-18 18:35:57 +00:00
|
|
|
text.output = 1;
|
2011-09-20 02:14:29 +00:00
|
|
|
|
2011-09-18 18:35:57 +00:00
|
|
|
parsetext(&text, nil);
|
|
|
|
emit(&text, "\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|