xref: /plan9/sys/src/cmd/htmlroff/html.c (revision 6f1c688ed9fbb1a02a7de2eec3e1a5be49f196a0)
1426d2b71SDavid du Colombier /*
2426d2b71SDavid du Colombier  * Emit html.  Keep track of tags so that user doesn't have to.
3426d2b71SDavid du Colombier  */
4426d2b71SDavid du Colombier 
5426d2b71SDavid du Colombier #include "a.h"
6426d2b71SDavid du Colombier 
7426d2b71SDavid du Colombier typedef struct Tag Tag;
8426d2b71SDavid du Colombier struct Tag
9426d2b71SDavid du Colombier {
10426d2b71SDavid du Colombier 	Tag *next;
11426d2b71SDavid du Colombier 	Rune *id;
12426d2b71SDavid du Colombier 	Rune *open;
13426d2b71SDavid du Colombier 	Rune *close;
14426d2b71SDavid du Colombier };
15426d2b71SDavid du Colombier 
16426d2b71SDavid du Colombier Tag *tagstack;
17426d2b71SDavid du Colombier Tag *tagset;
18426d2b71SDavid du Colombier int hidingset;
19426d2b71SDavid du Colombier 
20426d2b71SDavid du Colombier static Rune*
closingtag(Rune * s)21426d2b71SDavid du Colombier closingtag(Rune *s)
22426d2b71SDavid du Colombier {
23426d2b71SDavid du Colombier 	Rune *t;
24426d2b71SDavid du Colombier 	Rune *p0, *p;
25426d2b71SDavid du Colombier 
26426d2b71SDavid du Colombier 	t = runemalloc(sizeof(Rune));
27426d2b71SDavid du Colombier 	if(s == nil)
28426d2b71SDavid du Colombier 		return t;
29426d2b71SDavid du Colombier 	for(p=s; *p; p++){
30426d2b71SDavid du Colombier 		if(*p == Ult){
31426d2b71SDavid du Colombier 			p++;
32426d2b71SDavid du Colombier 			if(*p == '/'){
33426d2b71SDavid du Colombier 				while(*p && *p != Ugt)
34426d2b71SDavid du Colombier 					p++;
35426d2b71SDavid du Colombier 				goto close;
36426d2b71SDavid du Colombier 			}
37426d2b71SDavid du Colombier 			p0 = p;
38426d2b71SDavid du Colombier 			while(*p && !isspacerune(*p) && *p != Uspace && *p != Ugt)
39426d2b71SDavid du Colombier 				p++;
40426d2b71SDavid du Colombier 			t = runerealloc(t, 1+(p-p0)+2+runestrlen(t)+1);
41426d2b71SDavid du Colombier 			runemove(t+(p-p0)+3, t, runestrlen(t)+1);
42426d2b71SDavid du Colombier 			t[0] = Ult;
43426d2b71SDavid du Colombier 			t[1] = '/';
44426d2b71SDavid du Colombier 			runemove(t+2, p0, p-p0);
45426d2b71SDavid du Colombier 			t[2+(p-p0)] = Ugt;
46426d2b71SDavid du Colombier 		}
47426d2b71SDavid du Colombier 
48426d2b71SDavid du Colombier 		if(*p == Ugt && p>s && *(p-1) == '/'){
49426d2b71SDavid du Colombier 		close:
50426d2b71SDavid du Colombier 			for(p0=t+1; *p0 && *p0 != Ult; p0++)
51426d2b71SDavid du Colombier 				;
52426d2b71SDavid du Colombier 			runemove(t, p0, runestrlen(p0)+1);
53426d2b71SDavid du Colombier 		}
54426d2b71SDavid du Colombier 	}
55426d2b71SDavid du Colombier 	return t;
56426d2b71SDavid du Colombier }
57426d2b71SDavid du Colombier 
58426d2b71SDavid du Colombier void
html(Rune * id,Rune * s)59426d2b71SDavid du Colombier html(Rune *id, Rune *s)
60426d2b71SDavid du Colombier {
61426d2b71SDavid du Colombier 	Rune *es;
62426d2b71SDavid du Colombier 	Tag *t, *tt, *next;
63426d2b71SDavid du Colombier 
64426d2b71SDavid du Colombier 	br();
65426d2b71SDavid du Colombier 	hideihtml();	/* br already did, but be paranoid */
66426d2b71SDavid du Colombier 	for(t=tagstack; t; t=t->next){
67426d2b71SDavid du Colombier 		if(runestrcmp(t->id, id) == 0){
68426d2b71SDavid du Colombier 			for(tt=tagstack;; tt=next){
69426d2b71SDavid du Colombier 				next = tt->next;
70426d2b71SDavid du Colombier 				free(tt->id);
71426d2b71SDavid du Colombier 				free(tt->open);
72426d2b71SDavid du Colombier 				out(tt->close);
73426d2b71SDavid du Colombier 				outrune('\n');
74426d2b71SDavid du Colombier 				free(tt->close);
75426d2b71SDavid du Colombier 				free(tt);
76426d2b71SDavid du Colombier 				if(tt == t){
77426d2b71SDavid du Colombier 					tagstack = next;
78426d2b71SDavid du Colombier 					goto cleared;
79426d2b71SDavid du Colombier 				}
80426d2b71SDavid du Colombier 			}
81426d2b71SDavid du Colombier 		}
82426d2b71SDavid du Colombier 	}
83426d2b71SDavid du Colombier 
84426d2b71SDavid du Colombier cleared:
85426d2b71SDavid du Colombier 	if(s == nil || s[0] == 0)
86426d2b71SDavid du Colombier 		return;
87426d2b71SDavid du Colombier 	out(s);
88426d2b71SDavid du Colombier 	outrune('\n');
89426d2b71SDavid du Colombier 	es = closingtag(s);
90426d2b71SDavid du Colombier 	if(es[0] == 0){
91426d2b71SDavid du Colombier 		free(es);
92426d2b71SDavid du Colombier 		return;
93426d2b71SDavid du Colombier 	}
94426d2b71SDavid du Colombier 	if(runestrcmp(id, L("-")) == 0){
95426d2b71SDavid du Colombier 		out(es);
96426d2b71SDavid du Colombier 		outrune('\n');
97426d2b71SDavid du Colombier 		free(es);
98426d2b71SDavid du Colombier 		return;
99426d2b71SDavid du Colombier 	}
100426d2b71SDavid du Colombier 	t = emalloc(sizeof *t);
101426d2b71SDavid du Colombier 	t->id = erunestrdup(id);
102426d2b71SDavid du Colombier 	t->close = es;
103426d2b71SDavid du Colombier 	t->next = tagstack;
104426d2b71SDavid du Colombier 	tagstack = t;
105426d2b71SDavid du Colombier }
106426d2b71SDavid du Colombier 
107426d2b71SDavid du Colombier void
closehtml(void)108426d2b71SDavid du Colombier closehtml(void)
109426d2b71SDavid du Colombier {
110426d2b71SDavid du Colombier 	Tag *t, *next;
111426d2b71SDavid du Colombier 
112426d2b71SDavid du Colombier 	br();
113426d2b71SDavid du Colombier 	hideihtml();
114426d2b71SDavid du Colombier 	for(t=tagstack; t; t=next){
115426d2b71SDavid du Colombier 		next = t->next;
116426d2b71SDavid du Colombier 		out(t->close);
117426d2b71SDavid du Colombier 		outrune('\n');
118426d2b71SDavid du Colombier 		free(t->id);
119426d2b71SDavid du Colombier 		free(t->close);
120426d2b71SDavid du Colombier 		free(t);
121426d2b71SDavid du Colombier 	}
122426d2b71SDavid du Colombier }
123426d2b71SDavid du Colombier 
124426d2b71SDavid du Colombier static void
rshow(Tag * t,Tag * end)125426d2b71SDavid du Colombier rshow(Tag *t, Tag *end)
126426d2b71SDavid du Colombier {
127426d2b71SDavid du Colombier 	if(t == nil || t == end)
128426d2b71SDavid du Colombier 		return;
129426d2b71SDavid du Colombier 	rshow(t->next, end);
130426d2b71SDavid du Colombier 	out(t->open);
131426d2b71SDavid du Colombier }
132426d2b71SDavid du Colombier 
133426d2b71SDavid du Colombier void
ihtml(Rune * id,Rune * s)134426d2b71SDavid du Colombier ihtml(Rune *id, Rune *s)
135426d2b71SDavid du Colombier {
136426d2b71SDavid du Colombier 	Tag *t, *tt, **l;
137426d2b71SDavid du Colombier 
138426d2b71SDavid du Colombier 	for(t=tagset; t; t=t->next){
139426d2b71SDavid du Colombier 		if(runestrcmp(t->id, id) == 0){
140426d2b71SDavid du Colombier 			if(s && t->open && runestrcmp(t->open, s) == 0)
141426d2b71SDavid du Colombier 				return;
142426d2b71SDavid du Colombier 			for(l=&tagset; (tt=*l); l=&tt->next){
143426d2b71SDavid du Colombier 				if(!hidingset)
144426d2b71SDavid du Colombier 					out(tt->close);
145426d2b71SDavid du Colombier 				if(tt == t)
146426d2b71SDavid du Colombier 					break;
147426d2b71SDavid du Colombier 			}
148426d2b71SDavid du Colombier 			*l = t->next;
149426d2b71SDavid du Colombier 			free(t->id);
150426d2b71SDavid du Colombier 			free(t->close);
151426d2b71SDavid du Colombier 			free(t->open);
152426d2b71SDavid du Colombier 			free(t);
153426d2b71SDavid du Colombier 			if(!hidingset)
154426d2b71SDavid du Colombier 				rshow(tagset, *l);
155426d2b71SDavid du Colombier 			goto cleared;
156426d2b71SDavid du Colombier 		}
157426d2b71SDavid du Colombier 	}
158426d2b71SDavid du Colombier 
159426d2b71SDavid du Colombier cleared:
160426d2b71SDavid du Colombier 	if(s == nil || s[0] == 0)
161426d2b71SDavid du Colombier 		return;
162426d2b71SDavid du Colombier 	t = emalloc(sizeof *t);
163426d2b71SDavid du Colombier 	t->id = erunestrdup(id);
164426d2b71SDavid du Colombier 	t->open = erunestrdup(s);
165426d2b71SDavid du Colombier 	t->close = closingtag(s);
166426d2b71SDavid du Colombier 	if(!hidingset)
167426d2b71SDavid du Colombier 		out(s);
168426d2b71SDavid du Colombier 	t->next = tagset;
169426d2b71SDavid du Colombier 	tagset = t;
170426d2b71SDavid du Colombier }
171426d2b71SDavid du Colombier 
172426d2b71SDavid du Colombier void
hideihtml(void)173426d2b71SDavid du Colombier hideihtml(void)
174426d2b71SDavid du Colombier {
175426d2b71SDavid du Colombier 	Tag *t;
176426d2b71SDavid du Colombier 
177426d2b71SDavid du Colombier 	if(hidingset)
178426d2b71SDavid du Colombier 		return;
179426d2b71SDavid du Colombier 	hidingset = 1;
180426d2b71SDavid du Colombier 	for(t=tagset; t; t=t->next)
181426d2b71SDavid du Colombier 		out(t->close);
182426d2b71SDavid du Colombier }
183426d2b71SDavid du Colombier 
184426d2b71SDavid du Colombier void
showihtml(void)185426d2b71SDavid du Colombier showihtml(void)
186426d2b71SDavid du Colombier {
187426d2b71SDavid du Colombier 	if(!hidingset)
188426d2b71SDavid du Colombier 		return;
189426d2b71SDavid du Colombier 	hidingset = 0;
190426d2b71SDavid du Colombier 	rshow(tagset, nil);
191426d2b71SDavid du Colombier }
192426d2b71SDavid du Colombier 
193426d2b71SDavid du Colombier int
e_lt(void)194426d2b71SDavid du Colombier e_lt(void)
195426d2b71SDavid du Colombier {
196426d2b71SDavid du Colombier 	return Ult;
197426d2b71SDavid du Colombier }
198426d2b71SDavid du Colombier 
199426d2b71SDavid du Colombier int
e_gt(void)200426d2b71SDavid du Colombier e_gt(void)
201426d2b71SDavid du Colombier {
202426d2b71SDavid du Colombier 	return Ugt;
203426d2b71SDavid du Colombier }
204426d2b71SDavid du Colombier 
205426d2b71SDavid du Colombier int
e_at(void)206426d2b71SDavid du Colombier e_at(void)
207426d2b71SDavid du Colombier {
208426d2b71SDavid du Colombier 	return Uamp;
209426d2b71SDavid du Colombier }
210426d2b71SDavid du Colombier 
211426d2b71SDavid du Colombier int
e_tick(void)212426d2b71SDavid du Colombier e_tick(void)
213426d2b71SDavid du Colombier {
214426d2b71SDavid du Colombier 	return Utick;
215426d2b71SDavid du Colombier }
216426d2b71SDavid du Colombier 
217426d2b71SDavid du Colombier int
e_btick(void)218426d2b71SDavid du Colombier e_btick(void)
219426d2b71SDavid du Colombier {
220426d2b71SDavid du Colombier 	return Ubtick;
221426d2b71SDavid du Colombier }
222426d2b71SDavid du Colombier 
223426d2b71SDavid du Colombier int
e_minus(void)224426d2b71SDavid du Colombier e_minus(void)
225426d2b71SDavid du Colombier {
226426d2b71SDavid du Colombier 	return Uminus;
227426d2b71SDavid du Colombier }
228426d2b71SDavid du Colombier 
229426d2b71SDavid du Colombier void
r_html(Rune * name)230426d2b71SDavid du Colombier r_html(Rune *name)
231426d2b71SDavid du Colombier {
232426d2b71SDavid du Colombier 	Rune *id, *line, *p;
233426d2b71SDavid du Colombier 
234426d2b71SDavid du Colombier 	id = copyarg();
235426d2b71SDavid du Colombier 	line = readline(HtmlMode);
236426d2b71SDavid du Colombier 	for(p=line; *p; p++){
237426d2b71SDavid du Colombier 		switch(*p){
238426d2b71SDavid du Colombier 		case '<':
239426d2b71SDavid du Colombier 			*p = Ult;
240426d2b71SDavid du Colombier 			break;
241426d2b71SDavid du Colombier 		case '>':
242426d2b71SDavid du Colombier 			*p = Ugt;
243426d2b71SDavid du Colombier 			break;
244426d2b71SDavid du Colombier 		case '&':
245426d2b71SDavid du Colombier 			*p = Uamp;
246426d2b71SDavid du Colombier 			break;
247426d2b71SDavid du Colombier 		case ' ':
248426d2b71SDavid du Colombier 			*p = Uspace;
249426d2b71SDavid du Colombier 			break;
250426d2b71SDavid du Colombier 		}
251426d2b71SDavid du Colombier 	}
252426d2b71SDavid du Colombier 	if(name[0] == 'i')
253426d2b71SDavid du Colombier 		ihtml(id, line);
254426d2b71SDavid du Colombier 	else
255426d2b71SDavid du Colombier 		html(id, line);
256426d2b71SDavid du Colombier 	free(id);
257426d2b71SDavid du Colombier 	free(line);
258426d2b71SDavid du Colombier }
259426d2b71SDavid du Colombier 
260426d2b71SDavid du Colombier char defaultfont[] =
261426d2b71SDavid du Colombier 	".ihtml f1\n"
262426d2b71SDavid du Colombier 	".ihtml f\n"
263*6f1c688eSDavid du Colombier 	".ihtml f <span style=\"font-size: \\n(.spt\">\n"
264426d2b71SDavid du Colombier 	".if \\n(.f==2 .ihtml f1 <i>\n"
265426d2b71SDavid du Colombier 	".if \\n(.f==3 .ihtml f1 <b>\n"
266426d2b71SDavid du Colombier 	".if \\n(.f==4 .ihtml f1 <b><i>\n"
267426d2b71SDavid du Colombier 	".if \\n(.f==5 .ihtml f1 <tt>\n"
268426d2b71SDavid du Colombier 	".if \\n(.f==6 .ihtml f1 <tt><i>\n"
269426d2b71SDavid du Colombier 	"..\n"
270426d2b71SDavid du Colombier ;
271426d2b71SDavid du Colombier 
272426d2b71SDavid du Colombier void
htmlinit(void)273426d2b71SDavid du Colombier htmlinit(void)
274426d2b71SDavid du Colombier {
275426d2b71SDavid du Colombier 	addraw(L("html"), r_html);
276426d2b71SDavid du Colombier 	addraw(L("ihtml"), r_html);
277426d2b71SDavid du Colombier 
278426d2b71SDavid du Colombier 	addesc('<', e_lt, CopyMode);
279426d2b71SDavid du Colombier 	addesc('>', e_gt, CopyMode);
280426d2b71SDavid du Colombier 	addesc('\'', e_tick, CopyMode);
281426d2b71SDavid du Colombier 	addesc('`', e_btick, CopyMode);
282426d2b71SDavid du Colombier 	addesc('-', e_minus, CopyMode);
283426d2b71SDavid du Colombier 	addesc('@', e_at, CopyMode);
284426d2b71SDavid du Colombier 
285426d2b71SDavid du Colombier 	ds(L("font"), L(defaultfont));
286426d2b71SDavid du Colombier }
287426d2b71SDavid du Colombier 
288