xref: /plan9/sys/src/cmd/htmlroff/char.c (revision 82726826a7b3d40fb66339b4b0e95b60314f98b9)
1 #include "a.h"
2 
3 /*
4  * Translate Unicode to HTML by asking tcs(1).
5  * This way we don't have yet another table.
6  */
7 Rune*
rune2html(Rune r)8 rune2html(Rune r)
9 {
10 	static Biobuf b;
11 	static int fd = -1;
12 	static Rune **tcscache[256];
13 	int p[2];
14 	char *q;
15 
16 	if(r == '\n')
17 		return L("\n");
18 
19 	if(((uint)r&~0xFFFF) != 0){
20 		/* The cache must grow a lot to handle them */
21 		fprint(2, "%s: can't handle rune '%C'\n", argv0, r);
22 		return L("?");
23 	}
24 
25 	if(tcscache[r>>8] && tcscache[r>>8][r&0xFF])
26 		return tcscache[r>>8][r&0xFF];
27 
28 	if(fd < 0){
29 		if(pipe(p) < 0)
30 			sysfatal("pipe: %r");
31 		switch(fork()){
32 		case -1:
33 			sysfatal("fork: %r");
34 		case 0:
35 			dup(p[0], 0);
36 			dup(p[1], 1);
37 			close(p[0]);
38 			close(p[1]);
39 			execl("/bin/tcs", "tcs", "-t", "html", nil);
40 			_exits(0);
41 		default:
42 			fd = p[1];
43 			Binit(&b, p[0], OREAD);
44 			break;
45 		}
46 	}
47 	/* HACK: extra newlines force rune+\n through tcs now */
48 	fprint(fd, "%C\n\n\n\n", r);
49 	q = Brdline(&b, '\n');
50 	while (q != nil && *q == '\n')
51 		q = Brdline(&b, '\n');
52 	if(q == nil)
53 		sysfatal("tcs: early eof");
54 	q[Blinelen(&b)-1] = 0;
55 	if(tcscache[r>>8] == nil)
56 		tcscache[r>>8] = emalloc(256*sizeof tcscache[0][0]);
57 	tcscache[r>>8][r&0xFF] = erunesmprint("%s", q);
58 	return tcscache[r>>8][r&0xFF];
59 }
60 
61 /*
62  * Translate troff to Unicode by looking in troff's utfmap.
63  * This way we don't have yet another hard-coded table.
64  */
65 typedef struct Trtab Trtab;
66 struct Trtab
67 {
68 	char t[UTFmax];
69 	Rune r;
70 };
71 
72 static Trtab trtab[200];
73 int ntrtab;
74 
75 static Trtab trinit[] =
76 {
77 	"pl",		Upl,
78 	"eq",	Ueq,
79 	"em",	0x2014,
80 	"en",	0x2013,
81 	"mi",	Umi,
82 	"fm",	0x2032,
83 };
84 
85 Rune
troff2rune(Rune * rs)86 troff2rune(Rune *rs)
87 {
88 	char *file, *f[10], *p, s[3];
89 	int i, nf;
90 	Biobuf *b;
91 
92 	if(rs[0] >= Runeself || rs[1] >= Runeself)
93 		return Runeerror;
94 	s[0] = rs[0];
95 	s[1] = rs[1];
96 	s[2] = 0;
97 	if(ntrtab == 0){
98 		for(i=0; i<nelem(trinit) && ntrtab < nelem(trtab); i++){
99 			trtab[ntrtab] = trinit[i];
100 			ntrtab++;
101 		}
102 		file = "/sys/lib/troff/font/devutf/utfmap";
103 		if((b = Bopen(file, OREAD)) == nil)
104 			sysfatal("open %s: %r", file);
105 		while((p = Brdline(b, '\n')) != nil){
106 			p[Blinelen(b)-1] = 0;
107 			nf = getfields(p, f, nelem(f), 0, "\t");
108 			for(i=0; i+2<=nf && ntrtab<nelem(trtab); i+=2){
109 				chartorune(&trtab[ntrtab].r, f[i]);
110 				memmove(trtab[ntrtab].t, f[i+1], 2);
111 				ntrtab++;
112 			}
113 		}
114 		Bterm(b);
115 
116 		if(ntrtab >= nelem(trtab))
117 			fprint(2, "%s: trtab too small\n", argv0);
118 	}
119 
120 	for(i=0; i<ntrtab; i++)
121 		if(strcmp(s, trtab[i].t) == 0)
122 			return trtab[i].r;
123 	return Runeerror;
124 }
125 
126