diff options
Diffstat (limited to 'generic')
48 files changed, 1738 insertions, 818 deletions
diff --git a/generic/tcl.decls b/generic/tcl.decls index ba047a0..b2b91a9 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -1059,7 +1059,7 @@ declare 293 { int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags) } declare 294 { - void Tcl_ExitThread(int status) + TCL_NORETURN void Tcl_ExitThread(int status) } declare 295 { int Tcl_ExternalToUtf(Tcl_Interp *interp, Tcl_Encoding encoding, diff --git a/generic/tcl.h b/generic/tcl.h index d678229..6fa26f9 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -41,7 +41,6 @@ extern "C" { * unix/configure.ac (2 LOC Major, 2 LOC minor, 1 LOC patch) * win/configure.ac (as above) * win/tcl.m4 (not patchlevel) - * win/makefile.bc (not patchlevel) 2 LOC * README (sections 0 and 2, with and without separator) * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC @@ -61,6 +60,7 @@ extern "C" { #define TCL_VERSION "8.7" #define TCL_PATCH_LEVEL "8.7a0" +#if !defined(TCL_NO_DEPRECATED) || defined(RC_INVOKED) /* *---------------------------------------------------------------------------- * The following definitions set up the proper options for Windows compilers. @@ -89,6 +89,7 @@ extern "C" { # define JOIN(a,b) JOIN1(a,b) # define JOIN1(a,b) a##b #endif +#endif /* !TCL_NO_DEPRECATED */ /* * A special definition used to allow this header file to be included from @@ -140,7 +141,7 @@ extern "C" { # define TCL_VARARGS(type, name) (type name, ...) # define TCL_VARARGS_DEF(type, name) (type name, ...) # define TCL_VARARGS_START(type, name, list) (va_start(list, name), name) -#endif +#endif /* !TCL_NO_DEPRECATED */ #if defined(__GNUC__) && (__GNUC__ > 2) # define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b))) # define TCL_NORETURN __attribute__ ((noreturn)) @@ -256,7 +257,7 @@ extern "C" { #ifndef TCL_NO_DEPRECATED # undef _ANSI_ARGS_ # define _ANSI_ARGS_(x) x -#endif +#endif /* !TCL_NO_DEPRECATED */ /* * Definitions that allow this header file to be used either with or without @@ -376,8 +377,8 @@ typedef long LONG; * we have one, we can have the other.) * * Also defines the following macros: - * TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on a real - * 64-bit system.) + * TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on a + * LP64 system such as modern Solaris or Linux ... not including Win64) * Tcl_WideAsLong - forgetful converter from wideInt to long. * Tcl_LongAsWide - sign-extending converter from long to wideInt. * Tcl_WideAsDouble - converter from wideInt to double. @@ -394,11 +395,7 @@ typedef long LONG; #if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG) # if defined(_WIN32) # define TCL_WIDE_INT_TYPE __int64 -# ifdef __BORLANDC__ -# define TCL_LL_MODIFIER "L" -# else /* __BORLANDC__ */ -# define TCL_LL_MODIFIER "I64" -# endif /* __BORLANDC__ */ +# define TCL_LL_MODIFIER "I64" # elif defined(__GNUC__) # define TCL_WIDE_INT_TYPE long long # define TCL_LL_MODIFIER "ll" @@ -424,10 +421,6 @@ typedef TCL_WIDE_INT_TYPE Tcl_WideInt; typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; #ifdef TCL_WIDE_INT_IS_LONG -# define Tcl_WideAsLong(val) ((long)(val)) -# define Tcl_LongAsWide(val) ((long)(val)) -# define Tcl_WideAsDouble(val) ((double)((long)(val))) -# define Tcl_DoubleAsWide(val) ((long)((double)(val))) # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "l" # endif /* !TCL_LL_MODIFIER */ @@ -439,12 +432,13 @@ typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "ll" # endif /* !TCL_LL_MODIFIER */ -# define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val))) -# define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val))) -# define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) -# define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) #endif /* TCL_WIDE_INT_IS_LONG */ +#define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val))) +#define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val))) +#define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) +#define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) + #if defined(_WIN32) # ifdef __BORLANDC__ typedef struct stati64 Tcl_StatBuf; @@ -529,7 +523,7 @@ typedef struct Tcl_Interp int errorLineDontUse; /* Don't use in extensions! */ #endif } -#endif /* TCL_NO_DEPRECATED */ +#endif /* !TCL_NO_DEPRECATED */ Tcl_Interp; typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; @@ -1003,7 +997,9 @@ typedef struct Tcl_DString { #define Tcl_DStringLength(dsPtr) ((dsPtr)->length) #define Tcl_DStringValue(dsPtr) ((dsPtr)->string) -#define Tcl_DStringTrunc Tcl_DStringSetLength +#ifndef TCL_NO_DEPRECATED +# define Tcl_DStringTrunc Tcl_DStringSetLength +#endif /* !TCL_NO_DEPRECATED */ /* * Definitions for the maximum number of digits of precision that may be @@ -1131,7 +1127,7 @@ typedef struct Tcl_DString { #ifndef TCL_NO_DEPRECATED # define TCL_PARSE_PART1 0x400 -#endif +#endif /* !TCL_NO_DEPRECATED */ /* * Types for linked variables: @@ -2539,7 +2535,7 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); Tcl_DbNewBignumObj(val, __FILE__, __LINE__) # undef Tcl_NewBooleanObj # define Tcl_NewBooleanObj(val) \ - Tcl_DbNewBooleanObj(val, __FILE__, __LINE__) + Tcl_DbNewLongObj((val)!=0, __FILE__, __LINE__) # undef Tcl_NewByteArrayObj # define Tcl_NewByteArrayObj(bytes, len) \ Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) @@ -2632,7 +2628,6 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); # define panic Tcl_Panic #endif # define panicVA Tcl_PanicVA -#endif /* !TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------------- @@ -2643,6 +2638,8 @@ EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); extern Tcl_AppInitProc Tcl_AppInit; +#endif /* !TCL_NO_DEPRECATED */ + #endif /* RC_INVOKED */ /* diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c index 2212d1c..4c5ae68 100644 --- a/generic/tclAssembly.c +++ b/generic/tclAssembly.c @@ -137,6 +137,8 @@ typedef enum TalInstType { * ranges */ ASSEM_BOOL, /* One Boolean operand */ ASSEM_BOOL_LVT4, /* One Boolean, one 4-byte LVT ref. */ + ASSEM_CLOCK_READ, /* 1-byte unsigned-integer case number, in the + * range 0-3 */ ASSEM_CONCAT1, /* 1-byte unsigned-integer operand count, must * be strictly positive, consumes N, produces * 1 */ @@ -350,6 +352,7 @@ static const TalInstDesc TalInstructionTable[] = { {"bitnot", ASSEM_1BYTE, INST_BITNOT, 1, 1}, {"bitor", ASSEM_1BYTE, INST_BITOR, 2, 1}, {"bitxor", ASSEM_1BYTE, INST_BITXOR, 2, 1}, + {"clockRead", ASSEM_CLOCK_READ, INST_CLOCK_READ, 0, 1}, {"concat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1}, {"concatStk", ASSEM_LIST, INST_CONCAT_STK, INT_MIN,1}, {"coroName", ASSEM_1BYTE, INST_COROUTINE_NAME, 0, 1}, @@ -1361,6 +1364,23 @@ AssembleOneLine( TclEmitInt4(localVar, envPtr); break; + case ASSEM_CLOCK_READ: + if (parsePtr->numWords != 2) { + Tcl_WrongNumArgs(interp, 1, &instNameObj, "imm8"); + goto cleanup; + } + if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) { + goto cleanup; + } + if (opnd < 0 || opnd > 3) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("operand must be [0..3]", -1)); + Tcl_SetErrorCode(interp, "TCL", "ASSEM", "OPERAND<0,>3", NULL); + goto cleanup; + } + BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, opnd); + break; + case ASSEM_CONCAT1: if (parsePtr->numWords != 2) { Tcl_WrongNumArgs(interp, 1, &instNameObj, "imm8"); @@ -4246,7 +4266,7 @@ AddBasicBlockRangeToErrorInfo( Tcl_AppendObjToErrorInfo(interp, lineNo); Tcl_AddErrorInfo(interp, " and "); if (bbPtr->successor1 != NULL) { - Tcl_SetIntObj(lineNo, bbPtr->successor1->startLine); + TclSetLongObj(lineNo, bbPtr->successor1->startLine); Tcl_AppendObjToErrorInfo(interp, lineNo); } else { Tcl_AddErrorInfo(interp, "end of assembly code"); diff --git a/generic/tclBasic.c b/generic/tclBasic.c index cd7bd73..4093614 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -265,7 +265,6 @@ static const CmdInfo builtInCmds[] = { {"cd", Tcl_CdObjCmd, NULL, NULL, 0}, {"close", Tcl_CloseObjCmd, NULL, NULL, CMD_IS_SAFE}, {"eof", Tcl_EofObjCmd, NULL, NULL, CMD_IS_SAFE}, - {"encoding", Tcl_EncodingObjCmd, NULL, NULL, 0}, {"exec", Tcl_ExecObjCmd, NULL, NULL, 0}, {"exit", Tcl_ExitObjCmd, NULL, NULL, 0}, {"fblocked", Tcl_FblockedObjCmd, NULL, NULL, CMD_IS_SAFE}, @@ -512,7 +511,11 @@ Tcl_CreateInterp(void) iPtr = ckalloc(sizeof(Interp)); interp = (Tcl_Interp *) iPtr; +#ifdef TCL_NO_DEPRECATED + iPtr->result = &tclEmptyString; +#else iPtr->result = iPtr->resultSpace; +#endif iPtr->freeProc = NULL; iPtr->errorLine = 0; iPtr->objResultPtr = Tcl_NewObj(); @@ -572,9 +575,11 @@ Tcl_CreateInterp(void) iPtr->rootFramePtr = NULL; /* Initialise as soon as :: is available */ iPtr->lookupNsPtr = NULL; +#ifndef TCL_NO_DEPRECATED iPtr->appendResult = NULL; iPtr->appendAvl = 0; iPtr->appendUsed = 0; +#endif Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS); iPtr->packageUnknown = NULL; @@ -604,7 +609,9 @@ Tcl_CreateInterp(void) iPtr->emptyObjPtr = Tcl_NewObj(); /* Another empty object. */ Tcl_IncrRefCount(iPtr->emptyObjPtr); +#ifndef TCL_NO_DEPRECATED iPtr->resultSpace[0] = 0; +#endif iPtr->threadId = Tcl_GetCurrentThread(); /* TIP #378 */ @@ -791,16 +798,17 @@ Tcl_CreateInterp(void) } /* - * Create the "array", "binary", "chan", "dict", "file", "info", - * "namespace" and "string" ensembles. Note that all these commands (and - * their subcommands that are not present in the global namespace) are - * wholly safe *except* for "file". + * Create the "array", "binary", "chan", "clock", "dict", "encoding", + * "file", "info", "namespace" and "string" ensembles. Note that all these + * commands (and their subcommands that are not present in the global + * namespace) are wholly safe *except* for "clock", "encoding" and "file". */ TclInitArrayCmd(interp); TclInitBinaryCmd(interp); TclInitChanCmd(interp); TclInitDictCmd(interp); + TclInitEncodingCmd(interp); TclInitFileCmd(interp); TclInitInfoCmd(interp); TclInitNamespaceCmd(interp); @@ -1028,6 +1036,7 @@ TclHideUnsafeCommands( Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name); } } + TclMakeEncodingCommandSafe(interp); /* Ugh! */ TclMakeFileCommandSafe(interp); /* Ugh! */ return TCL_OK; } @@ -1063,7 +1072,7 @@ Tcl_CallWhenDeleted( Interp *iPtr = (Interp *) interp; static Tcl_ThreadDataKey assocDataCounterKey; int *assocDataCounterPtr = - Tcl_GetThreadData(&assocDataCounterKey, (int)sizeof(int)); + Tcl_GetThreadData(&assocDataCounterKey, sizeof(int)); int isNew; char buffer[32 + TCL_INTEGER_SPACE]; AssocData *dPtr = ckalloc(sizeof(AssocData)); @@ -1535,10 +1544,12 @@ DeleteInterpProc( if (iPtr->returnOpts) { Tcl_DecrRefCount(iPtr->returnOpts); } +#ifndef TCL_NO_DEPRECATED if (iPtr->appendResult != NULL) { ckfree(iPtr->appendResult); iPtr->appendResult = NULL; } +#endif TclFreePackageInfo(iPtr); while (iPtr->tracePtr != NULL) { Tcl_DeleteTrace((Tcl_Interp *) iPtr, (Tcl_Trace) iPtr->tracePtr); @@ -5851,6 +5862,7 @@ TclArgumentGet( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_Eval int Tcl_Eval( @@ -5903,6 +5915,7 @@ Tcl_GlobalEvalObj( { return Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -6729,6 +6742,7 @@ Tcl_AppendObjToErrorInfo( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_AddErrorInfo void Tcl_AddErrorInfo( @@ -6738,6 +6752,7 @@ Tcl_AddErrorInfo( { Tcl_AddObjErrorInfo(interp, message, -1); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -6910,6 +6925,7 @@ Tcl_VarEval( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_GlobalEval int Tcl_GlobalEval( @@ -6927,6 +6943,7 @@ Tcl_GlobalEval( iPtr->varFramePtr = savedVarFramePtr; return result; } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -8754,6 +8771,35 @@ TclNRCoroutineActivateCallback( /* *---------------------------------------------------------------------- * + * TclNREvalList -- + * + * Callback to invoke command as list, used in order to delayed + * processing of canonical list command in sane environment. + * + *---------------------------------------------------------------------- + */ + +static int +TclNREvalList( + ClientData data[], + Tcl_Interp *interp, + int result) +{ + int objc; + Tcl_Obj **objv; + Tcl_Obj *listPtr = data[0]; + + Tcl_IncrRefCount(listPtr); + + TclMarkTailcall(interp); + TclNRAddCallback(interp, TclNRReleaseValues, listPtr, NULL, NULL,NULL); + TclListObjGetElements(NULL, listPtr, &objc, &objv); + return TclNREvalObjv(interp, objc, objv, 0, NULL); +} + +/* + *---------------------------------------------------------------------- + * * NRCoroInjectObjCmd -- * * Implementation of [::tcl::unsupported::inject] command. @@ -8805,7 +8851,8 @@ NRCoroInjectObjCmd( */ iPtr->execEnvPtr = corPtr->eePtr; - TclNREvalObjEx(interp, Tcl_NewListObj(objc-2, objv+2), 0, NULL, INT_MIN); + TclNRAddCallback(interp, TclNREvalList, Tcl_NewListObj(objc-2, objv+2), + NULL, NULL, NULL); iPtr->execEnvPtr = savedEEPtr; return TCL_OK; diff --git a/generic/tclBinary.c b/generic/tclBinary.c index a3e5071..72f1498 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -1743,7 +1743,15 @@ GetFormatSpec( (*formatPtr)++; *countPtr = BINARY_ALL; } else if (isdigit(UCHAR(**formatPtr))) { /* INTL: digit */ - *countPtr = strtoul(*formatPtr, (char **) formatPtr, 10); + unsigned long int count; + + errno = 0; + count = strtoul(*formatPtr, (char **) formatPtr, 10); + if (errno || (count > (unsigned long) INT_MAX)) { + *countPtr = INT_MAX; + } else { + *countPtr = (int) count; + } } else { *countPtr = BINARY_NOCOUNT; } diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index d42536e..123d872 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -89,14 +89,14 @@ static struct mem_header *allocHead = NULL; /* List of allocated structures */ #define BODY_OFFSET \ ((size_t) (&((struct mem_header *) 0)->body)) -static int total_mallocs = 0; -static int total_frees = 0; +static unsigned int total_mallocs = 0; +static unsigned int total_frees = 0; static size_t current_bytes_malloced = 0; static size_t maximum_bytes_malloced = 0; -static int current_malloc_packets = 0; -static int maximum_malloc_packets = 0; -static int break_on_malloc = 0; -static int trace_on_at_malloc = 0; +static unsigned int current_malloc_packets = 0; +static unsigned int maximum_malloc_packets = 0; +static unsigned int break_on_malloc = 0; +static unsigned int trace_on_at_malloc = 0; static int alloc_tracing = FALSE; static int init_malloced_bodies = TRUE; #ifdef MEM_VALIDATE @@ -184,18 +184,18 @@ TclDumpMemoryInfo( return 0; } sprintf(buf, - "total mallocs %10d\n" - "total frees %10d\n" - "current packets allocated %10d\n" - "current bytes allocated %10lu\n" - "maximum packets allocated %10d\n" - "maximum bytes allocated %10lu\n", + "total mallocs %10u\n" + "total frees %10u\n" + "current packets allocated %10u\n" + "current bytes allocated %10" TCL_LL_MODIFIER "u\n" + "maximum packets allocated %10u\n" + "maximum bytes allocated %10" TCL_LL_MODIFIER "u\n", total_mallocs, total_frees, current_malloc_packets, - (unsigned long)current_bytes_malloced, + (Tcl_WideInt)current_bytes_malloced, maximum_malloc_packets, - (unsigned long)maximum_bytes_malloced); + (Tcl_WideInt)maximum_bytes_malloced); if (flags == 0) { fprintf((FILE *)clientData, "%s", buf); } else { @@ -359,9 +359,8 @@ Tcl_DumpActiveMemory( Tcl_MutexLock(ckallocMutexPtr); for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { address = &memScanP->body[0]; - fprintf(fileP, "%8" TCL_LL_MODIFIER "x - %8" TCL_LL_MODIFIER "x %7" TCL_LL_MODIFIER "d @ %s %d %s", - (Tcl_WideInt)(size_t)address, - (Tcl_WideInt)((size_t)address + memScanP->length - 1), + fprintf(fileP, "%p - %p %" TCL_LL_MODIFIER "d @ %s %d %s", + address, address + memScanP->length - 1, (Tcl_WideInt)memScanP->length, memScanP->file, memScanP->line, (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string); (void) fputc('\n', fileP); @@ -450,7 +449,7 @@ Tcl_DbCkalloc( total_mallocs++; if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { (void) fflush(stdout); - fprintf(stderr, "reached malloc trace enable point (%d)\n", + fprintf(stderr, "reached malloc trace enable point (%u)\n", total_mallocs); fflush(stderr); alloc_tracing = TRUE; @@ -465,7 +464,7 @@ Tcl_DbCkalloc( if (break_on_malloc && (total_mallocs >= break_on_malloc)) { break_on_malloc = 0; (void) fflush(stdout); - Tcl_Panic("reached malloc break limit (%d)", total_mallocs); + Tcl_Panic("reached malloc break limit (%u)", total_mallocs); } current_malloc_packets++; @@ -848,22 +847,24 @@ MemoryCmd( return TCL_OK; } if (strcmp(argv[1],"break_on_malloc") == 0) { + int value; if (argc != 3) { goto argError; } - if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) { + if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) { return TCL_ERROR; } + break_on_malloc = (unsigned int) value; return TCL_OK; } if (strcmp(argv[1],"info") == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10lu\n%-25s %10d\n%-25s %10lu\n", + "%-25s %10u\n%-25s %10u\n%-25s %10u\n%-25s %10" TCL_LL_MODIFIER"d\n%-25s %10u\n%-25s %10" TCL_LL_MODIFIER "d\n", "total mallocs", total_mallocs, "total frees", total_frees, "current packets allocated", current_malloc_packets, - "current bytes allocated", (unsigned long)current_bytes_malloced, + "current bytes allocated", (Tcl_WideInt)current_bytes_malloced, "maximum packets allocated", maximum_malloc_packets, - "maximum bytes allocated", (unsigned long)maximum_bytes_malloced)); + "maximum bytes allocated", (Tcl_WideInt)maximum_bytes_malloced)); return TCL_OK; } if (strcmp(argv[1], "init") == 0) { @@ -934,12 +935,14 @@ MemoryCmd( } if (strcmp(argv[1],"trace_on_at_malloc") == 0) { + int value; if (argc != 3) { goto argError; } - if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) { + if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) { return TCL_ERROR; } + trace_on_at_malloc = value; return TCL_OK; } if (strcmp(argv[1],"validate") == 0) { diff --git a/generic/tclClock.c b/generic/tclClock.c index cf52673..8d06375 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -17,6 +17,7 @@ #include "tclInt.h" #include "tclStrIdxTree.h" #include "tclDate.h" +#include "tclCompile.h" /* * Windows has mktime. The configurators do not check. @@ -152,26 +153,29 @@ struct ClockCommand { Tcl_ObjCmdProc *objCmdProc; /* Function that implements the command. This * will always have the ClockClientData sent * to it, but may well ignore this data. */ + CompileProc *compileProc; /* The compiler for the command. */ + ClientData clientData; /* Any clientData to give the command (if NULL + * a reference to ClockClientData will be sent) */ }; static const struct ClockCommand clockCommands[] = { - { "add", ClockAddObjCmd }, - { "clicks", ClockClicksObjCmd }, - { "getenv", ClockGetenvObjCmd }, - { "microseconds", ClockMicrosecondsObjCmd }, - { "milliseconds", ClockMillisecondsObjCmd }, - { "seconds", ClockSecondsObjCmd }, - { "format", ClockFormatObjCmd }, - { "scan", ClockScanObjCmd }, - { "configure", ClockConfigureObjCmd }, - { "Oldscan", TclClockOldscanObjCmd }, - { "ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd }, - { "GetDateFields", ClockGetdatefieldsObjCmd }, - { "GetJulianDayFromEraYearMonthDay", - ClockGetjuliandayfromerayearmonthdayObjCmd }, - { "GetJulianDayFromEraYearWeekDay", - ClockGetjuliandayfromerayearweekdayObjCmd }, - { NULL, NULL } + {"add", ClockAddObjCmd, TclCompileBasicMin1ArgCmd, NULL}, + {"clicks", ClockClicksObjCmd, TclCompileClockClicksCmd, NULL}, + {"format", ClockFormatObjCmd, TclCompileBasicMin1ArgCmd, NULL}, + {"getenv", ClockGetenvObjCmd, TclCompileBasicMin1ArgCmd, NULL}, + {"microseconds", ClockMicrosecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(1)}, + {"milliseconds", ClockMillisecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(2)}, + {"scan", ClockScanObjCmd, TclCompileBasicMin1ArgCmd, NULL}, + {"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3)}, + {"configure", ClockConfigureObjCmd, NULL, NULL}, + {"Oldscan", TclClockOldscanObjCmd, NULL, NULL}, + {"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL}, + {"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL}, + {"GetJulianDayFromEraYearMonthDay", + ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL}, + {"GetJulianDayFromEraYearWeekDay", + ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL}, + {NULL, NULL, NULL, NULL} }; /* @@ -200,6 +204,7 @@ TclClockInit( char cmdName[50]; /* Buffer large enough to hold the string *::tcl::clock::GetJulianDayFromEraYearMonthDay * plus a terminating NUL. */ + Command *cmdPtr; ClockClientData *data; int i; @@ -255,10 +260,18 @@ TclClockInit( #define TCL_CLOCK_PREFIX_LEN 14 /* == strlen("::tcl::clock::") */ memcpy(cmdName, "::tcl::clock::", TCL_CLOCK_PREFIX_LEN); for (clockCmdPtr=clockCommands ; clockCmdPtr->name!=NULL ; clockCmdPtr++) { + ClientData clientData; + strcpy(cmdName + TCL_CLOCK_PREFIX_LEN, clockCmdPtr->name); - data->refCount++; - Tcl_CreateObjCommand(interp, cmdName, clockCmdPtr->objCmdProc, data, - ClockDeleteCmdProc); + if (!(clientData = clockCmdPtr->clientData)) { + clientData = data; + data->refCount++; + } + cmdPtr = (Command *)Tcl_CreateObjCommand(interp, cmdName, + clockCmdPtr->objCmdProc, clientData, + clockCmdPtr->clientData ? NULL : ClockDeleteCmdProc); + cmdPtr->compileProc = clockCmdPtr->compileProc ? + clockCmdPtr->compileProc : TclCompileBasicMin0ArgCmd; } } @@ -2789,7 +2802,7 @@ ThreadSafeLocalTime( * Get a thread-local buffer to hold the returned time. */ - struct tm *tmPtr = Tcl_GetThreadData(&tmKey, (int) sizeof(struct tm)); + struct tm *tmPtr = Tcl_GetThreadData(&tmKey, sizeof(struct tm)); #ifdef HAVE_LOCALTIME_R localtime_r(timePtr, tmPtr); #else @@ -2852,7 +2865,7 @@ ClockClicksObjCmd( } break; default: - Tcl_WrongNumArgs(interp, 1, objv, "?-switch?"); + Tcl_WrongNumArgs(interp, 0, NULL, "clock clicks ?-switch?"); return TCL_ERROR; } @@ -2905,7 +2918,7 @@ ClockMillisecondsObjCmd( Tcl_Time now; if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, NULL, "clock milliseconds"); return TCL_ERROR; } Tcl_GetTime(&now); @@ -2940,7 +2953,7 @@ ClockMicrosecondsObjCmd( Tcl_Obj *const *objv) /* Parameter values */ { if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, NULL, "clock microseconds"); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetMicroseconds())); @@ -3210,7 +3223,7 @@ ClockFormatObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, "clockval|-now " + Tcl_WrongNumArgs(interp, 0, NULL, "clock format clockval|-now " "?-format string? " "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"); @@ -3285,7 +3298,7 @@ ClockScanObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, "string " + Tcl_WrongNumArgs(interp, 0, NULL, "clock scan string " "?-base seconds? " "?-format string? " "?-gmt boolean? " @@ -3844,7 +3857,7 @@ ClockAddObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, "clockval|-now ?number units?..." + Tcl_WrongNumArgs(interp, 0, NULL, "clock add clockval|-now ?number units?..." "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); @@ -4001,7 +4014,7 @@ ClockSecondsObjCmd( Tcl_Time now; if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, NULL, "clock seconds"); return TCL_ERROR; } Tcl_GetTime(&now); diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index d875bd4..70b3ad7 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -634,7 +634,7 @@ ClockFmtObj_UpdateString(objPtr) * * This is normally stored in second pointer of internal representation. * If format object is not localizable, it is equal the given format - * pointer and the first pointer of internal representation may be NULL. + * pointer (special case to fast fallback by not-localizable formats). * * Results: * Returns tcl object with key or format object if not localizable. @@ -825,16 +825,20 @@ ClockLocalizeFormat( return opts->formatObj; } + /* prevents loss of key object if the format object (where key stored) + * becomes changed (loses its internal representation during evals) */ + Tcl_IncrRefCount(keyObj); + if (opts->mcDictObj == NULL) { ClockMCDict(opts); if (opts->mcDictObj == NULL) - return NULL; + goto done; } /* try to find in cache within locale mc-catalog */ if (Tcl_DictObjGet(NULL, opts->mcDictObj, keyObj, &valObj) != TCL_OK) { - return NULL; + goto done; } /* call LocalizeFormat locale format fmtkey */ @@ -844,10 +848,9 @@ ClockLocalizeFormat( callargs[1] = opts->localeObj; callargs[2] = opts->formatObj; callargs[3] = keyObj; - Tcl_IncrRefCount(keyObj); if (Tcl_EvalObjv(opts->interp, 4, callargs, 0) != TCL_OK ) { - goto clean; + goto done; } valObj = Tcl_GetObjResult(opts->interp); @@ -857,9 +860,11 @@ ClockLocalizeFormat( keyObj, valObj) != TCL_OK ) { valObj = NULL; - goto clean; + goto done; } + Tcl_ResetResult(opts->interp); + /* check special case - format object is not localizable */ if (valObj == opts->formatObj) { /* mark it as unlocalizable, by setting self as key (without refcount incr) */ @@ -868,14 +873,11 @@ ClockLocalizeFormat( ObjLocFmtKey(opts->formatObj) = opts->formatObj; } } -clean: - - Tcl_UnsetObjRef(keyObj); - if (valObj) { - Tcl_ResetResult(opts->interp); - } } +done: + + Tcl_UnsetObjRef(keyObj); return (opts->formatObj = valObj); } @@ -1172,7 +1174,7 @@ ClockMCGetListIdxTree( goto done; }; - if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv) != TCL_OK) { + if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) { goto done; } @@ -1247,7 +1249,7 @@ ClockMCGetMultiListIdxTree( goto done; }; - if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv) != TCL_OK) { + if (TclStrIdxTreeBuildFromList(idxTree, lstc, lstv, NULL) != TCL_OK) { goto done; } mcKeys++; @@ -1299,12 +1301,12 @@ ClockStrIdxTreeSearch(ClockFmtScnCmdArgs *opts, /* not found */ return TCL_RETURN; } - if (foundItem->value == -1) { + if (!foundItem->value) { /* ambigous */ return TCL_RETURN; } - *val = foundItem->value; + *val = PTR2INT(foundItem->value); /* shift input pointer */ yyInput = f; @@ -1404,7 +1406,7 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts, return ret; } - yyMonth = val + 1; + yyMonth = val; return TCL_OK; } @@ -1443,6 +1445,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, if (ret != TCL_OK) { return ret; } + --val; } if (val != -1) { @@ -1474,6 +1477,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, if (ret != TCL_OK) { return ret; } + --val; if (val == 0) { val = 7; @@ -1576,7 +1580,7 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts, } if (tok->map->offs > 0) { - *(int *)(((char *)info) + tok->map->offs) = val; + *(int *)(((char *)info) + tok->map->offs) = --val; } return TCL_OK; diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 9c6f6a1..807a1ac 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -46,9 +46,24 @@ struct ForeachState { static int CheckAccess(Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode); +static int BadEncodingSubcommand(ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); +static int EncodingConvertfromObjCmd(ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); +static int EncodingConverttoObjCmd(ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); static int EncodingDirsObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +static int EncodingNamesObjCmd(ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); +static int EncodingSystemObjCmd(ClientData dummy, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); static inline int ForeachAssignments(Tcl_Interp *interp, struct ForeachState *statePtr); static inline void ForeachCleanup(Tcl_Interp *interp, @@ -542,79 +557,280 @@ Tcl_EncodingObjCmd( switch ((enum options) index) { case ENC_CONVERTTO: - case ENC_CONVERTFROM: { - Tcl_Obj *data; - Tcl_DString ds; - Tcl_Encoding encoding; - int length; - const char *stringPtr; - - if (objc == 3) { - encoding = Tcl_GetEncoding(interp, NULL); - data = objv[2]; - } else if (objc == 4) { - if (Tcl_GetEncodingFromObj(interp, objv[2], &encoding) != TCL_OK) { - return TCL_ERROR; - } - data = objv[3]; - } else { - Tcl_WrongNumArgs(interp, 2, objv, "?encoding? data"); - return TCL_ERROR; - } + return EncodingConverttoObjCmd(dummy, interp, objc, objv); + case ENC_CONVERTFROM: + return EncodingConvertfromObjCmd(dummy, interp, objc, objv); + case ENC_DIRS: + return EncodingDirsObjCmd(dummy, interp, objc, objv); + case ENC_NAMES: + return EncodingNamesObjCmd(dummy, interp, objc, objv); + case ENC_SYSTEM: + return EncodingSystemObjCmd(dummy, interp, objc, objv); + } + return TCL_OK; +} + +/* + *----------------------------------------------------------------------------- + * + * TclInitEncodingCmd -- + * + * This function creates the 'encoding' ensemble. + * + * Results: + * Returns the Tcl_Command so created. + * + * Side effects: + * The ensemble is initialized. + * + * This command is hidden in a safe interpreter. + */ - if ((enum options) index == ENC_CONVERTFROM) { - /* - * Treat the string as binary data. - */ +Tcl_Command +TclInitEncodingCmd( + Tcl_Interp* interp) /* Tcl interpreter */ +{ + static const EnsembleImplMap encodingImplMap[] = { + {"convertfrom", EncodingConvertfromObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"convertto", EncodingConverttoObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, + {"dirs", EncodingDirsObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {"names", EncodingNamesObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, + {"system", EncodingSystemObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} + }; - stringPtr = (char *) Tcl_GetByteArrayFromObj(data, &length); - Tcl_ExternalToUtfDString(encoding, stringPtr, length, &ds); + return TclMakeEnsemble(interp, "encoding", encodingImplMap); +} + +/* + *----------------------------------------------------------------------------- + * + * TclMakeEncodingCommandSafe -- + * + * This function hides the unsafe 'dirs' and 'system' subcommands of + * the "encoding" Tcl command ensemble. It must be called only from + * TclHideUnsafeCommands. + * + * Results: + * A standard Tcl result + * + * Side effects: + * Adds commands to the table of hidden commands. + * + *----------------------------------------------------------------------------- + */ + +int +TclMakeEncodingCommandSafe( + Tcl_Interp* interp) /* Tcl interpreter */ +{ + static const struct { + const char *cmdName; + int unsafe; + } unsafeInfo[] = { + {"convertfrom", 0}, + {"convertto", 0}, + {"dirs", 1}, + {"names", 0}, + {"system", 0}, + {NULL, 0} + }; - /* - * Note that we cannot use Tcl_DStringResult here because it will - * truncate the string at the first null byte. - */ + int i; + Tcl_DString oldBuf, newBuf; - Tcl_SetObjResult(interp, TclDStringToObj(&ds)); - } else { - /* - * Store the result as binary data. - */ - - stringPtr = TclGetStringFromObj(data, &length); - Tcl_UtfToExternalDString(encoding, stringPtr, length, &ds); - Tcl_SetObjResult(interp, Tcl_NewByteArrayObj( - (unsigned char *) Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds))); - Tcl_DStringFree(&ds); + Tcl_DStringInit(&oldBuf); + TclDStringAppendLiteral(&oldBuf, "::tcl::encoding::"); + Tcl_DStringInit(&newBuf); + TclDStringAppendLiteral(&newBuf, "tcl:encoding:"); + for (i=0 ; unsafeInfo[i].cmdName != NULL ; i++) { + if (unsafeInfo[i].unsafe) { + const char *oldName, *newName; + + Tcl_DStringSetLength(&oldBuf, 17); + oldName = Tcl_DStringAppend(&oldBuf, unsafeInfo[i].cmdName, -1); + Tcl_DStringSetLength(&newBuf, 13); + newName = Tcl_DStringAppend(&newBuf, unsafeInfo[i].cmdName, -1); + if (TclRenameCommand(interp, oldName, "___tmp") != TCL_OK + || Tcl_HideCommand(interp, "___tmp", newName) != TCL_OK) { + Tcl_Panic("problem making 'encoding %s' safe: %s", + unsafeInfo[i].cmdName, + Tcl_GetString(Tcl_GetObjResult(interp))); + } + Tcl_CreateObjCommand(interp, oldName, BadEncodingSubcommand, + (ClientData) unsafeInfo[i].cmdName, NULL); } + } + Tcl_DStringFree(&oldBuf); + Tcl_DStringFree(&newBuf); - Tcl_FreeEncoding(encoding); - break; + /* + * Ugh. The [encoding] command is now actually safe, but it is assumed by + * scripts that it is not, which messes up security policies. + */ + + if (Tcl_HideCommand(interp, "encoding", "encoding") != TCL_OK) { + Tcl_Panic("problem making 'encoding' safe: %s", + Tcl_GetString(Tcl_GetObjResult(interp))); } - case ENC_DIRS: - return EncodingDirsObjCmd(dummy, interp, objc, objv); - case ENC_NAMES: - if (objc > 2) { - Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * BadEncodingSubcommand -- + * + * Command used to act as a backstop implementation when subcommands of + * "encoding" are unsafe (the real implementations of the subcommands are + * hidden). The clientData is always the full official subcommand name. + * + * Results: + * A standard Tcl result (always a TCL_ERROR). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +BadEncodingSubcommand( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + const char *subcommandName = (const char *) clientData; + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "not allowed to invoke subcommand %s of encoding", subcommandName)); + Tcl_SetErrorCode(interp, "TCL", "SAFE", "SUBCOMMAND", NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * EncodingConvertfromObjCmd -- + * + * This command converts a byte array in an external encoding into a + * Tcl string + * + * Results: + * A standard Tcl result. + * + *---------------------------------------------------------------------- + */ + +int +EncodingConvertfromObjCmd( + ClientData dummy, /* Not used. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + Tcl_Obj *data; /* Byte array to convert */ + Tcl_DString ds; /* Buffer to hold the string */ + Tcl_Encoding encoding; /* Encoding to use */ + int length; /* Length of the byte array being converted */ + const char *bytesPtr; /* Pointer to the first byte of the array */ + + if (objc == 2) { + encoding = Tcl_GetEncoding(interp, NULL); + data = objv[1]; + } else if (objc == 3) { + if (Tcl_GetEncodingFromObj(interp, objv[1], &encoding) != TCL_OK) { return TCL_ERROR; } - Tcl_GetEncodingNames(interp); - break; - case ENC_SYSTEM: - if (objc > 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?encoding?"); + data = objv[2]; + } else { + Tcl_WrongNumArgs(interp, 1, objv, "?encoding? data"); + return TCL_ERROR; + } + + /* + * Convert the string into a byte array in 'ds' + */ + bytesPtr = (char *) Tcl_GetByteArrayFromObj(data, &length); + Tcl_ExternalToUtfDString(encoding, bytesPtr, length, &ds); + + /* + * Note that we cannot use Tcl_DStringResult here because it will + * truncate the string at the first null byte. + */ + + Tcl_SetObjResult(interp, TclDStringToObj(&ds)); + + /* + * We're done with the encoding + */ + + Tcl_FreeEncoding(encoding); + return TCL_OK; + +} + +/* + *---------------------------------------------------------------------- + * + * EncodingConverttoObjCmd -- + * + * This command converts a Tcl string into a byte array that + * encodes the string according to some encoding. + * + * Results: + * A standard Tcl result. + * + *---------------------------------------------------------------------- + */ + +int +EncodingConverttoObjCmd( + ClientData dummy, /* Not used. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + Tcl_Obj *data; /* String to convert */ + Tcl_DString ds; /* Buffer to hold the byte array */ + Tcl_Encoding encoding; /* Encoding to use */ + int length; /* Length of the string being converted */ + const char *stringPtr; /* Pointer to the first byte of the string */ + + /* TODO - ADJUST OBJ INDICES WHEN ENSEMBLIFYING THIS */ + + if (objc == 2) { + encoding = Tcl_GetEncoding(interp, NULL); + data = objv[1]; + } else if (objc == 3) { + if (Tcl_GetEncodingFromObj(interp, objv[1], &encoding) != TCL_OK) { return TCL_ERROR; } - if (objc == 2) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - Tcl_GetEncodingName(NULL), -1)); - } else { - return Tcl_SetSystemEncoding(interp, TclGetString(objv[2])); - } - break; + data = objv[2]; + } else { + Tcl_WrongNumArgs(interp, 1, objv, "?encoding? data"); + return TCL_ERROR; } + + /* + * Convert the string to a byte array in 'ds' + */ + + stringPtr = TclGetStringFromObj(data, &length); + Tcl_UtfToExternalDString(encoding, stringPtr, length, &ds); + Tcl_SetObjResult(interp, + Tcl_NewByteArrayObj((unsigned char*) Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds))); + Tcl_DStringFree(&ds); + + /* + * We're done with the encoding + */ + + Tcl_FreeEncoding(encoding); return TCL_OK; + } /* @@ -642,16 +858,16 @@ EncodingDirsObjCmd( { Tcl_Obj *dirListObj; - if (objc > 3) { - Tcl_WrongNumArgs(interp, 2, objv, "?dirList?"); + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?dirList?"); return TCL_ERROR; } - if (objc == 2) { + if (objc == 1) { Tcl_SetObjResult(interp, Tcl_GetEncodingSearchPath()); return TCL_OK; } - dirListObj = objv[2]; + dirListObj = objv[1]; if (Tcl_SetEncodingSearchPath(dirListObj) == TCL_ERROR) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected directory list but got \"%s\"", @@ -665,6 +881,68 @@ EncodingDirsObjCmd( } /* + *----------------------------------------------------------------------------- + * + * EncodingNamesObjCmd -- + * + * This command returns a list of the available encoding names + * + * Results: + * Returns a standard Tcl result + * + *----------------------------------------------------------------------------- + */ + +int +EncodingNamesObjCmd(ClientData dummy, /* Unused */ + Tcl_Interp* interp, /* Tcl interpreter */ + int objc, /* Number of command line args */ + Tcl_Obj* const objv[]) /* Vector of command line args */ +{ + if (objc > 1) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return TCL_ERROR; + } + Tcl_GetEncodingNames(interp); + return TCL_OK; +} + +/* + *----------------------------------------------------------------------------- + * + * EncodingSystemObjCmd -- + * + * This command retrieves or changes the system encoding + * + * Results: + * Returns a standard Tcl result + * + * Side effects: + * May change the system encoding. + * + *----------------------------------------------------------------------------- + */ + +int +EncodingSystemObjCmd(ClientData dummy, /* Unused */ + Tcl_Interp* interp, /* Tcl interpreter */ + int objc, /* Number of command line args */ + Tcl_Obj* const objv[]) /* Vector of command line args */ +{ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?encoding?"); + return TCL_ERROR; + } + if (objc == 1) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj(Tcl_GetEncodingName(NULL), -1)); + } else { + return Tcl_SetSystemEncoding(interp, TclGetString(objv[1])); + } + return TCL_OK; +} + +/* *---------------------------------------------------------------------- * * Tcl_ErrorObjCmd -- diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 5f4c298..b9bc228 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -734,6 +734,105 @@ TclCompileCatchCmd( return TCL_OK; } +/*---------------------------------------------------------------------- + * + * TclCompileClockClicksCmd -- + * + * Procedure called to compile the "tcl::clock::clicks" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to run time. + * + * Side effects: + * Instructions are added to envPtr to execute the "clock clicks" + * command at runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileClockClicksCmd( + Tcl_Interp* interp, /* Tcl interpreter */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token* tokenPtr; + + switch (parsePtr->numWords) { + case 1: + /* + * No args + */ + TclEmitInstInt1(INST_CLOCK_READ, 0, envPtr); + break; + case 2: + /* + * -milliseconds or -microseconds + */ + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD + || tokenPtr[1].size < 4 + || tokenPtr[1].size > 13) { + return TCL_ERROR; + } else if (!strncmp(tokenPtr[1].start, "-microseconds", + tokenPtr[1].size)) { + TclEmitInstInt1(INST_CLOCK_READ, 1, envPtr); + break; + } else if (!strncmp(tokenPtr[1].start, "-milliseconds", + tokenPtr[1].size)) { + TclEmitInstInt1(INST_CLOCK_READ, 2, envPtr); + break; + } else { + return TCL_ERROR; + } + default: + return TCL_ERROR; + } + return TCL_OK; +} + + +/*---------------------------------------------------------------------- + * + * TclCompileClockReadingCmd -- + * + * Procedure called to compile the "tcl::clock::microseconds", + * "tcl::clock::milliseconds" and "tcl::clock::seconds" commands. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to run time. + * + * Side effects: + * Instructions are added to envPtr to execute the "clock clicks" + * command at runtime. + * + * Client data is 1 for microseconds, 2 for milliseconds, 3 for seconds. + *---------------------------------------------------------------------- + */ + +int +TclCompileClockReadingCmd( + Tcl_Interp* interp, /* Tcl interpreter */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + if (parsePtr->numWords != 1) { + return TCL_ERROR; + } + + TclEmitInstInt1(INST_CLOCK_READ, PTR2INT(cmdPtr->objClientData), envPtr); + + return TCL_OK; +} + /* *---------------------------------------------------------------------- * diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 7e6a5af..b5de230 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -654,6 +654,11 @@ InstructionDesc const tclInstructionTable[] = { /* Lappend list to general variable. * Stack: ... varName list => ... listVarContents */ + {"clockRead", 2, +1, 1, {OPERAND_UINT1}}, + /* Read clock out to the stack. Operand is which clock to read + * 0=clicks, 1=microseconds, 2=milliseconds, 3=seconds. + * Stack: ... => ... time */ + {NULL, 0, 0, 0, {OPERAND_NONE}} }; diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 5bc3e81..bd7aaab 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -821,8 +821,10 @@ typedef struct ByteCode { #define INST_LAPPEND_LIST_ARRAY_STK 187 #define INST_LAPPEND_LIST_STK 188 +#define INST_CLOCK_READ 189 + /* The last opcode */ -#define LAST_INST_OPCODE 188 +#define LAST_INST_OPCODE 189 /* * Table describing the Tcl bytecode instructions: their name (for displaying @@ -1238,10 +1240,10 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData, #define TclCheckStackDepth(depth, envPtr) \ do { \ - int dd = (depth); \ - if (dd != (envPtr)->currStackDepth) { \ + int _dd = (depth); \ + if (_dd != (envPtr)->currStackDepth) { \ Tcl_Panic("bad stack depth computations: is %i, should be %i", \ - (envPtr)->currStackDepth, dd); \ + (envPtr)->currStackDepth, _dd); \ } \ } while (0) @@ -1257,12 +1259,12 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData, #define TclUpdateStackReqs(op, i, envPtr) \ do { \ - int delta = tclInstructionTable[(op)].stackEffect; \ - if (delta) { \ - if (delta == INT_MIN) { \ - delta = 1 - (i); \ + int _delta = tclInstructionTable[(op)].stackEffect; \ + if (_delta) { \ + if (_delta == INT_MIN) { \ + _delta = 1 - (i); \ } \ - TclAdjustStackDepth(delta, envPtr); \ + TclAdjustStackDepth(_delta, envPtr); \ } \ } while (0) @@ -1376,11 +1378,11 @@ MODULE_SCOPE int TclPushProcCallFrame(ClientData clientData, #define TclEmitPush(objIndex, envPtr) \ do { \ - register int objIndexCopy = (objIndex); \ - if (objIndexCopy <= 255) { \ - TclEmitInstInt1(INST_PUSH1, objIndexCopy, (envPtr)); \ + register int _objIndexCopy = (objIndex); \ + if (_objIndexCopy <= 255) { \ + TclEmitInstInt1(INST_PUSH1, _objIndexCopy, (envPtr)); \ } else { \ - TclEmitInstInt4(INST_PUSH4, objIndexCopy, (envPtr)); \ + TclEmitInstInt4(INST_PUSH4, _objIndexCopy, (envPtr)); \ } \ } while (0) diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 0dbf345..d543238 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -878,7 +878,7 @@ EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, int objc, EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 294 */ -EXTERN void Tcl_ExitThread(int status); +EXTERN TCL_NORETURN void Tcl_ExitThread(int status); /* 295 */ EXTERN int Tcl_ExternalToUtf(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, @@ -2151,7 +2151,7 @@ typedef struct TclStubs { int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 291 */ int (*tcl_EvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 292 */ int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */ - void (*tcl_ExitThread) (int status); /* 294 */ + TCL_NORETURN1 void (*tcl_ExitThread) (int status); /* 294 */ int (*tcl_ExternalToUtf) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 295 */ char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 296 */ void (*tcl_FinalizeThread) (void); /* 297 */ @@ -3835,13 +3835,13 @@ extern const TclStubs *tclStubsPtr; sizeof(char *), msg, flags, indexPtr) #undef Tcl_NewBooleanObj #define Tcl_NewBooleanObj(boolValue) \ - Tcl_NewIntObj((boolValue)!=0) + Tcl_NewLongObj((boolValue)!=0) #undef Tcl_DbNewBooleanObj #define Tcl_DbNewBooleanObj(boolValue, file, line) \ Tcl_DbNewLongObj((boolValue)!=0, file, line) #undef Tcl_SetBooleanObj #define Tcl_SetBooleanObj(objPtr, boolValue) \ - Tcl_SetIntObj((objPtr), (boolValue)!=0) + Tcl_SetLongObj(objPtr, (boolValue)!=0) #undef Tcl_SetVar #define Tcl_SetVar(interp, varName, newValue, flags) \ Tcl_SetVar2(interp, varName, NULL, newValue, flags) @@ -3870,6 +3870,29 @@ extern const TclStubs *tclStubsPtr; #define Tcl_AddObjErrorInfo(interp, message, length) \ Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length)) #ifdef TCL_NO_DEPRECATED +#undef Tcl_Eval +#define Tcl_Eval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, -1, 0) +#undef Tcl_GlobalEval +#define Tcl_GlobalEval(interp, objPtr) \ + Tcl_EvalEx(interp, objPtr, -1, TCL_EVAL_GLOBAL) +#undef Tcl_SaveResult +#define Tcl_SaveResult(interp, statePtr) \ + do { \ + (statePtr)->objResultPtr = Tcl_GetObjResult(interp); \ + Tcl_IncrRefCount((statePtr)->objResultPtr); \ + Tcl_SetObjResult(interp, Tcl_NewObj()); \ + } while(0) +#undef Tcl_RestoreResult +#define Tcl_RestoreResult(interp, statePtr) \ + do { \ + Tcl_ResetResult(interp); \ + Tcl_SetObjResult(interp, (statePtr)->objResultPtr); \ + Tcl_DecrRefCount((statePtr)->objResultPtr); \ + } while(0) +#undef Tcl_DiscardResult +#define Tcl_DiscardResult(statePtr) \ + Tcl_DecrRefCount((statePtr)->objResultPtr) #undef Tcl_SetResult #define Tcl_SetResult(interp, result, freeProc) \ do { \ @@ -3939,10 +3962,10 @@ extern const TclStubs *tclStubsPtr; */ #undef Tcl_EvalObj -#define Tcl_EvalObj(interp,objPtr) \ - Tcl_EvalObjEx((interp),(objPtr),0) +#define Tcl_EvalObj(interp, objPtr) \ + Tcl_EvalObjEx(interp, objPtr, 0) #undef Tcl_GlobalEvalObj -#define Tcl_GlobalEvalObj(interp,objPtr) \ - Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL) +#define Tcl_GlobalEvalObj(interp, objPtr) \ + Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL) #endif /* _TCLDECLS */ diff --git a/generic/tclDisassemble.c b/generic/tclDisassemble.c index 0d6da8e..d61ed42 100644 --- a/generic/tclDisassemble.c +++ b/generic/tclDisassemble.c @@ -27,9 +27,8 @@ static Tcl_Obj * DisassembleByteCodeObj(Tcl_Interp *interp, Tcl_Obj *objPtr); static int FormatInstruction(ByteCode *codePtr, const unsigned char *pc, Tcl_Obj *bufferObj); -static void GetLocationInformation(Tcl_Interp *interp, - Proc *procPtr, Tcl_Obj **fileObjPtr, - int *linePtr); +static void GetLocationInformation(Proc *procPtr, + Tcl_Obj **fileObjPtr, int *linePtr); static void PrintSourceToObj(Tcl_Obj *appendObj, const char *stringPtr, int maxChars); static void UpdateStringOfInstName(Tcl_Obj *objPtr); @@ -73,8 +72,6 @@ static const Tcl_ObjType tclInstNameType = { static void GetLocationInformation( - Tcl_Interp *interp, /* Where to look up the location - * information. */ Proc *procPtr, /* What to look up the information for. */ Tcl_Obj **fileObjPtr, /* Where to write the information about what * file the code came from. Will be written @@ -88,20 +85,21 @@ GetLocationInformation( * either with the line number or with -1 if * the information is not available. */ { - Interp *iPtr = (Interp *) interp; - Tcl_HashEntry *hePtr; - CmdFrame *cfPtr; + CmdFrame *cfPtr = TclGetCmdFrameForProcedure(procPtr); *fileObjPtr = NULL; *linePtr = -1; - if (iPtr != NULL && procPtr != NULL) { - hePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, procPtr); - if (hePtr != NULL && (cfPtr = Tcl_GetHashValue(hePtr)) != NULL) { - *linePtr = cfPtr->line[0]; - if (cfPtr->type == TCL_LOCATION_SOURCE) { - *fileObjPtr = cfPtr->data.eval.path; - } - } + if (cfPtr == NULL) { + return; + } + + /* + * Get the source location data out of the CmdFrame. + */ + + *linePtr = cfPtr->line[0]; + if (cfPtr->type == TCL_LOCATION_SOURCE) { + *fileObjPtr = cfPtr->data.eval.path; } } @@ -254,7 +252,6 @@ DisassembleByteCodeObj( int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i, line; Interp *iPtr = (Interp *) *codePtr->interpHandle; Tcl_Obj *bufferObj, *fileObj; - char ptrBuf1[20], ptrBuf2[20]; TclNewObj(bufferObj); if (codePtr->refCount <= 0) { @@ -269,16 +266,14 @@ DisassembleByteCodeObj( * Print header lines describing the ByteCode. */ - sprintf(ptrBuf1, "%p", codePtr); - sprintf(ptrBuf2, "%p", iPtr); Tcl_AppendPrintfToObj(bufferObj, - "ByteCode 0x%s, refCt %u, epoch %u, interp 0x%s (epoch %u)\n", - ptrBuf1, codePtr->refCount, codePtr->compileEpoch, ptrBuf2, + "ByteCode %p, refCt %u, epoch %u, interp %p (epoch %u)\n", + codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr, iPtr->compileEpoch); Tcl_AppendToObj(bufferObj, " Source ", -1); PrintSourceToObj(bufferObj, codePtr->source, TclMin(codePtr->numSrcBytes, 55)); - GetLocationInformation(interp, codePtr->procPtr, &fileObj, &line); + GetLocationInformation(codePtr->procPtr, &fileObj, &line); if (line > -1 && fileObj != NULL) { Tcl_AppendPrintfToObj(bufferObj, "\n File \"%s\" Line %d", Tcl_GetString(fileObj), line); @@ -316,10 +311,9 @@ DisassembleByteCodeObj( Proc *procPtr = codePtr->procPtr; int numCompiledLocals = procPtr->numCompiledLocals; - sprintf(ptrBuf1, "%p", procPtr); Tcl_AppendPrintfToObj(bufferObj, - " Proc 0x%s, refCt %d, args %d, compiled locals %d\n", - ptrBuf1, procPtr->refCount, procPtr->numArgs, + " Proc %p, refCt %d, args %d, compiled locals %d\n", + procPtr, procPtr->refCount, procPtr->numArgs, numCompiledLocals); if (numCompiledLocals > 0) { CompiledLocal *localPtr = procPtr->firstLocalPtr; @@ -1221,7 +1215,7 @@ DisassembleByteCodeAsDicts( * system if it is available. */ - GetLocationInformation(interp, codePtr->procPtr, &file, &line); + GetLocationInformation(codePtr->procPtr, &file, &line); /* * Build the overall result. diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index f3e8187..c4cf7f1 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -55,11 +55,12 @@ enum EnsSubcmds { }; static const char *const ensembleCreateOptions[] = { - "-command", "-map", "-parameters", "-prefixes", "-subcommands", - "-unknown", NULL + "-command", "-compile", "-map", "-parameters", "-prefixes", + "-subcommands", "-unknown", NULL }; enum EnsCreateOpts { - CRT_CMD, CRT_MAP, CRT_PARAM, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN + CRT_CMD, CRT_COMPILE, CRT_MAP, CRT_PARAM, CRT_PREFIX, + CRT_SUBCMDS, CRT_UNKNOWN }; static const char *const ensembleConfigOptions[] = { @@ -183,6 +184,7 @@ TclNamespaceEnsembleCmd( int permitPrefix = 1; Tcl_Obj *unknownObj = NULL; Tcl_Obj *paramObj = NULL; + int ensCompFlag = -1; /* * Check that we've got option-value pairs... [Bug 1558654] @@ -325,6 +327,12 @@ TclNamespaceEnsembleCmd( return TCL_ERROR; } continue; + case CRT_COMPILE: + if (Tcl_GetBooleanFromObj(interp, objv[1], + &ensCompFlag) != TCL_OK) { + return TCL_ERROR; + }; + continue; case CRT_UNKNOWN: if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { if (allocatedMapFlag) { @@ -350,6 +358,12 @@ TclNamespaceEnsembleCmd( Tcl_SetEnsembleMappingDict(interp, token, mapObj); Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); Tcl_SetEnsembleParameterList(interp, token, paramObj); + /* + * Ensemble should be compiled if it has map (performance purposes) + */ + if (ensCompFlag > 0 && mapObj != NULL) { + Tcl_SetEnsembleFlags(interp, token, ENSEMBLE_COMPILE); + } /* * Tricky! Must ensure that the result is not shared (command delete diff --git a/generic/tclEvent.c b/generic/tclEvent.c index 436db7a..49fd2ae 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -37,7 +37,7 @@ typedef struct BgError { * pending background errors for the interpreter. */ -typedef struct ErrAssocData { +typedef struct { Tcl_Interp *interp; /* Interpreter in which error occurred. */ Tcl_Obj *cmdPrefix; /* First word(s) of the handler command */ BgError *firstBgPtr; /* First in list of all background errors diff --git a/generic/tclExecute.c b/generic/tclExecute.c index c244b08..cfcdd26 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -510,8 +510,7 @@ VarHashCreateVar( : (*(tPtr) = TCL_NUMBER_DOUBLE)), \ *(ptrPtr) = (ClientData) \ (&((objPtr)->internalRep.doubleValue)), TCL_OK) : \ - ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) || \ - (((objPtr)->bytes != NULL) && ((objPtr)->length == 0))) \ + (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)) \ ? TCL_ERROR : \ TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr))) #else /* !TCL_WIDE_INT_IS_LONG */ @@ -530,8 +529,7 @@ VarHashCreateVar( : (*(tPtr) = TCL_NUMBER_DOUBLE)), \ *(ptrPtr) = (ClientData) \ (&((objPtr)->internalRep.doubleValue)), TCL_OK) : \ - ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) || \ - (((objPtr)->bytes != NULL) && ((objPtr)->length == 0))) \ + (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)) \ ? TCL_ERROR : \ TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr))) #endif /* TCL_WIDE_INT_IS_LONG */ @@ -910,9 +908,9 @@ TclCreateExecEnv( + (size_t) (size-1) * sizeof(Tcl_Obj *)); eePtr->execStackPtr = esPtr; - TclNewBooleanObj(eePtr->constants[0], 0); + TclNewLongObj(eePtr->constants[0], 0); Tcl_IncrRefCount(eePtr->constants[0]); - TclNewBooleanObj(eePtr->constants[1], 1); + TclNewLongObj(eePtr->constants[1], 1); Tcl_IncrRefCount(eePtr->constants[1]); eePtr->interp = interp; eePtr->callbackPtr = NULL; @@ -7664,6 +7662,39 @@ TEBCresume( * ----------------------------------------------------------------- */ + case INST_CLOCK_READ: + { /* Read the wall clock */ + Tcl_WideInt wval; + Tcl_Time now; + switch(TclGetUInt1AtPtr(pc+1)) { + case 0: /* clicks */ +#ifdef TCL_WIDE_CLICKS + wval = TclpGetWideClicks(); +#else + wval = (Tcl_WideInt) TclpGetClicks(); +#endif + break; + case 1: /* microseconds */ + Tcl_GetTime(&now); + wval = (Tcl_WideInt) now.sec * 1000000 + now.usec; + break; + case 2: /* milliseconds */ + Tcl_GetTime(&now); + wval = (Tcl_WideInt) now.sec * 1000 + now.usec / 1000; + break; + case 3: /* seconds */ + Tcl_GetTime(&now); + wval = (Tcl_WideInt) now.sec; + break; + default: + Tcl_Panic("clockRead instruction with unknown clock#"); + } + /* TclNewWideObj(objResultPtr, wval); doesn't exist */ + objResultPtr = Tcl_NewWideIntObj(wval); + TRACE_WITH_OBJ(("=> "), objResultPtr); + NEXT_INST_F(2, 0, 1); + } + default: Tcl_Panic("TclNRExecuteByteCode: unrecognized opCode %u", *pc); } /* end of switch on opCode */ @@ -9199,7 +9230,7 @@ TclCompareTwoNumbers( Tcl_Obj *valuePtr, Tcl_Obj *value2Ptr) { - int type1, type2, compare; + int type1 = TCL_NUMBER_NAN, type2 = TCL_NUMBER_NAN, compare; ClientData ptr1, ptr2; mp_int big1, big2; double d1, d2, tmp; diff --git a/generic/tclIO.c b/generic/tclIO.c index 6bf8451..1460392 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -116,7 +116,7 @@ typedef struct CopyState { * The structure defined below is used in this file only. */ -typedef struct ThreadSpecificData { +typedef struct { NextChannelHandler *nestedHandlerPtr; /* This variable holds the list of nested * Tcl_NotifyChannel invocations. */ @@ -321,7 +321,7 @@ static int WillRead(Channel *chanPtr); typedef struct ResolvedChanName { ChannelState *statePtr; /* The saved lookup result */ Tcl_Interp *interp; /* The interp in which the lookup was done. */ - size_t epoch; /* The epoch of the channel when the lookup + size_t epoch; /* The epoch of the channel when the lookup * was done. Use to verify validity. */ size_t refCount; /* Share this struct among many Tcl_Obj. */ } ResolvedChanName; @@ -381,20 +381,20 @@ ChanCloseHalf( * * ChanRead -- * - * Read up to dstSize bytes using the inputProc of chanPtr, store - * them at dst, and return the number of bytes stored. + * Read up to dstSize bytes using the inputProc of chanPtr, store them at + * dst, and return the number of bytes stored. * * Results: * The return value of the driver inputProc, * - number of bytes stored at dst, ot - * - -1 on error, with a Posix error code available to the - * caller by calling Tcl_GetErrno(). + * - -1 on error, with a Posix error code available to the caller by + * calling Tcl_GetErrno(). * * Side effects: - * The CHANNEL_BLOCKED and CHANNEL_EOF flags of the channel state are - * set as appropriate. - * On EOF, the inputEncodingFlags are set to perform ending operations - * on decoding. + * The CHANNEL_BLOCKED and CHANNEL_EOF flags of the channel state are set + * as appropriate. On EOF, the inputEncodingFlags are set to perform + * ending operations on decoding. + * * TODO - Is this really the right place for that? * *--------------------------------------------------------------------------- @@ -408,15 +408,17 @@ ChanRead( int bytesRead, result; /* - * If the caller asked for zero bytes, we'd force the inputProc - * to return zero bytes, and then misinterpret that as EOF. + * If the caller asked for zero bytes, we'd force the inputProc to return + * zero bytes, and then misinterpret that as EOF. */ + assert(dstSize > 0); /* * Each read op must set the blocked and eof states anew, not let * the effect of prior reads leak through. */ + if (GotFlag(chanPtr->state, CHANNEL_EOF)) { chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START; } @@ -429,7 +431,10 @@ ChanRead( bytesRead = chanPtr->typePtr->inputProc(chanPtr->instanceData, dst, dstSize, &result); - /* Stop any flag leakage through stacked channel levels */ + /* + * Stop any flag leakage through stacked channel levels. + */ + if (GotFlag(chanPtr->state, CHANNEL_EOF)) { chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START; } @@ -437,10 +442,10 @@ ChanRead( chanPtr->state->inputEncodingFlags &= ~TCL_ENCODING_END; if (bytesRead > 0) { /* - * If we get a short read, signal up that we may be BLOCKED. - * We should avoid calling the driver because on some - * platforms we will block in the low level reading code even - * though the channel is set into nonblocking mode. + * If we get a short read, signal up that we may be BLOCKED. We should + * avoid calling the driver because on some platforms we will block in + * the low level reading code even though the channel is set into + * nonblocking mode. */ if (bytesRead < dstSize) { @@ -574,7 +579,10 @@ TclFinalizeIOSubsystem(void) int active = 1; /* Flag == 1 while there's still work to do */ int doflushnb; - /* Fetch the pre-TIP#398 compatibility flag */ + /* + * Fetch the pre-TIP#398 compatibility flag. + */ + { const char *s; Tcl_DString ds; @@ -619,18 +627,20 @@ TclFinalizeIOSubsystem(void) */ if (active) { - TclChannelPreserve((Tcl_Channel)chanPtr); + /* - * TIP #398: by default, we no longer set the channel back into - * blocking mode. To restore the old blocking behavior, the - * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set + * TIP #398: by default, we no longer set the channel back into + * blocking mode. To restore the old blocking behavior, the + * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set * and not be "0". */ + if (doflushnb) { - /* Set the channel back into blocking mode to ensure that we wait - * for all data to flush out. - */ + /* + * Set the channel back into blocking mode to ensure that we + * wait for all data to flush out. + */ (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, "-blocking", "on"); @@ -1511,8 +1521,10 @@ TclGetChannelFromObj( if ((resPtr->interp == interp) /* Same interp context */ /* No epoch change in channel since lookup */ && (resPtr->epoch == statePtr->epoch)) { + /* + * Have a valid saved lookup. Jump to end to return it. + */ - /* Have a valid saved lookup. Jump to end to return it. */ goto valid; } } @@ -1527,7 +1539,10 @@ TclGetChannelFromObj( } if (resPtr && resPtr->refCount == 1) { - /* Re-use the ResolvedCmdName struct */ + /* + * Re-use the ResolvedCmdName struct. + */ + Tcl_Release((ClientData) resPtr->statePtr); } else { @@ -1671,7 +1686,7 @@ Tcl_CreateChannel( * Set the channel up initially in AUTO input translation mode to accept * "\n", "\r" and "\r\n". Output translation mode is set to a platform * specific default value. The eofChar is set to 0 for both input and - * output, so that Tcl does not look for an in-file EOF indicator (e.g. + * output, so that Tcl does not look for an in-file EOF indicator (e.g., * ^Z) and does not append an EOF indicator to files. */ @@ -1899,7 +1914,6 @@ Tcl_StackChannel( */ if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) { - /* * When statePtr->inQueueHead is not NULL, we know * prevChanPtr->inQueueHead must be NULL. @@ -2031,9 +2045,7 @@ Tcl_UnstackChannel( * of registered channels we wind down the state of the * transformation, and then restore the state of underlying channel * into the old structure. - */ - - /* + * * TODO: Figure out how to handle the situation where the chan * operations called below by this unstacking operation cause * another unstacking recursively. In that case the downChanPtr @@ -2511,6 +2523,7 @@ RecycleBuffer( /* * Do we have to free the buffer to the OS? */ + if (IsShared(bufPtr)) { mustDiscard = 1; } @@ -2521,9 +2534,8 @@ RecycleBuffer( } /* - * Only save buffers which have the requested buffersize for the - * channel. This is to honor dynamic changes of the buffersize - * made by the user. + * Only save buffers which have the requested buffersize for the channel. + * This is to honor dynamic changes of the buffersize made by the user. */ if ((bufPtr->bufLength - BUFFER_PADDING) != statePtr->bufSize) { @@ -2693,14 +2705,18 @@ FlushChannel( /* * Should we shift the current output buffer over to the output queue? * First check that there are bytes in it. If so then... - * If the output queue is empty, then yes, trusting the caller called - * us only when written bytes ought to be flushed. - * If the current output buffer is full, then yes, so we can meet - * the post-condition that on a successful return to caller we've - * left space in the current output buffer for more writing (the flush - * call was to make new room). - * If the channel is blocking, then yes, so we guarantee that - * blocking flushes actually flush all pending data. + * + * If the output queue is empty, then yes, trusting the caller called us + * only when written bytes ought to be flushed. + * + * If the current output buffer is full, then yes, so we can meet the + * post-condition that on a successful return to caller we've left space + * in the current output buffer for more writing (the flush call was to + * make new room). + * + * If the channel is blocking, then yes, so we guarantee that blocking + * flushes actually flush all pending data. + * * Otherwise, no. Keep the current output buffer where it is so more * can be written to it, possibly filling it, to promote more efficient * buffer usage. @@ -2794,8 +2810,8 @@ FlushChannel( /* * TIP #219, Tcl Channel Reflection API. * When defering the error copy a message from the bypass into - * the unreported area. Or discard it if the new error is to be - * ignored in favor of an earlier defered error. + * the unreported area. Or discard it if the new error is to + * be ignored in favor of an earlier defered error. */ Tcl_Obj *msg = statePtr->chanMsg; @@ -2847,8 +2863,11 @@ FlushChannel( ReleaseChannelBuffer(bufPtr); break; } else { - /* TODO: Consider detecting and reacting to short writes - * on blocking channels. Ought not happen. See iocmd-24.2. */ + /* + * TODO: Consider detecting and reacting to short writes on + * blocking channels. Ought not happen. See iocmd-24.2. + */ + wroteSome = 1; } @@ -2882,7 +2901,6 @@ FlushChannel( ResetFlag(statePtr, BG_FLUSH_SCHEDULED); ChanWatch(chanPtr, statePtr->interestMask); } else { - /* * When we are calledFromAsyncFlush, that means a writable * state on the channel triggered the call, so we should be @@ -2927,7 +2945,8 @@ FlushChannel( (statePtr->outQueueHead == NULL) && ((statePtr->curOutPtr == NULL) || IsBufferEmpty(statePtr->curOutPtr))) { - errorCode = CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE); + errorCode = CloseChannelPart(interp, chanPtr, errorCode, + TCL_CLOSE_WRITE); goto done; } @@ -3398,7 +3417,6 @@ Tcl_Close( if (GotFlag(statePtr, TCL_WRITABLE) && (statePtr->encoding != NULL) && !(statePtr->outputEncodingFlags & TCL_ENCODING_START)) { - int code = CheckChannelErrors(statePtr, TCL_WRITABLE); if (code == 0) { @@ -3488,12 +3506,14 @@ Tcl_Close( } return TCL_ERROR; } + /* * Bug 97069ea11a: set error message if a flush code is set and no error * message set up to now. */ + if (flushcode != 0 && interp != NULL - && 0 == Tcl_GetCharLength(Tcl_GetObjResult(interp)) ) { + && 0 == Tcl_GetCharLength(Tcl_GetObjResult(interp))) { Tcl_SetErrno(flushcode); Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_PosixError(interp), -1)); @@ -3588,8 +3608,8 @@ Tcl_CloseEx( } /* - * A user may try to call half-close from within a channel close - * handler. That won't do. + * A user may try to call half-close from within a channel close handler. + * That won't do. */ if (statePtr->flags & CHANNEL_INCLOSE) { @@ -3660,9 +3680,12 @@ CloseWrite( * closed. May still be used by some * interpreter */ { - /* Notes: clear-channel-handlers - write side only ? or keep around, just - * not called. */ - /* No close cllbacks are run - channel is still open (read side) */ + /* + * Notes: clear-channel-handlers - write side only ? or keep around, just + * not called. + * + * No close callbacks are run - channel is still open (read side) + */ ChannelState *statePtr = chanPtr->state; /* State of real IO channel. */ @@ -3687,9 +3710,9 @@ CloseWrite( * Notes: Due to the assertion of CHANNEL_CLOSEDWRITE in the flags * FlushChannel() has called CloseChannelPart(). While we can still access * "chan" (no structures were freed), the only place which may still - * contain a message is the interpreter itself, and "CloseChannelPart" made - * sure to lift any channel message it generated into it. Hence the NULL - * argument in the call below. + * contain a message is the interpreter itself, and "CloseChannelPart" + * made sure to lift any channel message it generated into it. Hence the + * NULL argument in the call below. */ if (TclChanCaughtErrorBypass(interp, NULL)) { @@ -3913,10 +3936,10 @@ Tcl_ClearChannelHandlers( StopCopy(statePtr->csPtrW); /* - * Must set the interest mask now to 0, otherwise infinite loops - * will occur if Tcl_DoOneEvent is called before the channel is - * finally deleted in FlushChannel. This can happen if the channel - * has a background flush active. + * Must set the interest mask now to 0, otherwise infinite loops will + * occur if Tcl_DoOneEvent is called before the channel is finally deleted + * in FlushChannel. This can happen if the channel has a background flush + * active. */ statePtr->interestMask = 0; @@ -4185,22 +4208,24 @@ WillRead( Channel *chanPtr) { if (chanPtr->typePtr == NULL) { - /* Prevent read attempts on a closed channel */ + /* + * Prevent read attempts on a closed channel. + */ + DiscardInputQueued(chanPtr->state, 0); Tcl_SetErrno(EINVAL); return -1; } if ((chanPtr->typePtr->seekProc != NULL) && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) { - /* - * CAVEAT - The assumption here is that FlushChannel() will - * push out the bytes of any writes that are in progress. - * Since this is a seekable channel, we assume it is not one - * that can block and force bg flushing. Channels we know that - * can do that -- sockets, pipes -- are not seekable. If the - * assumption is wrong, more drastic measures may be required here - * like temporarily setting the channel into blocking mode. + * CAVEAT - The assumption here is that FlushChannel() will push out + * the bytes of any writes that are in progress. Since this is a + * seekable channel, we assume it is not one that can block and force + * bg flushing. Channels we know that can do that - sockets, pipes - + * are not seekable. If the assumption is wrong, more drastic measures + * may be required here like temporarily setting the channel into + * blocking mode. */ if (FlushChannel(NULL, chanPtr, 0) != 0) { @@ -4292,11 +4317,17 @@ Write( &statePtr->outputEncodingState, dst, dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL); - /* See chan-io-1.[89]. Tcl Bug 506297. */ + /* + * See chan-io-1.[89]. Tcl Bug 506297. + */ + statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; if ((result != TCL_OK) && (srcRead + dstWrote == 0)) { - /* We're reading from invalid/incomplete UTF-8 */ + /* + * We're reading from invalid/incomplete UTF-8. + */ + ReleaseChannelBuffer(bufPtr); if (total == 0) { Tcl_SetErrno(EINVAL); @@ -4336,11 +4367,10 @@ Write( } result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen, - statePtr->outputEncodingFlags, - &statePtr->outputEncodingState, dst, - dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL); - - assert (srcRead == nlLen); + statePtr->outputEncodingFlags, + &statePtr->outputEncodingState, dst, + dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL); + assert(srcRead == nlLen); bufPtr->nextAdded += dstWrote; src++; @@ -4354,11 +4384,11 @@ Write( if (IsBufferOverflowing(bufPtr)) { /* - * When translating from UTF-8 to external encoding, we - * allowed the translation to produce a character that crossed - * the end of the output buffer, so that we would get a - * completely full buffer before flushing it. The extra bytes - * will be moved to the beginning of the next buffer. + * When translating from UTF-8 to external encoding, we allowed + * the translation to produce a character that crossed the end of + * the output buffer, so that we would get a completely full + * buffer before flushing it. The extra bytes will be moved to the + * beginning of the next buffer. */ saved = -SpaceLeft(bufPtr); @@ -4378,15 +4408,16 @@ Write( flushed += statePtr->bufSize; /* - * We just flushed. So if we have needNlFlush set to record - * that we need to flush because theres a (translated) newline - * in the buffer, that's likely not true any more. But there - * is a tricky exception. If we have saved bytes that did not - * really get flushed and those bytes came from a translation - * of a newline as the last thing taken from the src array, - * then needNlFlush needs to remain set to flag that the - * next buffer still needs a newline flush. + * We just flushed. So if we have needNlFlush set to record that + * we need to flush because theres a (translated) newline in the + * buffer, that's likely not true any more. But there is a tricky + * exception. If we have saved bytes that did not really get + * flushed and those bytes came from a translation of a newline as + * the last thing taken from the src array, then needNlFlush needs + * to remain set to flag that the next buffer still needs a + * newline flush. */ + if (needNlFlush && (saved == 0 || src[-1] != '\n')) { needNlFlush = 0; } @@ -4492,8 +4523,8 @@ Tcl_GetsObj( if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) { SetFlag(statePtr, CHANNEL_EOF); - assert( statePtr->inputEncodingFlags & TCL_ENCODING_END ); - assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) ); + assert(statePtr->inputEncodingFlags & TCL_ENCODING_END); + assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR)); /* TODO: Do we need this? */ UpdateInterest(chanPtr); @@ -4833,17 +4864,17 @@ Tcl_GetsObj( */ done: - assert(!GotFlag(statePtr, CHANNEL_EOF) - || GotFlag(statePtr, CHANNEL_STICKY_EOF) - || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); - - assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) - == (CHANNEL_EOF|CHANNEL_BLOCKED)) ); + assert(!GotFlag(statePtr, CHANNEL_EOF) + || GotFlag(statePtr, CHANNEL_STICKY_EOF) + || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); + assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) + == (CHANNEL_EOF|CHANNEL_BLOCKED))); /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ + if (chanPtr != statePtr->topChanPtr) { TclChannelRelease((Tcl_Channel)chanPtr); chanPtr = statePtr->topChanPtr; @@ -4863,10 +4894,9 @@ Tcl_GetsObj( * end-of-line or end-of-file has been seen. Bytes read from the input * channel return as a ByteArray obj. * - * WARNING! The notion of "binary" used here is different from - * notions of "binary" used in other places. In particular, this - * "binary" routine may be called when an -eofchar is set on the - * channel. + * WARNING! The notion of "binary" used here is different from notions + * of "binary" used in other places. In particular, this "binary" routine + * may be called when an -eofchar is set on the channel. * * Results: * Number of characters accumulated in the object or -1 if error, @@ -4932,8 +4962,8 @@ TclGetsObjBinary( ResetFlag(statePtr, CHANNEL_BLOCKED); while (1) { /* - * Subtract the number of bytes that were removed from channel - * buffer during last call. + * Subtract the number of bytes that were removed from channel buffer + * during last call. */ if (bufPtr != NULL) { @@ -4945,10 +4975,11 @@ TclGetsObjBinary( if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) { /* - * All channel buffers were exhausted and the caller still - * hasn't seen EOL. Need to read more bytes from the channel - * device. Side effect is to allocate another channel buffer. + * All channel buffers were exhausted and the caller still hasn't + * seen EOL. Need to read more bytes from the channel device. Side + * effect is to allocate another channel buffer. */ + if (GetInput(chanPtr) != 0) { goto restore; } @@ -4958,15 +4989,15 @@ TclGetsObjBinary( } } else { /* - * Incoming CHANNEL_STICKY_EOF is filtered out on entry. - * A new CHANNEL_STICKY_EOF set in this routine leads to - * return before coming back here. When we are not dealing - * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an - * empty buffer. Here the buffer is non-empty so we know - * we're a non-EOF */ + * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new + * CHANNEL_STICKY_EOF set in this routine leads to return before + * coming back here. When we are not dealing with + * CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an empty buffer. + * Here the buffer is non-empty so we know we're a non-EOF. + */ - assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) ); - assert ( !GotFlag(statePtr, CHANNEL_EOF) ); + assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF)); + assert(!GotFlag(statePtr, CHANNEL_EOF)); } dst = (unsigned char *) RemovePoint(bufPtr); @@ -5033,8 +5064,8 @@ TclGetsObjBinary( } /* - * Copy bytes from the channel buffer to the ByteArray. - * This may realloc space, so keep track of result. + * Copy bytes from the channel buffer to the ByteArray. This may + * realloc space, so keep track of result. */ rawLen = dstEnd - dst; @@ -5118,11 +5149,11 @@ TclGetsObjBinary( */ done: - assert(!GotFlag(statePtr, CHANNEL_EOF) - || GotFlag(statePtr, CHANNEL_STICKY_EOF) - || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); - assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) - == (CHANNEL_EOF|CHANNEL_BLOCKED)) ); + assert(!GotFlag(statePtr, CHANNEL_EOF) + || GotFlag(statePtr, CHANNEL_STICKY_EOF) + || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); + assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) + == (CHANNEL_EOF|CHANNEL_BLOCKED))); UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)chanPtr); return copiedTotal; @@ -5255,15 +5286,15 @@ FilterInputBytes( } } else { /* - * Incoming CHANNEL_STICKY_EOF is filtered out on entry. - * A new CHANNEL_STICKY_EOF set in this routine leads to - * return before coming back here. When we are not dealing - * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an - * empty buffer. Here the buffer is non-empty so we know - * we're a non-EOF */ + * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new + * CHANNEL_STICKY_EOF set in this routine leads to return before + * coming back here. When we are not dealing with CHANNEL_STICKY_EOF, + * a CHANNEL_EOF implies an empty buffer. Here the buffer is + * non-empty so we know we're a non-EOF. + */ - assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) ); - assert ( !GotFlag(statePtr, CHANNEL_EOF) ); + assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF)); + assert(!GotFlag(statePtr, CHANNEL_EOF)); } /* @@ -5593,7 +5624,9 @@ Tcl_ReadRaw( return -1; } - /* First read bytes from the push-back buffers. */ + /* + * First read bytes from the push-back buffers. + */ while (chanPtr->inQueueHead && bytesToRead > 0) { ChannelBuffer *bufPtr = chanPtr->inQueueHead; @@ -5601,7 +5634,9 @@ Tcl_ReadRaw( int toCopy = (bytesInBuffer < bytesToRead) ? bytesInBuffer : bytesToRead; - /* Copy the current chunk into the read buffer. */ + /* + * Copy the current chunk into the read buffer. + */ memcpy(readBuf, RemovePoint(bufPtr), (size_t) toCopy); bufPtr->nextRemoved += toCopy; @@ -5609,7 +5644,9 @@ Tcl_ReadRaw( readBuf += toCopy; bytesToRead -= toCopy; - /* If the current buffer is empty recycle it. */ + /* + * If the current buffer is empty recycle it. + */ if (IsBufferEmpty(bufPtr)) { chanPtr->inQueueHead = bufPtr->nextPtr; @@ -5621,37 +5658,40 @@ Tcl_ReadRaw( } /* - * Go to the driver only if we got nothing from pushback. - * Have to do it this way to avoid EOF mis-timings when we - * consider the ability that EOF may not be a permanent - * condition in the driver, and in that case we have to - * synchronize. + * Go to the driver only if we got nothing from pushback. Have to do it + * this way to avoid EOF mis-timings when we consider the ability that EOF + * may not be a permanent condition in the driver, and in that case we + * have to synchronize. */ if (copied) { return copied; } - /* This test not needed. */ - if (bytesToRead > 0) { + /* + * This test not needed. + */ + if (bytesToRead > 0) { int nread = ChanRead(chanPtr, readBuf, bytesToRead); if (nread > 0) { - /* Successful read (short is OK) - add to bytes copied */ + /* + * Successful read (short is OK) - add to bytes copied. + */ + copied += nread; } else if (nread < 0) { /* - * An error signaled. If CHANNEL_BLOCKED, then the error - * is not real, but an indication of blocked state. In - * that case, retain the flag and let caller receive the - * short read of copied bytes from the pushback. - * HOWEVER, if copied==0 bytes from pushback then repeat - * signalling the blocked state as an error to caller so - * there is no false report of an EOF. - * When !CHANNEL_BLOCKED, the error is real and passes on - * to caller. + * An error signaled. If CHANNEL_BLOCKED, then the error is not + * real, but an indication of blocked state. In that case, retain + * the flag and let caller receive the short read of copied bytes + * from the pushback. HOWEVER, if copied==0 bytes from pushback + * then repeat signalling the blocked state as an error to caller + * so there is no false report of an EOF. When !CHANNEL_BLOCKED, + * the error is real and passes on to caller. */ + if (!GotFlag(statePtr, CHANNEL_BLOCKED) || copied == 0) { copied = -1; } @@ -5788,21 +5828,23 @@ DoReadChars( /* * Early out when next read will see eofchar. * - * NOTE: See DoRead for argument that it's a bug (one we're keeping) - * to have this escape before the one for zero-char read request. + * NOTE: See DoRead for argument that it's a bug (one we're keeping) to + * have this escape before the one for zero-char read request. */ if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) { SetFlag(statePtr, CHANNEL_EOF); - assert( statePtr->inputEncodingFlags & TCL_ENCODING_END ); - assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) ); + assert(statePtr->inputEncodingFlags & TCL_ENCODING_END); + assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR)); /* TODO: We don't need this call? */ UpdateInterest(chanPtr); return 0; } - /* Special handling for zero-char read request. */ + /* + * Special handling for zero-char read request. + */ if (toRead == 0) { if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; @@ -5821,7 +5863,10 @@ DoReadChars( chanPtr = statePtr->topChanPtr; TclChannelPreserve((Tcl_Channel)chanPtr); - /* Must clear the BLOCKED|EOF flags here since we check before reading */ + /* + * Must clear the BLOCKED|EOF flags here since we check before reading. + */ + if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; } @@ -5879,10 +5924,11 @@ DoReadChars( } /* - * Failure to fill a channel buffer may have left channel reporting - * a "blocked" state, but so long as we fulfilled the request here, - * the caller does not consider us blocked. + * Failure to fill a channel buffer may have left channel reporting a + * "blocked" state, but so long as we fulfilled the request here, the + * caller does not consider us blocked. */ + if (toRead == 0) { ResetFlag(statePtr, CHANNEL_BLOCKED); } @@ -5891,6 +5937,7 @@ DoReadChars( * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ + if (chanPtr != statePtr->topChanPtr) { TclChannelRelease((Tcl_Channel)chanPtr); chanPtr = statePtr->topChanPtr; @@ -5901,11 +5948,12 @@ DoReadChars( * Update the notifier state so we don't block while there is still data * in the buffers. */ - assert(!GotFlag(statePtr, CHANNEL_EOF) - || GotFlag(statePtr, CHANNEL_STICKY_EOF) - || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); - assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) - == (CHANNEL_EOF|CHANNEL_BLOCKED)) ); + + assert(!GotFlag(statePtr, CHANNEL_EOF) + || GotFlag(statePtr, CHANNEL_STICKY_EOF) + || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); + assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) + == (CHANNEL_EOF|CHANNEL_BLOCKED))); UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)chanPtr); return copied; @@ -6022,11 +6070,10 @@ ReadChars( int numBytes, srcLen = BytesLeft(bufPtr); /* - * One src byte can yield at most one character. So when the - * number of src bytes we plan to read is less than the limit on - * character count to be read, clearly we will remain within that - * limit, and we can use the value of "srcLen" as a tighter limit - * for sizing receiving buffers. + * One src byte can yield at most one character. So when the number of + * src bytes we plan to read is less than the limit on character count to + * be read, clearly we will remain within that limit, and we can use the + * value of "srcLen" as a tighter limit for sizing receiving buffers. */ int toRead = ((charsToRead<0)||(charsToRead > srcLen)) ? srcLen : charsToRead; @@ -6044,6 +6091,7 @@ ReadChars( Tcl_AppendToObj(objPtr, NULL, dstLimit); if (toRead == srcLen) { unsigned int size; + dst = TclGetStringStorage(objPtr, &size) + numBytes; dstLimit = size - numBytes; } else { @@ -6051,19 +6099,18 @@ ReadChars( } /* - * This routine is burdened with satisfying several constraints. - * It cannot append more than 'charsToRead` chars onto objPtr. - * This is measured after encoding and translation transformations - * are completed. There is no precise number of src bytes that can - * be associated with the limit. Yet, when we are done, we must know - * precisely the number of src bytes that were consumed to produce - * the appended chars, so that all subsequent bytes are left in - * the buffers for future read operations. + * This routine is burdened with satisfying several constraints. It cannot + * append more than 'charsToRead` chars onto objPtr. This is measured + * after encoding and translation transformations are completed. There is + * no precise number of src bytes that can be associated with the limit. + * Yet, when we are done, we must know precisely the number of src bytes + * that were consumed to produce the appended chars, so that all + * subsequent bytes are left in the buffers for future read operations. * - * The consequence is that we have no choice but to implement a - * "trial and error" approach, where in general we may need to - * perform transformations and copies multiple times to achieve - * a consistent set of results. This takes the shape of a loop. + * The consequence is that we have no choice but to implement a "trial and + * error" approach, where in general we may need to perform + * transformations and copies multiple times to achieve a consistent set + * of results. This takes the shape of a loop. */ while (1) { @@ -6076,18 +6123,17 @@ ReadChars( } /* - * Perform the encoding transformation. Read no more than - * srcLen bytes, write no more than dstLimit bytes. + * Perform the encoding transformation. Read no more than srcLen + * bytes, write no more than dstLimit bytes. * - * Some trickiness with encoding flags here. We do not want - * the end of a buffer to be treated as the end of all input - * when the presence of bytes in a next buffer are already - * known to exist. This is checked with an assert() because - * so far no test case causing the assertion to be false has - * been created. The normal operations of channel reading - * appear to cause EOF and TCL_ENCODING_END setting to appear - * only in situations where there are no further bytes in - * any buffers. + * Some trickiness with encoding flags here. We do not want the end + * of a buffer to be treated as the end of all input when the presence + * of bytes in a next buffer are already known to exist. This is + * checked with an assert() because so far no test case causing the + * assertion to be false has been created. The normal operations of + * channel reading appear to cause EOF and TCL_ENCODING_END setting to + * appear only in situations where there are no further bytes in any + * buffers. */ assert(bufPtr->nextPtr == NULL || BytesLeft(bufPtr->nextPtr) == 0 @@ -6098,10 +6144,10 @@ ReadChars( dst, dstLimit, &srcRead, &dstDecoded, &numChars); /* - * Perform the translation transformation in place. Read no more - * than the dstDecoded bytes the encoding transformation actually - * produced. Capture the number of bytes written in dstWrote. - * Capture the number of bytes actually consumed in dstRead. + * Perform the translation transformation in place. Read no more than + * the dstDecoded bytes the encoding transformation actually produced. + * Capture the number of bytes written in dstWrote. Capture the number + * of bytes actually consumed in dstRead. */ dstWrote = dstLimit; @@ -6109,11 +6155,9 @@ ReadChars( TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); if (dstRead < dstDecoded) { - /* - * The encoding transformation produced bytes that the - * translation transformation did not consume. Why did - * this happen? + * The encoding transformation produced bytes that the translation + * transformation did not consume. Why did this happen? */ if (statePtr->inEofChar && dst[dstRead] == statePtr->inEofChar) { @@ -6122,40 +6166,38 @@ ReadChars( * we saw it and stopped translating at that point. * * NOTE the bizarre spec of TranslateInputEOL in this case. - * Clearly the eof char had to be read in order to account - * for the stopping, but the value of dstRead does not - * include it. + * Clearly the eof char had to be read in order to account for + * the stopping, but the value of dstRead does not include it. * - * Also rather bizarre, our caller can only notice an - * EOF condition if we return the value -1 as the number - * of chars read. This forces us to perform a 2-call - * dance where the first call can read all the chars - * up to the eof char, and the second call is solely - * for consuming the encoded eof char then pointed at - * by src so that we can return that magic -1 value. - * This seems really wasteful, especially since - * the first decoding pass of each call is likely to - * decode many bytes beyond that eof char that's all we - * care about. + * Also rather bizarre, our caller can only notice an EOF + * condition if we return the value -1 as the number of chars + * read. This forces us to perform a 2-call dance where the + * first call can read all the chars up to the eof char, and + * the second call is solely for consuming the encoded eof + * char then pointed at by src so that we can return that + * magic -1 value. This seems really wasteful, especially + * since the first decoding pass of each call is likely to + * decode many bytes beyond that eof char that's all we care + * about. */ if (dstRead == 0) { /* - * Curious choice in the eof char handling. We leave - * the eof char in the buffer. So, no need to compute - * a proper srcRead value. At this point, there - * are no chars before the eof char in the buffer. + * Curious choice in the eof char handling. We leave the + * eof char in the buffer. So, no need to compute a proper + * srcRead value. At this point, there are no chars before + * the eof char in the buffer. */ + Tcl_SetObjLength(objPtr, numBytes); return -1; } { /* - * There are chars leading the buffer before the eof - * char. Adjust the dstLimit so we go back and read - * only those and do not encounter the eof char this - * time. + * There are chars leading the buffer before the eof char. + * Adjust the dstLimit so we go back and read only those + * and do not encounter the eof char this time. */ dstLimit = dstRead - 1 + TCL_UTF_MAX; @@ -6167,10 +6209,9 @@ ReadChars( } /* - * 2) The other way to read fewer bytes than are decoded - * is when the final byte is \r and we're in a CRLF - * translation mode so we cannot decide whether to - * record \r or \n yet. + * 2) The other way to read fewer bytes than are decoded is when + * the final byte is \r and we're in a CRLF translation mode so + * we cannot decide whether to record \r or \n yet. */ assert(dst[dstRead] == '\r'); @@ -6178,10 +6219,10 @@ ReadChars( if (dstWrote > 0) { /* - * There are chars we can read before we hit the bare cr. - * Go back with a smaller dstLimit so we get them in the - * next pass, compute a matching srcRead, and don't end - * up back here in this call. + * There are chars we can read before we hit the bare CR. Go + * back with a smaller dstLimit so we get them in the next + * pass, compute a matching srcRead, and don't end up back + * here in this call. */ dstLimit = dstRead - 1 + TCL_UTF_MAX; @@ -6195,9 +6236,9 @@ ReadChars( assert(dstRead == 0); /* - * We decoded only the bare cr, and we cannot read a - * translated char from that alone. We have to know what's - * next. So why do we only have the one decoded char? + * We decoded only the bare CR, and we cannot read a translated + * char from that alone. We have to know what's next. So why do + * we only have the one decoded char? */ if (code != TCL_OK) { @@ -6238,10 +6279,9 @@ ReadChars( } } else if (statePtr->flags & CHANNEL_EOF) { - /* - * The bare \r is the only char and we will never read - * a subsequent char to make the determination. + * The bare \r is the only char and we will never read a + * subsequent char to make the determination. */ dst[0] = '\r'; @@ -6251,8 +6291,8 @@ ReadChars( } /* - * Revise the dstRead value so that the numChars calc - * below correctly computes zero characters read. + * Revise the dstRead value so that the numChars calc below + * correctly computes zero characters read. */ dstRead = numChars; @@ -6261,9 +6301,9 @@ ReadChars( } /* - * The translation transformation can only reduce the number - * of chars when it converts \r\n into \n. The reduction in - * the number of chars is the difference in bytes read and written. + * The translation transformation can only reduce the number of chars + * when it converts \r\n into \n. The reduction in the number of chars + * is the difference in bytes read and written. */ numChars -= (dstRead - dstWrote); @@ -6273,10 +6313,9 @@ ReadChars( /* * TODO: This cannot happen anymore. * - * We read more chars than allowed. Reset limits to - * prevent that and try again. Don't forget the extra - * padding of TCL_UTF_MAX bytes demanded by the - * Tcl_ExternalToUtf() call! + * We read more chars than allowed. Reset limits to prevent that + * and try again. Don't forget the extra padding of TCL_UTF_MAX + * bytes demanded by the Tcl_ExternalToUtf() call! */ dstLimit = Tcl_UtfAtIndex(dst, charsToRead) - 1 + TCL_UTF_MAX - dst; @@ -6289,18 +6328,19 @@ ReadChars( if (dstWrote == 0) { ChannelBuffer *nextPtr; - /* We were not able to read any chars. */ + /* + * We were not able to read any chars. + */ - assert (numChars == 0); + assert(numChars == 0); /* - * There is one situation where this is the correct final - * result. If the src buffer contains only a single \n - * byte, and we are in TCL_TRANSLATE_AUTO mode, and - * when the translation pass was made the INPUT_SAW_CR - * flag was set on the channel. In that case, the - * correct behavior is to consume that \n and produce the - * empty string. + * There is one situation where this is the correct final result. + * If the src buffer contains only a single \n byte, and we are in + * TCL_TRANSLATE_AUTO mode, and when the translation pass was made + * the INPUT_SAW_CR flag was set on the channel. In that case, the + * correct behavior is to consume that \n and produce the empty + * string. */ if (dstRead == 1 && dst[0] == '\n') { @@ -6309,12 +6349,13 @@ ReadChars( goto consume; } - /* Otherwise, reading zero characters indicates there's - * something incomplete at the end of the src buffer. - * Maybe there were not enough src bytes to decode into - * a char. Maybe a lone \r could not be translated (crlf - * mode). Need to combine any unused src bytes we have - * in the first buffer with subsequent bytes to try again. + /* + * Otherwise, reading zero characters indicates there's something + * incomplete at the end of the src buffer. Maybe there were not + * enough src bytes to decode into a char. Maybe a lone \r could + * not be translated (crlf mode). Need to combine any unused src + * bytes we have in the first buffer with subsequent bytes to try + * again. */ nextPtr = bufPtr->nextPtr; @@ -6329,15 +6370,15 @@ ReadChars( /* * Space is made at the beginning of the buffer to copy the - * previous unused bytes there. Check first if the buffer we - * are using actually has enough space at its beginning for - * the data we are copying. Because if not we will write over - * the buffer management information, especially the 'nextPtr'. + * previous unused bytes there. Check first if the buffer we are + * using actually has enough space at its beginning for the data + * we are copying. Because if not we will write over the buffer + * management information, especially the 'nextPtr'. * - * Note that the BUFFER_PADDING (See AllocChannelBuffer) is - * used to prevent exactly this situation. I.e. it should never - * happen. Therefore it is ok to panic should it happen despite - * the precautions. + * Note that the BUFFER_PADDING (See AllocChannelBuffer) is used + * to prevent exactly this situation. I.e. it should never happen. + * Therefore it is ok to panic should it happen despite the + * precautions. */ if (nextPtr->nextRemoved - srcLen < 0) { @@ -6356,10 +6397,12 @@ ReadChars( consume: bufPtr->nextRemoved += srcRead; + /* - * If this read contained multibyte characters, revise factorPtr - * so the next read will allocate bigger buffers. + * If this read contained multibyte characters, revise factorPtr so + * the next read will allocate bigger buffers. */ + if (numChars && numChars < srcRead) { *factorPtr = srcRead * UTF_EXPANSION_FACTOR / numChars; } @@ -6407,22 +6450,27 @@ TranslateInputEOL( int inEofChar = statePtr->inEofChar; /* - * Depending on the translation mode in use, there's no need - * to scan more srcLen bytes at srcStart than can possibly transform - * to dstLen bytes. This keeps the scan for eof char below from - * being pointlessly long. + * Depending on the translation mode in use, there's no need to scan more + * srcLen bytes at srcStart than can possibly transform to dstLen bytes. + * This keeps the scan for eof char below from being pointlessly long. */ switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: case TCL_TRANSLATE_CR: if (srcLen > dstLen) { - /* In these modes, each src byte become a dst byte. */ + /* + * In these modes, each src byte become a dst byte. + */ + srcLen = dstLen; } break; default: - /* In other modes, at most 2 src bytes become a dst byte. */ + /* + * In other modes, at most 2 src bytes become a dst byte. + */ + if (srcLen/2 > dstLen) { srcLen = 2 * dstLen; } @@ -6755,7 +6803,7 @@ GetInput( * eofchar. */ - assert( !GotFlag(statePtr, CHANNEL_STICKY_EOF) ); + assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF)); /* * Prevent reading from a dead channel -- a channel that has been closed @@ -6769,24 +6817,21 @@ GetInput( } /* - * WARNING: There was once a comment here claiming that it was - * a bad idea to make another call to the inputproc of a channel - * driver when EOF has already been detected on the channel. Through - * much of Tcl's history, this warning was then completely negated - * by having all (most?) read paths clear the EOF setting before - * reaching here. So we had a guard that was never triggered. + * WARNING: There was once a comment here claiming that it was a bad idea + * to make another call to the inputproc of a channel driver when EOF has + * already been detected on the channel. Through much of Tcl's history, + * this warning was then completely negated by having all (most?) read + * paths clear the EOF setting before reaching here. So we had a guard + * that was never triggered. + * + * Don't be tempted to restore the guard. Even if EOF is set on the + * channel, continue through and call the inputproc again. This is the + * way to enable the ability to [read] again beyond the EOF, which seems a + * strange thing to do, but for which use cases exist [Tcl Bug 5adc350683] + * and which may even be essential for channels representing things like + * ttys or other devices where the stream might take the logical form of a + * series of 'files' separated by an EOF condition. * - * Don't be tempted to restore the guard. Even if EOF is set on - * the channel, continue through and call the inputproc again. This - * is the way to enable the ability to [read] again beyond the EOF, - * which seems a strange thing to do, but for which use cases exist - * [Tcl Bug 5adc350683] and which may even be essential for channels - * representing things like ttys or other devices where the stream - * might take the logical form of a series of 'files' separated by - * an EOF condition. - */ - - /* * First check for more buffers in the pushback area of the topmost * channel in the stack and use them. They can be the result of a * transformation which went away without reading all the information @@ -6794,7 +6839,6 @@ GetInput( */ if (chanPtr->inQueueHead != NULL) { - /* TODO: Tests to cover this. */ assert(statePtr->inQueueHead == NULL); @@ -6824,8 +6868,9 @@ GetInput( /* * Check the actual buffersize against the requested buffersize. - * Saved buffers of the wrong size are squashed. This is done - * to honor dynamic changes of the buffersize made by the user. + * Saved buffers of the wrong size are squashed. This is done to honor + * dynamic changes of the buffersize made by the user. + * * TODO: Tests to cover this. */ @@ -7132,7 +7177,7 @@ Tcl_Tell( * Truncate a channel to the given length. * * Results: - * TCL_OK on success, TCL_ERROR if the operation failed (e.g. is not + * TCL_OK on success, TCL_ERROR if the operation failed (e.g., is not * supported by the type of channel, or the underlying OS operation * failed in some way). * @@ -9276,7 +9321,7 @@ MBWrite( * then the calculations involving extra must be made wide too. * * Noted with Win32/MSVC debug build treating the warning (possible of - * data in int64 to int conversion) as error. + * data in __int64 to int conversion) as error. */ bufPtr = AllocChannelBuffer(extra); @@ -9492,7 +9537,10 @@ CopyData( } if (size == 0) { if (!GotFlag(inStatePtr, CHANNEL_NONBLOCKING)) { - /* We allowed a short read. Keep trying. */ + /* + * We allowed a short read. Keep trying. + */ + continue; } if (bufObj != NULL) { @@ -9706,7 +9754,7 @@ DoRead( ChannelState *statePtr = chanPtr->state; char *p = dst; - assert (bytesToRead >= 0); + assert(bytesToRead >= 0); /* * Early out when we know a read will get the eofchar. @@ -9722,15 +9770,18 @@ DoRead( if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) { SetFlag(statePtr, CHANNEL_EOF); - assert( statePtr->inputEncodingFlags & TCL_ENCODING_END ); - assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) ); + assert(statePtr->inputEncodingFlags & TCL_ENCODING_END); + assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR)); /* TODO: Don't need this call */ UpdateInterest(chanPtr); return 0; } - /* Special handling for zero-char read request. */ + /* + * Special handling for zero-char read request. + */ + if (bytesToRead == 0) { if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; @@ -9745,8 +9796,8 @@ DoRead( TclChannelPreserve((Tcl_Channel)chanPtr); while (bytesToRead) { /* - * Each pass through the loop is intended to process up to - * one channel buffer. + * Each pass through the loop is intended to process up to one channel + * buffer. */ int bytesRead, bytesWritten; @@ -9758,33 +9809,39 @@ DoRead( while (!bufPtr || /* We got no buffer! OR */ (!IsBufferFull(bufPtr) && /* Our buffer has room AND */ - (BytesLeft(bufPtr) < bytesToRead) ) ) { - /* Not enough bytes in it - * yet to fill the dst */ + (BytesLeft(bufPtr) < bytesToRead))) { + /* Not enough bytes in it yet + * to fill the dst */ int code; moreData: code = GetInput(chanPtr); bufPtr = statePtr->inQueueHead; - assert (bufPtr != NULL); + assert(bufPtr != NULL); if (GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)) { - /* Further reads cannot do any more */ + /* + * Further reads cannot do any more. + */ + break; } if (code) { - /* Read error */ + /* + * Read error + */ + UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)chanPtr); return -1; } - assert (IsBufferFull(bufPtr)); + assert(IsBufferFull(bufPtr)); } - assert (bufPtr != NULL); + assert(bufPtr != NULL); bytesRead = BytesLeft(bufPtr); bytesWritten = bytesToRead; @@ -9799,8 +9856,8 @@ DoRead( /* * Buffer is not empty. How can that be? * - * 0) We stopped early because we got all the bytes - * we were seeking. That's fine. + * 0) We stopped early because we got all the bytes we were + * seeking. That's fine. */ if (bytesToRead == 0) { @@ -9816,8 +9873,8 @@ DoRead( } /* - * 2) The buffer holds a \r while in CRLF translation, - * followed by the end of the buffer. + * 2) The buffer holds a \r while in CRLF translation, followed by + * the end of the buffer. */ assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF); @@ -9825,26 +9882,38 @@ DoRead( assert(BytesLeft(bufPtr) == 1); if (bufPtr->nextPtr == NULL) { - /* There's no more buffered data.... */ + /* + * There's no more buffered data... + */ if (statePtr->flags & CHANNEL_EOF) { - /* ...and there never will be. */ + /* + * ...and there never will be. + */ *p++ = '\r'; bytesToRead--; bufPtr->nextRemoved++; } else if (statePtr->flags & CHANNEL_BLOCKED) { - /* ...and we cannot get more now. */ + /* + * ...and we cannot get more now. + */ + SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); break; } else { - /* ... so we need to get some. */ + /* + * ...so we need to get some. + */ + goto moreData; } } if (bufPtr->nextPtr) { - /* There's a next buffer. Shift orphan \r to it. */ + /* + * There's a next buffer. Shift orphan \r to it. + */ ChannelBuffer *nextPtr = bufPtr->nextPtr; @@ -9869,8 +9938,8 @@ DoRead( } /* - * When there's no buffered data to read, and we're at EOF, - * escape to the caller. + * When there's no buffered data to read, and we're at EOF, escape to + * the caller. */ if (GotFlag(statePtr, CHANNEL_EOF) @@ -9882,11 +9951,11 @@ DoRead( ResetFlag(statePtr, CHANNEL_BLOCKED); } - assert(!GotFlag(statePtr, CHANNEL_EOF) - || GotFlag(statePtr, CHANNEL_STICKY_EOF) - || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); - assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) - == (CHANNEL_EOF|CHANNEL_BLOCKED)) ); + assert(!GotFlag(statePtr, CHANNEL_EOF) + || GotFlag(statePtr, CHANNEL_STICKY_EOF) + || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); + assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) + == (CHANNEL_EOF|CHANNEL_BLOCKED))); UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)chanPtr); return (int)(p - dst); diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c index 1bd3fe7..6e8bd09 100644 --- a/generic/tclIOCmd.c +++ b/generic/tclIOCmd.c @@ -25,7 +25,7 @@ typedef struct AcceptCallback { * It must be per-thread because of std channel limitations. */ -typedef struct ThreadSpecificData { +typedef struct { int initialized; /* Set to 1 when the module is initialized. */ Tcl_Obj *stdoutObjPtr; /* Cached stdout channel Tcl_Obj */ } ThreadSpecificData; @@ -113,7 +113,6 @@ Tcl_PutsObjCmd( int newline; /* Add a newline at end? */ int result; /* Result of puts operation. */ int mode; /* Mode in which channel is opened. */ - ThreadSpecificData *tsdPtr; switch (objc) { case 2: /* [puts $x] */ @@ -160,7 +159,7 @@ Tcl_PutsObjCmd( } if (chanObjPtr == NULL) { - tsdPtr = TCL_TSD_INIT(&dataKey); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->initialized) { tsdPtr->initialized = 1; @@ -1618,19 +1617,34 @@ Tcl_SocketObjCmd( return TCL_ERROR; } - // Set the options to their default value if the user didn't override their - // value. - if (reusep == -1) reusep = 0; - if (reusea == -1) reusea = 1; + /* + * Set the options to their default value if the user didn't override + * their value. + */ - // Build the bitset with the flags values. - if (reusea) + if (reusep == -1) { + reusep = 0; + } + if (reusea == -1) { + reusea = 1; + } + + /* + * Build the bitset with the flags values. + */ + + if (reusea) { flags |= TCL_TCPSERVER_REUSEADDR; - if (reusep) + } + if (reusep) { flags |= TCL_TCPSERVER_REUSEPORT; + } + + /* + * All the arguments should have been parsed by now, 'a' points to the + * last one, the port number. + */ - // All the arguments should have been parsed by now, 'a' points to the last - // one, the port number. if (a != objc-1) { goto wrongNumArgs; } @@ -1638,15 +1652,14 @@ Tcl_SocketObjCmd( port = TclGetString(objv[a]); if (server) { - AcceptCallback *acceptCallbackPtr = - ckalloc(sizeof(AcceptCallback)); + AcceptCallback *acceptCallbackPtr = ckalloc(sizeof(AcceptCallback)); Tcl_IncrRefCount(script); acceptCallbackPtr->script = script; acceptCallbackPtr->interp = interp; - chan = Tcl_OpenTcpServerEx(interp, port, host, flags, AcceptCallbackProc, - acceptCallbackPtr); + chan = Tcl_OpenTcpServerEx(interp, port, host, flags, + AcceptCallbackProc, acceptCallbackPtr); if (chan == NULL) { Tcl_DecrRefCount(script); ckfree(acceptCallbackPtr); diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 2fed3f4..aefa104 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -234,7 +234,7 @@ typedef enum { * sharing problems. */ -typedef struct ForwardParamBase { +typedef struct { int code; /* O: Ok/Fail of the cmd handler */ char *msgStr; /* O: Error message for handler failure */ int mustFree; /* O: True if msgStr is allocated, false if @@ -309,7 +309,7 @@ typedef struct ForwardingResult ForwardingResult; * General event structure, with reference to operation specific data. */ -typedef struct ForwardingEvent { +typedef struct { Tcl_Event event; /* Basic event data, has to be first item */ ForwardingResult *resultPtr; ForwardedOperation op; /* Forwarded driver operation */ @@ -346,7 +346,7 @@ struct ForwardingResult { * results. */ }; -typedef struct ThreadSpecificData { +typedef struct { /* * Table of all reflected channels owned by this thread. This is the * per-thread version of the per-interpreter map. @@ -723,7 +723,7 @@ TclChanCreateObjCmd( Tcl_DecrRefCount(rcPtr->name); Tcl_DecrRefCount(rcPtr->methods); Tcl_DecrRefCount(rcPtr->cmd); - ckfree((char*) rcPtr); + ckfree(rcPtr); return TCL_ERROR; #undef MODE @@ -748,7 +748,7 @@ TclChanCreateObjCmd( *---------------------------------------------------------------------- */ -typedef struct ReflectEvent { +typedef struct { Tcl_Event header; ReflectedChannel *rcPtr; int events; @@ -851,11 +851,12 @@ TclChanPostEventObjCmd( } /* - * Note that the search above subsumes several of the older checks, namely: + * Note that the search above subsumes several of the older checks, + * namely: * - * (1) Does the channel handle refer to a reflected channel ? + * (1) Does the channel handle refer to a reflected channel? * (2) Is the post event issued from the interpreter holding the handler - * of the reflected channel ? + * of the reflected channel? * * A successful search answers yes to both. Because the map holds only * handles of reflected channels, and only of such whose handler is @@ -939,7 +940,8 @@ TclChanPostEventObjCmd( (void) GetThreadReflectedChannelMap(); - /* XXX Race condition !! + /* + * XXX Race condition !! * XXX The destination thread may not exist anymore already. * XXX (Delayed postevent executed after channel got removed). * XXX Can we detect this ? (check the validity of the owner threadid ?) @@ -1221,8 +1223,8 @@ ReflectClose( #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { - ckfree(tctPtr); - ((Channel *)rcPtr->chan)->typePtr = NULL; + ckfree(tctPtr); + ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return (result == TCL_OK) ? EOK : EINVAL; @@ -1272,7 +1274,10 @@ ReflectInput( if (p.base.code != TCL_OK) { if (p.base.code < 0) { - /* No error message, this is an errno signal. */ + /* + * No error message, this is an errno signal. + */ + *errorCodePtr = -p.base.code; } else { PassReceivedError(rcPtr->chan, &p); @@ -1375,7 +1380,10 @@ ReflectOutput( if (p.base.code != TCL_OK) { if (p.base.code < 0) { - /* No error message, this is an errno signal. */ + /* + * No error message, this is an errno signal. + */ + *errorCodePtr = -p.base.code; } else { PassReceivedError(rcPtr->chan, &p); @@ -1426,8 +1434,8 @@ ReflectOutput( if ((written == 0) && (toWrite > 0)) { /* - * The handler claims to have written nothing of what it was - * given. That is bad. + * The handler claims to have written nothing of what it was given. + * That is bad. */ SetChannelErrorStr(rcPtr->chan, msg_write_nothing); @@ -2373,8 +2381,8 @@ InvokeTclMethod( * None. * * Users: - * ReflectInput/Output(), to enable the signaling of EAGAIN - * on 0-sized short reads/writes. + * ReflectInput/Output(), to enable the signaling of EAGAIN on 0-sized + * short reads/writes. * *---------------------------------------------------------------------- */ @@ -2560,7 +2568,10 @@ DeleteReflectedChannelMap( evPtr = resultPtr->evPtr; - /* Basic crash safety until this routine can get revised [3411310] */ + /* + * Basic crash safety until this routine can get revised [3411310] + */ + if (evPtr == NULL) { continue; } @@ -2675,8 +2686,8 @@ DeleteThreadReflectedChannelMap( /* * Go through the list of pending results and cancel all whose events were - * destined for this thread. While this is in progress we block any - * other access to the list of pending results. + * destined for this thread. While this is in progress we block any other + * access to the list of pending results. */ Tcl_MutexLock(&rcForwardMutex); @@ -2707,7 +2718,10 @@ DeleteThreadReflectedChannelMap( evPtr = resultPtr->evPtr; - /* Basic crash safety until this routine can get revised [3411310] */ + /* + * Basic crash safety until this routine can get revised [3411310] + */ + if (evPtr == NULL ) { continue; } @@ -2761,8 +2775,8 @@ ForwardOpToHandlerThread( const void *param) /* Arguments */ { /* - * Core of the communication from OWNER to HANDLER thread. - * The receiver is ForwardProc() below. + * Core of the communication from OWNER to HANDLER thread. The receiver is + * ForwardProc() below. */ Tcl_ThreadId dst = rcPtr->thread; @@ -2812,7 +2826,10 @@ ForwardOpToHandlerThread( */ TclSpliceIn(resultPtr, forwardList); - /* Do not unlock here. That is done by the ConditionWait */ + + /* + * Do not unlock here. That is done by the ConditionWait. + */ /* * Ensure cleanup of the event if the origin thread exits while this event @@ -2888,7 +2905,7 @@ ForwardProc( * Notes regarding access to the referenced data. * * In principle the data belongs to the originating thread (see - * evPtr->src), however this thread is currently blocked at (*), i.e. + * evPtr->src), however this thread is currently blocked at (*), i.e., * quiescent. Because of this we can treat the data as belonging to us, * without fear of race conditions. I.e. we can read and write as we like. * diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c index 8375926..f198c69 100644 --- a/generic/tclIORTrans.c +++ b/generic/tclIORTrans.c @@ -329,7 +329,7 @@ struct ForwardingResult { * results. */ }; -typedef struct ThreadSpecificData { +typedef struct { /* * Table of all reflected transformations owned by this thread. */ diff --git a/generic/tclIOSock.c b/generic/tclIOSock.c index 8ad268a..6abfa60 100644 --- a/generic/tclIOSock.c +++ b/generic/tclIOSock.c @@ -12,16 +12,21 @@ #include "tclInt.h" #if defined(_WIN32) && defined(UNICODE) -/* On Windows, we need to do proper Unicode->UTF-8 conversion. */ +/* + * On Windows, we need to do proper Unicode->UTF-8 conversion. + */ -typedef struct ThreadSpecificData { +typedef struct { int initialized; Tcl_DString errorMsg; /* UTF-8 encoded error-message */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; #undef gai_strerror -static const char *gai_strerror(int code) { +static const char * +gai_strerror( + int code) +{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->initialized) { @@ -126,7 +131,7 @@ TclSockMinimumBuffers( } len = sizeof(int); getsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF, - (char *) ¤t, &len); + (char *) ¤t, &len); if (current < size) { len = sizeof(int); setsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF, @@ -215,7 +220,7 @@ TclCreateSocketAddress( * We found some problems when using AI_ADDRCONFIG, e.g. on systems that * have no networking besides the loopback interface and want to resolve * localhost. See [Bugs 3385024, 3382419, 3382431]. As the advantage of - * using AI_ADDRCONFIG in situations where it works, is probably low, + * using AI_ADDRCONFIG is probably low even in situations where it works, * we'll leave it out for now. After all, it is just an optimisation. * * Missing on: OpenBSD, NetBSD. @@ -300,16 +305,20 @@ TclCreateSocketAddress( * *---------------------------------------------------------------------- */ -Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, - const char *host, Tcl_TcpAcceptProc *acceptProc, - ClientData callbackData) + +Tcl_Channel +Tcl_OpenTcpServer( + Tcl_Interp *interp, + int port, + const char *host, + Tcl_TcpAcceptProc *acceptProc, + ClientData callbackData) { char portbuf[TCL_INTEGER_SPACE]; TclFormatInt(portbuf, port); - return Tcl_OpenTcpServerEx(interp, portbuf, host, TCL_TCPSERVER_REUSEADDR, - acceptProc, callbackData); + acceptProc, callbackData); } /* diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index de5d62d..ea407ab 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -57,7 +57,7 @@ typedef struct FilesystemRecord { * this information each time the corresponding epoch counter changes. */ -typedef struct ThreadSpecificData { +typedef struct { int initialized; size_t cwdPathEpoch; size_t filesystemEpoch; @@ -611,6 +611,7 @@ FsRecacheFilesystemList(void) while (toFree) { FilesystemRecord *next = toFree->nextPtr; + toFree->fsPtr = NULL; ckfree(toFree); toFree = next; @@ -672,7 +673,6 @@ TclFSEpoch(void) return tsdPtr->filesystemEpoch; } - /* * If non-NULL, clientData is owned by us and must be freed later. @@ -784,7 +784,9 @@ TclFinalizeFilesystem(void) while (fsRecPtr != NULL) { FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr; - /* The native filesystem is static, so we don't free it. */ + /* + * The native filesystem is static, so we don't free it. + */ if (fsRecPtr != &nativeFilesystemRecord) { ckfree(fsRecPtr); @@ -947,7 +949,7 @@ Tcl_FSRegister( int Tcl_FSUnregister( - const Tcl_Filesystem *fsPtr) /* The filesystem record to remove. */ + const Tcl_Filesystem *fsPtr)/* The filesystem record to remove. */ { int retVal = TCL_ERROR; FilesystemRecord *fsRecPtr; @@ -1233,7 +1235,7 @@ FsAddMountsToGlobResult( len--; } - len++; /* account for '/' in the mElt [Bug 1602539] */ + len++; /* account for '/' in the mElt [Bug 1602539] */ mElt = TclNewFSPathObj(pathPtr, mount + len, mlen - len); Tcl_ListObjAppendElement(NULL, resultPtr, mElt); } @@ -1403,7 +1405,7 @@ TclFSNormalizeToUniquePath( * Call each of the "normalise path" functions in succession. This is a * special case, in which if we have a native filesystem handler, we call * it first. This is because the root of Tcl's filesystem is always a - * native filesystem (i.e. '/' on unix is native). + * native filesystem (i.e., '/' on unix is native). */ firstFsRecPtr = FsGetFirstFilesystem(); @@ -1525,7 +1527,7 @@ TclGetOpenModeEx( #define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR) /* - * Check for the simpler fopen-like access modes (e.g. "r"). They are + * Check for the simpler fopen-like access modes (e.g., "r"). They are * distinguished from the POSIX access modes by the presence of a * lower-case first letter. */ @@ -2671,6 +2673,7 @@ Tcl_FSGetCwd( fsRecPtr = fsRecPtr->nextPtr) { ClientData retCd; TclFSGetCwdProc2 *proc2; + if (fsRecPtr->fsPtr->getCwdProc == NULL) { continue; } @@ -3143,8 +3146,8 @@ Tcl_FSLoadFile( * Workaround for issue with modern HPUX which do allow the unlink (no ETXTBSY * error) yet somehow trash some internal data structures which prevents the * second and further shared libraries from getting properly loaded. Only the - * first is ok. We try to get around the issue by not unlinking, - * i.e. emulating the behaviour of the older HPUX which denied removal. + * first is ok. We try to get around the issue by not unlinking, i.e., + * emulating the behaviour of the older HPUX which denied removal. * * Doing the unlink is also an issue within docker containers, whose AUFS * bungles this as well, see @@ -3162,28 +3165,30 @@ Tcl_FSLoadFile( */ int -TclSkipUnlink (Tcl_Obj* shlibFile) +TclSkipUnlink( + Tcl_Obj *shlibFile) { - /* Order of testing: + /* + * Order of testing: * 1. On hpux we generally want to skip unlink in general * * Outside of hpux then: - * 2. For a general user request (TCL_TEMPLOAD_NO_UNLINK present, non-empty, => int) + * 2. For a general user request (TCL_TEMPLOAD_NO_UNLINK present, + * non-empty, => int) * 3. For general AUFS environment (statfs, if available). * * Ad 2: This variable can disable/override the AUFS detection, i.e. for - * testing if a newer AUFS does not have the bug any more. + * testing if a newer AUFS does not have the bug any more. * - * Ad 3: This is conditionally compiled in. Condition currently must be set manually. - * This part needs proper tests in the configure(.in). + * Ad 3: This is conditionally compiled in. Condition currently must be + * set manually. This part needs proper tests in the configure(.in). */ #ifdef hpux return 1; #else - char* skipstr; + char *skipstr = getenv("TCL_TEMPLOAD_NO_UNLINK"); - skipstr = getenv ("TCL_TEMPLOAD_NO_UNLINK"); if (skipstr && (skipstr[0] != '\0')) { return atoi(skipstr); } @@ -3192,7 +3197,8 @@ TclSkipUnlink (Tcl_Obj* shlibFile) #ifndef NO_FSTATFS { struct statfs fs; - /* Have fstatfs. May not have the AUFS super magic ... Indeed our build + /* + * Have fstatfs. May not have the AUFS super magic ... Indeed our build * box is too old to have it directly in the headers. Define taken from * http://mooon.googlecode.com/svn/trunk/linux_include/linux/aufs_type.h * http://aufs.sourceforge.net/ @@ -3209,8 +3215,10 @@ TclSkipUnlink (Tcl_Obj* shlibFile) #endif /* ... NO_FSTATFS */ #endif /* ... TCL_TEMPLOAD_NO_UNLINK */ - /* Fallback: !hpux, no EV override, no AUFS (detection, nor detected): - * Don't skip */ + /* + * Fallback: !hpux, no EV override, no AUFS (detection, nor detected): + * Don't skip + */ return 0; #endif /* hpux */ } @@ -3415,9 +3423,8 @@ Tcl_LoadFile( * avoids any worries about leaving the copy laying around on exit. */ - if ( - !TclSkipUnlink (copyToPtr) && - (Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) { + if (!TclSkipUnlink(copyToPtr) && + (Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) { Tcl_DecrRefCount(copyToPtr); /* diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 6a3e4e3..9f38638 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -101,6 +101,7 @@ typedef struct { *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_GetIndexFromObj int Tcl_GetIndexFromObj( @@ -137,6 +138,7 @@ Tcl_GetIndexFromObj( return Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, sizeof(char *), msg, flags, indexPtr); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- diff --git a/generic/tclInt.h b/generic/tclInt.h index 6f45a05..975c685 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1357,7 +1357,7 @@ MODULE_SCOPE void TclThreadDataKeySet(Tcl_ThreadDataKey *keyPtr, */ #define TCL_TSD_INIT(keyPtr) \ - (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData)) + Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData)) /* *---------------------------------------------------------------- @@ -1862,6 +1862,7 @@ typedef struct Interp { * See Tcl_AppendResult code for details. */ +#ifndef TCL_NO_DEPRECATED char *appendResult; /* Storage space for results generated by * Tcl_AppendResult. Ckalloc-ed. NULL means * not yet allocated. */ @@ -1869,6 +1870,11 @@ typedef struct Interp { * partialResult. */ int appendUsed; /* Number of non-null bytes currently stored * at partialResult. */ +#else + char *appendResultDontUse; + int appendAvlDontUse; + int appendUsedDontUse; +#endif /* * Information about packages. Used only in tclPkg.c. @@ -1930,8 +1936,12 @@ typedef struct Interp { * string. Returned by Tcl_ObjSetVar2 when * variable traces change a variable in a * gross way. */ +#ifndef TCL_NO_DEPRECATED char resultSpace[TCL_RESULT_SIZE+1]; /* Static space holding small results. */ +#else + char resultSpaceDontUse[TCL_RESULT_SIZE+1]; +#endif Tcl_Obj *objResultPtr; /* If the last command returned an object * result, this points to it. Should not be * accessed directly; see comment above. */ @@ -2620,7 +2630,7 @@ typedef void (TclInitProcessGlobalValueProc)(char **valuePtr, size_t *lengthPtr, */ typedef struct ProcessGlobalValue { - size_t epoch; /* Epoch counter to detect changes in the + size_t epoch; /* Epoch counter to detect changes in the * master value. */ size_t numBytes; /* Length of the master string. */ char *value; /* The master string value. */ @@ -2962,7 +2972,8 @@ MODULE_SCOPE Tcl_Obj * TclGetBgErrorHandler(Tcl_Interp *interp); MODULE_SCOPE int TclGetChannelFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Channel *chanPtr, int *modePtr, int flags); -MODULE_SCOPE int TclGetCompletionCodeFromObj(Tcl_Interp *interp, +MODULE_SCOPE CmdFrame * TclGetCmdFrameForProcedure(Proc *procPtr); +MODULE_SCOPE int TclGetCompletionCodeFromObj(Tcl_Interp *interp, Tcl_Obj *value, int *code); MODULE_SCOPE int TclGetNumberFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, ClientData *clientDataPtr, @@ -3115,7 +3126,7 @@ MODULE_SCOPE void TclpSetVariables(Tcl_Interp *interp); MODULE_SCOPE void * TclThreadStorageKeyGet(Tcl_ThreadDataKey *keyPtr); MODULE_SCOPE void TclThreadStorageKeySet(Tcl_ThreadDataKey *keyPtr, void *data); -MODULE_SCOPE void TclpThreadExit(int status); +MODULE_SCOPE TCL_NORETURN void TclpThreadExit(int status); MODULE_SCOPE void TclRememberCondition(Tcl_Condition *mutex); MODULE_SCOPE void TclRememberJoinableThread(Tcl_ThreadId id); MODULE_SCOPE void TclRememberMutex(Tcl_Mutex *mutex); @@ -3290,10 +3301,8 @@ MODULE_SCOPE int Tcl_AssembleObjCmd(ClientData clientData, MODULE_SCOPE int TclNRAssembleObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); - -MODULE_SCOPE int Tcl_EncodingObjCmd(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); +MODULE_SCOPE Tcl_Command TclInitEncodingCmd(Tcl_Interp *interp); +MODULE_SCOPE int TclMakeEncodingCommandSafe(Tcl_Interp *interp); MODULE_SCOPE int Tcl_EofObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -3534,6 +3543,12 @@ MODULE_SCOPE int TclCompileBreakCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileCatchCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileClockClicksCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileClockReadingCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileConcatCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3970,7 +3985,7 @@ MODULE_SCOPE int TclCompileAssembleCmd(Tcl_Interp *interp, struct CompileEnv *envPtr); /* - * Functions defined in generic/tclVar.c and currenttly exported only for use + * Functions defined in generic/tclVar.c and currently exported only for use * by the bytecode compiler and engine. Some of these could later be placed in * the public interface. */ @@ -4355,13 +4370,13 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file, #define TCL_MAX_TOKENS (int)(UINT_MAX / sizeof(Tcl_Token)) #define TclGrowTokenArray(tokenPtr, used, available, append, staticPtr) \ do { \ - int needed = (used) + (append); \ - if (needed > TCL_MAX_TOKENS) { \ + int _needed = (used) + (append); \ + if (_needed > TCL_MAX_TOKENS) { \ Tcl_Panic("max # of tokens for a Tcl parse (%d) exceeded", \ TCL_MAX_TOKENS); \ } \ - if (needed > (available)) { \ - int allocated = 2 * needed; \ + if (_needed > (available)) { \ + int allocated = 2 * _needed; \ Tcl_Token *oldPtr = (tokenPtr); \ Tcl_Token *newPtr; \ if (oldPtr == (staticPtr)) { \ @@ -4373,7 +4388,7 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file, newPtr = (Tcl_Token *) attemptckrealloc((char *) oldPtr, \ (unsigned int) (allocated * sizeof(Tcl_Token))); \ if (newPtr == NULL) { \ - allocated = needed + (append) + TCL_MIN_TOKEN_GROWTH; \ + allocated = _needed + (append) + TCL_MIN_TOKEN_GROWTH; \ if (allocated > TCL_MAX_TOKENS) { \ allocated = TCL_MAX_TOKENS; \ } \ @@ -4425,14 +4440,14 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file, #define TclNumUtfChars(numChars, bytes, numBytes) \ do { \ - int count, i = (numBytes); \ - unsigned char *str = (unsigned char *) (bytes); \ - while (i && (*str < 0xC0)) { i--; str++; } \ - count = (numBytes) - i; \ - if (i) { \ - count += Tcl_NumUtfChars((bytes) + count, i); \ + int _count, _i = (numBytes); \ + unsigned char *_str = (unsigned char *) (bytes); \ + while (_i && (*_str < 0xC0)) { _i--; _str++; } \ + _count = (numBytes) - _i; \ + if (_i) { \ + _count += Tcl_NumUtfChars((bytes) + _count, _i); \ } \ - (numChars) = count; \ + (numChars) = _count; \ } while (0); /* @@ -4532,9 +4547,7 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; * core. They should only be called on unshared objects. The ANSI C * "prototypes" for these macros are: * - * MODULE_SCOPE void TclSetIntObj(Tcl_Obj *objPtr, int intValue); * MODULE_SCOPE void TclSetLongObj(Tcl_Obj *objPtr, long longValue); - * MODULE_SCOPE void TclSetBooleanObj(Tcl_Obj *objPtr, long boolValue); * MODULE_SCOPE void TclSetWideIntObj(Tcl_Obj *objPtr, Tcl_WideInt w); * MODULE_SCOPE void TclSetDoubleObj(Tcl_Obj *objPtr, double d); *---------------------------------------------------------------- @@ -4548,19 +4561,6 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; (objPtr)->typePtr = &tclIntType; \ } while (0) -#define TclSetIntObj(objPtr, l) \ - TclSetLongObj(objPtr, l) - -/* - * NOTE: There is to be no such thing as a "pure" boolean. Boolean values set - * programmatically go straight to being "int" Tcl_Obj's, with value 0 or 1. - * The only "boolean" Tcl_Obj's shall be those holding the cached boolean - * value of strings like: "yes", "no", "true", "false", "on", "off". - */ - -#define TclSetBooleanObj(objPtr, b) \ - TclSetLongObj(objPtr, (b)!=0); - #ifndef TCL_WIDE_INT_IS_LONG #define TclSetWideIntObj(objPtr, w) \ do { \ @@ -4586,7 +4586,6 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; * the core. The ANSI C "prototypes" for these macros are: * * MODULE_SCOPE void TclNewLongObj(Tcl_Obj *objPtr, long l); - * MODULE_SCOPE void TclNewBooleanObj(Tcl_Obj *objPtr, int b); * MODULE_SCOPE void TclNewWideObj(Tcl_Obj *objPtr, Tcl_WideInt w); * MODULE_SCOPE void TclNewDoubleObj(Tcl_Obj *objPtr, double d); * MODULE_SCOPE void TclNewStringObj(Tcl_Obj *objPtr, const char *s, int len); @@ -4607,13 +4606,6 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; TCL_DTRACE_OBJ_CREATE(objPtr); \ } while (0) -/* - * NOTE: There is to be no such thing as a "pure" boolean. - * See comment above TclSetBooleanObj macro above. - */ -#define TclNewBooleanObj(objPtr, b) \ - TclNewLongObj((objPtr), (b)!=0) - #define TclNewDoubleObj(objPtr, d) \ do { \ TclIncrObjsAllocated(); \ @@ -4639,9 +4631,6 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; #define TclNewLongObj(objPtr, l) \ (objPtr) = Tcl_NewLongObj(l) -#define TclNewBooleanObj(objPtr, b) \ - (objPtr) = Tcl_NewBooleanObj(b) - #define TclNewDoubleObj(objPtr, d) \ (objPtr) = Tcl_NewDoubleObj(d) @@ -4783,11 +4772,11 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; #ifndef TCL_MEM_DEBUG #define TclSmallAllocEx(interp, nbytes, memPtr) \ do { \ - Tcl_Obj *objPtr; \ + Tcl_Obj *_objPtr; \ TCL_CT_ASSERT((nbytes)<=sizeof(Tcl_Obj)); \ TclIncrObjsAllocated(); \ - TclAllocObjStorageEx((interp), (objPtr)); \ - memPtr = (ClientData) (objPtr); \ + TclAllocObjStorageEx((interp), (_objPtr)); \ + memPtr = (ClientData) (_objPtr); \ } while (0) #define TclSmallFreeEx(interp, memPtr) \ @@ -4799,19 +4788,19 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit; #else /* TCL_MEM_DEBUG */ #define TclSmallAllocEx(interp, nbytes, memPtr) \ do { \ - Tcl_Obj *objPtr; \ + Tcl_Obj *_objPtr; \ TCL_CT_ASSERT((nbytes)<=sizeof(Tcl_Obj)); \ - TclNewObj(objPtr); \ - memPtr = (ClientData) objPtr; \ + TclNewObj(_objPtr); \ + memPtr = (ClientData) _objPtr; \ } while (0) #define TclSmallFreeEx(interp, memPtr) \ do { \ - Tcl_Obj *objPtr = (Tcl_Obj *) memPtr; \ + Tcl_Obj *_objPtr = (Tcl_Obj *) memPtr; \ objPtr->bytes = NULL; \ objPtr->typePtr = NULL; \ objPtr->refCount = 1; \ - TclDecrRefCount(objPtr); \ + TclDecrRefCount(_objPtr); \ } while (0) #endif /* TCL_MEM_DEBUG */ @@ -4863,15 +4852,15 @@ typedef struct NRE_callback { #define TclNRAddCallback(interp,postProcPtr,data0,data1,data2,data3) \ do { \ - 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->nextPtr = TOP_CB(interp); \ - TOP_CB(interp) = callbackPtr; \ + 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->nextPtr = TOP_CB(interp); \ + TOP_CB(interp) = _callbackPtr; \ } while (0) #if NRE_USE_SMALL_ALLOC diff --git a/generic/tclInterp.c b/generic/tclInterp.c index af9f1bf..d9dfd37 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -3533,9 +3533,6 @@ Tcl_LimitAddHandler( if (deleteProc == (Tcl_LimitHandlerDeleteProc *) TCL_DYNAMIC) { deleteProc = (Tcl_LimitHandlerDeleteProc *) Tcl_Free; } - if (deleteProc == (Tcl_LimitHandlerDeleteProc *) TCL_STATIC) { - deleteProc = NULL; - } /* * Allocate a handler record. diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 1e360d1..e1bad0e 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -31,7 +31,7 @@ * limited to a single interpreter. */ -typedef struct ThreadSpecificData { +typedef struct { size_t numNsCreated; /* Count of the number of namespaces created * within the thread. This value is used as a * unique id for each namespace. Cannot be diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index 8003345..ac0b94d 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -619,6 +619,7 @@ AddClassMethodNames( int isWanted = (!(flags & PUBLIC_METHOD) || (mPtr->flags & PUBLIC_METHOD)) ? IN_LIST : 0; + isWanted |= (mPtr->typePtr == NULL ? NO_IMPLEMENTATION : 0); Tcl_SetHashValue(hPtr, INT2PTR(isWanted)); } else if ((PTR2INT(Tcl_GetHashValue(hPtr)) & NO_IMPLEMENTATION) && mPtr->typePtr != NULL) { diff --git a/generic/tclObj.c b/generic/tclObj.c index 7ec259f..f4b81f2 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -75,7 +75,7 @@ typedef struct ObjData { * The structure defined below is used in this file only. */ -typedef struct ThreadSpecificData { +typedef struct { Tcl_HashTable *lineCLPtr; /* This table remembers for each Tcl_Obj * generated by a call to the function * TclSubstTokens() from a literal text @@ -1732,7 +1732,7 @@ Tcl_InvalidateStringRep( * is coerced to 1. * * When TCL_MEM_DEBUG is defined, this function just returns the result - * of calling the debugging version Tcl_DbNewBooleanObj. + * of calling the debugging version Tcl_DbNewLongObj. * * Results: * The newly created object is returned. This object will have an invalid @@ -1751,7 +1751,7 @@ Tcl_Obj * Tcl_NewBooleanObj( register int boolValue) /* Boolean used to initialize new object. */ { - return Tcl_DbNewBooleanObj(boolValue, "unknown", 0); + return Tcl_DbNewLongObj(boolValue!=0, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ @@ -1762,7 +1762,7 @@ Tcl_NewBooleanObj( { register Tcl_Obj *objPtr; - TclNewBooleanObj(objPtr, boolValue); + TclNewLongObj(objPtr, boolValue!=0); return objPtr; } #endif /* TCL_MEM_DEBUG */ @@ -1793,6 +1793,7 @@ Tcl_NewBooleanObj( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_DbNewBooleanObj #ifdef TCL_MEM_DEBUG @@ -1856,8 +1857,9 @@ Tcl_SetBooleanObj( Tcl_Panic("%s called with shared object", "Tcl_SetBooleanObj"); } - TclSetBooleanObj(objPtr, boolValue); + TclSetLongObj(objPtr, boolValue!=0); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -2458,7 +2460,7 @@ Tcl_SetIntObj( Tcl_Panic("%s called with shared object", "Tcl_SetIntObj"); } - TclSetIntObj(objPtr, intValue); + TclSetLongObj(objPtr, intValue); } /* @@ -4453,7 +4455,6 @@ Tcl_RepresentationCmd( int objc, Tcl_Obj *const objv[]) { - char ptrBuffer[2*TCL_INTEGER_SPACE+6]; Tcl_Obj *descObj; if (objc != 2) { @@ -4467,18 +4468,20 @@ Tcl_RepresentationCmd( * "1872361827361287" */ - sprintf(ptrBuffer, "%p", (void *) objv[1]); descObj = Tcl_ObjPrintf("value is a %s with a refcount of %d," - " object pointer at %s", - objv[1]->typePtr ? objv[1]->typePtr->name : "pure string", - objv[1]->refCount, ptrBuffer); + " object pointer at %p", + objv[1]->typePtr ? objv[1]->typePtr->name : "pure string", + objv[1]->refCount, objv[1]); if (objv[1]->typePtr) { - sprintf(ptrBuffer, "%p:%p", - (void *) objv[1]->internalRep.twoPtrValue.ptr1, - (void *) objv[1]->internalRep.twoPtrValue.ptr2); - Tcl_AppendPrintfToObj(descObj, ", internal representation %s", - ptrBuffer); + if (objv[1]->typePtr == &tclDoubleType) { + Tcl_AppendPrintfToObj(descObj, ", internal representation %g", + objv[1]->internalRep.doubleValue); + } else { + Tcl_AppendPrintfToObj(descObj, ", internal representation %p:%p", + (void *) objv[1]->internalRep.twoPtrValue.ptr1, + (void *) objv[1]->internalRep.twoPtrValue.ptr2); + } } if (objv[1]->bytes) { diff --git a/generic/tclParse.c b/generic/tclParse.c index 9b801a3..8a28bf2 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -1170,7 +1170,7 @@ ParseTokens( nestedPtr = TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse)); while (1) { const char *curEnd; - + if (Tcl_ParseCommand(parsePtr->interp, src, numBytes, 1, nestedPtr) != TCL_OK) { parsePtr->errorType = nestedPtr->errorType; diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 0053041..5984c16 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -921,7 +921,17 @@ TclJoinPath( if (res != NULL) { TclDecrRefCount(res); } - return TclNewFSPathObj(elt, str, len); + + if (PATHFLAGS(elt)) { + return TclNewFSPathObj(elt, str, len); + } + if (TCL_PATH_ABSOLUTE != Tcl_FSGetPathType(elt)) { + return TclNewFSPathObj(elt, str, len); + } + (void) Tcl_FSGetNormalizedPath(NULL, elt); + if (elt == PATHOBJ(elt)->normPathPtr) { + return TclNewFSPathObj(elt, str, len); + } } } @@ -948,6 +958,7 @@ TclJoinPath( } } strElt = TclGetStringFromObj(elt, &strEltLen); + driveNameLength = 0; type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName); if (type != TCL_PATH_RELATIVE) { /* @@ -1003,6 +1014,12 @@ TclJoinPath( } } ptr = strElt; + /* [Bug f34cf83dd0] */ + if (driveNameLength > 0) { + if (ptr[0] == '/' && ptr[-1] == '/') { + goto noQuickReturn; + } + } while (*ptr != '\0') { if (*ptr == '/' && (ptr[1] == '/' || ptr[1] == '\0')) { /* diff --git a/generic/tclPreserve.c b/generic/tclPreserve.c index 2d0e15c..5c6097f 100644 --- a/generic/tclPreserve.c +++ b/generic/tclPreserve.c @@ -155,7 +155,7 @@ Tcl_Preserve( refPtr->clientData = clientData; refPtr->refCount = 1; refPtr->mustFree = 0; - refPtr->freeProc = TCL_STATIC; + refPtr->freeProc = 0; inUse += 1; Tcl_MutexUnlock(&preserveMutex); } diff --git a/generic/tclProc.c b/generic/tclProc.c index 373192c..96bdcf3 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -2750,6 +2750,41 @@ MakeLambdaError( } /* + *---------------------------------------------------------------------- + * + * TclGetCmdFrameForProcedure -- + * + * How to get the CmdFrame information for a procedure. + * + * Results: + * A pointer to the CmdFrame (only guaranteed to be valid until the next + * Tcl command is processed or the interpreter's state is otherwise + * modified) or a NULL if the information is not available. + * + * Side effects: + * none. + * + *---------------------------------------------------------------------- + */ + +CmdFrame * +TclGetCmdFrameForProcedure( + Proc *procPtr) /* The procedure whose cmd-frame is to be + * looked up. */ +{ + Tcl_HashEntry *hePtr; + + if (procPtr == NULL || procPtr->iPtr == NULL) { + return NULL; + } + hePtr = Tcl_FindHashEntry(procPtr->iPtr->linePBodyPtr, procPtr); + if (hePtr == NULL) { + return NULL; + } + return (CmdFrame *) Tcl_GetHashValue(hePtr); +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tclRegexp.c b/generic/tclRegexp.c index eb23f72..5f8dc20 100644 --- a/generic/tclRegexp.c +++ b/generic/tclRegexp.c @@ -64,7 +64,7 @@ #define NUM_REGEXPS 30 -typedef struct ThreadSpecificData { +typedef struct { int initialized; /* Set to 1 when the module is initialized. */ char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled regular * expression patterns. NULL means that this @@ -679,7 +679,7 @@ TclRegAbout( resultObj = Tcl_NewObj(); Tcl_ListObjAppendElement(NULL, resultObj, - Tcl_NewIntObj((int) regexpPtr->re.re_nsub)); + Tcl_NewWideIntObj((Tcl_WideInt) regexpPtr->re.re_nsub)); /* * Now append a list of all the bit-flags set for the RE. diff --git a/generic/tclResult.c b/generic/tclResult.c index ddf764b..57a6de5 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -232,6 +232,7 @@ Tcl_DiscardInterpState( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_SaveResult void Tcl_SaveResult( @@ -409,7 +410,6 @@ Tcl_DiscardResult( *---------------------------------------------------------------------- */ -#ifndef TCL_NO_DEPRECATED void Tcl_SetResult( Tcl_Interp *interp, /* Interpreter with which to associate the diff --git a/generic/tclStrIdxTree.c b/generic/tclStrIdxTree.c index d9b5da0..291e481 100644 --- a/generic/tclStrIdxTree.c +++ b/generic/tclStrIdxTree.c @@ -24,26 +24,28 @@ * * Index-Tree: * - * j -1 * ... - * anuar 0 * - * u -1 * a -1 - * ni 5 * pril 3 - * li 6 * ugust 7 - * n -1 * gt 7 - * r 0 * s 8 - * i 5 * eptember 8 - * li 6 * pt 8 - * f 1 * oktober 9 - * ebruar 1 * n 10 - * br 1 * ovember 10 - * m -1 * vb 10 - * a -1 * d 11 - * erz 2 * ezember 11 - * i 4 * zb 11 - * rz 2 * + * j 0 * ... + * anuar 1 * + * u 0 * a 0 + * ni 6 * pril 4 + * li 7 * ugust 8 + * n 0 * gt 8 + * r 1 * s 9 + * i 6 * eptember 9 + * li 7 * pt 9 + * f 2 * oktober 10 + * ebruar 2 * n 11 + * br 2 * ovember 11 + * m 0 * vb 11 + * a 0 * d 12 + * erz 3 * ezember 12 + * i 5 * zb 12 + * rz 3 * * ... * - * Thereby value -1 shows pure group items (corresponding ambigous matches). + * Thereby value 0 shows pure group items (corresponding ambigous matches). + * But the group may have a value if it contains only same values + * (see for example group "f" above). * * StrIdxTree's are very fast, so: * build of above-mentioned tree takes about 10 microseconds. @@ -109,7 +111,7 @@ TclStrIdxTreeSearch( if (offs >= item->length && item->childTree.firstPtr) { /* save previuosly found item (if not ambigous) for * possible fallback (few greedy match) */ - if (item->value != -1) { + if (item->value != NULL) { prevf = f; prevItem = item; prevParent = parent; @@ -206,7 +208,9 @@ TclStrIdxTreeAppend( * TclStrIdxTreeBuildFromList -- * * Build or extend string indexed tree from tcl list. - * + * If the values not given the values of built list are indices starts with 1. + * Value of 0 is thereby reserved to the ambigous values. + * * Important: by multiple lists, optimal tree can be created only if list with * larger strings used firstly. * @@ -223,10 +227,12 @@ MODULE_SCOPE int TclStrIdxTreeBuildFromList( TclStrIdxTree *idxTree, int lstc, - Tcl_Obj **lstv) + Tcl_Obj **lstv, + ClientData *values) { Tcl_Obj **lwrv; int i, ret = TCL_ERROR; + ClientData val; const char *s, *e, *f; TclStrIdx *item; @@ -250,8 +256,9 @@ TclStrIdxTreeBuildFromList( TclStrIdxTree *foundParent = idxTree; e = s = TclGetString(lwrv[i]); e += lwrv[i]->length; + val = values ? values[i] : INT2PTR(i+1); - /* ignore empty values (impossible to index it) */ + /* ignore empty keys (impossible to index it) */ if (lwrv[i]->length == 0) continue; item = NULL; @@ -267,7 +274,7 @@ TclStrIdxTreeBuildFromList( } /* if shortest key was found with the same value, * just replace its current key with longest key */ - if ( foundItem->value == i + if ( foundItem->value == val && foundItem->length < lwrv[i]->length && foundItem->childTree.firstPtr == NULL ) { @@ -286,7 +293,7 @@ TclStrIdxTreeBuildFromList( Tcl_InitObjRef(item->key, foundItem->key); item->length = f - s; /* set value or mark as ambigous if not the same value of both */ - item->value = (foundItem->value == i) ? i : -1; + item->value = (foundItem->value == val) ? val : NULL; /* insert group item between foundParent and foundItem */ TclStrIdxTreeInsertBranch(foundParent, item, foundItem); foundParent = &item->childTree; @@ -304,7 +311,7 @@ TclStrIdxTreeBuildFromList( item->childTree.lastPtr = item->childTree.firstPtr = NULL; Tcl_InitObjRef(item->key, lwrv[i]); item->length = lwrv[i]->length; - item->value = i; + item->value = val; TclStrIdxTreeAppend(foundParent, item); }; @@ -496,7 +503,7 @@ TclStrIdxTreeTestObjCmd( &lstc, &lstv) != TCL_OK) { return TCL_ERROR; }; - TclStrIdxTreeBuildFromList(&idxTree, lstc, lstv); + TclStrIdxTreeBuildFromList(&idxTree, lstc, lstv, NULL); } if (optionIndex == O_PUTS_INDEX) { TclStrIdxTreePrint(interp, idxTree.firstPtr, 0); diff --git a/generic/tclStrIdxTree.h b/generic/tclStrIdxTree.h index 305053c..9f26907 100644 --- a/generic/tclStrIdxTree.h +++ b/generic/tclStrIdxTree.h @@ -27,9 +27,9 @@ typedef struct TclStrIdx { struct TclStrIdxTree childTree; struct TclStrIdx *nextPtr; struct TclStrIdx *prevPtr; - Tcl_Obj *key; - int length; - int value; + Tcl_Obj *key; + int length; + ClientData value; } TclStrIdx; @@ -152,7 +152,7 @@ MODULE_SCOPE const char* const char *start, const char *end); MODULE_SCOPE int TclStrIdxTreeBuildFromList(TclStrIdxTree *idxTree, - int lstc, Tcl_Obj **lstv); + int lstc, Tcl_Obj **lstv, ClientData *values); MODULE_SCOPE Tcl_Obj* TclStrIdxTreeNewObj(); diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c index 224ab45..c7fdc5a 100644 --- a/generic/tclStrToD.c +++ b/generic/tclStrToD.c @@ -3805,7 +3805,7 @@ ShorteningBignumConversion( --s5; /* - * IDEA: It might possibly be a win to fall back to int64 + * IDEA: It might possibly be a win to fall back to int64_t * arithmetic here if S < 2**64/10. But it's a win only for * a fairly narrow range of magnitudes so perhaps not worth * bothering. We already know that we shorten the @@ -3970,7 +3970,7 @@ StrictBignumConversion( * As with the shortening bignum conversion, it's possible at this * point that we will have reduced the denominator to less than * 2**64/10, at which point it would be possible to fall back to - * to int64 arithmetic. But the potential payoff is tremendously + * to int64_t arithmetic. But the potential payoff is tremendously * less - unless we're working in F format - because we know that * three groups of digits will always suffice for %#.17e, the * longest format that doesn't introduce empty precision. diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index c45baa1..7c898b7 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -1670,8 +1670,11 @@ Tcl_AppendFormatToObj( while (*format != '\0') { char *end; - int gotMinus, gotHash, gotZero, gotSpace, gotPlus, sawFlag; - int width, gotPrecision, precision, useShort, useWide, useBig; + int gotMinus = 0, gotHash = 0, gotZero = 0, gotSpace = 0, gotPlus = 0; + int width, gotPrecision, precision, sawFlag, useShort = 0, useBig = 0; +#ifndef TCL_WIDE_INT_IS_LONG + int useWide = 0; +#endif int newXpg, numChars, allocSegment = 0, segmentLimit, segmentNumBytes; Tcl_Obj *segment; Tcl_UniChar ch; @@ -1747,7 +1750,6 @@ Tcl_AppendFormatToObj( * Step 2. Set of flags. */ - gotMinus = gotHash = gotZero = gotSpace = gotPlus = 0; sawFlag = 1; do { switch (ch) { @@ -1848,7 +1850,6 @@ Tcl_AppendFormatToObj( * Step 5. Length modifier. */ - useShort = useWide = useBig = 0; if (ch == 'h') { useShort = 1; format += step; @@ -1865,14 +1866,34 @@ Tcl_AppendFormatToObj( useWide = 1; #endif } - } else if ((ch == 'I') && (format[1] == '6') && (format[2] == '4')) { - format += (step + 2); + } else if (ch == 'I') { + if ((format[1] == '6') && (format[2] == '4')) { + format += (step + 2); + step = Tcl_UtfToUniChar(format, &ch); +#ifndef TCL_WIDE_INT_IS_LONG + useWide = 1; +#endif + } else if ((format[1] == '3') && (format[2] == '2')) { + format += (step + 2); + step = Tcl_UtfToUniChar(format, &ch); + } else { + format += step; + step = Tcl_UtfToUniChar(format, &ch); + } + } else if ((ch == 't') || (ch == 'z')) { + format += step; step = Tcl_UtfToUniChar(format, &ch); - useBig = 1; - } else if (ch == 'L') { +#ifndef TCL_WIDE_INT_IS_LONG + if (sizeof(size_t) > sizeof(int)) { + useWide = 1; + } +#endif + } else if ((ch == 'q') ||(ch == 'j')) { format += step; step = Tcl_UtfToUniChar(format, &ch); - useBig = 1; +#ifndef TCL_WIDE_INT_IS_LONG + useWide = 1; +#endif } format += step; @@ -1925,6 +1946,7 @@ Tcl_AppendFormatToObj( } case 'd': case 'o': + case 'p': case 'x': case 'X': case 'b': { @@ -1935,11 +1957,17 @@ Tcl_AppendFormatToObj( mp_int big; int toAppend, isNegative = 0; +#ifndef TCL_WIDE_INT_IS_LONG + if (ch == 'p') { + useWide = 1; + } +#endif if (useBig) { if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) { goto error; } isNegative = (mp_cmp_d(&big, 0) == MP_LT); +#ifndef TCL_WIDE_INT_IS_LONG } else if (useWide) { if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { Tcl_Obj *objPtr; @@ -1954,6 +1982,7 @@ Tcl_AppendFormatToObj( Tcl_DecrRefCount(objPtr); } isNegative = (w < (Tcl_WideInt) 0); +#endif } else if (TclGetLongFromObj(NULL, segment, &l) != TCL_OK) { if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { Tcl_Obj *objPtr; @@ -1993,13 +2022,14 @@ Tcl_AppendFormatToObj( segmentLimit -= 1; } - if (gotHash) { + if (gotHash || (ch == 'p')) { switch (ch) { case 'o': Tcl_AppendToObj(segment, "0", 1); segmentLimit -= 1; precision--; break; + case 'p': case 'x': case 'X': Tcl_AppendToObj(segment, "0x", 2); @@ -2020,8 +2050,10 @@ Tcl_AppendFormatToObj( if (useShort) { pure = Tcl_NewIntObj((int) s); +#ifndef TCL_WIDE_INT_IS_LONG } else if (useWide) { pure = Tcl_NewWideIntObj(w); +#endif } else if (useBig) { pure = Tcl_NewBignumObj(&big); } else { @@ -2078,6 +2110,7 @@ Tcl_AppendFormatToObj( case 'u': case 'o': + case 'p': case 'x': case 'X': case 'b': { @@ -2104,6 +2137,7 @@ Tcl_AppendFormatToObj( numDigits++; us /= base; } +#ifndef TCL_WIDE_INT_IS_LONG } else if (useWide) { Tcl_WideUInt uw = (Tcl_WideUInt) w; @@ -2112,6 +2146,7 @@ Tcl_AppendFormatToObj( numDigits++; uw /= base; } +#endif } else if (useBig && big.used) { int leftover = (big.used * DIGIT_BIT) % numBits; mp_digit mask = (~(mp_digit)0) << (DIGIT_BIT-leftover); @@ -2467,6 +2502,7 @@ AppendPrintfToObjVA( case 'u': case 'd': case 'o': + case 'p': case 'x': case 'X': seekingConversion = 0; @@ -2517,7 +2553,15 @@ AppendPrintfToObjVA( ++size; p++; break; - case 'L': + case 't': + case 'z': + if (sizeof(size_t) == sizeof(Tcl_WideInt)) { + size = 2; + } + p++; + break; + case 'j': + case 'q': size = 2; p++; break; @@ -2525,6 +2569,10 @@ AppendPrintfToObjVA( if (p[1]=='6' && p[2]=='4') { p += 2; size = 2; + } else if (p[1]=='3' && p[2]=='2') { + p += 2; + } else if (sizeof(size_t) == sizeof(Tcl_WideInt)) { + size = 2; } p++; break; @@ -2732,7 +2780,7 @@ TclStringRepeat( if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "string size overflow: unable to alloc %" - TCL_LL_MODIFIER "u bytes", + TCL_LL_MODIFIER "d bytes", (Tcl_WideUInt)STRING_SIZE(count*length))); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); } @@ -2956,7 +3004,7 @@ TclStringCatObjv( if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "concatenation failed: unable to alloc %" - TCL_LL_MODIFIER "u bytes", + TCL_LL_MODIFIER "d bytes", (Tcl_WideUInt)STRING_SIZE(length))); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); } @@ -2972,7 +3020,7 @@ TclStringCatObjv( if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "concatenation failed: unable to alloc %" - TCL_LL_MODIFIER "u bytes", + TCL_LL_MODIFIER "d bytes", (Tcl_WideUInt)STRING_SIZE(length))); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); } diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 561b9dd..55ef325 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -41,15 +41,15 @@ #undef Tcl_FindExecutable #undef TclpGetPid #undef TclSockMinimumBuffers -#define TclBackgroundException Tcl_BackgroundException #undef Tcl_SetIntObj #undef TclpInetNtoa #undef TclWinGetServByName #undef TclWinGetSockOpt #undef TclWinSetSockOpt +#undef TclWinNToHS /* See bug 510001: TclSockMinimumBuffers needs plat imp */ -#ifdef _WIN64 +#if defined(_WIN64) || defined(TCL_NO_DEPRECATED) # define TclSockMinimumBuffersOld 0 #else #define TclSockMinimumBuffersOld sockMinimumBuffersOld @@ -59,6 +59,17 @@ static int TclSockMinimumBuffersOld(int sock, int size) } #endif +#if defined(TCL_NO_DEPRECATED) +# define TclSetStartupScriptPath 0 +# define TclGetStartupScriptPath 0 +# define TclSetStartupScriptFileName 0 +# define TclGetStartupScriptFileName 0 +# define TclpInetNtoa 0 +# define TclWinGetServByName 0 +# define TclWinGetSockOpt 0 +# define TclWinSetSockOpt 0 +# define TclWinNToHS 0 +#else #define TclSetStartupScriptPath setStartupScriptPath static void TclSetStartupScriptPath(Tcl_Obj *path) { @@ -92,6 +103,7 @@ static unsigned short TclWinNToHS(unsigned short ns) { return ntohs(ns); } #endif +#endif /* TCL_NO_DEPRECATED */ #ifdef _WIN32 # define TclUnixWaitForFile 0 @@ -131,6 +143,7 @@ void *TclWinGetTclInstance() return hInstance; } +#ifndef TCL_NO_DEPRECATED #define TclWinSetSockOpt winSetSockOpt static int TclWinSetSockOpt(SOCKET s, int level, int optname, @@ -153,6 +166,7 @@ TclWinGetServByName(const char *name, const char *proto) { return getservbyname(name, proto); } +#endif /* TCL_NO_DEPRECATED */ #define TclWinNoBackslash winNoBackslash static char * @@ -287,26 +301,79 @@ static int formatInt(char *buffer, int n){ } #define TclFormatInt (int(*)(char *, long))formatInt -#endif +#endif /* TCL_WIDE_INT_IS_LONG */ -#else /* UNIX and MAC */ -# ifdef TCL_NO_DEPRECATED -# define TclpLocaltime_unix 0 -# define TclpGmtime_unix 0 -# else -# define TclpLocaltime_unix TclpLocaltime -# define TclpGmtime_unix TclpGmtime -# endif -#endif +#endif /* __CYGWIN__ */ #ifdef TCL_NO_DEPRECATED # define Tcl_SeekOld 0 # define Tcl_TellOld 0 +# undef Tcl_SetBooleanObj +# define Tcl_SetBooleanObj 0 +# undef Tcl_PkgPresent +# define Tcl_PkgPresent 0 +# undef Tcl_PkgProvide +# define Tcl_PkgProvide 0 +# undef Tcl_PkgRequire +# define Tcl_PkgRequire 0 +# undef Tcl_GetIndexFromObj +# define Tcl_GetIndexFromObj 0 +# define Tcl_NewBooleanObj 0 +# undef Tcl_DbNewBooleanObj +# define Tcl_DbNewBooleanObj 0 +# undef Tcl_SetBooleanObj +# define Tcl_SetBooleanObj 0 +# undef Tcl_SetVar +# define Tcl_SetVar 0 +# undef Tcl_UnsetVar +# define Tcl_UnsetVar 0 +# undef Tcl_GetVar +# define Tcl_GetVar 0 +# undef Tcl_TraceVar +# define Tcl_TraceVar 0 +# undef Tcl_UntraceVar +# define Tcl_UntraceVar 0 +# undef Tcl_VarTraceInfo +# define Tcl_VarTraceInfo 0 +# undef Tcl_UpVar +# define Tcl_UpVar 0 +# undef Tcl_AddErrorInfo +# define Tcl_AddErrorInfo 0 +# undef Tcl_AddObjErrorInfo +# define Tcl_AddObjErrorInfo 0 +# undef Tcl_Eval +# define Tcl_Eval 0 +# undef Tcl_GlobalEval +# define Tcl_GlobalEval 0 +# undef Tcl_SaveResult +# define Tcl_SaveResult 0 +# undef Tcl_RestoreResult +# define Tcl_RestoreResult 0 +# undef Tcl_DiscardResult +# define Tcl_DiscardResult 0 # undef Tcl_SetResult # define Tcl_SetResult 0 +# undef Tcl_EvalObj +# define Tcl_EvalObj 0 +# undef Tcl_GlobalEvalObj +# define Tcl_GlobalEvalObj 0 +# define TclBackgroundException 0 +# undef TclpReaddir +# define TclpReaddir 0 +# undef TclpGetDate +# define TclpGetDate 0 +# undef TclpLocaltime +# define TclpLocaltime 0 +# undef TclpGmtime +# define TclpGmtime 0 +# define TclpLocaltime_unix 0 +# define TclpGmtime_unix 0 #else /* TCL_NO_DEPRECATED */ # define Tcl_SeekOld seekOld # define Tcl_TellOld tellOld +# define TclBackgroundException Tcl_BackgroundException +# define TclpLocaltime_unix TclpLocaltime +# define TclpGmtime_unix TclpGmtime static int seekOld( diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index dd951bf..5261591 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -67,7 +67,7 @@ Tcl_InitStubs( if (!stubsPtr || (stubsPtr->magic != (((exact&0xff00) >= 0x900) ? magic : TCL_STUB_MAGIC))) { iPtr->result = (char *)"interpreter uses an incompatible stubs mechanism"; - iPtr->freeProc = TCL_STATIC; + iPtr->freeProc = 0; return NULL; } diff --git a/generic/tclTest.c b/generic/tclTest.c index a9dc1ca..547dc9a 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -67,6 +67,18 @@ typedef struct TestAsyncHandler { /* Next is list of handlers. */ } TestAsyncHandler; +/* + * Start of the socket driver state structure to acces field testFlags + */ + +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 */ +}; + TCL_DECLARE_MUTEX(asyncTestMutex) static TestAsyncHandler *firstHandler = NULL; @@ -364,6 +376,8 @@ static int TestChannelCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char **argv); static int TestChannelEventCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char **argv); +static int TestSocketCmd(ClientData clientData, + Tcl_Interp *interp, int argc, const char **argv); static int TestFilesystemObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -676,6 +690,8 @@ Tcltest_Init( TestNumUtfCharsCmd, NULL, NULL); Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd, NULL, NULL); + Tcl_CreateCommand(interp, "testsocket", TestSocketCmd, + NULL, NULL); Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd, NULL, NULL); Tcl_CreateCommand(interp, "testtranslatefilename", @@ -3405,7 +3421,7 @@ TestMathFunc2( resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else { - Tcl_SetResult(interp, (char *)"T3: wrong type for arg 2", TCL_STATIC); + Tcl_AppendResult(interp, "T3: wrong type for arg 2", NULL); result = TCL_ERROR; } } else if (args[0].type == TCL_DOUBLE) { @@ -3427,7 +3443,7 @@ TestMathFunc2( resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else { - Tcl_SetResult(interp, (char *)"T3: wrong type for arg 2", TCL_STATIC); + Tcl_AppendResult(interp, "T3: wrong type for arg 2", NULL); result = TCL_ERROR; } } else if (args[0].type == TCL_WIDE_INT) { @@ -3450,11 +3466,11 @@ TestMathFunc2( resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else { - Tcl_SetResult(interp, (char *)"T3: wrong type for arg 2", TCL_STATIC); + Tcl_AppendResult(interp, "T3: wrong type for arg 2", NULL); result = TCL_ERROR; } } else { - Tcl_SetResult(interp, (char *)"T3: wrong type for arg 1", TCL_STATIC); + Tcl_AppendResult(interp, "T3: wrong type for arg 1", NULL); result = TCL_ERROR; } return result; @@ -3847,6 +3863,7 @@ TestprintObjCmd( Tcl_Obj *const objv[]) /* The argument objects. */ { Tcl_WideInt argv1 = 0; + size_t argv2; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "format wideint"); @@ -3855,7 +3872,8 @@ TestprintObjCmd( if (objc > 1) { Tcl_GetWideIntFromObj(interp, objv[2], &argv1); } - Tcl_SetObjResult(interp, Tcl_ObjPrintf(Tcl_GetString(objv[1]), argv1)); + argv2 = (size_t)argv1; + Tcl_SetObjResult(interp, Tcl_ObjPrintf(Tcl_GetString(objv[1]), argv1, argv2, argv2)); return TCL_OK; } @@ -6079,6 +6097,75 @@ TestChannelEventCmd( /* *---------------------------------------------------------------------- * + * TestSocketCmd -- + * + * Implements the Tcl "testsocket" debugging command and its + * subcommands. This is part of the testing environment. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +TestSocketCmd( + ClientData clientData, /* Not used. */ + Tcl_Interp *interp, /* Interpreter for result. */ + int argc, /* Count of additional args. */ + const char **argv) /* Additional arg strings. */ +{ + const char *cmdName; /* Sub command. */ + size_t len; /* Length of subcommand string. */ + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " subcommand ?additional args..?\"", NULL); + return TCL_ERROR; + } + cmdName = argv[1]; + len = strlen(cmdName); + + if ((cmdName[0] == 't') && (strncmp(cmdName, "testflags", len) == 0)) { + Tcl_Channel hChannel; + int modePtr; + TcpState *statePtr; + /* Set test value in the socket driver + */ + /* Check for argument "channel name" + */ + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " testflags channel flags\"", NULL); + return TCL_ERROR; + } + hChannel = Tcl_GetChannel(interp, argv[2], &modePtr); + if ( NULL == hChannel ) { + Tcl_AppendResult(interp, "unknown channel:", argv[2], NULL); + return TCL_ERROR; + } + statePtr = (TcpState *)Tcl_GetChannelInstanceData(hChannel); + if ( NULL == statePtr) { + Tcl_AppendResult(interp, "No channel instance data:", argv[2], + NULL); + return TCL_ERROR; + } + statePtr->testFlags = atoi(argv[3]); + return TCL_OK; + } + + Tcl_AppendResult(interp, "bad option \"", cmdName, "\": should be " + "testflags", NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * * TestWrongNumArgsObjCmd -- * * Test the Tcl_WrongNumArgs function. diff --git a/generic/tclThreadTest.c b/generic/tclThreadTest.c index 1a05f80..9c5fecb 100644 --- a/generic/tclThreadTest.c +++ b/generic/tclThreadTest.c @@ -341,7 +341,7 @@ ThreadObjCmd( } else if (objc == 3 && strcmp("-main", Tcl_GetString(objv[2])) == 0) { Tcl_MutexLock(&threadMutex); - idObj = Tcl_NewLongObj((long)(size_t)mainThreadId); + idObj = Tcl_NewWideIntObj((Tcl_WideInt)(size_t)mainThreadId); Tcl_MutexUnlock(&threadMutex); } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); @@ -655,7 +655,7 @@ ThreadErrorProc( char *script; char buf[TCL_DOUBLE_SPACE+1]; - sprintf(buf, "%" TCL_LL_MODIFIER "d", (Tcl_WideInt)(size_t)Tcl_GetCurrentThread()); + sprintf(buf, "%p", Tcl_GetCurrentThread()); errorInfo = Tcl_GetVar2(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY); if (errorProcString == NULL) { diff --git a/generic/tclTimer.c b/generic/tclTimer.c index 6d3938b..3467305 100644 --- a/generic/tclTimer.c +++ b/generic/tclTimer.c @@ -1053,11 +1053,17 @@ AfterDelay( if (diff > TCL_TIME_MAXIMUM_SLICE) { diff = TCL_TIME_MAXIMUM_SLICE; } - if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) diff = 1; + if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) { + diff = 1; + } if (diff > 0) { Tcl_Sleep((long) diff); - if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) break; - } else break; + if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) { + break; + } + } else { + break; + } } else { diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now); #ifndef TCL_WIDE_INT_IS_LONG diff --git a/generic/tclTrace.c b/generic/tclTrace.c index bea3162..f86f472 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -2819,6 +2819,7 @@ DisposeTraceResult( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_UntraceVar void Tcl_UntraceVar( @@ -2834,6 +2835,7 @@ Tcl_UntraceVar( { Tcl_UntraceVar2(interp, varName, NULL, flags, proc, clientData); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -2988,6 +2990,7 @@ Tcl_UntraceVar2( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_VarTraceInfo ClientData Tcl_VarTraceInfo( @@ -3005,6 +3008,7 @@ Tcl_VarTraceInfo( return Tcl_VarTraceInfo2(interp, varName, NULL, flags, proc, prevClientData); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -3097,6 +3101,7 @@ Tcl_VarTraceInfo2( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_TraceVar int Tcl_TraceVar( @@ -3114,6 +3119,7 @@ Tcl_TraceVar( { return Tcl_TraceVar2(interp, varName, NULL, flags, proc, clientData); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- diff --git a/generic/tclUtil.c b/generic/tclUtil.c index a4d523a..91cc3b4 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -3153,7 +3153,7 @@ Tcl_PrintDouble( int signum; char *digits; char *end; - int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int)); + int *precisionPtr = Tcl_GetThreadData(&precisionKey, sizeof(int)); /* * Handle NaN. @@ -3326,7 +3326,7 @@ TclPrecTraceProc( { Tcl_Obj *value; int prec; - int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int)); + int *precisionPtr = Tcl_GetThreadData(&precisionKey, sizeof(int)); /* * If the variable is unset, then recreate the trace. diff --git a/generic/tclVar.c b/generic/tclVar.c index 5ab6e8b..1947c8d 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -1067,6 +1067,7 @@ TclLookupArrayElement( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_GetVar const char * Tcl_GetVar( @@ -1087,6 +1088,7 @@ Tcl_GetVar( } return TclGetString(resultPtr); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -1410,6 +1412,7 @@ Tcl_SetObjCmd( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_SetVar const char * Tcl_SetVar( @@ -1422,18 +1425,15 @@ Tcl_SetVar( * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, * TCL_LEAVE_ERR_MSG. */ { - Tcl_Obj *varValuePtr, *varNamePtr = Tcl_NewStringObj(varName, -1); - - Tcl_IncrRefCount(varNamePtr); - varValuePtr = Tcl_ObjSetVar2(interp, varNamePtr, NULL, + Tcl_Obj *varValuePtr = Tcl_SetVar2Ex(interp, varName, NULL, Tcl_NewStringObj(newValue, -1), flags); - Tcl_DecrRefCount(varNamePtr); if (varValuePtr == NULL) { return NULL; } return TclGetString(varValuePtr); } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -2005,6 +2005,7 @@ TclPtrIncrObjVar( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_UnsetVar int Tcl_UnsetVar( @@ -2033,6 +2034,7 @@ Tcl_UnsetVar( Tcl_DecrRefCount(varNamePtr); return result; } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- @@ -4050,7 +4052,7 @@ TclInitArrayCmd( * * Results: * A standard Tcl completion code. If an error occurs then an error - * message is left in iPtr->result. + * message is left in interp. * * Side effects: * The variable given by myName is linked to the variable in framePtr @@ -4144,7 +4146,7 @@ ObjMakeUpvar( * * Results: * A standard Tcl completion code. If an error occurs then an error - * message is left in iPtr->result. + * message is left in interp. * * Side effects: * The variable given by myName is linked to the variable in framePtr @@ -4320,6 +4322,7 @@ TclPtrObjMakeUpvar( *---------------------------------------------------------------------- */ +#ifndef TCL_NO_DEPRECATED #undef Tcl_UpVar int Tcl_UpVar( @@ -4353,6 +4356,7 @@ Tcl_UpVar( Tcl_DecrRefCount(localNamePtr); return result; } +#endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- diff --git a/generic/tclZlib.c b/generic/tclZlib.c index 96b8318..33eebd1 100644 --- a/generic/tclZlib.c +++ b/generic/tclZlib.c @@ -3113,30 +3113,28 @@ ZlibTransformOutput( errorCodePtr); } + /* + * No zero-length writes. Flushes must be explicit. + */ + + if (toWrite == 0) { + return 0; + } + cd->outStream.next_in = (Bytef *) buf; cd->outStream.avail_in = toWrite; - do { + while (cd->outStream.avail_in > 0) { e = Deflate(&cd->outStream, cd->outBuffer, cd->outAllocated, Z_NO_FLUSH, &produced); + if (e != Z_OK || produced == 0) { + break; + } - if ((e == Z_OK && produced > 0) || e == Z_BUF_ERROR) { - /* - * deflate() indicates that it is out of space by returning - * Z_BUF_ERROR *or* by simply returning Z_OK with no remaining - * space; in either case, we must write the whole buffer out and - * retry to compress what is left. - */ - - if (e == Z_BUF_ERROR) { - produced = cd->outAllocated; - e = Z_OK; - } - if (Tcl_WriteRaw(cd->parent, cd->outBuffer, produced) < 0) { - *errorCodePtr = Tcl_GetErrno(); - return -1; - } + if (Tcl_WriteRaw(cd->parent, cd->outBuffer, produced) < 0) { + *errorCodePtr = Tcl_GetErrno(); + return -1; } - } while (e == Z_OK && produced > 0 && cd->outStream.avail_in > 0); + } if (e == Z_OK) { return toWrite - cd->outStream.avail_in; |