Added /dev/hostopen to replace winplumb stuff. also changes to compile using cygwin+mingw Reference: /n/sources/patch/applied/dt.devhostopen Date: Fri May 19 06:25:13 CES 2006 --- /sys/src/cmd/unix/drawterm/Make.win32 Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/Make.win32 Fri May 19 06:22:19 2006 @@ -0,0 +1,42 @@ +# Windows via mingw32 +# MING=mingw32- is necessary if you're cross-compiling +# on another platform. Otherwise the binaries are just +# named gcc, etc. + +#MING=i586-mingw32msvc- +MING= +AR=$(MING)ar +CC=$(MING)gcc +AS=$(MING)as +RANLIB=$(MING)ranlib +WINDRES=$(MING)windres +CFLAGS=-mno-cygwin -Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 +O=o +FS=fs-win32 +IP=win32 +OS=win32 +GUI=win32 +LDFLAGS=-L/usr/lib/mingw -mno-cygwin +LDADD=-lkernel32 -ladvapi32 -lgdi32 -lmpr -lwsock32 -lshell32 -lmsvcrt -lmingw32 -lcrtdll +TARG=drawterm.exe +XOFILES=9ball.$O + +# Windows via MSVC +#AR=link -lib +#CC=cl +#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -Iinclude -DWINDOWS +#O=obj +#FS=fs-win32 +#IP=win32 +#OS=win32 +#GUI=win32 + +all: default + +# for root +libmachdep.a: + (cd win32-386; make) + +9ball.$O: 9ball.rc 9ball.ico + $(WINDRES) -i 9ball.rc -o 9ball.o + --- /sys/src/cmd/unix/drawterm/README Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/README Fri May 19 06:22:26 2006 @@ -0,0 +1,49 @@ +INSTALLATION +-------------- +To build on Unix, run CONF=unix make. + +To build on Windows, you need Mingw. See http://www.mingw.org. +Edit Make.config to uncomment the Windows section +and comment out the rest. Then run CONF=windows make. + +(You can download nmake from +http://support.microsoft.com/default.aspx?scid=kb;en-us;Q132084 +Rename it to make.exe and put it in your path somewhere. +) + +I haven't tested the Windows build on Windows itself. +I cross-compile using mingw32 on Linux. + + I built drawterm using cygwin/mingw. there were some minor changes. + In Make.win32 add "-mno-cygwin" to CFLAGS and LDFLAGS. skip@9netics.com + + +BINARIES +--------- +See http://swtch.com/drawterm/ + + +SOURCE +------ +Use CVS: cvs -d :pserver:anoncvs@cvs.pdos.csail.mit.edu:/cvs co drawterm +On the web at http://cvs.pdos.csail.mit.edu/cvs/drawterm +In the Plan 9 distribution: /sys/src/cmd/unix/drawterm + + +HELP +---- +Email Russ Cox with bug reports or problems. + + +TO DO: +------ + +- Should import latest /dev/draw to allow resize of window + +- Should copy 9term code and make console window a real + 9term window instead. + +- Should implement /dev/label. + + + --- /sys/src/cmd/unix/drawterm/kern/devcons.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/kern/devcons.c Fri May 19 06:22:35 2006 @@ -0,0 +1,1188 @@ +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +#include "keyboard.h" + +void (*consdebug)(void) = nil; +void (*screenputs)(char*, int) = nil; + +Queue* kbdq; /* unprocessed console input */ +Queue* lineq; /* processed console input */ +Queue* serialoq; /* serial console output */ +Queue* kprintoq; /* console output, for /dev/kprint */ +long kprintinuse; /* test and set whether /dev/kprint is open */ +int iprintscreenputs = 0; + +int panicking; + +struct +{ + int exiting; + int machs; +} active; + +static struct +{ + QLock lk; + + int raw; /* true if we shouldn't process input */ + int ctl; /* number of opens to the control file */ + int x; /* index into line */ + char line[1024]; /* current input line */ + + int count; + int ctlpoff; + + /* a place to save up characters at interrupt time before dumping them in the queue */ + Lock lockputc; + char istage[1024]; + char *iw; + char *ir; + char *ie; +} kbd = { + { 0 }, + 0, + 0, + 0, + { 0 }, + 0, + 0, + { 0 }, + { 0 }, + kbd.istage, + kbd.istage, + kbd.istage + sizeof(kbd.istage), +}; + +char *sysname; +vlong fasthz; + +static int readtime(ulong, char*, int); +static int readbintime(char*, int); +static int writetime(char*, int); +static int writebintime(char*, int); + +enum +{ + CMreboot, + CMpanic, +}; + +Cmdtab rebootmsg[] = +{ + CMreboot, "reboot", 0, + CMpanic, "panic", 0, +}; + +int +return0(void *v) +{ + return 0; +} + +void +printinit(void) +{ + lineq = qopen(2*1024, 0, nil, nil); + if(lineq == nil) + panic("printinit"); + qnoblock(lineq, 1); + + kbdq = qopen(4*1024, 0, 0, 0); + if(kbdq == nil) + panic("kbdinit"); + qnoblock(kbdq, 1); +} + +int +consactive(void) +{ + if(serialoq) + return qlen(serialoq) > 0; + return 0; +} + +void +prflush(void) +{ +/* + ulong now; + + now = m->ticks; + while(consactive()) + if(m->ticks - now >= HZ) + break; +*/ +} + +/* + * Print a string on the console. Convert \n to \r\n for serial + * line consoles. Locking of the queues is left up to the screen + * or uart code. Multi-line messages to serial consoles may get + * interspersed with other messages. + */ +static void +putstrn0(char *str, int n, int usewrite) +{ + /* + * if someone is reading /dev/kprint, + * put the message there. + * if not and there's an attached bit mapped display, + * put the message there. + * + * if there's a serial line being used as a console, + * put the message there. + */ + if(kprintoq != nil && !qisclosed(kprintoq)){ + if(usewrite) + qwrite(kprintoq, str, n); + else + qiwrite(kprintoq, str, n); + }else if(screenputs != nil) + screenputs(str, n); +} + +void +putstrn(char *str, int n) +{ + putstrn0(str, n, 0); +} + +int noprint; + +int +print(char *fmt, ...) +{ + int n; + va_list arg; + char buf[PRINTSIZE]; + + if(noprint) + return -1; + + va_start(arg, fmt); + n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + putstrn(buf, n); + + return n; +} + +void +panic(char *fmt, ...) +{ + int n; + va_list arg; + char buf[PRINTSIZE]; + + kprintoq = nil; /* don't try to write to /dev/kprint */ + + if(panicking) + for(;;); + panicking = 1; + + splhi(); + strcpy(buf, "panic: "); + va_start(arg, fmt); + n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + buf[n] = '\n'; + uartputs(buf, n+1); + if(consdebug) + (*consdebug)(); + spllo(); + prflush(); + putstrn(buf, n+1); + dumpstack(); + + exit(1); +} + +int +pprint(char *fmt, ...) +{ + int n; + Chan *c; + va_list arg; + char buf[2*PRINTSIZE]; + + if(up == nil || up->fgrp == nil) + return 0; + + c = up->fgrp->fd[2]; + if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) + return 0; + n = sprint(buf, "%s %lud: ", up->text, up->pid); + va_start(arg, fmt); + n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + + if(waserror()) + return 0; + devtab[c->type]->write(c, buf, n, c->offset); + poperror(); + + lock(&c->ref.lk); + c->offset += n; + unlock(&c->ref.lk); + + return n; +} + +static void +echoscreen(char *buf, int n) +{ + char *e, *p; + char ebuf[128]; + int x; + + p = ebuf; + e = ebuf + sizeof(ebuf) - 4; + while(n-- > 0){ + if(p >= e){ + screenputs(ebuf, p - ebuf); + p = ebuf; + } + x = *buf++; + if(x == 0x15){ + *p++ = '^'; + *p++ = 'U'; + *p++ = '\n'; + } else + *p++ = x; + } + if(p != ebuf) + screenputs(ebuf, p - ebuf); +} + +static void +echoserialoq(char *buf, int n) +{ + char *e, *p; + char ebuf[128]; + int x; + + p = ebuf; + e = ebuf + sizeof(ebuf) - 4; + while(n-- > 0){ + if(p >= e){ + qiwrite(serialoq, ebuf, p - ebuf); + p = ebuf; + } + x = *buf++; + if(x == '\n'){ + *p++ = '\r'; + *p++ = '\n'; + } else if(x == 0x15){ + *p++ = '^'; + *p++ = 'U'; + *p++ = '\n'; + } else + *p++ = x; + } + if(p != ebuf) + qiwrite(serialoq, ebuf, p - ebuf); +} + +static void +echo(char *buf, int n) +{ + static int ctrlt; + int x; + char *e, *p; + + e = buf+n; + for(p = buf; p < e; p++){ + switch(*p){ + case 0x10: /* ^P */ + if(cpuserver && !kbd.ctlpoff){ + active.exiting = 1; + return; + } + break; + case 0x14: /* ^T */ + ctrlt++; + if(ctrlt > 2) + ctrlt = 2; + continue; + } + + if(ctrlt != 2) + continue; + + /* ^T escapes */ + ctrlt = 0; + switch(*p){ + case 'S': + x = splhi(); + dumpstack(); + procdump(); + splx(x); + return; + case 's': + dumpstack(); + return; + case 'x': + xsummary(); + ixsummary(); + mallocsummary(); + pagersummary(); + return; + case 'd': + if(consdebug == nil) + consdebug = rdb; + else + consdebug = nil; + print("consdebug now 0x%p\n", consdebug); + return; + case 'D': + if(consdebug == nil) + consdebug = rdb; + consdebug(); + return; + case 'p': + x = spllo(); + procdump(); + splx(x); + return; + case 'q': + scheddump(); + return; + case 'k': + killbig(); + return; + case 'r': + exit(0); + return; + } + } + + qproduce(kbdq, buf, n); + if(kbd.raw) + return; + if(screenputs != nil) + echoscreen(buf, n); + if(serialoq) + echoserialoq(buf, n); +} + +/* + * Called by a uart interrupt for console input. + * + * turn '\r' into '\n' before putting it into the queue. + */ +int +kbdcr2nl(Queue *q, int ch) +{ + char *next; + + USED(q); + ilock(&kbd.lockputc); /* just a mutex */ + if(ch == '\r' && !kbd.raw) + ch = '\n'; + next = kbd.iw+1; + if(next >= kbd.ie) + next = kbd.istage; + if(next != kbd.ir){ + *kbd.iw = ch; + kbd.iw = next; + } + iunlock(&kbd.lockputc); + return 0; +} +static +void +_kbdputc(int c) +{ + Rune r; + char buf[UTFmax]; + int n; + + r = c; + n = runetochar(buf, &r); + if(n == 0) + return; + echo(buf, n); +// kbd.c = r; +// qproduce(kbdq, buf, n); +} + +/* _kbdputc, but with compose translation */ +int +kbdputc(Queue *q, int c) +{ + int i; + static int collecting, nk; + static Rune kc[5]; + + if(c == Kalt){ + collecting = 1; + nk = 0; + return 0; + } + + if(!collecting){ + _kbdputc(c); + return 0; + } + + kc[nk++] = c; + c = latin1(kc, nk); + if(c < -1) /* need more keystrokes */ + return 0; + if(c != -1) /* valid sequence */ + _kbdputc(c); + else + for(i=0; i= size) + return 0; + if(off+n > size) + n = size-off; + memmove(buf, tmp+off, n); + return n; +} + +int +readstr(ulong off, char *buf, ulong n, char *str) +{ + int size; + + size = strlen(str); + if(off >= size) + return 0; + if(off+n > size) + n = size-off; + memmove(buf, str+off, n); + return n; +} + +static void +consinit(void) +{ + todinit(); + randominit(); + /* + * at 115200 baud, the 1024 char buffer takes 56 ms to process, + * processing it every 22 ms should be fine + */ +/* addclock0link(kbdputcclock, 22); */ +} + +static Chan* +consattach(char *spec) +{ + return devattach('c', spec); +} + +static Walkqid* +conswalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); +} + +static int +consstat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, consdir, nelem(consdir), devgen); +} + +static Chan* +consopen(Chan *c, int omode) +{ + c->aux = nil; + c = devopen(c, omode, consdir, nelem(consdir), devgen); + switch((ulong)c->qid.path){ + case Qconsctl: + qlock(&kbd.lk); + kbd.ctl++; + qunlock(&kbd.lk); + break; + + case Qkprint: + if(tas(&kprintinuse) != 0){ + c->flag &= ~COPEN; + error(Einuse); + } + if(kprintoq == nil){ + kprintoq = qopen(8*1024, Qcoalesce, 0, 0); + if(kprintoq == nil){ + c->flag &= ~COPEN; + error(Enomem); + } + qnoblock(kprintoq, 1); + }else + qreopen(kprintoq); + c->iounit = qiomaxatomic; + break; + + case Qsecstore: + if(omode == ORDWR) + error(Eperm); + if(omode != OREAD) + memset(secstorebuf, 0, sizeof secstorebuf); + break; + + case Qsnarf: + if(omode == ORDWR) + error(Eperm); + if(omode == OREAD) + c->aux = strdup(""); + else + c->aux = mallocz(SnarfSize, 1); + break; + } + return c; +} + +static void +consclose(Chan *c) +{ + switch((ulong)c->qid.path){ + /* last close of control file turns off raw */ + case Qconsctl: + if(c->flag&COPEN){ + qlock(&kbd.lk); + if(--kbd.ctl == 0) + kbd.raw = 0; + qunlock(&kbd.lk); + } + break; + + /* close of kprint allows other opens */ + case Qkprint: + if(c->flag & COPEN){ + kprintinuse = 0; + qhangup(kprintoq, nil); + } + break; + + case Qsnarf: + if(c->mode == OWRITE) + clipwrite(c->aux); + free(c->aux); + break; + } +} + +static long +consread(Chan *c, void *buf, long n, vlong off) +{ + char *b; + char tmp[128]; /* must be >= 6*NUMSIZE */ + char *cbuf = buf; + int ch, i, eol; + vlong offset = off; + + if(n <= 0) + return n; + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, buf, n, consdir, nelem(consdir), devgen); + + case Qcons: + qlock(&kbd.lk); + if(waserror()) { + qunlock(&kbd.lk); + nexterror(); + } + if(kbd.raw) { + if(qcanread(lineq)) + n = qread(lineq, buf, n); + else { + /* read as much as possible */ + do { + i = qread(kbdq, cbuf, n); + cbuf += i; + n -= i; + } while (n>0 && qcanread(kbdq)); + n = cbuf - (char*)buf; + } + } else { + while(!qcanread(lineq)) { + qread(kbdq, &kbd.line[kbd.x], 1); + ch = kbd.line[kbd.x]; + eol = 0; + switch(ch){ + case '\b': + if(kbd.x) + kbd.x--; + break; + case 0x15: + kbd.x = 0; + break; + case '\n': + case 0x04: + eol = 1; + default: + kbd.line[kbd.x++] = ch; + break; + } + if(kbd.x == sizeof(kbd.line) || eol){ + if(ch == 0x04) + kbd.x--; + qwrite(lineq, kbd.line, kbd.x); + kbd.x = 0; + } + } + n = qread(lineq, buf, n); + } + qunlock(&kbd.lk); + poperror(); + return n; + + case Qcpunote: + sleep(&up->sleep, return0, nil); + + case Qcputime: + return 0; + + case Qkprint: + return qread(kprintoq, buf, n); + + case Qpgrpid: + return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); + + case Qpid: + return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); + + case Qppid: + return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); + + case Qtime: + return readtime((ulong)offset, buf, n); + + case Qbintime: + return readbintime(buf, n); + + case Qhostowner: + return readstr((ulong)offset, buf, n, eve); + + case Qhostdomain: + return readstr((ulong)offset, buf, n, hostdomain); + + case Quser: + return readstr((ulong)offset, buf, n, up->user); + + case Qnull: + return 0; + + case Qsnarf: + if(offset == 0){ + free(c->aux); + c->aux = clipread(); + } + if(c->aux == nil) + return 0; + return readstr(offset, buf, n, c->aux); + + case Qsecstore: + return readstr(offset, buf, n, secstorebuf); + + case Qsysstat: + return 0; + + case Qswap: + return 0; + + case Qsysname: + if(sysname == nil) + return 0; + return readstr((ulong)offset, buf, n, sysname); + + case Qrandom: + return randomread(buf, n); + + case Qdrivers: + b = malloc(READSTR); + if(b == nil) + error(Enomem); + n = 0; + for(i = 0; devtab[i] != nil; i++) + n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); + if(waserror()){ + free(b); + nexterror(); + } + n = readstr((ulong)offset, buf, n, b); + free(b); + poperror(); + return n; + + case Qzero: + memset(buf, 0, n); + return n; + + case Qosversion: + snprint(tmp, sizeof tmp, "2000"); + n = readstr((ulong)offset, buf, n, tmp); + return n; + + default: + print("consread 0x%llux\n", c->qid.path); + error(Egreg); + } + return -1; /* never reached */ +} + +static long +conswrite(Chan *c, void *va, long n, vlong off) +{ + char buf[256]; + long l, bp; + char *a = va; + int fd; + Chan *swc; + ulong offset = off; + Cmdbuf *cb; + Cmdtab *ct; + + switch((ulong)c->qid.path){ + case Qcons: + /* + * Can't page fault in putstrn, so copy the data locally. + */ + l = n; + while(l > 0){ + bp = l; + if(bp > sizeof buf) + bp = sizeof buf; + memmove(buf, a, bp); + putstrn0(buf, bp, 1); + a += bp; + l -= bp; + } + break; + + case Qconsctl: + if(n >= sizeof(buf)) + n = sizeof(buf)-1; + strncpy(buf, a, n); + buf[n] = 0; + for(a = buf; a;){ + if(strncmp(a, "rawon", 5) == 0){ + qlock(&kbd.lk); + if(kbd.x){ + qwrite(kbdq, kbd.line, kbd.x); + kbd.x = 0; + } + kbd.raw = 1; + qunlock(&kbd.lk); + } else if(strncmp(a, "rawoff", 6) == 0){ + qlock(&kbd.lk); + kbd.raw = 0; + kbd.x = 0; + qunlock(&kbd.lk); + } else if(strncmp(a, "ctlpon", 6) == 0){ + kbd.ctlpoff = 0; + } else if(strncmp(a, "ctlpoff", 7) == 0){ + kbd.ctlpoff = 1; + } + if((a = strchr(a, ' '))) + a++; + } + break; + + case Qtime: + if(!iseve()) + error(Eperm); + return writetime(a, n); + + case Qbintime: + if(!iseve()) + error(Eperm); + return writebintime(a, n); + + case Qhostowner: + return hostownerwrite(a, n); + + case Qhostopen: + return hostopenwrite(a, n); + + case Qhostdomain: + return hostdomainwrite(a, n); + + case Quser: + return userwrite(a, n); + + case Qnull: + break; + + case Qreboot: + if(!iseve()) + error(Eperm); + cb = parsecmd(a, n); + + if(waserror()) { + free(cb); + nexterror(); + } + ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg)); + switch(ct->index) { + case CMreboot: + rebootcmd(cb->nf-1, cb->f+1); + break; + case CMpanic: + panic("/dev/reboot"); + } + poperror(); + free(cb); + break; + + case Qsecstore: + if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf) + error(Etoobig); + secstoretab->qid.vers++; + memmove(secstorebuf+offset, va, n); + return n; + + case Qsnarf: + if(offset >= SnarfSize || offset+n >= SnarfSize) + error(Etoobig); + snarftab->qid.vers++; + memmove((uchar*)c->aux+offset, va, n); + return n; + + case Qsysstat: + n = 0; + break; + + case Qswap: + if(n >= sizeof buf) + error(Egreg); + memmove(buf, va, n); /* so we can NUL-terminate */ + buf[n] = 0; + /* start a pager if not already started */ + if(strncmp(buf, "start", 5) == 0){ + kickpager(); + break; + } + if(cpuserver && !iseve()) + error(Eperm); + if(buf[0]<'0' || '9'= sizeof buf) + error(Ebadarg); + strncpy(buf, a, n); + buf[n] = 0; + if(buf[n-1] == '\n') + buf[n-1] = 0; + kstrdup(&sysname, buf); + break; + + default: + print("conswrite: 0x%llux\n", c->qid.path); + error(Egreg); + } + return n; +} + +Dev consdevtab = { + 'c', + "cons", + + devreset, + consinit, + devshutdown, + consattach, + conswalk, + consstat, + consopen, + devcreate, + consclose, + consread, + devbread, + conswrite, + devbwrite, + devremove, + devwstat, +}; + +static uvlong uvorder = (uvlong) 0x0001020304050607ULL; + +static uchar* +le2vlong(vlong *to, uchar *f) +{ + uchar *t, *o; + int i; + + t = (uchar*)to; + o = (uchar*)&uvorder; + for(i = 0; i < sizeof(vlong); i++) + t[o[i]] = f[i]; + return f+sizeof(vlong); +} + +static uchar* +vlong2le(uchar *t, vlong from) +{ + uchar *f, *o; + int i; + + f = (uchar*)&from; + o = (uchar*)&uvorder; + for(i = 0; i < sizeof(vlong); i++) + t[i] = f[o[i]]; + return t+sizeof(vlong); +} + +static long order = 0x00010203; + +static uchar* +le2long(long *to, uchar *f) +{ + uchar *t, *o; + int i; + + t = (uchar*)to; + o = (uchar*)ℴ + for(i = 0; i < sizeof(long); i++) + t[o[i]] = f[i]; + return f+sizeof(long); +} + +/* +static uchar* +long2le(uchar *t, long from) +{ + uchar *f, *o; + int i; + + f = (uchar*)&from; + o = (uchar*)ℴ + for(i = 0; i < sizeof(long); i++) + t[i] = f[o[i]]; + return t+sizeof(long); +} +*/ + +char *Ebadtimectl = "bad time control"; + +/* + * like the old #c/time but with added info. Return + * + * secs nanosecs fastticks fasthz + */ +static int +readtime(ulong off, char *buf, int n) +{ + vlong nsec, ticks; + long sec; + char str[7*NUMSIZE]; + + nsec = todget(&ticks); + if(fasthz == (vlong)0) + fastticks((uvlong*)&fasthz); + sec = nsec/((uvlong) 1000000000); + snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", + NUMSIZE-1, sec, + VLNUMSIZE-1, nsec, + VLNUMSIZE-1, ticks, + VLNUMSIZE-1, fasthz); + return readstr(off, buf, n, str); +} + +/* + * set the time in seconds + */ +static int +writetime(char *buf, int n) +{ + char b[13]; + long i; + vlong now; + + if(n >= sizeof(b)) + error(Ebadtimectl); + strncpy(b, buf, n); + b[n] = 0; + i = strtol(b, 0, 0); + if(i <= 0) + error(Ebadtimectl); + now = i*((vlong) 1000000000); + todset(now, 0, 0); + return n; +} + +/* + * read binary time info. all numbers are little endian. + * ticks and nsec are syncronized. + */ +static int +readbintime(char *buf, int n) +{ + int i; + vlong nsec, ticks; + uchar *b = (uchar*)buf; + + i = 0; + if(fasthz == (vlong)0) + fastticks((uvlong*)&fasthz); + nsec = todget(&ticks); + if(n >= 3*sizeof(uvlong)){ + vlong2le(b+2*sizeof(uvlong), fasthz); + i += sizeof(uvlong); + } + if(n >= 2*sizeof(uvlong)){ + vlong2le(b+sizeof(uvlong), ticks); + i += sizeof(uvlong); + } + if(n >= 8){ + vlong2le(b, nsec); + i += sizeof(vlong); + } + return i; +} + +/* + * set any of the following + * - time in nsec + * - nsec trim applied over some seconds + * - clock frequency + */ +static int +writebintime(char *buf, int n) +{ + uchar *p; + vlong delta; + long period; + + n--; + p = (uchar*)buf + 1; + switch(*buf){ + case 'n': + if(n < sizeof(vlong)) + error(Ebadtimectl); + le2vlong(&delta, p); + todset(delta, 0, 0); + break; + case 'd': + if(n < sizeof(vlong)+sizeof(long)) + error(Ebadtimectl); + p = le2vlong(&delta, p); + le2long(&period, p); + todset(-1, delta, period); + break; + case 'f': + if(n < sizeof(uvlong)) + error(Ebadtimectl); + le2vlong(&fasthz, p); + todsetfreq(fasthz); + break; + } + return n; +} + + +int +iprint(char *fmt, ...) +{ + int n, s; + va_list arg; + char buf[PRINTSIZE]; + + s = splhi(); + va_start(arg, fmt); + n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + if(screenputs != nil && iprintscreenputs) + screenputs(buf, n); +#undef write + write(2, buf, n); + splx(s); + + return n; +} + --- /sys/src/cmd/unix/drawterm/kern/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/kern/fns.h Fri May 19 06:22:46 2006 @@ -0,0 +1,392 @@ +#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) + +void accounttime(void); +void addclock0link(void (*)(void), int); +int addphysseg(Physseg*); +void addbootfile(char*, uchar*, ulong); +Block* adjustblock(Block*, int); +void alarmkproc(void*); +Block* allocb(int); +int anyhigher(void); +int anyready(void); +Page* auxpage(void); +Block* bl2mem(uchar*, Block*, int); +int blocklen(Block*); +void callwithureg(void(*)(Ureg*)); +char* c2name(Chan*); +int cangetc(void*); +int canlock(Lock*); +int canpage(Proc*); +int canputc(void*); +int canqlock(QLock*); +int canrlock(RWlock*); +void chandevinit(void); +void chandevreset(void); +void chandevshutdown(void); +void chanfree(Chan*); +void chanrec(Mnt*); +void checkalarms(void); +void checkb(Block*, char*); +void cinit(void); +Chan* cclone(Chan*); +void cclose(Chan*); +char* clipread(void); +int clipwrite(char*); +void closeegrp(Egrp*); +void closefgrp(Fgrp*); +void closemount(Mount*); +void closepgrp(Pgrp*); +void closergrp(Rgrp*); +long clrfpintr(void); +void cmderror(Cmdbuf*, char*); +int cmount(Chan**, Chan*, int, char*); +void cnameclose(Cname*); +void confinit(void); +void confinit1(int); +int consactive(void); +extern void (*consdebug)(void); +void copen(Chan*); +Block* concatblock(Block*); +Block* copyblock(Block*, int); +void copypage(Page*, Page*); +int cread(Chan*, uchar*, int, vlong); +void cunmount(Chan*, Chan*); +void cupdate(Chan*, uchar*, int, vlong); +void cwrite(Chan*, uchar*, int, vlong); +ulong dbgpc(Proc*); +int decref(Ref*); +int decrypt(void*, void*, int); +void delay(int); +Chan* devattach(int, char*); +Block* devbread(Chan*, long, ulong); +long devbwrite(Chan*, Block*, ulong); +Chan* devclone(Chan*); +int devconfig(int, char *, DevConf *); +void devcreate(Chan*, char*, int, ulong); +void devdir(Chan*, Qid, char*, vlong, char*, long, Dir*); +long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*); +Devgen devgen; +void devinit(void); +int devno(int, int); +Chan* devopen(Chan*, int, Dirtab*, int, Devgen*); +void devpermcheck(char*, ulong, int); +void devpower(int); +void devremove(Chan*); +void devreset(void); +void devshutdown(void); +int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*); +Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*); +int devwstat(Chan*, uchar*, int); +void drawactive(int); +void drawcmap(void); +int drawcanqlock(void); +void drawqlock(void); +void drawqunlock(void); +void dumpaproc(Proc*); +void dumpqueues(void); +void dumpregs(Ureg*); +void dumpstack(void); +Fgrp* dupfgrp(Fgrp*); +void duppage(Page*); +void dupswap(Page*); +int emptystr(char*); +int encrypt(void*, void*, int); +void envcpy(Egrp*, Egrp*); +int eqchan(Chan*, Chan*, int); +int eqqid(Qid, Qid); +void error(char*); +long execregs(ulong, ulong, ulong); +void exhausted(char*); +void exit(int); +uvlong fastticks(uvlong*); +int fault(ulong, int); +void fdclose(int, int); +Chan* fdtochan(int, int, int, int); +int fixfault(Segment*, ulong, int, int); +void flushmmu(void); +void forkchild(Proc*, Ureg*); +void forkret(void); +void free(void*); +void freeb(Block*); +void freeblist(Block*); +int freebroken(void); +void freepte(Segment*, Pte*); +void freesegs(int); +void freesession(Session*); +ulong getmalloctag(void*); +ulong getrealloctag(void*); +void gotolabel(Label*); +char* getconfenv(void); +int haswaitq(void*); +long hostdomainwrite(char*, int); +long hostopenwrite(char*, int); +long hostownerwrite(char*, int); +void hzsched(void); +void iallocinit(void); +Block* iallocb(int); +void iallocsummary(void); +long ibrk(ulong, int); +void ilock(Lock*); +void iunlock(Lock*); +int incref(Ref*); +void initseg(void); +int iprint(char*, ...); +void isdir(Chan*); +int iseve(void); +#define islo() (0) +Segment* isoverlap(Proc*, ulong, int); +int ispages(void*); +int isphysseg(char*); +void ixsummary(void); +void kbdclock(void); +int kbdcr2nl(Queue*, int); +int kbdputc(Queue*, int); +void kbdrepeat(int); +long keyread(char*, int, long); +void kickpager(void); +void killbig(void); +int kproc(char*, void(*)(void*), void*); +void kprocchild(Proc*, void (*)(void*), void*); +extern void (*kproftimer)(ulong); +void ksetenv(char*, char*, int); +void kstrcpy(char*, char*, int); +void kstrdup(char**, char*); +long latin1(Rune*, int); +void lock(Lock*); +void lockinit(void); +void logopen(Log*); +void logclose(Log*); +char* logctl(Log*, int, char**, Logflag*); +void logn(Log*, int, void*, int); +long logread(Log*, void*, ulong, long); +void log(Log*, int, char*, ...); +Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int); +void machinit(void); +void* mallocz(ulong, int); +#define malloc kmalloc +void* malloc(ulong); +void mallocsummary(void); +Block* mem2bl(uchar*, int); +void mfreeseg(Segment*, ulong, int); +void microdelay(int); +void mkqid(Qid*, vlong, ulong, int); +void mmurelease(Proc*); +void mmuswitch(Proc*); +Chan* mntauth(Chan*, char*); +void mntdump(void); +long mntversion(Chan*, char*, int, int); +void mountfree(Mount*); +ulong ms2tk(ulong); +ulong msize(void*); +ulong ms2tk(ulong); +uvlong ms2fastticks(ulong); +void muxclose(Mnt*); +Chan* namec(char*, int, int, ulong); +Chan* newchan(void); +int newfd(Chan*); +Mhead* newmhead(Chan*); +Mount* newmount(Mhead*, Chan*, int, char*); +Page* newpage(int, Segment **, ulong); +Pgrp* newpgrp(void); +Rgrp* newrgrp(void); +Proc* newproc(void); +char* nextelem(char*, char*); +void nexterror(void); +Cname* newcname(char*); +int notify(Ureg*); +int nrand(int); +int okaddr(ulong, ulong, int); +int openmode(ulong); +void oserrstr(void); +void oserror(void); +Block* packblock(Block*); +Block* padblock(Block*, int); +void pagechainhead(Page*); +void pageinit(void); +void pagersummary(void); +void panic(char*, ...); +Cmdbuf* parsecmd(char *a, int n); +ulong perfticks(void); +void pexit(char*, int); +int preempted(void); +void printinit(void); +int procindex(ulong); +void pgrpcpy(Pgrp*, Pgrp*); +void pgrpnote(ulong, char*, long, int); +Pgrp* pgrptab(int); +void pio(Segment *, ulong, ulong, Page **); +#define poperror() up->nerrlab-- +void portclock(Ureg*); +int postnote(Proc*, int, char*, int); +int pprint(char*, ...); +void prflush(void); +ulong procalarm(ulong); +int proccounter(char *name); +void procctl(Proc*); +void procdump(void); +int procfdprint(Chan*, int, int, char*, int); +void procinit0(void); +void procflushseg(Segment*); +void procpriority(Proc*, int, int); +Proc* proctab(int); +void procwired(Proc*, int); +Pte* ptealloc(void); +Pte* ptecpy(Pte*); +int pullblock(Block**, int); +Block* pullupblock(Block*, int); +Block* pullupqueue(Queue*, int); +void putmhead(Mhead*); +void putmmu(ulong, ulong, Page*); +void putpage(Page*); +void putseg(Segment*); +void putstr(char*); +void putstrn(char*, int); +void putswap(Page*); +ulong pwait(Waitmsg*); +Label* pwaserror(void); +void qaddlist(Queue*, Block*); +Block* qbread(Queue*, int); +long qbwrite(Queue*, Block*); +Queue* qbypass(void (*)(void*, Block*), void*); +int qcanread(Queue*); +void qclose(Queue*); +int qconsume(Queue*, void*, int); +Block* qcopy(Queue*, int, ulong); +int qdiscard(Queue*, int); +void qflush(Queue*); +void qfree(Queue*); +int qfull(Queue*); +Block* qget(Queue*); +void qhangup(Queue*, char*); +int qisclosed(Queue*); +void qinit(void); +int qiwrite(Queue*, void*, int); +int qlen(Queue*); +void qlock(QLock*); +Queue* qopen(int, int, void (*)(void*), void*); +int qpass(Queue*, Block*); +int qpassnolim(Queue*, Block*); +int qproduce(Queue*, void*, int); +void qputback(Queue*, Block*); +long qread(Queue*, void*, int); +Block* qremove(Queue*); +void qreopen(Queue*); +void qsetlimit(Queue*, int); +void qunlock(QLock*); +int qwindow(Queue*); +int qwrite(Queue*, void*, int); +void qnoblock(Queue*, int); +int rand(void); +void randominit(void); +ulong randomread(void*, ulong); +void rdb(void); +int readnum(ulong, char*, ulong, ulong, int); +int readstr(ulong, char*, ulong, char*); +void ready(Proc*); +void rebootcmd(int, char**); +void reboot(void*, void*, ulong); +void relocateseg(Segment*, ulong); +void renameuser(char*, char*); +void resched(char*); +void resrcwait(char*); +int return0(void*); +void rlock(RWlock*); +long rtctime(void); +void runlock(RWlock*); +Proc* runproc(void); +void savefpregs(FPsave*); +extern void (*saveintrts)(void); +void sched(void); +void scheddump(void); +void schedinit(void); +extern void (*screenputs)(char*, int); +long seconds(void); +ulong segattach(Proc*, ulong, char *, ulong, ulong); +void segclock(ulong); +void segpage(Segment*, Page*); +void setkernur(Ureg*, Proc*); +int setlabel(Label*); +void setmalloctag(void*, ulong); +void setrealloctag(void*, ulong); +void setregisters(Ureg*, char*, char*, int); +void setswapchan(Chan*); +char* skipslash(char*); +void sleep(Rendez*, int(*)(void*), void*); +void* smalloc(ulong); +int splhi(void); +int spllo(void); +void splx(int); +void splxpc(int); +char* srvname(Chan*); +int swapcount(ulong); +int swapfull(void); +void swapinit(void); +void timeradd(Timer*); +void timerdel(Timer*); +void timersinit(void); +void timerintr(Ureg*, uvlong); +void timerset(uvlong); +ulong tk2ms(ulong); +#define TK2MS(x) ((x)*(1000/HZ)) +vlong todget(vlong*); +void todfix(void); +void todsetfreq(vlong); +void todinit(void); +void todset(vlong, vlong, int); +Block* trimblock(Block*, int, int); +void tsleep(Rendez*, int (*)(void*), void*, int); +int uartctl(Uart*, char*); +int uartgetc(void); +void uartkick(void*); +void uartmouse(Uart*, int (*)(Queue*, int), int); +void uartputc(int); +void uartputs(char*, int); +void uartrecv(Uart*, char); +Uart* uartsetup(Uart*); +int uartstageoutput(Uart*); +void unbreak(Proc*); +void uncachepage(Page*); +long unionread(Chan*, void*, long); +void unlock(Lock*); +Proc** uploc(void); +void userinit(void); +ulong userpc(void); +long userwrite(char*, int); +#define validaddr(a, b, c) +void validname(char*, int); +void validstat(uchar*, int); +void vcacheinval(Page*, ulong); +void* vmemchr(void*, int, int); +Proc* wakeup(Rendez*); +int walk(Chan**, char**, int, int, int*); +#define waserror() (setjmp(pwaserror()->buf)) +void wlock(RWlock*); +void wunlock(RWlock*); +void* xalloc(ulong); +void* xallocz(ulong, int); +void xfree(void*); +void xhole(ulong, ulong); +void xinit(void); +int xmerge(void*, void*); +void* xspanalloc(ulong, int, ulong); +void xsummary(void); +void yield(void); +Segment* data2txt(Segment*); +Segment* dupseg(Segment**, int, int); +Segment* newseg(int, ulong, ulong); +Segment* seg(Proc*, ulong, int); +void hnputv(void*, vlong); +void hnputl(void*, ulong); +void hnputs(void*, ushort); +vlong nhgetv(void*); +ulong nhgetl(void*); +ushort nhgets(void*); +ulong ticks(void); +void osproc(Proc*); +void osnewproc(Proc*); +void procsleep(void); +void procwakeup(Proc*); +void osinit(void); +void screeninit(void); +extern void terminit(void); + --- /sys/src/cmd/unix/drawterm/kern/win32.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/kern/win32.c Fri May 19 06:22:57 2006 @@ -0,0 +1,467 @@ +#include +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include + +typedef struct Oproc Oproc; +struct Oproc { + int tid; + HANDLE *sema; +}; + +static int tlsx = TLS_OUT_OF_INDEXES; + +char *argv0; + +Proc* +_getproc(void) +{ + if(tlsx == TLS_OUT_OF_INDEXES) + return nil; + return TlsGetValue(tlsx); +} + +void +_setproc(Proc *p) +{ + if(tlsx == TLS_OUT_OF_INDEXES){ + tlsx = TlsAlloc(); + if(tlsx == TLS_OUT_OF_INDEXES) + panic("out of indexes"); + } + TlsSetValue(tlsx, p); +} + +void +oserror(void) +{ + oserrstr(); + nexterror(); +} + +void +osinit(void) +{ + Oproc *t; + static Proc firstprocCTstore; + + _setproc(&firstprocCTstore); + t = (Oproc*)firstprocCTstore.oproc; + assert(t != 0); + + t->tid = GetCurrentThreadId(); + t->sema = CreateSemaphore(0, 0, 1000, 0); + if(t->sema == 0) { + oserror(); + panic("could not create semaphore: %r"); + } +} + +void +osnewproc(Proc *p) +{ + Oproc *op; + + op = (Oproc*)p->oproc; + op->sema = CreateSemaphore(0, 0, 1000, 0); + if (op->sema == 0) { + oserror(); + panic("could not create semaphore: %r"); + } +} + +void +osmsleep(int ms) +{ + Sleep((DWORD) ms); +} + +void +osyield(void) +{ + Sleep(0); +} + +static DWORD WINAPI tramp(LPVOID vp); + +void +osproc(Proc *p) +{ + DWORD tid; + + if(CreateThread(0, 0, tramp, p, 0, &tid) == 0) { + oserror(); + panic("osproc: %r"); + } + + Sleep(0); +} + +static DWORD WINAPI +tramp(LPVOID vp) +{ + Proc *p = (Proc *) vp; + Oproc *op = (Oproc*) p->oproc; + + _setproc(p); + op->tid = GetCurrentThreadId(); + op->sema = CreateSemaphore(0, 0, 1000, 0); + if(op->sema == 0) { + oserror(); + panic("could not create semaphore: %r"); + } + + (*p->fn)(p->arg); + ExitThread(0); + return 0; +} + +void +procsleep(void) +{ + Proc *p; + Oproc *op; + + p = up; + op = (Oproc*)p->oproc; + WaitForSingleObject(op->sema, INFINITE);} + +void +procwakeup(Proc *p) +{ + Oproc *op; + + op = (Oproc*)p->oproc; + ReleaseSemaphore(op->sema, 1, 0); +} + +void +random20(uchar *p) +{ + LARGE_INTEGER ti; + int i, j; + FILETIME ft; + DigestState ds; + vlong tsc; + + GetSystemTimeAsFileTime(&ft); + memset(&ds, 0, sizeof ds); + sha1((uchar*)&ft, sizeof(ft), 0, &ds); + for(i=0; i<50; i++) { + for(j=0; j<10; j++) { + QueryPerformanceCounter(&ti); + sha1((uchar*)&ti, sizeof(ti), 0, &ds); + tsc = GetTickCount(); + sha1((uchar*)&tsc, sizeof(tsc), 0, &ds); + } + Sleep(10); + } + sha1(0, 0, p, &ds); +} + +void +randominit(void) +{ +} + +ulong +randomread(void *v, ulong n) +{ + int i; + uchar p[20]; + + for(i=0; i N backslashes and end quote + * 2N+1 backslashes + " ==> N backslashes + literal " + * N backslashes not followed by " ==> N backslashes + */ +static int +args(char *argv[], int n, char *p) +{ + char *p2; + int i, j, quote, nbs; + + for(i=0; *p && i>1); j++) + *p2++ = '\\'; + if(nbs&1) + *p2++ = *p; + else + quote = !quote; + } else { + for(j=0; jerrstr, ERRMAX); +} + +long +hostopenwrite(char *a, int n) +{ + wchar_t buf[4*1024], *p; + int wn; + + wn = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, a, n, buf, sizeof(buf)); + if (wn) { + if(buf[wn-1] == L'\n') + buf[wn-1] = 0; + + p = wcschr(buf, L' '); + if(p) + *p++ = 0; + + ShellExecute(0, 0, buf, p, 0, SW_SHOWNORMAL); + } + + return n; +} --- /sys/src/cmd/unix/drawterm/libc/runevsmprint.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/libc/runevsmprint.c Fri May 19 06:23:09 2006 @@ -0,0 +1,71 @@ +#include +#include +#include "fmtdef.h" + +static int +runeFmtStrFlush(Fmt *f) +{ + Rune *s; + int n; + + if(f->start == nil) + return 0; + n = (uintptr_t)f->farg; + n *= 2; + s = (Rune*)f->start; + f->start = realloc(s, sizeof(Rune)*n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)(uintptr_t)n; + f->to = (Rune*)f->start + ((Rune*)f->to - s); + f->stop = (Rune*)f->start + n - 1; + return 1; +} + +int +runefmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 1; + n = 32; + f->start = malloc(sizeof(Rune)*n); + if(f->start == nil) + return -1; + f->to = f->start; + f->stop = (Rune*)f->start + n - 1; + f->flush = runeFmtStrFlush; + f->farg = (void*)(uintptr_t)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +Rune* +runevsmprint(char *fmt, va_list args) +{ + Fmt f; + int n; + + if(runefmtstrinit(&f) < 0) + return nil; + VA_COPY(f.args,args); + n = dofmt(&f, fmt); + VA_END(f.args); + if(f.start == nil) + return nil; + if(n < 0){ + free(f.start); + return nil; + } + *(Rune*)f.to = '\0'; + return (Rune*)f.start; +} --- /sys/src/cmd/unix/drawterm/libc/sprint.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/libc/sprint.c Fri May 19 06:23:21 2006 @@ -0,0 +1,24 @@ +#include +#include +#include "fmtdef.h" + +int +sprint(char *buf, char *fmt, ...) +{ + int n; + uint len; + va_list args; + + len = 1<<30; /* big number, but sprint is deprecated anyway */ + /* + * on PowerPC, the stack is near the top of memory, so + * we must be sure not to overflow a 32-bit pointer. + */ + if(buf+len < buf) + len = -(uintptr_t)buf-1; + + va_start(args, fmt); + n = vsnprint(buf, len, fmt, args); + va_end(args); + return n; +} --- /sys/src/cmd/unix/drawterm/libc/vsmprint.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/unix/drawterm/libc/vsmprint.c Fri May 19 06:23:36 2006 @@ -0,0 +1,68 @@ +#include +#include +#include "fmtdef.h" + +static int +fmtStrFlush(Fmt *f) +{ + char *s; + int n; + + if(f->start == nil) + return 0; + n = (uintptr_t)f->farg; + n *= 2; + s = (char*)f->start; + f->start = realloc(s, n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)(uintptr_t)n; + f->to = (char*)f->start + ((char*)f->to - s); + f->stop = (char*)f->start + n - 1; + return 1; +} + +int +fmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 0; + n = 32; + f->start = malloc(n); + if(f->start == nil) + return -1; + f->to = f->start; + f->stop = (char*)f->start + n - 1; + f->flush = fmtStrFlush; + f->farg = (void*)(uintptr_t)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +char* +vsmprint(char *fmt, va_list args) +{ + Fmt f; + int n; + + if(fmtstrinit(&f) < 0) + return nil; + VA_COPY(f.args,args); + n = dofmt(&f, fmt); + VA_END(f.args); + if(n < 0){ + free(f.start); + return nil; + } + return fmtstrflush(&f); +}