| top | |
static int pipecommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
int p[2];
if (N!=1) {
Tcl_WrongNumArgs(intr,1,P,0);
return TCL_ERROR;
}
if (pipe(p)<0) {
Tcl_SetErrno(errno);
rprintf(intr,"fork failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}else {
Tcl_Channel reader = Tcl_MakeFileChannel((ClientData)p[0],TCL_READABLE);
Tcl_Channel writer = Tcl_MakeFileChannel((ClientData)p[1],TCL_WRITABLE);
Obj E[2];
Tcl_RegisterChannel(intr,reader);
Tcl_RegisterChannel(intr,writer);
E[0] = Tcl_NewStringObj(Tcl_GetChannelName(reader),-1);
E[1] = Tcl_NewStringObj(Tcl_GetChannelName(writer),-1);
Tcl_SetObjResult(intr,Tcl_NewListObj(2,E));
return TCL_OK;
}
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::pipe",pipecommand,0,0);
| ^ | Definition continued at: 37, 40, 43, 46, 49, 52, 55, 58, 64, 66, 72, 75, 78, 83, 86. | | | | | section top | | | ^ | Definition continued at: 38, 41, 44, 47, 50, 53, 56, 59, 67, 73, 76, 79, 84, 87. | | | | | section top | |
static int dupcommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
Tcl_Channel duplicated,replaced; int mood1,mood2; int p,q,r;
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,1,P,"duplicated-channel [replaced-channel]");
return TCL_ERROR;
}
duplicated = Tcl_GetChannel(intr,Tcl_GetString(P[1]),&mood1);
if (!duplicated) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[1]);
if (Tcl_GetChannelHandle(duplicated,TCL_READABLE,(ClientData*)(&q))==TCL_ERROR
&& Tcl_GetChannelHandle(duplicated,TCL_WRITABLE,(ClientData*)(&q))==TCL_ERROR)
return rprintf(intr,"%!could not get the file descriptor: %{y}s",TCL_ERROR,P[1]);
if (N==2) {
p = dup(q);
}else {
replaced = Tcl_GetChannel(intr,Tcl_GetString(P[2]),&mood2);
if (!replaced) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[1]);
if (Tcl_GetChannelHandle(replaced,TCL_READABLE,(ClientData*)(&r))==TCL_ERROR
&& Tcl_GetChannelHandle(replaced,TCL_WRITABLE,(ClientData*)(&r))==TCL_ERROR)
return rprintf(intr,"%!could not get the file descriptor: %{y}s",TCL_ERROR,P[2]);
p = dup2(q,r);
}
if (p<0) {
Tcl_SetErrno(errno);
rprintf(intr,"dup failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}else if (N==2) {
duplicated = Tcl_MakeFileChannel((ClientData)p,mood1);
Tcl_RegisterChannel(intr,duplicated);
Tcl_SetObjResult(intr,Tcl_NewStringObj(Tcl_GetChannelName(duplicated),-1));
return TCL_OK;
}else {
Tcl_SetObjResult(intr,P[2]);
return TCL_OK;
}
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::dup",dupcommand,0,0);
| ^ | Definition continued at: 40, 43, 46, 49, 52, 55, 58, 64, 66, 72, 75, 78, 83, 86. | | | | | section top | | | ^ | Definition continued at: 41, 44, 47, 50, 53, 56, 59, 67, 73, 76, 79, 84, 87. | | | | | section top | |
static int devnullcommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
Tcl_Channel channel; int mood; int p,q;
if (N!=2) {
Tcl_WrongNumArgs(intr,1,P,"redirected-channel");
return TCL_ERROR;
}
channel = Tcl_GetChannel(intr,Tcl_GetString(P[1]),&mood);
if (!channel) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[1]);
if (Tcl_GetChannelHandle(channel,TCL_READABLE,(ClientData*)(&q))==TCL_ERROR
&& Tcl_GetChannelHandle(channel,TCL_WRITABLE,(ClientData*)(&q))==TCL_ERROR)
return rprintf(intr,"%!could not get the file descriptor: %{y}s",TCL_ERROR,P[1]);
p = open("/dev/null",O_RDWR);
if (p<0) {
Tcl_SetErrno(errno);
rprintf(intr,"open /dev/null failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}
if (dup2(p,q)<0) {
Tcl_SetErrno(errno);
rprintf(intr,"dup failed: %s",Tcl_PosixError(intr));
close(p);
return TCL_ERROR;
}else {
Tcl_SetObjResult(intr,P[1]);
close(p);
return TCL_OK;
}
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::/dev/null",devnullcommand,0,0);
| ^ | Definition continued at: 43, 46, 49, 52, 55, 58, 64, 66, 72, 75, 78, 83, 86. | | | | | section top | | | ^ | Definition continued at: 44, 47, 50, 53, 56, 59, 67, 73, 76, 79, 84, 87. | | | | | section top | |
static Tcl_ThreadDataKey untilKey;
typedef struct ChannelHandler ChannelHandler;
struct ChannelHandler {
Intr intr; Tcl_Channel channel; Obj script;
ChannelHandler *pre,*post;
};
static void channelClose(ClientData clientData);
static void channelEvent(ClientData clientData,int mood);
static void channelClose(ClientData clientData) {
ChannelHandler **untilRing = Tcl_GetThreadData(&untilKey,sizeof(ChannelHandler*));
ChannelHandler *c = (ChannelHandler*)clientData;
Tcl_Release(c->intr);
Tcl_DeleteChannelHandler(c->channel,channelEvent,clientData);
Tcl_DeleteCloseHandler(c->channel,channelClose,clientData);
if (!c->pre) {
;
}else if (c==c->post) {
(*untilRing) = 0;
}else {
(*untilRing) = c->pre;
c->post->pre = (*untilRing);
(*untilRing)->post = c->post;
}
decr(c->script); dispose(c);
}
static void channelEvent(ClientData clientData,int mood) {
ChannelHandler *c = (ChannelHandler*)clientData;
if (Tcl_InterpDeleted(c->intr)) return;
Obj script = c->script,cn; int rc = TCL_OK;
Intr intr = c->intr;
Tcl_Preserve(c->intr);
Tcl_SavedResult state;
Tcl_SaveResult(intr,&state);
if (rc==TCL_OK) rc = Tcl_EvalObjEx(intr,script,TCL_EVAL_GLOBAL);
if (rc!=TCL_OK) Tcl_BackgroundError(intr);
Tcl_RestoreResult(intr,&state);
Tcl_Release(intr);
}
static int readercommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
ChannelHandler **untilRing = Tcl_GetThreadData(&untilKey,sizeof(ChannelHandler*));
Tcl_Channel channel; int mood; ChannelHandler *c;
if (N!=3 && N!=4) {
Tcl_WrongNumArgs(intr,1,P,"channel script [until]");
return TCL_ERROR;
}
if (N==4 && !objeq("until",P[3]))
return rprintf(intr,"%!expected 'until': %{y}s",TCL_ERROR,P[3]);
channel = Tcl_GetChannel(intr,Tcl_GetString(P[1]),&mood);
if (!channel) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[1]);
if (!(mood&TCL_READABLE)) return rprintf(intr,"%!not a readable channel: %{y}s",TCL_ERROR,P[1]);
if (Tcl_SetChannelOption(intr,channel,"-blocking","0")!=TCL_OK) return TCL_ERROR;
c = heap(ChannelHandler);
Tcl_Preserve(intr); c->intr = intr; c->channel = channel; c->script = incr(P[2]);
if (N==3) {
c->pre = c->post = 0;
}else if ((*untilRing)==0) {
(*untilRing) = c->pre = c->post = c;
}else {
c->pre = (*untilRing)->pre;
c->pre->post = c;
c->post = (*untilRing);
(*untilRing)->pre = c;
}
Tcl_CreateCloseHandler(channel,channelClose,(ClientData)c);
Tcl_CreateChannelHandler(channel,TCL_EXCEPTION|TCL_READABLE,channelEvent,(ClientData)c);
Tcl_SetObjResult(intr,P[1]);
return TCL_OK;
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::reader",readercommand,0,0);
| ^ | Definition continued at: 46, 49, 52, 55, 58, 64, 66, 72, 75, 78, 83, 86. | | | | | section top | | | ^ | Definition continued at: 47, 50, 53, 56, 59, 67, 73, 76, 79, 84, 87. | | | | | section top | |
static int writercommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
ChannelHandler **untilRing = Tcl_GetThreadData(&untilKey,sizeof(ChannelHandler*));
Tcl_Channel channel; int mood; ChannelHandler *c;
if (N!=3 && N!=4) {
Tcl_WrongNumArgs(intr,1,P,"channel script [until]");
return TCL_ERROR;
}
if (N==4 && !objeq("until",P[3]))
return rprintf(intr,"%!expected 'until': %{y}s",TCL_ERROR,P[3]);
channel = Tcl_GetChannel(intr,Tcl_GetString(P[1]),&mood);
if (!channel) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[1]);
if (!(mood&TCL_WRITABLE)) return rprintf(intr,"%!not a writable channel: %{y}s",TCL_ERROR,P[1]);
if (Tcl_SetChannelOption(intr,channel,"-blocking","0")!=TCL_OK) return TCL_ERROR;
c = heap(ChannelHandler);
Tcl_Preserve(intr); c->intr = intr; c->channel = channel; c->script = incr(P[2]);
if (N==3) {
c->pre = c->post = 0;
}else if ((*untilRing)==0) {
(*untilRing) = c->pre = c->post = c;
}else {
c->pre = (*untilRing)->pre;
c->pre->post = c;
c->post = (*untilRing);
(*untilRing)->post = c;
}
Tcl_CreateCloseHandler(channel,channelClose,(ClientData)c);
Tcl_CreateChannelHandler(channel,TCL_EXCEPTION|TCL_WRITABLE,channelEvent,(ClientData)c);
Tcl_SetObjResult(intr,P[1]);
return TCL_OK;
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::writer",writercommand,0,0);
| ^ | Definition continued at: 49, 52, 55, 58, 64, 66, 72, 75, 78, 83, 86. | | | | | section top | | | ^ | | | | | | section top | |
static int untilcommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
ChannelHandler **untilRing = Tcl_GetThreadData(&untilKey,sizeof(ChannelHandler*));
Tcl_Channel channel; int mood; ChannelHandler *c;
if (N!=1) {
Tcl_WrongNumArgs(intr,1,P,0);
return TCL_ERROR;
}
while ((*untilRing)) {
waitForSumpin();
}
Tcl_ResetResult(intr);
return TCL_OK;
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::until",untilcommand,0,0);
| ^ | | | | | | section top | | | ^ | | | | | | section top | | 51. unix::lock :: NAME
- unix::lock — Lock or unlock a file.
synopsis
wyrm::unix::lock create filepath
wyrm::unix::lock sh|ex|un [ nb ] channel
wyrm::unix::lock w|r|u [ nb|get ] channel
[ set|curr|end offset length ]
description
Provides for different kinds of file locks.
-
- create filepath
-
Create and open the file and return the channel to it.
If the file already exists, it is an error.
- sh|ex|un [ nb ] channel
-
Locks or unlocks the entire file with flock.
If nb
is specified and lock fails, it returns immediately.
Otherwise the command enters
the event loop and retries until it completes.
Returns a true value if locked, and false if not.
- w|r|u [ nb ] channel
[ set|curr|end
offset length ]
-
Locks or unlocks all or part of the file with fcntl.
If nb is specified and lock fails, it returns immediately.
Otherwise the command enters
the event loop and retries until it completes.
Returns a true value if locked, and false if not.
- w|r get channel
[ set|curr|end offset end ]
-
Identifies the first conflicting lock, if any.
The returned value is a list
w|r|u (u indicates no conflict),
set|curr|end,
offset,
length, and
owner-pid.
static int lockcommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
if (N==3 && objeq("create",P[1])) {
int fd = open(Tcl_GetString(P[2]),O_RDWR|O_CREAT|O_EXCL,0600);
if (fd<0) {
Tcl_SetErrno(errno);
rprintf(intr,"create failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}else {
Tcl_Channel channel = Tcl_MakeFileChannel((ClientData)fd,TCL_READABLE|TCL_WRITABLE);
Tcl_RegisterChannel(intr,channel);
Tcl_SetObjResult(intr,Tcl_NewStringObj(Tcl_GetChannelName(channel),-1));
return TCL_OK;
}
}else if ((N==3 || N==4 && objeq("nb",P[2]))
&& (objeq("sh",P[1]) || objeq("ex",P[1]) || objeq("un",P[1]) && N==3)
) {
int op = objeq("sh",P[1]) ? LOCK_SH|LOCK_NB : objeq("ex",P[1]) ? LOCK_EX|LOCK_NB : LOCK_UN;
int fd,mood; Tcl_Channel channel = Tcl_GetChannel(intr,Tcl_GetString(P[N-1]),&mood);
if (!channel) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[N-1]);
if (Tcl_GetChannelHandle(channel,TCL_READABLE,(ClientData*)(&fd))==TCL_ERROR
&& Tcl_GetChannelHandle(channel,TCL_WRITABLE,(ClientData*)(&fd))==TCL_ERROR)
return rprintf(intr,"%!could not get the file descriptor: %{y}s",TCL_ERROR,P[N-1]);
int r;
while ((r=flock(fd,op))<0) {
if (errno==EWOULDBLOCK) {
if (N==4) {
Tcl_SetObjResult(intr,Tcl_NewBooleanObj(0));
return TCL_OK;
}else {
waitForSumpin();
}
}else {
Tcl_SetErrno(errno);
rprintf(intr,"create failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}
}
Tcl_SetObjResult(intr,Tcl_NewBooleanObj(1));
return TCL_OK;
}else if ((N==3 || N==6 || (N==4 ||N==7) && (objeq("nb",P[2]) || objeq("get",P[2])))
&& (objeq("w",P[1]) || objeq("r",P[1]) || objeq("u",P[1]))
&& (N<6 || objeq("set",P[N-3]) || objeq("curr",P[N-3]) || objeq("end",P[N-3]))
) {
struct flock l; bool nb = N==4 || N==7; bool get = nb && objeq("get",P[2]);
int CN = 2 + (N==4 || N==7);
int fd,mood; Tcl_Channel channel = Tcl_GetChannel(intr,Tcl_GetString(P[CN]),&mood);
if (!channel) return rprintf(intr,"%!not a channel: %{y}s",TCL_ERROR,P[CN]);
if (Tcl_GetChannelHandle(channel,TCL_READABLE,(ClientData*)(&fd))==TCL_ERROR
&& Tcl_GetChannelHandle(channel,TCL_WRITABLE,(ClientData*)(&fd))==TCL_ERROR)
return rprintf(intr,"%!could not get the file descriptor: %{y}s",TCL_ERROR,P[CN]);
l.l_pid = 0;
l.l_type = objeq("w",P[1]) ? F_WRLCK : objeq("r",P[1]) ? F_RDLCK : F_UNLCK;
if (N<6) {
l.l_start = 0; l.l_len = 0; l.l_whence = SEEK_SET;
}else {
long long o;
if (Tcl_GetWideIntFromObj(intr,P[N-2],&o)!=TCL_OK) return TCL_ERROR; l.l_start = o;
if (Tcl_GetWideIntFromObj(intr,P[N-1],&o)!=TCL_OK) return TCL_ERROR; l.l_len = o;
l.l_whence = objeq("set",P[N-3]) ? SEEK_SET : objeq("curr",P[N-3]) ? SEEK_CUR : SEEK_END;
}
if (get) {
if (fcntl(fd,F_GETLK,&l)<0) {
Tcl_SetErrno(errno);
rprintf(intr,"fcntl F_GETLK failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}else {
Obj E[5];
E[0] = Tcl_NewStringObj(l.l_type==F_WRLCK ? "w" : l.l_type==F_RDLCK ? "r" : "u",1);
E[1] = Tcl_NewStringObj(l.l_whence==SEEK_SET ? "set"
: l.l_whence==SEEK_CUR ? "curr"
: "end",-1);
E[2] = Tcl_NewWideIntObj(l.l_start);
E[3] = Tcl_NewWideIntObj(l.l_len);
E[4] = Tcl_NewIntObj(l.l_pid);
Tcl_SetObjResult(intr,Tcl_NewListObj(5,E));
return TCL_OK;
}
}else {
while (fcntl(fd,F_SETLK,&l)<0) {
if (errno==EACCES || errno==EAGAIN) {
if (nb) {
Tcl_SetObjResult(intr,Tcl_NewBooleanObj(0));
return TCL_OK;
}else {
waitForSumpin();
}
}else {
Tcl_SetErrno(errno);
rprintf(intr,"partial lock failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}
}
Tcl_SetObjResult(intr,Tcl_NewBooleanObj(1));
return TCL_OK;
}
}else {
return rprintf(intr,"%!unrecognised lock request",TCL_ERROR);
}
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::lock",lockcommand,0,0);
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
static int truncatecommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
if (N!=2 && N!=3) {
Tcl_WrongNumArgs(intr,1,P,"file [length]");
return TCL_ERROR;
}else {
long long length = 0;
if (N==3 && Tcl_GetWideIntFromObj(intr,P[2],&length)!=TCL_OK) return TCL_ERROR;
if (truncate(Tcl_GetString(P[1]),length)<0) {
Tcl_SetErrno(errno);
rprintf(intr,"truncate failed: %s",Tcl_PosixError(intr));
return TCL_ERROR;
}else {
Tcl_ResetResult(intr);
return TCL_OK;
}
}
}
| ^ | | | | | | section top | |
Tcl_CreateObjCommand(intr,"::wyrm::unix::truncate",truncatecommand,0,0);
| ^ | | | | | | section top | | | ^ | |
|