]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/kbmap.c
kbmap: fix sprint() buffer overflow (thanks silasm)
[plan9front.git] / sys / src / cmd / kbmap.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5
6 typedef struct KbMap KbMap;
7 struct KbMap {
8         char *name;
9         char *file;
10         Rectangle r;
11         int current;
12 };
13
14 KbMap *map;
15 int nmap;
16 Image *lightblue;
17 Image *justblue;
18
19 enum {
20         PAD = 3,
21         MARGIN = 5
22 };
23
24 char *dir = "/sys/lib/kbmap";
25
26 void*
27 erealloc(void *v, ulong n)
28 {
29         v = realloc(v, n);
30         if(v == nil)
31                 sysfatal("out of memory reallocating %lud", n);
32         return v;
33 }
34
35 void*
36 emalloc(ulong n)
37 {
38         void *v;
39
40         v = malloc(n);
41         if(v == nil)
42                 sysfatal("out of memory allocating %lud", n);
43         memset(v, 0, n);
44         return v;
45 }
46
47 char*
48 estrdup(char *s)
49 {
50         int l;
51         char *t;
52
53         if (s == nil)
54                 return nil;
55         l = strlen(s)+1;
56         t = emalloc(l);
57         memcpy(t, s, l);
58
59         return t;
60 }
61
62 void
63 init(void)
64 {
65         int i, fd, nr;
66         Dir *pd;
67
68         if((fd = open(dir, OREAD)) < 0)
69                 return;
70
71         nmap = nr = dirreadall(fd, &pd);
72         map = emalloc(nr * sizeof(KbMap));
73         for(i=0; i<nr; i++){
74                 map[i].file = emalloc(strlen(dir) + strlen(pd[i].name) + 2);
75                 sprint(map[i].file, "%s/%s", dir, pd[i].name);
76                 map[i].name = estrdup(pd[i].name);
77                 map[i].current = 0;
78         }
79         free(pd);
80
81         close(fd);
82 }
83
84 void
85 drawmap(int i)
86 {
87         if(map[i].current)
88                 draw(screen, map[i].r, justblue, nil, ZP);
89         else
90                 draw(screen, map[i].r, lightblue, nil, ZP);
91
92         _string(screen, addpt(map[i].r.min, Pt(2,0)), display->black, ZP,
93                 font, map[i].name, nil, strlen(map[i].name), 
94                 map[i].r, nil, ZP, SoverD);
95         border(screen, map[i].r, 1, display->black, ZP);        
96 }
97
98 void
99 geometry(void)
100 {
101         int i, rows;
102         Rectangle r;
103
104         rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD);
105
106         r = Rect(0,0,(Dx(screen->r)-2*MARGIN), font->height);
107         for(i=0; i<nmap; i++)
108                 map[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
109                                         MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
110
111 }
112
113 void
114 redraw(Image *screen)
115 {
116         int i;
117
118         draw(screen, screen->r, lightblue, nil, ZP);
119         for(i=0; i<nmap; i++)
120                 drawmap(i);
121         flushimage(display, 1);
122 }
123
124 void
125 eresized(int new)
126 {
127         if(new && getwindow(display, Refmesg) < 0)
128                 fprint(2,"can't reattach to window");
129         geometry();
130         redraw(screen);
131 }
132
133 int
134 writemap(char *file)
135 {
136         int i, fd, ofd;
137         char buf[8192];
138
139         if((fd = open(file, OREAD)) < 0){
140                 fprint(2, "cannot open %s: %r", file);
141                 return -1;
142         }
143         if((ofd = open("/dev/kbmap", OWRITE)) < 0) {
144                 fprint(2, "cannot open /dev/kbmap: %r");
145                 close(fd);
146                 return -1;
147         }
148         while((i = read(fd, buf, sizeof buf)) > 0)
149                 if(write(ofd, buf, i) != i){
150                         fprint(2, "writing /dev/kbmap: %r");
151                         break;
152                 }
153
154         close(fd);
155         close(ofd);
156         return 0;
157 }
158
159 void
160 click(Mouse m)
161 {
162         int i, j;
163         char buf[128];
164
165         if(m.buttons == 0 || (m.buttons & ~4))
166                 return;
167
168         for(i=0; i<nmap; i++)
169                 if(ptinrect(m.xy, map[i].r))
170                         break;
171         if(i == nmap)
172                 return;
173
174         do
175                 m = emouse();
176         while(m.buttons == 4);
177
178         if(m.buttons != 0){
179                 do
180                         m = emouse();
181                 while(m.buttons);
182                 return;
183         }
184
185         for(j=0; j<nmap; j++)
186                 if(ptinrect(m.xy, map[j].r))
187                         break;
188         if(j != i)
189                 return;
190
191         /* since maps are often just a delta of the distributed map... */
192         snprint(buf, sizeof buf, "%s/ascii", dir);
193         writemap(buf);
194         writemap(map[i].file);
195
196         /* clean the previous current map */
197         for(j=0; j<nmap; j++)
198                 map[j].current = 0;
199
200         map[i].current = 1;
201
202         redraw(screen);
203 }
204
205 void
206 usage(void)
207 {
208         fprint(2, "usage: kbmap [file...]\n");
209         exits("usage");
210 }
211
212 void
213 main(int argc, char **argv)
214 {
215         Event e;
216         char *c;
217
218         if(argc > 1) {
219                 argv++; argc--;
220                 map = emalloc((argc)*sizeof(KbMap));
221                 while(argc--) {
222                         map[argc].file = estrdup(argv[argc]);
223                         c = strrchr(map[argc].file, '/');
224                         map[argc].name = (c == nil ? map[argc].file : c+1);
225                         map[argc].current = 0;
226                         nmap++;
227                 }
228         } else 
229                 init();
230
231         if(initdraw(0, 0, "kbmap") < 0){
232                 fprint(2, "kbmap: initdraw failed: %r\n");
233                 exits("initdraw");
234         }
235         lightblue = allocimagemix(display, DPalebluegreen, DWhite);
236         if(lightblue == nil)
237                 sysfatal("allocimagemix: %r");
238         justblue = allocimagemix(display, DBlue, DWhite);
239         if(justblue == nil)
240                 sysfatal("allocimagemix: %r");
241
242         eresized(0);
243         einit(Emouse|Ekeyboard);
244
245         for(;;){
246                 switch(eread(Emouse|Ekeyboard, &e)){
247                 case Ekeyboard:
248                         if(e.kbdc==0x7F || e.kbdc=='q')
249                                 exits(0);
250                         break;
251                 case Emouse:
252                         if(e.mouse.buttons)
253                                 click(e.mouse);
254                         break;
255                 }
256         }
257 }
258