11 void startcmd(char *[], int*);
12 void stdout2body(void*);
21 Window *win; /* the main window */
26 fprint(2, "usage: win [command]\n");
27 threadexitsall("usage");
31 threadmain(int argc, char *argv[])
47 {extern int _threaddebuglevel;
48 _threaddebuglevel = 1<<20;
53 av = emalloc(3*sizeof(char*));
59 wname = utfrrune(av[0], '/');
64 if(getwd(buf, sizeof buf) == 0)
70 snprint(buf, sizeof buf, "%d", win->id);
72 winsetdir(win, wdir, wname);
73 wintagwrite(win, "Send Noscroll", 5+8);
74 threadcreate(mainctl, win, STACK);
76 threadcreate(fsloop, nil, STACK);
78 startcmd(av, ¬epg);
82 for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){
84 strcpy(buf+j+1, argv[i]);
85 j += 1+strlen(argv[i]);
88 ctlprint(win->ctl, "scroll");
89 winsetdump(win, wdir, buf);
93 EQUAL(char *s, char *t)
95 while(tolower(*s) == tolower(*t++))
102 command(Window *w, char *s)
104 while(*s==' ' || *s=='\t' || *s=='\n')
106 if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){
111 if(EQUAL(s, "scroll")){
112 ctlprint(w->ctl, "scroll\nshow");
115 if(EQUAL(s, "noscroll")){
116 ctlprint(w->ctl, "noscroll");
123 utfncpy(char *to, char *from, int n)
130 end = memccpy(to, from, '\0', e - to);
134 if(end-2>=to && (end[-2]&0xE0)==0xC0)
136 if(end-3>=to && (end[-3]&0xF0)==0xE0)
138 while(end>to && (*--end&0xC0)==0x80)
146 /* sendinput and fsloop run in the same proc (can't interrupt each other). */
150 __sendinput(Window *w, ulong q0, ulong q1)
155 static char tmp[UTFmax];
167 if(nb > r->ifcall.count)
168 nb = r->ifcall.count;
169 memmove(r->ofcall.data, tmp, nb);
171 memmove(tmp, tmp+nb, partial-nb);
177 r->ofcall.count = nb;
179 fprint(2, "satisfy read with partial\n");
185 s = emalloc((q1-q0)*UTFmax+1);
186 n = winread(w, q0, q1, s);
188 t = strpbrk(s, "\n\004");
200 nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count);
201 if(nb==0 && s<t && r->ifcall.count > 0){
202 partial = utfncpy(tmp, s, UTFmax);
204 chartorune(&rune, tmp);
205 partial = runelen(rune);
210 n = utfnlen(r->ofcall.data, nb);
211 if(nb==strlen(s) && eofchar)
213 r->ofcall.count = nb;
219 fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data);
225 _sendinput(Window *w, ulong q0, ulong *q1)
230 n = __sendinput(w, q0, *q1);
231 if(!n || !eraseinput)
233 /* erase q0 to q0+n */
234 sprint(buf, "#%lud,#%lud", q0, q0+n);
235 winsetaddr(w, buf, 0);
236 write(w->data, buf, 0);
242 sendinput(Window *w, ulong q0, ulong *q1)
250 n += _sendinput(w, q0+n, q1);
263 memset(&esendinput, 0, sizeof esendinput);
266 while(recv(fschan, &e) == -1)
274 /* call sendinput with hostpt and endpt */
275 sendp(win->cevent, &esendinput);
278 for(l=&q; *l; l=&(*l)->aux){
283 respond(r->oldreq, "interrupted");
298 write(win->body, s, strlen(s));
300 * RSC: The problem here is that other procs can call sendit,
301 * so we lose our single-threadedness if we call sendinput.
302 * In fact, we don't even have the right queue memory,
303 * I think that we'll get a write event from the body write above,
304 * and we can do the sendinput then, from our single thread.
306 * I still need to figure out how to test this assertion for
307 * programs that use /srv/win*
309 winselect(win, "$", 0);
310 seek(win->addr, 0UL, 0);
311 if(read(win->addr, tmp, 2*12) == 2*12)
312 hostpt += sendinput(win, hostpt, atol(tmp), );
317 execevent(Window *w, Event *e, int (*command)(Window*, char*))
320 int n, na, len, needfree;
326 e2 = recvp(w->cevent);
328 ea = recvp(w->cevent);
336 if(e->nb==0 && (e->flag&2)){
342 if(e->nb==0 && e->q0<e->q1){
343 /* fetch data from window */
344 s = emalloc((e->q1-e->q0)*UTFmax+2);
345 n = winread(w, e->q0, e->q1, s);
350 t = emalloc(strlen(s)+1+na+2);
351 sprint(t, "%s %s", s, ea->b);
358 /* if it's a known command, do it */
359 /* if it's a long message, it can't be for us anyway */
360 if(!command(w, s) && s[0]!='\0'){ /* send it as typed text */
361 /* if it's a built-in from the tag, send it back */
363 fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
364 else{ /* send text to main window */
366 if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){
368 /* if(needfree), we left room for a newline before */
385 hasboundary(Rune *r, int nr)
390 if(r[i]=='\n' || r[i]=='\004')
400 int delta, pendingS, pendingK;
405 proccreate(wineventproc, w, STACK);
409 winsetaddr(w, "0", 0);
414 fprint(2, "input range %lud-%lud\n", hostpt, endpt);
415 e = recvp(w->cevent);
417 fprint(2, "msg: %C %C %d %d %d %d %q\n",
418 e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b);
422 fprint(2, "unknown message %c%c\n", e->c1, e->c2);
425 case 'C': /* input needed for /dev/cons */
429 hostpt += sendinput(w, hostpt, &endpt);
432 case 'S': /* output to stdout */
433 sprint(tmp, "#%lud", hostpt);
434 winsetaddr(w, tmp, 0);
435 write(w->data, e->b, e->nb);
439 case 'E': /* write to tag or body; body happens due to sendit */
446 hostpt += sendinput(w, hostpt, &endpt);
450 fprint(2, "win msg: %C %C %d %d %d %d %q\n",
451 e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
454 case 'F': /* generated by our actions (specifically case 'S' above) */
457 /* we know about the delete by _sendinput */
461 pendingS -= e->q1 - e->q0;
463 fprint(2, "win: pendingS = %d\n", pendingS);
465 fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt);
468 sendp(writechan, nil);
469 if(pendingS == 0 && pendingK){
471 hostpt += sendinput(w, hostpt, &endpt);
476 fprint(2, "win msg: %C %C %d %d %d %d %q\n",
477 e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
487 else if(e->q0 < hostpt)
491 delta = e->q1 - e->q0;
493 if(endpt < e->q1) /* just in case */
497 if(e->nr>0 && e->r[e->nr-1]==0x7F){
498 write(notepg, "interrupt", 9);
503 && hasboundary(e->r, e->nr)){
505 * If we are between the S message (which
506 * we processed by inserting text in the
507 * window) and the F message notifying us
508 * that the text has been inserted, then our
509 * impression of the hostpt and acme's
510 * may be different. This could be seen if you
511 * hit enter a bunch of times in a con
512 * session. To work around the unreliability,
513 * only send input if we don't have an S pending.
514 * The same race occurs between when a character
515 * is typed and when we get notice of it, but
516 * since characters tend to be typed at the end
517 * of the buffer, we don't run into it. There's
518 * no workaround possible for this typing race,
519 * since we can't tell when the user has typed
520 * something but we just haven't been notified.
525 hostpt += sendinput(w, hostpt, &endpt);
531 case 'M': /* mouse */
536 execevent(w, e, command);
539 case 'l': /* reflect all searches back to acme */
551 hostpt += sendinput(w, hostpt, &endpt);
558 else if(e->q0 < hostpt)
561 case 'd': /* modify away; we don't care */
576 EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
590 if(s[0]=='.' && s[1]=='/')
592 if(s[0]=='.' && s[1]=='.' && s[2]=='/')
597 /* adapted from mail. not entirely free of details from that environment */
606 rfork(RFCFDG|RFNOTEG);
609 open("/dev/cons", OREAD);
611 open("/dev/cons", OWRITE);
615 procexec(cpid, av[0], av);
616 if(lookinbin(av[0])){
617 cmd = estrstrdup("/bin/", av[0]);
618 procexec(cpid, cmd, av);
620 error("can't exec %s: %r", av[0]);
624 startcmd(char *argv[], int *notepg)
631 e = emalloc(sizeof(struct Exec));
633 cpid = chancreate(sizeof(ulong), 0);
635 sprint(buf, "/mnt/wsys/%d", win->id);
636 bind(buf, "/dev/acme", MREPL);
637 bind("/dev/acme/body", "/dev/text", MREPL)
638 proccreate(execproc, e, EXECSTACK);
642 sprint(buf, "/proc/%d/notepg", pid);
643 *notepg = open(buf, OWRITE);