win.c (5990B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <thread.h> 5 #include <plumb.h> 6 #include <9pclient.h> 7 #include "dat.h" 8 9 Window* 10 newwindow(void) 11 { 12 char buf[12]; 13 Window *w; 14 15 w = emalloc(sizeof(Window)); 16 w->ctl = fsopen(acmefs, "new/ctl", ORDWR|OCEXEC); 17 if(w->ctl == nil || fsread(w->ctl, buf, 12)!=12) 18 error("can't open window ctl file: %r"); 19 20 w->id = atoi(buf); 21 w->event = winopenfile(w, "event"); 22 w->addr = nil; /* will be opened when needed */ 23 w->body = nil; 24 w->data = nil; 25 w->cevent = chancreate(sizeof(Event*), 0); 26 w->ref = 1; 27 return w; 28 } 29 30 void 31 winincref(Window *w) 32 { 33 qlock(&w->lk); 34 ++w->ref; 35 qunlock(&w->lk); 36 } 37 38 void 39 windecref(Window *w) 40 { 41 qlock(&w->lk); 42 if(--w->ref > 0){ 43 qunlock(&w->lk); 44 return; 45 } 46 fsclose(w->event); 47 chanfree(w->cevent); 48 free(w); 49 } 50 51 void 52 winsetdump(Window *w, char *dir, char *cmd) 53 { 54 if(dir != nil) 55 ctlprint(w->ctl, "dumpdir %s\n", dir); 56 if(cmd != nil) 57 ctlprint(w->ctl, "dump %s\n", cmd); 58 } 59 60 void 61 wineventproc(void *v) 62 { 63 Window *w; 64 int i; 65 66 w = v; 67 for(i=0; ; i++){ 68 if(i >= NEVENT) 69 i = 0; 70 wingetevent(w, &w->e[i]); 71 sendp(w->cevent, &w->e[i]); 72 } 73 } 74 75 static CFid* 76 winopenfile1(Window *w, char *f, int m) 77 { 78 char buf[64]; 79 CFid* fd; 80 81 sprint(buf, "%d/%s", w->id, f); 82 fd = fsopen(acmefs, buf, m|OCEXEC); 83 if(fd == nil) 84 error("can't open window file %s: %r", f); 85 return fd; 86 } 87 88 CFid* 89 winopenfile(Window *w, char *f) 90 { 91 return winopenfile1(w, f, ORDWR); 92 } 93 94 void 95 wintagwrite(Window *w, char *s, int n) 96 { 97 CFid* fid; 98 99 fid = winopenfile(w, "tag"); 100 if(fswrite(fid, s, n) != n) 101 error("tag write: %r"); 102 fsclose(fid); 103 } 104 105 void 106 winname(Window *w, char *s) 107 { 108 int len; 109 char *ns, *sp; 110 Rune r = L'␣'; /* visible space */ 111 112 len = 0; 113 ns = emalloc(strlen(s)*runelen(r) + 1); 114 for(sp = s; *sp != '\0'; sp++, len++){ 115 if(isspace(*sp)){ 116 len += runetochar(ns+len, &r)-1; 117 continue; 118 } 119 *(ns+len) = *sp; 120 } 121 ctlprint(w->ctl, "name %s\n", ns); 122 free(ns); 123 return; 124 } 125 126 void 127 winopenbody(Window *w, int mode) 128 { 129 char buf[256]; 130 CFid* fid; 131 132 sprint(buf, "%d/body", w->id); 133 fid = fsopen(acmefs, buf, mode|OCEXEC); 134 w->body = fid; 135 if(w->body == nil) 136 error("can't open window body file: %r"); 137 } 138 139 void 140 winclosebody(Window *w) 141 { 142 if(w->body != nil){ 143 fsclose(w->body); 144 w->body = nil; 145 } 146 } 147 148 void 149 winwritebody(Window *w, char *s, int n) 150 { 151 if(w->body == nil) 152 winopenbody(w, OWRITE); 153 if(fswrite(w->body, s, n) != n) 154 error("write error to window: %r"); 155 } 156 157 int 158 wingetec(Window *w) 159 { 160 if(w->nbuf == 0){ 161 w->nbuf = fsread(w->event, w->buf, sizeof w->buf); 162 if(w->nbuf <= 0){ 163 /* probably because window has exited, and only called by wineventproc, so just shut down */ 164 windecref(w); 165 threadexits(nil); 166 } 167 w->bufp = w->buf; 168 } 169 w->nbuf--; 170 return *w->bufp++; 171 } 172 173 int 174 wingeten(Window *w) 175 { 176 int n, c; 177 178 n = 0; 179 while('0'<=(c=wingetec(w)) && c<='9') 180 n = n*10+(c-'0'); 181 if(c != ' ') 182 error("event number syntax"); 183 return n; 184 } 185 186 int 187 wingeter(Window *w, char *buf, int *nb) 188 { 189 Rune r; 190 int n; 191 192 r = wingetec(w); 193 buf[0] = r; 194 n = 1; 195 if(r >= Runeself) { 196 while(!fullrune(buf, n)) 197 buf[n++] = wingetec(w); 198 chartorune(&r, buf); 199 } 200 *nb = n; 201 return r; 202 } 203 204 void 205 wingetevent(Window *w, Event *e) 206 { 207 int i, nb; 208 209 e->c1 = wingetec(w); 210 e->c2 = wingetec(w); 211 e->q0 = wingeten(w); 212 e->q1 = wingeten(w); 213 e->flag = wingeten(w); 214 e->nr = wingeten(w); 215 if(e->nr > EVENTSIZE) 216 error("event string too long"); 217 e->nb = 0; 218 for(i=0; i<e->nr; i++){ 219 e->r[i] = wingeter(w, e->b+e->nb, &nb); 220 e->nb += nb; 221 } 222 e->r[e->nr] = 0; 223 e->b[e->nb] = 0; 224 if(wingetec(w) != '\n') 225 error("event syntax error"); 226 } 227 228 void 229 winwriteevent(Window *w, Event *e) 230 { 231 fsprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); 232 } 233 234 void 235 winread(Window *w, uint q0, uint q1, char *data) 236 { 237 int m, n, nr; 238 char buf[256]; 239 240 if(w->addr == nil) 241 w->addr = winopenfile(w, "addr"); 242 if(w->data == nil) 243 w->data = winopenfile(w, "data"); 244 m = q0; 245 while(m < q1){ 246 n = sprint(buf, "#%d", m); 247 if(fswrite(w->addr, buf, n) != n) 248 error("error writing addr: %r"); 249 n = fsread(w->data, buf, sizeof buf); 250 if(n <= 0) 251 error("reading data: %r"); 252 nr = utfnlen(buf, n); 253 while(m+nr >q1){ 254 do; while(n>0 && (buf[--n]&0xC0)==0x80); 255 --nr; 256 } 257 if(n == 0) 258 break; 259 memmove(data, buf, n); 260 data += n; 261 *data = 0; 262 m += nr; 263 } 264 } 265 266 void 267 windormant(Window *w) 268 { 269 if(w->addr != nil){ 270 fsclose(w->addr); 271 w->addr = nil; 272 } 273 if(w->body != nil){ 274 fsclose(w->body); 275 w->body = nil; 276 } 277 if(w->data != nil){ 278 fsclose(w->data); 279 w->data = nil; 280 } 281 } 282 283 284 int 285 windel(Window *w, int sure) 286 { 287 if(sure) 288 fswrite(w->ctl, "delete\n", 7); 289 else if(fswrite(w->ctl, "del\n", 4) != 4) 290 return 0; 291 /* event proc will die due to read error from event file */ 292 windormant(w); 293 fsclose(w->ctl); 294 w->ctl = nil; 295 return 1; 296 } 297 298 void 299 winclean(Window *w) 300 { 301 ctlprint(w->ctl, "clean\n"); 302 } 303 304 int 305 winsetaddr(Window *w, char *addr, int errok) 306 { 307 if(w->addr == nil) 308 w->addr = winopenfile(w, "addr"); 309 if(fswrite(w->addr, addr, strlen(addr)) < 0){ 310 if(!errok) 311 error("error writing addr(%s): %r", addr); 312 return 0; 313 } 314 return 1; 315 } 316 317 int 318 winselect(Window *w, char *addr, int errok) 319 { 320 if(winsetaddr(w, addr, errok)){ 321 ctlprint(w->ctl, "dot=addr\n"); 322 return 1; 323 } 324 return 0; 325 } 326 327 char* 328 winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ 329 { 330 char *s; 331 int m, na, n; 332 333 if(w->body != nil) 334 winclosebody(w); 335 winopenbody(w, OREAD); 336 s = nil; 337 na = 0; 338 n = 0; 339 for(;;){ 340 if(na < n+512){ 341 na += 1024; 342 s = realloc(s, na+1); 343 } 344 m = fsread(w->body, s+n, na-n); 345 if(m <= 0) 346 break; 347 n += m; 348 } 349 s[n] = 0; 350 winclosebody(w); 351 *np = n; 352 return s; 353 } 354 355 char* 356 winselection(Window *w) 357 { 358 int m, n; 359 char *buf; 360 char tmp[256]; 361 CFid* fid; 362 363 fid = winopenfile1(w, "rdsel", OREAD); 364 if(fid == nil) 365 error("can't open rdsel: %r"); 366 n = 0; 367 buf = nil; 368 for(;;){ 369 m = fsread(fid, tmp, sizeof tmp); 370 if(m <= 0) 371 break; 372 buf = erealloc(buf, n+m+1); 373 memmove(buf+n, tmp, m); 374 n += m; 375 buf[n] = '\0'; 376 } 377 fsclose(fid); 378 return buf; 379 }