ref: 28f4567ba615c4036c079021392825757ef2a008
dir: /sys/src/cmd/htmlroff/html.c/
/* * 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)); }