plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }