diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclBasic.c | 31 | ||||
-rw-r--r-- | generic/tclCmdAH.c | 41 | ||||
-rw-r--r-- | generic/tclCompile.c | 8 | ||||
-rw-r--r-- | generic/tclEncoding.c | 233 | ||||
-rw-r--r-- | generic/tclExecute.c | 13 | ||||
-rw-r--r-- | generic/tclFileName.c | 4 | ||||
-rw-r--r-- | generic/tclGet.c | 244 | ||||
-rw-r--r-- | generic/tclIO.c | 8 | ||||
-rw-r--r-- | generic/tclIOUtil.c | 17 | ||||
-rw-r--r-- | generic/tclInt.h | 7 | ||||
-rw-r--r-- | generic/tclInterp.c | 152 | ||||
-rw-r--r-- | generic/tclLiteral.c | 8 | ||||
-rw-r--r-- | generic/tclObj.c | 441 | ||||
-rwxr-xr-x | generic/tclThreadAlloc.c | 4 | ||||
-rw-r--r-- | generic/tclUtil.c | 16 | ||||
-rw-r--r-- | generic/tclVar.c | 4 |
16 files changed, 506 insertions, 725 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 66631a1..b7c1a1b 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.136.2.6 2005/04/10 23:14:45 kennykb Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.136.2.7 2005/04/25 21:37:19 kennykb Exp $ */ #include "tclInt.h" @@ -573,6 +573,10 @@ Tcl_CreateInterp() TclDefaultBgErrorHandlerObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL ); + /* Register the unsupported encoding search path command */ + Tcl_CreateObjCommand (interp, "::tcl::unsupported::EncodingDirs", + TclEncodingDirsObjCmd, NULL, NULL); + /* * Register the builtin math functions. */ @@ -4348,20 +4352,7 @@ Tcl_ExprBoolean(interp, string, ptr) /* * Store a boolean based on the expression result. */ - - if (resultPtr->typePtr == &tclIntType) { - *ptr = (resultPtr->internalRep.longValue != 0); - } else if (resultPtr->typePtr == &tclDoubleType) { - *ptr = (resultPtr->internalRep.doubleValue != 0.0); - } else if (resultPtr->typePtr == &tclWideIntType) { -#ifndef TCL_WIDE_INT_IS_LONG - *ptr = (resultPtr->internalRep.wideValue != 0); -#else - *ptr = (resultPtr->internalRep.longValue != 0); -#endif - } else { - result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); - } + result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); Tcl_DecrRefCount(resultPtr); /* discard the result object */ } if (result != TCL_OK) { @@ -4471,13 +4462,7 @@ Tcl_ExprBooleanObj(interp, objPtr, ptr) result = Tcl_ExprObj(interp, objPtr, &resultPtr); if (result == TCL_OK) { - if (resultPtr->typePtr == &tclIntType) { - *ptr = (resultPtr->internalRep.longValue != 0); - } else if (resultPtr->typePtr == &tclDoubleType) { - *ptr = (resultPtr->internalRep.doubleValue != 0.0); - } else { - result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); - } + result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); Tcl_DecrRefCount(resultPtr); /* discard the result object */ } return result; @@ -4620,7 +4605,7 @@ TclObjInvoke(interp, objc, objv, flags) Tcl_IncrRefCount( command ); cmdString = Tcl_GetStringFromObj(command, &length); Tcl_LogCommandInfo(interp, cmdString, cmdString, length); - Tcl_DecrRefCount( command ); + Tcl_DecrRefCount(command); iPtr->flags &= ~ERR_ALREADY_LOGGED; } return result; diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 60893fd..b75272a 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdAH.c,v 1.57.2.2 2005/04/10 23:14:45 kennykb Exp $ + * RCS: @(#) $Id: tclCmdAH.c,v 1.57.2.3 2005/04/25 21:37:19 kennykb Exp $ */ #include "tclInt.h" @@ -530,6 +530,45 @@ Tcl_EncodingObjCmd(dummy, interp, objc, objv) /* *---------------------------------------------------------------------- * + * TclEncodingDirsObjCmd -- + * + * This command manipulates the encoding search path. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Can set the encoding search path. + * + *---------------------------------------------------------------------- + */ + +int +TclEncodingDirsObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ +{ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?dirList?"); + } + if (objc == 1) { + Tcl_SetObjResult(interp, TclGetEncodingSearchPath()); + return TCL_OK; + } + if (TclSetEncodingSearchPath(objv[1]) == TCL_ERROR) { + Tcl_AppendResult(interp, "expected directory list but got \"", + Tcl_GetString(objv[1]), "\"", NULL); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, objv[1]); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_ErrorObjCmd -- * * This procedure is invoked to process the "error" Tcl command. diff --git a/generic/tclCompile.c b/generic/tclCompile.c index ccec254..f539bf2 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.c,v 1.78.2.3 2005/03/15 20:23:39 kennykb Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.78.2.4 2005/04/25 21:37:19 kennykb Exp $ */ #include "tclInt.h" @@ -3108,6 +3108,7 @@ TclPrintByteCodeObj(interp, objPtr) } #endif /* TCL_COMPILE_DEBUG */ +#ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * @@ -3238,7 +3239,9 @@ TclPrintInstruction(codePtr, pc) fprintf(stdout, "\n"); return numBytes; } +#endif /* TCL_COMPILE_DEBUG */ +#ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * @@ -3269,7 +3272,9 @@ TclPrintObject(outFile, objPtr, maxChars) bytes = Tcl_GetStringFromObj(objPtr, &length); TclPrintSource(outFile, bytes, TclMin(length, maxChars)); } +#endif /* TCL_COMPILE_DEBUG */ +#ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * @@ -3331,6 +3336,7 @@ TclPrintSource(outFile, stringPtr, maxChars) } fprintf(outFile, "\""); } +#endif /* TCL_COMPILE_DEBUG */ #ifdef TCL_COMPILE_STATS /* diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index 6b32340..fb1f100 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEncoding.c,v 1.29.2.3 2005/04/10 23:14:48 kennykb Exp $ + * RCS: @(#) $Id: tclEncoding.c,v 1.29.2.4 2005/04/25 21:37:19 kennykb Exp $ */ #include "tclInt.h" @@ -150,9 +150,8 @@ static ProcessGlobalValue encodingSearchPath = * threads. Access to the shared string is governed by a mutex lock. */ -static TclInitProcessGlobalValueProc InitializeEncodingFileMap; static ProcessGlobalValue encodingFileMap = - {0, 0, NULL, NULL, InitializeEncodingFileMap, NULL, NULL}; + {0, 0, NULL, NULL, NULL, NULL, NULL}; /* * A list of directories making up the "library path". Historically @@ -224,7 +223,8 @@ static Tcl_Encoding LoadTableEncoding _ANSI_ARGS_((CONST char *name, int type, Tcl_Channel chan)); static Tcl_Encoding LoadEscapeEncoding _ANSI_ARGS_((CONST char *name, Tcl_Channel chan)); -static Tcl_Obj * MakeFileMap (); +static Tcl_Channel OpenEncodingFileChannel _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *name)); static void TableFreeProc _ANSI_ARGS_((ClientData clientData)); static int TableFromUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, @@ -388,7 +388,6 @@ TclSetEncodingSearchPath(searchPath) return TCL_ERROR; } TclSetProcessGlobalValue(&encodingSearchPath, searchPath, NULL); - FillEncodingFileMap(); return TCL_OK; } @@ -441,7 +440,10 @@ TclSetLibraryPath(path) /* *--------------------------------------------------------------------------- * - * MakeFileMap -- + * FillEncodingFileMap -- + * + * Called to bring the encoding file map in sync with the current + * value of the encoding search path. * * Scan the directories on the encoding search path, find the * *.enc files, and store the found pathnames in a map associated @@ -462,8 +464,8 @@ TclSetLibraryPath(path) *--------------------------------------------------------------------------- */ -static Tcl_Obj * -MakeFileMap() +void +FillEncodingFileMap() { int i, numDirs = 0; Tcl_Obj *map, *searchPath; @@ -505,33 +507,6 @@ MakeFileMap() Tcl_DecrRefCount(directory); } Tcl_DecrRefCount(searchPath); - return map; -} - -/* - *--------------------------------------------------------------------------- - * - * FillEncodingFileMap -- - * - * Called to bring the encoding file map in sync with the current - * value of the encoding search path. - * - * TODO: Check the callers of this routine to see if it's called - * too frequently. - * - * Results: - * None. - * - * Side effects: - * Entries are added to the encoding file map. - * - *--------------------------------------------------------------------------- - */ - -void -FillEncodingFileMap() -{ - Tcl_Obj *map = MakeFileMap(); TclSetProcessGlobalValue(&encodingFileMap, map, NULL); Tcl_DecrRefCount(map); } @@ -1395,67 +1370,134 @@ Tcl_FindExecutable(argv0) /* *--------------------------------------------------------------------------- * - * LoadEncodingFile -- + * OpenEncodingFileChannel -- * - * Read a file that describes an encoding and create a new Encoding - * from the data. + * Open the file believed to hold data for the encoding, "name". * * Results: - * The return value is the newly loaded Encoding, or NULL if - * the file didn't exist of was in the incorrect format. If NULL was + * Returns the readable Tcl_Channel from opening the file, or NULL + * if the file could not be successfully opened. If NULL was * returned, an error message is left in interp's result object, * unless interp was NULL. * * Side effects: - * File read from disk. + * Channel may be opened. Information about the filesystem may be + * cached to speed later calls. * *--------------------------------------------------------------------------- */ -static Tcl_Encoding -LoadEncodingFile(interp, name) +static Tcl_Channel +OpenEncodingFileChannel(interp, name) Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ CONST char *name; /* The name of the encoding file on disk * and also the name for new encoding. */ { - Tcl_Channel chan; - Tcl_Encoding encoding; - Tcl_Obj *map, *path, *directory = NULL; Tcl_Obj *nameObj = Tcl_NewStringObj(name, -1); - int ch, scanned = 0; + Tcl_Obj *fileNameObj = Tcl_DuplicateObj(nameObj); + Tcl_Obj *searchPath = Tcl_DuplicateObj(TclGetEncodingSearchPath()); + Tcl_Obj *map = TclGetProcessGlobalValue(&encodingFileMap); + Tcl_Obj **dir, *path, *directory = NULL; + Tcl_Channel chan = NULL; + int i, numDirs; + + Tcl_ListObjGetElements(NULL, searchPath, &numDirs, &dir); + Tcl_IncrRefCount(nameObj); + Tcl_AppendToObj(fileNameObj, ".enc", -1); + Tcl_IncrRefCount(fileNameObj); + Tcl_DictObjGet(NULL, map, nameObj, &directory); + /* Check that any cached directory is still on the encoding search path */ + if (NULL != directory) { + int verified = 0; - Tcl_IncrRefCount(nameObj); - while (1) { - map = TclGetProcessGlobalValue(&encodingFileMap); - Tcl_DictObjGet(NULL, map, nameObj, &directory); - if (scanned || (NULL != directory)) { - break; + for (i=0; i<numDirs && !verified; i++) { + if (dir[i] == directory) { + verified = 1; + } + } + if (!verified) { + CONST char *dirString = Tcl_GetString(directory); + for (i=0; i<numDirs && !verified; i++) { + if (strcmp(dirString, Tcl_GetString(dir[i])) == 0) { + verified = 1; + } + } + } + if (!verified) { + /* Directory no longer on the search path. Remove from cache */ + map = Tcl_DuplicateObj(map); + Tcl_DictObjRemove(NULL, map, nameObj); + TclSetProcessGlobalValue(&encodingFileMap, map, NULL); + directory = NULL; } -scan: - FillEncodingFileMap(); - scanned = 1; } - if (NULL == directory) { - Tcl_DecrRefCount(nameObj); - goto unknown; + + if (NULL != directory) { + /* Got a directory from the cache. Try to use it first */ + Tcl_IncrRefCount(directory); + path = Tcl_FSJoinToPath(directory, 1, &fileNameObj); + Tcl_IncrRefCount(path); + Tcl_DecrRefCount(directory); + chan = Tcl_FSOpenFileChannel(NULL, path, "r", 0); + Tcl_DecrRefCount(path); } - /* Construct $directory/$encoding.enc path name */ - Tcl_IncrRefCount(directory); - Tcl_AppendToObj(nameObj, ".enc", -1); - path = Tcl_FSJoinToPath(directory, 1, &nameObj); - Tcl_DecrRefCount(directory); + /* Scan the search path until we find it. */ + for (i=0; i<numDirs && (chan == NULL); i++) { + path = Tcl_FSJoinToPath(dir[i], 1, &fileNameObj); + Tcl_IncrRefCount(path); + chan = Tcl_FSOpenFileChannel(NULL, path, "r", 0); + Tcl_DecrRefCount(path); + if (chan != NULL) { + /* Save directory in the cache */ + map = Tcl_DuplicateObj(TclGetProcessGlobalValue(&encodingFileMap)); + Tcl_DictObjPut(NULL, map, nameObj, dir[i]); + TclSetProcessGlobalValue(&encodingFileMap, map, NULL); + } + } + if ((NULL == chan) && (interp != NULL)) { + Tcl_AppendResult(interp, "unknown encoding \"", name, "\"", NULL); + } + Tcl_DecrRefCount(fileNameObj); Tcl_DecrRefCount(nameObj); - Tcl_IncrRefCount(path); - chan = Tcl_FSOpenFileChannel(NULL, path, "r", 0); - Tcl_DecrRefCount(path); + Tcl_DecrRefCount(searchPath); + return chan; +} + +/* + *--------------------------------------------------------------------------- + * + * LoadEncodingFile -- + * + * Read a file that describes an encoding and create a new Encoding + * from the data. + * + * Results: + * The return value is the newly loaded Encoding, or NULL if + * the file didn't exist of was in the incorrect format. If NULL was + * returned, an error message is left in interp's result object, + * unless interp was NULL. + * + * Side effects: + * File read from disk. + * + *--------------------------------------------------------------------------- + */ - if (NULL == chan) { - if (!scanned) { - goto scan; - } - goto unknown; +static Tcl_Encoding +LoadEncodingFile(interp, name) + Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ + CONST char *name; /* The name of the encoding file on disk + * and also the name for new encoding. */ +{ + Tcl_Channel chan = NULL; + Tcl_Encoding encoding = NULL; + int ch; + + chan = OpenEncodingFileChannel(interp, name); + if (chan == NULL) { + return NULL; } Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); @@ -1472,7 +1514,6 @@ scan: } } - encoding = NULL; switch (ch) { case 'S': { encoding = LoadTableEncoding(name, ENCODING_SINGLEBYTE, chan); @@ -1496,12 +1537,6 @@ scan: } Tcl_Close(NULL, chan); return encoding; - - unknown: - if (interp != NULL) { - Tcl_AppendResult(interp, "unknown encoding \"", name, "\"", NULL); - } - return NULL; } /* @@ -3185,43 +3220,3 @@ InitializeEncodingSearchPath(valuePtr, lengthPtr, encodingPtr) memcpy((VOID *) *valuePtr, (VOID *) bytes, (size_t) numBytes + 1); Tcl_DecrRefCount(searchPath); } - -/* - *------------------------------------------------------------------------- - * - * InitializeEncodingFileMap -- - * - * This is the fallback routine that fills the encoding data - * file map if the application has not set up an encoding - * search path by the first time the file map is needed to - * load encoding data. - * - * Results: - * None. - * - * Side effects: - * Fills the encoding data file map. - * - *------------------------------------------------------------------------- - */ - -void -InitializeEncodingFileMap(valuePtr, lengthPtr, encodingPtr) - char **valuePtr; - int *lengthPtr; - Tcl_Encoding *encodingPtr; -{ - char *bytes; - int numBytes; - Tcl_Obj *map = MakeFileMap(); - - *encodingPtr = encodingSearchPath.encoding; - if (*encodingPtr) { - ((Encoding *)(*encodingPtr))->refCount++; - } - bytes = Tcl_GetStringFromObj(map, &numBytes); - *lengthPtr = numBytes; - *valuePtr = ckalloc((unsigned int) numBytes + 1); - memcpy((VOID *) *valuePtr, (VOID *) bytes, (size_t) numBytes + 1); - Tcl_DecrRefCount(map); -} diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 75df800..a6d9442 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.167.2.10 2005/04/10 23:14:48 kennykb Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.167.2.11 2005/04/25 21:37:20 kennykb Exp $ */ #include "tclInt.h" @@ -4289,7 +4289,7 @@ TclExecuteByteCode(interp, codePtr) */ if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) { i = valuePtr->internalRep.longValue; - TclNewLongObj(objResultPtr, -i) + TclNewLongObj(objResultPtr, -i); TRACE_WITH_OBJ(("%ld => ", i), objResultPtr); } else if (tPtr == &tclWideIntType) { TclGetWide(w,valuePtr); @@ -4329,7 +4329,7 @@ TclExecuteByteCode(interp, codePtr) i = (w == W0); TRACE_WITH_OBJ((LLD" => ", w), objResultPtr); } else { - i = (valuePtr->internalRep.doubleValue == 0.0) + i = (valuePtr->internalRep.doubleValue == 0.0); TRACE_WITH_OBJ(("%.6g => ", d), objResultPtr); } objResultPtr = eePtr->constants[i]; @@ -4639,7 +4639,10 @@ TclExecuteByteCode(interp, codePtr) * If some var in some var list still has a remaining list * element iterate one more time. Assign to var the next * element from its value list. We already checked above - * that each list temp holds a valid list object. + * that each list temp holds a valid list object (by calling + * Tcl_ListObjLength), but cannot rely on that check remaining + * valid: one list could have been shimmered as a side effect of + * setting a traced variable. */ if (continueLoop) { @@ -4650,7 +4653,7 @@ TclExecuteByteCode(interp, codePtr) listVarPtr = &(compiledLocals[listTmpIndex]); listPtr = listVarPtr->value.objPtr; - TclListObjGetElements(listPtr, listLen, elements); + Tcl_ListObjGetElements(interp, listPtr, &listLen, &elements); valIndex = (iterNum * numVars); for (j = 0; j < numVars; j++) { diff --git a/generic/tclFileName.c b/generic/tclFileName.c index ab06aee..a5eca37 100644 --- a/generic/tclFileName.c +++ b/generic/tclFileName.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclFileName.c,v 1.60.2.5 2005/04/10 23:14:50 kennykb Exp $ + * RCS: @(#) $Id: tclFileName.c,v 1.60.2.6 2005/04/25 21:37:20 kennykb Exp $ */ #include "tclInt.h" @@ -2302,7 +2302,7 @@ DoGlob(interp, matchesObj, separators, pathPtr, flags, pattern, types) * The current prefix must end in a separator, unless * this is a volume-relative path. In particular * globbing in Windows shares, when not using -dir - * or -path, e.g. 'glob [file join //machine share dir *]' + * or -path, e.g. 'glob [file join //machine/share/subdir *]' * requires adding a separator here. This behaviour * is not currently tested for in the test suite. */ diff --git a/generic/tclGet.c b/generic/tclGet.c index b410ba1..0be4b7e 100644 --- a/generic/tclGet.c +++ b/generic/tclGet.c @@ -11,11 +11,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclGet.c,v 1.9.2.2 2005/03/04 20:43:46 kennykb Exp $ + * RCS: @(#) $Id: tclGet.c,v 1.9.2.3 2005/04/25 21:37:20 kennykb Exp $ */ #include "tclInt.h" -#include <math.h> /* @@ -38,76 +37,25 @@ */ int -Tcl_GetInt(interp, string, intPtr) +Tcl_GetInt(interp, str, intPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ - CONST char *string; /* String containing a (possibly signed) - * integer in a form acceptable to strtol. */ + CONST char *str; /* String containing a (possibly signed) + * integer in a form acceptable to strtoul. */ int *intPtr; /* Place to store converted result. */ { - char *end; - CONST char *p = string; - long i; - - /* - * Note: use strtoul instead of strtol for integer conversions - * to allow full-size unsigned numbers, but don't depend on strtoul - * to handle sign characters; it won't in some implementations. - */ - - errno = 0; -#ifdef TCL_STRTOUL_SIGN_CHECK - /* - * This special sign check actually causes bad numbers to be allowed - * when strtoul. I can't find a strtoul that doesn't validly handle - * signed characters, and the C standard implies that this is all - * unnecessary. [Bug #634856] - */ - for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ - /* Empty loop body. */ - } - if (*p == '-') { - p++; - i = -((long)strtoul(p, &end, 0)); /* INTL: Tcl source. */ - } else if (*p == '+') { - p++; - i = strtoul(p, &end, 0); /* INTL: Tcl source. */ - } else -#else - i = strtoul(p, &end, 0); /* INTL: Tcl source. */ -#endif - if (end == p) { - badInteger: - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "expected integer but got \"", string, - "\"", (char *) NULL); - TclCheckBadOctal(interp, string); - } - return TCL_ERROR; - } - - /* - * The second test below is needed on platforms where "long" is - * larger than "int" to detect values that fit in a long but not in - * an int. - */ - - if ((errno == ERANGE) || (((long)(int) i) != i)) { - if (interp != (Tcl_Interp *) NULL) { - Tcl_SetResult(interp, "integer value too large to represent", - TCL_STATIC); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", - Tcl_GetStringResult(interp), (char *) NULL); - } - return TCL_ERROR; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { /* INTL: ISO space. */ - end++; - } - if (*end != 0) { - goto badInteger; + Tcl_Obj obj; + int code; + + obj.refCount = 1; + obj.bytes = (char *) str; + obj.length = strlen(str); + obj.typePtr = NULL; + + code = Tcl_GetIntFromObj(interp, &obj, intPtr); + if (obj.refCount > 1) { + Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } - *intPtr = (int) i; - return TCL_OK; + return code; } /* @@ -133,64 +81,27 @@ Tcl_GetInt(interp, string, intPtr) */ int -TclGetLong(interp, string, longPtr) +TclGetLong(interp, str, longPtr) Tcl_Interp *interp; /* Interpreter used for error reporting * if not NULL. */ - CONST char *string; /* String containing a (possibly signed) + CONST char *str; /* String containing a (possibly signed) * long integer in a form acceptable to * strtoul. */ long *longPtr; /* Place to store converted long result. */ { - char *end; - CONST char *p = string; - long i; + Tcl_Obj obj; + int code; - /* - * Note: don't depend on strtoul to handle sign characters; it won't - * in some implementations. - */ + obj.refCount = 1; + obj.bytes = (char *) str; + obj.length = strlen(str); + obj.typePtr = NULL; - errno = 0; -#ifdef TCL_STRTOUL_SIGN_CHECK - for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ - /* Empty loop body. */ + code = Tcl_GetLongFromObj(interp, &obj, longPtr); + if (obj.refCount > 1) { + Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } - if (*p == '-') { - p++; - i = -(int)strtoul(p, &end, 0); /* INTL: Tcl source. */ - } else if (*p == '+') { - p++; - i = strtoul(p, &end, 0); /* INTL: Tcl source. */ - } else -#else - i = strtoul(p, &end, 0); /* INTL: Tcl source. */ -#endif - if (end == p) { - badInteger: - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "expected integer but got \"", string, - "\"", (char *) NULL); - TclCheckBadOctal(interp, string); - } - return TCL_ERROR; - } - if (errno == ERANGE) { - if (interp != (Tcl_Interp *) NULL) { - Tcl_SetResult(interp, "integer value too large to represent", - TCL_STATIC); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", - Tcl_GetStringResult(interp), (char *) NULL); - } - return TCL_ERROR; - } - while ((*end != '\0') && isspace(UCHAR(*end))) { /* INTL: ISO space. */ - end++; - } - if (*end != 0) { - goto badInteger; - } - *longPtr = i; - return TCL_OK; + return code; } /* @@ -214,34 +125,25 @@ TclGetLong(interp, string, longPtr) */ int -Tcl_GetDouble(interp, string, doublePtr) +Tcl_GetDouble(interp, str, doublePtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ - CONST char *string; /* String containing a floating-point number + CONST char *str; /* String containing a floating-point number * in a form acceptable to strtod. */ double *doublePtr; /* Place to store converted result. */ { - CONST char *end; - double d; + Tcl_Obj obj; + int code; - errno = 0; - d = TclStrToD(string, &end); /* INTL: Tcl source. */ - if (end == string) { - badDouble: - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, - "expected floating-point number but got \"", - string, "\"", (char *) NULL); - } - return TCL_ERROR; - } - while ((*end != 0) && isspace(UCHAR(*end))) { /* INTL: ISO space. */ - end++; - } - if (*end != 0) { - goto badDouble; + obj.refCount = 1; + obj.bytes = (char *) str; + obj.length = strlen(str); + obj.typePtr = NULL; + + code = Tcl_GetDoubleFromObj(interp, &obj, doublePtr); + if (obj.refCount > 1) { + Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } - *doublePtr = d; - return TCL_OK; + return code; } /* @@ -265,64 +167,28 @@ Tcl_GetDouble(interp, string, doublePtr) */ int -Tcl_GetBoolean(interp, string, boolPtr) +Tcl_GetBoolean(interp, str, boolPtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ - CONST char *string; /* String containing a boolean number + CONST char *str; /* String containing a boolean number * specified either as 1/0 or true/false or * yes/no. */ int *boolPtr; /* Place to store converted result, which * will be 0 or 1. */ { - int i; - char lowerCase[10], c; - size_t length; + Tcl_Obj obj; + int code; - /* - * Convert the input string to all lower-case. - * INTL: This code will work on UTF strings. - */ + obj.refCount = 1; + obj.bytes = (char *) str; + obj.length = strlen(str); + obj.typePtr = NULL; - for (i = 0; i < 9; i++) { - c = string[i]; - if (c == 0) { - break; - } - if ((c >= 'A') && (c <= 'Z')) { - c += (char) ('a' - 'A'); - } - lowerCase[i] = c; + code = Tcl_ConvertToType(interp, &obj, &tclBooleanType); + if (obj.refCount > 1) { + Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } - lowerCase[i] = 0; - - length = strlen(lowerCase); - c = lowerCase[0]; - if ((c == '0') && (lowerCase[1] == '\0')) { - *boolPtr = 0; - } else if ((c == '1') && (lowerCase[1] == '\0')) { - *boolPtr = 1; - } else if ((c == 'y') && (strncmp(lowerCase, "yes", length) == 0)) { - *boolPtr = 1; - } else if ((c == 'n') && (strncmp(lowerCase, "no", length) == 0)) { - *boolPtr = 0; - } else if ((c == 't') && (strncmp(lowerCase, "true", length) == 0)) { - *boolPtr = 1; - } else if ((c == 'f') && (strncmp(lowerCase, "false", length) == 0)) { - *boolPtr = 0; - } else if ((c == 'o') && (length >= 2)) { - if (strncmp(lowerCase, "on", length) == 0) { - *boolPtr = 1; - } else if (strncmp(lowerCase, "off", length) == 0) { - *boolPtr = 0; - } else { - goto badBoolean; - } - } else { - badBoolean: - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "expected boolean value but got \"", - string, "\"", (char *) NULL); - } - return TCL_ERROR; + if (code == TCL_OK) { + *boolPtr = obj.internalRep.longValue; } - return TCL_OK; + return code; } diff --git a/generic/tclIO.c b/generic/tclIO.c index 8b0636c..b1a0ed7 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIO.c,v 1.81.2.2 2005/04/10 23:14:51 kennykb Exp $ + * RCS: @(#) $Id: tclIO.c,v 1.81.2.3 2005/04/25 21:37:20 kennykb Exp $ */ #include "tclInt.h" @@ -6045,7 +6045,7 @@ Tcl_ChannelBuffered(chan) * Tcl_SetChannelBufferSize -- * * Sets the size of buffers to allocate to store input or output - * in the channel. The size must be between 10 bytes and 1 MByte. + * in the channel. The size must be between 1 byte and 1 MByte. * * Results: * None. @@ -6065,11 +6065,11 @@ Tcl_SetChannelBufferSize(chan, sz) ChannelState *statePtr; /* State of real channel structure. */ /* - * If the buffer size is smaller than 10 bytes or larger than one MByte, + * If the buffer size is smaller than 1 byte or larger than one MByte, * do not accept the requested size and leave the current buffer size. */ - if (sz < 10) { + if (sz < 1) { return; } if (sz > (1024 * 1024)) { diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 08224de..5e7863f 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -17,7 +17,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOUtil.c,v 1.113.2.1 2005/01/20 14:53:39 kennykb Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.113.2.2 2005/04/25 21:37:21 kennykb Exp $ */ #include "tclInt.h" @@ -2986,7 +2986,8 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, } /* Copy this across, since both are equal for the native fs */ *clientDataPtr = (ClientData)*handlePtr; - return retVal; + Tcl_ResetResult(interp); + return TCL_OK; } if (Tcl_GetErrno() != EXDEV) { return retVal; @@ -3011,7 +3012,9 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, */ copyToPtr = TclpTempFileName(); if (copyToPtr == NULL) { - return -1; + Tcl_AppendResult(interp, "couldn't create temporary file: ", + Tcl_PosixError(interp), (char *) NULL); + return TCL_ERROR; } Tcl_IncrRefCount(copyToPtr); @@ -3025,7 +3028,9 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, */ Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); - return -1; + Tcl_AppendResult(interp, "couldn't load from current filesystem", + (char *) NULL); + return TCL_ERROR; } if (TclCrossFilesystemCopy(interp, pathPtr, copyToPtr) == TCL_OK) { @@ -3090,6 +3095,7 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, (*handlePtr) = newLoadHandle; (*clientDataPtr) = newClientData; (*unloadProcPtr) = newUnloadProcPtr; + Tcl_ResetResult(interp); return TCL_OK; } /* @@ -3138,6 +3144,7 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, (*handlePtr) = newLoadHandle; (*clientDataPtr) = (ClientData)tvdlPtr; (*unloadProcPtr) = &FSUnloadTempFile; + Tcl_ResetResult(interp); return retVal; } else { /* Cross-platform copy failed */ @@ -3147,7 +3154,7 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, } } Tcl_SetErrno(ENOENT); - return -1; + return TCL_ERROR; } /* * This function used to be in the platform specific directories, but it diff --git a/generic/tclInt.h b/generic/tclInt.h index c6b7a1b..04b80ec 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.202.2.10 2005/04/10 23:14:52 kennykb Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.202.2.11 2005/04/25 21:37:22 kennykb Exp $ */ #ifndef _TCLINT @@ -2143,6 +2143,9 @@ MODULE_SCOPE int Tcl_DictObjCmd _ANSI_ARGS_((ClientData clientData, MODULE_SCOPE int Tcl_EncodingObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); +MODULE_SCOPE int TclEncodingDirsObjCmd _ANSI_ARGS_(( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[])); MODULE_SCOPE int Tcl_EofObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); @@ -2504,10 +2507,12 @@ MODULE_SCOPE Tcl_Obj * TclPtrIncrWideVar _ANSI_ARGS_((Tcl_Interp *interp, MODULE_SCOPE Tcl_Obj * TclThreadAllocObj _ANSI_ARGS_((void)); MODULE_SCOPE void TclThreadFreeObj _ANSI_ARGS_((Tcl_Obj *)); MODULE_SCOPE Tcl_Mutex *TclpNewAllocMutex _ANSI_ARGS_((void)); +MODULE_SCOPE void TclFreeAllocCache _ANSI_ARGS_((void *)); MODULE_SCOPE void * TclpGetAllocCache _ANSI_ARGS_((void)); MODULE_SCOPE void TclpSetAllocCache _ANSI_ARGS_((void *)); MODULE_SCOPE void TclFinalizeThreadAlloc _ANSI_ARGS_((void)); MODULE_SCOPE void TclpFreeAllocMutex _ANSI_ARGS_((Tcl_Mutex* mutex)); +MODULE_SCOPE void TclpFreeAllocCache _ANSI_ARGS_((void *)); # define TclAllocObjStorage(objPtr) \ (objPtr) = TclThreadAllocObj() diff --git a/generic/tclInterp.c b/generic/tclInterp.c index b21af73..ec78d95 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInterp.c,v 1.54.2.1 2004/12/29 22:47:00 kennykb Exp $ + * RCS: @(#) $Id: tclInterp.c,v 1.54.2.2 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -298,10 +298,6 @@ int Tcl_Init(interp) Tcl_Interp *interp; /* Interpreter to initialize. */ { - int code; - Tcl_DString script, encodingName; - Tcl_Obj *path; - if (tclPreInitScript != NULL) { if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) { return (TCL_ERROR); @@ -347,133 +343,69 @@ Tcl_Init(interp) * Note that this entire search mechanism can be bypassed by defining an * alternate tclInit procedure before calling Tcl_Init(). */ - code = Tcl_Eval(interp, + return Tcl_Eval(interp, "if {[info proc tclInit]==\"\"} {\n" " proc tclInit {} {\n" -" global tcl_libPath tcl_library\n" -" global env tclDefaultLibrary\n" -" variable ::tcl::LibPath\n" +" global tcl_libPath tcl_library env tclDefaultLibrary\n" " rename tclInit {}\n" -" set errors {}\n" -" set localPath {}\n" -" set LibPath {}\n" " if {[info exists tcl_library]} {\n" -" lappend localPath $tcl_library\n" +" set scripts {{set tcl_library}}\n" " } else {\n" -" if {[info exists env(TCL_LIBRARY)]\n" -" && [string length $env(TCL_LIBRARY)]} {\n" -" lappend localPath $env(TCL_LIBRARY)\n" -" lappend LibPath $env(TCL_LIBRARY)\n" -" if {[regexp ^tcl(.*)$ [file tail $env(TCL_LIBRARY)] -> tail]} {\n" -" if {$tail ne [info tclversion]} {\n" -" lappend localPath [file join [file dirname\\\n" -" $env(TCL_LIBRARY)] tcl[info tclversion]]\n" -" lappend LibPath [file join [file dirname\\\n" -" $env(TCL_LIBRARY)] tcl[info tclversion]]\n" -" }\n" -" }\n" +" set scripts {}\n" +" if {[info exists env(TCL_LIBRARY)] && ($env(TCL_LIBRARY) ne {})} {\n" +" lappend scripts {set env(TCL_LIBRARY)}\n" +" lappend scripts {\n" +"if {[regexp ^tcl(.*)$ [file tail $env(TCL_LIBRARY)] -> tail] == 0} continue\n" +"if {$tail eq [info tclversion]} continue\n" +"file join [file dirname $env(TCL_LIBRARY)] tcl[info tclversion]}\n" " }\n" -" if {[catch {\n" -" lappend localPath $tclDefaultLibrary\n" -" unset tclDefaultLibrary\n" -" }]} {\n" -" lappend localPath [::tcl::pkgconfig get scriptdir,runtime]\n" +" if {[info exists tclDefaultLibrary]} {\n" +" lappend scripts {set tclDefaultLibrary}\n" +" } else {\n" +" lappend scripts {::tcl::pkgconfig get scriptdir,runtime}\n" " }\n" -" set parentDir [file normalize [file dirname [file dirname\\\n" -" [info nameofexecutable]]]]\n" -" set grandParentDir [file dirname $parentDir]\n" -" lappend LibPath [file join $parentDir lib tcl[info tclversion]]\n" -" lappend LibPath [file join $grandParentDir lib tcl[info tclversion]]\n" -" lappend LibPath [file join $parentDir library]\n" -" lappend LibPath [file join $grandParentDir library]\n" -" lappend LibPath [file join $grandParentDir\\\n" -" tcl[info patchlevel] library]\n" -" lappend LibPath [file join [file dirname $grandParentDir]\\\n" -" tcl[info patchlevel] library]\n" -" catch {\n" -" set LibPath [concat $LibPath $tcl_libPath]\n" +" lappend scripts {\n" +"set parentDir [file dirname [file dirname [info nameofexecutable]]]\n" +"set grandParentDir [file dirname $parentDir]\n" +"file join $parentDir lib tcl[info tclversion]} \\\n" +" {file join $grandParentDir lib tcl[info tclversion]} \\\n" +" {file join $parentDir library} \\\n" +" {file join $grandParentDir library} \\\n" +" {file join $grandParentDir tcl[info patchlevel] library} \\\n" +" {\n" +"file join [file dirname $grandParentDir] tcl[info patchlevel] library}\n" +" if {[info exists tcl_libPath]\n" +" && [catch {llength $tcl_libPath} len] == 0} {\n" +" for {set i 0} {$i < $len} {incr i} {\n" +" lappend scripts [list lindex \\$tcl_libPath $i]\n" +" }\n" " }\n" " }\n" -" foreach i [concat $localPath $LibPath] {\n" -" set tcl_library $i\n" -" set tclfile [file join $i init.tcl]\n" +" set dirs {}\n" +" set errors {}\n" +" foreach script $scripts {\n" +" lappend dirs [eval $script]\n" +" set tcl_library [lindex $dirs end]\n" +" set tclfile [file join $tcl_library init.tcl]\n" " if {[file exists $tclfile]} {\n" -" if {![catch {uplevel #0 [list source $tclfile]} msg opts]} {\n" -" return\n" -" } else {\n" +" if {[catch {uplevel #0 [list source $tclfile]} msg opts]} {\n" " append errors \"$tclfile: $msg\n\"\n" " append errors \"[dict get $opts -errorinfo]\n\"\n" +" continue\n" " }\n" +" unset -nocomplain tclDefaultLibrary\n" +" return\n" " }\n" " }\n" +" unset -nocomplain tclDefaultLibrary\n" " set msg \"Can't find a usable init.tcl in the following directories: \n\"\n" -" append msg \" $localPath $LibPath\n\n\"\n" +" append msg \" $dirs\n\n\"\n" " append msg \"$errors\n\n\"\n" " append msg \"This probably means that Tcl wasn't installed properly.\n\"\n" " error $msg\n" " }\n" "}\n" "tclInit"); - - if (code != TCL_OK) { - return code; - } - - /* - * Now that [info library] is initialized, make sure that - * [file join [info library] encoding] is on the encoding - * search path. - * - * Relying on use of original built-in commands. - * Should be a safe assumption during interp initialization. - * More robust would be to use C-coded equivalents, but that's such - * a pain... - */ - - Tcl_DStringInit(&script); - Tcl_DStringAppend(&script, "lsearch -exact", -1); - path = Tcl_DuplicateObj(TclGetEncodingSearchPath()); - Tcl_IncrRefCount(path); - Tcl_DStringAppendElement(&script, Tcl_GetString(path)); - Tcl_DStringAppend(&script, " [file join [info library] encoding]", -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&script), - Tcl_DStringLength(&script), TCL_EVAL_GLOBAL); - Tcl_DStringFree(&script); - if (code == TCL_OK) { - int index; - Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &index); - if (index != -1) { - /* [info library]/encoding already on the encoding search path */ - goto done; - } - } - Tcl_DStringInit(&script); - Tcl_DStringAppend(&script, "file join [info library] encoding", -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&script), - Tcl_DStringLength(&script), TCL_EVAL_GLOBAL); - Tcl_DStringFree(&script); - if (code == TCL_OK) { - Tcl_ListObjAppendElement(NULL, path, Tcl_GetObjResult(interp)); - TclSetEncodingSearchPath(path); - } -done: - /* - * Now that we know the distributed *.enc files are on the encoding - * search path, check whether the [encoding system] matches that - * specified by the environment, and if not, attempt to correct it - */ - TclpGetEncodingNameFromEnvironment(&encodingName); - if (strcmp(Tcl_DStringValue(&encodingName), Tcl_GetEncodingName(NULL))) { - code = Tcl_SetSystemEncoding(NULL, Tcl_DStringValue(&encodingName)); - if (code == TCL_ERROR) { - Tcl_Panic("system encoding \"", Tcl_DStringValue(&encodingName), - "\" not available"); - } - } - Tcl_DStringFree(&encodingName); - Tcl_DecrRefCount(path); - Tcl_ResetResult(interp); - return TCL_OK; } /* diff --git a/generic/tclLiteral.c b/generic/tclLiteral.c index eb0e342..9564a98 100644 --- a/generic/tclLiteral.c +++ b/generic/tclLiteral.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclLiteral.c,v 1.20.2.1 2004/12/29 22:47:01 kennykb Exp $ + * RCS: @(#) $Id: tclLiteral.c,v 1.20.2.2 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -270,8 +270,6 @@ TclRegisterLiteral(envPtr, bytes, length, flags) register Tcl_Obj *objPtr; unsigned int hash; int localHash, globalHash, objIndex; - long n; - char buf[TCL_INTEGER_SPACE]; Namespace *nsPtr; if (length < 0) { @@ -366,10 +364,13 @@ TclRegisterLiteral(envPtr, bytes, length, flags) TclInitStringRep(objPtr, bytes, length); } +#if 0 if (TclLooksLikeInt(bytes, length)) { /* * From here we use the objPtr, because it is NULL terminated */ + long n; + char buf[TCL_INTEGER_SPACE]; if (TclGetLong((Tcl_Interp *) NULL, objPtr->bytes, &n) == TCL_OK) { TclFormatInt(buf, n); if (strcmp(objPtr->bytes, buf) == 0) { @@ -378,6 +379,7 @@ TclRegisterLiteral(envPtr, bytes, length, flags) } } } +#endif #ifdef TCL_COMPILE_DEBUG if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) { diff --git a/generic/tclObj.c b/generic/tclObj.c index 51b84bc..1861cb3 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclObj.c,v 1.72.2.10 2005/04/10 23:14:54 kennykb Exp $ + * RCS: @(#) $Id: tclObj.c,v 1.72.2.11 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -1284,9 +1284,8 @@ Tcl_SetBooleanObj(objPtr, boolValue) * * Tcl_GetBooleanFromObj -- * - * Attempt to return a boolean from the Tcl object "objPtr". If the - * object is not already a boolean, an attempt will be made to convert - * it to one. + * Attempt to return a boolean from the Tcl object "objPtr". This + * includes conversion from any of Tcl's numeric types. * * Results: * The return value is a standard Tcl object result. If an error occurs @@ -1294,8 +1293,7 @@ Tcl_SetBooleanObj(objPtr, boolValue) * result unless "interp" is NULL. * * Side effects: - * If the object is not already a boolean, the conversion will free - * any old internal representation. + * The intrep of *objPtr may be changed. * *---------------------------------------------------------------------- */ @@ -1306,18 +1304,54 @@ Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) register Tcl_Obj *objPtr; /* The object from which to get boolean. */ register int *boolPtr; /* Place to store resulting boolean. */ { - register int result; + double d; + long l; if (objPtr->typePtr == &tclBooleanType) { - result = TCL_OK; - } else { - result = SetBooleanFromAny(interp, objPtr); + *boolPtr = (int) objPtr->internalRep.longValue; + return TCL_OK; } + /* + * The following call retrieves a numeric value without shimmering + * away any existing numeric intrep Tcl_ObjTypes. + */ + if (Tcl_GetDoubleFromObj(NULL, objPtr, &d) == TCL_OK) { + *boolPtr = (d != 0.0); - if (result == TCL_OK) { + /* Attempt shimmer to "boolean" objType */ + SetBooleanFromAny(NULL, objPtr); + return TCL_OK; + } + /* + * Value didn't already have a numeric intrep, but perhaps we can + * generate one. Try a long value first... + */ + if (Tcl_GetLongFromObj(NULL, objPtr, &l) == TCL_OK) { + *boolPtr = (l != 0); + return TCL_OK; + } +#ifndef TCL_WIDE_INT_IS_LONG + else { + Tcl_WideInt w; + /* + * ...then a wide. Check in that order so that we don't promote + * anything to wide unnecessarily. + */ + if (Tcl_GetWideIntFromObj(NULL, objPtr, &w) == TCL_OK) { + *boolPtr = (w != 0); + return TCL_OK; + } + } +#endif + /* + * Finally, check for the string values like "yes" + * and generate error message for non-boolean values. + */ + if (SetBooleanFromAny(interp, objPtr) == TCL_OK) { *boolPtr = (int) objPtr->internalRep.longValue; + return TCL_OK; } - return result; + return TCL_ERROR; } /* @@ -1345,69 +1379,87 @@ SetBooleanFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { - char *string, *end; - register char c; - char lowerCase[8]; - int newBool, length; - register int i; - - /* - * Get the string representation. Make it up-to-date if necessary. - */ - - string = Tcl_GetStringFromObj(objPtr, &length); + char *str, lowerCase[6]; + int i, newBool, length; /* - * Use the obvious shortcuts for numerical values; if objPtr is not - * of numerical type, parse its string rep. + * For some "pure" numeric Tcl_ObjTypes (no string rep), we can + * determine whether a boolean conversion is possible without + * generating the string rep. */ - if (objPtr->typePtr == &tclIntType) { - newBool = (objPtr->internalRep.longValue != 0); - goto goodBoolean; - } else if (objPtr->typePtr == &tclDoubleType) { - newBool = (objPtr->internalRep.doubleValue != 0.0); - goto goodBoolean; - } else if (objPtr->typePtr == &tclWideIntType) { - newBool = (objPtr->internalRep.wideValue != 0); - goto goodBoolean; + if (objPtr->bytes == NULL) { + if (objPtr->typePtr == &tclDoubleType) { + goto badBoolean; + } + if (objPtr->typePtr == &tclIntType) { + long l = objPtr->internalRep.longValue; + switch (l) { + case 0: case 1: + newBool = (int)l; + goto goodBoolean; + } + goto badBoolean; + } + if (objPtr->typePtr == &tclWideIntType) { + Tcl_WideInt w = objPtr->internalRep.wideValue; + switch (w) { + case 0: case 1: + newBool = (int)w; + goto goodBoolean; + } + goto badBoolean; + } } /* * Parse the string as a boolean. We use an implementation here * that doesn't report errors in interp if interp is NULL. - * - * First we define a macro to factor out the to-lower-case code. - * The len parameter is the maximum number of characters to copy - * to allow the following comparisons to proceed correctly, - * including (properly) the trailing \0 character. This is done - * in multiple places so the number of copying steps is minimised - * and only performed when needed. */ -#define SBFA_TOLOWER(len) \ - for (i=0 ; i<(len) && i<length ; i++) { \ - c = string[i]; \ - if (c & 0x80) { \ - goto badBoolean; \ - } \ - if (Tcl_UniCharIsUpper(UCHAR(c))) { \ - c = (char) Tcl_UniCharToLower(UCHAR(c)); \ - } \ - lowerCase[i] = c; \ - } \ - lowerCase[i] = 0; - - switch (string[0]) { - case 'y': case 'Y': - /* - * Copy the string converting its characters to lower case. - * This also weeds out international characters so we can - * safely operate on single bytes. - */ + str = Tcl_GetStringFromObj(objPtr, &length); + if ((length == 0) || (length > 5)) { + /* longest valid boolean string rep. is "false" */ + goto badBoolean; + } + + switch (str[0]) { + case '0': + if (length == 1) { + newBool = 0; + goto goodBoolean; + } + goto badBoolean; + case '1': + if (length == 1) { + newBool = 1; + goto goodBoolean; + } + goto badBoolean; - SBFA_TOLOWER(4); + } + + /* + * Force to lower case for case-insensitive detection. + * Filter out known invalid characters at the same time. + */ + for (i=0; i < length; i++) { + char c = str[i]; + switch (c) { + case 'A': case 'E': case 'F': case 'L': case 'N': + case 'O': case 'R': case 'S': case 'T': case 'U': case 'Y': + lowerCase[i] = c + (char) ('a' - 'A'); break; + case 'a': case 'e': case 'f': case 'l': case 'n': + case 'o': case 'r': case 's': case 't': case 'u': case 'y': + lowerCase[i] = c; break; + default: + goto badBoolean; + } + } + lowerCase[length] = 0; + switch (lowerCase[0]) { + case 'y': /* * Checking the 'y' is redundant, but makes the code clearer. */ @@ -1416,32 +1468,28 @@ SetBooleanFromAny(interp, objPtr) goto goodBoolean; } goto badBoolean; - case 'n': case 'N': - SBFA_TOLOWER(3); + case 'n': if (strncmp(lowerCase, "no", (size_t) length) == 0) { newBool = 0; goto goodBoolean; } goto badBoolean; - case 't': case 'T': - SBFA_TOLOWER(5); + case 't': if (strncmp(lowerCase, "true", (size_t) length) == 0) { newBool = 1; goto goodBoolean; } goto badBoolean; - case 'f': case 'F': - SBFA_TOLOWER(6); + case 'f': if (strncmp(lowerCase, "false", (size_t) length) == 0) { newBool = 0; goto goodBoolean; } goto badBoolean; - case 'o': case 'O': + case 'o': if (length < 2) { goto badBoolean; } - SBFA_TOLOWER(4); if (strncmp(lowerCase, "on", (size_t) length) == 0) { newBool = 1; goto goodBoolean; @@ -1450,92 +1498,8 @@ SetBooleanFromAny(interp, objPtr) goto goodBoolean; } goto badBoolean; -#undef SBFA_TOLOWER - case '0': - if (string[1] == '\0') { - newBool = 0; - goto goodBoolean; - } - goto parseNumeric; - case '1': - if (string[1] == '\0') { - newBool = 1; - goto goodBoolean; - } - /* deliberate fall-through */ default: - parseNumeric: - { - double dbl; - /* - * Boolean values can be extracted from ints or doubles. - * Note that we don't use strtoul or strtoull here because - * we don't care about what the value is, just whether it - * is equal to zero or not. - */ -#ifdef TCL_WIDE_INT_IS_LONG - newBool = strtol(string, &end, 0); - if (end != string) { - /* - * Make sure the string has no garbage after the end of - * the int. - */ - while ((end < (string+length)) - && isspace(UCHAR(*end))) { /* INTL: ISO only */ - end++; - } - if (end == (string+length)) { - newBool = (newBool != 0); - goto goodBoolean; - } - } -#else /* !TCL_WIDE_INT_IS_LONG */ - Tcl_WideInt wide = strtoll(string, &end, 0); - if (end != string) { - /* - * Make sure the string has no garbage after the end of - * the wide int. - */ - while ((end < (string+length)) - && isspace(UCHAR(*end))) { /* INTL: ISO only */ - end++; - } - if (end == (string+length)) { - newBool = (wide != Tcl_LongAsWide(0)); - goto goodBoolean; - } - } -#endif /* TCL_WIDE_INT_IS_LONG */ - /* - * Still might be a string containing the characters - * representing an int or double that wasn't handled - * above. This would be a string like "27" or "1.0" that - * is non-zero and not "1". Such a string would result in - * the boolean value true. We try converting to double. If - * that succeeds and the resulting double is non-zero, we - * have a "true". Note that numbers can't have embedded - * NULLs. - */ - - dbl = TclStrToD(string, (CONST char **) &end); - if (end == string) { - goto badBoolean; - } - - /* - * Make sure the string has no garbage after the end of - * the double. - */ - - while ((end < (string+length)) - && isspace(UCHAR(*end))) { /* INTL: ISO only */ - end++; - } - if (end != (string+length)) { - goto badBoolean; - } - newBool = (dbl != 0.0); - } + goto badBoolean; } /* @@ -1554,7 +1518,8 @@ SetBooleanFromAny(interp, objPtr) if (interp != NULL) { Tcl_Obj *msg = Tcl_NewStringObj("expected boolean value but got \"", -1); - TclAppendLimitedToObj(msg, string, length, 50, ""); + str = Tcl_GetStringFromObj(objPtr, &length); + TclAppendLimitedToObj(msg, str, length, 50, ""); Tcl_AppendToObj(msg, "\"", -1); Tcl_SetObjResult(interp, msg); } @@ -1761,21 +1726,24 @@ Tcl_GetDoubleFromObj(interp, objPtr, dblPtr) result = TCL_OK; } else if (objPtr->typePtr == &tclIntType) { *dblPtr = objPtr->internalRep.longValue; - result = TCL_OK; - } else { - result = SetDoubleFromAny(interp, objPtr); - if (result == TCL_OK) { - *dblPtr = objPtr->internalRep.doubleValue; - } + return TCL_OK; + } else if (objPtr->typePtr == &tclWideIntType) { + *dblPtr = (double) objPtr->internalRep.wideValue; + return TCL_OK; } - if ( result == TCL_OK && IS_NAN( *dblPtr ) ) { - if ( interp != NULL ) { - Tcl_SetObjResult - ( interp, - Tcl_NewStringObj( "floating point value is Not a Number", - -1 ) ); + + result = SetDoubleFromAny(interp, objPtr); + if ( result == TCL_OK ) { + if ( IS_NAN( *dblPtr ) ) { + if ( interp != NULL ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "floating point value is Not a Number", + -1 ) ); + } + return TCL_ERROR; } - result = TCL_ERROR; + *dblPtr = objPtr->internalRep.doubleValue; } return result; } @@ -1847,6 +1815,13 @@ SetDoubleFromAny(interp, objPtr) goto badDouble; } + if (errno != 0) { + if (interp != NULL) { + TclExprFloatError(interp, newDouble); + } + return TCL_ERROR; + } + /* * The conversion to double succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the @@ -2012,15 +1987,14 @@ Tcl_GetIntFromObj(interp, objPtr, intPtr) register Tcl_Obj *objPtr; /* The object from which to get a int. */ register int *intPtr; /* Place to store resulting int. */ { - register long l = 0; int result; + Tcl_WideInt w = 0; /* If the object isn't already an integer of any width, try to * convert it to one. */ - if (objPtr->typePtr != &tclIntType - && objPtr->typePtr != &tclWideIntType) { + if (objPtr->typePtr != &tclIntType && objPtr->typePtr != &tclWideIntType) { result = SetIntOrWideFromAny(interp, objPtr); if (result != TCL_OK) { return result; @@ -2029,45 +2003,26 @@ Tcl_GetIntFromObj(interp, objPtr, intPtr) /* Object should now be either int or wide. Get its value. */ - if (objPtr->typePtr == &tclIntType) { - l = objPtr->internalRep.longValue; - } else if (objPtr->typePtr == &tclWideIntType) { #ifndef TCL_WIDE_INT_IS_LONG - /* - * If the object is already a wide integer, don't convert it. - * This code allows for any integer in the range -ULONG_MAX to - * ULONG_MAX to be converted to a long, ignoring overflow. - * The rule preserves existing semantics for conversion of - * integers on input, but avoids inadvertent demotion of - * wide integers to 32-bit ones in the internal rep. - */ - Tcl_WideInt w = objPtr->internalRep.wideValue; - if (w >= -(Tcl_WideInt)(ULONG_MAX) - && w <= (Tcl_WideInt)(ULONG_MAX)) { - l = Tcl_WideAsLong(w); - } else { - goto tooBig; - } -#else - l = objPtr->internalRep.longValue; + if (objPtr->typePtr == &tclWideIntType) { + w = objPtr->internalRep.wideValue; + } else #endif - } else { - Tcl_Panic("string->integer conversion failed to convert the obj."); + { + w = Tcl_LongAsWide(objPtr->internalRep.longValue); } - if (((long)((int)l)) == l) { - *intPtr = (int)l; - return TCL_OK; - } -#ifndef TCL_WIDE_INT_IS_LONG - tooBig: -#endif - if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( + if ((LLONG_MAX > UINT_MAX) + && ((w > UINT_MAX) || (w < -(Tcl_WideInt)UINT_MAX))) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( "integer value too large to represent as non-long integer", -1)); + } + return TCL_ERROR; } - return TCL_ERROR; + *intPtr = (int)w; + return TCL_OK; } /* @@ -2138,7 +2093,6 @@ SetIntOrWideFromAny(interp, objPtr) register char *p; unsigned long newLong; int isNegative = 0; - int isWide = 0; /* * Get the string representation. Make it up-to-date if necessary. @@ -2150,8 +2104,9 @@ SetIntOrWideFromAny(interp, objPtr) * Now parse "objPtr"s string as an int. We use an implementation here * that doesn't report errors in interp if interp is NULL. Note: use * strtoul instead of strtol for integer conversions to allow full-size - * unsigned numbers, but don't depend on strtoul to handle sign - * characters; it won't in some implementations. + * unsigned numbers. We parse the leading space and sign ourselves so + * we can tell the difference between apparently positive and negative + * values. */ errno = 0; @@ -2180,14 +2135,6 @@ SetIntOrWideFromAny(interp, objPtr) if (end == p) { goto badInteger; } - if (errno == ERANGE) { - if (interp != NULL) { - CONST char *s = "integer value too large to represent"; - Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1)); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); - } - return TCL_ERROR; - } /* * Make sure that the string has no garbage after the end of the int. @@ -2201,17 +2148,14 @@ SetIntOrWideFromAny(interp, objPtr) goto badInteger; } - /* - * If the resulting integer will exceed the range of a long, - * put it into a wide instead. (Tcl Bug #868489) - */ - -#ifndef TCL_WIDE_INT_IS_LONG - if ((isNegative && newLong > (unsigned long) (LONG_MAX) + 1) - || (!isNegative && newLong > LONG_MAX)) { - isWide = 1; + if (errno == ERANGE) { + if (interp != NULL) { + CONST char *s = "integer value too large to represent"; + Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1)); + Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); + } + return TCL_ERROR; } -#endif /* * The conversion to int succeeded. Free the old internalRep before @@ -2221,11 +2165,20 @@ SetIntOrWideFromAny(interp, objPtr) */ TclFreeIntRep(objPtr); - if (isWide) { +#ifndef TCL_WIDE_INT_IS_LONG + /* + * If the resulting integer will exceed the range of a long, + * put it into a wide instead. (Tcl Bug #868489) + */ + + if ((isNegative && newLong > (unsigned long) (LONG_MAX) + 1) + || (!isNegative && newLong > LONG_MAX)) { objPtr->internalRep.wideValue = (isNegative ? -(Tcl_WideInt)newLong : (Tcl_WideInt)newLong); objPtr->typePtr = &tclWideIntType; - } else { + } else +#endif + { objPtr->internalRep.longValue = (isNegative ? -(long)newLong : (long)newLong); objPtr->typePtr = &tclIntType; @@ -2528,25 +2481,11 @@ SetWideIntFromAny(interp, objPtr) * Now parse "objPtr"s string as an int. We use an implementation here * that doesn't report errors in interp if interp is NULL. Note: use * strtoull instead of strtoll for integer conversions to allow full-size - * unsigned numbers, but don't depend on strtoull to handle sign - * characters; it won't in some implementations. + * unsigned numbers. */ errno = 0; -#ifdef TCL_STRTOUL_SIGN_CHECK - for (; isspace(UCHAR(*p)) ; p++) { /* INTL: ISO space. */ - /* Empty loop body. */ - } - if (*p == '-') { - p++; - newWide = -((Tcl_WideInt)strtoull(p, &end, 0)); - } else if (*p == '+') { - p++; - newWide = strtoull(p, &end, 0); - } else -#else - newWide = strtoull(p, &end, 0); -#endif + newWide = strtoull(p, &end, 0); if (end == p) { badInteger: if (interp != NULL) { @@ -2559,14 +2498,6 @@ SetWideIntFromAny(interp, objPtr) } return TCL_ERROR; } - if (errno == ERANGE) { - if (interp != NULL) { - CONST char *s = "integer value too large to represent"; - Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1)); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); - } - return TCL_ERROR; - } /* * Make sure that the string has no garbage after the end of the int. @@ -2580,6 +2511,14 @@ SetWideIntFromAny(interp, objPtr) goto badInteger; } + if (errno == ERANGE) { + if (interp != NULL) { + CONST char *s = "integer value too large to represent"; + Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1)); + Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); + } + return TCL_ERROR; + } /* * The conversion to int succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the diff --git a/generic/tclThreadAlloc.c b/generic/tclThreadAlloc.c index 553bd4f..813b9a7 100755 --- a/generic/tclThreadAlloc.c +++ b/generic/tclThreadAlloc.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclThreadAlloc.c,v 1.14 2004/07/21 01:45:44 hobbs Exp $ + * RCS: @(#) $Id: tclThreadAlloc.c,v 1.14.2.1 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -988,6 +988,8 @@ TclFinalizeThreadAlloc() TclpFreeAllocMutex(listLockPtr); listLockPtr = NULL; + + TclpFreeAllocCache(NULL); } #else diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 6708699..0d538e0 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUtil.c,v 1.51.2.9 2005/04/10 23:14:57 kennykb Exp $ + * RCS: @(#) $Id: tclUtil.c,v 1.51.2.10 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -2851,14 +2851,14 @@ TclGetProcessGlobalValue(pgvPtr) /* If no thread has set the shared value, call the initializer */ Tcl_MutexLock(&pgvPtr->mutex); - if (NULL == pgvPtr->value) { - if (pgvPtr->proc) { - pgvPtr->epoch++; - (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes, - &pgvPtr->encoding); - Tcl_CreateExitHandler(FreeProcessGlobalValue, - (ClientData) pgvPtr); + if ((NULL == pgvPtr->value) && (pgvPtr->proc)) { + pgvPtr->epoch++; + (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes, + &pgvPtr->encoding); + if (pgvPtr->value == NULL) { + Tcl_Panic("PGV Initializer did not initialize."); } + Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData) pgvPtr); } /* Store a copy of the shared value in our epoch-indexed cache */ diff --git a/generic/tclVar.c b/generic/tclVar.c index 035de76..bac67dc 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.99.2.3 2005/04/10 23:14:57 kennykb Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.99.2.4 2005/04/25 21:37:22 kennykb Exp $ */ #include "tclInt.h" @@ -2917,8 +2917,8 @@ Tcl_ArrayObjCmd(dummy, interp, objc, objv) Tcl_DecrRefCount(namePtr); /* free unneeded name obj */ return result; } - Tcl_SetObjResult(interp, resultPtr); } + Tcl_SetObjResult(interp, resultPtr); break; } case ARRAY_NEXTELEMENT: { |