#include <9pm/windows.h>
#include <9pm/u.h>
#include <9pm/libc.h>
int debug;
int _dontforkconsole = 1;
int fd[3];
HANDLE h[3];
int tab[] = {
STD_INPUT_HANDLE,
STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE,
};
/*
* It appears that win NT 4.0 has a bug in ReadConsole
* If ReadConsole is called with a buffer that is smaller than
* the input that is buffered, it appears that readconsoles buffer
* can get corrupted by WriteConsole
* i.e
* char buf[3];
* int n2;
*
* for(;;) {
* if(!ReadConsole(h, buf, sizeof(buf), &n2, 0))
* exit(0);
* if(!WriteConsole(h2, buf, n2, &n2, 0))
* exit(0);
*
* Sleep(100);
* }
*
*/
static void
consoleread(HANDLE h, int fd)
{
int n2, i;
Rune r, rbuf[200];
char err[ERRMAX];
char *p;
uchar buf[200*UTFmax];
for(;;){
if(!ReadConsole(h, rbuf, nelem(rbuf), &n2, 0)){
if(debug){
osrerrstr(err, sizeof err);
pm_dprint(~0, "ReadConsole: %s\n", err);
}
break;
}
if(n2 == 0)
continue;
for(i=0,p=buf; i<n2; i++) {
r = rbuf[i];
if(r == '\r')
continue;
if(r == 0x4) {
if(write(fd, buf, p-buf) != p-buf){
if(debug)
pm_dprint(~0, "consoleread write: %r\n");
break;
}
p = buf;
continue;
}
p += runetochar(p, &r);
}
if(write(fd, buf, p-buf) != p-buf){
if(debug)
pm_dprint(~0, "consoleread write: %r\n");
break;
}
}
close(fd);
CloseHandle(h);
}
static void
consolewrite(int fd, HANDLE h)
{
char err[ERRMAX], buf[1000], *p;
Rune buf2[1000], *q;
int i, n, n2, nbuf, on;
for(;;){
n = read(fd, buf+nbuf, sizeof buf);
if(n < 0){
if(debug)
pm_dprint(~0, "consolewrite read: %r\n");
return;
}
p = buf;
on = n;
/* handle partial runes */
if(nbuf) {
i = nbuf;
assert(i < UTFmax);
while(i < UTFmax && n>0) {
buf[i] = *p;
i++;
p++;
n--;
if(fullrune(buf, i)) {
nbuf = 0;
chartorune(buf2, buf);
if(!WriteConsole(h, buf2, 1, &n, 0)){
if(debug){
osrerrstr(err, sizeof err);
pm_dprint(~0, "WriteConsole1: %s\n", err);
}
close(fd);
return;
}
break;
}
}
}
while(n >= UTFmax || fullrune(p, n)) {
n2 = nelem(buf2);
q = buf2;
while(n2) {
if(n < UTFmax && !fullrune(p, n))
break;
i = chartorune(q, p);
p += i;
n -= i;
n2--;
q++;
}
if(!WriteConsole(h, buf2, q-buf2, &n2, 0)) {
if(debug){
osrerrstr(err, sizeof err);
pm_dprint(~0, "WriteConsole2: %s\n", err);
}
close(fd);
return;
}
}
if(n != 0) {
assert(n+nbuf < UTFmax);
memmove(buf+nbuf, p, n);
nbuf += n;
}
}
close(fd);
CloseHandle(h);
}
void
dispatch(void *a)
{
switch((int)a){
case 0:
consoleread(h[0], fd[0]);
break;
case 1:
consolewrite(fd[1], h[1]);
break;
case 2:
consolewrite(fd[2], h[2]);
break;
default:
pm_dprint(~0, "dispatch %d?\n", (int)a);
}
}
void
watchproc(void *a)
{
WaitForSingleObject(a, INFINITE);
ExitProcess(0);
}
void
main(int argc, char **argv)
{
char buf[ERRMAX];
int i, pid, p[2], test;
HANDLE hproc;
test = 0;
ARGBEGIN{
case 'd':
debug = 1;
break;
case 't':
test = 1;
pipe(p);
break;
}ARGEND
if(argc != 3 && argc != 4){
pm_dwrite("usage: console [-t] fd0 fd1 fd2 [processid]\n");
exits("usage");
}
if(argc==4){
pid = atoi(argv[3]);
hproc = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if(hproc == nil){
osrerrstr(buf, sizeof buf);
pm_dprint(~0, "OpenProcess: %s\n", buf);
exits("OpenProcess");
}
ffork(0, watchproc, hproc, 8192);
}
for(i=0; i<3; i++){
if(test && i<2)
fd[i] = p[i];
else
fd[i] = atoi(argv[i]);
if(fd[i] != -1){
h[i] = GetStdHandle(tab[i]);
if(h[i]!=INVALID_HANDLE_VALUE && h[i]!=nil)
ffork(0, dispatch, (void*)i, 8192);
}
}
_exits(0);
}
syntax highlighted by Code2HTML, v. 0.9.1