xref: /plan9/sys/src/cmd/htmlroff/html.c (revision 6f1c688ed9fbb1a02a7de2eec3e1a5be49f196a0)
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*
closingtag(Rune * s)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
html(Rune * id,Rune * s)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
closehtml(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
rshow(Tag * t,Tag * end)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
ihtml(Rune * id,Rune * s)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
hideihtml(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
showihtml(void)185 showihtml(void)
186 {
187 	if(!hidingset)
188 		return;
189 	hidingset = 0;
190 	rshow(tagset, nil);
191 }
192 
193 int
e_lt(void)194 e_lt(void)
195 {
196 	return Ult;
197 }
198 
199 int
e_gt(void)200 e_gt(void)
201 {
202 	return Ugt;
203 }
204 
205 int
e_at(void)206 e_at(void)
207 {
208 	return Uamp;
209 }
210 
211 int
e_tick(void)212 e_tick(void)
213 {
214 	return Utick;
215 }
216 
217 int
e_btick(void)218 e_btick(void)
219 {
220 	return Ubtick;
221 }
222 
223 int
e_minus(void)224 e_minus(void)
225 {
226 	return Uminus;
227 }
228 
229 void
r_html(Rune * name)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
htmlinit(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 }
287 
288