From cacfaf16ecf05b44bacecbba3b2f673bf810e64c Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 1 Jun 2022 19:34:43 +0000 Subject: TIP #627 implementation --- doc/CrtObjCmd.3 | 19 ++- doc/CrtTrace.3 | 10 +- doc/NRE.3 | 11 ++ generic/tcl.decls | 17 +++ generic/tcl.h | 12 ++ generic/tclBasic.c | 142 +++++++++++++++++++++- generic/tclDecls.h | 33 ++++++ generic/tclStubInit.c | 6 + generic/tclTest.c | 320 ++++++++++++++++++++++++++------------------------ generic/tclTestObj.c | 55 ++++----- generic/tclTrace.c | 44 +++++++ 11 files changed, 484 insertions(+), 185 deletions(-) diff --git a/doc/CrtObjCmd.3 b/doc/CrtObjCmd.3 index 8d10418..57834da 100644 --- a/doc/CrtObjCmd.3 +++ b/doc/CrtObjCmd.3 @@ -8,7 +8,7 @@ .so man.macros .BS .SH NAME -Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj \- implement new commands in C +Tcl_CreateObjCommand, Tcl_CreateObjCommand2, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj \- implement new commands in C .SH SYNOPSIS .nf \fB#include \fR @@ -16,6 +16,9 @@ Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetComm Tcl_Command \fBTcl_CreateObjCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) .sp +Tcl_Command +\fBTcl_CreateObjCommand2\fR(\fIinterp, cmdName, proc2, clientData, deleteProc\fR) +.sp int \fBTcl_DeleteCommand\fR(\fIinterp, cmdName\fR) .sp @@ -52,6 +55,9 @@ Name of command. .AP Tcl_ObjCmdProc *proc in Implementation of the new command: \fIproc\fR will be called whenever \fIcmdName\fR is invoked as a command. +.AP Tcl_ObjCmdProc2 *proc2 in +Implementation of the new command: \fIproc2\fR will be called whenever +\fIcmdName\fR is invoked as a command. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. .AP Tcl_CmdDeleteProc *deleteProc in @@ -174,6 +180,17 @@ typedef void \fBTcl_CmdDeleteProc\fR( The \fIclientData\fR argument will be the same as the \fIclientData\fR argument passed to \fBTcl_CreateObjCommand\fR. .PP +\fBTcl_CreateObjCommand2\fR does the same as \fBTcl_CreateObjCommand2\fR, +except its \fIproc2\fR argument is of type \fBTcl_ObjCmdProc2\fR(. +.PP +.CS +typedef int \fBTcl_ObjCmdProc2\fR( + ClientData \fIclientData\fR, + Tcl_Interp *\fIinterp\fR, + size_t \fIobjc\fR, + Tcl_Obj *const \fIobjv\fR[]); +.CE +.PP \fBTcl_DeleteCommand\fR deletes a command from a command interpreter. Once the call completes, attempts to invoke \fIcmdName\fR in \fIinterp\fR will result in errors. diff --git a/doc/CrtTrace.3 b/doc/CrtTrace.3 index 620c081..417c892 100644 --- a/doc/CrtTrace.3 +++ b/doc/CrtTrace.3 @@ -10,7 +10,7 @@ .so man.macros .BS .SH NAME -Tcl_CreateTrace, Tcl_CreateObjTrace, Tcl_DeleteTrace \- arrange for command execution to be traced +Tcl_CreateTrace, Tcl_CreateObjTrace, Tcl_CreateObjTrace2, Tcl_DeleteTrace \- arrange for command execution to be traced .SH SYNOPSIS .nf \fB#include \fR @@ -21,6 +21,9 @@ Tcl_Trace Tcl_Trace \fBTcl_CreateObjTrace\fR(\fIinterp, level, flags, objProc, clientData, deleteProc\fR) .sp +Tcl_Trace +\fBTcl_CreateObjTrace2\fR(\fIinterp, level, flags, objProc2, clientData, deleteProc\fR) +.sp \fBTcl_DeleteTrace\fR(\fIinterp, trace\fR) .SH ARGUMENTS .AS Tcl_CmdObjTraceDeleteProc *deleteProc @@ -38,11 +41,14 @@ Flags governing the trace execution. See below for details. .AP Tcl_CmdObjTraceProc *objProc in Procedure to call for each command that is executed. See below for details of the calling sequence. +.AP Tcl_CmdObjTraceProc2 *objProc2 in +Procedure to call for each command that is executed. See below for +details of the calling sequence. .AP Tcl_CmdTraceProc *proc in Procedure to call for each command that is executed. See below for details on the calling sequence. .AP ClientData clientData in -Arbitrary one-word value to pass to \fIobjProc\fR or \fIproc\fR. +Arbitrary one-word value to pass to \fIobjProc\fR, \fIobjProc2\fR or \fIproc\fR. .AP Tcl_CmdObjTraceDeleteProc *deleteProc in Procedure to call when the trace is deleted. See below for details of the calling sequence. A NULL pointer is permissible and results in no diff --git a/doc/NRE.3 b/doc/NRE.3 index 72bb370..f3e0735 100644 --- a/doc/NRE.3 +++ b/doc/NRE.3 @@ -18,6 +18,10 @@ Tcl_Command \fBTcl_NRCreateCommand\fR(\fIinterp, cmdName, proc, nreProc, clientData, deleteProc\fR) .sp +Tcl_Command +\fBTcl_NRCreateCommand2\fR(\fIinterp, cmdName, proc2, nreProc2, clientData, + deleteProc\fR) +.sp int \fBTcl_NRCallObjProc\fR(\fIinterp, nreProc, clientData, objc, objv\fR) .sp @@ -47,8 +51,12 @@ Called in order to evaluate a command. Is often just a small wrapper that uses \fBTcl_NRCallObjProc\fR to call \fInreProc\fR using a new trampoline. Behaves in the same way as the \fIproc\fR argument to \fBTcl_CreateObjCommand\fR(3) (\fIq.v.\fR). +.AP Tcl_ObjCmdProc2 *proc2 in +Same as \fIproc\fR, but handles more arguments. .AP Tcl_ObjCmdProc *nreProc in Called instead of \fIproc\fR when a trampoline is already in use. +.AP Tcl_ObjCmdProc2 *nreProc2 in +Called instead of \fIproc2\fR when a trampoline is already in use. .AP ClientData clientData in Arbitrary one-word value passed to \fIproc\fR, \fInreProc\fR, \fIdeleteProc\fR and \fIobjProc\fR. @@ -104,6 +112,9 @@ first deleted. If \fIinterp\fR is in the process of being deleted \fBTcl_NRCreateCommand\fR does not create any command, does not delete any command, and returns NULL. .PP +\fBTcl_NRCreateCommand2\fR, is an alternative to \fBTcl_CreateObjCommand2\fR +in the same way as fBTcl_NRCreateCommand\fR. +.PP \fBTcl_NREvalObj\fR pushes a function that is like \fBTcl_EvalObjEx\fR but consumes no space on the C stack. .PP diff --git a/generic/tcl.decls b/generic/tcl.decls index 309eeb4..c39be2a 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -2470,6 +2470,23 @@ declare 673 { int TclGetUniChar(Tcl_Obj *objPtr, int index) } +declare 676 { + Tcl_Command Tcl_CreateObjCommand2(Tcl_Interp *interp, + const char *cmdName, + Tcl_ObjCmdProc2 *proc2, void *clientData, + Tcl_CmdDeleteProc *deleteProc) +} +declare 677 { + Tcl_Trace Tcl_CreateObjTrace2(Tcl_Interp *interp, int level, int flags, + Tcl_CmdObjTraceProc2 *objProc2, void *clientData, + Tcl_CmdObjTraceDeleteProc *delProc) +} +declare 679 { + Tcl_Command Tcl_NRCreateCommand2(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc2 *proc, + Tcl_ObjCmdProc2 *nreProc2, void *clientData, + Tcl_CmdDeleteProc *deleteProc) +} # ----- BASELINE -- FOR -- 8.7.0 ----- # diff --git a/generic/tcl.h b/generic/tcl.h index 274be35..886e42e 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -673,6 +673,9 @@ typedef void (Tcl_CmdTraceProc) (ClientData clientData, Tcl_Interp *interp, typedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp, int level, const char *command, Tcl_Command commandInfo, int objc, struct Tcl_Obj *const *objv); +typedef int (Tcl_CmdObjTraceProc2) (void *clientData, Tcl_Interp *interp, + int level, const char *command, Tcl_Command commandInfo, size_t objc, + struct Tcl_Obj *const objv[]); typedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData); typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, struct Tcl_Obj *dupPtr); @@ -697,6 +700,8 @@ typedef int (Tcl_MathProc) (ClientData clientData, Tcl_Interp *interp, typedef void (Tcl_NamespaceDeleteProc) (ClientData clientData); typedef int (Tcl_ObjCmdProc) (ClientData clientData, Tcl_Interp *interp, int objc, struct Tcl_Obj *const *objv); +typedef int (Tcl_ObjCmdProc2) (void *clientData, Tcl_Interp *interp, + size_t objc, struct Tcl_Obj *const *objv); typedef int (Tcl_LibraryInitProc) (Tcl_Interp *interp); typedef int (Tcl_LibraryUnloadProc) (Tcl_Interp *interp, int flags); typedef void (Tcl_PanicProc) (const char *format, ...); @@ -916,6 +921,13 @@ typedef struct Tcl_CmdInfo { * change a command's namespace; use * TclRenameCommand or Tcl_Eval (of 'rename') * to do that. */ +#if (TCL_MAJOR_VERSION > 8) || defined(TCL_NO_DEPRECATED) + Tcl_ObjCmdProc2 *objProc2; /* Command's object-based function. */ + void *objClientData2; /* ClientData for object proc. */ +#else + void *reserved1; + void *reserved2; +#endif } Tcl_CmdInfo; /* diff --git a/generic/tclBasic.c b/generic/tclBasic.c index f87e1e1..c1dd8cb 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -2689,6 +2689,58 @@ Tcl_CreateCommand( *---------------------------------------------------------------------- */ +typedef struct { + void *clientData; /* Arbitrary value to pass to object function. */ + Tcl_ObjCmdProc2 *proc; + Tcl_CmdDeleteProc *deleteProc; +} CmdWrapperInfo; + + +static int cmdWrapperProc(void *clientData, + Tcl_Interp *interp, + int objc, + struct Tcl_Obj * const *objv) +{ + CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + return info->proc(info->clientData, interp, objc, objv); +} + +static void cmdWrapperDeleteProc(void *clientData) { + CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + + clientData = info->clientData; + Tcl_CmdDeleteProc *deleteProc = info->deleteProc; + Tcl_Free(info); + if (deleteProc != NULL) { + deleteProc(clientData); + } +} + +Tcl_Command +Tcl_CreateObjCommand2( + Tcl_Interp *interp, /* Token for command interpreter (returned by + * previous call to Tcl_CreateInterp). */ + const char *cmdName, /* Name of command. If it contains namespace + * qualifiers, the new command is put in the + * specified namespace; otherwise it is put in + * the global namespace. */ + Tcl_ObjCmdProc2 *proc, /* Object-based function to associate with + * name. */ + void *clientData, /* Arbitrary value to pass to object + * function. */ + Tcl_CmdDeleteProc *deleteProc + /* If not NULL, gives a function to call when + * this command is deleted. */ +) +{ + CmdWrapperInfo *info = (CmdWrapperInfo *)Tcl_Alloc(sizeof(CmdWrapperInfo)); + info->proc = proc; + info->deleteProc = deleteProc; + info->clientData = clientData; + + return Tcl_CreateObjCommand(interp, cmdName, cmdWrapperProc, info, cmdWrapperDeleteProc); +} + Tcl_Command Tcl_CreateObjCommand( Tcl_Interp *interp, /* Token for command interpreter (returned by @@ -3377,6 +3429,21 @@ Tcl_GetCommandInfo( *---------------------------------------------------------------------- */ +#if TCL_MAJOR_VERSION > 8 || defined(TCL_NO_DEPRECATED) +static int cmdWrapper2Proc(void *clientData, + Tcl_Interp *interp, + size_t objc, + Tcl_Obj *const objv[]) +{ + Command *cmdPtr = (Command *)clientData; + if (objc > INT_MAX) { + Tcl_WrongNumArgs(interp, 1, objv, "?args?"); + return TCL_ERROR; + } + return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv); +} +#endif + int Tcl_GetCommandInfoFromToken( Tcl_Command cmd, @@ -3403,7 +3470,17 @@ Tcl_GetCommandInfoFromToken( infoPtr->deleteProc = cmdPtr->deleteProc; infoPtr->deleteData = cmdPtr->deleteData; infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr; - +#if TCL_MAJOR_VERSION > 8 || defined(TCL_NO_DEPRECATED) + if (infoPtr->objProc == cmdWrapperProc) { + CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->objClientData; + infoPtr->objProc2 = info->proc; + infoPtr->objClientData2 = info->clientData; + infoPtr->isNativeObjectProc = 2; + } else { + infoPtr->objProc2 = cmdWrapper2Proc; + infoPtr->objClientData2 = cmdPtr; + } +#endif return 1; } @@ -9125,6 +9202,69 @@ Tcl_NRCallObjProc( *---------------------------------------------------------------------- */ +typedef struct { + Tcl_ObjCmdProc2 *proc; + Tcl_ObjCmdProc2 *nreProc; + Tcl_CmdDeleteProc *delProc; + void *clientData; +} NRCommandWrapper; + +static int wrapperProc2( + void *clientData, + Tcl_Interp *interp, + int objc, + struct Tcl_Obj *const objv[]) +{ + NRCommandWrapper *wrapper = (NRCommandWrapper *)clientData; + return wrapper->proc(wrapper->clientData, interp, objc, objv); +} + +static int wrapperNRProc2( + void *clientData, + Tcl_Interp *interp, + int objc, + struct Tcl_Obj *const objv[]) +{ + NRCommandWrapper *wrapper = (NRCommandWrapper *)clientData; + return wrapper->nreProc(wrapper->clientData, interp, objc, objv); +} + +static void wrapperDelProc2(void *clientData) +{ + NRCommandWrapper *wrapper = (NRCommandWrapper *)clientData; + clientData = wrapper->clientData; + wrapper->delProc(clientData); + Tcl_Free(wrapper); +} + + +Tcl_Command +Tcl_NRCreateCommand2( + Tcl_Interp *interp, /* Token for command interpreter (returned by + * previous call to Tcl_CreateInterp). */ + const char *cmdName, /* Name of command. If it contains namespace + * qualifiers, the new command is put in the + * specified namespace; otherwise it is put in + * the global namespace. */ + Tcl_ObjCmdProc2 *proc, /* Object-based function to associate with + * name, provides direct access for direct + * calls. */ + Tcl_ObjCmdProc2 *nreProc, /* Object-based function to associate with + * name, provides NR implementation */ + void *clientData, /* Arbitrary value to pass to object + * function. */ + Tcl_CmdDeleteProc *deleteProc) + /* If not NULL, gives a function to call when + * this command is deleted. */ +{ + NRCommandWrapper *wrapper = (NRCommandWrapper *)Tcl_Alloc(sizeof(NRCommandWrapper)); + wrapper->proc = proc; + wrapper->nreProc = nreProc; + wrapper->delProc = deleteProc; + wrapper->clientData = clientData; + return Tcl_NRCreateCommand(interp, cmdName, wrapperProc2, wrapperNRProc2, wrapper, wrapperDelProc2); +} + Tcl_Command Tcl_NRCreateCommand( Tcl_Interp *interp, /* Token for command interpreter (returned by diff --git a/generic/tclDecls.h b/generic/tclDecls.h index ee9e02f..efc185a 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -1974,6 +1974,24 @@ EXTERN const char * TclUtfAtIndex(const char *src, int index); EXTERN Tcl_Obj * TclGetRange(Tcl_Obj *objPtr, int first, int last); /* 673 */ EXTERN int TclGetUniChar(Tcl_Obj *objPtr, int index); +/* Slot 674 is reserved */ +/* Slot 675 is reserved */ +/* 676 */ +EXTERN Tcl_Command Tcl_CreateObjCommand2(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc2 *proc2, + void *clientData, + Tcl_CmdDeleteProc *deleteProc); +/* 677 */ +EXTERN Tcl_Trace Tcl_CreateObjTrace2(Tcl_Interp *interp, int level, + int flags, Tcl_CmdObjTraceProc2 *objProc2, + void *clientData, + Tcl_CmdObjTraceDeleteProc *delProc); +/* Slot 678 is reserved */ +/* 679 */ +EXTERN Tcl_Command Tcl_NRCreateCommand2(Tcl_Interp *interp, + const char *cmdName, Tcl_ObjCmdProc2 *proc, + Tcl_ObjCmdProc2 *nreProc2, void *clientData, + Tcl_CmdDeleteProc *deleteProc); typedef struct { const struct TclPlatStubs *tclPlatStubs; @@ -2683,6 +2701,12 @@ typedef struct TclStubs { const char * (*tclUtfAtIndex) (const char *src, int index); /* 671 */ Tcl_Obj * (*tclGetRange) (Tcl_Obj *objPtr, int first, int last); /* 672 */ int (*tclGetUniChar) (Tcl_Obj *objPtr, int index); /* 673 */ + void (*reserved674)(void); + void (*reserved675)(void); + Tcl_Command (*tcl_CreateObjCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 676 */ + Tcl_Trace (*tcl_CreateObjTrace2) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc2 *objProc2, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 677 */ + void (*reserved678)(void); + Tcl_Command (*tcl_NRCreateCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc, Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 679 */ } TclStubs; extern const TclStubs *tclStubsPtr; @@ -4054,6 +4078,15 @@ extern const TclStubs *tclStubsPtr; (tclStubsPtr->tclGetRange) /* 672 */ #define TclGetUniChar \ (tclStubsPtr->tclGetUniChar) /* 673 */ +/* Slot 674 is reserved */ +/* Slot 675 is reserved */ +#define Tcl_CreateObjCommand2 \ + (tclStubsPtr->tcl_CreateObjCommand2) /* 676 */ +#define Tcl_CreateObjTrace2 \ + (tclStubsPtr->tcl_CreateObjTrace2) /* 677 */ +/* Slot 678 is reserved */ +#define Tcl_NRCreateCommand2 \ + (tclStubsPtr->tcl_NRCreateCommand2) /* 679 */ #endif /* defined(USE_TCL_STUBS) */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index d34aff4..0f49f93 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -1968,6 +1968,12 @@ const TclStubs tclStubs = { TclUtfAtIndex, /* 671 */ TclGetRange, /* 672 */ TclGetUniChar, /* 673 */ + 0, /* 674 */ + 0, /* 675 */ + Tcl_CreateObjCommand2, /* 676 */ + Tcl_CreateObjTrace2, /* 677 */ + 0, /* 678 */ + Tcl_NRCreateCommand2, /* 679 */ }; /* !END!: Do not edit above this line. */ diff --git a/generic/tclTest.c b/generic/tclTest.c index c740109..8502ccd 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -203,25 +203,25 @@ static int EncodingFromUtfProc(void *clientData, int *dstCharsPtr); static void ExitProcEven(void *clientData); static void ExitProcOdd(void *clientData); -static Tcl_ObjCmdProc GetTimesObjCmd; +static Tcl_ObjCmdProc2 GetTimesObjCmd; static Tcl_ResolveCompiledVarProc InterpCompiledVarResolver; static void MainLoop(void); static Tcl_CmdProc NoopCmd; -static Tcl_ObjCmdProc NoopObjCmd; +static Tcl_ObjCmdProc2 NoopObjCmd; static int ObjTraceProc(void *clientData, Tcl_Interp *interp, int level, const char *command, - Tcl_Command commandToken, int objc, + Tcl_Command commandToken, size_t objc, Tcl_Obj *const objv[]); static void ObjTraceDeleteProc(void *clientData); static void PrintParse(Tcl_Interp *interp, Tcl_Parse *parsePtr); static void SpecialFree(char *blockPtr); static int StaticInitProc(Tcl_Interp *interp); static Tcl_CmdProc TestasyncCmd; -static Tcl_ObjCmdProc TestbumpinterpepochObjCmd; -static Tcl_ObjCmdProc TestbytestringObjCmd; -static Tcl_ObjCmdProc TestsetbytearraylengthObjCmd; -static Tcl_ObjCmdProc TestpurebytesobjObjCmd; -static Tcl_ObjCmdProc TeststringbytesObjCmd; +static Tcl_ObjCmdProc2 TestbumpinterpepochObjCmd; +static Tcl_ObjCmdProc2 TestbytestringObjCmd; +static Tcl_ObjCmdProc2 TestsetbytearraylengthObjCmd; +static Tcl_ObjCmdProc2 TestpurebytesobjObjCmd; +static Tcl_ObjCmdProc2 TeststringbytesObjCmd; static Tcl_CmdProc TestcmdinfoCmd; static Tcl_CmdProc TestcmdtokenCmd; static Tcl_CmdProc TestcmdtraceCmd; @@ -230,70 +230,70 @@ static Tcl_CmdProc TestcreatecommandCmd; static Tcl_CmdProc TestdcallCmd; static Tcl_CmdProc TestdelCmd; static Tcl_CmdProc TestdelassocdataCmd; -static Tcl_ObjCmdProc TestdoubledigitsObjCmd; +static Tcl_ObjCmdProc2 TestdoubledigitsObjCmd; static Tcl_CmdProc TestdstringCmd; -static Tcl_ObjCmdProc TestencodingObjCmd; -static Tcl_ObjCmdProc TestevalexObjCmd; -static Tcl_ObjCmdProc TestevalobjvObjCmd; -static Tcl_ObjCmdProc TesteventObjCmd; +static Tcl_ObjCmdProc2 TestencodingObjCmd; +static Tcl_ObjCmdProc2 TestevalexObjCmd; +static Tcl_ObjCmdProc2 TestevalobjvObjCmd; +static Tcl_ObjCmdProc2 TesteventObjCmd; static int TesteventProc(Tcl_Event *event, int flags); static int TesteventDeleteProc(Tcl_Event *event, void *clientData); static Tcl_CmdProc TestexithandlerCmd; static Tcl_CmdProc TestexprlongCmd; -static Tcl_ObjCmdProc TestexprlongobjCmd; +static Tcl_ObjCmdProc2 TestexprlongobjCmd; static Tcl_CmdProc TestexprdoubleCmd; -static Tcl_ObjCmdProc TestexprdoubleobjCmd; -static Tcl_ObjCmdProc TestexprparserObjCmd; +static Tcl_ObjCmdProc2 TestexprdoubleobjCmd; +static Tcl_ObjCmdProc2 TestexprparserObjCmd; static Tcl_CmdProc TestexprstringCmd; -static Tcl_ObjCmdProc TestfileCmd; -static Tcl_ObjCmdProc TestfilelinkCmd; +static Tcl_ObjCmdProc2 TestfileCmd; +static Tcl_ObjCmdProc2 TestfilelinkCmd; static Tcl_CmdProc TestfeventCmd; static Tcl_CmdProc TestgetassocdataCmd; static Tcl_CmdProc TestgetintCmd; static Tcl_CmdProc TestlongsizeCmd; static Tcl_CmdProc TestgetplatformCmd; -static Tcl_ObjCmdProc TestgetvarfullnameCmd; +static Tcl_ObjCmdProc2 TestgetvarfullnameCmd; static Tcl_CmdProc TestinterpdeleteCmd; static Tcl_CmdProc TestlinkCmd; -static Tcl_ObjCmdProc TestlinkarrayCmd; -static Tcl_ObjCmdProc TestlocaleCmd; +static Tcl_ObjCmdProc2 TestlinkarrayCmd; +static Tcl_ObjCmdProc2 TestlocaleCmd; static Tcl_CmdProc TestmainthreadCmd; static Tcl_CmdProc TestsetmainloopCmd; static Tcl_CmdProc TestexitmainloopCmd; static Tcl_CmdProc TestpanicCmd; -static Tcl_ObjCmdProc TestparseargsCmd; -static Tcl_ObjCmdProc TestparserObjCmd; -static Tcl_ObjCmdProc TestparsevarObjCmd; -static Tcl_ObjCmdProc TestparsevarnameObjCmd; -static Tcl_ObjCmdProc TestpreferstableObjCmd; -static Tcl_ObjCmdProc TestprintObjCmd; -static Tcl_ObjCmdProc TestregexpObjCmd; -static Tcl_ObjCmdProc TestreturnObjCmd; +static Tcl_ObjCmdProc2 TestparseargsCmd; +static Tcl_ObjCmdProc2 TestparserObjCmd; +static Tcl_ObjCmdProc2 TestparsevarObjCmd; +static Tcl_ObjCmdProc2 TestparsevarnameObjCmd; +static Tcl_ObjCmdProc2 TestpreferstableObjCmd; +static Tcl_ObjCmdProc2 TestprintObjCmd; +static Tcl_ObjCmdProc2 TestregexpObjCmd; +static Tcl_ObjCmdProc2 TestreturnObjCmd; static void TestregexpXflags(const char *string, int length, int *cflagsPtr, int *eflagsPtr); -static Tcl_ObjCmdProc TestsaveresultCmd; +static Tcl_ObjCmdProc2 TestsaveresultCmd; static void TestsaveresultFree(char *blockPtr); static Tcl_CmdProc TestsetassocdataCmd; static Tcl_CmdProc TestsetCmd; static Tcl_CmdProc Testset2Cmd; static Tcl_CmdProc TestseterrorcodeCmd; -static Tcl_ObjCmdProc TestsetobjerrorcodeCmd; +static Tcl_ObjCmdProc2 TestsetobjerrorcodeCmd; static Tcl_CmdProc TestsetplatformCmd; static Tcl_CmdProc TeststaticlibraryCmd; static Tcl_CmdProc TesttranslatefilenameCmd; static Tcl_CmdProc TestupvarCmd; -static Tcl_ObjCmdProc TestWrongNumArgsObjCmd; -static Tcl_ObjCmdProc TestGetIndexFromObjStructObjCmd; +static Tcl_ObjCmdProc2 TestWrongNumArgsObjCmd; +static Tcl_ObjCmdProc2 TestGetIndexFromObjStructObjCmd; static Tcl_CmdProc TestChannelCmd; static Tcl_CmdProc TestChannelEventCmd; static Tcl_CmdProc TestSocketCmd; -static Tcl_ObjCmdProc TestFilesystemObjCmd; -static Tcl_ObjCmdProc TestSimpleFilesystemObjCmd; +static Tcl_ObjCmdProc2 TestFilesystemObjCmd; +static Tcl_ObjCmdProc2 TestSimpleFilesystemObjCmd; static void TestReport(const char *cmd, Tcl_Obj *arg1, Tcl_Obj *arg2); -static Tcl_ObjCmdProc TestgetencpathObjCmd; -static Tcl_ObjCmdProc TestsetencpathObjCmd; +static Tcl_ObjCmdProc2 TestgetencpathObjCmd; +static Tcl_ObjCmdProc2 TestsetencpathObjCmd; static Tcl_Obj * TestReportGetNativePath(Tcl_Obj *pathPtr); static Tcl_FSStatProc TestReportStat; static Tcl_FSAccessProc TestReportAccess; @@ -326,20 +326,20 @@ static Tcl_FSListVolumesProc SimpleListVolumes; static Tcl_FSPathInFilesystemProc SimplePathInFilesystem; static Tcl_Obj * SimpleRedirect(Tcl_Obj *pathPtr); static Tcl_FSMatchInDirectoryProc SimpleMatchInDirectory; -static Tcl_ObjCmdProc TestUtfNextCmd; -static Tcl_ObjCmdProc TestUtfPrevCmd; -static Tcl_ObjCmdProc TestNumUtfCharsCmd; -static Tcl_ObjCmdProc TestFindFirstCmd; -static Tcl_ObjCmdProc TestFindLastCmd; -static Tcl_ObjCmdProc TestHashSystemHashCmd; -static Tcl_ObjCmdProc TestGetIntForIndexCmd; +static Tcl_ObjCmdProc2 TestUtfNextCmd; +static Tcl_ObjCmdProc2 TestUtfPrevCmd; +static Tcl_ObjCmdProc2 TestNumUtfCharsCmd; +static Tcl_ObjCmdProc2 TestFindFirstCmd; +static Tcl_ObjCmdProc2 TestFindLastCmd; +static Tcl_ObjCmdProc2 TestHashSystemHashCmd; +static Tcl_ObjCmdProc2 TestGetIntForIndexCmd; static Tcl_NRPostProc NREUnwind_callback; -static Tcl_ObjCmdProc TestNREUnwind; -static Tcl_ObjCmdProc TestNRELevels; -static Tcl_ObjCmdProc TestInterpResolverCmd; +static Tcl_ObjCmdProc2 TestNREUnwind; +static Tcl_ObjCmdProc2 TestNRELevels; +static Tcl_ObjCmdProc2 TestInterpResolverCmd; #if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL) -static Tcl_ObjCmdProc TestcpuidCmd; +static Tcl_ObjCmdProc2 TestcpuidCmd; #endif static const Tcl_Filesystem testReportingFilesystem = { @@ -522,7 +522,7 @@ Tcltest_Init( { Tcl_CmdInfo info; Tcl_Obj **objv, *objPtr; - int objc, index; + size_t objc, index; static const char *const specialOptions[] = { "-appinitprocerror", "-appinitprocdeleteinterp", "-appinitprocclosestderr", "-appinitprocsetrcfile", NULL @@ -552,23 +552,23 @@ Tcltest_Init( * Create additional commands and math functions for testing Tcl. */ - Tcl_CreateObjCommand(interp, "gettimes", GetTimesObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "gettimes", GetTimesObjCmd, NULL, NULL); Tcl_CreateCommand(interp, "noop", NoopCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "noop", NoopObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testpurebytesobj", TestpurebytesobjObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testsetbytearraylength", TestsetbytearraylengthObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testbytestring", TestbytestringObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "teststringbytes", TeststringbytesObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testwrongnumargs", TestWrongNumArgsObjCmd, + Tcl_CreateObjCommand2(interp, "noop", NoopObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "testpurebytesobj", TestpurebytesobjObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "testsetbytearraylength", TestsetbytearraylengthObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "testbytestring", TestbytestringObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "teststringbytes", TeststringbytesObjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "testwrongnumargs", TestWrongNumArgsObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfilesystem", TestFilesystemObjCmd, + Tcl_CreateObjCommand2(interp, "testfilesystem", TestFilesystemObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testsimplefilesystem", TestSimpleFilesystemObjCmd, + Tcl_CreateObjCommand2(interp, "testsimplefilesystem", TestSimpleFilesystemObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testgetindexfromobjstruct", + Tcl_CreateObjCommand2(interp, "testgetindexfromobjstruct", TestGetIndexFromObjStructObjCmd, NULL, NULL); Tcl_CreateCommand(interp, "testasync", TestasyncCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testbumpinterpepoch", + Tcl_CreateObjCommand2(interp, "testbumpinterpepoch", TestbumpinterpepochObjCmd, NULL, NULL); Tcl_CreateCommand(interp, "testchannel", TestChannelCmd, NULL, NULL); @@ -588,40 +588,40 @@ Tcltest_Init( Tcl_CreateCommand(interp, "testdel", TestdelCmd, NULL, NULL); Tcl_CreateCommand(interp, "testdelassocdata", TestdelassocdataCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testdoubledigits", TestdoubledigitsObjCmd, + Tcl_CreateObjCommand2(interp, "testdoubledigits", TestdoubledigitsObjCmd, NULL, NULL); Tcl_DStringInit(&dstring); Tcl_CreateCommand(interp, "testdstring", TestdstringCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testencoding", TestencodingObjCmd, NULL, + Tcl_CreateObjCommand2(interp, "testencoding", TestencodingObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testevalex", TestevalexObjCmd, + Tcl_CreateObjCommand2(interp, "testevalex", TestevalexObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testevalobjv", TestevalobjvObjCmd, + Tcl_CreateObjCommand2(interp, "testevalobjv", TestevalobjvObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testevent", TesteventObjCmd, + Tcl_CreateObjCommand2(interp, "testevent", TesteventObjCmd, NULL, NULL); Tcl_CreateCommand(interp, "testexithandler", TestexithandlerCmd, NULL, NULL); Tcl_CreateCommand(interp, "testexprlong", TestexprlongCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testexprlongobj", TestexprlongobjCmd, + Tcl_CreateObjCommand2(interp, "testexprlongobj", TestexprlongobjCmd, NULL, NULL); Tcl_CreateCommand(interp, "testexprdouble", TestexprdoubleCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testexprdoubleobj", TestexprdoubleobjCmd, + Tcl_CreateObjCommand2(interp, "testexprdoubleobj", TestexprdoubleobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testexprparser", TestexprparserObjCmd, + Tcl_CreateObjCommand2(interp, "testexprparser", TestexprparserObjCmd, NULL, NULL); Tcl_CreateCommand(interp, "testexprstring", TestexprstringCmd, NULL, NULL); Tcl_CreateCommand(interp, "testfevent", TestfeventCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd, + Tcl_CreateObjCommand2(interp, "testfilelink", TestfilelinkCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfile", TestfileCmd, + Tcl_CreateObjCommand2(interp, "testfile", TestfileCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testhashsystemhash", + Tcl_CreateObjCommand2(interp, "testhashsystemhash", TestHashSystemHashCmd, NULL, NULL); Tcl_CreateCommand(interp, "testgetassocdata", TestgetassocdataCmd, NULL, NULL); @@ -631,31 +631,31 @@ Tcltest_Init( NULL, NULL); Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testgetvarfullname", + Tcl_CreateObjCommand2(interp, "testgetvarfullname", TestgetvarfullnameCmd, NULL, NULL); Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd, NULL, NULL); Tcl_CreateCommand(interp, "testlink", TestlinkCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testlinkarray", TestlinkarrayCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL, + Tcl_CreateObjCommand2(interp, "testlinkarray", TestlinkarrayCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "testlocale", TestlocaleCmd, NULL, NULL); Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testparseargs", TestparseargsCmd,NULL,NULL); - Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd, + Tcl_CreateObjCommand2(interp, "testparseargs", TestparseargsCmd,NULL,NULL); + Tcl_CreateObjCommand2(interp, "testparser", TestparserObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd, + Tcl_CreateObjCommand2(interp, "testparsevar", TestparsevarObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameObjCmd, + Tcl_CreateObjCommand2(interp, "testparsevarname", TestparsevarnameObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testpreferstable", TestpreferstableObjCmd, + Tcl_CreateObjCommand2(interp, "testpreferstable", TestpreferstableObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testprint", TestprintObjCmd, + Tcl_CreateObjCommand2(interp, "testprint", TestprintObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testregexp", TestregexpObjCmd, + Tcl_CreateObjCommand2(interp, "testregexp", TestregexpObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testreturn", TestreturnObjCmd, + Tcl_CreateObjCommand2(interp, "testreturn", TestreturnObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testsaveresult", TestsaveresultCmd, + Tcl_CreateObjCommand2(interp, "testsaveresult", TestsaveresultCmd, NULL, NULL); Tcl_CreateCommand(interp, "testservicemode", TestServiceModeCmd, NULL, NULL); @@ -669,19 +669,19 @@ Tcltest_Init( INT2PTR(TCL_LEAVE_ERR_MSG), NULL); Tcl_CreateCommand(interp, "testseterrorcode", TestseterrorcodeCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testsetobjerrorcode", + Tcl_CreateObjCommand2(interp, "testsetobjerrorcode", TestsetobjerrorcodeCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testutfnext", + Tcl_CreateObjCommand2(interp, "testutfnext", TestUtfNextCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testutfprev", + Tcl_CreateObjCommand2(interp, "testutfprev", TestUtfPrevCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testnumutfchars", + Tcl_CreateObjCommand2(interp, "testnumutfchars", TestNumUtfCharsCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfindfirst", + Tcl_CreateObjCommand2(interp, "testfindfirst", TestFindFirstCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfindlast", + Tcl_CreateObjCommand2(interp, "testfindlast", TestFindLastCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testgetintforindex", + Tcl_CreateObjCommand2(interp, "testgetintforindex", TestGetIntForIndexCmd, NULL, NULL); Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd, NULL, NULL); @@ -699,18 +699,18 @@ Tcltest_Init( Tcl_CreateCommand(interp, "testexitmainloop", TestexitmainloopCmd, NULL, NULL); #if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL) - Tcl_CreateObjCommand(interp, "testcpuid", TestcpuidCmd, + Tcl_CreateObjCommand2(interp, "testcpuid", TestcpuidCmd, NULL, NULL); #endif - Tcl_CreateObjCommand(interp, "testnreunwind", TestNREUnwind, + Tcl_CreateObjCommand2(interp, "testnreunwind", TestNREUnwind, NULL, NULL); - Tcl_CreateObjCommand(interp, "testnrelevels", TestNRELevels, + Tcl_CreateObjCommand2(interp, "testnrelevels", TestNRELevels, NULL, NULL); - Tcl_CreateObjCommand(interp, "testinterpresolver", TestInterpResolverCmd, + Tcl_CreateObjCommand2(interp, "testinterpresolver", TestInterpResolverCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testgetencpath", TestgetencpathObjCmd, + Tcl_CreateObjCommand2(interp, "testgetencpath", TestgetencpathObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testsetencpath", TestsetencpathObjCmd, + Tcl_CreateObjCommand2(interp, "testsetencpath", TestsetencpathObjCmd, NULL, NULL); if (TclObjTest_Init(interp) != TCL_OK) { @@ -731,9 +731,11 @@ Tcltest_Init( objPtr = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY); if (objPtr != NULL) { - if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { + int val; + if (Tcl_ListObjGetElements(interp, objPtr, &val, &objv) != TCL_OK) { return TCL_ERROR; } + objc = val; if (objc && (Tcl_GetIndexFromObj(NULL, objv[0], specialOptions, NULL, TCL_EXACT, &index) == TCL_OK)) { switch (index) { @@ -1025,7 +1027,7 @@ static int TestbumpinterpepochObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Interp *iPtr = (Interp *)interp; @@ -1101,7 +1103,9 @@ TestcmdinfoCmd( Tcl_AppendResult(interp, " unknown", NULL); } Tcl_AppendResult(interp, " ", info.namespacePtr->fullName, NULL); - if (info.isNativeObjectProc) { + if (info.isNativeObjectProc == 2) { + Tcl_AppendResult(interp, " nativeObjectProc2", NULL); + } else if (info.isNativeObjectProc == 1) { Tcl_AppendResult(interp, " nativeObjectProc", NULL); } else { Tcl_AppendResult(interp, " stringProc", NULL); @@ -1111,6 +1115,10 @@ TestcmdinfoCmd( info.clientData = (void *) "new_command_data"; info.objProc = NULL; info.objClientData = NULL; +#if TCL_MAJOR_VERSION > 8 || defined(TCL_NO_DEPRECATED) + info.objProc2 = NULL; + info.objClientData2 = NULL; +#endif info.deleteProc = CmdDelProc2; info.deleteData = (void *) "new_delete_data"; if (Tcl_SetCommandInfo(interp, argv[2], &info) == 0) { @@ -1302,7 +1310,7 @@ TestcmdtraceCmd( static int deleteCalled; deleteCalled = 0; - cmdTrace = Tcl_CreateObjTrace(interp, 50000, + cmdTrace = Tcl_CreateObjTrace2(interp, 50000, TCL_ALLOW_INLINE_COMPILATION, ObjTraceProc, &deleteCalled, ObjTraceDeleteProc); result = Tcl_EvalEx(interp, argv[2], -1, 0); @@ -1388,7 +1396,7 @@ ObjTraceProc( TCL_UNUSED(int) /*level*/, const char *command, TCL_UNUSED(Tcl_Command), - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, Tcl_Obj *const objv[]) /* Argument objects. */ { const char *word = Tcl_GetString(objv[0]); @@ -1708,7 +1716,7 @@ static int TestdoubledigitsObjCmd( TCL_UNUSED(void *), Tcl_Interp* interp, /* Tcl interpreter */ - int objc, /* Parameter count */ + size_t objc, /* Parameter count */ Tcl_Obj* const objv[]) /* Parameter vector */ { static const char *options[] = { @@ -1921,7 +1929,7 @@ static int TestencodingObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Encoding encoding; @@ -2081,7 +2089,7 @@ static int TestevalexObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { int length, flags; @@ -2126,7 +2134,7 @@ static int TestevalobjvObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { int evalGlobal; @@ -2175,7 +2183,7 @@ static int TesteventObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Parameter count */ + size_t objc, /* Parameter count */ Tcl_Obj *const objv[]) /* Parameter vector */ { static const char *const subcommands[] = { /* Possible subcommands */ @@ -2473,7 +2481,7 @@ static int TestexprlongobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Argument objects. */ { long exprResult; @@ -2559,7 +2567,7 @@ static int TestexprdoubleobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Argument objects. */ { double exprResult; @@ -2633,7 +2641,7 @@ static int TestfilelinkCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Tcl_Obj *contents; @@ -3286,7 +3294,7 @@ static int TestlinkarrayCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { static const char *LinkOption[] = { @@ -3305,7 +3313,8 @@ TestlinkarrayCmd( TCL_LINK_FLOAT, TCL_LINK_DOUBLE, TCL_LINK_STRING, TCL_LINK_CHARS, TCL_LINK_BINARY }; - int optionIndex, typeIndex, readonly, i, size, length; + int optionIndex, typeIndex, readonly, size, length; + size_t i; char *name, *arg; Tcl_WideInt addr; @@ -3404,7 +3413,7 @@ static int TestlocaleCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { int index; @@ -3490,7 +3499,7 @@ static int TestparserObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { const char *script; @@ -3546,7 +3555,7 @@ static int TestexprparserObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { const char *script; @@ -3694,7 +3703,7 @@ static int TestparsevarObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { const char *value, *name, *termPtr; @@ -3735,7 +3744,7 @@ static int TestparsevarnameObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { const char *script; @@ -3798,7 +3807,7 @@ static int TestpreferstableObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, TCL_UNUSED(Tcl_Obj *const *) /*objv*/) { Interp *iPtr = (Interp *) interp; @@ -3828,7 +3837,7 @@ static int TestprintObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Tcl_WideInt argv1 = 0; @@ -3869,10 +3878,11 @@ static int TestregexpObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, ii, indices, stringLength, match, about; + int ii, indices, stringLength, match, about; + size_t i; int hasxflags, cflags, eflags; Tcl_RegExp regExpr; const char *string; @@ -3941,7 +3951,7 @@ TestregexpObjCmd( } endOfForLoop: - if (objc - i < hasxflags + 2 - about) { + if (objc + about < hasxflags + i + 2) { Tcl_WrongNumArgs(interp, 1, objv, "?-switch ...? exp string ?matchVar? ?subMatchVar ...?"); return TCL_ERROR; @@ -4192,7 +4202,7 @@ static int TestreturnObjCmd( TCL_UNUSED(void *), TCL_UNUSED(Tcl_Interp *), - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, TCL_UNUSED(Tcl_Obj *const *) /*objv*/) { return TCL_RETURN; @@ -4516,7 +4526,7 @@ static int TestsetobjerrorcodeCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Tcl_SetObjErrorCode(interp, Tcl_ConcatObj(objc - 1, objv + 1)); @@ -4635,10 +4645,11 @@ static int TestfileCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int argc, /* Number of arguments. */ + size_t argc, /* Number of arguments. */ Tcl_Obj *const argv[]) /* The argument objects. */ { - int force, i, j, result; + int force, result; + size_t i, j; Tcl_Obj *error = NULL; const char *subcmd; @@ -4717,7 +4728,7 @@ static int TestgetvarfullnameCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { const char *name, *arg; @@ -4791,7 +4802,7 @@ static int GetTimesObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* The current interpreter. */ - TCL_UNUSED(int) /*cobjc*/, + TCL_UNUSED(size_t) /*cobjc*/, TCL_UNUSED(Tcl_Obj *const *) /*cobjv*/) { Interp *iPtr = (Interp *) interp; @@ -4997,7 +5008,7 @@ static int NoopObjCmd( TCL_UNUSED(void *), TCL_UNUSED(Tcl_Interp *), - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, TCL_UNUSED(Tcl_Obj *const *) /*objv*/) { return TCL_OK; @@ -5022,7 +5033,7 @@ static int TeststringbytesObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { int n; @@ -5062,7 +5073,7 @@ static int TestpurebytesobjObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Tcl_Obj *objPtr; @@ -5109,7 +5120,7 @@ static int TestsetbytearraylengthObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { int n; @@ -5153,7 +5164,7 @@ static int TestbytestringObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { size_t n = 0; @@ -5275,7 +5286,7 @@ static int TestsaveresultCmd( TCL_UNUSED(void *), Tcl_Interp *interp,/* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Interp* iPtr = (Interp*) interp; @@ -6318,10 +6329,11 @@ static int TestWrongNumArgsObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, length; + Tcl_WideInt i; + int length; const char *msg; if (objc < 3) { @@ -6333,7 +6345,7 @@ TestWrongNumArgsObjCmd( return TCL_ERROR; } - if (Tcl_GetIntFromObj(interp, objv[1], &i) != TCL_OK) { + if (Tcl_GetWideIntFromObj(interp, objv[1], &i) != TCL_OK) { return TCL_ERROR; } @@ -6342,7 +6354,7 @@ TestWrongNumArgsObjCmd( msg = NULL; } - if (i > objc - 3) { + if ((size_t)i + 3 > objc) { /* * Asked for more arguments than were given. */ @@ -6374,7 +6386,7 @@ static int TestGetIndexFromObjStructObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { const char *const ary[] = { @@ -6436,7 +6448,7 @@ static int TestFilesystemObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { int res, boolVal; @@ -6807,7 +6819,7 @@ static int TestSimpleFilesystemObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { int res, boolVal; @@ -6969,7 +6981,7 @@ static int TestUtfNextCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { int numBytes; @@ -7030,7 +7042,7 @@ static int TestUtfPrevCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { int numBytes, offset; @@ -7070,7 +7082,7 @@ static int TestNumUtfCharsCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { if (objc > 1) { @@ -7099,7 +7111,7 @@ static int TestFindFirstCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { if (objc > 1) { @@ -7121,7 +7133,7 @@ static int TestFindLastCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { if (objc > 1) { @@ -7139,7 +7151,7 @@ static int TestGetIntForIndexCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { int result; @@ -7190,7 +7202,7 @@ static int TestcpuidCmd( TCL_UNUSED(void *), Tcl_Interp* interp, /* Tcl interpreter */ - int objc, /* Parameter count */ + size_t objc, /* Parameter count */ Tcl_Obj *const * objv) /* Parameter vector */ { int status, index, i; @@ -7226,7 +7238,7 @@ static int TestHashSystemHashCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { static const Tcl_HashKeyType hkType = { @@ -7371,7 +7383,7 @@ static int TestNREUnwind( TCL_UNUSED(void *), Tcl_Interp *interp, - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, TCL_UNUSED(Tcl_Obj *const *) /*objv*/) { /* @@ -7389,7 +7401,7 @@ static int TestNRELevels( TCL_UNUSED(void *), Tcl_Interp *interp, - TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(size_t) /*objc*/, TCL_UNUSED(Tcl_Obj *const *) /*objv*/) { Interp *iPtr = (Interp *) interp; @@ -7735,7 +7747,7 @@ static int TestgetencpathObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Argument strings. */ { if (objc != 1) { @@ -7768,7 +7780,7 @@ static int TestsetencpathObjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Argument strings. */ { if (objc != 2) { @@ -7802,7 +7814,7 @@ static int TestparseargsCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Arguments. */ { static int foo = 0; @@ -8041,7 +8053,7 @@ static int TestInterpResolverCmd( TCL_UNUSED(void *), Tcl_Interp *interp, - int objc, + size_t objc, Tcl_Obj *const objv[]) { static const char *const table[] = { diff --git a/generic/tclTestObj.c b/generic/tclTestObj.c index 223eb98..52bbff8 100644 --- a/generic/tclTestObj.c +++ b/generic/tclTestObj.c @@ -42,14 +42,14 @@ static int CheckIfVarUnset(Tcl_Interp *interp, Tcl_Obj **varPtr, size_t varInde static int GetVariableIndex(Tcl_Interp *interp, Tcl_Obj *obj, size_t *indexPtr); static void SetVarToObj(Tcl_Obj **varPtr, size_t varIndex, Tcl_Obj *objPtr); -static Tcl_ObjCmdProc TestbignumobjCmd; -static Tcl_ObjCmdProc TestbooleanobjCmd; -static Tcl_ObjCmdProc TestdoubleobjCmd; -static Tcl_ObjCmdProc TestindexobjCmd; -static Tcl_ObjCmdProc TestintobjCmd; -static Tcl_ObjCmdProc TestlistobjCmd; -static Tcl_ObjCmdProc TestobjCmd; -static Tcl_ObjCmdProc TeststringobjCmd; +static Tcl_ObjCmdProc2 TestbignumobjCmd; +static Tcl_ObjCmdProc2 TestbooleanobjCmd; +static Tcl_ObjCmdProc2 TestdoubleobjCmd; +static Tcl_ObjCmdProc2 TestindexobjCmd; +static Tcl_ObjCmdProc2 TestintobjCmd; +static Tcl_ObjCmdProc2 TestlistobjCmd; +static Tcl_ObjCmdProc2 TestobjCmd; +static Tcl_ObjCmdProc2 TeststringobjCmd; #define VARPTR_KEY "TCLOBJTEST_VARPTR" #define NUMBER_OF_OBJECT_VARS 20 @@ -110,20 +110,20 @@ TclObjTest_Init( varPtr[i] = NULL; } - Tcl_CreateObjCommand(interp, "testbignumobj", TestbignumobjCmd, + Tcl_CreateObjCommand2(interp, "testbignumobj", TestbignumobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd, + Tcl_CreateObjCommand2(interp, "testbooleanobj", TestbooleanobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd, + Tcl_CreateObjCommand2(interp, "testdoubleobj", TestdoubleobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd, + Tcl_CreateObjCommand2(interp, "testintobj", TestintobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd, + Tcl_CreateObjCommand2(interp, "testindexobj", TestindexobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testlistobj", TestlistobjCmd, + Tcl_CreateObjCommand2(interp, "testlistobj", TestlistobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testobj", TestobjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd, + Tcl_CreateObjCommand2(interp, "testobj", TestobjCmd, NULL, NULL); + Tcl_CreateObjCommand2(interp, "teststringobj", TeststringobjCmd, NULL, NULL); return TCL_OK; } @@ -150,7 +150,7 @@ static int TestbignumobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Argument count */ + size_t objc, /* Argument count */ Tcl_Obj *const objv[]) /* Argument vector */ { const char *const subcmds[] = { @@ -349,7 +349,7 @@ static int TestbooleanobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { size_t varIndex; @@ -449,7 +449,7 @@ static int TestdoubleobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { size_t varIndex; @@ -565,10 +565,11 @@ static int TestindexobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int allowAbbrev, index, setError, i, result; + int allowAbbrev, index, setError, result; + size_t i; Tcl_WideInt index2; const char **argv; static const char *const tablePtr[] = {"a", "b", "check", NULL}; @@ -655,7 +656,7 @@ static int TestintobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { size_t varIndex; @@ -854,7 +855,7 @@ static int TestlistobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Number of arguments */ + size_t objc, /* Number of arguments */ Tcl_Obj *const objv[]) /* Argument objects */ { /* Subcommands supported by this command */ @@ -948,7 +949,7 @@ static int TestobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { size_t varIndex, destIndex; @@ -1151,12 +1152,12 @@ static int TeststringobjCmd( TCL_UNUSED(void *), Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ + size_t objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { unsigned short *unicode; - size_t varIndex; - int size, option, i; + size_t varIndex, i; + int size, option; Tcl_WideInt length; #define MAX_STRINGS 11 const char *string, *strings[MAX_STRINGS+1]; diff --git a/generic/tclTrace.c b/generic/tclTrace.c index c8f10e3..d84e183 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -2121,6 +2121,50 @@ TraceVarProc( *---------------------------------------------------------------------- */ +typedef struct { + Tcl_CmdObjTraceProc2 *proc; + Tcl_CmdObjTraceDeleteProc *delProc; + void *clientData; +} TraceWrapper; + +static int wrapperProc2( + void *clientData, + Tcl_Interp *interp, + int level, + const char *command, + Tcl_Command commandInfo, + int objc, + struct Tcl_Obj *const objv[]) +{ + TraceWrapper *wrapper = (TraceWrapper *)clientData; + return wrapper->proc(wrapper->clientData, interp, level, command, commandInfo, objc, objv); +} + +static void wrapperDelProc2(void *clientData) +{ + TraceWrapper *wrapper = (TraceWrapper *)clientData; + clientData = wrapper->clientData; + wrapper->delProc(clientData); + Tcl_Free(wrapper); +} + +Tcl_Trace +Tcl_CreateObjTrace2( + Tcl_Interp *interp, /* Tcl interpreter */ + int level, /* Maximum nesting level */ + int flags, /* Flags, see above */ + Tcl_CmdObjTraceProc2 *proc, /* Trace callback */ + void *clientData, /* Client data for the callback */ + Tcl_CmdObjTraceDeleteProc *delProc) + /* Function to call when trace is deleted */ +{ + TraceWrapper *wrapper = (TraceWrapper *)Tcl_Alloc(sizeof(TraceWrapper)); + wrapper->proc = proc; + wrapper->delProc = delProc; + wrapper->clientData = clientData; + return Tcl_CreateObjTrace(interp, level, flags, wrapperProc2, wrapper, wrapperDelProc2); +} + Tcl_Trace Tcl_CreateObjTrace( Tcl_Interp *interp, /* Tcl interpreter */ -- cgit v0.12 From a383c56d6c81e21d403e98d4370ee370fe1882b0 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 9 Jun 2022 12:39:29 +0000 Subject: Doc tweak --- doc/CrtObjCmd.3 | 4 ++-- generic/tclBasic.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/CrtObjCmd.3 b/doc/CrtObjCmd.3 index 57834da..0490bd7 100644 --- a/doc/CrtObjCmd.3 +++ b/doc/CrtObjCmd.3 @@ -180,8 +180,8 @@ typedef void \fBTcl_CmdDeleteProc\fR( The \fIclientData\fR argument will be the same as the \fIclientData\fR argument passed to \fBTcl_CreateObjCommand\fR. .PP -\fBTcl_CreateObjCommand2\fR does the same as \fBTcl_CreateObjCommand2\fR, -except its \fIproc2\fR argument is of type \fBTcl_ObjCmdProc2\fR(. +\fBTcl_CreateObjCommand2\fR does the same as \fBTcl_CreateObjCommand\fR, +except its \fIproc2\fR argument is of type \fBTcl_ObjCmdProc2\fR. .PP .CS typedef int \fBTcl_ObjCmdProc2\fR( diff --git a/generic/tclBasic.c b/generic/tclBasic.c index a1a7db7..8aa8e44 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3440,7 +3440,7 @@ static int cmdWrapper2Proc(void *clientData, { Command *cmdPtr = (Command *)clientData; if (objc > INT_MAX) { - Tcl_WrongNumArgs(interp, 1, objv, "?args?"); + Tcl_WrongNumArgs(interp, 1, objv, "?arg ...?"); return TCL_ERROR; } return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv); -- cgit v0.12 From 3d3e5e89e2157d39698cfd51aed533a297759e80 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 9 Jun 2022 21:15:17 +0000 Subject: Unicode 15.0.0 (Beta), to be released September 2022 --- generic/regc_locale.c | 288 ++++++++++---------- generic/tclUniData.c | 737 ++++++++++++++++++++++++++------------------------ 2 files changed, 531 insertions(+), 494 deletions(-) diff --git a/generic/regc_locale.c b/generic/regc_locale.c index cf751ba..e74b147 100644 --- a/generic/regc_locale.c +++ b/generic/regc_locale.c @@ -227,28 +227,30 @@ static const crange alphaRangeTable[] = { {0x119A0, 0x119A7}, {0x119AA, 0x119D0}, {0x11A0B, 0x11A32}, {0x11A5C, 0x11A89}, {0x11AB0, 0x11AF8}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C72, 0x11C8F}, {0x11D00, 0x11D06}, {0x11D0B, 0x11D30}, {0x11D60, 0x11D65}, {0x11D6A, 0x11D89}, - {0x11EE0, 0x11EF2}, {0x12000, 0x12399}, {0x12480, 0x12543}, {0x12F90, 0x12FF0}, - {0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, - {0x16A70, 0x16ABE}, {0x16AD0, 0x16AED}, {0x16B00, 0x16B2F}, {0x16B40, 0x16B43}, - {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E7F}, {0x16F00, 0x16F4A}, - {0x16F93, 0x16F9F}, {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, - {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1B000, 0x1B122}, {0x1B150, 0x1B152}, - {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, - {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, - {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, - {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, - {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, - {0x1D6A8, 0x1D6C0}, {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6FA}, {0x1D6FC, 0x1D714}, - {0x1D716, 0x1D734}, {0x1D736, 0x1D74E}, {0x1D750, 0x1D76E}, {0x1D770, 0x1D788}, - {0x1D78A, 0x1D7A8}, {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB}, {0x1DF00, 0x1DF1E}, - {0x1E100, 0x1E12C}, {0x1E137, 0x1E13D}, {0x1E290, 0x1E2AD}, {0x1E2C0, 0x1E2EB}, - {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, - {0x1E900, 0x1E943}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE29, 0x1EE32}, - {0x1EE34, 0x1EE37}, {0x1EE4D, 0x1EE4F}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, - {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, - {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x20000, 0x2A6DF}, - {0x2A700, 0x2B738}, {0x2B740, 0x2B81D}, {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, - {0x2F800, 0x2FA1D}, {0x30000, 0x3134A} + {0x11EE0, 0x11EF2}, {0x11F04, 0x11F10}, {0x11F12, 0x11F33}, {0x12000, 0x12399}, + {0x12480, 0x12543}, {0x12F90, 0x12FF0}, {0x13000, 0x1342F}, {0x13441, 0x13446}, + {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A70, 0x16ABE}, + {0x16AD0, 0x16AED}, {0x16B00, 0x16B2F}, {0x16B40, 0x16B43}, {0x16B63, 0x16B77}, + {0x16B7D, 0x16B8F}, {0x16E40, 0x16E7F}, {0x16F00, 0x16F4A}, {0x16F93, 0x16F9F}, + {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, {0x1AFF0, 0x1AFF3}, + {0x1AFF5, 0x1AFFB}, {0x1B000, 0x1B122}, {0x1B150, 0x1B152}, {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, + {0x1BC90, 0x1BC99}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D4A9, 0x1D4AC}, + {0x1D4AE, 0x1D4B9}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, + {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, + {0x1D540, 0x1D544}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, + {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6FA}, {0x1D6FC, 0x1D714}, {0x1D716, 0x1D734}, + {0x1D736, 0x1D74E}, {0x1D750, 0x1D76E}, {0x1D770, 0x1D788}, {0x1D78A, 0x1D7A8}, + {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB}, {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A}, + {0x1E030, 0x1E06D}, {0x1E100, 0x1E12C}, {0x1E137, 0x1E13D}, {0x1E290, 0x1E2AD}, + {0x1E2C0, 0x1E2EB}, {0x1E4D0, 0x1E4EB}, {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, + {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E900, 0x1E943}, {0x1EE00, 0x1EE03}, + {0x1EE05, 0x1EE1F}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, {0x1EE4D, 0x1EE4F}, + {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, + {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, + {0x1EEAB, 0x1EEBB}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B739}, {0x2B740, 0x2B81D}, + {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, {0x2F800, 0x2FA1D}, {0x30000, 0x3134A}, + {0x31350, 0x323AF} #endif }; @@ -276,15 +278,16 @@ static const chr alphaCharTable[] = { #if CHRBITS > 16 ,0x1003C, 0x1003D, 0x10594, 0x10595, 0x105BB, 0x105BC, 0x10808, 0x10837, 0x10838, 0x1083C, 0x108F4, 0x108F5, 0x109BE, 0x109BF, 0x10A00, 0x10EB0, 0x10EB1, 0x10F27, - 0x11071, 0x11072, 0x11075, 0x11144, 0x11147, 0x11176, 0x111DA, 0x111DC, 0x11288, - 0x1130F, 0x11310, 0x11332, 0x11333, 0x1133D, 0x11350, 0x114C4, 0x114C5, 0x114C7, - 0x11644, 0x116B8, 0x11909, 0x11915, 0x11916, 0x1193F, 0x11941, 0x119E1, 0x119E3, - 0x11A00, 0x11A3A, 0x11A50, 0x11A9D, 0x11C40, 0x11D08, 0x11D09, 0x11D46, 0x11D67, - 0x11D68, 0x11D98, 0x11FB0, 0x16F50, 0x16FE0, 0x16FE1, 0x16FE3, 0x1AFFD, 0x1AFFE, - 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4BB, 0x1D546, 0x1E14E, 0x1E7ED, - 0x1E7EE, 0x1E94B, 0x1EE21, 0x1EE22, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, 0x1EE42, - 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, - 0x1EE5D, 0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE7E + 0x11071, 0x11072, 0x11075, 0x11144, 0x11147, 0x11176, 0x111DA, 0x111DC, 0x1123F, + 0x11240, 0x11288, 0x1130F, 0x11310, 0x11332, 0x11333, 0x1133D, 0x11350, 0x114C4, + 0x114C5, 0x114C7, 0x11644, 0x116B8, 0x11909, 0x11915, 0x11916, 0x1193F, 0x11941, + 0x119E1, 0x119E3, 0x11A00, 0x11A3A, 0x11A50, 0x11A9D, 0x11C40, 0x11D08, 0x11D09, + 0x11D46, 0x11D67, 0x11D68, 0x11D98, 0x11F02, 0x11FB0, 0x16F50, 0x16FE0, 0x16FE1, + 0x16FE3, 0x1AFFD, 0x1AFFE, 0x1B132, 0x1B155, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, + 0x1D4A6, 0x1D4BB, 0x1D546, 0x1E14E, 0x1E7ED, 0x1E7EE, 0x1E94B, 0x1EE21, 0x1EE22, + 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, 0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE51, + 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, 0x1EE5D, 0x1EE5F, 0x1EE61, 0x1EE62, + 0x1EE64, 0x1EE7E #endif }; @@ -299,7 +302,7 @@ static const crange controlRangeTable[] = { {0x202A, 0x202E}, {0x2060, 0x2064}, {0x2066, 0x206F}, {0xE000, 0xF8FF}, {0xFFF9, 0xFFFB} #if CHRBITS > 16 - ,{0x13430, 0x13438}, {0x1BCA0, 0x1BCA3}, {0x1D173, 0x1D17A}, {0xE0020, 0xE007F}, + ,{0x13430, 0x1343F}, {0x1BCA0, 0x1BCA3}, {0x1D173, 0x1D17A}, {0xE0020, 0xE007F}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD} #endif }; @@ -335,9 +338,9 @@ static const crange digitRangeTable[] = { {0x11136, 0x1113F}, {0x111D0, 0x111D9}, {0x112F0, 0x112F9}, {0x11450, 0x11459}, {0x114D0, 0x114D9}, {0x11650, 0x11659}, {0x116C0, 0x116C9}, {0x11730, 0x11739}, {0x118E0, 0x118E9}, {0x11950, 0x11959}, {0x11C50, 0x11C59}, {0x11D50, 0x11D59}, - {0x11DA0, 0x11DA9}, {0x16A60, 0x16A69}, {0x16AC0, 0x16AC9}, {0x16B50, 0x16B59}, - {0x1D7CE, 0x1D7FF}, {0x1E140, 0x1E149}, {0x1E2F0, 0x1E2F9}, {0x1E950, 0x1E959}, - {0x1FBF0, 0x1FBF9} + {0x11DA0, 0x11DA9}, {0x11F50, 0x11F59}, {0x16A60, 0x16A69}, {0x16AC0, 0x16AC9}, + {0x16B50, 0x16B59}, {0x1D7CE, 0x1D7FF}, {0x1E140, 0x1E149}, {0x1E2F0, 0x1E2F9}, + {0x1E4F0, 0x1E4F9}, {0x1E950, 0x1E959}, {0x1FBF0, 0x1FBF9} #endif }; @@ -372,8 +375,9 @@ static const crange punctRangeTable[] = { {0x110BE, 0x110C1}, {0x11140, 0x11143}, {0x111C5, 0x111C8}, {0x111DD, 0x111DF}, {0x11238, 0x1123D}, {0x1144B, 0x1144F}, {0x115C1, 0x115D7}, {0x11641, 0x11643}, {0x11660, 0x1166C}, {0x1173C, 0x1173E}, {0x11944, 0x11946}, {0x11A3F, 0x11A46}, - {0x11A9A, 0x11A9C}, {0x11A9E, 0x11AA2}, {0x11C41, 0x11C45}, {0x12470, 0x12474}, - {0x16B37, 0x16B3B}, {0x16E97, 0x16E9A}, {0x1DA87, 0x1DA8B} + {0x11A9A, 0x11A9C}, {0x11A9E, 0x11AA2}, {0x11B00, 0x11B09}, {0x11C41, 0x11C45}, + {0x11F43, 0x11F4F}, {0x12470, 0x12474}, {0x16B37, 0x16B3B}, {0x16E97, 0x16E9A}, + {0x1DA87, 0x1DA8B} #endif }; @@ -449,7 +453,7 @@ static const crange lowerRangeTable[] = { {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6E1}, {0x1D6FC, 0x1D714}, {0x1D716, 0x1D71B}, {0x1D736, 0x1D74E}, {0x1D750, 0x1D755}, {0x1D770, 0x1D788}, {0x1D78A, 0x1D78F}, {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7C9}, {0x1DF00, 0x1DF09}, {0x1DF0B, 0x1DF1E}, - {0x1E922, 0x1E943} + {0x1DF25, 0x1DF2A}, {0x1E922, 0x1E943} #endif }; @@ -660,55 +664,55 @@ static const crange graphRangeTable[] = { {0xC58, 0xC5A}, {0xC60, 0xC63}, {0xC66, 0xC6F}, {0xC77, 0xC8C}, {0xC8E, 0xC90}, {0xC92, 0xCA8}, {0xCAA, 0xCB3}, {0xCB5, 0xCB9}, {0xCBC, 0xCC4}, {0xCC6, 0xCC8}, {0xCCA, 0xCCD}, {0xCE0, 0xCE3}, - {0xCE6, 0xCEF}, {0xD00, 0xD0C}, {0xD0E, 0xD10}, {0xD12, 0xD44}, - {0xD46, 0xD48}, {0xD4A, 0xD4F}, {0xD54, 0xD63}, {0xD66, 0xD7F}, - {0xD81, 0xD83}, {0xD85, 0xD96}, {0xD9A, 0xDB1}, {0xDB3, 0xDBB}, - {0xDC0, 0xDC6}, {0xDCF, 0xDD4}, {0xDD8, 0xDDF}, {0xDE6, 0xDEF}, - {0xDF2, 0xDF4}, {0xE01, 0xE3A}, {0xE3F, 0xE5B}, {0xE86, 0xE8A}, - {0xE8C, 0xEA3}, {0xEA7, 0xEBD}, {0xEC0, 0xEC4}, {0xEC8, 0xECD}, - {0xED0, 0xED9}, {0xEDC, 0xEDF}, {0xF00, 0xF47}, {0xF49, 0xF6C}, - {0xF71, 0xF97}, {0xF99, 0xFBC}, {0xFBE, 0xFCC}, {0xFCE, 0xFDA}, - {0x1000, 0x10C5}, {0x10D0, 0x1248}, {0x124A, 0x124D}, {0x1250, 0x1256}, - {0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D}, {0x1290, 0x12B0}, - {0x12B2, 0x12B5}, {0x12B8, 0x12BE}, {0x12C2, 0x12C5}, {0x12C8, 0x12D6}, - {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A}, {0x135D, 0x137C}, - {0x1380, 0x1399}, {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x167F}, - {0x1681, 0x169C}, {0x16A0, 0x16F8}, {0x1700, 0x1715}, {0x171F, 0x1736}, - {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, {0x1780, 0x17DD}, - {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x180D}, {0x180F, 0x1819}, - {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E}, - {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1944, 0x196D}, {0x1970, 0x1974}, - {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA}, {0x19DE, 0x1A1B}, - {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, - {0x1AA0, 0x1AAD}, {0x1AB0, 0x1ACE}, {0x1B00, 0x1B4C}, {0x1B50, 0x1B7E}, - {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49}, {0x1C4D, 0x1C88}, - {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7}, {0x1CD0, 0x1CFA}, {0x1D00, 0x1F15}, - {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, - {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FC4}, {0x1FC6, 0x1FD3}, - {0x1FD6, 0x1FDB}, {0x1FDD, 0x1FEF}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFE}, - {0x2010, 0x2027}, {0x2030, 0x205E}, {0x2074, 0x208E}, {0x2090, 0x209C}, - {0x20A0, 0x20C0}, {0x20D0, 0x20F0}, {0x2100, 0x218B}, {0x2190, 0x2426}, - {0x2440, 0x244A}, {0x2460, 0x2B73}, {0x2B76, 0x2B95}, {0x2B97, 0x2CF3}, - {0x2CF9, 0x2D25}, {0x2D30, 0x2D67}, {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, - {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, - {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2E5D}, - {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, - {0x3001, 0x303F}, {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312F}, - {0x3131, 0x318E}, {0x3190, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0xA48C}, - {0xA490, 0xA4C6}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, {0xA700, 0xA7CA}, - {0xA7D5, 0xA7D9}, {0xA7F2, 0xA82C}, {0xA830, 0xA839}, {0xA840, 0xA877}, - {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9}, {0xA8E0, 0xA953}, {0xA95F, 0xA97C}, - {0xA980, 0xA9CD}, {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36}, - {0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2}, {0xAADB, 0xAAF6}, - {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, - {0xAB28, 0xAB2E}, {0xAB30, 0xAB6B}, {0xAB70, 0xABED}, {0xABF0, 0xABF9}, - {0xAC00, 0xD7A3}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xF900, 0xFA6D}, - {0xFA70, 0xFAD9}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36}, - {0xFB38, 0xFB3C}, {0xFB46, 0xFBC2}, {0xFBD3, 0xFD8F}, {0xFD92, 0xFDC7}, - {0xFDF0, 0xFE19}, {0xFE20, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, - {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, {0xFF01, 0xFFBE}, {0xFFC2, 0xFFC7}, - {0xFFCA, 0xFFCF}, {0xFFD2, 0xFFD7}, {0xFFDA, 0xFFDC}, {0xFFE0, 0xFFE6}, - {0xFFE8, 0xFFEE} + {0xCE6, 0xCEF}, {0xCF1, 0xCF3}, {0xD00, 0xD0C}, {0xD0E, 0xD10}, + {0xD12, 0xD44}, {0xD46, 0xD48}, {0xD4A, 0xD4F}, {0xD54, 0xD63}, + {0xD66, 0xD7F}, {0xD81, 0xD83}, {0xD85, 0xD96}, {0xD9A, 0xDB1}, + {0xDB3, 0xDBB}, {0xDC0, 0xDC6}, {0xDCF, 0xDD4}, {0xDD8, 0xDDF}, + {0xDE6, 0xDEF}, {0xDF2, 0xDF4}, {0xE01, 0xE3A}, {0xE3F, 0xE5B}, + {0xE86, 0xE8A}, {0xE8C, 0xEA3}, {0xEA7, 0xEBD}, {0xEC0, 0xEC4}, + {0xEC8, 0xECE}, {0xED0, 0xED9}, {0xEDC, 0xEDF}, {0xF00, 0xF47}, + {0xF49, 0xF6C}, {0xF71, 0xF97}, {0xF99, 0xFBC}, {0xFBE, 0xFCC}, + {0xFCE, 0xFDA}, {0x1000, 0x10C5}, {0x10D0, 0x1248}, {0x124A, 0x124D}, + {0x1250, 0x1256}, {0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D}, + {0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE}, {0x12C2, 0x12C5}, + {0x12C8, 0x12D6}, {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A}, + {0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, + {0x1400, 0x167F}, {0x1681, 0x169C}, {0x16A0, 0x16F8}, {0x1700, 0x1715}, + {0x171F, 0x1736}, {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, + {0x1780, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x180D}, + {0x180F, 0x1819}, {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5}, + {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1944, 0x196D}, + {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA}, + {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89}, + {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD}, {0x1AB0, 0x1ACE}, {0x1B00, 0x1B4C}, + {0x1B50, 0x1B7E}, {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49}, + {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7}, {0x1CD0, 0x1CFA}, + {0x1D00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, + {0x1F50, 0x1F57}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FC4}, + {0x1FC6, 0x1FD3}, {0x1FD6, 0x1FDB}, {0x1FDD, 0x1FEF}, {0x1FF2, 0x1FF4}, + {0x1FF6, 0x1FFE}, {0x2010, 0x2027}, {0x2030, 0x205E}, {0x2074, 0x208E}, + {0x2090, 0x209C}, {0x20A0, 0x20C0}, {0x20D0, 0x20F0}, {0x2100, 0x218B}, + {0x2190, 0x2426}, {0x2440, 0x244A}, {0x2460, 0x2B73}, {0x2B76, 0x2B95}, + {0x2B97, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D30, 0x2D67}, {0x2D7F, 0x2D96}, + {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, + {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, + {0x2DE0, 0x2E5D}, {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, + {0x2FF0, 0x2FFB}, {0x3001, 0x303F}, {0x3041, 0x3096}, {0x3099, 0x30FF}, + {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3}, {0x31F0, 0x321E}, + {0x3220, 0xA48C}, {0xA490, 0xA4C6}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, + {0xA700, 0xA7CA}, {0xA7D5, 0xA7D9}, {0xA7F2, 0xA82C}, {0xA830, 0xA839}, + {0xA840, 0xA877}, {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9}, {0xA8E0, 0xA953}, + {0xA95F, 0xA97C}, {0xA980, 0xA9CD}, {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, + {0xAA00, 0xAA36}, {0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2}, + {0xAADB, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, {0xAB11, 0xAB16}, + {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, {0xAB30, 0xAB6B}, {0xAB70, 0xABED}, + {0xABF0, 0xABF9}, {0xAC00, 0xD7A3}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, + {0xF900, 0xFA6D}, {0xFA70, 0xFAD9}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, + {0xFB1D, 0xFB36}, {0xFB38, 0xFB3C}, {0xFB46, 0xFBC2}, {0xFBD3, 0xFD8F}, + {0xFD92, 0xFDC7}, {0xFDF0, 0xFE19}, {0xFE20, 0xFE52}, {0xFE54, 0xFE66}, + {0xFE68, 0xFE6B}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, {0xFF01, 0xFFBE}, + {0xFFC2, 0xFFC7}, {0xFFCA, 0xFFCF}, {0xFFD2, 0xFFD7}, {0xFFDA, 0xFFDC}, + {0xFFE0, 0xFFE6}, {0xFFE8, 0xFFEE} #if CHRBITS > 16 ,{0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003F, 0x1004D}, {0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133}, @@ -728,11 +732,11 @@ static const crange graphRangeTable[] = { {0x10B58, 0x10B72}, {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10E60, 0x10E7E}, {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, - {0x10F00, 0x10F27}, {0x10F30, 0x10F59}, {0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, + {0x10EFD, 0x10F27}, {0x10F30, 0x10F59}, {0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, {0x10FE0, 0x10FF6}, {0x11000, 0x1104D}, {0x11052, 0x11075}, {0x1107F, 0x110BC}, {0x110BE, 0x110C2}, {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147}, {0x11150, 0x11176}, {0x11180, 0x111DF}, {0x111E1, 0x111F4}, - {0x11200, 0x11211}, {0x11213, 0x1123E}, {0x11280, 0x11286}, {0x1128A, 0x1128D}, + {0x11200, 0x11211}, {0x11213, 0x11241}, {0x11280, 0x11286}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A9}, {0x112B0, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11303}, {0x11305, 0x1130C}, {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11335, 0x11339}, {0x1133B, 0x11344}, {0x1134B, 0x1134D}, {0x1135D, 0x11363}, @@ -743,47 +747,49 @@ static const crange graphRangeTable[] = { {0x11800, 0x1183B}, {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x1190C, 0x11913}, {0x11918, 0x11935}, {0x1193B, 0x11946}, {0x11950, 0x11959}, {0x119A0, 0x119A7}, {0x119AA, 0x119D7}, {0x119DA, 0x119E4}, {0x11A00, 0x11A47}, {0x11A50, 0x11AA2}, - {0x11AB0, 0x11AF8}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45}, - {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, - {0x11D00, 0x11D06}, {0x11D0B, 0x11D36}, {0x11D3F, 0x11D47}, {0x11D50, 0x11D59}, - {0x11D60, 0x11D65}, {0x11D6A, 0x11D8E}, {0x11D93, 0x11D98}, {0x11DA0, 0x11DA9}, - {0x11EE0, 0x11EF8}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399}, {0x12400, 0x1246E}, - {0x12470, 0x12474}, {0x12480, 0x12543}, {0x12F90, 0x12FF2}, {0x13000, 0x1342E}, - {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, - {0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5}, - {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, {0x16B63, 0x16B77}, - {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A}, {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, - {0x16F8F, 0x16F9F}, {0x16FE0, 0x16FE4}, {0x17000, 0x187F7}, {0x18800, 0x18CD5}, - {0x18D00, 0x18D08}, {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1B000, 0x1B122}, - {0x1B150, 0x1B152}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A}, - {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9F}, - {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3}, {0x1D000, 0x1D0F5}, - {0x1D100, 0x1D126}, {0x1D129, 0x1D172}, {0x1D17B, 0x1D1EA}, {0x1D200, 0x1D245}, - {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378}, {0x1D400, 0x1D454}, - {0x1D456, 0x1D49C}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BD, 0x1D4C3}, - {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, - {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D54A, 0x1D550}, - {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, - {0x1DAA1, 0x1DAAF}, {0x1DF00, 0x1DF1E}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, - {0x1E01B, 0x1E021}, {0x1E026, 0x1E02A}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D}, - {0x1E140, 0x1E149}, {0x1E290, 0x1E2AE}, {0x1E2C0, 0x1E2F9}, {0x1E7E0, 0x1E7E6}, - {0x1E7E8, 0x1E7EB}, {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6}, - {0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, - {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, - {0x1EE4D, 0x1EE4F}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, - {0x1EE79, 0x1EE7C}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, - {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x1F000, 0x1F02B}, {0x1F030, 0x1F093}, - {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CF}, {0x1F0D1, 0x1F0F5}, - {0x1F100, 0x1F1AD}, {0x1F1E6, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, - {0x1F260, 0x1F265}, {0x1F300, 0x1F6D7}, {0x1F6DD, 0x1F6EC}, {0x1F6F0, 0x1F6FC}, - {0x1F700, 0x1F773}, {0x1F780, 0x1F7D8}, {0x1F7E0, 0x1F7EB}, {0x1F800, 0x1F80B}, - {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, - {0x1F900, 0x1FA53}, {0x1FA60, 0x1FA6D}, {0x1FA70, 0x1FA74}, {0x1FA78, 0x1FA7C}, - {0x1FA80, 0x1FA86}, {0x1FA90, 0x1FAAC}, {0x1FAB0, 0x1FABA}, {0x1FAC0, 0x1FAC5}, - {0x1FAD0, 0x1FAD9}, {0x1FAE0, 0x1FAE7}, {0x1FAF0, 0x1FAF6}, {0x1FB00, 0x1FB92}, - {0x1FB94, 0x1FBCA}, {0x1FBF0, 0x1FBF9}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B738}, - {0x2B740, 0x2B81D}, {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, {0x2F800, 0x2FA1D}, - {0x30000, 0x3134A}, {0xE0100, 0xE01EF} + {0x11AB0, 0x11AF8}, {0x11B00, 0x11B09}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, + {0x11C38, 0x11C45}, {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7}, + {0x11CA9, 0x11CB6}, {0x11D00, 0x11D06}, {0x11D0B, 0x11D36}, {0x11D3F, 0x11D47}, + {0x11D50, 0x11D59}, {0x11D60, 0x11D65}, {0x11D6A, 0x11D8E}, {0x11D93, 0x11D98}, + {0x11DA0, 0x11DA9}, {0x11EE0, 0x11EF8}, {0x11F00, 0x11F10}, {0x11F12, 0x11F3A}, + {0x11F3E, 0x11F59}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399}, {0x12400, 0x1246E}, + {0x12470, 0x12474}, {0x12480, 0x12543}, {0x12F90, 0x12FF2}, {0x13000, 0x1342F}, + {0x13440, 0x13455}, {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, + {0x16A60, 0x16A69}, {0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {0x16AD0, 0x16AED}, + {0x16AF0, 0x16AF5}, {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, + {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A}, {0x16F00, 0x16F4A}, + {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F}, {0x16FE0, 0x16FE4}, {0x17000, 0x187F7}, + {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, + {0x1B000, 0x1B122}, {0x1B150, 0x1B152}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, + {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, + {0x1BC9C, 0x1BC9F}, {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3}, + {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D172}, {0x1D17B, 0x1D1EA}, + {0x1D200, 0x1D245}, {0x1D2C0, 0x1D2D3}, {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, + {0x1D360, 0x1D378}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D4A9, 0x1D4AC}, + {0x1D4AE, 0x1D4B9}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, + {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, + {0x1D540, 0x1D544}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, + {0x1D7CE, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1DF00, 0x1DF1E}, + {0x1DF25, 0x1DF2A}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, + {0x1E026, 0x1E02A}, {0x1E030, 0x1E06D}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D}, + {0x1E140, 0x1E149}, {0x1E290, 0x1E2AE}, {0x1E2C0, 0x1E2F9}, {0x1E4D0, 0x1E4F9}, + {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, + {0x1E8C7, 0x1E8D6}, {0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1EC71, 0x1ECB4}, + {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE29, 0x1EE32}, + {0x1EE34, 0x1EE37}, {0x1EE4D, 0x1EE4F}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, + {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, + {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x1F000, 0x1F02B}, + {0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CF}, + {0x1F0D1, 0x1F0F5}, {0x1F100, 0x1F1AD}, {0x1F1E6, 0x1F202}, {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, {0x1F260, 0x1F265}, {0x1F300, 0x1F6D7}, {0x1F6DC, 0x1F6EC}, + {0x1F6F0, 0x1F6FC}, {0x1F700, 0x1F776}, {0x1F77B, 0x1F7D9}, {0x1F7E0, 0x1F7EB}, + {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, + {0x1F890, 0x1F8AD}, {0x1F900, 0x1FA53}, {0x1FA60, 0x1FA6D}, {0x1FA70, 0x1FA7C}, + {0x1FA80, 0x1FA88}, {0x1FA90, 0x1FABD}, {0x1FABF, 0x1FAC5}, {0x1FACE, 0x1FADB}, + {0x1FAE0, 0x1FAE8}, {0x1FAF0, 0x1FAF8}, {0x1FB00, 0x1FB92}, {0x1FB94, 0x1FBCA}, + {0x1FBF0, 0x1FBF9}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B739}, {0x2B740, 0x2B81D}, + {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, {0x2F800, 0x2FA1D}, {0x30000, 0x3134A}, + {0x31350, 0x323AF}, {0xE0100, 0xE01EF} #endif }; @@ -795,23 +801,23 @@ static const chr graphCharTable[] = { 0xA3C, 0xA47, 0xA48, 0xA51, 0xA5E, 0xAB2, 0xAB3, 0xAD0, 0xB0F, 0xB10, 0xB32, 0xB33, 0xB47, 0xB48, 0xB5C, 0xB5D, 0xB82, 0xB83, 0xB99, 0xB9A, 0xB9C, 0xB9E, 0xB9F, 0xBA3, 0xBA4, 0xBD0, 0xBD7, - 0xC55, 0xC56, 0xC5D, 0xCD5, 0xCD6, 0xCDD, 0xCDE, 0xCF1, 0xCF2, - 0xDBD, 0xDCA, 0xDD6, 0xE81, 0xE82, 0xE84, 0xEA5, 0xEC6, 0x10C7, - 0x10CD, 0x1258, 0x12C0, 0x1772, 0x1773, 0x1940, 0x1F59, 0x1F5B, 0x1F5D, - 0x2070, 0x2071, 0x2D27, 0x2D2D, 0x2D6F, 0x2D70, 0xA7D0, 0xA7D1, 0xA7D3, - 0xFB3E, 0xFB40, 0xFB41, 0xFB43, 0xFB44, 0xFDCF, 0xFFFC, 0xFFFD + 0xC55, 0xC56, 0xC5D, 0xCD5, 0xCD6, 0xCDD, 0xCDE, 0xDBD, 0xDCA, + 0xDD6, 0xE81, 0xE82, 0xE84, 0xEA5, 0xEC6, 0x10C7, 0x10CD, 0x1258, + 0x12C0, 0x1772, 0x1773, 0x1940, 0x1F59, 0x1F5B, 0x1F5D, 0x2070, 0x2071, + 0x2D27, 0x2D2D, 0x2D6F, 0x2D70, 0xA7D0, 0xA7D1, 0xA7D3, 0xFB3E, 0xFB40, + 0xFB41, 0xFB43, 0xFB44, 0xFDCF, 0xFFFC, 0xFFFD #if CHRBITS > 16 ,0x1003C, 0x1003D, 0x101A0, 0x10594, 0x10595, 0x105BB, 0x105BC, 0x10808, 0x10837, 0x10838, 0x1083C, 0x108F4, 0x108F5, 0x1093F, 0x10A05, 0x10A06, 0x10EB0, 0x10EB1, 0x11288, 0x1130F, 0x11310, 0x11332, 0x11333, 0x11347, 0x11348, 0x11350, 0x11357, 0x11909, 0x11915, 0x11916, 0x11937, 0x11938, 0x11D08, 0x11D09, 0x11D3A, 0x11D3C, 0x11D3D, 0x11D67, 0x11D68, 0x11D90, 0x11D91, 0x11FB0, 0x16FF0, 0x16FF1, 0x1AFFD, - 0x1AFFE, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4BB, 0x1D546, 0x1E023, - 0x1E024, 0x1E14E, 0x1E14F, 0x1E2FF, 0x1E7ED, 0x1E7EE, 0x1E95E, 0x1E95F, 0x1EE21, - 0x1EE22, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, 0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, - 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, 0x1EE5D, 0x1EE5F, 0x1EE61, - 0x1EE62, 0x1EE64, 0x1EE7E, 0x1EEF0, 0x1EEF1, 0x1F250, 0x1F251, 0x1F7F0, 0x1F8B0, - 0x1F8B1 + 0x1AFFE, 0x1B132, 0x1B155, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4BB, + 0x1D546, 0x1E023, 0x1E024, 0x1E08F, 0x1E14E, 0x1E14F, 0x1E2FF, 0x1E7ED, 0x1E7EE, + 0x1E95E, 0x1E95F, 0x1EE21, 0x1EE22, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, 0x1EE42, + 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, + 0x1EE5D, 0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE7E, 0x1EEF0, 0x1EEF1, 0x1F250, + 0x1F251, 0x1F7F0, 0x1F8B0, 0x1F8B1 #endif }; diff --git a/generic/tclUniData.c b/generic/tclUniData.c index dc30794..8fa02cf 100644 --- a/generic/tclUniData.c +++ b/generic/tclUniData.c @@ -207,34 +207,34 @@ static const unsigned short pageMap[] = { 12128, 3296, 12160, 12192, 1344, 12224, 12256, 12288, 12320, 12352, 3296, 3296, 1344, 1344, 12384, 3296, 12416, 12448, 12480, 12512, 1344, 12544, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 12576, - 1344, 12608, 3296, 3296, 12128, 12640, 12672, 12704, 12736, 12704, - 12768, 7776, 12800, 12832, 12864, 12896, 5280, 12928, 12960, 12992, - 13024, 13056, 13088, 13120, 5280, 13152, 13184, 13216, 13248, 13280, - 3296, 3296, 13312, 13344, 13376, 13408, 13440, 13472, 13504, 13536, - 3296, 3296, 3296, 3296, 1344, 13568, 13600, 13632, 1344, 13664, 13696, - 3296, 3296, 3296, 3296, 3296, 1344, 13728, 13760, 3296, 1344, 13792, - 13824, 13856, 1344, 13888, 13920, 3296, 4032, 13952, 13984, 3296, 3296, - 3296, 3296, 3296, 1344, 14016, 3296, 3296, 3296, 14048, 14080, 14112, - 14144, 14176, 14208, 3296, 3296, 14240, 14272, 14304, 14336, 14368, - 14400, 1344, 14432, 14464, 1344, 4608, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 14496, 14528, 14560, 14592, 14624, 14656, 3296, 3296, - 14688, 14720, 14752, 14784, 14816, 13920, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 14848, 3296, 3296, 3296, 3296, 3296, 14880, - 14912, 14944, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 12608, 3296, 12640, 12128, 12672, 12704, 12736, 12768, 12736, + 12800, 7776, 12832, 12864, 12896, 12928, 5280, 12960, 12992, 13024, + 13056, 13088, 13120, 13152, 5280, 13184, 13216, 13248, 13280, 13312, + 13344, 3296, 13376, 13408, 13440, 13472, 13504, 13536, 13568, 13600, + 3296, 3296, 3296, 3296, 1344, 13632, 13664, 13696, 1344, 13728, 13760, + 3296, 3296, 3296, 3296, 3296, 1344, 13792, 13824, 3296, 1344, 13856, + 13888, 13920, 1344, 13952, 13984, 3296, 4032, 14016, 14048, 3296, 3296, + 3296, 3296, 3296, 1344, 14080, 3296, 3296, 3296, 14112, 14144, 14176, + 14208, 14240, 14272, 3296, 3296, 14304, 14336, 14368, 14400, 14432, + 14464, 1344, 14496, 14528, 1344, 4608, 14560, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 14592, 14624, 14656, 14688, 14720, 14752, 3296, 3296, + 14784, 14816, 14848, 14880, 14912, 13984, 3296, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 3296, 14944, 14976, 15008, 15040, 3296, 3296, 15072, + 15104, 15136, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9920, 3296, 3296, 3296, 10816, - 10816, 10816, 14976, 1344, 1344, 1344, 1344, 1344, 1344, 15008, 3296, + 10816, 10816, 15168, 1344, 1344, 1344, 1344, 1344, 1344, 15200, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 12704, 1344, 1344, - 15040, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 12736, 1344, 1344, + 15232, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 15072, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 15264, + 15296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, @@ -244,9 +244,9 @@ static const unsigned short pageMap[] = { 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 13984, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 1344, 14048, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, @@ -268,13 +268,13 @@ static const unsigned short pageMap[] = { 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 4608, 4736, 15104, 1344, 4736, 15136, 15168, 1344, 15200, 15232, 15264, - 15296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 14048, - 14080, 15328, 3296, 3296, 3296, 1344, 1344, 15360, 15392, 15424, 3296, - 3296, 15456, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 4608, 4736, 15328, 1344, 4736, 15360, 15392, 1344, 15424, 15456, + 15488, 15520, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 14112, 14144, 15552, 3296, 3296, 3296, 1344, 1344, 15584, 15616, 15648, + 3296, 3296, 15680, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -290,10 +290,10 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 15488, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 15712, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 4704, 3296, 12384, 3296, 3296, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 4704, 3296, 12384, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, @@ -317,15 +317,15 @@ static const unsigned short pageMap[] = { 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 15520, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 15552, - 15584, 15616, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 9792, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 3296, 15744, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 15776, 15808, 15840, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 9792, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 1344, 1344, 1344, 15648, 15680, 15712, 3296, 3296, + 3296, 3296, 3296, 3296, 1344, 1344, 1344, 15872, 15904, 15936, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, @@ -338,41 +338,42 @@ static const unsigned short pageMap[] = { 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 704, 15744, 15776, 4928, 4928, 4928, 15808, 3296, 4928, 4928, 4928, - 4928, 4928, 4928, 4928, 8000, 4928, 15840, 4928, 15872, 15904, 15936, - 4928, 6848, 4928, 4928, 15968, 3296, 3296, 3296, 3296, 16000, 4928, - 4928, 16032, 16064, 3296, 3296, 3296, 3296, 16096, 16128, 16160, 16192, - 16224, 16256, 16288, 16320, 16352, 16384, 16416, 16448, 16480, 16096, - 16128, 16512, 16192, 16544, 16576, 16608, 16320, 16640, 16672, 16704, - 16736, 16768, 16800, 16832, 16864, 16896, 16928, 16960, 4928, 4928, + 3296, 704, 15968, 16000, 4928, 4928, 4928, 16032, 3296, 4928, 4928, + 4928, 4928, 4928, 4928, 4928, 8000, 4928, 16064, 4928, 16096, 16128, + 16160, 4928, 6848, 4928, 4928, 16192, 3296, 3296, 3296, 16224, 16224, + 4928, 4928, 16256, 16288, 3296, 3296, 3296, 3296, 16320, 16352, 16384, + 16416, 16448, 16480, 16512, 16544, 16576, 16608, 16640, 16672, 16704, + 16320, 16352, 16736, 16416, 16768, 16800, 16832, 16544, 16864, 16896, + 16928, 16960, 16992, 17024, 17056, 17088, 17120, 17152, 17184, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, - 4928, 4928, 704, 16992, 704, 17024, 17056, 17088, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 17120, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 17152, 17184, 3296, 3296, 3296, 3296, 3296, - 3296, 1344, 17216, 17248, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 12704, 17280, 1344, 17312, 3296, 3296, 3296, 3296, 3296, + 4928, 4928, 4928, 704, 17216, 704, 17248, 17280, 17312, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 17344, - 1344, 1344, 1344, 1344, 1344, 1344, 17376, 3296, 17408, 17440, 17472, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 17344, 17376, 3296, + 3296, 3296, 3296, 3296, 3296, 17408, 17440, 5664, 17472, 17504, 3296, + 3296, 3296, 1344, 17536, 17568, 3296, 3296, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 12736, 17600, 1344, 17632, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 12736, + 17664, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 3296, 17696, 1344, 1344, 1344, 1344, 1344, 1344, 17728, 3296, 17760, + 17792, 17824, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 17504, 6880, 17536, 3296, 3296, 17568, 17600, 3296, 3296, 3296, 3296, - 3296, 3296, 17632, 17664, 17696, 17728, 17760, 17792, 3296, 17824, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 4928, 17856, 4928, - 4928, 7968, 17888, 17920, 8000, 17952, 4928, 4928, 4928, 4928, 17984, - 3296, 18016, 18048, 18080, 18112, 18144, 3296, 3296, 3296, 3296, 4928, - 4928, 4928, 4928, 4928, 4928, 4928, 18176, 4928, 4928, 4928, 4928, + 3296, 3296, 3296, 17856, 6880, 17888, 3296, 3296, 17920, 17952, 3296, + 3296, 3296, 3296, 3296, 3296, 17984, 18016, 18048, 18080, 18112, 18144, + 3296, 18176, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 4928, + 18208, 4928, 4928, 7968, 18240, 18272, 8000, 18304, 4928, 4928, 4928, + 4928, 18336, 3296, 18368, 18400, 18432, 18464, 18496, 3296, 3296, 3296, + 3296, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 18528, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, - 4928, 4928, 4928, 4928, 4928, 4928, 18208, 18240, 4928, 4928, 4928, - 7968, 4928, 4928, 18272, 18304, 17856, 4928, 18336, 4928, 18368, 18400, - 3296, 3296, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, - 7968, 18432, 18464, 18496, 18528, 18560, 4928, 4928, 4928, 4928, 18592, - 4928, 6848, 18624, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 18560, 18592, 4928, + 4928, 4928, 18624, 4928, 4928, 18656, 18688, 18208, 4928, 18720, 4928, + 18752, 18784, 3296, 3296, 4928, 4928, 4928, 4928, 4928, 4928, 4928, + 4928, 4928, 4928, 7968, 18816, 18848, 18880, 18912, 18944, 4928, 4928, + 4928, 4928, 18976, 4928, 6848, 19008, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, + 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -483,8 +484,8 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -494,8 +495,8 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 9920, 1344, 1344, 1344, 1344, 1344, 1344, 11328, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 4608, 1344, 1344, 1344, 1344, 1344, 1344, 11328, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -510,7 +511,7 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 18656, + 19040, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -529,8 +530,7 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 18688, 3296, 3296, 3296, 3296, 3296, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 19072, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, @@ -538,12 +538,17 @@ static const unsigned short pageMap[] = { 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11328, + 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 11328, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, - 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, + 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, @@ -552,11 +557,18 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, - 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 18720 + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, + 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 15520 + #endif /* TCL_UTF_MAX > 3 */ }; @@ -732,101 +744,101 @@ static const unsigned char groupMap[] = { 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 93, 15, 125, 93, 125, 125, 125, 125, 125, 0, 93, 125, 125, 0, 125, 125, 93, 93, 0, 0, 0, 0, 0, 0, 0, 125, 125, 0, 0, 0, 0, 0, 0, 15, 15, 0, 15, 15, 93, 93, - 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 93, 93, 125, 125, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 15, 125, 125, - 125, 93, 93, 93, 93, 0, 125, 125, 125, 0, 125, 125, 125, 93, 15, 14, - 0, 0, 0, 0, 15, 15, 15, 125, 18, 18, 18, 18, 18, 18, 18, 15, 15, 15, - 93, 93, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 14, 15, 15, 15, 15, 15, 15, 0, 93, 125, 125, 0, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, - 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 93, 0, 0, 0, - 0, 125, 125, 125, 93, 93, 93, 0, 93, 0, 125, 125, 125, 125, 125, 125, - 125, 125, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 125, - 125, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, + 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 15, 15, 125, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 93, 93, 125, 125, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 15, 125, + 125, 125, 93, 93, 93, 93, 0, 125, 125, 125, 0, 125, 125, 125, 93, 15, + 14, 0, 0, 0, 0, 15, 15, 15, 125, 18, 18, 18, 18, 18, 18, 18, 15, 15, + 15, 93, 93, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 14, 15, 15, 15, 15, 15, 15, 0, 93, 125, 125, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 93, 15, 15, 93, 93, 93, 93, 93, 93, - 93, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 92, 93, 93, 93, 93, 93, - 93, 93, 93, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 93, 0, 0, + 0, 0, 125, 125, 125, 93, 93, 93, 0, 93, 0, 125, 125, 125, 125, 125, + 125, 125, 125, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 125, 125, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 15, 15, 93, 93, 93, 93, 93, + 93, 93, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 92, 93, 93, 93, 93, + 93, 93, 93, 93, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 0, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 93, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 15, 0, 0, 15, 15, - 15, 15, 15, 0, 92, 0, 93, 93, 93, 93, 93, 93, 0, 0, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 15, 15, 15, 15, 15, 14, 14, 14, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 14, 14, 14, 93, 93, 14, 14, 14, - 14, 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 14, 93, 14, 93, 14, 93, 5, 6, 5, 6, 125, 125, 15, 15, 15, - 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 93, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 15, 0, + 0, 15, 15, 15, 15, 15, 0, 92, 0, 93, 93, 93, 93, 93, 93, 93, 0, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 15, 15, 15, 15, 15, 14, 14, 14, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 14, 14, 14, 93, 93, + 14, 14, 14, 14, 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 14, 93, 14, 93, 14, 93, 5, 6, 5, 6, 125, 125, + 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 125, 93, 93, 93, 93, 93, 3, 93, 93, - 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 125, 93, 93, 93, 93, 93, + 3, 93, 93, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 0, 14, 14, 14, 14, 14, 14, 14, 14, 93, 14, 14, 14, 14, 14, - 14, 0, 14, 14, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, 3, 0, 0, 0, 0, 0, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 125, 93, 93, 93, 93, - 125, 93, 93, 93, 93, 93, 93, 125, 93, 93, 125, 125, 93, 93, 15, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 15, 15, 15, 15, 15, 15, - 125, 125, 93, 93, 15, 15, 15, 15, 93, 93, 93, 15, 125, 125, 125, 15, - 15, 125, 125, 125, 125, 125, 125, 125, 15, 15, 15, 93, 93, 93, 93, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 125, 125, 93, - 93, 125, 125, 125, 125, 125, 125, 93, 15, 125, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 125, 125, 125, 93, 14, 14, 126, 126, 126, 126, 126, 126, 126, + 93, 93, 93, 93, 93, 0, 14, 14, 14, 14, 14, 14, 14, 14, 93, 14, 14, + 14, 14, 14, 14, 0, 14, 14, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, 3, 0, + 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 125, 93, + 93, 93, 93, 125, 93, 93, 93, 93, 93, 93, 125, 93, 93, 125, 125, 93, + 93, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 15, 15, 15, + 15, 15, 15, 125, 125, 93, 93, 15, 15, 15, 15, 93, 93, 93, 15, 125, + 125, 125, 15, 15, 125, 125, 125, 125, 125, 125, 125, 15, 15, 15, 93, + 93, 93, 93, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, + 125, 125, 93, 93, 125, 125, 125, 125, 125, 125, 93, 15, 125, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 125, 125, 125, 93, 14, 14, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 0, 126, 0, 0, 0, 0, 0, 126, 0, 0, 127, 127, 127, 127, + 126, 126, 126, 126, 126, 126, 0, 126, 0, 0, 0, 0, 0, 126, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 3, 92, 127, - 127, 127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, - 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, 0, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, - 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, - 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 93, 93, - 93, 3, 3, 3, 3, 3, 3, 3, 3, 3, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 3, 92, 127, 127, 127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, + 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, + 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, + 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, + 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 0, 0, 93, 93, 93, 3, 3, 3, 3, 3, 3, 3, 3, 3, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 105, 105, 105, 105, 105, 105, 0, 0, 111, 111, 111, 111, 111, 111, 0, - 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 128, 128, 105, 105, 105, 105, 105, 105, 0, 0, 111, 111, 111, 111, 111, + 111, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 3, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 3, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 5, 6, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 3, 3, 3, 129, 129, 129, 15, 15, 15, 15, 15, 15, 15, - 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 125, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 93, 93, 125, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 93, 93, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 93, 93, 125, 93, 93, 93, 93, 93, 93, 93, - 125, 125, 125, 125, 125, 125, 125, 125, 93, 125, 125, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 3, 3, 3, 92, 3, 3, 3, 4, 15, 93, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 8, 3, 3, 3, - 3, 93, 93, 93, 17, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 15, 15, 15, 92, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 5, 6, 0, 0, 0, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 3, 3, 3, 129, 129, 129, 15, 15, 15, 15, 15, + 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 125, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 93, 93, 125, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 93, 93, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 125, 93, 93, 93, 93, 93, 93, + 93, 125, 125, 125, 125, 125, 125, 125, 125, 93, 125, 125, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 3, 3, 3, 92, 3, 3, 3, 4, 15, 93, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 8, 3, 3, + 3, 3, 93, 93, 93, 17, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 15, 15, 15, 92, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, @@ -1284,55 +1296,58 @@ static const unsigned char groupMap[] = { 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 93, 93, 8, 0, 0, 15, 15, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, - 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 18, 18, 18, 18, 3, 3, 3, 3, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, - 93, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 18, 18, 18, 18, 18, 18, 18, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 93, 125, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, + 18, 18, 18, 18, 18, 18, 18, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 18, 18, 18, 18, + 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 93, 93, 93, 93, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 18, 18, + 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 125, 93, 125, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 93, 15, 15, 93, 93, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 125, 125, - 93, 93, 93, 93, 125, 125, 93, 93, 3, 3, 17, 3, 3, 3, 3, 93, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, - 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 93, - 93, 93, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 93, 93, 93, 93, 93, 125, 93, 93, 93, 93, 93, 93, 93, - 93, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 15, 125, 125, 15, - 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 93, 15, 15, 93, 93, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 93, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 125, 125, 125, 93, 93, 93, 93, 125, 125, 93, 93, 3, 3, + 17, 3, 3, 3, 3, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 0, 0, 0, 0, 0, 93, 93, 93, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 125, + 93, 93, 93, 93, 93, 93, 93, 93, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, + 3, 3, 3, 15, 125, 125, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 3, 3, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 125, 125, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 125, 125, 15, 15, 15, 15, 3, 3, 3, 3, 93, 93, 93, + 93, 3, 125, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 3, 15, 3, 3, 3, 0, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 93, 3, 3, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 15, 15, 15, 125, 125, 125, 93, 93, 93, 125, 125, 93, 125, 93, 93, + 3, 3, 3, 3, 3, 3, 93, 15, 15, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, + 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 3, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 125, 125, 125, 93, 93, 93, 93, 93, 93, 93, 93, 93, 125, 125, - 15, 15, 15, 15, 3, 3, 3, 3, 93, 93, 93, 93, 3, 125, 93, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 15, 3, 15, 3, 3, 3, 0, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 125, 125, - 93, 93, 93, 125, 125, 93, 125, 93, 93, 3, 3, 3, 3, 3, 3, 93, 0, 15, - 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 3, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 93, 125, 125, 125, 93, 93, 93, 93, 93, 93, 93, 93, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 93, + 93, 125, 125, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 93, 125, 125, 125, 93, 93, 93, 93, 93, 93, - 93, 93, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 0, 93, 93, 125, 125, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, - 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, - 15, 15, 15, 15, 15, 0, 93, 93, 15, 125, 125, 93, 125, 125, 125, 125, - 0, 0, 125, 125, 0, 0, 125, 125, 125, 0, 0, 15, 0, 0, 0, 0, 0, 0, 125, + 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, + 15, 15, 15, 15, 0, 93, 93, 15, 125, 125, 93, 125, 125, 125, 125, 0, + 0, 125, 125, 0, 0, 125, 125, 125, 0, 0, 15, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 125, 125, 0, 0, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, @@ -1384,169 +1399,184 @@ static const unsigned char groupMap[] = { 93, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 125, 93, 93, 3, 3, 3, 15, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 125, 93, 93, 93, 93, 93, 93, 93, 0, - 93, 93, 93, 93, 93, 93, 125, 93, 15, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 3, 3, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 0, 125, 93, 93, 93, 93, 93, 93, 93, 125, 93, 93, 125, 93, 93, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 0, 0, 0, 93, 0, 93, 93, 0, - 93, 93, 93, 93, 93, 93, 93, 15, 93, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 15, - 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 125, 93, 93, + 93, 93, 93, 93, 93, 0, 93, 93, 93, 93, 93, 93, 125, 93, 15, 3, 3, 3, + 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 0, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 0, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 0, 125, 93, 93, 93, 93, 93, 93, 93, 125, + 93, 93, 125, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, + 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 0, 0, 0, + 93, 0, 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, 15, 93, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, + 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 125, 125, 125, 125, 125, 0, 93, 93, 0, 125, 125, 93, + 125, 93, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 125, 125, 3, 3, 0, + 0, 0, 0, 0, 0, 0, 93, 93, 15, 125, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 125, 125, 125, 125, 125, 0, 93, 93, 0, 125, 125, 93, 125, 93, 15, 0, - 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 93, 93, 125, 125, 3, 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, - 14, 14, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0, 0, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 93, 93, 93, - 93, 93, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, 93, 93, 3, - 3, 3, 3, 3, 14, 14, 14, 14, 92, 92, 92, 92, 3, 14, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 18, 18, 18, 18, 18, 18, - 18, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 3, 3, 3, 3, 0, - 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, - 93, 15, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 15, 15, 15, 15, 15, 15, 125, 125, 93, 93, 93, 93, 93, 0, 0, 0, 125, + 125, 93, 125, 93, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 4, 4, 4, 4, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 93, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 3, 3, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 0, 0, 93, 93, 93, 93, 93, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 93, 93, 93, 93, 93, 93, 93, 3, 3, 3, 3, 3, 14, 14, 14, 14, 92, 92, + 92, 92, 3, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 0, 18, 18, 18, 18, 18, 18, 18, 0, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 3, 3, 3, 3, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 0, 0, 0, 0, 93, 15, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, 93, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 3, 92, 93, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 125, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, + 125, 125, 125, 125, 125, 125, 125, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, + 93, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 3, + 92, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 125, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 92, + 92, 0, 92, 92, 92, 92, 92, 92, 92, 0, 92, 92, 0, 15, 15, 15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, + 15, 15, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, + 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 0, 92, 92, 92, 92, 92, 92, - 92, 0, 92, 92, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 0, 0, 14, 93, 93, 3, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, - 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 125, - 125, 93, 93, 93, 14, 14, 14, 125, 125, 125, 125, 125, 125, 17, 17, - 17, 17, 17, 17, 17, 17, 93, 93, 93, 93, 93, 93, 93, 93, 14, 14, 93, - 93, 93, 93, 93, 93, 93, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 14, 93, 93, 3, 17, + 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 0, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 93, 93, 93, 93, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 93, 93, 93, 14, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 125, 125, 93, 93, 93, 14, + 14, 14, 125, 125, 125, 125, 125, 125, 17, 17, 17, 17, 17, 17, 17, 17, + 93, 93, 93, 93, 93, 93, 93, 93, 14, 14, 93, 93, 93, 93, 93, 93, 93, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, - 0, 0, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 93, 93, 93, 93, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 93, 93, 93, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, + 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, + 0, 108, 108, 0, 0, 108, 0, 0, 108, 108, 0, 0, 108, 108, 108, 108, 0, + 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 0, 21, 0, 21, + 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 108, 0, 108, 108, 0, 0, 108, 0, 0, 108, 108, - 0, 0, 108, 108, 108, 108, 0, 108, 108, 108, 108, 108, 108, 108, 108, - 21, 21, 21, 21, 0, 21, 0, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 0, 108, 108, 108, 108, 0, + 0, 108, 108, 108, 108, 108, 108, 108, 108, 0, 108, 108, 108, 108, 108, + 108, 108, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 0, 108, 108, + 108, 108, 0, 108, 108, 108, 108, 108, 0, 108, 0, 0, 0, 108, 108, 108, + 108, 108, 108, 108, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, - 0, 108, 108, 108, 108, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, - 0, 108, 108, 108, 108, 108, 108, 108, 0, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 108, 108, 0, 108, 108, 108, 108, 0, 108, 108, 108, 108, 108, - 0, 108, 0, 0, 0, 108, 108, 108, 108, 108, 108, 108, 0, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 108, + 21, 21, 21, 21, 21, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, + 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 21, 21, 21, 21, 21, 21, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, + 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, - 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 7, + 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, + 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 108, 108, + 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, 21, + 108, 108, 108, 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, - 21, 21, 21, 21, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, - 108, 21, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 21, 21, 7, 21, 21, 21, 21, 21, 21, 108, 21, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 14, 14, 14, 14, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 14, 14, 14, 14, 14, 14, 14, 14, 93, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 93, 14, 14, 3, 3, 3, 3, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, 93, 93, 0, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 15, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 0, 93, 93, 93, 93, 93, 93, 93, 0, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 93, 93, 93, 93, - 93, 93, 93, 0, 93, 93, 0, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 0, 0, 0, 93, 93, 93, 93, 93, 93, 93, 92, 92, - 92, 92, 92, 92, 92, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, - 15, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 93, 93, 93, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, - 4, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 15, 0, 15, + 93, 93, 93, 93, 93, 14, 14, 14, 14, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 14, 14, 14, 14, 14, 14, 14, + 14, 93, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 93, + 14, 14, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 93, 93, 93, 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, + 0, 21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 93, 93, 93, 93, 93, 93, 93, 0, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 93, 93, 93, + 93, 93, 93, 93, 0, 93, 93, 0, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 93, 93, 93, 93, + 93, 93, 93, 92, 92, 92, 92, 92, 92, 92, 0, 0, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 15, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 93, 93, 93, 93, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 0, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 92, 93, 93, 93, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 206, 206, 206, 206, 206, @@ -1595,34 +1625,35 @@ static const unsigned char groupMap[] = { 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 11, 11, 11, 11, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, + 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, + 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, + 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, + 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, - 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, - 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, - 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 14, 14, 14, - 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 + 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + #endif /* TCL_UTF_MAX > 3 */ }; @@ -1672,7 +1703,7 @@ static const int groups[] = { }; #if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 6 -# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1FFFFF) >= 0x31360) +# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1FFFFF) >= 0x323C0) #else # define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1F0000) != 0) #endif -- cgit v0.12 From 474c08922f5e9eb3699fba6cf236e4fde61ae390 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 15 Jun 2022 15:12:27 +0000 Subject: (experimental) TclOO > 2**31 args --- generic/tclExecute.c | 6 ++++- generic/tclOO.decls | 14 +++++++++++ generic/tclOO.h | 23 +++++++++++++++++- generic/tclOOCall.c | 6 ++++- generic/tclOODecls.h | 23 ++++++++++++++++++ generic/tclOOMethod.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclOOStubInit.c | 3 +++ 7 files changed, 135 insertions(+), 3 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2b197c6..fe809c1 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -4787,7 +4787,11 @@ TEBCresume( Method *const mPtr = contextPtr->callPtr->chain[newDepth].mPtr; - return mPtr->typePtr->callProc(mPtr->clientData, interp, + if (mPtr->typePtr->version == TCL_OO_METHOD_VERSION_1) { + return mPtr->typePtr->callProc(mPtr->clientData, interp, + (Tcl_ObjectContext) contextPtr, opnd, objv); + } + return ((Tcl_MethodCallProc2 *)(void *)(mPtr->typePtr->callProc))(mPtr->clientData, interp, (Tcl_ObjectContext) contextPtr, opnd, objv); } diff --git a/generic/tclOO.decls b/generic/tclOO.decls index e4063c7..3507c73 100644 --- a/generic/tclOO.decls +++ b/generic/tclOO.decls @@ -135,6 +135,20 @@ declare 30 { declare 31 { Tcl_Obj *Tcl_GetObjectClassName(Tcl_Interp *interp, Tcl_Object object) } +declare 32 { + int Tcl_MethodIsType2(Tcl_Method method, const Tcl_MethodType2 *typePtr, + void **clientDataPtr) +} +declare 33 { + Tcl_Method Tcl_NewInstanceMethod2(Tcl_Interp *interp, Tcl_Object object, + Tcl_Obj *nameObj, int flags, const Tcl_MethodType2 *typePtr, + void *clientData) +} +declare 34 { + Tcl_Method Tcl_NewMethod2(Tcl_Interp *interp, Tcl_Class cls, + Tcl_Obj *nameObj, int flags, const Tcl_MethodType2 *typePtr, + void *clientData) +} ###################################################################### # Private API, exposed to support advanced OO systems that plug in on top of diff --git a/generic/tclOO.h b/generic/tclOO.h index 9c1dd1e..0ddb13c 100644 --- a/generic/tclOO.h +++ b/generic/tclOO.h @@ -62,6 +62,8 @@ typedef struct Tcl_ObjectContext_ *Tcl_ObjectContext; typedef int (Tcl_MethodCallProc)(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext, int objc, Tcl_Obj *const *objv); +typedef int (Tcl_MethodCallProc2)(ClientData clientData, Tcl_Interp *interp, + Tcl_ObjectContext objectContext, size_t objc, Tcl_Obj *const *objv); typedef void (Tcl_MethodDeleteProc)(ClientData clientData); typedef int (Tcl_CloneProc)(Tcl_Interp *interp, ClientData oldClientData, ClientData *newClientData); @@ -77,7 +79,7 @@ typedef int (Tcl_ObjectMapMethodNameProc)(Tcl_Interp *interp, typedef struct { int version; /* Structure version field. Always to be equal - * to TCL_OO_METHOD_VERSION_CURRENT in + * to TCL_OO_METHOD_VERSION_(1|CURRENT) in * declarations. */ const char *name; /* Name of this type of method, mostly for * debugging purposes. */ @@ -92,12 +94,31 @@ typedef struct { * be copied directly. */ } Tcl_MethodType; +typedef struct { + int version; /* Structure version field. Always to be equal + * to TCL_OO_METHOD_VERSION_2 in + * declarations. */ + const char *name; /* Name of this type of method, mostly for + * debugging purposes. */ + Tcl_MethodCallProc2 *callProc; + /* How to invoke this method. */ + Tcl_MethodDeleteProc *deleteProc; + /* How to delete this method's type-specific + * data, or NULL if the type-specific data + * does not need deleting. */ + Tcl_CloneProc *cloneProc; /* How to copy this method's type-specific + * data, or NULL if the type-specific data can + * be copied directly. */ +} Tcl_MethodType2; + /* * The correct value for the version field of the Tcl_MethodType structure. * This allows new versions of the structure to be introduced without breaking * binary compatability. */ +#define TCL_OO_METHOD_VERSION_1 1 +#define TCL_OO_METHOD_VERSION_2 2 #define TCL_OO_METHOD_VERSION_CURRENT 1 /* diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index d265c1a..5558ab2 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -369,7 +369,11 @@ TclOOInvokeContext( * Run the method implementation. */ - return mPtr->typePtr->callProc(mPtr->clientData, interp, + if (mPtr->typePtr->version == TCL_OO_METHOD_VERSION_1) { + return (mPtr->typePtr->callProc)(mPtr->clientData, interp, + (Tcl_ObjectContext) contextPtr, objc, objv); + } + return ((Tcl_MethodCallProc2 *)(void *)(mPtr->typePtr->callProc))(mPtr->clientData, interp, (Tcl_ObjectContext) contextPtr, objc, objv); } diff --git a/generic/tclOODecls.h b/generic/tclOODecls.h index 3be1e3d..f75d65a 100644 --- a/generic/tclOODecls.h +++ b/generic/tclOODecls.h @@ -123,6 +123,20 @@ TCLAPI Tcl_Class Tcl_GetClassOfObject(Tcl_Object object); /* 31 */ TCLAPI Tcl_Obj * Tcl_GetObjectClassName(Tcl_Interp *interp, Tcl_Object object); +/* 32 */ +TCLAPI int Tcl_MethodIsType2(Tcl_Method method, + const Tcl_MethodType2 *typePtr, + void **clientDataPtr); +/* 33 */ +TCLAPI Tcl_Method Tcl_NewInstanceMethod2(Tcl_Interp *interp, + Tcl_Object object, Tcl_Obj *nameObj, + int flags, const Tcl_MethodType2 *typePtr, + void *clientData); +/* 34 */ +TCLAPI Tcl_Method Tcl_NewMethod2(Tcl_Interp *interp, Tcl_Class cls, + Tcl_Obj *nameObj, int flags, + const Tcl_MethodType2 *typePtr, + void *clientData); typedef struct { const struct TclOOIntStubs *tclOOIntStubs; @@ -164,6 +178,9 @@ typedef struct TclOOStubs { int (*tcl_MethodIsPrivate) (Tcl_Method method); /* 29 */ Tcl_Class (*tcl_GetClassOfObject) (Tcl_Object object); /* 30 */ Tcl_Obj * (*tcl_GetObjectClassName) (Tcl_Interp *interp, Tcl_Object object); /* 31 */ + int (*tcl_MethodIsType2) (Tcl_Method method, const Tcl_MethodType2 *typePtr, void **clientDataPtr); /* 32 */ + Tcl_Method (*tcl_NewInstanceMethod2) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int flags, const Tcl_MethodType2 *typePtr, void *clientData); /* 33 */ + Tcl_Method (*tcl_NewMethod2) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int flags, const Tcl_MethodType2 *typePtr, void *clientData); /* 34 */ } TclOOStubs; extern const TclOOStubs *tclOOStubsPtr; @@ -242,6 +259,12 @@ extern const TclOOStubs *tclOOStubsPtr; (tclOOStubsPtr->tcl_GetClassOfObject) /* 30 */ #define Tcl_GetObjectClassName \ (tclOOStubsPtr->tcl_GetObjectClassName) /* 31 */ +#define Tcl_MethodIsType2 \ + (tclOOStubsPtr->tcl_MethodIsType2) /* 32 */ +#define Tcl_NewInstanceMethod2 \ + (tclOOStubsPtr->tcl_NewInstanceMethod2) /* 33 */ +#define Tcl_NewMethod2 \ + (tclOOStubsPtr->tcl_NewMethod2) /* 34 */ #endif /* defined(USE_TCLOO_STUBS) */ diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index ae1f3bd..29f86d4 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -187,6 +187,28 @@ Tcl_NewInstanceMethod( oPtr->epoch++; return (Tcl_Method) mPtr; } +Tcl_Method +Tcl_NewInstanceMethod2( + TCL_UNUSED(Tcl_Interp *), + Tcl_Object object, /* The object that has the method attached to + * it. */ + Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so, + * up to caller to manage storage (e.g., when + * it is a constructor or destructor). */ + int flags, /* Whether this is a public method. */ + const Tcl_MethodType2 *typePtr, + /* The type of method this is, which defines + * how to invoke, delete and clone the + * method. */ + void *clientData) /* Some data associated with the particular + * method to be created. */ +{ + if (typePtr->version == TCL_OO_METHOD_VERSION_1) { + Tcl_Panic("%s: Wrong version in typePtr->version, should be TCL_OO_METHOD_VERSION_2", "Tcl_NewInstanceMethod2"); + } + return Tcl_NewInstanceMethod(NULL, object, nameObj, flags, + (const Tcl_MethodType *)typePtr, clientData); +} /* * ---------------------------------------------------------------------- @@ -255,6 +277,27 @@ Tcl_NewMethod( return (Tcl_Method) mPtr; } + +Tcl_Method +Tcl_NewMethod2( + TCL_UNUSED(Tcl_Interp *), + Tcl_Class cls, /* The class to attach the method to. */ + Tcl_Obj *nameObj, /* The name of the object. May be NULL (e.g., + * for constructors or destructors); if so, up + * to caller to manage storage. */ + int flags, /* Whether this is a public method. */ + const Tcl_MethodType2 *typePtr, + /* The type of method this is, which defines + * how to invoke, delete and clone the + * method. */ + void *clientData) /* Some data associated with the particular + * method to be created. */ +{ + if (typePtr->version == TCL_OO_METHOD_VERSION_1) { + Tcl_Panic("%s: Wrong version in typePtr->version, should be TCL_OO_METHOD_VERSION_2", "Tcl_NewMethod2"); + } + return Tcl_NewMethod(NULL, cls, nameObj, flags, (const Tcl_MethodType *)typePtr, clientData); +} /* * ---------------------------------------------------------------------- @@ -1689,6 +1732,26 @@ Tcl_MethodIsType( } int +Tcl_MethodIsType2( + Tcl_Method method, + const Tcl_MethodType2 *typePtr, + void **clientDataPtr) +{ + Method *mPtr = (Method *) method; + + if (typePtr->version == TCL_OO_METHOD_VERSION_1) { + Tcl_Panic("%s: Wrong version in typePtr->version, should be TCL_OO_METHOD_VERSION_2", "Tcl_NewInstanceMethod2"); + } + if (mPtr->typePtr == (const Tcl_MethodType *)typePtr) { + if (clientDataPtr != NULL) { + *clientDataPtr = mPtr->clientData; + } + return 1; + } + return 0; +} + +int Tcl_MethodIsPublic( Tcl_Method method) { diff --git a/generic/tclOOStubInit.c b/generic/tclOOStubInit.c index b9034f0..7b653cb 100644 --- a/generic/tclOOStubInit.c +++ b/generic/tclOOStubInit.c @@ -76,6 +76,9 @@ const TclOOStubs tclOOStubs = { Tcl_MethodIsPrivate, /* 29 */ Tcl_GetClassOfObject, /* 30 */ Tcl_GetObjectClassName, /* 31 */ + Tcl_MethodIsType2, /* 32 */ + Tcl_NewInstanceMethod2, /* 33 */ + Tcl_NewMethod2, /* 34 */ }; /* !END!: Do not edit above this line. */ -- cgit v0.12 From e3b234e70992ea1e4ccf0a5b2f7ff56fc7513b3a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 19 Jun 2022 19:32:59 +0000 Subject: Implement Tcl_NRCallObjProc2 --- generic/tcl.decls | 4 ++++ generic/tclBasic.c | 31 +++++++++++++++++++++++++++++++ generic/tclDecls.h | 7 +++++++ generic/tclStubInit.c | 1 + 4 files changed, 43 insertions(+) diff --git a/generic/tcl.decls b/generic/tcl.decls index e2b1db0..dcc0da5 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -2519,6 +2519,10 @@ declare 678 { Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc) } +declare 679 { + int Tcl_NRCallObjProc2(Tcl_Interp *interp, Tcl_ObjCmdProc2 *objProc2, + void *clientData, size_t objc, Tcl_Obj *const objv[]) +} # ----- BASELINE -- FOR -- 8.7.0 ----- # diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 2f09944..063afca 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -9178,6 +9178,37 @@ Tcl_NRCallObjProc( return TclNRRunCallbacks(interp, TCL_OK, rootPtr); } +int wrapperNRObjProc( + void *clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + clientData = info->clientData; + Tcl_ObjCmdProc2 *proc = info->proc; + ckfree(info); + return proc(clientData, interp, objc, objv); +} + +int +Tcl_NRCallObjProc2( + Tcl_Interp *interp, + Tcl_ObjCmdProc2 *objProc, + void *clientData, + size_t objc, + Tcl_Obj *const objv[]) +{ + NRE_callback *rootPtr = TOP_CB(interp); + CmdWrapperInfo *info = (CmdWrapperInfo *)ckalloc(sizeof(CmdWrapperInfo)); + info->clientData = clientData; + info->proc = objProc; + + TclNRAddCallback(interp, Dispatch, wrapperNRObjProc, info, + INT2PTR(objc), objv); + return TclNRRunCallbacks(interp, TCL_OK, rootPtr); +} + /* *---------------------------------------------------------------------- * diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 13abdfd..2a6e62c 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -2007,6 +2007,10 @@ EXTERN Tcl_Command Tcl_NRCreateCommand2(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc, Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); +/* 679 */ +EXTERN int Tcl_NRCallObjProc2(Tcl_Interp *interp, + Tcl_ObjCmdProc2 *objProc2, void *clientData, + size_t objc, Tcl_Obj *const objv[]); typedef struct { const struct TclPlatStubs *tclPlatStubs; @@ -2721,6 +2725,7 @@ typedef struct TclStubs { Tcl_Command (*tcl_CreateObjCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 676 */ Tcl_Trace (*tcl_CreateObjTrace2) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc2 *objProc2, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 677 */ Tcl_Command (*tcl_NRCreateCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc, Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 678 */ + int (*tcl_NRCallObjProc2) (Tcl_Interp *interp, Tcl_ObjCmdProc2 *objProc2, void *clientData, size_t objc, Tcl_Obj *const objv[]); /* 679 */ } TclStubs; extern const TclStubs *tclStubsPtr; @@ -4107,6 +4112,8 @@ extern const TclStubs *tclStubsPtr; (tclStubsPtr->tcl_CreateObjTrace2) /* 677 */ #define Tcl_NRCreateCommand2 \ (tclStubsPtr->tcl_NRCreateCommand2) /* 678 */ +#define Tcl_NRCallObjProc2 \ + (tclStubsPtr->tcl_NRCallObjProc2) /* 679 */ #endif /* defined(USE_TCL_STUBS) */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 22b273b..0052682 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -2038,6 +2038,7 @@ const TclStubs tclStubs = { Tcl_CreateObjCommand2, /* 676 */ Tcl_CreateObjTrace2, /* 677 */ Tcl_NRCreateCommand2, /* 678 */ + Tcl_NRCallObjProc2, /* 679 */ }; /* !END!: Do not edit above this line. */ -- cgit v0.12 From ccabfb8506f946c7cb5f1c38431197e4bdbf42b0 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Jun 2022 10:10:35 +0000 Subject: update doc --- doc/NRE.3 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/NRE.3 b/doc/NRE.3 index 109e3f0..f76938a 100644 --- a/doc/NRE.3 +++ b/doc/NRE.3 @@ -9,7 +9,7 @@ .so man.macros .BS .SH NAME -Tcl_NRCreateCommand, Tcl_NRCallObjProc, Tcl_NREvalObj, Tcl_NREvalObjv, Tcl_NRCmdSwap, Tcl_NRExprObj, Tcl_NRAddCallback \- Non-Recursive (stackless) evaluation of Tcl scripts. +Tcl_NRCreateCommand, Tcl_NRCreateCommand2, Tcl_NRCallObjProc, Tcl_NRCallObjProc2, Tcl_NREvalObj, Tcl_NREvalObjv, Tcl_NRCmdSwap, Tcl_NRExprObj, Tcl_NRAddCallback \- Non-Recursive (stackless) evaluation of Tcl scripts. .SH SYNOPSIS .nf \fB#include \fR @@ -26,6 +26,9 @@ int \fBTcl_NRCallObjProc\fR(\fIinterp, nreProc, clientData, objc, objv\fR) .sp int +\fBTcl_NRCallObjProc2\fR(\fIinterp, nreProc2, clientData, objc, objv\fR) +.sp +int \fBTcl_NREvalObj\fR(\fIinterp, objPtr, flags\fR) .sp int @@ -52,7 +55,10 @@ Called in order to evaluate a command. Is often just a small wrapper that uses in the same way as the \fIproc\fR argument to \fBTcl_CreateObjCommand\fR(3) (\fIq.v.\fR). .AP Tcl_ObjCmdProc2 *proc2 in -Same as \fIproc\fR, but handles more arguments. +Called in order to evaluate a command. Is often just a small wrapper that uses +\fBTcl_NRCallObjProc2\fR to call \fInreProc2\fR using a new trampoline. Behaves +in the same way as the \fIproc2\fR argument to \fBTcl_CreateObjCommand2\fR(3) +(\fIq.v.\fR). .AP Tcl_ObjCmdProc *nreProc in Called instead of \fIproc\fR when a trampoline is already in use. .AP Tcl_ObjCmdProc2 *nreProc2 in -- cgit v0.12 From 7a44e1418d89449aa3c31828d68632c9f5acc9d2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Jun 2022 10:16:02 +0000 Subject: indenting --- generic/tclBasic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 063afca..5501897 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -9184,11 +9184,11 @@ int wrapperNRObjProc( int objc, Tcl_Obj *const objv[]) { - CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; - clientData = info->clientData; - Tcl_ObjCmdProc2 *proc = info->proc; - ckfree(info); - return proc(clientData, interp, objc, objv); + CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + clientData = info->clientData; + Tcl_ObjCmdProc2 *proc = info->proc; + ckfree(info); + return proc(clientData, interp, objc, objv); } int -- cgit v0.12 From d51b6f7045d7043fa3ef9c8de6823a3b524ba50e Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 1 Jul 2022 14:55:42 +0000 Subject: TclOO version -> 1.3.0 --- generic/tclOO.c | 2 +- generic/tclOO.h | 6 +++--- tests/oo.test | 2 +- tests/ooNext2.test | 2 +- tests/ooUtil.test | 2 +- unix/tclooConfig.sh | 2 +- win/tclooConfig.sh | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/generic/tclOO.c b/generic/tclOO.c index 5051659..56423e1 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -137,7 +137,7 @@ static const Tcl_MethodType classConstructor = { * file). */ -static const char *initScript = +static const char initScript[] = #ifndef TCL_NO_DEPRECATED "package ifneeded TclOO " TCLOO_PATCHLEVEL " {# Already present, OK?};" #endif diff --git a/generic/tclOO.h b/generic/tclOO.h index dea1467..6f18491 100644 --- a/generic/tclOO.h +++ b/generic/tclOO.h @@ -24,8 +24,8 @@ * win/tclooConfig.sh */ -#define TCLOO_VERSION "1.2.0" -#define TCLOO_PATCHLEVEL TCLOO_VERSION +#define TCLOO_VERSION "1.3" +#define TCLOO_PATCHLEVEL TCLOO_VERSION ".0" #include "tcl.h" @@ -40,7 +40,7 @@ extern "C" { extern const char *TclOOInitializeStubs( Tcl_Interp *, const char *version); #define Tcl_OOInitStubs(interp) \ - TclOOInitializeStubs((interp), TCLOO_VERSION) + TclOOInitializeStubs((interp), TCLOO_PATCHLEVEL) #ifndef USE_TCL_STUBS # define TclOOInitializeStubs(interp, version) (TCLOO_PATCHLEVEL) #endif diff --git a/tests/oo.test b/tests/oo.test index 168baee..ff67cc1 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -7,7 +7,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require tcl::oo 1.0.3 +package require tcl::oo 1.3.0 if {"::tcltest" ni [namespace children]} { package require tcltest 2.5 namespace import -force ::tcltest::* diff --git a/tests/ooNext2.test b/tests/ooNext2.test index 3d28f3f..746f9a5 100644 --- a/tests/ooNext2.test +++ b/tests/ooNext2.test @@ -7,7 +7,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require tcl::oo 1.0.3 +package require tcl::oo 1.3.0 if {"::tcltest" ni [namespace children]} { package require tcltest 2.5 namespace import -force ::tcltest::* diff --git a/tests/ooUtil.test b/tests/ooUtil.test index 9a28c46..c8be9c8 100644 --- a/tests/ooUtil.test +++ b/tests/ooUtil.test @@ -9,7 +9,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require tcl::oo 1.0.3 +package require tcl::oo 1.3.0 if {"::tcltest" ni [namespace children]} { package require tcltest 2.5 namespace import -force ::tcltest::* diff --git a/unix/tclooConfig.sh b/unix/tclooConfig.sh index 4c2068c..27efbe9 100644 --- a/unix/tclooConfig.sh +++ b/unix/tclooConfig.sh @@ -16,4 +16,4 @@ TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" TCLOO_CFLAGS="" -TCLOO_VERSION=1.2.0 +TCLOO_VERSION=1.3.0 diff --git a/win/tclooConfig.sh b/win/tclooConfig.sh index 4c2068c..27efbe9 100644 --- a/win/tclooConfig.sh +++ b/win/tclooConfig.sh @@ -16,4 +16,4 @@ TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" TCLOO_CFLAGS="" -TCLOO_VERSION=1.2.0 +TCLOO_VERSION=1.3.0 -- cgit v0.12 -- cgit v0.12 From 90b60f208406b3811bad8f7327b663239fd1eea7 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Sat, 6 Aug 2022 03:12:49 +0000 Subject: Added file home command for (possible) Tcl 9 TIP 602 migration --- generic/tclCmdAH.c | 1 + generic/tclFCmd.c | 38 ++++++++ generic/tclInt.h | 7 ++ generic/tclPathObj.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/cmdAH.test | 4 +- tests/fCmd.test | 51 +++++++++++ 6 files changed, 338 insertions(+), 2 deletions(-) diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 28fc210..62c799a 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -1191,6 +1191,7 @@ TclInitFileCmd( {"executable", FileAttrIsExecutableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"exists", FileAttrIsExistingCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"extension", PathExtensionCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, + {"home", TclFileHomeCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"isdirectory", FileAttrIsDirectoryCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"isfile", FileAttrIsFileCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"join", PathJoinCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0}, diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index 6eb6644..747d8a6 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -1650,6 +1650,44 @@ TclFileTempDirCmd( } /* + *---------------------------------------------------------------------- + * + * TclFileHomeCmd -- + * + * This function is invoked to process the "file home" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclFileHomeCmd( + TCL_UNUSED(void *), + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *homeDirObj; + + if (objc != 1 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?user?"); + return TCL_ERROR; + } + homeDirObj = TclGetHomeDirObj(interp, objc == 1 ? NULL : Tcl_GetString(objv[1])); + if (homeDirObj == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, homeDirObj); + return TCL_OK; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tclInt.h b/generic/tclInt.h index ac6fb54..782eadb 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2976,6 +2976,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileHomeCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, @@ -3083,6 +3084,12 @@ MODULE_SCOPE int TclIsDigitProc(int byte); MODULE_SCOPE int TclIsBareword(int byte); MODULE_SCOPE Tcl_Obj * TclJoinPath(int elements, Tcl_Obj * const objv[], int forceRelative); +MODULE_SCOPE int TclGetHomeDir(Tcl_Interp *interp, const char *user, + Tcl_DString *dsPtr); +MODULE_SCOPE Tcl_Obj * TclGetHomeDirObj(Tcl_Interp *interp, const char *user); +MODULE_SCOPE Tcl_Obj * TclResolveTildePath(Tcl_Interp *interp, + Tcl_Obj *pathObj); +MODULE_SCOPE Tcl_Obj * TclResolveTildePathList(Tcl_Obj *pathsObj); MODULE_SCOPE int TclJoinThread(Tcl_ThreadId id, int *result); MODULE_SCOPE void TclLimitRemoveAllHandlers(Tcl_Interp *interp); MODULE_SCOPE Tcl_Obj * TclLindexList(Tcl_Interp *interp, diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 9524f26..bb269de 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -2559,6 +2559,245 @@ TclNativePathInFilesystem( } /* + *---------------------------------------------------------------------- + * + * TclGetHomeDir -- + * + * Returns the home directory of a user. Note there is a difference + * between not specifying a user and explicitly specifying the current + * user. This mimics Tcl8's tilde expansion. + * + * Results: + * Returns TCL_OK on success with home directory path in *dsPtr + * and TCL_ERROR on failure with error message in interp if non-NULL. + * + *---------------------------------------------------------------------- + */ +int +TclGetHomeDir( + Tcl_Interp *interp, /* May be NULL. Only used for error messages */ + const char *user, /* User name. NULL -> current user */ + Tcl_DString *dsPtr) /* Output. Is initialized by the function. Must be + freed on success */ +{ + const char *dir; + Tcl_DString nativeString; + + Tcl_DStringInit(dsPtr); + Tcl_DStringInit(&nativeString); + + if (user == NULL || user[0] == 0) { + /* No user name specified -> current user */ + + dir = TclGetEnv("HOME", &nativeString); + if (dir == NULL) { + if (interp) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "couldn't find HOME environment variable to" + " expand path", -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", + "HOMELESS", NULL); + } + return TCL_ERROR; + } + } else { + /* User name specified - ~user */ + dir = TclpGetUserHome(user, &nativeString); + if (dir == NULL) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "user \"%s\" doesn't exist", user)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "NOUSER", + NULL); + } + return TCL_ERROR; + } + } + Tcl_JoinPath(1, &dir, dsPtr); + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclGetHomeDirObj -- + * + * Wrapper around TclGetHomeDir. See that function. + * + * Results: + * Returns a Tcl_Obj containing the home directory of a user + * or NULL on failure with error message in interp if non-NULL. + * + *---------------------------------------------------------------------- + */ +Tcl_Obj * +TclGetHomeDirObj( + Tcl_Interp *interp, /* May be NULL. Only used for error messages */ + const char *user) /* User name. NULL -> current user */ +{ + Tcl_DString dirString; + + if (TclGetHomeDir(interp, user, &dirString) != TCL_OK) { + return NULL; + } + return TclDStringToObj(&dirString); +} + +/* + *---------------------------------------------------------------------- + * + * TclResolveTildePath -- + * + * If the passed path is begins with a tilde, does tilde resolution + * and returns a Tcl_Obj containing the resolved path. If the tilde + * component cannot be resolved, returns NULL. If the path does not + * begin with a tilde, returns as is. + * + * The trailing components of the path are returned verbatim. No + * processing is done on them. Moreover, no assumptions should be + * made about the separators in the returned path. They may be / + * or native. Appropriate path manipulations functions should be + * used by caller if desired. + * + * Results: + * Returns a Tcl_Obj with resolved path. This may be a new Tcl_Obj + * with ref count 0 or that pathObj that was passed in without its + * ref count modified. + * Returns NULL if the path begins with a ~ that cannot be resolved + * and stores an error message in interp if non-NULL. + * + *---------------------------------------------------------------------- + */ +Tcl_Obj * +TclResolveTildePath( + Tcl_Interp *interp, /* May be NULL. Only used for error messages */ + Tcl_Obj *pathObj) +{ + const char *path; + int len; + Tcl_Obj *resolvedObj; + Tcl_DString dirString; + int split; + + path = Tcl_GetStringFromObj(pathObj, &len); + if (path[0] != '~') { + return pathObj; + } + + /* + * We have multiple cases '~/foo/bar...', '~user/foo/bar...', etc. + * split becomes value 1 for '~/...' as well as for '~'. Note on + * Windows FindSplitPos will implicitly check for '\' as separator + * in addition to what is passed. + */ + split = FindSplitPos(path, '/'); + + if (split == 1) { + /* No user name specified -> current user */ + if (TclGetHomeDir(interp, NULL, &dirString) != TCL_OK) { + return NULL; + } + } else { + /* User name specified - ~user */ + + const char *expandedUser; + Tcl_DString userName; + + Tcl_DStringInit(&userName); + Tcl_DStringAppend(&userName, path+1, split-1); + expandedUser = Tcl_DStringValue(&userName); + + if (TclGetHomeDir(interp, expandedUser, &dirString) != TCL_OK) { + Tcl_DStringFree(&userName); + return NULL; + } + Tcl_DStringFree(&userName); + } + resolvedObj = TclDStringToObj(&dirString); + + if (split < len) { + /* If any trailer, append it verbatim */ + Tcl_AppendToObj(resolvedObj, split + path, len-split); + } + + return resolvedObj; +} + +/* + *---------------------------------------------------------------------- + * + * TclResolveTildePathList -- + * + * Given a Tcl_Obj that is a list of paths, returns a Tcl_Obj containing + * the paths with any ~-prefixed paths resolved. + * + * Empty strings and ~-prefixed paths that cannot be resolved are + * removed from the returned list. + * + * The trailing components of the path are returned verbatim. No + * processing is done on them. Moreover, no assumptions should be + * made about the separators in the returned path. They may be / + * or native. Appropriate path manipulations functions should be + * used by caller if desired. + * + * Results: + * Returns a Tcl_Obj with resolved paths. This may be a new Tcl_Obj with + * reference count 0 or the original passed-in Tcl_Obj if no paths needed + * resolution. A NULL is returned if the passed in value is not a list + * or was NULL. + * + *---------------------------------------------------------------------- + */ +Tcl_Obj * +TclResolveTildePathList( + Tcl_Obj *pathsObj) +{ + Tcl_Obj **objv; + int objc; + int i; + Tcl_Obj *resolvedPaths; + const char *path; + + if (pathsObj == NULL) { + return NULL; + } + if (Tcl_ListObjGetElements(NULL, pathsObj, &objc, &objv) != TCL_OK) { + return NULL; /* Not a list */ + } + + /* + * Figure out if any paths need resolving to avoid unnecessary allocations. + */ + for (i = 0; i < objc; ++i) { + path = Tcl_GetString(objv[i]); + if (path[0] == '~') { + break; /* At least one path needs resolution */ + } + } + if (i == objc) { + return pathsObj; /* No paths needed to be resolved */ + } + + resolvedPaths = Tcl_NewListObj(objc, NULL); + for (i = 0; i < objc; ++i) { + Tcl_Obj *resolvedPath; + path = Tcl_GetString(objv[i]); + if (path[0] == 0) { + continue; /* Skip empty strings */ + } + resolvedPath = TclResolveTildePath(NULL, objv[i]); + if (resolvedPath) { + /* Paths that cannot be resolved are skipped */ + Tcl_ListObjAppendElement(NULL, resolvedPaths, resolvedPath); + } + } + + return resolvedPaths; +} + + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/tests/cmdAH.test b/tests/cmdAH.test index ab1a8e6..3aa9f71 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -355,7 +355,7 @@ test cmdAH-5.1 {Tcl_FileObjCmd} -returnCodes error -body { } -result {wrong # args: should be "file subcommand ?arg ...?"} test cmdAH-5.2 {Tcl_FileObjCmd} -returnCodes error -body { file x -} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} +} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} test cmdAH-5.3 {Tcl_FileObjCmd} -returnCodes error -body { file exists } -result {wrong # args: should be "file exists name"} @@ -1686,7 +1686,7 @@ test cmdAH-29.6.1 { # Error conditions test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file gorp x -} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} +} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file ex x } -match glob -result {unknown or ambiguous subcommand "ex": must be *} diff --git a/tests/fCmd.test b/tests/fCmd.test index 13f3720..72a3cd5 100644 --- a/tests/fCmd.test +++ b/tests/fCmd.test @@ -2556,6 +2556,57 @@ test fCmd-30.3 {file readable on 'pagefile.sys'} -constraints {win notInCIenv} - } return $r } -result {exists 1 readable 0 stat 0 {}} + +test fCmd-31.1 {file home} -body { + file home +} -result [file join $::env(HOME)] +test fCmd-31.2 {file home - obeys env} -setup { + set ::env(HOME) $::env(HOME)/xxx +} -cleanup { + set ::env(HOME) [file dirname $::env(HOME)] +} -body { + file home +} -result [file join $::env(HOME) xxx] +test fCmd-31.3 {file home - \ -> /} -constraints win -setup { + set saved $::env(HOME) + set ::env(HOME) C:\\backslash\\path +} -cleanup { + set ::env(HOME) $saved +} -body { + file home +} -result C:/backslash/path +test fCmd-31.4 {file home - error} -setup { + set saved $::env(HOME) + unset ::env(HOME) +} -cleanup { + set ::env(HOME) $saved +} -body { + file home +} -returnCodes error -result {couldn't find HOME environment variable to expand path} +test fCmd-31.5 { + file home - relative path. Following 8.x ~ expansion behavior, relative + paths are not made absolute +} -setup { + set saved $::env(HOME) + set ::env(HOME) relative/path +} -cleanup { + set ::env(HOME) $saved +} -body { + file home +} -result relative/path +test fCmd-31.6 {file home USER} -body { + # Note - as in 8.x this form does NOT necessarily give same result as + # env(HOME) even when user is current user. Assume result contains user + # name, else not sure how to check + file home $::tcl_platform(user) +} -match glob -result "*$::tcl_platform(user)*" +test fCmd-31.6 {file home UNKNOWNUSER} -body { + file home nosuchuser +} -returnCodes error -result {user "nosuchuser" doesn't exist} +test fCmd-31.7 {file home extra arg} -body { + file home $::tcl_platform(user) arg +} -returnCodes error -result {wrong # args: should be "file home ?user?"} + # cleanup cleanup -- cgit v0.12 From 41e8f7c84390f1ed0ef602aba40544b6b2f383da Mon Sep 17 00:00:00 2001 From: oehhar Date: Thu, 18 Aug 2022 12:03:23 +0000 Subject: Ticket [a11678b759]: improve after documentation for time <= 0. --- doc/after.n | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/after.n b/doc/after.n index 3d0d2c4..1a814e0 100644 --- a/doc/after.n +++ b/doc/after.n @@ -33,6 +33,7 @@ depending on the first argument to the command: \fBafter \fIms\fR . \fIMs\fR must be an integer giving a time in milliseconds. +A negative number is treated as 0. The command sleeps for \fIms\fR milliseconds and then returns. While the command is sleeping the application does not respond to events. @@ -52,6 +53,9 @@ the background error will be reported by the command registered with \fBinterp bgerror\fR. The \fBafter\fR command returns an identifier that can be used to cancel the delayed command using \fBafter cancel\fR. +A \fIms\fR value of 0 (or negative) queues the event immediately with +priority over other event types (if not installed withn an event proc, +which will wait for next round of events). .TP \fBafter cancel \fIid\fR . -- cgit v0.12 From da40e7deb9d3e26315a495419b6ed50f0099bdc7 Mon Sep 17 00:00:00 2001 From: sebres Date: Sat, 20 Aug 2022 10:13:04 +0000 Subject: closes [baa51423c28a3baf]: needEvent must be initialized in cycle (for each watching channel) --- win/tclWinConsole.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 23652de..30a09fd 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -861,21 +861,25 @@ ConsoleCheckProc( handleInfoPtr = FindConsoleInfo(chanInfoPtr); /* Pointer is safe to access as we are holding gConsoleLock */ - if (handleInfoPtr != NULL) { - AcquireSRWLockShared(&handleInfoPtr->lock); - /* Rememebr channel is read or write, never both */ - if (chanInfoPtr->watchMask & TCL_READABLE) { - if (RingBufferLength(&handleInfoPtr->buffer) > 0 - || handleInfoPtr->lastError != ERROR_SUCCESS) { - needEvent = 1; /* Input data available or error/EOF */ - } - } else if (chanInfoPtr->watchMask & TCL_WRITABLE) { - if (RingBufferHasFreeSpace(&handleInfoPtr->buffer)) { - needEvent = 1; /* Output space available */ - } + if (handleInfoPtr == NULL) { + continue; + } + + needEvent = 0; + AcquireSRWLockShared(&handleInfoPtr->lock); + /* Rememebr channel is read or write, never both */ + if (chanInfoPtr->watchMask & TCL_READABLE) { + if (RingBufferLength(&handleInfoPtr->buffer) > 0 + || handleInfoPtr->lastError != ERROR_SUCCESS + ) { + needEvent = 1; /* Input data available or error/EOF */ + } + } else if (chanInfoPtr->watchMask & TCL_WRITABLE) { + if (RingBufferHasFreeSpace(&handleInfoPtr->buffer)) { + needEvent = 1; /* Output space available */ } - ReleaseSRWLockShared(&handleInfoPtr->lock); } + ReleaseSRWLockShared(&handleInfoPtr->lock); if (needEvent) { ConsoleEvent *evPtr = (ConsoleEvent *)ckalloc(sizeof(ConsoleEvent)); -- cgit v0.12 From b00b14a7fd336ad3a98519a59657d143e4ef1ae0 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Sat, 20 Aug 2022 12:16:10 +0000 Subject: Really closes [baa51423c28a3baf] --- win/tclWinConsole.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 30a09fd..0e38c5b 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -862,19 +862,26 @@ ConsoleCheckProc( /* Pointer is safe to access as we are holding gConsoleLock */ if (handleInfoPtr == NULL) { + /* Stale event */ continue; } - + needEvent = 0; AcquireSRWLockShared(&handleInfoPtr->lock); - /* Rememebr channel is read or write, never both */ + /* Rememeber channel is read or write, never both */ if (chanInfoPtr->watchMask & TCL_READABLE) { if (RingBufferLength(&handleInfoPtr->buffer) > 0 - || handleInfoPtr->lastError != ERROR_SUCCESS - ) { + || handleInfoPtr->lastError != ERROR_SUCCESS) { needEvent = 1; /* Input data available or error/EOF */ } - } else if (chanInfoPtr->watchMask & TCL_WRITABLE) { + /* + * TCL_READABLE watch means someone is looking out for data being + * available, let reader thread know. + */ + handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; + WakeConditionVariable(&handleInfoPtr->consoleThreadCV); + } + else if (chanInfoPtr->watchMask & TCL_WRITABLE) { if (RingBufferHasFreeSpace(&handleInfoPtr->buffer)) { needEvent = 1; /* Output space available */ } -- cgit v0.12 From 839d38fbba493c388c1d261f9b47b8b38e2b7cb4 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Sat, 20 Aug 2022 16:56:10 +0000 Subject: Added test for bug [baa51423c2] --- tests/winConsole.test | 46 +++++++++++++++++++++++++++++++++++++++++----- win/tclWinConsole.c | 3 ++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/tests/winConsole.test b/tests/winConsole.test index 0daf54c..821a143 100644 --- a/tests/winConsole.test +++ b/tests/winConsole.test @@ -52,13 +52,21 @@ test console-input-1.0 {Console blocking gets} -constraints {win interactive} -b test console-input-1.1 {Console file channel: non-blocking gets} -constraints { win interactive +} -setup { + unset -nocomplain result + unset -nocomplain result2 } -body { set oldmode [fconfigure stdin] prompt "Type \"abc\" and hit Enter: " fileevent stdin readable { if {[gets stdin line] >= 0} { - set result $line + lappend result2 $line + if {[llength $result2] > 1} { + set result $result2 + } else { + prompt "Type \"def\" and hit Enter: " + } } elseif {[eof stdin]} { set result "gets failed" } @@ -66,7 +74,6 @@ test console-input-1.1 {Console file channel: non-blocking gets} -constraints { fconfigure stdin -blocking 0 -buffering line - set result {} vwait result #cleanup the fileevent @@ -74,7 +81,35 @@ test console-input-1.1 {Console file channel: non-blocking gets} -constraints { fconfigure stdin {*}$oldmode set result -} -result abc +} -result {abc def} + +test console-input-1.1.1 {Bug baa51423c28a: Console file channel: fileevent with blocking gets} -constraints { + win interactive +} -setup { + unset -nocomplain result + unset -nocomplain result2 +} -body { + prompt "Type \"abc\" and hit Enter: " + fileevent stdin readable { + if {[gets stdin line] >= 0} { + lappend result2 $line + if {[llength $result2] > 1} { + set result $result2 + } else { + prompt "Type \"def\" and hit Enter: " + } + } elseif {[eof stdin]} { + set result "gets failed" + } + } + + vwait result + + #cleanup the fileevent + fileevent stdin readable {} + set result + +} -result {abc def} test console-input-2.0 {Console blocking read} -constraints {win interactive} -setup { set oldmode [fconfigure stdin] @@ -94,6 +129,7 @@ test console-input-2.1 {Console file channel: non-blocking read} -constraints { set oldmode [fconfigure stdin] } -cleanup { fconfigure stdin {*}$oldmode + puts ""; # Because CRLF also would not have been echoed } -body { set input "" fconfigure stdin -blocking 0 -buffering line -inputmode raw @@ -262,10 +298,10 @@ test console-fconfigure-set-1.1 { fconfigure stdin -inputmode normal lappend result [yesno "\nWere the characters echoed?"] - prompt "\nType the keys \"c\", Ctrl-H, \"d\" and hit Enter. You should see characters echoed: " + prompt "Type the keys \"c\", Ctrl-H, \"d\" and hit Enter. You should see characters echoed: " lappend result [gets stdin] lappend result [fconfigure stdin -inputmode] - lappend result [yesno "\nWere the characters echoed (c replaced by d)?"] + lappend result [yesno "Were the characters echoed (c replaced by d)?"] set result } -result [list a\x08b raw 0 d normal 1] diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 0e38c5b..4b2d1d3 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -876,7 +876,8 @@ ConsoleCheckProc( } /* * TCL_READABLE watch means someone is looking out for data being - * available, let reader thread know. + * available, let reader thread know. Note channel need not be + * ASYNC! (Bug [baa51423c2]) */ handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; WakeConditionVariable(&handleInfoPtr->consoleThreadCV); -- cgit v0.12 From 02c762f9ec9e806dbd2b392e0f19a035b7da31f2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 21 Aug 2022 20:28:57 +0000 Subject: ClientData -> 'void *" in TclOO headers --- generic/tclOO.h | 10 ++++---- generic/tclOOInt.h | 68 +++++++++++++++++++++++++++--------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/generic/tclOO.h b/generic/tclOO.h index a5c67b3..20dc281 100644 --- a/generic/tclOO.h +++ b/generic/tclOO.h @@ -60,12 +60,12 @@ typedef struct Tcl_ObjectContext_ *Tcl_ObjectContext; * and to allow the attachment of arbitrary data to objects and classes. */ -typedef int (Tcl_MethodCallProc)(ClientData clientData, Tcl_Interp *interp, +typedef int (Tcl_MethodCallProc)(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext, int objc, Tcl_Obj *const *objv); -typedef void (Tcl_MethodDeleteProc)(ClientData clientData); -typedef int (Tcl_CloneProc)(Tcl_Interp *interp, ClientData oldClientData, - ClientData *newClientData); -typedef void (Tcl_ObjectMetadataDeleteProc)(ClientData clientData); +typedef void (Tcl_MethodDeleteProc)(void *clientData); +typedef int (Tcl_CloneProc)(Tcl_Interp *interp, void *oldClientData, + void **newClientData); +typedef void (Tcl_ObjectMetadataDeleteProc)(void *clientData); typedef int (Tcl_ObjectMapMethodNameProc)(Tcl_Interp *interp, Tcl_Object object, Tcl_Class *startClsPtr, Tcl_Obj *methodNameObj); diff --git a/generic/tclOOInt.h b/generic/tclOOInt.h index f061bc6..2931044 100644 --- a/generic/tclOOInt.h +++ b/generic/tclOOInt.h @@ -47,7 +47,7 @@ typedef struct Method { * special flag record which is just used for * the setting of the flags field. */ int refCount; - ClientData clientData; /* Type-specific data. */ + void *clientData; /* Type-specific data. */ Tcl_Obj *namePtr; /* Name of the method. */ struct Object *declaringObjectPtr; /* The object that declares this method, or @@ -65,12 +65,12 @@ typedef struct Method { * tuned in their behaviour. */ -typedef int (TclOO_PreCallProc)(ClientData clientData, Tcl_Interp *interp, +typedef int (TclOO_PreCallProc)(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, Tcl_CallFrame *framePtr, int *isFinished); -typedef int (TclOO_PostCallProc)(ClientData clientData, Tcl_Interp *interp, +typedef int (TclOO_PostCallProc)(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, Tcl_Namespace *namespacePtr, int result); -typedef void (TclOO_PmCDDeleteProc)(ClientData clientData); -typedef ClientData (TclOO_PmCDCloneProc)(ClientData clientData); +typedef void (TclOO_PmCDDeleteProc)(void *clientData); +typedef void *(TclOO_PmCDCloneProc)(void *clientData); /* * Procedure-like methods have the following extra information. @@ -84,7 +84,7 @@ typedef struct ProcedureMethod { * body bytecodes. */ int flags; /* Flags to control features. */ int refCount; - ClientData clientData; + void *clientData; TclOO_PmCDDeleteProc *deleteClientdataProc; TclOO_PmCDCloneProc *cloneClientdataProc; ProcErrorProc *errProc; /* Replacement error handler. */ @@ -368,7 +368,7 @@ typedef struct CallContext { #define PUBLIC_METHOD 0x01 /* This is a public (exported) method. */ #define PRIVATE_METHOD 0x02 /* This is a private (class's direct instances - * only) method. */ + * only) method. Supports itcl. */ #define OO_UNKNOWN_METHOD 0x04 /* This is an unknown method. */ #define CONSTRUCTOR 0x08 /* This is a constructor. */ #define DESTRUCTOR 0x10 /* This is a destructor. */ @@ -390,55 +390,55 @@ typedef struct { */ MODULE_SCOPE int TclOOInit(Tcl_Interp *interp); -MODULE_SCOPE int TclOODefineObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOOObjDefObjCmd(ClientData clientData, +MODULE_SCOPE int TclOOObjDefObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineConstructorObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineConstructorObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineDeleteMethodObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineDeleteMethodObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineDestructorObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineDestructorObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineExportObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineExportObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineForwardObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineForwardObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineMethodObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineMethodObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineRenameMethodObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineRenameMethodObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineUnexportObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineUnexportObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineClassObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineClassObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOODefineSelfObjCmd(ClientData clientData, +MODULE_SCOPE int TclOODefineSelfObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOOUnknownDefinition(ClientData clientData, +MODULE_SCOPE int TclOOUnknownDefinition(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOOCopyObjectCmd(ClientData clientData, +MODULE_SCOPE int TclOOCopyObjectCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOONextObjCmd(ClientData clientData, +MODULE_SCOPE int TclOONextObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOONextToObjCmd(ClientData clientData, +MODULE_SCOPE int TclOONextToObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOOSelfObjCmd(ClientData clientData, +MODULE_SCOPE int TclOOSelfObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); @@ -446,31 +446,31 @@ MODULE_SCOPE int TclOOSelfObjCmd(ClientData clientData, * Method implementations (in tclOOBasic.c). */ -MODULE_SCOPE int TclOO_Class_Constructor(ClientData clientData, +MODULE_SCOPE int TclOO_Class_Constructor(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Class_Create(ClientData clientData, +MODULE_SCOPE int TclOO_Class_Create(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Class_CreateNs(ClientData clientData, +MODULE_SCOPE int TclOO_Class_CreateNs(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Class_New(ClientData clientData, +MODULE_SCOPE int TclOO_Class_New(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Object_Destroy(ClientData clientData, +MODULE_SCOPE int TclOO_Object_Destroy(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Object_Eval(ClientData clientData, +MODULE_SCOPE int TclOO_Object_Eval(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Object_LinkVar(ClientData clientData, +MODULE_SCOPE int TclOO_Object_LinkVar(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Object_Unknown(ClientData clientData, +MODULE_SCOPE int TclOO_Object_Unknown(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -MODULE_SCOPE int TclOO_Object_VarName(ClientData clientData, +MODULE_SCOPE int TclOO_Object_VarName(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); @@ -517,7 +517,7 @@ MODULE_SCOPE int TclOOGetSortedMethodList(Object *oPtr, int flags, const char ***stringsPtr); MODULE_SCOPE int TclOOInit(Tcl_Interp *interp); MODULE_SCOPE void TclOOInitInfo(Tcl_Interp *interp); -MODULE_SCOPE int TclOOInvokeContext(ClientData clientData, +MODULE_SCOPE int TclOOInvokeContext(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclNRObjectContextInvokeNext(Tcl_Interp *interp, -- cgit v0.12 From f8ed9f54314d3f2dc8fe1b157cc7358c9ed7b371 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 21 Aug 2022 20:53:08 +0000 Subject: More type-casts in tclOOMethod.c (backported from 8.7) --- generic/tclOOMethod.c | 131 ++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index 717aa09..c65003f 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -3,7 +3,7 @@ * * This file contains code to create and manage methods. * - * Copyright (c) 2005-2011 by Donal K. Fellows + * Copyright (c) 2005-2011 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -67,7 +67,7 @@ static Tcl_Obj ** InitEnsembleRewrite(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, int toRewrite, int rewriteLength, Tcl_Obj *const *rewriteObjs, int *lengthPtr); -static int InvokeProcedureMethod(ClientData clientData, +static int InvokeProcedureMethod(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); static Tcl_NRPostProc FinalizeForwardCall; @@ -77,22 +77,22 @@ static int PushMethodCallFrame(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, PMFrameData *fdPtr); static void DeleteProcedureMethodRecord(ProcedureMethod *pmPtr); -static void DeleteProcedureMethod(ClientData clientData); +static void DeleteProcedureMethod(void *clientData); static int CloneProcedureMethod(Tcl_Interp *interp, - ClientData clientData, ClientData *newClientData); + void *clientData, void **newClientData); static void MethodErrorHandler(Tcl_Interp *interp, Tcl_Obj *procNameObj); static void ConstructorErrorHandler(Tcl_Interp *interp, Tcl_Obj *procNameObj); static void DestructorErrorHandler(Tcl_Interp *interp, Tcl_Obj *procNameObj); -static Tcl_Obj * RenderDeclarerName(ClientData clientData); -static int InvokeForwardMethod(ClientData clientData, +static Tcl_Obj * RenderDeclarerName(void *clientData); +static int InvokeForwardMethod(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -static void DeleteForwardMethod(ClientData clientData); +static void DeleteForwardMethod(void *clientData); static int CloneForwardMethod(Tcl_Interp *interp, - ClientData clientData, ClientData *newClientData); + void *clientData, void **newClientData); static int ProcedureMethodVarResolver(Tcl_Interp *interp, const char *varName, Tcl_Namespace *contextNs, int flags, Tcl_Var *varPtr); @@ -146,7 +146,7 @@ Tcl_NewInstanceMethod( /* The type of method this is, which defines * how to invoke, delete and clone the * method. */ - ClientData clientData) /* Some data associated with the particular + void *clientData) /* Some data associated with the particular * method to be created. */ { Object *oPtr = (Object *) object; @@ -155,25 +155,25 @@ Tcl_NewInstanceMethod( int isNew; if (nameObj == NULL) { - mPtr = ckalloc(sizeof(Method)); + mPtr = (Method *)ckalloc(sizeof(Method)); mPtr->namePtr = NULL; mPtr->refCount = 1; goto populate; } if (!oPtr->methodsPtr) { - oPtr->methodsPtr = ckalloc(sizeof(Tcl_HashTable)); + oPtr->methodsPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitObjHashTable(oPtr->methodsPtr); oPtr->flags &= ~USE_CLASS_CACHE; } hPtr = Tcl_CreateHashEntry(oPtr->methodsPtr, (char *) nameObj, &isNew); if (isNew) { - mPtr = ckalloc(sizeof(Method)); + mPtr = (Method *)ckalloc(sizeof(Method)); mPtr->namePtr = nameObj; mPtr->refCount = 1; Tcl_IncrRefCount(nameObj); Tcl_SetHashValue(hPtr, mPtr); } else { - mPtr = Tcl_GetHashValue(hPtr); + mPtr = (Method *)Tcl_GetHashValue(hPtr); if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) { mPtr->typePtr->deleteProc(mPtr->clientData); } @@ -214,7 +214,7 @@ Tcl_NewMethod( /* The type of method this is, which defines * how to invoke, delete and clone the * method. */ - ClientData clientData) /* Some data associated with the particular + void *clientData) /* Some data associated with the particular * method to be created. */ { Class *clsPtr = (Class *) cls; @@ -223,20 +223,20 @@ Tcl_NewMethod( int isNew; if (nameObj == NULL) { - mPtr = ckalloc(sizeof(Method)); + mPtr = (Method *)ckalloc(sizeof(Method)); mPtr->namePtr = NULL; mPtr->refCount = 1; goto populate; } hPtr = Tcl_CreateHashEntry(&clsPtr->classMethods, (char *)nameObj,&isNew); if (isNew) { - mPtr = ckalloc(sizeof(Method)); + mPtr = (Method *)ckalloc(sizeof(Method)); mPtr->refCount = 1; mPtr->namePtr = nameObj; Tcl_IncrRefCount(nameObj); Tcl_SetHashValue(hPtr, mPtr); } else { - mPtr = Tcl_GetHashValue(hPtr); + mPtr = (Method *)Tcl_GetHashValue(hPtr); if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) { mPtr->typePtr->deleteProc(mPtr->clientData); } @@ -342,7 +342,7 @@ TclOONewProcInstanceMethod( if (TclListObjLength(interp, argsObj, &argsLen) != TCL_OK) { return NULL; } - pmPtr = ckalloc(sizeof(ProcedureMethod)); + pmPtr = (ProcedureMethod *)ckalloc(sizeof(ProcedureMethod)); memset(pmPtr, 0, sizeof(ProcedureMethod)); pmPtr->version = TCLOO_PROCEDURE_METHOD_VERSION; pmPtr->flags = flags & USE_DECLARER_NS; @@ -403,7 +403,7 @@ TclOONewProcMethod( procName = (nameObj==NULL ? "" : TclGetString(nameObj)); } - pmPtr = ckalloc(sizeof(ProcedureMethod)); + pmPtr = (ProcedureMethod *)ckalloc(sizeof(ProcedureMethod)); memset(pmPtr, 0, sizeof(ProcedureMethod)); pmPtr->version = TCLOO_PROCEDURE_METHOD_VERSION; pmPtr->flags = flags & USE_DECLARER_NS; @@ -450,7 +450,7 @@ TclOOMakeProcInstanceMethod( * NULL. */ const Tcl_MethodType *typePtr, /* The type of the method to create. */ - ClientData clientData, /* The per-method type-specific data. */ + void *clientData, /* The per-method type-specific data. */ Proc **procPtrPtr) /* A pointer to the variable in which to write * the procedure record reference. Presumably * inside the structure indicated by the @@ -497,12 +497,12 @@ TclOOMakeProcInstanceMethod( if (context.line && (context.nline >= 4) && (context.line[3] >= 0)) { int isNew; - CmdFrame *cfPtr = ckalloc(sizeof(CmdFrame)); + CmdFrame *cfPtr = (CmdFrame *)ckalloc(sizeof(CmdFrame)); Tcl_HashEntry *hPtr; cfPtr->level = -1; cfPtr->type = context.type; - cfPtr->line = ckalloc(sizeof(int)); + cfPtr->line = (int *)ckalloc(sizeof(int)); cfPtr->line[0] = context.line[3]; cfPtr->nline = 1; cfPtr->framePtr = NULL; @@ -563,7 +563,7 @@ TclOOMakeProcMethod( * NULL. */ const Tcl_MethodType *typePtr, /* The type of the method to create. */ - ClientData clientData, /* The per-method type-specific data. */ + void *clientData, /* The per-method type-specific data. */ Proc **procPtrPtr) /* A pointer to the variable in which to write * the procedure record reference. Presumably * inside the structure indicated by the @@ -610,12 +610,12 @@ TclOOMakeProcMethod( if (context.line && (context.nline >= 4) && (context.line[3] >= 0)) { int isNew; - CmdFrame *cfPtr = ckalloc(sizeof(CmdFrame)); + CmdFrame *cfPtr = (CmdFrame *)ckalloc(sizeof(CmdFrame)); Tcl_HashEntry *hPtr; cfPtr->level = -1; cfPtr->type = context.type; - cfPtr->line = ckalloc(sizeof(int)); + cfPtr->line = (int *)ckalloc(sizeof(int)); cfPtr->line[0] = context.line[3]; cfPtr->nline = 1; cfPtr->framePtr = NULL; @@ -658,13 +658,13 @@ TclOOMakeProcMethod( static int InvokeProcedureMethod( - ClientData clientData, /* Pointer to some per-method context. */ + void *clientData, /* Pointer to some per-method context. */ Tcl_Interp *interp, Tcl_ObjectContext context, /* The method calling context. */ int objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Arguments as actually seen. */ { - ProcedureMethod *pmPtr = clientData; + ProcedureMethod *pmPtr = (ProcedureMethod *)clientData; int result; PMFrameData *fdPtr; /* Important data that has to have a lifetime * matched by this function (or rather, by the @@ -686,7 +686,7 @@ InvokeProcedureMethod( * Allocate the special frame data. */ - fdPtr = TclStackAlloc(interp, sizeof(PMFrameData)); + fdPtr = (PMFrameData *)TclStackAlloc(interp, sizeof(PMFrameData)); /* * Create a call frame for this method. @@ -739,13 +739,13 @@ InvokeProcedureMethod( static int FinalizePMCall( - ClientData data[], + void *data[], Tcl_Interp *interp, int result) { - ProcedureMethod *pmPtr = data[0]; - Tcl_ObjectContext context = data[1]; - PMFrameData *fdPtr = data[2]; + ProcedureMethod *pmPtr = (ProcedureMethod *)data[0]; + Tcl_ObjectContext context = (Tcl_ObjectContext)data[1]; + PMFrameData *fdPtr = (PMFrameData *)data[2]; /* * Give the post-call callback a chance to do some cleanup. Note that at @@ -999,7 +999,7 @@ ProcedureMethodCompiledVarConnect( if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { return NULL; } - contextPtr = framePtr->clientData; + contextPtr = (CallContext *)framePtr->clientData; /* * If we've done the work before (in a comparable context) then reuse that @@ -1102,7 +1102,7 @@ ProcedureMethodCompiledVarResolver( return TCL_CONTINUE; } - infoPtr = ckalloc(sizeof(OOResVarInfo)); + infoPtr = (OOResVarInfo *)ckalloc(sizeof(OOResVarInfo)); infoPtr->info.fetchProc = ProcedureMethodCompiledVarConnect; infoPtr->info.deleteProc = ProcedureMethodCompiledVarDelete; infoPtr->cachedObjectVar = NULL; @@ -1127,9 +1127,9 @@ ProcedureMethodCompiledVarResolver( static Tcl_Obj * RenderDeclarerName( - ClientData clientData) + void *clientData) { - struct PNI *pni = clientData; + struct PNI *pni = (struct PNI *)clientData; Tcl_Object object = Tcl_MethodDeclarerObject(pni->method); if (object == NULL) { @@ -1163,11 +1163,12 @@ MethodErrorHandler( Tcl_Obj *methodNameObj) { int nameLen, objectNameLen; - CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData; + CallContext *contextPtr = (CallContext *)((Interp *) interp)->varFramePtr->clientData; Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; const char *objectName, *kindName, *methodName = Tcl_GetStringFromObj(mPtr->namePtr, &nameLen); Object *declarerPtr; + (void)methodNameObj;/* We pull the method name out of context instead of from argument */ if (mPtr->declaringObjectPtr != NULL) { declarerPtr = mPtr->declaringObjectPtr; @@ -1193,11 +1194,12 @@ ConstructorErrorHandler( Tcl_Interp *interp, Tcl_Obj *methodNameObj) { - CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData; + CallContext *contextPtr = (CallContext *)((Interp *) interp)->varFramePtr->clientData; Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; Object *declarerPtr; const char *objectName, *kindName; int objectNameLen; + (void)methodNameObj;/* Ignore. We know it is the constructor. */ if (mPtr->declaringObjectPtr != NULL) { declarerPtr = mPtr->declaringObjectPtr; @@ -1222,11 +1224,12 @@ DestructorErrorHandler( Tcl_Interp *interp, Tcl_Obj *methodNameObj) { - CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData; + CallContext *contextPtr = (CallContext *)((Interp *) interp)->varFramePtr->clientData; Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; Object *declarerPtr; const char *objectName, *kindName; int objectNameLen; + (void)methodNameObj; /* Ignore. We know it is the destructor. */ if (mPtr->declaringObjectPtr != NULL) { declarerPtr = mPtr->declaringObjectPtr; @@ -1269,9 +1272,9 @@ DeleteProcedureMethodRecord( static void DeleteProcedureMethod( - ClientData clientData) + void *clientData) { - ProcedureMethod *pmPtr = clientData; + ProcedureMethod *pmPtr = (ProcedureMethod *)clientData; if (pmPtr->refCount-- <= 1) { DeleteProcedureMethodRecord(pmPtr); @@ -1281,10 +1284,10 @@ DeleteProcedureMethod( static int CloneProcedureMethod( Tcl_Interp *interp, - ClientData clientData, - ClientData *newClientData) + void *clientData, + void **newClientData) { - ProcedureMethod *pmPtr = clientData; + ProcedureMethod *pmPtr = (ProcedureMethod *)clientData; ProcedureMethod *pm2Ptr; Tcl_Obj *bodyObj, *argsObj; CompiledLocal *localPtr; @@ -1323,7 +1326,7 @@ CloneProcedureMethod( * record. */ - pm2Ptr = ckalloc(sizeof(ProcedureMethod)); + pm2Ptr = (ProcedureMethod *)ckalloc(sizeof(ProcedureMethod)); memcpy(pm2Ptr, pmPtr, sizeof(ProcedureMethod)); pm2Ptr->refCount = 1; Tcl_IncrRefCount(argsObj); @@ -1377,7 +1380,7 @@ TclOONewForwardInstanceMethod( return NULL; } - fmPtr = ckalloc(sizeof(ForwardMethod)); + fmPtr = (ForwardMethod *)ckalloc(sizeof(ForwardMethod)); fmPtr->prefixObj = prefixObj; Tcl_IncrRefCount(prefixObj); return (Method *) Tcl_NewInstanceMethod(interp, (Tcl_Object) oPtr, @@ -1416,7 +1419,7 @@ TclOONewForwardMethod( return NULL; } - fmPtr = ckalloc(sizeof(ForwardMethod)); + fmPtr = (ForwardMethod *)ckalloc(sizeof(ForwardMethod)); fmPtr->prefixObj = prefixObj; Tcl_IncrRefCount(prefixObj); return (Method *) Tcl_NewMethod(interp, (Tcl_Class) clsPtr, nameObj, @@ -1436,14 +1439,14 @@ TclOONewForwardMethod( static int InvokeForwardMethod( - ClientData clientData, /* Pointer to some per-method context. */ + void *clientData, /* Pointer to some per-method context. */ Tcl_Interp *interp, Tcl_ObjectContext context, /* The method calling context. */ int objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Arguments as actually seen. */ { CallContext *contextPtr = (CallContext *) context; - ForwardMethod *fmPtr = clientData; + ForwardMethod *fmPtr = (ForwardMethod *)clientData; Tcl_Obj **argObjs, **prefixObjs; int numPrefixes, len, skip = contextPtr->skip; @@ -1470,11 +1473,11 @@ InvokeForwardMethod( static int FinalizeForwardCall( - ClientData data[], + void *data[], Tcl_Interp *interp, int result) { - Tcl_Obj **argObjs = data[0]; + Tcl_Obj **argObjs = (Tcl_Obj **)data[0]; TclStackFree(interp, argObjs); return result; @@ -1492,9 +1495,9 @@ FinalizeForwardCall( static void DeleteForwardMethod( - ClientData clientData) + void *clientData) { - ForwardMethod *fmPtr = clientData; + ForwardMethod *fmPtr = (ForwardMethod *)clientData; Tcl_DecrRefCount(fmPtr->prefixObj); ckfree(fmPtr); @@ -1503,11 +1506,11 @@ DeleteForwardMethod( static int CloneForwardMethod( Tcl_Interp *interp, - ClientData clientData, - ClientData *newClientData) + void *clientData, + void **newClientData) { - ForwardMethod *fmPtr = clientData; - ForwardMethod *fm2Ptr = ckalloc(sizeof(ForwardMethod)); + ForwardMethod *fmPtr = (ForwardMethod *)clientData; + ForwardMethod *fm2Ptr = (ForwardMethod *)ckalloc(sizeof(ForwardMethod)); fm2Ptr->prefixObj = fmPtr->prefixObj; Tcl_IncrRefCount(fm2Ptr->prefixObj); @@ -1531,7 +1534,7 @@ TclOOGetProcFromMethod( Method *mPtr) { if (mPtr->typePtr == &procMethodType) { - ProcedureMethod *pmPtr = mPtr->clientData; + ProcedureMethod *pmPtr = (ProcedureMethod *)mPtr->clientData; return pmPtr->procPtr; } @@ -1543,7 +1546,7 @@ TclOOGetMethodBody( Method *mPtr) { if (mPtr->typePtr == &procMethodType) { - ProcedureMethod *pmPtr = mPtr->clientData; + ProcedureMethod *pmPtr = (ProcedureMethod *)mPtr->clientData; if (pmPtr->procPtr->bodyPtr->bytes == NULL) { (void) Tcl_GetString(pmPtr->procPtr->bodyPtr); @@ -1558,7 +1561,7 @@ TclOOGetFwdFromMethod( Method *mPtr) { if (mPtr->typePtr == &fwdMethodType) { - ForwardMethod *fwPtr = mPtr->clientData; + ForwardMethod *fwPtr = (ForwardMethod *)mPtr->clientData; return fwPtr->prefixObj; } @@ -1600,7 +1603,7 @@ InitEnsembleRewrite( * array of rewritten arguments. */ { unsigned len = rewriteLength + objc - toRewrite; - Tcl_Obj **argObjs = TclStackAlloc(interp, sizeof(Tcl_Obj *) * len); + Tcl_Obj **argObjs = (Tcl_Obj **)TclStackAlloc(interp, sizeof(Tcl_Obj *) * len); memcpy(argObjs, rewriteObjs, rewriteLength * sizeof(Tcl_Obj *)); memcpy(argObjs + rewriteLength, objv + toRewrite, @@ -1655,7 +1658,7 @@ int Tcl_MethodIsType( Tcl_Method method, const Tcl_MethodType *typePtr, - ClientData *clientDataPtr) + void **clientDataPtr) { Method *mPtr = (Method *) method; @@ -1686,7 +1689,7 @@ TclOONewProcInstanceMethodEx( TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, - ClientData clientData, + void *clientData, Tcl_Obj *nameObj, /* The name of the method, which must not be * NULL. */ Tcl_Obj *argsObj, /* The formal argument list for the method, @@ -1723,7 +1726,7 @@ TclOONewProcMethodEx( TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, - ClientData clientData, + void *clientData, Tcl_Obj *nameObj, /* The name of the method, which may be NULL; * if so, up to caller to manage storage * (e.g., because it is a constructor or -- cgit v0.12 From e45303142daf39e0a1d4f7e0056c02fcbb3fff5f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 21 Aug 2022 21:00:30 +0000 Subject: Add (dummy) stub entries to TclOO (matching TIP #630) --- generic/tclOO.decls | 24 ++++++++++++------------ generic/tclOODecls.h | 43 ++++++++++++++++++++++++++----------------- generic/tclOOIntDecls.h | 28 ++++++++++++++-------------- generic/tclOOStubInit.c | 5 ++++- 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/generic/tclOO.decls b/generic/tclOO.decls index 8a4fd1e..67b1996 100644 --- a/generic/tclOO.decls +++ b/generic/tclOO.decls @@ -51,7 +51,7 @@ declare 8 { } declare 9 { int Tcl_MethodIsType(Tcl_Method method, const Tcl_MethodType *typePtr, - ClientData *clientDataPtr) + void **clientDataPtr) } declare 10 { Tcl_Obj *Tcl_MethodName(Tcl_Method method) @@ -59,12 +59,12 @@ declare 10 { declare 11 { Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, - ClientData clientData) + void *clientData) } declare 12 { Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, - ClientData clientData) + void *clientData) } declare 13 { Tcl_Object Tcl_NewObjectInstance(Tcl_Interp *interp, Tcl_Class cls, @@ -87,20 +87,20 @@ declare 18 { int Tcl_ObjectContextSkippedArgs(Tcl_ObjectContext context) } declare 19 { - ClientData Tcl_ClassGetMetadata(Tcl_Class clazz, + void *Tcl_ClassGetMetadata(Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr) } declare 20 { void Tcl_ClassSetMetadata(Tcl_Class clazz, - const Tcl_ObjectMetadataType *typePtr, ClientData metadata) + const Tcl_ObjectMetadataType *typePtr, void *metadata) } declare 21 { - ClientData Tcl_ObjectGetMetadata(Tcl_Object object, + void *Tcl_ObjectGetMetadata(Tcl_Object object, const Tcl_ObjectMetadataType *typePtr) } declare 22 { void Tcl_ObjectSetMetadata(Tcl_Object object, - const Tcl_ObjectMetadataType *typePtr, ClientData metadata) + const Tcl_ObjectMetadataType *typePtr, void *metadata) } declare 23 { int Tcl_ObjectContextInvokeNext(Tcl_Interp *interp, @@ -126,7 +126,7 @@ declare 27 { declare 28 { Tcl_Obj *Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object) } -declare 31 { +declare 34 { void TclOOUnusedStubEntry(void) } @@ -144,14 +144,14 @@ declare 0 { declare 1 { Tcl_Method TclOOMakeProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, - const Tcl_MethodType *typePtr, ClientData clientData, + const Tcl_MethodType *typePtr, void *clientData, Proc **procPtrPtr) } declare 2 { Tcl_Method TclOOMakeProcMethod(Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, - ClientData clientData, Proc **procPtrPtr) + void *clientData, Proc **procPtrPtr) } declare 3 { Method *TclOONewProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, @@ -182,13 +182,13 @@ declare 9 { Tcl_Method TclOONewProcInstanceMethodEx(Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, - ClientData clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, + void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr) } declare 10 { Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, - ProcErrorProc *errProc, ClientData clientData, Tcl_Obj *nameObj, + ProcErrorProc *errProc, void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr) } diff --git a/generic/tclOODecls.h b/generic/tclOODecls.h index ead34f7..647bbd5 100644 --- a/generic/tclOODecls.h +++ b/generic/tclOODecls.h @@ -53,19 +53,19 @@ TCLAPI int Tcl_MethodIsPublic(Tcl_Method method); /* 9 */ TCLAPI int Tcl_MethodIsType(Tcl_Method method, const Tcl_MethodType *typePtr, - ClientData *clientDataPtr); + void **clientDataPtr); /* 10 */ TCLAPI Tcl_Obj * Tcl_MethodName(Tcl_Method method); /* 11 */ TCLAPI Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, - ClientData clientData); + void *clientData); /* 12 */ TCLAPI Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, - ClientData clientData); + void *clientData); /* 13 */ TCLAPI Tcl_Object Tcl_NewObjectInstance(Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, @@ -84,19 +84,19 @@ TCLAPI Tcl_Object Tcl_ObjectContextObject(Tcl_ObjectContext context); TCLAPI int Tcl_ObjectContextSkippedArgs( Tcl_ObjectContext context); /* 19 */ -TCLAPI ClientData Tcl_ClassGetMetadata(Tcl_Class clazz, +TCLAPI void * Tcl_ClassGetMetadata(Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr); /* 20 */ TCLAPI void Tcl_ClassSetMetadata(Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr, - ClientData metadata); + void *metadata); /* 21 */ -TCLAPI ClientData Tcl_ObjectGetMetadata(Tcl_Object object, +TCLAPI void * Tcl_ObjectGetMetadata(Tcl_Object object, const Tcl_ObjectMetadataType *typePtr); /* 22 */ TCLAPI void Tcl_ObjectSetMetadata(Tcl_Object object, const Tcl_ObjectMetadataType *typePtr, - ClientData metadata); + void *metadata); /* 23 */ TCLAPI int Tcl_ObjectContextInvokeNext(Tcl_Interp *interp, Tcl_ObjectContext context, int objc, @@ -118,7 +118,10 @@ TCLAPI Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object); /* Slot 29 is reserved */ /* Slot 30 is reserved */ -/* 31 */ +/* Slot 31 is reserved */ +/* Slot 32 is reserved */ +/* Slot 33 is reserved */ +/* 34 */ TCLAPI void TclOOUnusedStubEntry(void); typedef struct { @@ -138,20 +141,20 @@ typedef struct TclOOStubs { Tcl_Class (*tcl_MethodDeclarerClass) (Tcl_Method method); /* 6 */ Tcl_Object (*tcl_MethodDeclarerObject) (Tcl_Method method); /* 7 */ int (*tcl_MethodIsPublic) (Tcl_Method method); /* 8 */ - int (*tcl_MethodIsType) (Tcl_Method method, const Tcl_MethodType *typePtr, ClientData *clientDataPtr); /* 9 */ + int (*tcl_MethodIsType) (Tcl_Method method, const Tcl_MethodType *typePtr, void **clientDataPtr); /* 9 */ Tcl_Obj * (*tcl_MethodName) (Tcl_Method method); /* 10 */ - Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 11 */ - Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */ + Tcl_Method (*tcl_NewInstanceMethod) (Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, void *clientData); /* 11 */ + Tcl_Method (*tcl_NewMethod) (Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, void *clientData); /* 12 */ Tcl_Object (*tcl_NewObjectInstance) (Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, const char *nsNameStr, int objc, Tcl_Obj *const *objv, int skip); /* 13 */ int (*tcl_ObjectDeleted) (Tcl_Object object); /* 14 */ int (*tcl_ObjectContextIsFiltering) (Tcl_ObjectContext context); /* 15 */ Tcl_Method (*tcl_ObjectContextMethod) (Tcl_ObjectContext context); /* 16 */ Tcl_Object (*tcl_ObjectContextObject) (Tcl_ObjectContext context); /* 17 */ int (*tcl_ObjectContextSkippedArgs) (Tcl_ObjectContext context); /* 18 */ - ClientData (*tcl_ClassGetMetadata) (Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr); /* 19 */ - void (*tcl_ClassSetMetadata) (Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr, ClientData metadata); /* 20 */ - ClientData (*tcl_ObjectGetMetadata) (Tcl_Object object, const Tcl_ObjectMetadataType *typePtr); /* 21 */ - void (*tcl_ObjectSetMetadata) (Tcl_Object object, const Tcl_ObjectMetadataType *typePtr, ClientData metadata); /* 22 */ + void * (*tcl_ClassGetMetadata) (Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr); /* 19 */ + void (*tcl_ClassSetMetadata) (Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr, void *metadata); /* 20 */ + void * (*tcl_ObjectGetMetadata) (Tcl_Object object, const Tcl_ObjectMetadataType *typePtr); /* 21 */ + void (*tcl_ObjectSetMetadata) (Tcl_Object object, const Tcl_ObjectMetadataType *typePtr, void *metadata); /* 22 */ int (*tcl_ObjectContextInvokeNext) (Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv, int skip); /* 23 */ Tcl_ObjectMapMethodNameProc * (*tcl_ObjectGetMethodNameMapper) (Tcl_Object object); /* 24 */ void (*tcl_ObjectSetMethodNameMapper) (Tcl_Object object, Tcl_ObjectMapMethodNameProc *mapMethodNameProc); /* 25 */ @@ -160,7 +163,10 @@ typedef struct TclOOStubs { Tcl_Obj * (*tcl_GetObjectName) (Tcl_Interp *interp, Tcl_Object object); /* 28 */ void (*reserved29)(void); void (*reserved30)(void); - void (*tclOOUnusedStubEntry) (void); /* 31 */ + void (*reserved31)(void); + void (*reserved32)(void); + void (*reserved33)(void); + void (*tclOOUnusedStubEntry) (void); /* 34 */ } TclOOStubs; extern const TclOOStubs *tclOOStubsPtr; @@ -235,8 +241,11 @@ extern const TclOOStubs *tclOOStubsPtr; (tclOOStubsPtr->tcl_GetObjectName) /* 28 */ /* Slot 29 is reserved */ /* Slot 30 is reserved */ +/* Slot 31 is reserved */ +/* Slot 32 is reserved */ +/* Slot 33 is reserved */ #define TclOOUnusedStubEntry \ - (tclOOStubsPtr->tclOOUnusedStubEntry) /* 31 */ + (tclOOStubsPtr->tclOOUnusedStubEntry) /* 34 */ #endif /* defined(USE_TCLOO_STUBS) */ diff --git a/generic/tclOOIntDecls.h b/generic/tclOOIntDecls.h index 74a8d81..6a5cfd3 100644 --- a/generic/tclOOIntDecls.h +++ b/generic/tclOOIntDecls.h @@ -22,14 +22,14 @@ TCLAPI Tcl_Method TclOOMakeProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, - ClientData clientData, Proc **procPtrPtr); + void *clientData, Proc **procPtrPtr); /* 2 */ TCLAPI Tcl_Method TclOOMakeProcMethod(Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, - ClientData clientData, Proc **procPtrPtr); + void *clientData, Proc **procPtrPtr); /* 3 */ TCLAPI Method * TclOONewProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, @@ -59,19 +59,19 @@ TCLAPI Tcl_Method TclOONewProcInstanceMethodEx(Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, - ProcErrorProc *errProc, - ClientData clientData, Tcl_Obj *nameObj, - Tcl_Obj *argsObj, Tcl_Obj *bodyObj, - int flags, void **internalTokenPtr); + ProcErrorProc *errProc, void *clientData, + Tcl_Obj *nameObj, Tcl_Obj *argsObj, + Tcl_Obj *bodyObj, int flags, + void **internalTokenPtr); /* 10 */ TCLAPI Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, - ProcErrorProc *errProc, - ClientData clientData, Tcl_Obj *nameObj, - Tcl_Obj *argsObj, Tcl_Obj *bodyObj, - int flags, void **internalTokenPtr); + ProcErrorProc *errProc, void *clientData, + Tcl_Obj *nameObj, Tcl_Obj *argsObj, + Tcl_Obj *bodyObj, int flags, + void **internalTokenPtr); /* 11 */ TCLAPI int TclOOInvokeObject(Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, @@ -97,16 +97,16 @@ typedef struct TclOOIntStubs { void *hooks; Tcl_Object (*tclOOGetDefineCmdContext) (Tcl_Interp *interp); /* 0 */ - Tcl_Method (*tclOOMakeProcInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, ClientData clientData, Proc **procPtrPtr); /* 1 */ - Tcl_Method (*tclOOMakeProcMethod) (Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, ClientData clientData, Proc **procPtrPtr); /* 2 */ + Tcl_Method (*tclOOMakeProcInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, void *clientData, Proc **procPtrPtr); /* 1 */ + Tcl_Method (*tclOOMakeProcMethod) (Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, void *clientData, Proc **procPtrPtr); /* 2 */ Method * (*tclOONewProcInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 3 */ Method * (*tclOONewProcMethod) (Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 4 */ int (*tclOOObjectCmdCore) (Object *oPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls); /* 5 */ int (*tclOOIsReachable) (Class *targetPtr, Class *startPtr); /* 6 */ Method * (*tclOONewForwardMethod) (Tcl_Interp *interp, Class *clsPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 7 */ Method * (*tclOONewForwardInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 8 */ - Tcl_Method (*tclOONewProcInstanceMethodEx) (Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, ClientData clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 9 */ - Tcl_Method (*tclOONewProcMethodEx) (Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, ClientData clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 10 */ + Tcl_Method (*tclOONewProcInstanceMethodEx) (Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 9 */ + Tcl_Method (*tclOONewProcMethodEx) (Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 10 */ int (*tclOOInvokeObject) (Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, int publicPrivate, int objc, Tcl_Obj *const *objv); /* 11 */ void (*tclOOObjectSetFilters) (Object *oPtr, int numFilters, Tcl_Obj *const *filters); /* 12 */ void (*tclOOClassSetFilters) (Tcl_Interp *interp, Class *classPtr, int numFilters, Tcl_Obj *const *filters); /* 13 */ diff --git a/generic/tclOOStubInit.c b/generic/tclOOStubInit.c index e8534eb..735d871 100644 --- a/generic/tclOOStubInit.c +++ b/generic/tclOOStubInit.c @@ -77,7 +77,10 @@ const TclOOStubs tclOOStubs = { Tcl_GetObjectName, /* 28 */ 0, /* 29 */ 0, /* 30 */ - TclOOUnusedStubEntry, /* 31 */ + 0, /* 31 */ + 0, /* 32 */ + 0, /* 33 */ + TclOOUnusedStubEntry, /* 34 */ }; /* !END!: Do not edit above this line. */ -- cgit v0.12 From 267ce5dd65e1d36a209381dc9077ddaa94b6e8e3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 21 Aug 2022 22:34:42 +0000 Subject: ubuntu-18.04 is deprecated --- .github/workflows/onefiledist.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/onefiledist.yml b/.github/workflows/onefiledist.yml index c4212d4..45ce720 100644 --- a/.github/workflows/onefiledist.yml +++ b/.github/workflows/onefiledist.yml @@ -5,7 +5,7 @@ permissions: jobs: linux: name: Linux - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 defaults: run: shell: bash -- cgit v0.12 From 192a96c334f64f1187e9088a912f79970ceab7b3 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Mon, 22 Aug 2022 03:50:43 +0000 Subject: Add two missing locks. Enable read-ahead if read fileevent registered even for blocking console. Account for focus-in events in console buffer. --- win/tclWinConsole.c | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 4b2d1d3..753a572 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -19,8 +19,8 @@ #include /* - * A general note on the design: The console channel driver differs from most - * other drivers in the following respects: + * A general note on the design: The console channel driver differs from + * most other drivers in the following respects: * * - There can be at most 3 console handles at any time since Windows does * support allocation of more than one console (with three handles @@ -35,9 +35,10 @@ * std* channels are shared amongst threads which means there can be * multiple Tcl channels corresponding to a single console handle. * - * - Even with multiple threads, more than one file event handler is unlikely. - * It does not make sense for multiple threads to register handlers for - * stdin because the input would be randomly fragmented amongst the threads. + * - Even with multiple threads, more than one file event handler is + * unlikely. It does not make sense for multiple threads to register + * handlers for stdin because the input would be randomly fragmented amongst + * the threads. * * Various design factors are driven by the above, e.g. use of lists instead * of hash tables (at most 3 console handles) and use of global instead of @@ -55,9 +56,9 @@ * because an interpreter may (for example) turn off echo for passwords and * the read ahead would come in the way of that. * - * If multiple threads are reading from stdin, the input is sprayed in random - * fashion. This is not good application design and hence no plan to address - * this (not clear what should be done even in theory) + * If multiple threads are reading from stdin, the input is sprayed in + * random fashion. This is not good application design and hence no plan to + * address this (not clear what should be done even in theory) * * For output, we do not restrict all output to the console writer threads. * See ConsoleOutputProc for the conditions. @@ -152,7 +153,7 @@ typedef struct ConsoleHandleInfo { * only from the thread owning channel EXCEPT when a console traverses it * looking for a channel that is watching for events on the console. Even * in that case, no locking is required because that access is only under - * the consoleLock lock which prevents the channel from being removed from + * the gConsoleLock lock which prevents the channel from being removed from * the gWatchingChannelList which in turn means it will not be deallocated * from under the console thread. Access to individual fields does not need * to be controlled because @@ -1115,12 +1116,6 @@ ConsoleInputProc( * buffered data, we will pass it up. */ if (numRead != 0) { - /* If console thread was blocked, awaken it */ - if (chanInfoPtr->flags & CONSOLE_ASYNC) { - /* Async channels always want read ahead */ - handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; - WakeConditionVariable(&handleInfoPtr->consoleThreadCV); - } break; } /* @@ -1211,7 +1206,9 @@ ConsoleInputProc( /* Lock is reacquired, loop back to try again */ } - if (chanInfoPtr->flags & CONSOLE_ASYNC) { + /* We read data. Ask for more if either async or watching for reads */ + if ((chanInfoPtr->flags & CONSOLE_ASYNC) + || (chanInfoPtr->watchMask & TCL_READABLE)) { handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; WakeConditionVariable(&handleInfoPtr->consoleThreadCV); } @@ -1345,7 +1342,7 @@ ConsoleOutputProc( } } - /* Lock is reacquired. Continue loop */ + /* Lock must have been reacquired before continuing loop */ } WakeConditionVariable(&handleInfoPtr->consoleThreadCV); ReleaseSRWLockExclusive(&handleInfoPtr->lock); @@ -1511,8 +1508,10 @@ ConsoleWatchProc( ConsoleHandleInfo *handleInfoPtr; handleInfoPtr = FindConsoleInfo(chanInfoPtr); if (handleInfoPtr) { + AcquireSRWLockExclusive(&handleInfoPtr->lock); handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; WakeConditionVariable(&handleInfoPtr->consoleThreadCV); + ReleaseSRWLockExclusive(&handleInfoPtr->lock); } ReleaseSRWLockExclusive(&gConsoleLock); } @@ -1520,6 +1519,7 @@ ConsoleWatchProc( } else if (oldMask) { /* Remove from list of watched channels */ + AcquireSRWLockExclusive(&gConsoleLock); for (nextPtrPtr = &gWatchingChannelList, ptr = *nextPtrPtr; ptr != NULL; nextPtrPtr = &ptr->nextWatchingChannelPtr, ptr = *nextPtrPtr) { @@ -1528,6 +1528,7 @@ ConsoleWatchProc( break; } } + ReleaseSRWLockExclusive(&gConsoleLock); } } @@ -1583,7 +1584,7 @@ ConsoleGetHandleProc( static int ConsoleDataAvailable (HANDLE consoleHandle) { - INPUT_RECORD input[5]; + INPUT_RECORD input[10]; DWORD count; DWORD i; @@ -1595,11 +1596,17 @@ ConsoleGetHandleProc( == FALSE) { return -1; } + /* + * Even if windows size and mouse events are disabled, can still have + * events other than keyboard, like focus events. Look for at least one + * keydown event because a trailing LF keyup is always present from the + * last input. However, if our buffer is full, assume there is a key + * down somewhere in the unread buffer. I suppose we could expand the + * buffer but not worth... + */ + if (count == (sizeof(input)/sizeof(input[0]))) + return 1; for (i = 0; i < count; ++i) { - /* - * Event must be a keydown because a trailing LF keyup event is always - * present for line based input. - */ if (input[i].EventType == KEY_EVENT && input[i].Event.KeyEvent.bKeyDown) { return 1; @@ -1996,6 +2003,7 @@ AllocateConsoleHandleInfo( handleInfoPtr = (ConsoleHandleInfo *)ckalloc(sizeof(*handleInfoPtr)); + memset(handleInfoPtr, 0, sizeof(*handleInfoPtr)); handleInfoPtr->console = consoleHandle; InitializeSRWLock(&handleInfoPtr->lock); InitializeConditionVariable(&handleInfoPtr->consoleThreadCV); -- cgit v0.12 From 25934485e8192cdf5832602923131de652588ffb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Aug 2022 07:22:29 +0000 Subject: ubuntu-18.04 is deprecated --- .github/workflows/linux-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 0bbfbd2..d619507 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -4,7 +4,7 @@ permissions: contents: read jobs: gcc: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: matrix: cfgopt: -- cgit v0.12 From 1baffa9080094e6b95d3ece1f49479ae26c78bec Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Aug 2022 07:29:21 +0000 Subject: Do github actions builds on Ubuntu 22.04 (was: 20.04) --- .github/workflows/linux-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index d5b9c78..01fcdfd 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -4,7 +4,7 @@ permissions: contents: read jobs: gcc: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: cfgopt: -- cgit v0.12 From 7fd9e2f5fdd413114e252c3c3db7546551e309a9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Aug 2022 10:17:38 +0000 Subject: Fix build error in tclTest.c (conflict with TIP #630). Handled deleteProc correctly in Tcl_(Set|Get)CommandInfo. --- generic/tclBasic.c | 35 ++++++++++++++++------------------- generic/tclTest.c | 4 ++-- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index f7f6ed8..645a581 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3377,8 +3377,14 @@ Tcl_SetCommandInfoFromToken( } cmdPtr->objClientData = infoPtr->objClientData; } - cmdPtr->deleteProc = infoPtr->deleteProc; - cmdPtr->deleteData = infoPtr->deleteData; + if (cmdPtr->deleteProc == cmdWrapperDeleteProc) { + CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->deleteData; + info->deleteProc = infoPtr->deleteProc; + info->clientData = infoPtr->deleteData; + } else { + cmdPtr->deleteProc = infoPtr->deleteProc; + cmdPtr->deleteData = infoPtr->deleteData; + } return 1; } @@ -3432,21 +3438,6 @@ Tcl_GetCommandInfo( *---------------------------------------------------------------------- */ -#if TCL_MAJOR_VERSION > 8 || defined(TCL_NO_DEPRECATED) -static int cmdWrapper2Proc(void *clientData, - Tcl_Interp *interp, - size_t objc, - Tcl_Obj *const objv[]) -{ - Command *cmdPtr = (Command *)clientData; - if (objc > INT_MAX) { - Tcl_WrongNumArgs(interp, 1, objv, "?arg ...?"); - return TCL_ERROR; - } - return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv); -} -#endif - int Tcl_GetCommandInfoFromToken( Tcl_Command cmd, @@ -3470,8 +3461,14 @@ Tcl_GetCommandInfoFromToken( infoPtr->objClientData = cmdPtr->objClientData; infoPtr->proc = cmdPtr->proc; infoPtr->clientData = cmdPtr->clientData; - infoPtr->deleteProc = cmdPtr->deleteProc; - infoPtr->deleteData = cmdPtr->deleteData; + if (cmdPtr->deleteProc == cmdWrapperDeleteProc) { + CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->deleteData; + infoPtr->deleteProc = info->deleteProc; + infoPtr->deleteData = info->clientData; + } else { + infoPtr->deleteProc = cmdPtr->deleteProc; + infoPtr->deleteData = cmdPtr->deleteData; + } infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr; return 1; } diff --git a/generic/tclTest.c b/generic/tclTest.c index 3db70fc..7cdd354 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -222,7 +222,7 @@ static Tcl_ObjCmdProc2 TestbytestringObjCmd; static Tcl_ObjCmdProc2 TestsetbytearraylengthObjCmd; static Tcl_ObjCmdProc2 TestpurebytesobjObjCmd; static Tcl_ObjCmdProc2 TeststringbytesObjCmd; -static Tcl_ObjCmdProc Testutf16stringObjCmd; +static Tcl_ObjCmdProc2 Testutf16stringObjCmd; static Tcl_CmdProc TestcmdinfoCmd; static Tcl_CmdProc TestcmdtokenCmd; static Tcl_CmdProc TestcmdtraceCmd; @@ -4039,7 +4039,7 @@ TestregexpObjCmd( Tcl_Obj *newPtr, *varPtr, *valuePtr; varPtr = objv[i]; - ii = ((cflags®_EXPECT) && i == objc-1) ? -1 : i; + ii = ((cflags®_EXPECT) && i == objc-1) ? -1 : (int)i; if (indices) { Tcl_Obj *objs[2]; -- cgit v0.12 From db0b1d30827fba12dba7afb143c0ff8d0daceddd Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 23 Aug 2022 06:32:49 +0000 Subject: Update tzdata to 2022c --- library/tzdata/America/Punta_Arenas | 1 + library/tzdata/America/Santiago | 4 +- library/tzdata/Antarctica/Vostok | 7 +- library/tzdata/Arctic/Longyearbyen | 6 +- library/tzdata/Asia/Brunei | 8 +- library/tzdata/Asia/Ho_Chi_Minh | 4 +- library/tzdata/Asia/Kuala_Lumpur | 14 +- library/tzdata/Asia/Tehran | 165 +---------------- library/tzdata/Atlantic/Jan_Mayen | 6 +- library/tzdata/Atlantic/Reykjavik | 74 +------- library/tzdata/Canada/East-Saskatchewan | 5 - library/tzdata/Europe/Amsterdam | 311 +------------------------------ library/tzdata/Europe/Copenhagen | 265 +------------------------- library/tzdata/Europe/Dublin | 4 +- library/tzdata/Europe/Kiev | 252 +------------------------ library/tzdata/Europe/Luxembourg | 314 +------------------------------ library/tzdata/Europe/Monaco | 316 +------------------------------- library/tzdata/Europe/Oslo | 272 +-------------------------- library/tzdata/Europe/Simferopol | 8 +- library/tzdata/Europe/Stockholm | 251 +------------------------ library/tzdata/Iceland | 6 +- library/tzdata/Indian/Christmas | 7 +- library/tzdata/Indian/Cocos | 7 +- library/tzdata/Indian/Kerguelen | 7 +- library/tzdata/Indian/Mahe | 7 +- library/tzdata/Indian/Reunion | 7 +- library/tzdata/Pacific/Chuuk | 12 +- library/tzdata/Pacific/Easter | 2 +- library/tzdata/Pacific/Funafuti | 7 +- library/tzdata/Pacific/Majuro | 13 +- library/tzdata/Pacific/Pohnpei | 13 +- library/tzdata/Pacific/Ponape | 6 +- library/tzdata/Pacific/Truk | 6 +- library/tzdata/Pacific/Wake | 7 +- library/tzdata/Pacific/Wallis | 7 +- library/tzdata/Pacific/Yap | 6 +- library/tzdata/US/Pacific-New | 5 - 37 files changed, 102 insertions(+), 2310 deletions(-) delete mode 100644 library/tzdata/Canada/East-Saskatchewan delete mode 100644 library/tzdata/US/Pacific-New diff --git a/library/tzdata/America/Punta_Arenas b/library/tzdata/America/Punta_Arenas index 959a0c1..8b06e6a 100644 --- a/library/tzdata/America/Punta_Arenas +++ b/library/tzdata/America/Punta_Arenas @@ -21,6 +21,7 @@ set TZData(:America/Punta_Arenas) { {-1178132400 -14400 0 -04} {-870552000 -18000 0 -05} {-865278000 -14400 0 -04} + {-736632000 -14400 1 -04} {-718056000 -18000 0 -05} {-713649600 -14400 0 -04} {-36619200 -10800 1 -04} diff --git a/library/tzdata/America/Santiago b/library/tzdata/America/Santiago index 801d3f2..13b8b99 100644 --- a/library/tzdata/America/Santiago +++ b/library/tzdata/America/Santiago @@ -22,7 +22,7 @@ set TZData(:America/Santiago) { {-870552000 -18000 0 -05} {-865278000 -14400 0 -04} {-740520000 -10800 1 -03} - {-736376400 -14400 0 -04} + {-736635600 -14400 1 -04} {-718056000 -18000 0 -05} {-713649600 -14400 0 -04} {-36619200 -10800 1 -04} @@ -131,7 +131,7 @@ set TZData(:America/Santiago) { {1617505200 -14400 0 -04} {1630814400 -10800 1 -04} {1648954800 -14400 0 -04} - {1662264000 -10800 1 -04} + {1662868800 -10800 1 -04} {1680404400 -14400 0 -04} {1693713600 -10800 1 -04} {1712458800 -14400 0 -04} diff --git a/library/tzdata/Antarctica/Vostok b/library/tzdata/Antarctica/Vostok index 7f345a2..1a19a5d 100644 --- a/library/tzdata/Antarctica/Vostok +++ b/library/tzdata/Antarctica/Vostok @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Antarctica/Vostok) { - {-9223372036854775808 0 0 -00} - {-380073600 21600 0 +06} +if {![info exists TZData(Asia/Urumqi)]} { + LoadTimeZoneFile Asia/Urumqi } +set TZData(:Antarctica/Vostok) $TZData(:Asia/Urumqi) diff --git a/library/tzdata/Arctic/Longyearbyen b/library/tzdata/Arctic/Longyearbyen index 51f83dc..4b52387 100644 --- a/library/tzdata/Arctic/Longyearbyen +++ b/library/tzdata/Arctic/Longyearbyen @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Europe/Oslo)]} { - LoadTimeZoneFile Europe/Oslo +if {![info exists TZData(Europe/Berlin)]} { + LoadTimeZoneFile Europe/Berlin } -set TZData(:Arctic/Longyearbyen) $TZData(:Europe/Oslo) +set TZData(:Arctic/Longyearbyen) $TZData(:Europe/Berlin) diff --git a/library/tzdata/Asia/Brunei b/library/tzdata/Asia/Brunei index e8cc8c3..ec1a78d 100644 --- a/library/tzdata/Asia/Brunei +++ b/library/tzdata/Asia/Brunei @@ -1,7 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Asia/Brunei) { - {-9223372036854775808 27580 0 LMT} - {-1383464380 27000 0 +0730} - {-1167636600 28800 0 +08} +if {![info exists TZData(Asia/Kuching)]} { + LoadTimeZoneFile Asia/Kuching } +set TZData(:Asia/Brunei) $TZData(:Asia/Kuching) diff --git a/library/tzdata/Asia/Ho_Chi_Minh b/library/tzdata/Asia/Ho_Chi_Minh index b4e749b..4689516 100644 --- a/library/tzdata/Asia/Ho_Chi_Minh +++ b/library/tzdata/Asia/Ho_Chi_Minh @@ -1,8 +1,8 @@ # created by tools/tclZIC.tcl - do not edit set TZData(:Asia/Ho_Chi_Minh) { - {-9223372036854775808 25600 0 LMT} - {-2004073600 25590 0 PLMT} + {-9223372036854775808 25590 0 LMT} + {-2004073590 25590 0 PLMT} {-1851577590 25200 0 +07} {-852105600 28800 0 +08} {-782643600 32400 0 +09} diff --git a/library/tzdata/Asia/Kuala_Lumpur b/library/tzdata/Asia/Kuala_Lumpur index 84eae1d..177539a 100644 --- a/library/tzdata/Asia/Kuala_Lumpur +++ b/library/tzdata/Asia/Kuala_Lumpur @@ -1,13 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Asia/Kuala_Lumpur) { - {-9223372036854775808 24406 0 LMT} - {-2177477206 24925 0 SMT} - {-2038200925 25200 0 +07} - {-1167634800 26400 1 +0720} - {-1073028000 26400 0 +0720} - {-894180000 27000 0 +0730} - {-879665400 32400 0 +09} - {-767005200 27000 0 +0730} - {378664200 28800 0 +08} +if {![info exists TZData(Asia/Singapore)]} { + LoadTimeZoneFile Asia/Singapore } +set TZData(:Asia/Kuala_Lumpur) $TZData(:Asia/Singapore) diff --git a/library/tzdata/Asia/Tehran b/library/tzdata/Asia/Tehran index 4515523..c453c48 100644 --- a/library/tzdata/Asia/Tehran +++ b/library/tzdata/Asia/Tehran @@ -3,12 +3,13 @@ set TZData(:Asia/Tehran) { {-9223372036854775808 12344 0 LMT} {-1704165944 12344 0 TMT} - {-757394744 12600 0 +0330} - {247177800 14400 0 +04} - {259272000 18000 1 +04} - {277758000 14400 0 +04} + {-1090466744 12600 0 +0330} + {227820600 16200 1 +0330} + {246227400 14400 0 +04} + {259617600 18000 1 +04} + {271108800 14400 0 +04} {283982400 12600 0 +0330} - {290809800 16200 1 +0330} + {296598600 16200 1 +0330} {306531000 12600 0 +0330} {322432200 16200 1 +0330} {338499000 12600 0 +0330} @@ -72,158 +73,4 @@ set TZData(:Asia/Tehran) { {1632252600 12600 0 +0330} {1647894600 16200 1 +0330} {1663788600 12600 0 +0330} - {1679430600 16200 1 +0330} - {1695324600 12600 0 +0330} - {1710966600 16200 1 +0330} - {1726860600 12600 0 +0330} - {1742589000 16200 1 +0330} - {1758483000 12600 0 +0330} - {1774125000 16200 1 +0330} - {1790019000 12600 0 +0330} - {1805661000 16200 1 +0330} - {1821555000 12600 0 +0330} - {1837197000 16200 1 +0330} - {1853091000 12600 0 +0330} - {1868733000 16200 1 +0330} - {1884627000 12600 0 +0330} - {1900355400 16200 1 +0330} - {1916249400 12600 0 +0330} - {1931891400 16200 1 +0330} - {1947785400 12600 0 +0330} - {1963427400 16200 1 +0330} - {1979321400 12600 0 +0330} - {1994963400 16200 1 +0330} - {2010857400 12600 0 +0330} - {2026585800 16200 1 +0330} - {2042479800 12600 0 +0330} - {2058121800 16200 1 +0330} - {2074015800 12600 0 +0330} - {2089657800 16200 1 +0330} - {2105551800 12600 0 +0330} - {2121193800 16200 1 +0330} - {2137087800 12600 0 +0330} - {2152816200 16200 1 +0330} - {2168710200 12600 0 +0330} - {2184352200 16200 1 +0330} - {2200246200 12600 0 +0330} - {2215888200 16200 1 +0330} - {2231782200 12600 0 +0330} - {2247424200 16200 1 +0330} - {2263318200 12600 0 +0330} - {2279046600 16200 1 +0330} - {2294940600 12600 0 +0330} - {2310582600 16200 1 +0330} - {2326476600 12600 0 +0330} - {2342118600 16200 1 +0330} - {2358012600 12600 0 +0330} - {2373654600 16200 1 +0330} - {2389548600 12600 0 +0330} - {2405277000 16200 1 +0330} - {2421171000 12600 0 +0330} - {2436813000 16200 1 +0330} - {2452707000 12600 0 +0330} - {2468349000 16200 1 +0330} - {2484243000 12600 0 +0330} - {2499885000 16200 1 +0330} - {2515779000 12600 0 +0330} - {2531507400 16200 1 +0330} - {2547401400 12600 0 +0330} - {2563043400 16200 1 +0330} - {2578937400 12600 0 +0330} - {2594579400 16200 1 +0330} - {2610473400 12600 0 +0330} - {2626115400 16200 1 +0330} - {2642009400 12600 0 +0330} - {2657737800 16200 1 +0330} - {2673631800 12600 0 +0330} - {2689273800 16200 1 +0330} - {2705167800 12600 0 +0330} - {2720809800 16200 1 +0330} - {2736703800 12600 0 +0330} - {2752345800 16200 1 +0330} - {2768239800 12600 0 +0330} - {2783968200 16200 1 +0330} - {2799862200 12600 0 +0330} - {2815504200 16200 1 +0330} - {2831398200 12600 0 +0330} - {2847040200 16200 1 +0330} - {2862934200 12600 0 +0330} - {2878576200 16200 1 +0330} - {2894470200 12600 0 +0330} - {2910112200 16200 1 +0330} - {2926006200 12600 0 +0330} - {2941734600 16200 1 +0330} - {2957628600 12600 0 +0330} - {2973270600 16200 1 +0330} - {2989164600 12600 0 +0330} - {3004806600 16200 1 +0330} - {3020700600 12600 0 +0330} - {3036342600 16200 1 +0330} - {3052236600 12600 0 +0330} - {3067965000 16200 1 +0330} - {3083859000 12600 0 +0330} - {3099501000 16200 1 +0330} - {3115395000 12600 0 +0330} - {3131037000 16200 1 +0330} - {3146931000 12600 0 +0330} - {3162573000 16200 1 +0330} - {3178467000 12600 0 +0330} - {3194195400 16200 1 +0330} - {3210089400 12600 0 +0330} - {3225731400 16200 1 +0330} - {3241625400 12600 0 +0330} - {3257267400 16200 1 +0330} - {3273161400 12600 0 +0330} - {3288803400 16200 1 +0330} - {3304697400 12600 0 +0330} - {3320425800 16200 1 +0330} - {3336319800 12600 0 +0330} - {3351961800 16200 1 +0330} - {3367855800 12600 0 +0330} - {3383497800 16200 1 +0330} - {3399391800 12600 0 +0330} - {3415033800 16200 1 +0330} - {3430927800 12600 0 +0330} - {3446656200 16200 1 +0330} - {3462550200 12600 0 +0330} - {3478192200 16200 1 +0330} - {3494086200 12600 0 +0330} - {3509728200 16200 1 +0330} - {3525622200 12600 0 +0330} - {3541264200 16200 1 +0330} - {3557158200 12600 0 +0330} - {3572886600 16200 1 +0330} - {3588780600 12600 0 +0330} - {3604422600 16200 1 +0330} - {3620316600 12600 0 +0330} - {3635958600 16200 1 +0330} - {3651852600 12600 0 +0330} - {3667494600 16200 1 +0330} - {3683388600 12600 0 +0330} - {3699117000 16200 1 +0330} - {3715011000 12600 0 +0330} - {3730653000 16200 1 +0330} - {3746547000 12600 0 +0330} - {3762189000 16200 1 +0330} - {3778083000 12600 0 +0330} - {3793725000 16200 1 +0330} - {3809619000 12600 0 +0330} - {3825261000 16200 1 +0330} - {3841155000 12600 0 +0330} - {3856883400 16200 1 +0330} - {3872777400 12600 0 +0330} - {3888419400 16200 1 +0330} - {3904313400 12600 0 +0330} - {3919955400 16200 1 +0330} - {3935849400 12600 0 +0330} - {3951491400 16200 1 +0330} - {3967385400 12600 0 +0330} - {3983113800 16200 1 +0330} - {3999007800 12600 0 +0330} - {4014649800 16200 1 +0330} - {4030543800 12600 0 +0330} - {4046185800 16200 1 +0330} - {4062079800 12600 0 +0330} - {4077721800 16200 1 +0330} - {4093615800 12600 0 +0330} } diff --git a/library/tzdata/Atlantic/Jan_Mayen b/library/tzdata/Atlantic/Jan_Mayen index e592187..468d819 100644 --- a/library/tzdata/Atlantic/Jan_Mayen +++ b/library/tzdata/Atlantic/Jan_Mayen @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Europe/Oslo)]} { - LoadTimeZoneFile Europe/Oslo +if {![info exists TZData(Europe/Berlin)]} { + LoadTimeZoneFile Europe/Berlin } -set TZData(:Atlantic/Jan_Mayen) $TZData(:Europe/Oslo) +set TZData(:Atlantic/Jan_Mayen) $TZData(:Europe/Berlin) diff --git a/library/tzdata/Atlantic/Reykjavik b/library/tzdata/Atlantic/Reykjavik index 6270572..3c4a133 100644 --- a/library/tzdata/Atlantic/Reykjavik +++ b/library/tzdata/Atlantic/Reykjavik @@ -1,73 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Atlantic/Reykjavik) { - {-9223372036854775808 -5280 0 LMT} - {-1956609120 -3600 0 -01} - {-1668211200 0 1 -01} - {-1647212400 -3600 0 -01} - {-1636675200 0 1 -01} - {-1613430000 -3600 0 -01} - {-1605139200 0 1 -01} - {-1581894000 -3600 0 -01} - {-1539561600 0 1 -01} - {-1531350000 -3600 0 -01} - {-968025600 0 1 -01} - {-952293600 -3600 0 -01} - {-942008400 0 1 -01} - {-920239200 -3600 0 -01} - {-909957600 0 1 -01} - {-888789600 -3600 0 -01} - {-877903200 0 1 -01} - {-857944800 -3600 0 -01} - {-846453600 0 1 -01} - {-826495200 -3600 0 -01} - {-815004000 0 1 -01} - {-795045600 -3600 0 -01} - {-783554400 0 1 -01} - {-762991200 -3600 0 -01} - {-752104800 0 1 -01} - {-731541600 -3600 0 -01} - {-717631200 0 1 -01} - {-700092000 -3600 0 -01} - {-686181600 0 1 -01} - {-668642400 -3600 0 -01} - {-654732000 0 1 -01} - {-636588000 -3600 0 -01} - {-623282400 0 1 -01} - {-605743200 -3600 0 -01} - {-591832800 0 1 -01} - {-573688800 -3600 0 -01} - {-559778400 0 1 -01} - {-542239200 -3600 0 -01} - {-528328800 0 1 -01} - {-510789600 -3600 0 -01} - {-496879200 0 1 -01} - {-479340000 -3600 0 -01} - {-465429600 0 1 -01} - {-447890400 -3600 0 -01} - {-433980000 0 1 -01} - {-415836000 -3600 0 -01} - {-401925600 0 1 -01} - {-384386400 -3600 0 -01} - {-370476000 0 1 -01} - {-352936800 -3600 0 -01} - {-339026400 0 1 -01} - {-321487200 -3600 0 -01} - {-307576800 0 1 -01} - {-290037600 -3600 0 -01} - {-276127200 0 1 -01} - {-258588000 -3600 0 -01} - {-244677600 0 1 -01} - {-226533600 -3600 0 -01} - {-212623200 0 1 -01} - {-195084000 -3600 0 -01} - {-181173600 0 1 -01} - {-163634400 -3600 0 -01} - {-149724000 0 1 -01} - {-132184800 -3600 0 -01} - {-118274400 0 1 -01} - {-100735200 -3600 0 -01} - {-86824800 0 1 -01} - {-68680800 -3600 0 -01} - {-54770400 0 0 GMT} +if {![info exists TZData(Africa/Abidjan)]} { + LoadTimeZoneFile Africa/Abidjan } +set TZData(:Atlantic/Reykjavik) $TZData(:Africa/Abidjan) diff --git a/library/tzdata/Canada/East-Saskatchewan b/library/tzdata/Canada/East-Saskatchewan deleted file mode 100644 index f7e500c..0000000 --- a/library/tzdata/Canada/East-Saskatchewan +++ /dev/null @@ -1,5 +0,0 @@ -# created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(America/Regina)]} { - LoadTimeZoneFile America/Regina -} -set TZData(:Canada/East-Saskatchewan) $TZData(:America/Regina) diff --git a/library/tzdata/Europe/Amsterdam b/library/tzdata/Europe/Amsterdam index b683c99..7fbe3aa 100644 --- a/library/tzdata/Europe/Amsterdam +++ b/library/tzdata/Europe/Amsterdam @@ -1,310 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Amsterdam) { - {-9223372036854775808 1172 0 LMT} - {-4260212372 1172 0 AMT} - {-1693700372 4772 1 NST} - {-1680484772 1172 0 AMT} - {-1663453172 4772 1 NST} - {-1650147572 1172 0 AMT} - {-1633213172 4772 1 NST} - {-1617488372 1172 0 AMT} - {-1601158772 4772 1 NST} - {-1586038772 1172 0 AMT} - {-1569709172 4772 1 NST} - {-1554589172 1172 0 AMT} - {-1538259572 4772 1 NST} - {-1523139572 1172 0 AMT} - {-1507501172 4772 1 NST} - {-1490566772 1172 0 AMT} - {-1470176372 4772 1 NST} - {-1459117172 1172 0 AMT} - {-1443997172 4772 1 NST} - {-1427667572 1172 0 AMT} - {-1406672372 4772 1 NST} - {-1396217972 1172 0 AMT} - {-1376950772 4772 1 NST} - {-1364768372 1172 0 AMT} - {-1345414772 4772 1 NST} - {-1333318772 1172 0 AMT} - {-1313792372 4772 1 NST} - {-1301264372 1172 0 AMT} - {-1282256372 4772 1 NST} - {-1269814772 1172 0 AMT} - {-1250720372 4772 1 NST} - {-1238365172 1172 0 AMT} - {-1219184372 4772 1 NST} - {-1206915572 1172 0 AMT} - {-1186957172 4772 1 NST} - {-1175465972 1172 0 AMT} - {-1156025972 4772 1 NST} - {-1143411572 1172 0 AMT} - {-1124489972 4772 1 NST} - {-1111961972 1172 0 AMT} - {-1092953972 4772 1 NST} - {-1080512372 1172 0 AMT} - {-1061331572 4772 1 NST} - {-1049062772 1172 0 AMT} - {-1029190772 4772 1 NST} - {-1025741972 4800 0 +0120} - {-1017613200 1200 0 +0020} - {-998259600 4800 1 +0120} - {-986163600 1200 0 +0020} - {-966723600 4800 1 +0120} - {-954109200 1200 0 +0020} - {-935022000 7200 0 CEST} - {-857257200 3600 0 CET} - {-844556400 7200 1 CEST} - {-828226800 3600 0 CET} - {-812502000 7200 1 CEST} - {-796777200 3600 0 CET} - {-781052400 7200 0 CEST} - {-766623600 3600 0 CET} - {220921200 3600 0 CET} - {228877200 7200 1 CEST} - {243997200 3600 0 CET} - {260326800 7200 1 CEST} - {276051600 3600 0 CET} - {291776400 7200 1 CEST} - {307501200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Brussels)]} { + LoadTimeZoneFile Europe/Brussels } +set TZData(:Europe/Amsterdam) $TZData(:Europe/Brussels) diff --git a/library/tzdata/Europe/Copenhagen b/library/tzdata/Europe/Copenhagen index c747e58..1b144d1 100644 --- a/library/tzdata/Europe/Copenhagen +++ b/library/tzdata/Europe/Copenhagen @@ -1,264 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Copenhagen) { - {-9223372036854775808 3020 0 LMT} - {-2524524620 3020 0 CMT} - {-2398294220 3600 0 CET} - {-1692496800 7200 1 CEST} - {-1680490800 3600 0 CET} - {-935110800 7200 1 CEST} - {-857257200 3600 0 CET} - {-844556400 7200 1 CEST} - {-828226800 3600 0 CET} - {-812502000 7200 1 CEST} - {-796777200 3600 0 CET} - {-781052400 7200 0 CEST} - {-769388400 3600 0 CET} - {-747010800 7200 1 CEST} - {-736383600 3600 0 CET} - {-715215600 7200 1 CEST} - {-706748400 3600 0 CET} - {-683161200 7200 1 CEST} - {-675298800 3600 0 CET} - {315529200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Berlin)]} { + LoadTimeZoneFile Europe/Berlin } +set TZData(:Europe/Copenhagen) $TZData(:Europe/Berlin) diff --git a/library/tzdata/Europe/Dublin b/library/tzdata/Europe/Dublin index 56afc93..eb0d182 100644 --- a/library/tzdata/Europe/Dublin +++ b/library/tzdata/Europe/Dublin @@ -1,8 +1,8 @@ # created by tools/tclZIC.tcl - do not edit set TZData(:Europe/Dublin) { - {-9223372036854775808 -1500 0 LMT} - {-2821649700 -1521 0 DMT} + {-9223372036854775808 -1521 0 LMT} + {-2821649679 -1521 0 DMT} {-1691962479 2079 1 IST} {-1680471279 0 0 GMT} {-1664143200 3600 1 BST} diff --git a/library/tzdata/Europe/Kiev b/library/tzdata/Europe/Kiev index 8da7061..ac5e50a 100644 --- a/library/tzdata/Europe/Kiev +++ b/library/tzdata/Europe/Kiev @@ -1,251 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Kiev) { - {-9223372036854775808 7324 0 LMT} - {-2840148124 7324 0 KMT} - {-1441159324 7200 0 EET} - {-1247536800 10800 0 MSK} - {-892522800 3600 0 CET} - {-857257200 3600 0 CET} - {-844556400 7200 1 CEST} - {-828226800 3600 0 CET} - {-825382800 10800 0 MSD} - {354920400 14400 1 MSD} - {370728000 10800 0 MSK} - {386456400 14400 1 MSD} - {402264000 10800 0 MSK} - {417992400 14400 1 MSD} - {433800000 10800 0 MSK} - {449614800 14400 1 MSD} - {465346800 10800 0 MSK} - {481071600 14400 1 MSD} - {496796400 10800 0 MSK} - {512521200 14400 1 MSD} - {528246000 10800 0 MSK} - {543970800 14400 1 MSD} - {559695600 10800 0 MSK} - {575420400 14400 1 MSD} - {591145200 10800 0 MSK} - {606870000 14400 1 MSD} - {622594800 10800 0 MSK} - {638319600 14400 1 MSD} - {646786800 10800 1 EEST} - {686102400 7200 0 EET} - {701827200 10800 1 EEST} - {717552000 7200 0 EET} - {733276800 10800 1 EEST} - {749001600 7200 0 EET} - {764726400 10800 1 EEST} - {780451200 7200 0 EET} - {796176000 10800 1 EEST} - {811900800 7200 0 EET} - {828230400 10800 1 EEST} - {831938400 10800 0 EEST} - {846378000 7200 0 EET} - {859683600 10800 1 EEST} - {877827600 7200 0 EET} - {891133200 10800 1 EEST} - {909277200 7200 0 EET} - {922582800 10800 1 EEST} - {941331600 7200 0 EET} - {954032400 10800 1 EEST} - {972781200 7200 0 EET} - {985482000 10800 1 EEST} - {1004230800 7200 0 EET} - {1017536400 10800 1 EEST} - {1035680400 7200 0 EET} - {1048986000 10800 1 EEST} - {1067130000 7200 0 EET} - {1080435600 10800 1 EEST} - {1099184400 7200 0 EET} - {1111885200 10800 1 EEST} - {1130634000 7200 0 EET} - {1143334800 10800 1 EEST} - {1162083600 7200 0 EET} - {1174784400 10800 1 EEST} - {1193533200 7200 0 EET} - {1206838800 10800 1 EEST} - {1224982800 7200 0 EET} - {1238288400 10800 1 EEST} - {1256432400 7200 0 EET} - {1269738000 10800 1 EEST} - {1288486800 7200 0 EET} - {1301187600 10800 1 EEST} - {1319936400 7200 0 EET} - {1332637200 10800 1 EEST} - {1351386000 7200 0 EET} - {1364691600 10800 1 EEST} - {1382835600 7200 0 EET} - {1396141200 10800 1 EEST} - {1414285200 7200 0 EET} - {1427590800 10800 1 EEST} - {1445734800 7200 0 EET} - {1459040400 10800 1 EEST} - {1477789200 7200 0 EET} - {1490490000 10800 1 EEST} - {1509238800 7200 0 EET} - {1521939600 10800 1 EEST} - {1540688400 7200 0 EET} - {1553994000 10800 1 EEST} - {1572138000 7200 0 EET} - {1585443600 10800 1 EEST} - {1603587600 7200 0 EET} - {1616893200 10800 1 EEST} - {1635642000 7200 0 EET} - {1648342800 10800 1 EEST} - {1667091600 7200 0 EET} - {1679792400 10800 1 EEST} - {1698541200 7200 0 EET} - {1711846800 10800 1 EEST} - {1729990800 7200 0 EET} - {1743296400 10800 1 EEST} - {1761440400 7200 0 EET} - {1774746000 10800 1 EEST} - {1792890000 7200 0 EET} - {1806195600 10800 1 EEST} - {1824944400 7200 0 EET} - {1837645200 10800 1 EEST} - {1856394000 7200 0 EET} - {1869094800 10800 1 EEST} - {1887843600 7200 0 EET} - {1901149200 10800 1 EEST} - {1919293200 7200 0 EET} - {1932598800 10800 1 EEST} - {1950742800 7200 0 EET} - {1964048400 10800 1 EEST} - {1982797200 7200 0 EET} - {1995498000 10800 1 EEST} - {2014246800 7200 0 EET} - {2026947600 10800 1 EEST} - {2045696400 7200 0 EET} - {2058397200 10800 1 EEST} - {2077146000 7200 0 EET} - {2090451600 10800 1 EEST} - {2108595600 7200 0 EET} - {2121901200 10800 1 EEST} - {2140045200 7200 0 EET} - {2153350800 10800 1 EEST} - {2172099600 7200 0 EET} - {2184800400 10800 1 EEST} - {2203549200 7200 0 EET} - {2216250000 10800 1 EEST} - {2234998800 7200 0 EET} - {2248304400 10800 1 EEST} - {2266448400 7200 0 EET} - {2279754000 10800 1 EEST} - {2297898000 7200 0 EET} - {2311203600 10800 1 EEST} - {2329347600 7200 0 EET} - {2342653200 10800 1 EEST} - {2361402000 7200 0 EET} - {2374102800 10800 1 EEST} - {2392851600 7200 0 EET} - {2405552400 10800 1 EEST} - {2424301200 7200 0 EET} - {2437606800 10800 1 EEST} - {2455750800 7200 0 EET} - {2469056400 10800 1 EEST} - {2487200400 7200 0 EET} - {2500506000 10800 1 EEST} - {2519254800 7200 0 EET} - {2531955600 10800 1 EEST} - {2550704400 7200 0 EET} - {2563405200 10800 1 EEST} - {2582154000 7200 0 EET} - {2595459600 10800 1 EEST} - {2613603600 7200 0 EET} - {2626909200 10800 1 EEST} - {2645053200 7200 0 EET} - {2658358800 10800 1 EEST} - {2676502800 7200 0 EET} - {2689808400 10800 1 EEST} - {2708557200 7200 0 EET} - {2721258000 10800 1 EEST} - {2740006800 7200 0 EET} - {2752707600 10800 1 EEST} - {2771456400 7200 0 EET} - {2784762000 10800 1 EEST} - {2802906000 7200 0 EET} - {2816211600 10800 1 EEST} - {2834355600 7200 0 EET} - {2847661200 10800 1 EEST} - {2866410000 7200 0 EET} - {2879110800 10800 1 EEST} - {2897859600 7200 0 EET} - {2910560400 10800 1 EEST} - {2929309200 7200 0 EET} - {2942010000 10800 1 EEST} - {2960758800 7200 0 EET} - {2974064400 10800 1 EEST} - {2992208400 7200 0 EET} - {3005514000 10800 1 EEST} - {3023658000 7200 0 EET} - {3036963600 10800 1 EEST} - {3055712400 7200 0 EET} - {3068413200 10800 1 EEST} - {3087162000 7200 0 EET} - {3099862800 10800 1 EEST} - {3118611600 7200 0 EET} - {3131917200 10800 1 EEST} - {3150061200 7200 0 EET} - {3163366800 10800 1 EEST} - {3181510800 7200 0 EET} - {3194816400 10800 1 EEST} - {3212960400 7200 0 EET} - {3226266000 10800 1 EEST} - {3245014800 7200 0 EET} - {3257715600 10800 1 EEST} - {3276464400 7200 0 EET} - {3289165200 10800 1 EEST} - {3307914000 7200 0 EET} - {3321219600 10800 1 EEST} - {3339363600 7200 0 EET} - {3352669200 10800 1 EEST} - {3370813200 7200 0 EET} - {3384118800 10800 1 EEST} - {3402867600 7200 0 EET} - {3415568400 10800 1 EEST} - {3434317200 7200 0 EET} - {3447018000 10800 1 EEST} - {3465766800 7200 0 EET} - {3479072400 10800 1 EEST} - {3497216400 7200 0 EET} - {3510522000 10800 1 EEST} - {3528666000 7200 0 EET} - {3541971600 10800 1 EEST} - {3560115600 7200 0 EET} - {3573421200 10800 1 EEST} - {3592170000 7200 0 EET} - {3604870800 10800 1 EEST} - {3623619600 7200 0 EET} - {3636320400 10800 1 EEST} - {3655069200 7200 0 EET} - {3668374800 10800 1 EEST} - {3686518800 7200 0 EET} - {3699824400 10800 1 EEST} - {3717968400 7200 0 EET} - {3731274000 10800 1 EEST} - {3750022800 7200 0 EET} - {3762723600 10800 1 EEST} - {3781472400 7200 0 EET} - {3794173200 10800 1 EEST} - {3812922000 7200 0 EET} - {3825622800 10800 1 EEST} - {3844371600 7200 0 EET} - {3857677200 10800 1 EEST} - {3875821200 7200 0 EET} - {3889126800 10800 1 EEST} - {3907270800 7200 0 EET} - {3920576400 10800 1 EEST} - {3939325200 7200 0 EET} - {3952026000 10800 1 EEST} - {3970774800 7200 0 EET} - {3983475600 10800 1 EEST} - {4002224400 7200 0 EET} - {4015530000 10800 1 EEST} - {4033674000 7200 0 EET} - {4046979600 10800 1 EEST} - {4065123600 7200 0 EET} - {4078429200 10800 1 EEST} - {4096573200 7200 0 EET} +if {![info exists TZData(Europe/Kyiv)]} { + LoadTimeZoneFile Europe/Kyiv } +set TZData(:Europe/Kiev) $TZData(:Europe/Kyiv) diff --git a/library/tzdata/Europe/Luxembourg b/library/tzdata/Europe/Luxembourg index 2a88c4b..da3ebe2 100644 --- a/library/tzdata/Europe/Luxembourg +++ b/library/tzdata/Europe/Luxembourg @@ -1,313 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Luxembourg) { - {-9223372036854775808 1476 0 LMT} - {-2069713476 3600 0 CET} - {-1692496800 7200 1 CEST} - {-1680483600 3600 0 CET} - {-1662343200 7200 1 CEST} - {-1650157200 3600 0 CET} - {-1632006000 7200 1 CEST} - {-1618700400 3600 0 CET} - {-1612659600 0 0 WET} - {-1604278800 3600 1 WEST} - {-1585519200 0 0 WET} - {-1574038800 3600 1 WEST} - {-1552258800 0 0 WET} - {-1539997200 3600 1 WEST} - {-1520550000 0 0 WET} - {-1507510800 3600 1 WEST} - {-1490572800 0 0 WET} - {-1473642000 3600 1 WEST} - {-1459119600 0 0 WET} - {-1444006800 3600 1 WEST} - {-1427673600 0 0 WET} - {-1411866000 3600 1 WEST} - {-1396224000 0 0 WET} - {-1379293200 3600 1 WEST} - {-1364774400 0 0 WET} - {-1348448400 3600 1 WEST} - {-1333324800 0 0 WET} - {-1316394000 3600 1 WEST} - {-1301270400 0 0 WET} - {-1284339600 3600 1 WEST} - {-1269813600 0 0 WET} - {-1253484000 3600 1 WEST} - {-1238364000 0 0 WET} - {-1221429600 3600 1 WEST} - {-1206914400 0 0 WET} - {-1191189600 3600 1 WEST} - {-1175464800 0 0 WET} - {-1160344800 3600 1 WEST} - {-1143410400 0 0 WET} - {-1127685600 3600 1 WEST} - {-1111960800 0 0 WET} - {-1096840800 3600 1 WEST} - {-1080511200 0 0 WET} - {-1063576800 3600 1 WEST} - {-1049061600 0 0 WET} - {-1033336800 3600 1 WEST} - {-1017612000 0 0 WET} - {-1002492000 3600 1 WEST} - {-986162400 0 0 WET} - {-969228000 3600 1 WEST} - {-950479200 0 0 WET} - {-942012000 3600 1 WEST} - {-935186400 7200 0 WEST} - {-857257200 3600 0 WET} - {-844556400 7200 1 WEST} - {-828226800 3600 0 WET} - {-812502000 7200 1 WEST} - {-797983200 3600 0 CET} - {-781052400 7200 1 CEST} - {-766623600 3600 0 CET} - {-745455600 7200 1 CEST} - {-733273200 3600 0 CET} - {220921200 3600 0 CET} - {228877200 7200 1 CEST} - {243997200 3600 0 CET} - {260326800 7200 1 CEST} - {276051600 3600 0 CET} - {291776400 7200 1 CEST} - {307501200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Brussels)]} { + LoadTimeZoneFile Europe/Brussels } +set TZData(:Europe/Luxembourg) $TZData(:Europe/Brussels) diff --git a/library/tzdata/Europe/Monaco b/library/tzdata/Europe/Monaco index 7428b2f..54f9d27 100644 --- a/library/tzdata/Europe/Monaco +++ b/library/tzdata/Europe/Monaco @@ -1,315 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Monaco) { - {-9223372036854775808 1772 0 LMT} - {-2448318572 561 0 PMT} - {-1854403761 0 0 WET} - {-1689814800 3600 1 WEST} - {-1680397200 0 0 WET} - {-1665363600 3600 1 WEST} - {-1648342800 0 0 WET} - {-1635123600 3600 1 WEST} - {-1616893200 0 0 WET} - {-1604278800 3600 1 WEST} - {-1585443600 0 0 WET} - {-1574038800 3600 1 WEST} - {-1552266000 0 0 WET} - {-1539997200 3600 1 WEST} - {-1520557200 0 0 WET} - {-1507510800 3600 1 WEST} - {-1490576400 0 0 WET} - {-1470618000 3600 1 WEST} - {-1459126800 0 0 WET} - {-1444006800 3600 1 WEST} - {-1427677200 0 0 WET} - {-1411952400 3600 1 WEST} - {-1396227600 0 0 WET} - {-1379293200 3600 1 WEST} - {-1364778000 0 0 WET} - {-1348448400 3600 1 WEST} - {-1333328400 0 0 WET} - {-1316394000 3600 1 WEST} - {-1301274000 0 0 WET} - {-1284339600 3600 1 WEST} - {-1269824400 0 0 WET} - {-1253494800 3600 1 WEST} - {-1238374800 0 0 WET} - {-1221440400 3600 1 WEST} - {-1206925200 0 0 WET} - {-1191200400 3600 1 WEST} - {-1175475600 0 0 WET} - {-1160355600 3600 1 WEST} - {-1143421200 0 0 WET} - {-1127696400 3600 1 WEST} - {-1111971600 0 0 WET} - {-1096851600 3600 1 WEST} - {-1080522000 0 0 WET} - {-1063587600 3600 1 WEST} - {-1049072400 0 0 WET} - {-1033347600 3600 1 WEST} - {-1017622800 0 0 WET} - {-1002502800 3600 1 WEST} - {-986173200 0 0 WET} - {-969238800 3600 1 WEST} - {-950490000 0 0 WET} - {-942012000 3600 1 WEST} - {-904438800 7200 1 WEMT} - {-891136800 3600 1 WEST} - {-877827600 7200 1 WEMT} - {-857257200 3600 1 WEST} - {-844556400 7200 1 WEMT} - {-828226800 3600 1 WEST} - {-812502000 7200 1 WEMT} - {-796266000 3600 1 WEST} - {-781052400 7200 1 WEMT} - {-766616400 3600 0 CET} - {196819200 7200 1 CEST} - {212540400 3600 0 CET} - {220921200 3600 0 CET} - {228877200 7200 1 CEST} - {243997200 3600 0 CET} - {260326800 7200 1 CEST} - {276051600 3600 0 CET} - {291776400 7200 1 CEST} - {307501200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Paris)]} { + LoadTimeZoneFile Europe/Paris } +set TZData(:Europe/Monaco) $TZData(:Europe/Paris) diff --git a/library/tzdata/Europe/Oslo b/library/tzdata/Europe/Oslo index 6787c1e..d6d564d 100644 --- a/library/tzdata/Europe/Oslo +++ b/library/tzdata/Europe/Oslo @@ -1,271 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Oslo) { - {-9223372036854775808 2580 0 LMT} - {-2366757780 3600 0 CET} - {-1691884800 7200 1 CEST} - {-1680573600 3600 0 CET} - {-927511200 7200 0 CEST} - {-857257200 3600 0 CET} - {-844556400 7200 1 CEST} - {-828226800 3600 0 CET} - {-812502000 7200 1 CEST} - {-796777200 3600 0 CET} - {-781052400 7200 0 CEST} - {-765327600 3600 0 CET} - {-340844400 7200 1 CEST} - {-324514800 3600 0 CET} - {-308790000 7200 1 CEST} - {-293065200 3600 0 CET} - {-277340400 7200 1 CEST} - {-261615600 3600 0 CET} - {-245890800 7200 1 CEST} - {-230166000 3600 0 CET} - {-214441200 7200 1 CEST} - {-198716400 3600 0 CET} - {-182991600 7200 1 CEST} - {-166662000 3600 0 CET} - {-147913200 7200 1 CEST} - {-135212400 3600 0 CET} - {315529200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Berlin)]} { + LoadTimeZoneFile Europe/Berlin } +set TZData(:Europe/Oslo) $TZData(:Europe/Berlin) diff --git a/library/tzdata/Europe/Simferopol b/library/tzdata/Europe/Simferopol index e296862..4a5a77f 100644 --- a/library/tzdata/Europe/Simferopol +++ b/library/tzdata/Europe/Simferopol @@ -38,11 +38,11 @@ set TZData(:Europe/Simferopol) { {749001600 7200 0 EET} {764726400 10800 1 EEST} {767743200 14400 0 MSD} - {780436800 10800 0 MSK} - {796165200 14400 1 MSD} - {811886400 10800 0 MSK} + {780447600 10800 0 MSK} + {796172400 14400 1 MSD} + {811897200 10800 0 MSK} {828219600 14400 1 MSD} - {852066000 10800 0 MSK} + {846374400 10800 0 MSK} {859683600 10800 0 EEST} {877827600 7200 0 EET} {891133200 10800 1 EEST} diff --git a/library/tzdata/Europe/Stockholm b/library/tzdata/Europe/Stockholm index b74d327..6b5c55a 100644 --- a/library/tzdata/Europe/Stockholm +++ b/library/tzdata/Europe/Stockholm @@ -1,250 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Europe/Stockholm) { - {-9223372036854775808 4332 0 LMT} - {-2871681132 3614 0 SET} - {-2208992414 3600 0 CET} - {-1692496800 7200 1 CEST} - {-1680483600 3600 0 CET} - {315529200 3600 0 CET} - {323830800 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} - {449024400 7200 1 CEST} - {465354000 3600 0 CET} - {481078800 7200 1 CEST} - {496803600 3600 0 CET} - {512528400 7200 1 CEST} - {528253200 3600 0 CET} - {543978000 7200 1 CEST} - {559702800 3600 0 CET} - {575427600 7200 1 CEST} - {591152400 3600 0 CET} - {606877200 7200 1 CEST} - {622602000 3600 0 CET} - {638326800 7200 1 CEST} - {654656400 3600 0 CET} - {670381200 7200 1 CEST} - {686106000 3600 0 CET} - {701830800 7200 1 CEST} - {717555600 3600 0 CET} - {733280400 7200 1 CEST} - {749005200 3600 0 CET} - {764730000 7200 1 CEST} - {780454800 3600 0 CET} - {796179600 7200 1 CEST} - {811904400 3600 0 CET} - {828234000 7200 1 CEST} - {846378000 3600 0 CET} - {859683600 7200 1 CEST} - {877827600 3600 0 CET} - {891133200 7200 1 CEST} - {909277200 3600 0 CET} - {922582800 7200 1 CEST} - {941331600 3600 0 CET} - {954032400 7200 1 CEST} - {972781200 3600 0 CET} - {985482000 7200 1 CEST} - {1004230800 3600 0 CET} - {1017536400 7200 1 CEST} - {1035680400 3600 0 CET} - {1048986000 7200 1 CEST} - {1067130000 3600 0 CET} - {1080435600 7200 1 CEST} - {1099184400 3600 0 CET} - {1111885200 7200 1 CEST} - {1130634000 3600 0 CET} - {1143334800 7200 1 CEST} - {1162083600 3600 0 CET} - {1174784400 7200 1 CEST} - {1193533200 3600 0 CET} - {1206838800 7200 1 CEST} - {1224982800 3600 0 CET} - {1238288400 7200 1 CEST} - {1256432400 3600 0 CET} - {1269738000 7200 1 CEST} - {1288486800 3600 0 CET} - {1301187600 7200 1 CEST} - {1319936400 3600 0 CET} - {1332637200 7200 1 CEST} - {1351386000 3600 0 CET} - {1364691600 7200 1 CEST} - {1382835600 3600 0 CET} - {1396141200 7200 1 CEST} - {1414285200 3600 0 CET} - {1427590800 7200 1 CEST} - {1445734800 3600 0 CET} - {1459040400 7200 1 CEST} - {1477789200 3600 0 CET} - {1490490000 7200 1 CEST} - {1509238800 3600 0 CET} - {1521939600 7200 1 CEST} - {1540688400 3600 0 CET} - {1553994000 7200 1 CEST} - {1572138000 3600 0 CET} - {1585443600 7200 1 CEST} - {1603587600 3600 0 CET} - {1616893200 7200 1 CEST} - {1635642000 3600 0 CET} - {1648342800 7200 1 CEST} - {1667091600 3600 0 CET} - {1679792400 7200 1 CEST} - {1698541200 3600 0 CET} - {1711846800 7200 1 CEST} - {1729990800 3600 0 CET} - {1743296400 7200 1 CEST} - {1761440400 3600 0 CET} - {1774746000 7200 1 CEST} - {1792890000 3600 0 CET} - {1806195600 7200 1 CEST} - {1824944400 3600 0 CET} - {1837645200 7200 1 CEST} - {1856394000 3600 0 CET} - {1869094800 7200 1 CEST} - {1887843600 3600 0 CET} - {1901149200 7200 1 CEST} - {1919293200 3600 0 CET} - {1932598800 7200 1 CEST} - {1950742800 3600 0 CET} - {1964048400 7200 1 CEST} - {1982797200 3600 0 CET} - {1995498000 7200 1 CEST} - {2014246800 3600 0 CET} - {2026947600 7200 1 CEST} - {2045696400 3600 0 CET} - {2058397200 7200 1 CEST} - {2077146000 3600 0 CET} - {2090451600 7200 1 CEST} - {2108595600 3600 0 CET} - {2121901200 7200 1 CEST} - {2140045200 3600 0 CET} - {2153350800 7200 1 CEST} - {2172099600 3600 0 CET} - {2184800400 7200 1 CEST} - {2203549200 3600 0 CET} - {2216250000 7200 1 CEST} - {2234998800 3600 0 CET} - {2248304400 7200 1 CEST} - {2266448400 3600 0 CET} - {2279754000 7200 1 CEST} - {2297898000 3600 0 CET} - {2311203600 7200 1 CEST} - {2329347600 3600 0 CET} - {2342653200 7200 1 CEST} - {2361402000 3600 0 CET} - {2374102800 7200 1 CEST} - {2392851600 3600 0 CET} - {2405552400 7200 1 CEST} - {2424301200 3600 0 CET} - {2437606800 7200 1 CEST} - {2455750800 3600 0 CET} - {2469056400 7200 1 CEST} - {2487200400 3600 0 CET} - {2500506000 7200 1 CEST} - {2519254800 3600 0 CET} - {2531955600 7200 1 CEST} - {2550704400 3600 0 CET} - {2563405200 7200 1 CEST} - {2582154000 3600 0 CET} - {2595459600 7200 1 CEST} - {2613603600 3600 0 CET} - {2626909200 7200 1 CEST} - {2645053200 3600 0 CET} - {2658358800 7200 1 CEST} - {2676502800 3600 0 CET} - {2689808400 7200 1 CEST} - {2708557200 3600 0 CET} - {2721258000 7200 1 CEST} - {2740006800 3600 0 CET} - {2752707600 7200 1 CEST} - {2771456400 3600 0 CET} - {2784762000 7200 1 CEST} - {2802906000 3600 0 CET} - {2816211600 7200 1 CEST} - {2834355600 3600 0 CET} - {2847661200 7200 1 CEST} - {2866410000 3600 0 CET} - {2879110800 7200 1 CEST} - {2897859600 3600 0 CET} - {2910560400 7200 1 CEST} - {2929309200 3600 0 CET} - {2942010000 7200 1 CEST} - {2960758800 3600 0 CET} - {2974064400 7200 1 CEST} - {2992208400 3600 0 CET} - {3005514000 7200 1 CEST} - {3023658000 3600 0 CET} - {3036963600 7200 1 CEST} - {3055712400 3600 0 CET} - {3068413200 7200 1 CEST} - {3087162000 3600 0 CET} - {3099862800 7200 1 CEST} - {3118611600 3600 0 CET} - {3131917200 7200 1 CEST} - {3150061200 3600 0 CET} - {3163366800 7200 1 CEST} - {3181510800 3600 0 CET} - {3194816400 7200 1 CEST} - {3212960400 3600 0 CET} - {3226266000 7200 1 CEST} - {3245014800 3600 0 CET} - {3257715600 7200 1 CEST} - {3276464400 3600 0 CET} - {3289165200 7200 1 CEST} - {3307914000 3600 0 CET} - {3321219600 7200 1 CEST} - {3339363600 3600 0 CET} - {3352669200 7200 1 CEST} - {3370813200 3600 0 CET} - {3384118800 7200 1 CEST} - {3402867600 3600 0 CET} - {3415568400 7200 1 CEST} - {3434317200 3600 0 CET} - {3447018000 7200 1 CEST} - {3465766800 3600 0 CET} - {3479072400 7200 1 CEST} - {3497216400 3600 0 CET} - {3510522000 7200 1 CEST} - {3528666000 3600 0 CET} - {3541971600 7200 1 CEST} - {3560115600 3600 0 CET} - {3573421200 7200 1 CEST} - {3592170000 3600 0 CET} - {3604870800 7200 1 CEST} - {3623619600 3600 0 CET} - {3636320400 7200 1 CEST} - {3655069200 3600 0 CET} - {3668374800 7200 1 CEST} - {3686518800 3600 0 CET} - {3699824400 7200 1 CEST} - {3717968400 3600 0 CET} - {3731274000 7200 1 CEST} - {3750022800 3600 0 CET} - {3762723600 7200 1 CEST} - {3781472400 3600 0 CET} - {3794173200 7200 1 CEST} - {3812922000 3600 0 CET} - {3825622800 7200 1 CEST} - {3844371600 3600 0 CET} - {3857677200 7200 1 CEST} - {3875821200 3600 0 CET} - {3889126800 7200 1 CEST} - {3907270800 3600 0 CET} - {3920576400 7200 1 CEST} - {3939325200 3600 0 CET} - {3952026000 7200 1 CEST} - {3970774800 3600 0 CET} - {3983475600 7200 1 CEST} - {4002224400 3600 0 CET} - {4015530000 7200 1 CEST} - {4033674000 3600 0 CET} - {4046979600 7200 1 CEST} - {4065123600 3600 0 CET} - {4078429200 7200 1 CEST} - {4096573200 3600 0 CET} +if {![info exists TZData(Europe/Berlin)]} { + LoadTimeZoneFile Europe/Berlin } +set TZData(:Europe/Stockholm) $TZData(:Europe/Berlin) diff --git a/library/tzdata/Iceland b/library/tzdata/Iceland index eb3f3eb..3e7cd0c 100644 --- a/library/tzdata/Iceland +++ b/library/tzdata/Iceland @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Atlantic/Reykjavik)]} { - LoadTimeZoneFile Atlantic/Reykjavik +if {![info exists TZData(Africa/Abidjan)]} { + LoadTimeZoneFile Africa/Abidjan } -set TZData(:Iceland) $TZData(:Atlantic/Reykjavik) +set TZData(:Iceland) $TZData(:Africa/Abidjan) diff --git a/library/tzdata/Indian/Christmas b/library/tzdata/Indian/Christmas index 76f8cbe..dea9f90 100644 --- a/library/tzdata/Indian/Christmas +++ b/library/tzdata/Indian/Christmas @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Indian/Christmas) { - {-9223372036854775808 25372 0 LMT} - {-2364102172 25200 0 +07} +if {![info exists TZData(Asia/Bangkok)]} { + LoadTimeZoneFile Asia/Bangkok } +set TZData(:Indian/Christmas) $TZData(:Asia/Bangkok) diff --git a/library/tzdata/Indian/Cocos b/library/tzdata/Indian/Cocos index 833eb20..cb474c9 100644 --- a/library/tzdata/Indian/Cocos +++ b/library/tzdata/Indian/Cocos @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Indian/Cocos) { - {-9223372036854775808 23260 0 LMT} - {-2209012060 23400 0 +0630} +if {![info exists TZData(Asia/Yangon)]} { + LoadTimeZoneFile Asia/Yangon } +set TZData(:Indian/Cocos) $TZData(:Asia/Yangon) diff --git a/library/tzdata/Indian/Kerguelen b/library/tzdata/Indian/Kerguelen index 93f2d94..b3cbeee 100644 --- a/library/tzdata/Indian/Kerguelen +++ b/library/tzdata/Indian/Kerguelen @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Indian/Kerguelen) { - {-9223372036854775808 0 0 -00} - {-631152000 18000 0 +05} +if {![info exists TZData(Indian/Maldives)]} { + LoadTimeZoneFile Indian/Maldives } +set TZData(:Indian/Kerguelen) $TZData(:Indian/Maldives) diff --git a/library/tzdata/Indian/Mahe b/library/tzdata/Indian/Mahe index dcafc36..3c728d2 100644 --- a/library/tzdata/Indian/Mahe +++ b/library/tzdata/Indian/Mahe @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Indian/Mahe) { - {-9223372036854775808 13308 0 LMT} - {-1988163708 14400 0 +04} +if {![info exists TZData(Asia/Dubai)]} { + LoadTimeZoneFile Asia/Dubai } +set TZData(:Indian/Mahe) $TZData(:Asia/Dubai) diff --git a/library/tzdata/Indian/Reunion b/library/tzdata/Indian/Reunion index aa78dec..14f2320 100644 --- a/library/tzdata/Indian/Reunion +++ b/library/tzdata/Indian/Reunion @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Indian/Reunion) { - {-9223372036854775808 13312 0 LMT} - {-1848886912 14400 0 +04} +if {![info exists TZData(Asia/Dubai)]} { + LoadTimeZoneFile Asia/Dubai } +set TZData(:Indian/Reunion) $TZData(:Asia/Dubai) diff --git a/library/tzdata/Pacific/Chuuk b/library/tzdata/Pacific/Chuuk index ea1cba2..5e2960c 100644 --- a/library/tzdata/Pacific/Chuuk +++ b/library/tzdata/Pacific/Chuuk @@ -1,11 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Chuuk) { - {-9223372036854775808 -49972 0 LMT} - {-3944628428 36428 0 LMT} - {-2177489228 36000 0 +10} - {-1743674400 32400 0 +09} - {-1606813200 36000 0 +10} - {-907408800 32400 0 +09} - {-770634000 36000 0 +10} +if {![info exists TZData(Pacific/Port_Moresby)]} { + LoadTimeZoneFile Pacific/Port_Moresby } +set TZData(:Pacific/Chuuk) $TZData(:Pacific/Port_Moresby) diff --git a/library/tzdata/Pacific/Easter b/library/tzdata/Pacific/Easter index 7a8d525..97e1f4f 100644 --- a/library/tzdata/Pacific/Easter +++ b/library/tzdata/Pacific/Easter @@ -110,7 +110,7 @@ set TZData(:Pacific/Easter) { {1617505200 -21600 0 -06} {1630814400 -18000 1 -06} {1648954800 -21600 0 -06} - {1662264000 -18000 1 -06} + {1662868800 -18000 1 -06} {1680404400 -21600 0 -06} {1693713600 -18000 1 -06} {1712458800 -21600 0 -06} diff --git a/library/tzdata/Pacific/Funafuti b/library/tzdata/Pacific/Funafuti index d806525..d932469 100644 --- a/library/tzdata/Pacific/Funafuti +++ b/library/tzdata/Pacific/Funafuti @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Funafuti) { - {-9223372036854775808 43012 0 LMT} - {-2177495812 43200 0 +12} +if {![info exists TZData(Pacific/Tarawa)]} { + LoadTimeZoneFile Pacific/Tarawa } +set TZData(:Pacific/Funafuti) $TZData(:Pacific/Tarawa) diff --git a/library/tzdata/Pacific/Majuro b/library/tzdata/Pacific/Majuro index a263a62..b30f494 100644 --- a/library/tzdata/Pacific/Majuro +++ b/library/tzdata/Pacific/Majuro @@ -1,12 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Majuro) { - {-9223372036854775808 41088 0 LMT} - {-2177493888 39600 0 +11} - {-1743678000 32400 0 +09} - {-1606813200 39600 0 +11} - {-1041418800 36000 0 +10} - {-907408800 32400 0 +09} - {-818067600 39600 0 +11} - {-7988400 43200 0 +12} +if {![info exists TZData(Pacific/Tarawa)]} { + LoadTimeZoneFile Pacific/Tarawa } +set TZData(:Pacific/Majuro) $TZData(:Pacific/Tarawa) diff --git a/library/tzdata/Pacific/Pohnpei b/library/tzdata/Pacific/Pohnpei index 7d0adf3..a8d9779 100644 --- a/library/tzdata/Pacific/Pohnpei +++ b/library/tzdata/Pacific/Pohnpei @@ -1,12 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Pohnpei) { - {-9223372036854775808 -48428 0 LMT} - {-3944629972 37972 0 LMT} - {-2177490772 39600 0 +11} - {-1743678000 32400 0 +09} - {-1606813200 39600 0 +11} - {-1041418800 36000 0 +10} - {-907408800 32400 0 +09} - {-770634000 39600 0 +11} +if {![info exists TZData(Pacific/Guadalcanal)]} { + LoadTimeZoneFile Pacific/Guadalcanal } +set TZData(:Pacific/Pohnpei) $TZData(:Pacific/Guadalcanal) diff --git a/library/tzdata/Pacific/Ponape b/library/tzdata/Pacific/Ponape index 89644f7..1211f14 100644 --- a/library/tzdata/Pacific/Ponape +++ b/library/tzdata/Pacific/Ponape @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Pacific/Pohnpei)]} { - LoadTimeZoneFile Pacific/Pohnpei +if {![info exists TZData(Pacific/Guadalcanal)]} { + LoadTimeZoneFile Pacific/Guadalcanal } -set TZData(:Pacific/Ponape) $TZData(:Pacific/Pohnpei) +set TZData(:Pacific/Ponape) $TZData(:Pacific/Guadalcanal) diff --git a/library/tzdata/Pacific/Truk b/library/tzdata/Pacific/Truk index c9b1894..7ddbad7 100644 --- a/library/tzdata/Pacific/Truk +++ b/library/tzdata/Pacific/Truk @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Pacific/Chuuk)]} { - LoadTimeZoneFile Pacific/Chuuk +if {![info exists TZData(Pacific/Port_Moresby)]} { + LoadTimeZoneFile Pacific/Port_Moresby } -set TZData(:Pacific/Truk) $TZData(:Pacific/Chuuk) +set TZData(:Pacific/Truk) $TZData(:Pacific/Port_Moresby) diff --git a/library/tzdata/Pacific/Wake b/library/tzdata/Pacific/Wake index 67eab37..945a863 100644 --- a/library/tzdata/Pacific/Wake +++ b/library/tzdata/Pacific/Wake @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Wake) { - {-9223372036854775808 39988 0 LMT} - {-2177492788 43200 0 +12} +if {![info exists TZData(Pacific/Tarawa)]} { + LoadTimeZoneFile Pacific/Tarawa } +set TZData(:Pacific/Wake) $TZData(:Pacific/Tarawa) diff --git a/library/tzdata/Pacific/Wallis b/library/tzdata/Pacific/Wallis index 152e6af..92748f4 100644 --- a/library/tzdata/Pacific/Wallis +++ b/library/tzdata/Pacific/Wallis @@ -1,6 +1,5 @@ # created by tools/tclZIC.tcl - do not edit - -set TZData(:Pacific/Wallis) { - {-9223372036854775808 44120 0 LMT} - {-2177496920 43200 0 +12} +if {![info exists TZData(Pacific/Tarawa)]} { + LoadTimeZoneFile Pacific/Tarawa } +set TZData(:Pacific/Wallis) $TZData(:Pacific/Tarawa) diff --git a/library/tzdata/Pacific/Yap b/library/tzdata/Pacific/Yap index 4931030..f0b6ae7 100644 --- a/library/tzdata/Pacific/Yap +++ b/library/tzdata/Pacific/Yap @@ -1,5 +1,5 @@ # created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(Pacific/Chuuk)]} { - LoadTimeZoneFile Pacific/Chuuk +if {![info exists TZData(Pacific/Port_Moresby)]} { + LoadTimeZoneFile Pacific/Port_Moresby } -set TZData(:Pacific/Yap) $TZData(:Pacific/Chuuk) +set TZData(:Pacific/Yap) $TZData(:Pacific/Port_Moresby) diff --git a/library/tzdata/US/Pacific-New b/library/tzdata/US/Pacific-New deleted file mode 100644 index 2eb30f8..0000000 --- a/library/tzdata/US/Pacific-New +++ /dev/null @@ -1,5 +0,0 @@ -# created by tools/tclZIC.tcl - do not edit -if {![info exists TZData(America/Los_Angeles)]} { - LoadTimeZoneFile America/Los_Angeles -} -set TZData(:US/Pacific-New) $TZData(:America/Los_Angeles) -- cgit v0.12 From 2f8f82a2b16cc444c327e2d3e49d9c858b8270ae Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 23 Aug 2022 06:41:53 +0000 Subject: Add Europe/Kyiv to tzdata (missing from previous commit) --- library/tzdata/Europe/Kyiv | 251 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 library/tzdata/Europe/Kyiv diff --git a/library/tzdata/Europe/Kyiv b/library/tzdata/Europe/Kyiv new file mode 100644 index 0000000..c7c0e2f --- /dev/null +++ b/library/tzdata/Europe/Kyiv @@ -0,0 +1,251 @@ +# created by tools/tclZIC.tcl - do not edit + +set TZData(:Europe/Kyiv) { + {-9223372036854775808 7324 0 LMT} + {-2840148124 7324 0 KMT} + {-1441159324 7200 0 EET} + {-1247536800 10800 0 MSK} + {-892522800 3600 0 CET} + {-857257200 3600 0 CET} + {-844556400 7200 1 CEST} + {-828226800 3600 0 CET} + {-825382800 10800 0 MSD} + {354920400 14400 1 MSD} + {370728000 10800 0 MSK} + {386456400 14400 1 MSD} + {402264000 10800 0 MSK} + {417992400 14400 1 MSD} + {433800000 10800 0 MSK} + {449614800 14400 1 MSD} + {465346800 10800 0 MSK} + {481071600 14400 1 MSD} + {496796400 10800 0 MSK} + {512521200 14400 1 MSD} + {528246000 10800 0 MSK} + {543970800 14400 1 MSD} + {559695600 10800 0 MSK} + {575420400 14400 1 MSD} + {591145200 10800 0 MSK} + {606870000 14400 1 MSD} + {622594800 10800 0 MSK} + {638319600 14400 1 MSD} + {646786800 10800 1 EEST} + {686102400 7200 0 EET} + {701827200 10800 1 EEST} + {717552000 7200 0 EET} + {733276800 10800 1 EEST} + {749001600 7200 0 EET} + {764726400 10800 1 EEST} + {780451200 7200 0 EET} + {796176000 10800 1 EEST} + {811900800 7200 0 EET} + {828230400 10800 1 EEST} + {831938400 10800 0 EEST} + {846378000 7200 0 EET} + {859683600 10800 1 EEST} + {877827600 7200 0 EET} + {891133200 10800 1 EEST} + {909277200 7200 0 EET} + {922582800 10800 1 EEST} + {941331600 7200 0 EET} + {954032400 10800 1 EEST} + {972781200 7200 0 EET} + {985482000 10800 1 EEST} + {1004230800 7200 0 EET} + {1017536400 10800 1 EEST} + {1035680400 7200 0 EET} + {1048986000 10800 1 EEST} + {1067130000 7200 0 EET} + {1080435600 10800 1 EEST} + {1099184400 7200 0 EET} + {1111885200 10800 1 EEST} + {1130634000 7200 0 EET} + {1143334800 10800 1 EEST} + {1162083600 7200 0 EET} + {1174784400 10800 1 EEST} + {1193533200 7200 0 EET} + {1206838800 10800 1 EEST} + {1224982800 7200 0 EET} + {1238288400 10800 1 EEST} + {1256432400 7200 0 EET} + {1269738000 10800 1 EEST} + {1288486800 7200 0 EET} + {1301187600 10800 1 EEST} + {1319936400 7200 0 EET} + {1332637200 10800 1 EEST} + {1351386000 7200 0 EET} + {1364691600 10800 1 EEST} + {1382835600 7200 0 EET} + {1396141200 10800 1 EEST} + {1414285200 7200 0 EET} + {1427590800 10800 1 EEST} + {1445734800 7200 0 EET} + {1459040400 10800 1 EEST} + {1477789200 7200 0 EET} + {1490490000 10800 1 EEST} + {1509238800 7200 0 EET} + {1521939600 10800 1 EEST} + {1540688400 7200 0 EET} + {1553994000 10800 1 EEST} + {1572138000 7200 0 EET} + {1585443600 10800 1 EEST} + {1603587600 7200 0 EET} + {1616893200 10800 1 EEST} + {1635642000 7200 0 EET} + {1648342800 10800 1 EEST} + {1667091600 7200 0 EET} + {1679792400 10800 1 EEST} + {1698541200 7200 0 EET} + {1711846800 10800 1 EEST} + {1729990800 7200 0 EET} + {1743296400 10800 1 EEST} + {1761440400 7200 0 EET} + {1774746000 10800 1 EEST} + {1792890000 7200 0 EET} + {1806195600 10800 1 EEST} + {1824944400 7200 0 EET} + {1837645200 10800 1 EEST} + {1856394000 7200 0 EET} + {1869094800 10800 1 EEST} + {1887843600 7200 0 EET} + {1901149200 10800 1 EEST} + {1919293200 7200 0 EET} + {1932598800 10800 1 EEST} + {1950742800 7200 0 EET} + {1964048400 10800 1 EEST} + {1982797200 7200 0 EET} + {1995498000 10800 1 EEST} + {2014246800 7200 0 EET} + {2026947600 10800 1 EEST} + {2045696400 7200 0 EET} + {2058397200 10800 1 EEST} + {2077146000 7200 0 EET} + {2090451600 10800 1 EEST} + {2108595600 7200 0 EET} + {2121901200 10800 1 EEST} + {2140045200 7200 0 EET} + {2153350800 10800 1 EEST} + {2172099600 7200 0 EET} + {2184800400 10800 1 EEST} + {2203549200 7200 0 EET} + {2216250000 10800 1 EEST} + {2234998800 7200 0 EET} + {2248304400 10800 1 EEST} + {2266448400 7200 0 EET} + {2279754000 10800 1 EEST} + {2297898000 7200 0 EET} + {2311203600 10800 1 EEST} + {2329347600 7200 0 EET} + {2342653200 10800 1 EEST} + {2361402000 7200 0 EET} + {2374102800 10800 1 EEST} + {2392851600 7200 0 EET} + {2405552400 10800 1 EEST} + {2424301200 7200 0 EET} + {2437606800 10800 1 EEST} + {2455750800 7200 0 EET} + {2469056400 10800 1 EEST} + {2487200400 7200 0 EET} + {2500506000 10800 1 EEST} + {2519254800 7200 0 EET} + {2531955600 10800 1 EEST} + {2550704400 7200 0 EET} + {2563405200 10800 1 EEST} + {2582154000 7200 0 EET} + {2595459600 10800 1 EEST} + {2613603600 7200 0 EET} + {2626909200 10800 1 EEST} + {2645053200 7200 0 EET} + {2658358800 10800 1 EEST} + {2676502800 7200 0 EET} + {2689808400 10800 1 EEST} + {2708557200 7200 0 EET} + {2721258000 10800 1 EEST} + {2740006800 7200 0 EET} + {2752707600 10800 1 EEST} + {2771456400 7200 0 EET} + {2784762000 10800 1 EEST} + {2802906000 7200 0 EET} + {2816211600 10800 1 EEST} + {2834355600 7200 0 EET} + {2847661200 10800 1 EEST} + {2866410000 7200 0 EET} + {2879110800 10800 1 EEST} + {2897859600 7200 0 EET} + {2910560400 10800 1 EEST} + {2929309200 7200 0 EET} + {2942010000 10800 1 EEST} + {2960758800 7200 0 EET} + {2974064400 10800 1 EEST} + {2992208400 7200 0 EET} + {3005514000 10800 1 EEST} + {3023658000 7200 0 EET} + {3036963600 10800 1 EEST} + {3055712400 7200 0 EET} + {3068413200 10800 1 EEST} + {3087162000 7200 0 EET} + {3099862800 10800 1 EEST} + {3118611600 7200 0 EET} + {3131917200 10800 1 EEST} + {3150061200 7200 0 EET} + {3163366800 10800 1 EEST} + {3181510800 7200 0 EET} + {3194816400 10800 1 EEST} + {3212960400 7200 0 EET} + {3226266000 10800 1 EEST} + {3245014800 7200 0 EET} + {3257715600 10800 1 EEST} + {3276464400 7200 0 EET} + {3289165200 10800 1 EEST} + {3307914000 7200 0 EET} + {3321219600 10800 1 EEST} + {3339363600 7200 0 EET} + {3352669200 10800 1 EEST} + {3370813200 7200 0 EET} + {3384118800 10800 1 EEST} + {3402867600 7200 0 EET} + {3415568400 10800 1 EEST} + {3434317200 7200 0 EET} + {3447018000 10800 1 EEST} + {3465766800 7200 0 EET} + {3479072400 10800 1 EEST} + {3497216400 7200 0 EET} + {3510522000 10800 1 EEST} + {3528666000 7200 0 EET} + {3541971600 10800 1 EEST} + {3560115600 7200 0 EET} + {3573421200 10800 1 EEST} + {3592170000 7200 0 EET} + {3604870800 10800 1 EEST} + {3623619600 7200 0 EET} + {3636320400 10800 1 EEST} + {3655069200 7200 0 EET} + {3668374800 10800 1 EEST} + {3686518800 7200 0 EET} + {3699824400 10800 1 EEST} + {3717968400 7200 0 EET} + {3731274000 10800 1 EEST} + {3750022800 7200 0 EET} + {3762723600 10800 1 EEST} + {3781472400 7200 0 EET} + {3794173200 10800 1 EEST} + {3812922000 7200 0 EET} + {3825622800 10800 1 EEST} + {3844371600 7200 0 EET} + {3857677200 10800 1 EEST} + {3875821200 7200 0 EET} + {3889126800 10800 1 EEST} + {3907270800 7200 0 EET} + {3920576400 10800 1 EEST} + {3939325200 7200 0 EET} + {3952026000 10800 1 EEST} + {3970774800 7200 0 EET} + {3983475600 10800 1 EEST} + {4002224400 7200 0 EET} + {4015530000 10800 1 EEST} + {4033674000 7200 0 EET} + {4046979600 10800 1 EEST} + {4065123600 7200 0 EET} + {4078429200 10800 1 EEST} + {4096573200 7200 0 EET} +} -- cgit v0.12 From ce60b9f9bf7ea98961297c9757251a4abcdaa4de Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 23 Aug 2022 07:27:08 +0000 Subject: Patch (8) from [37108037b9]: Code cleanups to support CHERI --- generic/tclCompCmdsSZ.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 4c325c2..bfa1957 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -2383,7 +2383,7 @@ IssueSwitchJumpTable( * point to here. */ - Tcl_SetHashValue(hPtr, CurrentOffset(envPtr) - jumpLocation); + Tcl_SetHashValue(hPtr, INT2PTR(CurrentOffset(envPtr) - jumpLocation)); } Tcl_DStringFree(&buffer); } else { -- cgit v0.12 From ec609cef016b8d3c191e599f4ca70aace4e11c53 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 25 Aug 2022 20:36:39 +0000 Subject: [37108037b9]: Code cleanups to support CHERI. Apply patch 0001 and 0003 (and a few more potential alignment problems, inspired by those patches) --- generic/tclCompile.c | 8 ++++++-- generic/tclDisassemble.c | 13 +++++++------ generic/tclExecute.c | 4 ++-- generic/tclInt.h | 26 +++++++++++++++++++------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 80d8a09..2d22dc1 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -2838,9 +2838,13 @@ TclInitByteCode( /* * Compute the total number of bytes needed for this bytecode. + * + * Note that code bytes need not be aligned but since later elements are we + * need to pad anyway, either directly after ByteCode or after codeBytes, + * and it's easier and more consistent to do the former. */ - structureSize = sizeof(ByteCode); + structureSize = TCL_ALIGN(sizeof(ByteCode)); /* align code bytes */ structureSize += TCL_ALIGN(codeBytes); /* align object array */ structureSize += TCL_ALIGN(objArrayBytes); /* align exc range arr */ structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */ @@ -2879,7 +2883,7 @@ TclInitByteCode( codePtr->maxExceptDepth = envPtr->maxExceptDepth; codePtr->maxStackDepth = envPtr->maxStackDepth; - p += sizeof(ByteCode); + p += TCL_ALIGN(sizeof(ByteCode)); /* align code bytes */ codePtr->codeStart = p; memcpy(p, envPtr->codeStart, codeBytes); diff --git a/generic/tclDisassemble.c b/generic/tclDisassemble.c index 2653630..0bc3de1 100644 --- a/generic/tclDisassemble.c +++ b/generic/tclDisassemble.c @@ -301,13 +301,14 @@ DisassembleByteCodeObj( #ifdef TCL_COMPILE_STATS Tcl_AppendPrintfToObj(bufferObj, - " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", - (unsigned long) codePtr->structureSize, - (unsigned long) (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)), + " Code %" TCL_Z_MODIFIER "u = header %" TCL_Z_MODIFIER "u+inst %d+litObj %" + TCL_Z_MODIFIER "u+exc %" TCL_Z_MODIFIER "u+aux %" TCL_Z_MODIFIER "u+cmdMap %d\n", + codePtr->structureSize, + offsetof(ByteCode, localCachePtr), codePtr->numCodeBytes, - (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)), - (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)), - (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)), + codePtr->numLitObjects * sizeof(Tcl_Obj *), + codePtr->numExceptRanges*sizeof(ExceptionRange), + codePtr->numAuxDataItems * sizeof(AuxData), codePtr->numCmdLocBytes); #endif /* TCL_COMPILE_STATS */ diff --git a/generic/tclExecute.c b/generic/tclExecute.c index dd50be0..3fb7e07 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -9080,7 +9080,7 @@ PrintByteCodeInfo( #ifdef TCL_COMPILE_STATS fprintf(stdout, " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", (unsigned long) codePtr->structureSize, - (unsigned long) (sizeof(ByteCode)-sizeof(size_t)-sizeof(Tcl_Time)), + (unsigned long) offsetof(ByteCode, localCachePtr), codePtr->numCodeBytes, (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)), (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)), @@ -9723,7 +9723,7 @@ EvalStatsCmd( numCurrentByteCodes = statsPtr->numCompilations - statsPtr->numByteCodesFreed; currentHeaderBytes = numCurrentByteCodes - * (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)); + * offsetof(ByteCode, localCachePtr); literalMgmtBytes = sizeof(LiteralTable) + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)) + (iPtr->literalTable.numEntries * sizeof(LiteralEntry)); diff --git a/generic/tclInt.h b/generic/tclInt.h index ac6fb54..f032efb 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2358,22 +2358,34 @@ typedef struct Interp { #endif /* - * This macro is used to determine the offset needed to safely allocate any + * TCL_ALIGN is used to determine the offset needed to safely allocate any * data structure in memory. Given a starting offset or size, it "rounds up" - * or "aligns" the offset to the next 8-byte boundary so that any data - * structure can be placed at the resulting offset without fear of an - * alignment error. + * or "aligns" the offset to the next aligned (typically 8-byte) boundary so + * that any data structure can be placed at the resulting offset without fear + * of an alignment error. Note this is clamped to a minimum of 8 for API + * compatibility. * * WARNING!! DO NOT USE THIS MACRO TO ALIGN POINTERS: it will produce the - * wrong result on platforms that allocate addresses that are divisible by 4 - * or 2. Only use it for offsets or sizes. + * wrong result on platforms that allocate addresses that are divisible by a + * non-trivial factor of this alignment. Only use it for offsets or sizes. * * This macro is only used by tclCompile.c in the core (Bug 926445). It * however not be made file static, as extensions that touch bytecodes * (notably tbcload) require it. */ -#define TCL_ALIGN(x) (((int)(x) + 7) & ~7) +struct TclMaxAlignment { + char unalign[8]; + union { + long long maxAlignLongLong; + double maxAlignDouble; + void *maxAlignPointer; + } aligned; +}; +#define TCL_ALIGN_BYTES \ + offsetof(struct TclMaxAlignment, aligned) +#define TCL_ALIGN(x) \ + (((x) + (TCL_ALIGN_BYTES - 1)) & ~(TCL_ALIGN_BYTES - 1)) /* * A common panic alert when memory allocation fails. -- cgit v0.12 From 17775db55f95232f3821a717f6df97c4a1f3f010 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 26 Aug 2022 20:23:14 +0000 Subject: [37108037b9]: Code cleanups to support CHERI: Apply patch 0007 (modified) --- generic/tclHash.c | 28 ++++++---------------------- generic/tclProc.c | 2 +- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/generic/tclHash.c b/generic/tclHash.c index 606d26b..37e45e7 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.c @@ -685,21 +685,16 @@ AllocArrayEntry( Tcl_HashTable *tablePtr, /* Hash table. */ void *keyPtr) /* Key to store in the hash table entry. */ { - int *array = (int *) keyPtr; - int *iPtr1, *iPtr2; Tcl_HashEntry *hPtr; - int count = tablePtr->keyType; - TCL_HASH_TYPE size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key); + TCL_HASH_TYPE count = tablePtr->keyType * sizeof(int); + TCL_HASH_TYPE size = offsetof(Tcl_HashEntry, key) + count; if (size < sizeof(Tcl_HashEntry)) { size = sizeof(Tcl_HashEntry); } hPtr = (Tcl_HashEntry *)ckalloc(size); - for (iPtr1 = array, iPtr2 = hPtr->key.words; - count > 0; count--, iPtr1++, iPtr2++) { - *iPtr2 = *iPtr1; - } + memcpy(hPtr->key.string, keyPtr, count); Tcl_SetHashValue(hPtr, NULL); return hPtr; @@ -727,20 +722,9 @@ CompareArrayKeys( void *keyPtr, /* New key to compare. */ Tcl_HashEntry *hPtr) /* Existing key to compare. */ { - const int *iPtr1 = (const int *)keyPtr; - const int *iPtr2 = hPtr->key.words; - Tcl_HashTable *tablePtr = hPtr->tablePtr; - int count; + size_t count = hPtr->tablePtr->keyType * sizeof(int); - for (count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { - if (count == 0) { - return 1; - } - if (*iPtr1 != *iPtr2) { - break; - } - } - return 0; + return !memcmp(keyPtr, hPtr->key.string, count); } /* @@ -807,7 +791,7 @@ AllocStringEntry( allocsize = sizeof(hPtr->key); } hPtr = (Tcl_HashEntry *)ckalloc(offsetof(Tcl_HashEntry, key) + allocsize); - memset(hPtr, 0, sizeof(Tcl_HashEntry) + allocsize - sizeof(hPtr->key)); + memset(hPtr, 0, offsetof(Tcl_HashEntry, key) + allocsize); memcpy(hPtr->key.string, string, size); Tcl_SetHashValue(hPtr, NULL); return hPtr; diff --git a/generic/tclProc.c b/generic/tclProc.c index e6b1372..9a3785c 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -2163,7 +2163,7 @@ TclProcCleanupProc( if (bodyPtr != NULL) { /* procPtr is stored in body's ByteCode, so ensure to reset it. */ ByteCode *codePtr; - + ByteCodeGetInternalRep(bodyPtr, &tclByteCodeType, codePtr); if (codePtr != NULL && codePtr->procPtr == procPtr) { codePtr->procPtr = NULL; -- cgit v0.12 From c1b4a8688f530f2fb6ab049c3304c1d11e385ebc Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 26 Aug 2022 22:47:05 +0000 Subject: Use TclOffset() in stead of magic calculations using sizeof(), which might give unexpected results when padding is involved --- generic/tclDisassemble.c | 2 +- generic/tclExecute.c | 4 ++-- generic/tclHash.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tclDisassemble.c b/generic/tclDisassemble.c index 6f463ca..4a61f69 100644 --- a/generic/tclDisassemble.c +++ b/generic/tclDisassemble.c @@ -296,7 +296,7 @@ DisassembleByteCodeObj( Tcl_AppendPrintfToObj(bufferObj, " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", (unsigned long) codePtr->structureSize, - (unsigned long) (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)), + (unsigned long) (TclOffset(ByteCode, localCachePtr)), codePtr->numCodeBytes, (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)), (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)), diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 25b9409..a16334a 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -9629,7 +9629,7 @@ PrintByteCodeInfo( #ifdef TCL_COMPILE_STATS fprintf(stdout, " Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", (unsigned long) codePtr->structureSize, - (unsigned long) (sizeof(ByteCode)-sizeof(size_t)-sizeof(Tcl_Time)), + (unsigned long) (TclOffset(ByteCode, localCachePtr)), codePtr->numCodeBytes, (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)), (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)), @@ -10272,7 +10272,7 @@ EvalStatsCmd( numCurrentByteCodes = statsPtr->numCompilations - statsPtr->numByteCodesFreed; currentHeaderBytes = numCurrentByteCodes - * (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)); + * (TclOffset(ByteCode, localCachePtr)); literalMgmtBytes = sizeof(LiteralTable) + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)) + (iPtr->literalTable.numEntries * sizeof(LiteralEntry)); diff --git a/generic/tclHash.c b/generic/tclHash.c index 5de8168..709831d 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.c @@ -722,7 +722,7 @@ AllocArrayEntry( count = tablePtr->keyType; - size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key); + size = TclOffset(Tcl_HashEntry, key) + count*sizeof(int); if (size < sizeof(Tcl_HashEntry)) { size = sizeof(Tcl_HashEntry); } @@ -839,7 +839,7 @@ AllocStringEntry( allocsize = sizeof(hPtr->key); } hPtr = ckalloc(TclOffset(Tcl_HashEntry, key) + allocsize); - memset(hPtr, 0, sizeof(Tcl_HashEntry) + allocsize - sizeof(hPtr->key)); + memset(hPtr, 0, TclOffset(Tcl_HashEntry, key) + allocsize); memcpy(hPtr->key.string, string, size); hPtr->clientData = 0; return hPtr; -- cgit v0.12 From 5e5b9a09942ea8a669f9652d4ede50a0afcc10b3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 26 Aug 2022 23:11:44 +0000 Subject: [37108037b9]: Apply patch 0005 for CHERI --- generic/tclTest.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index ed5f34b..9284969 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -61,6 +61,21 @@ static Tcl_DString delString; static Tcl_Interp *delInterp; /* + * One of the following structures exists for each command created by the + * "testcmdtoken" command. + */ + +typedef struct TestCommandTokenRef { + int id; /* Identifier for this reference. */ + Tcl_Command token; /* Tcl's token for the command. */ + struct TestCommandTokenRef *nextPtr; + /* Next in list of references. */ +} TestCommandTokenRef; + +static TestCommandTokenRef *firstCommandTokenRef = NULL; +static int nextCommandTokenRefId = 1; + +/* * One of the following structures exists for each asynchronous handler * created by the "testasync" command". */ @@ -1196,9 +1211,9 @@ TestcmdtokenCmd( int argc, /* Number of arguments. */ const char **argv) /* Argument strings. */ { - Tcl_Command token; - int *l; + TestCommandTokenRef *refPtr; char buf[30]; + int id; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], @@ -1206,24 +1221,42 @@ TestcmdtokenCmd( return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { - token = Tcl_CreateCommand(interp, argv[2], CmdProc1, + refPtr = (TestCommandTokenRef *)Tcl_Alloc(sizeof(TestCommandTokenRef)); + refPtr->token = Tcl_CreateCommand(interp, argv[2], CmdProc1, (void *) "original", NULL); - sprintf(buf, "%p", (void *)token); + refPtr->id = nextCommandTokenRefId; + nextCommandTokenRefId++; + refPtr->nextPtr = firstCommandTokenRef; + firstCommandTokenRef = refPtr; + sprintf(buf, "%d", refPtr->id); Tcl_AppendResult(interp, buf, NULL); } else if (strcmp(argv[1], "name") == 0) { Tcl_Obj *objPtr; - if (sscanf(argv[2], "%p", &l) != 1) { + if (sscanf(argv[2], "%d", &id) != 1) { + Tcl_AppendResult(interp, "bad command token \"", argv[2], + "\"", NULL); + return TCL_ERROR; + } + + for (refPtr = firstCommandTokenRef; refPtr != NULL; + refPtr = refPtr->nextPtr) { + if (refPtr->id == id) { + break; + } + } + + if (refPtr == NULL) { Tcl_AppendResult(interp, "bad command token \"", argv[2], "\"", NULL); return TCL_ERROR; } objPtr = Tcl_NewObj(); - Tcl_GetCommandFullName(interp, (Tcl_Command) l, objPtr); + Tcl_GetCommandFullName(interp, refPtr->token, objPtr); Tcl_AppendElement(interp, - Tcl_GetCommandName(interp, (Tcl_Command) l)); + Tcl_GetCommandName(interp, refPtr->token)); Tcl_AppendElement(interp, Tcl_GetString(objPtr)); Tcl_DecrRefCount(objPtr); } else { -- cgit v0.12 -- cgit v0.12 From 8c034cf9ce62c27025614676e999df1db4e75686 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 29 Aug 2022 09:56:51 +0000 Subject: Remove TODO's already done. Only use ListSizeT for types which are 'size_t' in the Tcl 9 implementation --- generic/tclInt.h | 6 +++--- generic/tclListObj.c | 30 ++++++++++-------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index ae88cfe..29fa847 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2437,18 +2437,18 @@ typedef enum TclEolTranslation { #define TCL_INVOKE_NO_TRACEBACK (1<<2) /* - * TclListSizeT is the type for holding list element counts. It's defined + * ListSizeT is the type for holding list element counts. It's defined * simplify sharing source between Tcl8 and Tcl9. */ #if TCL_MAJOR_VERSION > 8 -typedef ptrdiff_t ListSizeT; /* TODO - may need to fix to match Tcl9's API */ +typedef size_t ListSizeT; /* * SSIZE_MAX, NOT SIZE_MAX as negative differences need to be expressed * between values of the ListSizeT type so limit the range to signed */ -#define ListSizeT_MAX PTRDIFF_MAX +#define ListSizeT_MAX ((ListSizeT)PTRDIFF_MAX) #else diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 5100159..0d3b5a0 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -919,14 +919,6 @@ ListRepInit( { ListStore *storePtr; - /* - * The whole list implementation has an implicit assumption that lenths - * and indices used a signed integer type. Tcl9 API's currently use - * unsigned types. This assert is to remind that need to review code - * when adapting for Tcl9. - */ - LIST_ASSERT(((ListSizeT)-1) < 0); - storePtr = ListStoreNew(objc, objv, flags); if (storePtr) { repPtr->storePtr = storePtr; @@ -2078,12 +2070,12 @@ Tcl_ListObjReplace( { ListRep listRep; ListSizeT origListLen; - ListSizeT lenChange; - ListSizeT leadSegmentLen; - ListSizeT tailSegmentLen; + int lenChange; + int leadSegmentLen; + int tailSegmentLen; ListSizeT numFreeSlots; - ListSizeT leadShift; - ListSizeT tailShift; + int leadShift; + int tailShift; Tcl_Obj **listObjs; int favor; @@ -2386,9 +2378,9 @@ Tcl_ListObjReplace( * or need to shift both. In the former case, favor shifting the * smaller segment. */ - ListSizeT leadSpace = ListRepNumFreeHead(&listRep); - ListSizeT tailSpace = ListRepNumFreeTail(&listRep); - ListSizeT finalFreeSpace = leadSpace + tailSpace - lenChange; + int leadSpace = ListRepNumFreeHead(&listRep); + int tailSpace = ListRepNumFreeTail(&listRep); + int finalFreeSpace = leadSpace + tailSpace - lenChange; LIST_ASSERT((leadSpace + tailSpace) >= lenChange); if (leadSpace >= lenChange @@ -2405,7 +2397,7 @@ Tcl_ListObjReplace( * insertions. */ if (finalFreeSpace > 1 && (tailSpace == 0 || tailSegmentLen == 0)) { - ListSizeT postShiftLeadSpace = leadSpace - lenChange; + int postShiftLeadSpace = leadSpace - lenChange; if (postShiftLeadSpace > (finalFreeSpace/2)) { ListSizeT extraShift = postShiftLeadSpace - (finalFreeSpace / 2); leadShift -= extraShift; @@ -2422,7 +2414,7 @@ Tcl_ListObjReplace( * See comments above. This is analogous. */ if (finalFreeSpace > 1 && (leadSpace == 0 || leadSegmentLen == 0)) { - ListSizeT postShiftTailSpace = tailSpace - lenChange; + int postShiftTailSpace = tailSpace - lenChange; if (postShiftTailSpace > (finalFreeSpace/2)) { /* T:listrep-1.{1,3,14,18,21},3.{2,3,26,27} */ ListSizeT extraShift = postShiftTailSpace - (finalFreeSpace / 2); @@ -3431,11 +3423,9 @@ UpdateStringOfList( elem = TclGetStringFromObj(elemPtrs[i], &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i); if (bytesNeeded < 0) { - /* TODO - what is the max #define for Tcl9? */ Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } } - /* TODO - what is the max #define for Tcl9? */ if (bytesNeeded > INT_MAX - numElems + 1) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } -- cgit v0.12 From b0aac11cdb0e31babc4c89aeda27223f4a731162 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 29 Aug 2022 20:53:44 +0000 Subject: Add 2 unused (internal) stub entries --- generic/tclInt.decls | 2 +- generic/tclIntDecls.h | 9 ++++++--- generic/tclStubInit.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/generic/tclInt.decls b/generic/tclInt.decls index df39bef..b76d06b 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -957,7 +957,7 @@ declare 257 { Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc) } -declare 260 { +declare 261 { void TclUnusedStubEntry(void) } diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 4d98d00..a8bb18e 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -1078,9 +1078,10 @@ EXTERN void TclStaticPackage(Tcl_Interp *interp, #endif /* Slot 258 is reserved */ /* Slot 259 is reserved */ +/* Slot 260 is reserved */ #ifndef TclUnusedStubEntry_TCL_DECLARED #define TclUnusedStubEntry_TCL_DECLARED -/* 260 */ +/* 261 */ EXTERN void TclUnusedStubEntry(void); #endif @@ -1348,7 +1349,8 @@ typedef struct TclIntStubs { void (*tclStaticPackage) (Tcl_Interp *interp, CONST char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 257 */ VOID *reserved258; VOID *reserved259; - void (*tclUnusedStubEntry) (void); /* 260 */ + VOID *reserved260; + void (*tclUnusedStubEntry) (void); /* 261 */ } TclIntStubs; extern TclIntStubs *tclIntStubsPtr; @@ -2094,9 +2096,10 @@ extern TclIntStubs *tclIntStubsPtr; #endif /* Slot 258 is reserved */ /* Slot 259 is reserved */ +/* Slot 260 is reserved */ #ifndef TclUnusedStubEntry #define TclUnusedStubEntry \ - (tclIntStubsPtr->tclUnusedStubEntry) /* 260 */ + (tclIntStubsPtr->tclUnusedStubEntry) /* 261 */ #endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 0bebc15..0d2a3c2 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -561,7 +561,8 @@ TclIntStubs tclIntStubs = { TclStaticPackage, /* 257 */ NULL, /* 258 */ NULL, /* 259 */ - TclUnusedStubEntry, /* 260 */ + NULL, /* 260 */ + TclUnusedStubEntry, /* 261 */ }; TclIntPlatStubs tclIntPlatStubs = { -- cgit v0.12 From 1aa64a54f72a97753e3cc7e75eb93ac625d66a33 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 29 Aug 2022 22:48:41 +0000 Subject: [37108037b9], patch 0004 --- generic/tclExecute.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 8ca56c9..af93636 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -169,11 +169,11 @@ static BuiltinFunc const tclBuiltinFuncTable[] = { typedef struct TEBCdata { ByteCode *codePtr; /* Constant until the BC returns */ /* -----------------------------------------*/ - ptrdiff_t *catchTop; /* These fields are used on return TO this */ + Tcl_Obj **catchTop; /* These fields are used on return TO this */ Tcl_Obj *auxObjList; /* this level: they record the state when a */ CmdFrame cmdFrame; /* new codePtr was received for NR */ /* execution. */ - void *stack[1]; /* Start of the actual combined catch and obj + Tcl_Obj *stack[1]; /* Start of the actual combined catch and obj * stacks; the struct will be expanded as * necessary */ } TEBCdata; @@ -1935,8 +1935,8 @@ ArgumentBCEnter( *---------------------------------------------------------------------- */ #define bcFramePtr (&TD->cmdFrame) -#define initCatchTop ((ptrdiff_t *) (TD->stack-1)) -#define initTosPtr ((Tcl_Obj **) (initCatchTop+codePtr->maxExceptDepth)) +#define initCatchTop (TD->stack-1) +#define initTosPtr (initCatchTop+codePtr->maxExceptDepth) #define esPtr (iPtr->execEnvPtr->execStackPtr) int @@ -6805,7 +6805,7 @@ TEBCresume( * stack. */ - *(++catchTop) = CURR_DEPTH; + *(++catchTop) = INT2PTR(CURR_DEPTH); TRACE(("%u => catchTop=%d, stackTop=%d\n", TclGetUInt4AtPtr(pc+1), (int) (catchTop - initCatchTop - 1), (int) CURR_DEPTH)); @@ -7717,8 +7717,8 @@ TEBCresume( while (auxObjList) { if ((catchTop != initCatchTop) - && (*catchTop > (ptrdiff_t) - auxObjList->internalRep.twoPtrValue.ptr2)) { + && (PTR2INT(*catchTop) > + PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2))) { break; } POP_TAUX_OBJ(); @@ -7793,7 +7793,7 @@ TEBCresume( */ processCatch: - while (CURR_DEPTH > *catchTop) { + while (CURR_DEPTH > PTR2INT(*catchTop)) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } @@ -7802,7 +7802,7 @@ TEBCresume( fprintf(stdout, " ... found catch at %d, catchTop=%d, " "unwound to %ld, new pc %u\n", rangePtr->codeOffset, (int) (catchTop - initCatchTop - 1), - (long)*catchTop, (unsigned) rangePtr->catchOffset); + (long)PTR2INT(*catchTop), (unsigned) rangePtr->catchOffset); } #endif pc = (codePtr->codeStart + rangePtr->catchOffset); -- cgit v0.12 From b3500c7657421cc9309d8b22a9e40b8d70bd2d00 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 30 Aug 2022 06:53:35 +0000 Subject: gcc warning (-Wc++-compat) --- generic/tclExecute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index af93636..91cce46 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -6805,7 +6805,7 @@ TEBCresume( * stack. */ - *(++catchTop) = INT2PTR(CURR_DEPTH); + *(++catchTop) = (Tcl_Obj *)INT2PTR(CURR_DEPTH); TRACE(("%u => catchTop=%d, stackTop=%d\n", TclGetUInt4AtPtr(pc+1), (int) (catchTop - initCatchTop - 1), (int) CURR_DEPTH)); -- cgit v0.12 From 74f8d5493bfe3936ae043a8bea5478decf86a33b Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Tue, 30 Aug 2022 09:40:35 +0000 Subject: Backport TIP 602 tildeexpand --- generic/tclCmdAH.c | 3 +- generic/tclFCmd.c | 38 +++++++++++++++++++++++++ generic/tclInt.h | 5 ++-- generic/tclPathObj.c | 80 +++++++++++++++++++++++++++++----------------------- tests/cmdAH.test | 4 +-- tests/fCmd.test | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 166 insertions(+), 43 deletions(-) diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 62c799a..06919a2 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -1191,7 +1191,7 @@ TclInitFileCmd( {"executable", FileAttrIsExecutableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"exists", FileAttrIsExistingCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"extension", PathExtensionCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, - {"home", TclFileHomeCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"home", TclFileHomeCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1}, {"isdirectory", FileAttrIsDirectoryCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"isfile", FileAttrIsFileCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"join", PathJoinCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0}, @@ -1215,6 +1215,7 @@ TclInitFileCmd( {"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"tempdir", TclFileTempDirCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1}, {"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 1}, + {"tildeexpand", TclFileTildeExpandCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1}, {"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index 747d8a6..2d24207 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -1688,6 +1688,44 @@ TclFileHomeCmd( } /* + *---------------------------------------------------------------------- + * + * TclFileTildeExpandCmd -- + * + * This function is invoked to process the "file tildeexpand" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclFileTildeExpandCmd( + TCL_UNUSED(void *), + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *expandedPathObj; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "path"); + return TCL_ERROR; + } + expandedPathObj = TclResolveTildePath(interp, objv[1]); + if (expandedPathObj == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, expandedPathObj); + return TCL_OK; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tclInt.h b/generic/tclInt.h index 9fec5b0..80e60a3 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3141,6 +3141,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileHomeCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileTildeExpandCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, @@ -3248,8 +3249,8 @@ MODULE_SCOPE int TclIsDigitProc(int byte); MODULE_SCOPE int TclIsBareword(int byte); MODULE_SCOPE Tcl_Obj * TclJoinPath(int elements, Tcl_Obj * const objv[], int forceRelative); -MODULE_SCOPE int TclGetHomeDir(Tcl_Interp *interp, const char *user, - Tcl_DString *dsPtr); +MODULE_SCOPE int MakeTildeRelativePath(Tcl_Interp *interp, const char *user, + const char *subPath, Tcl_DString *dsPtr); MODULE_SCOPE Tcl_Obj * TclGetHomeDirObj(Tcl_Interp *interp, const char *user); MODULE_SCOPE Tcl_Obj * TclResolveTildePath(Tcl_Interp *interp, Tcl_Obj *pathObj); diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index bb269de..250ad6a 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -2561,11 +2561,17 @@ TclNativePathInFilesystem( /* *---------------------------------------------------------------------- * - * TclGetHomeDir -- + * MakeTildeRelativePath -- * - * Returns the home directory of a user. Note there is a difference - * between not specifying a user and explicitly specifying the current - * user. This mimics Tcl8's tilde expansion. + * Returns a path relative to the home directory of a user. + * Note there is a difference between not specifying a user and + * explicitly specifying the current user. This mimics Tcl8's tilde + * expansion. + * + * The subPath argument is joined to the expanded home directory + * as in Tcl_JoinPath. This means if it is not relative, it will + * returned as the result with the home directory only checked + * for user name validity. * * Results: * Returns TCL_OK on success with home directory path in *dsPtr @@ -2574,22 +2580,23 @@ TclNativePathInFilesystem( *---------------------------------------------------------------------- */ int -TclGetHomeDir( - Tcl_Interp *interp, /* May be NULL. Only used for error messages */ - const char *user, /* User name. NULL -> current user */ - Tcl_DString *dsPtr) /* Output. Is initialized by the function. Must be +MakeTildeRelativePath( + Tcl_Interp *interp, /* May be NULL. Only used for error messages */ + const char *user, /* User name. NULL -> current user */ + const char *subPath, /* Rest of path. May be NULL */ + Tcl_DString *dsPtr) /* Output. Is initialized by the function. Must be freed on success */ { const char *dir; - Tcl_DString nativeString; + Tcl_DString dirString; Tcl_DStringInit(dsPtr); - Tcl_DStringInit(&nativeString); + Tcl_DStringInit(&dirString); if (user == NULL || user[0] == 0) { /* No user name specified -> current user */ - dir = TclGetEnv("HOME", &nativeString); + dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -2602,7 +2609,7 @@ TclGetHomeDir( } } else { /* User name specified - ~user */ - dir = TclpGetUserHome(user, &nativeString); + dir = TclpGetUserHome(user, &dirString); if (dir == NULL) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( @@ -2613,7 +2620,16 @@ TclGetHomeDir( return TCL_ERROR; } } - Tcl_JoinPath(1, &dir, dsPtr); + if (subPath) { + const char *parts[2]; + parts[0] = dir; + parts[1] = subPath; + Tcl_JoinPath(2, parts, dsPtr); + } else { + Tcl_JoinPath(1, &dir, dsPtr); + } + + Tcl_DStringFree(&dirString); return TCL_OK; } @@ -2623,7 +2639,7 @@ TclGetHomeDir( * * TclGetHomeDirObj -- * - * Wrapper around TclGetHomeDir. See that function. + * Wrapper around MakeTildeRelativePath. See that function. * * Results: * Returns a Tcl_Obj containing the home directory of a user @@ -2638,7 +2654,7 @@ TclGetHomeDirObj( { Tcl_DString dirString; - if (TclGetHomeDir(interp, user, &dirString) != TCL_OK) { + if (MakeTildeRelativePath(interp, user, NULL, &dirString) != TCL_OK) { return NULL; } return TclDStringToObj(&dirString); @@ -2654,12 +2670,6 @@ TclGetHomeDirObj( * component cannot be resolved, returns NULL. If the path does not * begin with a tilde, returns as is. * - * The trailing components of the path are returned verbatim. No - * processing is done on them. Moreover, no assumptions should be - * made about the separators in the returned path. They may be / - * or native. Appropriate path manipulations functions should be - * used by caller if desired. - * * Results: * Returns a Tcl_Obj with resolved path. This may be a new Tcl_Obj * with ref count 0 or that pathObj that was passed in without its @@ -2676,9 +2686,8 @@ TclResolveTildePath( { const char *path; int len; - Tcl_Obj *resolvedObj; - Tcl_DString dirString; int split; + Tcl_DString resolvedPath; path = Tcl_GetStringFromObj(pathObj, &len); if (path[0] != '~') { @@ -2695,12 +2704,13 @@ TclResolveTildePath( if (split == 1) { /* No user name specified -> current user */ - if (TclGetHomeDir(interp, NULL, &dirString) != TCL_OK) { + if (MakeTildeRelativePath( + interp, NULL, path[1] ? 2 + path : NULL, &resolvedPath) + != TCL_OK) { return NULL; } } else { /* User name specified - ~user */ - const char *expandedUser; Tcl_DString userName; @@ -2708,20 +2718,18 @@ TclResolveTildePath( Tcl_DStringAppend(&userName, path+1, split-1); expandedUser = Tcl_DStringValue(&userName); - if (TclGetHomeDir(interp, expandedUser, &dirString) != TCL_OK) { - Tcl_DStringFree(&userName); + /* path[split] is / or \0 */ + if (MakeTildeRelativePath(interp, + expandedUser, + path[split] ? &path[split+1] : NULL, + &resolvedPath) + != TCL_OK) { + Tcl_DStringFree(&userName); return NULL; } - Tcl_DStringFree(&userName); - } - resolvedObj = TclDStringToObj(&dirString); - - if (split < len) { - /* If any trailer, append it verbatim */ - Tcl_AppendToObj(resolvedObj, split + path, len-split); + Tcl_DStringFree(&userName); } - - return resolvedObj; + return TclDStringToObj(&resolvedPath); } /* diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 3aa9f71..a734541 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -355,7 +355,7 @@ test cmdAH-5.1 {Tcl_FileObjCmd} -returnCodes error -body { } -result {wrong # args: should be "file subcommand ?arg ...?"} test cmdAH-5.2 {Tcl_FileObjCmd} -returnCodes error -body { file x -} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} +} -result {unknown or ambiguous subcommand "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, tildeexpand, type, volumes, or writable} test cmdAH-5.3 {Tcl_FileObjCmd} -returnCodes error -body { file exists } -result {wrong # args: should be "file exists name"} @@ -1686,7 +1686,7 @@ test cmdAH-29.6.1 { # Error conditions test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file gorp x -} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, type, volumes, or writable} +} -result {unknown or ambiguous subcommand "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, home, isdirectory, isfile, join, link, lstat, mkdir, mtime, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, tempdir, tempfile, tildeexpand, type, volumes, or writable} test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} -returnCodes error -body { file ex x } -match glob -result {unknown or ambiguous subcommand "ex": must be *} diff --git a/tests/fCmd.test b/tests/fCmd.test index 72a3cd5..73118f4 100644 --- a/tests/fCmd.test +++ b/tests/fCmd.test @@ -2600,13 +2600,88 @@ test fCmd-31.6 {file home USER} -body { # name, else not sure how to check file home $::tcl_platform(user) } -match glob -result "*$::tcl_platform(user)*" -test fCmd-31.6 {file home UNKNOWNUSER} -body { +test fCmd-31.7 {file home UNKNOWNUSER} -body { file home nosuchuser } -returnCodes error -result {user "nosuchuser" doesn't exist} -test fCmd-31.7 {file home extra arg} -body { +test fCmd-31.8 {file home extra arg} -body { file home $::tcl_platform(user) arg } -returnCodes error -result {wrong # args: should be "file home ?user?"} +test fCmd-32.1 {file tildeexpand ~} -body { + file tildeexpand ~ +} -result [file join $::env(HOME)] +test fCmd-32.2 {file tildeexpand ~ - obeys env} -setup { + set ::env(HOME) $::env(HOME)/xxx +} -cleanup { + set ::env(HOME) [file dirname $::env(HOME)] +} -body { + file tildeexpand ~ +} -result [file join $::env(HOME) xxx] +test fCmd-32.3 {file tildeexpand ~ - error} -setup { + set saved $::env(HOME) + unset ::env(HOME) +} -cleanup { + set ::env(HOME) $saved +} -body { + file tildeexpand ~ +} -returnCodes error -result {couldn't find HOME environment variable to expand path} +test fCmd-32.4 { + file tildeexpand ~ - relative path. Following 8.x ~ expansion behavior, relative + paths are not made absolute +} -setup { + set saved $::env(HOME) + set ::env(HOME) relative/path +} -cleanup { + set ::env(HOME) $saved +} -body { + file tildeexpand ~ +} -result relative/path +test fCmd-32.5 {file tildeexpand ~USER} -body { + # Note - as in 8.x this form does NOT necessarily give same result as + # env(HOME) even when user is current user. Assume result contains user + # name, else not sure how to check + file tildeexpand ~$::tcl_platform(user) +} -match glob -result "*$::tcl_platform(user)*" +test fCmd-32.6 {file tildeexpand ~UNKNOWNUSER} -body { + file tildeexpand ~nosuchuser +} -returnCodes error -result {user "nosuchuser" doesn't exist} +test fCmd-32.7 {file tildeexpand ~extra arg} -body { + file tildeexpand ~ arg +} -returnCodes error -result {wrong # args: should be "file tildeexpand path"} +test fCmd-32.8 {file tildeexpand ~/path} -body { + file tildeexpand ~/foo +} -result [file join $::env(HOME)/foo] +test fCmd-32.9 {file tildeexpand ~USER/bar} -body { + # Note - as in 8.x this form does NOT necessarily give same result as + # env(HOME) even when user is current user. Assume result contains user + # name, else not sure how to check + file tildeexpand ~$::tcl_platform(user)/bar +} -match glob -result "*$::tcl_platform(user)*/bar" +test fCmd-32.10 {file tildeexpand ~UNKNOWNUSER} -body { + file tildeexpand ~nosuchuser/foo +} -returnCodes error -result {user "nosuchuser" doesn't exist} +test fCmd-32.11 {file tildeexpand /~/path} -body { + file tildeexpand /~/foo +} -result /~/foo +test fCmd-32.12 {file tildeexpand /~user/path} -body { + file tildeexpand /~$::tcl_platform(user)/foo +} -result /~$::tcl_platform(user)/foo +test fCmd-32.13 {file tildeexpand ./~} -body { + file tildeexpand ./~ +} -result ./~ +test fCmd-32.14 {file tildeexpand relative/path} -body { + file tildeexpand relative/path +} -result relative/path +test fCmd-32.15 {file tildeexpand ~\\path} -body { + file tildeexpand ~\\foo +} -constraints win -result [file join $::env(HOME)/foo] +test fCmd-32.16 {file tildeexpand ~USER\\bar} -body { + # Note - as in 8.x this form does NOT necessarily give same result as + # env(HOME) even when user is current user. Assume result contains user + # name, else not sure how to check + file tildeexpand ~$::tcl_platform(user)\\bar +} -constraints win -match glob -result "*$::tcl_platform(user)*/bar" + # cleanup cleanup -- cgit v0.12 From 33fa3f7f1fd8342215ce4fe948434c6c87274deb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 30 Aug 2022 22:30:20 +0000 Subject: More code cleanup, inspired by [37108037b9] --- generic/tclExecute.c | 78 ++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 91cce46..27ebeec 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -424,7 +424,7 @@ VarHashCreateVar( #define OBJ_AT_DEPTH(n) *(tosPtr-(n)) -#define CURR_DEPTH ((ptrdiff_t) (tosPtr - initTosPtr)) +#define CURR_DEPTH ((size_t)(tosPtr - initTosPtr)) #define STACK_BASE(esPtr) ((esPtr)->stackWords - 1) @@ -437,9 +437,9 @@ VarHashCreateVar( #ifdef TCL_COMPILE_DEBUG # define TRACE(a) \ while (traceInstructions) { \ - fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \ - (int) CURR_DEPTH, \ - (unsigned) (pc - codePtr->codeStart), \ + fprintf(stdout, "%2d: %2" TCL_Z_MODIFIER "u (%" TCL_Z_MODIFIER "u) %s ", iPtr->numLevels, \ + CURR_DEPTH, \ + (size_t)(pc - codePtr->codeStart), \ GetOpcodeName(pc)); \ printf a; \ break; \ @@ -453,9 +453,9 @@ VarHashCreateVar( TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); # define TRACE_WITH_OBJ(a, objPtr) \ while (traceInstructions) { \ - fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \ - (int) CURR_DEPTH, \ - (unsigned) (pc - codePtr->codeStart), \ + fprintf(stdout, "%2d: %2" TCL_Z_MODIFIER "u (%" TCL_Z_MODIFIER "u) %s ", iPtr->numLevels, \ + CURR_DEPTH, \ + (size_t)(pc - codePtr->codeStart), \ GetOpcodeName(pc)); \ printf a; \ TclPrintObject(stdout, objPtr, 30); \ @@ -678,7 +678,7 @@ static const char * GetOpcodeName(const unsigned char *pc); static void PrintByteCodeInfo(ByteCode *codePtr); static const char * StringForResultCode(int result); static void ValidatePcAndStackTop(ByteCode *codePtr, - const unsigned char *pc, int stackTop, + const unsigned char *pc, size_t stackTop, int checkStack); #endif /* TCL_COMPILE_DEBUG */ static ByteCode * CompileExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr); @@ -2007,7 +2007,7 @@ TclNRExecuteByteCode( */ TclNRAddCallback(interp, TEBCresume, TD, /* pc */ NULL, - /* cleanup */ INT2PTR(0), INT2PTR(iPtr->evalFlags)); + /* cleanup */ NULL, INT2PTR(iPtr->evalFlags)); /* * Reset discard result flag - because it is applicable for this call only, @@ -2123,7 +2123,7 @@ TEBCresume( #ifdef TCL_COMPILE_DEBUG if (!pc && (tclTraceExec >= 2)) { PrintByteCodeInfo(codePtr); - fprintf(stdout, " Starting stack top=%d\n", (int) CURR_DEPTH); + fprintf(stdout, " Starting stack top=%" TCL_Z_MODIFIER "u\n", CURR_DEPTH); fflush(stdout); } #endif @@ -2327,7 +2327,7 @@ TEBCresume( CHECK_STACK(); if (traceInstructions) { - fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH); + fprintf(stdout, "%2d: %2" TCL_Z_MODIFIER "u ", iPtr->numLevels, CURR_DEPTH); TclPrintInstruction(codePtr, pc); fflush(stdout); } @@ -2694,10 +2694,10 @@ TEBCresume( */ TclNewObj(objPtr); - objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(CURR_DEPTH); + objPtr->internalRep.twoPtrValue.ptr2 = UINT2PTR(CURR_DEPTH); objPtr->length = 0; PUSH_TAUX_OBJ(objPtr); - TRACE(("=> mark depth as %d\n", (int) CURR_DEPTH)); + TRACE(("=> mark depth as %" TCL_Z_MODIFIER "u\n", CURR_DEPTH)); NEXT_INST_F(1, 0, 0); break; @@ -2709,7 +2709,7 @@ TEBCresume( */ CLANG_ASSERT(auxObjList); - objc = CURR_DEPTH - PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2); + objc = CURR_DEPTH - PTR2UINT(auxObjList->internalRep.twoPtrValue.ptr2); POP_TAUX_OBJ(); #ifdef TCL_COMPILE_DEBUG /* Ugly abuse! */ @@ -2813,7 +2813,7 @@ TEBCresume( case INST_INVOKE_EXPANDED: CLANG_ASSERT(auxObjList); - objc = CURR_DEPTH - PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2); + objc = CURR_DEPTH - PTR2UINT(auxObjList->internalRep.twoPtrValue.ptr2); POP_TAUX_OBJ(); if (objc) { pcAdjustment = 1; @@ -5998,7 +5998,7 @@ TEBCresume( * Handle shifts within the native long range. */ - if (((size_t) shift < CHAR_BIT*sizeof(long)) + if (((size_t)shift < CHAR_BIT*sizeof(long)) && !((w1>0 ? w1 : ~w1) & -(1UL<<(CHAR_BIT*sizeof(long) - 1 - shift)))) { wResult = (Tcl_WideUInt)w1 << shift; @@ -6805,10 +6805,10 @@ TEBCresume( * stack. */ - *(++catchTop) = (Tcl_Obj *)INT2PTR(CURR_DEPTH); - TRACE(("%u => catchTop=%d, stackTop=%d\n", - TclGetUInt4AtPtr(pc+1), (int) (catchTop - initCatchTop - 1), - (int) CURR_DEPTH)); + *(++catchTop) = (Tcl_Obj *)UINT2PTR(CURR_DEPTH); + TRACE(("%u => catchTop=%" TCL_Z_MODIFIER "u, stackTop=%" TCL_Z_MODIFIER "u\n", + TclGetUInt4AtPtr(pc+1), (size_t)(catchTop - initCatchTop - 1), + CURR_DEPTH)); NEXT_INST_F(5, 0, 0); break; @@ -6818,7 +6818,7 @@ TEBCresume( Tcl_ResetResult(interp); CACHE_STACK_INFO(); result = TCL_OK; - TRACE(("=> catchTop=%d\n", (int) (catchTop - initCatchTop - 1))); + TRACE(("=> catchTop=%" TCL_Z_MODIFIER "u\n", (size_t)(catchTop - initCatchTop - 1))); NEXT_INST_F(1, 0, 0); break; @@ -7717,8 +7717,8 @@ TEBCresume( while (auxObjList) { if ((catchTop != initCatchTop) - && (PTR2INT(*catchTop) > - PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2))) { + && (PTR2UINT(*catchTop) > + PTR2UINT(auxObjList->internalRep.twoPtrValue.ptr2))) { break; } POP_TAUX_OBJ(); @@ -7793,16 +7793,16 @@ TEBCresume( */ processCatch: - while (CURR_DEPTH > PTR2INT(*catchTop)) { + while (CURR_DEPTH > PTR2UINT(*catchTop)) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { - fprintf(stdout, " ... found catch at %d, catchTop=%d, " - "unwound to %ld, new pc %u\n", - rangePtr->codeOffset, (int) (catchTop - initCatchTop - 1), - (long)PTR2INT(*catchTop), (unsigned) rangePtr->catchOffset); + fprintf(stdout, " ... found catch at %d, catchTop=%" TCL_Z_MODIFIER "u, " + "unwound to %" TCL_Z_MODIFIER "u, new pc %" TCL_Z_MODIFIER "u\n", + rangePtr->codeOffset, (size_t)(catchTop - initCatchTop - 1), + PTR2UINT(*catchTop), (size_t)rangePtr->catchOffset); } #endif pc = (codePtr->codeStart + rangePtr->catchOffset); @@ -7838,10 +7838,10 @@ TEBCresume( if (tosPtr < initTosPtr) { fprintf(stderr, - "\nTclNRExecuteByteCode: abnormal return at pc %u: " - "stack top %d < entry stack top %d\n", - (unsigned)(pc - codePtr->codeStart), - (unsigned) CURR_DEPTH, (unsigned) 0); + "\nTclNRExecuteByteCode: abnormal return at pc %" TCL_Z_MODIFIER "u: " + "stack top %" TCL_Z_MODIFIER "u < entry stack top %d\n", + (size_t)(pc - codePtr->codeStart), + CURR_DEPTH, 0); Tcl_Panic("TclNRExecuteByteCode execution failure: end stack top < start stack top"); } CLANG_ASSERT(bcFramePtr); @@ -9122,21 +9122,21 @@ ValidatePcAndStackTop( * stdout. */ const unsigned char *pc, /* Points to first byte of a bytecode * instruction. The program counter. */ - int stackTop, /* Current stack top. Must be between + size_t stackTop, /* Current stack top. Must be between * stackLowerBound and stackUpperBound * (inclusive). */ int checkStack) /* 0 if the stack depth check should be * skipped. */ { - int stackUpperBound = codePtr->maxStackDepth; + size_t stackUpperBound = codePtr->maxStackDepth; /* Greatest legal value for stackTop. */ - size_t relativePc = (size_t) (pc - codePtr->codeStart); - size_t codeStart = (size_t) codePtr->codeStart; + size_t relativePc = (size_t)(pc - codePtr->codeStart); + size_t codeStart = (size_t)codePtr->codeStart; size_t codeEnd = (size_t) (codePtr->codeStart + codePtr->numCodeBytes); unsigned char opCode = *pc; - if (((size_t) pc < codeStart) || ((size_t) pc > codeEnd)) { + if ((PTR2UINT(pc) < codeStart) || (PTR2UINT(pc) > codeEnd)) { fprintf(stderr, "\nBad instruction pc 0x%p in TclNRExecuteByteCode\n", pc); Tcl_Panic("TclNRExecuteByteCode execution failure: bad pc"); @@ -9147,11 +9147,11 @@ ValidatePcAndStackTop( Tcl_Panic("TclNRExecuteByteCode execution failure: bad opcode"); } if (checkStack && - ((stackTop < 0) || (stackTop > stackUpperBound))) { + (stackTop > stackUpperBound)) { int numChars; const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars, NULL, NULL); - fprintf(stderr, "\nBad stack top %d at pc %" TCL_Z_MODIFIER "u in TclNRExecuteByteCode (min 0, max %i)", + fprintf(stderr, "\nBad stack top %" TCL_Z_MODIFIER "u at pc %" TCL_Z_MODIFIER "u in TclNRExecuteByteCode (min 0, max %" TCL_Z_MODIFIER "u)", stackTop, relativePc, stackUpperBound); if (cmd != NULL) { Tcl_Obj *message; -- cgit v0.12 From 4f320507252b9d045785f3606b57bd776c30f64b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 30 Aug 2022 23:02:16 +0000 Subject: Apply patch 0006 from [37108037b9]: Code cleanups to support CHERI --- generic/tclExecute.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 27ebeec..8aa3bb2 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2720,7 +2720,8 @@ TEBCresume( case INST_EXPAND_STKTOP: { int i; - ptrdiff_t moved; + TEBCdata *newTD; + ptrdiff_t oldCatchTopOff, oldTosPtrOff; /* * Make sure that the element at stackTop is a list; if not, just @@ -2749,19 +2750,21 @@ TEBCresume( + codePtr->maxStackDepth /* Beyond the original max */ - CURR_DEPTH; /* Relative to where we are */ DECACHE_STACK_INFO(); - moved = GrowEvaluationStack(iPtr->execEnvPtr, length, 1) - - (Tcl_Obj **) TD; - if (moved) { + oldCatchTopOff = catchTop - initCatchTop; + oldTosPtrOff = tosPtr - initTosPtr; + newTD = (TEBCdata *) + GrowEvaluationStack(iPtr->execEnvPtr, length, 1); + if (newTD != TD) { /* * Change the global data to point to the new stack: move the * TEBCdataPtr TD, recompute the position of every other * stack-allocated parameter, update the stack pointers. */ - TD = (TEBCdata *) (((Tcl_Obj **)TD) + moved); + TD = newTD; - catchTop += moved; - tosPtr += moved; + catchTop = initCatchTop + oldCatchTopOff; + tosPtr = initTosPtr + oldTosPtrOff; } } -- cgit v0.12 From 78e661957cafca9e2f11726f4bbdded4e824d53f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 31 Aug 2022 10:00:33 +0000 Subject: Fix [0aa7638534]: .gitignore ignores library/tcltest.tcl --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 74bf502..504f1e4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ manifest.uuid _FOSSIL_ */tclConfig.sh */tclsh* -*/tcltest* +*/tcltest */versions.vc */version.vc */libtcl.vfs -- cgit v0.12 From e1d37a6c49a751970baba2aed8e4b824744b7e8f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 1 Sep 2022 14:49:57 +0000 Subject: Change refCount (in ListStore/ListSpan) to size_t. More ClientData -> void *. Eliminate warning about unused functions --- generic/tclInt.h | 276 +++++++++++++++++++++++++-------------------------- generic/tclListObj.c | 23 +---- 2 files changed, 140 insertions(+), 159 deletions(-) diff --git a/generic/tclInt.h b/generic/tclInt.h index 29fa847..a7c5c2c 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1439,7 +1439,7 @@ typedef int (CompileProc)(Tcl_Interp *interp, Tcl_Parse *parsePtr, */ typedef int (CompileHookProc)(Tcl_Interp *interp, - struct CompileEnv *compEnvPtr, ClientData clientData); + struct CompileEnv *compEnvPtr, void *clientData); /* * The data structure for a (linked list of) execution stacks. @@ -2486,7 +2486,7 @@ typedef struct ListStore { ListSizeT firstUsed; /* Index of first slot in use within slots[] */ ListSizeT numUsed; /* Number of slots in use (starting firstUsed) */ ListSizeT numAllocated; /* Total number of slots[] array slots. */ - int refCount; /* Number of references to this instance */ + size_t refCount; /* Number of references to this instance */ int flags; /* LISTSTORE_* flags */ Tcl_Obj *slots[TCLFLEXARRAY]; /* Variable size array. Grown as needed */ } ListStore; @@ -2510,7 +2510,7 @@ typedef struct ListStore { typedef struct ListSpan { ListSizeT spanStart; /* Starting index of the span */ ListSizeT spanLength; /* Number of elements in the span */ - int refCount; /* Count of references to this span record */ + size_t refCount; /* Count of references to this span record */ } ListSpan; #ifndef LIST_SPAN_THRESHOLD /* May be set on build line */ #define LIST_SPAN_THRESHOLD 101 @@ -2747,7 +2747,7 @@ typedef struct ListRep { */ #define TCL_FILESYSTEM_VERSION_2 ((Tcl_FSVersion) 0x2) -typedef ClientData (TclFSGetCwdProc2)(ClientData clientData); +typedef void *(TclFSGetCwdProc2)(void *clientData); typedef int (Tcl_FSLoadFileProc2) (Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr, int flags); @@ -2909,7 +2909,7 @@ MODULE_SCOPE Tcl_Encoding tclIdentityEncoding; MODULE_SCOPE Tcl_GetTimeProc *tclGetTimeProcPtr; MODULE_SCOPE Tcl_ScaleTimeProc *tclScaleTimeProcPtr; -MODULE_SCOPE ClientData tclTimeClientData; +MODULE_SCOPE void *tclTimeClientData; /* * Variables denoting the Tcl object types defined in the core. @@ -3085,7 +3085,7 @@ MODULE_SCOPE void TclArgumentBCRelease(Tcl_Interp *interp, MODULE_SCOPE void TclArgumentGet(Tcl_Interp *interp, Tcl_Obj *obj, CmdFrame **cfPtrPtr, int *wordPtr); MODULE_SCOPE int TclAsyncNotifier(int sigNumber, Tcl_ThreadId threadId, - ClientData clientData, int *flagPtr, int value); + void *clientData, int *flagPtr, int value); MODULE_SCOPE void TclAsyncMarkFromNotifier(void); MODULE_SCOPE double TclBignumToDouble(const void *bignum); MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string, @@ -3116,7 +3116,7 @@ MODULE_SCOPE int TclConvertElement(const char *src, int length, char *dst, int flags); MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, - Tcl_ObjCmdProc *proc, ClientData clientData, + Tcl_ObjCmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp, const char *name, Tcl_Namespace *nameNamespacePtr, @@ -3141,9 +3141,9 @@ MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, - ClientData clientData); + void *clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, - ClientData clientData); + void *clientData); MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr, Tcl_Obj *objPtr); MODULE_SCOPE char * TclDStringAppendDString(Tcl_DString *dsPtr, @@ -3198,7 +3198,7 @@ MODULE_SCOPE int TclGetCompletionCodeFromObj(Tcl_Interp *interp, MODULE_SCOPE Proc * TclGetLambdaFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **nsObjPtrPtr); MODULE_SCOPE int TclGetNumberFromObj(Tcl_Interp *interp, - Tcl_Obj *objPtr, ClientData *clientDataPtr, + Tcl_Obj *objPtr, void **clientDataPtr, int *typePtr); MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, const char *modeString, int *seekFlagPtr, @@ -3220,16 +3220,16 @@ MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_Obj *incrPtr); MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, int flags); -MODULE_SCOPE int TclInfoExistsCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int TclInfoExistsCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclInfoCoroutineCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int TclInfoCoroutineCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Obj * TclInfoFrame(Tcl_Interp *interp, CmdFrame *framePtr); -MODULE_SCOPE int TclInfoGlobalsCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int TclInfoGlobalsCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclInfoLocalsCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int TclInfoLocalsCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclInfoVarsCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int TclInfoVarsCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE void TclInitAlloc(void); MODULE_SCOPE void TclInitDbCkalloc(void); @@ -3304,18 +3304,18 @@ MODULE_SCOPE Tcl_Obj * TclpTempFileNameForLibrary(Tcl_Interp *interp, Tcl_Obj* pathPtr); MODULE_SCOPE Tcl_Obj * TclNewFSPathObj(Tcl_Obj *dirPtr, const char *addStrRep, int len); -MODULE_SCOPE void TclpAlertNotifier(ClientData clientData); -MODULE_SCOPE ClientData TclpNotifierData(void); +MODULE_SCOPE void TclpAlertNotifier(void *clientData); +MODULE_SCOPE void *TclpNotifierData(void); MODULE_SCOPE void TclpServiceModeHook(int mode); MODULE_SCOPE void TclpSetTimer(const Tcl_Time *timePtr); MODULE_SCOPE int TclpWaitForEvent(const Tcl_Time *timePtr); MODULE_SCOPE void TclpCreateFileHandler(int fd, int mask, - Tcl_FileProc *proc, ClientData clientData); + Tcl_FileProc *proc, void *clientData); MODULE_SCOPE int TclpDeleteFile(const void *path); MODULE_SCOPE void TclpDeleteFileHandler(int fd); MODULE_SCOPE void TclpFinalizeCondition(Tcl_Condition *condPtr); MODULE_SCOPE void TclpFinalizeMutex(Tcl_Mutex *mutexPtr); -MODULE_SCOPE void TclpFinalizeNotifier(ClientData clientData); +MODULE_SCOPE void TclpFinalizeNotifier(void *clientData); MODULE_SCOPE void TclpFinalizePipes(void); MODULE_SCOPE void TclpFinalizeSockets(void); MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp, @@ -3323,13 +3323,13 @@ MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp, const char *host, int port, int willBind, const char **errorMsgPtr); MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr, - Tcl_ThreadCreateProc *proc, ClientData clientData, + Tcl_ThreadCreateProc *proc, void *clientData, int stackSize, int flags); MODULE_SCOPE int TclpFindVariable(const char *name, int *lengthPtr); MODULE_SCOPE void TclpInitLibraryPath(char **valuePtr, TCL_HASH_TYPE *lengthPtr, Tcl_Encoding *encodingPtr); MODULE_SCOPE void TclpInitLock(void); -MODULE_SCOPE ClientData TclpInitNotifier(void); +MODULE_SCOPE void *TclpInitNotifier(void); MODULE_SCOPE void TclpInitPlatform(void); MODULE_SCOPE void TclpInitUnlock(void); MODULE_SCOPE Tcl_Obj * TclpObjListVolumes(void); @@ -3348,7 +3348,7 @@ MODULE_SCOPE int TclCrossFilesystemCopy(Tcl_Interp *interp, MODULE_SCOPE int TclpMatchInDirectory(Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); -MODULE_SCOPE ClientData TclpGetNativeCwd(ClientData clientData); +MODULE_SCOPE void *TclpGetNativeCwd(void *clientData); MODULE_SCOPE Tcl_FSDupInternalRepProc TclNativeDupInternalRep; MODULE_SCOPE Tcl_Obj * TclpObjLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkType); @@ -3437,7 +3437,7 @@ MODULE_SCOPE int TclUtfCount(int ch); MODULE_SCOPE int TclUniCharToUCS4(const Tcl_UniChar *, int *); MODULE_SCOPE const Tcl_UniChar *TclUCS4Prev(const Tcl_UniChar *, const Tcl_UniChar *); #endif -MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData); +MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(void *clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, @@ -3533,60 +3533,60 @@ MODULE_SCOPE int TclIsSpaceProc(int byte); *---------------------------------------------------------------- */ -MODULE_SCOPE int Tcl_AfterObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_AfterObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_AppendObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_AppendObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ApplyObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ApplyObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitArrayCmd(Tcl_Interp *interp); MODULE_SCOPE Tcl_Command TclInitBinaryCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_BreakObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_BreakObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #if !defined(TCL_NO_DEPRECATED) -MODULE_SCOPE int Tcl_CaseObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_CaseObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); #endif -MODULE_SCOPE int Tcl_CatchObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_CatchObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_CdObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_CdObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitChanCmd(Tcl_Interp *interp); -MODULE_SCOPE int TclChanCreateObjCmd(ClientData clientData, +MODULE_SCOPE int TclChanCreateObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclChanPostEventObjCmd(ClientData clientData, +MODULE_SCOPE int TclChanPostEventObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclChanPopObjCmd(ClientData clientData, +MODULE_SCOPE int TclChanPopObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclChanPushObjCmd(ClientData clientData, +MODULE_SCOPE int TclChanPushObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE void TclClockInit(Tcl_Interp *interp); MODULE_SCOPE int TclClockOldscanObjCmd( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_CloseObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_CloseObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ConcatObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ConcatObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ContinueObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ContinueObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler( Tcl_Time *timePtr, Tcl_TimerProc *proc, - ClientData clientData); + void *clientData); MODULE_SCOPE int TclDefaultBgErrorHandlerObjCmd( - ClientData clientData, Tcl_Interp *interp, + void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp); MODULE_SCOPE int TclDictWithFinish(Tcl_Interp *interp, Var *varPtr, @@ -3595,236 +3595,236 @@ MODULE_SCOPE int TclDictWithFinish(Tcl_Interp *interp, Var *varPtr, Tcl_Obj *const pathv[], Tcl_Obj *keysPtr); MODULE_SCOPE Tcl_Obj * TclDictWithInit(Tcl_Interp *interp, Tcl_Obj *dictPtr, int pathc, Tcl_Obj *const pathv[]); -MODULE_SCOPE int Tcl_DisassembleObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_DisassembleObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* Assemble command function */ -MODULE_SCOPE int Tcl_AssembleObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_AssembleObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclNRAssembleObjCmd(ClientData clientData, +MODULE_SCOPE int TclNRAssembleObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitEncodingCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_EofObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_EofObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ErrorObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ErrorObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_EvalObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_EvalObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ExecObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ExecObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ExitObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ExitObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ExprObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ExprObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_FblockedObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_FblockedObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_FconfigureObjCmd( - ClientData clientData, Tcl_Interp *interp, + void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_FcopyObjCmd(ClientData dummy, +MODULE_SCOPE int Tcl_FcopyObjCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitFileCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_FileEventObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_FileEventObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_FlushObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_FlushObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ForObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ForObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ForeachObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ForeachObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_FormatObjCmd(ClientData dummy, +MODULE_SCOPE int Tcl_FormatObjCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_GetsObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_GetsObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_GlobalObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_GlobalObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_GlobObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_GlobObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_IfObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_IfObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_IncrObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_IncrObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitInfoCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_InterpObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_InterpObjCmd(void *clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_JoinObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_JoinObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LappendObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LappendObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LassignObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LassignObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LindexObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LindexObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LinsertObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LinsertObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LlengthObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LlengthObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ListObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ListObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LmapObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LmapObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LoadObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LoadObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LpopObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LpopObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LrangeObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LrangeObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LremoveObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LremoveObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LrepeatObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LrepeatObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LreplaceObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LreplaceObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LreverseObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LreverseObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LsearchObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LsearchObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LsetObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LsetObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_LsortObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_LsortObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitNamespaceCmd(Tcl_Interp *interp); -MODULE_SCOPE int TclNamespaceEnsembleCmd(ClientData dummy, +MODULE_SCOPE int TclNamespaceEnsembleCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_OpenObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_OpenObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_PackageObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_PackageObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_PidObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_PidObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitPrefixCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_PutsObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_PutsObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_PwdObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_PwdObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ReadObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ReadObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_RegexpObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_RegexpObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_RegsubObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_RegsubObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_RenameObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_RenameObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_RepresentationCmd(ClientData clientData, +MODULE_SCOPE int Tcl_RepresentationCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ReturnObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ReturnObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ScanObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_ScanObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SeekObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SeekObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SetObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SetObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SplitObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SplitObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SocketObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SocketObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SourceObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SourceObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitStringCmd(Tcl_Interp *interp); -MODULE_SCOPE int Tcl_SubstObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SubstObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_SwitchObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_SwitchObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_TellObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_TellObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_ThrowObjCmd(ClientData dummy, Tcl_Interp *interp, +MODULE_SCOPE int Tcl_ThrowObjCmd(void *dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_TimeObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_TimeObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_TimeRateObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_TimeRateObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_TraceObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_TraceObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_TryObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_TryObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_UnloadObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_UnloadObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_UnsetObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_UnsetObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_UpdateObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_UpdateObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_UplevelObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_UplevelObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_UpvarObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_UpvarObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_VariableObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_VariableObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_VwaitObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_VwaitObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_WhileObjCmd(ClientData clientData, +MODULE_SCOPE int Tcl_WhileObjCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -4156,103 +4156,103 @@ MODULE_SCOPE int TclCompileBasicMin2ArgCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclInvertOpCmd(ClientData clientData, +MODULE_SCOPE int TclInvertOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileInvertOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclNotOpCmd(ClientData clientData, +MODULE_SCOPE int TclNotOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileNotOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclAddOpCmd(ClientData clientData, +MODULE_SCOPE int TclAddOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileAddOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclMulOpCmd(ClientData clientData, +MODULE_SCOPE int TclMulOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileMulOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclAndOpCmd(ClientData clientData, +MODULE_SCOPE int TclAndOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileAndOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclOrOpCmd(ClientData clientData, +MODULE_SCOPE int TclOrOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileOrOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclXorOpCmd(ClientData clientData, +MODULE_SCOPE int TclXorOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileXorOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclPowOpCmd(ClientData clientData, +MODULE_SCOPE int TclPowOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompilePowOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclLshiftOpCmd(ClientData clientData, +MODULE_SCOPE int TclLshiftOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileLshiftOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclRshiftOpCmd(ClientData clientData, +MODULE_SCOPE int TclRshiftOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileRshiftOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclModOpCmd(ClientData clientData, +MODULE_SCOPE int TclModOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileModOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclNeqOpCmd(ClientData clientData, +MODULE_SCOPE int TclNeqOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileNeqOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclStrneqOpCmd(ClientData clientData, +MODULE_SCOPE int TclStrneqOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileStrneqOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclInOpCmd(ClientData clientData, +MODULE_SCOPE int TclInOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileInOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclNiOpCmd(ClientData clientData, +MODULE_SCOPE int TclNiOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileNiOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclMinusOpCmd(ClientData clientData, +MODULE_SCOPE int TclMinusOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileMinusOpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); -MODULE_SCOPE int TclDivOpCmd(ClientData clientData, +MODULE_SCOPE int TclDivOpCmd(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclCompileDivOpCmd(Tcl_Interp *interp, @@ -5336,7 +5336,7 @@ void Tcl_Panic(const char *, ...) __attribute__((analyzer_noreturn)); typedef struct NRE_callback { Tcl_NRPostProc *procPtr; - ClientData data[4]; + void *data[4]; struct NRE_callback *nextPtr; } NRE_callback; @@ -5351,10 +5351,10 @@ typedef struct NRE_callback { NRE_callback *_callbackPtr; \ TCLNR_ALLOC((interp), (_callbackPtr)); \ _callbackPtr->procPtr = (postProcPtr); \ - _callbackPtr->data[0] = (ClientData)(data0); \ - _callbackPtr->data[1] = (ClientData)(data1); \ - _callbackPtr->data[2] = (ClientData)(data2); \ - _callbackPtr->data[3] = (ClientData)(data3); \ + _callbackPtr->data[0] = (void *)(data0); \ + _callbackPtr->data[1] = (void *)(data1); \ + _callbackPtr->data[2] = (void *)(data2); \ + _callbackPtr->data[3] = (void *)(data3); \ _callbackPtr->nextPtr = TOP_CB(interp); \ TOP_CB(interp) = _callbackPtr; \ } while (0) @@ -5410,8 +5410,8 @@ typedef struct NRE_callback { * Other externals. */ -MODULE_SCOPE size_t TclEnvEpoch; /* Epoch of the tcl environment - * (if changed with tcl-env). */ +MODULE_SCOPE size_t TclEnvEpoch; /* Epoch of the tcl environment + * (if changed with tcl-env). */ #endif /* _TCLINT */ diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 0d3b5a0..7a702e0 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -249,27 +249,6 @@ ListSpanNew( /* *------------------------------------------------------------------------ * - * ListSpanIncrRefs -- - * - * Increments the reference count on the spanPtr - * - * Results: - * None. - * - * Side effects: - * The obvious. - * - *------------------------------------------------------------------------ - */ -static inline void -ListSpanIncrRefs(ListSpan *spanPtr) -{ - spanPtr->refCount += 1; -} - -/* - *------------------------------------------------------------------------ - * * ListSpanDecrRefs -- * * Decrements the reference count on a span, freeing the memory if @@ -620,6 +599,7 @@ ListRepUnsharedShiftDown(ListRep *repPtr, ListSizeT shiftCount) * *------------------------------------------------------------------------ */ +#if 0 static inline void ListRepUnsharedShiftUp(ListRep *repPtr, ListSizeT shiftCount) { @@ -648,6 +628,7 @@ ListRepUnsharedShiftUp(ListRep *repPtr, ListSizeT shiftCount) LISTREP_CHECK(repPtr); } +#endif /* *------------------------------------------------------------------------ -- cgit v0.12 From 2ad836a4e03d557997264f6e8647abcb34cdaa64 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 1 Sep 2022 15:40:55 +0000 Subject: Fix [36ec49db6abc3b1a]: Tcl_TraceVar manpage : missing `const` on char* fields --- doc/TraceVar.3 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/TraceVar.3 b/doc/TraceVar.3 index c3edfa4..3d506b3 100644 --- a/doc/TraceVar.3 +++ b/doc/TraceVar.3 @@ -126,8 +126,8 @@ It should have arguments and result that match the type typedef char *\fBTcl_VarTraceProc\fR( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, - char *\fIname1\fR, - char *\fIname2\fR, + const char *\fIname1\fR, + const char *\fIname2\fR, int \fIflags\fR); .CE .PP -- cgit v0.12 From 9cc16840e841d6cf4f857d9853838cd86f42b48d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 2 Sep 2022 12:32:10 +0000 Subject: -1 -> TCL_INDEX_NONE, where appropriate --- generic/tclTest.c | 174 +++++++++++++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 82 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index 8d106f9..d13b7ce 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -560,6 +560,12 @@ Tcltest_Init( } if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) { +#if TCL_MAJOR_VERSION > 8 + if (info.isNativeObjectProc == 2) { + Tcl_CreateObjCommand2(interp, "::tcl::test::build-info", + info.objProc2, (void *)version, NULL); + } else +#endif Tcl_CreateObjCommand(interp, "::tcl::test::build-info", info.objProc, (void *)version, NULL); } @@ -772,7 +778,7 @@ Tcltest_Init( return TCL_ERROR; } case 3: - if (objc-1) { + if (objc > 1) { Tcl_SetVar2Ex(interp, "tcl_rcFileName", NULL, objv[1], TCL_GLOBAL_ONLY); } @@ -817,6 +823,12 @@ Tcltest_SafeInit( return TCL_ERROR; } if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) { +#if TCL_MAJOR_VERSION > 8 + if (info.isNativeObjectProc == 2) { + Tcl_CreateObjCommand2(interp, "::tcl::test::build-info", + info.objProc2, (void *)version, NULL); + } else +#endif Tcl_CreateObjCommand(interp, "::tcl::test::build-info", info.objProc, (void *)version, NULL); } @@ -927,7 +939,7 @@ TestasyncCmd( break; } } - Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], TCL_INDEX_NONE)); Tcl_MutexUnlock(&asyncTestMutex); return code; } else if (strcmp(argv[1], "marklater") == 0) { @@ -995,7 +1007,7 @@ AsyncHandlerProc( listArgv[3] = NULL; cmd = Tcl_Merge(3, listArgv); if (interp != NULL) { - code = Tcl_EvalEx(interp, cmd, -1, 0); + code = Tcl_EvalEx(interp, cmd, TCL_INDEX_NONE, 0); } else { /* * this should not happen, but by definition of how async handlers are @@ -1176,8 +1188,8 @@ CmdDelProc1( void *clientData) /* String to save. */ { Tcl_DStringInit(&delString); - Tcl_DStringAppend(&delString, "CmdDelProc1 ", -1); - Tcl_DStringAppend(&delString, (char *) clientData, -1); + Tcl_DStringAppend(&delString, "CmdDelProc1 ", TCL_INDEX_NONE); + Tcl_DStringAppend(&delString, (char *) clientData, TCL_INDEX_NONE); } static void @@ -1185,8 +1197,8 @@ CmdDelProc2( void *clientData) /* String to save. */ { Tcl_DStringInit(&delString); - Tcl_DStringAppend(&delString, "CmdDelProc2 ", -1); - Tcl_DStringAppend(&delString, (char *) clientData, -1); + Tcl_DStringAppend(&delString, "CmdDelProc2 ", TCL_INDEX_NONE); + Tcl_DStringAppend(&delString, (char *) clientData, TCL_INDEX_NONE); } /* @@ -1306,7 +1318,7 @@ TestcmdtraceCmd( if (strcmp(argv[1], "tracetest") == 0) { Tcl_DStringInit(&buffer); cmdTrace = Tcl_CreateTrace(interp, 50000, CmdTraceProc, &buffer); - result = Tcl_EvalEx(interp, argv[2], -1, 0); + result = Tcl_EvalEx(interp, argv[2], TCL_INDEX_NONE, 0); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); @@ -1322,13 +1334,13 @@ TestcmdtraceCmd( */ cmdTrace = Tcl_CreateTrace(interp, 50000, CmdTraceDeleteProc, NULL); - Tcl_EvalEx(interp, argv[2], -1, 0); + Tcl_EvalEx(interp, argv[2], TCL_INDEX_NONE, 0); } else if (strcmp(argv[1], "leveltest") == 0) { Interp *iPtr = (Interp *) interp; Tcl_DStringInit(&buffer); cmdTrace = Tcl_CreateTrace(interp, iPtr->numLevels + 4, CmdTraceProc, &buffer); - result = Tcl_EvalEx(interp, argv[2], -1, 0); + result = Tcl_EvalEx(interp, argv[2], TCL_INDEX_NONE, 0); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); @@ -1346,7 +1358,7 @@ TestcmdtraceCmd( cmdTrace = Tcl_CreateObjTrace(interp, 50000, TCL_ALLOW_INLINE_COMPILATION, ObjTraceProc, &deleteCalled, ObjTraceDeleteProc); - result = Tcl_EvalEx(interp, argv[2], -1, 0); + result = Tcl_EvalEx(interp, argv[2], TCL_INDEX_NONE, 0); Tcl_DeleteTrace(interp, cmdTrace); if (!deleteCalled) { Tcl_AppendResult(interp, "Delete wasn't called", NULL); @@ -1360,7 +1372,7 @@ TestcmdtraceCmd( Tcl_DStringInit(&buffer); t1 = Tcl_CreateTrace(interp, 1, CmdTraceProc, &buffer); t2 = Tcl_CreateTrace(interp, 50000, CmdTraceProc, &buffer); - result = Tcl_EvalEx(interp, argv[2], -1, 0); + result = Tcl_EvalEx(interp, argv[2], TCL_INDEX_NONE, 0); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); @@ -1435,7 +1447,7 @@ ObjTraceProc( const char *word = Tcl_GetString(objv[0]); if (!strcmp(word, "Error")) { - Tcl_SetObjResult(interp, Tcl_NewStringObj(command, -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(command, TCL_INDEX_NONE)); return TCL_ERROR; } else if (!strcmp(word, "Break")) { return TCL_BREAK; @@ -1684,7 +1696,7 @@ DelDeleteProc( { DelCmd *dPtr = (DelCmd *)clientData; - Tcl_EvalEx(dPtr->interp, dPtr->deleteCmd, -1, 0); + Tcl_EvalEx(dPtr->interp, dPtr->deleteCmd, TCL_INDEX_NONE, 0); Tcl_ResetResult(dPtr->interp); ckfree(dPtr->deleteCmd); ckfree(dPtr); @@ -1799,7 +1811,7 @@ TestdoubledigitsObjCmd( type = types[type]; if (objc > 4) { if (strcmp(Tcl_GetString(objv[4]), "shorten")) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("bad flag", -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj("bad flag", TCL_INDEX_NONE)); return TCL_ERROR; } type |= TCL_DD_SHORTEST; @@ -2043,7 +2055,7 @@ EncodingToUtfProc( TclEncoding *encodingPtr; encodingPtr = (TclEncoding *) clientData; - Tcl_EvalEx(encodingPtr->interp, encodingPtr->toUtfCmd, -1, TCL_EVAL_GLOBAL); + Tcl_EvalEx(encodingPtr->interp, encodingPtr->toUtfCmd, TCL_INDEX_NONE, TCL_EVAL_GLOBAL); len = strlen(Tcl_GetStringResult(encodingPtr->interp)); if (len > dstLen) { @@ -2075,7 +2087,7 @@ EncodingFromUtfProc( TclEncoding *encodingPtr; encodingPtr = (TclEncoding *) clientData; - Tcl_EvalEx(encodingPtr->interp, encodingPtr->fromUtfCmd, -1, TCL_EVAL_GLOBAL); + Tcl_EvalEx(encodingPtr->interp, encodingPtr->fromUtfCmd, TCL_INDEX_NONE, TCL_EVAL_GLOBAL); len = strlen(Tcl_GetStringResult(encodingPtr->interp)); if (len > dstLen) { @@ -3114,7 +3126,7 @@ TestlinkCmd( } } if (argv[6][0] != 0) { - tmp = Tcl_NewStringObj(argv[6], -1); + tmp = Tcl_NewStringObj(argv[6], TCL_INDEX_NONE); if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; @@ -3172,7 +3184,7 @@ TestlinkCmd( } if (argv[15][0]) { Tcl_WideInt w; - tmp = Tcl_NewStringObj(argv[15], -1); + tmp = Tcl_NewStringObj(argv[15], TCL_INDEX_NONE); if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; @@ -3222,7 +3234,7 @@ TestlinkCmd( Tcl_UpdateLinkedVar(interp, "string"); } if (argv[6][0] != 0) { - tmp = Tcl_NewStringObj(argv[6], -1); + tmp = Tcl_NewStringObj(argv[6], TCL_INDEX_NONE); if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; @@ -3289,7 +3301,7 @@ TestlinkCmd( } if (argv[15][0]) { Tcl_WideInt w; - tmp = Tcl_NewStringObj(argv[15], -1); + tmp = Tcl_NewStringObj(argv[15], TCL_INDEX_NONE); if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; @@ -3396,7 +3408,7 @@ TestlinkarrayCmd( return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[i++], &size) == TCL_ERROR) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong size value", -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong size value", TCL_INDEX_NONE)); return TCL_ERROR; } name = Tcl_GetString(objv[i++]); @@ -3408,7 +3420,7 @@ TestlinkarrayCmd( if (i < objc) { if (Tcl_GetWideIntFromObj(interp, objv[i], &addr) == TCL_ERROR) { Tcl_SetObjResult(interp, Tcl_NewStringObj( - "wrong address value", -1)); + "wrong address value", TCL_INDEX_NONE)); return TCL_ERROR; } } else { @@ -3504,7 +3516,7 @@ TestlistrepCmd( #define APPEND_FIELD(targetObj_, structPtr_, fld_) \ do { \ Tcl_ListObjAppendElement( \ - interp, (targetObj_), Tcl_NewStringObj(#fld_, -1)); \ + interp, (targetObj_), Tcl_NewStringObj(#fld_, TCL_INDEX_NONE)); \ Tcl_ListObjAppendElement( \ interp, (targetObj_), Tcl_NewWideIntObj((structPtr_)->fld_)); \ } while (0) @@ -3522,10 +3534,10 @@ TestlistrepCmd( return TCL_ERROR; } ListObjGetRep(objv[2], &listRep); - listRepObjs[0] = Tcl_NewStringObj("store", -1); + listRepObjs[0] = Tcl_NewStringObj("store", TCL_INDEX_NONE); listRepObjs[1] = Tcl_NewListObj(12, NULL); Tcl_ListObjAppendElement( - interp, listRepObjs[1], Tcl_NewStringObj("memoryAddress", -1)); + interp, listRepObjs[1], Tcl_NewStringObj("memoryAddress", TCL_INDEX_NONE)); Tcl_ListObjAppendElement( interp, listRepObjs[1], Tcl_ObjPrintf("%p", listRep.storePtr)); APPEND_FIELD(listRepObjs[1], listRep.storePtr, firstUsed); @@ -3534,11 +3546,11 @@ TestlistrepCmd( APPEND_FIELD(listRepObjs[1], listRep.storePtr, refCount); APPEND_FIELD(listRepObjs[1], listRep.storePtr, flags); if (listRep.spanPtr) { - listRepObjs[2] = Tcl_NewStringObj("span", -1); + listRepObjs[2] = Tcl_NewStringObj("span", TCL_INDEX_NONE); listRepObjs[3] = Tcl_NewListObj(8, NULL); Tcl_ListObjAppendElement(interp, listRepObjs[3], - Tcl_NewStringObj("memoryAddress", -1)); + Tcl_NewStringObj("memoryAddress", TCL_INDEX_NONE)); Tcl_ListObjAppendElement( interp, listRepObjs[3], Tcl_ObjPrintf("%p", listRep.spanPtr)); APPEND_FIELD(listRepObjs[3], listRep.spanPtr, spanStart); @@ -3558,7 +3570,7 @@ TestlistrepCmd( } resultObj = Tcl_NewListObj(2, NULL); Tcl_ListObjAppendElement( - NULL, resultObj, Tcl_NewStringObj("LIST_SPAN_THRESHOLD", -1)); + NULL, resultObj, Tcl_NewStringObj("LIST_SPAN_THRESHOLD", TCL_INDEX_NONE)); Tcl_ListObjAppendElement( NULL, resultObj, Tcl_NewWideIntObj(LIST_SPAN_THRESHOLD)); break; @@ -3632,7 +3644,7 @@ TestlocaleCmd( } locale = setlocale(lcTypes[index], locale); if (locale) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), locale, -1); + Tcl_SetStringObj(Tcl_GetObjResult(interp), locale, TCL_INDEX_NONE); } return TCL_OK; } @@ -3854,7 +3866,7 @@ PrintParse( break; } Tcl_ListObjAppendElement(NULL, objPtr, - Tcl_NewStringObj(typeString, -1)); + Tcl_NewStringObj(typeString, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(tokenPtr->start, tokenPtr->size)); Tcl_ListObjAppendElement(NULL, objPtr, @@ -3863,7 +3875,7 @@ PrintParse( Tcl_ListObjAppendElement(NULL, objPtr, parsePtr->commandStart ? Tcl_NewStringObj(parsePtr->commandStart + parsePtr->commandSize, - -1) : Tcl_NewObj()); + TCL_INDEX_NONE) : Tcl_NewObj()); } /* @@ -4182,7 +4194,7 @@ TestregexpObjCmd( char resinfo[TCL_INTEGER_SPACE * 2]; varName = Tcl_GetString(objv[2]); - TclRegExpRangeUniChar(regExpr, -1, &start, &end); + TclRegExpRangeUniChar(regExpr, TCL_INDEX_NONE, &start, &end); sprintf(resinfo, "%d %d", start, end-1); value = Tcl_SetVar2(interp, varName, NULL, resinfo, 0); if (value == NULL) { @@ -4222,15 +4234,15 @@ TestregexpObjCmd( Tcl_Obj *newPtr, *varPtr, *valuePtr; varPtr = objv[i]; - ii = ((cflags®_EXPECT) && i == objc-1) ? -1 : i; + ii = ((cflags®_EXPECT) && i == objc-1) ? TCL_INDEX_NONE : i; if (indices) { Tcl_Obj *objs[2]; - if (ii == -1) { + if (ii == TCL_INDEX_NONE) { TclRegExpRangeUniChar(regExpr, ii, &start, &end); } else if (ii > info.nsubs) { - start = -1; - end = -1; + start = TCL_INDEX_NONE; + end = TCL_INDEX_NONE; } else { start = info.matches[ii].start; end = info.matches[ii].end; @@ -4250,7 +4262,7 @@ TestregexpObjCmd( newPtr = Tcl_NewListObj(2, objs); } else { - if (ii == -1) { + if (ii == TCL_INDEX_NONE) { TclRegExpRangeUniChar(regExpr, ii, &start, &end); newPtr = Tcl_GetRange(objPtr, start, end); } else if (ii > info.nsubs || info.matches[ii].end <= 0) { @@ -4298,7 +4310,8 @@ TestregexpXflags( int *cflagsPtr, /* compile flags word */ int *eflagsPtr) /* exec flags word */ { - int i, cflags, eflags; + int i; + int cflags, eflags; cflags = *cflagsPtr; eflags = *eflagsPtr; @@ -4756,7 +4769,7 @@ TestfeventCmd( return TCL_ERROR; } if (interp2 != NULL) { - code = Tcl_EvalEx(interp2, argv[2], -1, TCL_EVAL_GLOBAL); + code = Tcl_EvalEx(interp2, argv[2], TCL_INDEX_NONE, TCL_EVAL_GLOBAL); Tcl_SetObjResult(interp, Tcl_GetObjResult(interp2)); return code; } else { @@ -5050,15 +5063,15 @@ GetTimesObjCmd( ckfree(objv); /* TclGetString 100000 times */ - fprintf(stderr, "TclGetStringFromObj of \"12345\" 100000 times\n"); - objPtr = Tcl_NewStringObj("12345", -1); + fprintf(stderr, "Tcl_GetStringFromObj of \"12345\" 100000 times\n"); + objPtr = Tcl_NewStringObj("12345", TCL_INDEX_NONE); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { (void) TclGetString(objPtr); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); - fprintf(stderr, " %.3f usec per TclGetStringFromObj of \"12345\"\n", + fprintf(stderr, " %.3f usec per Tcl_GetStringFromObj of \"12345\"\n", timePer/100000); /* Tcl_GetIntFromObj 100000 times */ @@ -5398,7 +5411,7 @@ Testutf16stringObjCmd( } p = Tcl_GetUnicode(objv[1]); - Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(p, -1)); + Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(p, TCL_INDEX_NONE)); return TCL_OK; } @@ -5536,7 +5549,7 @@ TestsaveresultCmd( } freeCount = 0; - objPtr = NULL; /* Lint. */ + objPtr = NULL; switch ((enum options) index) { case RESULT_SMALL: Tcl_AppendResult(interp, "small result", NULL); @@ -5555,7 +5568,7 @@ TestsaveresultCmd( Tcl_SetResult(interp, (char *)"dynamic result", TestsaveresultFree); break; case RESULT_OBJECT: - objPtr = Tcl_NewStringObj("object result", -1); + objPtr = Tcl_NewStringObj("object result", TCL_INDEX_NONE); Tcl_SetObjResult(interp, objPtr); break; } @@ -5565,7 +5578,7 @@ TestsaveresultCmd( if (((enum options) index) == RESULT_OBJECT) { result = Tcl_EvalObjEx(interp, objv[2], 0); } else { - result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), -1, 0); + result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0); } if (discard) { @@ -5817,7 +5830,7 @@ TestChannelCmd( if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerror", len) == 0)) { - Tcl_Obj *msg = Tcl_NewStringObj(argv[3],-1); + Tcl_Obj *msg = Tcl_NewStringObj(argv[3], TCL_INDEX_NONE); Tcl_IncrRefCount(msg); Tcl_SetChannelError(chan, msg); @@ -5830,7 +5843,7 @@ TestChannelCmd( } if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerrorinterp", len) == 0)) { - Tcl_Obj *msg = Tcl_NewStringObj(argv[3],-1); + Tcl_Obj *msg = Tcl_NewStringObj(argv[3], TCL_INDEX_NONE); Tcl_IncrRefCount(msg); Tcl_SetChannelErrorInterp(interp, msg); @@ -6178,7 +6191,7 @@ TestChannelCmd( } return TclChannelTransform(interp, chan, - Tcl_NewStringObj(argv[4], -1)); + Tcl_NewStringObj(argv[4], TCL_INDEX_NONE)); } if ((cmdName[0] == 'u') && (strncmp(cmdName, "unstack", len) == 0)) { @@ -6269,7 +6282,7 @@ TestChannelEventCmd( esPtr->chanPtr = chanPtr; esPtr->interp = interp; esPtr->mask = mask; - esPtr->scriptPtr = Tcl_NewStringObj(argv[4], -1); + esPtr->scriptPtr = Tcl_NewStringObj(argv[4], TCL_INDEX_NONE); Tcl_IncrRefCount(esPtr->scriptPtr); Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, @@ -6336,10 +6349,10 @@ TestChannelEventCmd( esPtr = esPtr->nextPtr) { if (esPtr->mask) { Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj( - (esPtr->mask == TCL_READABLE) ? "readable" : "writable", -1)); + (esPtr->mask == TCL_READABLE) ? "readable" : "writable", TCL_INDEX_NONE)); } else { Tcl_ListObjAppendElement(interp, resultListPtr, - Tcl_NewStringObj("none", -1)); + Tcl_NewStringObj("none", TCL_INDEX_NONE)); } Tcl_ListObjAppendElement(interp, resultListPtr, esPtr->scriptPtr); } @@ -6551,16 +6564,12 @@ TestWrongNumArgsObjCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - int i, length; + int i; + int length; const char *msg; if (objc < 3) { - /* - * Don't use Tcl_WrongNumArgs here, as that is the function - * we want to test! - */ - Tcl_AppendResult(interp, "insufficient arguments", NULL); - return TCL_ERROR; + goto insufArgs; } if (Tcl_GetIntFromObj(interp, objv[1], &i) != TCL_OK) { @@ -6576,6 +6585,7 @@ TestWrongNumArgsObjCmd( /* * Asked for more arguments than were given. */ + insufArgs: Tcl_AppendResult(interp, "insufficient arguments", NULL); return TCL_ERROR; } @@ -6686,7 +6696,7 @@ TestFilesystemObjCmd( res = Tcl_FSUnregister(&testReportingFilesystem); msg = (res == TCL_OK) ? "unregistered" : "failed"; } - Tcl_SetObjResult(interp, Tcl_NewStringObj(msg , -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(msg , TCL_INDEX_NONE)); return res; } @@ -6768,7 +6778,7 @@ TestReport( Tcl_DString ds; Tcl_DStringInit(&ds); - Tcl_DStringAppend(&ds, "lappend filesystemReport ", -1); + Tcl_DStringAppend(&ds, "lappend filesystemReport ", TCL_INDEX_NONE); Tcl_DStringStartSublist(&ds); Tcl_DStringAppendElement(&ds, cmd); if (path != NULL) { @@ -6781,7 +6791,7 @@ TestReport( savedResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(savedResult); Tcl_SetObjResult(interp, Tcl_NewObj()); - Tcl_EvalEx(interp, Tcl_DStringValue(&ds), -1, 0); + Tcl_EvalEx(interp, Tcl_DStringValue(&ds), TCL_INDEX_NONE, 0); Tcl_DStringFree(&ds); Tcl_ResetResult(interp); Tcl_SetObjResult(interp, savedResult); @@ -7057,7 +7067,7 @@ TestSimpleFilesystemObjCmd( res = Tcl_FSUnregister(&simpleFilesystem); msg = (res == TCL_OK) ? "unregistered" : "failed"; } - Tcl_SetObjResult(interp, Tcl_NewStringObj(msg , -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(msg , TCL_INDEX_NONE)); return res; } @@ -7084,7 +7094,7 @@ SimpleRedirect( Tcl_IncrRefCount(pathPtr); return pathPtr; } - origPtr = Tcl_NewStringObj(str+10,-1); + origPtr = Tcl_NewStringObj(str+10, TCL_INDEX_NONE); Tcl_IncrRefCount(origPtr); return origPtr; } @@ -7184,7 +7194,7 @@ SimpleListVolumes(void) /* Add one new volume */ Tcl_Obj *retVal; - retVal = Tcl_NewStringObj("simplefs:/", -1); + retVal = Tcl_NewStringObj("simplefs:/", TCL_INDEX_NONE); Tcl_IncrRefCount(retVal); return retVal; } @@ -7304,7 +7314,7 @@ TestNumUtfCharsCmd( Tcl_Obj *const objv[]) { if (objc > 1) { - int numBytes, len, limit = -1; + int numBytes, len, limit = TCL_INDEX_NONE; const char *bytes = Tcl_GetStringFromObj(objv[1], &numBytes); if (objc > 2) { @@ -7338,7 +7348,7 @@ TestFindFirstCmd( if (objc > 2) { (void) Tcl_GetIntFromObj(interp, objv[2], &len); } - Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindFirst(Tcl_GetString(objv[1]), len), -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindFirst(Tcl_GetString(objv[1]), len), TCL_INDEX_NONE)); } return TCL_OK; } @@ -7360,7 +7370,7 @@ TestFindLastCmd( if (objc > 2) { (void) Tcl_GetIntFromObj(interp, objv[2], &len); } - Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindLast(Tcl_GetString(objv[1]), len), -1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindLast(Tcl_GetString(objv[1]), len), TCL_INDEX_NONE)); } return TCL_OK; } @@ -7437,7 +7447,7 @@ TestcpuidCmd( status = TclWinCPUID(index, regs); if (status != TCL_OK) { Tcl_SetObjResult(interp, - Tcl_NewStringObj("operation not available", -1)); + Tcl_NewStringObj("operation not available", TCL_INDEX_NONE)); return status; } for (i=0 ; i<4 ; ++i) { @@ -7483,7 +7493,7 @@ TestHashSystemHashCmd( hPtr = Tcl_CreateHashEntry(&hash, INT2PTR(i), &isNew); if (!isNew) { Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i)); - Tcl_AppendToObj(Tcl_GetObjResult(interp)," creation problem",-1); + Tcl_AppendToObj(Tcl_GetObjResult(interp)," creation problem", TCL_INDEX_NONE); Tcl_DeleteHashTable(&hash); return TCL_ERROR; } @@ -7500,13 +7510,13 @@ TestHashSystemHashCmd( hPtr = Tcl_FindHashEntry(&hash, (char *) INT2PTR(i)); if (hPtr == NULL) { Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i)); - Tcl_AppendToObj(Tcl_GetObjResult(interp)," lookup problem",-1); + Tcl_AppendToObj(Tcl_GetObjResult(interp)," lookup problem", TCL_INDEX_NONE); Tcl_DeleteHashTable(&hash); return TCL_ERROR; } if (PTR2INT(Tcl_GetHashValue(hPtr)) != i+42) { Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i)); - Tcl_AppendToObj(Tcl_GetObjResult(interp)," value problem",-1); + Tcl_AppendToObj(Tcl_GetObjResult(interp)," value problem", TCL_INDEX_NONE); Tcl_DeleteHashTable(&hash); return TCL_ERROR; } @@ -7589,9 +7599,9 @@ NREUnwind_callback( &none, NULL); } else { Tcl_Obj *idata[3]; - idata[0] = Tcl_NewWideIntObj((int) ((char *) data[1] - (char *) data[0])); - idata[1] = Tcl_NewWideIntObj((int) ((char *) data[2] - (char *) data[0])); - idata[2] = Tcl_NewWideIntObj((int) ((char *) &none - (char *) data[0])); + idata[0] = Tcl_NewWideIntObj(((char *) data[1] - (char *) data[0])); + idata[1] = Tcl_NewWideIntObj(((char *) data[2] - (char *) data[0])); + idata[2] = Tcl_NewWideIntObj(((char *) &none - (char *) data[0])); Tcl_SetObjResult(interp, Tcl_NewListObj(3, idata)); } return TCL_OK; @@ -7689,15 +7699,15 @@ TestconcatobjCmd( */ Tcl_SetObjResult(interp, - Tcl_NewStringObj("Tcl_ConcatObj is unsafe:", -1)); + Tcl_NewStringObj("Tcl_ConcatObj is unsafe:", TCL_INDEX_NONE)); emptyPtr = Tcl_NewObj(); - list1Ptr = Tcl_NewStringObj("foo bar sum", -1); + list1Ptr = Tcl_NewStringObj("foo bar sum", TCL_INDEX_NONE); Tcl_ListObjLength(NULL, list1Ptr, &len); Tcl_InvalidateStringRep(list1Ptr); - list2Ptr = Tcl_NewStringObj("eeny meeny", -1); + list2Ptr = Tcl_NewStringObj("eeny meeny", TCL_INDEX_NONE); Tcl_ListObjLength(NULL, list2Ptr, &len); Tcl_InvalidateStringRep(list2Ptr); @@ -8260,7 +8270,7 @@ InterpCompiledVarResolver( resVarInfo->vInfo.fetchProc = MyCompiledVarFetch; resVarInfo->vInfo.deleteProc = MyCompiledVarFree; resVarInfo->var = NULL; - resVarInfo->nameObj = Tcl_NewStringObj(name, -1); + resVarInfo->nameObj = Tcl_NewStringObj(name, TCL_INDEX_NONE); Tcl_IncrRefCount(resVarInfo->nameObj); *rPtr = &resVarInfo->vInfo; return TCL_OK; @@ -8344,12 +8354,12 @@ int TestApplyLambdaObjCmd ( /* Create a lambda {{} {set a 42}} */ lambdaObjs[0] = Tcl_NewObj(); /* No parameters */ - lambdaObjs[1] = Tcl_NewStringObj("set a 42", -1); /* Body */ + lambdaObjs[1] = Tcl_NewStringObj("set a 42", TCL_INDEX_NONE); /* Body */ lambdaObj = Tcl_NewListObj(2, lambdaObjs); Tcl_IncrRefCount(lambdaObj); /* Create the command "apply {{} {set a 42}" */ - evalObjs[0] = Tcl_NewStringObj("apply", -1); + evalObjs[0] = Tcl_NewStringObj("apply", TCL_INDEX_NONE); Tcl_IncrRefCount(evalObjs[0]); /* * NOTE: IMPORTANT TO EXHIBIT THE BUG. We duplicate the lambda because -- cgit v0.12 From ead37ca168eb29e8afc501d242116547534d619b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 2 Sep 2022 12:35:15 +0000 Subject: Bugfix for TIP #627: If only objProc or deleteProc is updated with Tcl_SetCommandInfo(), for a command registered with Tcl_CreateObjCmd2() ... --- generic/tclBasic.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 645a581..85b74b4 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -2690,26 +2690,30 @@ Tcl_CreateCommand( */ typedef struct { - void *clientData; /* Arbitrary value to pass to object function. */ Tcl_ObjCmdProc2 *proc; - Tcl_ObjCmdProc2 *nreProc; + void *clientData; /* Arbitrary value to pass to proc function. */ Tcl_CmdDeleteProc *deleteProc; + void *deleteData; /* Arbitrary value to pass to deleteProc function. */ + Tcl_ObjCmdProc2 *nreProc; } CmdWrapperInfo; static int cmdWrapperProc(void *clientData, - Tcl_Interp *interp, - int objc, + Tcl_Interp *interp, + int objc, Tcl_Obj * const *objv) { CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + if (objc < 0) { + objc = -1; + } return info->proc(info->clientData, interp, objc, objv); } static void cmdWrapperDeleteProc(void *clientData) { CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; - clientData = info->clientData; + clientData = info->deleteData; Tcl_CmdDeleteProc *deleteProc = info->deleteProc; ckfree(info); if (deleteProc != NULL) { @@ -2736,8 +2740,9 @@ Tcl_CreateObjCommand2( { CmdWrapperInfo *info = (CmdWrapperInfo *)ckalloc(sizeof(CmdWrapperInfo)); info->proc = proc; - info->deleteProc = deleteProc; info->clientData = clientData; + info->deleteProc = deleteProc; + info->deleteData = clientData; return Tcl_CreateObjCommand(interp, cmdName, (proc ? cmdWrapperProc : NULL), @@ -3380,7 +3385,7 @@ Tcl_SetCommandInfoFromToken( if (cmdPtr->deleteProc == cmdWrapperDeleteProc) { CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->deleteData; info->deleteProc = infoPtr->deleteProc; - info->clientData = infoPtr->deleteData; + info->deleteData = infoPtr->deleteData; } else { cmdPtr->deleteProc = infoPtr->deleteProc; cmdPtr->deleteData = infoPtr->deleteData; @@ -3464,7 +3469,7 @@ Tcl_GetCommandInfoFromToken( if (cmdPtr->deleteProc == cmdWrapperDeleteProc) { CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->deleteData; infoPtr->deleteProc = info->deleteProc; - infoPtr->deleteData = info->clientData; + infoPtr->deleteData = info->deleteData; } else { infoPtr->deleteProc = cmdPtr->deleteProc; infoPtr->deleteData = cmdPtr->deleteData; @@ -9256,9 +9261,10 @@ Tcl_NRCreateCommand2( { CmdWrapperInfo *info = (CmdWrapperInfo *)ckalloc(sizeof(CmdWrapperInfo)); info->proc = proc; + info->clientData = clientData; info->nreProc = nreProc; info->deleteProc = deleteProc; - info->clientData = clientData; + info->deleteData = clientData; return Tcl_NRCreateCommand(interp, cmdName, (proc ? cmdWrapperProc : NULL), (nreProc ? cmdWrapperNreProc : NULL), -- cgit v0.12 From a1e647c6847503d5c146857dd0435fac4caa7490 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 2 Sep 2022 13:54:04 +0000 Subject: Fix [95b6a1747a]: Eval.3 docu fix --- doc/Eval.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Eval.3 b/doc/Eval.3 index be1598a..1318fdb 100644 --- a/doc/Eval.3 +++ b/doc/Eval.3 @@ -54,7 +54,7 @@ ORed combination of flag bits that specify additional options. .AP "const char" *fileName in Name of a file containing a Tcl script. .AP int objc in -The number of values in the array pointed to by \fIobjPtr\fR; +The number of values in the array pointed to by \fIobjv\fR; this is also the number of words in the command. .AP Tcl_Obj **objv in Points to an array of pointers to values; each value holds the -- cgit v0.12 From f22c567b842667d01d4734847495c6b477244d97 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 2 Sep 2022 14:11:39 +0000 Subject: Mark httpold-4.12 knownBug. See [2641672]: http1.0 failing test: httpold-4.12 --- tests/httpold.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/httpold.test b/tests/httpold.test index 67ab119..e43a550 100644 --- a/tests/httpold.test +++ b/tests/httpold.test @@ -256,7 +256,7 @@ test httpold-4.11 {httpEvent} { http_reset $token http_status $token } {reset} -test httpold-4.12 {httpEvent} { +test httpold-4.12 {httpEvent See [2641672]} knownBug { update set x {} after 500 {lappend x ok} -- cgit v0.12 From 46cf6812fcfb415aae1696cf0b29cd2a6a77917a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 2 Sep 2022 15:16:30 +0000 Subject: TIP #627: Some more protection against invalid objc values --- generic/tclBasic.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 85b74b4..4bacba6 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -9192,6 +9192,11 @@ Tcl_NRCallObjProc2( size_t objc, Tcl_Obj *const objv[]) { + if (objc > INT_MAX) { + Tcl_WrongNumArgs(interp, 1, objv, "?args?"); + return TCL_ERROR; + } + NRE_callback *rootPtr = TOP_CB(interp); CmdWrapperInfo *info = (CmdWrapperInfo *)ckalloc(sizeof(CmdWrapperInfo)); info->clientData = clientData; @@ -9237,6 +9242,9 @@ static int cmdWrapperNreProc( Tcl_Obj *const objv[]) { CmdWrapperInfo *info = (CmdWrapperInfo *)clientData; + if (objc < 0) { + objc = -1; + } return info->nreProc(info->clientData, interp, objc, objv); } -- cgit v0.12 From 3fa8112c7afe69df643dcccb9570e698f2173da4 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 2 Sep 2022 17:02:56 +0000 Subject: really closes [2641672fff] - resolved timing sensitivity of httpold-4.12 and speed-up all httpd depending tests (removed 50ms delay unneeded in other cases) --- tests/httpd | 6 +++++- tests/httpold.test | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/httpd b/tests/httpd index 3cf2170..9fd23e7 100644 --- a/tests/httpd +++ b/tests/httpd @@ -45,7 +45,7 @@ proc httpdAccept {newsock ipaddr port} { fconfigure $newsock -blocking 0 -translation {auto crlf} httpd_log $newsock Connect $ipaddr $port set data(ipaddr) $ipaddr - after 50 [list fileevent $newsock readable [list httpdRead $newsock]] + fileevent $newsock readable [list httpdRead $newsock] } # read data from a client request @@ -69,6 +69,10 @@ proc httpdRead { sock } { httpd_log $sock Error "bad first line:$line" httpdSockDone $sock } + if {[regexp {[\?&]delay=([^&]+)} val]} { + fileevent $sock readable {} + after $val [list fileevent $sock readable [list httpdRead $sock]] + } return } elseif {$data(state) == "mime"} { diff --git a/tests/httpold.test b/tests/httpold.test index e43a550..439ce92 100644 --- a/tests/httpold.test +++ b/tests/httpold.test @@ -256,14 +256,21 @@ test httpold-4.11 {httpEvent} { http_reset $token http_status $token } {reset} -test httpold-4.12 {httpEvent See [2641672]} knownBug { +test httpold-4.12 {httpEvent} -body { + set tout {} update set x {} - after 500 {lappend x ok} - set token [http_get $url -timeout 1 -command {lappend x fail}] - vwait x - list [http_status $token] $x -} {timeout ok} + set token [http_get $url -query delay=500 -timeout 1 -command {lappend x fail}] + set i 0; while {$x eq {} && [incr i] < 50} { + set tout [after 20 {set x progress}] + vwait x + if {$x ne "progress"} break + set x [http_status $token] + } + set x +} -cleanup { + if {$tout ne {}} {after cancel $tout} +} -result timeout test httpold-5.1 {http_formatQuery} { http_formatQuery name1 value1 name2 "value two" -- cgit v0.12 From 337b5ab155b13596235bd36549efe9673cc6c7c9 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 2 Sep 2022 17:17:53 +0000 Subject: amend to [2641672fff], guarantees a delay to cause a timeout definitely + switch delay-argument from post to get (it expects delay in query string of url) --- tests/httpd | 2 +- tests/httpold.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/httpd b/tests/httpd index 9fd23e7..682556b 100644 --- a/tests/httpd +++ b/tests/httpd @@ -69,7 +69,7 @@ proc httpdRead { sock } { httpd_log $sock Error "bad first line:$line" httpdSockDone $sock } - if {[regexp {[\?&]delay=([^&]+)} val]} { + if {[regexp {(?:^|[\?&])delay=([^&]+)} $data(query) {} val]} { fileevent $sock readable {} after $val [list fileevent $sock readable [list httpdRead $sock]] } diff --git a/tests/httpold.test b/tests/httpold.test index 439ce92..e760c92 100644 --- a/tests/httpold.test +++ b/tests/httpold.test @@ -260,7 +260,7 @@ test httpold-4.12 {httpEvent} -body { set tout {} update set x {} - set token [http_get $url -query delay=500 -timeout 1 -command {lappend x fail}] + set token [http_get $url?delay=500 -timeout 1 -command {lappend x fail}] set i 0; while {$x eq {} && [incr i] < 50} { set tout [after 20 {set x progress}] vwait x -- cgit v0.12 From dc84ff9d0cfccec952277549d3b5031bd84c8860 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 3 Sep 2022 13:57:45 +0000 Subject: typo's --- unix/tclUnixSock.c | 4 ++-- win/tclWinSock.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index 1a54914..858afdb 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -418,7 +418,7 @@ TcpBlockModeProc( * * Side effects: * Processes socket events off the system queue. May process - * asynchroneous connects. + * asynchronous connects. * *---------------------------------------------------------------------- */ @@ -1328,7 +1328,7 @@ TcpConnect( } /* - * We need to forward the writable event that brought us here, bcasue + * We need to forward the writable event that brought us here, because * 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 diff --git a/win/tclWinSock.c b/win/tclWinSock.c index a05b8f6..a4547a8 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -566,7 +566,7 @@ TcpBlockModeProc( * * Side effects: * Processes socket events off the system queue. - * May process asynchroneous connect. + * May process asynchronous connect. * *---------------------------------------------------------------------- */ @@ -1706,7 +1706,7 @@ TcpConnect( continue; } /* - * For asynchroneous connect set the socket in nonblocking mode + * For asynchronous connect set the socket in nonblocking mode * and activate connect notification */ if (async_connect) { @@ -1794,7 +1794,7 @@ TcpConnect( /* * Clear the tsd socket list pointer if we did not wait for - * the FD_CONNECT asynchroneously + * the FD_CONNECT asynchronously */ tsdPtr->pendingTcpState = NULL; -- cgit v0.12 From df50b9ade238e19ef27748a4a037b384d70bdf0a Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 5 Sep 2022 10:30:34 +0000 Subject: closes [2641672fff], httpd - don't parse delay argument by error 400 (wrong URI/proto) --- tests/httpd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/httpd b/tests/httpd index 682556b..48e14ea 100644 --- a/tests/httpd +++ b/tests/httpd @@ -64,15 +64,15 @@ proc httpdRead { sock } { -> data(proto) data(url) data(query) data(httpversion)]} { set data(state) mime httpd_log $sock Query $line + if {[regexp {(?:^|[\?&])delay=([^&]+)} $data(query) {} val]} { + fileevent $sock readable {} + after $val [list fileevent $sock readable [list httpdRead $sock]] + } } else { httpdError $sock 400 httpd_log $sock Error "bad first line:$line" httpdSockDone $sock } - if {[regexp {(?:^|[\?&])delay=([^&]+)} $data(query) {} val]} { - fileevent $sock readable {} - after $val [list fileevent $sock readable [list httpdRead $sock]] - } return } elseif {$data(state) == "mime"} { -- cgit v0.12 From 1197ccadc0ba24b8f5dc9debc59ca25593067f64 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Mon, 5 Sep 2022 11:37:54 +0000 Subject: Ticket [55a02f20ec] - fallback to USERPROFILE when setting HOME env on Windows --- tests/env.test | 40 +++++++++++++++++++++++++++++++++++++++- win/tclWinInit.c | 9 ++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tests/env.test b/tests/env.test index 905cdab..ea58b26 100644 --- a/tests/env.test +++ b/tests/env.test @@ -105,6 +105,7 @@ variable keep { CommonProgramFiles CommonProgramFiles(x86) ProgramFiles ProgramFiles(x86) CommonProgramW6432 ProgramW6432 WINECONFIGDIR WINEDATADIR WINEDLLDIR0 WINEHOMEDIR PROCESSOR_ARCHITECTURE + USERPROFILE } variable printenvScript [makeFile [string map [list @keep@ [list $keep]] { @@ -409,7 +410,7 @@ test env-7.3 { return [info exists ::env(test7_3)] }} } -cleanup cleanup1 -result 1 - + test env-8.0 { memory usage - valgrind does not report reachable memory } -body { @@ -419,6 +420,43 @@ test env-8.0 { } -result {i'm with dummy} +test env-9.0 { + Initialization of HOME from HOMEDRIVE and HOMEPATH +} -constraints win -setup { + setup1 + unset -nocomplain ::env(HOME) + set ::env(HOMEDRIVE) X: + set ::env(HOMEPATH) \\home\\path +} -cleanup { + cleanup1 +} -body { + set pipe [open |[list [interpreter]] r+] + puts $pipe {puts $::env(HOME); flush stdout; exit} + flush $pipe + set result [gets $pipe] + close $pipe + set result +} -result {X:\home\path} + +test env-9.1 { + Initialization of HOME from USERPROFILE +} -constraints win -setup { + setup1 + unset -nocomplain ::env(HOME) + unset -nocomplain ::env(HOMEDRIVE) + unset -nocomplain ::env(HOMEPATH) +} -cleanup { + cleanup1 +} -body { + set pipe [open |[list [interpreter]] r+] + puts $pipe {puts $::env(HOME); flush stdout; exit} + flush $pipe + set result [gets $pipe] + close $pipe + set result +} -result $::env(USERPROFILE) + + # cleanup rename getenv {} diff --git a/win/tclWinInit.c b/win/tclWinInit.c index 4f59c1a..eae4404 100644 --- a/win/tclWinInit.c +++ b/win/tclWinInit.c @@ -593,7 +593,14 @@ TclpSetVariables( Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY); } else { - Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY); + /* None of HOME, HOMEDRIVE, HOMEPATH exists. Try USERPROFILE */ + ptr = Tcl_GetVar2(interp, "env", "USERPROFILE", TCL_GLOBAL_ONLY); + if (ptr != NULL && ptr[0]) { + Tcl_SetVar2(interp, "env", "HOME", ptr, TCL_GLOBAL_ONLY); + } else { + /* Last resort */ + Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY); + } } } -- cgit v0.12 From f0db029a8a8640d92c9f9e3fdd9571c65aa66539 Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 6 Sep 2022 00:25:31 +0000 Subject: Add explicit return to most commands. --- library/http/http.tcl | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 48e1b4b..fb30a5e 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -101,6 +101,7 @@ namespace eval http { array set socketWrQueue {} array set socketClosing {} array set socketPlayCmd {} + return } init @@ -230,6 +231,7 @@ proc http::config {args} { } set http($flag) $value } + return } } @@ -327,6 +329,7 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { } { http::CloseQueuedQueries $connId $token } + return } # http::KeepSocket - @@ -512,6 +515,7 @@ proc http::KeepSocket {token} { # There is no socketMapping($state(socketinfo)), so it does not matter # that CloseQueuedQueries is not called. } + return } # http::CheckEof - @@ -537,6 +541,7 @@ proc http::CheckEof {sock} { # will then be error-handled. CloseSocket $sock } + return } # http::CloseSocket - @@ -592,6 +597,7 @@ proc http::CloseSocket {s {token {}}} { Log "Error closing socket: $err" } } + return } # http::CloseQueuedQueries @@ -648,6 +654,7 @@ proc http::CloseQueuedQueries {connId {token {}}} { - token $token {*}$unfinished } + return } # http::Unset @@ -673,6 +680,7 @@ proc http::Unset {connId} { unset -nocomplain socketWrQueue($connId) unset -nocomplain socketClosing($connId) unset -nocomplain socketPlayCmd($connId) + return } # http::reset -- @@ -698,6 +706,7 @@ proc http::reset {token {why reset}} { unset state eval ::error $errorlist } + return } # http::geturl -- @@ -1601,6 +1610,7 @@ proc http::Connected {token proto phost srvurl} { Finish $token $err } } + return } # http::registerError @@ -1706,6 +1716,7 @@ proc http::DoneRequest {token} { # In the nonpipeline case, connection for reading always occurs. ReceiveResponse $token } + return } # http::ReceiveResponse @@ -1880,6 +1891,7 @@ proc http::NextPipelinedWrite {token} { #Log re-use nonpipeline, GRANT delayed write access to $token in NextP.. set socketWrState($connId) peNding } + return } # http::CancelReadPipeline @@ -1912,6 +1924,7 @@ proc http::CancelReadPipeline {name1 connId op} { } set socketRdQueue($connId) {} } + return } # http::CancelWritePipeline @@ -1945,6 +1958,7 @@ proc http::CancelWritePipeline {name1 connId op} { } set socketWrQueue($connId) {} } + return } # http::ReplayIfDead -- @@ -2078,6 +2092,7 @@ proc http::ReplayIfDead {tokenArg doing} { # to new values in ReplayCore. ReplayCore $newQueue + return } # http::ReplayIfClose -- @@ -2117,6 +2132,7 @@ proc http::ReplayIfClose {Wstate Rqueue Wqueue} { # 2. Cleanup - none needed, done by the caller. ReplayCore $newQueue + return } # http::ReInit -- @@ -2323,6 +2339,7 @@ proc http::ReplayCore {newQueue} { # Connect does its own fconfigure. fileevent $sock writable [list http::Connect $token {*}$tmpConnArgs] #Log ---- $sock << conn to $token for HTTP request (e) + return } # Data access functions: @@ -2374,7 +2391,7 @@ proc http::error {token} { if {[info exists state(error)]} { return $state(error) } - return "" + return } # http::cleanup @@ -2400,6 +2417,7 @@ proc http::cleanup {token} { if {[info exists state]} { unset state } + return } # http::Connect @@ -2443,6 +2461,7 @@ proc http::Connect {token proto phost srvurl} { fileevent $state(sock) writable {} ::http::Connected $token $proto $phost $srvurl } + return } # http::Write @@ -2547,6 +2566,7 @@ proc http::Write {token} { eval $state(-queryprogress) \ [list $token $state(querylength) $state(queryoffset)] } + return } # http::Event @@ -3059,6 +3079,7 @@ proc http::Event {sock token} { return } } + return } # http::TestForReplay @@ -3324,6 +3345,7 @@ proc http::CopyStart {sock token {initial 1}} { Finish $token $err } } + return } proc http::CopyChunk {token chunk} { @@ -3353,6 +3375,7 @@ proc http::CopyChunk {token chunk} { } Eot $token ;# FIX ME: pipelining. } + return } # http::CopyDone @@ -3383,6 +3406,7 @@ proc http::CopyDone {token count {error {}}} { } else { CopyStart $sock $token 0 } + return } # http::Eot @@ -3452,6 +3476,7 @@ proc http::Eot {token {reason {}}} { } } Finish $token $reason + return } # http::wait -- @@ -3550,6 +3575,8 @@ proc http::ProxyRequired {host} { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] + } else { + return } } @@ -3698,6 +3725,7 @@ proc http::GetFieldValue {headers fieldName} { proc http::make-transformation-chunked {chan command} { coroutine [namespace current]::dechunk$chan ::http::ReceiveChunked $chan $command chan event $chan readable [namespace current]::dechunk$chan + return } # Local variables: -- cgit v0.12 From e2d3a22117be56d8e4985323046560db17ad682b Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 6 Sep 2022 01:00:26 +0000 Subject: Refactor some variable, command and coroutine names. --- library/http/http.tcl | 126 ++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 65 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index fb30a5e..34cad93 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -267,8 +267,8 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { set state(error) [list $errormsg $errorInfo $errorCode] set state(status) "error" } - if {[info commands ${token}EventCoroutine] ne {}} { - rename ${token}EventCoroutine {} + if {[info commands ${token}--EventCoroutine] ne {}} { + rename ${token}--EventCoroutine {} } # Is this an upgrade request/response? @@ -387,9 +387,6 @@ proc http::KeepSocket {token} { # queued, arrange to read it. set token3 [lindex $socketRdQueue($connId) 0] set socketRdQueue($connId) [lrange $socketRdQueue($connId) 1 end] - variable $token3 - upvar 0 $token3 state3 - set tk2 [namespace tail $token3] #Log pipelined, GRANT read access to $token3 in KeepSocket set socketRdState($connId) $token3 @@ -428,8 +425,7 @@ proc http::KeepSocket {token} { # first item in the write queue, a non-pipelined request that is # waiting for the read queue to empty. That has now happened: so # give that request read and write access. - variable $token3 - set conn [set ${token3}(tmpConnArgs)] + set conn [set ${token3}(connArgs)] #Log nonpipeline, GRANT r/w access to $token3 in KeepSocket set socketRdState($connId) $token3 set socketWrState($connId) $token3 @@ -473,8 +469,7 @@ proc http::KeepSocket {token} { # Code: # - The code is the same as the code below for the nonpipelined # case with a queued request. - variable $token3 - set conn [set ${token3}(tmpConnArgs)] + set conn [set ${token3}(connArgs)] #Log nonpipeline, GRANT r/w access to $token3 in KeepSocket set socketRdState($connId) $token3 set socketWrState($connId) $token3 @@ -495,8 +490,7 @@ proc http::KeepSocket {token} { # If the next request is pipelined, it receives premature read # access to the socket. This is not a problem. set token3 [lindex $socketWrQueue($connId) 0] - variable $token3 - set conn [set ${token3}(tmpConnArgs)] + set conn [set ${token3}(connArgs)] #Log nonpipeline, GRANT r/w access to $token3 in KeepSocket set socketRdState($connId) $token3 set socketWrState($connId) $token3 @@ -967,6 +961,9 @@ proc http::geturl {url args} { if {![catch {$http(-proxyfilter) $host} proxy]} { set phost [lindex $proxy 0] set pport [lindex $proxy 1] + } else { + set phost {} + set pport {} } # OK, now reassemble into a full URL @@ -1235,10 +1232,11 @@ proc http::geturl {url args} { if {![info exists phost]} { set phost "" } + set state(connArgs) [list $proto $phost $srvurl] if {$reusing} { # For use by http::ReplayIfDead if the persistent connection has died. # Also used by NextPipelinedWrite. - set state(tmpConnArgs) [list $proto $phost $srvurl] + set state(tmpConnArgs) $state(connArgs) } # The element socketWrState($connId) has a value which is either the name of @@ -1735,11 +1733,11 @@ proc http::ReceiveResponse {token} { -buffersize $state(-blocksize) Log ^D$tk begin receiving response - token $token - coroutine ${token}EventCoroutine http::Event $sock $token + coroutine ${token}--EventCoroutine http::Event $sock $token if {[info exists state(-handler)] || [info exists state(-progress)]} { fileevent $sock readable [list http::EventGateway $sock $token] } else { - fileevent $sock readable ${token}EventCoroutine + fileevent $sock readable ${token}--EventCoroutine } return } @@ -1763,8 +1761,8 @@ proc http::EventGateway {sock token} { variable $token upvar 0 $token state fileevent $sock readable {} - catch {${token}EventCoroutine} res opts - if {[info commands ${token}EventCoroutine] ne {}} { + catch {${token}--EventCoroutine} res opts + if {[info commands ${token}--EventCoroutine] ne {}} { # The coroutine can be deleted by completion (a non-yield return), by # http::Finish (when there is a premature end to the transaction), by # http::reset or http::cleanup, or if the caller set option -channel @@ -1832,7 +1830,7 @@ proc http::NextPipelinedWrite {token} { } { # - The usual case for a pipelined connection, ready for a new request. #Log pipelined, GRANT write access to $token2 in NextPipelinedWrite - set conn [set ${token2}(tmpConnArgs)] + set conn [set ${token2}(connArgs)] set socketWrState($connId) $token2 set socketWrQueue($connId) [lrange $socketWrQueue($connId) 1 end] # Connect does its own fconfigure. @@ -1857,9 +1855,7 @@ proc http::NextPipelinedWrite {token} { # The case in which the next request will be non-pipelined, and the read # and write queues is ready: which is the condition for a non-pipelined # write. - variable $token3 - upvar 0 $token3 state3 - set conn [set ${token3}(tmpConnArgs)] + set conn [set ${token3}(connArgs)] #Log nonpipeline, GRANT r/w access to $token3 in NextPipelinedWrite set socketRdState($connId) $token3 set socketWrState($connId) $token3 @@ -1981,7 +1977,7 @@ proc http::CancelWritePipeline {name1 connId op} { # Side Effects: # Use the same token, but try to open a new socket. -proc http::ReplayIfDead {tokenArg doing} { +proc http::ReplayIfDead {token doing} { variable socketMapping variable socketRdState variable socketWrState @@ -1990,10 +1986,10 @@ proc http::ReplayIfDead {tokenArg doing} { variable socketClosing variable socketPlayCmd - variable $tokenArg - upvar 0 $tokenArg stateArg + variable $token + upvar 0 $token state - Log running http::ReplayIfDead for $tokenArg $doing + Log running http::ReplayIfDead for $token $doing # 1. Merge the tokens for transactions in flight, the read (response) queue, # and the write (request) queue. @@ -2002,85 +1998,85 @@ proc http::ReplayIfDead {tokenArg doing} { set InFlightW {} # Obtain the tokens for transactions in flight. - if {$stateArg(-pipeline)} { + if {$state(-pipeline)} { # Two transactions may be in flight. The "read" transaction was first. # It is unlikely that the server would close the socket if a response # was pending; however, an earlier request (as well as the present # request) may have been sent and ignored if the socket was half-closed # by the server. - if { [info exists socketRdState($stateArg(socketinfo))] - && ($socketRdState($stateArg(socketinfo)) ne "Rready") + if { [info exists socketRdState($state(socketinfo))] + && ($socketRdState($state(socketinfo)) ne "Rready") } { - lappend InFlightR $socketRdState($stateArg(socketinfo)) + lappend InFlightR $socketRdState($state(socketinfo)) } elseif {($doing eq "read")} { - lappend InFlightR $tokenArg + lappend InFlightR $token } - if { [info exists socketWrState($stateArg(socketinfo))] - && $socketWrState($stateArg(socketinfo)) ni {Wready peNding} + if { [info exists socketWrState($state(socketinfo))] + && $socketWrState($state(socketinfo)) ni {Wready peNding} } { - lappend InFlightW $socketWrState($stateArg(socketinfo)) + lappend InFlightW $socketWrState($state(socketinfo)) } elseif {($doing eq "write")} { - lappend InFlightW $tokenArg + lappend InFlightW $token } - # Report any inconsistency of $tokenArg with socket*state. + # Report any inconsistency of $token with socket*state. if { ($doing eq "read") - && [info exists socketRdState($stateArg(socketinfo))] - && ($tokenArg ne $socketRdState($stateArg(socketinfo))) + && [info exists socketRdState($state(socketinfo))] + && ($token ne $socketRdState($state(socketinfo))) } { - Log WARNING - ReplayIfDead pipelined tokenArg $tokenArg $doing \ - ne socketRdState($stateArg(socketinfo)) \ - $socketRdState($stateArg(socketinfo)) + Log WARNING - ReplayIfDead pipelined token $token $doing \ + ne socketRdState($state(socketinfo)) \ + $socketRdState($state(socketinfo)) } elseif { ($doing eq "write") - && [info exists socketWrState($stateArg(socketinfo))] - && ($tokenArg ne $socketWrState($stateArg(socketinfo))) + && [info exists socketWrState($state(socketinfo))] + && ($token ne $socketWrState($state(socketinfo))) } { - Log WARNING - ReplayIfDead pipelined tokenArg $tokenArg $doing \ - ne socketWrState($stateArg(socketinfo)) \ - $socketWrState($stateArg(socketinfo)) + Log WARNING - ReplayIfDead pipelined token $token $doing \ + ne socketWrState($state(socketinfo)) \ + $socketWrState($state(socketinfo)) } } else { # One transaction should be in flight. # socketRdState, socketWrQueue are used. # socketRdQueue should be empty. - # Report any inconsistency of $tokenArg with socket*state. - if {$tokenArg ne $socketRdState($stateArg(socketinfo))} { - Log WARNING - ReplayIfDead nonpipeline tokenArg $tokenArg $doing \ - ne socketRdState($stateArg(socketinfo)) \ - $socketRdState($stateArg(socketinfo)) + # Report any inconsistency of $token with socket*state. + if {$token ne $socketRdState($state(socketinfo))} { + Log WARNING - ReplayIfDead nonpipeline token $token $doing \ + ne socketRdState($state(socketinfo)) \ + $socketRdState($state(socketinfo)) } # Report the inconsistency that socketRdQueue is non-empty. - if { [info exists socketRdQueue($stateArg(socketinfo))] - && ($socketRdQueue($stateArg(socketinfo)) ne {}) + if { [info exists socketRdQueue($state(socketinfo))] + && ($socketRdQueue($state(socketinfo)) ne {}) } { - Log WARNING - ReplayIfDead nonpipeline tokenArg $tokenArg $doing \ - has read queue socketRdQueue($stateArg(socketinfo)) \ - $socketRdQueue($stateArg(socketinfo)) ne {} + Log WARNING - ReplayIfDead nonpipeline token $token $doing \ + has read queue socketRdQueue($state(socketinfo)) \ + $socketRdQueue($state(socketinfo)) ne {} } - lappend InFlightW $socketRdState($stateArg(socketinfo)) - set socketRdQueue($stateArg(socketinfo)) {} + lappend InFlightW $socketRdState($state(socketinfo)) + set socketRdQueue($state(socketinfo)) {} } set newQueue {} lappend newQueue {*}$InFlightR - lappend newQueue {*}$socketRdQueue($stateArg(socketinfo)) + lappend newQueue {*}$socketRdQueue($state(socketinfo)) lappend newQueue {*}$InFlightW - lappend newQueue {*}$socketWrQueue($stateArg(socketinfo)) + lappend newQueue {*}$socketWrQueue($state(socketinfo)) - # 2. Tidy up tokenArg. This is a cut-down form of Finish/CloseSocket. + # 2. Tidy up token. This is a cut-down form of Finish/CloseSocket. # Do not change state(status). - # No need to after cancel stateArg(after) - either this is done in + # No need to after cancel state(after) - either this is done in # ReplayCore/ReInit, or Finish is called. - catch {close $stateArg(sock)} + catch {close $state(sock)} # 2a. Tidy the tokens in the queues - this is done in ReplayCore/ReInit. # - Transactions, if any, that are awaiting responses cannot be completed. @@ -2407,8 +2403,8 @@ proc http::error {token} { proc http::cleanup {token} { variable $token upvar 0 $token state - if {[info commands ${token}EventCoroutine] ne {}} { - rename ${token}EventCoroutine {} + if {[info commands ${token}--EventCoroutine] ne {}} { + rename ${token}--EventCoroutine {} } if {[info exists state(after)]} { after cancel $state(after) @@ -2572,7 +2568,7 @@ proc http::Write {token} { # http::Event # # Handle input on the socket. This command is the core of -# the coroutine commands ${token}EventCoroutine that are +# the coroutine commands ${token}--EventCoroutine that are # bound to "fileevent $sock readable" and process input. # # Arguments @@ -2823,7 +2819,7 @@ proc http::Event {sock token} { if {![info exists state(-handler)]} { # Initiate a sequence of background fcopies. fileevent $sock readable {} - rename ${token}EventCoroutine {} + rename ${token}--EventCoroutine {} CopyStart $sock $token return } -- cgit v0.12 From 5b6aa149be96496401121819fd44e5b1d5f923a5 Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 6 Sep 2022 01:53:02 +0000 Subject: Minor bugfixes, improvments to layout, comments, logging. --- library/http/http.tcl | 65 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 34cad93..ce337e6 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -224,6 +224,9 @@ proc http::config {args} { return -code error "Unknown option $flag, must be: $usage" } return $http($flag) + } elseif {[llength $args] % 2} { + return -code error "If more than one argument is supplied, the\ + number of arguments must be even" } else { foreach {flag value} $args { if {![regexp -- $pat $flag]} { @@ -273,10 +276,15 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { # Is this an upgrade request/response? set upgradeResponse \ - [expr { [info exists state(upgradeRequest)] && $state(upgradeRequest) - && [info exists state(http)] && [ncode $token] eq {101} - && [info exists state(connection)] && "upgrade" in $state(connection) - && [info exists state(upgrade)] && "" ne $state(upgrade)}] + [expr { [info exists state(upgradeRequest)] + && $state(upgradeRequest) + && [info exists state(http)] + && ([ncode $token] eq {101}) + && [info exists state(connection)] + && ("upgrade" in $state(connection)) + && [info exists state(upgrade)] + && ("" ne $state(upgrade)) + }] if { ($state(status) eq "timeout") || ($state(status) eq "error") @@ -328,6 +336,7 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { && ($socketMapping($connId) eq $sock) } { http::CloseQueuedQueries $connId $token + # This calls Unset. Other cases do not need the call. } return } @@ -579,16 +588,19 @@ proc http::CloseSocket {s {token {}}} { Log "Closing connection $connId (sock $socketMapping($connId))" if {[catch {close $socketMapping($connId)} err]} { Log "Error closing connection: $err" + } else { } if {$token eq {}} { # Cases with a non-empty token are handled by Finish, so the tokens # are finished in connection order. http::CloseQueuedQueries $connId + } else { } } else { Log "Closing socket $s (no connection info)" if {[catch {close $s} err]} { Log "Error closing socket: $err" + } else { } } return @@ -611,6 +623,7 @@ proc http::CloseQueuedQueries {connId {token {}}} { variable socketClosing variable socketPlayCmd + ##Log CloseQueuedQueries $connId if {![info exists socketMapping($connId)]} { # Command has already been called. # Don't come here again - especially recursively. @@ -645,7 +658,7 @@ proc http::CloseQueuedQueries {connId {token {}}} { if {$unfinished ne {}} { Log ^R$tk Any unfinished transactions (excluding $token) failed \ - - token $token + - token $token - unfinished $unfinished {*}$unfinished } return @@ -796,8 +809,8 @@ proc http::geturl {url args} { } if {($flag eq "-headers") && ([llength $value] % 2 != 0)} { unset $token - return -code error \ - "Bad value for $flag ($value), number of list elements must be even" + return -code error "Bad value for $flag ($value), number\ + of list elements must be even" } set state($flag) $value } else { @@ -1084,14 +1097,17 @@ proc http::geturl {url args} { # causes a call to Finish. set reusing 1 set sock $socketMapping($state(socketinfo)) - Log "reusing socket $sock for $state(socketinfo) - token $token" + Log "reusing closing socket $sock for $state(socketinfo) - token $token" set alreadyQueued 1 lassign $socketPlayCmd($state(socketinfo)) com0 com1 com2 com3 lappend com3 $token set socketPlayCmd($state(socketinfo)) [list $com0 $com1 $com2 $com3] lappend socketWrQueue($state(socketinfo)) $token + ##Log socketPlayCmd($state(socketinfo)) is $socketPlayCmd($state(socketinfo)) + ##Log socketWrQueue($state(socketinfo)) is $socketWrQueue($state(socketinfo)) } elseif {[catch {fconfigure $socketMapping($state(socketinfo))}]} { + ###Log "Socket $socketMapping($state(socketinfo)) for $state(socketinfo)" # FIXME Is it still possible for this code to be executed? If # so, this could be another place to call TestForReplay, # rather than discarding the queued transactions. @@ -1105,14 +1121,13 @@ proc http::geturl {url args} { Unset $state(socketinfo) } else { # Use the persistent socket. - # The socket may not be ready to write: an earlier request might - # still be still writing (in the pipelined case) or - # writing/reading (in the nonpipeline case). This possibility - # is handled by socketWrQueue later in this command. + # - The socket may not be ready to write: an earlier request might + # still be still writing (in the pipelined case) or + # writing/reading (in the nonpipeline case). This possibility + # is handled by socketWrQueue later in this command. set reusing 1 set sock $socketMapping($state(socketinfo)) - Log "reusing socket $sock for $state(socketinfo) - token $token" - + Log "reusing open socket $sock for $state(socketinfo) - token $token" } # Do not automatically close the connection socket. set state(connection) keep-alive @@ -1315,7 +1330,17 @@ proc http::geturl {url args} { [list http::Connect $token $proto $phost $srvurl] } - # Wait for the connection to complete. + # -------------------------------------------------------------------------- + # Synchronous Call to http::geturl + # -------------------------------------------------------------------------- + # - If the call to http::geturl is asynchronous, it is now complete (apart + # from delivering the return value). + # - If the call to http::geturl is synchronous, the command must now wait + # for the HTTP transaction to be completed. The call to http::wait uses + # vwait, which may be inappropriate if the caller makes other HTTP + # requests in the background. + # -------------------------------------------------------------------------- + if {![info exists state(-command)]} { # geturl does EVERYTHING asynchronously, so if the user # calls it synchronously, we just do a wait here. @@ -2077,6 +2102,7 @@ proc http::ReplayIfDead {token doing} { # ReplayCore/ReInit, or Finish is called. catch {close $state(sock)} + Unset $state(socketinfo) # 2a. Tidy the tokens in the queues - this is done in ReplayCore/ReInit. # - Transactions, if any, that are awaiting responses cannot be completed. @@ -2119,7 +2145,7 @@ proc http::ReplayIfClose {Wstate Rqueue Wqueue} { if {$Wstate ni {Wready peNding}} { lappend InFlightW $Wstate } - + ##Log $Rqueue -- $InFlightW -- $Wqueue set newQueue {} lappend newQueue {*}$Rqueue lappend newQueue {*}$InFlightW @@ -2318,7 +2344,7 @@ proc http::ReplayCore {newQueue} { } else { set ${tok}(reusing) 1 set ${tok}(sock) NONE - Finish $token {cannot send this request again} + Finish $tok {cannot send this request again} } } @@ -2745,7 +2771,8 @@ proc http::Event {sock token} { {ReplayIfClose Wready {} {}} } - # Do not allow further connections on this socket. + # Do not allow further connections on this socket (but + # geturl can add new requests to the replay). set socketClosing($state(socketinfo)) 1 } @@ -3318,7 +3345,7 @@ proc http::BlockingGets {sock} { # This closes the connection upon error proc http::CopyStart {sock token {initial 1}} { - upvar #0 $token state + upvar 0 $token state if {[info exists state(transfer)] && $state(transfer) eq "chunked"} { foreach coding [ContentEncoding $token] { lappend state(zlib) [zlib stream $coding] -- cgit v0.12 From 79d5320ceb313aa0509fd80893563022e1e2093e Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 6 Sep 2022 04:06:21 +0000 Subject: Revise http::geturl to open its socket in an idletask coroutine. This is preparation for a workaround to bug 824251. Revise test http-4.15 because error message has changed. This commit passes all tests. --- library/http/http.tcl | 895 +++++++++++++++++++++++++++++++++++++------------- tests/http.test | 6 +- 2 files changed, 665 insertions(+), 236 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index ce337e6..c3679f1 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -70,8 +70,10 @@ namespace eval http { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent if {[info exists socketMapping]} { # Close open sockets on re-init. Do not permit retries. foreach {url sock} [array get socketMapping] { @@ -92,15 +94,19 @@ namespace eval http { array unset socketWrState array unset socketRdQueue array unset socketWrQueue + array unset socketPhQueue array unset socketClosing array unset socketPlayCmd + array unset socketCoEvent array set socketMapping {} array set socketRdState {} array set socketWrState {} array set socketRdQueue {} array set socketWrQueue {} + array set socketPhQueue {} array set socketClosing {} array set socketPlayCmd {} + array set socketCoEvent {} return } init @@ -141,6 +147,8 @@ namespace eval http { )? } + variable TmpSockCounter 0 + namespace export geturl config reset wait formatQuery quoteString namespace export register unregister registerError # - Useful, but not exported: data, size, status, code, cleanup, error, @@ -259,8 +267,10 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -273,6 +283,9 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { if {[info commands ${token}--EventCoroutine] ne {}} { rename ${token}--EventCoroutine {} } + if {[info commands ${token}--SocketCoroutine] ne {}} { + rename ${token}--SocketCoroutine {} + } # Is this an upgrade request/response? set upgradeResponse \ @@ -292,8 +305,14 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { } { set closeQueue 1 set connId $state(socketinfo) - set sock $state(sock) - CloseSocket $state(sock) $token + if {[info exists state(sock)]} { + set sock $state(sock) + CloseSocket $state(sock) $token + } else { + # When opening the socket and calling http::reset + # immediately, the socket may not yet exist. + # Test http-4.11 may come here. + } } elseif {$upgradeResponse} { # Special handling for an upgrade request/response. # - geturl ensures that this is not a "persistent" socket used for @@ -310,8 +329,14 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { } { set closeQueue 1 set connId $state(socketinfo) - set sock $state(sock) - CloseSocket $state(sock) $token + if {[info exists state(sock)]} { + set sock $state(sock) + CloseSocket $state(sock) $token + } else { + # When opening the socket and calling http::reset + # immediately, the socket may not yet exist. + # Test http-4.11 may come here. + } } elseif { ([info exists state(-keepalive)] && $state(-keepalive)) && ([info exists state(connection)] && ("close" ni $state(connection))) @@ -360,8 +385,10 @@ proc http::KeepSocket {token} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -560,8 +587,10 @@ proc http::CloseSocket {s {token {}}} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent set tk [namespace tail $token] @@ -620,8 +649,10 @@ proc http::CloseQueuedQueries {connId {token {}}} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent ##Log CloseQueuedQueries $connId if {![info exists socketMapping($connId)]} { @@ -677,8 +708,10 @@ proc http::Unset {connId} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent unset socketMapping($connId) unset socketRdState($connId) @@ -729,11 +762,74 @@ proc http::reset {token {why reset}} { # array that the caller should unset to garbage collect the state. proc http::geturl {url args} { + set token [CreateToken $url {*}$args] + variable $token + upvar 0 $token state + + AsyncTransaction $token + + # -------------------------------------------------------------------------- + # Synchronous Call to http::geturl + # -------------------------------------------------------------------------- + # - If the call to http::geturl is asynchronous, it is now complete (apart + # from delivering the return value). + # - If the call to http::geturl is synchronous, the command must now wait + # for the HTTP transaction to be completed. The call to http::wait uses + # vwait, which may be inappropriate if the caller makes other HTTP + # requests in the background. + # -------------------------------------------------------------------------- + + if {![info exists state(-command)]} { + # geturl does EVERYTHING asynchronously, so if the user + # calls it synchronously, we just do a wait here. + http::wait $token + + if {![info exists state]} { + # If we timed out then Finish has been called and the users + # command callback may have cleaned up the token. If so we end up + # here with nothing left to do. + return $token + } elseif {$state(status) eq "error"} { + # Something went wrong while trying to establish the connection. + # Clean up after events and such, but DON'T call the command + # callback (if available) because we're going to throw an + # exception from here instead. + set err [lindex $state(error) 0] + cleanup $token + return -code error $err + } + } + + return $token +} + +# ------------------------------------------------------------------------------ +# Proc http::CreateToken +# ------------------------------------------------------------------------------ +# Command to convert arguments into an initialised request token. +# The return value is the variable name of the token. +# +# Other effects: +# - Sets ::http::http(uid) if not already done +# - Increments ::http::http(uid) +# - May increment ::http::TmpSockCounter +# - Alters ::http::socketPlayCmd, ::http::socketWrQueue if a -keepalive 1 +# request is appended to the queue of a persistent socket that is already +# scheduled to close. +# This also sets state(alreadyQueued) to 1. +# - Alters ::http::socketPhQueue if a -keepalive 1 request is appended to the +# queue of a persistent socket that has not yet been created (and is therefore +# represented by a placeholder). +# This also sets state(ReusingPlaceholder) to 1. +# ------------------------------------------------------------------------------ + +proc http::CreateToken {url args} { variable http variable urlTypes variable defaultCharset variable defaultKeepalive variable strict + variable TmpSockCounter # Initialize the state variable, an array. We'll return the name of this # array as the token for the transaction. @@ -993,17 +1089,6 @@ proc http::geturl {url args} { # Don't append the fragment! set state(url) $url - set sockopts [list -async] - - # If we are using the proxy, we must pass in the full URL that includes - # the server name. - - if {[info exists phost] && ($phost ne "")} { - set srvurl $url - set targetAddr [list $phost $pport] - } else { - set targetAddr [list $host $port] - } # Proxy connections aren't shared among different hosts. set state(socketinfo) $host:$port @@ -1057,6 +1142,25 @@ proc http::geturl {url args} { set state(-keepalive) 0 } + # If we are using the proxy, we must pass in the full URL that includes + # the server name. + if {$phost ne ""} { + set srvurl $url + set targetAddr [list $phost $pport] + } else { + set targetAddr [list $host $port] + } + + set sockopts [list -async] + + # Pass -myaddr directly to the socket command + if {[info exists state(-myaddr)]} { + lappend sockopts -myaddr $state(-myaddr) + } + + set state(connArgs) [list $proto $phost $srvurl] + set state(openCmd) [list {*}$defcmd {*}$sockopts {*}$targetAddr] + # See if we are supposed to use a previously opened channel. # - In principle, ANY call to http::geturl could use a previously opened # channel if it is available - the "Connection: keep-alive" header is a @@ -1066,15 +1170,18 @@ proc http::geturl {url args} { # $state(socketinfo). This property simplifies the mapping of open # channels. set reusing 0 - set alreadyQueued 0 + set state(alreadyQueued) 0 + set state(ReusingPlaceholder) 0 if {$state(-keepalive)} { variable socketMapping variable socketRdState variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent if {[info exists socketMapping($state(socketinfo))]} { # - If the connection is idle, it has a "fileevent readable" binding @@ -1099,14 +1206,16 @@ proc http::geturl {url args} { set sock $socketMapping($state(socketinfo)) Log "reusing closing socket $sock for $state(socketinfo) - token $token" - set alreadyQueued 1 + set state(alreadyQueued) 1 lassign $socketPlayCmd($state(socketinfo)) com0 com1 com2 com3 lappend com3 $token set socketPlayCmd($state(socketinfo)) [list $com0 $com1 $com2 $com3] lappend socketWrQueue($state(socketinfo)) $token ##Log socketPlayCmd($state(socketinfo)) is $socketPlayCmd($state(socketinfo)) ##Log socketWrQueue($state(socketinfo)) is $socketWrQueue($state(socketinfo)) - } elseif {[catch {fconfigure $socketMapping($state(socketinfo))}]} { + } elseif { [catch {fconfigure $socketMapping($state(socketinfo))}] + && (![SockIsPlaHolder $socketMapping($state(socketinfo))]) + } { ###Log "Socket $socketMapping($state(socketinfo)) for $state(socketinfo)" # FIXME Is it still possible for this code to be executed? If # so, this could be another place to call TestForReplay, @@ -1125,8 +1234,14 @@ proc http::geturl {url args} { # still be still writing (in the pipelined case) or # writing/reading (in the nonpipeline case). This possibility # is handled by socketWrQueue later in this command. + # - The socket may not yet exist, and be defined with a placeholder. set reusing 1 set sock $socketMapping($state(socketinfo)) + if {[SockIsPlaHolder $sock]} { + set state(ReusingPlaceholder) 1 + lappend socketPhQueue($sock) $token + } else { + } Log "reusing open socket $sock for $state(socketinfo) - token $token" } # Do not automatically close the connection socket. @@ -1134,29 +1249,94 @@ proc http::geturl {url args} { } } - if {$reusing} { - # Define state(tmpState) and state(tmpOpenCmd) for use - # by http::ReplayIfDead if the persistent connection has died. - set state(tmpState) [array get state] + set state(reusing) $reusing + unset reusing - # Pass -myaddr directly to the socket command - if {[info exists state(-myaddr)]} { - lappend sockopts -myaddr $state(-myaddr) - } + if {![info exists sock]} { + # N.B. At this point ([info exists sock] == $state(reusing)). + # This will no longer be true after we set a value of sock here. + # Give the socket a placeholder name. + set sock HTTP_PLACEHOLDER_[incr TmpSockCounter] + } + set state(sock) $sock - set state(tmpOpenCmd) [list {*}$defcmd {*}$sockopts {*}$targetAddr] + if {$state(reusing)} { + # Define these for use (only) by http::ReplayIfDead if the persistent + # connection has died. + set state(tmpConnArgs) $state(connArgs) + set state(tmpState) [array get state] + set state(tmpOpenCmd) $state(openCmd) } + return $token +} - set state(reusing) $reusing - # Excluding ReplayIfDead and the decision whether to call it, there are four - # places outside http::geturl where state(reusing) is used: - # - Connected - if reusing and not pipelined, start the state(-timeout) - # timeout (when writing). - # - DoneRequest - if reusing and pipelined, send the next pipelined write - # - Event - if reusing and pipelined, start the state(-timeout) - # timeout (when reading). - # - Event - if (not reusing) and pipelined, send the next pipelined - # write + +# ------------------------------------------------------------------------------ +# Proc ::http::SockIsPlaHolder +# ------------------------------------------------------------------------------ +# Command to return 0 if the argument is a genuine socket handle, or 1 if is a +# placeholder value generated by geturl or ReplayCore before the real socket is +# created. +# +# Arguments: +# sock - either a valid socket handle or a placeholder value +# +# Return Value: 0 or 1 +# ------------------------------------------------------------------------------ + +proc http::SockIsPlaHolder {sock} { + expr {[string range $sock 0 16] eq {HTTP_PLACEHOLDER_}} +} + + +# ------------------------------------------------------------------------------ +# state(reusing) +# ------------------------------------------------------------------------------ +# - state(reusing) is set by geturl, ReplayCore +# - state(reusing) is used by geturl, AsyncTransaction, OpenSocket, +# ConfigureNewSocket, and ScheduleRequest when creating and configuring the +# connection. +# - state(reusing) is used by Connect, Connected, Event x 2 when deciding +# whether to call TestForReplay. +# - Other places where state(reusing) is used: +# - Connected - if reusing and not pipelined, start the state(-timeout) +# timeout (when writing). +# - DoneRequest - if reusing and pipelined, send the next pipelined write +# - Event - if reusing and pipelined, start the state(-timeout) +# timeout (when reading). +# - Event - if (not reusing) and pipelined, send the next pipelined +# write. +# ------------------------------------------------------------------------------ + + +# ------------------------------------------------------------------------------ +# Proc http::AsyncTransaction +# ------------------------------------------------------------------------------ +# This command is called by geturl and ReplayCore to prepare the HTTP +# transaction prescribed by a suitably prepared token. +# +# Arguments: +# token - connection token (name of an array) +# +# Return Value: none +# ------------------------------------------------------------------------------ + +proc http::AsyncTransaction {token} { + variable $token + upvar 0 $token state + set tk [namespace tail $token] + + variable socketMapping + variable socketRdState + variable socketWrState + variable socketRdQueue + variable socketWrQueue + variable socketPhQueue + variable socketClosing + variable socketPlayCmd + variable socketCoEvent + + set sock $state(sock) # See comments above re the start of this timeout in other cases. if {(!$state(reusing)) && ($state(-timeout) > 0)} { @@ -1164,29 +1344,185 @@ proc http::geturl {url args} { [list http::reset $token timeout]] } - if {![info exists sock]} { - # Pass -myaddr directly to the socket command - if {[info exists state(-myaddr)]} { - lappend sockopts -myaddr $state(-myaddr) - } + if { $state(-keepalive) + && (![info exists socketMapping($state(socketinfo))]) + } { + # This code is executed only for the first -keepalive request on a + # socket. It makes the socket persistent. + ##Log " PreparePersistentConnection" $token -- $sock -- DO + set DoLater [PreparePersistentConnection $token] + } else { + ##Log " PreparePersistentConnection" $token -- $sock -- SKIP + set DoLater {-traceread 0 -tracewrite 0} + } + + if {$state(ReusingPlaceholder)} { + # - This request is scheduled to re-use a persistent connection; + # - But the connection has not yet been created and is a placeholder; + # - And the placeholder was created by an earlier request. + # - When that earlier request calls OpenSocket, its placeholder is + # replaced with a true socket, and it then executes the equivalent of + # OpenSocket for any subsequent requests that have + # $state(ReusingPlaceholder). + Log >J$tk after idle coro NO - ReusingPlaceholder + } else { + Log >J$tk after idle coro YES + # Called if (not reusing) || (socket is not a placeholder). + set CoroName ${token}--SocketCoroutine + set cancel [after idle [list coroutine $CoroName ::http::OpenSocket \ + $token $DoLater]] + dict set socketCoEvent($state(socketinfo)) $token $cancel + } + + return +} + + +# ------------------------------------------------------------------------------ +# Proc http::PreparePersistentConnection +# ------------------------------------------------------------------------------ +# This command is called by AsyncTransaction to initialise a "persistent +# connection" based upon a socket placeholder. It is called the first time the +# socket is associated with a "-keepalive" request. +# +# Arguments: +# token - connection token (name of an array) +# +# Return Value: - DoLater, a dictionary of boolean values listing unfinished +# tasks; to be passed to ConfigureNewSocket via OpenSocket. +# ------------------------------------------------------------------------------ + +proc http::PreparePersistentConnection {token} { + variable $token + upvar 0 $token state + + variable socketMapping + variable socketRdState + variable socketWrState + variable socketRdQueue + variable socketWrQueue + variable socketPhQueue + variable socketClosing + variable socketPlayCmd + variable socketCoEvent + + set DoLater {-traceread 0 -tracewrite 0} + set socketMapping($state(socketinfo)) $state(sock) + + if {![info exists socketRdState($state(socketinfo))]} { + set socketRdState($state(socketinfo)) {} + # set varName ::http::socketRdState($state(socketinfo)) + # trace add variable $varName unset ::http::CancelReadPipeline + dict set DoLater -traceread 1 + } + if {![info exists socketWrState($state(socketinfo))]} { + set socketWrState($state(socketinfo)) {} + # set varName ::http::socketWrState($state(socketinfo)) + # trace add variable $varName unset ::http::CancelWritePipeline + dict set DoLater -tracewrite 1 + } + + if {$state(-pipeline)} { + #Log new, init for pipelined, GRANT write access to $token in geturl + # Also grant premature read access to the socket. This is OK. + set socketRdState($state(socketinfo)) $token + set socketWrState($state(socketinfo)) $token + } else { + # socketWrState is not used by this non-pipelined transaction. + # We cannot leave it as "Wready" because the next call to + # http::geturl with a pipelined transaction would conclude that the + # socket is available for writing. + #Log new, init for nonpipeline, GRANT r/w access to $token in geturl + set socketRdState($state(socketinfo)) $token + set socketWrState($state(socketinfo)) $token + } + + set socketRdQueue($state(socketinfo)) {} + set socketWrQueue($state(socketinfo)) {} + set socketPhQueue($state(socketinfo)) {} + set socketClosing($state(socketinfo)) 0 + set socketPlayCmd($state(socketinfo)) {ReplayIfClose Wready {} {}} + set socketCoEvent($state(socketinfo)) {} + + return $DoLater +} + +# ------------------------------------------------------------------------------ +# Proc ::http::OpenSocket +# ------------------------------------------------------------------------------ +# This command is called as a coroutine idletask to start the asynchronous HTTP +# transaction in most cases. For the exceptions, see the calling code in +# command AsyncTransaction. +# +# Arguments: +# token - connection token (name of an array) +# DoLater - dictionary of boolean values listing unfinished tasks +# +# Return Value: none +# ------------------------------------------------------------------------------ + +proc http::OpenSocket {token DoLater} { + variable $token + upvar 0 $token state + set tk [namespace tail $token] + + variable socketMapping + variable socketRdState + variable socketWrState + variable socketRdQueue + variable socketWrQueue + variable socketPhQueue + variable socketClosing + variable socketPlayCmd + variable socketCoEvent + + Log >K$tk Start OpenSocket coroutine + + if {![info exists state(-keepalive)]} { + # The request has already been cancelled by the calling script. + return + } + + set sockOld $state(sock) + + dict unset socketCoEvent($state(socketinfo)) $token + + set reusing $state(reusing) + + if {$reusing} { + # If ($reusing) is true, then we do not need to create a new socket, + # even if $sockOld is only a placeholder for a socket. + set sock $sockOld + } else { + # set sock in the [catch] below. set pre [clock milliseconds] ##Log pre socket opened, - token $token - ##Log [concat $defcmd $sockopts $targetAddr] - token $token - if {[catch {eval $defcmd $sockopts $targetAddr} sock errdict]} { + ##Log $state(openCmd) - token $token + if {[catch {eval $state(openCmd)} sock errdict]} { + # ERROR CASE # Something went wrong while trying to establish the connection. - # Clean up after events and such, but DON'T call the command - # callback (if available) because we're going to throw an - # exception from here instead. + # Tidy up after events and such, but DON'T call the command + # callback (if available). + # - When this was inline code in http::geturl, it threw an exception + # from here instead. + # - Now that this code is called from geturl as an idletask and not + # as inline code, it is inappropriate to run cleanup or throw an + # exception. Instead do a normal return, and let Finish report + # the error using token/state and the -command callback. + # Finish also undoes PreparePersistentConnection. set state(sock) NONE - Finish $token $sock 1 - cleanup $token - dict unset errdict -level - return -options $errdict $sock + set ::errorInfo [dict get $errdict -errorinfo] + set ::errorCode [dict get $errdict -errorcode] + Finish $token $sock + # cleanup $token + return } else { + # Normal return from $state(openCmd) always returns a valid socket. # Initialisation of a new socket. ##Log post socket opened, - token $token ##Log socket opened, now fconfigure - token $token + set state(sock) $sock set delay [expr {[clock milliseconds] - $pre}] if {$delay > 3000} { Log socket delay $delay - token $token @@ -1196,84 +1532,220 @@ proc http::geturl {url args} { ##Log socket opened, DONE fconfigure - token $token } } - # Command [socket] is called with -async, but takes 5s to 5.1s to return, - # with probability of order 1 in 10,000. This may be a bizarre scheduling - # issue with my (KJN's) system (Fedora Linux). - # This does not cause a problem (unless the request times out when this - # command returns). - set state(sock) $sock Log "Using $sock for $state(socketinfo) - token $token" \ [expr {$state(-keepalive)?"keepalive":""}] - if { $state(-keepalive) - && (![info exists socketMapping($state(socketinfo))]) - } { - # Freshly-opened socket that we would like to become persistent. - set socketMapping($state(socketinfo)) $sock + # Code above has set state(sock) $sock + ConfigureNewSocket $token $sockOld $DoLater + + ##Log Leaving http::OpenSocket coroutine [info coroutine] - token $token + return +} + + +# ------------------------------------------------------------------------------ +# Proc ::http::ConfigureNewSocket +# ------------------------------------------------------------------------------ +# Command to initialise a newly-created socket. Called only from OpenSocket. +# +# This command is called by OpenSocket whenever a genuine socket (sockNew) has +# been opened for for use by HTTP. It does two things: +# (1) If $token uses a placeholder socket, this command replaces the placeholder +# socket with the real socket, not only in $token but in all other requests +# that use the same placeholder. +# (2) It calls ScheduleRequest to schedule each request that uses the socket. +# +# +# Value of sockOld/sockNew can be "sock" (genuine socket) or "ph" (placeholder). +# sockNew is ${token}(sock) +# sockOld sockNew CASES +# sock sock (if $reusing, and sockOld is sock) +# ph sock (if (not $reusing), and sockOld is ph) +# ph ph (if $reusing, and sockOld is ph) - not called in this case +# sock ph (cannot occur unless a bug) - not called in this case +# (if (not $reusing), and sockOld is sock) - illogical +# +# Arguments: +# token - connection token (name of an array) +# sockOld - handle or placeholder used for a socket before the call to OpenSocket +# DoLater - dictionary of boolean values listing unfinished tasks +# +# Return Value: none +# ------------------------------------------------------------------------------ + +proc http::ConfigureNewSocket {token sockOld DoLater} { + variable $token + upvar 0 $token state + set tk [namespace tail $token] + + variable socketMapping + variable socketRdState + variable socketWrState + variable socketRdQueue + variable socketWrQueue + variable socketPhQueue + variable socketClosing + variable socketPlayCmd + variable socketCoEvent + + ##Log " ConfigureNewSocket" $token $sockOld $sock ... + + set reusing $state(reusing) + set sock $state(sock) + + if {(!$reusing) && ($sock ne $sockOld)} { + # Replace the placeholder value sockOld with sock. - if {![info exists socketRdState($state(socketinfo))]} { - set socketRdState($state(socketinfo)) {} + if { [info exists socketMapping($state(socketinfo))] + && ($socketMapping($state(socketinfo)) eq $sockOld) + } { + set socketMapping($state(socketinfo)) $sock + ##Log set socketMapping($state(socketinfo)) $sock + } + + # Now finish any tasks left over from PreparePersistentConnection on + # the connection. + # + # The "unset" traces are fired by init (clears entire arrays), and + # by http::Unset. + # Unset is called by CloseQueuedQueries and (possibly never) by geturl. + # + # CancelReadPipeline, CancelWritePipeline call http::Finish for each + # token. + # + # FIXME If Finish is placeholder-aware, these traces can be set earlier, + # in PreparePersistentConnection. + + if {[dict get $DoLater -traceread]} { set varName ::http::socketRdState($state(socketinfo)) trace add variable $varName unset ::http::CancelReadPipeline - } - if {![info exists socketWrState($state(socketinfo))]} { - set socketWrState($state(socketinfo)) {} + } + if {[dict get $DoLater -tracewrite]} { set varName ::http::socketWrState($state(socketinfo)) trace add variable $varName unset ::http::CancelWritePipeline - } + } + } - if {$state(-pipeline)} { - #Log new, init for pipelined, GRANT write access to $token in geturl - # Also grant premature read access to the socket. This is OK. - set socketRdState($state(socketinfo)) $token - set socketWrState($state(socketinfo)) $token - } else { - # socketWrState is not used by this non-pipelined transaction. - # We cannot leave it as "Wready" because the next call to - # http::geturl with a pipelined transaction would conclude that the - # socket is available for writing. - #Log new, init for nonpipeline, GRANT r/w access to $token in geturl - set socketRdState($state(socketinfo)) $token - set socketWrState($state(socketinfo)) $token - } + # Do this in all cases. + ScheduleRequest $token - set socketRdQueue($state(socketinfo)) {} - set socketWrQueue($state(socketinfo)) {} - set socketClosing($state(socketinfo)) 0 - set socketPlayCmd($state(socketinfo)) {ReplayIfClose Wready {} {}} - } + # Now look at all other tokens that use the placeholder $sockOld. + if { (!$reusing) + && ($sock ne $sockOld) + && [info exists socketPhQueue($sockOld)] + } { + foreach tok $socketPhQueue($sockOld) { + # 1. Amend the token's (sock). + ##Log set ${tok}(sock) $sock + set ${tok}(sock) $sock - if {![info exists phost]} { - set phost "" - } - set state(connArgs) [list $proto $phost $srvurl] - if {$reusing} { - # For use by http::ReplayIfDead if the persistent connection has died. - # Also used by NextPipelinedWrite. - set state(tmpConnArgs) $state(connArgs) + # 2. Schedule the token's HTTP request. + # Every token in socketPhQueue(*) has reusing 1 alreadyQueued 0. + set ${tok}(reusing) 1 + set ${tok}(alreadyQueued) 0 + ScheduleRequest $tok + } + set socketPhQueue($sockOld) {} } - # The element socketWrState($connId) has a value which is either the name of - # the token that is permitted to write to the socket, or "Wready" if no - # token is permitted to write. - # - # The code that sets the value to Wready immediately calls - # http::NextPipelinedWrite, which examines socketWrQueue($connId) and - # processes the next request in the queue, if there is one. The value - # Wready is not found when the interpreter is in the event loop unless the - # socket is idle. - # - # The element socketRdState($connId) has a value which is either the name of - # the token that is permitted to read from the socket, or "Rready" if no - # token is permitted to read. - # - # The code that sets the value to Rready then examines - # socketRdQueue($connId) and processes the next request in the queue, if - # there is one. The value Rready is not found when the interpreter is in - # the event loop unless the socket is idle. + return +} + + +# ------------------------------------------------------------------------------ +# The values of array variables socketMapping etc. +# ------------------------------------------------------------------------------ +# connId "$host:$port" +# socketMapping($connId) the handle or placeholder for the socket that is used +# for "-keepalive 1" requests to $connId. +# socketRdState($connId) the token that is currently reading from the socket. +# Other values: Rready (ready for next token to read). +# socketWrState($connId) the token that is currently writing to the socket. +# Other values: Wready (ready for next token to write), +# peNding (would be ready for next write, except that +# the integrity of a non-pipelined transaction requires +# waiting until the read(s) in progress are finished). +# socketRdQueue($connId) List of tokens that are queued for reading later. +# socketWrQueue($connId) List of tokens that are queued for writing later. +# socketPhQueue($connId) List of tokens that are queued to use a placeholder +# socket, when the real socket has not yet been created. +# socketClosing($connId) (boolean) true iff a server response header indicates +# that the server will close the connection at the end of +# the current response. +# socketPlayCmd($connId) The command to execute to replay pending and +# part-completed transactions if the socket closes early. +# socketCoEvent($connId) Identifier for the "after idle" event that will launch +# an OpenSocket coroutine to open or re-use a socket. +# ------------------------------------------------------------------------------ + + +# ------------------------------------------------------------------------------ +# Using socketWrState(*), socketWrQueue(*), socketRdState(*), socketRdQueue(*) +# ------------------------------------------------------------------------------ +# The element socketWrState($connId) has a value which is either the name of +# the token that is permitted to write to the socket, or "Wready" if no +# token is permitted to write. +# +# The code that sets the value to Wready immediately calls +# http::NextPipelinedWrite, which examines socketWrQueue($connId) and +# processes the next request in the queue, if there is one. The value +# Wready is not found when the interpreter is in the event loop unless the +# socket is idle. +# +# The element socketRdState($connId) has a value which is either the name of +# the token that is permitted to read from the socket, or "Rready" if no +# token is permitted to read. +# +# The code that sets the value to Rready then examines +# socketRdQueue($connId) and processes the next request in the queue, if +# there is one. The value Rready is not found when the interpreter is in +# the event loop unless the socket is idle. +# ------------------------------------------------------------------------------ + + +# ------------------------------------------------------------------------------ +# Proc http::ScheduleRequest +# ------------------------------------------------------------------------------ +# Command to either begin the HTTP request, or add it to the appropriate queue. +# Called from two places in ConfigureNewSocket. +# +# Arguments: +# token - connection token (name of an array) +# +# Return Value: none +# ------------------------------------------------------------------------------ - if {$alreadyQueued} { +proc http::ScheduleRequest {token} { + variable $token + upvar 0 $token state + set tk [namespace tail $token] + + Log >L$tk ScheduleRequest + + variable socketMapping + variable socketRdState + variable socketWrState + variable socketRdQueue + variable socketWrQueue + variable socketPhQueue + variable socketClosing + variable socketPlayCmd + variable socketCoEvent + + set Unfinished 0 + + set reusing $state(reusing) + set sockNew $state(sock) + + # The "if" tests below: must test against the current values of + # socketWrState, socketRdState, and so the tests must be done here, + # not earlier in PreparePersistentConnection. + + if {$state(alreadyQueued)} { + # The request has been appended to the queue of a persistent socket + # (that is scheduled to close and have its queue replayed). + # # A write may or may not be in progress. There is no need to set # socketWrState to prevent another call stealing write access - all # subsequent calls on this socket will come here because the socket @@ -1306,65 +1778,56 @@ proc http::geturl {url args} { # pipelined request jumping the queue. ##Log "HTTP request for token $token is queued for nonpipeline use" #Log re-use nonpipeline, GRANT delayed write access to $token in geturl - set socketWrState($state(socketinfo)) peNding lappend socketWrQueue($state(socketinfo)) $token } else { - if {$reusing && $state(-pipeline)} { - #Log re-use pipelined, GRANT write access to $token in geturl - set socketWrState($state(socketinfo)) $token - - } elseif {$reusing} { - # Cf tests above - both are ready. - #Log re-use nonpipeline, GRANT r/w access to $token in geturl - set socketRdState($state(socketinfo)) $token - set socketWrState($state(socketinfo)) $token - } - - # All (!$reusing) cases come here, and also some $reusing cases if the - # connection is ready. + if {$reusing && $state(-pipeline)} { + #Log new, init for pipelined, GRANT write access to $token in geturl + # DO NOT grant premature read access to the socket. + # set socketRdState($state(socketinfo)) $token + set socketWrState($state(socketinfo)) $token + } elseif {$reusing} { + # socketWrState is not used by this non-pipelined transaction. + # We cannot leave it as "Wready" because the next call to + # http::geturl with a pipelined transaction would conclude that the + # socket is available for writing. + #Log new, init for nonpipeline, GRANT r/w access to $token in geturl + set socketRdState($state(socketinfo)) $token + set socketWrState($state(socketinfo)) $token + } else { + } + + # Process the request now. + # - Command is not called unless $state(sock) is a real socket handle + # and not a placeholder. + # - All (!$reusing) cases come here. + # - Some $reusing cases come here too if the connection is + # marked as ready. Those $reusing cases are: + # $reusing && ($socketWrState($state(socketinfo)) eq "Wready") && + # EITHER !$pipeline && ($socketRdState($state(socketinfo)) eq "Rready") + # OR $pipeline + # #Log ---- $state(socketinfo) << conn to $token for HTTP request (a) + ##Log " ScheduleRequest" $token -- fileevent $state(sock) writable for $token # Connect does its own fconfigure. - fileevent $sock writable \ - [list http::Connect $token $proto $phost $srvurl] - } - # -------------------------------------------------------------------------- - # Synchronous Call to http::geturl - # -------------------------------------------------------------------------- - # - If the call to http::geturl is asynchronous, it is now complete (apart - # from delivering the return value). - # - If the call to http::geturl is synchronous, the command must now wait - # for the HTTP transaction to be completed. The call to http::wait uses - # vwait, which may be inappropriate if the caller makes other HTTP - # requests in the background. - # -------------------------------------------------------------------------- + lassign $state(connArgs) proto phost srvurl - if {![info exists state(-command)]} { - # geturl does EVERYTHING asynchronously, so if the user - # calls it synchronously, we just do a wait here. - http::wait $token - - if {![info exists state]} { - # If we timed out then Finish has been called and the users - # command callback may have cleaned up the token. If so we end up - # here with nothing left to do. - return $token - } elseif {$state(status) eq "error"} { - # Something went wrong while trying to establish the connection. - # Clean up after events and such, but DON'T call the command - # callback (if available) because we're going to throw an - # exception from here instead. - set err [lindex $state(error) 0] - cleanup $token - return -code error $err + if {[catch { + fileevent $state(sock) writable \ + [list http::Connect $token $proto $phost $srvurl] + } res opts]} { + # The socket no longer exists. + ##Log bug -- socket gone -- $res -- $opts } + } - ##Log Leaving http::geturl - token $token - return $token + + return } + # http::Connected -- # # Callback used when the connection to the HTTP server is actually @@ -1386,8 +1849,10 @@ proc http::Connected {token proto phost srvurl} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -1679,8 +2144,10 @@ proc http::DoneRequest {token} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -2008,8 +2475,10 @@ proc http::ReplayIfDead {token doing} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -2237,13 +2706,17 @@ proc http::ReInit {token} { # Use existing tokens, but try to open a new socket. proc http::ReplayCore {newQueue} { + variable TmpSockCounter + variable socketMapping variable socketRdState variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent if {[llength $newQueue] == 0} { # Nothing to do. @@ -2275,72 +2748,20 @@ proc http::ReplayCore {newQueue} { unset state(tmpConnArgs) set state(reusing) 0 + set state(ReusingPlaceholder) 0 + set state(alreadyQueued) 0 - if {$state(-timeout) > 0} { - set resetCmd [list http::reset $token timeout] - set state(after) [after $state(-timeout) $resetCmd] - } - - set pre [clock milliseconds] - ##Log pre socket opened, - token $token - ##Log $tmpOpenCmd - token $token - # 4. Open a socket. - if {[catch {eval $tmpOpenCmd} sock]} { - # Something went wrong while trying to establish the connection. - Log FAILED - $sock - set state(sock) NONE - Finish $token $sock - return - } - ##Log post socket opened, - token $token - set delay [expr {[clock milliseconds] - $pre}] - if {$delay > 3000} { - Log socket delay $delay - token $token - } - # Command [socket] is called with -async, but takes 5s to 5.1s to return, - # with probability of order 1 in 10,000. This may be a bizarre scheduling - # issue with my (KJN's) system (Fedora Linux). - # This does not cause a problem (unless the request times out when this - # command returns). - - # 5. Configure the persistent socket data. - if {$state(-keepalive)} { - set socketMapping($state(socketinfo)) $sock - - if {![info exists socketRdState($state(socketinfo))]} { - set socketRdState($state(socketinfo)) {} - set varName ::http::socketRdState($state(socketinfo)) - trace add variable $varName unset ::http::CancelReadPipeline - } - - if {![info exists socketWrState($state(socketinfo))]} { - set socketWrState($state(socketinfo)) {} - set varName ::http::socketWrState($state(socketinfo)) - trace add variable $varName unset ::http::CancelWritePipeline - } - - if {$state(-pipeline)} { - #Log new, init for pipelined, GRANT write acc to $token ReplayCore - set socketRdState($state(socketinfo)) $token - set socketWrState($state(socketinfo)) $token - } else { - #Log new, init for nonpipeline, GRANT r/w acc to $token ReplayCore - set socketRdState($state(socketinfo)) $token - set socketWrState($state(socketinfo)) $token - } - - set socketRdQueue($state(socketinfo)) {} - set socketWrQueue($state(socketinfo)) $newQueue - set socketClosing($state(socketinfo)) 0 - set socketPlayCmd($state(socketinfo)) {ReplayIfClose Wready {} {}} - } + # Give the socket a placeholder name before it is created. + set sock HTTP_PLACEHOLDER_[incr TmpSockCounter] + set state(sock) $sock - ##Log pre newQueue ReInit, - token $token - # 6. Configure sockets in the queue. + # Move the $newQueue into the placeholder socket's socketPhQueue. + set socketPhQueue($sock) {} foreach tok $newQueue { if {[ReInit $tok]} { set ${tok}(reusing) 1 set ${tok}(sock) $sock + lappend socketPhQueue($sock) $tok } else { set ${tok}(reusing) 1 set ${tok}(sock) NONE @@ -2348,19 +2769,8 @@ proc http::ReplayCore {newQueue} { } } - # 7. Configure the socket for newToken to send a request. - set state(sock) $sock - Log "Using $sock for $state(socketinfo) - token $token" \ - [expr {$state(-keepalive)?"keepalive":""}] + AsyncTransaction $token - # Initialisation of a new socket. - ##Log socket opened, now fconfigure - token $token - fconfigure $sock -translation {auto crlf} -buffersize $state(-blocksize) - ##Log socket opened, DONE fconfigure - token $token - - # Connect does its own fconfigure. - fileevent $sock writable [list http::Connect $token {*}$tmpConnArgs] - #Log ---- $sock << conn to $token for HTTP request (e) return } @@ -2432,6 +2842,9 @@ proc http::cleanup {token} { if {[info commands ${token}--EventCoroutine] ne {}} { rename ${token}--EventCoroutine {} } + if {[info commands ${token}--SocketCoroutine] ne {}} { + rename ${token}--SocketCoroutine {} + } if {[info exists state(after)]} { after cancel $state(after) unset state(after) @@ -2503,8 +2916,10 @@ proc http::Write {token} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -2611,8 +3026,10 @@ proc http::Event {sock token} { variable socketWrState variable socketRdQueue variable socketWrQueue + variable socketPhQueue variable socketClosing variable socketPlayCmd + variable socketCoEvent variable $token upvar 0 $token state @@ -2736,6 +3153,17 @@ proc http::Event {sock token} { # response. ##Log WARNING - socket will close after response for $token # Prepare data for a call to ReplayIfClose. + + # 1. Cancel socket-assignment coro events that have not yet + # launched, and add the tokens to the write queue. + if {[info exists socketCoEvent($state(socketinfo))]} { + foreach {tok can} $socketCoEvent($state(socketinfo)) { + lappend socketWrQueue($state(socketinfo)) $tok + after cancel $can + } + set socketCoEvent($state(socketinfo)) {} + } + if { ($socketRdQueue($state(socketinfo)) ne {}) || ($socketWrQueue($state(socketinfo)) ne {}) || ($socketWrState($state(socketinfo)) ni @@ -2748,7 +3176,6 @@ proc http::Event {sock token} { set msg "token ${InFlightW} is InFlightW" ##Log $msg - token $token } - set socketPlayCmd($state(socketinfo)) \ [list ReplayIfClose $InFlightW \ $socketRdQueue($state(socketinfo)) \ diff --git a/tests/http.test b/tests/http.test index a6f1ce6..59078f2 100644 --- a/tests/http.test +++ b/tests/http.test @@ -611,17 +611,19 @@ test http-4.14 {http::Event} -body { } -cleanup { catch {http::cleanup $token} } -result {connect failed connection refused} + # Bogus host test http-4.15 {http::Event} -body { # This test may fail if you use a proxy server. That is to be # expected and is not a problem with Tcl. set token [http::geturl //not_a_host.tcl.tk -timeout 3000 -command \#] http::wait $token - http::status $token + set result "[http::status $token] -- [lindex [http::error $token] 0]" # error codes vary among platforms. } -cleanup { catch {http::cleanup $token} -} -returnCodes 1 -match glob -result "couldn't open socket*" +} -match glob -result "error -- couldn't open socket*" + test http-4.16 {Leak with Close vs Keepalive (bug [6ca52aec14]} -setup { proc list-difference {l1 l2} { lmap item $l2 {if {$item in $l1} continue; set item} -- cgit v0.12 From 67331f69a606991d6a166d2c722f61541a5561eb Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 6 Sep 2022 09:04:18 +0000 Subject: amend to [55a02f20ec]: fixes test env-9.1 for not windows - USERPROFILE is not set under unix, and win constraint isn't effective yet since it'll be supplied to test as argument in global scope (check moved to test now) --- tests/env.test | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/env.test b/tests/env.test index ea58b26..25367c3 100644 --- a/tests/env.test +++ b/tests/env.test @@ -453,8 +453,10 @@ test env-9.1 { flush $pipe set result [gets $pipe] close $pipe - set result -} -result $::env(USERPROFILE) + if {$result ne $::env(USERPROFILE)} { + list ERROR $result ne $::env(USERPROFILE) + } +} -result {} -- cgit v0.12 From d041253d886295e7de0e6171a443ccb3f319f3ad Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 6 Sep 2022 15:53:20 +0000 Subject: (Still buggy.) Add the ::socket replacement ::http::socket and its dependencies as a workaround to bug 824251. Integrate with tls. Allow configuration -threadlevel for socket creation (package Thread may not be available and by default it is not used). Revise tests http-1.1, http-1.4, http-1.5 for new option -threadlevel. Run tests for each value of -threadlevel. --- doc/http.n | 27 +++++ library/http/http.tcl | 300 ++++++++++++++++++++++++++++++++++++++++++++++-- tests/http.test | 49 +++++--- tests/http11.test | 22 +++- tests/httpPipeline.test | 26 ++++- 5 files changed, 398 insertions(+), 26 deletions(-) diff --git a/doc/http.n b/doc/http.n index 4781a1b..2c9f809 100644 --- a/doc/http.n +++ b/doc/http.n @@ -173,6 +173,19 @@ retrying the POST. The value \fBtrue\fR should be used only under certain conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The default is 0. .TP +\fB\-threadlevel\fR \fIlevel\fR +. +Specifies whether and how to use the \fBThread\fR package. Possible values of \fIlevel\fR are 0, 1 or 2. +.RS +.PP +.DS +0 - (the default) do not use Thread +1 - use Thread if it is available, do not use it if it is unavailable +2 - use Thread if it is available, raise an error if it is unavailable +.DE +The Tcl \fBsocket -async\fR command can block in adverse cases (e.g. a slow DNS lookup). Using the Thread package works around this problem, for both HTTP and HTTPS transactions. Values of \fIlevel\fR other than 0 are available only to the main interpreter in each thread. See section \fBTHREADS\fR for more information. +.RE +.TP \fB\-urlencoding\fR \fIencoding\fR . The \fIencoding\fR used for creating the x-url-encoded URLs with @@ -986,6 +999,20 @@ the server response code is a 307 redirect, and the response header again in order to fetch this URL. See https://w3c.github.io/webappsec-upgrade-insecure-requests/ .PP +.SH THREADS +.PP +.SS "PURPOSE" +.PP +Command \fB::http::geturl\fR uses the Tcl \fB::socket\fR command with the \-async option to connect to a remote server, but the return from this command can be delayed in adverse cases (e.g. a slow DNS lookup), preventing the event loop from processing other events. This delay is avoided if the \fB::socket\fR command is evaluated in another thread. The Thread package is not part of Tcl but is provided in "Batteries Included" distributions. Instead of the \fB::socket\fR command, the http package uses \fB::http::socket\fR which makes connections in the manner specified by the value of \-threadlevel and the availability of package Thread. +.PP +.SS "WITH TLS (HTTPS)" +.PP +The same \-threadlevel configuration applies to both HTTP and HTTPS connections. HTTPS is enabled by using the \fBhttp::register\fR command, typically by specifying the \fB::tls::socket\fR command of the tls package to handle TLS cryptography. The \fB::tls::socket\fR command connects to the remote server by using the command specified by the value of variable \fI::tls::socketCmd\fR, and this value defaults to "::socket". If http::geturl finds that \fI::tls::socketCmd\fR has this value, it replaces it with the value "::http::socket". If \fI::tls::socketCmd\fR has a value other than "::socket", i.e. if the script or the Tcl installation has replaced the value "::socket" with the name of a different command, then http does not change the value. The script or installation that modified \fI::tls::socketCmd\fR is responsible for integrating \fR::http::socket\fR into its own replacement command. +.PP +.SS "WITH A CHILD INTERPRETER" +.PP +The peer thread can transfer the socket only to the main interpreter of the script's thread. Therefore the thread-based \fB::http::socket\fR works with non-zero \-threadlevel values only if the script runs in the main interpreter. A child interpreter must use \-threadlevel 0 unless the parent interpreter has provided alternative facilities. The main parent interpreter may grant full \-threadlevel facilities to a child interpreter, for example by aliasing, to \fB::http::socket\fR in the child, a command that runs \fBhttp::socket\fR in the parent, and then transfers the socket to the child. +.PP .SH EXAMPLE .PP This example creates a procedure to copy a URL to a file while printing a diff --git a/library/http/http.tcl b/library/http/http.tcl index c3679f1..01d3f8b 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -27,6 +27,7 @@ namespace eval http { -proxyport {} -proxyfilter http::ProxyRequired -repost 0 + -threadlevel 0 -urlencoding utf-8 -zip 1 } @@ -113,7 +114,7 @@ namespace eval http { variable urlTypes if {![info exists urlTypes]} { - set urlTypes(http) [list 80 ::socket] + set urlTypes(http) [list 80 ::http::socket] } variable encodings [string tolower [encoding names]] @@ -148,6 +149,7 @@ namespace eval http { } variable TmpSockCounter 0 + variable ThreadCounter 0 namespace export geturl config reset wait formatQuery quoteString namespace export register unregister registerError @@ -240,6 +242,9 @@ proc http::config {args} { if {![regexp -- $pat $flag]} { return -code error "Unknown option $flag, must be: $usage" } + if {($flag eq {-threadlevel}) && ($value ni {0 1 2})} { + return -code error {Option -threadlevel must be 0, 1 or 2} + } set http($flag) $value } return @@ -313,6 +318,14 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { # immediately, the socket may not yet exist. # Test http-4.11 may come here. } + if {$state(tid) ne {}} { + # When opening the socket in a thread, and calling http::reset + # immediately, the thread may still exist. + # Test http-4.11 may come here. + thread::release $state(tid) + set state(tid) {} + } else { + } } elseif {$upgradeResponse} { # Special handling for an upgrade request/response. # - geturl ensures that this is not a "persistent" socket used for @@ -762,6 +775,24 @@ proc http::reset {token {why reset}} { # array that the caller should unset to garbage collect the state. proc http::geturl {url args} { + variable urlTypes + + # The value is set in the namespace header of this file. If the file has + # not been modified the value is "::http::socket". + set socketCmd [lindex $urlTypes(http) 1] + + # - If ::tls::socketCmd has its default value "::socket", change it to the + # new value $socketCmd. + # - If the old value is different, then it has been modified either by the + # script or by the Tcl installation, and replaced by a new command. The + # script or installation that modified ::tls::socketCmd is also + # responsible for integrating ::http::socket into its own "new" command, + # if it wishes to do so. + + if {[info exists ::tls::socketCmd] && ($::tls::socketCmd eq {::socket})} { + set ::tls::socketCmd $socketCmd + } + set token [CreateToken $url {*}$args] variable $token upvar 0 $token state @@ -810,6 +841,7 @@ proc http::geturl {url args} { # The return value is the variable name of the token. # # Other effects: +# - Sets ::http::http(usingThread) if not already done # - Sets ::http::http(uid) if not already done # - Increments ::http::http(uid) # - May increment ::http::TmpSockCounter @@ -834,6 +866,9 @@ proc http::CreateToken {url args} { # Initialize the state variable, an array. We'll return the name of this # array as the token for the transaction. + if {![info exists http(usingThread)]} { + set http(usingThread) 0 + } if {![info exists http(uid)]} { set http(uid) 0 } @@ -871,6 +906,7 @@ proc http::CreateToken {url args} { status "" http "" connection keep-alive + tid {} } set state(-keepalive) $defaultKeepalive set state(-strict) $strict @@ -1086,7 +1122,7 @@ proc http::CreateToken {url args} { append url : $port } append url $srvurl - # Don't append the fragment! + # Don't append the fragment! RFC 7230 Sec 5.1 set state(url) $url # Proxy connections aren't shared among different hosts. @@ -1213,8 +1249,9 @@ proc http::CreateToken {url args} { lappend socketWrQueue($state(socketinfo)) $token ##Log socketPlayCmd($state(socketinfo)) is $socketPlayCmd($state(socketinfo)) ##Log socketWrQueue($state(socketinfo)) is $socketWrQueue($state(socketinfo)) - } elseif { [catch {fconfigure $socketMapping($state(socketinfo))}] - && (![SockIsPlaHolder $socketMapping($state(socketinfo))]) + } elseif { + [catch {fconfigure $socketMapping($state(socketinfo))}] + && (![SockIsPlaceHolder $socketMapping($state(socketinfo))]) } { ###Log "Socket $socketMapping($state(socketinfo)) for $state(socketinfo)" # FIXME Is it still possible for this code to be executed? If @@ -1237,7 +1274,7 @@ proc http::CreateToken {url args} { # - The socket may not yet exist, and be defined with a placeholder. set reusing 1 set sock $socketMapping($state(socketinfo)) - if {[SockIsPlaHolder $sock]} { + if {[SockIsPlaceHolder $sock]} { set state(ReusingPlaceholder) 1 lappend socketPhQueue($sock) $token } else { @@ -1272,7 +1309,7 @@ proc http::CreateToken {url args} { # ------------------------------------------------------------------------------ -# Proc ::http::SockIsPlaHolder +# Proc ::http::SockIsPlaceHolder # ------------------------------------------------------------------------------ # Command to return 0 if the argument is a genuine socket handle, or 1 if is a # placeholder value generated by geturl or ReplayCore before the real socket is @@ -1284,7 +1321,7 @@ proc http::CreateToken {url args} { # Return Value: 0 or 1 # ------------------------------------------------------------------------------ -proc http::SockIsPlaHolder {sock} { +proc http::SockIsPlaceHolder {sock} { expr {[string range $sock 0 16] eq {HTTP_PLACEHOLDER_}} } @@ -4178,6 +4215,255 @@ proc http::make-transformation-chunked {chan command} { return } + +# ------------------------------------------------------------------------------ +# Proc http::socket +# ------------------------------------------------------------------------------ +# This command is a drop-in replacement for ::socket. +# Arguments and return value as for ::socket. +# +# Notes. +# - http::socket is specified in place of ::socket by the definition of urlTypes +# in the namespace header of this file (http.tcl). +# - The command makes a simple call to ::socket unless the user has called +# http::config to change the value of -threadlevel from the default value 0. +# - For -threadlevel 1 or 2, if the Thread package is available, the command +# waits in the event loop while the socket is opened in another thread. This +# is a workaround for bug [824251] - it prevents http::geturl from blocking +# the event loop if the DNS lookup or server connection is slow. +# - FIXME Use a thread pool if connections are very frequent. +# - FIXME The peer thread can transfer the socket only to the main interpreter +# in the present thread. Therefore this code works only if this script runs +# in the main interpreter. In a child interpreter, the parent must alias a +# command to ::http::socket in the child, run http::socket in the parent, +# and then transfer the socket to the child. +# - The http::socket command is simple, and can easily be replaced with an +# alternative command that uses a different technique to open a socket while +# entering the event loop. +# ------------------------------------------------------------------------------ + +proc http::socket {args} { + variable ThreadVar + variable ThreadCounter + variable http + + LoadThreadIfNeeded + + set targ [lsearch -exact $args -token] + if {$targ != -1} { + set token [lindex $args $targ+1] + set args [lreplace $args $targ $targ+1] + upvar 0 $token state + } + + if {!$http(usingThread)} { + # Use plain "::socket". This is the default. + return [eval ::socket $args] + } + + set defcmd ::socket + set sockargs $args + set script " + [list proc ::SockInThread {caller defcmd sockargs} [info body http::SockInThread]] + [list ::SockInThread [thread::id] $defcmd $sockargs] + " + + set state(tid) [thread::create] + set varName ::http::ThreadVar([incr ThreadCounter]) + thread::send -async $state(tid) $script $varName + Log >T Thread Start Wait $args -- coro [info coroutine] $varName + if {[info coroutine] ne {}} { + # All callers in the http package are coroutines launched by + # the event loop. + # The cwait command requires a coroutine because it yields + # to the caller; $varName is traced and the coroutine resumes + # when the variable is written. + cwait $varName + } else { + return -code error {code must run in a coroutine} + # For testing with a non-coroutine caller outside the http package. + # vwait $varName + } + Log >U Thread End Wait $args -- coro [info coroutine] $varName [set $varName] + thread::release $state(tid) + set state(tid) {} + lassign [set $varName] catchCode errdict sock + unset $varName + dict set errdict -code $catchCode + return -options $errdict $sock +} + +# The commands below are dependencies of http::socket and +# are not used elsewhere. + +# ------------------------------------------------------------------------------ +# Proc http::LoadThreadIfNeeded +# ------------------------------------------------------------------------------ +# Command to load the Thread package if it is needed. If it is needed and not +# loadable, the outcome depends on $http(-threadlevel): +# value 0 => Thread package not required, no problem +# value 1 => operate as if -threadlevel 0 +# value 2 => error return +# +# Arguments: none +# Return Value: none +# ------------------------------------------------------------------------------ + +proc http::LoadThreadIfNeeded {} { + variable http + if {$http(usingThread) || ($http(-threadlevel) == 0)} { + return + } + if {[catch {package require Thread}]} { + if {$http(-threadlevel) == 2} { + set msg {[http::config -threadlevel] has value 2,\ + but the Thread package is not available} + return -code error $msg + } + return + } + set http(usingThread) 1 + return +} + + +# ------------------------------------------------------------------------------ +# Proc http::SockInThread +# ------------------------------------------------------------------------------ +# Command http::socket is a ::socket replacement. It defines and runs this +# command, http::SockInThread, in a peer thread. +# +# Arguments: +# caller +# defcmd +# sockargs +# +# Return value: list of values that describe the outcome. The return is +# intended to be a normal (non-error) return in all cases. +# ------------------------------------------------------------------------------ + +proc http::SockInThread {caller defcmd sockargs} { + package require Thread + + set catchCode [catch {eval $defcmd $sockargs} sock errdict] + if {$catchCode == 0} { + set catchCode [catch {thread::transfer $caller $sock; set sock} sock errdict] + } + return [list $catchCode $errdict $sock] +} + + +# ------------------------------------------------------------------------------ +# Proc ::http::cwaiter::cwait +# ------------------------------------------------------------------------------ +# Command to substitute for vwait, without the ordering issues. +# A command that uses cwait must be a coroutine that is launched by an event, +# e.g. fileevent or after idle, and has no calling code to be resumed upon +# "yield". It cannot return a value. +# +# Arguments: +# varName - fully-qualified name of the variable that the calling script +# will write to resume the coroutine. Any scalar variable or +# array element is permitted. +# coroName - (optional) name of the coroutine to be called when varName is +# written - defaults to this coroutine +# timeout - (optional) timeout value in ms +# timeoutValue - (optional) value to assign to varName if there is a timeout +# +# Return Value: none +# ------------------------------------------------------------------------------ + +namespace eval ::http::cwaiter { + namespace export cwait + variable log {} + variable logOn 0 +} + +proc ::http::cwaiter::cwait { + varName {coroName {}} {timeout {}} {timeoutValue {}} +} { + set thisCoro [info coroutine] + if {$thisCoro eq {}} { + return -code error {cwait cannot be called outside a coroutine} + } + if {$coroName eq {}} { + set coroName $thisCoro + } + if {[string range $varName 0 1] ne {::}} { + return -code error {argument varName must be fully qualified} + } + if {$timeout eq {}} { + set toe {} + } elseif {[string is integer -strict $timeout] && ($timeout > 0)} { + set toe [after $timeout [list set $varName $timeoutValue]] + } else { + return -code error {if timeout is supplied it must be a positive integer} + } + + set cmd [list ::http::cwaiter::CwaitHelper $varName $coroName $toe] + trace add variable $varName write $cmd + CoLog "Yield $varName $coroName" + yield + CoLog "Resume $varName $coroName" + return +} + + +# ------------------------------------------------------------------------------ +# Proc ::http::cwaiter::CwaitHelper +# ------------------------------------------------------------------------------ +# Helper command called by the trace set by cwait. +# - Ignores the arguments added by trace. +# - A simple call to $coroName works, and in error cases gives a suitable stack +# trace, but because it is inside a trace the headline error message is +# something like {can't set "::Result(6)": error}, not the actual +# error. So let the trace command return. +# - Remove the trace immediately. We don't want multiple calls. +# ------------------------------------------------------------------------------ + +proc ::http::cwaiter::CwaitHelper {varName coroName toe args} { + CoLog "got $varName for $coroName" + set cmd [list ::http::cwaiter::CwaitHelper $varName $coroName $toe] + trace remove variable $varName write $cmd + after cancel $toe + + after 0 $coroName + return +} + + +# ------------------------------------------------------------------------------ +# Proc ::http::cwaiter::LogInit +# ------------------------------------------------------------------------------ +# Call this command to initiate debug logging and clear the log. +# ------------------------------------------------------------------------------ + +proc ::http::cwaiter::LogInit {} { + variable log + variable logOn + set log {} + set logOn 1 + return +} + +proc ::http::cwaiter::LogRead {} { + variable log + return $log +} + +proc ::http::cwaiter::CoLog {msg} { + variable log + variable logOn + if {$logOn} { + append log $msg \n + } + return +} + +namespace eval ::http { + namespace import ::http::cwaiter::* +} + # Local variables: # indent-tabs-mode: t # End: diff --git a/tests/http.test b/tests/http.test index 59078f2..26ba710 100644 --- a/tests/http.test +++ b/tests/http.test @@ -17,20 +17,7 @@ if {"::tcltest" ni [namespace children]} { } package require tcltests -if {[catch {package require http 2} version]} { - if {[info exists http2]} { - catch {puts "Cannot load http 2.* package"} - return - } else { - catch {puts "Running http 2.* tests in child interp"} - set interp [interp create http2] - $interp eval [list set http2 "running"] - $interp eval [list set argv $argv] - $interp eval [list source [info script]] - interp delete $interp - return - } -} +package require http 2.10 proc bgerror {args} { global errorInfo @@ -78,11 +65,31 @@ if {[catch {package present Thread}] == 0 && [file exists $httpdFile]} { return } } + +if {![info exists ThreadLevel]} { + if {[catch {package require Thread}] == 0} { + set ValueRange {0 1 2} + } else { + set ValueRange {0 1} + } + + # For each value of ThreadLevel, source this file recursively in the + # same interpreter. + foreach ThreadLevel $ValueRange { + source [info script] + } + catch {unset ThreadLevel} + catch {unset ValueRange} + return +} + +catch {puts "==== Test with ThreadLevel $ThreadLevel ===="} +http::config -threadlevel $ThreadLevel test http-1.1 {http::config} { http::config -useragent UserAgent http::config -} [list -accept */* -cookiejar {} -pipeline 1 -postfresh 0 -proxyfilter http::ProxyRequired -proxyhost {} -proxyport {} -repost 0 -urlencoding utf-8 -useragent UserAgent -zip 1] +} [list -accept */* -cookiejar {} -pipeline 1 -postfresh 0 -proxyfilter http::ProxyRequired -proxyhost {} -proxyport {} -repost 0 -threadlevel $ThreadLevel -urlencoding utf-8 -useragent UserAgent -zip 1] test http-1.2 {http::config} { http::config -proxyfilter } http::ProxyRequired @@ -97,10 +104,10 @@ test http-1.4 {http::config} { set x [http::config] http::config {*}$savedconf set x -} {-accept */* -cookiejar {} -pipeline 1 -postfresh 0 -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -repost 0 -urlencoding iso8859-1 -useragent {Tcl Test Suite} -zip 1} +} [list -accept */* -cookiejar {} -pipeline 1 -postfresh 0 -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -repost 0 -threadlevel $ThreadLevel -urlencoding iso8859-1 -useragent {Tcl Test Suite} -zip 1] test http-1.5 {http::config} -returnCodes error -body { http::config -proxyhost {} -junk 8080 -} -result {Unknown option -junk, must be: -accept, -cookiejar, -pipeline, -postfresh, -proxyfilter, -proxyhost, -proxyport, -repost, -urlencoding, -useragent, -zip} +} -result {Unknown option -junk, must be: -accept, -cookiejar, -pipeline, -postfresh, -proxyfilter, -proxyhost, -proxyport, -repost, -threadlevel, -urlencoding, -useragent, -zip} test http-1.6 {http::config} -setup { set oldenc [http::config -urlencoding] } -body { @@ -139,9 +146,11 @@ test http-2.8 {http::CharsetToEncoding} { test http-3.1 {http::geturl} -returnCodes error -body { http::geturl -bogus flag } -result {Unknown option flag, can be: -binary, -blocksize, -channel, -command, -handler, -headers, -keepalive, -method, -myaddr, -progress, -protocol, -query, -queryblocksize, -querychannel, -queryprogress, -strict, -timeout, -type, -validate} + test http-3.2 {http::geturl} -returnCodes error -body { http::geturl http:junk } -result {Unsupported URL: http:junk} + set url //${::HOST}:$port set badurl //${::HOST}:[expr {$port+1}] test http-3.3 {http::geturl} -body { @@ -153,6 +162,7 @@ test http-3.3 {http::geturl} -body {

Hello, World!

GET /

" + set tail /a/b/c set url //${::HOST}:$port/a/b/c set fullurl HTTP://user:pass@${::HOST}:$port/a/b/c @@ -162,6 +172,7 @@ set posturl //${::HOST}:$port/post set badposturl //${::HOST}:$port/droppost set authorityurl //${::HOST}:$port set ipv6url http://\[::1\]:$port/ + test http-3.4 {http::geturl} -body { set token [http::geturl $url] http::data $token @@ -572,6 +583,7 @@ test http-4.10 {http::Event} -body { } -cleanup { http::cleanup $token } -result {111} + # Timeout cases # Short timeout to working server (the test server). This lets us try a # reset during the connection. @@ -582,6 +594,7 @@ test http-4.11 {http::Event} -body { } -cleanup { http::cleanup $token } -result {reset} + # Longer timeout with reset. test http-4.12 {http::Event} -body { set token [http::geturl $url/?timeout=10 -keepalive 0 -command \#] @@ -590,6 +603,7 @@ test http-4.12 {http::Event} -body { } -cleanup { http::cleanup $token } -result {reset} + # Medium timeout to working server that waits even longer. The timeout # hits while waiting for a reply. test http-4.13 {http::Event} -body { @@ -599,6 +613,7 @@ test http-4.13 {http::Event} -body { } -cleanup { http::cleanup $token } -result {timeout} + # Longer timeout to good host, bad port, gets an error after the # connection "completes" but the socket is bad. test http-4.14 {http::Event} -body { diff --git a/tests/http11.test b/tests/http11.test index 4f6fb92..346e334 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -12,7 +12,7 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } -package require http 2.9 +package require http 2.10 # start the server variable httpd_output @@ -87,6 +87,26 @@ proc check_crc {tok args} { } makeFile "test

this is a test

\n[string repeat {

This is a tcl test file.

} 4192]\n" testdoc.html + +if {![info exists ThreadLevel]} { + if {[catch {package require Thread}] == 0} { + set ValueRange {0 1 2} + } else { + set ValueRange {0 1} + } + + # For each value of ThreadLevel, source this file recursively in the + # same interpreter. + foreach ThreadLevel $ValueRange { + source [info script] + } + catch {unset ThreadLevel} + catch {unset ValueRange} + return +} + +catch {puts "==== Test with ThreadLevel $ThreadLevel ===="} +http::config -threadlevel $ThreadLevel # ------------------------------------------------------------------------- diff --git a/tests/httpPipeline.test b/tests/httpPipeline.test index 4e55a10..161519f 100644 --- a/tests/httpPipeline.test +++ b/tests/httpPipeline.test @@ -13,7 +13,31 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } -package require http 2.9 +package require http 2.10 + +# ------------------------------------------------------------------------------ +# (0) Socket Creation in Thread, which triples the number of tests. +# ------------------------------------------------------------------------------ + +if {![info exists ThreadLevel]} { + if {[catch {package require Thread}] == 0} { + set ValueRange {0 1 2} + } else { + set ValueRange {0 1} + } + + # For each value of ThreadLevel, source this file recursively in the + # same interpreter. + foreach ThreadLevel $ValueRange { + source [info script] + } + catch {unset ThreadLevel} + catch {unset ValueRange} + return +} + +catch {puts "==== Test with ThreadLevel $ThreadLevel ===="} +http::config -threadlevel $ThreadLevel set sourcedir [file normalize [file dirname [info script]]] source [file join $sourcedir httpTest.tcl] -- cgit v0.12 From ea5d97f286ae2af57a461f9935df7664ca625edf Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 7 Sep 2022 07:22:07 +0000 Subject: code cleanup (backported from 8.7) --- unix/tclUnixSock.c | 78 +++--- win/tclWinSock.c | 766 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 497 insertions(+), 347 deletions(-) diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index 858afdb..ffb70e1 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -64,7 +64,7 @@ struct TcpState { Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ - ClientData acceptProcData; /* The data for the accept proc. */ + void *acceptProcData; /* The data for the accept proc. */ /* * Only needed for client sockets @@ -118,27 +118,27 @@ struct TcpState { * Static routines for this file: */ -static void TcpAsyncCallback(ClientData clientData, int mask); +static void TcpAsyncCallback(void *clientData, int mask); static int TcpConnect(Tcl_Interp *interp, TcpState *state); -static void TcpAccept(ClientData data, int mask); -static int TcpBlockModeProc(ClientData data, int mode); -static int TcpCloseProc(ClientData instanceData, +static void TcpAccept(void *data, int mask); +static int TcpBlockModeProc(void *data, int mode); +static int TcpCloseProc(void *instanceData, Tcl_Interp *interp); -static int TcpClose2Proc(ClientData instanceData, +static int TcpClose2Proc(void *instanceData, Tcl_Interp *interp, int flags); -static int TcpGetHandleProc(ClientData instanceData, - int direction, ClientData *handlePtr); -static int TcpGetOptionProc(ClientData instanceData, +static int TcpGetHandleProc(void *instanceData, + int direction, void **handlePtr); +static int TcpGetOptionProc(void *instanceData, Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); -static int TcpInputProc(ClientData instanceData, char *buf, +static int TcpInputProc(void *instanceData, char *buf, int toRead, int *errorCode); -static int TcpOutputProc(ClientData instanceData, +static int TcpOutputProc(void *instanceData, const char *buf, int toWrite, int *errorCode); -static void TcpThreadActionProc(ClientData instanceData, int action); -static void TcpWatchProc(ClientData instanceData, int mask); +static void TcpThreadActionProc(void *instanceData, int action); +static void TcpWatchProc(void *instanceData, int mask); static int WaitForConnect(TcpState *statePtr, int *errorCodePtr); -static void WrapNotify(ClientData clientData, int mask); +static void WrapNotify(void *clientData, int mask); /* * This structure describes the channel type structure for TCP socket @@ -218,7 +218,7 @@ InitializeHostName( struct hostent *hp; memset(&u, (int) 0, sizeof(struct utsname)); - if (uname(&u) > -1) { /* INTL: Native. */ + if (uname(&u) >= 0) { /* INTL: Native. */ hp = TclpGetHostByName(u.nodename); /* INTL: Native. */ if (hp == NULL) { /* @@ -269,14 +269,14 @@ InitializeHostName( char buffer[256]; # endif - if (gethostname(buffer, sizeof(buffer)) > -1) { /* INTL: Native. */ + if (gethostname(buffer, sizeof(buffer)) >= 0) { /* INTL: Native. */ native = buffer; } #endif /* NO_UNAME */ *encodingPtr = Tcl_GetEncoding(NULL, NULL); *lengthPtr = strlen(native); - *valuePtr = ckalloc(*lengthPtr + 1); + *valuePtr = (char *)ckalloc(*lengthPtr + 1); memcpy(*valuePtr, native, *lengthPtr + 1); } @@ -370,7 +370,7 @@ TclpFinalizeSockets(void) static int TcpBlockModeProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ int mode) /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ @@ -501,7 +501,7 @@ WaitForConnect( static int TcpInputProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available in the * buffer? */ @@ -514,8 +514,8 @@ TcpInputProc( if (WaitForConnect(statePtr, errorCodePtr) != 0) { return -1; } - bytesRead = recv(statePtr->fds.fd, buf, (size_t) bufSize, 0); - if (bytesRead > -1) { + bytesRead = recv(statePtr->fds.fd, buf, bufSize, 0); + if (bytesRead >= 0) { return bytesRead; } if (errno == ECONNRESET) { @@ -552,7 +552,7 @@ TcpInputProc( static int TcpOutputProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ const char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCodePtr) /* Where to store error code. */ @@ -566,7 +566,7 @@ TcpOutputProc( } written = send(statePtr->fds.fd, buf, (size_t) toWrite, 0); - if (written > -1) { + if (written >= 0) { return written; } *errorCodePtr = errno; @@ -593,7 +593,7 @@ TcpOutputProc( static int TcpCloseProc( - ClientData instanceData, /* The socket to close. */ + void *instanceData, /* The socket to close. */ Tcl_Interp *dummy) /* For error reporting - unused. */ { TcpState *statePtr = (TcpState *)instanceData; @@ -655,7 +655,7 @@ TcpCloseProc( static int TcpClose2Proc( - ClientData instanceData, /* The socket to close. */ + void *instanceData, /* The socket to close. */ Tcl_Interp *dummy, /* For error reporting. */ int flags) /* Flags that indicate which side to close. */ { @@ -807,7 +807,7 @@ TcpHostPortList( static int TcpGetOptionProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ const char *optionName, /* Name of the option to retrieve the value * for, or NULL to get all options and their @@ -852,8 +852,8 @@ TcpGetOptionProc( if ((len > 1) && (optionName[1] == 'c') && (strncmp(optionName, "-connecting", len) == 0)) { - Tcl_DStringAppend(dsPtr, - GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT) ? "1" : "0", -1); + Tcl_DStringAppend(dsPtr, + GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT) ? "1" : "0", -1); return TCL_OK; } @@ -973,7 +973,7 @@ TcpGetOptionProc( static void TcpThreadActionProc( - ClientData instanceData, + void *instanceData, int action) { TcpState *statePtr = (TcpState *)instanceData; @@ -1018,7 +1018,7 @@ TcpThreadActionProc( static void WrapNotify( - ClientData clientData, + void *clientData, int mask) { TcpState *statePtr = (TcpState *) clientData; @@ -1047,7 +1047,7 @@ WrapNotify( static void TcpWatchProc( - ClientData instanceData, /* The socket state. */ + void *instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ @@ -1120,9 +1120,9 @@ TcpWatchProc( static int TcpGetHandleProc( - ClientData instanceData, /* The socket state. */ + void *instanceData, /* The socket state. */ int direction, /* Not used. */ - ClientData *handlePtr) /* Where to store the handle. */ + void **handlePtr) /* Where to store the handle. */ { TcpState *statePtr = (TcpState *)instanceData; (void)direction; @@ -1145,7 +1145,7 @@ TcpGetHandleProc( static void TcpAsyncCallback( - ClientData clientData, /* The socket state. */ + void *clientData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ @@ -1428,7 +1428,7 @@ Tcl_OpenTcpClient( return NULL; } - sprintf(channelName, SOCK_TEMPLATE, (long) statePtr); + sprintf(channelName, SOCK_TEMPLATE, (long)statePtr); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, statePtr, TCL_READABLE | TCL_WRITABLE); @@ -1458,7 +1458,7 @@ Tcl_OpenTcpClient( Tcl_Channel Tcl_MakeTcpClientChannel( - ClientData sock) /* The socket to wrap up into a channel. */ + void *sock) /* The socket to wrap up into a channel. */ { return (Tcl_Channel) TclpMakeTcpClientChannelMode(sock, TCL_READABLE | TCL_WRITABLE); @@ -1532,7 +1532,7 @@ Tcl_OpenTcpServer( Tcl_TcpAcceptProc *acceptProc, /* Callback for accepting connections from new * clients. */ - ClientData acceptProcData) /* Data for the callback. */ + void *acceptProcData) /* Data for the callback. */ { int status = 0, sock = -1, reuseaddr = 1, chosenport = 0; struct addrinfo *addrlist = NULL, *addrPtr; /* socket address */ @@ -1717,7 +1717,7 @@ Tcl_OpenTcpServer( static void TcpAccept( - ClientData data, /* Callback token. */ + void *data, /* Callback token. */ int mask) /* Not used. */ { TcpFdList *fds = (TcpFdList *)data; /* Client data of server socket. */ @@ -1747,7 +1747,7 @@ TcpAccept( newSockState->flags = 0; newSockState->fds.fd = newsock; - sprintf(channelName, SOCK_TEMPLATE, (long) newSockState); + sprintf(channelName, SOCK_TEMPLATE, (long)newSockState); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, newSockState, TCL_READABLE | TCL_WRITABLE); diff --git a/win/tclWinSock.c b/win/tclWinSock.c index a4547a8..09b5d52 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -78,6 +78,7 @@ #define SET_BITS(var, bits) ((var) |= (bits)) #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) +#define GOT_BITS(var, bits) (((var) & (bits)) != 0) /* "sock" + a pointer in hex + \0 */ #define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1) @@ -90,7 +91,7 @@ */ static int initialized = 0; -static const WCHAR classname[] = L"TclSocket"; +static const WCHAR className[] = L"TclSocket"; TCL_DECLARE_MUTEX(socketMutex) /* @@ -155,7 +156,7 @@ struct TcpState { * protected by semaphore */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ - ClientData acceptProcData; /* The data for the accept proc. */ + void *acceptProcData; /* The data for the accept proc. */ /* * Only needed for client sockets @@ -242,7 +243,7 @@ static int TcpConnect(Tcl_Interp *interp, TcpState *state); static void InitSockets(void); static TcpState * NewSocketInfo(SOCKET socket); -static void SocketExitHandler(ClientData clientData); +static void SocketExitHandler(void *clientData); static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static int SocketsEnabled(void); @@ -253,7 +254,7 @@ static int WaitForSocketEvent(TcpState *statePtr, int events, static void AddSocketInfoFd(TcpState *statePtr, SOCKET socket); static int FindFDInList(TcpState *statePtr, SOCKET socket); static DWORD WINAPI SocketThread(LPVOID arg); -static void TcpThreadActionProc(ClientData instanceData, +static void TcpThreadActionProc(void *instanceData, int action); static Tcl_EventCheckProc SocketCheckProc; @@ -301,22 +302,39 @@ static const Tcl_ChannelType tcpChannelType = { static TclInitProcessGlobalValueProc InitializeHostName; static ProcessGlobalValue hostName = {0, 0, NULL, NULL, InitializeHostName, NULL, NULL}; + +/* + * Simple wrapper round the SendMessage syscall. + */ + +#define SendSelectMessage(tsdPtr, message, payload) \ + SendMessageW((tsdPtr)->hwnd, SOCKET_SELECT, \ + (WPARAM) (message), (LPARAM) (payload)) + /* * Address print debug functions */ #if 0 -void printaddrinfo(struct addrinfo *ai, char *prefix) +void +printaddrinfo( + struct addrinfo *ai, + char *prefix) { char host[NI_MAXHOST], port[NI_MAXSERV]; + getnameinfo(ai->ai_addr, ai->ai_addrlen, - host, sizeof(host), - port, sizeof(port), - NI_NUMERICHOST|NI_NUMERICSERV); + host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST|NI_NUMERICSERV); } -void printaddrinfolist(struct addrinfo *addrlist, char *prefix) + +void +printaddrinfolist( + struct addrinfo *addrlist, + char *prefix) { struct addrinfo *ai; + for (ai = addrlist; ai != NULL; ai = ai->ai_next) { printaddrinfo(ai, prefix); } @@ -368,8 +386,8 @@ InitializeHostName( Tcl_DStringSetLength(&inDs, 256); if (gethostname(Tcl_DStringValue(&inDs), Tcl_DStringLength(&inDs)) == 0) { - Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&inDs), -1, - &ds); + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&inDs), + -1, &ds); } Tcl_DStringFree(&inDs); } @@ -377,7 +395,7 @@ InitializeHostName( *encodingPtr = Tcl_GetEncoding(NULL, "utf-8"); *lengthPtr = Tcl_DStringLength(&ds); - *valuePtr = ckalloc((*lengthPtr) + 1); + *valuePtr = (char *)ckalloc(*lengthPtr + 1); memcpy(*valuePtr, Tcl_DStringValue(&ds), *lengthPtr + 1); Tcl_DStringFree(&ds); } @@ -469,7 +487,7 @@ TclpHasSockets( void TclpFinalizeSockets(void) { - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Careful! This is a finalizer! @@ -524,17 +542,17 @@ TclpFinalizeSockets(void) static int TcpBlockModeProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ int mode) /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; if (mode == TCL_MODE_NONBLOCKING) { - statePtr->flags |= TCP_NONBLOCKING; + SET_BITS(statePtr->flags, TCP_NONBLOCKING); } else { - statePtr->flags &= ~(TCP_NONBLOCKING); + CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING); } return 0; } @@ -544,29 +562,28 @@ TcpBlockModeProc( * * WaitForConnect -- * - * Check the state of an async connect process. If a connection - * attempt terminated, process it, which may finalize it or may - * start the next attempt. If a connect error occures, it is saved - * in statePtr->connectError to be reported by 'fconfigure -error'. + * Check the state of an async connect process. If a connection attempt + * terminated, process it, which may finalize it or may start the next + * attempt. If a connect error occures, it is saved in + * statePtr->connectError to be reported by 'fconfigure -error'. * * There are two modes of operation, defined by errorCodePtr: - * * non-NULL: Called by explicite read/write command. block if - * socket is blocking. + * * non-NULL: Called by explicite read/write command. Block if socket + * is blocking. * May return two error codes: * * EWOULDBLOCK: if connect is still in progress - * * ENOTCONN: if connect failed. This would be the error - * message of a rect or sendto syscall so this is - * emulated here. - * * Null: Called by a backround operation. Do not block and - * don't return any error code. + * * ENOTCONN: if connect failed. This would be the error message + * of a rect or sendto syscall so this is emulated here. + * * Null: Called by a backround operation. Do not block and don't + * return any error code. * * Results: - * 0 if the connection has completed, -1 if still in progress - * or there is an error. + * 0 if the connection has completed, -1 if still in progress or there is + * an error. * * Side effects: - * Processes socket events off the system queue. - * May process asynchronous connect. + * Processes socket events off the system queue. May process + * asynchronous connect. * *---------------------------------------------------------------------- */ @@ -574,20 +591,19 @@ TcpBlockModeProc( static int WaitForConnect( TcpState *statePtr, /* State of the socket. */ - int *errorCodePtr) /* Where to store errors? - * A passed null-pointer activates background mode. - */ + int *errorCodePtr) /* Where to store errors? A passed + * null-pointer activates background mode. */ { int result; int oldMode; ThreadSpecificData *tsdPtr; /* - * Check if an async connect failed already and error reporting is demanded, - * return the error ENOTCONN + * Check if an async connect failed already and error reporting is + * demanded, return the error ENOTCONN. */ - if (errorCodePtr != NULL && (statePtr->flags & TCP_ASYNC_FAILED)) { + if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { *errorCodePtr = ENOTCONN; return -1; } @@ -596,7 +612,7 @@ WaitForConnect( * Check if an async connect is running. If not return ok */ - if (!(statePtr->flags & TCP_ASYNC_CONNECT)) { + if (!GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { return 0; } @@ -611,36 +627,51 @@ WaitForConnect( */ while (1) { + /* + * Get the statePtr lock. + */ - /* get statePtr lock */ - tsdPtr = TclThreadDataKeyGet(&dataKey); + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - /* Check for connect event */ - if (statePtr->readyEvents & FD_CONNECT) { + /* + * Check for connect event. + */ - /* Consume the connect event */ - statePtr->readyEvents &= ~(FD_CONNECT); + if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) { + /* + * Consume the connect event. + */ + + CLEAR_BITS(statePtr->readyEvents, FD_CONNECT); /* - * For blocking sockets and foreground processing - * disable async connect as we continue now synchoneously + * For blocking sockets and foreground processing, disable async + * connect as we continue now synchoneously. */ - if ( errorCodePtr != NULL && - ! (statePtr->flags & TCP_NONBLOCKING) ) { + + if (errorCodePtr != NULL && + !GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); } - /* Free list lock */ + /* + * Free list lock. + */ + SetEvent(tsdPtr->socketListLock); /* - * Continue connect. - * If switched to synchroneous connect, the connect is terminated. + * Continue connect. If switched to synchroneous connect, the + * connect is terminated. */ + result = TcpConnect(NULL, statePtr); - /* Restore event service mode */ + /* + * Restore event service mode. + */ + (void) Tcl_SetServiceMode(oldMode); /* @@ -649,10 +680,11 @@ WaitForConnect( if (result == TCL_OK) { /* - * Check for async connect restart - * (not possible for foreground blocking operation) + * Check for async connect restart (not possible for + * foreground blocking operation) */ - if ( statePtr->flags & TCP_ASYNC_PENDING ) { + + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { if (errorCodePtr != NULL) { *errorCodePtr = EWOULDBLOCK; } @@ -662,8 +694,8 @@ WaitForConnect( } /* - * Connect finally failed. - * For foreground operation return ENOTCONN. + * Connect finally failed. For foreground operation return + * ENOTCONN. */ if (errorCodePtr != NULL) { @@ -672,7 +704,10 @@ WaitForConnect( return -1; } - /* Free list lock */ + /* + * Free list lock. + */ + SetEvent(tsdPtr->socketListLock); /* @@ -680,7 +715,7 @@ WaitForConnect( * event */ - if ( errorCodePtr == NULL ) { + if (errorCodePtr == NULL) { return -1; } @@ -689,7 +724,7 @@ WaitForConnect( * returns directly the error EWOULDBLOCK */ - if (statePtr->flags & TCP_NONBLOCKING) { + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { *errorCodePtr = EWOULDBLOCK; return -1; } @@ -723,16 +758,16 @@ WaitForConnect( static int TcpInputProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available in the * buffer? */ int *errorCodePtr) /* Where to store error code. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; int bytesRead; DWORD error; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -752,7 +787,7 @@ TcpInputProc( * socket stack after the first time EOF is detected. */ - if (statePtr->flags & SOCKET_EOF) { + if (GOT_BITS(statePtr->flags, SOCKET_EOF)) { return 0; } @@ -775,18 +810,22 @@ TcpInputProc( */ while (1) { - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); - /* single fd operation: this proc is only called for a connected socket. */ + SendSelectMessage(tsdPtr, UNSELECT, statePtr); + + /* + * Single fd operation: this proc is only called for a connected + * socket. + */ + bytesRead = recv(statePtr->sockets->fd, buf, bufSize, 0); - statePtr->readyEvents &= ~(FD_READ); + CLEAR_BITS(statePtr->readyEvents, FD_READ); /* * Check for end-of-file condition or successful read. */ if (bytesRead == 0) { - statePtr->flags |= SOCKET_EOF; + SET_BITS(statePtr->flags, SOCKET_EOF); } if (bytesRead != SOCKET_ERROR) { break; @@ -797,8 +836,8 @@ TcpInputProc( * error and report an EOF. */ - if (statePtr->readyEvents & FD_CLOSE) { - statePtr->flags |= SOCKET_EOF; + if (GOT_BITS(statePtr->readyEvents, FD_CLOSE)) { + SET_BITS(statePtr->flags, SOCKET_EOF); bytesRead = 0; break; } @@ -811,7 +850,7 @@ TcpInputProc( */ if (error == WSAECONNRESET) { - statePtr->flags |= SOCKET_EOF; + SET_BITS(statePtr->flags, SOCKET_EOF); bytesRead = 0; break; } @@ -820,7 +859,8 @@ TcpInputProc( * Check for error condition or underflow in non-blocking case. */ - if ((statePtr->flags & TCP_NONBLOCKING) || (error != WSAEWOULDBLOCK)) { + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING) + || (error != WSAEWOULDBLOCK)) { TclWinConvertError(error); *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; @@ -838,7 +878,7 @@ TcpInputProc( } } - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); return bytesRead; } @@ -862,15 +902,15 @@ TcpInputProc( static int TcpOutputProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ const char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCodePtr) /* Where to store error code. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; int written; DWORD error; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -896,10 +936,13 @@ TcpOutputProc( } while (1) { - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); + + /* + * Single fd operation: this proc is only called for a connected + * socket. + */ - /* single fd operation: this proc is only called for a connected socket. */ written = send(statePtr->sockets->fd, buf, toWrite, 0); if (written != SOCKET_ERROR) { /* @@ -908,8 +951,9 @@ TcpOutputProc( * until the condition changes. */ - if (statePtr->watchEvents & FD_WRITE) { + if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) { Tcl_Time blockTime = { 0, 0 }; + Tcl_SetMaxBlockTime(&blockTime); } break; @@ -924,8 +968,8 @@ TcpOutputProc( error = WSAGetLastError(); if (error == WSAEWOULDBLOCK) { - statePtr->readyEvents &= ~(FD_WRITE); - if (statePtr->flags & TCP_NONBLOCKING) { + CLEAR_BITS(statePtr->readyEvents, FD_WRITE); + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { *errorCodePtr = EWOULDBLOCK; written = -1; break; @@ -948,7 +992,7 @@ TcpOutputProc( } } - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); return written; } @@ -973,10 +1017,10 @@ TcpOutputProc( static int TcpCloseProc( - ClientData instanceData, /* The socket to close. */ + void *instanceData, /* The socket to close. */ Tcl_Interp *interp) /* Unused. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; /* TIP #218 */ int errorCode = 0; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -994,10 +1038,10 @@ TcpCloseProc( * background. */ - while ( statePtr->sockets != NULL ) { + while (statePtr->sockets != NULL) { TcpFdList *thisfd = statePtr->sockets; - statePtr->sockets = thisfd->next; + statePtr->sockets = thisfd->next; if (closesocket(thisfd->fd) == SOCKET_ERROR) { TclWinConvertError((DWORD) WSAGetLastError()); errorCode = Tcl_GetErrno(); @@ -1015,18 +1059,25 @@ TcpCloseProc( /* * Clear an eventual tsd info list pointer. + * * This may be called, if an async socket connect fails or is closed * between connect and thread action callback. */ + if (tsdPtr->pendingTcpState != NULL && tsdPtr->pendingTcpState == statePtr) { + /* + * Get infoPtr lock, because this concerns the notifier thread. + */ - /* get infoPtr lock, because this concerns the notifier thread */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); tsdPtr->pendingTcpState = NULL; - /* Free list lock */ + /* + * Free list lock. + */ + SetEvent(tsdPtr->socketListLock); } @@ -1060,11 +1111,11 @@ TcpCloseProc( static int TcpClose2Proc( - ClientData instanceData, /* The socket to close. */ + void *instanceData, /* The socket to close. */ Tcl_Interp *interp, /* For error reporting. */ int flags) /* Flags that indicate which side to close. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; int readError = 0; int writeError = 0; @@ -1076,8 +1127,11 @@ TcpClose2Proc( return TcpCloseProc(instanceData, interp); } - /* single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or - * TCL_WRITABLE so this should never be called for a server socket. */ + /* + * Single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or + * TCL_WRITABLE so this should never be called for a server socket. + */ + if ((flags & TCL_CLOSE_READ) && (shutdown(statePtr->sockets->fd, SD_RECEIVE) == SOCKET_ERROR)) { TclWinConvertError((DWORD) WSAGetLastError()); readError = Tcl_GetErrno(); @@ -1107,7 +1161,7 @@ TcpClose2Proc( static int TcpSetOptionProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ const char *optionName, /* Name of the option to set. */ const char *value) /* New value for option. */ @@ -1132,7 +1186,7 @@ TcpSetOptionProc( } #ifdef TCL_FEATURE_KEEPALIVE_NAGLE - #error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat statePtr->sockets as single fd or list" +#error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat statePtr->sockets as single fd or list" sock = statePtr->sockets->fd; if (!strcasecmp(optionName, "-keepalive")) { @@ -1210,7 +1264,7 @@ TcpSetOptionProc( static int TcpGetOptionProc( - ClientData instanceData, /* Socket state. */ + void *instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ const char *optionName, /* Name of the option to retrieve the value * for, or NULL to get all options and their @@ -1218,7 +1272,7 @@ TcpGetOptionProc( Tcl_DString *dsPtr) /* Where to store the computed value; * initialized by caller. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; char host[NI_MAXHOST], port[NI_MAXSERV]; SOCKET sock; size_t len = 0; @@ -1241,7 +1295,9 @@ TcpGetOptionProc( /* * Go one step in async connect - * If any error is thrown save it as backround error to report eventually below + * + * If any error is thrown save it as backround error to report eventually + * below. */ WaitForConnect(statePtr, NULL); @@ -1252,31 +1308,26 @@ TcpGetOptionProc( if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { - /* - * Do not return any errors if async connect is running - */ - if ( ! (statePtr->flags & TCP_ASYNC_PENDING) ) { - - - if ( statePtr->flags & TCP_ASYNC_FAILED ) { + * Do not return any errors if async connect is running. + */ + if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { /* * In case of a failed async connect, eventually report the - * connect error only once. - * Do not report the system error, as this comes again and again. + * connect error only once. Do not report the system error, + * as this comes again and again. */ - if ( statePtr->connectError != 0 ) { + if (statePtr->connectError != 0) { Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(statePtr->connectError), -1); statePtr->connectError = 0; } - } else { - /* - * Report an eventual last error of the socket system + * Report an eventual last error of the socket system. */ int optlen; @@ -1284,21 +1335,26 @@ TcpGetOptionProc( DWORD err; /* - * Populater the err Variable with a possix error + * Populate the err variable with a POSIX error */ + optlen = sizeof(int); ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); + /* - * The error was not returned directly but should be - * taken from WSA + * The error was not returned directly but should be taken + * from WSA. */ + if (ret == SOCKET_ERROR) { err = WSAGetLastError(); } + /* - * Return error message + * Return error message. */ + if (err) { TclWinConvertError(err); Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); @@ -1310,14 +1366,14 @@ TcpGetOptionProc( if ((len > 1) && (optionName[1] == 'c') && (strncmp(optionName, "-connecting", len) == 0)) { - Tcl_DStringAppend(dsPtr, - (statePtr->flags & TCP_ASYNC_PENDING) + GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING) ? "1" : "0", -1); return TCL_OK; } - if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) { + if (interp != NULL + && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) { reverseDNS = NI_NUMERICHOST; } @@ -1326,20 +1382,23 @@ TcpGetOptionProc( address peername; socklen_t size = sizeof(peername); - if ( (statePtr->flags & TCP_ASYNC_PENDING) ) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * In async connect output an empty string */ + if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringAppendElement(dsPtr, ""); } else { return TCL_OK; } - } else if ( getpeername(sock, (LPSOCKADDR) &(peername.sa), &size) == 0) { + } else if (getpeername(sock, (LPSOCKADDR) &(peername.sa), + &size) == 0) { /* * Peername fetch succeeded - output list */ + if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); @@ -1388,11 +1447,12 @@ TcpGetOptionProc( Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } - if ( (statePtr->flags & TCP_ASYNC_PENDING ) ) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * In async connect output an empty string */ - found = 1; + + found = 1; } else { for (fds = statePtr->sockets; fds != NULL; fds = fds->next) { sock = fds->fd; @@ -1406,9 +1466,11 @@ TcpGetOptionProc( Tcl_DStringAppendElement(dsPtr, host); /* - * We don't want to resolve INADDR_ANY and sin6addr_any; they - * can sometimes cause problems (and never have a name). + * We don't want to resolve INADDR_ANY and sin6addr_any; + * they can sometimes cause problems (and never have a + * name). */ + flags |= NI_NUMERICSERV; if (sockname.sa.sa_family == AF_INET) { if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) { @@ -1492,7 +1554,8 @@ TcpGetOptionProc( return Tcl_BadChannelOption(interp, optionName, "connecting peername sockname keepalive nagle"); #else - return Tcl_BadChannelOption(interp, optionName, "connecting peername sockname"); + return Tcl_BadChannelOption(interp, optionName, + "connecting peername sockname"); #endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ } @@ -1519,12 +1582,12 @@ TcpGetOptionProc( static void TcpWatchProc( - ClientData instanceData, /* The socket state. */ + void *instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; /* * Update the watch events mask. Only if the socket is not a server @@ -1533,11 +1596,11 @@ TcpWatchProc( if (!statePtr->acceptProc) { statePtr->watchEvents = 0; - if (mask & TCL_READABLE) { - statePtr->watchEvents |= (FD_READ|FD_CLOSE); + if (GOT_BITS(mask, TCL_READABLE)) { + SET_BITS(statePtr->watchEvents, FD_READ | FD_CLOSE); } - if (mask & TCL_WRITABLE) { - statePtr->watchEvents |= (FD_WRITE|FD_CLOSE); + if (GOT_BITS(mask, TCL_WRITABLE)) { + SET_BITS(statePtr->watchEvents, FD_WRITE | FD_CLOSE); } /* @@ -1573,11 +1636,11 @@ TcpWatchProc( static int TcpGetHandleProc( - ClientData instanceData, /* The socket state. */ + void *instanceData, /* The socket state. */ int direction, /* Not used. */ - ClientData *handlePtr) /* Where to store the handle. */ + void **handlePtr) /* Where to store the handle. */ { - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; *handlePtr = INT2PTR(statePtr->sockets->fd); return TCL_OK; @@ -1627,25 +1690,24 @@ TcpConnect( TcpState *statePtr) { DWORD error; - /* - * We are started with async connect and the connect notification - * was not jet received - */ - int async_connect = statePtr->flags & TCP_ASYNC_CONNECT; - /* We were called by the event procedure and continue our loop */ - int async_callback = statePtr->flags & TCP_ASYNC_PENDING; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + int async_connect = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT); + /* We are started with async connect and the + * connect notification was not yet + * received. */ + int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING); + /* We were called by the event procedure and + * continue our loop. */ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); 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) { - + statePtr->addr = statePtr->addr->ai_next) { + for (statePtr->myaddr = statePtr->myaddrlist; + statePtr->myaddr != NULL; + statePtr->myaddr = statePtr->myaddr->ai_next) { /* * No need to try combinations of local and remote addresses * of different families. @@ -1659,25 +1721,37 @@ TcpConnect( * Close the socket if it is still open from the last unsuccessful * iteration. */ + if (statePtr->sockets->fd != INVALID_SOCKET) { closesocket(statePtr->sockets->fd); } - /* get statePtr lock */ + /* + * Get statePtr lock. + */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); /* * Reset last error from last try */ + statePtr->notifierConnectError = 0; Tcl_SetErrno(0); - statePtr->sockets->fd = socket(statePtr->myaddr->ai_family, SOCK_STREAM, 0); + statePtr->sockets->fd = socket(statePtr->myaddr->ai_family, + SOCK_STREAM, 0); + + /* + * Free list lock. + */ - /* Free list lock */ SetEvent(tsdPtr->socketListLock); - /* continue on socket creation error */ + /* + * Continue on socket creation error. + */ + if (statePtr->sockets->fd == INVALID_SOCKET) { TclWinConvertError((DWORD) WSAGetLastError()); continue; @@ -1688,31 +1762,39 @@ TcpConnect( * processes by default. Turn off the inherit bit. */ - SetHandleInformation((HANDLE) statePtr->sockets->fd, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation((HANDLE) statePtr->sockets->fd, + HANDLE_FLAG_INHERIT, 0); /* * Set kernel space buffering */ - TclSockMinimumBuffers((void *) statePtr->sockets->fd, TCP_BUFFER_SIZE); + TclSockMinimumBuffers((void *) statePtr->sockets->fd, + TCP_BUFFER_SIZE); /* * Try to bind to a local port. */ if (bind(statePtr->sockets->fd, statePtr->myaddr->ai_addr, - statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) { + statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) { TclWinConvertError((DWORD) WSAGetLastError()); continue; } + /* * For asynchronous connect set the socket in nonblocking mode * and activate connect notification */ + if (async_connect) { TcpState *statePtr2; int in_socket_list = 0; - /* get statePtr lock */ + + /* + * Get statePtr lock. + */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); /* @@ -1722,8 +1804,8 @@ TcpConnect( * It is set after this call by TcpThreadActionProc and is set * on a second round. * - * If not, we buffer my statePtr in the tsd memory so it is not - * lost by the event procedure + * If not, we buffer my statePtr in the tsd memory so it is + * not lost by the event procedure */ for (statePtr2 = tsdPtr->socketList; statePtr2 != NULL; @@ -1736,21 +1818,27 @@ TcpConnect( if (!in_socket_list) { tsdPtr->pendingTcpState = statePtr; } + /* * Set connect mask to connect events - * This is activated by a SOCKET_SELECT message to the notifier - * thread. + * + * This is activated by a SOCKET_SELECT message to the + * notifier thread. */ - statePtr->selectEvents |= FD_CONNECT; + + SET_BITS(statePtr->selectEvents, FD_CONNECT); /* - * Free list lock + * Free list lock. */ + SetEvent(tsdPtr->socketListLock); - /* activate accept notification */ - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + /* + * Activate accept notification. + */ + + SendSelectMessage(tsdPtr, SELECT, statePtr); } /* @@ -1766,12 +1854,11 @@ TcpConnect( if (async_connect && error == WSAEWOULDBLOCK) { /* * Asynchroneous connect - */ - - /* + * * Remember that we jump back behind this next round */ - statePtr->flags |= TCP_ASYNC_PENDING; + + SET_BITS(statePtr->flags, TCP_ASYNC_PENDING); return TCL_OK; reenter: @@ -1781,14 +1868,31 @@ TcpConnect( * * Clear the reenter flag */ - statePtr->flags &= ~(TCP_ASYNC_PENDING); - /* get statePtr lock */ + + CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING); + + /* + * Get statePtr lock. + */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - /* Get signaled connect error */ + + /* + * Get signaled connect error. + */ + TclWinConvertError((DWORD) statePtr->notifierConnectError); - /* Clear eventual connect flag */ - statePtr->selectEvents &= ~(FD_CONNECT); - /* Free list lock */ + + /* + * Clear eventual connect flag. + */ + + CLEAR_BITS(statePtr->selectEvents, FD_CONNECT); + + /* + * Free list lock. + */ + SetEvent(tsdPtr->socketListLock); } @@ -1796,6 +1900,7 @@ TcpConnect( * Clear the tsd socket list pointer if we did not wait for * the FD_CONNECT asynchronously */ + tsdPtr->pendingTcpState = NULL; if (Tcl_GetErrno() == 0) { @@ -1804,7 +1909,7 @@ TcpConnect( } } -out: + out: /* * Socket connected or connection failed */ @@ -1815,13 +1920,13 @@ out: CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); - if ( Tcl_GetErrno() == 0 ) { + if (Tcl_GetErrno() == 0) { /* * Succesfully connected - */ - /* + * * Set up the select mask for read/write events. */ + statePtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; /* @@ -1829,35 +1934,56 @@ out: * automatically places the socket into non-blocking mode. */ - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); } else { /* * Connect failed - */ - - /* + * * For async connect schedule a writable event to report the fail. */ + if (async_callback) { /* * Set up the select mask for read/write events. */ + statePtr->selectEvents = FD_WRITE|FD_READ; - /* get statePtr lock */ + + /* + * Get statePtr lock. + */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - /* Signal ready readable and writable events */ - statePtr->readyEvents |= FD_WRITE | FD_READ; - /* Flag error to event routine */ - statePtr->flags |= TCP_ASYNC_FAILED; - /* Save connect error to be reported by 'fconfigure -error' */ + + /* + * Signal ready readable and writable events. + */ + + SET_BITS(statePtr->readyEvents, FD_WRITE | FD_READ); + + /* + * Flag error to event routine. + */ + + SET_BITS(statePtr->flags, TCP_ASYNC_FAILED); + + /* + * Save connect error to be reported by 'fconfigure -error'. + */ + statePtr->connectError = Tcl_GetErrno(); - /* Free list lock */ + + /* + * Free list lock. + */ + SetEvent(tsdPtr->socketListLock); } + /* * Error message on synchroneous connect */ + if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't open socket: %s", Tcl_PosixError(interp))); @@ -1935,7 +2061,7 @@ Tcl_OpenTcpClient( statePtr->addrlist = addrlist; statePtr->myaddrlist = myaddrlist; if (async) { - statePtr->flags |= TCP_ASYNC_CONNECT; + SET_BITS(statePtr->flags, TCP_ASYNC_CONNECT); } /* @@ -1980,7 +2106,7 @@ Tcl_OpenTcpClient( Tcl_Channel Tcl_MakeTcpClientChannel( - ClientData sock) /* The socket to wrap up into a channel. */ + void *sock) /* The socket to wrap up into a channel. */ { TcpState *statePtr; char channelName[SOCK_CHAN_LENGTH]; @@ -1990,7 +2116,7 @@ Tcl_MakeTcpClientChannel( return NULL; } - tsdPtr = TclThreadDataKeyGet(&dataKey); + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Set kernel space buffering and non-blocking. @@ -2005,7 +2131,7 @@ Tcl_MakeTcpClientChannel( */ statePtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); sprintf(channelName, SOCK_TEMPLATE, statePtr); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, @@ -2039,7 +2165,7 @@ Tcl_OpenTcpServer( Tcl_TcpAcceptProc *acceptProc, /* Callback for accepting connections from new * clients. */ - ClientData acceptProcData) /* Data for the callback. */ + void *acceptProcData) /* Data for the callback. */ { SOCKET sock = INVALID_SOCKET; unsigned short chosenport = 0; @@ -2068,7 +2194,8 @@ Tcl_OpenTcpServer( * Construct the addresses for each end of the socket. */ - if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { + if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, + &errorMsg)) { goto error; } @@ -2116,8 +2243,8 @@ Tcl_OpenTcpServer( * place to look for bugs. */ - if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) - == SOCKET_ERROR) { + if (bind(sock, addrPtr->ai_addr, + addrPtr->ai_addrlen) == SOCKET_ERROR) { TclWinConvertError((DWORD) WSAGetLastError()); closesocket(sock); continue; @@ -2152,19 +2279,20 @@ Tcl_OpenTcpServer( /* * Add this socket to the global list of sockets. */ + statePtr = NewSocketInfo(sock); } else { - AddSocketInfoFd( statePtr, sock ); + AddSocketInfoFd(statePtr, sock); } } -error: + error: if (addrlist != NULL) { freeaddrinfo(addrlist); } if (statePtr != NULL) { - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; @@ -2183,8 +2311,7 @@ error: */ ioctlsocket(sock, (long) FIONBIO, &flag); - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); if (Tcl_SetChannelOption(interp, statePtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close(NULL, statePtr->channel); @@ -2232,7 +2359,7 @@ TcpAccept( int len = sizeof(addr); char channelName[SOCK_CHAN_LENGTH]; char host[NI_MAXHOST], port[NI_MAXSERV]; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Win-NT has a misfeature that sockets are inherited in child processes @@ -2252,8 +2379,7 @@ TcpAccept( */ newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) newInfoPtr); + SendSelectMessage(tsdPtr, SELECT, newInfoPtr); sprintf(channelName, SOCK_TEMPLATE, newInfoPtr); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, @@ -2304,7 +2430,7 @@ static void InitSockets(void) { DWORD id; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (!initialized) { initialized = 1; @@ -2320,10 +2446,10 @@ InitSockets(void) windowClass.style = 0; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; - windowClass.hInstance = TclWinGetTclInstance(); + windowClass.hInstance = (HINSTANCE)TclWinGetTclInstance(); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; - windowClass.lpszClassName = classname; + windowClass.lpszClassName = className; windowClass.lpfnWndProc = SocketProc; windowClass.hIcon = NULL; windowClass.hCursor = NULL; @@ -2441,7 +2567,7 @@ SocketsEnabled(void) static void SocketExitHandler( - ClientData clientData) /* Not used. */ + void *clientData) /* Not used. */ { Tcl_MutexLock(&socketMutex); @@ -2451,7 +2577,7 @@ SocketExitHandler( */ TclpFinalizeSockets(); - UnregisterClassW(classname, TclWinGetTclInstance()); + UnregisterClassW(className, (HINSTANCE)TclWinGetTclInstance()); initialized = 0; Tcl_MutexUnlock(&socketMutex); } @@ -2475,14 +2601,14 @@ SocketExitHandler( void SocketSetupProc( - ClientData data, /* Not used. */ + void *data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { TcpState *statePtr; Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return; } @@ -2492,9 +2618,8 @@ SocketSetupProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (statePtr = tsdPtr->socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { - if (statePtr->readyEvents & - (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT) - ) { + if (GOT_BITS(statePtr->readyEvents, + statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) { Tcl_SetMaxBlockTime(&blockTime); break; } @@ -2521,14 +2646,14 @@ SocketSetupProc( static void SocketCheckProc( - ClientData data, /* Not used. */ + void *data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { TcpState *statePtr; SocketEvent *evPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return; } @@ -2541,12 +2666,11 @@ SocketCheckProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (statePtr = tsdPtr->socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { - if ((statePtr->readyEvents & - (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) - && !(statePtr->flags & SOCKET_PENDING) - ) { - statePtr->flags |= SOCKET_PENDING; - evPtr = ckalloc(sizeof(SocketEvent)); + if (GOT_BITS(statePtr->readyEvents, + statePtr->watchEvents | FD_CONNECT | FD_ACCEPT) + && !GOT_BITS(statePtr->flags, SOCKET_PENDING)) { + SET_BITS(statePtr->flags, SOCKET_PENDING); + evPtr = (SocketEvent *)ckalloc(sizeof(SocketEvent)); evPtr->header.proc = SocketEventProc; evPtr->socket = statePtr->sockets->fd; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); @@ -2591,7 +2715,7 @@ SocketEventProc( address addr; int len; - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return 0; } @@ -2620,29 +2744,26 @@ SocketEventProc( * Clear flag that (this) event is pending */ - statePtr->flags &= ~SOCKET_PENDING; + CLEAR_BITS(statePtr->flags, SOCKET_PENDING); /* * Continue async connect if pending and ready */ - if ( statePtr->readyEvents & FD_CONNECT ) { - if ( statePtr->flags & TCP_ASYNC_PENDING ) { - + if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * Do one step and save eventual connect error */ SetEvent(tsdPtr->socketListLock); WaitForConnect(statePtr,NULL); - } else { - /* * No async connect reenter pending. Just clear event. */ - statePtr->readyEvents &= ~(FD_CONNECT); + CLEAR_BITS(statePtr->readyEvents, FD_CONNECT); SetEvent(tsdPtr->socketListLock); } return 1; @@ -2651,20 +2772,23 @@ SocketEventProc( /* * Handle connection requests directly. */ - if (statePtr->readyEvents & FD_ACCEPT) { - for (fds = statePtr->sockets; fds != NULL; fds = fds->next) { + if (GOT_BITS(statePtr->readyEvents, FD_ACCEPT)) { + for (fds = statePtr->sockets; fds != NULL; fds = fds->next) { /* - * Accept the incoming connection request. - */ - len = sizeof(address); + * Accept the incoming connection request. + */ + len = sizeof(address); newSocket = accept(fds->fd, &(addr.sa), &len); - /* On Tcl server sockets with multiple OS fds we loop over the fds trying - * an accept() on each, so we expect INVALID_SOCKET. There are also other - * network stack conditions that can result in FD_ACCEPT but a subsequent - * failure on accept() by the time we get around to it. + /* + * On Tcl server sockets with multiple OS fds we loop over the fds + * trying an accept() on each, so we expect INVALID_SOCKET. There + * are also other network stack conditions that can result in + * FD_ACCEPT but a subsequent failure on accept() by the time we + * get around to it. + * * Access to sockets (acceptEventCount, readyEvents) in socketList * is still protected by the lock (prevents reintroduction of * SF Tcl Bug 3056775. @@ -2676,35 +2800,40 @@ SocketEventProc( } /* - * It is possible that more than one FD_ACCEPT has been sent, so an extra - * count must be kept. Decrement the count, and reset the readyEvent bit - * if the count is no longer > 0. + * It is possible that more than one FD_ACCEPT has been sent, so + * an extra count must be kept. Decrement the count, and reset the + * readyEvent bit if the count is no longer > 0. */ + statePtr->acceptEventCount--; if (statePtr->acceptEventCount <= 0) { - statePtr->readyEvents &= ~(FD_ACCEPT); + CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT); } SetEvent(tsdPtr->socketListLock); - /* Caution: TcpAccept() has the side-effect of evaluating the server - * accept script (via AcceptCallbackProc() in tclIOCmd.c), which can - * close the server socket and invalidate statePtr and fds. - * If TcpAccept() accepts a socket we must return immediately and let - * SocketCheckProc queue additional FD_ACCEPT events. + /* + * Caution: TcpAccept() has the side-effect of evaluating the + * server accept script (via AcceptCallbackProc() in tclIOCmd.c), + * which can close the server socket and invalidate statePtr and + * fds. If TcpAccept() accepts a socket we must return immediately + * and let SocketCheckProc queue additional FD_ACCEPT events. */ + TcpAccept(fds, newSocket, addr); return 1; } - /* Loop terminated with no sockets accepted; clear the ready mask so + /* + * Loop terminated with no sockets accepted; clear the ready mask so * we can detect the next connection request. Note that connection * requests are level triggered, so if there is a request already * pending, a new event will be generated. */ + statePtr->acceptEventCount = 0; - statePtr->readyEvents &= ~(FD_ACCEPT); + CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT); SetEvent(tsdPtr->socketListLock); return 1; @@ -2719,7 +2848,7 @@ SocketEventProc( events = statePtr->readyEvents & statePtr->watchEvents; - if (events & FD_CLOSE) { + if (GOT_BITS(events, FD_CLOSE)) { /* * If the socket was closed and the channel is still interested in * read events, then we need to ensure that we keep polling for this @@ -2733,17 +2862,14 @@ SocketEventProc( Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); - mask |= TCL_READABLE|TCL_WRITABLE; - } else if (events & FD_READ) { - + SET_BITS(mask, TCL_READABLE | TCL_WRITABLE); + } else if (GOT_BITS(events, FD_READ)) { /* * Throw the readable event if an async connect failed. */ - if ( statePtr->flags & TCP_ASYNC_FAILED ) { - - mask |= TCL_READABLE; - + if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { + SET_BITS(mask, TCL_READABLE); } else { fd_set readFds; struct timeval timeout; @@ -2756,8 +2882,7 @@ SocketEventProc( * async select handler and keep waiting. */ - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); FD_ZERO(&readFds); FD_SET(statePtr->sockets->fd, &readFds); @@ -2765,11 +2890,10 @@ SocketEventProc( timeout.tv_sec = 0; if (select(0, &readFds, NULL, NULL, &timeout) != 0) { - mask |= TCL_READABLE; + SET_BITS(mask, TCL_READABLE); } else { - statePtr->readyEvents &= ~(FD_READ); - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) SELECT, (LPARAM) statePtr); + CLEAR_BITS(statePtr->readyEvents, FD_READ); + SendSelectMessage(tsdPtr, SELECT, statePtr); } } } @@ -2778,8 +2902,8 @@ SocketEventProc( * writable event */ - if (events & FD_WRITE) { - mask |= TCL_WRITABLE; + if (GOT_BITS(events, FD_WRITE)) { + SET_BITS(mask, TCL_WRITABLE); } /* @@ -2816,21 +2940,30 @@ AddSocketInfoFd( { TcpFdList *fds = statePtr->sockets; - if ( fds == NULL ) { - /* Add the first FD */ - statePtr->sockets = ckalloc(sizeof(TcpFdList)); + if (fds == NULL) { + /* + * Add the first FD. + */ + + statePtr->sockets = (TcpFdList *)ckalloc(sizeof(TcpFdList)); fds = statePtr->sockets; } else { - /* Find end of list and append FD */ - while ( fds->next != NULL ) { + /* + * Find end of list and append FD. + */ + + while (fds->next != NULL) { fds = fds->next; } - fds->next = ckalloc(sizeof(TcpFdList)); + fds->next = (TcpFdList *)ckalloc(sizeof(TcpFdList)); fds = fds->next; } - /* Populate new FD */ + /* + * Populate new FD. + */ + fds->fd = socket; fds->statePtr = statePtr; fds->next = NULL; @@ -2856,7 +2989,7 @@ AddSocketInfoFd( static TcpState * NewSocketInfo(SOCKET socket) { - TcpState *statePtr = ckalloc(sizeof(TcpState)); + TcpState *statePtr = (TcpState *)ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); @@ -2899,7 +3032,8 @@ WaitForSocketEvent( { int result = 1; int oldMode; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + /* * Be sure to disable event servicing so we are truly modal. */ @@ -2910,29 +3044,42 @@ WaitForSocketEvent( * Reset WSAAsyncSelect so we have a fresh set of events pending. */ - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, - (LPARAM) statePtr); - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); while (1) { int event_found; - /* get statePtr lock */ + /* + * Get statePtr lock. + */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - /* Check if event occured */ - event_found = (statePtr->readyEvents & events); + /* + * Check if event occured. + */ + + event_found = GOT_BITS(statePtr->readyEvents, events); + + /* + * Free list lock. + */ - /* Free list lock */ SetEvent(tsdPtr->socketListLock); - /* exit loop if event occured */ + /* + * Exit loop if event occured. + */ + if (event_found) { break; } - /* Exit loop if event did not occur but this is a non-blocking channel */ + /* + * Exit loop if event did not occur but this is a non-blocking channel + */ + if (statePtr->flags & TCP_NONBLOCKING) { *errorCodePtr = EWOULDBLOCK; result = 0; @@ -2971,13 +3118,13 @@ SocketThread( LPVOID arg) { MSG msg; - ThreadSpecificData *tsdPtr = arg; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)arg; /* * Create a dummy window receiving socket events. */ - tsdPtr->hwnd = CreateWindowW(classname, classname, WS_TILED, 0, 0, 0, 0, + tsdPtr->hwnd = CreateWindowW(className, className, WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); /* @@ -3089,55 +3236,59 @@ SocketProc( for (statePtr = tsdPtr->socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { - if ( FindFDInList(statePtr,socket) ) { + if (FindFDInList(statePtr, socket)) { info_found = 1; break; } } + /* - * Check if there is a pending info structure not jet in the - * list + * Check if there is a pending info structure not jet in the list. */ - if ( !info_found + + if (!info_found && tsdPtr->pendingTcpState != NULL - && FindFDInList(tsdPtr->pendingTcpState,socket) ) { + && FindFDInList(tsdPtr->pendingTcpState, socket)) { statePtr = tsdPtr->pendingTcpState; info_found = 1; } if (info_found) { - /* * Update the socket state. * * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event - * happens, then clear the FD_ACCEPT count. Otherwise, - * increment the count if the current event is an FD_ACCEPT. + * happens, then clear the FD_ACCEPT count. Otherwise, increment + * the count if the current event is an FD_ACCEPT. */ - if (event & FD_CLOSE) { + if (GOT_BITS(event, FD_CLOSE)) { statePtr->acceptEventCount = 0; - statePtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); - } else if (event & FD_ACCEPT) { + CLEAR_BITS(statePtr->readyEvents, FD_WRITE | FD_ACCEPT); + } else if (GOT_BITS(event, FD_ACCEPT)) { statePtr->acceptEventCount++; } - if (event & FD_CONNECT) { + if (GOT_BITS(event, FD_CONNECT)) { /* * Remember any error that occurred so we can report * connection failures. */ + if (error != ERROR_SUCCESS) { statePtr->notifierConnectError = error; } } + /* * Inform main thread about signaled events */ - statePtr->readyEvents |= event; + + SET_BITS(statePtr->readyEvents, event); /* * Wake up the Main Thread. */ + SetEvent(tsdPtr->readyEvent); Tcl_ThreadAlert(tsdPtr->threadId); } @@ -3276,11 +3427,11 @@ TclWinGetServByName( static void TcpThreadActionProc( - ClientData instanceData, + void *instanceData, int action) { ThreadSpecificData *tsdPtr; - TcpState *statePtr = instanceData; + TcpState *statePtr = (TcpState *)instanceData; int notifyCmd; if (action == TCL_CHANNEL_THREAD_INSERT) { @@ -3346,8 +3497,7 @@ TcpThreadActionProc( * thread. */ - SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) notifyCmd, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, notifyCmd, statePtr); } /* -- cgit v0.12 From 607e3a5ba3c721c845b29c89db243882f25c5ba5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 8 Sep 2022 14:06:46 +0000 Subject: Combine flags and testFlags in TcpState. That should unbreak socket testcase failure --- generic/tclTest.c | 17 ++++++++++++++--- unix/tclUnixSock.c | 13 +++---------- win/tclWinSock.c | 15 ++++----------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/generic/tclTest.c b/generic/tclTest.c index d13b7ce..f6515c1 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -97,8 +97,7 @@ typedef struct TcpState TcpState; struct TcpState { Tcl_Channel channel; /* Channel associated with this socket. */ - int testFlags; /* bit field for tests. Is set by testsocket - * test procedure */ + int flags; /* ORed combination of various bitfields. */ }; TCL_DECLARE_MUTEX(asyncTestMutex) @@ -6442,6 +6441,10 @@ TestChannelEventCmd( *---------------------------------------------------------------------- */ +#define TCP_ASYNC_TEST_MODE (1<<8) /* Async testing activated. Do not + * automatically continue connection + * process. */ + static int TestSocketCmd( TCL_UNUSED(void *), @@ -6463,6 +6466,7 @@ TestSocketCmd( if ((cmdName[0] == 't') && (strncmp(cmdName, "testflags", len) == 0)) { Tcl_Channel hChannel; int modePtr; + int testMode; TcpState *statePtr; /* Set test value in the socket driver */ @@ -6484,7 +6488,14 @@ TestSocketCmd( NULL); return TCL_ERROR; } - statePtr->testFlags = atoi(argv[3]); + if (Tcl_GetBoolean(interp, argv[3], &testMode) != TCL_OK) { + return TCL_ERROR; + } + if (testMode) { + statePtr->flags |= TCP_ASYNC_TEST_MODE; + } else { + statePtr->flags &= ~TCP_ASYNC_TEST_MODE; + } return TCL_OK; } diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index 1c07e8d..217d5ce 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -53,9 +53,9 @@ typedef struct TcpFdList { struct TcpState { Tcl_Channel channel; /* Channel associated with this file. */ - TcpFdList fds; /* The file descriptors of the sockets. */ int flags; /* ORed combination of the bitfields defined * below. */ + TcpFdList fds; /* The file descriptors of the sockets. */ int interest; /* Event types of interest */ /* @@ -78,8 +78,6 @@ struct TcpState { * an async socket is not yet connected. */ int connectError; /* Cache SO_ERROR of async socket. */ int cachedBlocking; /* Cache blocking mode of async socket. */ - int testFlags; /* bit field for tests. Is set by testsocket - * test procedure */ }; /* @@ -95,12 +93,7 @@ struct TcpState { * still pending */ #define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */ -/* - * These bits may be ORed together into the "testFlags" field of a TcpState - * structure. - */ - -#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not +#define TCP_ASYNC_TEST_MODE (1<<8) /* Async testing activated. Do not * automatically continue connection * process. */ @@ -471,7 +464,7 @@ WaitForConnect( * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING)) */ - if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE) + if (GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE) && !(errorCodePtr != NULL && !GOT_BITS(statePtr->flags, TCP_NONBLOCKING))) { *errorCodePtr = EWOULDBLOCK; diff --git a/win/tclWinSock.c b/win/tclWinSock.c index f85e444..f1a6a5e 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -125,9 +125,9 @@ typedef struct TcpFdList { struct TcpState { Tcl_Channel channel; /* Channel associated with this socket. */ - struct TcpFdList *sockets; /* Windows SOCKET handle. */ int flags; /* Bit field comprised of the flags described * below. */ + struct TcpFdList *sockets; /* Windows SOCKET handle. */ int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events are interesting. */ @@ -165,8 +165,6 @@ struct TcpState { * Access must be protected by semaphore */ struct TcpState *nextPtr; /* The next socket on the per-thread socket * list. */ - int testFlags; /* bit field for tests. Is set by testsocket - * test procedure */ }; /* @@ -186,12 +184,7 @@ struct TcpState { * still pending */ #define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */ -/* - * These bits may be ORed together into the "testFlags" field of a TcpState - * structure. - */ - -#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not +#define TCP_ASYNC_TEST_MODE (1<<8) /* Async testing activated. Do not * automatically continue connection * process */ @@ -630,7 +623,7 @@ WaitForConnect( * - Call by the event queue (errorCodePtr == NULL) */ - if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE) + if (GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE) && errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { *errorCodePtr = EWOULDBLOCK; @@ -1323,7 +1316,7 @@ TcpGetOptionProc( * below. */ - if (!GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)) { + if (!GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE)) { WaitForConnect(statePtr, NULL); } -- cgit v0.12 From 04fca9a30cb9aef5ab11d633a18fcba33db0a036 Mon Sep 17 00:00:00 2001 From: kjnash Date: Thu, 8 Sep 2022 14:49:33 +0000 Subject: Bugfixes - treat a disappearing socket as eof; do not open a (second) socket for a request that is already queued; cancel idletasks when no longer needed. This commit passes all tests. --- library/http/http.tcl | 86 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 01d3f8b..38e07cc 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -291,6 +291,11 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { if {[info commands ${token}--SocketCoroutine] ne {}} { rename ${token}--SocketCoroutine {} } + if {[info exists state(socketcoro)]} { + Log $token Cancel socket after-idle event (Finish) + after cancel $state(socketcoro) + unset state(socketcoro) + } # Is this an upgrade request/response? set upgradeResponse \ @@ -691,6 +696,7 @@ proc http::CloseQueuedQueries {connId {token {}}} { # - Also clear the queues to prevent calls to Finish that would set the # state for the requests that will be retried to "finished with error # status". + # - At this stage socketPhQueue is empty. set unfinished $socketPlayCmd($connId) set socketRdQueue($connId) {} set socketWrQueue($connId) {} @@ -704,6 +710,7 @@ proc http::CloseQueuedQueries {connId {token {}}} { Log ^R$tk Any unfinished transactions (excluding $token) failed \ - token $token - unfinished $unfinished {*}$unfinished + # Calls ReplayIfClose. } return } @@ -1394,7 +1401,8 @@ proc http::AsyncTransaction {token} { } if {$state(ReusingPlaceholder)} { - # - This request is scheduled to re-use a persistent connection; + # - This request was added to the socketPhQueue of a persistent + # connection. # - But the connection has not yet been created and is a placeholder; # - And the placeholder was created by an earlier request. # - When that earlier request calls OpenSocket, its placeholder is @@ -1402,13 +1410,18 @@ proc http::AsyncTransaction {token} { # OpenSocket for any subsequent requests that have # $state(ReusingPlaceholder). Log >J$tk after idle coro NO - ReusingPlaceholder + } elseif {$state(alreadyQueued)} { + # - This request was added to the socketWrQueue and socketPlayCmd + # of a persistent connection that will close at the end of its current + # read operation. + Log >J$tk after idle coro NO - alreadyQueued } else { Log >J$tk after idle coro YES - # Called if (not reusing) || (socket is not a placeholder). set CoroName ${token}--SocketCoroutine set cancel [after idle [list coroutine $CoroName ::http::OpenSocket \ $token $DoLater]] dict set socketCoEvent($state(socketinfo)) $token $cancel + set state(socketcoro) $cancel } return @@ -1523,6 +1536,7 @@ proc http::OpenSocket {token DoLater} { set sockOld $state(sock) dict unset socketCoEvent($state(socketinfo)) $token + unset -nocomplain state(socketcoro) set reusing $state(reusing) @@ -1626,10 +1640,9 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { variable socketPlayCmd variable socketCoEvent - ##Log " ConfigureNewSocket" $token $sockOld $sock ... - set reusing $state(reusing) set sock $state(sock) + ##Log " ConfigureNewSocket" $token $sockOld ... -- $sock if {(!$reusing) && ($sock ne $sockOld)} { # Replace the placeholder value sockOld with sock. @@ -1672,6 +1685,7 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { && ($sock ne $sockOld) && [info exists socketPhQueue($sockOld)] } { + ##Log " ConfigureNewSocket" $token scheduled, now do $socketPhQueue($sockOld) foreach tok $socketPhQueue($sockOld) { # 1. Amend the token's (sock). ##Log set ${tok}(sock) $sock @@ -1685,6 +1699,7 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { } set socketPhQueue($sockOld) {} } + ##Log " ConfigureNewSocket" $token DONE return } @@ -2704,6 +2719,11 @@ proc http::ReInit {token} { after cancel $state(after) unset state(after) } + if {[info exists state(socketcoro)]} { + Log $token Cancel socket after-idle event (ReInit) + after cancel $state(socketcoro) + unset state(socketcoro) + } # Don't alter state(status) - this would trigger http::wait if it is in use. set tmpState $state(tmpState) @@ -2886,6 +2906,11 @@ proc http::cleanup {token} { after cancel $state(after) unset state(after) } + if {[info exists state(socketcoro)]} { + Log $token Cancel socket after-idle event (cleanup) + after cancel $state(socketcoro) + unset state(socketcoro) + } if {[info exists state]} { unset state } @@ -2907,11 +2932,20 @@ proc http::Connect {token proto phost srvurl} { variable $token upvar 0 $token state set tk [namespace tail $token] - set err "due to unexpected EOF" - if { - [eof $state(sock)] || - [set err [fconfigure $state(sock) -error]] ne "" - } { + + if {[catch {eof $state(sock)} tmp] || $tmp} { + set err "due to unexpected EOF" + } elseif {[set err [fconfigure $state(sock) -error]] ne ""} { + # set err is done in test + } else { + # All OK + set state(state) connecting + fileevent $state(sock) writable {} + ::http::Connected $token $proto $phost $srvurl + return + } + + # Error cases. Log "WARNING - if testing, pay special attention to this\ case (GJ) which is seldom executed - token $token" if {[info exists state(reusing)] && $state(reusing)} { @@ -2928,11 +2962,6 @@ proc http::Connect {token proto phost srvurl} { # be discarded. } Finish $token "connect failed $err" - } else { - set state(state) connecting - fileevent $state(sock) writable {} - ::http::Connected $token $proto $phost $srvurl - } return } @@ -3077,7 +3106,7 @@ proc http::Event {sock token} { if {![info exists state]} { Log "Event $sock with invalid token '$token' - remote close?" - if {![eof $sock]} { + if {!([catch {eof $sock} tmp] || $tmp)} { if {[set d [read $sock]] ne ""} { Log "WARNING: additional data left on closed socket\ - token $token" @@ -3122,7 +3151,7 @@ proc http::Event {sock token} { } elseif {$nsl >= 0} { ##Log - connecting 1 - token $token set state(state) "header" - } elseif { [eof $sock] + } elseif { ([catch {eof $sock} tmp] || $tmp) && [info exists state(reusing)] && $state(reusing) } { @@ -3190,13 +3219,16 @@ proc http::Event {sock token} { # response. ##Log WARNING - socket will close after response for $token # Prepare data for a call to ReplayIfClose. - + Log $token socket will close after this transaction # 1. Cancel socket-assignment coro events that have not yet # launched, and add the tokens to the write queue. if {[info exists socketCoEvent($state(socketinfo))]} { foreach {tok can} $socketCoEvent($state(socketinfo)) { lappend socketWrQueue($state(socketinfo)) $tok + unset -nocomplain ${tok}(socketcoro) after cancel $can + Log $tok Cancel socket after-idle event (Event) + Log Move $tok from socketCoEvent to socketWrQueue and cancel its after idle coro } set socketCoEvent($state(socketinfo)) {} } @@ -3228,8 +3260,9 @@ proc http::Event {sock token} { after cancel [set ${tokenVal}(after)] unset ${tokenVal}(after) } + # Tokens in the read queue have no (socketcoro) to + # cancel. } - } else { set socketPlayCmd($state(socketinfo)) \ {ReplayIfClose Wready {} {}} @@ -3540,7 +3573,8 @@ proc http::Event {sock token} { # catch as an Eot above may have closed the socket already # $state(state) may be connecting, header, body, or complete - if {![set cc [catch {eof $sock} eof]] && $eof} { + if {(![catch {eof $sock} eof]) && $eof} { + # [eof sock] succeeded and the result was 1 ##Log eof - token $token if {[info exists $token]} { set state(connection) close @@ -3562,8 +3596,9 @@ proc http::Event {sock token} { Log ^X$tk end of response (token error) - token $token CloseSocket $sock } - } elseif {$cc} { - return + } else { + # EITHER [eof sock] failed - presumed done by Eot + # OR [eof sock] succeeded and the result was 0 } } return @@ -3736,7 +3771,8 @@ proc http::ParseCookie {token value} { # http::getTextLine -- # # Get one line with the stream in crlf mode. -# Used if Transfer-Encoding is chunked. +# Used if Transfer-Encoding is chunked, to read the line that +# reports the size of the following chunk. # Empty line is not distinguished from eof. The caller must # be able to handle this. # @@ -3759,6 +3795,8 @@ proc http::getTextLine {sock} { # # Replacement for a blocking read. # The caller must be a coroutine. +# Used when we expect to read a chunked-encoding +# chunk of known size. proc http::BlockingRead {sock size} { if {$size < 1} { @@ -3768,7 +3806,7 @@ proc http::BlockingRead {sock size} { while 1 { set need [expr {$size - [string length $result]}] set block [read $sock $need] - set eof [eof $sock] + set eof [expr {[catch {eof $sock} tmp] || $tmp}] append result $block if {[string length $result] >= $size || $eof} { return $result @@ -3788,7 +3826,7 @@ proc http::BlockingRead {sock size} { proc http::BlockingGets {sock} { while 1 { set count [gets $sock line] - set eof [eof $sock] + set eof [expr {[catch {eof $sock} tmp] || $tmp}] if {$count >= 0 || $eof} { return $line } else { -- cgit v0.12 From 05c97af25931eb72c7feb658c8b1d50d5056361a Mon Sep 17 00:00:00 2001 From: kjnash Date: Thu, 8 Sep 2022 17:51:56 +0000 Subject: Add command http::reason to return the recommended reason phrase for a HTTP server status code (bug [1214322]). --- doc/http.n | 49 ++++++++++++++++++++++++--- library/http/http.tcl | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 4 deletions(-) diff --git a/doc/http.n b/doc/http.n index 2c9f809..f0018e3 100644 --- a/doc/http.n +++ b/doc/http.n @@ -36,6 +36,8 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::ncode \fItoken\fR .sp +\fB::http::reason \fIcode\fR +.sp \fB::http::meta \fItoken\fR .sp \fB::http::data \fItoken\fR @@ -492,13 +494,52 @@ the state array. .TP \fB::http::code\fR \fItoken\fR . -This is a convenience procedure that returns the \fBhttp\fR element of the -state array. +This command returns the "status line" of the server response (which is stored +as element \fBhttp\fR of the state array). +The "status line" is the first line of a HTTP server response, and has three +elements separated by spaces: the HTTP version, a three-digit numerical +"status code", and a "reason phrase". Only the reason phrase may contain +spaces. Examples: +.PP +.DS +.RS +HTTP/1.1 200 OK +HTTP/1.0 404 Not Found +.RE +.DE +.PP +.RS +The "reason phrase" for a given status code may vary from server to server, +and can be changed without affecting the HTTP protocol. The recommended +values (RFC 7231 and IANA assignments) for each code are provided by the +command \fB::http::reason\fR. +.RE .TP \fB::http::ncode\fR \fItoken\fR . -This is a convenience procedure that returns just the numeric return -code (200, 404, etc.) from the \fBhttp\fR element of the state array. +This command returns the "status code" (200, 404, etc.) of the server response. +The full status line can be obtained with command \fB::http::code\fR. +.TP +\fB::http::reason\fR \fIcode\fR +. +This command returns the IANA recommended "reason phrase" for a particular +"status code" returned by a HTTP server. The argument \fIcode\fR is a valid +status code, and therefore is an integer in the range 100 to 599 inclusive. +For numbers in this range with no assigned meaning, the command returns the +value "Unassigned". Several status codes are used only in response to the +methods defined by HTTP extensions such as WebDAV, and not in response to a +HEAD, GET, or POST request method. +.PP +.RS +The "reason phrase" returned by a HTTP server may differ from the recommended +value, without affecting the HTTP protocol. The value returned by +\fB::http::geturl\fR can be obtained by calling either command +\fB::http::code\fR (which returns the full status line) or command +\fB::http::ncode\fR (for the status code only). +.PP +A registry of valid status codes is maintained at +https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml +.RE .TP \fB::http::size\fR \fItoken\fR . diff --git a/library/http/http.tcl b/library/http/http.tcl index 38e07cc..fe4d302 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -151,6 +151,72 @@ namespace eval http { variable TmpSockCounter 0 variable ThreadCounter 0 + variable reasonDict [dict create {*}{ + 100 Continue + 101 {Switching Protocols} + 102 Processing + 103 {Early Hints} + 200 OK + 201 Created + 202 Accepted + 203 {Non-Authoritative Information} + 204 {No Content} + 205 {Reset Content} + 206 {Partial Content} + 207 Multi-Status + 208 {Already Reported} + 226 {IM Used} + 300 {Multiple Choices} + 301 {Moved Permanently} + 302 Found + 303 {See Other} + 304 {Not Modified} + 305 {Use Proxy} + 306 (Unused) + 307 {Temporary Redirect} + 308 {Permanent Redirect} + 400 {Bad Request} + 401 Unauthorized + 402 {Payment Required} + 403 Forbidden + 404 {Not Found} + 405 {Method Not Allowed} + 406 {Not Acceptable} + 407 {Proxy Authentication Required} + 408 {Request Timeout} + 409 Conflict + 410 Gone + 411 {Length Required} + 412 {Precondition Failed} + 413 {Content Too Large} + 414 {URI Too Long} + 415 {Unsupported Media Type} + 416 {Range Not Satisfiable} + 417 {Expectation Failed} + 418 (Unused) + 421 {Misdirected Request} + 422 {Unprocessable Content} + 423 Locked + 424 {Failed Dependency} + 425 {Too Early} + 426 {Upgrade Required} + 428 {Precondition Required} + 429 {Too Many Requests} + 431 {Request Header Fields Too Large} + 451 {Unavailable For Legal Reasons} + 500 {Internal Server Error} + 501 {Not Implemented} + 502 {Bad Gateway} + 503 {Service Unavailable} + 504 {Gateway Timeout} + 505 {HTTP Version Not Supported} + 506 {Variant Also Negotiates} + 507 {Insufficient Storage} + 508 {Loop Detected} + 510 {Not Extended (OBSOLETED)} + 511 {Network Authentication Required} + }] + namespace export geturl config reset wait formatQuery quoteString namespace export register unregister registerError # - Useful, but not exported: data, size, status, code, cleanup, error, @@ -251,6 +317,33 @@ proc http::config {args} { } } +# ------------------------------------------------------------------------------ +# Proc http::reason +# ------------------------------------------------------------------------------ +# Command to return the IANA-recommended "reason phrase" for a HTTP Status Code. +# Information obtained from: +# https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml +# +# Arguments: +# code - A valid HTTP Status Code (integer from 100 to 599) +# +# Return Value: the reason phrase +# ------------------------------------------------------------------------------ + +proc http::reason {code} { + variable reasonDict + if {![regexp -- {^[1-5][0-9][0-9]$} $code]} { + set msg {argument must be a three-digit integer from 100 to 599} + return -code error $msg + } + if {[dict exists $reasonDict $code]} { + set reason [dict get $reasonDict $code] + } else { + set reason Unassigned + } + return $reason +} + # http::Finish -- # # Clean up the socket and eval close time callbacks -- cgit v0.12 From 1a8f9e37f48db662f43a0d1169c729f2c6ce3eb9 Mon Sep 17 00:00:00 2001 From: kjnash Date: Thu, 8 Sep 2022 21:16:57 +0000 Subject: Fix bug [2841176]. Evaluate all callbacks (and urlTypes commands) in global namespace. --- library/http/http.tcl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index fe4d302..67f0309 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -461,7 +461,7 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { if {[info exists state(-command)] && (!$skipCB) && (![info exists state(done-command-cb)])} { set state(done-command-cb) yes - if {[catch {eval $state(-command) {$token}} err] && $errormsg eq ""} { + if {[catch {namespace eval :: $state(-command) $token} err] && $errormsg eq ""} { set state(error) [list $err $errorInfo $errorCode] set state(status) error } @@ -1642,7 +1642,7 @@ proc http::OpenSocket {token DoLater} { set pre [clock milliseconds] ##Log pre socket opened, - token $token ##Log $state(openCmd) - token $token - if {[catch {eval $state(openCmd)} sock errdict]} { + if {[catch {namespace eval :: $state(openCmd)} sock errdict]} { # ERROR CASE # Something went wrong while trying to establish the connection. # Tidy up after events and such, but DON'T call the command @@ -3159,7 +3159,7 @@ proc http::Write {token} { # Callback to the client after we've completely handled everything. if {[string length $state(-queryprogress)]} { - eval $state(-queryprogress) \ + namespace eval :: $state(-queryprogress) \ [list $token $state(querylength) $state(queryoffset)] } return @@ -3493,7 +3493,7 @@ proc http::Event {sock token} { ##Log body - token $token if {[catch { if {[info exists state(-handler)]} { - set n [eval $state(-handler) [list $sock $token]] + set n [namespace eval :: $state(-handler) [list $sock $token]] ##Log handler $n - token $token # N.B. the protocol has been set to 1.0 because the -handler # logic is not expected to handle chunked encoding. @@ -3658,7 +3658,7 @@ proc http::Event {sock token} { return } else { if {[info exists state(-progress)]} { - eval $state(-progress) \ + namespace eval :: $state(-progress) \ [list $token $state(totalsize) $state(currentsize)] } } @@ -3977,7 +3977,7 @@ proc http::CopyChunk {token chunk} { } puts -nonewline $state(-channel) $chunk if {[info exists state(-progress)]} { - eval [linsert $state(-progress) end \ + namespace eval :: [linsert $state(-progress) end \ $token $state(totalsize) $state(currentsize)] } } else { @@ -4013,7 +4013,7 @@ proc http::CopyDone {token count {error {}}} { set sock $state(sock) incr state(currentsize) $count if {[info exists state(-progress)]} { - eval $state(-progress) \ + namespace eval :: $state(-progress) \ [list $token $state(totalsize) $state(currentsize)] } # At this point the token may have been reset. -- cgit v0.12 From d28f51fb1ea027faf72a3dd2ad64d76209d57e89 Mon Sep 17 00:00:00 2001 From: kjnash Date: Fri, 9 Sep 2022 08:04:55 +0000 Subject: Fix bug [2927221] - revised http::meta, new http::metaValue, header names are case-insensitive so convert to lower case. --- doc/http.n | 71 ++++++++++++++++++++++++++++++++++----------------- library/http/http.tcl | 41 ++++++++++++++++++++++++++--- tests/http.test | 8 +++--- tests/http11.test | 22 ++++++++-------- 4 files changed, 99 insertions(+), 43 deletions(-) diff --git a/doc/http.n b/doc/http.n index f0018e3..135774d 100644 --- a/doc/http.n +++ b/doc/http.n @@ -38,7 +38,9 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::reason \fIcode\fR .sp -\fB::http::meta \fItoken\fR +\fB::http::meta \fItoken\fR ?\fIheaderName\fR? +.sp +\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR .sp \fB::http::data \fItoken\fR .sp @@ -58,7 +60,8 @@ Namespace \fBhttp\fR exports the commands \fBconfig\fR, \fBformatQuery\fR, \fBreset\fR, \fBunregister\fR, and \fBwait\fR. .PP It does not export the commands \fBcleanup\fR, \fBcode\fR, \fBdata\fR, -\fBerror\fR, \fBmeta\fR, \fBncode\fR, \fBsize\fR, or \fBstatus\fR. +\fBerror\fR, \fBmeta\fR, \fBmetaValue\fR, \fBncode\fR, \fBreason\fR, +\fBsize\fR, or \fBstatus\fR. .BE .SH DESCRIPTION .PP @@ -357,7 +360,7 @@ multiple interfaces are available. The \fIcallback\fR is made after each transfer of data from the URL. The callback gets three additional arguments: the \fItoken\fR from \fB::http::geturl\fR, the expected total size of the contents from the -\fBContent-Length\fR meta-data, and the current number of bytes +\fBContent-Length\fR metadata, and the current number of bytes transferred so far. The expected total size may be unknown, in which case zero is passed to the callback. Here is a template for the progress callback: @@ -547,11 +550,31 @@ This is a convenience procedure that returns the \fBcurrentsize\fR element of the state array, which represents the number of bytes received from the URL in the \fB::http::geturl\fR call. .TP -\fB::http::meta\fR \fItoken\fR -. -This is a convenience procedure that returns the \fBmeta\fR -element of the state array which contains the HTTP response -headers. See below for an explanation of this element. +\fB::http::meta\fR \fItoken\fR ?\fIheaderName\fR? +. +This command returns a list of HTTP response header names and values, in the +order that they were received from the server: a Tcl list of the form +?name value ...? Header names are case-insensitive and are converted to lower +case. The return value is not a \fBdict\fR because some header names may occur +more than once, notably \fIset-cookie\fR. If one argument is supplied, all +response headers are returned: the value is that of the \fBmeta\fR element +of the state array (described below). If two arguments are supplied, the +second provides the value of a header name. Only headers with the requested +name (converted to lower case) are returned. If no such headers are found, +an empty list is returned. +.TP +\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR +. +This command returns the value of the HTTP response header named +\fIheaderName\fR. Header names are case-insensitive and are converted to +lower case. If no such header exists, the return value is the empty string. +If there are multiple headers named \fIheaderName\fR, the result is obtained +by joining the individual values with the string ", " (comma and space), +preserving their order. Multiple headers with the same name may be processed +in this manner, except \fIset-cookie\fR which does not conform to the +comma-separated-list syntax and cannot be combined into a single value. +Each \fIset-cookie\fR header must be treated individually, e.g. by processing +the return value of \fB::http::meta\fR \fIset-cookie\fR. .TP \fB::http::cleanup\fR \fItoken\fR . @@ -713,14 +736,14 @@ command. .TP \fBcharset\fR . -The value of the charset attribute from the \fBContent-Type\fR meta-data +The value of the charset attribute from the \fBContent-Type\fR metadata value. If none was specified, this defaults to the RFC standard \fBiso8859-1\fR, or the value of \fB$::http::defaultCharset\fR. Incoming text data will be automatically converted from this charset to utf-8. .TP \fBcoding\fR . -A copy of the \fBContent-Encoding\fR meta-data value. +A copy of the \fBContent-Encoding\fR metadata value. .TP \fBcurrentsize\fR . @@ -745,23 +768,23 @@ is returned by the \fB::http::code\fR command. The format of this value is: The \fIcode\fR is a three-digit number defined in the HTTP standard. A code of 200 is OK. Codes beginning with 4 or 5 indicate errors. Codes beginning with 3 are redirection errors. In this case the -\fBLocation\fR meta-data specifies a new URL that contains the +\fBLocation\fR metadata specifies a new URL that contains the requested information. .RE .TP \fBmeta\fR . -The HTTP protocol returns meta-data that describes the URL contents. -The \fBmeta\fR element of the state array is a list of the keys and -values of the meta-data. This is in a format useful for initializing -an array that just contains the meta-data: -.RS +The response from a HTTP server includes metadata headers that describe the +response body and the message from the server. The \fBmeta\fR element of the +state array is a list of the keys (header names) and values (header values) of +the metadata. Header names are case-insensitive and are converted to lower +case. The value of meta is not a \fBdict\fR because some header names may +occur more than once, notably "set-cookie". If the value \fBmeta\fR is read +into a dict or into an array (using array set), only the last header with each +name will be preserved. .PP -.CS -array set meta $state(meta) -.CE -.PP -Some of the meta-data keys are listed below, but the HTTP standard defines +.RS +Some of the metadata keys are listed below, but the HTTP standard defines more, and servers are free to add their own. .TP \fBContent-Type\fR @@ -793,11 +816,11 @@ During the transaction this value is the empty string. .TP \fBtotalsize\fR . -A copy of the \fBContent-Length\fR meta-data value. +A copy of the \fBContent-Length\fR metadata value. .TP \fBtype\fR . -A copy of the \fBContent-Type\fR meta-data value. +A copy of the \fBContent-Type\fR metadata value. .TP \fBurl\fR . @@ -1057,7 +1080,7 @@ The peer thread can transfer the socket only to the main interpreter of the scri .SH EXAMPLE .PP This example creates a procedure to copy a URL to a file while printing a -progress meter, and prints the meta-data associated with the URL. +progress meter, and prints the metadata associated with the URL. .PP .CS proc httpcopy { url file {chunk 4096} } { diff --git a/library/http/http.tcl b/library/http/http.tcl index 67f0309..ba8e1ab 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -2962,11 +2962,45 @@ proc http::size {token} { upvar 0 $token state return $state(currentsize) } -proc http::meta {token} { +proc http::meta {token args} { + set lenny [llength $args] + if {$lenny > 1} { + return -code error {usage: ::http::meta token ?headerName?} + } else { + return [Meta $token {*}$args] + } +} +proc http::metaValue {token header} { + Meta $token $header VALUE +} +proc http::Meta {token args} { variable $token upvar 0 $token state - return $state(meta) + + set header [string tolower [lindex $args 0]] + set how [string tolower [lindex $args 1]] + set lenny [llength $args] + if {$lenny == 0} { + return $state(meta) + } elseif {($lenny > 2) || (($lenny == 2) && ($how ne {value}))} { + return -code error {usage: ::http::Meta token ?headerName ?VALUE??} + } else { + set result {} + set combined {} + foreach {key value} $state(meta) { + if {$key eq $header} { + lappend result $key $value + append combined $value {, } + } + } + if {$lenny == 1} { + return $result + } else { + return [string range $combined 0 end-2] + } + } } + proc http::error {token} { variable $token upvar 0 $token state @@ -3445,7 +3479,8 @@ proc http::Event {sock token} { # Process header lines. ##Log header - token $token - $line if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} { - switch -- [string tolower $key] { + set key [string tolower $key] + switch -- $key { content-type { set state(type) [string trim [string tolower $value]] # Grab the optional charset information. diff --git a/tests/http.test b/tests/http.test index 26ba710..08f6311 100644 --- a/tests/http.test +++ b/tests/http.test @@ -390,7 +390,7 @@ test http-3.25 {http::meta} -setup { } -cleanup { http::cleanup $token unset -nocomplain m token -} -result {Content-Length Content-Type Date} +} -result {content-length content-type date} test http-3.26 {http::meta} -setup { unset -nocomplain m token } -body { @@ -400,7 +400,7 @@ test http-3.26 {http::meta} -setup { } -cleanup { http::cleanup $token unset -nocomplain m token -} -result {Content-Length Content-Type Date X-Check} +} -result {content-length content-type date x-check} test http-3.27 {http::geturl: -headers override -type} -body { set token [http::geturl $url/headers -type "text/plain" -query dummy \ -headers [list "Content-Type" "text/plain;charset=utf-8"]] @@ -485,7 +485,7 @@ test http-4.1 {http::Event} -body { set token [http::geturl $url -keepalive 0] upvar #0 $token data array set meta $data(meta) - expr {($data(totalsize) == $meta(Content-Length))} + expr {($data(totalsize) == $meta(content-length))} } -cleanup { http::cleanup $token } -result 1 @@ -493,7 +493,7 @@ test http-4.2 {http::Event} -body { set token [http::geturl $url] upvar #0 $token data array set meta $data(meta) - string compare $data(type) [string trim $meta(Content-Type)] + string compare $data(type) [string trim $meta(content-type)] } -cleanup { http::cleanup $token } -result 0 diff --git a/tests/http11.test b/tests/http11.test index 346e334..912e069 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -51,15 +51,11 @@ proc halt_httpd {} { } proc meta {tok {key ""}} { - set meta [http::meta $tok] - if {$key ne ""} { - if {[dict exists $meta $key]} { - return [dict get $meta $key] - } else { - return "" - } + if {$key eq ""} { + return [http::meta $tok] + } else { + return [http::metaValue $tok $key] } - return $meta } proc state {tok {key ""}} { @@ -128,11 +124,12 @@ test http11-1.1 "normal,gzip,non-chunked" -setup { -timeout 10000 -headers {accept-encoding gzip}] http::wait $tok list [http::status $tok] [http::code $tok] [check_crc $tok] \ - [meta $tok content-encoding] [meta $tok transfer-encoding] + [meta $tok content-encoding] [meta $tok transfer-encoding] \ + [http::meta $tok content-encoding] [http::meta $tok transfer-encoding] } -cleanup { http::cleanup $tok halt_httpd -} -result {ok {HTTP/1.1 200 OK} ok gzip {}} +} -result {ok {HTTP/1.1 200 OK} ok gzip {} {content-encoding gzip} {}} test http11-1.2 "normal,deflated,non-chunked" -setup { variable httpd [create_httpd] @@ -193,11 +190,12 @@ test http11-1.6 "normal, specify 1.1 " -setup { -protocol 1.1 -timeout 10000] http::wait $tok list [http::status $tok] [http::code $tok] [check_crc $tok] \ - [meta $tok connection] [meta $tok transfer-encoding] + [meta $tok connection] [meta $tok transfer-encoding] \ + [http::meta $tok connection] [http::meta $tok transfer-encoding] } -cleanup { http::cleanup $tok halt_httpd -} -result {ok {HTTP/1.1 200 OK} ok close chunked} +} -result {ok {HTTP/1.1 200 OK} ok close chunked {connection close} {transfer-encoding chunked}} test http11-1.7 "normal, 1.1 and keepalive " -setup { variable httpd [create_httpd] -- cgit v0.12 From 34d4a98d7cf24421a7b65fbff7ff06a7d535579c Mon Sep 17 00:00:00 2001 From: kjnash Date: Fri, 9 Sep 2022 08:28:16 +0000 Subject: Add missing "else" clauses to "if" commands in http::Event. --- library/http/http.tcl | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index ba8e1ab..be991fc 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -3237,11 +3237,14 @@ proc http::Event {sock token} { if {[set d [read $sock]] ne ""} { Log "WARNING: additional data left on closed socket\ - token $token" + } else { } + } else { } Log ^X$tk end of response (token error) - token $token CloseSocket $sock return + } else { } if {$state(state) eq "connecting"} { ##Log - connecting - token $token @@ -3252,6 +3255,7 @@ proc http::Event {sock token} { } { set state(after) [after $state(-timeout) \ [list http::reset $token timeout]] + } else { } if {[catch {gets $sock state(http)} nsl]} { @@ -3263,8 +3267,8 @@ proc http::Event {sock token} { if {[TestForReplay $token read $nsl c]} { return + } else { } - # else: # This is NOT a persistent socket that has been closed since # its last use. @@ -3288,6 +3292,7 @@ proc http::Event {sock token} { if {[TestForReplay $token read {} d]} { return + } else { } # else: @@ -3295,6 +3300,7 @@ proc http::Event {sock token} { # last use. # If any other requests are in flight or pipelined/queued, they # will be discarded. + } else { } } elseif {$state(state) eq "header"} { if {[catch {gets $sock line} nhl]} { @@ -3313,6 +3319,7 @@ proc http::Event {sock token} { set state(state) "connecting" continue # This was a "return" in the pre-coroutine code. + } else { } if { ([info exists state(connection)]) @@ -3328,6 +3335,7 @@ proc http::Event {sock token} { # Previous value is $token. It cannot be "pending". set socketWrState($state(socketinfo)) Wready http::NextPipelinedWrite $token + } else { } # Once a "close" has been signaled, the client MUST NOT send any @@ -3358,6 +3366,7 @@ proc http::Event {sock token} { Log Move $tok from socketCoEvent to socketWrQueue and cancel its after idle coro } set socketCoEvent($state(socketinfo)) {} + } else { } if { ($socketRdQueue($state(socketinfo)) ne {}) @@ -3386,6 +3395,7 @@ proc http::Event {sock token} { if {[info exists ${tokenVal}(after)]} { after cancel [set ${tokenVal}(after)] unset ${tokenVal}(after) + } else { } # Tokens in the read queue have no (socketcoro) to # cancel. @@ -3398,6 +3408,7 @@ proc http::Event {sock token} { # Do not allow further connections on this socket (but # geturl can add new requests to the replay). set socketClosing($state(socketinfo)) 1 + } else { } set state(state) body @@ -3413,6 +3424,7 @@ proc http::Event {sock token} { && ("keep-alive" ni $state(connection)) } { lappend state(connection) "keep-alive" + } else { } # If doing a HEAD, then we won't get any body @@ -3421,6 +3433,7 @@ proc http::Event {sock token} { set state(state) complete Eot $token return + } else { } # - For non-chunked transfer we may have no body - in this case @@ -3451,6 +3464,7 @@ proc http::Event {sock token} { set state(state) complete Eot $token return + } else { } # We have to use binary translation to count bytes properly. @@ -3462,10 +3476,12 @@ proc http::Event {sock token} { } { # Turn off conversions for non-text data. set state(binary) 1 + } else { } if {[info exists state(-channel)]} { if {$state(binary) || [llength [ContentEncoding $token]]} { fconfigure $state(-channel) -translation binary + } else { } if {![info exists state(-handler)]} { # Initiate a sequence of background fcopies. @@ -3473,7 +3489,9 @@ proc http::Event {sock token} { rename ${token}--EventCoroutine {} CopyStart $sock $token return + } else { } + } else { } } elseif {$nhl > 0} { # Process header lines. @@ -3517,11 +3535,14 @@ proc http::Event {sock token} { set-cookie { if {$http(-cookiejar) ne ""} { ParseCookie $token [string trim $value] + } else { } } } lappend state(meta) $key [string trim $value] + } else { } + } else { } } else { # Now reading body @@ -3537,6 +3558,7 @@ proc http::Event {sock token} { # We know the transfer is complete only when the server # closes the connection - i.e. eof is not an error. set state(state) complete + } else { } if {![string is integer -strict $n]} { if 1 { @@ -3566,6 +3588,7 @@ proc http::Event {sock token} { set n 0 set state(state) complete } + } else { } } elseif {[info exists state(transfer_final)]} { # This code forgives EOF in place of the final CRLF. @@ -3605,6 +3628,7 @@ proc http::Event {sock token} { incr state(log_size) [string length $chunk] ##Log chunk $n cumul $state(log_size) -\ token $token + } else { } if {$size != [string length $chunk]} { Log "WARNING: mis-sized chunk:\ @@ -3617,6 +3641,7 @@ proc http::Event {sock token} { set msg {error in chunked encoding - fetch\ terminated} Eot $token $msg + } else { } # CRLF that follows chunk. # If eof, this is handled at the end of this proc. @@ -3664,6 +3689,7 @@ proc http::Event {sock token} { append state(body) $block ##Log non-chunk [string length $state(body)] -\ token $token + } else { } } # This calculation uses n from the -handler, chunked, or @@ -3675,6 +3701,7 @@ proc http::Event {sock token} { set t $state(totalsize) ##Log another $n currentsize $c totalsize $t -\ token $token + } else { } # If Content-Length - check for end of data. if { @@ -3685,7 +3712,9 @@ proc http::Event {sock token} { token $token set state(state) complete Eot $token + } else { } + } else { } } err]} { Log ^X$tk end of response (error ${err}) - token $token @@ -3695,6 +3724,7 @@ proc http::Event {sock token} { if {[info exists state(-progress)]} { namespace eval :: $state(-progress) \ [list $token $state(totalsize) $state(currentsize)] + } else { } } } -- cgit v0.12 From 673f931995a184eea390ad5d745cd102312e6343 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 9 Sep 2022 12:04:29 +0000 Subject: Change TclObjInterpProc() to a macro, since extensions should never invoke it directly, always through TclGetObjInterpProc() --- generic/tclBasic.c | 1 + generic/tclIntDecls.h | 2 ++ generic/tclProc.c | 2 ++ generic/tclStubInit.c | 1 + 4 files changed, 6 insertions(+) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 4bacba6..b806c33 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -780,6 +780,7 @@ Tcl_CreateInterp(void) Tcl_MutexUnlock(&cancelLock); } +#undef TclObjInterpProc if (commandTypeInit == 0) { TclRegisterCommandTypeName(TclObjInterpProc, "proc"); TclRegisterCommandTypeName(TclEnsembleImplementationCmd, "ensemble"); diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 69aee7c..588a1fa 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -1418,6 +1418,8 @@ extern const TclIntStubs *tclIntStubsPtr; #undef TclGuessPackageName #undef TclUnusedStubEntry #undef TclSetPreInitScript +#undef TclObjInterpProc +#define TclObjInterpProc TclGetObjInterpProc() #ifndef TCL_NO_DEPRECATED # define TclSetPreInitScript Tcl_SetPreInitScript # define TclGuessPackageName(fileName, pkgName) ((void)fileName,(void)pkgName,0) diff --git a/generic/tclProc.c b/generic/tclProc.c index 9a3785c..059e751 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -148,6 +148,7 @@ static const Tcl_ObjType lambdaType = { *---------------------------------------------------------------------- */ +#undef TclObjInterpProc int Tcl_ProcObjCmd( TCL_UNUSED(ClientData), @@ -1645,6 +1646,7 @@ TclPushProcCallFrame( *---------------------------------------------------------------------- */ +#undef TclObjInterpProc int TclObjInterpProc( ClientData clientData, /* Record describing procedure to be diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 87c9d0a..ae00b04 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -83,6 +83,7 @@ #undef Tcl_UtfAtIndex #undef Tcl_GetRange #undef Tcl_GetUniChar +#undef TclObjInterpProc #if defined(_WIN32) || defined(__CYGWIN__) #define TclWinConvertWSAError (void (*)(DWORD))(void *)Tcl_WinConvertError -- cgit v0.12 From a81159df88c89e6950dff666b7e507a0285c616a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 9 Sep 2022 13:12:43 +0000 Subject: Fix formatting in http.n --- doc/http.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/http.n b/doc/http.n index 2c9f809..d531995 100644 --- a/doc/http.n +++ b/doc/http.n @@ -1007,7 +1007,7 @@ Command \fB::http::geturl\fR uses the Tcl \fB::socket\fR command with the \-asyn .PP .SS "WITH TLS (HTTPS)" .PP -The same \-threadlevel configuration applies to both HTTP and HTTPS connections. HTTPS is enabled by using the \fBhttp::register\fR command, typically by specifying the \fB::tls::socket\fR command of the tls package to handle TLS cryptography. The \fB::tls::socket\fR command connects to the remote server by using the command specified by the value of variable \fI::tls::socketCmd\fR, and this value defaults to "::socket". If http::geturl finds that \fI::tls::socketCmd\fR has this value, it replaces it with the value "::http::socket". If \fI::tls::socketCmd\fR has a value other than "::socket", i.e. if the script or the Tcl installation has replaced the value "::socket" with the name of a different command, then http does not change the value. The script or installation that modified \fI::tls::socketCmd\fR is responsible for integrating \fR::http::socket\fR into its own replacement command. +The same \-threadlevel configuration applies to both HTTP and HTTPS connections. HTTPS is enabled by using the \fBhttp::register\fR command, typically by specifying the \fB::tls::socket\fR command of the tls package to handle TLS cryptography. The \fB::tls::socket\fR command connects to the remote server by using the command specified by the value of variable \fB::tls::socketCmd\fR, and this value defaults to "::socket". If http::geturl finds that \fB::tls::socketCmd\fR has this value, it replaces it with the value "::http::socket". If \fB::tls::socketCmd\fR has a value other than "::socket", i.e. if the script or the Tcl installation has replaced the value "::socket" with the name of a different command, then http does not change the value. The script or installation that modified \fB::tls::socketCmd\fR is responsible for integrating \fB::http::socket\fR into its own replacement command. .PP .SS "WITH A CHILD INTERPRETER" .PP -- cgit v0.12 From b83ee238f996e0d84b24b61566fedf5fb91919d9 Mon Sep 17 00:00:00 2001 From: oehhar Date: Fri, 9 Sep 2022 13:34:30 +0000 Subject: Ticket [6978c01b65]: add file encoding tests, which should fail in 9.0, but are ok in 8.6 and 8.7: write unrepresentable character and read invalid multi-byte character --- tests/io.test | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/io.test b/tests/io.test index 3b374c1..7c12b7b 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8805,6 +8805,39 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { removeFile io-74.1 } -returnCodes error -match glob -result {can not find channel named "*"} +# Note: the following tests are in preparation for TCL 9.0, where those should +# result in an error result +test io-75.1 {multibyte encoding error read results in raw bytes} -setup { + set fn [makeFile {} io-75.1] + set f [open $fn w+] + fconfigure $f -encoding binary + puts -nonewline $f "A\xC0\x40" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none +} -body { + read $f +} -cleanup { + close $f + removeFile io-75.1 +} -returnCodes ok -result "A\xC0\x40" +# for TCL 9.0, the result is error + +test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { + set fn [makeFile {} io-75.2] + set f [open $fn w+] + fconfigure $f -encoding iso8859-1 +} -body { + # the following command gets in result error in TCL 9.0 + puts -nonewline $f "A\u2022" + flush $f + seek $f 0 + read $f +} -cleanup { + close $f + removeFile io-75.2 +} -returnCodes ok -result "A?" + # ### ### ### ######### ######### ######### # cleanup -- cgit v0.12 From 6ed82bc4e590af32ae2a7742913dbd3388d6ce81 Mon Sep 17 00:00:00 2001 From: kjnash Date: Fri, 9 Sep 2022 15:32:00 +0000 Subject: Fix bug [338d979f5b] - default content-type is application/octet-stream --- library/http/http.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index be991fc..8e4c205 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -1001,7 +1001,7 @@ proc http::CreateToken {url args} { totalsize 0 querylength 0 queryoffset 0 - type text/html + type application/octet-stream body {} status "" http "" -- cgit v0.12 From d894ead020bd4783df01cd4b5a0ac882dcae5d2f Mon Sep 17 00:00:00 2001 From: oehhar Date: Sat, 10 Sep 2022 06:04:09 +0000 Subject: Ticket [6978c01b65]: add file encoding test io-75.3 with incomplete multibyte sequence. This may fail in TCL 9. --- tests/io.test | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/io.test b/tests/io.test index 88d13de..764e9f0 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8814,12 +8814,14 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { removeFile io-74.1 } -returnCodes error -match glob -result {can not find channel named "*"} -# Note: the following tests are in preparation for TCL 9.0, where those should -# result in an error result +# Note: the following tests 75.1 to 75.3 are in preparation for TCL 9.0, where +# those should result in an error result test io-75.1 {multibyte encoding error read results in raw bytes} -setup { set fn [makeFile {} io-75.1] set f [open $fn w+] fconfigure $f -encoding binary + # In UTF-8, a byte 0xCx starts a multibyte sequence and must be followed + # by a byte > 0x7F. This is violated to get an invalid sequence. puts -nonewline $f "A\xC0\x40" flush $f seek $f 0 @@ -8847,6 +8849,25 @@ test io-75.2 {unrepresentable character write passes and is replaced by ?} -setu removeFile io-75.2 } -returnCodes ok -result "A?" +# Incomplete sequence test. +# This error may IMHO only be detected with the close. +# But the read already returns the incomplete sequence. +test io-75.3 {incomplete multibyte encoding read is ignored} -setup { + set fn [makeFile {} io-75.3] + set f [open $fn w+] + fconfigure $f -encoding binary + puts -nonewline $f "A\xC0" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none +} -body { + set d [read $f] + close $f + set d +} -cleanup { + removeFile io-75.3 +} -returnCodes ok -result "A\xC0" + # ### ### ### ######### ######### ######### # cleanup -- cgit v0.12 From d288bedb47342cb10920f38467bcbfcded335e97 Mon Sep 17 00:00:00 2001 From: kjnash Date: Sat, 10 Sep 2022 11:47:34 +0000 Subject: Add option to detect XML files and their encoding when the server supplies no content-type. Fix for bugs [2998307] and [3165071]. --- doc/http.n | 13 ++++++++ library/http/http.tcl | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- tests/http.test | 2 +- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/doc/http.n b/doc/http.n index 135774d..5b70671 100644 --- a/doc/http.n +++ b/doc/http.n @@ -273,6 +273,19 @@ not call the \fBbgerror\fR handler. See the \fBERRORS\fR section for details. .RE .TP +\fB\-guesstype\fR \fIboolean\fR +. +Attempt to guess the Content-Type and character set when a misconfigured +server provides no information. The default value is \fIfalse\fR (do +nothing). If boolean \fItrue\fR then, if the server does not send a +"Content-Type" header, or if it sends the value "application/octet-stream", +\fBhttp::geturl\fR will attempt to guess appropriate values. This is not +intended to become a general-purpose tool, and currently it is limited to +detecting XML documents that begin with an XML declaration. In this case +the Content-Type is changed to "application/xml", and the character set to +the one specified by the "encoding" tag of the XML line, or to utf-8 if no +encoding is specified. +.TP \fB\-handler\fR \fIcallback\fR . Invoke \fIcallback\fR whenever HTTP data is available; if present, nothing diff --git a/library/http/http.tcl b/library/http/http.tcl index 8e4c205..a76ce15 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -992,6 +992,7 @@ proc http::CreateToken {url args} { -type application/x-www-form-urlencoded -queryprogress {} -protocol 1.1 + -guesstype 0 binary 0 state created meta {} @@ -1014,6 +1015,7 @@ proc http::CreateToken {url args} { array set type { -binary boolean -blocksize integer + -guesstype boolean -queryblocksize integer -strict boolean -timeout integer @@ -1022,7 +1024,7 @@ proc http::CreateToken {url args} { } set state(charset) $defaultCharset set options { - -binary -blocksize -channel -command -handler -headers -keepalive + -binary -blocksize -channel -command -guesstype -handler -headers -keepalive -method -myaddr -progress -protocol -query -queryblocksize -querychannel -queryprogress -strict -timeout -type -validate } @@ -4157,11 +4159,91 @@ proc http::Eot {token {reason {}}} { # Translate text line endings. set state(body) [string map {\r\n \n \r \n} $state(body)] } + if {[info exists state(-guesstype)] && $state(-guesstype)} { + GuessType $token + } } Finish $token $reason return } + +# ------------------------------------------------------------------------------ +# Proc http::GuessType +# ------------------------------------------------------------------------------ +# Command to attempt limited analysis of a resource with undetermined +# Content-Type, i.e. "application/octet-stream". This value can be set for two +# reasons: +# (a) by the server, in a Content-Type header +# (b) by http::geturl, as the default value if the server does not supply a +# Content-Type header. +# +# This command converts a resource if: +# (1) it has type application/octet-stream +# (2) it begins with an XML declaration "?" +# (3) one tag is named "encoding" and has a recognised value; or no "encoding" +# tag exists (defaulting to utf-8) +# +# RFC 9110 Sec. 8.3 states: +# "If a Content-Type header field is not present, the recipient MAY either +# assume a media type of "application/octet-stream" ([RFC2046], Section 4.5.1) +# or examine the data to determine its type." +# +# The RFC goes on to describe the pitfalls of "MIME sniffing", including +# possible security risks. +# +# Arguments: +# token - connection token +# +# Return Value: (boolean) true iff a change has been made +# ------------------------------------------------------------------------------ + +proc http::GuessType {token} { + variable $token + upvar 0 $token state + + if {$state(type) ne {application/octet-stream}} { + return 0 + } + + set body $state(body) + # e.g. { ...} + + if {![regexp -nocase -- {^<[?]xml[[:space:]][^>?]*[?]>} $body match]} { + return 0 + } + # e.g. {} + + set contents [regsub -- {[[:space:]]+} $match { }] + set contents [string range [string tolower $contents] 6 end-2] + # e.g. {version="1.0" encoding="utf-8"} + # without excess whitespace or upper-case letters + + if {![regexp -- {^([^=" ]+="[^"]+" )+$} "$contents "]} { + return 0 + } + # The application/xml default encoding: + set res utf-8 + + set tagList [regexp -all -inline -- {[^=" ]+="[^"]+"} $contents] + foreach tag $tagList { + regexp -- {([^=" ]+)="([^"]+)"} $tag -> name value + if {$name eq {encoding}} { + set res $value + } + } + set enc [CharsetToEncoding $res] + if {$enc eq "binary"} { + return 0 + } + set state(body) [encoding convertfrom $enc $state(body)] + set state(body) [string map {\r\n \n \r \n} $state(body)] + set state(type) application/xml + set state(charset) $res + return 1 +} + + # http::wait -- # # See documentation for details. diff --git a/tests/http.test b/tests/http.test index 08f6311..e88210a 100644 --- a/tests/http.test +++ b/tests/http.test @@ -145,7 +145,7 @@ test http-2.8 {http::CharsetToEncoding} { test http-3.1 {http::geturl} -returnCodes error -body { http::geturl -bogus flag -} -result {Unknown option flag, can be: -binary, -blocksize, -channel, -command, -handler, -headers, -keepalive, -method, -myaddr, -progress, -protocol, -query, -queryblocksize, -querychannel, -queryprogress, -strict, -timeout, -type, -validate} +} -result {Unknown option flag, can be: -binary, -blocksize, -channel, -command, -guesstype, -handler, -headers, -keepalive, -method, -myaddr, -progress, -protocol, -query, -queryblocksize, -querychannel, -queryprogress, -strict, -timeout, -type, -validate} test http-3.2 {http::geturl} -returnCodes error -body { http::geturl http:junk -- cgit v0.12 From 2d2a526d32f26572b36d183481c994fea88a4fd3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 10 Sep 2022 12:20:44 +0000 Subject: Add two "deprecated" constraints: those testcases test deprecated behavior which will change in 9.0 --- tests/io.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/io.test b/tests/io.test index fd0c3ca..5c45918 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8954,7 +8954,7 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { # Note: the following tests 75.1 to 75.3 are in preparation for TCL 9.0, where # those should result in an error result -test io-75.1 {multibyte encoding error read results in raw bytes} -setup { +test io-75.1 {multibyte encoding error read results in raw bytes} -constraints deprecated -setup { set fn [makeFile {} io-75.1] set f [open $fn w+] fconfigure $f -encoding binary @@ -8972,7 +8972,7 @@ test io-75.1 {multibyte encoding error read results in raw bytes} -setup { } -returnCodes ok -result "A\xC0\x40" # for TCL 9.0, the result is error -test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { +test io-75.2 {unrepresentable character write passes and is replaced by ?} -constraints deprecated -setup { set fn [makeFile {} io-75.2] set f [open $fn w+] fconfigure $f -encoding iso8859-1 -- cgit v0.12 From 65417af213a463e7b15e6d853dc1b6046bb4f4e7 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 10 Sep 2022 21:02:11 +0000 Subject: code cleanup (typo's, type casts) --- generic/tclOOCall.c | 83 +++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index 65b1e38..68a7173 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -4,7 +4,7 @@ * This file contains the method call chain management code for the * object-system core. * - * Copyright (c) 2005-2012 by Donal K. Fellows + * Copyright (c) 2005-2012 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -52,7 +52,7 @@ struct ChainBuilder { static void AddClassFiltersToCallContext(Object *const oPtr, Class *clsPtr, struct ChainBuilder *const cbPtr, Tcl_HashTable *const doneFilters, int flags); -static void AddClassMethodNames(Class *clsPtr, const int flags, +static void AddClassMethodNames(Class *clsPtr, int flags, Tcl_HashTable *const namesPtr, Tcl_HashTable *const examinedClassesPtr); static inline void AddMethodToCallChain(Method *const mPtr, @@ -90,6 +90,7 @@ static const Tcl_ObjType methodNameType = { NULL, NULL }; + /* * ---------------------------------------------------------------------- @@ -247,7 +248,7 @@ FreeMethodNameRep( int TclOOInvokeContext( - ClientData clientData, /* The method call context. */ + void *clientData, /* The method call context. */ Tcl_Interp *interp, /* Interpreter for error reporting, and many * other sorts of context handling (e.g., * commands, variables) depending on method @@ -255,7 +256,7 @@ TclOOInvokeContext( int objc, /* The number of arguments. */ Tcl_Obj *const objv[]) /* The arguments as actually seen. */ { - CallContext *const contextPtr = clientData; + CallContext *const contextPtr = (CallContext *)clientData; Method *const mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; const int isFilter = contextPtr->callPtr->chain[contextPtr->index].isFilter; @@ -316,11 +317,11 @@ TclOOInvokeContext( static int SetFilterFlags( - ClientData data[], + void *data[], Tcl_Interp *interp, int result) { - CallContext *contextPtr = data[0]; + CallContext *contextPtr = (CallContext *)data[0]; contextPtr->oPtr->flags |= FILTER_HANDLING; return result; @@ -328,11 +329,11 @@ SetFilterFlags( static int ResetFilterFlags( - ClientData data[], + void *data[], Tcl_Interp *interp, int result) { - CallContext *contextPtr = data[0]; + CallContext *contextPtr = (CallContext *)data[0]; contextPtr->oPtr->flags &= ~FILTER_HANDLING; return result; @@ -340,11 +341,11 @@ ResetFilterFlags( static int FinalizeMethodRefs( - ClientData data[], + void *data[], Tcl_Interp *interp, int result) { - CallContext *contextPtr = data[0]; + CallContext *contextPtr = (CallContext *)data[0]; int i; for (i = 0 ; i < contextPtr->callPtr->numChain ; i++) { @@ -543,7 +544,7 @@ TclOOGetSortedClassMethodList( * heavily sorted when it is long enough to matter. */ - strings = ckalloc(sizeof(char *) * names.numEntries); + strings = (const char **)ckalloc(sizeof(char *) * names.numEntries); FOREACH_HASH(namePtr, isWanted, &names) { if (!(flags & PUBLIC_METHOD) || (PTR2INT(isWanted) & IN_LIST)) { if (PTR2INT(isWanted) & NO_IMPLEMENTATION) { @@ -602,7 +603,7 @@ CmpStr( static void AddClassMethodNames( Class *clsPtr, /* Class to get method names from. */ - const int flags, /* Whether we are interested in just the + int flags, /* Whether we are interested in just the * public method names. */ Tcl_HashTable *const namesPtr, /* Reference to the hash table to put the @@ -726,7 +727,7 @@ AddSimpleChainToCallContext( (char *) methodNameObj); if (hPtr != NULL) { - Method *mPtr = Tcl_GetHashValue(hPtr); + Method *mPtr = (Method *)Tcl_GetHashValue(hPtr); if (flags & PUBLIC_METHOD) { if (!(mPtr->flags & PUBLIC_METHOD)) { @@ -750,7 +751,7 @@ AddSimpleChainToCallContext( if (oPtr->methodsPtr) { hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char*) methodNameObj); if (hPtr != NULL) { - AddMethodToCallChain(Tcl_GetHashValue(hPtr), cbPtr, + AddMethodToCallChain((Method *)Tcl_GetHashValue(hPtr), cbPtr, doneFilters, filterDecl, flags); } } @@ -861,11 +862,11 @@ AddMethodToCallChain( if (callPtr->numChain == CALL_CHAIN_STATIC_SIZE) { callPtr->chain = - ckalloc(sizeof(struct MInvoke) * (callPtr->numChain + 1)); + (struct MInvoke *)ckalloc(sizeof(struct MInvoke) * (callPtr->numChain + 1)); memcpy(callPtr->chain, callPtr->staticChain, sizeof(struct MInvoke) * callPtr->numChain); } else if (callPtr->numChain > CALL_CHAIN_STATIC_SIZE) { - callPtr->chain = ckrealloc(callPtr->chain, + callPtr->chain = (struct MInvoke *)ckrealloc(callPtr->chain, sizeof(struct MInvoke) * (callPtr->numChain + 1)); } callPtr->chain[i].mPtr = mPtr; @@ -908,12 +909,13 @@ InitCallChain( * ---------------------------------------------------------------------- * * IsStillValid -- + * * Calculates whether the given call chain can be used for executing a * method for the given object. The condition on a chain from a cached * location being reusable is: * - Refers to the same object (same creation epoch), and * - Still across the same class structure (same global epoch), and - * - Still across the same object strucutre (same local epoch), and + * - Still across the same object structure (same local epoch), and * - No public/private/filter magic leakage (same flags, modulo the fact * that a public chain will satisfy a non-public call). * @@ -966,7 +968,8 @@ TclOOGetCallContext( CallContext *contextPtr; CallChain *callPtr; struct ChainBuilder cb; - int i, count, doFilters; + int i, count; + int doFilters; Tcl_HashEntry *hPtr; Tcl_HashTable doneFilters; @@ -1009,7 +1012,7 @@ TclOOGetCallContext( const int reuseMask = ((flags & PUBLIC_METHOD) ? ~0 : ~PUBLIC_METHOD); if (cacheInThisObj->typePtr == &methodNameType) { - callPtr = cacheInThisObj->internalRep.twoPtrValue.ptr1; + callPtr = (CallChain *)cacheInThisObj->internalRep.twoPtrValue.ptr1; if (IsStillValid(callPtr, oPtr, flags, reuseMask)) { callPtr->refCount++; goto returnContext; @@ -1034,7 +1037,7 @@ TclOOGetCallContext( } if (hPtr != NULL && Tcl_GetHashValue(hPtr) != NULL) { - callPtr = Tcl_GetHashValue(hPtr); + callPtr = (CallChain *)Tcl_GetHashValue(hPtr); if (IsStillValid(callPtr, oPtr, flags, reuseMask)) { callPtr->refCount++; goto returnContext; @@ -1046,7 +1049,7 @@ TclOOGetCallContext( doFilters = 1; } - callPtr = ckalloc(sizeof(CallChain)); + callPtr = (CallChain *)ckalloc(sizeof(CallChain)); InitCallChain(callPtr, oPtr, flags); cb.callChainPtr = callPtr; @@ -1143,7 +1146,7 @@ TclOOGetCallContext( if (oPtr->flags & USE_CLASS_CACHE) { if (oPtr->selfCls->classChainCache == NULL) { oPtr->selfCls->classChainCache = - ckalloc(sizeof(Tcl_HashTable)); + (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitObjHashTable(oPtr->selfCls->classChainCache); } @@ -1151,7 +1154,7 @@ TclOOGetCallContext( (char *) methodNameObj, &i); } else { if (oPtr->chainCache == NULL) { - oPtr->chainCache = ckalloc(sizeof(Tcl_HashTable)); + oPtr->chainCache = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitObjHashTable(oPtr->chainCache); } @@ -1177,7 +1180,7 @@ TclOOGetCallContext( } returnContext: - contextPtr = TclStackAlloc(oPtr->fPtr->interp, sizeof(CallContext)); + contextPtr = (CallContext *)TclStackAlloc(oPtr->fPtr->interp, sizeof(CallContext)); contextPtr->oPtr = oPtr; /* @@ -1247,7 +1250,7 @@ TclOOGetStereotypeCallChain( const int reuseMask = ((flags & PUBLIC_METHOD) ? ~0 : ~PUBLIC_METHOD); - callPtr = Tcl_GetHashValue(hPtr); + callPtr = (CallChain *)Tcl_GetHashValue(hPtr); if (IsStillValid(callPtr, &obj, flags, reuseMask)) { callPtr->refCount++; return callPtr; @@ -1259,7 +1262,7 @@ TclOOGetStereotypeCallChain( hPtr = NULL; } - callPtr = ckalloc(sizeof(CallChain)); + callPtr = (CallChain *)ckalloc(sizeof(CallChain)); memset(callPtr, 0, sizeof(CallChain)); callPtr->flags = flags & (PUBLIC_METHOD|PRIVATE_METHOD|FILTER_HANDLING); callPtr->epoch = fPtr->epoch; @@ -1313,7 +1316,7 @@ TclOOGetStereotypeCallChain( } else { if (hPtr == NULL) { if (clsPtr->classChainCache == NULL) { - clsPtr->classChainCache = ckalloc(sizeof(Tcl_HashTable)); + clsPtr->classChainCache = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitObjHashTable(clsPtr->classChainCache); } hPtr = Tcl_CreateHashEntry(clsPtr->classChainCache, @@ -1350,7 +1353,8 @@ AddClassFiltersToCallContext( int flags) /* Whether we've gone along a mixin link * yet. */ { - int i, clearedFlags = + int i; + int clearedFlags = flags & ~(TRAVERSED_MIXIN|OBJECT_MIXIN|BUILDING_MIXINS); Class *superPtr, *mixinPtr; Tcl_Obj *filterObj; @@ -1463,7 +1467,7 @@ AddSimpleClassChainToCallContext( (char *) methodNameObj); if (hPtr != NULL) { - Method *mPtr = Tcl_GetHashValue(hPtr); + Method *mPtr = (Method *)Tcl_GetHashValue(hPtr); if (!(flags & KNOWN_STATE)) { if (flags & PUBLIC_METHOD) { @@ -1489,6 +1493,7 @@ AddSimpleClassChainToCallContext( AddSimpleClassChainToCallContext(superPtr, methodNameObj, cbPtr, doneFilters, flags, filterDecl); } + /* FALLTHRU */ case 0: return; } @@ -1538,20 +1543,18 @@ TclOORenderCallChain( * method (or "object" if it is declared on the instance). */ - objv = TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *)); + objv = (Tcl_Obj **)TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *)); for (i = 0 ; i < callPtr->numChain ; i++) { struct MInvoke *miPtr = &callPtr->chain[i]; - descObjs[0] = miPtr->isFilter - ? filterLiteral - : callPtr->flags & OO_UNKNOWN_METHOD - ? fPtr->unknownMethodNameObj - : methodLiteral; - descObjs[1] = callPtr->flags & CONSTRUCTOR - ? fPtr->constructorName - : callPtr->flags & DESTRUCTOR - ? fPtr->destructorName - : miPtr->mPtr->namePtr; + descObjs[0] = + miPtr->isFilter ? filterLiteral : + callPtr->flags & OO_UNKNOWN_METHOD ? fPtr->unknownMethodNameObj : + methodLiteral; + descObjs[1] = + callPtr->flags & CONSTRUCTOR ? fPtr->constructorName : + callPtr->flags & DESTRUCTOR ? fPtr->destructorName : + miPtr->mPtr->namePtr; descObjs[2] = miPtr->mPtr->declaringClassPtr ? Tcl_GetObjectName(interp, (Tcl_Object) miPtr->mPtr->declaringClassPtr->thisPtr) -- cgit v0.12 From 6cd305a23929b3f7c41c64fbbb552c9c579dd39d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 10 Sep 2022 23:25:22 +0000 Subject: Branch meant for investigation of [6978c01b65]. Ongoing --- .github/workflows/linux-build.yml | 5 -- .github/workflows/mac-build.yml | 66 ----------------- .github/workflows/onefiledist.yml | 146 -------------------------------------- .github/workflows/win-build.yml | 11 --- tests/io.test | 8 +-- 5 files changed, 4 insertions(+), 232 deletions(-) delete mode 100644 .github/workflows/mac-build.yml delete mode 100644 .github/workflows/onefiledist.yml diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 7ba9e89..0bcb51f 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -9,12 +9,7 @@ jobs: matrix: cfgopt: - "" - - "CFLAGS=-DTCL_UTF_MAX=3" - "CFLAGS=-DTCL_NO_DEPRECATED=1" - - "--disable-shared" - - "--enable-symbols" - - "--enable-symbols=mem" - - "--enable-symbols=all" defaults: run: shell: bash diff --git a/.github/workflows/mac-build.yml b/.github/workflows/mac-build.yml deleted file mode 100644 index 1ec784a..0000000 --- a/.github/workflows/mac-build.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: macOS -on: [push] -permissions: - contents: read -jobs: - xcode: - runs-on: macos-11 - defaults: - run: - shell: bash - working-directory: macosx - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Prepare - run: | - touch tclStubInit.c tclOOStubInit.c tclOOScript.h - working-directory: generic - - name: Build - run: make all - env: - CFLAGS: -arch x86_64 -arch arm64e - - name: Run Tests - run: make test styles=develop - env: - ERROR_ON_FAILURES: 1 - MAC_CI: 1 - clang: - runs-on: macos-11 - strategy: - matrix: - cfgopt: - - "" - - "--disable-shared" - - "--enable-symbols" - - "--enable-symbols=mem" - - "--enable-symbols=all" - defaults: - run: - shell: bash - working-directory: unix - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Prepare - run: | - touch tclStubInit.c tclOOStubInit.c tclOOScript.h - mkdir "$HOME/install dir" - working-directory: generic - - name: Configure ${{ matrix.cfgopt }} - # Note that macOS is always a 64 bit platform - run: ./configure --enable-dtrace --enable-framework ${CFGOPT} "--prefix=$HOME/install" || (cat config.log && exit 1) - env: - CFLAGS: -arch x86_64 -arch arm64e - CFGOPT: ${{ matrix.cfgopt }} - - name: Build - run: | - make all tcltest - env: - CFLAGS: -arch x86_64 -arch arm64e - - name: Run Tests - run: | - make test - env: - ERROR_ON_FAILURES: 1 - MAC_CI: 1 diff --git a/.github/workflows/onefiledist.yml b/.github/workflows/onefiledist.yml deleted file mode 100644 index 45ce720..0000000 --- a/.github/workflows/onefiledist.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: Build Binaries -on: [push] -permissions: - contents: read -jobs: - linux: - name: Linux - runs-on: ubuntu-20.04 - defaults: - run: - shell: bash - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Prepare - run: | - touch generic/tclStubInit.c generic/tclOOStubInit.c - mkdir 1dist - echo "VER_PATH=$(cd tools; pwd)/addVerToFile.tcl" >> $GITHUB_ENV - working-directory: . - - name: Configure - run: ./configure --disable-symbols --disable-shared --enable-zipfs - working-directory: unix - - name: Build - run: | - make tclsh - make shell SCRIPT="$VER_PATH $GITHUB_ENV" - echo "TCL_ZIP=`pwd`/`echo libtcl*.zip`" >> $GITHUB_ENV - working-directory: unix - - name: Package - run: | - cp ../unix/tclsh tclsh${TCL_PATCHLEVEL}_snapshot - chmod +x tclsh${TCL_PATCHLEVEL}_snapshot - tar -cf tclsh${TCL_PATCHLEVEL}_snapshot.tar tclsh${TCL_PATCHLEVEL}_snapshot - working-directory: 1dist - - name: Upload - uses: actions/upload-artifact@v3 - with: - name: Tclsh ${{ env.TCL_PATCHLEVEL }} Linux single-file build (snapshot) - path: 1dist/*.tar - macos: - name: macOS - runs-on: macos-11 - defaults: - run: - shell: bash - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Checkout create-dmg - uses: actions/checkout@v3 - with: - repository: create-dmg/create-dmg - ref: v1.0.8 - path: create-dmg - - name: Prepare - run: | - mkdir 1dist - touch generic/tclStubInit.c generic/tclOOStubInit.c || true - wget https://github.com/culler/macher/releases/download/v1.3/macher - sudo cp macher /usr/local/bin - sudo chmod a+x /usr/local/bin/macher - echo "VER_PATH=$(cd tools; pwd)/addVerToFile.tcl" >> $GITHUB_ENV - echo "CREATE_DMG=$(cd create-dmg;pwd)/create-dmg" >> $GITHUB_ENV - echo "CFLAGS=-arch x86_64 -arch arm64e" >> $GITHUB_ENV - - name: Configure - run: ./configure --disable-symbols --disable-shared --enable-zipfs - working-directory: unix - - name: Build - run: | - make tclsh - make shell SCRIPT="$VER_PATH $GITHUB_ENV" - echo "TCL_BIN=`pwd`/tclsh" >> $GITHUB_ENV - echo "TCL_ZIP=`pwd`/`echo libtcl*.zip`" >> $GITHUB_ENV - working-directory: unix - - name: Package - run: | - mkdir contents - cp $TCL_BIN contents/tclsh${TCL_PATCHLEVEL}_snapshot - chmod +x contents/tclsh${TCL_PATCHLEVEL}_snapshot - cat > contents/README.txt <> $GITHUB_ENV - mkdir 1dist - working-directory: . - - name: Configure - run: ./configure $CFGOPT - working-directory: win - - name: Build - run: | - make binaries libraries - echo "TCL_ZIP=`pwd`/`echo libtcl*.zip`" >> $GITHUB_ENV - working-directory: win - - name: Get Exact Version - run: | - ./tclsh*.exe $VER_PATH $GITHUB_ENV - working-directory: win - - name: Set Executable Name - run: | - cp ../win/tclsh*.exe tclsh${TCL_PATCHLEVEL}_snapshot.exe - working-directory: 1dist - - name: Upload - uses: actions/upload-artifact@v3 - with: - name: Tclsh ${{ env.TCL_PATCHLEVEL }} Windows single-file build (snapshot) - path: '1dist/*_snapshot.exe' diff --git a/.github/workflows/win-build.yml b/.github/workflows/win-build.yml index ba4e5ba..6fe21d5 100644 --- a/.github/workflows/win-build.yml +++ b/.github/workflows/win-build.yml @@ -14,12 +14,7 @@ jobs: strategy: matrix: cfgopt: - - "" - - "OPTS=utf16" - "CHECKS=nodep" - - "OPTS=static" - - "OPTS=symbols" - - "OPTS=symbols STATS=compdbg,memdbg" # Using powershell means we need to explicitly stop on failure steps: - name: Checkout @@ -53,13 +48,7 @@ jobs: strategy: matrix: cfgopt: - - "" - - "CFLAGS=-DTCL_UTF_MAX=3" - "CFLAGS=-DTCL_NO_DEPRECATED=1" - - "--disable-shared" - - "--enable-symbols" - - "--enable-symbols=mem" - - "--enable-symbols=all" # Using powershell means we need to explicitly stop on failure steps: - name: Install MSYS2 diff --git a/tests/io.test b/tests/io.test index 5c45918..49cec51 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8954,7 +8954,7 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { # Note: the following tests 75.1 to 75.3 are in preparation for TCL 9.0, where # those should result in an error result -test io-75.1 {multibyte encoding error read results in raw bytes} -constraints deprecated -setup { +test io-75.1 {multibyte encoding error read results in raw bytes} -setup { set fn [makeFile {} io-75.1] set f [open $fn w+] fconfigure $f -encoding binary @@ -8969,10 +8969,10 @@ test io-75.1 {multibyte encoding error read results in raw bytes} -constraints d } -cleanup { close $f removeFile io-75.1 -} -returnCodes ok -result "A\xC0\x40" +} -returnCodes ok -result "A" # for TCL 9.0, the result is error -test io-75.2 {unrepresentable character write passes and is replaced by ?} -constraints deprecated -setup { +test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { set fn [makeFile {} io-75.2] set f [open $fn w+] fconfigure $f -encoding iso8859-1 @@ -8985,7 +8985,7 @@ test io-75.2 {unrepresentable character write passes and is replaced by ?} -cons } -cleanup { close $f removeFile io-75.2 -} -returnCodes ok -result "A?" +} -returnCodes ok -result "A" # Incomplete sequence test. # This error may IMHO only be detected with the close. -- cgit v0.12 From e777b5ba8f9283bbc4ab4859e6beccea01b6ac37 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sat, 10 Sep 2022 23:42:56 +0000 Subject: Update comment regarding isNativeObjectProc --- generic/tcl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index 101ae0b..f17d43e 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -680,7 +680,7 @@ typedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp, struct Tcl_Obj *const *objv); typedef int (Tcl_CmdObjTraceProc2) (void *clientData, Tcl_Interp *interp, int level, const char *command, Tcl_Command commandInfo, size_t objc, - struct Tcl_Obj *const objv[]); + struct Tcl_Obj *const *objv); typedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData); typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, struct Tcl_Obj *dupPtr); @@ -909,17 +909,17 @@ typedef struct Tcl_CallFrame { typedef struct Tcl_CmdInfo { int isNativeObjectProc; /* 1 if objProc was registered by a call to - * Tcl_CreateObjCommand; 0 otherwise. - * Tcl_SetCmdInfo does not modify this - * field. */ + * Tcl_CreateObjCommand; 2 if objProc was registered by + * a call to Tcl_CreateObjCommand2; 0 otherwise. + * Tcl_SetCmdInfo does not modify this field. */ Tcl_ObjCmdProc *objProc; /* Command's object-based function. */ - ClientData objClientData; /* ClientData for object proc. */ + void *objClientData; /* ClientData for object proc. */ Tcl_CmdProc *proc; /* Command's string-based function. */ - ClientData clientData; /* ClientData for string proc. */ + void *clientData; /* ClientData for string proc. */ Tcl_CmdDeleteProc *deleteProc; /* Function to call when command is * deleted. */ - ClientData deleteData; /* Value to pass to deleteProc (usually the + void *deleteData; /* Value to pass to deleteProc (usually the * same as clientData). */ Tcl_Namespace *namespacePtr;/* Points to the namespace that contains this * command. Note that Tcl_SetCmdInfo will not -- cgit v0.12 From 0f674c548252976d41f9ac1c0cf4668cb8eaaabe Mon Sep 17 00:00:00 2001 From: oehhar Date: Sun, 11 Sep 2022 08:39:20 +0000 Subject: Tests io-75.x tolerant encoding: correct indention and comments --- tests/io.test | 58 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/tests/io.test b/tests/io.test index 764e9f0..e338749 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8814,58 +8814,58 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { removeFile io-74.1 } -returnCodes error -match glob -result {can not find channel named "*"} -# Note: the following tests 75.1 to 75.3 are in preparation for TCL 9.0, where -# those should result in an error result +# The following tests 75.1 to 75.3 exercice strict or tolerant channel +# encoding. +# TCL 8.6 only offers tolerant channel encoding, what is tested here. test io-75.1 {multibyte encoding error read results in raw bytes} -setup { - set fn [makeFile {} io-75.1] + set fn [makeFile {} io-75.1] set f [open $fn w+] fconfigure $f -encoding binary - # In UTF-8, a byte 0xCx starts a multibyte sequence and must be followed - # by a byte > 0x7F. This is violated to get an invalid sequence. - puts -nonewline $f "A\xC0\x40" - flush $f - seek $f 0 - fconfigure $f -encoding utf-8 -buffering none + # In UTF-8, a byte 0xCx starts a multibyte sequence and must be followed + # by a byte > 0x7F. This is violated to get an invalid sequence. + puts -nonewline $f "A\xC0\x40" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none } -body { - read $f + read $f } -cleanup { - close $f - removeFile io-75.1 + close $f + removeFile io-75.1 } -returnCodes ok -result "A\xC0\x40" # for TCL 9.0, the result is error test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { - set fn [makeFile {} io-75.2] + set fn [makeFile {} io-75.2] set f [open $fn w+] fconfigure $f -encoding iso8859-1 } -body { - # the following command gets in result error in TCL 9.0 - puts -nonewline $f "A\u2022" - flush $f - seek $f 0 - read $f + puts -nonewline $f "A\u2022" + flush $f + seek $f 0 + read $f } -cleanup { - close $f - removeFile io-75.2 + close $f + removeFile io-75.2 } -returnCodes ok -result "A?" # Incomplete sequence test. # This error may IMHO only be detected with the close. # But the read already returns the incomplete sequence. test io-75.3 {incomplete multibyte encoding read is ignored} -setup { - set fn [makeFile {} io-75.3] + set fn [makeFile {} io-75.3] set f [open $fn w+] fconfigure $f -encoding binary - puts -nonewline $f "A\xC0" - flush $f - seek $f 0 - fconfigure $f -encoding utf-8 -buffering none + puts -nonewline $f "A\xC0" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none } -body { - set d [read $f] - close $f - set d + set d [read $f] + close $f + set d } -cleanup { - removeFile io-75.3 + removeFile io-75.3 } -returnCodes ok -result "A\xC0" # ### ### ### ######### ######### ######### -- cgit v0.12 From b34f06a4afa5f57846efbe55f8dccb29e4611e2b Mon Sep 17 00:00:00 2001 From: kjnash Date: Sun, 11 Sep 2022 10:57:34 +0000 Subject: Fix bug [a13b9d0ce1] on HTTP compression: remove "compress", amend "deflate". --- doc/http.n | 6 +-- library/http/http.tcl | 62 ++++++++++++++++++++++++++--- tests/http11.test | 107 +++++++++++++++++++++++++++++++++++++++++++++++--- tests/httpd11.tcl | 27 +++++++++++-- 4 files changed, 185 insertions(+), 17 deletions(-) diff --git a/doc/http.n b/doc/http.n index 5b70671..e61f52f 100644 --- a/doc/http.n +++ b/doc/http.n @@ -210,7 +210,7 @@ numbers of \fBhttp\fR and \fBTcl\fR. \fB\-zip\fR \fIboolean\fR . If the value is boolean \fBtrue\fR, then by default requests will send a header -.QW "\fBAccept-Encoding: gzip,deflate,compress\fR" . +.QW "\fBAccept-Encoding: gzip,deflate\fR" . If the value is boolean \fBfalse\fR, then by default this header will not be sent. In either case the default can be overridden for an individual request by supplying a custom \fBAccept-Encoding\fR header in the \fB\-headers\fR option @@ -236,7 +236,7 @@ that is invoked when the HTTP transaction completes. . Specifies whether to force interpreting the URL data as binary. Normally this is auto-detected (anything not beginning with a \fBtext\fR content -type or whose content encoding is \fBgzip\fR or \fBcompress\fR is +type or whose content encoding is \fBgzip\fR or \fBdeflate\fR is considered binary data). .TP \fB\-blocksize\fR \fIsize\fR @@ -314,7 +314,7 @@ The \fBhttp::geturl\fR code for the \fB\-handler\fR option is not compatible with either compression or chunked transfer-encoding. If \fB\-handler\fR is specified, then to work around these issues \fBhttp::geturl\fR will reduce the HTTP protocol to 1.0, and override the \fB\-zip\fR option (i.e. it will not -send the header "\fBAccept-Encoding: gzip,deflate,compress\fR"). +send the header "\fBAccept-Encoding: gzip,deflate\fR"). .PP If options \fB\-handler\fR and \fB\-channel\fR are used together, the handler is responsible for copying the data from the HTTP socket to the specified diff --git a/library/http/http.tcl b/library/http/http.tcl index a76ce15..691355c 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -2128,7 +2128,7 @@ proc http::Connected {token proto phost srvurl} { && (![info exists state(-handler)]) && $http(-zip) } { - puts $sock "Accept-Encoding: gzip,deflate,compress" + puts $sock "Accept-Encoding: gzip,deflate" } if {$isQueryChannel && ($state(querylength) == 0)} { # Try to determine size of data in channel. If we cannot seek, the @@ -4010,13 +4010,25 @@ proc http::CopyStart {sock token {initial 1}} { upvar 0 $token state if {[info exists state(transfer)] && $state(transfer) eq "chunked"} { foreach coding [ContentEncoding $token] { - lappend state(zlib) [zlib stream $coding] + if {$coding eq {deflateX}} { + # Use the standards-compliant choice. + set coding2 decompress + } else { + set coding2 $coding + } + lappend state(zlib) [zlib stream $coding2] } make-transformation-chunked $sock [namespace code [list CopyChunk $token]] } else { if {$initial} { foreach coding [ContentEncoding $token] { - zlib push $coding $sock + if {$coding eq {deflateX}} { + # Use the standards-compliant choice. + set coding2 decompress + } else { + set coding2 $coding + } + zlib push $coding2 $sock } } if {[catch { @@ -4137,7 +4149,20 @@ proc http::Eot {token {reason {}}} { if {[string length $state(body)] > 0} { if {[catch { foreach coding [ContentEncoding $token] { - set state(body) [zlib $coding $state(body)] + if {$coding eq {deflateX}} { + # First try the standards-compliant choice. + set coding2 decompress + if {[catch {zlib $coding2 $state(body)} result]} { + # If that fails, try the MS non-compliant choice. + set coding2 inflate + set state(body) [zlib $coding2 $state(body)] + } else { + # error {failed at standards-compliant deflate} + set state(body) $result + } + } else { + set state(body) [zlib $coding $state(body)] + } } } err]} { Log "error doing decompression for token $token: $err" @@ -4387,16 +4412,41 @@ proc http::CharsetToEncoding {charset} { } } + +# ------------------------------------------------------------------------------ +# Proc http::ContentEncoding +# ------------------------------------------------------------------------------ # Return the list of content-encoding transformations we need to do in order. +# + # -------------------------------------------------------------------------- + # Options for Accept-Encoding, Content-Encoding: the switch command + # -------------------------------------------------------------------------- + # The symbol deflateX allows http to attempt both versions of "deflate", + # unless there is a -channel - for a -channel, only "decompress" is tried. + # Alternative/extra lines for switch: + # The standards-compliant version of "deflate" can be chosen with: + # deflate { lappend r decompress } + # The Microsoft non-compliant version of "deflate" can be chosen with: + # deflate { lappend r inflate } + # The previously used implementation of "compress", which appears to be + # incorrect and is rarely used by web servers, can be chosen with: + # compress - x-compress { lappend r decompress } + # -------------------------------------------------------------------------- +# +# Arguments: +# token - Connection token. +# +# Return Value: list +# ------------------------------------------------------------------------------ + proc http::ContentEncoding {token} { upvar 0 $token state set r {} if {[info exists state(coding)]} { foreach coding [split $state(coding) ,] { switch -exact -- $coding { - deflate { lappend r inflate } + deflate { lappend r deflateX } gzip - x-gzip { lappend r gunzip } - compress - x-compress { lappend r decompress } identity {} br { return -code error\ diff --git a/tests/http11.test b/tests/http11.test index 912e069..b3d9edb 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -144,7 +144,22 @@ test http11-1.2 "normal,deflated,non-chunked" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok deflate {}} -test http11-1.3 "normal,compressed,non-chunked" -setup { +test http11-1.2.1 "normal,deflated,non-chunked,msdeflate" -setup { + variable httpd [create_httpd] +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?close=1&msdeflate=1 \ + -timeout 10000 -headers {accept-encoding deflate}] + http::wait $tok + list [http::status $tok] [http::code $tok] [check_crc $tok] \ + [meta $tok content-encoding] [meta $tok transfer-encoding] +} -cleanup { + http::cleanup $tok + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok deflate {}} + +test http11-1.3 "normal,compressed,non-chunked" -constraints badCompress -setup { + # The Tcl "compress" algorithm appears to be incorrect and has been removed. + # Bug [a13b9d0ce1]. variable httpd [create_httpd] } -body { set tok [http::geturl http://localhost:$httpd_port/testdoc.html?close=1 \ @@ -249,7 +264,22 @@ test http11-1.10 "normal,deflate,chunked" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok deflate chunked} -test http11-1.11 "normal,compress,chunked" -setup { +test http11-1.10.1 "normal,deflate,chunked,msdeflate" -setup { + variable httpd [create_httpd] +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?msdeflate=1 \ + -timeout 10000 -headers {accept-encoding deflate}] + http::wait $tok + list [http::status $tok] [http::code $tok] [check_crc $tok] \ + [meta $tok content-encoding] [meta $tok transfer-encoding] +} -cleanup { + http::cleanup $tok + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok deflate chunked} + +test http11-1.11 "normal,compress,chunked" -constraints badCompress -setup { + # The Tcl "compress" algorithm appears to be incorrect and has been removed. + # Bug [a13b9d0ce1]. variable httpd [create_httpd] } -body { set tok [http::geturl http://localhost:$httpd_port/testdoc.html \ @@ -370,7 +400,28 @@ test http11-2.2 "-channel, encoding deflate" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok close deflate chunked} -test http11-2.3 "-channel,encoding compress" -setup { +test http11-2.2.1 "-channel, encoding deflate,msdeflate" -setup { + variable httpd [create_httpd] + set chan [open [makeFile {} testfile.tmp] wb+] +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?msdeflate=1 \ + -timeout 5000 -channel $chan -headers {accept-encoding deflate}] + http::wait $tok + seek $chan 0 + set data [read $chan] + list [http::status $tok] [http::code $tok] [check_crc $tok $data]\ + [meta $tok connection] [meta $tok content-encoding]\ + [meta $tok transfer-encoding] +} -cleanup { + http::cleanup $tok + close $chan + removeFile testfile.tmp + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok close deflate chunked} + +test http11-2.3 "-channel,encoding compress" -constraints badCompress -setup { + # The Tcl "compress" algorithm appears to be incorrect and has been removed. + # Bug [a13b9d0ce1]. variable httpd [create_httpd] set chan [open [makeFile {} testfile.tmp] wb+] } -body { @@ -522,7 +573,32 @@ test http11-2.7 "-channel,encoding deflate,non-chunked" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok close deflate {} 0} -test http11-2.8 "-channel,encoding compress,non-chunked" -setup { +test http11-2.7.1 "-channel,encoding deflate,non-chunked,msdeflate" -constraints knownBug -setup { + # Test fails because a -channel can only try one un-deflate algorithm, and the + # compliant "decompress" is tried, not the non-compliant "inflate" of + # the MS browser implementation. + variable httpd [create_httpd] + set chan [open [makeFile {} testfile.tmp] wb+] +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?close=1&msdeflate=1 \ + -timeout 5000 -channel $chan -headers {accept-encoding deflate}] + http::wait $tok + seek $chan 0 + set data [read $chan] + list [http::status $tok] [http::code $tok] [check_crc $tok $data]\ + [meta $tok connection] [meta $tok content-encoding]\ + [meta $tok transfer-encoding]\ + [expr {[file size testdoc.html]-[file size testfile.tmp]}] +} -cleanup { + http::cleanup $tok + close $chan + removeFile testfile.tmp + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok close deflate {} 0} + +test http11-2.8 "-channel,encoding compress,non-chunked" -constraints badCompress -setup { + # The Tcl "compress" algorithm appears to be incorrect and has been removed. + # Bug [a13b9d0ce1]. variable httpd [create_httpd] set chan [open [makeFile {} testfile.tmp] wb+] } -body { @@ -583,6 +659,27 @@ test http11-2.10 "-channel,deflate,keepalive" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok {} deflate chunked 0} +test http11-2.10.1 "-channel,deflate,keepalive,msdeflate" -setup { + variable httpd [create_httpd] + set chan [open [makeFile {} testfile.tmp] wb+] +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?msdeflate=1 \ + -timeout 5000 -channel $chan -keepalive 1 \ + -headers {accept-encoding deflate}] + http::wait $tok + seek $chan 0 + set data [read $chan] + list [http::status $tok] [http::code $tok] [check_crc $tok $data]\ + [meta $tok connection] [meta $tok content-encoding]\ + [meta $tok transfer-encoding]\ + [expr {[file size testdoc.html]-[file size testfile.tmp]}] +} -cleanup { + http::cleanup $tok + close $chan + removeFile testfile.tmp + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok {} deflate chunked 0} + test http11-2.11 "-channel,identity,keepalive" -setup { variable httpd [create_httpd] set chan [open [makeFile {} testfile.tmp] wb+] @@ -621,7 +718,7 @@ test http11-2.12 "-channel,negotiate,keepalive" -setup { close $chan removeFile testfile.tmp halt_httpd -} -result {ok {HTTP/1.1 200 OK} ok {} gzip chunked gzip,deflate,compress 0} +} -result {ok {HTTP/1.1 200 OK} ok {} gzip chunked gzip,deflate 0} # ------------------------------------------------------------------------- diff --git a/tests/httpd11.tcl b/tests/httpd11.tcl index d0624f8..6570ee9 100644 --- a/tests/httpd11.tcl +++ b/tests/httpd11.tcl @@ -160,6 +160,12 @@ proc Service {chan addr port} { if {$protocol eq "HTTP/1.1"} { foreach enc [split [dict get? $meta accept-encoding] ,] { set enc [string trim $enc] + # The current implementation of "compress" appears to be + # incorrect (bug [a13b9d0ce1]). Keep it here for + # experimentation only. The tests that use it have the + # constraint "badCompress". The client code in http has + # been removed, but can be restored from comments if + # experimentation is desired. if {$enc in {deflate gzip compress}} { set encoding $enc break @@ -171,6 +177,7 @@ proc Service {chan addr port} { } set nosendclose 0 + set msdeflate 0 foreach pair [split $query &] { if {[scan $pair {%[^=]=%s} key val] != 2} {set val ""} switch -exact -- $key { @@ -178,6 +185,7 @@ proc Service {chan addr port} { close {set close 1 ; set transfer 0} transfer {set transfer $val} content-type {set type $val} + msdeflate {set msdeflate $val} } } if {$protocol eq "HTTP/1.1"} { @@ -211,10 +219,23 @@ proc Service {chan addr port} { flush $chan chan configure $chan -buffering full -translation binary + if {$encoding eq {deflate}} { + # When http.tcl uses the correct decoder (bug [a13b9d0ce1]) for + # "accept-encoding deflate", i.e. "zlib decompress", this choice of + # encoding2 allows the tests to pass. It appears to do "deflate" + # correctly, but this has not been verified with a non-Tcl client. + set encoding2 compress + } else { + set encoding2 $encoding + } if {$transfer eq "chunked"} { - blow-chunks $data $chan $encoding - } elseif {$encoding ne "identity"} { - puts -nonewline $chan [zlib $encoding $data] + blow-chunks $data $chan $encoding2 + } elseif {$encoding2 ne "identity" && $msdeflate eq {1}} { + puts -nonewline $chan [string range [zlib $encoding2 $data] 2 end-4] + # Used in some tests of "deflate" to produce the non-RFC-compliant + # Microsoft version of "deflate". + } elseif {$encoding2 ne "identity"} { + puts -nonewline $chan [zlib $encoding2 $data] } else { puts -nonewline $chan $data } -- cgit v0.12 From e681ade127e237c8ebf20bbaf02f6c5757671b71 Mon Sep 17 00:00:00 2001 From: kjnash Date: Sun, 11 Sep 2022 16:32:30 +0000 Subject: Fix bug [3610253] - apply the patch supplied with the ticket, and add a test. REVIEW REQUESTED! Also fix -zip 0 so it sends "Accept-Encoding: identity". --- library/http/http.tcl | 10 +++++++++- tests/http11.test | 32 ++++++++++++++++++++++++++++++-- tests/httpd11.tcl | 4 ++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 691355c..551b323 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -2129,6 +2129,9 @@ proc http::Connected {token proto phost srvurl} { && $http(-zip) } { puts $sock "Accept-Encoding: gzip,deflate" + } elseif {!$accept_encoding_seen} { + puts $sock "Accept-Encoding: identity" + } else { } if {$isQueryChannel && ($state(querylength) == 0)} { # Try to determine size of data in channel. If we cannot seek, the @@ -4064,7 +4067,12 @@ proc http::CopyChunk {token chunk} { if {[info exists state(zlib)]} { set excess "" foreach stream $state(zlib) { - catch {set excess [$stream add -finalize $excess]} + catch { + $stream put -finalize $excess + set excess "" + set overflood "" + while {[set overflood [$stream get]] ne ""} { append excess $overflood } + } } puts -nonewline $state(-channel) $excess foreach stream $state(zlib) { $stream close } diff --git a/tests/http11.test b/tests/http11.test index b3d9edb..71ef4c7 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -84,6 +84,8 @@ proc check_crc {tok args} { makeFile "test

this is a test

\n[string repeat {

This is a tcl test file.

} 4192]\n" testdoc.html +makeFile "test

this is a test

\n[string repeat {

This is a tcl test file.

} 5000]\n" largedoc.html + if {![info exists ThreadLevel]} { if {[catch {package require Thread}] == 0} { set ValueRange {0 1 2} @@ -371,15 +373,40 @@ test http11-2.1 "-channel, encoding gzip" -setup { http::wait $tok seek $chan 0 set data [read $chan] + set diff [expr {[file size testdoc.html] - [file size testfile.tmp]}] list [http::status $tok] [http::code $tok] [check_crc $tok $data]\ [meta $tok connection] [meta $tok content-encoding]\ - [meta $tok transfer-encoding] + [meta $tok transfer-encoding] -- $diff bytes lost +} -cleanup { + http::cleanup $tok + close $chan + removeFile testfile.tmp + halt_httpd +} -result {ok {HTTP/1.1 200 OK} ok close gzip chunked -- 0 bytes lost} + +# Cf. Bug [3610253] "CopyChunk does not drain decompressor(s)" +# This test failed before the bugfix. +# The pass/fail depended on file size. +test http11-2.1.1 "-channel, encoding gzip" -setup { + variable httpd [create_httpd] + set chan [open [makeFile {} testfile.tmp] wb+] + set fileName largedoc.html +} -body { + set tok [http::geturl http://localhost:$httpd_port/$fileName \ + -timeout 5000 -channel $chan -headers {accept-encoding gzip}] + http::wait $tok + seek $chan 0 + set data [read $chan] + set diff [expr {[file size $fileName] - [file size testfile.tmp]}] + list [http::status $tok] [http::code $tok] [check_crc $tok $data]\ + [meta $tok connection] [meta $tok content-encoding]\ + [meta $tok transfer-encoding] -- $diff bytes lost } -cleanup { http::cleanup $tok close $chan removeFile testfile.tmp halt_httpd -} -result {ok {HTTP/1.1 200 OK} ok close gzip chunked} +} -result {ok {HTTP/1.1 200 OK} ok close gzip chunked -- 0 bytes lost} test http11-2.2 "-channel, encoding deflate" -setup { variable httpd [create_httpd] @@ -1033,6 +1060,7 @@ foreach p {create_httpd httpd_read halt_httpd meta check_crc} { if {[llength [info proc $p]]} {rename $p {}} } removeFile testdoc.html +removeFile largedoc.html unset -nocomplain httpd_port httpd p ::tcltest::cleanupTests diff --git a/tests/httpd11.tcl b/tests/httpd11.tcl index 6570ee9..55b52fd 100644 --- a/tests/httpd11.tcl +++ b/tests/httpd11.tcl @@ -46,7 +46,7 @@ proc get-chunks {data {compression gzip}} { } set data "" - set chunker [make-chunk-generator $data 512] + set chunker [make-chunk-generator $data 671] while {[string length [set chunk [$chunker]]]} { append data $chunk } @@ -60,7 +60,7 @@ proc blow-chunks {data {ochan stdout} {compression gzip}} { compress { set data [zlib compress $data] } } - set chunker [make-chunk-generator $data 512] + set chunker [make-chunk-generator $data 671] while {[string length [set chunk [$chunker]]]} { puts -nonewline $ochan $chunk } -- cgit v0.12 From fcfbc3a606dd31e90fcc3a6bb847042e19e1722b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 11 Sep 2022 21:37:34 +0000 Subject: complete the fix --- generic/tclIO.c | 20 +++++++++++++++++++- tests/io.test | 8 ++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 5313eed..c6402f1 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4335,6 +4335,7 @@ Write( char *nextNewLine = NULL; int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0; char safe[BUFFER_PADDING]; + int encodingError = 0; if (srcLen) { WillWrite(chanPtr); @@ -4351,7 +4352,7 @@ Write( nextNewLine = (char *)memchr(src, '\n', srcLen); } - while (srcLen + saved + endEncoding > 0) { + while (srcLen + saved + endEncoding > 0 && !encodingError) { ChannelBuffer *bufPtr; char *dst; int result, srcRead, dstLen, dstWrote, srcLimit = srcLen; @@ -4390,6 +4391,19 @@ Write( statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; + /* + * See io-75.2, TCL bug 6978c01b65. + * Check, if an encoding error occured and should be reported to the + * script level. + * This happens, if a written character may not be represented by the + * current output encoding and strict encoding is active. + */ + + if (result == TCL_CONVERT_UNKNOWN) { + encodingError = 1; + result = TCL_OK; + } + if ((result != TCL_OK) && (srcRead + dstWrote == 0)) { /* * We're reading from invalid/incomplete UTF-8. @@ -4497,6 +4511,10 @@ Write( UpdateInterest(chanPtr); + if (encodingError) { + Tcl_SetErrno(EILSEQ); + return -1; + } return total; } diff --git a/tests/io.test b/tests/io.test index 3d6b0da..cd04b115 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8977,14 +8977,14 @@ test io-75.2 {unrepresentable character write passes and is replaced by ?} -setu set f [open $fn w+] fconfigure $f -encoding iso8859-1 } -body { - puts -nonewline $f "A\u2022" + catch {puts -nonewline $f "A\u2022"} msg flush $f seek $f 0 - read $f + list [read $f] $msg } -cleanup { close $f - removeFile io-75.2 -} -returnCodes ok -result "A" + removeFile io-75.5 +} -match glob -result [list {A} {error writing "*": illegal byte sequence}] # Incomplete sequence test. # This error may IMHO only be detected with the close. -- cgit v0.12 From 5a421912ecffcfe680588b3b91ac62ee907e79ec Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 12 Sep 2022 10:54:02 +0000 Subject: testcase cleanup --- tests/io.test | 162 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 84 insertions(+), 78 deletions(-) diff --git a/tests/io.test b/tests/io.test index e338749..4b7a61e 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8,7 +8,7 @@ # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. -# Copyright (c) 1998-1999 by Scriptics Corporation. +# Copyright (c) 1998-1999 Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -108,17 +108,17 @@ set path(test1) [makeFile {} test1] test io-1.6 {Tcl_WriteChars: WriteBytes} { set f [open $path(test1) w] fconfigure $f -encoding binary - puts -nonewline $f "a\u4e4d\0" + puts -nonewline $f "a\u4E4D\x00" close $f contents $path(test1) -} "a\x4d\x00" +} "a\x4D\x00" test io-1.7 {Tcl_WriteChars: WriteChars} { set f [open $path(test1) w] fconfigure $f -encoding shiftjis - puts -nonewline $f "a\u4e4d\0" + puts -nonewline $f "a\u4e4d\x00" close $f contents $path(test1) -} "a\x93\xe1\x00" +} "a\x93\xE1\x00" set path(test2) [makeFile {} test2] test io-1.8 {Tcl_WriteChars: WriteChars} { # This test written for SF bug #506297. @@ -132,7 +132,7 @@ test io-1.8 {Tcl_WriteChars: WriteChars} { puts -nonewline $f [format %s%c [string repeat " " 4] 12399] close $f contents $path(test2) -} " \x1b\$B\$O\x1b(B" +} " \x1B\$B\$O\x1B(B" test io-1.9 {Tcl_WriteChars: WriteChars} { # When closing a channel with an encoding that appends @@ -268,7 +268,7 @@ test io-3.3 {WriteChars: compatibility with WriteBytes: flush on line} { close $f set x } "\r\n12" -test io-3.4 {WriteChars: loop over stage buffer} { +test io-3.4 {WriteChars: loop over stage buffer} -body { # stage buffer maps to more than can be queued at once. set f [open $path(test1) w] @@ -277,8 +277,10 @@ test io-3.4 {WriteChars: loop over stage buffer} { set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] -} [list "!)!)!)!)!)!)!)!)" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] -test io-3.5 {WriteChars: saved != 0} { +} -cleanup { + catch {close $f} +} -result [list "!)!)!)!)!)!)!)!)" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] +test io-3.5 {WriteChars: saved != 0} -body { # Bytes produced by UtfToExternal from end of last channel buffer # had to be moved to beginning of next channel buffer to preserve # requested buffersize. @@ -289,25 +291,27 @@ test io-3.5 {WriteChars: saved != 0} { set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] -} [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] +} -cleanup { + catch {close $f} +} -result [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] test io-3.6 {WriteChars: (stageRead + dstWrote == 0)} { # One incomplete UTF-8 character at end of staging buffer. Backup # in src to the beginning of that UTF-8 character and try again. # # Translate the first 16 bytes, produce 14 bytes of output, 2 left over - # (first two bytes of \uff21 in UTF-8). Given those two bytes try + # (first two bytes of \uFF21 in UTF-8). Given those two bytes try # translating them again, find that no bytes are read produced, and break # to outer loop where those two bytes will have the remaining 4 bytes - # (the last byte of \uff21 plus the all of \uff22) appended. + # (the last byte of \uFF21 plus the all of \uFF22) appended. set f [open $path(test1) w] fconfigure $f -encoding shiftjis -buffersize 16 - puts -nonewline $f "12345678901234\uff21\uff22" + puts -nonewline $f "12345678901234\uFF21\uFF22" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "12345678901234\x82\x60" "12345678901234\x82\x60\x82\x61"] -test io-3.7 {WriteChars: (bufPtr->nextAdded > bufPtr->length)} { +test io-3.7 {WriteChars: (bufPtr->nextAdded > bufPtr->length)} -body { # When translating UTF-8 to external, the produced bytes went past end # of the channel buffer. This is done purpose -- we then truncate the # bytes at the end of the partial character to preserve the requested @@ -320,7 +324,9 @@ test io-3.7 {WriteChars: (bufPtr->nextAdded > bufPtr->length)} { set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] -} [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] +} -cleanup { + catch {close $f} +} -result [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] test io-3.8 {WriteChars: reset sawLF after each buffer} { set f [open $path(test1) w] fconfigure $f -encoding ascii -buffering line -translation lf \ @@ -460,7 +466,7 @@ test io-6.3 {Tcl_GetsObj: how many have we used?} { test io-6.4 {Tcl_GetsObj: encoding == NULL} { set f [open $path(test1) w] fconfigure $f -translation binary - puts $f "\x81\u1234\0" + puts $f "\x81\u1234\x00" close $f set f [open $path(test1)] fconfigure $f -translation binary @@ -471,14 +477,14 @@ test io-6.4 {Tcl_GetsObj: encoding == NULL} { test io-6.5 {Tcl_GetsObj: encoding != NULL} { set f [open $path(test1) w] fconfigure $f -translation binary - puts $f "\x88\xea\x92\x9a" + puts $f "\x88\xEA\x92\x9A" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis set x [list [gets $f line] $line] close $f set x -} [list 2 "\u4e00\u4e01"] +} [list 2 "\u4E00\u4E01"] set a "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" append a $a append a $a @@ -518,7 +524,7 @@ test io-6.8 {Tcl_GetsObj: remember if EOF is seen} { } {6 abcdef -1 {}} test io-6.9 {Tcl_GetsObj: remember if EOF is seen} { set f [open $path(test1) w] - puts $f "abcdefghijk\nwom\u001abat" + puts $f "abcdefghijk\nwom\u001Abat" close $f set f [open $path(test1)] fconfigure $f -eofchar \x1A @@ -1061,14 +1067,14 @@ test io-6.55 {Tcl_GetsObj: overconverted} { set f [open $path(test1) w] fconfigure $f -encoding iso2022-jp - puts $f "there\u4e00ok\n\u4e01more bytes\nhere" + puts $f "there\u4E00ok\n\u4E01more bytes\nhere" close $f set f [open $path(test1)] fconfigure $f -encoding iso2022-jp set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x -} [list 8 "there\u4e00ok" 11 "\u4e01more bytes" 4 "here"] +} [list 8 "there\u4E00ok" 11 "\u4E01more bytes" 4 "here"] test io-6.56 {Tcl_GetsObj: incomplete lines should disable file events} {stdio fileevent} { update set f [open "|[list [interpreter] $path(cat)]" w+] @@ -1095,20 +1101,20 @@ test io-7.1 {FilterInputBytes: split up character at end of buffer} { set f [open $path(test1) w] fconfigure $f -encoding shiftjis - puts $f "1234567890123\uff10\uff11\uff12\uff13\uff14\nend" + puts $f "1234567890123\uFF10\uFF11\uFF12\uFF13\uFF14\nend" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis -buffersize 16 set x [gets $f] close $f set x -} "1234567890123\uff10\uff11\uff12\uff13\uff14" +} "1234567890123\uFF10\uFF11\uFF12\uFF13\uFF14" test io-7.2 {FilterInputBytes: split up character in middle of buffer} { # (bufPtr->nextAdded < bufPtr->bufLength) set f [open $path(test1) w] fconfigure $f -encoding binary - puts -nonewline $f "1234567890\n123\x82\x4f\x82\x50\x82" + puts -nonewline $f "1234567890\n123\x82\x4F\x82\x50\x82" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis @@ -1119,7 +1125,7 @@ test io-7.2 {FilterInputBytes: split up character in middle of buffer} { test io-7.3 {FilterInputBytes: split up character at EOF} {testchannel} { set f [open $path(test1) w] fconfigure $f -encoding binary - puts -nonewline $f "1234567890123\x82\x4f\x82\x50\x82" + puts -nonewline $f "1234567890123\x82\x4F\x82\x50\x82" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis @@ -1128,11 +1134,11 @@ test io-7.3 {FilterInputBytes: split up character at EOF} {testchannel} { lappend x [gets $f line] $line close $f set x -} [list 15 "1234567890123\uff10\uff11" 18 0 1 -1 ""] +} [list 15 "1234567890123\uFF10\uFF11" 18 0 1 -1 ""] test io-7.4 {FilterInputBytes: recover from split up character} {stdio fileevent} { set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -encoding binary -buffering none - puts -nonewline $f "1234567890123\x82\x4f\x82\x50\x82" + puts -nonewline $f "1234567890123\x82\x4F\x82\x50\x82" fconfigure $f -encoding shiftjis -blocking 0 fileevent $f read [namespace code "ready $f"] variable x {} @@ -1147,7 +1153,7 @@ test io-7.4 {FilterInputBytes: recover from split up character} {stdio fileevent vwait [namespace which -variable x] close $f set x -} [list -1 "" 1 17 "1234567890123\uff10\uff11\uff12\uff13" 0] +} [list -1 "" 1 17 "1234567890123\uFF10\uFF11\uFF12\uFF13" 0] test io-8.1 {PeekAhead: only go to device if no more cached data} {testchannel} { # (bufPtr->nextPtr == NULL) @@ -1424,19 +1430,19 @@ test io-12.4 {ReadChars: split-up char} {stdio testchannel fileevent} { fconfigure $f -encoding shiftjis vwait [namespace which -variable x] fconfigure $f -encoding binary -blocking 1 - puts -nonewline $f "\x7b" + puts -nonewline $f "\x7B" after 500 ;# Give the cat process time to catch up fconfigure $f -encoding shiftjis -blocking 0 vwait [namespace which -variable x] close $f set x -} [list "123456789012345" 1 "\u672c" 0] +} [list "123456789012345" 1 "\u672C" 0] test io-12.5 {ReadChars: fileevents on partial characters} {stdio fileevent} { set path(test1) [makeFile { fconfigure stdout -encoding binary -buffering none - gets stdin; puts -nonewline "\xe7" + gets stdin; puts -nonewline "\xE7" gets stdin; puts -nonewline "\x89" - gets stdin; puts -nonewline "\xa6" + gets stdin; puts -nonewline "\xA6" } test1] set f [open "|[list [interpreter] $path(test1)]" r+] fileevent $f readable [namespace code { @@ -1533,7 +1539,7 @@ test io-12.7 {ReadChars: too many chars read [bc5b790099]} { test io-12.8 {ReadChars: multibyte chars split} { set f [open $path(test1) w] fconfigure $f -translation binary - puts -nonewline $f [string repeat a 9]\xc2\xa0 + puts -nonewline $f [string repeat a 9]\xC2\xA0 close $f set f [open $path(test1)] fconfigure $f -encoding utf-8 -buffersize 10 @@ -1541,28 +1547,32 @@ test io-12.8 {ReadChars: multibyte chars split} { close $f scan [string index $in end] %c } 160 -test io-12.9 {ReadChars: multibyte chars split} { +test io-12.9 {ReadChars: multibyte chars split} -body { set f [open $path(test1) w] fconfigure $f -translation binary - puts -nonewline $f [string repeat a 9]\xc2 + puts -nonewline $f [string repeat a 9]\xC2 close $f set f [open $path(test1)] fconfigure $f -encoding utf-8 -buffersize 10 set in [read $f] close $f scan [string index $in end] %c -} 194 -test io-12.10 {ReadChars: multibyte chars split} { +} -cleanup { + catch {close $f} +} -result 194 +test io-12.10 {ReadChars: multibyte chars split} -body { set f [open $path(test1) w] fconfigure $f -translation binary - puts -nonewline $f [string repeat a 9]\xc2 + puts -nonewline $f [string repeat a 9]\xC2 close $f set f [open $path(test1)] fconfigure $f -encoding utf-8 -buffersize 11 set in [read $f] close $f scan [string index $in end] %c -} 194 +} -cleanup { + catch {close $f} +} -result 194 test io-13.1 {TranslateInputEOL: cr mode} {} { set f [open $path(test1) w] @@ -1741,7 +1751,7 @@ test io-13.10 {TranslateInputEOL: auto mode: \n} { set x } "abcd\ndef" test io-13.11 {TranslateInputEOL: EOF char} { - # (*chanPtr->inEofChar != '\0') + # (*chanPtr->inEofChar != '\x00') set f [open $path(test1) w] fconfigure $f -translation lf @@ -1754,7 +1764,7 @@ test io-13.11 {TranslateInputEOL: EOF char} { set x } "abcd\nd" test io-13.12 {TranslateInputEOL: find EOF char in src} { - # (*chanPtr->inEofChar != '\0') + # (*chanPtr->inEofChar != '\x00') set f [open $path(test1) w] fconfigure $f -translation lf @@ -2355,9 +2365,9 @@ test io-28.3 {CloseChannel, not called before output queue is empty} \ set result ok } } ok -test io-28.4 {Tcl_Close} {testchannel} { +test io-28.4 Tcl_Close testchannel { file delete $path(test1) - set l "" + set l {} lappend l [lsort [testchannel open]] set f [open $path(test1) w] lappend l [lsort [testchannel open]] @@ -3304,7 +3314,7 @@ test io-30.16 {Tcl_Write ^Z at end, Tcl_Read auto} { puts -nonewline $f hello\nthere\nand\rhere\n\x1A close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set c [read $f] close $f set c @@ -3316,11 +3326,11 @@ here test io-30.17 {Tcl_Write, implicit ^Z at end, Tcl_Read auto} {win} { file delete $path(test1) set f [open $path(test1) w] - fconfigure $f -eofchar \x1A -translation lf + fconfigure $f -translation lf -eofchar \x1A puts $f hello\nthere\nand\rhere close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set c [read $f] close $f set c @@ -3337,7 +3347,7 @@ test io-30.18 {Tcl_Write, ^Z in middle, Tcl_Read auto} { puts $f $s close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -3357,7 +3367,7 @@ test io-30.19 {Tcl_Write, ^Z no newline in middle, Tcl_Read auto} { puts $f $s close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -3838,7 +3848,7 @@ test io-31.18 {Tcl_Write ^Z at end, Tcl_Gets auto} { puts $f $s close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -3853,11 +3863,11 @@ test io-31.18 {Tcl_Write ^Z at end, Tcl_Gets auto} { test io-31.19 {Tcl_Write, implicit ^Z at end, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] - fconfigure $f -eofchar \x1A -translation lf + fconfigure $f -translation lf -eofchar \x1A puts $f hello\nthere\nand\rhere close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -3877,8 +3887,7 @@ test io-31.20 {Tcl_Write, ^Z in middle, Tcl_Gets auto, eofChar} { puts $f $s close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A - fconfigure $f -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -3896,7 +3905,7 @@ test io-31.21 {Tcl_Write, no newline ^Z in middle, Tcl_Gets auto, eofChar} { puts $f $s close $f set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A set l "" lappend l [gets $f] lappend l [gets $f] @@ -5413,9 +5422,6 @@ test io-39.1 {Tcl_GetChannelOption} { close $f1 set x } 1 -# -# Test 17.2 was removed. -# test io-39.2 {Tcl_GetChannelOption} { file delete $path(test1) set f1 [open $path(test1) w] @@ -5581,7 +5587,7 @@ test io-39.14 {Tcl_SetChannelOption: -encoding, binary & utf-8} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -encoding {} - puts -nonewline $f \xe7\x89\xa6 + puts -nonewline $f \xE7\x89\xA6 close $f set f [open $path(test1) r] fconfigure $f -encoding utf-8 @@ -5593,7 +5599,7 @@ test io-39.15 {Tcl_SetChannelOption: -encoding, binary & utf-8} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -encoding binary - puts -nonewline $f \xe7\x89\xa6 + puts -nonewline $f \xE7\x89\xA6 close $f set f [open $path(test1) r] fconfigure $f -encoding utf-8 @@ -5611,7 +5617,7 @@ test io-39.16 {Tcl_SetChannelOption: -encoding, errors} { test io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_DATA} {stdio fileevent} { set f [open "|[list [interpreter] $path(cat)]" r+] fconfigure $f -encoding binary - puts -nonewline $f "\xe7" + puts -nonewline $f "\xE7" flush $f fconfigure $f -encoding utf-8 -blocking 0 variable x {} @@ -5629,7 +5635,7 @@ test io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_DATA} vwait [namespace which -variable x] close $f set x -} "{} timeout {} timeout \xe7 timeout" +} "{} timeout {} timeout \xE7 timeout" test io-39.18 {Tcl_SetChannelOption, setting read mode independently} \ {socket} { proc accept {s a p} {close $s} @@ -5757,8 +5763,8 @@ test io-40.3 {POSIX open access modes: CREAT} {unix umask} { set f [open $path(test3) {WRONLY CREAT}] close $f file stat $path(test3) stats - format "0o%03o" [expr {$stats(mode)&0o777}] -} [format "0o%03o" [expr {0o666 & ~ $umaskValue}]] + format 0o%03o [expr {$stats(mode)&0o777}] +} [format 0o%03o [expr {0o666 & ~ $umaskValue}]] test io-40.4 {POSIX open access modes: CREAT} { file delete $path(test3) set f [open $path(test3) w] @@ -5932,11 +5938,11 @@ test io-42.2 {Tcl_FileeventCmd: replacing} {fileevent} { } {{first script} {new script} {yet another} {}} test io-42.3 {Tcl_FileeventCmd: replacing, with NULL chars in script} {fileevent} { set result {} - fileevent $f r "first scr\0ipt" + fileevent $f r "first scr\x00ipt" lappend result [string length [fileevent $f readable]] - fileevent $f r "new scr\0ipt" + fileevent $f r "new scr\x00ipt" lappend result [string length [fileevent $f readable]] - fileevent $f r "yet ano\0ther" + fileevent $f r "yet ano\x00ther" lappend result [string length [fileevent $f readable]] fileevent $f r "" lappend result [fileevent $f readable] @@ -6429,7 +6435,7 @@ test io-48.5 {lf write, testing readability, ^Z in middle, auto read mode} {file set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -6485,7 +6491,7 @@ test io-48.7 {cr write, testing readability, ^Z in middle, auto read mode} {file set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -6541,7 +6547,7 @@ test io-48.9 {crlf write, testing readability, ^Z in middle, auto read mode} {fi set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation auto + fconfigure $f -translation auto -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -6569,7 +6575,7 @@ test io-48.10 {lf write, testing readability, ^Z in middle, lf read mode} {filee set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation lf + fconfigure $f -translation lf -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -6625,7 +6631,7 @@ test io-48.12 {cr write, testing readability, ^Z in middle, cr read mode} {filee set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation cr + fconfigure $f -translation cr -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -6681,7 +6687,7 @@ test io-48.14 {crlf write, testing readability, ^Z in middle, crlf read mode} {f set c 0 set l "" set f [open $path(test1) r] - fconfigure $f -eofchar \x1A -translation crlf + fconfigure $f -translation crlf -eofchar \x1A fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] @@ -8428,7 +8434,7 @@ test io-60.1 {writing illegal utf sequences} {fileevent testbytestring} { set out [open $path(script) w] puts $out "catch {load $::tcltestlib Tcltest}" puts $out { - puts [testbytestring \xe2] + puts [testbytestring \xE2] exit 1 } proc readit {pipe} { @@ -8786,7 +8792,7 @@ test io-73.5 {effect of eof on encoding end flags} -setup { read $rfd } -body { set result [eof $rfd] - puts -nonewline $wfd "more\u00c2\u00a0data" + puts -nonewline $wfd "more\u00C2\u00A0data" lappend result [eof $rfd] lappend result [read $rfd] lappend result [eof $rfd] @@ -8794,7 +8800,7 @@ test io-73.5 {effect of eof on encoding end flags} -setup { close $wfd close $rfd removeFile io-73.5 -} -result [list 1 1 more\u00a0data 1] +} -result [list 1 1 more\u00A0data 1] test io-74.1 {[104f2885bb] improper cache validity check} -setup { set fn [makeFile {} io-74.1] @@ -8832,7 +8838,7 @@ test io-75.1 {multibyte encoding error read results in raw bytes} -setup { } -cleanup { close $f removeFile io-75.1 -} -returnCodes ok -result "A\xC0\x40" +} -result "A\xC0\x40" # for TCL 9.0, the result is error test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { @@ -8847,7 +8853,7 @@ test io-75.2 {unrepresentable character write passes and is replaced by ?} -setu } -cleanup { close $f removeFile io-75.2 -} -returnCodes ok -result "A?" +} -result "A?" # Incomplete sequence test. # This error may IMHO only be detected with the close. @@ -8866,7 +8872,7 @@ test io-75.3 {incomplete multibyte encoding read is ignored} -setup { set d } -cleanup { removeFile io-75.3 -} -returnCodes ok -result "A\xC0" +} -result "A\xC0" # ### ### ### ######### ######### ######### -- cgit v0.12 From 7ddf89897fec5a06a8df45f510984b16e93aa117 Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 12 Sep 2022 11:56:00 +0000 Subject: Ticket [6978c01b65]: as utf-8 is "special", also add invalid/incomplete sequence test cases for shiftjis. --- tests/io.test | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/tests/io.test b/tests/io.test index 4b7a61e..edadfed 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8820,7 +8820,7 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { removeFile io-74.1 } -returnCodes error -match glob -result {can not find channel named "*"} -# The following tests 75.1 to 75.3 exercice strict or tolerant channel +# The following tests 75.1 to 75.5 exercise strict or tolerant channel # encoding. # TCL 8.6 only offers tolerant channel encoding, what is tested here. test io-75.1 {multibyte encoding error read results in raw bytes} -setup { @@ -8834,12 +8834,13 @@ test io-75.1 {multibyte encoding error read results in raw bytes} -setup { seek $f 0 fconfigure $f -encoding utf-8 -buffering none } -body { - read $f + set d [read $f] + binary scan $d H* hd + set hd } -cleanup { close $f removeFile io-75.1 -} -result "A\xC0\x40" -# for TCL 9.0, the result is error +} -result "41c040" test io-75.2 {unrepresentable character write passes and is replaced by ?} -setup { set fn [makeFile {} io-75.2] @@ -8869,10 +8870,51 @@ test io-75.3 {incomplete multibyte encoding read is ignored} -setup { } -body { set d [read $f] close $f - set d + binary scan $d H* hd + set hd } -cleanup { removeFile io-75.3 -} -result "A\xC0" +} -result "41c0" + +# As utf-8 has a special treatment in multi-byte decoding, also test another +# one. +test io-75.4 {shiftjis encoding error read results in raw bytes} -setup { + set fn [makeFile {} io-75.4] + set f [open $fn w+] + fconfigure $f -encoding binary + # In shiftjis, \x81 starts a two-byte sequence. + # But 2nd byte \xFF is not allowed + puts -nonewline $f "A\x81\xFFA" + flush $f + seek $f 0 + fconfigure $f -encoding shiftjis -buffering none -eofchar "" -translation lf +} -body { + set d [read $f] + binary scan $d H* hd + set hd +} -cleanup { + close $f + removeFile io-75.4 +} -result "4181ff41" + +test io-75.5 {incomplete shiftjis encoding read is ignored} -setup { + set fn [makeFile {} io-75.5] + set f [open $fn w+] + fconfigure $f -encoding binary + # \x81 announces a two byte sequence. + puts -nonewline $f "A\x81" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf +} -body { + set d [read $f] + close $f + binary scan $d H* hd + set hd +} -cleanup { + removeFile io-75.5 +} -result "4181" + # ### ### ### ######### ######### ######### -- cgit v0.12 From f18eb707ea105404984b5741a6ff4f5953e5eeb6 Mon Sep 17 00:00:00 2001 From: kjnash Date: Mon, 12 Sep 2022 13:22:14 +0000 Subject: Record HTTP request line and request headers for debugging purposes. --- library/http/http.tcl | 61 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index 551b323..ba9d920 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -1008,6 +1008,8 @@ proc http::CreateToken {url args} { http "" connection keep-alive tid {} + requestHeaders {} + requestLine {} } set state(-keepalive) $defaultKeepalive set state(-strict) $strict @@ -1096,6 +1098,9 @@ proc http::CreateToken {url args} { # Note that the RE actually combines the user and password parts, as # recommended in RFC 3986. Indeed, that RFC states that putting passwords # in URLs is a Really Bad Idea, something with which I would agree utterly. + # RFC 9110 Sec 4.2.4 goes further than this, and deprecates the format + # "user:password@". It is retained here for backward compatibility, + # but its use is not recommended. # # From a validation perspective, we need to ensure that the parts of the # URL that are going to the server are correctly encoded. This is only @@ -1975,6 +1980,30 @@ proc http::ScheduleRequest {token} { } +# ------------------------------------------------------------------------------ +# Proc http::SendHeader +# ------------------------------------------------------------------------------ +# Command to send a request header, and keep a copy in state(requestHeaders) +# for debugging purposes. +# +# Arguments: +# token - connection token (name of an array) +# key - header name +# value - header value +# +# Return Value: none +# ------------------------------------------------------------------------------ + +proc http::SendHeader {token key value} { + variable $token + upvar 0 $token state + set tk [namespace tail $token] + set sock $state(sock) + lappend state(requestHeaders) [string tolower $key] $value + puts $sock "$key: $value" + return +} + # http::Connected -- # # Callback used when the connection to the HTTP server is actually @@ -2059,29 +2088,31 @@ proc http::Connected {token proto phost srvurl} { if {[catch { set state(method) $how - puts $sock "$how $srvurl HTTP/$state(-protocol)" + set state(requestHeaders) {} + set state(requestLine) "$how $srvurl HTTP/$state(-protocol)" + puts $sock $state(requestLine) set hostValue [GetFieldValue $state(-headers) Host] if {$hostValue ne {}} { # Allow Host spoofing. [Bug 928154] regexp {^[^:]+} $hostValue state(host) - puts $sock "Host: $hostValue" + SendHeader $token Host $hostValue } elseif {$port == $defport} { # Don't add port in this case, to handle broken servers. [Bug # #504508] set state(host) $host - puts $sock "Host: $host" + SendHeader $token Host $host } else { set state(host) $host - puts $sock "Host: $host:$port" + SendHeader $token Host "$host:$port" } - puts $sock "User-Agent: $http(-useragent)" + SendHeader $token User-Agent $http(-useragent) if {($state(-protocol) > 1.0) && $state(-keepalive)} { # Send this header, because a 1.1 server is not compelled to treat # this as the default. - puts $sock "Connection: keep-alive" + SendHeader $token Connection keep-alive } if {($state(-protocol) > 1.0) && !$state(-keepalive)} { - puts $sock "Connection: close" ;# RFC2616 sec 8.1.2.1 + SendHeader $token Connection close ;# RFC2616 sec 8.1.2.1 } if {($state(-protocol) < 1.1)} { # RFC7230 A.1 @@ -2090,7 +2121,7 @@ proc http::Connected {token proto phost srvurl} { # Don't leave this to chance. # For HTTP/1.0 we have already "set state(connection) close" # and "state(-keepalive) 0". - puts $sock "Connection: close" + SendHeader $token Connection close } # RFC7230 A.1 - "clients are encouraged not to send the # Proxy-Connection header field in any requests" @@ -2116,21 +2147,21 @@ proc http::Connected {token proto phost srvurl} { set state(querylength) $value } if {[string length $key]} { - puts $sock "$key: $value" + SendHeader $token $key $value } } # Allow overriding the Accept header on a per-connection basis. Useful # for working with REST services. [Bug c11a51c482] if {!$accept_types_seen} { - puts $sock "Accept: $state(accept-types)" + SendHeader $token Accept $state(accept-types) } if { (!$accept_encoding_seen) && (![info exists state(-handler)]) && $http(-zip) } { - puts $sock "Accept-Encoding: gzip,deflate" + SendHeader $token Accept-Encoding gzip,deflate } elseif {!$accept_encoding_seen} { - puts $sock "Accept-Encoding: identity" + SendHeader $token Accept-Encoding identity } else { } if {$isQueryChannel && ($state(querylength) == 0)} { @@ -2156,7 +2187,7 @@ proc http::Connected {token proto phost srvurl} { set separator "; " } if {$cookies ne ""} { - puts $sock "Cookie: $cookies" + SendHeader $token Cookie $cookies } } @@ -2180,10 +2211,10 @@ proc http::Connected {token proto phost srvurl} { if {$isQuery || $isQueryChannel} { # POST method. if {!$content_type_seen} { - puts $sock "Content-Type: $state(-type)" + SendHeader $token Content-Type $state(-type) } if {!$contDone} { - puts $sock "Content-Length: $state(querylength)" + SendHeader $token Content-Length $state(querylength) } puts $sock "" flush $sock -- cgit v0.12 From accc6b2ae999a22f2993b26e6a980a0f9a8fe0c2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 12 Sep 2022 14:28:58 +0000 Subject: (adapted) Testcase and fix for [1073daf086]: Bug in handling illegal utf-8 sequence --- generic/tclIO.c | 19 ++++++++----------- tests/io.test | 4 ++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 6b7ccdf..d228d50 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4278,6 +4278,7 @@ Write( char *nextNewLine = NULL; int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0; char safe[BUFFER_PADDING]; + int encodingError = 0; if (srcLen) { WillWrite(chanPtr); @@ -4294,7 +4295,7 @@ Write( nextNewLine = (char *)memchr(src, '\n', srcLen); } - while (srcLen + saved + endEncoding > 0) { + while (srcLen + saved + endEncoding > 0 && !encodingError) { ChannelBuffer *bufPtr; char *dst; int result, srcRead, dstLen, dstWrote, srcLimit = srcLen; @@ -4335,16 +4336,8 @@ Write( statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; if ((result != TCL_OK) && (srcRead + dstWrote == 0)) { - /* - * We're reading from invalid/incomplete UTF-8. - */ - - ReleaseChannelBuffer(bufPtr); - if (total == 0) { - Tcl_SetErrno(EINVAL); - return -1; - } - break; + encodingError = 1; + result = TCL_OK; } bufPtr->nextAdded += dstWrote; @@ -4442,6 +4435,10 @@ Write( } } + if (encodingError) { + Tcl_SetErrno(EINVAL); + return -1; + } return total; } diff --git a/tests/io.test b/tests/io.test index edadfed..94d8764 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8434,7 +8434,7 @@ test io-60.1 {writing illegal utf sequences} {fileevent testbytestring} { set out [open $path(script) w] puts $out "catch {load $::tcltestlib Tcltest}" puts $out { - puts [testbytestring \xE2] + puts ABC[testbytestring \xE2] exit 1 } proc readit {pipe} { @@ -8458,7 +8458,7 @@ test io-60.1 {writing illegal utf sequences} {fileevent testbytestring} { # cut of the remainder of the error stack, especially the filename set result [lreplace $result 3 3 [lindex [split [lindex $result 3] \n] 0]] list $x $result -} {1 {gets {} catch {error writing "stdout": invalid argument}}} +} {1 {gets ABC catch {error writing "stdout": invalid argument}}} test io-61.1 {Reset eof state after changing the eof char} -setup { set datafile [makeFile {} eofchar] -- cgit v0.12 From a194e805e604396e9ad9a39a4e7c569334b2d35c Mon Sep 17 00:00:00 2001 From: kjnash Date: Mon, 12 Sep 2022 17:12:12 +0000 Subject: Add new commands http::requestLine, requestHeaders, requestHeaderValue. Add aliases http::responseBody -> http::data, responseLine -> code, responseCode -> ncode, responseHeaders -> meta, responseHeaderValue -> metaValue. --- doc/http.n | 124 +++++++++++++++++++++++++++++++++++++++++++------- library/http/http.tcl | 53 ++++++++++++++++----- 2 files changed, 148 insertions(+), 29 deletions(-) diff --git a/doc/http.n b/doc/http.n index e61f52f..5a7009e 100644 --- a/doc/http.n +++ b/doc/http.n @@ -32,17 +32,23 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::size \fItoken\fR .sp -\fB::http::code \fItoken\fR +\fB::http::responseLine\fR \fItoken\fR .sp -\fB::http::ncode \fItoken\fR +\fB::http::responseCode\fR \fItoken\fR .sp \fB::http::reason \fIcode\fR .sp -\fB::http::meta \fItoken\fR ?\fIheaderName\fR? +\fB::http::requestLine\fR \fItoken\fR .sp -\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR +\fB::http::requestHeaders\fR \fItoken\fR ?\fIheaderName\fR? .sp -\fB::http::data \fItoken\fR +\fB::http::requestHeaderValue\fR \fItoken\fR \fIheaderName\fR +.sp +\fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? +.sp +\fB::http::responseHeaderValue\fR \fItoken\fR \fIheaderName\fR +.sp +\fB::http::responseBody\fR \fItoken\fR .sp \fB::http::error \fItoken\fR .sp @@ -53,6 +59,16 @@ http \- Client-side implementation of the HTTP/1.1 protocol \fB::http::registerError \fIport\fR ?\fImessage\fR? .sp \fB::http::unregister \fIproto\fR +.sp +\fB::http::code \fItoken\fR +.sp +\fB::http::data \fItoken\fR +.sp +\fB::http::meta \fItoken\fR ?\fIheaderName\fR? +.sp +\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR +.sp +\fB::http::ncode \fItoken\fR .SH "EXPORTED COMMANDS" .PP Namespace \fBhttp\fR exports the commands \fBconfig\fR, \fBformatQuery\fR, @@ -493,10 +509,18 @@ because in this case the \fB::http::geturl\fR call does not return until the HTTP transaction is complete, and thus there is nothing to wait for. .TP -\fB::http::data\fR \fItoken\fR +\fB::http::responseBody\fR \fItoken\fR . -This is a convenience procedure that returns the \fBbody\fR element -(i.e., the URL data) of the state array. +This command returns the entity sent by the HTTP server (unless +\fI-channel\fR was used, in which case the entity was delivered to the +channel, and the command returns the empty string). +.RS +.PP +Other terms for +"entity", with varying precision, include "representation of resource", +"resource", "response body after decoding", "payload", +"message body after decoding", "content", and "file". +.RE .TP \fB::http::error\fR \fItoken\fR . @@ -508,7 +532,7 @@ of the state array. This is a convenience procedure that returns the \fBstatus\fR element of the state array. .TP -\fB::http::code\fR \fItoken\fR +\fB::http::responseLine\fR \fItoken\fR . This command returns the "status line" of the server response (which is stored as element \fBhttp\fR of the state array). @@ -523,18 +547,27 @@ HTTP/1.1 200 OK HTTP/1.0 404 Not Found .RE .DE -.PP .RS -The "reason phrase" for a given status code may vary from server to server, +The "status code" is a three-digit number in the range 100 to 599. +A value of 200 is the normal return from a GET request, and its matching +"reason phrase" is "OK". Codes beginning with 4 or 5 indicate errors. +Codes beginning with 3 are redirection errors. In this case the +\fBLocation\fR response header specifies a new URL that contains the +requested information. +.PP +The "reason phrase" is a textual description of the "status code": it may +vary from server to server, and can be changed without affecting the HTTP protocol. The recommended values (RFC 7231 and IANA assignments) for each code are provided by the command \fB::http::reason\fR. .RE .TP -\fB::http::ncode\fR \fItoken\fR +\fB::http::responseCode\fR \fItoken\fR . -This command returns the "status code" (200, 404, etc.) of the server response. -The full status line can be obtained with command \fB::http::code\fR. +This command returns the "status code" (200, 404, etc.) of the server +"status line". If a three-digit code cannot be found, the full status +line is returned. See command \fB::http::code\fR for more information +on the "status line". .TP \fB::http::reason\fR \fIcode\fR . @@ -563,7 +596,44 @@ This is a convenience procedure that returns the \fBcurrentsize\fR element of the state array, which represents the number of bytes received from the URL in the \fB::http::geturl\fR call. .TP -\fB::http::meta\fR \fItoken\fR ?\fIheaderName\fR? +\fB::http::requestLine\fR \fItoken\fR +. +This command returns the "request line" sent to the server. +The "request line" is the first line of a HTTP client request, and has three +elements separated by spaces: the HTTP method, the URL relative to the server, +and the HTTP version. Examples: +.PP +.DS +.RS +GET / HTTP/1.1 +GET /introduction.html?subject=plumbing HTTP/1.1 +POST /forms/order.html HTTP/1.1 +.RE +.DE +.TP +\fB::http::requestHeaders\fR \fItoken\fR ?\fIheaderName\fR? +. +This command returns a list of the HTTP request header names and values, in the +order that they were sent to the server: a Tcl list of the form +?name value ...? Header names are case-insensitive and are converted to lower +case. The return value is not a \fBdict\fR because some header names may occur +more than once. If one argument is supplied, all request headers +are returned: the value is that of the \fBrequestHeaders\fR element +of the state array (described below). If two arguments are supplied, the +second provides the value of a header name. Only headers with the requested +name (converted to lower case) are returned. If no such headers are found, +an empty list is returned. +.TP +\fB::http::requestHeaderValue\fR \fItoken\fR \fIheaderName\fR +. +This command returns the value of the HTTP request header named +\fIheaderName\fR. Header names are case-insensitive and are converted to +lower case. If no such header exists, the return value is the empty string. +If there are multiple headers named \fIheaderName\fR, the result is obtained +by joining the individual values with the string ", " (comma and space), +preserving their order. +.TP +\fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? . This command returns a list of HTTP response header names and values, in the order that they were received from the server: a Tcl list of the form @@ -576,7 +646,7 @@ second provides the value of a header name. Only headers with the requested name (converted to lower case) are returned. If no such headers are found, an empty list is returned. .TP -\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR +\fB::http::responseHeaderValue\fR \fItoken\fR \fIheaderName\fR . This command returns the value of the HTTP response header named \fIheaderName\fR. Header names are case-insensitive and are converted to @@ -587,7 +657,7 @@ preserving their order. Multiple headers with the same name may be processed in this manner, except \fIset-cookie\fR which does not conform to the comma-separated-list syntax and cannot be combined into a single value. Each \fIset-cookie\fR header must be treated individually, e.g. by processing -the return value of \fB::http::meta\fR \fIset-cookie\fR. +the return value of \fB::http::responseHeaders\fR \fItoken\fR \fIset-cookie\fR. .TP \fB::http::cleanup\fR \fItoken\fR . @@ -635,6 +705,26 @@ registered via \fB::http::register\fR, returning a two-item list of the default port and handler command that was previously installed (via \fB::http::register\fR) if there was such a handler, and an error if there was no such handler. +.TP +\fB::http::code\fR \fItoken\fR +. +An alternative name for the command \fB::http::responseLine\fR +.TP +\fB::http::data\fR \fItoken\fR +. +An alternative name for the command \fB::http::responseBody\fR. +.TP +\fB::http::meta\fR \fItoken\fR ?\fIheaderName\fR? +. +An alternative name for the command \fB::http::responseHeaders\fR +.TP +\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR +. +An alternative name for the command \fB::http::responseHeaderValue\fR +.TP +\fB::http::ncode\fR \fItoken\fR +. +An alternative name for the command \fB::http::responseCode\fR .SH ERRORS The \fB::http::geturl\fR procedure will raise errors in the following cases: invalid command line options, diff --git a/library/http/http.tcl b/library/http/http.tcl index ba9d920..359666d 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -2966,7 +2966,7 @@ proc http::ReplayCore {newQueue} { # Code - the HTTP transaction code, e.g., 200 # Size - the size of the URL data -proc http::data {token} { +proc http::responseBody {token} { variable $token upvar 0 $token state return $state(body) @@ -2979,12 +2979,17 @@ proc http::status {token} { upvar 0 $token state return $state(status) } -proc http::code {token} { +proc http::responseLine {token} { variable $token upvar 0 $token state return $state(http) } -proc http::ncode {token} { +proc http::requestLine {token} { + variable $token + upvar 0 $token state + return $state(requestLine) +} +proc http::responseCode {token} { variable $token upvar 0 $token state if {[regexp {[0-9]{3}} $state(http) numeric_code]} { @@ -2998,32 +3003,51 @@ proc http::size {token} { upvar 0 $token state return $state(currentsize) } -proc http::meta {token args} { +proc http::requestHeaders {token args} { + set lenny [llength $args] + if {$lenny > 1} { + return -code error {usage: ::http::requestHeaders token ?headerName?} + } else { + return [Meta $token request {*}$args] + } +} +proc http::responseHeaders {token args} { set lenny [llength $args] if {$lenny > 1} { - return -code error {usage: ::http::meta token ?headerName?} + return -code error {usage: ::http::responseHeaders token ?headerName?} } else { - return [Meta $token {*}$args] + return [Meta $token response {*}$args] } } -proc http::metaValue {token header} { - Meta $token $header VALUE +proc http::requestHeaderValue {token header} { + Meta $token request $header VALUE +} +proc http::responseHeaderValue {token header} { + Meta $token response $header VALUE } -proc http::Meta {token args} { +proc http::Meta {token who args} { variable $token upvar 0 $token state + if {$who eq {request}} { + set whom requestHeaders + } elseif {$who eq {response}} { + set whom meta + } else { + return -code error {usage: ::http::Meta token request|response ?headerName ?VALUE??} + } + set header [string tolower [lindex $args 0]] set how [string tolower [lindex $args 1]] set lenny [llength $args] if {$lenny == 0} { - return $state(meta) + return $state($whom) } elseif {($lenny > 2) || (($lenny == 2) && ($how ne {value}))} { - return -code error {usage: ::http::Meta token ?headerName ?VALUE??} + return -code error {usage: ::http::Meta token request|response ?headerName ?VALUE??} } else { set result {} set combined {} - foreach {key value} $state(meta) { + foreach {key value} $state($whom) { if {$key eq $header} { lappend result $key $value append combined $value {, } @@ -4582,6 +4606,11 @@ proc http::make-transformation-chunked {chan command} { return } +interp alias {} http::data {} http::responseBody +interp alias {} http::code {} http::responseLine +interp alias {} http::meta {} http::responseHeaders +interp alias {} http::metaValue {} http::responseHeaderValue +interp alias {} http::ncode {} http::responseCode # ------------------------------------------------------------------------------ # Proc http::socket -- cgit v0.12 From 83b951fbc6b973b4d850c1293cd82559a9c96228 Mon Sep 17 00:00:00 2001 From: kjnash Date: Mon, 12 Sep 2022 17:33:50 +0000 Subject: Rearrange groups of lines in http.n without other changes to content. --- doc/http.n | 148 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/doc/http.n b/doc/http.n index 5a7009e..dcd65ae 100644 --- a/doc/http.n +++ b/doc/http.n @@ -32,11 +32,9 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::size \fItoken\fR .sp -\fB::http::responseLine\fR \fItoken\fR -.sp -\fB::http::responseCode\fR \fItoken\fR +\fB::http::error \fItoken\fR .sp -\fB::http::reason \fIcode\fR +\fB::http::cleanup \fItoken\fR .sp \fB::http::requestLine\fR \fItoken\fR .sp @@ -44,16 +42,18 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::requestHeaderValue\fR \fItoken\fR \fIheaderName\fR .sp +\fB::http::responseLine\fR \fItoken\fR +.sp +\fB::http::responseCode\fR \fItoken\fR +.sp +\fB::http::reason \fIcode\fR +.sp \fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? .sp \fB::http::responseHeaderValue\fR \fItoken\fR \fIheaderName\fR .sp \fB::http::responseBody\fR \fItoken\fR .sp -\fB::http::error \fItoken\fR -.sp -\fB::http::cleanup \fItoken\fR -.sp \fB::http::register \fIproto port command\fR .sp \fB::http::registerError \fIport\fR ?\fImessage\fR? @@ -509,28 +509,69 @@ because in this case the \fB::http::geturl\fR call does not return until the HTTP transaction is complete, and thus there is nothing to wait for. .TP -\fB::http::responseBody\fR \fItoken\fR +\fB::http::status\fR \fItoken\fR . -This command returns the entity sent by the HTTP server (unless -\fI-channel\fR was used, in which case the entity was delivered to the -channel, and the command returns the empty string). -.RS -.PP -Other terms for -"entity", with varying precision, include "representation of resource", -"resource", "response body after decoding", "payload", -"message body after decoding", "content", and "file". -.RE +This is a convenience procedure that returns the \fBstatus\fR element of +the state array. +.TP +\fB::http::size\fR \fItoken\fR +. +This is a convenience procedure that returns the \fBcurrentsize\fR +element of the state array, which represents the number of bytes +received from the URL in the \fB::http::geturl\fR call. .TP \fB::http::error\fR \fItoken\fR . This is a convenience procedure that returns the \fBerror\fR element of the state array. .TP -\fB::http::status\fR \fItoken\fR +\fB::http::cleanup\fR \fItoken\fR . -This is a convenience procedure that returns the \fBstatus\fR element of -the state array. +This procedure cleans up the state associated with the connection +identified by \fItoken\fR. After this call, the procedures +like \fB::http::data\fR cannot be used to get information +about the operation. It is \fIstrongly\fR recommended that you call +this function after you are done with a given HTTP request. Not doing +so will result in memory not being freed, and if your app calls +\fB::http::geturl\fR enough times, the memory leak could cause a +performance hit...or worse. +.TP +\fB::http::requestLine\fR \fItoken\fR +. +This command returns the "request line" sent to the server. +The "request line" is the first line of a HTTP client request, and has three +elements separated by spaces: the HTTP method, the URL relative to the server, +and the HTTP version. Examples: +.PP +.DS +.RS +GET / HTTP/1.1 +GET /introduction.html?subject=plumbing HTTP/1.1 +POST /forms/order.html HTTP/1.1 +.RE +.DE +.TP +\fB::http::requestHeaders\fR \fItoken\fR ?\fIheaderName\fR? +. +This command returns a list of the HTTP request header names and values, in the +order that they were sent to the server: a Tcl list of the form +?name value ...? Header names are case-insensitive and are converted to lower +case. The return value is not a \fBdict\fR because some header names may occur +more than once. If one argument is supplied, all request headers +are returned: the value is that of the \fBrequestHeaders\fR element +of the state array (described below). If two arguments are supplied, the +second provides the value of a header name. Only headers with the requested +name (converted to lower case) are returned. If no such headers are found, +an empty list is returned. +.TP +\fB::http::requestHeaderValue\fR \fItoken\fR \fIheaderName\fR +. +This command returns the value of the HTTP request header named +\fIheaderName\fR. Header names are case-insensitive and are converted to +lower case. If no such header exists, the return value is the empty string. +If there are multiple headers named \fIheaderName\fR, the result is obtained +by joining the individual values with the string ", " (comma and space), +preserving their order. .TP \fB::http::responseLine\fR \fItoken\fR . @@ -590,49 +631,6 @@ A registry of valid status codes is maintained at https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml .RE .TP -\fB::http::size\fR \fItoken\fR -. -This is a convenience procedure that returns the \fBcurrentsize\fR -element of the state array, which represents the number of bytes -received from the URL in the \fB::http::geturl\fR call. -.TP -\fB::http::requestLine\fR \fItoken\fR -. -This command returns the "request line" sent to the server. -The "request line" is the first line of a HTTP client request, and has three -elements separated by spaces: the HTTP method, the URL relative to the server, -and the HTTP version. Examples: -.PP -.DS -.RS -GET / HTTP/1.1 -GET /introduction.html?subject=plumbing HTTP/1.1 -POST /forms/order.html HTTP/1.1 -.RE -.DE -.TP -\fB::http::requestHeaders\fR \fItoken\fR ?\fIheaderName\fR? -. -This command returns a list of the HTTP request header names and values, in the -order that they were sent to the server: a Tcl list of the form -?name value ...? Header names are case-insensitive and are converted to lower -case. The return value is not a \fBdict\fR because some header names may occur -more than once. If one argument is supplied, all request headers -are returned: the value is that of the \fBrequestHeaders\fR element -of the state array (described below). If two arguments are supplied, the -second provides the value of a header name. Only headers with the requested -name (converted to lower case) are returned. If no such headers are found, -an empty list is returned. -.TP -\fB::http::requestHeaderValue\fR \fItoken\fR \fIheaderName\fR -. -This command returns the value of the HTTP request header named -\fIheaderName\fR. Header names are case-insensitive and are converted to -lower case. If no such header exists, the return value is the empty string. -If there are multiple headers named \fIheaderName\fR, the result is obtained -by joining the individual values with the string ", " (comma and space), -preserving their order. -.TP \fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? . This command returns a list of HTTP response header names and values, in the @@ -659,16 +657,18 @@ comma-separated-list syntax and cannot be combined into a single value. Each \fIset-cookie\fR header must be treated individually, e.g. by processing the return value of \fB::http::responseHeaders\fR \fItoken\fR \fIset-cookie\fR. .TP -\fB::http::cleanup\fR \fItoken\fR +\fB::http::responseBody\fR \fItoken\fR . -This procedure cleans up the state associated with the connection -identified by \fItoken\fR. After this call, the procedures -like \fB::http::data\fR cannot be used to get information -about the operation. It is \fIstrongly\fR recommended that you call -this function after you are done with a given HTTP request. Not doing -so will result in memory not being freed, and if your app calls -\fB::http::geturl\fR enough times, the memory leak could cause a -performance hit...or worse. +This command returns the entity sent by the HTTP server (unless +\fI-channel\fR was used, in which case the entity was delivered to the +channel, and the command returns the empty string). +.RS +.PP +Other terms for +"entity", with varying precision, include "representation of resource", +"resource", "response body after decoding", "payload", +"message body after decoding", "content", and "file". +.RE .TP \fB::http::register\fR \fIproto port command\fR . -- cgit v0.12 From 55d9cca97fb558444ff53d71b4aef4ba99ef0274 Mon Sep 17 00:00:00 2001 From: kjnash Date: Tue, 13 Sep 2022 12:54:26 +0000 Subject: In namespace ::http, add new commands postError, responseInfo. Rename (the unreleased public API) reason to reasonPhrase. Rename private commands make-transformation-chunked to MakeTransformationChunked, getTextLine to GetTextLine. Rename mapReply to quoteString (and reverse the aliasing). Update namespace exports. Conventional use of fully-qualified command names. Initialise some members of state array. --- doc/http.n | 137 ++++++++++++++++++++++++++++++++++++++++-- library/http/http.tcl | 160 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 260 insertions(+), 37 deletions(-) diff --git a/doc/http.n b/doc/http.n index dcd65ae..8a9c35b 100644 --- a/doc/http.n +++ b/doc/http.n @@ -34,6 +34,8 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::error \fItoken\fR .sp +\fB::http::postError \fItoken\fR +.sp \fB::http::cleanup \fItoken\fR .sp \fB::http::requestLine\fR \fItoken\fR @@ -46,12 +48,14 @@ http \- Client-side implementation of the HTTP/1.1 protocol .sp \fB::http::responseCode\fR \fItoken\fR .sp -\fB::http::reason \fIcode\fR +\fB::http::reasonPhrase\fR \fIcode\fR .sp \fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? .sp \fB::http::responseHeaderValue\fR \fItoken\fR \fIheaderName\fR .sp +\fB::http::responseInfo\fR \fItoken\fR +.sp \fB::http::responseBody\fR \fItoken\fR .sp \fB::http::register \fIproto port command\fR @@ -72,11 +76,15 @@ http \- Client-side implementation of the HTTP/1.1 protocol .SH "EXPORTED COMMANDS" .PP Namespace \fBhttp\fR exports the commands \fBconfig\fR, \fBformatQuery\fR, -\fBgeturl\fR, \fBquoteString\fR, \fBregister\fR, \fBregisterError\fR, +\fBgeturl\fR, \fBpostError\fR, \fBquoteString\fR, \fBreasonPhrase\fR, +\fBregister\fR, +\fBregisterError\fR, \fBrequestHeaders\fR, \fBrequestHeaderValue\fR, +\fBrequestLine\fR, \fBresponseBody\fR, \fBresponseCode\fR, +\fBresponseHeaders\fR, \fBresponseHeaderValue\fR, \fBresponseInfo\fR, \fBresponseLine\fR, \fBreset\fR, \fBunregister\fR, and \fBwait\fR. .PP It does not export the commands \fBcleanup\fR, \fBcode\fR, \fBdata\fR, -\fBerror\fR, \fBmeta\fR, \fBmetaValue\fR, \fBncode\fR, \fBreason\fR, +\fBerror\fR, \fBmeta\fR, \fBmetaValue\fR, \fBncode\fR, \fBsize\fR, or \fBstatus\fR. .BE .SH DESCRIPTION @@ -525,6 +533,10 @@ received from the URL in the \fB::http::geturl\fR call. This is a convenience procedure that returns the \fBerror\fR element of the state array. .TP +\fB::http::postError\fR \fItoken\fR +. +A POST request is a call to \fB::http::geturl\fR with either the \fB\-query\fR or \fB\-querychannel\fR option. The \fB::http::postError\fR command returns the error string generated when a HTTP POST request sends its request-body to the server; or the empty string if there was no error. When this type of error occurs, the \fB::http::geturl\fR command continues the transaction and attempts to receive a response from the server. +.TP \fB::http::cleanup\fR \fItoken\fR . This procedure cleans up the state associated with the connection @@ -600,7 +612,7 @@ The "reason phrase" is a textual description of the "status code": it may vary from server to server, and can be changed without affecting the HTTP protocol. The recommended values (RFC 7231 and IANA assignments) for each code are provided by the -command \fB::http::reason\fR. +command \fB::http::reasonPhrase\fR. .RE .TP \fB::http::responseCode\fR \fItoken\fR @@ -610,7 +622,7 @@ This command returns the "status code" (200, 404, etc.) of the server line is returned. See command \fB::http::code\fR for more information on the "status line". .TP -\fB::http::reason\fR \fIcode\fR +\fB::http::reasonPhrase\fR \fIcode\fR . This command returns the IANA recommended "reason phrase" for a particular "status code" returned by a HTTP server. The argument \fIcode\fR is a valid @@ -657,6 +669,14 @@ comma-separated-list syntax and cannot be combined into a single value. Each \fIset-cookie\fR header must be treated individually, e.g. by processing the return value of \fB::http::responseHeaders\fR \fItoken\fR \fIset-cookie\fR. .TP +\fB::http::responseInfo\fR \fItoken\fR +. +This command returns a \fBdict\fR of selected response metadata that are essential for identifying a successful transaction and making use of the response, along with other metadata that are informational. The keys of the \fBdict\fR are \fIstage\fR, \fIstatus\fR, \fIncode\fR, \fIreason\fR, \fItype\fR, \fIbinary\fR, \fIredirection\fR, \fIcharset\fR, \fIcoding\fR, \fIhttpRequest\fR, \fIhttpResponse\fR, \fIurl\fR, \fIconnRequest\fR, \fIconnResponse\fR, \fIconnection\fR, \fItransfer\fR, \fItotalsize\fR, and \fIcurrentsize\fR. The meaning of these keys is described in the chapter \fBMETADATA\fR below. +.RS +.PP +It is always worth checking the value of \fIbinary\fR after a HTTP transaction, to determine whether a misconfigured server has caused http to interpret a text resource as a binary, or vice versa. +.RE +.TP \fB::http::responseBody\fR \fItoken\fR . This command returns the entity sent by the HTTP server (unless @@ -807,6 +827,113 @@ transaction. If it can read the server's response it will end up with an \fBok\fR status, otherwise it will have an \fBeof\fR status. +.SH "METADATA" +When a HTTP server responds to a request, it supplies not only the entity requested, but also metadata. This is provided by the first line (the "status line") of the response, and by a number of HTTP headers. Further metadata relates to how \fB::http::geturl\fR has processed the response from the server. +.PP +The most important metadata can be accessed with the command +\fB::http::responseInfo\fR. +This command returns a \fBdict\fR of metadata that are essential for identifying a successful transaction and making use of the response, along with other metadata that are informational. The keys of the \fBdict\fR are: +.RS +.RS +\fB===== Essential Values =====\fR +.RE +.RE +.TP +\fBstage\fR +. +This value, set by \fB::http::geturl\fR, describes the stage that the transaction has reached. Values, in order of the transaction lifecycle, are: "created", "connecting", "header", "body", and "complete". Other \fBdict\fR keys are available when the value of stage is "body" or "complete". The key \fBconnection\fR has its final value only when \fBstage\fR is "complete". +.TP +\fBstatus\fR +. +This value, set by \fB::http::geturl\fR, is "ok" for a successful transaction; "eof", "error", "timeout", or "reset" for an unsuccessful transaction; or "" if the transaction is still in progress. In the last case the values for other dictionary keys may not be available. The meaning of these values is described in the chapter \fBERRORS\fR (above). +.TP +\fBncode\fR +. +The "HTTP status code" for the response. +.TP +\fBreason\fR +. +The "reason phrase" sent by the server. +.TP +\fBcontent-type\fR +. +The value of the \fBContent-Type\fR response header or, if the header was not supplied, the default value "application/octet-stream". +.TP +\fBbinary\fR +. +This boolean value, set by \fB::http::geturl\fR, describes how the command has interpreted the entity returned by the server (after decoding any compression specified +by the +.QW "Content-Encoding" +response header). This decoded entity is accessible as the return value of the command \fB::http::responseBody\fR. + +The value is \fBtrue\fR if http has interpreted the decoded entity as binary. The value returned by ::http::responseBody is a Tcl binary string. This is a suitable format for image data, zip files, etc. +\fB::http::geturl\fR chooses this value if the user has requested a binary interpretation by passing the option \fI\-binary\fR to the command, or if the server has supplied a binary content type in a Content-Type response header, or if the server has not supplied any Content-Type header. + +The value is \fBfalse\fR if http has interpreted the decoded entity as text. The text has been converted from the character set notified by the server into Tcl's internal Unicode format, and the value returned by ::http::responseBody is an ordinary Tcl string. + +It is always worth checking the value of "binary" after a HTTP transaction, to determine whether a misconfigured server has caused http to interpret a text resource as a binary, or vice versa. +.TP +\fBredirection\fR +. +The URL that is the redirection target. The value is that of the Location response header. This header is sent when a response has status code 3XX (redirection). +.RS +.RS +\fB===== Informational Values =====\fR +.RE +.RE +.TP +\fBcharset\fR +. +The value of the charset attribute of the \fBContent-Type\fR response header. The charset value is used only for a text resource. If the server did not specify a charset, the value defaults to that of the variable \fB::http::defaultCharset\fR, which unless it has been deliberately modified by the caller is \fBiso8859-1\fR. Incoming text data is automatically converted from the character set defined by \fBcharset\fR to Tcl's internal Unicode representation, i.e. to a Tcl string. +.TP +\fBcoding\fR +. +A copy of the \fBContent-Encoding\fR response-header value. +.TP +\fBhttpRequest\fR +. +The version of HTTP specified in the request (i.e. sent in the request line). +.TP +\fBhttpResponse\fR +. +The version of HTTP used by the server (obtained from the response "status line"). The server uses this version of HTTP in its response, but ensures that this response is compatible with the HTTP version specified in the client's request. +.TP +\fBurl\fR +. +The requested URL, typically the URL supplied as an argument to \fB::http::geturl\fR but without its "fragment" (the final part of the URL beginning with "#". +.TP +\fBconnRequest\fR +. +The value, if any, sent to the server in "Connection" request header(s). +.TP +\fBconnResponse\fR +. +The value, if any, received from the server in "Connection" response header(s). +.TP +\fBconnection\fR +. +This value, set by \fB::http::geturl\fR, reports whether the connection was closed after the transaction (value "close"), or left open (value "keep-alive"). +.TP +\fBtransfer\fR +. +The value of the Transfer-Encoding response header, if it is present. The value is either "chunked" (indicating HTTP/1.1 "chunked encoding") or the empty string. +.TP +\fBquerylength\fR +. +The total length of the request body in a POST request. +.TP +\fBqueryoffset\fR +. +The number of bytes of the POST request body sent to the server so far. +.TP +\fBtotalsize\fR +. +A copy of the \fBContent-Length\fR response-header value. +The number of bytes specified in a Content-Length header, if one was sent. If none was sent, the value is 0. A correctly configured server omits this header if the transfer-encoding is "chunked", or (for older servers) if the server closes the connection when it reaches the end of the resource. +.TP +\fBcurrentsize\fR +. +The number of bytes fetched from the server so far. .SH "STATE ARRAY" The \fB::http::geturl\fR procedure returns a \fItoken\fR that can be used to get to the state of the HTTP transaction in the form of a Tcl array. diff --git a/library/http/http.tcl b/library/http/http.tcl index 359666d..15fd031 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -217,13 +217,22 @@ namespace eval http { 511 {Network Authentication Required} }] - namespace export geturl config reset wait formatQuery quoteString + namespace export geturl config reset wait formatQuery postError quoteString namespace export register unregister registerError - # - Useful, but not exported: data, size, status, code, cleanup, error, - # meta, ncode, mapReply, init. Comments suggest that "init" can be used - # for re-initialisation, although the command is undocumented. - # - Not exported, probably should be upper-case initial letter as part - # of the internals: getTextLine, make-transformation-chunked. + namespace export requestLine requestHeaders requestHeaderValue + namespace export responseLine responseHeaders responseHeaderValue + namespace export responseCode responseBody responseInfo reasonPhrase + # - Legacy aliases, were never exported: + # data, code, mapReply, meta, ncode + # - Callable from outside (e.g. from TLS) by fully-qualified name, but + # not exported: + # socket + # - Useful, but never exported (and likely to have naming collisions): + # size, status, cleanup, error, init + # Comments suggest that "init" can be used for re-initialisation, + # although the command is undocumented. + # - Never exported, renamed from lower-case names: + # GetTextLine, MakeTransformationChunked. } # http::Log -- @@ -318,7 +327,7 @@ proc http::config {args} { } # ------------------------------------------------------------------------------ -# Proc http::reason +# Proc http::reasonPhrase # ------------------------------------------------------------------------------ # Command to return the IANA-recommended "reason phrase" for a HTTP Status Code. # Information obtained from: @@ -330,7 +339,7 @@ proc http::config {args} { # Return Value: the reason phrase # ------------------------------------------------------------------------------ -proc http::reason {code} { +proc http::reasonPhrase {code} { variable reasonDict if {![regexp -- {^[1-5][0-9][0-9]$} $code]} { set msg {argument must be a three-digit integer from 100 to 599} @@ -1006,10 +1015,14 @@ proc http::CreateToken {url args} { body {} status "" http "" + httpResponse {} + ncode {} + reason {} connection keep-alive tid {} requestHeaders {} requestLine {} + transfer {} } set state(-keepalive) $defaultKeepalive set state(-strict) $strict @@ -2441,7 +2454,7 @@ proc http::EventGateway {sock token} { # http::reset or http::cleanup, or if the caller set option -channel # but not option -handler: in the last case reading from the socket is # now managed by commands ::http::Copy*, http::ReceiveChunked, and - # http::make-transformation-chunked. + # http::MakeTransformationChunked. # # Catch in case the coroutine has closed the socket. catch {fileevent $sock readable [list http::EventGateway $sock $token]} @@ -3061,6 +3074,61 @@ proc http::Meta {token who args} { } } + +# ------------------------------------------------------------------------------ +# Proc http::responseInfo +# ------------------------------------------------------------------------------ +# Command to return a dictionary of the most useful metadata of a HTTP +# response. +# +# Arguments: +# token - connection token (name of an array) +# +# Return Value: a dict +# ------------------------------------------------------------------------------ + +proc http::responseInfo {token} { + variable $token + upvar 0 $token state + set result {} + foreach key { + stage + status + ncode + reason + type + binary + redirection + charset + coding + httpRequest + httpResponse + url + connRequest + connResponse + connection + transfer + querylength + queryoffset + totalsize + currentsize + } { + if {$key eq {stage}} { + dict set result $key $state(state) + } elseif {$key eq {redirection}} { + dict set result $key [responseHeaderValue $token Location] + } elseif {$key eq {httpRequest}} { + dict set result $key $state(-protocol) + } elseif {$key eq {connRequest}} { + dict set result $key [requestHeaderValue $token connection] + } elseif {$key eq {connResponse}} { + dict set result $key [responseHeaderValue $token connection] + } else { + dict set result $key $state($key) + } + } + return $result +} proc http::error {token} { variable $token upvar 0 $token state @@ -3069,6 +3137,14 @@ proc http::error {token} { } return } +proc http::postError {token} { + variable $token + upvar 0 $token state + if {[info exists state(posterror)]} { + return $state(posterror) + } + return +} # http::cleanup # @@ -3382,6 +3458,19 @@ proc http::Event {sock token} { } else { } + # We have $state(http) so let's split it into its components. + if {[regexp {^HTTP/(\S+) ([0-9]{3}) (.*)$} $state(http) \ + -> httpResponse ncode reason] + } { + set state(httpResponse) $httpResponse + set state(ncode) $ncode + set state(reason) $reason + } else { + set state(httpResponse) $state(http) + set state(ncode) $state(http) + set state(reason) $state(http) + } + if { ([info exists state(connection)]) && ([info exists socketMapping($state(socketinfo))]) && ("keep-alive" in $state(connection)) @@ -3514,7 +3603,7 @@ proc http::Event {sock token} { && ("close" in $state(connection)) ) ) - && (![info exists state(transfer)]) + && ($state(transfer) eq {}) && ($state(totalsize) == 0) } { set msg {body size is 0 and no events likely - complete} @@ -3585,6 +3674,13 @@ proc http::Event {sock token} { connection { # RFC 7230 Section 6.1 states that a comma-separated # list is an acceptable value. + if {![info exists state(connectionResponse)]} { + # This is the first "Connection" response header. + # Scrub the earlier value set by iniitialisation. + set state(connectionResponse) {} + set state(connection) {} + } + set state(connOrig[incr ::countConn]) [string trim $value] foreach el [SplitCommaSeparatedFieldValue $value] { lappend state(connection) [string tolower $el] } @@ -3652,7 +3748,7 @@ proc http::Event {sock token} { } } elseif {[info exists state(transfer_final)]} { # This code forgives EOF in place of the final CRLF. - set line [getTextLine $sock] + set line [GetTextLine $sock] set n [string length $line] set state(state) complete if {$n > 0} { @@ -3675,7 +3771,7 @@ proc http::Event {sock token} { } { ##Log chunked - token $token set size 0 - set hexLenChunk [getTextLine $sock] + set hexLenChunk [GetTextLine $sock] #set ntl [string length $hexLenChunk] if {[string trim $hexLenChunk] ne ""} { scan $hexLenChunk %x size @@ -3705,7 +3801,7 @@ proc http::Event {sock token} { } # CRLF that follows chunk. # If eof, this is handled at the end of this proc. - getTextLine $sock + GetTextLine $sock } else { set n 0 set state(transfer_final) {} @@ -3986,7 +4082,7 @@ proc http::ParseCookie {token value} { {*}$http(-cookiejar) storeCookie $realopts } -# http::getTextLine -- +# http::GetTextLine -- # # Get one line with the stream in crlf mode. # Used if Transfer-Encoding is chunked, to read the line that @@ -4000,7 +4096,7 @@ proc http::ParseCookie {token value} { # Results: # The line of text, without trailing newline -proc http::getTextLine {sock} { +proc http::GetTextLine {sock} { set tr [fconfigure $sock -translation] lassign $tr trRead trWrite fconfigure $sock -translation [list crlf $trWrite] @@ -4076,7 +4172,7 @@ proc http::CopyStart {sock token {initial 1}} { } lappend state(zlib) [zlib stream $coding2] } - make-transformation-chunked $sock [namespace code [list CopyChunk $token]] + MakeTransformationChunked $sock [namespace code [list CopyChunk $token]] } else { if {$initial} { foreach coding [ContentEncoding $token] { @@ -4376,7 +4472,7 @@ proc http::formatQuery {args} { set result "" set sep "" foreach i $args { - append result $sep [mapReply $i] + append result $sep [quoteString $i] if {$sep eq "="} { set sep & } else { @@ -4386,7 +4482,7 @@ proc http::formatQuery {args} { return $result } -# http::mapReply -- +# http::quoteString -- # # Do x-www-urlencoded character mapping # @@ -4396,7 +4492,7 @@ proc http::formatQuery {args} { # Results: # The encoded string -proc http::mapReply {string} { +proc http::quoteString {string} { variable http variable formMap @@ -4407,7 +4503,6 @@ proc http::mapReply {string} { set string [encoding convertto $http(-urlencoding) $string] return [string map $formMap $string] } -interp alias {} http::quoteString {} http::mapReply # http::ProxyRequired -- # Default proxy filter. @@ -4600,7 +4695,7 @@ proc http::GetFieldValue {headers fieldName} { return $r } -proc http::make-transformation-chunked {chan command} { +proc http::MakeTransformationChunked {chan command} { coroutine [namespace current]::dechunk$chan ::http::ReceiveChunked $chan $command chan event $chan readable [namespace current]::dechunk$chan return @@ -4608,6 +4703,7 @@ proc http::make-transformation-chunked {chan command} { interp alias {} http::data {} http::responseBody interp alias {} http::code {} http::responseLine +interp alias {} http::mapReply {} http::quoteString interp alias {} http::meta {} http::responseHeaders interp alias {} http::metaValue {} http::responseHeaderValue interp alias {} http::ncode {} http::responseCode @@ -4660,7 +4756,7 @@ proc http::socket {args} { set defcmd ::socket set sockargs $args set script " - [list proc ::SockInThread {caller defcmd sockargs} [info body http::SockInThread]] + [list proc ::SockInThread {caller defcmd sockargs} [info body ::http::SockInThread]] [list ::SockInThread [thread::id] $defcmd $sockargs] " @@ -4750,7 +4846,7 @@ proc http::SockInThread {caller defcmd sockargs} { # ------------------------------------------------------------------------------ -# Proc ::http::cwaiter::cwait +# Proc http::cwaiter::cwait # ------------------------------------------------------------------------------ # Command to substitute for vwait, without the ordering issues. # A command that uses cwait must be a coroutine that is launched by an event, @@ -4769,13 +4865,13 @@ proc http::SockInThread {caller defcmd sockargs} { # Return Value: none # ------------------------------------------------------------------------------ -namespace eval ::http::cwaiter { +namespace eval http::cwaiter { namespace export cwait variable log {} variable logOn 0 } -proc ::http::cwaiter::cwait { +proc http::cwaiter::cwait { varName {coroName {}} {timeout {}} {timeoutValue {}} } { set thisCoro [info coroutine] @@ -4806,7 +4902,7 @@ proc ::http::cwaiter::cwait { # ------------------------------------------------------------------------------ -# Proc ::http::cwaiter::CwaitHelper +# Proc http::cwaiter::CwaitHelper # ------------------------------------------------------------------------------ # Helper command called by the trace set by cwait. # - Ignores the arguments added by trace. @@ -4817,7 +4913,7 @@ proc ::http::cwaiter::cwait { # - Remove the trace immediately. We don't want multiple calls. # ------------------------------------------------------------------------------ -proc ::http::cwaiter::CwaitHelper {varName coroName toe args} { +proc http::cwaiter::CwaitHelper {varName coroName toe args} { CoLog "got $varName for $coroName" set cmd [list ::http::cwaiter::CwaitHelper $varName $coroName $toe] trace remove variable $varName write $cmd @@ -4829,12 +4925,12 @@ proc ::http::cwaiter::CwaitHelper {varName coroName toe args} { # ------------------------------------------------------------------------------ -# Proc ::http::cwaiter::LogInit +# Proc http::cwaiter::LogInit # ------------------------------------------------------------------------------ # Call this command to initiate debug logging and clear the log. # ------------------------------------------------------------------------------ -proc ::http::cwaiter::LogInit {} { +proc http::cwaiter::LogInit {} { variable log variable logOn set log {} @@ -4842,12 +4938,12 @@ proc ::http::cwaiter::LogInit {} { return } -proc ::http::cwaiter::LogRead {} { +proc http::cwaiter::LogRead {} { variable log return $log } -proc ::http::cwaiter::CoLog {msg} { +proc http::cwaiter::CoLog {msg} { variable log variable logOn if {$logOn} { @@ -4856,7 +4952,7 @@ proc ::http::cwaiter::CoLog {msg} { return } -namespace eval ::http { +namespace eval http { namespace import ::http::cwaiter::* } -- cgit v0.12 From 535acd95da296aad6bce5f59b57b5d4d83291b4a Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 14 Sep 2022 17:52:43 +0000 Subject: eol-spacing --- generic/tclUniData.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclUniData.c b/generic/tclUniData.c index d8c93f3..33bdb8e 100644 --- a/generic/tclUniData.c +++ b/generic/tclUniData.c @@ -568,7 +568,7 @@ static const unsigned short pageMap[] = { 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 15520 - + #endif /* TCL_UTF_MAX > 3 */ }; @@ -1653,7 +1653,7 @@ static const unsigned char groupMap[] = { 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - + #endif /* TCL_UTF_MAX > 3 */ }; -- cgit v0.12 From 0371b9ed8d4bd0943122234faf1c03cfc14b3405 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Thu, 15 Sep 2022 13:41:20 +0000 Subject: Document TIP 602 --- doc/file.n | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/file.n b/doc/file.n index c5a5eed..daa0ad8 100644 --- a/doc/file.n +++ b/doc/file.n @@ -180,6 +180,24 @@ Returns all of the characters in \fIname\fR after and including the last dot in the last element of \fIname\fR. If there is no dot in the last element of \fIname\fR then returns the empty string. .TP +\fBfile home ?\fIusername\fR? +.VS "8.7, TIP 602" +If no argument is specified, the command returns the home directory +of the current user. This is generally the value of the \fB$HOME\fR +environment variable except that on Windows platforms backslashes +in the path are replaced by forward slashes. An error is raised if +the \fB$HOME\fR environment variable is not set. +.RS +.PP +If \fIusername\fR is specified, the command returns the home directory +configured in the system for the specified user. Note this may be +different than the value of the \fB$HOME\fR environment variable +even when \fIusername\fR corresponds to the current user. An error is +raised if the \fIusername\fR does not correspond to a user account +on the system. +.RE +.VE "8.7, TIP 602" +.TP \fBfile isdirectory \fIname\fR . Returns \fB1\fR if file \fIname\fR is a directory, \fB0\fR otherwise. @@ -483,6 +501,22 @@ filesystem. As such, they can be relied upon to be used with operating-system native APIs and external programs that require a filename. .RE .TP +\fBfile tildeexpand \fIname\fR +.VS "8.7, TIP 602" +Returns the result of performing tilde substitution on \fIname\fR. If the name +begins with a tilde, then the file name will be interpreted as if the first +element is replaced with the location of the home directory for the given user. +If the tilde is followed immediately by a path separator, the \fBHOME\fR +environment variable is substituted. Otherwise the characters between the +tilde and the next separator are taken as a user name, which is used to +retrieve the user's home directory for substitution. An error is raised if the +\fBHOME\fR environment variable or user does not exist. +.RS +.PP +If the file name does not begin with a tilde, it is returned unmodified. +.RE +.VE "8.7, TIP 602" +.TP \fBfile type \fIname\fR . Returns a string giving the type of file \fIname\fR, which will be one of -- cgit v0.12 From aca6eed0f36ee531e3e3c8eeb6c6c966ad80057f Mon Sep 17 00:00:00 2001 From: kjnash Date: Thu, 15 Sep 2022 14:39:41 +0000 Subject: Minor bugfixes and refactoring of new code. Handle more errors in OpenSocket. Rename some keys of dict returned by ::http::responseInfo, and add more keys. Improve error reporting from ::http::OpenSocket and ::http::socket, especially when using threads. Adapt http(n) to emphasize using http::* commands rather than peeking at internal state array. --- doc/http.n | 774 ++++++++++++++++++++++++++++++++++---------------- library/http/http.tcl | 200 +++++++------ 2 files changed, 646 insertions(+), 328 deletions(-) diff --git a/doc/http.n b/doc/http.n index 8a9c35b..5ba4813 100644 --- a/doc/http.n +++ b/doc/http.n @@ -13,7 +13,7 @@ .SH NAME http \- Client-side implementation of the HTTP/1.1 protocol .SH SYNOPSIS -\fBpackage require http\fI ?\fB2.10\fR? +\fBpackage require http\fR ?\fB2.10\fR? .\" See Also -useragent option documentation in body! .sp \fB::http::config\fR ?\fI\-option value\fR ...? @@ -80,7 +80,8 @@ Namespace \fBhttp\fR exports the commands \fBconfig\fR, \fBformatQuery\fR, \fBregister\fR, \fBregisterError\fR, \fBrequestHeaders\fR, \fBrequestHeaderValue\fR, \fBrequestLine\fR, \fBresponseBody\fR, \fBresponseCode\fR, -\fBresponseHeaders\fR, \fBresponseHeaderValue\fR, \fBresponseInfo\fR, \fBresponseLine\fR, +\fBresponseHeaders\fR, \fBresponseHeaderValue\fR, \fBresponseInfo\fR, +\fBresponseLine\fR, \fBreset\fR, \fBunregister\fR, and \fBwait\fR. .PP It does not export the commands \fBcleanup\fR, \fBcode\fR, \fBdata\fR, @@ -90,7 +91,8 @@ It does not export the commands \fBcleanup\fR, \fBcode\fR, \fBdata\fR, .SH DESCRIPTION .PP The \fBhttp\fR package provides the client side of the HTTP/1.1 -protocol, as defined in RFC 7230 to RFC 7235, which supersede RFC 2616. +protocol, as defined in RFC 9110 to 9112, which supersede RFC 7230 +to RFC 7235, which in turn supersede RFC 2616. The package implements the GET, POST, and HEAD operations of HTTP/1.1. It allows configuration of a proxy host to get through firewalls. The package is compatible with the \fBSafesock\fR security @@ -103,14 +105,13 @@ The \fB::http::geturl\fR procedure does a HTTP transaction. Its \fIoptions \fR determine whether a GET, POST, or HEAD transaction is performed. The return value of \fB::http::geturl\fR is a token for the transaction. -The value is also the name of an array in the ::http namespace -that contains state information about the transaction. The elements -of this array are described in the \fBSTATE ARRAY\fR section. +The token can be supplied as an argument to other commands, to manage the +transaction and examine its results. .PP If the \fB\-command\fR option is specified, then the HTTP operation is done in the background. \fB::http::geturl\fR returns immediately after generating the -HTTP request and the callback is invoked +HTTP request and the \fB\-command\fR callback is invoked when the transaction completes. For this to work, the Tcl event loop must be active. In Tk applications this is always true. For pure-Tcl applications, the caller can use \fB::http::wait\fR after calling @@ -119,6 +120,15 @@ applications, the caller can use \fB::http::wait\fR after calling \fBNote:\fR The event queue is even used without the \fB\-command\fR option. As a side effect, arbitrary commands may be processed while \fBhttp::geturl\fR is running. +.PP +When the HTTP server has replied to the request, call the command +\fB::http::responseInfo\fR, which +returns a \fBdict\fR of metadata that is essential for identifying a +successful transaction and making use of the response. See +section \fBMETADATA\fR for details of the information returned. +The response itself is returned by command \fB::http::responseBody\fR, +unless it has been redirected to a file by the \fI\-channel\fR option +of \fB::http::geturl\fR. .SH COMMANDS .TP \fB::http::config\fR ?\fIoptions\fR? @@ -204,7 +214,8 @@ default is 0. .TP \fB\-threadlevel\fR \fIlevel\fR . -Specifies whether and how to use the \fBThread\fR package. Possible values of \fIlevel\fR are 0, 1 or 2. +Specifies whether and how to use the \fBThread\fR package. Possible values +of \fIlevel\fR are 0, 1 or 2. .RS .PP .DS @@ -212,7 +223,11 @@ Specifies whether and how to use the \fBThread\fR package. Possible values of \ 1 - use Thread if it is available, do not use it if it is unavailable 2 - use Thread if it is available, raise an error if it is unavailable .DE -The Tcl \fBsocket -async\fR command can block in adverse cases (e.g. a slow DNS lookup). Using the Thread package works around this problem, for both HTTP and HTTPS transactions. Values of \fIlevel\fR other than 0 are available only to the main interpreter in each thread. See section \fBTHREADS\fR for more information. +The Tcl \fBsocket -async\fR command can block in adverse cases (e.g. a slow +DNS lookup). Using the Thread package works around this problem, for both +HTTP and HTTPS transactions. Values of \fIlevel\fR other than 0 are +available only to the main interpreter in each thread. See +section \fBTHREADS\fR for more information. .RE .TP \fB\-urlencoding\fR \fIencoding\fR @@ -235,20 +250,21 @@ numbers of \fBhttp\fR and \fBTcl\fR. . If the value is boolean \fBtrue\fR, then by default requests will send a header .QW "\fBAccept-Encoding: gzip,deflate\fR" . -If the value is boolean \fBfalse\fR, then by default this header will not be -sent. In either case the default can be overridden for an individual request by +If the value is boolean \fBfalse\fR, then by default requests will send a header +.QW "\fBAccept-Encoding: identity\fR" . +In either case the default can be overridden for an individual request by supplying a custom \fBAccept-Encoding\fR header in the \fB\-headers\fR option -of \fBhttp::geturl\fR. The default is 1. +of \fBhttp::geturl\fR. The default value is 1. .RE .TP \fB::http::geturl\fR \fIurl\fR ?\fIoptions\fR? . The \fB::http::geturl\fR command is the main procedure in the package. -The \fB\-query\fR option causes a POST operation and +The \fB\-query\fR or \fB\-querychannel\fR option causes a POST operation and the \fB\-validate\fR option causes a HEAD operation; otherwise, a GET operation is performed. The \fB::http::geturl\fR command -returns a \fItoken\fR value that can be used to get -information about the transaction. See the \fBSTATE ARRAY\fR and +returns a \fItoken\fR value that can be passed as an argument to other commands +to get information about the transaction. See the \fBMETADATA\fR and \fBERRORS\fR section for details. The \fB::http::geturl\fR command blocks until the operation completes, unless the \fB\-command\fR option specifies a callback @@ -272,13 +288,14 @@ At most \fIsize\fR bytes are read at once. After each block, a call to the \fB\-channel\fR \fIname\fR . Copy the URL contents to channel \fIname\fR instead of saving it in -\fBstate(body)\fR. +a Tcl variable for retrieval by \fB::http::responseBody\fR. .TP \fB\-command\fR \fIcallback\fR . -Invoke \fIcallback\fR after the HTTP transaction completes. -This option causes \fB::http::geturl\fR to return immediately. -The \fIcallback\fR gets an additional argument that is the \fItoken\fR returned +The presence of this option causes \fB::http::geturl\fR to return immediately. +After the HTTP transaction completes, the value of \fIcallback\fR is expanded, +an additional argument is added, and the resulting command is evaluated. +The additional argument is the \fItoken\fR returned from \fB::http::geturl\fR. This token is the name of an array that is described in the \fBSTATE ARRAY\fR section. Here is a template for the callback: @@ -286,8 +303,10 @@ callback: .PP .CS proc httpCallback {token} { - upvar #0 $token state - # Access state as a Tcl array + upvar 0 $token state + # Access state as a Tcl array defined in this proc + ... + return } .CE .PP @@ -299,22 +318,28 @@ details. .TP \fB\-guesstype\fR \fIboolean\fR . -Attempt to guess the Content-Type and character set when a misconfigured +Attempt to guess the \fBContent-Type\fR and character set when a misconfigured server provides no information. The default value is \fIfalse\fR (do nothing). If boolean \fItrue\fR then, if the server does not send a -"Content-Type" header, or if it sends the value "application/octet-stream", +\fBContent-Type\fR header, or if it sends the value "application/octet-stream", \fBhttp::geturl\fR will attempt to guess appropriate values. This is not intended to become a general-purpose tool, and currently it is limited to detecting XML documents that begin with an XML declaration. In this case -the Content-Type is changed to "application/xml", and the character set to +the \fBContent-Type\fR is changed to "application/xml", the binary flag +state(binary) is changed to 0, and the character set is changed to the one specified by the "encoding" tag of the XML line, or to utf-8 if no -encoding is specified. +encoding is specified. Not used if a \fI\-channel\fR is specified. .TP \fB\-handler\fR \fIcallback\fR . -Invoke \fIcallback\fR whenever HTTP data is available; if present, nothing -else will be done with the HTTP data. This procedure gets two additional -arguments: the socket for the HTTP data and the \fItoken\fR returned from +If this option is absent, \fBhttp::geturl\fR processes incoming data itself, +either appending it to the state(body) variable or writing it to the -channel. +But if the \fB\-handler\fR option is present, \fBhttp::geturl\fR does not do +this processing and instead calls \fIcallback\fR. +Whenever HTTP data is available, the value of \fIcallback\fR is expanded, an +additional two arguments are added, and the resulting command is evaluated. +The two additional +arguments are: the socket for the HTTP data and the \fItoken\fR returned from \fB::http::geturl\fR. The token is the name of a global array that is described in the \fBSTATE ARRAY\fR section. The procedure is expected to return the number of bytes read from the socket. Here is a @@ -323,8 +348,8 @@ template for the callback: .PP .CS proc httpHandlerCallback {socket token} { - upvar #0 $token state - # Access socket, and state as a Tcl array + upvar 0 $token state + # Access socket, and state as a Tcl array defined in this proc # For example... ... set data [read $socket 1000] @@ -337,8 +362,9 @@ proc httpHandlerCallback {socket token} { The \fBhttp::geturl\fR code for the \fB\-handler\fR option is not compatible with either compression or chunked transfer-encoding. If \fB\-handler\fR is specified, then to work around these issues \fBhttp::geturl\fR will reduce the -HTTP protocol to 1.0, and override the \fB\-zip\fR option (i.e. it will not -send the header "\fBAccept-Encoding: gzip,deflate\fR"). +HTTP protocol to 1.0, and override the \fB\-zip\fR option (i.e. it will +send the header \fBAccept-Encoding: identity\fR instead +of \fBAccept-Encoding: gzip,deflate\fR). .PP If options \fB\-handler\fR and \fB\-channel\fR are used together, the handler is responsible for copying the data from the HTTP socket to the specified @@ -384,7 +410,10 @@ It is the caller's responsibility to ensure that the headers and request body (if any) conform to the requirements of the request method. For example, if using \fB\-method\fR \fIPOST\fR to send a POST with an empty request body, the caller must also supply the option -.QW "\-headers {Content-Length 0}" . +.PP +.CS +\-headers {Content-Length 0} +.CE .RE .TP \fB\-myaddr\fR \fIaddress\fR @@ -394,18 +423,26 @@ multiple interfaces are available. .TP \fB\-progress\fR \fIcallback\fR . -The \fIcallback\fR is made after each transfer of data from the URL. -The callback gets three additional arguments: the \fItoken\fR from +If the \fB\-progress\fR option is present, +then the \fIcallback\fR is made after each transfer of data from the URL. +The value of \fIcallback\fR is expanded, an additional three arguments are +added, and the resulting command is evaluated. +The three additional arguments are: the \fItoken\fR returned from \fB::http::geturl\fR, the expected total size of the contents from the -\fBContent-Length\fR metadata, and the current number of bytes -transferred so far. The expected total size may be unknown, in which +\fBContent-Length\fR response header, and the current number of bytes +transferred so far. The token is the name of a global array that is +described in the \fBSTATE ARRAY\fR section. The expected total size may +be unknown, in which case zero is passed to the callback. Here is a template for the progress callback: .RS .PP .CS proc httpProgress {token total current} { - upvar #0 $token state + upvar 0 $token state + # Access state as a Tcl array defined in this proc + ... + return } .CE .RE @@ -449,20 +486,24 @@ This flag causes \fB::http::geturl\fR to do a POST request that passes the data contained in \fIchannelID\fR to the server. The data contained in \fIchannelID\fR must be an x-url-encoding formatted query unless the \fB\-type\fR option below is used. -If a Content-Length header is not specified via the \fB\-headers\fR options, -\fB::http::geturl\fR attempts to determine the size of the post data +If a \fBContent-Length\fR header is not specified via the \fB\-headers\fR +options, \fB::http::geturl\fR attempts to determine the size of the post data in order to create that header. If it is unable to determine the size, it returns an error. .TP \fB\-queryprogress\fR \fIcallback\fR . -The \fIcallback\fR is made after each transfer of data to the URL -(i.e. POST) and acts exactly like the \fB\-progress\fR option (the -callback format is the same). +If the \fB\-queryprogress\fR option is present, +then the \fIcallback\fR is made after each transfer of data to the URL +in a POST request (i.e. a call to \fB::http::geturl\fR with +option \fB\-query\fR or \fB\-querychannel\fR) and acts exactly like +the \fB\-progress\fR option (the callback format is the same). .TP \fB\-strict\fR \fIboolean\fR . -Whether to enforce RFC 3986 URL validation on the request. Default is 1. +If true then the command will test that the URL complies with RFC 3986, i.e. +that it has no characters that should be "x-url-encoded" (e.g. a space should +be encoded to "%20"). Default value is 1. .TP \fB\-timeout\fR \fImilliseconds\fR . @@ -470,7 +511,8 @@ If \fImilliseconds\fR is non-zero, then \fB::http::geturl\fR sets up a timeout to occur after the specified number of milliseconds. A timeout results in a call to \fB::http::reset\fR and to the \fB\-command\fR callback, if specified. -The return value of \fB::http::status\fR is \fBtimeout\fR +The return value of \fB::http::status\fR (and the value of the \fIstatus\fR key +in the dictionary returned by \fB::http::responseInfo\fR) is \fBtimeout\fR after a timeout has occurred. .TP \fB\-type\fR \fImime-type\fR @@ -482,10 +524,11 @@ POST operation. \fB\-validate\fR \fIboolean\fR . If \fIboolean\fR is non-zero, then \fB::http::geturl\fR does an HTTP HEAD -request. This request returns meta information about the URL, but the -contents are not returned. The meta information is available in the -\fBstate(meta) \fR variable after the transaction. See the -\fBSTATE ARRAY\fR section for details. +request. This server returns the same status line and response headers as it +would for a HTTP GET request, but omits the response entity +(the URL "contents"). The response headers are available after the +transaction using command \fB::http::responseHeaders\fR or, for selected +information, \fB::http::responseInfo\fR. .RE .TP \fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...? @@ -509,7 +552,7 @@ This sets the \fBstate(status)\fR value to \fIwhy\fR, which defaults to .TP \fB::http::wait\fR \fItoken\fR . -This is a convenience procedure that blocks and waits for the +This command blocks and waits for the transaction to complete. This only works in trusted code because it uses \fBvwait\fR. Also, it is not useful for the case where \fB::http::geturl\fR is called \fIwithout\fR the \fB\-command\fR option @@ -519,29 +562,44 @@ wait for. .TP \fB::http::status\fR \fItoken\fR . -This is a convenience procedure that returns the \fBstatus\fR element of -the state array. +This command returns a description of the status of the HTTP transaction. +The return value is the empty string until the HTTP transaction is +completed; after completion it has one of the values ok, eof, error, +timeout, and reset. The meaning of these values is described in the +section \fBERRORS\fR (below). +.PP +.RS +The name "status" is not related to the terms "status line" and +"status code" that are defined for a HTTP response. +.RE .TP \fB::http::size\fR \fItoken\fR . -This is a convenience procedure that returns the \fBcurrentsize\fR -element of the state array, which represents the number of bytes -received from the URL in the \fB::http::geturl\fR call. +This command returns the number of bytes +received so far from the URL in the \fB::http::geturl\fR call. .TP \fB::http::error\fR \fItoken\fR . -This is a convenience procedure that returns the \fBerror\fR element -of the state array. +This command returns the error information if the HTTP transaction failed, +or the empty string if there was no error. The information is a Tcl list of +the error message, stack trace, and error code. .TP \fB::http::postError\fR \fItoken\fR . -A POST request is a call to \fB::http::geturl\fR with either the \fB\-query\fR or \fB\-querychannel\fR option. The \fB::http::postError\fR command returns the error string generated when a HTTP POST request sends its request-body to the server; or the empty string if there was no error. When this type of error occurs, the \fB::http::geturl\fR command continues the transaction and attempts to receive a response from the server. +A POST request is a call to \fB::http::geturl\fR with either +the \fB\-query\fR or \fB\-querychannel\fR option. +The \fB::http::postError\fR command returns the error information generated +when a HTTP POST request sends its request-body to the server; or the empty +string if there was no error. The information is a Tcl list of the error +message, stack trace, and error code. When this type of error occurs, +the \fB::http::geturl\fR command continues the transaction and attempts to +receive a response from the server. .TP \fB::http::cleanup\fR \fItoken\fR . This procedure cleans up the state associated with the connection identified by \fItoken\fR. After this call, the procedures -like \fB::http::data\fR cannot be used to get information +like \fB::http::responseBody\fR cannot be used to get information about the operation. It is \fIstrongly\fR recommended that you call this function after you are done with a given HTTP request. Not doing so will result in memory not being freed, and if your app calls @@ -565,13 +623,12 @@ POST /forms/order.html HTTP/1.1 .TP \fB::http::requestHeaders\fR \fItoken\fR ?\fIheaderName\fR? . -This command returns a list of the HTTP request header names and values, in the -order that they were sent to the server: a Tcl list of the form +This command returns the HTTP request header names and values, in the +order that they were sent to the server, as a Tcl list of the form ?name value ...? Header names are case-insensitive and are converted to lower case. The return value is not a \fBdict\fR because some header names may occur more than once. If one argument is supplied, all request headers -are returned: the value is that of the \fBrequestHeaders\fR element -of the state array (described below). If two arguments are supplied, the +are returned. If two arguments are supplied, the second provides the value of a header name. Only headers with the requested name (converted to lower case) are returned. If no such headers are found, an empty list is returned. @@ -587,9 +644,8 @@ preserving their order. .TP \fB::http::responseLine\fR \fItoken\fR . -This command returns the "status line" of the server response (which is stored -as element \fBhttp\fR of the state array). -The "status line" is the first line of a HTTP server response, and has three +This command returns the first line of the server response: the +HTTP "status line". The "status line" has three elements separated by spaces: the HTTP version, a three-digit numerical "status code", and a "reason phrase". Only the reason phrase may contain spaces. Examples: @@ -619,7 +675,7 @@ command \fB::http::reasonPhrase\fR. . This command returns the "status code" (200, 404, etc.) of the server "status line". If a three-digit code cannot be found, the full status -line is returned. See command \fB::http::code\fR for more information +line is returned. See command \fB::http::responseLine\fR for more information on the "status line". .TP \fB::http::reasonPhrase\fR \fIcode\fR @@ -636,8 +692,9 @@ HEAD, GET, or POST request method. The "reason phrase" returned by a HTTP server may differ from the recommended value, without affecting the HTTP protocol. The value returned by \fB::http::geturl\fR can be obtained by calling either command -\fB::http::code\fR (which returns the full status line) or command -\fB::http::ncode\fR (for the status code only). +\fB::http::responseLine\fR (which returns the full status line) or command +\fB::http::responseInfo\fR (which returns a dictionary, with +the "reason phrase" stored in key \fIreasonPhrase\fR). .PP A registry of valid status codes is maintained at https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml @@ -645,16 +702,18 @@ https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml .TP \fB::http::responseHeaders\fR \fItoken\fR ?\fIheaderName\fR? . -This command returns a list of HTTP response header names and values, in the -order that they were received from the server: a Tcl list of the form +The response from a HTTP server includes metadata headers that describe the +response body and the transaction itself. +This command returns the HTTP response header names and values, in the +order that they were received from the server, as a Tcl list of the form ?name value ...? Header names are case-insensitive and are converted to lower case. The return value is not a \fBdict\fR because some header names may occur -more than once, notably \fIset-cookie\fR. If one argument is supplied, all -response headers are returned: the value is that of the \fBmeta\fR element -of the state array (described below). If two arguments are supplied, the -second provides the value of a header name. Only headers with the requested -name (converted to lower case) are returned. If no such headers are found, -an empty list is returned. +more than once, notably \fBSet-Cookie\fR. If the second argument is not +supplied, all response headers are returned. If the second argument is +supplied, it provides the value of a header name. Only headers with the +requested name (converted to lower case) are returned. If no such headers +are found, an empty list is returned. See section \fBMETADATA\fR for more +information. .TP \fB::http::responseHeaderValue\fR \fItoken\fR \fIheaderName\fR . @@ -664,17 +723,32 @@ lower case. If no such header exists, the return value is the empty string. If there are multiple headers named \fIheaderName\fR, the result is obtained by joining the individual values with the string ", " (comma and space), preserving their order. Multiple headers with the same name may be processed -in this manner, except \fIset-cookie\fR which does not conform to the +in this manner, except \fBSet-Cookie\fR which does not conform to the comma-separated-list syntax and cannot be combined into a single value. -Each \fIset-cookie\fR header must be treated individually, e.g. by processing -the return value of \fB::http::responseHeaders\fR \fItoken\fR \fIset-cookie\fR. +Each \fBSet-Cookie\fR header must be treated individually, e.g. by processing +the return value of \fB::http::responseHeaders\fR \fItoken\fR \fBSet-Cookie\fR. .TP \fB::http::responseInfo\fR \fItoken\fR . -This command returns a \fBdict\fR of selected response metadata that are essential for identifying a successful transaction and making use of the response, along with other metadata that are informational. The keys of the \fBdict\fR are \fIstage\fR, \fIstatus\fR, \fIncode\fR, \fIreason\fR, \fItype\fR, \fIbinary\fR, \fIredirection\fR, \fIcharset\fR, \fIcoding\fR, \fIhttpRequest\fR, \fIhttpResponse\fR, \fIurl\fR, \fIconnRequest\fR, \fIconnResponse\fR, \fIconnection\fR, \fItransfer\fR, \fItotalsize\fR, and \fIcurrentsize\fR. The meaning of these keys is described in the chapter \fBMETADATA\fR below. +This command returns a \fBdict\fR of selected response metadata that are +essential for identifying a successful transaction and making use of the +response, along with other metadata that are informational. The keys of +the \fBdict\fR are \fIstage\fR, \fIstatus\fR, \fIresponseCode\fR, +\fIreasonPhrase\fR, \fIcontentType\fR, \fIbinary\fR, \fIredirection\fR, +\fIupgrade\fR, \fIerror\fR, \fIpostError\fR, \fImethod\fR, \fIcharset\fR, +\fIcompression\fR, \fIhttpRequest\fR, \fIhttpResponse\fR, \fIurl\fR, +\fIconnectionRequest\fR, \fIconnectionResponse\fR, \fIconnectionActual\fR, +\fItransferEncoding\fR, \fItotalPost\fR, \fIcurrentPost\fR, \fItotalSize\fR, +and \fIcurrentSize\fR. The meaning of these keys is described in the +section \fBMETADATA\fR below. .RS .PP -It is always worth checking the value of \fIbinary\fR after a HTTP transaction, to determine whether a misconfigured server has caused http to interpret a text resource as a binary, or vice versa. +It is always worth checking the value of \fIbinary\fR after a HTTP transaction, +to determine whether a misconfigured server has caused http to interpret a +text resource as a binary, or vice versa. +.PP +After a POST transaction, check the value of \fIpostError\fR to verify that +the request body was uploaded without error. .RE .TP \fB::http::responseBody\fR \fItoken\fR @@ -687,7 +761,7 @@ channel, and the command returns the empty string). Other terms for "entity", with varying precision, include "representation of resource", "resource", "response body after decoding", "payload", -"message body after decoding", "content", and "file". +"message body after decoding", "content(s)", and "file". .RE .TP \fB::http::register\fR \fIproto port command\fR @@ -738,25 +812,21 @@ An alternative name for the command \fB::http::responseBody\fR. . An alternative name for the command \fB::http::responseHeaders\fR .TP -\fB::http::metaValue\fR \fItoken\fR \fIheaderName\fR -. -An alternative name for the command \fB::http::responseHeaderValue\fR -.TP \fB::http::ncode\fR \fItoken\fR . An alternative name for the command \fB::http::responseCode\fR .SH ERRORS The \fB::http::geturl\fR procedure will raise errors in the following cases: invalid command line options, -an invalid URL, -a URL on a non-existent host, -or a URL at a bad port on an existing host. +or an invalid URL. These errors mean that it cannot even start the network transaction. -It will also raise an error if it gets an I/O error while -writing out the HTTP request header. For synchronous \fB::http::geturl\fR calls (where \fB\-command\fR is -not specified), it will raise an error if it gets an I/O error while +not specified), it will raise an error if +the URL is on a non-existent host +or at a bad port on an existing host. +It will also raise an error for any I/O errors while +writing out the HTTP request line and headers, or reading the HTTP reply headers or data. Because \fB::http::geturl\fR does not return a token in these cases, it does all the required cleanup and there is no issue of your app having to call @@ -768,13 +838,12 @@ HTTP reply headers or data, no exception is thrown. This is because after writing the HTTP headers, \fB::http::geturl\fR returns, and the rest of the HTTP transaction occurs in the background. The command callback can check if any error occurred during the read by calling -\fB::http::status\fR to check the status and if its \fIerror\fR, -calling \fB::http::error\fR to get the error message. +\fB::http::responseInfo\fR to check the transaction status. .PP Alternatively, if the main program flow reaches a point where it needs to know the result of the asynchronous HTTP request, it can call \fB::http::wait\fR and then check status and error, just as the -callback does. +synchronous call does. .PP The \fB::http::geturl\fR command runs the \fB\-command\fR, \fB\-handler\fR, and \fB\-proxyfilter\fR callbacks inside a \fBcatch\fR command. Therefore @@ -788,15 +857,17 @@ In any case, you must still call \fB::http::cleanup\fR to delete the state array when you are done. .PP There are other possible results of the HTTP transaction -determined by examining the status from \fB::http::status\fR. +determined by examining the status from \fB::http::status\fR (or the value +of the \fIstatus\fR key in the dictionary returned +by \fB::http::responseInfo\fR). These are described below. .TP \fBok\fR . If the HTTP transaction completes entirely, then status will be \fBok\fR. -However, you should still check the \fB::http::code\fR value to get -the HTTP status. The \fB::http::ncode\fR procedure provides just -the numeric error (e.g., 200, 404 or 500) while the \fB::http::code\fR +However, you should still check the \fB::http::responseLine\fR value to get +the HTTP status. The \fB::http::responseCode\fR procedure provides just +the numeric error (e.g., 200, 404 or 500) while the \fB::http::responseLine\fR procedure returns a value like .QW "HTTP 404 File not found" . .TP @@ -807,32 +878,47 @@ is raised, but the status of the transaction will be \fBeof\fR. .TP \fBerror\fR . -The error message will also be stored in the \fBerror\fR status -array element, accessible via \fB::http::error\fR. +The error message, stack trace, and error code are accessible +via \fB::http::error\fR. The error message is also provided by the value of +the \fIerror\fR key in the dictionary returned by \fB::http::responseInfo\fR. .TP \fBtimeout\fR . -A timeout occurred before the transaction could complete +A timeout occurred before the transaction could complete. .TP \fBreset\fR . -user-reset -.PP -Another error possibility is that \fB::http::geturl\fR is unable to -write all the post query data to the server before the server -responds and closes the socket. -The error message is saved in the \fBposterror\fR status array -element and then \fB::http::geturl\fR attempts to complete the -transaction. -If it can read the server's response -it will end up with an \fBok\fR status, otherwise it will have -an \fBeof\fR status. +The user has called \fB::http::reset\fR. +.TP +\fB""\fR +. +(empty string) The transaction has not yet finished. +.PP +Another error possibility is that \fB::http::geturl\fR failed to +write the whole of the POST request body (\fB-query\fR or \fB-querychannel\fR +data) to the server. \fB::http::geturl\fR stores the error message for later +retrieval by the \fB::http::postError\fR or \fB::http::responseInfo\fR +commands, and then attempts to complete the transaction. +If it can read the server's response the status will be \fBok\fR, but it is +important to call \fB::http::postError\fR or \fB::http::responseInfo\fR after +every POST to check that the data was sent in full. +If the server has closed the connection the status will be \fBeof\fR. .SH "METADATA" -When a HTTP server responds to a request, it supplies not only the entity requested, but also metadata. This is provided by the first line (the "status line") of the response, and by a number of HTTP headers. Further metadata relates to how \fB::http::geturl\fR has processed the response from the server. +.PP +.SS "MOST USEFUL METADATA" +When a HTTP server responds to a request, it supplies not only the entity +requested, but also metadata. This is provided by the first line (the +"status line") of the response, and by a number of HTTP headers. Further +metadata relates to how \fB::http::geturl\fR has processed the response +from the server. .PP The most important metadata can be accessed with the command \fB::http::responseInfo\fR. -This command returns a \fBdict\fR of metadata that are essential for identifying a successful transaction and making use of the response, along with other metadata that are informational. The keys of the \fBdict\fR are: +This command returns a \fBdict\fR of metadata that are essential for +identifying a successful transaction and making use of the response, +along with other metadata that are informational. The keys of +the \fBdict\fR are: +.PP .RS .RS \fB===== Essential Values =====\fR @@ -841,220 +927,398 @@ This command returns a \fBdict\fR of metadata that are essential for identifying .TP \fBstage\fR . -This value, set by \fB::http::geturl\fR, describes the stage that the transaction has reached. Values, in order of the transaction lifecycle, are: "created", "connecting", "header", "body", and "complete". Other \fBdict\fR keys are available when the value of stage is "body" or "complete". The key \fBconnection\fR has its final value only when \fBstage\fR is "complete". +This value, set by \fB::http::geturl\fR, describes the stage that the +transaction has reached. Values, in order of the transaction lifecycle, +are: "created", "connecting", "header", "body", and "complete". The +other \fBdict\fR keys will not be available until the value of \fBstage\fR +is "body" or "complete". The key \fBcurrentSize\fR has its final value only +when \fBstage\fR is "complete". .TP \fBstatus\fR . -This value, set by \fB::http::geturl\fR, is "ok" for a successful transaction; "eof", "error", "timeout", or "reset" for an unsuccessful transaction; or "" if the transaction is still in progress. In the last case the values for other dictionary keys may not be available. The meaning of these values is described in the chapter \fBERRORS\fR (above). +This value, set by \fB::http::geturl\fR, is "ok" for a successful transaction; +"eof", "error", "timeout", or "reset" for an unsuccessful transaction; or "" +if the transaction is still in progress. The value is the same as that +returned by command \fB::http::status\fR. The meaning of these values is +described in the section \fBERRORS\fR (above). .TP -\fBncode\fR +\fBresponseCode\fR . -The "HTTP status code" for the response. +The "HTTP status code" sent by the server in the first line (the "status line") +of the response. If the value cannot be extracted from the status line, the +full status line is returned. .TP -\fBreason\fR +\fBreasonPhrase\fR . -The "reason phrase" sent by the server. +The "reason phrase" sent by the server as a description of the HTTP status code. +If the value cannot be extracted from the status line, the full status +line is returned. .TP -\fBcontent-type\fR +\fBcontentType\fR . -The value of the \fBContent-Type\fR response header or, if the header was not supplied, the default value "application/octet-stream". +The value of the \fBContent-Type\fR response header or, if the header was not +supplied, the default value "application/octet-stream". .TP \fBbinary\fR . -This boolean value, set by \fB::http::geturl\fR, describes how the command has interpreted the entity returned by the server (after decoding any compression specified -by the -.QW "Content-Encoding" -response header). This decoded entity is accessible as the return value of the command \fB::http::responseBody\fR. - -The value is \fBtrue\fR if http has interpreted the decoded entity as binary. The value returned by ::http::responseBody is a Tcl binary string. This is a suitable format for image data, zip files, etc. -\fB::http::geturl\fR chooses this value if the user has requested a binary interpretation by passing the option \fI\-binary\fR to the command, or if the server has supplied a binary content type in a Content-Type response header, or if the server has not supplied any Content-Type header. - -The value is \fBfalse\fR if http has interpreted the decoded entity as text. The text has been converted from the character set notified by the server into Tcl's internal Unicode format, and the value returned by ::http::responseBody is an ordinary Tcl string. - -It is always worth checking the value of "binary" after a HTTP transaction, to determine whether a misconfigured server has caused http to interpret a text resource as a binary, or vice versa. +This boolean value, set by \fB::http::geturl\fR, describes how the command +has interpreted the entity returned by the server (after decoding any +compression specified by the \fBContent-Encoding\fR response header). +This decoded entity is accessible as the return value of the +command \fB::http::responseBody\fR. +.PP +.RS +The value is \fBtrue\fR if http has interpreted the decoded entity as binary. +The value returned by \fB::http::responseBody\fR is a Tcl binary string. +This is a suitable format for image data, zip files, etc. +\fB::http::geturl\fR chooses this value if the user has requested a binary +interpretation by passing the option \fI\-binary\fR to the command, or if the +server has supplied a binary content type in a \fBContent-Type\fR response +header, or if the server has not supplied any \fBContent-Type\fR header. +.PP +The value is \fBfalse\fR in other cases, and this means that http has +interpreted the decoded entity as text. The text has been converted, from the +character set notified by the server, into Tcl's internal Unicode format; +the value returned by \fB::http::responseBody\fR is an ordinary Tcl string. +.PP +It is always worth checking the value of "binary" after a HTTP transaction, +to determine whether a misconfigured server has caused http to interpret a +text resource as a binary, or vice versa. +.RE .TP \fBredirection\fR . -The URL that is the redirection target. The value is that of the Location response header. This header is sent when a response has status code 3XX (redirection). +The URL that is the redirection target. The value is that of the \fBLocation\fR +response header. This header is sent when a response has status code +3XX (redirection). +.TP +\fBupgrade\fR +. +If not empty, the value indicates the protocol(s) to which the server will +switch after completion of this transaction, while continuing to use the +same connection. When the server intends to switch protocols, it will also +send the value "101" as the status code (the \fBresponseCode\fR key), and the +word "upgrade" as an element of the \fBConnection\fR response header (the +\fBconnectionResponse\fR key), and it will not send a response body. +See the section \fBPROTOCOL UPGRADES\fR for more information. +.TP +\fBerror\fR +. +The error message, if there is one. Further information, including a stack +trace and error code, are available from command \fB::http::error\fR. +.TP +\fBpostError\fR +. +The error message (if any) generated when a HTTP POST request sends its +request-body to the server. Further information, including a stack trace +and error code, are available from command \fB::http::postError\fR. A POST +transaction may appear complete, according to the +keys \fBstage\fR, \fBstatus\fR, and \fBresponseCode\fR, but it is important +to check this \fBpostError\fR key in case an error occurred when uploading +the request-body. +.PP .RS .RS \fB===== Informational Values =====\fR .RE .RE .TP +\fBmethod\fR +. +The HTTP method used in the request. +.TP \fBcharset\fR . -The value of the charset attribute of the \fBContent-Type\fR response header. The charset value is used only for a text resource. If the server did not specify a charset, the value defaults to that of the variable \fB::http::defaultCharset\fR, which unless it has been deliberately modified by the caller is \fBiso8859-1\fR. Incoming text data is automatically converted from the character set defined by \fBcharset\fR to Tcl's internal Unicode representation, i.e. to a Tcl string. +The value of the charset attribute of the \fBContent-Type\fR response header. +The charset value is used only for a text resource. If the server did not +specify a charset, the value defaults to that of the +variable \fB::http::defaultCharset\fR, which unless it has been deliberately +modified by the caller is \fBiso8859-1\fR. Incoming text data is automatically +converted from the character set defined by \fBcharset\fR to Tcl's internal +Unicode representation, i.e. to a Tcl string. .TP -\fBcoding\fR +\fBcompression\fR . A copy of the \fBContent-Encoding\fR response-header value. .TP \fBhttpRequest\fR . The version of HTTP specified in the request (i.e. sent in the request line). +The value is that of the option \fB\-protocol\fR supplied +to \fB::http::geturl\fR (default value "1.1"), unless the command reduced the +value to "1.0" because it was passed the \fB\-handler\fR option. .TP \fBhttpResponse\fR . -The version of HTTP used by the server (obtained from the response "status line"). The server uses this version of HTTP in its response, but ensures that this response is compatible with the HTTP version specified in the client's request. +The version of HTTP used by the server (obtained from the response +"status line"). The server uses this version of HTTP in its response, but +ensures that this response is compatible with the HTTP version specified in the +client's request. If the value cannot be extracted from the status line, the +full status line is returned. .TP \fBurl\fR . -The requested URL, typically the URL supplied as an argument to \fB::http::geturl\fR but without its "fragment" (the final part of the URL beginning with "#". +The requested URL, typically the URL supplied as an argument +to \fB::http::geturl\fR but without its "fragment" (the final part of the URL +beginning with "#"). .TP -\fBconnRequest\fR +\fBconnectionRequest\fR . -The value, if any, sent to the server in "Connection" request header(s). +The value, if any, sent to the server in \fBConnection\fR request header(s). .TP -\fBconnResponse\fR +\fBconnectionResponse\fR . -The value, if any, received from the server in "Connection" response header(s). +The value, if any, received from the server in \fBConnection\fR response +header(s). .TP -\fBconnection\fR +\fBconnectionActual\fR . -This value, set by \fB::http::geturl\fR, reports whether the connection was closed after the transaction (value "close"), or left open (value "keep-alive"). +This value, set by \fB::http::geturl\fR, reports whether the connection was +closed after the transaction (value "close"), or left open (value "keep-alive"). .TP -\fBtransfer\fR +\fBtransferEncoding\fR . -The value of the Transfer-Encoding response header, if it is present. The value is either "chunked" (indicating HTTP/1.1 "chunked encoding") or the empty string. +The value of the Transfer-Encoding response header, if it is present. +The value is either "chunked" (indicating HTTP/1.1 "chunked encoding") or +the empty string. .TP -\fBquerylength\fR +\fBtotalPost\fR . The total length of the request body in a POST request. .TP -\fBqueryoffset\fR +\fBcurrentPost\fR . The number of bytes of the POST request body sent to the server so far. +The value is the same as that returned by command \fB::http::size\fR. .TP -\fBtotalsize\fR +\fBtotalSize\fR . A copy of the \fBContent-Length\fR response-header value. -The number of bytes specified in a Content-Length header, if one was sent. If none was sent, the value is 0. A correctly configured server omits this header if the transfer-encoding is "chunked", or (for older servers) if the server closes the connection when it reaches the end of the resource. +The number of bytes specified in a \fBContent-Length\fR header, if one +was sent. If none was sent, the value is 0. A correctly configured server +omits this header if the transfer-encoding is "chunked", or (for older +servers) if the server closes the connection when it reaches the end of +the resource. .TP -\fBcurrentsize\fR +\fBcurrentSize\fR . The number of bytes fetched from the server so far. +.PP +.SS "MORE METADATA" +The dictionary returned by \fB::http::responseInfo\fR is the most useful +subset of the available metadata. Other metadata include: +.PP +1. The full "status line" of the response, available as the return value +of command \fB::http::responseLine\fR. +.PP +2. The full response headers, available as the return value of +command \fB::http::responseHeaders\fR. This return value is a list of the +response-header names and values, in the order that they were received from +the server. +.PP +The return value is not a \fBdict\fR because some header names may +occur more than once, notably \fBSet-Cookie\fR. If the value is read +into a \fBdict\fR or into an array (using array set), only the last header +with each name will be preserved. +.PP +.RS +Some of the header names (metadata keys) are listed below, but the HTTP +standard defines several more, and servers are free to add their own. +When a dictionary key is mentioned below, this refers to the \fBdict\fR +value returned by command \fB::http::responseInfo\fR. +.TP +\fBContent-Type\fR +. +The content type of the URL contents. Examples include \fBtext/html\fR, +\fBimage/gif,\fR \fBapplication/postscript\fR and +\fBapplication/x-tcl\fR. Text values typically specify a character set, e.g. +\fBtext/html; charset=UTF-8\fR. Dictionary key \fIcontentType\fR. +.TP +\fBContent-Length\fR +. +The advertised size in bytes of the contents, available as dictionary +key \fItotalSize\fR. The actual number of bytes read by \fB::http::geturl\fR +so far is available as dictionary key \fBcurrentSize\fR. +.TP +\fBContent-Encoding\fR +. +The compression algorithm used for the contents. +Examples include \fBgzip\fR, \fBdeflate\fR. +Dictionary key \fIcontent\fR. +.TP +\fBLocation\fR +. +This header is sent when a response has status code 3XX (redirection). +It provides the URL that is the redirection target. +Dictionary key \fIredirection\fR. +.TP +\fBSet-Cookie\fR +. +This header is sent to offer a cookie to the client. Cookie management is +done by the \fB::http::config\fR option \fI\-cookiejar\fR, and so +the \fBSet-Cookie\fR headers need not be parsed by user scripts. +See section \fBCOOKIE JAR PROTOCOL\fR. +.TP +\fBConnection\fR +. +The value can be supplied as a comma-separated list, or by multiple headers. +The list often has only one element, either "close" or "keep-alive". +The value "upgrade" indicates a successful upgrade request and is typically +combined with the status code 101, an \fBUpgrade\fR response header, and no +response body. Dictionary key \fIconnectionResponse\fR. +.TP +\fBUpgrade\fR +. +The value indicates the protocol(s) to which the server will switch +immediately after the empty line that terminates the 101 response headers. +Dictionary key \fIupgrade\fR. +.RE +.PP +.SS "EVEN MORE METADATA" +.PP +1. Details of the HTTP request. The request is determined by the options +supplied to \fB::http::geturl\fR and \fB::http::config\fR. However, it is +sometimes helpful to examine what \fB::http::geturl\fR actually sent to the +server, and this information is available through +commands \fB::http::requestHeaders\fR and \fB::http::requestLine\fR. +.PP +2. The state array: the internal variables of \fB::http::geturl\fR. +It may sometimes be helpful to examine this array. +Details are given in the next section. .SH "STATE ARRAY" -The \fB::http::geturl\fR procedure returns a \fItoken\fR that can be used to -get to the state of the HTTP transaction in the form of a Tcl array. -Use this construct to create an easy-to-use array variable: +The \fB::http::geturl\fR procedure returns a \fItoken\fR that can be used +as an argument to other \fB::http::*\fR commands, which examine and manage +the state of the HTTP transaction. For most purposes these commands are +sufficient. The \fItoken\fR can also be used to access +the internal state of the transaction, which is stored in a Tcl array. +This facility is most useful when writing callback commands for the +options \fB\-command\fR, \fB\-handler\fR, \fB\-progress\fR, +or \fB\-queryprogress\fR. +Use the following command inside the proc to define an easy-to-use +array \fIstate\fR as a local variable within the proc .PP .CS -upvar #0 $token state +upvar 0 $token state .CE .PP Once the data associated with the URL is no longer needed, the state array should be unset to free up storage. The \fB::http::cleanup\fR procedure is provided for that purpose. -The following elements of -the array are supported: +.PP +The following elements of the array are supported, and are the origin of the +values returned by commands as described below. When a dictionary key is +mentioned below, this refers to the \fBdict\fR value returned by +command \fB::http::responseInfo\fR. .RS .TP \fBbinary\fR . -This is boolean \fBtrue\fR if (after decoding any compression specified -by the -.QW "Content-Encoding" -response header) the HTTP response is binary. It is boolean \fBfalse\fR -if the HTTP response is text. +For dictionary key \fIbinary\fR. .TP \fBbody\fR . -The contents of the URL. This will be empty if the \fB\-channel\fR -option has been specified. This value is returned by the \fB::http::data\fR -command. +For command \fB::http::responseBody\fR. .TP \fBcharset\fR . -The value of the charset attribute from the \fBContent-Type\fR metadata -value. If none was specified, this defaults to the RFC standard -\fBiso8859-1\fR, or the value of \fB$::http::defaultCharset\fR. Incoming -text data will be automatically converted from this charset to utf-8. +For dictionary key \fIcharset\fR. .TP \fBcoding\fR . -A copy of the \fBContent-Encoding\fR metadata value. +For dictionary key \fIcompression\fR. +.TP +\fBconnection\fR +. +For dictionary key \fIconnectionActual\fR. .TP \fBcurrentsize\fR . -The current number of bytes fetched from the URL. -This value is returned by the \fB::http::size\fR command. +For command \fB::http::size\fR; and for dictionary key \fIcurrentSize\fR. .TP \fBerror\fR . -If defined, this is the error string seen when the HTTP transaction -was aborted. +For command \fB::http::error\fR; part is used in dictionary key \fIerror\fR. .TP \fBhttp\fR . -The HTTP status reply from the server. This value -is returned by the \fB::http::code\fR command. The format of this value is: -.RS -.PP -.CS -\fIHTTP/1.1 code string\fR -.CE -.PP -The \fIcode\fR is a three-digit number defined in the HTTP standard. -A code of 200 is OK. Codes beginning with 4 or 5 indicate errors. -Codes beginning with 3 are redirection errors. In this case the -\fBLocation\fR metadata specifies a new URL that contains the -requested information. -.RE +For command \fB::http::responseLine\fR. +.TP +\fBhttpResponse\fR +. +For dictionary key \fIhttpResponse\fR. .TP \fBmeta\fR . -The response from a HTTP server includes metadata headers that describe the -response body and the message from the server. The \fBmeta\fR element of the -state array is a list of the keys (header names) and values (header values) of -the metadata. Header names are case-insensitive and are converted to lower -case. The value of meta is not a \fBdict\fR because some header names may -occur more than once, notably "set-cookie". If the value \fBmeta\fR is read -into a dict or into an array (using array set), only the last header with each -name will be preserved. -.PP -.RS -Some of the metadata keys are listed below, but the HTTP standard defines -more, and servers are free to add their own. +For command \fB::http::responseHeaders\fR. Further discussion above in the +section \fBMORE METADATA\fR. .TP -\fBContent-Type\fR +\fBmethod\fR . -The type of the URL contents. Examples include \fBtext/html\fR, -\fBimage/gif,\fR \fBapplication/postscript\fR and -\fBapplication/x-tcl\fR. +For dictionary key \fImethod\fR. .TP -\fBContent-Length\fR +\fBposterror\fR . -The advertised size of the contents. The actual size obtained by -\fB::http::geturl\fR is available as \fBstate(currentsize)\fR. +For dictionary key \fIpostError\fR. .TP -\fBLocation\fR +\fBpostErrorFull\fR . -An alternate URL that contains the requested data. -.RE +For command \fB::http::postError\fR. .TP -\fBposterror\fR +\fB\-protocol\fR . -The error, if any, that occurred while writing -the post query data to the server. +For dictionary key \fIhttpRequest\fR. +.TP +\fBquerylength\fR +. +For dictionary key \fItotalPost\fR. +.TP +\fBqueryoffset\fR +. +For dictionary key \fIcurrentPost\fR. +.TP +\fBreasonPhrase\fR +. +For dictionary key \fIreasonPhrase\fR. +.TP +\fBrequestHeaders\fR +. +For command \fB::http::requestHeaders\fR. +.TP +\fBrequestLine\fR +. +For command \fB::http::requestLine\fR. +.TP +\fBresponseCode\fR +. +For dictionary key \fIresponseCode\fR. +.TP +\fBstate\fR +. +For dictionary key \fIstage\fR. .TP \fBstatus\fR . -See description in the chapter \fBERRORS\fR above for a -list and description of \fBstatus\fR. -During the transaction this value is the empty string. +For command \fB::http::status\fR; and for dictionary key \fIstatus\fR. .TP \fBtotalsize\fR . -A copy of the \fBContent-Length\fR metadata value. +For dictionary key \fItotalSize\fR. +.TP +\fBtransfer\fR +. +For dictionary key \fItransferEncoding\fR. .TP \fBtype\fR . -A copy of the \fBContent-Type\fR metadata value. +For dictionary key \fIcontentType\fR. +.TP +\fBupgrade\fR +. +For dictionary key \fIupgrade\fR. .TP \fBurl\fR . -The requested URL. +For dictionary key \fIurl\fR. .RE .SH "PERSISTENT CONNECTIONS" .PP @@ -1153,7 +1417,7 @@ that fails because it uses a persistent connection that the server has half-closed (an .QW "asynchronous close event" ). Subsequent GET and HEAD requests in a failed pipeline will also be retried. -\fIThe \-repost option should be used only if the application understands +\fIThe \fB\-repost\fI option should be used only if the application understands that the retry is appropriate\fR - specifically, the application must know that if the failed POST successfully modified the state of the server, a repeat POST would have no adverse effect. @@ -1261,22 +1525,25 @@ Other keys may always be ignored; they have no meaning in this protocol. .VE TIP406 .SH "PROTOCOL UPGRADES" .PP -The HTTP/1.1 \fBConnection\fR and \fBUpgrade\fR client headers inform the server -that the client wishes to change the protocol used over the existing connection -(RFC 7230). This mechanism can be used to request a WebSocket (RFC 6455), a +The HTTP/1.1 \fBConnection\fR and \fBUpgrade\fR request headers inform the +server that the client wishes to change the protocol used over the existing +connection (RFC 7230). +This mechanism can be used to request a WebSocket (RFC 6455), a higher version of the HTTP protocol (HTTP 2), or TLS encryption. If the server accepts the upgrade request, its response code will be 101. .PP -To request a protocol upgrade when calling \fBhttp::geturl\fR, the \fB\-headers\fR -option must supply appropriate values for \fBConnection\fR and \fBUpgrade\fR, and +To request a protocol upgrade when calling \fBhttp::geturl\fR, +the \fB\-headers\fR option must supply appropriate values for \fBConnection\fR +and \fBUpgrade\fR, and the \fB\-command\fR option must supply a command that implements the requested protocol and can also handle the server response if the server refuses the protocol upgrade. For upgrade requests \fBhttp::geturl\fR ignores the value of option \fB\-keepalive\fR, and always uses the value \fB0\fR so that the upgrade -request is not made over a connection that is intended for multiple HTTP requests. +request is not made over a connection that is intended for multiple HTTP +requests. .PP -The Tcllib library \fBwebsocket\fR implements WebSockets, and makes the necessary -calls to commands in the \fBhttp\fR package. +The Tcllib library \fBwebsocket\fR implements WebSockets, and makes the +necessary calls to commands in the \fBhttp\fR package. .PP There is currently no native Tcl client library for HTTP/2. .PP @@ -1287,30 +1554,59 @@ protocols such as Internet Printing Protocol (IPP) that are built on top of traffic. .PP In browsers, opportunistic encryption is instead implemented by the -\fBUpgrade-Insecure-Requests\fR client header. If a secure service is available, -the server response code is a 307 redirect, and the response header -\fBLocation\fR specifies the target URL. The browser must call \fBhttp::geturl\fR -again in order to fetch this URL. +\fBUpgrade-Insecure-Requests\fR client header. If a secure service is +available, the server response code is a 307 redirect, and the response header +\fBLocation\fR specifies the target URL. The browser must +call \fBhttp::geturl\fR again in order to fetch this URL. See https://w3c.github.io/webappsec-upgrade-insecure-requests/ .PP .SH THREADS .PP .SS "PURPOSE" .PP -Command \fB::http::geturl\fR uses the Tcl \fB::socket\fR command with the \-async option to connect to a remote server, but the return from this command can be delayed in adverse cases (e.g. a slow DNS lookup), preventing the event loop from processing other events. This delay is avoided if the \fB::socket\fR command is evaluated in another thread. The Thread package is not part of Tcl but is provided in "Batteries Included" distributions. Instead of the \fB::socket\fR command, the http package uses \fB::http::socket\fR which makes connections in the manner specified by the value of \-threadlevel and the availability of package Thread. +Command \fB::http::geturl\fR uses the Tcl \fB::socket\fR command with +the \fI\-async\fR option to connect to a remote server, but the return from +this command can be delayed in adverse cases (e.g. a slow DNS lookup), +preventing the event loop from processing other events. +This delay is avoided if the \fB::socket\fR command is evaluated in another +thread. The Thread package is not part of Tcl but is provided in +"Batteries Included" distributions. Instead of the \fB::socket\fR command, +the http package uses \fB::http::socket\fR which makes connections in the +manner specified by the value of \fI\-threadlevel\fR and the availability +of package Thread. .PP .SS "WITH TLS (HTTPS)" .PP -The same \-threadlevel configuration applies to both HTTP and HTTPS connections. HTTPS is enabled by using the \fBhttp::register\fR command, typically by specifying the \fB::tls::socket\fR command of the tls package to handle TLS cryptography. The \fB::tls::socket\fR command connects to the remote server by using the command specified by the value of variable \fI::tls::socketCmd\fR, and this value defaults to "::socket". If http::geturl finds that \fI::tls::socketCmd\fR has this value, it replaces it with the value "::http::socket". If \fI::tls::socketCmd\fR has a value other than "::socket", i.e. if the script or the Tcl installation has replaced the value "::socket" with the name of a different command, then http does not change the value. The script or installation that modified \fI::tls::socketCmd\fR is responsible for integrating \fR::http::socket\fR into its own replacement command. +The same \fI\-threadlevel\fR configuration applies to both HTTP and HTTPS +connections. +HTTPS is enabled by using the \fBhttp::register\fR command, typically by +specifying the \fB::tls::socket\fR command of the tls package to handle TLS +cryptography. The \fB::tls::socket\fR command connects to the remote server by +using the command specified by the value of variable \fI::tls::socketCmd\fR, and +this value defaults to "::socket". If http::geturl finds +that \fI::tls::socketCmd\fR has this value, it replaces it with the value +"::http::socket". If \fI::tls::socketCmd\fR has a value other than "::socket", +i.e. if the script or the Tcl installation has replaced the value "::socket" +with the name of a different command, then http does not change the value. +The script or installation that modified \fI::tls::socketCmd\fR is responsible +for integrating \fR::http::socket\fR into its own replacement command. .PP .SS "WITH A CHILD INTERPRETER" .PP -The peer thread can transfer the socket only to the main interpreter of the script's thread. Therefore the thread-based \fB::http::socket\fR works with non-zero \-threadlevel values only if the script runs in the main interpreter. A child interpreter must use \-threadlevel 0 unless the parent interpreter has provided alternative facilities. The main parent interpreter may grant full \-threadlevel facilities to a child interpreter, for example by aliasing, to \fB::http::socket\fR in the child, a command that runs \fBhttp::socket\fR in the parent, and then transfers the socket to the child. +The peer thread can transfer the socket only to the main interpreter of the +script's thread. Therefore the thread-based \fB::http::socket\fR works with +non-zero \fI\-threadlevel\fR values only if the script runs in the main +interpreter. A child interpreter must use \fI\-threadlevel 0\fR unless the +parent interpreter has provided alternative facilities. The main parent +interpreter may grant full \fI\-threadlevel\fR facilities to a child +interpreter, for example by aliasing, to \fB::http::socket\fR in the child, +a command that runs \fBhttp::socket\fR in the parent, and then transfers +the socket to the child. .PP .SH EXAMPLE .PP This example creates a procedure to copy a URL to a file while printing a -progress meter, and prints the metadata associated with the URL. +progress meter, and prints the response headers associated with the URL. .PP .CS proc httpcopy { url file {chunk 4096} } { @@ -1322,7 +1618,7 @@ proc httpcopy { url file {chunk 4096} } { # This ends the line started by httpCopyProgress puts stderr "" - upvar #0 $token state + upvar 0 $token state set max 0 foreach {name value} $state(meta) { if {[string length $name] > $max} { diff --git a/library/http/http.tcl b/library/http/http.tcl index 15fd031..23b065c 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -1016,8 +1016,8 @@ proc http::CreateToken {url args} { status "" http "" httpResponse {} - ncode {} - reason {} + responseCode {} + reasonPhrase {} connection keep-alive tid {} requestHeaders {} @@ -1651,37 +1651,18 @@ proc http::OpenSocket {token DoLater} { dict unset socketCoEvent($state(socketinfo)) $token unset -nocomplain state(socketcoro) - set reusing $state(reusing) + if {[catch { + if {$state(reusing)} { + # If ($state(reusing)) is true, then we do not need to create a new + # socket, even if $sockOld is only a placeholder for a socket. + set sock $sockOld + } else { + # set sock in the [catch] below. + set pre [clock milliseconds] + ##Log pre socket opened, - token $token + ##Log $state(openCmd) - token $token + set sock [namespace eval :: $state(openCmd)] - if {$reusing} { - # If ($reusing) is true, then we do not need to create a new socket, - # even if $sockOld is only a placeholder for a socket. - set sock $sockOld - } else { - # set sock in the [catch] below. - set pre [clock milliseconds] - ##Log pre socket opened, - token $token - ##Log $state(openCmd) - token $token - if {[catch {namespace eval :: $state(openCmd)} sock errdict]} { - # ERROR CASE - # Something went wrong while trying to establish the connection. - # Tidy up after events and such, but DON'T call the command - # callback (if available). - # - When this was inline code in http::geturl, it threw an exception - # from here instead. - # - Now that this code is called from geturl as an idletask and not - # as inline code, it is inappropriate to run cleanup or throw an - # exception. Instead do a normal return, and let Finish report - # the error using token/state and the -command callback. - # Finish also undoes PreparePersistentConnection. - - set state(sock) NONE - set ::errorInfo [dict get $errdict -errorinfo] - set ::errorCode [dict get $errdict -errorcode] - Finish $token $sock - # cleanup $token - return - } else { # Normal return from $state(openCmd) always returns a valid socket. # Initialisation of a new socket. ##Log post socket opened, - token $token @@ -1694,15 +1675,16 @@ proc http::OpenSocket {token DoLater} { fconfigure $sock -translation {auto crlf} \ -buffersize $state(-blocksize) ##Log socket opened, DONE fconfigure - token $token - } - } - - Log "Using $sock for $state(socketinfo) - token $token" \ - [expr {$state(-keepalive)?"keepalive":""}] + } - # Code above has set state(sock) $sock - ConfigureNewSocket $token $sockOld $DoLater + Log "Using $sock for $state(socketinfo) - token $token" \ + [expr {$state(-keepalive)?"keepalive":""}] + # Code above has set state(sock) $sock + ConfigureNewSocket $token $sockOld $DoLater + } result errdict]} { + Finish $token $result + } ##Log Leaving http::OpenSocket coroutine [info coroutine] - token $token return } @@ -3084,47 +3066,62 @@ proc http::Meta {token who args} { # Arguments: # token - connection token (name of an array) # -# Return Value: a dict +# Return Value: a dict. See man page http(n) for a description of each item. # ------------------------------------------------------------------------------ proc http::responseInfo {token} { variable $token upvar 0 $token state set result {} - foreach key { - stage - status - ncode - reason - type - binary - redirection - charset - coding - httpRequest - httpResponse - url - connRequest - connResponse - connection - transfer - querylength - queryoffset - totalsize - currentsize + foreach {key origin name} { + stage STATE state + status STATE status + responseCode STATE responseCode + reasonPhrase STATE reasonPhrase + contentType STATE type + binary STATE binary + redirection RESP location + upgrade STATE upgrade + error ERROR - + postError STATE posterror + method STATE method + charset STATE charset + compression STATE coding + httpRequest STATE -protocol + httpResponse STATE httpResponse + url STATE url + connectionRequest REQ connection + connectionResponse RESP connection + connectionActual STATE connection + transferEncoding STATE transfer + totalPost STATE querylength + currentPost STATE queryoffset + totalSize STATE totalsize + currentSize STATE currentsize } { - if {$key eq {stage}} { - dict set result $key $state(state) - } elseif {$key eq {redirection}} { - dict set result $key [responseHeaderValue $token Location] - } elseif {$key eq {httpRequest}} { - dict set result $key $state(-protocol) - } elseif {$key eq {connRequest}} { - dict set result $key [requestHeaderValue $token connection] - } elseif {$key eq {connResponse}} { - dict set result $key [responseHeaderValue $token connection] + if {$origin eq {STATE}} { + if {[info exists state($name)]} { + dict set result $key $state($name) + } else { + # Should never come here + dict set result $key {} + } + } elseif {$origin eq {REQ}} { + dict set result $key [requestHeaderValue $token $name] + } elseif {$origin eq {RESP}} { + dict set result $key [responseHeaderValue $token $name] + } elseif {$origin eq {ERROR}} { + # Don't flood the dict with data. The command ::http::error is + # available. + if {[info exists state(error)]} { + set msg [lindex $state(error) 0] + } else { + set msg {} + } + dict set result $key $msg } else { - dict set result $key $state($key) + # Should never come here + dict set result $key {} } } return $result @@ -3140,8 +3137,8 @@ proc http::error {token} { proc http::postError {token} { variable $token upvar 0 $token state - if {[info exists state(posterror)]} { - return $state(posterror) + if {[info exists state(postErrorFull)]} { + return $state(postErrorFull) } return } @@ -3309,11 +3306,13 @@ proc http::Write {token} { set done 1 } } - } err]} { + } err opts]} { # Do not call Finish here, but instead let the read half of the socket # process whatever server reply there is to get. - set state(posterror) $err + set info [dict get $opts -errorinfo] + set code [dict get $opts -code] + set state(postErrorFull) [list $err $info $code] set done 1 } @@ -3460,15 +3459,15 @@ proc http::Event {sock token} { # We have $state(http) so let's split it into its components. if {[regexp {^HTTP/(\S+) ([0-9]{3}) (.*)$} $state(http) \ - -> httpResponse ncode reason] + -> httpResponse responseCode reasonPhrase] } { set state(httpResponse) $httpResponse - set state(ncode) $ncode - set state(reason) $reason + set state(responseCode) $responseCode + set state(reasonPhrase) $reasonPhrase } else { set state(httpResponse) $state(http) - set state(ncode) $state(http) - set state(reason) $state(http) + set state(responseCode) $state(http) + set state(reasonPhrase) $state(http) } if { ([info exists state(connection)]) @@ -3674,13 +3673,12 @@ proc http::Event {sock token} { connection { # RFC 7230 Section 6.1 states that a comma-separated # list is an acceptable value. - if {![info exists state(connectionResponse)]} { + if {![info exists state(connectionRespFlag)]} { # This is the first "Connection" response header. # Scrub the earlier value set by iniitialisation. - set state(connectionResponse) {} + set state(connectionRespFlag) {} set state(connection) {} } - set state(connOrig[incr ::countConn]) [string trim $value] foreach el [SplitCommaSeparatedFieldValue $value] { lappend state(connection) [string tolower $el] } @@ -4423,6 +4421,7 @@ proc http::GuessType {token} { set state(body) [encoding convertfrom $enc $state(body)] set state(body) [string map {\r\n \n \r \n} $state(body)] set state(type) application/xml + set state(binary) 0 set state(charset) $res return 1 } @@ -4732,6 +4731,10 @@ interp alias {} http::ncode {} http::responseCode # - The http::socket command is simple, and can easily be replaced with an # alternative command that uses a different technique to open a socket while # entering the event loop. +# - Unexpected behaviour by thread::send -async (Thread 2.8.6). +# An error in thread::send -async causes return of just the error message +# (not the expected 3 elements), and raises a bgerror in the main thread. +# Hence wrap the command with catch as a precaution. # ------------------------------------------------------------------------------ proc http::socket {args} { @@ -4756,8 +4759,11 @@ proc http::socket {args} { set defcmd ::socket set sockargs $args set script " - [list proc ::SockInThread {caller defcmd sockargs} [info body ::http::SockInThread]] - [list ::SockInThread [thread::id] $defcmd $sockargs] + set code \[catch { + [list proc ::SockInThread {caller defcmd sockargs} [info body ::http::SockInThread]] + [list ::SockInThread [thread::id] $defcmd $sockargs] + } result opts\] + list \$code \$opts \$result " set state(tid) [thread::create] @@ -4779,10 +4785,26 @@ proc http::socket {args} { Log >U Thread End Wait $args -- coro [info coroutine] $varName [set $varName] thread::release $state(tid) set state(tid) {} - lassign [set $varName] catchCode errdict sock + set result [set $varName] unset $varName - dict set errdict -code $catchCode - return -options $errdict $sock + if {(![string is list $result]) || ([llength $result] != 3)} { + return -code error "result from peer thread is not a list of\ + length 3: it is \n$result" + } + lassign $result threadCode threadDict threadResult + if {($threadCode != 0)} { + # This is an error in thread::send. Return the lot. + return -options $threadDict -code error $threadResult + } + + # Now the results of the catch in the peer thread. + lassign $threadResult catchCode errdict sock + + if {($catchCode == 0) && ($sock ni [chan names])} { + return -code error {Transfer of socket from peer thread failed.\ + Check that this script is not running in a child interpreter.} + } + return -options $errdict -code $catchCode $sock } # The commands below are dependencies of http::socket and -- cgit v0.12 From 95b9c7ea088595db27c858b2f8c651f4a5a27e3b Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 15 Sep 2022 18:34:56 +0000 Subject: When zipfs is finalized, be sure to unregister it. If this isn't done, then path resolution can re-enter the zipfs implementation code and try to lookup pathnames in hash tables that have been deleted. Crash! Panic! Bad! I see this easily in an app that embeds Tcl/Tk and uses multiple interps. Did not easily find a demo script in Tcl alone. --- generic/tclZipfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c index 82e125c..3b1d787 100644 --- a/generic/tclZipfs.c +++ b/generic/tclZipfs.c @@ -5773,6 +5773,7 @@ ZipfsExitHandler( static void ZipfsFinalize(void) { + Tcl_FSUnregister(&zipfsFilesystem); Tcl_DeleteHashTable(&ZipFS.fileHash); ckfree(ZipFS.fallbackEntryEncoding); ZipFS.initialized = -1; -- cgit v0.12 From bf9bd6f5fe6cf2220c77b85a5881596b5eebf27e Mon Sep 17 00:00:00 2001 From: kjnash Date: Thu, 15 Sep 2022 19:09:03 +0000 Subject: Undo temporary mods to tests. --- tests/httpPipeline.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/httpPipeline.test b/tests/httpPipeline.test index 50db441..161519f 100644 --- a/tests/httpPipeline.test +++ b/tests/httpPipeline.test @@ -674,7 +674,7 @@ proc RunTest {header footer delay te} { # If still obscure, uncomment #Log and ##Log lines in the http package. # ------------------------------------------------------------------------------ -setHttpTestOptions -verbose 2 +setHttpTestOptions -verbose 0 # ------------------------------------------------------------------------------ # (4) Define the base URLs used for testing. Each must have a query string. @@ -699,9 +699,9 @@ setHttpTestOptions -verbose 2 namespace eval ::httpTestScript { variable URL array set URL { - a http://test-tcl-http.kerlin.org.minerva/index.html?page=privacy - b http://test-tcl-http.kerlin.org.minerva/index.html?page=conditions - c http://test-tcl-http.kerlin.org.minerva/index.html?page=welcome + a http://test-tcl-http.kerlin.org/index.html?page=privacy + b http://test-tcl-http.kerlin.org/index.html?page=conditions + c http://test-tcl-http.kerlin.org/index.html?page=welcome } } -- cgit v0.12 From 9b0b59d046f223efca4855691ed4f476fa43b1b8 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 15 Sep 2022 22:14:24 +0000 Subject: new testcase proc-7.6 --- tests/proc.test | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/proc.test b/tests/proc.test index f453bea..72cb412 100644 --- a/tests/proc.test +++ b/tests/proc.test @@ -8,7 +8,7 @@ # No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. -# Copyright (c) 1998-1999 by Scriptics Corporation. +# Copyright (c) 1998-1999 Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -411,6 +411,13 @@ test proc-7.5 {[631b4c45df] Crash in argument processing} { unset -nocomplain val } {} +test proc-7.6 {[51d5f22997] Crash in argument processing} -cleanup { + rename foo {} +} -body { + proc foo {{x {}} {y {}} args} {} + foo +} -result {} + # cleanup catch {rename p ""} -- cgit v0.12