/*
Copyright (c) 1995-1999 Nick Ing-Simmons. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
*/
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
#include "tkGlue.def"
#define TCL_EVENT_IMPLEMENT
#include "pTk/Lang.h"
#include "pTk/tkEvent.h"
#include "pTk/tkEvent_f.h"
void
LangDebug(char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
PerlIO_vprintf(PerlIO_stderr(), fmt, ap);
PerlIO_flush(PerlIO_stderr());
va_end(ap);
}
void
#ifdef STANDARD_C
Tcl_Panic(char *fmt,...)
#else
/*VARARGS0 */
Tcl_Panic(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#ifdef I_STDARG
va_start(ap, fmt);
#else
va_start(ap);
#endif
PerlIO_flush(PerlIO_stderr());
PerlIO_vprintf(PerlIO_stderr(), fmt, ap);
PerlIO_putc(PerlIO_stderr(),'\n');
va_end(ap);
croak("Tcl_Panic");
}
#undef Tcl_Realloc
#undef Tcl_Alloc
#undef Tcl_Free
int
Tcl_DumpActiveMemory (char *fileName)
{
return 0;
}
void
Tcl_ValidateAllMemory (char *file, int line)
{
}
#ifdef DO_CHECK_TCL_ALLOC
long Tcl_AllocCount = 0;
static int
is_perl_arena(void *ptr)
{
SV *sv = ptr;
SV* sva;
register SV* svend;
for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
svend = &sva[SvREFCNT(sva)];
if (sva <= sv && sv < svend)
return 1;
}
return 0;
}
static void
check_lp(long *lp,char *s)
{
if (is_perl_arena(lp))
{
warn("Attempt to '%s(%p)' perl data",s,lp+2);
abort();
}
if (lp[0] != (long)lp || lp[lp[1]-1] != (long)lp)
{
warn("Invalid '%s(%p)' %lx,%lx,%lx",
s,lp+2,lp[0],lp[1],lp[lp[1]-1]);
abort();
}
}
char *
Tcl_Realloc(char *p, unsigned int size)
{
long *lp = ((long *)p)-2;
check_lp(lp,__FUNCTION__);
if ((int) size < 0)
abort();
size = (size+sizeof(long)-1)/sizeof(long)+3;
Renew(lp,size,long);
lp[0] = (long)lp;
lp[1] = size;
lp[size-1] = (long)lp;
return (char *)(lp+2);
}
char *
Tcl_Alloc(unsigned int size)
{
long *lp;
if ((int) size < 0)
abort();
size = (size+sizeof(long)-1)/sizeof(long)+3;
Newz(603, lp, size, long);
lp[0] = (long)lp;
lp[1] = size;
lp[size-1] = (long)lp;
Tcl_AllocCount++;
return (char *)(lp+2);
}
void
Tcl_Free(char *p)
{
if (p)
{
long *lp = ((long *)p)-2;
check_lp(lp,__FUNCTION__);
memset(lp,-1,lp[1]*sizeof(long));
Tcl_AllocCount--;
Safefree(lp);
}
else
{
warn("Attempt to 'free(%p)' NULL",p);
}
}
void
Event_CleanupGlue(void)
{
#if 0
warn("%ld Tcl_Alloc packets un-freed",Tcl_AllocCount);
#endif
}
#else
char *
Tcl_Realloc(char *p, unsigned int size)
{
if ((int) size < 0)
abort();
Renew(p,size,char);
return p;
}
char *
Tcl_Alloc(unsigned int size)
{
char *p;
if ((int) size < 0)
abort();
Newz(603, p, size, char);
return p;
}
void
Tcl_Free(char *p)
{
Safefree(p);
}
void
Event_CleanupGlue(void)
{
}
#endif
char *
Tcl_DbCkalloc (unsigned int size,char *file,int line)
{
return Tcl_Alloc(size);
}
void
Tcl_DbCkfree (char *ptr,char *file ,int line)
{
Tcl_Free(ptr);
}
char *
Tcl_DbCkrealloc (char *ptr,unsigned int size,char *file,int line)
{
return Tcl_Realloc(ptr,size);
}
void
LangExit(value)
int value;
{
my_exit((unsigned) value);
}
long
Lang_OSHandle(fd)
int fd;
{
#ifdef WIN32
return win32_get_osfhandle(fd);
#else
return fd;
#endif
}
static SV *
FindVarName(varName,flags)
char *varName;
int flags;
{
STRLEN len;
SV *name = newSVpv("Tk",2);
SV *sv;
sv_catpv(name,"::");
sv_catpv(name,varName);
sv = perl_get_sv(SvPV(name,len),flags);
SvREFCNT_dec(name);
return sv;
}
static void
install_vtab(name, table, size)
char *name;
void *table;
size_t size;
{
if (table)
{
typedef int (*fptr)_((void));
fptr *q = table;
unsigned i;
sv_setiv(FindVarName(name,GV_ADD|GV_ADDMULTI),(IV) table);
if (size % sizeof(fptr))
{
warn("%s is strange size %d",name,size);
}
size /= sizeof(void *);
for (i=0; i < size; i++)
{
if (!q[i])
warn("%s slot %d is NULL",name,i);
}
}
else
{
croak("%s pointer is NULL",name);
}
}
static void SetupProc _ANSI_ARGS_((ClientData clientData, int flags));
static void CheckProc _ANSI_ARGS_((ClientData clientData, int flags));
static int EventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags));
typedef struct PerlIOHandler
{
struct PerlIOHandler *nextPtr; /* Next in list of all files we care about. */
SV *handle; /* Handle we are tied to */
IO *io; /* Current IO within handle */
GV *untied; /* Another handle to pass to methods
* it is untied to avoid recusion and
* has IoIFP/IoOFP of its IO dynamically set to those
* of io.
*/
LangCallback *readHandler;
LangCallback *writeHandler;
LangCallback *exceptionHandler;
int mask; /* Mask of desired events: TCL_READABLE etc. */
int readyMask; /* Mask of events that have been seen since the
* last time file handlers were invoked for
* this file. */
int waitMask; /* Events on which we are doing blocking wait */
int handlerMask; /* Events for which we have callbacks */
int callingMask; /* Events for which we are in callbacks */
int pending;
} PerlIOHandler;
typedef struct PerlIOEvent
{
Tcl_Event header; /* Information that is standard for all events. */
IO *io; /* PerlIO descriptor that is ready. */
} PerlIOEvent;
static int initialized = 0;
static PerlIOHandler *firstPerlIOHandler;
static void PerlIOEventInit(void);
static void PerlIO_watch(PerlIOHandler *filePtr);
static volatile int stuck;
void
PerlIO_MaskCheck(PerlIOHandler *filePtr)
{
if (filePtr->mask & ~(filePtr->waitMask|filePtr->handlerMask))
{
warn("Mask=%d wait=%d handler=%d",
filePtr->mask, filePtr->waitMask, filePtr->handlerMask);
PerlIO_watch(filePtr);
}
}
static void
PerlIOFileProc(ClientData clientData, int mask)
{
PerlIOHandler *filePtr = (PerlIOHandler *) clientData;
PerlIO_MaskCheck(filePtr);
filePtr->readyMask |= (mask & filePtr->mask);
}
SV *
PerlIO_handle(filePtr)
PerlIOHandler *filePtr;
{
filePtr->io = sv_2io(filePtr->handle);
if (filePtr->io)
{
/* io exists - copy current PerlIO * from io to our un-tied IO */
IO *tmpio = GvIOp(filePtr->untied);
IoIFP(tmpio) = IoIFP(filePtr->io);
IoOFP(tmpio) = IoOFP(filePtr->io);
return newRV((SV *) filePtr->untied);
}
return &PL_sv_undef;
}
void
PerlIO_unwatch(PerlIOHandler *filePtr)
{
filePtr->waitMask = filePtr->handlerMask = 0;
PerlIO_watch(filePtr);
}
void
PerlIO_watch(PerlIOHandler *filePtr)
{
PerlIO *ip = IoIFP(filePtr->io);
PerlIO *op = IoOFP(filePtr->io);
int fd = (ip) ? PerlIO_fileno(ip) : ((op) ? PerlIO_fileno(op) : -1);
int mask = filePtr->waitMask|filePtr->handlerMask;
if (mask & ~(TCL_READABLE|TCL_EXCEPTION|TCL_WRITABLE))
{
LangDebug("Invalid mask %x",mask);
croak("Invalid mask %x",mask);
}
if (mask & (TCL_READABLE|TCL_EXCEPTION))
{
if (!ip)
croak("Handle not opened for input");
}
if (mask & (TCL_WRITABLE))
{
if (!op)
croak("Handle not opened for output");
}
if ((mask & TCL_READABLE) && (mask & TCL_WRITABLE))
{
/* Both read and write IO - make sure buffers not shared */
if (op && (op == ip) && fd >= 0)
{
IoOFP(filePtr->io) = op = PerlIO_fdopen(fd, "w");
}
if (PerlIO_fileno(ip) != PerlIO_fileno(op))
{
croak("fileno not same for read %d and write %d",
PerlIO_fileno(ip) , PerlIO_fileno(op));
}
}
if (filePtr->mask != mask)
{
if (fd >= 0)
{
Tcl_DeleteFileHandler(fd);
}
if (mask && fd >= 0)
{
Tcl_CreateFileHandler(fd, mask, PerlIOFileProc, (ClientData) filePtr );
}
filePtr->mask = mask;
}
}
int
PerlIO_is_writable(filePtr)
PerlIOHandler *filePtr;
{
if (!(filePtr->readyMask & TCL_WRITABLE))
{
PerlIO *op = IoOFP(filePtr->io);
if (op)
{
if (PerlIO_has_cntptr(op) && PerlIO_get_cnt(op) > 0)
{
filePtr->readyMask |= TCL_WRITABLE;
}
}
}
return (filePtr->readyMask & TCL_WRITABLE);
}
int
PerlIO_is_readable(filePtr)
PerlIOHandler *filePtr;
{
if (!(filePtr->readyMask & TCL_READABLE))
{
PerlIO *io = IoIFP(filePtr->io);
if (io)
{
#ifdef PERLIO_LAYERS
if (PerlIO_has_cntptr(io) && PerlIO_get_cnt(io) > 0)
{
filePtr->readyMask |= TCL_READABLE;
}
#else
/* Turn this buffer stuff off for now */
if (PerlIO_has_cntptr(io) && PerlIO_get_cnt(io) > 0)
{
filePtr->readyMask |= TCL_READABLE;
}
#endif
}
}
return (filePtr->readyMask & TCL_READABLE);
}
int
PerlIO_has_exception(filePtr)
PerlIOHandler *filePtr;
{
return (filePtr->readyMask & TCL_EXCEPTION);
}
void
PerlIO_wait(filePtr,mask)
PerlIOHandler * filePtr;
int mask;
{
/* Return at once if we are in the callback */
if (!(filePtr->callingMask & mask))
{
int oldMask = filePtr->mask & mask;
int oldWait = filePtr->waitMask & mask;
int (*check)(PerlIOHandler *) = NULL;
/* Prepare to poll */
switch (mask)
{
case TCL_EXCEPTION:
check = PerlIO_has_exception;
break;
case TCL_WRITABLE:
check = PerlIO_is_writable;
break;
case TCL_READABLE:
check = PerlIO_is_readable;
break;
default:
croak("Invalid wait type %d",mask);
}
/* Inhibit callbacks */
filePtr->waitMask |= mask;
/* Watch handle if we are not already */
if (!oldMask)
PerlIO_watch(filePtr);
while (!(*check)(filePtr))
{
Tcl_DoOneEvent(0);
}
/* Restore watch state */
filePtr->waitMask = (filePtr->waitMask&~mask)|oldWait;
PerlIO_watch(filePtr);
/* Re-enable callbacks */
/* Consume the readiness */
filePtr->readyMask &= ~mask;
}
}
void
TkPerlIO_debug(filePtr,s)
PerlIOHandler *filePtr;
char *s;
{
PerlIO *ip = IoIFP(filePtr->io);
PerlIO *op = IoOFP(filePtr->io);
int ifd = (ip) ? PerlIO_fileno(ip) : -1;
int ofd = (op) ? PerlIO_fileno(op) : -1;
LangDebug("%s: ip=%p count=%d, op=%p count=%d\n",s,
ip,PerlIO_get_cnt(ip),
op,PerlIO_get_cnt(op));
}
static void
PerlIOSetupProc(ClientData data, int flags)
{
static Tcl_Time blockTime = {0, 0};
if (flags & TCL_FILE_EVENTS)
{
PerlIOHandler *filePtr = firstPerlIOHandler;
while (filePtr != NULL)
{
/* file is ready do not block */
if ((filePtr->mask & TCL_READABLE)
&& PerlIO_is_readable(filePtr))
Tcl_SetMaxBlockTime(&blockTime);
if ((filePtr->mask & TCL_WRITABLE)
&& PerlIO_is_writable(filePtr))
Tcl_SetMaxBlockTime(&blockTime);
if ((filePtr->mask & TCL_EXCEPTION)
&& PerlIO_has_exception(filePtr))
Tcl_SetMaxBlockTime(&blockTime);
filePtr = filePtr->nextPtr;
}
}
}
static int
PerlIOEventProc(evPtr, flags)
Tcl_Event *evPtr; /* Event to service. */
int flags; /* Flags that indicate what events to
* handle, such as TCL_FILE_EVENTS. */
{
if (flags & TCL_FILE_EVENTS)
{
PerlIOEvent *fileEvPtr = (PerlIOEvent *) evPtr;
PerlIOHandler *filePtr = firstPerlIOHandler;
dTHX;
/*
* Search through the file handlers to find the one whose handle matches
* the event. We do this rather than keeping a pointer to the file
* handler directly in the event, so that the handler can be deleted
* while the event is queued without leaving a dangling pointer.
*/
while (filePtr != NULL)
{
if (filePtr->io == fileEvPtr->io)
{
int doMask;
/*
* The code is tricky for two reasons:
* 1. The file handler's desired events could have changed
* since the time when the event was queued, so AND the
* ready mask with the desired mask.
* 2. The file could have been closed and re-opened since
* the time when the event was queued. This is why the
* ready mask is stored in the file handler rather than
* the queued event: it will be zeroed when a new
* file handler is created for the newly opened file.
*/
PerlIO_MaskCheck(filePtr);
/* clear bits nobody cares about */
filePtr->readyMask &= filePtr->mask;
/* Decide which callbacks will be called */
doMask = (filePtr->readyMask) & (~(filePtr->waitMask)) & (filePtr->handlerMask);
/* clear bits we are going to callback */
filePtr->readyMask &= ~doMask;
filePtr->pending = 0;
if ((doMask & TCL_READABLE) && filePtr->readHandler)
{
SV *sv = filePtr->readHandler;
ENTER;
SAVETMPS;
filePtr->callingMask |= TCL_READABLE;
LangPushCallbackArgs(&sv);
LangCallCallback(sv,G_DISCARD);
filePtr->callingMask &= ~TCL_READABLE;
FREETMPS;
LEAVE;
}
if ((doMask & TCL_WRITABLE) && filePtr->writeHandler)
{
SV *sv = filePtr->writeHandler;
ENTER;
SAVETMPS;
filePtr->callingMask |= TCL_WRITABLE;
LangPushCallbackArgs(&sv);
LangCallCallback(sv,G_DISCARD);
filePtr->callingMask &= ~TCL_WRITABLE;
FREETMPS;
LEAVE;
}
if ((doMask & TCL_EXCEPTION) && filePtr->exceptionHandler)
{
SV *sv = filePtr->exceptionHandler;
ENTER;
SAVETMPS;
filePtr->callingMask |= TCL_EXCEPTION;
LangPushCallbackArgs(&sv);
LangCallCallback(sv,G_DISCARD);
filePtr->callingMask &= ~TCL_EXCEPTION;
FREETMPS;
LEAVE;
}
break;
}
filePtr = filePtr->nextPtr;
}
return 1; /* Say we have handled event */
}
return 0; /* Event is deferred */
}
static void
PerlIOCheckProc(data, flags)
ClientData data; /* Not used. */
int flags; /* Event flags as passed to Tcl_DoOneEvent. */
{
if (flags & TCL_FILE_EVENTS)
{
PerlIOEvent *fileEvPtr;
PerlIOHandler *filePtr = firstPerlIOHandler;
while (filePtr)
{
PerlIO_MaskCheck(filePtr);
if ((filePtr->readyMask & ~filePtr->waitMask & filePtr->handlerMask)
&& !filePtr->pending)
{
fileEvPtr = (PerlIOEvent *) ckalloc(sizeof(PerlIOEvent));
fileEvPtr->io = filePtr->io;
Tcl_QueueProcEvent(PerlIOEventProc, (Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
filePtr->pending = 1;
}
filePtr = filePtr->nextPtr;
}
}
}
static void
PerlIOExitHandler(ClientData clientData)
{
Tcl_DeleteEventSource(PerlIOSetupProc, PerlIOCheckProc, NULL);
initialized = 0;
}
static void
PerlIOEventInit(void)
{
initialized = 1;
firstPerlIOHandler = NULL;
Tcl_CreateEventSource(PerlIOSetupProc, PerlIOCheckProc, NULL);
Tcl_CreateExitHandler(PerlIOExitHandler, NULL);
}
PerlIOHandler *
SVtoPerlIOHandler(sv)
SV *sv;
{
if (sv_isa(sv,"Tk::Event::IO"))
return (PerlIOHandler *) SvPVX(SvRV(sv));
croak("Not an Tk::Event::IO");
return NULL;
}
SV *
PerlIO_TIEHANDLE(class, fh, mask)
char *class;
SV *fh;
int mask; /* OR'ed TCL_READABLE, TCL_WRITABLE, and TCL_EXCEPTION */
{
HV *stash = gv_stashpv(class, TRUE);
GV *tmpgv = newGVgen(class);
IO *tmpio = newIO();
IO *io = sv_2io(fh);
SV *obj = newSV(sizeof(PerlIOHandler));
PerlIOHandler *filePtr = (PerlIOHandler *)SvPVX(obj);
GvIOp(tmpgv) = tmpio;
if (!initialized)
PerlIOEventInit();
Zero(filePtr,1,PerlIOHandler);
filePtr->io = io;
filePtr->handle = SvREFCNT_inc(fh);
filePtr->untied = tmpgv;
filePtr->readyMask = 0;
filePtr->handlerMask = 0;
filePtr->mask = 0;
filePtr->waitMask = mask;
filePtr->pending = 0;
filePtr->nextPtr = firstPerlIOHandler;
firstPerlIOHandler = filePtr;
PerlIO_watch(filePtr);
obj = newRV_noinc(obj);
sv_bless(obj, stash);
return obj;
}
SV *
PerlIO_handler(filePtr, mask, cb)
PerlIOHandler *filePtr;
int mask;
LangCallback *cb;
{
STRLEN len;
if (cb)
{
if (!SvROK(cb))
cb = NULL;
if (mask & TCL_READABLE)
{
if (filePtr->readHandler)
{
LangFreeCallback(filePtr->readHandler);
filePtr->readHandler = NULL;
}
if (cb)
{
filePtr->readHandler = LangCopyCallback(cb);
}
}
if (mask & TCL_WRITABLE)
{
if (filePtr->writeHandler)
{
LangFreeCallback(filePtr->writeHandler);
filePtr->writeHandler = NULL;
}
if (cb)
{
filePtr->writeHandler = LangCopyCallback(cb);
}
}
if (mask & TCL_EXCEPTION)
{
if (filePtr->exceptionHandler)
{
LangFreeCallback(filePtr->exceptionHandler);
filePtr->exceptionHandler = NULL;
}
if (cb)
{
filePtr->exceptionHandler = LangCopyCallback(cb);
}
}
if (cb)
{
filePtr->handlerMask |= mask;
}
else
{
filePtr->handlerMask &= ~mask;
}
PerlIO_watch(filePtr);
}
else
{
switch (mask)
{
case TCL_EXCEPTION:
cb = filePtr->exceptionHandler;
break;
case TCL_WRITABLE:
cb = filePtr->writeHandler;
break;
case TCL_READABLE:
cb = filePtr->readHandler;
break;
default:
croak("Invalid handler type %d",mask);
}
}
return (cb) ? LangCallbackObj(cb) : &PL_sv_undef;
}
void
PerlIO_Cleanup(PerlIOHandler *filePtr)
{
PerlIO_unwatch(filePtr);
if (filePtr->readHandler)
{
LangFreeCallback(filePtr->readHandler);
filePtr->readHandler = NULL;
}
if (filePtr->writeHandler)
{
LangFreeCallback(filePtr->writeHandler);
filePtr->writeHandler = NULL;
}
if (filePtr->exceptionHandler)
{
LangFreeCallback(filePtr->exceptionHandler);
filePtr->exceptionHandler = NULL;
}
}
void
PerlIO_DESTROY(thisPtr)
PerlIOHandler *thisPtr;
{
if (initialized)
{
PerlIOHandler **link = &firstPerlIOHandler;
PerlIOHandler *filePtr;
while ((filePtr = *link))
{
if (!thisPtr || filePtr == thisPtr)
{
IO *tmpio;
*link = filePtr->nextPtr;
PerlIO_unwatch(filePtr);
if (filePtr->readHandler)
{
LangFreeCallback(filePtr->readHandler);
filePtr->readHandler = NULL;
}
if (filePtr->writeHandler)
{
LangFreeCallback(filePtr->writeHandler);
filePtr->writeHandler = NULL;
}
if (filePtr->exceptionHandler)
{
LangFreeCallback(filePtr->exceptionHandler);
filePtr->exceptionHandler = NULL;
}
tmpio = GvIOp(filePtr->untied);
IoIFP(tmpio) = NULL;
IoOFP(tmpio) = NULL;
SvREFCNT_dec(filePtr->untied);
SvREFCNT_dec(filePtr->handle);
}
else
{
link = &filePtr->nextPtr;
}
}
}
}
void
PerlIO_END(void)
{
PerlIO_DESTROY(NULL);
}
static void
SetupProc(clientData,flags)
ClientData clientData;
int flags;
{
dSP;
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal(newRV((SV *)clientData)));
XPUSHs(sv_2mortal(newSViv(flags)));
PUTBACK;
perl_call_method("setup",G_VOID);
FREETMPS;
LEAVE;
}
static void
CheckProc(clientData,flags)
ClientData clientData;
int flags;
{
dSP;
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal(newRV((SV *)clientData)));
XPUSHs(sv_2mortal(newSViv(flags)));
PUTBACK;
perl_call_method("check",G_VOID);
FREETMPS;
LEAVE;
}
typedef struct
{
Tcl_Event sv;
SV *obj;
} PerlEvent;
static int
EventProc(evPtr, flags)
Tcl_Event *evPtr;
int flags;
{PerlEvent *pe = (PerlEvent *) evPtr;
int code = 1;
int count;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(pe->obj);
XPUSHs(sv_2mortal(newSViv(flags)));
PUTBACK;
count = perl_call_method("event",G_SCALAR);
SPAGAIN;
if (count)
{
SV *result = POPs;
code = SvIV(result);
}
PUTBACK;
FREETMPS;
LEAVE;
return code;
}
#ifndef NSIG
#define NSIG 64
#endif
static Signal_t handle_signal _((int sig));
static Signal_t (*old_handler) _((int sig)) = NULL;
static char seen[NSIG];
static int asyncReady;
static int asyncActive;
int
Tcl_AsyncInvoke(interp,code)
Tcl_Interp *interp;
int code;
{
int i;
int done_one = 1;
asyncReady = 0;
asyncActive = 1;
while (done_one)
{
done_one = 0;
for (i=0; i < NSIG; i++)
{
if (seen[i] > 0)
{
seen[i]--;
(*old_handler)(i);
done_one = 1;
break;
}
}
}
asyncActive = 0;
return code;
}
int
Tcl_AsyncReady()
{
return asyncReady;
}
static Signal_t
handle_signal(sig)
int sig;
{
if (sig >= 0 && sig < NSIG)
{
seen[sig]++;
if (!asyncActive)
{
asyncReady = 1;
}
}
}
void
HandleSignals()
{
#if defined(PATCHLEVEL) && (PATCHLEVEL < 5)
croak("Cannot HandleSignals with before perl5.005");
#else
if (PL_sighandlerp != handle_signal)
{
old_handler = PL_sighandlerp;
PL_sighandlerp = handle_signal;
}
#endif
}
XS(XS_Tk__Callback_Call)
{
dXSARGS;
STRLEN na;
int i;
int count;
SV *cb = ST(0);
SV *err;
int wantarray = GIMME;
if (!items)
{
croak("No arguments");
}
LangPushCallbackArgs(&ST(0));
SPAGAIN;
for (i=1; i < items; i++)
{
if (SvTAINTED(ST(i)))
{
croak("Arg %d to callback %_ is tainted",i,ST(i));
}
XPUSHs(ST(i));
}
PUTBACK;
count = LangCallCallback(ST(0),GIMME|G_EVAL);
SPAGAIN;
err = ERRSV;
if (SvTRUE(err))
{
croak("%s",SvPV(err,na));
}
if (count)
{
for (i=1; i <= count; i++)
{
ST(i-1) = sp[i-count];
}
}
else
{
if (!(wantarray & G_ARRAY))
{
ST(0) = &PL_sv_undef;
count++;
}
}
PUTBACK;
XSRETURN(count);
}
static void
Callback_DESTROY(SV *sv)
{
}
#define Tcl_setup(obj,flags)
#define Tcl_check(obj,flags)
#define Const_READABLE() TCL_READABLE
#define Const_WRITABLE() TCL_WRITABLE
#define Const_EXCEPTION() TCL_EXCEPTION
#define Const_DONT_WAIT() (TCL_DONT_WAIT)
#define Const_WINDOW_EVENTS() (TCL_WINDOW_EVENTS)
#define Const_FILE_EVENTS() (TCL_FILE_EVENTS)
#define Const_TIMER_EVENTS() (TCL_TIMER_EVENTS)
#define Const_IDLE_EVENTS() (TCL_IDLE_EVENTS)
#define Const_ALL_EVENTS() (TCL_ALL_EVENTS)
#define Event_INIT()
extern XSdec(XS_Tk__Event_INIT);
XS(XS_Tk__Event_INIT)
{
dXSARGS;
install_vtab("TkeventVtab",TkeventVGet(),sizeof(TkeventVtab));
XSRETURN_EMPTY;
}
MODULE = Tk::Event PACKAGE = Tk::Callback PREFIX = Callback_
PROTOTYPES: DISABLE
void
Callback_DESTROY(object)
SV * object
MODULE = Tk::Event PACKAGE = Tk::Event::IO PREFIX = Const_
PROTOTYPES: ENABLE
int
Const_READABLE()
int
Const_WRITABLE()
int
Const_EXCEPTION()
MODULE = Tk::Event PACKAGE = Tk::Event PREFIX = Const_
PROTOTYPES: ENABLE
IV
Const_DONT_WAIT()
IV
Const_WINDOW_EVENTS()
IV
Const_FILE_EVENTS()
IV
Const_TIMER_EVENTS()
IV
Const_IDLE_EVENTS()
IV
Const_ALL_EVENTS()
MODULE = Tk::Event PACKAGE = Tk::Event::IO PREFIX = TkPerlIO_
PROTOTYPES: DISABLE
void
TkPerlIO_debug(filePtr,s)
PerlIOHandler * filePtr
char * s
MODULE = Tk::Event PACKAGE = Tk::Event::IO PREFIX = PerlIO_
PROTOTYPES: DISABLE
SV *
PerlIO_TIEHANDLE(class,fh,mask = 0)
char * class
SV * fh
int mask
SV *
PerlIO_handle(filePtr)
PerlIOHandler * filePtr
void
PerlIO_unwatch(filePtr)
PerlIOHandler * filePtr
void
PerlIO_wait(filePtr,mode)
PerlIOHandler * filePtr
int mode
int
PerlIO_is_readable(filePtr)
PerlIOHandler * filePtr
int
PerlIO_has_exception(filePtr)
PerlIOHandler * filePtr
int
PerlIO_is_writable(filePtr)
PerlIOHandler * filePtr
SV *
PerlIO_handler(filePtr, mask = TCL_READABLE, cb = NULL)
PerlIOHandler * filePtr
int mask
LangCallback * cb
void
PerlIO_DESTROY(filePtr)
PerlIOHandler * filePtr
void
PerlIO_END()
MODULE = Tk::Event PACKAGE = Tk::Event::Source PREFIX = Tcl_
void
Tcl_setup(obj,flags)
SV * obj
int flags
void
Tcl_check(obj,flags)
SV * obj
int flags
void
new(class,sv)
char * class
SV * sv
CODE:
{
HV *stash = gv_stashpv(class, TRUE);
if (SvROK(sv))
{
sv = newSVsv(sv);
}
else
{
sv = newRV(sv);
}
sv_bless(sv, stash);
Tcl_CreateEventSource(SetupProc,CheckProc,(ClientData)SvRV(sv));
ST(0) = sv;
}
void
delete(sv)
SV * sv
CODE:
{
SV *obj = SvRV(sv);
Tcl_DeleteEventSource(SetupProc,CheckProc,(ClientData)obj);
SvREFCNT_dec(obj);
}
MODULE = Tk::Event PACKAGE = Tk::Event PREFIX = Tcl_
double
dGetTime()
CODE:
{Tcl_Time time;
TclpGetTime(&time);
RETVAL = (double) time.sec + time.usec * 1e-6;
}
OUTPUT:
RETVAL
void
Tcl_Exit(status)
int status
int
Tcl_DoOneEvent(flags)
int flags
void
Tcl_QueueEvent(evPtr, position = TCL_QUEUE_TAIL)
Tcl_Event * evPtr
Tcl_QueuePosition position
void
Tcl_QueueProcEvent(proc, evPtr, position = TCL_QUEUE_TAIL)
Tcl_EventProc * proc
Tcl_Event * evPtr
Tcl_QueuePosition position
int
Tcl_ServiceEvent(flags)
int flags
Tcl_TimerToken
Tcl_CreateTimerHandler(milliseconds, proc, clientData = NULL)
int milliseconds
Tcl_TimerProc * proc
ClientData clientData
void
Tcl_DeleteTimerHandler(token)
Tcl_TimerToken token
void
Tcl_SetMaxBlockTime(sec, usec = 0)
double sec
IV usec
CODE:
{
Tcl_Time ttime;
ttime.sec = sec;
ttime.usec = (sec - ttime.sec) * 1e6 + usec;
Tcl_SetMaxBlockTime(&ttime);
}
void
Tcl_DoWhenIdle(proc,clientData = NULL)
Tcl_IdleProc * proc
ClientData clientData
void
Tcl_CancelIdleCall(proc,clientData = NULL)
Tcl_IdleProc * proc
ClientData clientData
void
Tcl_CreateExitHandler(proc,clientData = NULL)
Tcl_ExitProc * proc
ClientData clientData
void
Tcl_CreateFileHandler(fd, mask, proc, clientData = NULL)
int fd
int mask
Tcl_FileProc * proc
ClientData clientData
void
Tcl_DeleteFileHandler(fd)
int fd
void
Tcl_Sleep(ms)
int ms
int
Tcl_GetServiceMode()
int
Tcl_SetServiceMode(mode)
int mode
int
Tcl_ServiceAll()
void
HandleSignals()
MODULE = Tk::Event PACKAGE = Tk::Event PREFIX = Event_
void
Event_CleanupGlue()
MODULE = Tk::Event PACKAGE = Tk::Event
PROTOTYPES: DISABLE
BOOT:
{
#ifdef pWARN_NONE
SV *old_warn = PL_curcop->cop_warnings;
PL_curcop->cop_warnings = pWARN_NONE;
#endif
newXS("Tk::Event::INIT", XS_Tk__Event_INIT, file);
#ifdef pWARN_NONE
PL_curcop->cop_warnings = old_warn;
#endif
newXS("Tk::Callback::Call", XS_Tk__Callback_Call, __FILE__);
install_vtab("TkeventVtab",TkeventVGet(),sizeof(TkeventVtab));
}