#ifdef TESTING
static Tcl_Channel channel(Intr intr,Obj name) {
int mode;
chars s = Tcl_GetStringFromObj(name,0);
Tcl_Channel c = Tcl_GetChannel(intr,s,&mode);
if (!c) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"unknown channel: ",s);
}
return c;
}
static void result(Intr intr,chars p,int n,int N) {
switch (N) {
case EOF: Tcl_SetResult(intr,"<EOF>",TCL_STATIC); return;
case BLK: Tcl_SetResult(intr,"<BLK>",TCL_STATIC); return;
case ERR: Tcl_SetResult(intr,"<ERR>",TCL_STATIC); return;
default:
if (p) {
char B[20]; Obj o; sprintf(B,"<%d>",N);
o = Tcl_NewStringObj(p,n<0 ? 0 : n);
Tcl_AppendToObj(o,B,-1);
Tcl_SetObjResult(intr,o);
}else Tcl_SetObjResult(intr,Tcl_NewIntObj(n));
return;
}
}
static void resulto(Intr intr,Obj p,int n) {
switch (n) {
case EOF: Tcl_SetResult(intr,"<EOF>",TCL_STATIC); return;
case BLK: Tcl_SetResult(intr,"<BLK>",TCL_STATIC); return;
case ERR: Tcl_SetResult(intr,"<ERR>",TCL_STATIC); return;
default:
if (p) {
char B[20]; sprintf(B,"<%d>",n);
p = Tcl_DuplicateObj(p);
Tcl_AppendToObj(p,B,-1);
Tcl_SetObjResult(intr,p);
}else Tcl_SetObjResult(intr,Tcl_NewIntObj(n));
return;
}
}
typedef union {
int i;
double d;
Obj o;
chars s;
Intr r;
} Value;
static long mv(Intr intr,Obj *P,int N,Value *x,Value *y,Value *z) {
long mode = wyrm_stringToC(Tcl_GetStringFromObj(P[1],0));
switch (mode) {
case '-':
break;
case 'ii':
if (Tcl_GetIntFromObj(intr,P[2],&x->i)!=TCL_OK) return 0;
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
break;
case 'oo':
x->o = P[2];
y->o = P[3];
break;
case 'dd':
if (Tcl_GetDoubleFromObj(intr,P[2],&x->d)!=TCL_OK) return 0;
if (Tcl_GetDoubleFromObj(intr,P[3],&y->d)!=TCL_OK) return 0;
break;
case 'ss':
x->s = Tcl_GetStringFromObj(P[2],0);
y->s = Tcl_GetStringFromObj(P[3],0);
break;
case 'iii':
if (Tcl_GetIntFromObj(intr,P[2],&x->i)!=TCL_OK) return 0;
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
if (Tcl_GetIntFromObj(intr,P[4],&z->i)!=TCL_OK) return 0;
break;
case 'oio':
x->o = P[2];
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
z->o = P[4];
break;
case 'did':
if (Tcl_GetDoubleFromObj(intr,P[2],&x->d)!=TCL_OK) return 0;
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
if (Tcl_GetDoubleFromObj(intr,P[4],&z->d)!=TCL_OK) return 0;
break;
case 'sis':
x->s = Tcl_GetStringFromObj(P[2],0);
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
z->s = Tcl_GetStringFromObj(P[4],0);
break;
case 'ri':
x->r = intr;
Tcl_SetObjResult(intr,P[2]);
if (Tcl_GetIntFromObj(intr,P[3],&y->i)!=TCL_OK) return 0;
break;
default:
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"unknown format mode: ",Tcl_GetStringFromObj(P[1],0),0);
mode = 0;
break;
}
return mode;
}
static int chanBlock(ptr context,int mode) {
chars c = context;
if (*c!='e') {
*c = mode==TCL_MODE_BLOCKING ? 'b' : 'B';
}
return 0;
}
static int chanClose(ptr context,Intr intr) {
dispose(context);
return 0;
}
static int chanTransput(ptr context,chars buf,int size,int *ec) {
chars c = context;
switch (*c) {
case 'e':
*ec = EIO;
break;
case 'B':
*ec = EAGAIN;
break;
case 'b':
*c = 'e';
return 0;
}
return -1;
}
static void chanWatch(ptr context,int mask) {
return;
}
static int chanHandle(ptr context,int direction,ptr *handle) {
*handle = context; return TCL_OK;
}
static Tcl_ChannelType SpecialChannel = {
"qio-channel",(ClientData)chanBlock,chanClose,
chanTransput,(Tcl_DriverOutputProc*)chanTransput,
0,0,0,chanWatch,chanHandle
};
static int wyrm_testIOCommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
Tcl_Channel c; chars p; int n; Obj o; Value x,y,z;
if (N<2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio <subcommand> ...",0);
return TCL_ERROR;
}
P++,N--;
p = Tcl_GetStringFromObj(*P,0); P++,N--;
if (streq(p,"error") || streq(p,"block")) {
static int K = 0; char name[20]; chars q;
if (N!=0) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio error|block",0);
return TCL_ERROR;
}
q = heap(char); *q = *p; sprintf(name,"qio%d",++K);
c = Tcl_CreateChannel(&SpecialChannel,name,q,TCL_READABLE|TCL_WRITABLE);
Tcl_RegisterChannel(intr,c);
Tcl_SetChannelOption(intr,c,"-buffering","none");
Tcl_SetResult(intr,Tcl_GetChannelName(c),TCL_VOLATILE);
}else if (streq(p,"read")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio read channel n",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
if (Tcl_GetIntFromObj(intr,P[1],&n)!=TCL_OK) return TCL_ERROR;
p = nheap(n,char); n = cread(c,p,n);
result(intr,p,n,n); dispose(p);
}else if (streq(p,"getc")) {
char C;
if (N!=1) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio getc channel",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
n = cgetc(c); C = n; result(intr,&C,1,n);
}else if (streq(p,"gets")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio gets channel s",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
o = incr(Tcl_DuplicateObj(P[1]));
n = cgets(c,o); resulto(intr,o,n); decr(o);
}else if (streq(p,"geto")) {
if (N!=1) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio geto channel",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
o = cgeto(c); resulto(intr,o,o ? 1 : EOF); decr(o);
}else if (streq(p,"write")) {
if (N!=3) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio write channel s n",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
p = Tcl_GetStringFromObj(P[1],0);
if (Tcl_GetIntFromObj(intr,P[2],&n)!=TCL_OK) return TCL_ERROR;
n = cwrite(c,p,n);
result(intr,0,n,n);
}else if (streq(p,"putc")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio putc channel c",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
p = Tcl_GetStringFromObj(P[1],0);
n = cputc(c,*p); result(intr,0,n,n);
}else if (streq(p,"puts")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio puts channel s",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
p = Tcl_GetStringFromObj(P[1],0);
n = cputs(c,p); result(intr,0,n,n);
}else if (streq(p,"puto")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio puto channel s",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR;
n = cputo(c,P[1]); resulto(intr,0,n);
}else if (streq(p,"cprintf")) {
p = N>=3 ? Tcl_GetStringFromObj(P[2],0) : "";
n = strlen(p);
if (!(*p=='-' && N==3) && (n<2 || n>3 || N!=3+n)) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio cprintf channel format mode value value [value]",0);
return TCL_ERROR;
}
c = channel(intr,P[0]); if (!c) return TCL_ERROR; P++,N--;
switch (mv(intr,(Obj*)P,N,&x,&y,&z)) {
case '-': n = cprintf(c,Tcl_GetStringFromObj(*P,0)); break;
case 'ii': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.i,y.i); break;
case 'oo': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.o,y.o); break;
case 'dd': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.d,y.d); break;
case 'ss': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.s,y.s); break;
case 'iii': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.i,y.i,z.i); break;
case 'oio': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.o,y.i,z.o); break;
case 'did': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.d,y.i,z.d); break;
case 'sis': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.s,y.i,z.s); break;
case 'ri': n = cprintf(c,Tcl_GetStringFromObj(*P,0),x.r,y.i); break;
default: return TCL_ERROR;
}
result(intr,0,n,n);
}else if (streq(p,"oprintf")) {
p = N>=2 ? Tcl_GetStringFromObj(P[1],0) : "";
n = strlen(p);
if (!(*p=='-' && N==2) && (n<2 || n>3 || N!=2+n)) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio oprintf format mode value value [value]",0);
return TCL_ERROR;
}
switch (mv(intr,(Obj*)P,N,&x,&y,&z)) {
case '-': o = oprintf(Tcl_GetStringFromObj(*P,0)); break;
case 'ii': o = oprintf(Tcl_GetStringFromObj(*P,0),x.i,y.i); break;
case 'oo': o = oprintf(Tcl_GetStringFromObj(*P,0),x.o,y.o); break;
case 'dd': o = oprintf(Tcl_GetStringFromObj(*P,0),x.d,y.d); break;
case 'ss': o = oprintf(Tcl_GetStringFromObj(*P,0),x.s,y.s); break;
case 'iii': o = oprintf(Tcl_GetStringFromObj(*P,0),x.i,y.i,z.i); break;
case 'oio': o = oprintf(Tcl_GetStringFromObj(*P,0),x.o,y.i,z.o); break;
case 'did': o = oprintf(Tcl_GetStringFromObj(*P,0),x.d,y.i,z.d); break;
case 'sis': o = oprintf(Tcl_GetStringFromObj(*P,0),x.s,y.i,z.s); break;
case 'ri': o = oprintf(Tcl_GetStringFromObj(*P,0),x.r,y.i); break;
default: return TCL_ERROR;
}
resulto(intr,o,o ? 1 : EOF); decr(o);
}else if (streq(p,"rprintf")) {
p = N>=2 ? Tcl_GetStringFromObj(P[1],0) : "";
n = strlen(p);
if (!(*p=='-' && N==2) && (n<2 || n>3 || N!=2+n)) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio rprintf format mode value value [value]",0);
return TCL_ERROR;
}
switch (mv(intr,(Obj*)P,N,&x,&y,&z)) {
case '-': return rprintf(intr,Tcl_GetStringFromObj(*P,0)); break;
case 'ii': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.i,y.i);
case 'oo': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.o,y.o);
case 'dd': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.d,y.d);
case 'ss': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.s,y.s);
case 'iii': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.i,y.i,z.i);
case 'oio': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.o,y.i,z.o);
case 'did': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.d,y.i,z.d);
case 'sis': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.s,y.i,z.s);
case 'ri': return rprintf(intr,Tcl_GetStringFromObj(*P,0),x.r,y.i);
default: return TCL_ERROR;
}
}else if (streq(p,"dprintf")) {
p = N>=2 ? Tcl_GetStringFromObj(P[1],0) : "";
n = strlen(p);
if (!(*p=='-' && N==2) && (n<2 || n>3 || N!=2+n)) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio dprintf format mode value value [value]",0);
return TCL_ERROR;
}
switch (mv(intr,(Obj*)P,N,&x,&y,&z)) {
case '-': dprintf(Tcl_GetStringFromObj(*P,0)); break;
case 'ii': dprintf(Tcl_GetStringFromObj(*P,0),x.i,y.i); break;
case 'oo': dprintf(Tcl_GetStringFromObj(*P,0),x.o,y.o); break;
case 'dd': dprintf(Tcl_GetStringFromObj(*P,0),x.d,y.d); break;
case 'ss': dprintf(Tcl_GetStringFromObj(*P,0),x.s,y.s); break;
case 'iii': dprintf(Tcl_GetStringFromObj(*P,0),x.i,y.i,z.i); break;
case 'oio': dprintf(Tcl_GetStringFromObj(*P,0),x.o,y.i,z.o); break;
case 'did': dprintf(Tcl_GetStringFromObj(*P,0),x.d,y.i,z.d); break;
case 'sis': dprintf(Tcl_GetStringFromObj(*P,0),x.s,y.i,z.s); break;
case 'ri': dprintf(Tcl_GetStringFromObj(*P,0),x.r,y.i); break;
default: return TCL_ERROR;
}
}else if (streq(p,"yformat")) {
int pre,post; char R[40];
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio yformat format string",0);
return TCL_ERROR;
}
incr(P[1]); pre = P[1]->refCount;
decr(oprintf(Tcl_GetStringFromObj(P[0],0),P[1]));
post = P[1]->refCount;
if (pre==post) decr(P[1]);
sprintf(R,"%d %d",pre,post); Tcl_SetResult(intr,R,TCL_VOLATILE);
}else if (streq(p,"oresult")) {
if (N!=2) {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"usage: qio oresult format string",0);
return TCL_ERROR;
}
o = oprintf(Tcl_GetStringFromObj(P[0],0),P[1]);
Tcl_SetObjResult(intr,Tcl_NewIntObj(o->refCount));
decr(o);
}else {
Tcl_ResetResult(intr);
Tcl_AppendResult(intr,"qio: unknown subcommand: ",p,0);
return TCL_ERROR;
}
return TCL_OK;
}
int wyrm_testIOCommandInit(Intr intr) {
Tcl_CreateObjCommand(intr,"::wyrm::wif::qio",wyrm_testIOCommand,0,0);
return TCL_OK;
}
#endif