html.c (3984B)
1 /* 2 * Emit html. Keep track of tags so that user doesn't have to. 3 */ 4 5 #include "a.h" 6 7 typedef struct Tag Tag; 8 struct Tag 9 { 10 Tag *next; 11 Rune *id; 12 Rune *open; 13 Rune *close; 14 }; 15 16 Tag *tagstack; 17 Tag *tagset; 18 int hidingset; 19 20 static Rune* 21 closingtag(Rune *s) 22 { 23 Rune *t; 24 Rune *p0, *p; 25 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 } 47 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 } 57 58 void 59 html(Rune *id, Rune *s) 60 { 61 Rune *es; 62 Tag *t, *tt, *next; 63 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 } 83 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 } 106 107 void 108 closehtml(void) 109 { 110 Tag *t, *next; 111 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 } 123 124 static void 125 rshow(Tag *t, Tag *end) 126 { 127 if(t == nil || t == end) 128 return; 129 rshow(t->next, end); 130 out(t->open); 131 } 132 133 void 134 ihtml(Rune *id, Rune *s) 135 { 136 Tag *t, *tt, **l; 137 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 } 158 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 } 171 172 void 173 hideihtml(void) 174 { 175 Tag *t; 176 177 if(hidingset) 178 return; 179 hidingset = 1; 180 for(t=tagset; t; t=t->next) 181 out(t->close); 182 } 183 184 void 185 showihtml(void) 186 { 187 if(!hidingset) 188 return; 189 hidingset = 0; 190 rshow(tagset, nil); 191 } 192 193 int 194 e_lt(void) 195 { 196 return Ult; 197 } 198 199 int 200 e_gt(void) 201 { 202 return Ugt; 203 } 204 205 int 206 e_at(void) 207 { 208 return Uamp; 209 } 210 211 int 212 e_tick(void) 213 { 214 return Utick; 215 } 216 217 int 218 e_btick(void) 219 { 220 return Ubtick; 221 } 222 223 int 224 e_minus(void) 225 { 226 return Uminus; 227 } 228 229 void 230 r_html(Rune *name) 231 { 232 Rune *id, *line, *p; 233 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 else 255 html(id, line); 256 free(id); 257 free(line); 258 } 259 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 ; 271 272 void 273 htmlinit(void) 274 { 275 addraw(L("html"), r_html); 276 addraw(L("ihtml"), r_html); 277 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); 284 285 ds(L("font"), L(defaultfont)); 286 }