diff options
| author | Kevin B Kenny <kennykb@acm.org> | 2010-12-11 18:39:27 (GMT) |
|---|---|---|
| committer | Kevin B Kenny <kennykb@acm.org> | 2010-12-11 18:39:27 (GMT) |
| commit | fbefb585cb3784a6afcfa775c2c0554e4036f907 (patch) | |
| tree | fe86a2d97e77053d9c344bfd81ded64a9bdc7f9f /generic | |
| parent | 921c2612861d68b7b4eee66736379431ac081f30 (diff) | |
| download | tcl-fbefb585cb3784a6afcfa775c2c0554e4036f907.zip tcl-fbefb585cb3784a6afcfa775c2c0554e4036f907.tar.gz tcl-fbefb585cb3784a6afcfa775c2c0554e4036f907.tar.bz2 | |
merge
Diffstat (limited to 'generic')
| -rw-r--r-- | generic/tcl.h | 4 | ||||
| -rw-r--r-- | generic/tclBasic.c | 12 | ||||
| -rw-r--r-- | generic/tclBinary.c | 45 | ||||
| -rw-r--r-- | generic/tclCkalloc.c | 14 | ||||
| -rw-r--r-- | generic/tclCmdAH.c | 1785 | ||||
| -rw-r--r-- | generic/tclCmdIL.c | 52 | ||||
| -rw-r--r-- | generic/tclCmdMZ.c | 48 | ||||
| -rw-r--r-- | generic/tclCompile.c | 7 | ||||
| -rw-r--r-- | generic/tclDictObj.c | 42 | ||||
| -rw-r--r-- | generic/tclEnsemble.c | 43 | ||||
| -rw-r--r-- | generic/tclFCmd.c | 443 | ||||
| -rw-r--r-- | generic/tclHash.c | 14 | ||||
| -rw-r--r-- | generic/tclIO.c | 39 | ||||
| -rw-r--r-- | generic/tclIO.h | 8 | ||||
| -rw-r--r-- | generic/tclIOCmd.c | 75 | ||||
| -rw-r--r-- | generic/tclIOSock.c | 17 | ||||
| -rw-r--r-- | generic/tclIndexObj.c | 10 | ||||
| -rw-r--r-- | generic/tclInt.decls | 8 | ||||
| -rw-r--r-- | generic/tclInt.h | 30 | ||||
| -rw-r--r-- | generic/tclIntDecls.h | 6 | ||||
| -rw-r--r-- | generic/tclIntPlatDecls.h | 10 | ||||
| -rw-r--r-- | generic/tclProc.c | 7 | ||||
| -rwxr-xr-x | generic/tclStrToD.c | 2247 | ||||
| -rw-r--r-- | generic/tclTrace.c | 27 | ||||
| -rw-r--r-- | generic/tclUtil.c | 18 | ||||
| -rw-r--r-- | generic/tclVar.c | 26 |
26 files changed, 2994 insertions, 2043 deletions
diff --git a/generic/tcl.h b/generic/tcl.h index 76e7c86..27ed895 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -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: tcl.h,v 1.308 2010/08/14 20:58:30 nijtmans Exp $ + * RCS: @(#) $Id: tcl.h,v 1.308.2.1 2010/12/11 18:39:28 kennykb Exp $ */ #ifndef _TCL @@ -1165,7 +1165,7 @@ struct Tcl_HashEntry { int words[1]; /* Multiple integer words for key. The actual * size will be as large as necessary for this * table's keys. */ - char string[4]; /* String for key. The actual size will be as + char string[1]; /* String for key. The actual size will be as * large as needed to hold the key. */ } key; /* MUST BE LAST FIELD IN RECORD!! */ }; diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 90d5460..816f0f6 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -16,7 +16,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.465.2.5 2010/12/01 16:42:34 kennykb Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.465.2.6 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -276,7 +276,6 @@ static const CmdInfo builtInCmds[] = { {"fblocked", Tcl_FblockedObjCmd, NULL, NULL, 1}, {"fconfigure", Tcl_FconfigureObjCmd, NULL, NULL, 0}, {"fcopy", Tcl_FcopyObjCmd, NULL, NULL, 1}, - {"file", Tcl_FileObjCmd, NULL, NULL, 0}, {"fileevent", Tcl_FileEventObjCmd, NULL, NULL, 1}, {"flush", Tcl_FlushObjCmd, NULL, NULL, 1}, {"gets", Tcl_GetsObjCmd, NULL, NULL, 1}, @@ -783,15 +782,17 @@ Tcl_CreateInterp(void) } /* - * Create the "array", "binary", "chan", "dict", "info" and "string" - * ensembles. Note that all these commands (and their subcommands that are - * not present in the global namespace) are wholly safe. + * Create the "array", "binary", "chan", "dict", "file", "info" 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". */ TclInitArrayCmd(interp); TclInitBinaryCmd(interp); TclInitChanCmd(interp); TclInitDictCmd(interp); + TclInitFileCmd(interp); TclInitInfoCmd(interp); TclInitStringCmd(interp); TclInitPrefixCmd(interp); @@ -1014,6 +1015,7 @@ TclHideUnsafeCommands( Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name); } } + TclMakeFileCommandSafe(interp); /* Ugh! */ return TCL_OK; } diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 5a92f8d..165da34 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.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: tclBinary.c,v 1.66.2.1 2010/12/01 16:42:34 kennykb Exp $ + * RCS: @(#) $Id: tclBinary.c,v 1.66.2.2 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -174,13 +174,13 @@ typedef struct ByteArray { * array. */ int allocated; /* The amount of space actually allocated * minus 1 byte. */ - unsigned char bytes[4]; /* The array of bytes. The actual size of this + unsigned char bytes[1]; /* The array of bytes. The actual size of this * field depends on the 'allocated' field * above. */ } ByteArray; #define BYTEARRAY_SIZE(len) \ - ((unsigned) (sizeof(ByteArray) - 4 + (len))) + ((unsigned) (TclOffset(ByteArray, bytes) + (len))) #define GET_BYTEARRAY(objPtr) \ ((ByteArray *) (objPtr)->internalRep.otherValuePtr) #define SET_BYTEARRAY(objPtr, baPtr) \ @@ -691,29 +691,30 @@ TclAppendBytesToByteArray( *---------------------------------------------------------------------- */ +static const EnsembleImplMap binaryMap[] = { +{ "format", BinaryFormatCmd, NULL, NULL, NULL, 0 }, +{ "scan", BinaryScanCmd, NULL, NULL, NULL, 0 }, +{ "encode", NULL, NULL, NULL, NULL, 0 }, +{ "decode", NULL, NULL, NULL, NULL, 0 }, +{ NULL, NULL, NULL, NULL, NULL, 0 } +}; +static const EnsembleImplMap encodeMap[] = { +{ "hex", BinaryEncodeHex, NULL, NULL, (ClientData)HexDigits, 0 }, +{ "uuencode", BinaryEncode64, NULL, NULL, (ClientData)UueDigits, 0 }, +{ "base64", BinaryEncode64, NULL, NULL, (ClientData)B64Digits, 0 }, +{ NULL, NULL, NULL, NULL, NULL, 0 } +}; +static const EnsembleImplMap decodeMap[] = { +{ "hex", BinaryDecodeHex, NULL, NULL, NULL, 0 }, +{ "uuencode", BinaryDecodeUu, NULL, NULL, NULL, 0 }, +{ "base64", BinaryDecode64, NULL, NULL, NULL, 0 }, +{ NULL, NULL, NULL, NULL, NULL, 0 } +}; + Tcl_Command TclInitBinaryCmd( Tcl_Interp *interp) { - const EnsembleImplMap binaryMap[] = { - { "format", BinaryFormatCmd, NULL, NULL ,NULL }, - { "scan", BinaryScanCmd, NULL,NULL ,NULL }, - { "encode", NULL, NULL, NULL, NULL }, - { "decode", NULL, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL } - }; - const EnsembleImplMap encodeMap[] = { - { "hex", BinaryEncodeHex, NULL, NULL, (ClientData)HexDigits }, - { "uuencode", BinaryEncode64, NULL, NULL, (ClientData)UueDigits }, - { "base64", BinaryEncode64, NULL, NULL, (ClientData)B64Digits }, - { NULL, NULL, NULL, NULL, NULL } - }; - const EnsembleImplMap decodeMap[] = { - { "hex", BinaryDecodeHex, NULL, NULL, NULL }, - { "uuencode", BinaryDecodeUu, NULL, NULL, NULL }, - { "base64", BinaryDecode64, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL } - }; Tcl_Command binaryEnsemble; binaryEnsemble = TclMakeEnsemble(interp, "binary", binaryMap); diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index 1ef646c..4ea1c78 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -14,7 +14,7 @@ * * This code contributed by Karl Lehenbauer and Mark Diekhans * - * RCS: @(#) $Id: tclCkalloc.c,v 1.38.4.2 2010/12/01 16:42:34 kennykb Exp $ + * RCS: @(#) $Id: tclCkalloc.c,v 1.38.4.3 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -32,12 +32,12 @@ typedef struct MemTag { int refCount; /* Number of mem_headers referencing this * tag. */ - char string[4]; /* Actual size of string will be as large as + char string[1]; /* Actual size of string will be as large as * needed for actual tag. This must be the * last field in the structure. */ } MemTag; -#define TAG_SIZE(bytesInString) ((unsigned) sizeof(MemTag) + bytesInString - 3) +#define TAG_SIZE(bytesInString) ((unsigned) ((TclOffset(MemTag, string) + 1) + bytesInString)) static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers (set * by "memory tag" command). */ @@ -185,7 +185,7 @@ TclDumpMemoryInfo(ClientData clientData, int flags) maximum_malloc_packets, maximum_bytes_malloced); if (flags == 0) { - fprintf((FILE *)clientData, buf); + fprintf((FILE *)clientData, "%s", buf); } else { /* Assume objPtr to append to */ Tcl_AppendToObj((Tcl_Obj *) clientData, buf, -1); @@ -814,6 +814,7 @@ MemoryCmd( FILE *fileP; Tcl_DString buffer; int result; + size_t len; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], @@ -909,9 +910,10 @@ MemoryCmd( if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) { TclpFree((char *) curTagPtr); } - curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(strlen(argv[2]))); + len = strlen(argv[2]); + curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(len)); curTagPtr->refCount = 0; - strcpy(curTagPtr->string, argv[2]); + memcpy(curTagPtr->string, argv[2], len + 1); return TCL_OK; } if (strcmp(argv[1],"trace") == 0) { diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index 2f52595..2d4fc83 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -10,12 +10,11 @@ * 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.126.2.1 2010/09/25 14:51:12 kennykb Exp $ + * RCS: @(#) $Id: tclCmdAH.c,v 1.126.2.2 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" #include <locale.h> -#include "tclFileSystem.h" /* * The state structure used by [foreach]. Note that the actual structure has @@ -46,8 +45,6 @@ static int CheckAccess(Tcl_Interp *interp, Tcl_Obj *pathPtr, static int EncodingDirsObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -static int FileTempfileCmd(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, @@ -65,6 +62,32 @@ static Tcl_NRPostProc ForNextCallback; static Tcl_NRPostProc ForPostNextCallback; static Tcl_NRPostProc ForeachLoopStep; static Tcl_NRPostProc EvalCmdErrMsg; + +static Tcl_ObjCmdProc FileAttrAccessTimeCmd; +static Tcl_ObjCmdProc FileAttrIsDirectoryCmd; +static Tcl_ObjCmdProc FileAttrIsExecutableCmd; +static Tcl_ObjCmdProc FileAttrIsExistingCmd; +static Tcl_ObjCmdProc FileAttrIsFileCmd; +static Tcl_ObjCmdProc FileAttrIsOwnedCmd; +static Tcl_ObjCmdProc FileAttrIsReadableCmd; +static Tcl_ObjCmdProc FileAttrIsWritableCmd; +static Tcl_ObjCmdProc FileAttrLinkStatCmd; +static Tcl_ObjCmdProc FileAttrModifyTimeCmd; +static Tcl_ObjCmdProc FileAttrSizeCmd; +static Tcl_ObjCmdProc FileAttrStatCmd; +static Tcl_ObjCmdProc FileAttrTypeCmd; +static Tcl_ObjCmdProc FilesystemSeparatorCmd; +static Tcl_ObjCmdProc FilesystemVolumesCmd; +static Tcl_ObjCmdProc PathDirNameCmd; +static Tcl_ObjCmdProc PathExtensionCmd; +static Tcl_ObjCmdProc PathFilesystemCmd; +static Tcl_ObjCmdProc PathJoinCmd; +static Tcl_ObjCmdProc PathNativeNameCmd; +static Tcl_ObjCmdProc PathNormalizeCmd; +static Tcl_ObjCmdProc PathRootNameCmd; +static Tcl_ObjCmdProc PathSplitCmd; +static Tcl_ObjCmdProc PathTailCmd; +static Tcl_ObjCmdProc PathTypeCmd; /* *---------------------------------------------------------------------- @@ -882,13 +905,14 @@ ExprCallback( /* *---------------------------------------------------------------------- * - * Tcl_FileObjCmd -- + * TclInitFileCmd -- * - * This procedure is invoked to process the "file" Tcl command. See the - * user documentation for details on what it does. PLEASE NOTE THAT THIS - * FAILS WITH FILENAMES AND PATHS WITH EMBEDDED NULLS. With the - * object-based Tcl_FS APIs, the above NOTE may no longer be true. In any - * case this assertion should be tested. + * This function builds the "file" Tcl command ensemble. See the user + * documentation for details on what that ensemble does. + * + * PLEASE NOTE THAT THIS FAILS WITH FILENAMES AND PATHS WITH EMBEDDED + * NULLS. With the object-based Tcl_FS APIs, the above NOTE may no longer + * be true. In any case this assertion should be tested. * * Results: * A standard Tcl result. @@ -899,570 +923,1160 @@ ExprCallback( *---------------------------------------------------------------------- */ - /* ARGSUSED */ -int -Tcl_FileObjCmd( - ClientData dummy, /* Not used. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ +Tcl_Command +TclInitFileCmd( + Tcl_Interp *interp) { - int index, value; - Tcl_StatBuf buf; - struct utimbuf tval; - /* - * This list of constants should match the fileOption string array below. + * Note that most subcommands are unsafe because either they manipulate + * the native filesystem or because they reveal information about the + * native filesystem. */ - static const char *const fileOptions[] = { - "atime", "attributes", "channels", "copy", - "delete", - "dirname", "executable", "exists", "extension", - "isdirectory", "isfile", "join", "link", - "lstat", "mtime", "mkdir", "nativename", - "normalize", "owned", - "pathtype", "readable", "readlink", "rename", - "rootname", "separator", "size", "split", - "stat", "system", "tail", "tempfile", - "type", "volumes", "writable", - NULL + static const EnsembleImplMap initMap[] = { + {"atime", FileAttrAccessTimeCmd, NULL, NULL, NULL, 0}, + {"attributes", TclFileAttrsCmd, NULL, NULL, NULL, 0}, + {"channels", TclChannelNamesCmd, NULL, NULL, NULL, 0}, + {"copy", TclFileCopyCmd, NULL, NULL, NULL, 0}, + {"delete", TclFileDeleteCmd, NULL, NULL, NULL, 0}, + {"dirname", PathDirNameCmd, NULL, NULL, NULL, 0}, + {"executable", FileAttrIsExecutableCmd, NULL, NULL, NULL, 0}, + {"exists", FileAttrIsExistingCmd, NULL, NULL, NULL, 0}, + {"extension", PathExtensionCmd, NULL, NULL, NULL, 0}, + {"isdirectory", FileAttrIsDirectoryCmd, NULL, NULL, NULL, 0}, + {"isfile", FileAttrIsFileCmd, NULL, NULL, NULL, 0}, + {"join", PathJoinCmd, NULL, NULL, NULL, 0}, + {"link", TclFileLinkCmd, NULL, NULL, NULL, 0}, + {"lstat", FileAttrLinkStatCmd, NULL, NULL, NULL, 0}, + {"mtime", FileAttrModifyTimeCmd, NULL, NULL, NULL, 0}, + {"mkdir", TclFileMakeDirsCmd, NULL, NULL, NULL, 0}, + {"nativename", PathNativeNameCmd, NULL, NULL, NULL, 0}, + {"normalize", PathNormalizeCmd, NULL, NULL, NULL, 0}, + {"owned", FileAttrIsOwnedCmd, NULL, NULL, NULL, 0}, + {"pathtype", PathTypeCmd, NULL, NULL, NULL, 0}, + {"readable", FileAttrIsReadableCmd, NULL, NULL, NULL, 0}, + {"readlink", TclFileReadLinkCmd, NULL, NULL, NULL, 0}, + {"rename", TclFileRenameCmd, NULL, NULL, NULL, 0}, + {"rootname", PathRootNameCmd, NULL, NULL, NULL, 0}, + {"separator", FilesystemSeparatorCmd, NULL, NULL, NULL, 0}, + {"size", FileAttrSizeCmd, NULL, NULL, NULL, 0}, + {"split", PathSplitCmd, NULL, NULL, NULL, 0}, + {"stat", FileAttrStatCmd, NULL, NULL, NULL, 0}, + {"system", PathFilesystemCmd, NULL, NULL, NULL, 0}, + {"tail", PathTailCmd, NULL, NULL, NULL, 0}, + {"tempfile", TclFileTemporaryCmd, NULL, NULL, NULL, 0}, + {"type", FileAttrTypeCmd, NULL, NULL, NULL, 0}, + {"volumes", FilesystemVolumesCmd, NULL, NULL, NULL, 0}, + {"writable", FileAttrIsWritableCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; - enum options { - FCMD_ATIME, FCMD_ATTRIBUTES, FCMD_CHANNELS, FCMD_COPY, - FCMD_DELETE, - FCMD_DIRNAME, FCMD_EXECUTABLE, FCMD_EXISTS, FCMD_EXTENSION, - FCMD_ISDIRECTORY, FCMD_ISFILE, FCMD_JOIN, FCMD_LINK, - FCMD_LSTAT, FCMD_MTIME, FCMD_MKDIR, FCMD_NATIVENAME, - FCMD_NORMALIZE, FCMD_OWNED, - FCMD_PATHTYPE, FCMD_READABLE, FCMD_READLINK, FCMD_RENAME, - FCMD_ROOTNAME, FCMD_SEPARATOR, FCMD_SIZE, FCMD_SPLIT, - FCMD_STAT, FCMD_SYSTEM, FCMD_TAIL, FCMD_TEMPFILE, - FCMD_TYPE, FCMD_VOLUMES, FCMD_WRITABLE + return TclMakeEnsemble(interp, "file", initMap); +} + +/* + *---------------------------------------------------------------------- + * + * TclMakeFileCommandSafe -- + * + * This function hides the unsafe subcommands of the "file" Tcl command + * ensemble. It must only be called from TclHideUnsafeCommands. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Adds commands to the table of hidden commands. + * + *---------------------------------------------------------------------- + */ + +int +TclMakeFileCommandSafe( + Tcl_Interp *interp) +{ + static const struct { + const char *cmdName; + int unsafe; + } unsafeInfo[] = { + {"atime", 1}, + {"attributes", 1}, + {"channels", 0}, + {"copy", 1}, + {"delete", 1}, + {"dirname", 1}, + {"executable", 1}, + {"exists", 1}, + {"extension", 1}, + {"isdirectory", 1}, + {"isfile", 1}, + {"join", 0}, + {"link", 1}, + {"lstat", 1}, + {"mtime", 1}, + {"mkdir", 1}, + {"nativename", 1}, + {"normalize", 1}, + {"owned", 1}, + {"pathtype", 0}, + {"readable", 1}, + {"readlink", 1}, + {"rename", 1}, + {"rootname", 1}, + {"separator", 0}, + {"size", 1}, + {"split", 0}, + {"stat", 1}, + {"system", 0}, + {"tail", 1}, + {"tempfile", 1}, + {"type", 1}, + {"volumes", 1}, + {"writable", 1}, + {NULL, 0} }; + int i; + Tcl_DString oldBuf, newBuf; + + Tcl_DStringInit(&oldBuf); + Tcl_DStringAppend(&oldBuf, "::tcl::file::", -1); + Tcl_DStringInit(&newBuf); + Tcl_DStringAppend(&newBuf, "tcl:file:", -1); + for (i=0 ; unsafeInfo[i].cmdName != NULL ; i++) { + if (unsafeInfo[i].unsafe) { + const char *oldName, *newName; + + Tcl_DStringSetLength(&oldBuf, 13); + oldName = Tcl_DStringAppend(&oldBuf, unsafeInfo[i].cmdName, -1); + Tcl_DStringSetLength(&newBuf, 9); + 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 'file %s' safe: %s", + unsafeInfo[i].cmdName, + Tcl_GetString(Tcl_GetObjResult(interp))); + } + } + } + Tcl_DStringFree(&oldBuf); + Tcl_DStringFree(&newBuf); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrAccessTimeCmd -- + * + * This function is invoked to process the "file atime" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * May update the access time on the file, if requested by the user. + * + *---------------------------------------------------------------------- + */ - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); +static int +FileAttrAccessTimeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + struct utimbuf tval; + + if (objc < 2 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); return TCL_ERROR; } - if (Tcl_GetIndexFromObj(interp, objv[1], fileOptions, "option", 0, - &index) != TCL_OK) { + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } + if (objc == 3) { + /* + * Need separate variable for reading longs from an object on 64-bit + * platforms. [Bug 698146] + */ - switch ((enum options) index) { + long newTime; - case FCMD_ATIME: - case FCMD_MTIME: - if ((objc < 3) || (objc > 4)) { - Tcl_WrongNumArgs(interp, 2, objv, "name ?time?"); + if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) { return TCL_ERROR; } - if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { + + tval.actime = newTime; + tval.modtime = buf.st_mtime; + + if (Tcl_FSUtime(objv[1], &tval) != 0) { + Tcl_AppendResult(interp, "could not set access time for file \"", + TclGetString(objv[1]), "\": ", Tcl_PosixError(interp), + NULL); return TCL_ERROR; } - if (objc == 4) { - /* - * Need separate variable for reading longs from an object on - * 64-bit platforms. [Bug #698146] - */ - long newTime; + /* + * Do another stat to ensure that the we return the new recognized + * atime - hopefully the same as the one we sent in. However, fs's + * like FAT don't even know what atime is. + */ - if (TclGetLongFromObj(interp, objv[3], &newTime) != TCL_OK) { - return TCL_ERROR; - } + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { + return TCL_ERROR; + } + } - if (index == FCMD_ATIME) { - tval.actime = newTime; - tval.modtime = buf.st_mtime; - } else { /* index == FCMD_MTIME */ - tval.actime = buf.st_atime; - tval.modtime = newTime; - } + Tcl_SetObjResult(interp, Tcl_NewLongObj((long) buf.st_atime)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrModifyTimeCmd -- + * + * This function is invoked to process the "file mtime" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * May update the modification time on the file, if requested by the + * user. + * + *---------------------------------------------------------------------- + */ - if (Tcl_FSUtime(objv[2], &tval) != 0) { - Tcl_AppendResult(interp, "could not set ", - (index == FCMD_ATIME ? "access" : "modification"), - " time for file \"", TclGetString(objv[2]), "\": ", - Tcl_PosixError(interp), NULL); - return TCL_ERROR; - } +static int +FileAttrModifyTimeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + struct utimbuf tval; - /* - * Do another stat to ensure that the we return the new recognized - * atime - hopefully the same as the one we sent in. However, fs's - * like FAT don't even know what atime is. - */ + if (objc < 2 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "name ?time?"); + return TCL_ERROR; + } + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { + return TCL_ERROR; + } + if (objc == 3) { + /* + * Need separate variable for reading longs from an object on 64-bit + * platforms. [Bug 698146] + */ - if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { - return TCL_ERROR; - } - } + long newTime; - Tcl_SetObjResult(interp, Tcl_NewLongObj((long) - (index == FCMD_ATIME ? buf.st_atime : buf.st_mtime))); - return TCL_OK; - case FCMD_ATTRIBUTES: - return TclFileAttrsCmd(interp, objc, objv); - case FCMD_CHANNELS: - if ((objc < 2) || (objc > 3)) { - Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); + if (TclGetLongFromObj(interp, objv[2], &newTime) != TCL_OK) { return TCL_ERROR; } - return Tcl_GetChannelNamesEx(interp, - ((objc == 2) ? NULL : TclGetString(objv[2]))); - case FCMD_COPY: - return TclFileCopyCmd(interp, objc, objv); - case FCMD_DELETE: - return TclFileDeleteCmd(interp, objc, objv); - case FCMD_DIRNAME: { - Tcl_Obj *dirPtr; - - if (objc != 3) { - goto only3Args; - } - dirPtr = TclPathPart(interp, objv[2], TCL_PATH_DIRNAME); - if (dirPtr == NULL) { + + tval.actime = buf.st_atime; + tval.modtime = newTime; + + if (Tcl_FSUtime(objv[1], &tval) != 0) { + Tcl_AppendResult(interp, "could not set modification time for " + "file \"", TclGetString(objv[1]), "\": ", + Tcl_PosixError(interp), NULL); return TCL_ERROR; } - Tcl_SetObjResult(interp, dirPtr); - Tcl_DecrRefCount(dirPtr); - return TCL_OK; - } - case FCMD_EXECUTABLE: - if (objc != 3) { - goto only3Args; - } - return CheckAccess(interp, objv[2], X_OK); - case FCMD_EXISTS: - if (objc != 3) { - goto only3Args; - } - return CheckAccess(interp, objv[2], F_OK); - case FCMD_EXTENSION: { - Tcl_Obj *ext; - if (objc != 3) { - goto only3Args; - } - ext = TclPathPart(interp, objv[2], TCL_PATH_EXTENSION); - if (ext == NULL) { + /* + * Do another stat to ensure that the we return the new recognized + * mtime - hopefully the same as the one we sent in. + */ + + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } - Tcl_SetObjResult(interp, ext); - Tcl_DecrRefCount(ext); - return TCL_OK; } - case FCMD_ISDIRECTORY: - if (objc != 3) { - goto only3Args; - } - value = 0; - if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { - value = S_ISDIR(buf.st_mode); - } - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); - return TCL_OK; - case FCMD_ISFILE: - if (objc != 3) { - goto only3Args; - } - value = 0; - if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { - value = S_ISREG(buf.st_mode); - } - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); - return TCL_OK; - case FCMD_OWNED: - if (objc != 3) { - goto only3Args; - } - value = 0; - if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { - /* - * For Windows, there are no user ids associated with a file, so - * we always return 1. - * - * TODO: use GetSecurityInfo to get the real owner of the file and - * test for equivalence to the current user. - */ -#if defined(__WIN32__) - value = 1; -#else - value = (geteuid() == buf.st_uid); -#endif - } - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); - return TCL_OK; - case FCMD_JOIN: { - Tcl_Obj *resObj; + Tcl_SetObjResult(interp, Tcl_NewLongObj((long) buf.st_mtime)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrLinkStatCmd -- + * + * This function is invoked to process the "file lstat" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Writes to an array named by the user. + * + *---------------------------------------------------------------------- + */ - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?"); - return TCL_ERROR; - } - resObj = Tcl_FSJoinToPath(NULL, objc - 2, objv + 2); - Tcl_SetObjResult(interp, resObj); - return TCL_OK; +static int +FileAttrLinkStatCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "name varName"); + return TCL_ERROR; + } + if (GetStatBuf(interp, objv[1], Tcl_FSLstat, &buf) != TCL_OK) { + return TCL_ERROR; } - case FCMD_LINK: { - Tcl_Obj *contents; + return StoreStatData(interp, objv[2], &buf); +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrStatCmd -- + * + * This function is invoked to process the "file stat" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Writes to an array named by the user. + * + *---------------------------------------------------------------------- + */ - if (objc < 3 || objc > 5) { - Tcl_WrongNumArgs(interp, 2, objv, "?-linktype? linkname ?target?"); - return TCL_ERROR; - } +static int +FileAttrStatCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "name varName"); + return TCL_ERROR; + } + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { + return TCL_ERROR; + } + return StoreStatData(interp, objv[2], &buf); +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrTypeCmd -- + * + * This function is invoked to process the "file type" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static int +FileAttrTypeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + if (GetStatBuf(interp, objv[1], Tcl_FSLstat, &buf) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj( + GetTypeFromMode((unsigned short) buf.st_mode), -1)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrSizeCmd -- + * + * This function is invoked to process the "file size" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrSizeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + if (GetStatBuf(interp, objv[1], Tcl_FSStat, &buf) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) buf.st_size)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsDirectoryCmd -- + * + * This function is invoked to process the "file isdirectory" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrIsDirectoryCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + int value = 0; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + if (GetStatBuf(NULL, objv[1], Tcl_FSStat, &buf) == TCL_OK) { + value = S_ISDIR(buf.st_mode); + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsExecutableCmd -- + * + * This function is invoked to process the "file executable" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrIsExecutableCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + return CheckAccess(interp, objv[1], X_OK); +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsExistingCmd -- + * + * This function is invoked to process the "file exists" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrIsExistingCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + return CheckAccess(interp, objv[1], F_OK); +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsFileCmd -- + * + * This function is invoked to process the "file isfile" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrIsFileCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + int value = 0; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + if (GetStatBuf(NULL, objv[1], Tcl_FSStat, &buf) == TCL_OK) { + value = S_ISREG(buf.st_mode); + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsOwnedCmd -- + * + * This function is invoked to process the "file owned" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +FileAttrIsOwnedCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_StatBuf buf; + int value = 0; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + if (GetStatBuf(NULL, objv[1], Tcl_FSStat, &buf) == TCL_OK) { /* - * Index of the 'source' argument. + * For Windows, there are no user ids associated with a file, so we + * always return 1. + * + * TODO: use GetSecurityInfo to get the real owner of the file and + * test for equivalence to the current user. */ - if (objc == 5) { - index = 3; - } else { - index = 2; - } +#ifdef __WIN32__ + value = 1; +#else + value = (geteuid() == buf.st_uid); +#endif + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsReadableCmd -- + * + * This function is invoked to process the "file readable" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc > 3) { - int linkAction; - if (objc == 5) { - /* - * We have a '-linktype' argument. - */ - - static const char *const linkTypes[] = { - "-symbolic", "-hard", NULL - }; - if (Tcl_GetIndexFromObj(interp, objv[2], linkTypes, "switch", - 0, &linkAction) != TCL_OK) { - return TCL_ERROR; - } - if (linkAction == 0) { - linkAction = TCL_CREATE_SYMBOLIC_LINK; - } else { - linkAction = TCL_CREATE_HARD_LINK; - } - } else { - linkAction = TCL_CREATE_SYMBOLIC_LINK|TCL_CREATE_HARD_LINK; - } - if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { - return TCL_ERROR; - } +static int +FileAttrIsReadableCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + return CheckAccess(interp, objv[1], R_OK); +} + +/* + *---------------------------------------------------------------------- + * + * FileAttrIsWritableCmd -- + * + * This function is invoked to process the "file writable" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - /* - * Create link from source to target. - */ +static int +FileAttrIsWritableCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + return CheckAccess(interp, objv[1], W_OK); +} + +/* + *---------------------------------------------------------------------- + * + * PathDirNameCmd -- + * + * This function is invoked to process the "file dirname" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - contents = Tcl_FSLink(objv[index], objv[index+1], linkAction); - if (contents == NULL) { - /* - * We handle three common error cases specially, and for all - * other errors, we use the standard posix error message. - */ - - if (errno == EEXIST) { - Tcl_AppendResult(interp, "could not create new link \"", - TclGetString(objv[index]), - "\": that path already exists", NULL); - } else if (errno == ENOENT) { - /* - * There are two cases here: either the target doesn't - * exist, or the directory of the src doesn't exist. - */ - - int access; - Tcl_Obj *dirPtr = TclPathPart(interp, objv[index], - TCL_PATH_DIRNAME); - - if (dirPtr == NULL) { - return TCL_ERROR; - } - access = Tcl_FSAccess(dirPtr, F_OK); - Tcl_DecrRefCount(dirPtr); - if (access != 0) { - Tcl_AppendResult(interp, - "could not create new link \"", - TclGetString(objv[index]), - "\": no such file or directory", NULL); - } else { - Tcl_AppendResult(interp, - "could not create new link \"", - TclGetString(objv[index]), "\": target \"", - TclGetString(objv[index+1]), - "\" doesn't exist", NULL); - } - } else { - Tcl_AppendResult(interp, - "could not create new link \"", - TclGetString(objv[index]), "\" pointing to \"", - TclGetString(objv[index+1]), "\": ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; - } - } else { - if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { - return TCL_ERROR; - } +static int +PathDirNameCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *dirPtr; - /* - * Read link - */ + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + dirPtr = TclPathPart(interp, objv[1], TCL_PATH_DIRNAME); + if (dirPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, dirPtr); + Tcl_DecrRefCount(dirPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathExtensionCmd -- + * + * This function is invoked to process the "file extension" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - contents = Tcl_FSLink(objv[index], NULL, 0); - if (contents == NULL) { - Tcl_AppendResult(interp, "could not read link \"", - TclGetString(objv[index]), "\": ", - Tcl_PosixError(interp), NULL); - return TCL_ERROR; - } - } - Tcl_SetObjResult(interp, contents); - if (objc == 3) { - /* - * If we are reading a link, we need to free this result refCount. - * If we are creating a link, this will just be objv[index+1], and - * so we don't own it. - */ +static int +PathExtensionCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *dirPtr; - Tcl_DecrRefCount(contents); - } - return TCL_OK; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; } - case FCMD_LSTAT: - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "name varName"); - return TCL_ERROR; - } - if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) { - return TCL_ERROR; - } - return StoreStatData(interp, objv[3], &buf); - case FCMD_STAT: - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "name varName"); - return TCL_ERROR; - } - if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { - return TCL_ERROR; - } - return StoreStatData(interp, objv[3], &buf); - case FCMD_SIZE: - if (objc != 3) { - goto only3Args; - } - if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, - Tcl_NewWideIntObj((Tcl_WideInt) buf.st_size)); - return TCL_OK; - case FCMD_TYPE: - if (objc != 3) { - goto only3Args; - } - if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj( - GetTypeFromMode((unsigned short) buf.st_mode), -1)); - return TCL_OK; - case FCMD_MKDIR: - return TclFileMakeDirsCmd(interp, objc, objv); - case FCMD_NATIVENAME: { - const char *fileName; - Tcl_DString ds; - - if (objc != 3) { - goto only3Args; - } - fileName = TclGetString(objv[2]); - fileName = Tcl_TranslateFileName(interp, fileName, &ds); - if (fileName == NULL) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(fileName, - Tcl_DStringLength(&ds))); - Tcl_DStringFree(&ds); - return TCL_OK; + dirPtr = TclPathPart(interp, objv[1], TCL_PATH_EXTENSION); + if (dirPtr == NULL) { + return TCL_ERROR; } - case FCMD_NORMALIZE: { - Tcl_Obj *fileName; + Tcl_SetObjResult(interp, dirPtr); + Tcl_DecrRefCount(dirPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathRootNameCmd -- + * + * This function is invoked to process the "file root" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - Tcl_WrongNumArgs(interp, 2, objv, "filename"); - return TCL_ERROR; - } +static int +PathRootNameCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *dirPtr; - fileName = Tcl_FSGetNormalizedPath(interp, objv[2]); - if (fileName == NULL) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, fileName); - return TCL_OK; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + dirPtr = TclPathPart(interp, objv[1], TCL_PATH_ROOT); + if (dirPtr == NULL) { + return TCL_ERROR; } - case FCMD_PATHTYPE: { - Tcl_Obj *typeName; + Tcl_SetObjResult(interp, dirPtr); + Tcl_DecrRefCount(dirPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathTailCmd -- + * + * This function is invoked to process the "file tail" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - goto only3Args; - } +static int +PathTailCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *dirPtr; - switch (Tcl_FSGetPathType(objv[2])) { - case TCL_PATH_ABSOLUTE: - TclNewLiteralStringObj(typeName, "absolute"); - break; - case TCL_PATH_RELATIVE: - TclNewLiteralStringObj(typeName, "relative"); - break; - case TCL_PATH_VOLUME_RELATIVE: - TclNewLiteralStringObj(typeName, "volumerelative"); - break; - default: - return TCL_OK; - } - Tcl_SetObjResult(interp, typeName); - return TCL_OK; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; } - case FCMD_READABLE: - if (objc != 3) { - goto only3Args; - } - return CheckAccess(interp, objv[2], R_OK); - case FCMD_READLINK: { - Tcl_Obj *contents; + dirPtr = TclPathPart(interp, objv[1], TCL_PATH_TAIL); + if (dirPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, dirPtr); + Tcl_DecrRefCount(dirPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathFilesystemCmd -- + * + * This function is invoked to process the "file system" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - goto only3Args; - } +static int +PathFilesystemCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *fsInfo; - if (Tcl_FSConvertToPathType(interp, objv[2]) != TCL_OK) { - return TCL_ERROR; - } + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + fsInfo = Tcl_FSFileSystemInfo(objv[1]); + if (fsInfo == NULL) { + Tcl_SetResult(interp, "unrecognised path", TCL_STATIC); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, fsInfo); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathJoinCmd -- + * + * This function is invoked to process the "file join" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +PathJoinCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name ?name ...?"); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_FSJoinToPath(NULL, objc - 1, objv + 1)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathNativeNameCmd -- + * + * This function is invoked to process the "file nativename" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - contents = Tcl_FSLink(objv[2], NULL, 0); +static int +PathNativeNameCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + const char *fileName; + Tcl_DString ds; - if (contents == NULL) { - Tcl_AppendResult(interp, "could not readlink \"", - TclGetString(objv[2]), "\": ", Tcl_PosixError(interp), - NULL); - return TCL_ERROR; - } - Tcl_SetObjResult(interp, contents); - Tcl_DecrRefCount(contents); - return TCL_OK; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; } - case FCMD_RENAME: - return TclFileRenameCmd(interp, objc, objv); - case FCMD_ROOTNAME: { - Tcl_Obj *root; + fileName = Tcl_TranslateFileName(interp, TclGetString(objv[1]), &ds); + if (fileName == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj(fileName, + Tcl_DStringLength(&ds))); + Tcl_DStringFree(&ds); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathNormalizeCmd -- + * + * This function is invoked to process the "file normalize" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - goto only3Args; - } - root = TclPathPart(interp, objv[2], TCL_PATH_ROOT); - if (root == NULL) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, root); - Tcl_DecrRefCount(root); - return TCL_OK; +static int +PathNormalizeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *fileName; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; } - case FCMD_SEPARATOR: - if ((objc < 2) || (objc > 3)) { - Tcl_WrongNumArgs(interp, 2, objv, "?name?"); - return TCL_ERROR; - } - if (objc == 2) { - const char *separator = NULL; /* lint */ + fileName = Tcl_FSGetNormalizedPath(interp, objv[1]); + if (fileName == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, fileName); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathSplitCmd -- + * + * This function is invoked to process the "file split" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - switch (tclPlatform) { - case TCL_PLATFORM_UNIX: - separator = "/"; - break; - case TCL_PLATFORM_WINDOWS: - separator = "\\"; - break; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(separator, 1)); - } else { - Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[2]); +static int +PathSplitCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *res; - if (separatorObj == NULL) { - Tcl_SetResult(interp, "Unrecognised path", TCL_STATIC); - return TCL_ERROR; - } - Tcl_SetObjResult(interp, separatorObj); - } - return TCL_OK; - case FCMD_SPLIT: { - Tcl_Obj *res; + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + res = Tcl_FSSplitPath(objv[1], NULL); + if (res == NULL) { + Tcl_AppendResult(interp, "could not read \"", TclGetString(objv[1]), + "\": no such file or directory", NULL); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, res); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * PathTypeCmd -- + * + * This function is invoked to process the "file pathtype" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - goto only3Args; - } - res = Tcl_FSSplitPath(objv[2], NULL); - if (res == NULL) { - /* How can the interp be NULL here?! DKF */ - if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(objv[2]), - "\": no such file or directory", NULL); - } - return TCL_ERROR; - } - Tcl_SetObjResult(interp, res); +static int +PathTypeCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *typeName; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + switch (Tcl_FSGetPathType(objv[1])) { + case TCL_PATH_ABSOLUTE: + TclNewLiteralStringObj(typeName, "absolute"); + break; + case TCL_PATH_RELATIVE: + TclNewLiteralStringObj(typeName, "relative"); + break; + case TCL_PATH_VOLUME_RELATIVE: + TclNewLiteralStringObj(typeName, "volumerelative"); + break; + default: + /* Should be unreachable */ return TCL_OK; } - case FCMD_SYSTEM: { - Tcl_Obj *fsInfo; + Tcl_SetObjResult(interp, typeName); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FilesystemSeparatorCmd -- + * + * This function is invoked to process the "file separator" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - if (objc != 3) { - goto only3Args; - } - fsInfo = Tcl_FSFileSystemInfo(objv[2]); - if (fsInfo == NULL) { - Tcl_SetResult(interp, "Unrecognised path", TCL_STATIC); - return TCL_ERROR; - } - Tcl_SetObjResult(interp, fsInfo); - return TCL_OK; +static int +FilesystemSeparatorCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc < 1 || objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?name?"); + return TCL_ERROR; } - case FCMD_TAIL: { - Tcl_Obj *dirPtr; + if (objc == 1) { + const char *separator = NULL; /* lint */ - if (objc != 3) { - goto only3Args; - } - dirPtr = TclPathPart(interp, objv[2], TCL_PATH_TAIL); - if (dirPtr == NULL) { - return TCL_ERROR; + switch (tclPlatform) { + case TCL_PLATFORM_UNIX: + separator = "/"; + break; + case TCL_PLATFORM_WINDOWS: + separator = "\\"; + break; } - Tcl_SetObjResult(interp, dirPtr); - Tcl_DecrRefCount(dirPtr); - return TCL_OK; - } - case FCMD_TEMPFILE: - return FileTempfileCmd(interp, objc, objv); - case FCMD_VOLUMES: - if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(separator, 1)); + } else { + Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[1]); + + if (separatorObj == NULL) { + Tcl_SetResult(interp, "unrecognised path", TCL_STATIC); return TCL_ERROR; } - Tcl_SetObjResult(interp, Tcl_FSListVolumes()); - return TCL_OK; - case FCMD_WRITABLE: - if (objc != 3) { - goto only3Args; - } - return CheckAccess(interp, objv[2], W_OK); + Tcl_SetObjResult(interp, separatorObj); } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * FilesystemVolumesCmd -- + * + * This function is invoked to process the "file volumes" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ - only3Args: - Tcl_WrongNumArgs(interp, 2, objv, "name"); - return TCL_ERROR; +static int +FilesystemVolumesCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_FSListVolumes()); + return TCL_OK; } /* @@ -1590,13 +2204,13 @@ StoreStatData( */ #define STORE_ARY(fieldName, object) \ - TclNewLiteralStringObj(field, fieldName); \ - Tcl_IncrRefCount(field); \ - value = (object); \ + TclNewLiteralStringObj(field, fieldName); \ + Tcl_IncrRefCount(field); \ + value = (object); \ if (Tcl_ObjSetVar2(interp,varName,field,value,TCL_LEAVE_ERR_MSG)==NULL) { \ - TclDecrRefCount(field); \ - return TCL_ERROR; \ - } \ + TclDecrRefCount(field); \ + return TCL_ERROR; \ + } \ TclDecrRefCount(field); /* @@ -1670,165 +2284,6 @@ GetTypeFromMode( } /* - *--------------------------------------------------------------------------- - * - * FileTempfileCmd - * - * This function implements the "tempfile" subcommand of the "file" - * command. - * - * Results: - * Returns a standard Tcl result. - * - * Side effects: - * Creates a temporary file. Opens a channel to that file and puts the - * name of that channel in the result. *Might* register suitable exit - * handlers to ensure that the temporary file gets deleted. Might write - * to a variable, so reentrancy is a potential issue. - * - *--------------------------------------------------------------------------- - */ - -static int -FileTempfileCmd( - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_Obj *nameVarObj = NULL; /* Variable to store the name of the temporary - * file in. */ - Tcl_Obj *nameObj = NULL; /* Object that will contain the filename. */ - Tcl_Channel chan; /* The channel opened (RDWR) on the temporary - * file, or NULL if there's an error. */ - Tcl_Obj *tempDirObj = NULL, *tempBaseObj = NULL, *tempExtObj = NULL; - /* Pieces of template. Each piece is NULL if - * it is omitted. The platform temporary file - * engine might ignore some pieces. */ - - if (objc < 2 || objc > 4) { - Tcl_WrongNumArgs(interp, 2, objv, "?nameVar? ?template?"); - return TCL_ERROR; - } - - if (objc > 2) { - nameVarObj = objv[2]; - TclNewObj(nameObj); - } - if (objc > 3) { - int length; - const char *string = TclGetStringFromObj(objv[3], &length); - - /* - * Treat an empty string as if it wasn't there. - */ - - if (length == 0) { - goto makeTemporary; - } - - /* - * The template only gives a directory if there is a directory - * separator in it. - */ - - if (strchr(string, '/') != NULL - || (tclPlatform == TCL_PLATFORM_WINDOWS - && strchr(string, '\\') != NULL)) { - tempDirObj = TclPathPart(interp, objv[3], TCL_PATH_DIRNAME); - - /* - * Only allow creation of temporary files in the native filesystem - * since they are frequently used for integration with external - * tools or system libraries. [Bug 2388866] - */ - - if (tempDirObj != NULL && Tcl_FSGetFileSystemForPath(tempDirObj) - != &tclNativeFilesystem) { - TclDecrRefCount(tempDirObj); - tempDirObj = NULL; - } - } - - /* - * The template only gives the filename if the last character isn't a - * directory separator. - */ - - if (string[length-1] != '/' && (tclPlatform != TCL_PLATFORM_WINDOWS - || string[length-1] != '\\')) { - Tcl_Obj *tailObj = TclPathPart(interp, objv[3], TCL_PATH_TAIL); - - if (tailObj != NULL) { - tempBaseObj = TclPathPart(interp, tailObj, TCL_PATH_ROOT); - tempExtObj = TclPathPart(interp, tailObj, TCL_PATH_EXTENSION); - TclDecrRefCount(tailObj); - } - } - } - - /* - * Convert empty parts of the template into unspecified parts. - */ - - if (tempDirObj && !TclGetString(tempDirObj)[0]) { - TclDecrRefCount(tempDirObj); - tempDirObj = NULL; - } - if (tempBaseObj && !TclGetString(tempBaseObj)[0]) { - TclDecrRefCount(tempBaseObj); - tempBaseObj = NULL; - } - if (tempExtObj && !TclGetString(tempExtObj)[0]) { - TclDecrRefCount(tempExtObj); - tempExtObj = NULL; - } - - /* - * Create and open the temporary file. - */ - - makeTemporary: - chan = TclpOpenTemporaryFile(tempDirObj,tempBaseObj,tempExtObj, nameObj); - - /* - * If we created pieces of template, get rid of them now. - */ - - if (tempDirObj) { - TclDecrRefCount(tempDirObj); - } - if (tempBaseObj) { - TclDecrRefCount(tempBaseObj); - } - if (tempExtObj) { - TclDecrRefCount(tempExtObj); - } - - /* - * Deal with results. - */ - - if (chan == NULL) { - if (nameVarObj) { - TclDecrRefCount(nameObj); - } - Tcl_AppendResult(interp, "can't create temporary file: ", - Tcl_PosixError(interp), NULL); - return TCL_ERROR; - } - Tcl_RegisterChannel(interp, chan); - if (nameVarObj != NULL) { - if (Tcl_ObjSetVar2(interp, nameVarObj, NULL, nameObj, - TCL_LEAVE_ERR_MSG) == NULL) { - Tcl_UnregisterChannel(interp, chan); - return TCL_ERROR; - } - } - Tcl_AppendResult(interp, Tcl_GetChannelName(chan), NULL); - return TCL_OK; -} - -/* *---------------------------------------------------------------------- * * Tcl_ForObjCmd -- diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 44a3bf3..8900d14 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -16,7 +16,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdIL.c,v 1.184.2.1 2010/09/27 20:33:37 kennykb Exp $ + * RCS: @(#) $Id: tclCmdIL.c,v 1.184.2.2 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -160,31 +160,31 @@ static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr, */ static const EnsembleImplMap defaultInfoMap[] = { - {"args", InfoArgsCmd, NULL, NULL, NULL}, - {"body", InfoBodyCmd, NULL, NULL, NULL}, - {"cmdcount", InfoCmdCountCmd, NULL, NULL, NULL}, - {"commands", InfoCommandsCmd, NULL, NULL, NULL}, - {"complete", InfoCompleteCmd, NULL, NULL, NULL}, - {"coroutine", TclInfoCoroutineCmd, NULL, NULL, NULL}, - {"default", InfoDefaultCmd, NULL, NULL, NULL}, - {"errorstack", InfoErrorStackCmd, NULL, NULL, NULL}, - {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL}, - {"frame", InfoFrameCmd, NULL, NULL, NULL}, - {"functions", InfoFunctionsCmd, NULL, NULL, NULL}, - {"globals", TclInfoGlobalsCmd, NULL, NULL, NULL}, - {"hostname", InfoHostnameCmd, NULL, NULL, NULL}, - {"level", InfoLevelCmd, NULL, NULL, NULL}, - {"library", InfoLibraryCmd, NULL, NULL, NULL}, - {"loaded", InfoLoadedCmd, NULL, NULL, NULL}, - {"locals", TclInfoLocalsCmd, NULL, NULL, NULL}, - {"nameofexecutable", InfoNameOfExecutableCmd, NULL, NULL, NULL}, - {"patchlevel", InfoPatchLevelCmd, NULL, NULL, NULL}, - {"procs", InfoProcsCmd, NULL, NULL, NULL}, - {"script", InfoScriptCmd, NULL, NULL, NULL}, - {"sharedlibextension", InfoSharedlibCmd, NULL, NULL, NULL}, - {"tclversion", InfoTclVersionCmd, NULL, NULL, NULL}, - {"vars", TclInfoVarsCmd, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL} + {"args", InfoArgsCmd, NULL, NULL, NULL, 0}, + {"body", InfoBodyCmd, NULL, NULL, NULL, 0}, + {"cmdcount", InfoCmdCountCmd, NULL, NULL, NULL, 0}, + {"commands", InfoCommandsCmd, NULL, NULL, NULL, 0}, + {"complete", InfoCompleteCmd, NULL, NULL, NULL, 0}, + {"coroutine", TclInfoCoroutineCmd, NULL, NULL, NULL, 0}, + {"default", InfoDefaultCmd, NULL, NULL, NULL, 0}, + {"errorstack", InfoErrorStackCmd, NULL, NULL, NULL, 0}, + {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0}, + {"frame", InfoFrameCmd, NULL, NULL, NULL, 0}, + {"functions", InfoFunctionsCmd, NULL, NULL, NULL, 0}, + {"globals", TclInfoGlobalsCmd, NULL, NULL, NULL, 0}, + {"hostname", InfoHostnameCmd, NULL, NULL, NULL, 0}, + {"level", InfoLevelCmd, NULL, NULL, NULL, 0}, + {"library", InfoLibraryCmd, NULL, NULL, NULL, 0}, + {"loaded", InfoLoadedCmd, NULL, NULL, NULL, 0}, + {"locals", TclInfoLocalsCmd, NULL, NULL, NULL, 0}, + {"nameofexecutable", InfoNameOfExecutableCmd, NULL, NULL, NULL, 0}, + {"patchlevel", InfoPatchLevelCmd, NULL, NULL, NULL, 0}, + {"procs", InfoProcsCmd, NULL, NULL, NULL, 0}, + {"script", InfoScriptCmd, NULL, NULL, NULL, 0}, + {"sharedlibextension", InfoSharedlibCmd, NULL, NULL, NULL, 0}, + {"tclversion", InfoTclVersionCmd, NULL, NULL, NULL, 0}, + {"vars", TclInfoVarsCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; /* diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index ae2688d..7c30685 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.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: tclCmdMZ.c,v 1.214.2.1 2010/12/01 16:42:34 kennykb Exp $ + * RCS: @(#) $Id: tclCmdMZ.c,v 1.214.2.2 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -3346,29 +3346,29 @@ TclInitStringCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap stringImplMap[] = { - {"bytelength", StringBytesCmd, NULL, NULL, NULL}, - {"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL}, - {"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL}, - {"first", StringFirstCmd, NULL, NULL, NULL}, - {"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, NULL}, - {"is", StringIsCmd, NULL, NULL, NULL}, - {"last", StringLastCmd, NULL, NULL, NULL}, - {"length", StringLenCmd, TclCompileStringLenCmd, NULL, NULL}, - {"map", StringMapCmd, NULL, NULL, NULL}, - {"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL}, - {"range", StringRangeCmd, NULL, NULL, NULL}, - {"repeat", StringReptCmd, NULL, NULL, NULL}, - {"replace", StringRplcCmd, NULL, NULL, NULL}, - {"reverse", StringRevCmd, NULL, NULL, NULL}, - {"tolower", StringLowerCmd, NULL, NULL, NULL}, - {"toupper", StringUpperCmd, NULL, NULL, NULL}, - {"totitle", StringTitleCmd, NULL, NULL, NULL}, - {"trim", StringTrimCmd, NULL, NULL, NULL}, - {"trimleft", StringTrimLCmd, NULL, NULL, NULL}, - {"trimright", StringTrimRCmd, NULL, NULL, NULL}, - {"wordend", StringEndCmd, NULL, NULL, NULL}, - {"wordstart", StringStartCmd, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL} + {"bytelength", StringBytesCmd, NULL, NULL, NULL, 0}, + {"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL, 0}, + {"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL, 0}, + {"first", StringFirstCmd, NULL, NULL, NULL, 0}, + {"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, NULL, 0}, + {"is", StringIsCmd, NULL, NULL, NULL, 0}, + {"last", StringLastCmd, NULL, NULL, NULL, 0}, + {"length", StringLenCmd, TclCompileStringLenCmd, NULL, NULL, 0}, + {"map", StringMapCmd, NULL, NULL, NULL, 0}, + {"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0}, + {"range", StringRangeCmd, NULL, NULL, NULL, 0}, + {"repeat", StringReptCmd, NULL, NULL, NULL, 0}, + {"replace", StringRplcCmd, NULL, NULL, NULL, 0}, + {"reverse", StringRevCmd, NULL, NULL, NULL, 0}, + {"tolower", StringLowerCmd, NULL, NULL, NULL, 0}, + {"toupper", StringUpperCmd, NULL, NULL, NULL, 0}, + {"totitle", StringTitleCmd, NULL, NULL, NULL, 0}, + {"trim", StringTrimCmd, NULL, NULL, NULL, 0}, + {"trimleft", StringTrimLCmd, NULL, NULL, NULL, 0}, + {"trimright", StringTrimRCmd, NULL, NULL, NULL, 0}, + {"wordend", StringEndCmd, NULL, NULL, NULL, 0}, + {"wordstart", StringStartCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; return TclMakeEnsemble(interp, "string", stringImplMap); diff --git a/generic/tclCompile.c b/generic/tclCompile.c index be688e1..833a920 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.187.2.4 2010/10/23 15:49:54 kennykb Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.187.2.5 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -2600,8 +2600,7 @@ TclFindCompiledLocal( if (create || (name == NULL)) { localVar = procPtr->numCompiledLocals; localPtr = (CompiledLocal *) ckalloc((unsigned) - (sizeof(CompiledLocal) - sizeof(localPtr->name) - + nameBytes + 1)); + (TclOffset(CompiledLocal, name) + nameBytes + 1)); if (procPtr->firstLocalPtr == NULL) { procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr; } else { @@ -4404,7 +4403,7 @@ static void UpdateStringOfInstName(Tcl_Obj *objPtr) } len = strlen(s); objPtr->bytes = ckalloc((unsigned) len + 1); - strcpy(objPtr->bytes, s); + memcpy(objPtr->bytes, s, len + 1); objPtr->length = len; } diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 6a17b02..8affede 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclDictObj.c,v 1.84 2010/08/22 18:53:26 nijtmans Exp $ + * RCS: @(#) $Id: tclDictObj.c,v 1.84.2.1 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -87,26 +87,26 @@ static int DictForLoopCallback(ClientData data[], */ static const EnsembleImplMap implementationMap[] = { - {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL }, - {"create", DictCreateCmd, NULL, NULL, NULL }, - {"exists", DictExistsCmd, NULL, NULL, NULL }, - {"filter", DictFilterCmd, NULL, NULL, NULL }, - {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL }, - {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL }, - {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL }, - {"info", DictInfoCmd, NULL, NULL, NULL }, - {"keys", DictKeysCmd, NULL, NULL, NULL }, - {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL }, - {"merge", DictMergeCmd, NULL, NULL, NULL }, - {"remove", DictRemoveCmd, NULL, NULL, NULL }, - {"replace", DictReplaceCmd, NULL, NULL, NULL }, - {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL }, - {"size", DictSizeCmd, NULL, NULL, NULL }, - {"unset", DictUnsetCmd, NULL, NULL, NULL }, - {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL }, - {"values", DictValuesCmd, NULL, NULL, NULL }, - {"with", DictWithCmd, NULL, NULL, NULL }, - {NULL, NULL, NULL, NULL, NULL} + {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 }, + {"create", DictCreateCmd, NULL, NULL, NULL, 0 }, + {"exists", DictExistsCmd, NULL, NULL, NULL, 0 }, + {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, + {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 }, + {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 }, + {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 }, + {"info", DictInfoCmd, NULL, NULL, NULL, 0 }, + {"keys", DictKeysCmd, NULL, NULL, NULL, 0 }, + {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 }, + {"merge", DictMergeCmd, NULL, NULL, NULL, 0 }, + {"remove", DictRemoveCmd, NULL, NULL, NULL, 0 }, + {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, + {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, + {"size", DictSizeCmd, NULL, NULL, NULL, 0 }, + {"unset", DictUnsetCmd, NULL, NULL, NULL, 0 }, + {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, + {"values", DictValuesCmd, NULL, NULL, NULL, 0 }, + {"with", DictWithCmd, NULL, NULL, NULL, 0 }, + {NULL, NULL, NULL, NULL, NULL, 0} }; /* diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index c4750c5..1bf9be1 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEnsemble.c,v 1.5 2010/03/05 14:34:04 dkf Exp $ + * RCS: @(#) $Id: tclEnsemble.c,v 1.5.4.1 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" @@ -1417,16 +1417,21 @@ TclMakeEnsemble( { Tcl_Command ensemble; Tcl_Namespace *ns; - Tcl_DString buf; + Tcl_DString buf, hiddenBuf; const char **nameParts = NULL; const char *cmdName = NULL; - int i, nameCount = 0, ensembleFlags = 0; + int i, nameCount = 0, ensembleFlags = 0, hiddenLen; /* * Construct the path for the ensemble namespace and create it. */ Tcl_DStringInit(&buf); + Tcl_DStringInit(&hiddenBuf); + Tcl_DStringAppend(&hiddenBuf, "tcl:", -1); + Tcl_DStringAppend(&hiddenBuf, name, -1); + Tcl_DStringAppend(&hiddenBuf, ":", -1); + hiddenLen = Tcl_DStringLength(&hiddenBuf); if (name[0] == ':' && name[1] == ':') { /* * An absolute name, so use it directly. @@ -1491,10 +1496,35 @@ TclMakeEnsemble( Tcl_DStringLength(&buf)); Tcl_AppendToObj(toObj, map[i].name, -1); Tcl_DictObjPut(NULL, mapDict, fromObj, toObj); + if (map[i].proc || map[i].nreProc) { - cmdPtr = (Command *) - Tcl_NRCreateCommand(interp, TclGetString(toObj), - map[i].proc, map[i].nreProc, map[i].clientData, NULL); + /* + * If the command is unsafe, hide it when we're in a safe + * interpreter. The code to do this is really hokey! It also + * doesn't work properly yet; this function is always + * currently called before the safe-interp flag is set so the + * Tcl_IsSafe check fails. + */ + + if (map[i].unsafe && Tcl_IsSafe(interp)) { + cmdPtr = (Command *) + Tcl_NRCreateCommand(interp, "___tmp", map[i].proc, + map[i].nreProc, map[i].clientData, NULL); + Tcl_DStringSetLength(&hiddenBuf, hiddenLen); + if (Tcl_HideCommand(interp, "___tmp", + Tcl_DStringAppend(&hiddenBuf, map[i].name, -1))) { + Tcl_Panic(Tcl_GetString(Tcl_GetObjResult(interp))); + } + } else { + /* + * Not hidden, so just create it. Yay! + */ + + cmdPtr = (Command *) + Tcl_NRCreateCommand(interp, TclGetString(toObj), + map[i].proc, map[i].nreProc, map[i].clientData, + NULL); + } cmdPtr->compileProc = map[i].compileProc; if (map[i].compileProc != NULL) { ensembleFlags |= ENSEMBLE_COMPILE; @@ -1508,6 +1538,7 @@ TclMakeEnsemble( } Tcl_DStringFree(&buf); + Tcl_DStringFree(&hiddenBuf); if (nameParts != NULL) { Tcl_Free((char *) nameParts); } diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index 8ff6e39..277afa6 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -9,10 +9,11 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclFCmd.c,v 1.51 2010/02/24 10:32:17 dkf Exp $ + * RCS: @(#) $Id: tclFCmd.c,v 1.51.4.1 2010/12/11 18:39:28 kennykb Exp $ */ #include "tclInt.h" +#include "tclFileSystem.h" /* * Declarations for local functions defined in this file: @@ -48,6 +49,7 @@ static int FileForceOption(Tcl_Interp *interp, int TclFileRenameCmd( + ClientData clientData, /* Unused */ Tcl_Interp *interp, /* Interp for error reporting or recursive * calls in the case of a tricky rename. */ int objc, /* Number of arguments. */ @@ -76,6 +78,7 @@ TclFileRenameCmd( int TclFileCopyCmd( + ClientData clientData, /* Unused */ Tcl_Interp *interp, /* Used for error reporting or recursive calls * in the case of a tricky copy. */ int objc, /* Number of arguments. */ @@ -113,22 +116,20 @@ FileCopyRename( Tcl_StatBuf statBuf; Tcl_Obj *target; - i = FileForceOption(interp, objc - 2, objv + 2, &force); + i = FileForceOption(interp, objc - 1, objv + 1, &force); if (i < 0) { return TCL_ERROR; } - i += 2; + i++; if ((objc - i) < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - TclGetString(objv[0]), " ", TclGetString(objv[1]), - " ?-option value ...? source ?source ...? target\"", NULL); + Tcl_WrongNumArgs(interp, 1, objv, + "?-option value ...? source ?source ...? target"); return TCL_ERROR; } /* - * If target doesn't exist or isn't a directory, try the copy/rename. - * More than 2 arguments is only valid if the target is an existing - * directory. + * If target doesn't exist or isn't a directory, try the copy/rename. More + * than 2 arguments is only valid if the target is an existing directory. */ target = objv[objc - 1]; @@ -218,26 +219,25 @@ FileCopyRename( int TclFileMakeDirsCmd( + ClientData clientData, /* Unused */ Tcl_Interp *interp, /* Used for error reporting. */ int objc, /* Number of arguments */ Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */ { - Tcl_Obj *errfile; + Tcl_Obj *errfile = NULL; int result, i, j, pobjc; Tcl_Obj *split = NULL; Tcl_Obj *target = NULL; Tcl_StatBuf statBuf; - errfile = NULL; - result = TCL_OK; - for (i = 2; i < objc; i++) { + for (i = 1; i < objc; i++) { if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) { result = TCL_ERROR; break; } - split = Tcl_FSSplitPath(objv[i],&pobjc); + split = Tcl_FSSplitPath(objv[i], &pobjc); Tcl_IncrRefCount(split); if (pobjc == 0) { errno = ENOENT; @@ -274,19 +274,17 @@ TclFileMakeDirsCmd( * subdirectory. */ - if (errno == EEXIST) { - if ((Tcl_FSStat(target, &statBuf) == 0) - && S_ISDIR(statBuf.st_mode)) { - /* - * It is a directory that wasn't there before, so keep - * going without error. - */ - - Tcl_ResetResult(interp); - } else { - errfile = target; - goto done; - } + if (errno != EEXIST) { + errfile = target; + goto done; + } else if ((Tcl_FSStat(target, &statBuf) == 0) + && S_ISDIR(statBuf.st_mode)) { + /* + * It is a directory that wasn't there before, so keep + * going without error. + */ + + Tcl_ResetResult(interp); } else { errfile = target; goto done; @@ -338,6 +336,7 @@ TclFileMakeDirsCmd( int TclFileDeleteCmd( + ClientData clientData, /* Unused */ Tcl_Interp *interp, /* Used for error reporting */ int objc, /* Number of arguments */ Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */ @@ -346,16 +345,15 @@ TclFileDeleteCmd( Tcl_Obj *errfile; Tcl_Obj *errorBuffer = NULL; - i = FileForceOption(interp, objc - 2, objv + 2, &force); + i = FileForceOption(interp, objc - 1, objv + 1, &force); if (i < 0) { return TCL_ERROR; } - i += 2; errfile = NULL; result = TCL_OK; - for ( ; i < objc; i++) { + for (i++ ; i < objc; i++) { Tcl_StatBuf statBuf; errfile = objv[i]; @@ -821,22 +819,25 @@ FileForceOption( int *forcePtr) /* If the "-force" was specified, *forcePtr is * filled with 1, otherwise with 0. */ { - int force, i; + int force, i, idx; + static const char *const options[] = { + "-force", "--", NULL + }; force = 0; for (i = 0; i < objc; i++) { if (TclGetString(objv[i])[0] != '-') { break; } - if (strcmp(TclGetString(objv[i]), "-force") == 0) { + if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", TCL_EXACT, + &idx) != TCL_OK) { + return -1; + } + if (idx == 0 /* -force */) { force = 1; - } else if (strcmp(TclGetString(objv[i]), "--") == 0) { + } else { /* -- */ i++; break; - } else { - Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[i]), - "\": should be -force or --", NULL); - return -1; } } *forcePtr = force; @@ -940,6 +941,7 @@ FileBasename( int TclFileAttrsCmd( + ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The interpreter for error reporting. */ int objc, /* Number of command line arguments. */ Tcl_Obj *const objv[]) /* The command line objects. */ @@ -951,19 +953,18 @@ TclFileAttrsCmd( int numObjStrings = -1; Tcl_Obj *filePtr; - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, - "name ?-option value ...?"); + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name ?-option value ...?"); return TCL_ERROR; } - filePtr = objv[2]; + filePtr = objv[1]; if (Tcl_FSConvertToPathType(interp, filePtr) != TCL_OK) { return TCL_ERROR; } - objc -= 3; - objv += 3; + objc -= 2; + objv += 2; result = TCL_ERROR; Tcl_SetErrno(0); @@ -1125,6 +1126,362 @@ TclFileAttrsCmd( } /* + *---------------------------------------------------------------------- + * + * TclFileLinkCmd -- + * + * This function is invoked to process the "file link" Tcl command. See + * the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * May create a new link. + * + *---------------------------------------------------------------------- + */ + +int +TclFileLinkCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *contents; + int index; + + if (objc < 2 || objc > 4) { + Tcl_WrongNumArgs(interp, 1, objv, "?-linktype? linkname ?target?"); + return TCL_ERROR; + } + + /* + * Index of the 'source' argument. + */ + + if (objc == 4) { + index = 2; + } else { + index = 1; + } + + if (objc > 2) { + int linkAction; + + if (objc == 4) { + /* + * We have a '-linktype' argument. + */ + + static const char *const linkTypes[] = { + "-symbolic", "-hard", NULL + }; + if (Tcl_GetIndexFromObj(interp, objv[1], linkTypes, "switch", 0, + &linkAction) != TCL_OK) { + return TCL_ERROR; + } + if (linkAction == 0) { + linkAction = TCL_CREATE_SYMBOLIC_LINK; + } else { + linkAction = TCL_CREATE_HARD_LINK; + } + } else { + linkAction = TCL_CREATE_SYMBOLIC_LINK | TCL_CREATE_HARD_LINK; + } + if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Create link from source to target. + */ + + contents = Tcl_FSLink(objv[index], objv[index+1], linkAction); + if (contents == NULL) { + /* + * We handle three common error cases specially, and for all other + * errors, we use the standard posix error message. + */ + + if (errno == EEXIST) { + Tcl_AppendResult(interp, "could not create new link \"", + TclGetString(objv[index]), + "\": that path already exists", NULL); + } else if (errno == ENOENT) { + /* + * There are two cases here: either the target doesn't exist, + * or the directory of the src doesn't exist. + */ + + int access; + Tcl_Obj *dirPtr = TclPathPart(interp, objv[index], + TCL_PATH_DIRNAME); + + if (dirPtr == NULL) { + return TCL_ERROR; + } + access = Tcl_FSAccess(dirPtr, F_OK); + Tcl_DecrRefCount(dirPtr); + if (access != 0) { + Tcl_AppendResult(interp, "could not create new link \"", + TclGetString(objv[index]), + "\": no such file or directory", NULL); + } else { + Tcl_AppendResult(interp, "could not create new link \"", + TclGetString(objv[index]), "\": target \"", + TclGetString(objv[index+1]), "\" doesn't exist", + NULL); + } + } else { + Tcl_AppendResult(interp, "could not create new link \"", + TclGetString(objv[index]), "\" pointing to \"", + TclGetString(objv[index+1]), "\": ", + Tcl_PosixError(interp), NULL); + } + return TCL_ERROR; + } + } else { + if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Read link + */ + + contents = Tcl_FSLink(objv[index], NULL, 0); + if (contents == NULL) { + Tcl_AppendResult(interp, "could not read link \"", + TclGetString(objv[index]), "\": ", Tcl_PosixError(interp), + NULL); + return TCL_ERROR; + } + } + Tcl_SetObjResult(interp, contents); + if (objc == 2) { + /* + * If we are reading a link, we need to free this result refCount. If + * we are creating a link, this will just be objv[index+1], and so we + * don't own it. + */ + + Tcl_DecrRefCount(contents); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclFileReadLinkCmd -- + * + * This function is invoked to process the "file readlink" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclFileReadLinkCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *contents; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "name"); + return TCL_ERROR; + } + + if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { + return TCL_ERROR; + } + + contents = Tcl_FSLink(objv[1], NULL, 0); + + if (contents == NULL) { + Tcl_AppendResult(interp, "could not readlink \"", + TclGetString(objv[1]), "\": ", Tcl_PosixError(interp), NULL); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, contents); + Tcl_DecrRefCount(contents); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * TclFileTemporaryCmd + * + * This function implements the "tempfile" subcommand of the "file" + * command. + * + * Results: + * Returns a standard Tcl result. + * + * Side effects: + * Creates a temporary file. Opens a channel to that file and puts the + * name of that channel in the result. *Might* register suitable exit + * handlers to ensure that the temporary file gets deleted. Might write + * to a variable, so reentrancy is a potential issue. + * + *--------------------------------------------------------------------------- + */ + +int +TclFileTemporaryCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *nameVarObj = NULL; /* Variable to store the name of the temporary + * file in. */ + Tcl_Obj *nameObj = NULL; /* Object that will contain the filename. */ + Tcl_Channel chan; /* The channel opened (RDWR) on the temporary + * file, or NULL if there's an error. */ + Tcl_Obj *tempDirObj = NULL, *tempBaseObj = NULL, *tempExtObj = NULL; + /* Pieces of template. Each piece is NULL if + * it is omitted. The platform temporary file + * engine might ignore some pieces. */ + + if (objc < 1 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "?nameVar? ?template?"); + return TCL_ERROR; + } + + if (objc > 1) { + nameVarObj = objv[1]; + TclNewObj(nameObj); + } + if (objc > 2) { + int length; + Tcl_Obj *templateObj = objv[2]; + const char *string = TclGetStringFromObj(templateObj, &length); + + /* + * Treat an empty string as if it wasn't there. + */ + + if (length == 0) { + goto makeTemporary; + } + + /* + * The template only gives a directory if there is a directory + * separator in it. + */ + + if (strchr(string, '/') != NULL + || (tclPlatform == TCL_PLATFORM_WINDOWS + && strchr(string, '\\') != NULL)) { + tempDirObj = TclPathPart(interp, templateObj, TCL_PATH_DIRNAME); + + /* + * Only allow creation of temporary files in the native filesystem + * since they are frequently used for integration with external + * tools or system libraries. [Bug 2388866] + */ + + if (tempDirObj != NULL && Tcl_FSGetFileSystemForPath(tempDirObj) + != &tclNativeFilesystem) { + TclDecrRefCount(tempDirObj); + tempDirObj = NULL; + } + } + + /* + * The template only gives the filename if the last character isn't a + * directory separator. + */ + + if (string[length-1] != '/' && (tclPlatform != TCL_PLATFORM_WINDOWS + || string[length-1] != '\\')) { + Tcl_Obj *tailObj = TclPathPart(interp, templateObj, + TCL_PATH_TAIL); + + if (tailObj != NULL) { + tempBaseObj = TclPathPart(interp, tailObj, TCL_PATH_ROOT); + tempExtObj = TclPathPart(interp, tailObj, TCL_PATH_EXTENSION); + TclDecrRefCount(tailObj); + } + } + } + + /* + * Convert empty parts of the template into unspecified parts. + */ + + if (tempDirObj && !TclGetString(tempDirObj)[0]) { + TclDecrRefCount(tempDirObj); + tempDirObj = NULL; + } + if (tempBaseObj && !TclGetString(tempBaseObj)[0]) { + TclDecrRefCount(tempBaseObj); + tempBaseObj = NULL; + } + if (tempExtObj && !TclGetString(tempExtObj)[0]) { + TclDecrRefCount(tempExtObj); + tempExtObj = NULL; + } + + /* + * Create and open the temporary file. + */ + + makeTemporary: + chan = TclpOpenTemporaryFile(tempDirObj,tempBaseObj,tempExtObj, nameObj); + + /* + * If we created pieces of template, get rid of them now. + */ + + if (tempDirObj) { + TclDecrRefCount(tempDirObj); + } + if (tempBaseObj) { + TclDecrRefCount(tempBaseObj); + } + if (tempExtObj) { + TclDecrRefCount(tempExtObj); + } + + /* + * Deal with results. + */ + + if (chan == NULL) { + if (nameVarObj) { + TclDecrRefCount(nameObj); + } + Tcl_AppendResult(interp, "can't create temporary file: ", + Tcl_PosixError(interp), NULL); + return TCL_ERROR; + } + Tcl_RegisterChannel(interp, chan); + if (nameVarObj != NULL) { + if (Tcl_ObjSetVar2(interp, nameVarObj, NULL, nameObj, + TCL_LEAVE_ERR_MSG) == NULL) { + Tcl_UnregisterChannel(interp, chan); + return TCL_ERROR; + } + } + Tcl_AppendResult(interp, Tcl_GetChannelName(chan), NULL); + return TCL_OK; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tclHash.c b/generic/tclHash.c index f53bbfe..d5ce21f 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.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: tclHash.c,v 1.46.2.1 2010/12/01 16:42:35 kennykb Exp $ + * RCS: @(#) $Id: tclHash.c,v 1.46.2.2 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -829,14 +829,14 @@ AllocStringEntry( { const char *string = (const char *) keyPtr; Tcl_HashEntry *hPtr; - unsigned int size; + unsigned int size, allocsize; - size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key); - if (size < sizeof(Tcl_HashEntry)) { - size = sizeof(Tcl_HashEntry); + allocsize = size = strlen(string) + 1; + if (size < sizeof(hPtr->key)) { + allocsize = sizeof(hPtr->key); } - hPtr = (Tcl_HashEntry *) ckalloc(size); - strcpy(hPtr->key.string, string); + hPtr = (Tcl_HashEntry *) ckalloc(TclOffset(Tcl_HashEntry, key) + allocsize); + memcpy(hPtr->key.string, string, size); hPtr->clientData = 0; return hPtr; } diff --git a/generic/tclIO.c b/generic/tclIO.c index 0ed57d0..0f490b3 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.175 2010/03/20 17:49:15 dkf Exp $ + * RCS: @(#) $Id: tclIO.c,v 1.175.2.1 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -8915,6 +8915,33 @@ Tcl_FileEventObjCmd( /* *---------------------------------------------------------------------- * + * ZeroTransferTimerProc -- + * + * Timer handler scheduled by TclCopyChannel so that -command is + * called asynchronously even when -size is 0. + * + * Results: + * None. + * + * Side effects: + * Calls CopyData for -command invocation. + * + *---------------------------------------------------------------------- + */ + +static void +ZeroTransferTimerProc( + ClientData clientData) +{ + /* calling CopyData with mask==0 still implies immediate invocation of the + * -command callback, and completion of the fcopy. + */ + CopyData(clientData, 0); +} + +/* + *---------------------------------------------------------------------- + * * TclCopyChannel -- * * This routine copies data from one channel to another, either @@ -9033,6 +9060,16 @@ TclCopyChannel( outStatePtr->csPtrW = csPtr; /* + * Special handling of -size 0 async transfers, so that the -command is + * still called asynchronously. + */ + + if ((nonBlocking == CHANNEL_NONBLOCKING) && (toRead == 0)) { + Tcl_CreateTimerHandler(0, ZeroTransferTimerProc, csPtr); + return 0; + } + + /* * Start copying data between the channels. */ diff --git a/generic/tclIO.h b/generic/tclIO.h index 5ff855f..ad57391 100644 --- a/generic/tclIO.h +++ b/generic/tclIO.h @@ -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.h,v 1.17 2010/03/20 15:39:46 dkf Exp $ + * RCS: @(#) $Id: tclIO.h,v 1.17.2.1 2010/12/11 18:39:29 kennykb Exp $ */ /* @@ -65,13 +65,13 @@ typedef struct ChannelBuffer { int bufLength; /* How big is the buffer? */ struct ChannelBuffer *nextPtr; /* Next buffer in chain. */ - char buf[4]; /* Placeholder for real buffer. The real - * buffer occuppies this space + bufSize-4 + char buf[1]; /* Placeholder for real buffer. The real + * buffer occuppies this space + bufSize-1 * bytes. This must be the last field in the * structure. */ } ChannelBuffer; -#define CHANNELBUFFER_HEADER_SIZE (sizeof(ChannelBuffer) - 4) +#define CHANNELBUFFER_HEADER_SIZE TclOffset(ChannelBuffer, buf) /* * How much extra space to allocate in buffer to hold bytes from previous diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c index 696b3ac..fe7fc36 100644 --- a/generic/tclIOCmd.c +++ b/generic/tclIOCmd.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: tclIOCmd.c,v 1.69 2010/08/22 18:53:26 nijtmans Exp $ + * RCS: @(#) $Id: tclIOCmd.c,v 1.69.2.1 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -1898,6 +1898,39 @@ ChanPipeObjCmd( /* *---------------------------------------------------------------------- * + * TclChannelNamesCmd -- + * + * This function is invoked to process the "chan names" and "file + * channels" Tcl commands. See the user documentation for details on + * what they do. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclChannelNamesCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc < 1 || objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); + return TCL_ERROR; + } + return Tcl_GetChannelNamesEx(interp, + ((objc == 1) ? NULL : TclGetString(objv[1]))); +} + +/* + *---------------------------------------------------------------------- + * * TclInitChanCmd -- * * This function is invoked to create the "chan" Tcl command. See the @@ -1924,29 +1957,29 @@ TclInitChanCmd( * function at the moment. */ static const EnsembleImplMap initMap[] = { - {"blocked", Tcl_FblockedObjCmd, NULL, NULL, NULL}, - {"close", Tcl_CloseObjCmd, NULL, NULL, NULL}, - {"copy", Tcl_FcopyObjCmd, NULL, NULL, NULL}, - {"create", TclChanCreateObjCmd, NULL, NULL, NULL}, /* TIP #219 */ - {"eof", Tcl_EofObjCmd, NULL, NULL, NULL}, - {"event", Tcl_FileEventObjCmd, NULL, NULL, NULL}, - {"flush", Tcl_FlushObjCmd, NULL, NULL, NULL}, - {"gets", Tcl_GetsObjCmd, NULL, NULL, NULL}, - {"pending", ChanPendingObjCmd, NULL, NULL, NULL}, /* TIP #287 */ - {"pop", TclChanPopObjCmd, NULL, NULL, NULL}, /* TIP #230 */ - {"postevent", TclChanPostEventObjCmd, NULL, NULL, NULL}, /* TIP #219 */ - {"push", TclChanPushObjCmd, NULL, NULL, NULL}, /* TIP #230 */ - {"puts", Tcl_PutsObjCmd, NULL, NULL, NULL}, - {"read", Tcl_ReadObjCmd, NULL, NULL, NULL}, - {"seek", Tcl_SeekObjCmd, NULL, NULL, NULL}, - {"pipe", ChanPipeObjCmd, NULL, NULL, NULL}, /* TIP #304 */ - {"tell", Tcl_TellObjCmd, NULL, NULL, NULL}, - {"truncate", ChanTruncateObjCmd, NULL, NULL, NULL}, /* TIP #208 */ - {NULL, NULL, NULL, NULL, NULL} + {"blocked", Tcl_FblockedObjCmd, NULL, NULL, NULL, 0}, + {"close", Tcl_CloseObjCmd, NULL, NULL, NULL, 0}, + {"copy", Tcl_FcopyObjCmd, NULL, NULL, NULL, 0}, + {"create", TclChanCreateObjCmd, NULL, NULL, NULL, 0}, /* TIP #219 */ + {"eof", Tcl_EofObjCmd, NULL, NULL, NULL, 0}, + {"event", Tcl_FileEventObjCmd, NULL, NULL, NULL, 0}, + {"flush", Tcl_FlushObjCmd, NULL, NULL, NULL, 0}, + {"gets", Tcl_GetsObjCmd, NULL, NULL, NULL, 0}, + {"names", TclChannelNamesCmd, NULL, NULL, NULL, 0}, + {"pending", ChanPendingObjCmd, NULL, NULL, NULL, 0}, /* TIP #287 */ + {"pop", TclChanPopObjCmd, NULL, NULL, NULL, 0}, /* TIP #230 */ + {"postevent", TclChanPostEventObjCmd, NULL, NULL, NULL, 0}, /* TIP #219 */ + {"push", TclChanPushObjCmd, NULL, NULL, NULL, 0}, /* TIP #230 */ + {"puts", Tcl_PutsObjCmd, NULL, NULL, NULL, 0}, + {"read", Tcl_ReadObjCmd, NULL, NULL, NULL, 0}, + {"seek", Tcl_SeekObjCmd, NULL, NULL, NULL, 0}, + {"pipe", ChanPipeObjCmd, NULL, NULL, NULL, 0}, /* TIP #304 */ + {"tell", Tcl_TellObjCmd, NULL, NULL, NULL, 0}, + {"truncate", ChanTruncateObjCmd, NULL, NULL, NULL, 0}, /* TIP #208 */ + {NULL, NULL, NULL, NULL, NULL, 0} }; static const char *const extras[] = { "configure", "::fconfigure", - "names", "::file channels", NULL }; Tcl_Command ensemble; diff --git a/generic/tclIOSock.c b/generic/tclIOSock.c index c34a6bf..a8b2674 100644 --- a/generic/tclIOSock.c +++ b/generic/tclIOSock.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: tclIOSock.c,v 1.11.10.3 2010/10/28 19:42:20 kennykb Exp $ + * RCS: @(#) $Id: tclIOSock.c,v 1.11.10.4 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -89,25 +89,30 @@ TclSockGetPort( *---------------------------------------------------------------------- */ +#ifdef _WIN32 +# define PTR2SOCK(a) (SOCKET)a +#else +# define PTR2SOCK(a) PTR2INT(a) +#endif int TclSockMinimumBuffers( - int sock, /* Socket file descriptor */ + ClientData sock, /* Socket file descriptor */ int size) /* Minimum buffer size */ { int current; socklen_t len; len = sizeof(int); - getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)¤t, &len); + getsockopt(PTR2SOCK(sock), SOL_SOCKET, SO_SNDBUF, (char *)¤t, &len); if (current < size) { len = sizeof(int); - setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, len); + setsockopt(PTR2SOCK(sock), SOL_SOCKET, SO_SNDBUF, (char *)&size, len); } len = sizeof(int); - getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)¤t, &len); + getsockopt(PTR2SOCK(sock), SOL_SOCKET, SO_RCVBUF, (char *)¤t, &len); if (current < size) { len = sizeof(int); - setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, len); + setsockopt(PTR2SOCK(sock), SOL_SOCKET, SO_RCVBUF, (char *)&size, len); } return TCL_OK; } diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 9eef11a..dd66ec6 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.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: tclIndexObj.c,v 1.59 2010/03/30 13:17:18 nijtmans Exp $ + * RCS: @(#) $Id: tclIndexObj.c,v 1.59.2.1 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -529,10 +529,10 @@ TclInitPrefixCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap prefixImplMap[] = { - {"all", PrefixAllObjCmd, NULL, NULL, NULL}, - {"longest", PrefixLongestObjCmd, NULL, NULL, NULL}, - {"match", PrefixMatchObjCmd, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL} + {"all", PrefixAllObjCmd, NULL, NULL, NULL, 0}, + {"longest", PrefixLongestObjCmd, NULL, NULL, NULL, 0}, + {"match", PrefixMatchObjCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; Tcl_Command prefixCmd; diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 2b2274d..ac246f0 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -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: tclInt.decls,v 1.148.2.3 2010/12/01 16:42:35 kennykb Exp $ +# RCS: @(#) $Id: tclInt.decls,v 1.148.2.4 2010/12/11 18:39:29 kennykb Exp $ library tcl @@ -423,7 +423,7 @@ declare 103 { int *portPtr) } declare 104 { - int TclSockMinimumBuffers(int sock, int size) + int TclSockMinimumBuffers(ClientData sock, int size) } # Replaced by Tcl_FSStat in 8.4: #declare 105 { @@ -1023,7 +1023,7 @@ declare 2 win { const char *proto) } declare 3 win { - int TclWinGetSockOpt(int s, int level, int optname, + int TclWinGetSockOpt(SOCKET s, int level, int optname, char FAR *optval, int FAR *optlen) } declare 4 win { @@ -1037,7 +1037,7 @@ declare 6 win { u_short TclWinNToHS(u_short ns) } declare 7 win { - int TclWinSetSockOpt(int s, int level, int optname, + int TclWinSetSockOpt(SOCKET s, int level, int optname, const char FAR *optval, int optlen) } declare 8 win { diff --git a/generic/tclInt.h b/generic/tclInt.h index dbabccf..ea8f948 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -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: tclInt.h,v 1.482.2.5 2010/12/01 16:42:36 kennykb Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.482.2.6 2010/12/11 18:39:29 kennykb Exp $ */ #ifndef _TCLINT @@ -954,7 +954,7 @@ typedef struct CompiledLocal { * is marked by a unique ClientData tag during * compilation, and that same tag is used to * find the variable at runtime. */ - char name[4]; /* Name of the local variable starts here. If + char name[1]; /* Name of the local variable starts here. If * the name is NULL, this will just be '\0'. * The actual size of this field will be large * enough to hold the name. MUST BE THE LAST @@ -1601,6 +1601,8 @@ typedef struct { CompileProc *compileProc; /* The compiler for the subcommand. */ Tcl_ObjCmdProc *nreProc; /* NRE implementation of this command. */ ClientData clientData; /* Any clientData to give the command. */ + int unsafe; /* Whether this command is to be hidden by + * default in a safe interpreter. */ } EnsembleImplMap; /* @@ -2858,6 +2860,7 @@ MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp, const char *value); MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp, Tcl_Channel chan); +MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd; MODULE_SCOPE int TclClearRootEnsemble(ClientData data[], Tcl_Interp *interp, int result); MODULE_SCOPE void TclCleanupLiteralTable(Tcl_Interp *interp, @@ -2874,16 +2877,14 @@ MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags, int line, int *clNextOuter, const char *outerScript); -MODULE_SCOPE int TclFileAttrsCmd(Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclFileCopyCmd(Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclFileDeleteCmd(Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclFileMakeDirsCmd(Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int TclFileRenameCmd(Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); +MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileLinkCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileMakeDirsCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, @@ -3234,9 +3235,8 @@ MODULE_SCOPE int Tcl_FconfigureObjCmd( MODULE_SCOPE int Tcl_FcopyObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -MODULE_SCOPE int Tcl_FileObjCmd(ClientData dummy, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); +MODULE_SCOPE Tcl_Command TclInitFileCmd(Tcl_Interp *interp); +MODULE_SCOPE int TclMakeFileCommandSafe(Tcl_Interp *interp); MODULE_SCOPE int Tcl_FileEventObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index ba82f75..8be8577 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -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: tclIntDecls.h,v 1.142.2.3 2010/12/01 16:42:36 kennykb Exp $ + * RCS: @(#) $Id: tclIntDecls.h,v 1.142.2.4 2010/12/11 18:39:29 kennykb Exp $ */ #ifndef _TCLINTDECLS @@ -265,7 +265,7 @@ EXTERN void TclSetupEnv(Tcl_Interp *interp); EXTERN int TclSockGetPort(Tcl_Interp *interp, const char *str, const char *proto, int *portPtr); /* 104 */ -EXTERN int TclSockMinimumBuffers(int sock, int size); +EXTERN int TclSockMinimumBuffers(ClientData sock, int size); /* Slot 105 is reserved */ /* Slot 106 is reserved */ /* Slot 107 is reserved */ @@ -709,7 +709,7 @@ typedef struct TclIntStubs { CONST86 char * (*tclSetPreInitScript) (const char *string); /* 101 */ void (*tclSetupEnv) (Tcl_Interp *interp); /* 102 */ int (*tclSockGetPort) (Tcl_Interp *interp, const char *str, const char *proto, int *portPtr); /* 103 */ - int (*tclSockMinimumBuffers) (int sock, int size); /* 104 */ + int (*tclSockMinimumBuffers) (ClientData sock, int size); /* 104 */ void (*reserved105)(void); void (*reserved106)(void); void (*reserved107)(void); diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index 95a6016..ceda11c 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -9,7 +9,7 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.44 2010/08/21 16:30:26 nijtmans Exp $ + * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.44.2.1 2010/12/11 18:39:29 kennykb Exp $ */ #ifndef _TCLINTPLATDECLS @@ -86,7 +86,7 @@ EXTERN void TclWinConvertWSAError(unsigned long errCode); EXTERN struct servent * TclWinGetServByName(const char *nm, const char *proto); /* 3 */ -EXTERN int TclWinGetSockOpt(int s, int level, int optname, +EXTERN int TclWinGetSockOpt(SOCKET s, int level, int optname, char FAR *optval, int FAR *optlen); /* 4 */ EXTERN HINSTANCE TclWinGetTclInstance(void); @@ -94,7 +94,7 @@ EXTERN HINSTANCE TclWinGetTclInstance(void); /* 6 */ EXTERN u_short TclWinNToHS(u_short ns); /* 7 */ -EXTERN int TclWinSetSockOpt(int s, int level, int optname, +EXTERN int TclWinSetSockOpt(SOCKET s, int level, int optname, const char FAR *optval, int optlen); /* 8 */ EXTERN unsigned long TclpGetPid(Tcl_Pid pid); @@ -227,11 +227,11 @@ typedef struct TclIntPlatStubs { void (*tclWinConvertError) (unsigned long errCode); /* 0 */ void (*tclWinConvertWSAError) (unsigned long errCode); /* 1 */ struct servent * (*tclWinGetServByName) (const char *nm, const char *proto); /* 2 */ - int (*tclWinGetSockOpt) (int s, int level, int optname, char FAR *optval, int FAR *optlen); /* 3 */ + int (*tclWinGetSockOpt) (SOCKET s, int level, int optname, char FAR *optval, int FAR *optlen); /* 3 */ HINSTANCE (*tclWinGetTclInstance) (void); /* 4 */ void (*reserved5)(void); u_short (*tclWinNToHS) (u_short ns); /* 6 */ - int (*tclWinSetSockOpt) (int s, int level, int optname, const char FAR *optval, int optlen); /* 7 */ + int (*tclWinSetSockOpt) (SOCKET s, int level, int optname, const char FAR *optval, int optlen); /* 7 */ unsigned long (*tclpGetPid) (Tcl_Pid pid); /* 8 */ int (*tclWinGetPlatformId) (void); /* 9 */ void (*reserved10)(void); diff --git a/generic/tclProc.c b/generic/tclProc.c index d0c1ca3..92e4169 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.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: tclProc.c,v 1.181.2.1 2010/09/27 20:33:37 kennykb Exp $ + * RCS: @(#) $Id: tclProc.c,v 1.181.2.2 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -622,8 +622,7 @@ TclCreateProc( */ localPtr = (CompiledLocal *) ckalloc((unsigned) - (sizeof(CompiledLocal) - sizeof(localPtr->name) - + nameLength + 1)); + (TclOffset(CompiledLocal, name) + nameLength + 1)); if (procPtr->firstLocalPtr == NULL) { procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr; } else { @@ -643,7 +642,7 @@ TclCreateProc( } else { localPtr->defValuePtr = NULL; } - strcpy(localPtr->name, fieldValues[0]); + memcpy(localPtr->name, fieldValues[0], nameLength + 1); if ((i == numArgs - 1) && (localPtr->nameLength == 4) && (localPtr->name[0] == 'a') diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c index 8544351..76895df 100755 --- a/generic/tclStrToD.c +++ b/generic/tclStrToD.c @@ -1,6 +1,4 @@ /* - *---------------------------------------------------------------------- - * * tclStrToD.c -- * * This file contains a collection of procedures for managing conversions @@ -14,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: tclStrToD.c,v 1.46.2.1 2010/12/01 16:42:36 kennykb Exp $ + * RCS: @(#) $Id: tclStrToD.c,v 1.46.2.2 2010/12/11 18:39:29 kennykb Exp $ * *---------------------------------------------------------------------- */ @@ -41,6 +39,11 @@ #endif /* + * Rounding controls. (Thanks a lot, Intel!) + */ + +#ifdef __i386 +/* * gcc on x86 needs access to rounding controls, because of a questionable * feature where it retains intermediate results as IEEE 'long double' values * somewhat unpredictably. It is tempting to include fpu_control.h, but that @@ -48,41 +51,65 @@ * and ix86-isms are factored out here. */ -#if defined(__GNUC__) && defined(__i386) -typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); -#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw)) -#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw)) +#if defined(__GNUC__) +typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); + +#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw)) +#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw)) # define FPU_IEEE_ROUNDING 0x027f # define ADJUST_FPU_CONTROL_WORD -#endif +#define TCL_IEEE_DOUBLE_ROUNDING \ + fpu_control_t roundTo53Bits = FPU_IEEE_ROUNDING; \ + fpu_control_t oldRoundingMode; \ + _FPU_GETCW(oldRoundingMode); \ + _FPU_SETCW(roundTo53Bits) +#define TCL_DEFAULT_DOUBLE_ROUNDING \ + _FPU_SETCW(oldRoundingMode) -/* Sun ProC needs sunmath for rounding control on x86 like gcc above. - * - * +/* + * Sun ProC needs sunmath for rounding control on x86 like gcc above. */ -#if defined(__sun) && defined(__i386) && !defined(__GNUC__) +#elif defined(__sun) #include <sunmath.h> +#define TCL_IEEE_DOUBLE_ROUNDING \ + ieee_flags("set","precision","double",NULL) +#define TCL_DEFAULT_DOUBLE_ROUNDING \ + ieee_flags("clear","precision",NULL,NULL) + +/* + * Other platforms are assumed to always operate in full IEEE mode, so we make + * the macros to go in and out of that mode do nothing. + */ + +#else /* !__GNUC__ && !__sun */ +#define TCL_IEEE_DOUBLE_ROUNDING ((void) 0) +#define TCL_DEFAULT_DOUBLE_ROUNDING ((void) 0) +#endif +#else /* !__i386 */ +#define TCL_IEEE_DOUBLE_ROUNDING ((void) 0) +#define TCL_DEFAULT_DOUBLE_ROUNDING ((void) 0) #endif /* - * MIPS floating-point units need special settings in control registers - * to use gradual underflow as we expect. This fix is for the MIPSpro - * compiler. + * MIPS floating-point units need special settings in control registers to use + * gradual underflow as we expect. This fix is for the MIPSpro compiler. */ + #if defined(__sgi) && defined(_COMPILER_VERSION) #include <sys/fpu.h> #endif + /* * HP's PA_RISC architecture uses 7ff4000000000000 to represent a quiet NaN. * Everyone else uses 7ff8000000000000. (Why, HP, why?) */ #ifdef __hppa -# define NAN_START 0x7ff4 -# define NAN_MASK (((Tcl_WideUInt) 1) << 50) +# define NAN_START 0x7ff4 +# define NAN_MASK (((Tcl_WideUInt) 1) << 50) #else -# define NAN_START 0x7ff8 -# define NAN_MASK (((Tcl_WideUInt) 1) << 51) +# define NAN_START 0x7ff8 +# define NAN_MASK (((Tcl_WideUInt) 1) << 51) #endif /* @@ -96,45 +123,44 @@ typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); #define TWO_OVER_3LOG10 0.28952965460216784 #define LOG10_3HALVES_PLUS_FUDGE 0.1760912590558 -/* Definitions of the parts of an IEEE754-format floating point number */ - -#define SIGN_BIT 0x80000000 - /* Mask for the sign bit in the first - * word of a double */ -#define EXP_MASK 0x7ff00000 - /* Mask for the exponent field in the - * first word of a double */ -#define EXP_SHIFT 20 - /* Shift count to make the exponent an - * integer */ -#define HIDDEN_BIT (((Tcl_WideUInt) 0x00100000) << 32) - /* Hidden 1 bit for the significand */ -#define HI_ORDER_SIG_MASK 0x000fffff +/* + * Definitions of the parts of an IEEE754-format floating point number. + */ + +#define SIGN_BIT 0x80000000 + /* Mask for the sign bit in the first word of + * a double. */ +#define EXP_MASK 0x7ff00000 + /* Mask for the exponent field in the first + * word of a double. */ +#define EXP_SHIFT 20 /* Shift count to make the exponent an + * integer. */ +#define HIDDEN_BIT (((Tcl_WideUInt) 0x00100000) << 32) + /* Hidden 1 bit for the significand. */ +#define HI_ORDER_SIG_MASK 0x000fffff /* Mask for the high-order part of the * significand in the first word of a - * double */ -#define SIG_MASK (((Tcl_WideUInt) HI_ORDER_SIG_MASK << 32) \ - | 0xffffffff) + * double. */ +#define SIG_MASK (((Tcl_WideUInt) HI_ORDER_SIG_MASK << 32) \ + | 0xffffffff) /* Mask for the 52-bit significand. */ -#define FP_PRECISION 53 - /* Number of bits of significand plus the - * hidden bit */ -#define EXPONENT_BIAS 0x3ff - /* Bias of the exponent 0 */ - -/* Derived quantities */ - -#define TEN_PMAX 22 - /* floor(FP_PRECISION*log(2)/log(5)) */ -#define QUICK_MAX 14 - /* floor((FP_PRECISION-1)*log(2)/log(10)) - 1 */ -#define BLETCH 0x10 - /* Highest power of two that is greater than - * DBL_MAX_10_EXP, divided by 16 */ -#define DIGIT_GROUP 8 - /* floor(DIGIT_BIT*log(2)/log(10)) */ - -/* Union used to dismantle floating point numbers. */ +#define FP_PRECISION 53 /* Number of bits of significand plus the + * hidden bit. */ +#define EXPONENT_BIAS 0x3ff /* Bias of the exponent 0. */ + +/* + * Derived quantities. + */ + +#define TEN_PMAX 22 /* floor(FP_PRECISION*log(2)/log(5)) */ +#define QUICK_MAX 14 /* floor((FP_PRECISION-1)*log(2)/log(10))-1 */ +#define BLETCH 0x10 /* Highest power of two that is greater than + * DBL_MAX_10_EXP, divided by 16. */ +#define DIGIT_GROUP 8 /* floor(DIGIT_BIT*log(2)/log(10)) */ + +/* + * Union used to dismantle floating point numbers. + */ typedef union Double { struct { @@ -165,7 +191,7 @@ static int log2FLT_RADIX; /* Logarithm of the floating point radix. */ static int mantBits; /* Number of bits in a double's significand */ static mp_int pow5[9]; /* Table of powers of 5**(2**n), up to * 5**256 */ -static double tiny = 0.0; /* The smallest representable double */ +static double tiny = 0.0; /* The smallest representable double. */ static int maxDigits; /* The maximum number of digits to the left of * the decimal point of a double. */ static int minDigits; /* The maximum number of digits to the right @@ -189,10 +215,12 @@ static int n770_fp; /* Flag is 1 on Nokia N770 floating point. * reversed: if big-endian is 7654 3210, * and little-endian is 0123 4567, * then Nokia's FP is 4567 0123; - * little-endian within the 32-bit words - * but big-endian between them. */ + * little-endian within the 32-bit words but + * big-endian between them. */ -/* Table of powers of 5 that are small enough to fit in an mp_digit. */ +/* + * Table of powers of 5 that are small enough to fit in an mp_digit. + */ static const mp_digit dpow5[13] = { 1, 5, 25, 125, @@ -201,7 +229,10 @@ static const mp_digit dpow5[13] = { 244140625 }; -/* Table of powers: pow5_13[n] = 5**(13*2**(n+1)) */ +/* + * Table of powers: pow5_13[n] = 5**(13*2**(n+1)) + */ + static mp_int pow5_13[5]; /* Table of powers: 5**13, 5**26, 5**52, * 5**104, 5**208 */ static const double tens[] = { @@ -229,7 +260,6 @@ static const Tcl_WideUInt wtens[] = { (Tcl_WideUInt) 1000000*100000, (Tcl_WideUInt) 1000000*1000000, (Tcl_WideUInt) 1000000*1000000*10, (Tcl_WideUInt) 1000000*1000000*100, (Tcl_WideUInt) 1000000*1000000*1000,(Tcl_WideUInt) 1000000*1000000*10000 - }; static const double bigtens[] = { @@ -278,75 +308,81 @@ static const Tcl_WideUInt wuipow5[27] = { * Static functions defined in this file. */ -static int AccumulateDecimalDigit(unsigned, int, +static int AccumulateDecimalDigit(unsigned, int, Tcl_WideUInt *, mp_int *, int); static double MakeHighPrecisionDouble(int signum, mp_int *significand, int nSigDigs, int exponent); static double MakeLowPrecisionDouble(int signum, Tcl_WideUInt significand, int nSigDigs, int exponent); +#ifdef IEEE_FLOATING_POINT static double MakeNaN(int signum, Tcl_WideUInt tag); +#endif static double RefineApproximation(double approx, mp_int *exactSignificand, int exponent); -static void MulPow5(mp_int*, unsigned, mp_int*); -static int NormalizeRightward(Tcl_WideUInt*); +static void MulPow5(mp_int *, unsigned, mp_int *); +static int NormalizeRightward(Tcl_WideUInt *); static int RequiredPrecision(Tcl_WideUInt); -static void DoubleToExpAndSig(double, Tcl_WideUInt*, int*, int*); -static void TakeAbsoluteValue(Double*, int*); -static char* FormatInfAndNaN(Double*, int*, char**); -static char* FormatZero(int*, char**); +static void DoubleToExpAndSig(double, Tcl_WideUInt *, int *, + int *); +static void TakeAbsoluteValue(Double *, int *); +static char * FormatInfAndNaN(Double *, int *, char **); +static char * FormatZero(int *, char **); static int ApproximateLog10(Tcl_WideUInt, int, int); -static int BetterLog10(double, int, int*); -static void ComputeScale(int, int, int*, int*, int*, int*); -static void SetPrecisionLimits(int, int, int*, int*, int*, int*); -static char* BumpUp(char*, char*, int*); -static int AdjustRange(double*, int); -static char* ShorteningQuickFormat(double, int, int, double, - char*, int*); -static char* StrictQuickFormat(double, int, int, double, - char*, int*); -static char* QuickConversion(double, int, int, int, int, int, int, - int*, char**); -static void CastOutPowersOf2(int*, int*, int*); -static char* ShorteningInt64Conversion(Double*, int, Tcl_WideUInt, +static int BetterLog10(double, int, int *); +static void ComputeScale(int, int, int *, int *, int *, int *); +static void SetPrecisionLimits(int, int, int *, int *, int *, + int *); +static char * BumpUp(char *, char *, int *); +static int AdjustRange(double *, int); +static char * ShorteningQuickFormat(double, int, int, double, + char *, int *); +static char * StrictQuickFormat(double, int, int, double, + char *, int *); +static char * QuickConversion(double, int, int, int, int, int, int, + int *, char **); +static void CastOutPowersOf2(int *, int *, int *); +static char * ShorteningInt64Conversion(Double *, int, Tcl_WideUInt, int, int, int, int, int, int, int, int, int, - int, int, int*, char**); -static char* StrictInt64Conversion(Double*, int, Tcl_WideUInt, + int, int, int *, char **); +static char * StrictInt64Conversion(Double *, int, Tcl_WideUInt, int, int, int, int, int, int, - int, int, int*, char**); -static int ShouldBankerRoundUpPowD(mp_int*, int, int); -static int ShouldBankerRoundUpToNextPowD(mp_int*, mp_int*, - int, int, int, mp_int*); -static char* ShorteningBignumConversionPowD(Double* dPtr, + int, int, int *, char **); +static int ShouldBankerRoundUpPowD(mp_int *, int, int); +static int ShouldBankerRoundUpToNextPowD(mp_int *, mp_int *, + int, int, int, mp_int *); +static char * ShorteningBignumConversionPowD(Double *dPtr, int convType, Tcl_WideUInt bw, int b2, int b5, int m2plus, int m2minus, int m5, - int sd, int k, int len, - int ilim, int ilim1, int* decpt, - char** endPtr); -static char* StrictBignumConversionPowD(Double* dPtr, int convType, + int sd, int k, int len, + int ilim, int ilim1, int *decpt, + char **endPtr); +static char * StrictBignumConversionPowD(Double *dPtr, int convType, Tcl_WideUInt bw, int b2, int b5, - int sd, int k, int len, - int ilim, int ilim1, int* decpt, - char** endPtr); -static int ShouldBankerRoundUp(mp_int*, mp_int*, int); -static int ShouldBankerRoundUpToNext(mp_int*, mp_int*, mp_int*, - int, int, mp_int*); -static char* ShorteningBignumConversion(Double* dPtr, int convType, + int sd, int k, int len, + int ilim, int ilim1, int *decpt, + char **endPtr); +static int ShouldBankerRoundUp(mp_int *, mp_int *, int); +static int ShouldBankerRoundUpToNext(mp_int *, mp_int *, + mp_int *, int, int, mp_int *); +static char * ShorteningBignumConversion(Double *dPtr, int convType, Tcl_WideUInt bw, int b2, int m2plus, int m2minus, - int s2, int s5, int k, int len, - int ilim, int ilim1, int* decpt, - char** endPtr); -static char* StrictBignumConversion(Double* dPtr, int convType, + int s2, int s5, int k, int len, + int ilim, int ilim1, int *decpt, + char **endPtr); +static char * StrictBignumConversion(Double *dPtr, int convType, Tcl_WideUInt bw, int b2, - int s2, int s5, int k, int len, - int ilim, int ilim1, int* decpt, - char** endPtr); + int s2, int s5, int k, int len, + int ilim, int ilim1, int *decpt, + char **endPtr); static double BignumToBiasedFrExp(const mp_int *big, int *machexp); static double Pow10TimesFrExp(int exponent, double fraction, int *machexp); static double SafeLdExp(double fraction, int exponent); +#ifdef IEEE_FLOATING_POINT static Tcl_WideUInt Nokia770Twiddle(Tcl_WideUInt w); +#endif /* *---------------------------------------------------------------------- @@ -476,38 +512,38 @@ TclParseNumber( } state = INITIAL; enum State acceptState = INITIAL; - int signum = 0; /* Sign of the number being parsed */ + int signum = 0; /* Sign of the number being parsed. */ Tcl_WideUInt significandWide = 0; /* Significand of the number being parsed (if - * no overflow) */ + * no overflow). */ mp_int significandBig; /* Significand of the number being parsed (if - * it overflows significandWide) */ - int significandOverflow = 0;/* Flag==1 iff significandBig is used */ + * it overflows significandWide). */ + int significandOverflow = 0;/* Flag==1 iff significandBig is used. */ Tcl_WideUInt octalSignificandWide = 0; /* Significand of an octal number; needed * because we don't know whether a number with * a leading zero is octal or decimal until - * we've scanned forward to a '.' or 'e' */ + * we've scanned forward to a '.' or 'e'. */ mp_int octalSignificandBig; /* Significand of octal number once - * octalSignificandWide overflows */ + * octalSignificandWide overflows. */ int octalSignificandOverflow = 0; - /* Flag==1 if octalSignificandBig is used */ + /* Flag==1 if octalSignificandBig is used. */ int numSigDigs = 0; /* Number of significant digits in the decimal - * significand */ + * significand. */ int numTrailZeros = 0; /* Number of trailing zeroes at the current * point in the parse. */ int numDigitsAfterDp = 0; /* Number of digits scanned after the decimal - * point */ + * point. */ int exponentSignum = 0; /* Signum of the exponent of a floating point - * number */ - long exponent = 0; /* Exponent of a floating point number */ - const char *p; /* Pointer to next character to scan */ - size_t len; /* Number of characters remaining after p */ + * number. */ + long exponent = 0; /* Exponent of a floating point number. */ + const char *p; /* Pointer to next character to scan. */ + size_t len; /* Number of characters remaining after p. */ const char *acceptPoint; /* Pointer to position after last character in - * an acceptable number */ + * an acceptable number. */ size_t acceptLen; /* Number of characters following that * point. */ - int status = TCL_OK; /* Status to return to caller */ + int status = TCL_OK; /* Status to return to caller. */ char d = 0; /* Last hexadecimal digit scanned; initialized * to avoid a compiler warning. */ int shift = 0; /* Amount to shift when accumulating binary */ @@ -597,9 +633,9 @@ TclParseNumber( case ZERO: /* * Scanned a leading zero (perhaps with a + or -). Acceptable - * inputs are digits, period, X, b, and E. If 8 or 9 is encountered, - * the number can't be octal. This state and the OCTAL state - * differ only in whether they recognize 'X' and 'b'. + * inputs are digits, period, X, b, and E. If 8 or 9 is + * encountered, the number can't be octal. This state and the + * OCTAL state differ only in whether they recognize 'X' and 'b'. */ acceptState = state; @@ -1193,7 +1229,7 @@ TclParseNumber( case OCTAL: /* - * Returning an octal integer. Final scaling step + * Returning an octal integer. Final scaling step. */ shift = 3 * numTrailZeros; @@ -1254,7 +1290,7 @@ TclParseNumber( case DECIMAL: significandOverflow = AccumulateDecimalDigit(0, numTrailZeros-1, &significandWide, &significandBig, significandOverflow); - if (!significandOverflow && (significandWide > MOST_BITS+signum)) { + if (!significandOverflow && (significandWide > MOST_BITS+signum)){ significandOverflow = 1; TclBNInitBignumFromWideUInt(&significandBig, significandWide); } @@ -1310,16 +1346,16 @@ TclParseNumber( objPtr->typePtr = &tclDoubleType; if (exponentSignum) { - exponent = - exponent; + exponent = -exponent; } if (!significandOverflow) { objPtr->internalRep.doubleValue = MakeLowPrecisionDouble( signum, significandWide, numSigDigs, - (numTrailZeros + exponent - numDigitsAfterDp)); + numTrailZeros + exponent - numDigitsAfterDp); } else { objPtr->internalRep.doubleValue = MakeHighPrecisionDouble( signum, &significandBig, numSigDigs, - (numTrailZeros + exponent - numDigitsAfterDp)); + numTrailZeros + exponent - numDigitsAfterDp); } break; @@ -1336,12 +1372,12 @@ TclParseNumber( #ifdef IEEE_FLOATING_POINT case sNAN: case sNANFINISH: - objPtr->internalRep.doubleValue = MakeNaN(signum, significandWide); + objPtr->internalRep.doubleValue = MakeNaN(signum,significandWide); objPtr->typePtr = &tclDoubleType; break; #endif case INITIAL: - /* This case only to silence compiler warning */ + /* This case only to silence compiler warning. */ Tcl_Panic("TclParseNumber: state INITIAL can't happen here"); } } @@ -1413,7 +1449,7 @@ AccumulateDecimalDigit( Tcl_WideUInt w; /* - * Try wide multiplication first + * Try wide multiplication first. */ if (!bignumFlag) { @@ -1426,10 +1462,10 @@ AccumulateDecimalDigit( *wideRepPtr = digit; return 0; } else if (numZeros >= maxpow10_wide - || w > ((~(Tcl_WideUInt)0)-digit)/pow10_wide[numZeros+1]) { + || w > ((~(Tcl_WideUInt)0)-digit)/pow10_wide[numZeros+1]) { /* - * Wide multiplication will overflow. Expand the - * number to a bignum and fall through into the bignum case. + * Wide multiplication will overflow. Expand the number to a + * bignum and fall through into the bignum case. */ TclBNInitBignumFromWideUInt(bignumRepPtr, w); @@ -1437,6 +1473,7 @@ AccumulateDecimalDigit( /* * Wide multiplication. */ + *wideRepPtr = w * pow10_wide[numZeros+1] + digit; return 0; } @@ -1504,12 +1541,12 @@ AccumulateDecimalDigit( static double MakeLowPrecisionDouble( int signum, /* 1 if the number is negative, 0 otherwise */ - Tcl_WideUInt significand, /* Significand of the number */ - int numSigDigs, /* Number of digits in the significand */ - int exponent) /* Power of ten */ + Tcl_WideUInt significand, /* Significand of the number. */ + int numSigDigs, /* Number of digits in the significand. */ + int exponent) /* Power of ten. */ { - double retval; /* Value of the number */ - mp_int significandBig; /* Significand expressed as a bignum */ + double retval; /* Value of the number. */ + mp_int significandBig; /* Significand expressed as a bignum. */ /* * With gcc on x86, the floating point rounding mode is double-extended. @@ -1519,15 +1556,7 @@ MakeLowPrecisionDouble( * ulp, so we need to change rounding mode to 53-bits. */ -#if defined(__GNUC__) && defined(__i386) - fpu_control_t roundTo53Bits = 0x027f; - fpu_control_t oldRoundingMode; - _FPU_GETCW(oldRoundingMode); - _FPU_SETCW(roundTo53Bits); -#endif -#if defined(__sun) && defined(__i386) && !defined(__GNUC__) - ieee_flags("set","precision","double",NULL); -#endif + TCL_IEEE_DOUBLE_ROUNDING; /* * Test for the easy cases. @@ -1542,10 +1571,12 @@ MakeLowPrecisionDouble( * without special handling. */ - retval = (double)(Tcl_WideInt)significand * pow10vals[exponent]; + retval = (double) + ((Tcl_WideInt)significand * pow10vals[exponent]); goto returnValue; } else { int diff = DBL_DIG - numSigDigs; + if (exponent-diff <= mmaxpow) { /* * 10**exponent is not an exact integer, but @@ -1554,8 +1585,8 @@ MakeLowPrecisionDouble( * with only one roundoff. */ - volatile double factor = - (double)(Tcl_WideInt)significand * pow10vals[diff]; + volatile double factor = (double) + ((Tcl_WideInt)significand * pow10vals[diff]); retval = factor * pow10vals[exponent-diff]; goto returnValue; } @@ -1568,7 +1599,8 @@ MakeLowPrecisionDouble( * only one rounding. */ - retval = (double)(Tcl_WideInt)significand / pow10vals[-exponent]; + retval = (double) + ((Tcl_WideInt)significand / pow10vals[-exponent]); goto returnValue; } } @@ -1597,12 +1629,7 @@ MakeLowPrecisionDouble( * On gcc on x86, restore the floating point mode word. */ -#if defined(__GNUC__) && defined(__i386) - _FPU_SETCW(oldRoundingMode); -#endif -#if defined(__sun) && defined(__i386) && !defined(__GNUC__) - ieee_flags("clear","precision",NULL,NULL); -#endif + TCL_DEFAULT_DOUBLE_ROUNDING; return retval; } @@ -1627,13 +1654,13 @@ MakeLowPrecisionDouble( static double MakeHighPrecisionDouble( - int signum, /* 1=negative, 0=nonnegative */ - mp_int *significand, /* Exact significand of the number */ - int numSigDigs, /* Number of significant digits */ - int exponent) /* Power of 10 by which to multiply */ + int signum, /* 1=negative, 0=nonnegative. */ + mp_int *significand, /* Exact significand of the number. */ + int numSigDigs, /* Number of significant digits. */ + int exponent) /* Power of 10 by which to multiply. */ { double retval; - int machexp; /* Machine exponent of a power of 10 */ + int machexp; /* Machine exponent of a power of 10. */ /* * With gcc on x86, the floating point rounding mode is double-extended. @@ -1643,15 +1670,7 @@ MakeHighPrecisionDouble( * ulp, so we need to change rounding mode to 53-bits. */ -#if defined(__GNUC__) && defined(__i386) - fpu_control_t roundTo53Bits = 0x027f; - fpu_control_t oldRoundingMode; - _FPU_GETCW(oldRoundingMode); - _FPU_SETCW(roundTo53Bits); -#endif -#if defined(__sun) && defined(__i386) && !defined(__GNUC__) - ieee_flags("set","precision","double",NULL); -#endif + TCL_IEEE_DOUBLE_ROUNDING; /* * Quick checks for over/underflow. @@ -1710,12 +1729,8 @@ MakeHighPrecisionDouble( * On gcc on x86, restore the floating point mode word. */ -#if defined(__GNUC__) && defined(__i386) - _FPU_SETCW(oldRoundingMode); -#endif -#if defined(__sun) && defined(__i386) && !defined(__GNUC__) - ieee_flags("clear","precision",NULL,NULL); -#endif + TCL_DEFAULT_DOUBLE_ROUNDING; + return retval; } @@ -1734,8 +1749,8 @@ MakeHighPrecisionDouble( #ifdef IEEE_FLOATING_POINT static double MakeNaN( - int signum, /* Sign bit (1=negative, 0=nonnegative */ - Tcl_WideUInt tags) /* Tag bits to put in the NaN */ + int signum, /* Sign bit (1=negative, 0=nonnegative. */ + Tcl_WideUInt tags) /* Tag bits to put in the NaN. */ { union { Tcl_WideUInt iv; @@ -1773,28 +1788,28 @@ MakeNaN( static double RefineApproximation( - double approxResult, /* Approximate result of conversion */ - mp_int *exactSignificand, /* Integer significand */ - int exponent) /* Power of 10 to multiply by significand */ + double approxResult, /* Approximate result of conversion. */ + mp_int *exactSignificand, /* Integer significand. */ + int exponent) /* Power of 10 to multiply by significand. */ { int M2, M5; /* Powers of 2 and of 5 needed to put the * decimal and binary numbers over a common * denominator. */ - double significand; /* Sigificand of the binary number */ - int binExponent; /* Exponent of the binary number */ + double significand; /* Sigificand of the binary number. */ + int binExponent; /* Exponent of the binary number. */ int msb; /* Most significant bit position of an - * intermediate result */ + * intermediate result. */ int nDigits; /* Number of mp_digit's in an intermediate - * result */ + * result. */ mp_int twoMv; /* Approx binary value expressed as an exact - * integer scaled by the multiplier 2M */ + * integer scaled by the multiplier 2M. */ mp_int twoMd; /* Exact decimal value expressed as an exact - * integer scaled by the multiplier 2M */ - int scale; /* Scale factor for M */ - int multiplier; /* Power of two to scale M */ + * integer scaled by the multiplier 2M. */ + int scale; /* Scale factor for M. */ + int multiplier; /* Power of two to scale M. */ double num, den; /* Numerator and denominator of the correction - * term */ - double quot; /* Correction term */ + * term. */ + double quot; /* Correction term. */ double minincr; /* Lower bound on the absolute value of the * correction term. */ int i; @@ -1824,8 +1839,8 @@ RefineApproximation( M5 = 0; } else { M5 = -exponent; - if ((M5-1) > M2) { - M2 = M5-1; + if (M5 - 1 > M2) { + M2 = M5 - 1; } } @@ -1864,7 +1879,7 @@ RefineApproximation( mp_init_copy(&twoMd, exactSignificand); for (i=0; i<=8; ++i) { - if ((M5+exponent) & (1 << i)) { + if ((M5 + exponent) & (1 << i)) { mp_mul(&twoMd, pow5+i, &twoMd); } } @@ -1874,7 +1889,7 @@ RefineApproximation( /* * The result, 2Mv-2Md, needs to be divided by 2M to yield a correction * term. Because 2M may well overflow a double, we need to scale the - * denominator by a factor of 2**binExponent-mantBits + * denominator by a factor of 2**binExponent-mantBits. */ scale = binExponent - mantBits - 1; @@ -1927,26 +1942,28 @@ RefineApproximation( } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * MultPow5 -- * * Multiply a bignum by a power of 5. * * Side effects: - * Stores base*5**n in result + * Stores base*5**n in result. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static void -MulPow5(mp_int* base, /* Number to multiply */ - unsigned n, /* Power of 5 to multiply by */ - mp_int* result) /* Place to store the result */ +MulPow5( + mp_int *base, /* Number to multiply. */ + unsigned n, /* Power of 5 to multiply by. */ + mp_int *result) /* Place to store the result. */ { - mp_int* p = base; + mp_int *p = base; int n13 = n / 13; int r = n % 13; + if (r != 0) { mp_mul_d(p, dpow5[r], result); p = result; @@ -1966,12 +1983,12 @@ MulPow5(mp_int* base, /* Number to multiply */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * NormalizeRightward -- * - * Shifts a number rightward until it is odd (that is, until the - * least significant bit is nonzero. + * Shifts a number rightward until it is odd (that is, until the least + * significant bit is nonzero. * * Results: * Returns the number of bit positions by which the number was shifted. @@ -1979,18 +1996,19 @@ MulPow5(mp_int* base, /* Number to multiply */ * Side effects: * Shifts the number in place; *wPtr is replaced by the shifted number. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -NormalizeRightward(Tcl_WideUInt* wPtr) - /* INOUT: Number to shift */ +NormalizeRightward( + Tcl_WideUInt *wPtr) /* INOUT: Number to shift. */ { int rv = 0; Tcl_WideUInt w = *wPtr; + if (!(w & (Tcl_WideUInt) 0xffffffff)) { w >>= 32; rv += 32; - } + } if (!(w & (Tcl_WideUInt) 0xffff)) { w >>= 16; rv += 16; } @@ -2011,25 +2029,26 @@ NormalizeRightward(Tcl_WideUInt* wPtr) } /* - *-----------------------------------------------------------------------------0 + *---------------------------------------------------------------------- * * RequiredPrecision -- * * Determines the number of bits needed to hold an intger. * * Results: - * Returns the position of the most significant bit (0 - 63). - * Returns 0 if the number is zero. + * Returns the position of the most significant bit (0 - 63). Returns 0 + * if the number is zero. * - *---------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ static int -RequiredPrecision(Tcl_WideUInt w) - /* Number to interrogate */ +RequiredPrecision( + Tcl_WideUInt w) /* Number to interrogate. */ { int rv; unsigned long wi; + if (w & ((Tcl_WideUInt) 0xffffffff << 32)) { wi = (unsigned long) (w >> 32); rv = 32; } else { @@ -2057,36 +2076,38 @@ RequiredPrecision(Tcl_WideUInt w) } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * DoubleToExpAndSig -- * * Separates a 'double' into exponent and significand. * * Side effects: - * Stores the significand in '*significand' and the exponent in - * '*expon' so that dv == significand * 2.0**expon, and significand - * is odd. Also stores the position of the leftmost 1-bit in 'significand' - * in 'bits'. + * Stores the significand in '*significand' and the exponent in '*expon' + * so that dv == significand * 2.0**expon, and significand is odd. Also + * stores the position of the leftmost 1-bit in 'significand' in 'bits'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static void -DoubleToExpAndSig(double dv, /* Number to convert */ - Tcl_WideUInt* significand, - /* OUTPUT: Significand of the number */ - int* expon, /* OUTPUT: Exponent to multiply the number by */ - int* bits) /* OUTPUT: Number of significant bits */ +DoubleToExpAndSig( + double dv, /* Number to convert. */ + Tcl_WideUInt *significand, /* OUTPUT: Significand of the number. */ + int *expon, /* OUTPUT: Exponent to multiply the number + * by. */ + int *bits) /* OUTPUT: Number of significant bits. */ { - Double d; /* Number being converted */ - Tcl_WideUInt z; /* Significand under construction */ - int de; /* Exponent of the number */ - int k; /* Bit count */ + Double d; /* Number being converted. */ + Tcl_WideUInt z; /* Significand under construction. */ + int de; /* Exponent of the number. */ + int k; /* Bit count. */ d.d = dv; - /* Extract exponent and significand */ + /* + * Extract exponent and significand. + */ de = (d.w.word0 & EXP_MASK) >> EXP_SHIFT; z = d.q & SIG_MASK; @@ -2104,22 +2125,23 @@ DoubleToExpAndSig(double dv, /* Number to convert */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TakeAbsoluteValue -- * * Takes the absolute value of a 'double' including 0, Inf and NaN * * Side effects: - * The 'double' in *d is replaced with its absolute value. The - * signum is stored in 'sign': 1 for negative, 0 for nonnegative. + * The 'double' in *d is replaced with its absolute value. The signum is + * stored in 'sign': 1 for negative, 0 for nonnegative. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ - + inline static void -TakeAbsoluteValue(Double* d, /* Number to replace with absolute value */ - int* sign) /* Place to put the signum */ +TakeAbsoluteValue( + Double *d, /* Number to replace with absolute value. */ + int *sign) /* Place to put the signum. */ { if (d->w.word0 & SIGN_BIT) { *sign = 1; @@ -2130,30 +2152,31 @@ TakeAbsoluteValue(Double* d, /* Number to replace with absolute value */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * FormatInfAndNaN -- * * Bailout for formatting infinities and Not-A-Number. * * Results: - * Returns one of the strings 'Infinity' and 'NaN'. + * Returns one of the strings 'Infinity' and 'NaN'. The string returned + * must be freed by the caller using 'ckfree'. * * Side effects: - * Stores 9999 in *decpt, and sets '*endPtr' to designate the - * terminating NUL byte of the string if 'endPtr' is not NULL. + * Stores 9999 in *decpt, and sets '*endPtr' to designate the terminating + * NUL byte of the string if 'endPtr' is not NULL. * - * The string returned must be freed by the caller using 'ckfree'. - * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -FormatInfAndNaN(Double* d, /* Exceptional number to format */ - int* decpt, /* Decimal point to set to a bogus value */ - char** endPtr) /* Pointer to the end of the formatted data */ +inline static char * +FormatInfAndNaN( + Double *d, /* Exceptional number to format. */ + int *decpt, /* Decimal point to set to a bogus value. */ + char **endPtr) /* Pointer to the end of the formatted data */ { - char* retval; + char *retval; + *decpt = 9999; if (!(d->w.word1) && !(d->w.word0 & HI_ORDER_SIG_MASK)) { retval = ckalloc(9); @@ -2172,7 +2195,7 @@ FormatInfAndNaN(Double* d, /* Exceptional number to format */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * FormatZero -- * @@ -2185,14 +2208,16 @@ FormatInfAndNaN(Double* d, /* Exceptional number to format */ * Stores 1 in '*decpt' and puts a pointer to the NUL byte terminating * the string in '*endPtr' if 'endPtr' is not NULL. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -FormatZero(int* decpt, /* Location of the decimal point */ - char** endPtr) /* Pointer to the end of the formatted data */ +inline static char * +FormatZero( + int *decpt, /* Location of the decimal point. */ + char **endPtr) /* Pointer to the end of the formatted data */ { - char* retval = ckalloc(2); + char *retval = ckalloc(2); + strcpy(retval, "0"); if (endPtr) { *endPtr = retval+1; @@ -2202,35 +2227,35 @@ FormatZero(int* decpt, /* Location of the decimal point */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ApproximateLog10 -- * - * Computes a two-term Taylor series approximation to the common - * log of a number, and computes the number's binary log. + * Computes a two-term Taylor series approximation to the common log of a + * number, and computes the number's binary log. * * Results: - * Return an approximation to floor(log10(bw*2**be)) that is either - * exact or 1 too high. + * Return an approximation to floor(log10(bw*2**be)) that is either exact + * or 1 too high. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -ApproximateLog10(Tcl_WideUInt bw, - /* Integer significand of the number */ - int be, /* Power of two to scale bw */ - int bbits) /* Number of bits of precision in bw */ +ApproximateLog10( + Tcl_WideUInt bw, /* Integer significand of the number. */ + int be, /* Power of two to scale bw. */ + int bbits) /* Number of bits of precision in bw. */ { - int i; /* Log base 2 of the number */ + int i; /* Log base 2 of the number. */ int k; /* Floor(Log base 10 of the number) */ - double ds; /* Mantissa of the number */ + double ds; /* Mantissa of the number. */ Double d2; /* * Compute i and d2 such that d = d2*2**i, and 1 < d2 < 2. - * Compute an approximation to log10(d), - * log10(d) ~ log10(2) * i + log10(1.5) + * Compute an approximation to log10(d), + * log10(d) ~ log10(2) * i + log10(1.5) * + (significand-1.5)/(1.5 * log(10)) */ @@ -2238,8 +2263,7 @@ ApproximateLog10(Tcl_WideUInt bw, d2.w.word0 |= (EXPONENT_BIAS) << EXP_SHIFT; i = be + bbits - 1; ds = (d2.d - 1.5) * TWO_OVER_3LOG10 - + LOG10_3HALVES_PLUS_FUDGE - + LOG10_2 * i; + + LOG10_3HALVES_PLUS_FUDGE + LOG10_2 * i; k = (int) ds; if (k > ds) { --k; @@ -2248,7 +2272,7 @@ ApproximateLog10(Tcl_WideUInt bw, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * BetterLog10 -- * @@ -2256,24 +2280,27 @@ ApproximateLog10(Tcl_WideUInt bw, * 1 .. 10**(TEN_PMAX)-1 * * Side effects: - * Sets k_check to 0 if the new result is known to be exact, and to - * 1 if it may still be one too high. + * Sets k_check to 0 if the new result is known to be exact, and to 1 if + * it may still be one too high. * * Results: - * Returns the improved approximation to log10(d) + * Returns the improved approximation to log10(d). * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -BetterLog10(double d, /* Original number to format */ - int k, /* Characteristic(Log base 10) of the number */ - int* k_check) /* Flag == 1 if k is inexact */ +BetterLog10( + double d, /* Original number to format. */ + int k, /* Characteristic(Log base 10) of the + * number. */ + int *k_check) /* Flag == 1 if k is inexact. */ { - /* - * Performance hack. If k is in the range 0..TEN_PMAX, then we can - * use a powers-of-ten table to check it. + /* + * Performance hack. If k is in the range 0..TEN_PMAX, then we can use a + * powers-of-ten table to check it. */ + if (k >= 0 && k <= TEN_PMAX) { if (d < tens[k]) { k--; @@ -2285,39 +2312,40 @@ BetterLog10(double d, /* Original number to format */ return k; } -/* - *----------------------------------------------------------------------------- +/* + *---------------------------------------------------------------------- * * ComputeScale -- * * Prepares to format a floating-point number as decimal. * * Parameters: - * floor(log10*x) is k (or possibly k-1). floor(log2(x) is i. - * The significand of x requires bbits bits to represent. + * floor(log10*x) is k (or possibly k-1). floor(log2(x) is i. The + * significand of x requires bbits bits to represent. * * Results: * Determines integers b2, b5, s2, s5 so that sig*2**b2*5**b5/2**s2*2**s5 - * exactly represents the value of the x/10**k. This value will lie - * in the range [1 .. 10), and allows for computing successive digits - * by multiplying sig%10 by 10. + * exactly represents the value of the x/10**k. This value will lie in + * the range [1 .. 10), and allows for computing successive digits by + * multiplying sig%10 by 10. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static void -ComputeScale(int be, /* Exponent part of number: d = bw * 2**be */ - int k, /* Characteristic of log10(number) */ - int* b2, /* OUTPUT: Power of 2 in the numerator */ - int* b5, /* OUTPUT: Power of 5 in the numerator */ - int* s2, /* OUTPUT: Power of 2 in the denominator */ - int* s5) /* OUTPUT: Power of 5 in the denominator */ +ComputeScale( + int be, /* Exponent part of number: d = bw * 2**be. */ + int k, /* Characteristic of log10(number). */ + int *b2, /* OUTPUT: Power of 2 in the numerator. */ + int *b5, /* OUTPUT: Power of 5 in the numerator. */ + int *s2, /* OUTPUT: Power of 2 in the denominator. */ + int *s5) /* OUTPUT: Power of 5 in the denominator. */ { - - /* - * Scale numerator and denominator powers of 2 so that the - * input binary number is the ratio of integers + /* + * Scale numerator and denominator powers of 2 so that the input binary + * number is the ratio of integers. */ + if (be <= 0) { *b2 = 0; *s2 = -be; @@ -2326,10 +2354,11 @@ ComputeScale(int be, /* Exponent part of number: d = bw * 2**be */ *s2 = 0; } - /* - * Scale numerator and denominator so that the output decimal number - * is the ratio of integers + /* + * Scale numerator and denominator so that the output decimal number is + * the ratio of integers. */ + if (k >= 0) { *b5 = 0; *s5 = k; @@ -2342,49 +2371,45 @@ ComputeScale(int be, /* Exponent part of number: d = bw * 2**be */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * SetPrecisionLimits -- * - * Determines how many digits of significance should be computed - * (and, hence, how much memory need be allocated) for formatting a - * floating point number. + * Determines how many digits of significance should be computed (and, + * hence, how much memory need be allocated) for formatting a floating + * point number. * * Given that 'k' is floor(log10(x)): - * if 'shortest' format is used, there will be at most 18 digits in the result. + * if 'shortest' format is used, there will be at most 18 digits in the + * result. * if 'F' format is used, there will be at most 'ndigits' + k + 1 digits * if 'E' format is used, there will be exactly 'ndigits' digits. * * Side effects: - * Adjusts '*ndigitsPtr' to have a valid value. - * Stores the maximum memory allocation needed in *iPtr. - * Sets '*iLimPtr' to the limiting number of digits to convert if k - * has been guessed correctly, and '*iLim1Ptr' to the limiting number - * of digits to convert if k has been guessed to be one too high. + * Adjusts '*ndigitsPtr' to have a valid value. Stores the maximum memory + * allocation needed in *iPtr. Sets '*iLimPtr' to the limiting number of + * digits to convert if k has been guessed correctly, and '*iLim1Ptr' to + * the limiting number of digits to convert if k has been guessed to be + * one too high. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static void -SetPrecisionLimits(int convType, - /* Type of conversion: - * TCL_DD_SHORTEST - * TCL_DD_STEELE0 - * TCL_DD_E_FMT - * TCL_DD_F_FMT */ - int k, /* Floor(log10(number to convert)) */ - int* ndigitsPtr, - /* IN/OUT: Number of digits requested - * (Will be adjusted if needed) */ - int* iPtr, /* OUT: Maximum number of digits - * to return */ - int *iLimPtr,/* OUT: Number of digits of significance - * if the bignum method is used.*/ - int *iLim1Ptr) - /* OUT: Number of digits of significance - * if the quick method is used. */ +SetPrecisionLimits( + int convType, /* Type of conversion: TCL_DD_SHORTEST, + * TCL_DD_STEELE0, TCL_DD_E_FMT, + * TCL_DD_F_FMT. */ + int k, /* Floor(log10(number to convert)) */ + int *ndigitsPtr, /* IN/OUT: Number of digits requested (will be + * adjusted if needed). */ + int *iPtr, /* OUT: Maximum number of digits to return. */ + int *iLimPtr, /* OUT: Number of digits of significance if + * the bignum method is used.*/ + int *iLim1Ptr) /* OUT: Number of digits of significance if + * the quick method is used. */ { - switch(convType) { + switch (convType) { case TCL_DD_SHORTEST0: case TCL_DD_STEELE0: *iLimPtr = *iLim1Ptr = -1; @@ -2414,29 +2439,29 @@ SetPrecisionLimits(int convType, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * BumpUp -- * - * Increases a string of digits ending in a series of nines to - * designate the next higher number. xxxxb9999... -> xxxx(b+1)0000... + * Increases a string of digits ending in a series of nines to designate + * the next higher number. xxxxb9999... -> xxxx(b+1)0000... * * Results: * Returns a pointer to the end of the adjusted string. * * Side effects: - * In the case that the string consists solely of '999999', sets it - * to "1" and moves the decimal point (*kPtr) one place to the right. + * In the case that the string consists solely of '999999', sets it to + * "1" and moves the decimal point (*kPtr) one place to the right. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ - -inline static char* -BumpUp(char* s, /* Cursor pointing one past the end of the - * string */ - char* retval, /* Start of the string of digits */ - int* kPtr) /* Position of the decimal point */ +inline static char * +BumpUp( + char *s, /* Cursor pointing one past the end of the + * string. */ + char *retval, /* Start of the string of digits. */ + int *kPtr) /* Position of the decimal point. */ { while (*--s == '9') { if (s == retval) { @@ -2451,27 +2476,28 @@ BumpUp(char* s, /* Cursor pointing one past the end of the } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * AdjustRange -- * - * Rescales a 'double' in preparation for formatting it using the - * 'quick' double-to-string method. + * Rescales a 'double' in preparation for formatting it using the 'quick' + * double-to-string method. * * Results: - * Returns the precision that has been lost in the prescaling as - * a count of units in the least significant place. + * Returns the precision that has been lost in the prescaling as a count + * of units in the least significant place. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -AdjustRange(double* dPtr, /* INOUT: Number to adjust */ - int k) /* IN: floor(log10(d)) */ +AdjustRange( + double *dPtr, /* INOUT: Number to adjust. */ + int k) /* IN: floor(log10(d)) */ { int ieps; /* Number of roundoff errors that have - * accumulated */ - double d = *dPtr; /* Number to adjust */ + * accumulated. */ + double d = *dPtr; /* Number to adjust. */ double ds; int i, j, j1; @@ -2481,6 +2507,7 @@ AdjustRange(double* dPtr, /* INOUT: Number to adjust */ /* * The number must be reduced to bring it into range. */ + ds = tens[k & 0xf]; j = k >> 4; if (j & BLETCH) { @@ -2499,8 +2526,9 @@ AdjustRange(double* dPtr, /* INOUT: Number to adjust */ d /= ds; } else if ((j1 = -k) != 0) { /* - * The number must be increased to bring it into range + * The number must be increased to bring it into range. */ + d *= tens[j1 & 0xf]; i = 0; for (j = j1>>4; j; j>>=1) { @@ -2517,52 +2545,52 @@ AdjustRange(double* dPtr, /* INOUT: Number to adjust */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShorteningQuickFormat -- * - * Returns a 'quick' format of a double precision number to a string - * of digits, preferring a shorter string of digits if the shorter - * string is still within 1/2 ulp of the number. + * Returns a 'quick' format of a double precision number to a string of + * digits, preferring a shorter string of digits if the shorter string is + * still within 1/2 ulp of the number. * * Results: - * Returns the string of digits. Returns NULL if the 'quick' method - * fails and the bignum method must be used. + * Returns the string of digits. Returns NULL if the 'quick' method fails + * and the bignum method must be used. * * Side effects: * Stores the position of the decimal point at '*kPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -ShorteningQuickFormat(double d, /* Number to convert */ - int k, /* floor(log10(d)) */ - int ilim, /* Number of significant digits to return */ - double eps, - /* Estimated roundoff error */ - char* retval, - /* Buffer to receive the digit string */ - int* kPtr) - /* Pointer to stash the position of - * the decimal point */ +inline static char * +ShorteningQuickFormat( + double d, /* Number to convert. */ + int k, /* floor(log10(d)) */ + int ilim, /* Number of significant digits to return. */ + double eps, /* Estimated roundoff error. */ + char *retval, /* Buffer to receive the digit string. */ + int *kPtr) /* Pointer to stash the position of the + * decimal point. */ { - char* s = retval; /* Cursor in the return value */ - int digit; /* Current digit */ + char *s = retval; /* Cursor in the return value. */ + int digit; /* Current digit. */ int i; eps = 0.5 / tens[ilim-1] - eps; i = 0; for (;;) { - /* Convert a digit */ + /* + * Convert a digit. + */ digit = (int) d; d -= digit; *s++ = '0' + digit; - /* - * Truncate the conversion if the string of digits is within - * 1/2 ulp of the actual value. + /* + * Truncate the conversion if the string of digits is within 1/2 ulp + * of the actual value. */ if (d < eps) { @@ -2576,7 +2604,7 @@ ShorteningQuickFormat(double d, /* Number to convert */ /* * Bail out if the conversion fails to converge to a sufficiently - * precise value + * precise value. */ if (++i >= ilim) { @@ -2593,40 +2621,44 @@ ShorteningQuickFormat(double d, /* Number to convert */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * StrictQuickFormat -- * - * Convert a double precision number of a string of a precise number - * of digits, using the 'quick' double precision method. + * Convert a double precision number of a string of a precise number of + * digits, using the 'quick' double precision method. * * Results: - * Returns the digit string, or NULL if the bignum method must be - * used to do the formatting. + * Returns the digit string, or NULL if the bignum method must be used to + * do the formatting. * * Side effects: * Stores the position of the decimal point in '*kPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -StrictQuickFormat(double d, /* Number to convert */ - int k, /* floor(log10(d)) */ - int ilim, /* Number of significant digits to return */ - double eps, /* Estimated roundoff error */ - char* retval, /* Start of the digit string */ - int* kPtr) /* Pointer to stash the position of - * the decimal point */ +inline static char * +StrictQuickFormat( + double d, /* Number to convert. */ + int k, /* floor(log10(d)) */ + int ilim, /* Number of significant digits to return. */ + double eps, /* Estimated roundoff error. */ + char *retval, /* Start of the digit string. */ + int *kPtr) /* Pointer to stash the position of the + * decimal point. */ { - char* s = retval; /* Cursor in the return value */ - int digit; /* Current digit of the answer */ + char *s = retval; /* Cursor in the return value. */ + int digit; /* Current digit of the answer. */ int i; eps *= tens[ilim-1]; i = 1; for (;;) { - /* Extract a digit */ + /* + * Extract a digit. + */ + digit = (int) d; d -= digit; if (d == 0.0) { @@ -2634,10 +2666,11 @@ StrictQuickFormat(double d, /* Number to convert */ } *s++ = '0' + digit; - /* - * When the given digit count is reached, handle trailing strings - * of 0 and 9. + /* + * When the given digit count is reached, handle trailing strings of 0 + * and 9. */ + if (i == ilim) { if (d > 0.5 + eps) { *kPtr = k; @@ -2654,14 +2687,17 @@ StrictQuickFormat(double d, /* Number to convert */ } } - /* Advance to the next digit */ + /* + * Advance to the next digit. + */ + ++i; d *= 10.0; } } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * QuickConversion -- * @@ -2670,42 +2706,46 @@ StrictQuickFormat(double d, /* Number to convert */ * therefore be used for the intermediate results. * * Results: - * Returns the converted string, or NULL if the bignum method must - * be used. + * Returns the converted string, or NULL if the bignum method must be + * used. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -QuickConversion(double d, /* Number to format */ - int k, /* floor(log10(d)), approximately */ - int k_check, /* 0 if k is exact, 1 if it may be too high */ - int flags, /* Flags passed to dtoa: +inline static char * +QuickConversion( + double d, /* Number to format. */ + int k, /* floor(log10(d)), approximately. */ + int k_check, /* 0 if k is exact, 1 if it may be too high */ + int flags, /* Flags passed to dtoa: * TCL_DD_SHORTEN_FLAG */ - int len, /* Length of the return value */ - int ilim, /* Number of digits to store */ - int ilim1, /* Number of digits to store if we - * musguessed k */ - int* decpt, /* OUTPUT: Location of the decimal point */ - char** endPtr) /* OUTPUT: Pointer to the terminal null byte */ + int len, /* Length of the return value. */ + int ilim, /* Number of digits to store. */ + int ilim1, /* Number of digits to store if we misguessed + * k. */ + int *decpt, /* OUTPUT: Location of the decimal point. */ + char **endPtr) /* OUTPUT: Pointer to the terminal null + * byte. */ { int ieps; /* Number of 1-ulp roundoff errors that have - * accumulated in the calculation*/ - Double eps; /* Estimated roundoff error */ - char* retval; /* Returned string */ - char* end; /* Pointer to the terminal null byte in the - * returned string */ + * accumulated in the calculation. */ + Double eps; /* Estimated roundoff error. */ + char *retval; /* Returned string. */ + char *end; /* Pointer to the terminal null byte in the + * returned string. */ /* - * Bring d into the range [1 .. 10) + * Bring d into the range [1 .. 10). */ + ieps = AdjustRange(&d, k); /* - * If the guessed value of k didn't get d into range, adjust it - * by one. If that leaves us outside the range in which quick format - * is accurate, bail out. + * If the guessed value of k didn't get d into range, adjust it by one. If + * that leaves us outside the range in which quick format is accurate, + * bail out. */ + if (k_check && d < 1. && ilim > 0) { if (ilim1 < 0) { return NULL; @@ -2717,15 +2757,16 @@ QuickConversion(double d, /* Number to format */ } /* - * Compute estimated roundoff error + * Compute estimated roundoff error. */ + eps.d = ieps * d + 7.; eps.w.word0 -= (FP_PRECISION-1) << EXP_SHIFT; /* - * Handle the peculiar case where the result has no significant - * digits. + * Handle the peculiar case where the result has no significant digits. */ + retval = ckalloc(len + 1); if (ilim == 0) { d -= 5.; @@ -2742,7 +2783,9 @@ QuickConversion(double d, /* Number to format */ } } - /* Format the digit string */ + /* + * Format the digit string. + */ if (flags & TCL_DD_SHORTEN_FLAG) { end = ShorteningQuickFormat(d, k, ilim, eps.d, retval, decpt); @@ -2761,106 +2804,99 @@ QuickConversion(double d, /* Number to format */ } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * CastOutPowersOf2 -- * - * Adjust the factors 'b2', 'm2', and 's2' to cast out common powers - * of 2 from numerator and denominator in preparation for the 'bignum' - * method of floating point conversion. + * Adjust the factors 'b2', 'm2', and 's2' to cast out common powers of 2 + * from numerator and denominator in preparation for the 'bignum' method + * of floating point conversion. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static void -CastOutPowersOf2(int* b2, /* Power of 2 to multiply the significand */ - int* m2, /* Power of 2 to multiply 1/2 ulp */ - int* s2) /* Power of 2 to multiply the common - * denominator */ +CastOutPowersOf2( + int *b2, /* Power of 2 to multiply the significand. */ + int *m2, /* Power of 2 to multiply 1/2 ulp. */ + int *s2) /* Power of 2 to multiply the common + * denominator. */ { int i; + if (*m2 > 0 && *s2 > 0) { /* Find the smallest power of 2 in the - * numerator */ - if (*m2 < *s2) { /* Find the lowest common denominatorr */ + * numerator. */ + if (*m2 < *s2) { /* Find the lowest common denominator. */ i = *m2; } else { i = *s2; } - *b2 -= i; /* Reduce to lowest terms */ + *b2 -= i; /* Reduce to lowest terms. */ *m2 -= i; *s2 -= i; } } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShorteningInt64Conversion -- * - * Converts a double-precision number to the shortest string of - * digits that reconverts exactly to the given number, or to - * 'ilim' digits if that will yield a shorter result. The numerator and - * denominator in David Gay's conversion algorithm are known to fit - * in Tcl_WideUInt, giving considerably faster arithmetic than mp_int's. + * Converts a double-precision number to the shortest string of digits + * that reconverts exactly to the given number, or to 'ilim' digits if + * that will yield a shorter result. The numerator and denominator in + * David Gay's conversion algorithm are known to fit in Tcl_WideUInt, + * giving considerably faster arithmetic than mp_int's. * * Results: - * Returns the string of significant decimal digits, in newly - * allocated memory + * Returns the string of significant decimal digits, in newly allocated + * memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the - * location of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the location + * of the terminal null byte in '*endPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -ShorteningInt64Conversion(Double* dPtr, - /* Original number to convert */ - int convType, - /* Type of conversion (shortest, Steele, - E format, F format) */ - Tcl_WideUInt bw, - /* Integer significand */ - int b2, int b5, - /* Scale factor for the significand - * in the numerator */ - int m2plus, int m2minus, int m5, - /* Scale factors for 1/2 ulp in - * the numerator (will be different if - * bw == 1 */ - int s2, int s5, - /* Scale factors for the denominator */ - int k, - /* Number of output digits before the decimal - * point */ - int len, - /* Number of digits to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Position of the terminal '\0' - * at the end of the returned string */ +inline static char * +ShorteningInt64Conversion( + Double *dPtr, /* Original number to convert. */ + int convType, /* Type of conversion (shortest, Steele, + * E format, F format). */ + Tcl_WideUInt bw, /* Integer significand. */ + int b2, int b5, /* Scale factor for the significand in the + * numerator. */ + int m2plus, int m2minus, int m5, + /* Scale factors for 1/2 ulp in the numerator + * (will be different if bw == 1. */ + int s2, int s5, /* Scale factors for the denominator. */ + int k, /* Number of output digits before the decimal + * point. */ + int len, /* Number of digits to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Position of the terminal '\0' at + * the end of the returned string. */ { - - char* retval = ckalloc(len + 1); - /* Output buffer */ + char *retval = ckalloc(len + 1); + /* Output buffer. */ Tcl_WideUInt b = (bw * wuipow5[b5]) << b2; - /* Numerator of the fraction being converted */ + /* Numerator of the fraction being + * converted. */ Tcl_WideUInt S = wuipow5[s5] << s2; - /* Denominator of the fraction being - * converted */ - Tcl_WideUInt mplus, mminus; /* Ranges for testing whether the result - * is within roundoff of being exact */ - int digit; /* Current output digit */ - char* s = retval; /* Cursor in the output buffer */ - int i; /* Current position in the output buffer */ + /* Denominator of the fraction being + * converted. */ + Tcl_WideUInt mplus, mminus; /* Ranges for testing whether the result is + * within roundoff of being exact. */ + int digit; /* Current output digit. */ + char *s = retval; /* Cursor in the output buffer. */ + int i; /* Current position in the output buffer. */ - /* Adjust if the logarithm was guessed wrong */ + /* + * Adjust if the logarithm was guessed wrong. + */ if (b < S) { b = 10 * b; @@ -2869,12 +2905,16 @@ ShorteningInt64Conversion(Double* dPtr, --k; } - /* Compute roundoff ranges */ + /* + * Compute roundoff ranges. + */ mplus = wuipow5[m5] << m2plus; mminus = wuipow5[m5] << m2minus; - /* Loop through the digits */ + /* + * Loop through the digits. + */ i = 1; for (;;) { @@ -2884,21 +2924,19 @@ ShorteningInt64Conversion(Double* dPtr, } b = b % S; - /* + /* * Does the current digit put us on the low side of the exact value * but within within roundoff of being exact? */ - if (b < mplus - || (b == mplus - && convType != TCL_DD_STEELE0 - && (dPtr->w.word1 & 1) == 0)) { + + if (b < mplus || (b == mplus + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { /* - * Make sure we shouldn't be rounding *up* instead, - * in case the next number above is closer + * Make sure we shouldn't be rounding *up* instead, in case the + * next number above is closer. */ - if (2 * b > S - || (2 * b == S - && (digit & 1) != 0)) { + + if (2 * b > S || (2 * b == S && (digit & 1) != 0)) { ++digit; if (digit == 10) { *s++ = '9'; @@ -2907,7 +2945,9 @@ ShorteningInt64Conversion(Double* dPtr, } } - /* Stash the current digit */ + /* + * Stash the current digit. + */ *s++ = '0' + digit; break; @@ -2917,10 +2957,9 @@ ShorteningInt64Conversion(Double* dPtr, * Does one plus the current digit put us within roundoff of the * number? */ - if (b > S - mminus - || (b == S - mminus - && convType != TCL_DD_STEELE0 - && (dPtr->w.word1 & 1) == 0)) { + + if (b > S - mminus || (b == S - mminus + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { if (digit == 9) { *s++ = '9'; s = BumpUp(s, retval, &k); @@ -2934,27 +2973,30 @@ ShorteningInt64Conversion(Double* dPtr, /* * Have we converted all the requested digits? */ + *s++ = '0' + digit; if (i == ilim) { - if (2*b > S - || (2*b == S && (digit & 1) != 0)) { + if (2*b > S || (2*b == S && (digit & 1) != 0)) { s = BumpUp(s, retval, &k); } break; } - - /* Advance to the next digit */ - + + /* + * Advance to the next digit. + */ + b = 10 * b; mplus = 10 * mplus; mminus = 10 * mminus; ++i; } - /* + /* * Endgame - store the location of the decimal point and the end of the * string. */ + *s = '\0'; *decpt = k; if (endPtr) { @@ -2964,69 +3006,61 @@ ShorteningInt64Conversion(Double* dPtr, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * StrictInt64Conversion -- * - * Converts a double-precision number to a fixed-length string of - * 'ilim' digits that reconverts exactly to the given number. - * ('ilim' should be replaced with 'ilim1' in the case where - * log10(d) has been overestimated). The numerator and - * denominator in David Gay's conversion algorithm are known to fit - * in Tcl_WideUInt, giving considerably faster arithmetic than mp_int's. + * Converts a double-precision number to a fixed-length string of 'ilim' + * digits that reconverts exactly to the given number. ('ilim' should be + * replaced with 'ilim1' in the case where log10(d) has been + * overestimated). The numerator and denominator in David Gay's + * conversion algorithm are known to fit in Tcl_WideUInt, giving + * considerably faster arithmetic than mp_int's. * * Results: - * Returns the string of significant decimal digits, in newly - * allocated memory + * Returns the string of significant decimal digits, in newly allocated + * memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the - * location of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the location + * of the terminal null byte in '*endPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -StrictInt64Conversion(Double* dPtr, - /* Original number to convert */ - int convType, - /* Type of conversion (shortest, Steele, - E format, F format) */ - Tcl_WideUInt bw, - /* Integer significand */ - int b2, int b5, - /* Scale factor for the significand - * in the numerator */ - int s2, int s5, - /* Scale factors for the denominator */ - int k, - /* Number of output digits before the decimal - * point */ - int len, - /* Number of digits to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Position of the terminal '\0' - * at the end of the returned string */ +inline static char * +StrictInt64Conversion( + Double *dPtr, /* Original number to convert. */ + int convType, /* Type of conversion (shortest, Steele, + * E format, F format). */ + Tcl_WideUInt bw, /* Integer significand. */ + int b2, int b5, /* Scale factor for the significand in the + * numerator. */ + int s2, int s5, /* Scale factors for the denominator. */ + int k, /* Number of output digits before the decimal + * point. */ + int len, /* Number of digits to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Position of the terminal '\0' at + * the end of the returned string. */ { - - char* retval = ckalloc(len + 1); - /* Output buffer */ + char *retval = ckalloc(len + 1); + /* Output buffer. */ Tcl_WideUInt b = (bw * wuipow5[b5]) << b2; - /* Numerator of the fraction being converted */ + /* Numerator of the fraction being + * converted. */ Tcl_WideUInt S = wuipow5[s5] << s2; - /* Denominator of the fraction being - * converted */ - int digit; /* Current output digit */ - char* s = retval; /* Cursor in the output buffer */ - int i; /* Current position in the output buffer */ + /* Denominator of the fraction being + * converted. */ + int digit; /* Current output digit. */ + char *s = retval; /* Cursor in the output buffer. */ + int i; /* Current position in the output buffer. */ - /* Adjust if the logarithm was guessed wrong */ + /* + * Adjust if the logarithm was guessed wrong. + */ if (b < S) { b = 10 * b; @@ -3034,7 +3068,9 @@ StrictInt64Conversion(Double* dPtr, --k; } - /* Loop through the digits */ + /* + * Loop through the digits. + */ i = 1; for (;;) { @@ -3047,25 +3083,28 @@ StrictInt64Conversion(Double* dPtr, /* * Have we converted all the requested digits? */ + *s++ = '0' + digit; if (i == ilim) { - if (2*b > S - || (2*b == S && (digit & 1) != 0)) { + if (2*b > S || (2*b == S && (digit & 1) != 0)) { s = BumpUp(s, retval, &k); } break; } - - /* Advance to the next digit */ - + + /* + * Advance to the next digit. + */ + b = 10 * b; ++i; } - /* + /* * Endgame - store the location of the decimal point and the end of the * string. */ + *s = '\0'; *decpt = k; if (endPtr) { @@ -3075,30 +3114,30 @@ StrictInt64Conversion(Double* dPtr, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShouldBankerRoundUpPowD -- * - * Test whether bankers' rounding should round a digit up. Assumption - * is made that the denominator of the fraction being tested is - * a power of 2**DIGIT_BIT. + * Test whether bankers' rounding should round a digit up. Assumption is + * made that the denominator of the fraction being tested is a power of + * 2**DIGIT_BIT. * * Results: - * Returns 1 iff the fraction is more than 1/2, or if the fraction - * is exactly 1/2 and the digit is odd. + * Returns 1 iff the fraction is more than 1/2, or if the fraction is + * exactly 1/2 and the digit is odd. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -ShouldBankerRoundUpPowD(mp_int* b, - /* Numerator of the fraction */ - int sd, /* Denominator is 2**(sd*DIGIT_BIT) */ - int isodd) - /* 1 if the digit is odd, 0 if even */ +ShouldBankerRoundUpPowD( + mp_int *b, /* Numerator of the fraction. */ + int sd, /* Denominator is 2**(sd*DIGIT_BIT). */ + int isodd) /* 1 if the digit is odd, 0 if even. */ { int i; - static const mp_digit topbit = (1<<(DIGIT_BIT-1)); + static const mp_digit topbit = 1 << (DIGIT_BIT - 1); + if (b->used < sd || (b->dp[sd-1] & topbit) == 0) { return 0; } @@ -3114,45 +3153,41 @@ ShouldBankerRoundUpPowD(mp_int* b, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShouldBankerRoundUpToNextPowD -- * - * Tests whether bankers' rounding will round down in the - * "denominator is a power of 2**MP_DIGIT" case. + * Tests whether bankers' rounding will round down in the "denominator is + * a power of 2**MP_DIGIT" case. * * Results: * Returns 1 if the rounding will be performed - which increases the * digit by one - and 0 otherwise. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -ShouldBankerRoundUpToNextPowD(mp_int* b, - /* Numerator of the fraction */ - mp_int* m, - /* Numerator of the rounding tolerance */ - int sd, - /* Common denominator is 2**(sd*DIGIT_BIT) */ - int convType, - /* Conversion type: STEELE defeats - * round-to-even (Not sure why one wants to - * do this; I copied it from Gay) FIXME */ - int isodd, - /* 1 if the integer significand is odd */ - mp_int* temp) - /* Work area for the calculation */ +ShouldBankerRoundUpToNextPowD( + mp_int *b, /* Numerator of the fraction. */ + mp_int *m, /* Numerator of the rounding tolerance. */ + int sd, /* Common denominator is 2**(sd*DIGIT_BIT). */ + int convType, /* Conversion type: STEELE defeats + * round-to-even (not sure why one wants to do + * this; I copied it from Gay). FIXME */ + int isodd, /* 1 if the integer significand is odd. */ + mp_int *temp) /* Work area for the calculation. */ { int i; - /* - * Compare B and S-m -- which is the same as comparing B+m and S -- - * which we do by computing b+m and doing a bitwhack compare against + /* + * Compare B and S-m - which is the same as comparing B+m and S - which we + * do by computing b+m and doing a bitwhack compare against * 2**(DIGIT_BIT*sd) */ + mp_add(b, m, temp); - if (temp->used <= sd) { /* too few digits to be > S */ + if (temp->used <= sd) { /* Too few digits to be > s */ return 0; } if (temp->used > sd+1 || temp->dp[sd] > 1) { @@ -3160,85 +3195,74 @@ ShouldBankerRoundUpToNextPowD(mp_int* b, return 1; } for (i = sd-1; i >= 0; --i) { - /* check for ==s */ + /* Check for ==s */ if (temp->dp[i] != 0) { /* > s */ return 1; } } if (convType == TCL_DD_STEELE0) { - /* biased rounding */ + /* Biased rounding. */ return 0; } return isodd; } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShorteningBignumConversionPowD -- * - * Converts a double-precision number to the shortest string of - * digits that reconverts exactly to the given number, or to - * 'ilim' digits if that will yield a shorter result. The denominator - * in David Gay's conversion algorithm is known to be a power of - * 2**DIGIT_BIT, and hence the division in the main loop may be replaced - * by a digit shift and mask. + * Converts a double-precision number to the shortest string of digits + * that reconverts exactly to the given number, or to 'ilim' digits if + * that will yield a shorter result. The denominator in David Gay's + * conversion algorithm is known to be a power of 2**DIGIT_BIT, and hence + * the division in the main loop may be replaced by a digit shift and + * mask. * * Results: - * Returns the string of significant decimal digits, in newly - * allocated memory + * Returns the string of significant decimal digits, in newly allocated + * memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the - * location of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the location + * of the terminal null byte in '*endPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -ShorteningBignumConversionPowD(Double* dPtr, - /* Original number to convert */ - int convType, - /* Type of conversion (shortest, Steele, - E format, F format) */ - Tcl_WideUInt bw, - /* Integer significand */ - int b2, int b5, - /* Scale factor for the significand - * in the numerator */ - int m2plus, int m2minus, int m5, - /* Scale factors for 1/2 ulp in - * the numerator (will be different if - * bw == 1 */ - int sd, - /* Scale factor for the denominator */ - int k, - /* Number of output digits before the decimal - * point */ - int len, - /* Number of digits to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Position of the terminal '\0' - * at the end of the returned string */ +inline static char * +ShorteningBignumConversionPowD( + Double *dPtr, /* Original number to convert. */ + int convType, /* Type of conversion (shortest, Steele, + * E format, F format). */ + Tcl_WideUInt bw, /* Integer significand. */ + int b2, int b5, /* Scale factor for the significand in the + * numerator. */ + int m2plus, int m2minus, int m5, + /* Scale factors for 1/2 ulp in the numerator + * (will be different if bw == 1). */ + int sd, /* Scale factor for the denominator. */ + int k, /* Number of output digits before the decimal + * point. */ + int len, /* Number of digits to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Position of the terminal '\0' at + * the end of the returned string. */ { - - char* retval = ckalloc(len + 1); - /* Output buffer */ - mp_int b; /* Numerator of the fraction being converted */ - mp_int mplus, mminus; /* Bounds for roundoff */ - mp_digit digit; /* Current output digit */ - char* s = retval; /* Cursor in the output buffer */ - int i; /* Index in the output buffer */ + char *retval = ckalloc(len + 1); + /* Output buffer. */ + mp_int b; /* Numerator of the fraction being + * converted. */ + mp_int mplus, mminus; /* Bounds for roundoff. */ + mp_digit digit; /* Current output digit. */ + char *s = retval; /* Cursor in the output buffer. */ + int i; /* Index in the output buffer. */ mp_int temp; int r1; - /* + /* * b = bw * 2**b2 * 5**b5 * mminus = 5**m5 */ @@ -3248,7 +3272,9 @@ ShorteningBignumConversionPowD(Double* dPtr, MulPow5(&b, b5, &b); mp_mul_2d(&b, b2, &b); - /* Adjust if the logarithm was guessed wrong */ + /* + * Adjust if the logarithm was guessed wrong. + */ if (b.used <= sd) { mp_mul_d(&b, 10, &b); @@ -3270,8 +3296,10 @@ ShorteningBignumConversionPowD(Double* dPtr, } mp_init(&temp); - /* Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT) - * by mp_digit extraction */ + /* + * Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT) + * by mp_digit extraction. + */ i = 0; for (;;) { @@ -3285,20 +3313,19 @@ ShorteningBignumConversionPowD(Double* dPtr, --b.used; mp_clamp(&b); } - /* + /* * Does the current digit put us on the low side of the exact value * but within within roundoff of being exact? */ - + r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus); - if (r1 == MP_LT - || (r1 == MP_EQ - && convType != TCL_DD_STEELE0 - && (dPtr->w.word1 & 1) == 0)) { + if (r1 == MP_LT || (r1 == MP_EQ + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { /* - * Make sure we shouldn't be rounding *up* instead, - * in case the next number above is closer + * Make sure we shouldn't be rounding *up* instead, in case the + * next number above is closer. */ + if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { ++digit; if (digit == 10) { @@ -3308,7 +3335,9 @@ ShorteningBignumConversionPowD(Double* dPtr, } } - /* Stash the last digit */ + /* + * Stash the last digit. + */ *s++ = '0' + digit; break; @@ -3318,10 +3347,9 @@ ShorteningBignumConversionPowD(Double* dPtr, * Does one plus the current digit put us within roundoff of the * number? */ - - if (ShouldBankerRoundUpToNextPowD(&b, &mminus, sd, - convType, dPtr->w.word1 & 1, - &temp)) { + + if (ShouldBankerRoundUpToNextPowD(&b, &mminus, sd, convType, + dPtr->w.word1 & 1, &temp)) { if (digit == 9) { *s++ = '9'; s = BumpUp(s, retval, &k); @@ -3335,6 +3363,7 @@ ShorteningBignumConversionPowD(Double* dPtr, /* * Have we converted all the requested digits? */ + *s++ = '0' + digit; if (i == ilim) { if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { @@ -3342,9 +3371,11 @@ ShorteningBignumConversionPowD(Double* dPtr, } break; } - - /* Advance to the next digit */ - + + /* + * Advance to the next digit. + */ + mp_mul_d(&b, 10, &b); mp_mul_d(&mminus, 10, &mminus); if (m2plus > m2minus) { @@ -3353,10 +3384,11 @@ ShorteningBignumConversionPowD(Double* dPtr, ++i; } - /* + /* * Endgame - store the location of the decimal point and the end of the * string. */ + if (m2plus > m2minus) { mp_clear(&mplus); } @@ -3370,65 +3402,55 @@ ShorteningBignumConversionPowD(Double* dPtr, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * StrictBignumConversionPowD -- * - * Converts a double-precision number to a fixed-lengt string of - * 'ilim' digits (or 'ilim1' if log10(d) has been overestimated.) - * The denominator in David Gay's conversion algorithm is known to - * be a power of 2**DIGIT_BIT, and hence the division in the main - * loop may be replaced by a digit shift and mask. + * Converts a double-precision number to a fixed-lengt string of 'ilim' + * digits (or 'ilim1' if log10(d) has been overestimated). The + * denominator in David Gay's conversion algorithm is known to be a power + * of 2**DIGIT_BIT, and hence the division in the main loop may be + * replaced by a digit shift and mask. * * Results: - * Returns the string of significant decimal digits, in newly - * allocated memory. + * Returns the string of significant decimal digits, in newly allocated + * memory. * * Side effects: - * Stores the location of the decimal point in '*decpt' and the - * location of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the location + * of the terminal null byte in '*endPtr'. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -StrictBignumConversionPowD(Double* dPtr, - /* Original number to convert */ - int convType, - /* Type of conversion (shortest, Steele, - E format, F format) */ - Tcl_WideUInt bw, - /* Integer significand */ - int b2, int b5, - /* Scale factor for the significand - * in the numerator */ - int sd, - /* Scale factor for the denominator */ - int k, - /* Number of output digits before the decimal - * point */ - int len, - /* Number of digits to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Position of the terminal '\0' - * at the end of the returned string */ +inline static char * +StrictBignumConversionPowD( + Double *dPtr, /* Original number to convert. */ + int convType, /* Type of conversion (shortest, Steele, + * E format, F format). */ + Tcl_WideUInt bw, /* Integer significand. */ + int b2, int b5, /* Scale factor for the significand in the + * numerator. */ + int sd, /* Scale factor for the denominator. */ + int k, /* Number of output digits before the decimal + * point. */ + int len, /* Number of digits to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Position of the terminal '\0' at + * the end of the returned string. */ { - - char* retval = ckalloc(len + 1); - /* Output buffer */ - mp_int b; /* Numerator of the fraction being converted */ - mp_digit digit; /* Current output digit */ - char* s = retval; /* Cursor in the output buffer */ - int i; /* Index in the output buffer */ + char *retval = ckalloc(len + 1); + /* Output buffer. */ + mp_int b; /* Numerator of the fraction being + * converted. */ + mp_digit digit; /* Current output digit. */ + char *s = retval; /* Cursor in the output buffer. */ + int i; /* Index in the output buffer. */ mp_int temp; - /* + /* * b = bw * 2**b2 * 5**b5 */ @@ -3436,7 +3458,9 @@ StrictBignumConversionPowD(Double* dPtr, MulPow5(&b, b5, &b); mp_mul_2d(&b, b2, &b); - /* Adjust if the logarithm was guessed wrong */ + /* + * Adjust if the logarithm was guessed wrong. + */ if (b.used <= sd) { mp_mul_d(&b, 10, &b); @@ -3445,9 +3469,9 @@ StrictBignumConversionPowD(Double* dPtr, } mp_init(&temp); - /* + /* * Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT) - * by mp_digit extraction + * by mp_digit extraction. */ i = 1; @@ -3459,12 +3483,14 @@ StrictBignumConversionPowD(Double* dPtr, if (b.used > sd+1 || digit >= 10) { Tcl_Panic("wrong digit!"); } - --b.used; mp_clamp(&b); + --b.used; + mp_clamp(&b); } /* * Have we converted all the requested digits? */ + *s++ = '0' + digit; if (i == ilim) { if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { @@ -3472,17 +3498,20 @@ StrictBignumConversionPowD(Double* dPtr, } break; } - - /* Advance to the next digit */ - + + /* + * Advance to the next digit. + */ + mp_mul_d(&b, 10, &b); ++i; } - /* + /* * Endgame - store the location of the decimal point and the end of the * string. */ + mp_clear_multi(&b, &temp, NULL); *s = '\0'; *decpt = k; @@ -3493,7 +3522,7 @@ StrictBignumConversionPowD(Double* dPtr, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShouldBankerRoundUp -- * @@ -3503,17 +3532,18 @@ StrictBignumConversionPowD(Double* dPtr, * Results: * Returns 1 if the number needs to be rounded up, 0 otherwise. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -ShouldBankerRoundUp(mp_int* twor, - /* 2x the remainder from thd division that - * produced the last digit */ - mp_int* S, /* Denominator */ - int isodd) /* Flag == 1 if the last digit is odd */ +ShouldBankerRoundUp( + mp_int *twor, /* 2x the remainder from thd division that + * produced the last digit. */ + mp_int *S, /* Denominator. */ + int isodd) /* Flag == 1 if the last digit is odd. */ { int r = mp_cmp_mag(twor, S); + switch (r) { case MP_LT: return 0; @@ -3527,38 +3557,37 @@ ShouldBankerRoundUp(mp_int* twor, } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShouldBankerRoundUpToNext -- * - * Tests whether the remainder is great enough to force rounding - * to the next higher digit. + * Tests whether the remainder is great enough to force rounding to the + * next higher digit. * * Results: * Returns 1 if the number should be rounded up, 0 otherwise. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ inline static int -ShouldBankerRoundUpToNext(mp_int* b, - /* Remainder from the division that produced +ShouldBankerRoundUpToNext( + mp_int *b, /* Remainder from the division that produced * the last digit. */ - mp_int* m, - /* Numerator of the rounding tolerance */ - mp_int* S, - /* Denominator */ - int convType, - /* Conversion type: STEELE0 defeats - * round-to-even. (Not sure why one would - * want this; I coped it from Gay. FIXME */ - int isodd, - /* 1 if the integer significand is odd */ - mp_int* temp) - /* Work area needed for the calculation */ + mp_int *m, /* Numerator of the rounding tolerance. */ + mp_int *S, /* Denominator. */ + int convType, /* Conversion type: STEELE0 defeats + * round-to-even. (Not sure why one would want + * this; I coped it from Gay). FIXME */ + int isodd, /* 1 if the integer significand is odd. */ + mp_int *temp) /* Work area needed for the calculation. */ { int r; - /* Compare b and S-m: this is the same as comparing B+m and S. */ + + /* + * Compare b and S-m: this is the same as comparing B+m and S. + */ + mp_add(b, m, temp); r = mp_cmp_mag(temp, S); switch(r) { @@ -3576,9 +3605,9 @@ ShouldBankerRoundUpToNext(mp_int* b, Tcl_Panic("in ShouldBankerRoundUpToNext, trichotomy fails!"); return 0; } - + /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * ShorteningBignumConversion -- * @@ -3589,49 +3618,38 @@ ShouldBankerRoundUpToNext(mp_int* b, * Returns the string of digits. * * Side effects: - * Stores the position of the decimal point in *decpt. - * Stores a pointer to the end of the number in *endPtr. + * Stores the position of the decimal point in *decpt. Stores a pointer + * to the end of the number in *endPtr. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -ShorteningBignumConversion(Double* dPtr, - /* Original number being converted */ - int convType, - /* Conversion type */ - Tcl_WideUInt bw, - /* Integer significand and exponent */ - int b2, - /* Scale factor for the significand */ - int m2plus, int m2minus, - /* Scale factors for 1/2 ulp in numerator */ - int s2, int s5, - /* Scale factors for denominator */ - int k, - /* Guessed position of the decimal point */ - int len, - /* Size of the digit buffer to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Pointer to the end of the number */ +inline static char * +ShorteningBignumConversion( + Double *dPtr, /* Original number being converted. */ + int convType, /* Conversion type. */ + Tcl_WideUInt bw, /* Integer significand and exponent. */ + int b2, /* Scale factor for the significand. */ + int m2plus, int m2minus, /* Scale factors for 1/2 ulp in numerator. */ + int s2, int s5, /* Scale factors for denominator. */ + int k, /* Guessed position of the decimal point. */ + int len, /* Size of the digit buffer to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Pointer to the end of the number */ { - char* retval = ckalloc(len+1); - /* Buffer of digits to return */ - char* s = retval; /* Cursor in the return value */ - mp_int b; /* Numerator of the result */ - mp_int mminus; /* 1/2 ulp below the result */ - mp_int mplus; /* 1/2 ulp above the result */ - mp_int S; /* Denominator of the result */ - mp_int dig; /* Current digit of the result */ - int digit; /* Current digit of the result */ - mp_int temp; /* Work area */ - int minit = 1; /* Fudge factor for when we misguess k */ + char *retval = ckalloc(len+1); + /* Buffer of digits to return. */ + char *s = retval; /* Cursor in the return value. */ + mp_int b; /* Numerator of the result. */ + mp_int mminus; /* 1/2 ulp below the result. */ + mp_int mplus; /* 1/2 ulp above the result. */ + mp_int S; /* Denominator of the result. */ + mp_int dig; /* Current digit of the result. */ + int digit; /* Current digit of the result. */ + mp_int temp; /* Work area. */ + int minit = 1; /* Fudge factor for when we misguess k. */ int i; int r1; @@ -3646,10 +3664,9 @@ ShorteningBignumConversion(Double* dPtr, MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S); /* - * Handle the case where we guess the position of the decimal point - * wrong. + * Handle the case where we guess the position of the decimal point wrong. */ - + if (mp_cmp_mag(&b, &S) == MP_LT) { mp_mul_d(&b, 10, &b); minit = 10; @@ -3657,7 +3674,9 @@ ShorteningBignumConversion(Double* dPtr, --k; } - /* mminus = 2**m2minus * 5**m5 */ + /* + * mminus = 2**m2minus * 5**m5 + */ mp_init_set_int(&mminus, minit); mp_mul_2d(&mminus, m2minus, &mminus); @@ -3667,7 +3686,9 @@ ShorteningBignumConversion(Double* dPtr, } mp_init(&temp); - /* Loop through the digits */ + /* + * Loop through the digits. + */ mp_init(&dig); i = 1; @@ -3678,17 +3699,15 @@ ShorteningBignumConversion(Double* dPtr, } digit = dig.dp[0]; - /* + /* * Does the current digit leave us with a remainder small enough to * round to it? */ r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus); - if (r1 == MP_LT - || (r1 == MP_EQ - && convType != TCL_DD_STEELE0 - && (dPtr->w.word1 & 1) == 0)) { - mp_mul_2d(&b, 1, &b); + if (r1 == MP_LT || (r1 == MP_EQ + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { + mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { ++digit; if (digit == 10) { @@ -3702,12 +3721,12 @@ ShorteningBignumConversion(Double* dPtr, } /* - * Does the current digit leave us with a remainder large enough - * to commit to rounding up to the next higher digit? + * Does the current digit leave us with a remainder large enough to + * commit to rounding up to the next higher digit? */ if (ShouldBankerRoundUpToNext(&b, &mminus, &S, convType, - dPtr->w.word1 & 1, &temp)) { + dPtr->w.word1 & 1, &temp)) { ++digit; if (digit == 10) { *s++ = '9'; @@ -3718,22 +3737,28 @@ ShorteningBignumConversion(Double* dPtr, break; } - /* Have we converted all the requested digits? */ + /* + * Have we converted all the requested digits? + */ *s++ = '0' + digit; if (i == ilim) { mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { - s = BumpUp(s, retval, &k); + s = BumpUp(s, retval, &k); } break; } - /* Advance to the next digit */ + /* + * Advance to the next digit. + */ if (s5 > 0) { + /* + * Can possibly shorten the denominator. + */ - /* Can possibly shorten the denominator */ mp_mul_2d(&b, 1, &b); mp_mul_2d(&mminus, 1, &mminus); if (m2plus > m2minus) { @@ -3741,17 +3766,18 @@ ShorteningBignumConversion(Double* dPtr, } mp_div_d(&S, 5, &S, NULL); --s5; - /* - * TODO: It might possibly be a win to fall back to - * int64 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 denominator by at least 1 mp_digit, perhaps - * 2. as we do the conversion for 17 digits of significance. + + /* + * TODO: It might possibly be a win to fall back to int64 + * 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 + * denominator by at least 1 mp_digit, perhaps 2, as we do + * the conversion for 17 digits of significance. * Possible savings: * 10**26 1 trip through loop before fallback possible * 10**27 1 trip - * 10**28 2 trips + * 10**28 2 trips * 10**29 3 trips * 10**30 4 trips * 10**31 5 trips @@ -3766,7 +3792,7 @@ ShorteningBignumConversion(Double* dPtr, * 10**40 14 trips * 10**41 15 trips * 10**42 16 trips - * thereafter no gain. + * thereafter no gain. */ } else { mp_mul_d(&b, 10, &b); @@ -3779,11 +3805,11 @@ ShorteningBignumConversion(Double* dPtr, ++i; } - - /* + /* * Endgame - store the location of the decimal point and the end of the * string. */ + if (m2plus > m2minus) { mp_clear(&mplus); } @@ -3794,59 +3820,51 @@ ShorteningBignumConversion(Double* dPtr, *endPtr = s; } return retval; - } - + /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * StrictBignumConversion -- * - * Convert a floating point number to a fixed-length digit string - * using the multiprecision method. + * Convert a floating point number to a fixed-length digit string using + * the multiprecision method. * * Results: * Returns the string of digits. * * Side effects: - * Stores the position of the decimal point in *decpt. - * Stores a pointer to the end of the number in *endPtr. + * Stores the position of the decimal point in *decpt. Stores a pointer + * to the end of the number in *endPtr. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -inline static char* -StrictBignumConversion(Double* dPtr, - /* Original number being converted */ - int convType, - /* Conversion type */ - Tcl_WideUInt bw, - /* Integer significand and exponent */ - int b2, /* Scale factor for the significand */ - int s2, int s5, - /* Scale factors for denominator */ - int k, /* Guessed position of the decimal point */ - int len, /* Size of the digit buffer to allocate */ - int ilim, - /* Number of digits to convert if b >= s */ - int ilim1, - /* Number of digits to convert if b < s */ - int* decpt, - /* OUTPUT: Position of the decimal point */ - char** endPtr) - /* OUTPUT: Pointer to the end of the number */ +inline static char * +StrictBignumConversion( + Double *dPtr, /* Original number being converted. */ + int convType, /* Conversion type. */ + Tcl_WideUInt bw, /* Integer significand and exponent. */ + int b2, /* Scale factor for the significand. */ + int s2, int s5, /* Scale factors for denominator. */ + int k, /* Guessed position of the decimal point. */ + int len, /* Size of the digit buffer to allocate. */ + int ilim, /* Number of digits to convert if b >= s */ + int ilim1, /* Number of digits to convert if b < s */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + char **endPtr) /* OUTPUT: Pointer to the end of the number */ { - char* retval = ckalloc(len+1); - /* Buffer of digits to return */ - char* s = retval; /* Cursor in the return value */ - mp_int b; /* Numerator of the result */ - mp_int S; /* Denominator of the result */ - mp_int dig; /* Current digit of the result */ - int digit; /* Current digit of the result */ - mp_int temp; /* Work area */ - int g; /* Size of the current digit groun */ + char *retval = ckalloc(len+1); + /* Buffer of digits to return. */ + char *s = retval; /* Cursor in the return value. */ + mp_int b; /* Numerator of the result. */ + mp_int S; /* Denominator of the result. */ + mp_int dig; /* Current digit of the result. */ + int digit; /* Current digit of the result. */ + mp_int temp; /* Work area. */ + int g; /* Size of the current digit ground. */ int i, j; - + /* * b = bw * 2**b2 * 5**b5 * S = 2**s2 * 5*s5 @@ -3858,10 +3876,9 @@ StrictBignumConversion(Double* dPtr, MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S); /* - * Handle the case where we guess the position of the decimal point - * wrong. + * Handle the case where we guess the position of the decimal point wrong. */ - + if (mp_cmp_mag(&b, &S) == MP_LT) { mp_mul_d(&b, 10, &b); ilim =ilim1; @@ -3869,29 +3886,33 @@ StrictBignumConversion(Double* dPtr, } mp_init(&temp); - /* Convert the leading digit */ + /* + * Convert the leading digit. + */ mp_init(&dig); i = 0; mp_div(&b, &S, &dig, &b); if (dig.used > 1 || dig.dp[0] >= 10) { - Tcl_Panic("wrong digit!"); - } + Tcl_Panic("wrong digit!"); + } digit = dig.dp[0]; - /* Is a single digit all that was requested? */ + /* + * Is a single digit all that was requested? + */ *s++ = '0' + digit; if (++i >= ilim) { mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { - s = BumpUp(s, retval, &k); + s = BumpUp(s, retval, &k); } } else { - for (;;) { - - /* Shift by a group of digits. */ + /* + * Shift by a group of digits. + */ g = ilim - i; if (g > DIGIT_GROUP) { @@ -3908,20 +3929,19 @@ StrictBignumConversion(Double* dPtr, mp_mul_d(&b, dpow5[g], &b); } mp_mul_2d(&b, g, &b); - + /* - * 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 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. + * 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 + * 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. + * + * Extract the next group of digits. */ - /* Extract the next group of digits */ - mp_div(&b, &S, &dig, &b); if (dig.used > 1) { Tcl_Panic("wrong digit!"); @@ -3929,26 +3949,31 @@ StrictBignumConversion(Double* dPtr, digit = dig.dp[0]; for (j = g-1; j >= 0; --j) { int t = itens[j]; + *s++ = digit / t + '0'; digit %= t; } i += g; - - /* Have we converted all the requested digits? */ - + + /* + * Have we converted all the requested digits? + */ + if (i == ilim) { mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { - s = BumpUp(s, retval, &k); + s = BumpUp(s, retval, &k); } break; } } } - /* + + /* * Endgame - store the location of the decimal point and the end of the * string. */ + mp_clear_multi(&b, &temp, NULL); *s = '\0'; *decpt = k; @@ -3956,120 +3981,120 @@ StrictBignumConversion(Double* dPtr, *endPtr = s; } return retval; - } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TclDoubleDigits -- * - * Core of Tcl's conversion of double-precision floating point numbers - * to decimal. + * Core of Tcl's conversion of double-precision floating point numbers to + * decimal. * * Results: * Returns a newly-allocated string of digits. * * Side effects: * Sets *decpt to the index of the character in the string before the - * place that the decimal point should go. If 'endPtr' is not NULL, - * sets endPtr to point to the terminating '\0' byte of the string. - * Sets *sign to 1 if a minus sign should be printed with the number, - * or 0 if a plus sign (or no sign) should appear. + * place that the decimal point should go. If 'endPtr' is not NULL, sets + * endPtr to point to the terminating '\0' byte of the string. Sets *sign + * to 1 if a minus sign should be printed with the number, or 0 if a plus + * sign (or no sign) should appear. * - * This function is a service routine that produces the string of digits - * for floating-point-to-decimal conversion. It can do a number of things + * This function is a service routine that produces the string of digits for + * floating-point-to-decimal conversion. It can do a number of things * according to the 'flags' argument. Valid values for 'flags' include: - * TCL_DD_SHORTEST - This is the default for floating point conversion - * if ::tcl_precision is 0. It constructs the shortest string - * of digits that will reconvert to the given number when scanned. + * TCL_DD_SHORTEST - This is the default for floating point conversion if + * ::tcl_precision is 0. It constructs the shortest string of + * digits that will reconvert to the given number when scanned. * For floating point numbers that are exactly between two * decimal numbers, it resolves using the 'round to even' rule. * With this value, the 'ndigits' parameter is ignored. - * TCL_DD_STEELE - This value is not recommended and may be removed - * in the future. It follows the conversion algorithm outlined - * in "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, - * pp. 112-126]. This rule has the effect of rendering 1e23 - * as 9.9999999999999999e22 - which is a 'better' approximation - * in the sense that it will reconvert correctly even if - * a subsequent input conversion is 'round up' or 'round down' + * TCL_DD_STEELE - This value is not recommended and may be removed in + * the future. It follows the conversion algorithm outlined in + * "How to Print Floating-Point Numbers Accurately" by Guy + * L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, + * pp. 112-126]. This rule has the effect of rendering 1e23 as + * 9.9999999999999999e22 - which is a 'better' approximation in + * the sense that it will reconvert correctly even if a + * subsequent input conversion is 'round up' or 'round down' * rather than 'round to nearest', but is surprising otherwise. - * TCL_DD_E_FORMAT - This value is used to prepare numbers for %e - * format conversion (or for default floating->string if - * tcl_precision is not 0). It constructs a string of at most - * 'ndigits' digits, choosing the one that is closest to the - * given number (and resolving ties with 'round to even'). - * It is allowed to return fewer than 'ndigits' if the number - * converts exactly; if the TCL_DD_E_FORMAT|TCL_DD_SHORTEN_FLAG - * is supplied instead, it is also allowed to return fewer digits - * if the shorter string will still reconvert to the given - * input number. - * TCL_DD_F_FORMAT - This value is used to prepare numbers for %f - * format conversion. It requests that conversion proceed until + * TCL_DD_E_FORMAT - This value is used to prepare numbers for %e format + * conversion (or for default floating->string if tcl_precision + * is not 0). It constructs a string of at most 'ndigits' digits, + * choosing the one that is closest to the given number (and + * resolving ties with 'round to even'). It is allowed to return + * fewer than 'ndigits' if the number converts exactly; if the + * TCL_DD_E_FORMAT|TCL_DD_SHORTEN_FLAG is supplied instead, it is + * also allowed to return fewer digits if the shorter string will + * still reconvert to the given input number. + * TCL_DD_F_FORMAT - This value is used to prepare numbers for %f format + * conversion. It requests that conversion proceed until * 'ndigits' digits after the decimal point have been converted. - * It is possible for this format to result in a zero-length - * string if the number is sufficiently small. Again, it - * is permissible for TCL_DD_F_FORMAT to return fewer digits - * for a number that converts exactly, and changing the - * argument to TCL_DD_F_FORMAT|TCL_DD_SHORTEN_FLAG will allow - * the routine also to return fewer digits if the shorter string - * will still reconvert without loss to the given input number. - * - * To any of these flags may be OR'ed TCL_DD_NO_QUICK; this flag - * requires all calculations to be done in exact arithmetic. Normally, - * E and F format with fewer than about 14 digits will be done with - * a quick floating point approximation and fall back on the exact - * arithmetic only if the input number is close enough to the - * midpoint between two decimal strings that more precision is needed - * to resolve which string is correct. - * - * The value stored in the 'decpt' argument on return may be negative - * (indicating that the decimal point falls to the left of the string) - * or greater than the length of the string. In addition, the value -9999 - * is used as a sentinel to indicate that the string is one of the special - * values "Infinity" and "NaN", and that no decimal point should be inserted. - * - *----------------------------------------------------------------------------- + * It is possible for this format to result in a zero-length + * string if the number is sufficiently small. Again, it is + * permissible for TCL_DD_F_FORMAT to return fewer digits for a + * number that converts exactly, and changing the argument to + * TCL_DD_F_FORMAT|TCL_DD_SHORTEN_FLAG will allow the routine + * also to return fewer digits if the shorter string will still + * reconvert without loss to the given input number. + * + * To any of these flags may be OR'ed TCL_DD_NO_QUICK; this flag requires + * all calculations to be done in exact arithmetic. Normally, E and F + * format with fewer than about 14 digits will be done with a quick + * floating point approximation and fall back on the exact arithmetic + * only if the input number is close enough to the midpoint between two + * decimal strings that more precision is needed to resolve which string + * is correct. + * + * The value stored in the 'decpt' argument on return may be negative + * (indicating that the decimal point falls to the left of the string) or + * greater than the length of the string. In addition, the value -9999 is used + * as a sentinel to indicate that the string is one of the special values + * "Infinity" and "NaN", and that no decimal point should be inserted. + * + *---------------------------------------------------------------------- */ -char* -TclDoubleDigits(double dv, /* Number to convert */ - int ndigits, /* Number of digits requested */ - int flags, /* Conversion flags */ - int* decpt, /* OUTPUT: Position of the decimal point */ - int* sign, /* OUTPUT: 1 if the result is negative */ - char** endPtr) /* OUTPUT: If not NULL, receives a pointer - * to one character beyond the end - * of the returned string */ + +char * +TclDoubleDigits( + double dv, /* Number to convert. */ + int ndigits, /* Number of digits requested. */ + int flags, /* Conversion flags. */ + int *decpt, /* OUTPUT: Position of the decimal point. */ + int *sign, /* OUTPUT: 1 if the result is negative. */ + char **endPtr) /* OUTPUT: If not NULL, receives a pointer to + * one character beyond the end of the + * returned string. */ { int convType = (flags & TCL_DD_CONVERSION_TYPE_MASK); - /* Type of conversion being performed - * TCL_DD_SHORTEST0 - * TCL_DD_STEELE0 - * TCL_DD_E_FORMAT - * TCL_DD_F_FORMAT */ - Double d; /* Union for deconstructing doubles */ - Tcl_WideUInt bw; /* Integer significand */ + /* Type of conversion being performed: + * TCL_DD_SHORTEST0, TCL_DD_STEELE0, + * TCL_DD_E_FORMAT, or TCL_DD_F_FORMAT. */ + Double d; /* Union for deconstructing doubles. */ + Tcl_WideUInt bw; /* Integer significand. */ int be; /* Power of 2 by which b must be multiplied */ - int bbits; /* Number of bits needed to represent b */ + int bbits; /* Number of bits needed to represent b. */ int denorm; /* Flag == 1 iff the input number was - * denormalized */ - int k; /* Estimate of floor(log10(d)) */ - int k_check; /* Flag == 1 if d is near enough to a - * power of ten that k must be checked */ + * denormalized. */ + int k; /* Estimate of floor(log10(d)). */ + int k_check; /* Flag == 1 if d is near enough to a power of + * ten that k must be checked. */ int b2, b5, s2, s5; /* Powers of 2 and 5 in the numerator and - * denominator of intermediate results */ - int ilim = -1, ilim1 = -1; /* Number of digits to convert, and number - * to convert if log10(d) has been - * overestimated */ - char* retval; /* Return value from this function */ + * denominator of intermediate results. */ + int ilim = -1, ilim1 = -1; /* Number of digits to convert, and number to + * convert if log10(d) has been + * overestimated. */ + char *retval; /* Return value from this function. */ int i = -1; - /* Put the input number into a union for bit-whacking */ + /* + * Put the input number into a union for bit-whacking. + */ d.d = dv; - /* + /* * Handle the cases of negative numbers (by taking the absolute value: * this includes -Inf and -NaN!), infinity, Not a Number, and zero. */ @@ -4082,12 +4107,12 @@ TclDoubleDigits(double dv, /* Number to convert */ return FormatZero(decpt, endPtr); } - /* + /* * Unpack the floating point into a wide integer and an exponent. - * Determine the number of bits that the big integer requires, and - * compute a quick approximation (which may be one too high) of - * ceil(log10(d.d)). + * Determine the number of bits that the big integer requires, and compute + * a quick approximation (which may be one too high) of ceil(log10(d.d)). */ + denorm = ((d.w.word0 & EXP_MASK) == 0); DoubleToExpAndSig(d.d, &bw, &be, &bbits); k = ApproximateLog10(bw, be, bbits); @@ -4095,60 +4120,59 @@ TclDoubleDigits(double dv, /* Number to convert */ /* At this point, we have: * d is the number to convert. - * bw are significand and exponent: d == bw*2**be, + * bw are significand and exponent: d == bw*2**be, * bbits is the length of bw: 2**bbits-1 <= bw < 2**bbits - * k is either ceil(log10(d)) or ceil(log10(d))+1. k_check is 0 - * if we know that k is exactly ceil(log10(d)) and 1 if we need to - * check. - * We want a rational number + * k is either ceil(log10(d)) or ceil(log10(d))+1. k_check is 0 if we + * know that k is exactly ceil(log10(d)) and 1 if we need to check. + * We want a rational number * r = b * 10**(1-k) = bw * 2**b2 * 5**b5 / (2**s2 / 5**s5), * with b2, b5, s2, s5 >= 0. Note that the most significant decimal - * digit is floor(r) and that successive digits can be obtained - * by setting r <- 10*floor(r) (or b <= 10 * (b % S)). - * Find appropriate b2, b5, s2, s5. + * digit is floor(r) and that successive digits can be obtained by + * setting r <- 10*floor(r) (or b <= 10 * (b % S)). Find appropriate + * b2, b5, s2, s5. */ ComputeScale(be, k, &b2, &b5, &s2, &s5); /* - * Correct an incorrect caller-supplied 'ndigits'. - * Also determine: + * Correct an incorrect caller-supplied 'ndigits'. Also determine: * i = The maximum number of decimal digits that will be returned in the * formatted string. This is k + 1 + ndigits for F format, 18 for - * shortest and Steele, and ndigits for E format. - * ilim = The number of significant digits to convert if - * k has been guessed correctly. This is -1 for shortest and Steele - * (which stop when all significance has been lost), 'ndigits' - * for E format, and 'k + 1 + ndigits' for F format. - * ilim1 = The minimum number of significant digits to convert if - * k has been guessed 1 too high. This, too, is -1 for shortest - * and Steele, and 'ndigits' for E format, but it's 'ndigits-1' - * for F format. + * shortest and Steele, and ndigits for E format. + * ilim = The number of significant digits to convert if k has been + * guessed correctly. This is -1 for shortest and Steele (which + * stop when all significance has been lost), 'ndigits' for E + * format, and 'k + 1 + ndigits' for F format. + * ilim1 = The minimum number of significant digits to convert if k has + * been guessed 1 too high. This, too, is -1 for shortest and + * Steele, and 'ndigits' for E format, but it's 'ndigits-1' for F + * format. */ SetPrecisionLimits(convType, k, &ndigits, &i, &ilim, &ilim1); - /* - * Try to do low-precision conversion in floating point rather - * than resorting to expensive multiprecision arithmetic + /* + * Try to do low-precision conversion in floating point rather than + * resorting to expensive multiprecision arithmetic. */ + if (ilim >= 0 && ilim <= QUICK_MAX && !(flags & TCL_DD_NO_QUICK)) { - if ((retval = QuickConversion(d.d, k, k_check, flags, - i, ilim, ilim1, - decpt, endPtr)) != NULL) { + retval = QuickConversion(d.d, k, k_check, flags, i, ilim, ilim1, + decpt, endPtr); + if (retval != NULL) { return retval; } } - /* - * For shortening conversions, determine the upper and lower bounds - * for the remainder at which we can stop. - * m+ = (2**m2plus * 5**m5) / (2**s2 * 5**s5) is the limit on the - * high side, and - * m- = (2**m2minus * 5**m5) / (2**s2 * 5**s5) is the limit on the - * low side. - * We may need to increase s2 to put m2plus, m2minus, b2 over a - * common denominator. + /* + * For shortening conversions, determine the upper and lower bounds for + * the remainder at which we can stop. + * m+ = (2**m2plus * 5**m5) / (2**s2 * 5**s5) is the limit on the high + * side, and + * m- = (2**m2minus * 5**m5) / (2**s2 * 5**s5) is the limit on the low + * side. + * We may need to increase s2 to put m2plus, m2minus, b2 over a common + * denominator. */ if (flags & TCL_DD_SHORTEN_FLAG) { @@ -4157,11 +4181,11 @@ TclDoubleDigits(double dv, /* Number to convert */ int m5 = b5; int len = i; - /* - * Find the quantity i so that (2**i*5**b5)/(2**s2*5**s5) - * is 1/2 unit in the least significant place of the floating - * point number. + /* + * Find the quantity i so that (2**i*5**b5)/(2**s2*5**s5) is 1/2 unit + * in the least significant place of the floating point number. */ + if (denorm) { i = be + EXPONENT_BIAS + (FP_PRECISION-1); } else { @@ -4170,16 +4194,18 @@ TclDoubleDigits(double dv, /* Number to convert */ b2 += i; s2 += i; - /* + /* * Reduce the fractions to lowest terms, since the above calculation - * may have left excess powers of 2 in numerator and denominator + * may have left excess powers of 2 in numerator and denominator. */ + CastOutPowersOf2(&b2, &m2minus, &s2); /* * In the special case where bw==1, the nearest floating point number * to it on the low side is 1/4 ulp below it. Adjust accordingly. */ + m2plus = m2minus; if (!denorm && bw == 1) { ++b2; @@ -4187,60 +4213,56 @@ TclDoubleDigits(double dv, /* Number to convert */ ++m2plus; } - if (s5+1 < N_LOG2POW5 - && s2+1 + log2pow5[s5+1] <= 64) { + if (s5+1 < N_LOG2POW5 && s2+1 + log2pow5[s5+1] <= 64) { /* - * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit - * word, then all our intermediate calculations can be done - * using exact 64-bit arithmetic with no need for expensive - * multiprecision operations. (This will be true for all numbers - * in the range [1.0e-3 .. 1.0e+24]). + * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit word, + * then all our intermediate calculations can be done using exact + * 64-bit arithmetic with no need for expensive multiprecision + * operations. (This will be true for all numbers in the range + * [1.0e-3 .. 1.0e+24]). */ - return ShorteningInt64Conversion(&d, convType, bw, b2, b5, - m2plus, m2minus, m5, - s2, s5, k, len, ilim, ilim1, - decpt, endPtr); + return ShorteningInt64Conversion(&d, convType, bw, b2, b5, m2plus, + m2minus, m5, s2, s5, k, len, ilim, ilim1, decpt, endPtr); } else if (s5 == 0) { /* - * The denominator is a power of 2, so we can replace division - * by digit shifts. First we round up s2 to a multiple of - * DIGIT_BIT, and adjust m2 and b2 accordingly. Then we launch - * into a version of the comparison that's specialized for - * the 'power of mp_digit in the denominator' case. + * The denominator is a power of 2, so we can replace division by + * digit shifts. First we round up s2 to a multiple of DIGIT_BIT, + * and adjust m2 and b2 accordingly. Then we launch into a version + * of the comparison that's specialized for the 'power of mp_digit + * in the denominator' case. */ + if (s2 % DIGIT_BIT != 0) { int delta = DIGIT_BIT - (s2 % DIGIT_BIT); + b2 += delta; m2plus += delta; m2minus += delta; s2 += delta; } return ShorteningBignumConversionPowD(&d, convType, bw, b2, b5, - m2plus, m2minus, m5, - s2/DIGIT_BIT, k, len, - ilim, ilim1, decpt, endPtr); + m2plus, m2minus, m5, s2/DIGIT_BIT, k, len, ilim, ilim1, + decpt, endPtr); } else { - - /* - * Alas, there's no helpful special case; use full-up - * bignum arithmetic for the conversion + /* + * Alas, there's no helpful special case; use full-up bignum + * arithmetic for the conversion. */ - return ShorteningBignumConversion(&d, convType, bw, - b2, m2plus, m2minus, - s2, s5, k, len, - ilim, ilim1, decpt, endPtr); - + return ShorteningBignumConversion(&d, convType, bw, b2, m2plus, + m2minus, s2, s5, k, len, ilim, ilim1, decpt, endPtr); } - } else { - - /* Non-shortening conversion */ + /* + * Non-shortening conversion. + */ int len = i; - /* Reduce numerator and denominator to lowest terms */ + /* + * Reduce numerator and denominator to lowest terms. + */ if (b2 >= s2 && s2 > 0) { b2 -= s2; s2 = 0; @@ -4248,48 +4270,46 @@ TclDoubleDigits(double dv, /* Number to convert */ s2 -= b2; b2 = 0; } - if (s5+1 < N_LOG2POW5 - && s2+1 + log2pow5[s5+1] <= 64) { + if (s5+1 < N_LOG2POW5 && s2+1 + log2pow5[s5+1] <= 64) { /* - * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit - * word, then all our intermediate calculations can be done - * using exact 64-bit arithmetic with no need for expensive - * multiprecision operations. + * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit word, + * then all our intermediate calculations can be done using exact + * 64-bit arithmetic with no need for expensive multiprecision + * operations. */ - return StrictInt64Conversion(&d, convType, bw, b2, b5, - s2, s5, k, len, ilim, ilim1, - decpt, endPtr); - + return StrictInt64Conversion(&d, convType, bw, b2, b5, s2, s5, k, + len, ilim, ilim1, decpt, endPtr); } else if (s5 == 0) { /* - * The denominator is a power of 2, so we can replace division - * by digit shifts. First we round up s2 to a multiple of - * DIGIT_BIT, and adjust m2 and b2 accordingly. Then we launch - * into a version of the comparison that's specialized for - * the 'power of mp_digit in the denominator' case. + * The denominator is a power of 2, so we can replace division by + * digit shifts. First we round up s2 to a multiple of DIGIT_BIT, + * and adjust m2 and b2 accordingly. Then we launch into a version + * of the comparison that's specialized for the 'power of mp_digit + * in the denominator' case. */ + if (s2 % DIGIT_BIT != 0) { int delta = DIGIT_BIT - (s2 % DIGIT_BIT); + b2 += delta; s2 += delta; } return StrictBignumConversionPowD(&d, convType, bw, b2, b5, - s2/DIGIT_BIT, k, len, - ilim, ilim1, decpt, endPtr); + s2/DIGIT_BIT, k, len, ilim, ilim1, decpt, endPtr); } else { /* - * There are no helpful special cases, but at least we know - * in advance how many digits we will convert. We can run the - * conversion in steps of DIGIT_GROUP digits, so as to - * have many fewer mp_int divisions. + * There are no helpful special cases, but at least we know in + * advance how many digits we will convert. We can run the + * conversion in steps of DIGIT_GROUP digits, so as to have many + * fewer mp_int divisions. */ - return StrictBignumConversion(&d, convType, bw, b2, s2, s5, - k, len, ilim, ilim1, decpt, endPtr); + + return StrictBignumConversion(&d, convType, bw, b2, s2, s5, k, + len, ilim, ilim1, decpt, endPtr); } - } + } } - /* *---------------------------------------------------------------------- @@ -4317,14 +4337,12 @@ TclInitDoubleConversion(void) int x; Tcl_WideUInt u; double d; - #ifdef IEEE_FLOATING_POINT union { double dv; Tcl_WideUInt iv; } bitwhack; #endif - #if defined(__sgi) && defined(_COMPILER_VERSION) union fpc_csr mipsCR; @@ -4349,8 +4367,8 @@ TclInitDoubleConversion(void) pow10_wide[i] = u; /* - * Determine how many bits of precision a double has, and how many - * decimal digits that represents. + * Determine how many bits of precision a double has, and how many decimal + * digits that represents. */ if (frexp((double) FLT_RADIX, &log2FLT_RADIX) != 0.5) { @@ -4361,8 +4379,8 @@ TclInitDoubleConversion(void) d = 1.0; /* - * Initialize a table of powers of ten that can be exactly represented - * in a double. + * Initialize a table of powers of ten that can be exactly represented in + * a double. */ x = (int) (DBL_MANT_DIG * log((double) FLT_RADIX) / log(5.0)); @@ -4474,9 +4492,9 @@ TclFinalizeDoubleConversion(void) int Tcl_InitBignumFromDouble( - Tcl_Interp *interp, /* For error message */ - double d, /* Number to convert */ - mp_int *b) /* Place to store the result */ + Tcl_Interp *interp, /* For error message. */ + double d, /* Number to convert. */ + mp_int *b) /* Place to store the result. */ { double fract; int expt; @@ -4590,7 +4608,7 @@ TclBignumToDouble( } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TclCeil -- * @@ -4600,7 +4618,7 @@ TclBignumToDouble( * Results: * Returns the floating point number. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ double @@ -4647,17 +4665,17 @@ TclCeil( } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TclFloor -- * - * Computes the largest floating point number less than or equal to - * the mp_int argument. + * Computes the largest floating point number less than or equal to the + * mp_int argument. * * Results: * Returns the floating point value. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ double @@ -4718,8 +4736,8 @@ TclFloor( static double BignumToBiasedFrExp( - const mp_int *a, /* Integer to convert */ - int *machexp) /* Power of two */ + const mp_int *a, /* Integer to convert. */ + int *machexp) /* Power of two. */ { mp_int b; int bits; @@ -4783,8 +4801,8 @@ BignumToBiasedFrExp( static double Pow10TimesFrExp( - int exponent, /* Power of 10 to multiply by */ - double fraction, /* Significand of multiplicand */ + int exponent, /* Power of 10 to multiply by. */ + double fraction, /* Significand of multiplicand. */ int *machexp) /* On input, exponent of multiplicand. On * output, exponent of result. */ { @@ -4794,7 +4812,7 @@ Pow10TimesFrExp( if (exponent > 0) { /* - * Multiply by 10**exponent + * Multiply by 10**exponent. */ retval = frexp(retval * pow10vals[exponent&0xf], &j); @@ -4807,7 +4825,7 @@ Pow10TimesFrExp( } } else if (exponent < 0) { /* - * Divide by 10**-exponent + * Divide by 10**-exponent. */ retval = frexp(retval / pow10vals[(-exponent) & 0xf], &j); @@ -4916,26 +4934,27 @@ TclFormatNaN( * * Nokia770Twiddle -- * - * Transpose the two words of a number for Nokia 770 floating - * point handling. + * Transpose the two words of a number for Nokia 770 floating point + * handling. * *---------------------------------------------------------------------- */ - +#ifdef IEEE_FLOATING_POINT static Tcl_WideUInt Nokia770Twiddle( - Tcl_WideUInt w) /* Number to transpose */ + Tcl_WideUInt w) /* Number to transpose. */ { return (((w >> 32) & 0xffffffff) | (w << 32)); } +#endif /* *---------------------------------------------------------------------- * * TclNokia770Doubles -- * - * Transpose the two words of a number for Nokia 770 floating - * point handling. + * Transpose the two words of a number for Nokia 770 floating point + * handling. * *---------------------------------------------------------------------- */ diff --git a/generic/tclTrace.c b/generic/tclTrace.c index 2e8759e..755614a 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.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: tclTrace.c,v 1.60 2010/08/22 18:53:26 nijtmans Exp $ + * RCS: @(#) $Id: tclTrace.c,v 1.60.2.1 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -24,11 +24,11 @@ typedef struct { int flags; /* Operations for which Tcl command is to be * invoked. */ size_t length; /* Number of non-NUL chars. in command. */ - char command[4]; /* Space for Tcl command to invoke. Actual + char command[1]; /* Space for Tcl command to invoke. Actual * size will be as large as necessary to hold * command. This field must be the last in the - * structure, so that it can be larger than 4 - * bytes. */ + * structure, so that it can be larger than 1 + * byte. */ } TraceVarInfo; typedef struct { @@ -58,11 +58,11 @@ typedef struct { * deleted too early. Keeps track of how many * pieces of code have a pointer to this * structure. */ - char command[4]; /* Space for Tcl command to invoke. Actual + char command[1]; /* Space for Tcl command to invoke. Actual * size will be as large as necessary to hold * command. This field must be the last in the - * structure, so that it can be larger than 4 - * bytes. */ + * structure, so that it can be larger than 1 + * byte. */ } TraceCommandInfo; /* @@ -464,9 +464,8 @@ TraceExecutionObjCmd( length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) - ckalloc((unsigned) (sizeof(TraceCommandInfo) - - sizeof(tcmdPtr->command) + length + 1)); - + ckalloc((unsigned) ((TclOffset(TraceCommandInfo, command) + + 1) + length)); tcmdPtr->flags = flags; tcmdPtr->stepTrace = NULL; tcmdPtr->startLevel = 0; @@ -701,8 +700,8 @@ TraceCommandObjCmd( length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) - ckalloc((unsigned) (sizeof(TraceCommandInfo) - - sizeof(tcmdPtr->command) + length + 1)); + ckalloc((unsigned) ((TclOffset(TraceCommandInfo, command) + + 1) + length)); tcmdPtr->flags = flags; tcmdPtr->stepTrace = NULL; @@ -902,8 +901,8 @@ TraceVariableObjCmd( length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { CombinedTraceVarInfo *ctvarPtr = (CombinedTraceVarInfo *) - ckalloc((unsigned) (sizeof(CombinedTraceVarInfo) - + length + 1 - sizeof(ctvarPtr->traceCmdInfo.command))); + ckalloc((unsigned) ((TclOffset(CombinedTraceVarInfo, + traceCmdInfo.command) + 1) + length)); ctvarPtr->traceCmdInfo.flags = flags; if (objv[0] == NULL) { diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 4e43176..2e435e6 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.117.2.2 2010/12/01 16:42:36 kennykb Exp $ + * RCS: @(#) $Id: tclUtil.c,v 1.117.2.3 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -2527,7 +2527,7 @@ TclFormatInt(buffer, n) long intVal; int i; int numFormatted, j; - char *digits = "0123456789"; + const char *digits = "0123456789"; /* * Check first whether "n" is zero. @@ -3328,7 +3328,7 @@ TclReToGlob( Tcl_DString *dsPtr, int *exactPtr) { - int anchorLeft, anchorRight, lastIsStar; + int anchorLeft, anchorRight, lastIsStar, numStars; char *dsStr, *dsStrStart; const char *msg, *p, *strEnd; @@ -3387,6 +3387,7 @@ TclReToGlob( p = reStr; anchorRight = 0; lastIsStar = 0; + numStars = 0; if (*p == '^') { anchorLeft = 1; @@ -3450,6 +3451,7 @@ TclReToGlob( if (!lastIsStar) { *dsStr++ = '*'; lastIsStar = 1; + numStars++; } continue; } else if (p[1] == '+') { @@ -3457,6 +3459,7 @@ TclReToGlob( *dsStr++ = '?'; *dsStr++ = '*'; lastIsStar = 1; + numStars++; continue; } } @@ -3480,6 +3483,15 @@ TclReToGlob( } lastIsStar = 0; } + if (numStars > 1) { + /* + * Heuristic: if >1 non-anchoring *, the risk is large that glob + * matching is slower than the RE engine, so report invalid. + */ + msg = "excessive recursive glob backtrack potential"; + goto invalidGlob; + } + if (!anchorRight && !lastIsStar) { *dsStr++ = '*'; } diff --git a/generic/tclVar.c b/generic/tclVar.c index 75363cf..2d67a7c 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -16,7 +16,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.203.2.2 2010/09/27 20:33:37 kennykb Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.203.2.3 2010/12/11 18:39:29 kennykb Exp $ */ #include "tclInt.h" @@ -4226,18 +4226,18 @@ TclInitArrayCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap arrayImplMap[] = { - {"anymore", ArrayAnyMoreCmd, NULL, NULL, NULL}, - {"donesearch", ArrayDoneSearchCmd, NULL, NULL, NULL}, - {"exists", ArrayExistsCmd, NULL, NULL, NULL}, - {"get", ArrayGetCmd, NULL, NULL, NULL}, - {"names", ArrayNamesCmd, NULL, NULL, NULL}, - {"nextelement", ArrayNextElementCmd, NULL, NULL, NULL}, - {"set", ArraySetCmd, NULL, NULL, NULL}, - {"size", ArraySizeCmd, NULL, NULL, NULL}, - {"startsearch", ArrayStartSearchCmd, NULL, NULL, NULL}, - {"statistics", ArrayStatsCmd, NULL, NULL, NULL}, - {"unset", ArrayUnsetCmd, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL} + {"anymore", ArrayAnyMoreCmd, NULL, NULL, NULL, 0}, + {"donesearch", ArrayDoneSearchCmd, NULL, NULL, NULL, 0}, + {"exists", ArrayExistsCmd, NULL, NULL, NULL, 0}, + {"get", ArrayGetCmd, NULL, NULL, NULL, 0}, + {"names", ArrayNamesCmd, NULL, NULL, NULL, 0}, + {"nextelement", ArrayNextElementCmd, NULL, NULL, NULL, 0}, + {"set", ArraySetCmd, NULL, NULL, NULL, 0}, + {"size", ArraySizeCmd, NULL, NULL, NULL, 0}, + {"startsearch", ArrayStartSearchCmd, NULL, NULL, NULL, 0}, + {"statistics", ArrayStatsCmd, NULL, NULL, NULL, 0}, + {"unset", ArrayUnsetCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; return TclMakeEnsemble(interp, "array", arrayImplMap); |
