11 void startcmd(char *[], int*);
12 void stdout2body(void*);
19 Window *win; /* the main window */
24 fprint(2, "usage: win [command]\n");
25 threadexitsall("usage");
29 threadmain(int argc, char *argv[])
32 char *dir, *tag, *name;
46 {extern int _threaddebuglevel;
47 _threaddebuglevel = 1<<20;
52 av = emalloc(3*sizeof(char*));
55 name = getenv("sysname");
58 name = utfrrune(av[0], '/');
65 if(getwd(buf, sizeof buf) == 0)
71 tag = eappend(estrdup(tag), "/-", name);
73 snprint(buf, sizeof buf, "%d", win->id);
76 wintagwrite(win, "Send Noscroll", 5+8);
77 threadcreate(mainctl, win, STACK);
79 threadcreate(fsloop, nil, STACK);
81 startcmd(av, ¬epg);
85 for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){
87 strcpy(buf+j+1, argv[i]);
88 j += 1+strlen(argv[i]);
91 ctlprint(win->ctl, "scroll");
92 winsetdump(win, dir, buf);
96 EQUAL(char *s, char *t)
98 while(tolower(*s) == tolower(*t++))
105 command(Window *w, char *s)
107 while(*s==' ' || *s=='\t' || *s=='\n')
109 if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){
114 if(EQUAL(s, "scroll")){
115 ctlprint(w->ctl, "scroll\nshow");
118 if(EQUAL(s, "noscroll")){
119 ctlprint(w->ctl, "noscroll");
126 utfncpy(char *to, char *from, int n)
133 end = memccpy(to, from, '\0', e - to);
137 if(end-2>=to && (end[-2]&0xE0)==0xC0)
139 if(end-3>=to && (end[-3]&0xF0)==0xE0)
141 while(end>to && (*--end&0xC0)==0x80)
149 /* sendinput and fsloop run in the same proc (can't interrupt each other). */
153 __sendinput(Window *w, ulong q0, ulong q1)
158 static char tmp[UTFmax];
170 if(nb > r->ifcall.count)
171 nb = r->ifcall.count;
172 memmove(r->ofcall.data, tmp, nb);
174 memmove(tmp, tmp+nb, partial-nb);
180 r->ofcall.count = nb;
182 fprint(2, "satisfy read with partial\n");
188 s = emalloc((q1-q0)*UTFmax+1);
189 n = winread(w, q0, q1, s);
191 t = strpbrk(s, "\n\004");
203 nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count);
204 if(nb==0 && s<t && r->ifcall.count > 0){
205 partial = utfncpy(tmp, s, UTFmax);
207 chartorune(&rune, tmp);
208 partial = runelen(rune);
213 n = utfnlen(r->ofcall.data, nb);
214 if(nb==strlen(s) && eofchar)
216 r->ofcall.count = nb;
222 fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data);
228 _sendinput(Window *w, ulong q0, ulong *q1)
233 n = __sendinput(w, q0, *q1);
234 if(!n || !eraseinput)
236 /* erase q0 to q0+n */
237 sprint(buf, "#%lud,#%lud", q0, q0+n);
238 winsetaddr(w, buf, 0);
239 write(w->data, buf, 0);
245 sendinput(Window *w, ulong q0, ulong *q1)
253 n += _sendinput(w, q0+n, q1);
266 memset(&esendinput, 0, sizeof esendinput);
269 while(recv(fschan, &e) == -1)
277 /* call sendinput with hostpt and endpt */
278 sendp(win->cevent, &esendinput);
281 for(l=&q; *l; l=&(*l)->aux){
286 respond(r->oldreq, "interrupted");
301 write(win->body, s, strlen(s));
303 * RSC: The problem here is that other procs can call sendit,
304 * so we lose our single-threadedness if we call sendinput.
305 * In fact, we don't even have the right queue memory,
306 * I think that we'll get a write event from the body write above,
307 * and we can do the sendinput then, from our single thread.
309 * I still need to figure out how to test this assertion for
310 * programs that use /srv/win*
312 winselect(win, "$", 0);
313 seek(win->addr, 0UL, 0);
314 if(read(win->addr, tmp, 2*12) == 2*12)
315 hostpt += sendinput(win, hostpt, atol(tmp), );
320 execevent(Window *w, Event *e, int (*command)(Window*, char*))
323 int n, na, len, needfree;
329 e2 = recvp(w->cevent);
331 ea = recvp(w->cevent);
339 if(e->nb==0 && (e->flag&2)){
345 if(e->nb==0 && e->q0<e->q1){
346 /* fetch data from window */
347 s = emalloc((e->q1-e->q0)*UTFmax+2);
348 n = winread(w, e->q0, e->q1, s);
353 t = emalloc(strlen(s)+1+na+2);
354 sprint(t, "%s %s", s, ea->b);
361 /* if it's a known command, do it */
362 /* if it's a long message, it can't be for us anyway */
363 if(!command(w, s) && s[0]!='\0'){ /* send it as typed text */
364 /* if it's a built-in from the tag, send it back */
366 fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1);
367 else{ /* send text to main window */
369 if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){
371 /* if(needfree), we left room for a newline before */
388 hasboundary(Rune *r, int nr)
393 if(r[i]=='\n' || r[i]=='\004')
403 int delta, pendingS, pendingK;
408 proccreate(wineventproc, w, STACK);
412 winsetaddr(w, "0", 0);
417 fprint(2, "input range %lud-%lud\n", hostpt, endpt);
418 e = recvp(w->cevent);
420 fprint(2, "msg: %C %C %d %d %d %d %q\n",
421 e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b);
425 fprint(2, "unknown message %c%c\n", e->c1, e->c2);
428 case 'C': /* input needed for /dev/cons */
432 hostpt += sendinput(w, hostpt, &endpt);
435 case 'S': /* output to stdout */
436 sprint(tmp, "#%lud", hostpt);
437 winsetaddr(w, tmp, 0);
438 write(w->data, e->b, e->nb);
442 case 'E': /* write to tag or body; body happens due to sendit */
449 hostpt += sendinput(w, hostpt, &endpt);
453 fprint(2, "win msg: %C %C %d %d %d %d %q\n",
454 e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
457 case 'F': /* generated by our actions (specifically case 'S' above) */
460 /* we know about the delete by _sendinput */
464 pendingS -= e->q1 - e->q0;
466 fprint(2, "win: pendingS = %d\n", pendingS);
468 fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt);
471 sendp(writechan, nil);
472 if(pendingS == 0 && pendingK){
474 hostpt += sendinput(w, hostpt, &endpt);
479 fprint(2, "win msg: %C %C %d %d %d %d %q\n",
480 e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
490 else if(e->q0 < hostpt)
494 delta = e->q1 - e->q0;
496 if(endpt < e->q1) /* just in case */
500 if(e->nr>0 && e->r[e->nr-1]==0x7F){
501 write(notepg, "interrupt", 9);
506 && hasboundary(e->r, e->nr)){
508 * If we are between the S message (which
509 * we processed by inserting text in the
510 * window) and the F message notifying us
511 * that the text has been inserted, then our
512 * impression of the hostpt and acme's
513 * may be different. This could be seen if you
514 * hit enter a bunch of times in a con
515 * session. To work around the unreliability,
516 * only send input if we don't have an S pending.
517 * The same race occurs between when a character
518 * is typed and when we get notice of it, but
519 * since characters tend to be typed at the end
520 * of the buffer, we don't run into it. There's
521 * no workaround possible for this typing race,
522 * since we can't tell when the user has typed
523 * something but we just haven't been notified.
528 hostpt += sendinput(w, hostpt, &endpt);
534 case 'M': /* mouse */
539 execevent(w, e, command);
542 case 'l': /* reflect all searches back to acme */
554 hostpt += sendinput(w, hostpt, &endpt);
561 else if(e->q0 < hostpt)
564 case 'd': /* modify away; we don't care */
579 EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
593 if(s[0]=='.' && s[1]=='/')
595 if(s[0]=='.' && s[1]=='.' && s[2]=='/')
600 /* adapted from mail. not entirely free of details from that environment */
609 rfork(RFCFDG|RFNOTEG);
612 open("/dev/cons", OREAD);
614 open("/dev/cons", OWRITE);
618 procexec(cpid, av[0], av);
619 if(lookinbin(av[0])){
620 cmd = estrstrdup("/bin/", av[0]);
621 procexec(cpid, cmd, av);
623 error("can't exec %s: %r", av[0]);
627 startcmd(char *argv[], int *notepg)
634 e = emalloc(sizeof(struct Exec));
636 cpid = chancreate(sizeof(ulong), 0);
638 sprint(buf, "/mnt/wsys/%d", win->id);
639 bind(buf, "/dev/acme", MREPL);
640 proccreate(execproc, e, EXECSTACK);
644 sprint(buf, "/proc/%d/notepg", pid);
645 *notepg = open(buf, OWRITE);