| /* |
| * 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)); |
| } |
| |