Blob
1 /*2 * Emit html. Keep track of tags so that user doesn't have to.3 */5 #include "a.h"7 typedef struct Tag Tag;8 struct Tag9 {10 Tag *next;11 Rune *id;12 Rune *open;13 Rune *close;14 };16 Tag *tagstack;17 Tag *tagset;18 int hidingset;20 static Rune*21 closingtag(Rune *s)22 {23 Rune *t;24 Rune *p0, *p;26 t = runemalloc(sizeof(Rune));27 if(s == nil)28 return t;29 for(p=s; *p; p++){30 if(*p == Ult){31 p++;32 if(*p == '/'){33 while(*p && *p != Ugt)34 p++;35 goto close;36 }37 p0 = p;38 while(*p && !isspacerune(*p) && *p != Uspace && *p != Ugt)39 p++;40 t = runerealloc(t, 1+(p-p0)+2+runestrlen(t)+1);41 runemove(t+(p-p0)+3, t, runestrlen(t)+1);42 t[0] = Ult;43 t[1] = '/';44 runemove(t+2, p0, p-p0);45 t[2+(p-p0)] = Ugt;46 }48 if(*p == Ugt && p>s && *(p-1) == '/'){49 close:50 for(p0=t+1; *p0 && *p0 != Ult; p0++)51 ;52 runemove(t, p0, runestrlen(p0)+1);53 }54 }55 return t;56 }58 void59 html(Rune *id, Rune *s)60 {61 Rune *es;62 Tag *t, *tt, *next;64 br();65 hideihtml(); /* br already did, but be paranoid */66 for(t=tagstack; t; t=t->next){67 if(runestrcmp(t->id, id) == 0){68 for(tt=tagstack;; tt=next){69 next = tt->next;70 free(tt->id);71 free(tt->open);72 out(tt->close);73 outrune('\n');74 free(tt->close);75 free(tt);76 if(tt == t){77 tagstack = next;78 goto cleared;79 }80 }81 }82 }84 cleared:85 if(s == nil || s[0] == 0)86 return;87 out(s);88 outrune('\n');89 es = closingtag(s);90 if(es[0] == 0){91 free(es);92 return;93 }94 if(runestrcmp(id, L("-")) == 0){95 out(es);96 outrune('\n');97 free(es);98 return;99 }100 t = emalloc(sizeof *t);101 t->id = erunestrdup(id);102 t->close = es;103 t->next = tagstack;104 tagstack = t;105 }107 void108 closehtml(void)109 {110 Tag *t, *next;112 br();113 hideihtml();114 for(t=tagstack; t; t=next){115 next = t->next;116 out(t->close);117 outrune('\n');118 free(t->id);119 free(t->close);120 free(t);121 }122 }124 static void125 rshow(Tag *t, Tag *end)126 {127 if(t == nil || t == end)128 return;129 rshow(t->next, end);130 out(t->open);131 }133 void134 ihtml(Rune *id, Rune *s)135 {136 Tag *t, *tt, **l;138 for(t=tagset; t; t=t->next){139 if(runestrcmp(t->id, id) == 0){140 if(s && t->open && runestrcmp(t->open, s) == 0)141 return;142 for(l=&tagset; (tt=*l); l=&tt->next){143 if(!hidingset)144 out(tt->close);145 if(tt == t)146 break;147 }148 *l = t->next;149 free(t->id);150 free(t->close);151 free(t->open);152 free(t);153 if(!hidingset)154 rshow(tagset, *l);155 goto cleared;156 }157 }159 cleared:160 if(s == nil || s[0] == 0)161 return;162 t = emalloc(sizeof *t);163 t->id = erunestrdup(id);164 t->open = erunestrdup(s);165 t->close = closingtag(s);166 if(!hidingset)167 out(s);168 t->next = tagset;169 tagset = t;170 }172 void173 hideihtml(void)174 {175 Tag *t;177 if(hidingset)178 return;179 hidingset = 1;180 for(t=tagset; t; t=t->next)181 out(t->close);182 }184 void185 showihtml(void)186 {187 if(!hidingset)188 return;189 hidingset = 0;190 rshow(tagset, nil);191 }193 int194 e_lt(void)195 {196 return Ult;197 }199 int200 e_gt(void)201 {202 return Ugt;203 }205 int206 e_at(void)207 {208 return Uamp;209 }211 int212 e_tick(void)213 {214 return Utick;215 }217 int218 e_btick(void)219 {220 return Ubtick;221 }223 int224 e_minus(void)225 {226 return Uminus;227 }229 void230 r_html(Rune *name)231 {232 Rune *id, *line, *p;234 id = copyarg();235 line = readline(HtmlMode);236 for(p=line; *p; p++){237 switch(*p){238 case '<':239 *p = Ult;240 break;241 case '>':242 *p = Ugt;243 break;244 case '&':245 *p = Uamp;246 break;247 case ' ':248 *p = Uspace;249 break;250 }251 }252 if(name[0] == 'i')253 ihtml(id, line);254 else255 html(id, line);256 free(id);257 free(line);258 }260 char defaultfont[] =261 ".ihtml f1\n"262 ".ihtml f\n"263 ".ihtml f <span style=\"font-size: \\n(.spt\">\n"264 ".if \\n(.f==2 .ihtml f1 <i>\n"265 ".if \\n(.f==3 .ihtml f1 <b>\n"266 ".if \\n(.f==4 .ihtml f1 <b><i>\n"267 ".if \\n(.f==5 .ihtml f1 <tt>\n"268 ".if \\n(.f==6 .ihtml f1 <tt><i>\n"269 "..\n"270 ;272 void273 htmlinit(void)274 {275 addraw(L("html"), r_html);276 addraw(L("ihtml"), r_html);278 addesc('<', e_lt, CopyMode);279 addesc('>', e_gt, CopyMode);280 addesc('\'', e_tick, CopyMode);281 addesc('`', e_btick, CopyMode);282 addesc('-', e_minus, CopyMode);283 addesc('@', e_at, CopyMode);285 ds(L("font"), L(defaultfont));286 }