diff options
Diffstat (limited to 'generic/tclIORChan.c')
| -rw-r--r-- | generic/tclIORChan.c | 113 |
1 files changed, 103 insertions, 10 deletions
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index e50c96f..88f6de8 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -10,7 +10,7 @@ * * See TIP #219 for the specification of this functionality. * - * Copyright (c) 2004-2005 ActiveState, a divison of Sophos + * Copyright © 2004-2005 ActiveState, a divison of Sophos * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -44,8 +44,8 @@ static void ReflectThread(ClientData clientData, int action); static int ReflectEventRun(Tcl_Event *ev, int flags); static int ReflectEventDelete(Tcl_Event *ev, ClientData cd); #endif -static Tcl_WideInt ReflectSeekWide(ClientData clientData, - Tcl_WideInt offset, int mode, int *errorCodePtr); +static long long ReflectSeekWide(ClientData clientData, + long long offset, int mode, int *errorCodePtr); #ifndef TCL_NO_DEPRECATED static int ReflectSeek(ClientData clientData, long offset, int mode, int *errorCodePtr); @@ -56,12 +56,13 @@ static int ReflectGetOption(ClientData clientData, static int ReflectSetOption(ClientData clientData, Tcl_Interp *interp, const char *optionName, const char *newValue); +static int ReflectTruncate(ClientData clientData, + long long length); static void TimerRunRead(ClientData clientData); static void TimerRunWrite(ClientData clientData); /* - * The C layer channel type/driver definition used by the reflection. This is - * a version 3 structure. + * The C layer channel type/driver definition used by the reflection. */ static const Tcl_ChannelType tclRChannelType = { @@ -89,7 +90,7 @@ static const Tcl_ChannelType tclRChannelType = { #else NULL, /* thread action */ #endif - NULL /* truncate */ + ReflectTruncate /* Truncate. NULL'able */ }; /* @@ -187,6 +188,7 @@ static const char *const methodNames[] = { "initialize", /* */ "read", /* OPT */ "seek", /* OPT */ + "truncate", /* OPT */ "watch", /* */ "write", /* OPT */ NULL @@ -200,6 +202,7 @@ typedef enum { METH_INIT, METH_READ, METH_SEEK, + METH_TRUNCATE, METH_WATCH, METH_WRITE } MethodName; @@ -209,7 +212,8 @@ typedef enum { (FLAG(METH_INIT) | FLAG(METH_FINAL) | FLAG(METH_WATCH)) #define NULLABLE_METHODS \ (FLAG(METH_BLOCKING) | FLAG(METH_SEEK) | \ - FLAG(METH_CONFIGURE) | FLAG(METH_CGET) | FLAG(METH_CGETALL)) + FLAG(METH_CONFIGURE) | FLAG(METH_CGET) | \ + FLAG(METH_CGETALL) | FLAG(METH_TRUNCATE)) #define RANDW \ (TCL_READABLE | TCL_WRITABLE) @@ -239,7 +243,8 @@ typedef enum { ForwardedBlock, ForwardedSetOpt, ForwardedGetOpt, - ForwardedGetOptAll + ForwardedGetOptAll, + ForwardedTruncate } ForwardedOperation; /* @@ -302,6 +307,10 @@ struct ForwardParamGetOpt { const char *name; /* Name of option to get, maybe NULL */ Tcl_DString *value; /* Result */ }; +struct ForwardParamTruncate { + ForwardParamBase base; /* "Supertype". MUST COME FIRST. */ + Tcl_WideInt length; /* I: Length of file. */ +}; /* * Now join all these together in a single union for convenience. @@ -316,6 +325,7 @@ typedef union ForwardParam { struct ForwardParamBlock block; struct ForwardParamSetOpt setOpt; struct ForwardParamGetOpt getOpt; + struct ForwardParamTruncate truncate; } ForwardParam; /* @@ -706,6 +716,9 @@ TclChanCreateObjCmd( #endif clonePtr->wideSeekProc = NULL; } + if (!(methods & FLAG(METH_TRUNCATE))) { + clonePtr->truncateProc = NULL; + } chanPtr->typePtr = clonePtr; } @@ -1550,10 +1563,10 @@ ReflectOutput( *---------------------------------------------------------------------- */ -static Tcl_WideInt +static long long ReflectSeekWide( ClientData clientData, - Tcl_WideInt offset, + long long offset, int seekMode, int *errorCodePtr) { @@ -2048,6 +2061,73 @@ ReflectGetOption( } /* + *---------------------------------------------------------------------- + * + * ReflectTruncate -- + * + * This function is invoked to truncate a channel's file size. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Arbitrary, as it calls upon a Tcl script. + * + *---------------------------------------------------------------------- + */ + +static int +ReflectTruncate( + ClientData clientData, /* Channel to query */ + long long length) /* Length to truncate to. */ +{ + ReflectedChannel *rcPtr = (ReflectedChannel *)clientData; + Tcl_Obj *lenObj; + int errorNum; /* EINVAL or EOK (success). */ + Tcl_Obj *resObj; /* Result for 'truncate' */ + + /* + * Are we in the correct thread? + */ + +#ifdef TCL_THREADS + if (rcPtr->thread != Tcl_GetCurrentThread()) { + ForwardParam p; + + p.truncate.length = length; + + ForwardOpToHandlerThread(rcPtr, ForwardedTruncate, &p); + + if (p.base.code != TCL_OK) { + PassReceivedError(rcPtr->chan, &p); + return EINVAL; + } + + return EOK; + } +#endif + + /* ASSERT: rcPtr->method & FLAG(METH_TRUNCATE) */ + + Tcl_Preserve(rcPtr); + + lenObj = Tcl_NewIntObj(length); + Tcl_IncrRefCount(lenObj); + + if (InvokeTclMethod(rcPtr,METH_TRUNCATE,lenObj,NULL,&resObj)!=TCL_OK) { + Tcl_SetChannelError(rcPtr->chan, resObj); + errorNum = EINVAL; + } else { + errorNum = EOK; + } + + Tcl_DecrRefCount(lenObj); + Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ + Tcl_Release(rcPtr); + return errorNum; +} + +/* * Helpers. ========================================================= */ @@ -3278,6 +3358,19 @@ ForwardProc( Tcl_Release(rcPtr); break; + case ForwardedTruncate: { + Tcl_Obj *lenObj = Tcl_NewIntObj(paramPtr->truncate.length); + + Tcl_IncrRefCount(lenObj); + Tcl_Preserve(rcPtr); + if (InvokeTclMethod(rcPtr,METH_TRUNCATE,lenObj,NULL,&resObj)!=TCL_OK) { + ForwardSetObjError(paramPtr, resObj); + } + Tcl_Release(rcPtr); + Tcl_DecrRefCount(lenObj); + break; + } + default: /* * Bad operation code. |
