static void PipeWatchProc( ClientData instanceData, /* The pipe state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { PipeState *psPtr = (PipeState *) instanceData; int newmask; if (psPtr->inFile) { newmask = mask & (TCL_READABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); } } if (psPtr->outFile) { newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); } } }
binding *kit::bind(int fd, handler *h, int mask) { binding *b; if(fd_table.find(fd) != fd_table.end()) // change binding (i.e. change handler or mask) { Tcl_DeleteFileHandler(fd); b = fd_table[fd]; b->h = h; b->mask = mask; Tcl_CreateFileHandler(fd, mask, dispatch_fdevent, (ClientData) fd); return b; } // New binding... b = new binding(); b->h = h; b->fd = fd; b->mask = mask; b->cmd << "fdevent" << fd; Tcl_CreateFileHandler(fd, mask, dispatch_fdevent, (ClientData) fd); fd_table[fd] = b; return b; }
value caml_Tcl_CreateFileHandler(value callback_fn, value file_descriptor, value mask) { filehandler *h; int m, tcl_m; CAMLparam3(callback_fn, file_descriptor, mask); h = (filehandler *) (stat_alloc(sizeof(filehandler))); /* This must be a malloc'ed data block. */ register_global_root(&(h->callback_fn)); h->callback_fn = callback_fn; h->fd = Int_val(file_descriptor); m = Int_val(mask); tcl_m = 0; if (m & 1) tcl_m |= TCL_READABLE; if (m & 2) tcl_m |= TCL_WRITABLE; if (m & 4) tcl_m |= TCL_EXCEPTION; Tcl_CreateFileHandler(Int_val(file_descriptor), tcl_m, file_proc, (ClientData) h); CAMLreturn((value) h); }
void PgStartNotifyEventSource(Pg_ConnectionId * connid) { /* Start the notify event source if it isn't already running */ if (!connid->notifier_running) { int pqsock = PQsocket(connid->conn); if (pqsock >= 0) { #if TCL_MAJOR_VERSION >= 8 Tcl_CreateChannelHandler(connid->notifier_channel, TCL_READABLE, Pg_Notify_FileHandler, (ClientData) connid); #else /* In Tcl 7.5 and 7.6, we need to gin up a Tcl_File. */ Tcl_File tclfile = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD); Tcl_CreateFileHandler(tclfile, TCL_READABLE, Pg_Notify_FileHandler, (ClientData) connid); connid->notifier_socket = pqsock; #endif connid->notifier_running = 1; } } }
static void TcpWatchProc( ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = instanceData; if (statePtr->acceptProc != NULL) { /* * Make sure we don't mess with server sockets since they will never * be readable or writable at the Tcl level. This keeps Tcl scripts * from interfering with the -accept behavior (bug #3394732). */ return; } if (statePtr->flags & TCP_ASYNC_CONNECT) { /* Async sockets use a FileHandler internally while connecting, so we * need to cache this request until the connection has succeeded. */ statePtr->filehandlers = mask; } else if (mask) { Tcl_CreateFileHandler(statePtr->fds.fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, statePtr->channel); } else { Tcl_DeleteFileHandler(statePtr->fds.fd); } }
static int TB_Init(Tcl_Interp *interp) { global_interp = interp; BUF = (char *)malloc(bufsize); if(!BUF) ATerror("Not enough space to allocate text buffer!\n"); Tcl_CreateCommand(interp, "TBsend", Tcl_TBsend, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); Tcl_CreateCommand(interp, "TBstring", Tcl_TBstring, NULL, NULL); Tcl_CreateCommand(interp, "bgerror", Tcl_bgerror, NULL, NULL); if(use_toolbus) { /*TB_connect(cid);*/ /*toolbus_file = Tcl_GetFile((ClientData)TB_getSocket(cid), TCL_UNIX_FD);*/ Tcl_CreateFileHandler(cid, TCL_READABLE, tcl_toolbus_handler, NULL); } if(Tcl_EvalFile(interp, LIBDIR "/tcltk.tcl") != TCL_OK) { interp->result = "Cannot load file " LIBDIR "/tcltk.tcl"; return TCL_ERROR; } Tcl_SetVar(interp, "TB_LIBDIR", LIBDIR, TCL_GLOBAL_ONLY); return !TCL_ERROR; }
CAMLprim value camltk_add_file_output(value fd, value cbid) { CheckInit(); Tcl_CreateFileHandler(tcl_filehandle(fd), TCL_WRITABLE, FileProc, (ClientData) (Long_val(cbid))); return Val_unit; }
/* * create/delete the Tcl file handler */ void RtdCamera::fileHandler(int create) { if (! eventHndl_->socket) return; if (create) Tcl_CreateFileHandler(RTD_TCL_GETFILE_(eventHndl_->socket), TCL_READABLE, fileEventProc, (ClientData)this); else Tcl_DeleteFileHandler(RTD_TCL_GETFILE_(eventHndl_->socket)); }
/* this one is verbatim from FileWatchProc in tcl8.5.8/unix/tclUnixChan.c */ void sequencer_watch(ClientData instanceData, int mask) { sequencer_instance_t *sqi = (sequencer_instance_t *)instanceData; mask &= sqi->direction; if (mask) { Tcl_CreateFileHandler(sqi->fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) sqi->chan); } else { Tcl_DeleteFileHandler(sqi->fd); } }
static void set_mask(int fd) { int mask = 0; const struct file_handler * const h = &array[fd]; if (NULL != h->f[OOP_READ]) mask |= TCL_READABLE; if (NULL != h->f[OOP_WRITE]) mask |= TCL_WRITABLE; if (NULL != h->f[OOP_EXCEPTION]) mask |= TCL_EXCEPTION; if (0 == mask) Tcl_DeleteFileHandler(fd); else Tcl_CreateFileHandler(fd,mask,file_call,(ClientData) fd); }
static void TcpWatchProc( ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = instanceData; if (statePtr->acceptProc != NULL) { /* * Make sure we don't mess with server sockets since they will never * be readable or writable at the Tcl level. This keeps Tcl scripts * from interfering with the -accept behavior (bug #3394732). */ return; } if (statePtr->flags & TCP_ASYNC_PENDING) { /* Async sockets use a FileHandler internally while connecting, so we * need to cache this request until the connection has succeeded. */ statePtr->filehandlers = mask; } else if (mask) { /* * Whether it is a bug or feature or otherwise, it is a fact * of life that on at least some Linux kernels select() fails * to report that a socket file descriptor is writable when * the other end of the socket is closed. This is in contrast * to the guarantees Tcl makes that its channels become * writable and fire writable events on an error conditon. * This has caused a leak of file descriptors in a state of * background flushing. See Tcl ticket 1758a0b603. * * As a workaround, when our caller indicates an interest in * writable notifications, we must tell the notifier built * around select() that we are interested in the readable state * of the file descriptor as well, as that is the only reliable * means to get notified of error conditions. Then it is the * task of WrapNotify() above to untangle the meaning of these * channel states and report the chan events as best it can. * We save a copy of the mask passed in to assist with that. */ statePtr->interest = mask; Tcl_CreateFileHandler(statePtr->fds.fd, mask|TCL_READABLE, (Tcl_FileProc *) WrapNotify, statePtr); } else { Tcl_DeleteFileHandler(statePtr->fds.fd); } }
TkDisplay * TkpOpenDisplay( CONST char *displayNameStr) { TkDisplay *dispPtr; Display *display; int event = 0; int error = 0; int major = 1; int minor = 0; int reason = 0; unsigned int use_xkb = 0; /* ** Bug [3607830]: Before using Xkb, it must be initialized and confirmed ** that the serve supports it. The XkbOpenDisplay call ** will perform this check and return NULL if the extension ** is not supported. ** ** Work around un-const-ified Xkb headers using (char *) cast. */ display = XkbOpenDisplay((char *)displayNameStr, &event, &error, &major, &minor, &reason); if (display == NULL) { /*fprintf(stderr,"event=%d error=%d major=%d minor=%d reason=%d\nDisabling xkb\n", event, error, major, minor, reason);*/ display = XOpenDisplay(displayNameStr); } else { use_xkb = TK_DISPLAY_USE_XKB; /*fprintf(stderr, "Using xkb %d.%d\n", major, minor);*/ } if (display == NULL) { return NULL; } dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay)); memset(dispPtr, 0, sizeof(TkDisplay)); dispPtr->display = display; dispPtr->flags |= use_xkb; #ifdef TK_USE_INPUT_METHODS OpenIM(dispPtr); #endif Tcl_CreateFileHandler(ConnectionNumber(display), TCL_READABLE, DisplayFileProc, (ClientData) dispPtr); return dispPtr; }
static void FileWatchProc( ClientData instanceData, /* The file state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { FileState *fsPtr = instanceData; /* * Make sure we only register for events that are valid on this file. Note * that we are passing Tcl_NotifyChannel directly to Tcl_CreateFileHandler * with the channel pointer as the client data. */ mask &= fsPtr->validMask; if (mask) { Tcl_CreateFileHandler(fsPtr->fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, fsPtr->channel); } else { Tcl_DeleteFileHandler(fsPtr->fd); } }
int _ged_run_rtwizard(struct ged *gedp) { int i; FILE *fp_in; #ifndef _WIN32 int pipe_in[2]; int pipe_err[2]; #else HANDLE pipe_in[2], pipe_inDup; HANDLE pipe_err[2], pipe_errDup; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; SECURITY_ATTRIBUTES sa = {0}; struct bu_vls line = BU_VLS_INIT_ZERO; #endif struct ged_run_rt *run_rtp; struct _ged_rt_client_data *drcdp; #ifndef _WIN32 int pid; int ret; ret = pipe(pipe_in); if (ret < 0) perror("pipe"); ret = pipe(pipe_err); if (ret < 0) perror("pipe"); if ((pid = fork()) == 0) { /* make this a process group leader */ setpgid(0, 0); /* Redirect stdin and stderr */ (void)close(0); ret = dup(pipe_in[0]); if (ret < 0) perror("dup"); (void)close(2); ret = dup(pipe_err[1]); if (ret < 0) perror("dup"); /* close pipes */ (void)close(pipe_in[0]); (void)close(pipe_in[1]); (void)close(pipe_err[0]); (void)close(pipe_err[1]); for (i = 3; i < 20; i++) (void)close(i); (void)execvp(gedp->ged_gdp->gd_rt_cmd[0], gedp->ged_gdp->gd_rt_cmd); perror(gedp->ged_gdp->gd_rt_cmd[0]); exit(16); } /* As parent, send view information down pipe */ (void)close(pipe_in[0]); fp_in = fdopen(pipe_in[1], "w"); (void)close(pipe_err[1]); (void)fclose(fp_in); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(run_rtp, struct ged_run_rt); BU_LIST_INIT(&run_rtp->l); BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l); run_rtp->fd = pipe_err[0]; run_rtp->pid = pid; /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(drcdp, struct _ged_rt_client_data); drcdp->gedp = gedp; drcdp->rrtp = run_rtp; Tcl_CreateFileHandler(run_rtp->fd, TCL_READABLE, _ged_rt_output_handler, (ClientData)drcdp); return 0; #else sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* Create a pipe for the child process's STDOUT. */ CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0); /* Create noninheritable read handle and close the inheritable read handle. */ DuplicateHandle(GetCurrentProcess(), pipe_err[0], GetCurrentProcess(), &pipe_errDup , 0, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(pipe_err[0]); /* Create a pipe for the child process's STDIN. */ CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0); /* Duplicate the write handle to the pipe so it is not inherited. */ DuplicateHandle(GetCurrentProcess(), pipe_in[1], GetCurrentProcess(), &pipe_inDup, 0, FALSE, /* not inherited */ DUPLICATE_SAME_ACCESS); CloseHandle(pipe_in[1]); si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpReserved2 = NULL; si.cbReserved2 = 0; si.lpDesktop = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = pipe_in[0]; si.hStdOutput = pipe_err[1]; si.hStdError = pipe_err[1]; for (i = 0; i < gedp->ged_gdp->gd_rt_cmd_len; i++) { bu_vls_printf(&line, "\"%s\" ", gedp->ged_gdp->gd_rt_cmd[i]); } CreateProcess(NULL, bu_vls_addr(&line), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi); bu_vls_free(&line); CloseHandle(pipe_in[0]); CloseHandle(pipe_err[1]); /* As parent, send view information down pipe */ fp_in = _fdopen(_open_osfhandle((intptr_t)pipe_inDup, _O_TEXT), "wb"); (void)fclose(fp_in); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(run_rtp, struct ged_run_rt); BU_LIST_INIT(&run_rtp->l); BU_LIST_APPEND(&gedp->ged_gdp->gd_headRunRt.l, &run_rtp->l); run_rtp->fd = pipe_errDup; run_rtp->hProcess = pi.hProcess; run_rtp->pid = pi.dwProcessId; run_rtp->aborted=0; run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE); /* must be BU_GET() to match release in _ged_rt_output_handler */ BU_GET(drcdp, struct _ged_rt_client_data); drcdp->gedp = gedp; drcdp->rrtp = run_rtp; Tcl_CreateChannelHandler(run_rtp->chan, TCL_READABLE, _ged_rt_output_handler, (ClientData)drcdp); return 0; #endif }
Tcl_Channel Tcl_OpenTcpServer( Tcl_Interp *interp, /* For error reporting - may be NULL. */ int port, /* Port number to open. */ const char *myHost, /* Name of local host. */ Tcl_TcpAcceptProc *acceptProc, /* Callback for accepting connections from new * clients. */ ClientData acceptProcData) /* Data for the callback. */ { int status = 0, sock = -1, reuseaddr = 1, chosenport = 0; struct addrinfo *addrlist = NULL, *addrPtr; /* socket address */ TcpState *statePtr = NULL; char channelName[SOCK_CHAN_LENGTH]; const char *errorMsg = NULL; TcpFdList *fds = NULL, *newfds; /* * Try to record and return the most meaningful error message, i.e. the * one from the first socket that went the farthest before it failed. */ enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP; int my_errno = 0; if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { my_errno = errno; goto error; } for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { sock = socket(addrPtr->ai_family, addrPtr->ai_socktype, addrPtr->ai_protocol); if (sock == -1) { if (howfar < SOCKET) { howfar = SOCKET; my_errno = errno; } continue; } /* * Set the close-on-exec flag so that the socket will not get * inherited by child processes. */ fcntl(sock, F_SETFD, FD_CLOEXEC); /* * Set kernel space buffering */ TclSockMinimumBuffers(INT2PTR(sock), SOCKET_BUFSIZE); /* * Set up to reuse server addresses automatically and bind to the * specified port. */ (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr, sizeof(reuseaddr)); /* * Make sure we use the same port number when opening two server * sockets for IPv4 and IPv6 on a random port. * * As sockaddr_in6 uses the same offset and size for the port member * as sockaddr_in, we can handle both through the IPv4 API. */ if (port == 0 && chosenport != 0) { ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port = htons(chosenport); } #ifdef IPV6_V6ONLY /* Missing on: Solaris 2.8 */ if (addrPtr->ai_family == AF_INET6) { int v6only = 1; (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)); } #endif /* IPV6_V6ONLY */ status = bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen); if (status == -1) { if (howfar < BIND) { howfar = BIND; my_errno = errno; } close(sock); sock = -1; continue; } if (port == 0 && chosenport == 0) { address sockname; socklen_t namelen = sizeof(sockname); /* * Synchronize port numbers when binding to port 0 of multiple * addresses. */ if (getsockname(sock, &sockname.sa, &namelen) >= 0) { chosenport = ntohs(sockname.sa4.sin_port); } } status = listen(sock, SOMAXCONN); if (status < 0) { if (howfar < LISTEN) { howfar = LISTEN; my_errno = errno; } close(sock); sock = -1; continue; } if (statePtr == NULL) { /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; sprintf(channelName, SOCK_TEMPLATE, (long) statePtr); newfds = &statePtr->fds; } else { newfds = ckalloc(sizeof(TcpFdList)); memset(newfds, (int) 0, sizeof(TcpFdList)); fds->next = newfds; } newfds->fd = sock; newfds->statePtr = statePtr; fds = newfds; /* * Set up the callback mechanism for accepting connections from new * clients. */ Tcl_CreateFileHandler(sock, TCL_READABLE, TcpAccept, fds); } error: if (addrlist != NULL) { freeaddrinfo(addrlist); } if (statePtr != NULL) { statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, statePtr, 0); return statePtr->channel; } if (interp != NULL) { Tcl_Obj *errorObj = Tcl_NewStringObj("couldn't open socket: ", -1); if (errorMsg == NULL) { errno = my_errno; Tcl_AppendToObj(errorObj, Tcl_PosixError(interp), -1); } else { Tcl_AppendToObj(errorObj, errorMsg, -1); } Tcl_SetObjResult(interp, errorObj); } if (sock != -1) { close(sock); } return NULL; }
static int TcpConnect( Tcl_Interp *interp, /* For error reporting; can be NULL. */ TcpState *statePtr) { socklen_t optlen; int async_callback = statePtr->flags & TCP_ASYNC_PENDING; int ret = -1, error = errno; int async = statePtr->flags & TCP_ASYNC_CONNECT; if (async_callback) { goto reenter; } for (statePtr->addr = statePtr->addrlist; statePtr->addr != NULL; statePtr->addr = statePtr->addr->ai_next) { for (statePtr->myaddr = statePtr->myaddrlist; statePtr->myaddr != NULL; statePtr->myaddr = statePtr->myaddr->ai_next) { int reuseaddr = 1; /* * No need to try combinations of local and remote addresses of * different families. */ if (statePtr->myaddr->ai_family != statePtr->addr->ai_family) { continue; } /* * Close the socket if it is still open from the last unsuccessful * iteration. */ if (statePtr->fds.fd >= 0) { close(statePtr->fds.fd); statePtr->fds.fd = -1; errno = 0; } statePtr->fds.fd = socket(statePtr->addr->ai_family, SOCK_STREAM, 0); if (statePtr->fds.fd < 0) { continue; } /* * Set the close-on-exec flag so that the socket will not get * inherited by child processes. */ fcntl(statePtr->fds.fd, F_SETFD, FD_CLOEXEC); /* * Set kernel space buffering */ TclSockMinimumBuffers(INT2PTR(statePtr->fds.fd), SOCKET_BUFSIZE); if (async) { ret = TclUnixSetBlockingMode(statePtr->fds.fd,TCL_MODE_NONBLOCKING); if (ret < 0) { continue; } } /* Gotta reset the error variable here, before we use it for the * first time in this iteration. */ error = 0; (void) setsockopt(statePtr->fds.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr, sizeof(reuseaddr)); ret = bind(statePtr->fds.fd, statePtr->myaddr->ai_addr, statePtr->myaddr->ai_addrlen); if (ret < 0) { error = errno; continue; } /* * Attempt to connect. The connect may fail at present with an * EINPROGRESS but at a later time it will complete. The caller * will set up a file handler on the socket if she is interested * in being informed when the connect completes. */ ret = connect(statePtr->fds.fd, statePtr->addr->ai_addr, statePtr->addr->ai_addrlen); if (ret < 0) error = errno; if (ret < 0 && errno == EINPROGRESS) { Tcl_CreateFileHandler(statePtr->fds.fd, TCL_WRITABLE|TCL_EXCEPTION, TcpAsyncCallback, statePtr); errno = EWOULDBLOCK; SET_BITS(statePtr->flags, TCP_ASYNC_PENDING); return TCL_OK; reenter: CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING); Tcl_DeleteFileHandler(statePtr->fds.fd); /* * Read the error state from the socket to see if the async * connection has succeeded or failed. As this clears the * error condition, we cache the status in the socket state * struct for later retrieval by [fconfigure -error]. */ optlen = sizeof(int); getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR, (char *) &error, &optlen); errno = error; } if (error == 0) { goto out; } } } out: statePtr->connectError = error; CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); if (async_callback) { /* * An asynchonous connection has finally succeeded or failed. */ TcpWatchProc(statePtr, statePtr->filehandlers); TclUnixSetBlockingMode(statePtr->fds.fd, statePtr->cachedBlocking); if (error != 0) { SET_BITS(statePtr->flags, TCP_ASYNC_FAILED); } /* * We need to forward the writable event that brought us here, bcasue * upon reading of getsockopt(SO_ERROR), at least some OSes clear the * writable state from the socket, and so a subsequent select() on * behalf of a script level [fileevent] would not fire. It doesn't * hurt that this is also called in the successful case and will save * the event mechanism one roundtrip through select(). */ if (statePtr->cachedBlocking == TCL_MODE_NONBLOCKING) { Tcl_NotifyChannel(statePtr->channel, TCL_WRITABLE); } } if (error != 0) { /* * Failure for either a synchronous connection, or an async one that * failed before it could enter background mode, e.g. because an * invalid -myaddr was given. */ if (interp != NULL) { errno = error; Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't open socket: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } return TCL_OK; }
static int TestfilehandlerCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int argc, /* Number of arguments. */ CONST char **argv) /* Argument strings. */ { Pipe *pipePtr; int i, mask, timeout; static int initialized = 0; char buffer[4000]; TclFile file; /* * NOTE: When we make this code work on Windows also, the following * variable needs to be made Unix-only. */ if (!initialized) { for (i = 0; i < MAX_PIPES; i++) { testPipes[i].readFile = NULL; } initialized = 1; } if (argc < 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " option ... \"", NULL); return TCL_ERROR; } pipePtr = NULL; if (argc >= 3) { if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) { return TCL_ERROR; } if (i >= MAX_PIPES) { Tcl_AppendResult(interp, "bad index ", argv[2], NULL); return TCL_ERROR; } pipePtr = &testPipes[i]; } if (strcmp(argv[1], "close") == 0) { for (i = 0; i < MAX_PIPES; i++) { if (testPipes[i].readFile != NULL) { TclpCloseFile(testPipes[i].readFile); testPipes[i].readFile = NULL; TclpCloseFile(testPipes[i].writeFile); testPipes[i].writeFile = NULL; } } } else if (strcmp(argv[1], "clear") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " clear index\"", NULL); return TCL_ERROR; } pipePtr->readCount = pipePtr->writeCount = 0; } else if (strcmp(argv[1], "counts") == 0) { char buf[TCL_INTEGER_SPACE * 2]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " counts index\"", NULL); return TCL_ERROR; } sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "create") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " create index readMode writeMode\"", NULL); return TCL_ERROR; } if (pipePtr->readFile == NULL) { if (!TclpCreatePipe(&pipePtr->readFile, &pipePtr->writeFile)) { Tcl_AppendResult(interp, "couldn't open pipe: ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } #ifdef O_NONBLOCK fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK); fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK); #else Tcl_SetResult(interp, "can't make pipes non-blocking", TCL_STATIC); return TCL_ERROR; #endif } pipePtr->readCount = 0; pipePtr->writeCount = 0; if (strcmp(argv[3], "readable") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->readFile), TCL_READABLE, TestFileHandlerProc, (ClientData) pipePtr); } else if (strcmp(argv[3], "off") == 0) { Tcl_DeleteFileHandler(GetFd(pipePtr->readFile)); } else if (strcmp(argv[3], "disabled") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->readFile), 0, TestFileHandlerProc, (ClientData) pipePtr); } else { Tcl_AppendResult(interp, "bad read mode \"", argv[3], "\"", NULL); return TCL_ERROR; } if (strcmp(argv[4], "writable") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), TCL_WRITABLE, TestFileHandlerProc, (ClientData) pipePtr); } else if (strcmp(argv[4], "off") == 0) { Tcl_DeleteFileHandler(GetFd(pipePtr->writeFile)); } else if (strcmp(argv[4], "disabled") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), 0, TestFileHandlerProc, (ClientData) pipePtr); } else { Tcl_AppendResult(interp, "bad read mode \"", argv[4], "\"", NULL); return TCL_ERROR; } } else if (strcmp(argv[1], "empty") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " empty index\"", NULL); return TCL_ERROR; } while (read(GetFd(pipePtr->readFile), buffer, 4000) > 0) { /* Empty loop body. */ } } else if (strcmp(argv[1], "fill") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " fill index\"", NULL); return TCL_ERROR; } memset(buffer, 'a', 4000); while (write(GetFd(pipePtr->writeFile), buffer, 4000) > 0) { /* Empty loop body. */ } } else if (strcmp(argv[1], "fillpartial") == 0) { char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " fillpartial index\"", NULL); return TCL_ERROR; } memset(buffer, 'b', 10); TclFormatInt(buf, write(GetFd(pipePtr->writeFile), buffer, 10)); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "oneevent") == 0) { Tcl_DoOneEvent(TCL_FILE_EVENTS|TCL_DONT_WAIT); } else if (strcmp(argv[1], "wait") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " wait index readable|writable timeout\"", NULL); return TCL_ERROR; } if (pipePtr->readFile == NULL) { Tcl_AppendResult(interp, "pipe ", argv[2], " doesn't exist", NULL); return TCL_ERROR; } if (strcmp(argv[3], "readable") == 0) { mask = TCL_READABLE; file = pipePtr->readFile; } else { mask = TCL_WRITABLE; file = pipePtr->writeFile; } if (Tcl_GetInt(interp, argv[4], &timeout) != TCL_OK) { return TCL_ERROR; } i = TclUnixWaitForFile(GetFd(file), mask, timeout); if (i & TCL_READABLE) { Tcl_AppendElement(interp, "readable"); } if (i & TCL_WRITABLE) { Tcl_AppendElement(interp, "writable"); } } else if (strcmp(argv[1], "windowevent") == 0) { Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be close, clear, counts, create, empty, fill, " "fillpartial, oneevent, wait, or windowevent", NULL); return TCL_ERROR; } return TCL_OK; }