add
diff --git a/src/cmd/htmlroff/html.c b/src/cmd/htmlroff/html.c
new file mode 100644
index 0000000..fd48382
--- /dev/null
+++ b/src/cmd/htmlroff/html.c
@@ -0,0 +1,287 @@
+/*
+ * Emit html.  Keep track of tags so that user doesn't have to.
+ */
+
+#include "a.h"
+
+typedef struct Tag Tag;
+struct Tag
+{
+	Tag *next;
+	Rune *id;
+	Rune *open;
+	Rune *close;
+};
+
+Tag *tagstack;
+Tag *tagset;
+int hidingset;
+
+static Rune*
+closingtag(Rune *s)
+{
+	Rune *t;
+	Rune *p0, *p;
+	
+	t = runemalloc(sizeof(Rune));
+	if(s == nil)
+		return t;
+	for(p=s; *p; p++){
+		if(*p == Ult){
+			p++;
+			if(*p == '/'){
+				while(*p && *p != Ugt)
+					p++;
+				goto close;
+			}
+			p0 = p;
+			while(*p && !isspacerune(*p) && *p != Uspace && *p != Ugt)
+				p++;
+			t = runerealloc(t, 1+(p-p0)+2+runestrlen(t)+1);
+			runemove(t+(p-p0)+3, t, runestrlen(t)+1);
+			t[0] = Ult;
+			t[1] = '/';
+			runemove(t+2, p0, p-p0);
+			t[2+(p-p0)] = Ugt;
+		}
+		
+		if(*p == Ugt && p>s && *(p-1) == '/'){
+		close:
+			for(p0=t+1; *p0 && *p0 != Ult; p0++)
+				;
+			runemove(t, p0, runestrlen(p0)+1);
+		}
+	}
+	return t;	
+}
+
+void
+html(Rune *id, Rune *s)
+{
+	Rune *es;
+	Tag *t, *tt, *next;
+
+	br();
+	hideihtml();	/* br already did, but be paranoid */
+	for(t=tagstack; t; t=t->next){
+		if(runestrcmp(t->id, id) == 0){
+			for(tt=tagstack;; tt=next){
+				next = tt->next;
+				free(tt->id);
+				free(tt->open);
+				out(tt->close);
+				outrune('\n');
+				free(tt->close);
+				free(tt);
+				if(tt == t){
+					tagstack = next;
+					goto cleared;
+				}
+			}
+		}
+	}
+
+cleared:
+	if(s == nil || s[0] == 0)
+		return;
+	out(s);
+	outrune('\n');
+	es = closingtag(s);
+	if(es[0] == 0){
+		free(es);
+		return;
+	}
+	if(runestrcmp(id, L("-")) == 0){
+		out(es);
+		outrune('\n');
+		free(es);
+		return;
+	}
+	t = emalloc(sizeof *t);
+	t->id = erunestrdup(id);
+	t->close = es;
+	t->next = tagstack;
+	tagstack = t;
+}
+
+void
+closehtml(void)
+{
+	Tag *t, *next;
+	
+	br();
+	hideihtml();
+	for(t=tagstack; t; t=next){
+		next = t->next;
+		out(t->close);
+		outrune('\n');
+		free(t->id);
+		free(t->close);
+		free(t);
+	}
+}
+
+static void
+rshow(Tag *t, Tag *end)
+{
+	if(t == nil || t == end)
+		return;
+	rshow(t->next, end);
+	out(t->open);
+}
+
+void
+ihtml(Rune *id, Rune *s)
+{
+	Tag *t, *tt, **l;
+
+	for(t=tagset; t; t=t->next){
+		if(runestrcmp(t->id, id) == 0){
+			if(s && t->open && runestrcmp(t->open, s) == 0)
+				return;
+			for(l=&tagset; (tt=*l); l=&tt->next){
+				if(!hidingset)
+					out(tt->close);
+				if(tt == t)
+					break;
+			}
+			*l = t->next;
+			free(t->id);
+			free(t->close);
+			free(t->open);
+			free(t);
+			if(!hidingset)
+				rshow(tagset, *l);
+			goto cleared;
+		}
+	}
+
+cleared:
+	if(s == nil || s[0] == 0)
+		return;
+	t = emalloc(sizeof *t);
+	t->id = erunestrdup(id);
+	t->open = erunestrdup(s);
+	t->close = closingtag(s);
+	if(!hidingset)
+		out(s);
+	t->next = tagset;
+	tagset = t;
+}
+
+void
+hideihtml(void)
+{
+	Tag *t;
+
+	if(hidingset)
+		return;
+	hidingset = 1;
+	for(t=tagset; t; t=t->next)
+		out(t->close);
+}
+
+void
+showihtml(void)
+{
+	if(!hidingset)
+		return;
+	hidingset = 0;
+	rshow(tagset, nil);
+}
+
+int
+e_lt(void)
+{
+	return Ult;
+}
+
+int
+e_gt(void)
+{
+	return Ugt;
+}
+
+int
+e_at(void)
+{
+	return Uamp;
+}
+
+int
+e_tick(void)
+{
+	return Utick;
+}
+
+int
+e_btick(void)
+{
+	return Ubtick;
+}
+
+int
+e_minus(void)
+{
+	return Uminus;
+}
+
+void
+r_html(Rune *name)
+{
+	Rune *id, *line, *p;
+	
+	id = copyarg();
+	line = readline(HtmlMode);
+	for(p=line; *p; p++){
+		switch(*p){
+		case '<':
+			*p = Ult;
+			break;
+		case '>':
+			*p = Ugt;
+			break;
+		case '&':
+			*p = Uamp;
+			break;
+		case ' ':
+			*p = Uspace;
+			break;
+		}
+	}
+	if(name[0] == 'i')
+		ihtml(id, line);
+	else
+		html(id, line);
+	free(id);
+	free(line);
+}
+
+char defaultfont[] =
+	".ihtml f1\n"
+	".ihtml f\n"
+	".ihtml f <span style=\"font-size=\\n(.spt\">\n"
+	".if \\n(.f==2 .ihtml f1 <i>\n"
+	".if \\n(.f==3 .ihtml f1 <b>\n"
+	".if \\n(.f==4 .ihtml f1 <b><i>\n"
+	".if \\n(.f==5 .ihtml f1 <tt>\n"
+	".if \\n(.f==6 .ihtml f1 <tt><i>\n"
+	"..\n"
+;
+
+void
+htmlinit(void)
+{
+	addraw(L("html"), r_html);
+	addraw(L("ihtml"), r_html);
+
+	addesc('<', e_lt, CopyMode);
+	addesc('>', e_gt, CopyMode);
+	addesc('\'', e_tick, CopyMode);
+	addesc('`', e_btick, CopyMode);
+	addesc('-', e_minus, CopyMode);
+	addesc('@', e_at, CopyMode);
+	
+	ds(L("font"), L(defaultfont));
+}
+