From e729c2775a2779c6a58e56fd171dbee06bcc53d9 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 3 Mar 2011 21:02:15 +0000 Subject: Simplified the logic of the Scan/Convert pair of routines for generating string reps of lists to stop using the unnecessary flag BRACES_UNMATCHED. --- generic/tclUtil.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/generic/tclUtil.c b/generic/tclUtil.c index dcd2d5e..8296859 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -39,8 +39,6 @@ static ProcessGlobalValue executableName = { * USE_BRACES - 1 means the string contains a special * character that can be handled simply by * enclosing the entire argument in braces. - * BRACES_UNMATCHED - 1 means that braces aren't properly matched in - * the argument. * TCL_DONT_QUOTE_HASH - 1 means the caller insists that a leading hash * character ('#') should *not* be quoted. This * is appropriate when the caller can guarantee @@ -50,7 +48,6 @@ static ProcessGlobalValue executableName = { */ #define USE_BRACES 2 -#define BRACES_UNMATCHED 4 /* * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to @@ -720,7 +717,7 @@ Tcl_ScanCountedElement( case '}': nestingLevel--; if (nestingLevel < 0) { - flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; + flags |= TCL_DONT_USE_BRACES; } break; case '[': @@ -736,7 +733,7 @@ Tcl_ScanCountedElement( break; case '\\': if ((p+1 == lastChar) || (p[1] == '\n')) { - flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; + flags = TCL_DONT_USE_BRACES; } else { int size; @@ -748,7 +745,7 @@ Tcl_ScanCountedElement( } } if (nestingLevel != 0) { - flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; + flags = TCL_DONT_USE_BRACES; } *flagPtr = flags; @@ -848,20 +845,7 @@ Tcl_ConvertCountedElement( *p = '}'; p++; } else { - if (*src == '{') { - /* - * Can't have a leading brace unless the whole element is enclosed - * in braces. Add a backslash before the brace. Furthermore, this - * may destroy the balance between open and close braces, so set - * BRACES_UNMATCHED. - */ - - p[0] = '\\'; - p[1] = '{'; - p += 2; - src++; - flags |= BRACES_UNMATCHED; - } else if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { + if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { /* * Leading '#' could be seen by [eval] as the start of a comment, * if on the first element of a list, so quote it. @@ -895,7 +879,7 @@ Tcl_ConvertCountedElement( * backslashed. */ - if (flags & BRACES_UNMATCHED) { + if (flags & TCL_DONT_USE_BRACES) { *p = '\\'; p++; } -- cgit v0.12 From 3369c9129fa90ad0a083438bb7b066a1df3ee8d6 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 3 Mar 2011 21:07:17 +0000 Subject: Significant rewrite of the Tcl*(Scan|Convert)*Element() system, and revisions to the callers. Needs more work on comments, and testing to check for any performance impact in either direction. Fixes reported bug. --- generic/tclDictObj.c | 58 +++--- generic/tclIndexObj.c | 10 +- generic/tclInt.h | 4 + generic/tclListObj.c | 67 ++++--- generic/tclUtil.c | 497 +++++++++++++++++++++++++++++++------------------- 5 files changed, 394 insertions(+), 242 deletions(-) diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 593108f..072f3fa 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -459,19 +459,27 @@ UpdateStringOfDict( Tcl_Obj *dictPtr) { #define LOCAL_SIZE 20 - int localFlags[LOCAL_SIZE], *flagPtr; + int localFlags[LOCAL_SIZE], *flagPtr = NULL; Dict *dict = dictPtr->internalRep.otherValuePtr; ChainEntry *cPtr; Tcl_Obj *keyPtr, *valuePtr; - int numElems, i, length; + int i, length, bytesNeeded = 0; char *elem, *dst; + const int maxFlags = UINT_MAX / sizeof(int); /* * This field is the most useful one in the whole hash structure, and it * is not exposed by any API function... */ - numElems = dict->table.numEntries * 2; + int numElems = dict->table.numEntries * 2; + + /* Handle empty list case first, simplifies what follows */ + if (numElems == 0) { + dictPtr->bytes = tclEmptyStringRep; + dictPtr->length = 0; + return; + } /* * Pass 1: estimate space, gather flags. @@ -479,55 +487,63 @@ UpdateStringOfDict( if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; + } else if (numElems > maxFlags) { + Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); } else { flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int)); } - dictPtr->length = 1; for (i=0,cPtr=dict->entryChainHead; inextPtr) { /* * Assume that cPtr is never NULL since we know the number of array * elements already. */ + flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); keyPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, &cPtr->entry); elem = TclGetStringFromObj(keyPtr, &length); - dictPtr->length += Tcl_ScanCountedElement(elem, length, - &flagPtr[i]) + 1; + bytesNeeded += TclScanElement(elem, length, flagPtr+i); + if (bytesNeeded < 0) { + Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + } + flagPtr[i+1] = TCL_DONT_QUOTE_HASH; valuePtr = Tcl_GetHashValue(&cPtr->entry); elem = TclGetStringFromObj(valuePtr, &length); - dictPtr->length += Tcl_ScanCountedElement(elem, length, - &flagPtr[i+1]) + 1; + bytesNeeded += TclScanElement(elem, length, flagPtr+i+1); + if (bytesNeeded < 0) { + Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + } } + if (bytesNeeded > INT_MAX - numElems + 1) { + Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + } + bytesNeeded += numElems; /* * Pass 2: copy into string rep buffer. */ - dictPtr->bytes = ckalloc((unsigned) dictPtr->length); + dictPtr->length = bytesNeeded - 1; + dictPtr->bytes = ckalloc((unsigned) bytesNeeded); dst = dictPtr->bytes; for (i=0,cPtr=dict->entryChainHead; inextPtr) { + flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 ); keyPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, &cPtr->entry); elem = TclGetStringFromObj(keyPtr, &length); - dst += Tcl_ConvertCountedElement(elem, length, dst, - flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH)); - *(dst++) = ' '; + dst += TclConvertElement(elem, length, dst, flagPtr[i]); + *dst++ = ' '; + flagPtr[i+1] |= TCL_DONT_QUOTE_HASH; valuePtr = Tcl_GetHashValue(&cPtr->entry); elem = TclGetStringFromObj(valuePtr, &length); - dst += Tcl_ConvertCountedElement(elem, length, dst, - flagPtr[i+1] | TCL_DONT_QUOTE_HASH); - *(dst++) = ' '; + dst += TclConvertElement(elem, length, dst, flagPtr[i+1]); + *dst++ = ' '; } + dictPtr->bytes[dictPtr->length] = '\0'; + if (flagPtr != localFlags) { ckfree((char *) flagPtr); } - if (dst == dictPtr->bytes) { - *dst = 0; - } else { - *(--dst) = 0; - } - dictPtr->length = dst - dictPtr->bytes; } /* diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index af29363..dcedd4e 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -534,12 +534,13 @@ Tcl_WrongNumArgs( } else { elementStr = TclGetStringFromObj(origObjv[i], &elemLen); } - len = Tcl_ScanCountedElement(elementStr, elemLen, &flags); + flags = 0; + len = TclScanElement(elementStr, elemLen, &flags); if (MAY_QUOTE_WORD && len != elemLen) { char *quotedElementStr = TclStackAlloc(interp, (unsigned)len); - len = Tcl_ConvertCountedElement(elementStr, elemLen, + len = TclConvertElement(elementStr, elemLen, quotedElementStr, flags); Tcl_AppendToObj(objPtr, quotedElementStr, len); TclStackFree(interp, quotedElementStr); @@ -588,12 +589,13 @@ Tcl_WrongNumArgs( */ elementStr = TclGetStringFromObj(objv[i], &elemLen); - len = Tcl_ScanCountedElement(elementStr, elemLen, &flags); + flags = 0; + len = TclScanElement(elementStr, elemLen, &flags); if (MAY_QUOTE_WORD && len != elemLen) { char *quotedElementStr = TclStackAlloc(interp,(unsigned) len); - len = Tcl_ConvertCountedElement(elementStr, elemLen, + len = TclConvertElement(elementStr, elemLen, quotedElementStr, flags); Tcl_AppendToObj(objPtr, quotedElementStr, len); TclStackFree(interp, quotedElementStr); diff --git a/generic/tclInt.h b/generic/tclInt.h index 649d0cd..f6ed2d5 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2558,6 +2558,8 @@ MODULE_SCOPE void TclContinuationsEnterDerived(Tcl_Obj *objPtr, MODULE_SCOPE ContLineLoc* TclContinuationsGet(Tcl_Obj *objPtr); MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr, Tcl_Obj *originObjPtr); +MODULE_SCOPE int TclConvertElement(CONST char *src, int length, + char *dst, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); /* TIP #280 - Modified token based evulation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, @@ -2766,6 +2768,8 @@ MODULE_SCOPE void TclRememberMutex(Tcl_Mutex *mutex); MODULE_SCOPE void TclRemoveScriptLimitCallbacks(Tcl_Interp *interp); MODULE_SCOPE int TclReToGlob(Tcl_Interp *interp, const char *reStr, int reStrLen, Tcl_DString *dsPtr, int *flagsPtr); +MODULE_SCOPE int TclScanElement(CONST char *string, int length, + int *flagPtr); MODULE_SCOPE void TclSetBgErrorHandler(Tcl_Interp *interp, Tcl_Obj *cmdPrefix); MODULE_SCOPE void TclSetBignumIntRep(Tcl_Obj *objPtr, diff --git a/generic/tclListObj.c b/generic/tclListObj.c index b2a951e..3c48a2f 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -1842,74 +1842,73 @@ UpdateStringOfList( Tcl_Obj *listPtr) /* List object with string rep to update. */ { # define LOCAL_SIZE 20 - int localFlags[LOCAL_SIZE], *flagPtr; + int localFlags[LOCAL_SIZE], *flagPtr = NULL; List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; int numElems = listRepPtr->elemCount; - register int i; + int i, length, bytesNeeded = 0; char *elem, *dst; - int length; Tcl_Obj **elemPtrs; + const int maxFlags = UINT_MAX / sizeof(int); /* - * Convert each element of the list to string form and then convert it to - * proper list element form, adding it to the result buffer. + * Mark the list as being canonical; although it will now have a string + * rep, it is one we derived through proper "canonical" quoting and so + * it's known to be free from nasties relating to [concat] and [eval]. */ + listRepPtr->canonicalFlag = 1; + + /* Handle empty list case first, so rest of the routine is simpler */ + + if (numElems == 0) { + listPtr->bytes = tclEmptyStringRep; + listPtr->length = 0; + return; + } + /* * Pass 1: estimate space, gather flags. */ if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; + } else if (numElems > maxFlags) { + Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); } else { flagPtr = (int *) ckalloc((unsigned) numElems * sizeof(int)); } - listPtr->length = 1; elemPtrs = &listRepPtr->elements; for (i = 0; i < numElems; i++) { + flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); elem = TclGetStringFromObj(elemPtrs[i], &length); - listPtr->length += Tcl_ScanCountedElement(elem, length, flagPtr+i)+1; - - /* - * Check for continued sanity. [Bug 1267380] - */ - - if (listPtr->length < 1) { - Tcl_Panic("string representation size exceeds sane bounds"); + bytesNeeded += TclScanElement(elem, length, flagPtr+i); + if (bytesNeeded < 0) { + Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); } } + if (bytesNeeded > INT_MAX - numElems + 1) { + Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); + } + bytesNeeded += numElems; /* * Pass 2: copy into string rep buffer. */ - listPtr->bytes = ckalloc((unsigned) listPtr->length); + listPtr->length = bytesNeeded - 1; + listPtr->bytes = ckalloc((unsigned) bytesNeeded); dst = listPtr->bytes; for (i = 0; i < numElems; i++) { + flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 ); elem = TclGetStringFromObj(elemPtrs[i], &length); - dst += Tcl_ConvertCountedElement(elem, length, dst, - flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH)); - *dst = ' '; - dst++; + dst += TclConvertElement(elem, length, dst, flagPtr[i]); + *dst++ = ' '; } + listPtr->bytes[listPtr->length] = '\0'; + if (flagPtr != localFlags) { ckfree((char *) flagPtr); } - if (dst == listPtr->bytes) { - *dst = 0; - } else { - dst--; - *dst = 0; - } - listPtr->length = dst - listPtr->bytes; - - /* - * Mark the list as being canonical; although it has a string rep, it is - * one we derived through proper "canonical" quoting and so it's known to - * be free from nasties relating to [concat] and [eval]. - */ - - listRepPtr->canonicalFlag = 1; } /* diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 8296859..9358ede 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -645,6 +645,15 @@ Tcl_ScanElement( *---------------------------------------------------------------------- */ +#define COMPAT 1 + +#define CONVERT_NONE 0 +#define CONVERT_BRACE 2 +#define CONVERT_ESCAPE 4 +#define CONVERT_SAFE 16 +#define CONVERT_MASK (CONVERT_BRACE | CONVERT_ESCAPE) + + int Tcl_ScanCountedElement( CONST char *string, /* String to convert to Tcl list element. */ @@ -652,74 +661,73 @@ Tcl_ScanCountedElement( int *flagPtr) /* Where to store information to guide * Tcl_ConvertElement. */ { - int flags, nestingLevel; - register CONST char *p, *lastChar; + int flags = CONVERT_SAFE; + int numBytes = TclScanElement(string, length, &flags); - /* - * This function and Tcl_ConvertElement together do two things: - * - * 1. They produce a proper list, one that will yield back the argument - * strings when evaluated or when disassembled with Tcl_SplitList. This - * is the most important thing. - * - * 2. They try to produce legible output, which means minimizing the use - * of backslashes (using braces instead). However, there are some - * situations where backslashes must be used (e.g. an element like - * "{abc": the leading brace will have to be backslashed. For each - * element, one of three things must be done: - * - * (a) Use the element as-is (it doesn't contain any special - * characters). This is the most desirable option. - * - * (b) Enclose the element in braces, but leave the contents alone. - * This happens if the element contains embedded space, or if it - * contains characters with special interpretation ($, [, ;, or \), - * or if it starts with a brace or double-quote, or if there are no - * characters in the element. - * - * (c) Don't enclose the element in braces, but add backslashes to - * prevent special interpretation of special characters. This is a - * last resort used when the argument would normally fall under - * case (b) but contains unmatched braces. It also occurs if the - * last character of the argument is a backslash or if the element - * contains a backslash followed by newline. - * - * The function figures out how many bytes will be needed to store the - * result (actually, it overestimates). It also collects information about - * the element in the form of a flags word. - * - * Note: list elements produced by this function and - * Tcl_ConvertCountedElement must have the property that they can be - * enclosing in curly braces to make sub-lists. This means, for example, - * that we must not leave unmatched curly braces in the resulting list - * element. This property is necessary in order for functions like - * Tcl_DStringStartSublist to work. - */ + *flagPtr = flags; + return numBytes; +} - nestingLevel = 0; - flags = 0; - if (string == NULL) { - string = ""; - } - if (length == -1) { - length = strlen(string); +int +TclScanElement( + CONST char *string, /* String to convert to Tcl list element. */ + int length, /* Number of bytes in string, or -1. */ + int *flagPtr) /* Where to store information to guide + * Tcl_ConvertElement. */ +{ + CONST char *p = string; + int nestingLevel = 0; + int forbidNone = 0; + int requireEscape = 0; + int extra = 0; + int bytesNeeded; +#if COMPAT + int preferEscape = 0; + int preferBrace = 0; + int braceCount = 0; +#endif + + if ((p == NULL) || (length == 0)) { + *flagPtr = CONVERT_BRACE; + return 2; } - lastChar = string + length; - p = string; - if ((p == lastChar) || (*p == '{') || (*p == '"')) { - flags |= USE_BRACES; + + if ((*p == '{') || (*p == '"') || ((*p == '\0') && (length == -1))) { + forbidNone = 1; +#if COMPAT + preferBrace = 1; +#endif } - for (; p < lastChar; p++) { + + while (length) { switch (*p) { case '{': +#if COMPAT + braceCount++; +#endif + extra++; nestingLevel++; break; case '}': +#if COMPAT + braceCount++; +#endif + extra++; nestingLevel--; if (nestingLevel < 0) { - flags |= TCL_DONT_USE_BRACES; + requireEscape = 1; } break; + case ']': + case '"': +#if COMPAT + forbidNone = 1; + extra++; + preferEscape = 1; + break; +#else + /* FLOW THROUGH */ +#endif case '[': case '$': case ';': @@ -729,32 +737,103 @@ Tcl_ScanCountedElement( case '\r': case '\t': case '\v': - flags |= USE_BRACES; + forbidNone = 1; + extra++; +#if COMPAT + preferBrace = 1; +#endif break; case '\\': - if ((p+1 == lastChar) || (p[1] == '\n')) { - flags = TCL_DONT_USE_BRACES; - } else { - int size; - - Tcl_UtfBackslash(p, &size, NULL); - p += size-1; - flags |= USE_BRACES; + extra++; + if ((length == 1) || ((length == -1) && (p[1] == '\0'))) { + requireEscape = 1; + break; + } + if (p[1] == '\n') { + extra++; + requireEscape = 1; + length -= (length > 0); + p++; + break; } + if ((p[1] == '{') || (p[1] == '}')) { + extra++; + length -= (length > 0); + p++; + } + forbidNone = 1; +#if COMPAT + preferBrace = 1; +#endif + break; + case '\0': + if (length == -1) { + goto endOfString; + } + /* TODO: Panic on improper encoding? */ break; } + length -= (length > 0); + p++; } + + endOfString: if (nestingLevel != 0) { - flags = TCL_DONT_USE_BRACES; + requireEscape = 1; } - *flagPtr = flags; - /* - * Allow enough space to backslash every character plus leave two spaces - * for braces. - */ + bytesNeeded = p - string; + + if (requireEscape) { + bytesNeeded += extra; + if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + bytesNeeded++; + } + *flagPtr = CONVERT_ESCAPE; + goto overflowCheck; + } + if (*flagPtr & CONVERT_SAFE) { + if (extra < 2) { + extra = 2; + } + *flagPtr |= TCL_DONT_USE_BRACES; + } + if (forbidNone) { +#if COMPAT + if (preferEscape && !preferBrace) { + bytesNeeded += (extra - braceCount); + if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + bytesNeeded++; + } + if (*flagPtr & TCL_DONT_USE_BRACES) { + bytesNeeded += braceCount; + } + *flagPtr = CONVERT_MASK; + goto overflowCheck; + } +#endif + if (*flagPtr & TCL_DONT_USE_BRACES) { + bytesNeeded += extra; + if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + bytesNeeded++; + } + } else { + bytesNeeded += 2; + } + *flagPtr = CONVERT_BRACE; + goto overflowCheck; + } - return 2*(p-string) + 2; + if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + bytesNeeded += 2; + } + *flagPtr = CONVERT_NONE; + + overflowCheck: + if (bytesNeeded < 0) { + Tcl_Panic("TclScanElement: string length overflow"); + } + return bytesNeeded; } /* @@ -815,112 +894,139 @@ Tcl_ConvertCountedElement( char *dst, /* Place to put list-ified element. */ int flags) /* Flags produced by Tcl_ScanElement. */ { - register char *p = dst; - register CONST char *lastChar; + int numBytes = TclConvertElement(src, length, dst, flags); + dst[numBytes] = '\0'; + return numBytes; +} - /* - * See the comment block at the beginning of the Tcl_ScanElement code for - * details of how this works. - */ +int TclConvertElement( + register CONST char *src, /* Source information for list element. */ + int length, /* Number of bytes in src, or -1. */ + char *dst, /* Place to put list-ified element. */ + int flags) /* Flags produced by Tcl_ScanElement. */ +{ + int conversion = flags & CONVERT_MASK; + char *p = dst; - if (src && length == -1) { - length = strlen(src); + if ((flags & TCL_DONT_USE_BRACES) && (conversion & CONVERT_BRACE)) { + conversion = CONVERT_ESCAPE; } if ((src == NULL) || (length == 0)) { - p[0] = '{'; - p[1] = '}'; - p[2] = 0; - return 2; + src = tclEmptyStringRep; + length = 0; + conversion = CONVERT_BRACE; } - lastChar = src + length; if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { - flags |= USE_BRACES; + if (conversion == CONVERT_ESCAPE) { + p[0] = '\\'; + p[1] = '#'; + p += 2; + src++; + length--; + } else { + conversion = CONVERT_BRACE; + } } - if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) { + if (conversion == CONVERT_NONE) { + if (length == -1) { + /* TODO: INT_MAX overflow? */ + while (*src) { + *p++ = *src++; + } + return p - dst; + } else { + memcpy(dst, src, length); + return length; + } + } + if (conversion == CONVERT_BRACE) { *p = '{'; p++; - for (; src != lastChar; src++, p++) { - *p = *src; + if (length == -1) { + /* TODO: INT_MAX overflow? */ + while (*src) { + *p++ = *src++; + } + } else { + memcpy(p, src, length); + p += length; } *p = '}'; p++; - } else { - if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { - /* - * Leading '#' could be seen by [eval] as the start of a comment, - * if on the first element of a list, so quote it. - */ - - p[0] = '\\'; - p[1] = '#'; - p += 2; - src++; - } - for (; src != lastChar; src++) { - switch (*src) { - case ']': - case '[': - case '$': - case ';': - case ' ': - case '\\': - case '"': - *p = '\\'; - p++; - break; - case '{': - case '}': - /* - * It may not seem necessary to backslash braces, but it is. - * The reason for this is that the resulting list element may - * actually be an element of a sub-list enclosed in braces - * (e.g. if Tcl_DStringStartSublist has been invoked), so - * there may be a brace mismatch if the braces aren't - * backslashed. - */ + return p - dst; + } + /* conversion == CONVERT_ESCAPE or CONVERT_MASK */ - if (flags & TCL_DONT_USE_BRACES) { - *p = '\\'; - p++; - } - break; - case '\f': - *p = '\\'; - p++; - *p = 'f'; - p++; - continue; - case '\n': - *p = '\\'; - p++; - *p = 'n'; - p++; - continue; - case '\r': - *p = '\\'; - p++; - *p = 'r'; - p++; - continue; - case '\t': - *p = '\\'; - p++; - *p = 't'; - p++; - continue; - case '\v': + for ( ; length; src++, length -= (length > 0)) { + switch (*src) { + case ']': + case '[': + case '$': + case ';': + case ' ': + case '\\': + case '"': + *p = '\\'; + p++; + break; + case '{': + case '}': +#if COMPAT + if (conversion == CONVERT_ESCAPE) { +#endif *p = '\\'; p++; - *p = 'v'; - p++; - continue; +#if COMPAT } - *p = *src; +#endif + break; + case '\f': + *p = '\\'; + p++; + *p = 'f'; + p++; + continue; + case '\n': + *p = '\\'; + p++; + *p = 'n'; + p++; + continue; + case '\r': + *p = '\\'; + p++; + *p = 'r'; + p++; + continue; + case '\t': + *p = '\\'; + p++; + *p = 't'; p++; + continue; + case '\v': + *p = '\\'; + p++; + *p = 'v'; + p++; + continue; + case '\0': + if (length == -1) { + return p - dst; + } + /* + * If we reach this point, there's an embedded NULL in the + * string range being processed, which should not happen when + * the encoding rules for Tcl strings are properly followed. + * If the day ever comes when we stop tolerating such things, + * this is where to put the Tcl_Panic(). + */ + break; } + *p = *src; + p++; } - *p = '\0'; - return p-dst; + return p - dst; } /* @@ -949,11 +1055,20 @@ Tcl_Merge( CONST char * CONST *argv) /* Array of string values. */ { # define LOCAL_SIZE 20 - int localFlags[LOCAL_SIZE], *flagPtr; - int numChars; - char *result; - char *dst; - int i; + int localFlags[LOCAL_SIZE], *flagPtr = NULL; + int i, bytesNeeded = 0; + char *result, *dst; + const int maxFlags = UINT_MAX / sizeof(int); + + if (argc == 0) { + /* + * Handle empty list case first, so logic of the general case + * can be simpler. + */ + result = ckalloc(1); + result[0] = '\0'; + return result; + } /* * Pass 1: estimate space, gather flags. @@ -961,32 +1076,48 @@ Tcl_Merge( if (argc <= LOCAL_SIZE) { flagPtr = localFlags; + } else if (argc > maxFlags) { + /* + * We cannot allocate a large enough flag array to format this + * list in one pass. We could imagine converting this routine + * to a multi-pass implementation, but for sizeof(int) == 4, + * the limit is a max of 2^30 list elements and since each element + * is at least one byte formatted, and requires one byte space + * between it and the next one, that a minimum space requirement + * of 2^31 bytes, which is already INT_MAX. If we tried to format + * a list of > maxFlags elements, we're just going to overflow + * the size limits on the formatted string anyway, so just issue + * that same panic early. + */ + Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); } else { flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int)); } - numChars = 1; for (i = 0; i < argc; i++) { - numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1; + flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); + bytesNeeded += TclScanElement(argv[i], -1, &flagPtr[i]); + if (bytesNeeded < 0) { + Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); + } } + if (bytesNeeded > INT_MAX - argc + 1) { + Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); + } + bytesNeeded += argc; /* * Pass two: copy into the result area. */ - result = (char *) ckalloc((unsigned) numChars); + result = ckalloc((unsigned) bytesNeeded); dst = result; for (i = 0; i < argc; i++) { - numChars = Tcl_ConvertElement(argv[i], dst, - flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH)); - dst += numChars; + flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 ); + dst += TclConvertElement(argv[i], -1, dst, flagPtr[i]); *dst = ' '; dst++; } - if (dst == result) { - *dst = 0; - } else { - dst[-1] = 0; - } + dst[-1] = 0; if (flagPtr != localFlags) { ckfree((char *) flagPtr); @@ -1877,12 +2008,11 @@ Tcl_DStringAppendElement( CONST char *element) /* String to append. Must be * null-terminated. */ { - int newSize, flags, strSize; - char *dst; - - strSize = ((element== NULL) ? 0 : strlen(element)); - newSize = Tcl_ScanCountedElement(element, strSize, &flags) - + dsPtr->length + 1; + char *dst = dsPtr->string + dsPtr->length; + int needSpace = TclNeedSpace(dsPtr->string, dst); + int flags = needSpace ? TCL_DONT_QUOTE_HASH : 0; + int newSize = dsPtr->length + needSpace + + TclScanElement(element, -1, &flags); /* * Allocate a larger buffer for the string if the current one isn't large @@ -1903,6 +2033,7 @@ Tcl_DStringAppendElement( dsPtr->string = (char *) ckrealloc((void *) dsPtr->string, (size_t) dsPtr->spaceAvl); } + dst = dsPtr->string + dsPtr->length; } /* @@ -1910,8 +2041,7 @@ Tcl_DStringAppendElement( * the end, with a space, if needed. */ - dst = dsPtr->string + dsPtr->length; - if (TclNeedSpace(dsPtr->string, dst)) { + if (needSpace) { *dst = ' '; dst++; dsPtr->length++; @@ -1924,7 +2054,8 @@ Tcl_DStringAppendElement( flags |= TCL_DONT_QUOTE_HASH; } - dsPtr->length += Tcl_ConvertCountedElement(element, strSize, dst, flags); + dsPtr->length += TclConvertElement(element, -1, dst, flags); + dsPtr->string[dsPtr->length] = '\0'; return dsPtr->string; } -- cgit v0.12 From 33babada06e91831ef25c24d6930a111463995a1 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 3 Mar 2011 21:13:30 +0000 Subject: Correct flaw in the rewrite handling [list \\\\\}]. --- generic/tclUtil.c | 2 +- tests/list.test | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 9358ede..558d77b 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -756,7 +756,7 @@ TclScanElement( p++; break; } - if ((p[1] == '{') || (p[1] == '}')) { + if ((p[1] == '{') || (p[1] == '}') || (p[1] == '\\')) { extra++; length -= (length > 0); p++; diff --git a/tests/list.test b/tests/list.test index aab165c..5a002a9 100644 --- a/tests/list.test +++ b/tests/list.test @@ -105,6 +105,10 @@ test list-3.1 {SetListFromAny and lrange/concat results} { slowsort {fred julie alex carol bill annie} } {alex annie bill carol fred julie} +test list-4.1 {Bug 3173086} { + string is list "{[list \\\\\}]}" +} 1 + # cleanup ::tcltest::cleanupTests return -- cgit v0.12 From b1c2f2c9c6fcb329f1e23f9f5f1ef53c84b01bae Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 7 Mar 2011 14:55:52 +0000 Subject: merge trunk + partial improvements to comments --- ChangeLog | 10 +++++ generic/tcl.h | 2 - generic/tclBasic.c | 4 +- generic/tclCompile.c | 8 ++-- generic/tclObj.c | 2 +- generic/tclParse.c | 4 +- generic/tclUtil.c | 116 +++++++++++++++++++++++++++++++++------------------ 7 files changed, 96 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index aadf181..e33ff69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2011-03-06 Don Porter + + * generic/tclBasic.c: More replacements of Tcl_UtfBackslash() calls + * generic/tclCompile.c: with TclParseBackslash() where possible. + * generic/tclParse.c: + * generic/tclUtil.c: + + * generic/tclUtil.c (TclFindElement): Guard escape sequence scans + to not overrun the string end. [Bug 3192636] + 2011-03-05 Don Porter * generic/tclParse.c (TclParseBackslash): Correct trunction checks in diff --git a/generic/tcl.h b/generic/tcl.h index 45da4f1..fe384c4 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -954,8 +954,6 @@ typedef struct Tcl_DString { * is safe to leave the hash unquoted when the element is not the first * element of a list, and this flag can be used by the caller to indicate * that condition. - * (Careful! If you change these flag values be sure to change the definitions - * at the front of tclUtil.c). */ #define TCL_DONT_USE_BRACES 1 diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 33fed8d..36ece2c 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4066,7 +4066,7 @@ TclEvalEx( int line, /* The line the script starts on. */ int* clNextOuter, /* Information about an outer context for */ CONST char* outerScript) /* continuation line data. This is set only in - * EvalTokensStandard(), to properly handle + * TclSubstTokens(), to properly handle * [...]-nested commands. The 'outerScript' * refers to the most-outer script containing the * embedded command, which is refered to by @@ -4573,7 +4573,7 @@ TclAdvanceContinuations (line,clNextPtrPtr,loc) /* * Track the invisible continuation lines embedded in a script, if * any. Here they are just spaces (already). They were removed by - * EvalTokensStandard() via Tcl_UtfBackslash(). + * TclSubstTokens() via TclParseBackslash(). * * *clNextPtrPtr <=> We have continuation lines to track. * **clNextPtrPtr >= 0 <=> We are not beyond the last possible location. diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 6b00a0e..f2c4fdc 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -1136,7 +1136,8 @@ TclWordKnownAtCompileTime( case TCL_TOKEN_BS: if (tempPtr != NULL) { char utfBuf[TCL_UTF_MAX]; - int length = Tcl_UtfBackslash(tokenPtr->start, NULL, utfBuf); + int length = TclParseBackslash(tokenPtr->start, + tokenPtr->size, NULL, utfBuf); Tcl_AppendToObj(tempPtr, utfBuf, length); } break; @@ -1667,7 +1668,7 @@ TclCompileTokens( * any. The table is extended if needed. * * Note: Different to the equivalent code in function - * 'EvalTokensStandard()' (see file "tclBasic.c") we do not seem to need + * 'TclSubstTokens()' (see file "tclParse.c") we do not seem to need * the 'adjust' variable. We also do not seem to need code which merges * continuation line information of multiple words which concat'd at * runtime. Either that or I have not managed to find a test case for @@ -1700,7 +1701,8 @@ TclCompileTokens( break; case TCL_TOKEN_BS: - length = Tcl_UtfBackslash(tokenPtr->start, NULL, buffer); + length = TclParseBackslash(tokenPtr->start, tokenPtr->size, + NULL, buffer); Tcl_DStringAppend(&textBuffer, buffer, length); /* diff --git a/generic/tclObj.c b/generic/tclObj.c index 513a79d..d084692 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -80,7 +80,7 @@ typedef struct ObjData { typedef struct ThreadSpecificData { Tcl_HashTable* lineCLPtr; /* This table remembers for each Tcl_Obj * generated by a call to the function - * EvalTokensStandard() from a literal text + * TclSubstTokens() from a literal text * where bs+nl sequences occured in it, if * any. I.e. this table keeps track of * invisible/stripped continuation lines. Its diff --git a/generic/tclParse.c b/generic/tclParse.c index 963fad6..158ff42 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -2219,8 +2219,8 @@ TclSubstTokens( break; case TCL_TOKEN_BS: - appendByteLength = Tcl_UtfBackslash(tokenPtr->start, NULL, - utfCharBytes); + appendByteLength = TclParseBackslash(tokenPtr->start, + tokenPtr->size, NULL, utfCharBytes); append = utfCharBytes; /* * If the backslash sequence we found is in a literal, and diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 558d77b..8e295f4 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -26,28 +26,71 @@ static ProcessGlobalValue executableName = { }; /* - * The following values are used in the flags returned by Tcl_ScanElement and - * used by Tcl_ConvertElement. The values TCL_DONT_USE_BRACES and - * TCL_DONT_QUOTE_HASH are defined in tcl.h; make sure neither value overlaps - * with any of the values below. - * - * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in - * braces (e.g. it contains unmatched braces, or - * ends in a backslash character, or user just - * doesn't want braces); handle all special - * characters by adding backslashes. - * USE_BRACES - 1 means the string contains a special - * character that can be handled simply by - * enclosing the entire argument in braces. + * The following values are used in the flags arguments of Tcl*Scan*Element and + * Tcl*Convert*Element. The values TCL_DONT_USE_BRACES and TCL_DONT_QUOTE_HASH + * are defined in tcl.h, like so: + * +#define TCL_DONT_USE_BRACES 1 +#define TCL_DONT_QUOTE_HASH 8 + * + * Those are public flag bits which callers of the public routines + * Tcl_Convert*Element() can use to indicate: + * + * TCL_DONT_USE_BRACES - 1 means the caller is insisting that brace + * quoting not be used when converting the list + * element. * TCL_DONT_QUOTE_HASH - 1 means the caller insists that a leading hash * character ('#') should *not* be quoted. This * is appropriate when the caller can guarantee * the element is not the first element of a * list, so [eval] cannot mis-parse the element * as a comment. + * + * The remaining values which can be carried by the flags of these routines + * are for internal use only. Make sure they do not overlap with the public + * values above. + * + * The Tcl*Scan*Element() routines make a determination which of 4 modes of + * conversion is most appropriate for Tcl*Convert*Element() to perform, and + * sets two bits of the flags value to indicate the mode selected. + * + * CONVERT_NONE The element needs no quoting. Its literal string + * is suitable as is. + * CONVERT_BRACE The conversion should be enclosing the literal string + * in braces. + * CONVERT_ESCAPE The conversion should be using backslashes to escape + * any characters in the string that require it. + * CONVERT_MASK A mask value used to extract the conversion mode from + * the flags argument. + * Also indicates a strange conversion mode where all + * special characters are escaped with backslashes + * *except for braces*. This is a strange and unnecessary + * case, but it's part of the historical way in which + * lists have been formatted in Tcl. To experiment with + * removing this case, set the value of COMPAT to 0. + * + * One last flag value is used only by callers of TclScanElement(). The flag + * value produced by a call to Tcl*Scan*Element() will never leave this bit + * set. + * + * CONVERT_ANY The caller of TclScanElement() declares it can make + * no promise about what public flags will be passed to + * the matching call of TclConvertElement(). As such, + * TclScanElement() has to determine the worst case + * destination buffer length over all possibilities, and + * in other cases this means an overestimate of the + * required size. + * + * For more details, see the comments on the Tcl*Scan*Element and + * Tcl*Convert*Element routines. */ -#define USE_BRACES 2 +#define COMPAT 1 +#define CONVERT_NONE 0 +#define CONVERT_BRACE 2 +#define CONVERT_ESCAPE 4 +#define CONVERT_MASK (CONVERT_BRACE | CONVERT_ESCAPE) +#define CONVERT_ANY 16 /* * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to @@ -230,7 +273,7 @@ TclFindElement( */ case '\\': - Tcl_UtfBackslash(p, &numChars, NULL); + TclParseBackslash(p, limit - p, &numChars, NULL); p += (numChars - 1); break; @@ -324,14 +367,13 @@ TclFindElement( * * TclCopyAndCollapse -- * - * Copy a string and eliminate any backslashes that aren't in braces. + * Copy a string and substitute all backslash escape sequences * * Results: - * Count characters get copied from src to dst. Along the way, if - * backslash sequences are found outside braces, the backslashes are - * eliminated in the copy. After scanning count chars from source, a null - * character is placed at the end of dst. Returns the number of - * characters that got copied. + * Count bytes get copied from src to dst. Along the way, backslash + * sequences are substituted in the copy. After scanning count bytes + * from src, a null character is placed at the end of dst. Returns + * the number of bytes that got written to dst. * * Side effects: * None. @@ -341,26 +383,28 @@ TclFindElement( int TclCopyAndCollapse( - int count, /* Number of characters to copy from src. */ + int count, /* Number of byte to copy from src. */ CONST char *src, /* Copy from here... */ char *dst) /* ... to here. */ { - register char c; - int numRead; int newCount = 0; - int backslashCount; - for (c = *src; count > 0; src++, c = *src, count--) { + while (count > 0) { + char c = *src; if (c == '\\') { - backslashCount = Tcl_UtfBackslash(src, &numRead, dst); + int numRead; + int backslashCount = TclParseBackslash(src, count, &numRead, dst); + dst += backslashCount; newCount += backslashCount; - src += numRead-1; - count -= numRead-1; + src += numRead; + count -= numRead; } else { *dst = c; dst++; newCount++; + src++; + count--; } } *dst = 0; @@ -645,15 +689,6 @@ Tcl_ScanElement( *---------------------------------------------------------------------- */ -#define COMPAT 1 - -#define CONVERT_NONE 0 -#define CONVERT_BRACE 2 -#define CONVERT_ESCAPE 4 -#define CONVERT_SAFE 16 -#define CONVERT_MASK (CONVERT_BRACE | CONVERT_ESCAPE) - - int Tcl_ScanCountedElement( CONST char *string, /* String to convert to Tcl list element. */ @@ -661,7 +696,7 @@ Tcl_ScanCountedElement( int *flagPtr) /* Where to store information to guide * Tcl_ConvertElement. */ { - int flags = CONVERT_SAFE; + int flags = CONVERT_ANY; int numBytes = TclScanElement(string, length, &flags); *flagPtr = flags; @@ -792,10 +827,11 @@ TclScanElement( *flagPtr = CONVERT_ESCAPE; goto overflowCheck; } - if (*flagPtr & CONVERT_SAFE) { + if (*flagPtr & CONVERT_ANY) { if (extra < 2) { extra = 2; } + *flagPtr &= ~CONVERT_ANY; *flagPtr |= TCL_DONT_USE_BRACES; } if (forbidNone) { -- cgit v0.12 From f9dece7738d140a66ebb5d47ee85c4d57249258a Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 10 May 2011 16:05:48 +0000 Subject: Completed patch with mucho comments. Merge 8.5. --- ChangeLog | 259 +++++++ README | 27 +- doc/SourceRCFile.3 | 2 +- doc/Tcl.n | 2 +- doc/lreplace.n | 2 +- doc/namespace.n | 2 +- doc/re_syntax.n | 2 +- doc/tclvars.n | 6 +- generic/tcl.decls | 8 +- generic/tcl.h | 26 +- generic/tclBasic.c | 107 ++- generic/tclBinary.c | 1 + generic/tclCkalloc.c | 8 +- generic/tclCmdIL.c | 51 +- generic/tclCmdMZ.c | 133 +--- generic/tclCompCmds.c | 141 +--- generic/tclCompile.c | 8 +- generic/tclConfig.c | 12 +- generic/tclDecls.h | 10 +- generic/tclDictObj.c | 192 ++--- generic/tclEncoding.c | 1 + generic/tclExecute.c | 76 +- generic/tclFCmd.c | 25 +- generic/tclIO.c | 3 + generic/tclIndexObj.c | 3 + generic/tclInt.decls | 2 +- generic/tclInt.h | 32 +- generic/tclIntDecls.h | 192 ++--- generic/tclIntPlatDecls.h | 18 +- generic/tclListObj.c | 356 +++++----- generic/tclNamesp.c | 30 +- generic/tclObj.c | 5 + generic/tclParse.c | 77 +- generic/tclPathObj.c | 5 +- generic/tclProc.c | 26 +- generic/tclRegexp.c | 1 + generic/tclResult.c | 12 +- generic/tclStrToD.c | 12 +- generic/tclStringObj.c | 2 + generic/tclStubInit.c | 2 + generic/tclUtf.c | 2 +- generic/tclUtil.c | 1065 +++++++++++++++++++--------- generic/tclVar.c | 10 +- library/tzdata/Africa/Casablanca | 2 + library/tzdata/America/Havana | 2 +- library/tzdata/America/Juneau | 5 +- library/tzdata/America/Metlakatla | 275 +++++++ library/tzdata/America/North_Dakota/Beulah | 279 ++++++++ library/tzdata/America/Santiago | 4 +- library/tzdata/America/Sitka | 275 +++++++ library/tzdata/Atlantic/Stanley | 3 +- library/tzdata/Europe/Istanbul | 3 +- library/tzdata/Pacific/Apia | 2 +- library/tzdata/Pacific/Easter | 4 +- library/tzdata/Pacific/Honolulu | 8 +- libtommath/bn_mp_div_d.c | 2 +- libtommath/bn_mp_montgomery_setup.c | 2 +- libtommath/bn_mp_prime_next_prime.c | 2 +- libtommath/bn_mp_shrink.c | 11 +- libtommath/changes.txt | 14 + libtommath/etc/drprimes.txt | 11 +- libtommath/makefile | 7 +- libtommath/makefile.shared | 2 +- libtommath/pre_gen/mpi.c | 24 +- macosx/README | 11 +- macosx/tclMacOSXFCmd.c | 6 +- tests/namespace.test | 23 +- tests/parse.test | 12 + tests/string.test | 11 +- tools/configure | 266 ++++--- tools/genStubs.tcl | 2 +- tools/tclZIC.tcl | 3 + unix/.cvsignore | 7 - unix/Makefile.in | 5 +- unix/README | 5 - unix/configure | 45 +- unix/configure.in | 8 +- unix/dltest/.cvsignore | 5 - unix/ldAix | 2 +- unix/tcl.m4 | 49 +- unix/tclLoadDl.c | 20 +- unix/tclLoadDyld.c | 10 +- unix/tclUnixFile.c | 2 +- unix/tclUnixInit.c | 10 + unix/tclUnixThrd.c | 2 +- unix/tclUnixTime.c | 28 +- win/.cvsignore | 27 - win/README | 3 - win/configure | 71 +- win/configure.in | 19 + win/makefile.vc | 19 +- win/rules.vc | 87 +-- win/tcl.m4 | 2 +- win/tclWinFile.c | 5 +- win/tclWinPort.h | 25 + 95 files changed, 3076 insertions(+), 1607 deletions(-) create mode 100644 library/tzdata/America/Metlakatla create mode 100644 library/tzdata/America/North_Dakota/Beulah create mode 100644 library/tzdata/America/Sitka delete mode 100644 unix/.cvsignore delete mode 100644 unix/dltest/.cvsignore delete mode 100644 win/.cvsignore diff --git a/ChangeLog b/ChangeLog index e33ff69..74d5613 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,262 @@ +2011-05-09 Don Porter + + * generic/tclListObj.c: Revise empty string tests so that we avoid + potentially expensive string rep generations, especially for dicts. + +2011-05-07 Miguel Sofer + + * generic/tclInt.h: fix USE_TCLALLOC so that it can be enabled + * unix/Makefile.in: without editing the Makefile + +2011-05-05 Don Porter + + * generic/tclListObj.c: Stop generating string rep of dict when + converting to list. Tolerate NULL interps more completely. + +2011-05-03 Don Porter + + * generic/tclUtil.c: Tighten Tcl_SplitList(). + * generic/tclListObj.c: Tighten SetListFromAny(). + * generic/tclDictObj.c: Tighten SetDictFromAny(). + +2011-05-02 Don Porter + + * generic/tclCmdMZ.c: Revised TclFindElement() interface. The + * generic/tclDictObj.c: final argument had been bracePtr, the address + * generic/tclListObj.c: of a boolean var, where the caller can be told + * generic/tclParse.c: whether or not the parsed list element was + * generic/tclUtil.c: enclosed in braces. In practice, no callers + really care about that. What the callers really want to know is + whether the list element value exists as a literal substring of the + string being parsed, or whether a call to TclCopyAndCollpase() is + needed to produce the list element value. Now the final argument + is changed to do what callers actually need. This is a better fit + for the calls in tclParse.c, where now a good deal of post-processing + checking for "naked backslashes" is no longer necessary. + ***POTENTIAL INCOMPATIBILITY*** + For any callers calling in via the internal stubs table who really + do use the final argument explicitly to check for the enclosing brace + scenario. Simply looking for the braces where they must be is the + revision available to those callers, and it will backport cleanly. + + * tests/parse.test: Tests for expanded literals quoting detection. + + * generic/tclCompCmds.c: New TclFindElement() is also a better + fit for the [switch] compiler. + + * generic/tclInt.h: Replace TclCountSpaceRuns() with + * generic/tclListObj.c: TclMaxListLength() which is the function we + * generic/tclUtil.c: actually want. + * generic/tclCompCmds.c: + + * generic/tclCompCmds.c: Rewrite of parts of the switch compiler to + better use the powers of TclFindElement() and do less parsing on + its own. + +2011-04-28 Don Porter + + * generic/tclInt.h: New utility routines: + * generic/tclParse.c: TclIsSpaceProc() and + * generic/tclUtil.c: TclCountSpaceRuns() + + * generic/tclCmdMZ.c: Use new routines to replace calls to + * generic/tclListObj.c: isspace() and their /* INTL */ risk. + * generic/tclStrToD.c: + * generic/tclUtf.c: + * unix/tclUnixFile.c: + +2011-04-27 Don Porter + + * generic/tclListObj.c: FreeListInternalRep() cleanup. + + * generic/tclBinary.c: Backport fix for [Bug 2857044]. + * generic/tclDictObj.c: All freeIntRepProcs set typePtr to NULL. + * generic/tclEncoding.c: + * generic/tclIndexObj.c: + * generic/tclListObj.c: + * generic/tclNamesp.c: + * generic/tclObj.c: + * generic/tclPathObj.c: + * generic/tclProc.c: + * generic/tclRegexp.c: + * generic/tclStringObj.c: + * generic/tclVar.c: + +2011-04-21 Don Porter + + * generic/tclInt.h: Use macro to set List intreps. + * generic/tclListObj.c: + + * generic/tclCmdIL.c: Limits on list length were too strict. + * generic/tclInt.h: Revised panics to errors where possible. + * generic/tclListObj.c: + + * generic/tclCompile.c: Make sure SetFooFromAny routines react + * generic/tclIO.c: reasonably when passed a NULL interp. + * generic/tclIndexObj.c: + * generic/tclListObj.c: + * generic/tclNamesp.c: + * generic/tclObj.c: + * generic/tclProc.c: + * macosx/tclMacOSXFCmd.c: + +2011-04-21 Jan Nijtmans + + * generic/tcl.h: fix for [Bug 3288345]: Wrong Tcl_StatBuf + * generic/tclInt.h: used on MinGW. Make sure that all _WIN32 + * win/tclWinFile.c: compilers use exactly the same layout + * win/configure.in: for Tcl_StatBuf - the one used by MSVC6 - + * win/configure: in all situations. + +2011-04-20 Andreas Kupries + + * generic/tclFCmd.c (TclFileAttrsCmd): Added commands to reset the + typePtr of the Tcl_Obj* whose int-rep was just purged. Required to + prevent a dangling IndexRep* to reused, smashing the heap. See + also the entries at 2011-04-16 and 2011-03-24 for the history of + the problem. + +2011-04-19 Don Porter + + * generic/tclConfig.c: Reduce internals access in the implementation + of [::pkgconfig list]. + +2011-04-18 Don Porter + + * generic/tclCmdIL.c: Use ListRepPtr(.) and other cleanup. + * generic/tclConfig.c: + * generic/tclListObj.c: + + * generic/tclInt.h: Define and use macros that test whether + * generic/tclBasic.c: a Tcl list value is canonical. + * generic/tclUtil.c: + +2011-04-16 Donal K. Fellows + + * generic/tclFCmd.c (TclFileAttrsCmd): Tidied up the memory management + a bit to try to ensure that the dynamic and static cases don't get + confused while still promoting caching where possible. Added a panic + to trap problems in the case where an extension is misusing the API. + +2011-04-13 Don Porter + + * generic/tclUtil.c: [Bug 3285375]: Rewrite of Tcl_Concat*() + routines to prevent segfaults on buffer overflow. Build them out of + existing primitives already coded to handle overflow properly. Uses + the new TclTrim*() routines. + + * generic/tclCmdMZ.c: New internal utility routines TclTrimLeft() + * generic/tclInt.h: and TclTrimRight(). Refactor the + * generic/tclUtil.c: [string trim*] implementations to use them. + +2011-04-13 Miguel Sofer + + * generic/tclVar.c: [Bug 2662380]: Fix crash caused by appending to a + variable with a write trace that unsets it. + +2011-04-12 Don Porter + + * generic/tclStringObj.c: [Bug 3285472]: Repair corruption in + * tests/string.test: [string reverse] when string rep invalidation + failed to also reset the bytes allocated for string rep to zero. + +2011-04-12 Venkat Iyer + + * library/tzdata/Atlantic/Stanley: Update to Olson tzdata2011f + +2011-04-06 Miguel Sofer + + * generic/tclExecute.c (TclCompEvalObj): Earlier return if Tip280 + gymnastics not needed. + +2011-04-05 Venkat Iyer + + * library/tzdata/Africa/Casablanca: Update to Olson's tzdata2011e + * library/tzdata/America/Santiago: + * library/tzdata/Pacific/Easter: + * library/tzdata/America/Metlakatla: (new) + * library/tzdata/America/North_Dakota/Beulah: (new) + * library/tzdata/America/Sitka: (new) + +2011-04-04 Don Porter + + * README: Updated README files, repairing broken URLs and + * macosx/README: removing other bits that were clearly wrong. + * unix/README: Still could use more eyeballs on the detailed build + * win/README: advice on various plaforms. [Bug 3202030] + +2011-04-02 Kevin B. Kenny + + * generic/tclStrToD.c (QuickConversion): Replaced another couple of + 'double' declarations with 'volatile double' to work around + misrounding issues in mingw-gcc 3.4.5. + +2011-03-24 Donal K. Fellows + + * generic/tclFCmd.c (TclFileAttrsCmd): Ensure that any reference to + temporary index tables is squelched immediately rather than hanging + around to trip us up in the future. + +2011-03-21 Jan Nijtmans + + * unix/tclLoadDl.c: [Bug #3216070]: Loading extension libraries + * unix/tclLoadDyld.c: from embedded Tcl applications. + +2011-03-16 Jan Nijtmans + + * generic/tclCkalloc.c: [Bug #3197864]: pointer truncation on Win64 + TCL_MEM_DEBUG builds + +2011-03-16 Don Porter + + * generic/tclBasic.c: Some rewrites to eliminate calls to + * generic/tclParse.c: isspace() and their /* INTL */ risk. + * generic/tclProc.c: + +2011-03-16 Jan Nijtmans + + * unix/tcl.m4: Make SHLIB_LD_LIBS='${LIBS}' the default and + * unix/configure: set to "" on per-platform necessary basis. + Backported from TEA, but kept all original platform code which was + removed from TEA. + +2011-03-14 Kevin B. Kenny + + * tools/tclZIC.tcl (onDayOfMonth): Allow for leading zeroes + in month and day so that tzdata2011d parses correctly. + * library/tzdata/America/Havana: + * library/tzdata/America/Juneau: + * library/tzdata/America/Santiago: + * library/tzdata/Europe/Istanbul: + * library/tzdata/Pacific/Apia: + * library/tzdata/Pacific/Easter: + * library/tzdata/Pacific/Honolulu: tzdata2011d + + + * unix/configure.in [Bug 3205320]: stack space detection defeated by inlining + * unix/configure: (autoconf-2.59) + +2011-03-09 Don Porter + + * generic/tclNamesp.c: Tighten the detector of nested [namespace code] + * tests/namespace.test: quoting that the quoted scripts function + properly even in a namespace that contains a custom "namespace" + command. [Bug 3202171] + + * doc/tclvars.n: Formatting fix. Thanks to Pat Thotys. + +2011-03-08 Jan Nijtmans + + * generic/tclBasic.c: Fix gcc warnings: variable set but not used + +2011-03-08 Don Porter + + * generic/tclInt.h: Remove TclMarkList() routine, an experimental + * generic/tclUtil.c: dead-end from the 8.5 alpha days. + + * generic/tclResult.c (ResetObjResult): Correct failure to clear + invalid intrep. Thanks to Colin McDonald. [Bug 3202905] + 2011-03-06 Don Porter * generic/tclBasic.c: More replacements of Tcl_UtfBackslash() calls diff --git a/README b/README index 7693034..5a65698 100644 --- a/README +++ b/README @@ -1,6 +1,5 @@ README: Tcl This is the Tcl 8.5.9 source distribution. - Tcl/Tk is also available through NetCVS: http://tcl.sourceforge.net/ You can get any source release of Tcl from the file distributions link at the above URL. @@ -12,10 +11,10 @@ Contents 3. Compiling and installing Tcl 4. Development tools 5. Tcl newsgroup - 6. Tcl contributed archive - 7. Tcl Resource Center - 8. Mailing lists - 9. Support and Training + 6. The Tcler's Wiki + 7. Mailing lists + 8. Support and Training + 9. Tracking Development 10. Thank You 1. Introduction @@ -28,7 +27,7 @@ Tcl can also be used for a variety of web-related tasks and for creating powerful command languages for applications. Tcl is maintained, enhanced, and distributed freely by the Tcl community. -The home for Tcl/Tk sources and bug/patch database is on SourceForge: +The home for Tcl/Tk releases and bug/patch database is on SourceForge: http://tcl.sourceforge.net/ @@ -50,13 +49,17 @@ The home page for this release, including new features, is Detailed release notes can be found at the file distributions page by clicking on the relevant version. - http://sourceforge.net/project/showfiles.php?group_id=10894 + http://sourceforge.net/projects/tcl/files/ Information about Tcl itself can be found at - http://www.tcl.tk/scripting/ + http://www.tcl.tk/about/ There have been many Tcl books on the market. Many are mentioned in the Wiki: - http://wiki.tcl.tk/book + http://wiki.tcl.tk/_/ref?N=25206 + +To view the complete set of reference manual entries for Tcl 8.5 online, +visit the URL: + http://www.tcl.tk/man/tcl8.5/ 2a. Unix Documentation ---------------------- @@ -169,6 +172,12 @@ Tcl/Tk training: http://wiki.tcl.tk/training +9. Tracking Development +----------------------- + +Tcl is developed in public. To keep an eye on how Tcl is changing, see + http://core.tcl.tk/ + 10. Thank You ------------- diff --git a/doc/SourceRCFile.3 b/doc/SourceRCFile.3 index 7fae1c7..eabc47c 100644 --- a/doc/SourceRCFile.3 +++ b/doc/SourceRCFile.3 @@ -1,7 +1,7 @@ '\" '\" Copyright (c) 1998-2000 by Scriptics Corporation. '\" All rights reserved. -'\" +'\" .so man.macros .TH Tcl_SourceRCFile 3 8.3 Tcl "Tcl Library Procedures" .BS diff --git a/doc/Tcl.n b/doc/Tcl.n index 6b43840..8b5b501 100644 --- a/doc/Tcl.n +++ b/doc/Tcl.n @@ -4,7 +4,7 @@ '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. -'\" +'\" .so man.macros .TH Tcl n "8.5" Tcl "Tcl Built-In Commands" .BS diff --git a/doc/lreplace.n b/doc/lreplace.n index a241e6f..2cd79d8 100644 --- a/doc/lreplace.n +++ b/doc/lreplace.n @@ -5,7 +5,7 @@ '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. -'\" +'\" .so man.macros .TH lreplace n 7.4 Tcl "Tcl Built-In Commands" .BS diff --git a/doc/namespace.n b/doc/namespace.n index ee4f908..ddf7b51 100644 --- a/doc/namespace.n +++ b/doc/namespace.n @@ -6,7 +6,7 @@ '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. -'\" +'\" .so man.macros .TH namespace n 8.5 Tcl "Tcl Built-In Commands" .BS diff --git a/doc/re_syntax.n b/doc/re_syntax.n index 1b32118..8701641 100644 --- a/doc/re_syntax.n +++ b/doc/re_syntax.n @@ -4,7 +4,7 @@ '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. -'\" +'\" .so man.macros .TH re_syntax n "8.1" Tcl "Tcl Built-In Commands" .BS diff --git a/doc/tclvars.n b/doc/tclvars.n index a54fa1f..885de34 100644 --- a/doc/tclvars.n +++ b/doc/tclvars.n @@ -315,7 +315,7 @@ binary number. .RE .PP .RS -If \Btcl_precision\fB is not zero, then when Tcl converts a floating +If \fBtcl_precision\fR is not zero, then when Tcl converts a floating point number, it creates a decimal representation of at most \fBtcl_precision\fR significant digits; the result may be shorter if the shorter result represents the original number exactly. If no @@ -324,7 +324,7 @@ of the original number, the one that is closest to the original number is chosen. If the original number lies precisely between two equally accurate decimal representations, then the one with an even value for the least -significant digit is chosen; for instance, if tcl_precision is 3, then +significant digit is chosen; for instance, if \fBtcl_precision\fR is 3, then 0.3125 will convert to 0.312, not 0.313, while 0.6875 will convert to 0.688, not 0.687. Any string of trailing zeroes that remains is trimmed. .RE @@ -348,7 +348,7 @@ variable. .RE .PP .RS -Valid values for \Btcl_precision\fR range from 0 to 17. +Valid values for \fBtcl_precision\fR range from 0 to 17. .RE .TP \fBtcl_rcFileName\fR diff --git a/generic/tcl.decls b/generic/tcl.decls index e1093e6..20e9575 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -774,10 +774,10 @@ declare 217 generic { void Tcl_ResetResult(Tcl_Interp *interp) } declare 218 generic { - int Tcl_ScanElement(CONST char *str, int *flagPtr) + int Tcl_ScanElement(CONST char *src, int *flagPtr) } declare 219 generic { - int Tcl_ScanCountedElement(CONST char *str, int length, int *flagPtr) + int Tcl_ScanCountedElement(CONST char *src, int length, int *flagPtr) } # Obsolete declare 220 generic { @@ -1093,11 +1093,11 @@ declare 303 generic { } declare 304 generic { int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, Tcl_Obj *objPtr, - CONST VOID *tablePtr, int offset, CONST char *msg, int flags, + CONST void *tablePtr, int offset, CONST char *msg, int flags, int *indexPtr) } declare 305 generic { - VOID *Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, int size) + void *Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, int size) } declare 306 generic { Tcl_Obj *Tcl_GetVar2Ex(Tcl_Interp *interp, CONST char *part1, diff --git a/generic/tcl.h b/generic/tcl.h index fe384c4..015995c 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -352,28 +352,30 @@ typedef long LONG; */ #if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG) -# if defined(__GNUC__) -# define TCL_WIDE_INT_TYPE long long -# if defined(__WIN32__) && !defined(__CYGWIN__) -# define TCL_LL_MODIFIER "I64" -# else -# define TCL_LL_MODIFIER "ll" -# endif -typedef struct stat Tcl_StatBuf; -# elif defined(__WIN32__) +# if defined(__WIN32__) && !defined(__CYGWIN__) # define TCL_WIDE_INT_TYPE __int64 # ifdef __BORLANDC__ typedef struct stati64 Tcl_StatBuf; # define TCL_LL_MODIFIER "L" # else /* __BORLANDC__ */ -# if _MSC_VER < 1400 || !defined(_M_IX86) +# if defined(_WIN64) +typedef struct __stat64 Tcl_StatBuf; +# elif (defined(_MSC_VER) && (_MSC_VER < 1400)) typedef struct _stati64 Tcl_StatBuf; # else -typedef struct _stat64 Tcl_StatBuf; +typedef struct _stat32i64 Tcl_StatBuf; # endif /* _MSC_VER < 1400 */ # define TCL_LL_MODIFIER "I64" # endif /* __BORLANDC__ */ -# else /* __WIN32__ */ +# elif defined(__GNUC__) +# define TCL_WIDE_INT_TYPE long long +# define TCL_LL_MODIFIER "ll" +# if defined(__WIN32__) +typedef struct _stat32i64 Tcl_StatBuf; +# else +typedef struct stat Tcl_StatBuf; +# endif +# else /* ! __WIN32__ && ! __GNUC__ */ /* * Don't know what platform it is and configure hasn't discovered what is * going on for us. Try to guess... diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 36ece2c..71bd45c 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -3664,6 +3664,7 @@ TclEvalObjvInternal( } } +#ifdef USE_DTRACE if (TCL_DTRACE_CMD_ARGS_ENABLED()) { char *a[10]; int i = 0; @@ -3682,6 +3683,7 @@ TclEvalObjvInternal( TCL_DTRACE_CMD_INFO(a[0], a[1], a[2], a[3], i[0], i[1]); TclDecrRefCount(info); } +#endif /* USE_DTRACE */ /* * Finally, invoke the command's Tcl_ObjCmdProc. @@ -3756,12 +3758,14 @@ TclEvalObjvInternal( (void) Tcl_GetObjResult(interp); } +#ifdef USE_DTRACE if (TCL_DTRACE_CMD_RESULT_ENABLED()) { Tcl_Obj *r; r = Tcl_GetObjResult(interp); TCL_DTRACE_CMD_RESULT(TclGetString(objv[0]), code, TclGetString(r),r); } +#endif /* USE_DTRACE */ done: if (savedVarFramePtr) { @@ -4896,8 +4900,7 @@ TclArgumentGet(interp,obj,cfPtrPtr,wordPtr) * up by the caller. It knows better than us. */ - if ((!obj->bytes) || ((obj->typePtr == &tclListType) && - ((List *)obj->internalRep.twoPtrValue.ptr1)->canonicalFlag)) { + if ((obj->bytes == NULL) || TclListObjIsCanonical(obj)) { return; } @@ -5079,61 +5082,50 @@ TclEvalObjEx( * internal rep). */ - if (objPtr->typePtr == &tclListType) { /* is a list... */ - List *listRepPtr = objPtr->internalRep.twoPtrValue.ptr1; - - if (objPtr->bytes == NULL || /* ...without a string rep */ - listRepPtr->canonicalFlag) {/* ...or that is canonical */ - /* - * TIP #280 Structures for tracking lines. As we know that this is - * dynamic execution we ignore the invoker, even if known. - */ + if (TclListObjIsCanonical(objPtr)) { + /* + * TIP #280 Structures for tracking lines. As we know that this is + * dynamic execution we ignore the invoker, even if known. + */ - int nelements; - Tcl_Obj **elements, *copyPtr = TclListObjCopy(NULL, objPtr); - CmdFrame *eoFramePtr = (CmdFrame *) + int nelements; + Tcl_Obj **elements, *copyPtr = TclListObjCopy(NULL, objPtr); + CmdFrame *eoFramePtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame)); - eoFramePtr->type = TCL_LOCATION_EVAL_LIST; - eoFramePtr->level = (iPtr->cmdFramePtr == NULL? - 1 : iPtr->cmdFramePtr->level + 1); - eoFramePtr->framePtr = iPtr->framePtr; - eoFramePtr->nextPtr = iPtr->cmdFramePtr; - - eoFramePtr->nline = 0; - eoFramePtr->line = NULL; + eoFramePtr->type = TCL_LOCATION_EVAL_LIST; + eoFramePtr->level = (iPtr->cmdFramePtr == NULL? 1 + : iPtr->cmdFramePtr->level + 1); + eoFramePtr->framePtr = iPtr->framePtr; + eoFramePtr->nextPtr = iPtr->cmdFramePtr; - eoFramePtr->cmd.listPtr = objPtr; - Tcl_IncrRefCount(eoFramePtr->cmd.listPtr); - eoFramePtr->data.eval.path = NULL; - - /* - * TIP #280 We do _not_ compute all the line numbers for the words - * in the command. For the eval of a pure list the most sensible - * choice is to put all words on line 1. Given that we neither - * need memory for them nor compute anything. 'line' is left - * NULL. The two places using this information (TclInfoFrame, and - * TclInitCompileEnv), are special-cased to use the proper line - * number directly instead of accessing the 'line' array. - */ + eoFramePtr->nline = 0; + eoFramePtr->line = NULL; - Tcl_ListObjGetElements(NULL, copyPtr, - &nelements, &elements); + eoFramePtr->cmd.listPtr = objPtr; + Tcl_IncrRefCount(eoFramePtr->cmd.listPtr); + eoFramePtr->data.eval.path = NULL; - iPtr->cmdFramePtr = eoFramePtr; - result = Tcl_EvalObjv(interp, nelements, elements, - flags); + /* + * TIP #280 We do _not_ compute all the line numbers for the words + * in the command. For the eval of a pure list the most sensible + * choice is to put all words on line 1. Given that we neither + * need memory for them nor compute anything. 'line' is left + * NULL. The two places using this information (TclInfoFrame, and + * TclInitCompileEnv), are special-cased to use the proper line + * number directly instead of accessing the 'line' array. + */ - Tcl_DecrRefCount(copyPtr); - iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; - Tcl_DecrRefCount(eoFramePtr->cmd.listPtr); - TclStackFree(interp, eoFramePtr); + Tcl_ListObjGetElements(NULL, copyPtr, &nelements, &elements); - goto done; - } - } + iPtr->cmdFramePtr = eoFramePtr; + result = Tcl_EvalObjv(interp, nelements, elements, flags); - if (flags & TCL_EVAL_DIRECT) { + Tcl_DecrRefCount(copyPtr); + iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; + Tcl_DecrRefCount(eoFramePtr->cmd.listPtr); + TclStackFree(interp, eoFramePtr); + } else if (flags & TCL_EVAL_DIRECT) { /* * We're not supposed to use the compiler or byte-code interpreter. * Let Tcl_EvalEx evaluate the command directly (and probably more @@ -5293,7 +5285,6 @@ TclEvalObjEx( iPtr->varFramePtr = savedVarFramePtr; } - done: TclDecrRefCount(objPtr); return result; } @@ -6477,16 +6468,16 @@ ExprAbsFunc( goto unChanged; } else if (l == (long)0) { const char *string = objv[1]->bytes; - if (!string) { - /* There is no string representation, so internal one is correct */ - goto unChanged; - } - while (isspace(UCHAR(*string))) { - ++string; - } - if (*string != '-') { - goto unChanged; + if (string) { + while (*string != '0') { + if (*string == '-') { + Tcl_SetObjResult(interp, Tcl_NewLongObj(0)); + return TCL_OK; + } + string++; + } } + goto unChanged; } else if (l == LONG_MIN) { TclBNInitBignumFromLong(&big, l); goto tooLarge; diff --git a/generic/tclBinary.c b/generic/tclBinary.c index b1bf2ab..90d392b 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -436,6 +436,7 @@ FreeByteArrayInternalRep( Tcl_Obj *objPtr) /* Object with internal rep to free. */ { ckfree((char *) GET_BYTEARRAY(objPtr)); + objPtr->typePtr = NULL; } /* diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index 5579b47..9d3d6d7 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -81,7 +81,7 @@ static struct mem_header *allocHead = NULL; /* List of allocated structures */ */ #define BODY_OFFSET \ - ((unsigned long) (&((struct mem_header *) 0)->body)) + ((size_t) (&((struct mem_header *) 0)->body)) static int total_mallocs = 0; static int total_frees = 0; @@ -603,7 +603,7 @@ Tcl_DbCkfree( * words on these machines). */ - memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); + memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); if (alloc_tracing) { fprintf(stderr, "ckfree %lx %ld %s %d\n", @@ -682,7 +682,7 @@ Tcl_DbCkrealloc( * See comment from Tcl_DbCkfree before you change the following line. */ - memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); + memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); copySize = size; if (copySize > (unsigned int) memp->length) { @@ -713,7 +713,7 @@ Tcl_AttemptDbCkrealloc( * See comment from Tcl_DbCkfree before you change the following line. */ - memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); + memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); copySize = size; if (copySize > (unsigned int) memp->length) { diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 87c5435..13db6d5 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -1540,7 +1540,6 @@ InfoLoadedCmd( Tcl_Obj *CONST objv[]) /* Argument objects. */ { char *interpName; - int result; if ((objc != 1) && (objc != 2)) { Tcl_WrongNumArgs(interp, 1, objv, "?interp?"); @@ -1552,8 +1551,7 @@ InfoLoadedCmd( } else { /* Get pkgs just in specified interp. */ interpName = TclGetString(objv[1]); } - result = TclGetLoadedPackages(interp, interpName); - return result; + return TclGetLoadedPackages(interp, interpName); } /* @@ -2403,7 +2401,7 @@ Tcl_LrepeatObjCmd( register Tcl_Obj *CONST objv[]) /* The argument objects. */ { - int elementCount, i, result, totalElems; + int elementCount, i, totalElems; Tcl_Obj *listPtr, **dataArray; List *listRepPtr; @@ -2416,8 +2414,7 @@ Tcl_LrepeatObjCmd( Tcl_WrongNumArgs(interp, 1, objv, "positiveCount value ?value ...?"); return TCL_ERROR; } - result = TclGetIntFromObj(interp, objv[1], &elementCount); - if (result == TCL_ERROR) { + if (TCL_ERROR == TclGetIntFromObj(interp, objv[1], &elementCount)) { return TCL_ERROR; } if (elementCount < 1) { @@ -2432,21 +2429,14 @@ Tcl_LrepeatObjCmd( objc -= 2; objv += 2; - /* - * Final sanity check. Total number of elements must fit in a signed - * integer. We also limit the number of elements to 512M-1 so allocations - * on 32-bit machines are guaranteed to be less than 2GB! [Bug 2130992] - */ + /* Final sanity check. Do not exceed limits on max list length. */ - totalElems = objc * elementCount; - if (totalElems/objc != elementCount || totalElems/elementCount != objc) { - Tcl_AppendResult(interp, "too many elements in result list", NULL); - return TCL_ERROR; - } - if (totalElems >= 0x20000000) { - Tcl_AppendResult(interp, "too many elements in result list", NULL); + if (objc > LIST_MAX/elementCount) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "max length of a Tcl list (%d elements) exceeded", LIST_MAX)); return TCL_ERROR; } + totalElems = objc * elementCount; /* * Get an empty list object that is allocated large enough to hold each @@ -2454,7 +2444,7 @@ Tcl_LrepeatObjCmd( */ listPtr = Tcl_NewListObj(totalElems, NULL); - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); listRepPtr->elemCount = elementCount*objc; dataArray = &listRepPtr->elements; @@ -2639,15 +2629,15 @@ Tcl_LreverseObjCmd( return TCL_OK; } - if (Tcl_IsShared(objv[1])) { + if (Tcl_IsShared(objv[1]) + || (ListRepPtr(objv[1])->refCount > 1)) { /* Bug 1675044 */ Tcl_Obj *resultObj, **dataArray; - List *listPtr; + List *listRepPtr; - makeNewReversedList: resultObj = Tcl_NewListObj(elemc, NULL); - listPtr = (List *) resultObj->internalRep.twoPtrValue.ptr1; - listPtr->elemCount = elemc; - dataArray = &listPtr->elements; + listRepPtr = ListRepPtr(resultObj); + listRepPtr->elemCount = elemc; + dataArray = &listRepPtr->elements; for (i=0,j=elemc-1 ; iinternalRep.twoPtrValue.ptr1)->refCount > 1) { - goto makeNewReversedList; - } /* * Not shared, so swap "in place". This relies on Tcl_LOGE above @@ -3763,7 +3744,7 @@ Tcl_LsortObjCmd( int i; resultPtr = Tcl_NewListObj(sortInfo.numElements, NULL); - listRepPtr = (List *) resultPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(resultPtr); newArray = &listRepPtr->elements; if (indices) { for (i = 0; elementPtr != NULL ; elementPtr = elementPtr->nextPtr){ diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index cf74db5..60a9414 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -1621,7 +1621,7 @@ StringIsCmd( */ const char *elemStart, *nextElem; - int lenRemain, elemSize, hasBrace; + int lenRemain, elemSize; register const char *p; string1 = TclGetStringFromObj(objPtr, &length1); @@ -1630,7 +1630,7 @@ StringIsCmd( for (p=string1, lenRemain=length1; lenRemain > 0; p=nextElem, lenRemain=end-nextElem) { if (TCL_ERROR == TclFindElement(NULL, p, lenRemain, - &elemStart, &nextElem, &elemSize, &hasBrace)) { + &elemStart, &nextElem, &elemSize, NULL)) { Tcl_Obj *tmpStr; /* @@ -1643,7 +1643,7 @@ StringIsCmd( * if it is the first "element" that has the failure. */ - while (isspace(UCHAR(*p))) { /* INTL: ? */ + while (TclIsSpaceProc(*p)) { p++; } TclNewStringObj(tmpStr, string1, p-string1); @@ -3108,10 +3108,8 @@ StringTrimCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - Tcl_UniChar ch, trim; - register const char *p, *end; - const char *check, *checkEnd, *string1, *string2; - int offset, length1, length2; + const char *string1, *string2; + int triml, trimr, length1, length2; if (objc == 3) { string2 = TclGetStringFromObj(objv[2], &length2); @@ -3123,58 +3121,12 @@ StringTrimCmd( return TCL_ERROR; } string1 = TclGetStringFromObj(objv[1], &length1); - checkEnd = string2 + length2; - /* - * The outer loop iterates over the string. The inner loop iterates over - * the trim characters. The loops terminate as soon as a non-trim - * character is discovered and string1 is left pointing at the first - * non-trim character. - */ - - end = string1 + length1; - for (p = string1; p < end; p += offset) { - offset = TclUtfToUniChar(p, &ch); - - for (check = string2; ; ) { - if (check >= checkEnd) { - p = end; - break; - } - check += TclUtfToUniChar(check, &trim); - if (ch == trim) { - length1 -= offset; - string1 += offset; - break; - } - } - } - - /* - * The outer loop iterates over the string. The inner loop iterates over - * the trim characters. The loops terminate as soon as a non-trim - * character is discovered and length1 marks the last non-trim character. - */ - - end = string1; - for (p = string1 + length1; p > end; ) { - p = Tcl_UtfPrev(p, string1); - offset = TclUtfToUniChar(p, &ch); - check = string2; - while (1) { - if (check >= checkEnd) { - p = end; - break; - } - check += TclUtfToUniChar(check, &trim); - if (ch == trim) { - length1 -= offset; - break; - } - } - } + triml = TclTrimLeft(string1, length1, string2, length2); + trimr = TclTrimRight(string1 + triml, length1 - triml, string2, length2); - Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1)); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(string1 + triml, length1 - triml - trimr)); return TCL_OK; } @@ -3204,10 +3156,8 @@ StringTrimLCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - Tcl_UniChar ch, trim; - register const char *p, *end; - const char *check, *checkEnd, *string1, *string2; - int offset, length1, length2; + const char *string1, *string2; + int trim, length1, length2; if (objc == 3) { string2 = TclGetStringFromObj(objv[2], &length2); @@ -3219,34 +3169,10 @@ StringTrimLCmd( return TCL_ERROR; } string1 = TclGetStringFromObj(objv[1], &length1); - checkEnd = string2 + length2; - - /* - * The outer loop iterates over the string. The inner loop iterates over - * the trim characters. The loops terminate as soon as a non-trim - * character is discovered and string1 is left pointing at the first - * non-trim character. - */ - - end = string1 + length1; - for (p = string1; p < end; p += offset) { - offset = TclUtfToUniChar(p, &ch); - for (check = string2; ; ) { - if (check >= checkEnd) { - p = end; - break; - } - check += TclUtfToUniChar(check, &trim); - if (ch == trim) { - length1 -= offset; - string1 += offset; - break; - } - } - } + trim = TclTrimLeft(string1, length1, string2, length2); - Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(string1+trim, length1-trim)); return TCL_OK; } @@ -3276,10 +3202,8 @@ StringTrimRCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - Tcl_UniChar ch, trim; - register const char *p, *end; - const char *check, *checkEnd, *string1, *string2; - int offset, length1, length2; + const char *string1, *string2; + int trim, length1, length2; if (objc == 3) { string2 = TclGetStringFromObj(objv[2], &length2); @@ -3291,33 +3215,10 @@ StringTrimRCmd( return TCL_ERROR; } string1 = TclGetStringFromObj(objv[1], &length1); - checkEnd = string2 + length2; - /* - * The outer loop iterates over the string. The inner loop iterates over - * the trim characters. The loops terminate as soon as a non-trim - * character is discovered and length1 marks the last non-trim character. - */ - - end = string1; - for (p = string1 + length1; p > end; ) { - p = Tcl_UtfPrev(p, string1); - offset = TclUtfToUniChar(p, &ch); - check = string2; - while (1) { - if (check >= checkEnd) { - p = end; - break; - } - check += TclUtfToUniChar(check, &trim); - if (ch == trim) { - length1 -= offset; - break; - } - } - } + trim = TclTrimRight(string1, length1, string2, length2); - Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1)); + Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1-trim)); return TCL_OK; } diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index ddd2242..f2d1bfb 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3907,7 +3907,6 @@ TclCompileSwitchCmd( int savedStackDepth = envPtr->currStackDepth; int noCase; /* Has the -nocase flag been given? */ int foundMode = 0; /* Have we seen a mode flag yet? */ - int isListedArms = 0; int i, valueIndex; DefineLineInformation; /* TIP #280 */ int* clNext = envPtr->clNext; @@ -4047,89 +4046,40 @@ TclCompileSwitchCmd( */ if (numWords == 1) { - Tcl_DString bodyList; - const char **argv = NULL, *tokenStartPtr, *p; + CONST char *bytes; + int maxLen, numBytes; int bline; /* TIP #280: line of the pattern/action list, * and start of list for when tracking the * location. This list comes immediately after * the value we switch on. */ - int isTokenBraced; - - /* - * Test that we've got a suitable body list as a simple (i.e. braced) - * word, and that the elements of the body are simple words too. This - * is really rather nasty indeed. - */ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_ERROR; } + bytes = tokenPtr[1].start; + numBytes = tokenPtr[1].size; - Tcl_DStringInit(&bodyList); - Tcl_DStringAppend(&bodyList, tokenPtr[1].start, tokenPtr[1].size); - if (Tcl_SplitList(NULL, Tcl_DStringValue(&bodyList), &numWords, - &argv) != TCL_OK) { - Tcl_DStringFree(&bodyList); - return TCL_ERROR; - } - Tcl_DStringFree(&bodyList); - - /* - * Now we know what the switch arms are, we've got to see whether we - * can synthesize tokens for the arms. First check whether we've got a - * valid number of arms since we can do that now. - */ - - if (numWords == 0 || numWords % 2) { - ckfree((char *) argv); + /* Allocate enough space to work in. */ + maxLen = TclMaxListLength(bytes, numBytes, NULL); + if (maxLen < 2) { return TCL_ERROR; } - - isListedArms = 1; - bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * numWords); - bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * numWords); - bodyLines = (int *) ckalloc(sizeof(int) * numWords); - bodyNext = (int **) ckalloc(sizeof(int*) * numWords); - - /* - * Locate the start of the arms within the overall word. - */ + bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * maxLen); + bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * maxLen); + bodyLines = (int *) ckalloc(sizeof(int) * maxLen); + bodyNext = (int **) ckalloc(sizeof(int*) * maxLen); bline = mapPtr->loc[eclIndex].line[valueIndex+1]; - p = tokenStartPtr = tokenPtr[1].start; - while (isspace(UCHAR(*tokenStartPtr))) { - tokenStartPtr++; - } - if (*tokenStartPtr == '{') { - tokenStartPtr++; - isTokenBraced = 1; - } else { - isTokenBraced = 0; - } + numWords = 0; - /* - * TIP #280: Count lines within the literal list. - */ - - for (i=0 ; i 0) { + CONST char *prevBytes = bytes; + int literal; - if ((isTokenBraced && *(tokenStartPtr++) != '}') || - (tokenStartPtr < tokenPtr[1].start+tokenPtr[1].size - && !isspace(UCHAR(*tokenStartPtr)))) { - ckfree((char *) argv); + if (TCL_OK != TclFindElement(NULL, bytes, numBytes, + &(bodyTokenArray[numWords].start), &bytes, + &(bodyTokenArray[numWords].size), &literal) || !literal) { + abort: ckfree((char *) bodyToken); ckfree((char *) bodyTokenArray); ckfree((char *) bodyLines); @@ -4137,48 +4087,30 @@ TclCompileSwitchCmd( return TCL_ERROR; } + bodyTokenArray[numWords].type = TCL_TOKEN_TEXT; + bodyTokenArray[numWords].numComponents = 0; + bodyToken[numWords] = bodyTokenArray + numWords; + /* * TIP #280: Now determine the line the list element starts on * (there is no need to do it earlier, due to the possibility of * aborting, see above). */ - TclAdvanceLines(&bline, p, bodyTokenArray[i].start); + TclAdvanceLines(&bline, prevBytes, bodyTokenArray[numWords].start); TclAdvanceContinuations (&bline, &clNext, - bodyTokenArray[i].start - envPtr->source); - bodyLines[i] = bline; - bodyNext[i] = clNext; - p = bodyTokenArray[i].start; - - while (isspace(UCHAR(*tokenStartPtr))) { - tokenStartPtr++; - if (tokenStartPtr >= tokenPtr[1].start+tokenPtr[1].size) { - break; - } - } - if (*tokenStartPtr == '{') { - tokenStartPtr++; - isTokenBraced = 1; - } else { - isTokenBraced = 0; - } + bodyTokenArray[numWords].start - envPtr->source); + bodyLines[numWords] = bline; + bodyNext[numWords] = clNext; + TclAdvanceLines(&bline, bodyTokenArray[numWords].start, bytes); + TclAdvanceContinuations (&bline, &clNext, bytes - envPtr->source); + + numBytes -= (bytes - prevBytes); + numWords++; } - ckfree((char *) argv); - - /* - * Check that we've parsed everything we thought we were going to - * parse. If not, something odd is going on (I believe it is possible - * to defeat the code above) and we should bail out. - */ - - if (tokenStartPtr != tokenPtr[1].start+tokenPtr[1].size) { - ckfree((char *) bodyToken); - ckfree((char *) bodyTokenArray); - ckfree((char *) bodyLines); - ckfree((char *) bodyNext); - return TCL_ERROR; + if (numWords % 2) { + goto abort; } - } else if (numWords % 2 || numWords == 0) { /* * Odd number of words (>1) available, or no words at all available. @@ -4205,8 +4137,7 @@ TclCompileSwitchCmd( * traces, etc. */ - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || - tokenPtr->numComponents != 1) { + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { ckfree((char *) bodyToken); ckfree((char *) bodyLines); ckfree((char *) bodyNext); @@ -4255,7 +4186,7 @@ TclCompileSwitchCmd( * but it handles the most common case well enough. */ - if (isListedArms && mode == Switch_Exact && !noCase) { + if (mode == Switch_Exact) { JumptableInfo *jtPtr; int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation; int mustGenerate, jumpToDefault; diff --git a/generic/tclCompile.c b/generic/tclCompile.c index f2c4fdc..2d8d58c 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -454,12 +454,13 @@ Tcl_ObjType tclByteCodeType = { * generate an byte code internal form for the Tcl object "objPtr" by * compiling its string representation. This function also takes a hook * procedure that will be invoked to perform any needed post processing - * on the compilation results before generating byte codes. + * on the compilation results before generating byte codes. interp is + * compilation context and may not be NULL. * * Results: * The return value is a standard Tcl object result. If an error occurs * during compilation, an error message is left in the interpreter's - * result unless "interp" is NULL. + * result. * * Side effects: * Frees the old internal representation. If no error occurs, then the @@ -616,6 +617,9 @@ SetByteCodeFromAny( * compiled. Must not be NULL. */ Tcl_Obj *objPtr) /* The object to make a ByteCode object. */ { + if (interp == NULL) { + return TCL_ERROR; + } (void) TclSetByteCodeFromAny(interp, objPtr, NULL, (ClientData) NULL); return TCL_OK; } diff --git a/generic/tclConfig.c b/generic/tclConfig.c index c91ee64..251868e 100644 --- a/generic/tclConfig.c +++ b/generic/tclConfig.c @@ -273,19 +273,13 @@ QueryConfigObjCmd( } if (n) { - List *listRepPtr = (List *) - listPtr->internalRep.twoPtrValue.ptr1; Tcl_DictSearch s; - Tcl_Obj *key, **vals; - int done, i = 0; - - listRepPtr->elemCount = n; - vals = &listRepPtr->elements; + Tcl_Obj *key; + int done; for (Tcl_DictObjFirst(interp, pkgDict, &s, &key, NULL, &done); !done; Tcl_DictObjNext(&s, &key, NULL, &done)) { - vals[i++] = key; - Tcl_IncrRefCount(key); + Tcl_ListObjAppendElement(NULL, listPtr, key); } } diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 46e90ad..b741475 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -3432,7 +3432,7 @@ typedef struct TclStubs { void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ #endif /* UNIX */ #ifdef __WIN32__ /* WIN */ - void *reserved9; + VOID *reserved9; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ @@ -3441,7 +3441,7 @@ typedef struct TclStubs { void (*tcl_DeleteFileHandler) (int fd); /* 10 */ #endif /* UNIX */ #ifdef __WIN32__ /* WIN */ - void *reserved10; + VOID *reserved10; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_DeleteFileHandler) (int fd); /* 10 */ @@ -3606,7 +3606,7 @@ typedef struct TclStubs { int (*tcl_GetOpenFile) (Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ #endif /* UNIX */ #ifdef __WIN32__ /* WIN */ - void *reserved167; + VOID *reserved167; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_GetOpenFile) (Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ @@ -3631,7 +3631,7 @@ typedef struct TclStubs { int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */ char * (*tcl_JoinPath) (int argc, CONST84 char *CONST *argv, Tcl_DString *resultPtr); /* 186 */ int (*tcl_LinkVar) (Tcl_Interp *interp, CONST char *varName, char *addr, int type); /* 187 */ - void *reserved188; + VOID *reserved188; Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */ int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */ Tcl_Channel (*tcl_MakeTcpClientChannel) (ClientData tcpSocket); /* 191 */ @@ -3728,7 +3728,7 @@ typedef struct TclStubs { int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */ - void *reserved285; + VOID *reserved285; void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */ Tcl_Encoding (*tcl_CreateEncoding) (CONST Tcl_EncodingType *typePtr); /* 287 */ void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 288 */ diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 072f3fa..06c5754 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -402,6 +402,7 @@ FreeDictInternalRep( } dictPtr->internalRep.otherValuePtr = NULL; /* Belt and braces! */ + dictPtr->typePtr = NULL; } /* @@ -488,7 +489,7 @@ UpdateStringOfDict( if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; } else if (numElems > maxFlags) { - Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } else { flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int)); } @@ -503,7 +504,7 @@ UpdateStringOfDict( elem = TclGetStringFromObj(keyPtr, &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i); if (bytesNeeded < 0) { - Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } flagPtr[i+1] = TCL_DONT_QUOTE_HASH; @@ -511,11 +512,11 @@ UpdateStringOfDict( elem = TclGetStringFromObj(valuePtr, &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i+1); if (bytesNeeded < 0) { - Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } } if (bytesNeeded > INT_MAX - numElems + 1) { - Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } bytesNeeded += numElems; @@ -571,14 +572,11 @@ SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { - char *string, *s; - const char *elemStart, *nextElem; - int lenRemain, length, elemSize, hasBrace, result, isNew; - char *limit; /* Points just after string's last byte. */ - register const char *p; - register Tcl_Obj *keyPtr, *valuePtr; - Dict *dict; Tcl_HashEntry *hPtr; + int isNew, result; + Dict *dict = (Dict *) ckalloc(sizeof(Dict)); + + InitChainTable(dict); /* * Since lists and dictionaries have very closely-related string @@ -590,28 +588,15 @@ SetDictFromAny( int objc, i; Tcl_Obj **objv; - if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } + /* Cannot fail, we already know the Tcl_ObjType is "list". */ + TclListObjGetElements(NULL, objPtr, &objc, &objv); if (objc & 1) { - if (interp != NULL) { - Tcl_SetResult(interp, "missing value to go with key", - TCL_STATIC); - } - return TCL_ERROR; + goto missingValue; } - /* - * Build the hash of key/value pairs. - */ - - dict = (Dict *) ckalloc(sizeof(Dict)); - InitChainTable(dict); for (i=0 ; i 0; - p = nextElem, lenRemain = (limit - nextElem)) { - result = TclFindElement(interp, p, lenRemain, - &elemStart, &nextElem, &elemSize, &hasBrace); - if (result != TCL_OK) { - goto errorExit; - } - if (elemStart >= limit) { - break; - } - - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ - - s = ckalloc((unsigned) elemSize + 1); - if (hasBrace) { - memcpy(s, elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); - } - - TclNewObj(keyPtr); - keyPtr->bytes = s; - keyPtr->length = elemSize; - - p = nextElem; - lenRemain = (limit - nextElem); - if (lenRemain <= 0) { - goto missingKey; - } - - result = TclFindElement(interp, p, lenRemain, - &elemStart, &nextElem, &elemSize, &hasBrace); - if (result != TCL_OK) { - TclDecrRefCount(keyPtr); - goto errorExit; - } - if (elemStart >= limit) { - goto missingKey; - } - - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ - - s = ckalloc((unsigned) elemSize + 1); - if (hasBrace) { - memcpy((void *) s, (void *) elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); - } + if (literal) { + TclNewStringObj(keyPtr, elemStart, elemSize); + } else { + /* Avoid double copy */ + TclNewObj(keyPtr); + keyPtr->bytes = ckalloc((unsigned) elemSize + 1); + keyPtr->length = TclCopyAndCollapse(elemSize, elemStart, + keyPtr->bytes); + } - TclNewObj(valuePtr); - valuePtr->bytes = s; - valuePtr->length = elemSize; + result = TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal); + if (result != TCL_OK) { + TclDecrRefCount(keyPtr); + goto errorExit; + } - /* - * Store key and value in the hash table we're building. - */ + if (literal) { + TclNewStringObj(valuePtr, elemStart, elemSize); + } else { + /* Avoid double copy */ + TclNewObj(valuePtr); + valuePtr->bytes = ckalloc((unsigned) elemSize + 1); + valuePtr->length = TclCopyAndCollapse(elemSize, elemStart, + valuePtr->bytes); + } - hPtr = CreateChainEntry(dict, keyPtr, &isNew); - if (!isNew) { - Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); + /* Store key and value in the hash table we're building. */ + hPtr = CreateChainEntry(dict, keyPtr, &isNew); + if (!isNew) { + Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); - TclDecrRefCount(keyPtr); - TclDecrRefCount(discardedValue); + TclDecrRefCount(keyPtr); + TclDecrRefCount(discardedValue); + } + Tcl_SetHashValue(hPtr, valuePtr); + Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */ } - Tcl_SetHashValue(hPtr, valuePtr); - Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */ } - installHash: /* * Free the old internalRep before setting the new one. We do this as late * as possible to allow the conversion code, in particular @@ -743,11 +690,10 @@ SetDictFromAny( objPtr->typePtr = &tclDictType; return TCL_OK; - missingKey: + missingValue: if (interp != NULL) { Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC); } - TclDecrRefCount(keyPtr); result = TCL_ERROR; errorExit: diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index ad60ed7..2e0d51f 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -334,6 +334,7 @@ FreeEncodingIntRep( Tcl_Obj *objPtr) { Tcl_FreeEncoding((Tcl_Encoding) objPtr->internalRep.otherValuePtr); + objPtr->typePtr = NULL; } /* diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 6ef4ac7..dc87d70 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1473,57 +1473,55 @@ TclCompEvalObj( * information. */ - { + if (invoker) { Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr, (char *) codePtr); if (hePtr) { ExtCmdLoc *eclPtr = Tcl_GetHashValue(hePtr); int redo = 0; + CmdFrame *ctxPtr = TclStackAlloc(interp,sizeof(CmdFrame)); - if (invoker) { - CmdFrame *ctxPtr = TclStackAlloc(interp,sizeof(CmdFrame)); - *ctxPtr = *invoker; - - if (invoker->type == TCL_LOCATION_BC) { - /* - * Note: Type BC => ctx.data.eval.path is not used. - * ctx.data.tebc.codePtr used instead - */ - - TclGetSrcInfoForPc(ctxPtr); - if (ctxPtr->type == TCL_LOCATION_SOURCE) { - /* - * The reference made by 'TclGetSrcInfoForPc' is - * dead. - */ - - Tcl_DecrRefCount(ctxPtr->data.eval.path); - ctxPtr->data.eval.path = NULL; - } - } + *ctxPtr = *invoker; - if (word < ctxPtr->nline) { + if (invoker->type == TCL_LOCATION_BC) { + /* + * Note: Type BC => ctx.data.eval.path is not used. + * ctx.data.tebc.codePtr used instead + */ + + TclGetSrcInfoForPc(ctxPtr); + if (ctxPtr->type == TCL_LOCATION_SOURCE) { /* - * Note: We do not care if the line[word] is -1. This - * is a difference and requires a recompile (location - * changed from absolute to relative, literal is used - * fixed and through variable) - * - * Example: - * test info-32.0 using literal of info-24.8 - * (dict with ... vs set body ...). + * The reference made by 'TclGetSrcInfoForPc' is + * dead. */ - - redo = ((eclPtr->type == TCL_LOCATION_SOURCE) - && (eclPtr->start != ctxPtr->line[word])) - || ((eclPtr->type == TCL_LOCATION_BC) - && (ctxPtr->type == TCL_LOCATION_SOURCE)); + + Tcl_DecrRefCount(ctxPtr->data.eval.path); + ctxPtr->data.eval.path = NULL; } - - TclStackFree(interp, ctxPtr); } - + + if (word < ctxPtr->nline) { + /* + * Note: We do not care if the line[word] is -1. This + * is a difference and requires a recompile (location + * changed from absolute to relative, literal is used + * fixed and through variable) + * + * Example: + * test info-32.0 using literal of info-24.8 + * (dict with ... vs set body ...). + */ + + redo = ((eclPtr->type == TCL_LOCATION_SOURCE) + && (eclPtr->start != ctxPtr->line[word])) + || ((eclPtr->type == TCL_LOCATION_BC) + && (ctxPtr->type == TCL_LOCATION_SOURCE)); + } + + TclStackFree(interp, ctxPtr); + if (redo) { goto recompileObj; } diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index 6cd641f..2b4977b 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -950,7 +950,7 @@ TclFileAttrsCmd( int result; CONST char ** attributeStrings; Tcl_Obj* objStrings = NULL; - int numObjStrings = -1; + int numObjStrings = -1, didAlloc = 0; Tcl_Obj *filePtr; if (objc < 3) { @@ -983,9 +983,8 @@ TclFileAttrsCmd( Tcl_AppendResult(interp, "could not read \"", TclGetString(filePtr), "\": ", Tcl_PosixError(interp), NULL); - return TCL_ERROR; } - goto end; + return TCL_ERROR; } /* @@ -1003,12 +1002,16 @@ TclFileAttrsCmd( } attributeStrings = (CONST char **) TclStackAlloc(interp, (1+numObjStrings) * sizeof(char*)); + didAlloc = 1; for (index = 0; index < numObjStrings; index++) { Tcl_ListObjIndex(interp, objStrings, index, &objPtr); attributeStrings[index] = TclGetString(objPtr); } attributeStrings[index] = NULL; + } else if (objStrings != NULL) { + Tcl_Panic("must not update objPtrRef's variable and return non-NULL"); } + if (objc == 0) { /* * Get all attributes. @@ -1069,6 +1072,10 @@ TclFileAttrsCmd( "option", 0, &index) != TCL_OK) { goto end; } + if (didAlloc) { + TclFreeIntRep(objv[0]); + objv[0]->typePtr = NULL; + } if (Tcl_FSFileAttrsGet(interp, index, filePtr, &objPtr) != TCL_OK) { goto end; @@ -1093,6 +1100,10 @@ TclFileAttrsCmd( "option", 0, &index) != TCL_OK) { goto end; } + if (didAlloc) { + TclFreeIntRep(objv[i]); + objv[i]->typePtr = NULL; + } if (i + 1 == objc) { Tcl_AppendResult(interp, "value for \"", TclGetString(objv[i]), "\" missing", NULL); @@ -1107,20 +1118,20 @@ TclFileAttrsCmd( result = TCL_OK; end: - if (numObjStrings != -1) { + if (didAlloc) { /* * Free up the array we allocated. */ TclStackFree(interp, (void *)attributeStrings); + } + if (objStrings != NULL) { /* * We don't need this object that was passed to us any more. */ - if (objStrings != NULL) { - Tcl_DecrRefCount(objStrings); - } + Tcl_DecrRefCount(objStrings); } return result; } diff --git a/generic/tclIO.c b/generic/tclIO.c index 2ece2f4..0f01baa 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -10741,6 +10741,9 @@ SetChannelFromAny( ChannelState *statePtr; Interp *interpPtr; + if (interp == NULL) { + return TCL_ERROR; + } if (objPtr->typePtr == &tclChannelType) { /* * The channel is valid until any call to DetachChannel occurs. diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index dcedd4e..3e37f0f 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -303,9 +303,11 @@ SetIndexFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr) /* The object to convert. */ { + if (interp) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "can't convert value to index except via Tcl_GetIndexFromObj API", -1)); + } return TCL_ERROR; } @@ -395,6 +397,7 @@ FreeIndex( Tcl_Obj *objPtr) { ckfree((char *) objPtr->internalRep.otherValuePtr); + objPtr->typePtr = NULL; } /* diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 6d63164..e30379e 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -576,7 +576,7 @@ declare 145 generic { struct AuxDataType *TclGetAuxDataType(char *typeName) } declare 146 generic { - TclHandle TclHandleCreate(VOID *ptr) + TclHandle TclHandleCreate(void *ptr) } declare 147 generic { void TclHandleFree(TclHandle handle) diff --git a/generic/tclInt.h b/generic/tclInt.h index f6ed2d5..1c1e615 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2193,6 +2193,9 @@ typedef struct List { * accomodate all elements. */ } List; +#define LIST_MAX \ + (1 + (int)(((size_t)UINT_MAX - sizeof(List))/sizeof(Tcl_Obj *))) + /* * Macro used to get the elements of a list object. */ @@ -2200,6 +2203,12 @@ typedef struct List { #define ListRepPtr(listPtr) \ ((List *) (listPtr)->internalRep.twoPtrValue.ptr1) +#define ListSetIntRep(objPtr, listRepPtr) \ + (objPtr)->internalRep.twoPtrValue.ptr1 = (void *)(listRepPtr), \ + (objPtr)->internalRep.twoPtrValue.ptr2 = NULL, \ + (listRepPtr)->refCount++, \ + (objPtr)->typePtr = &tclListType + #define ListObjGetElements(listPtr, objc, objv) \ ((objv) = &(ListRepPtr(listPtr)->elements), \ (objc) = ListRepPtr(listPtr)->elemCount) @@ -2207,6 +2216,9 @@ typedef struct List { #define ListObjLength(listPtr, len) \ ((len) = ListRepPtr(listPtr)->elemCount) +#define ListObjIsCanonical(listPtr) \ + (((listPtr)->bytes == NULL) || ListRepPtr(listPtr)->canonicalFlag) + #define TclListObjGetElements(interp, listPtr, objcPtr, objvPtr) \ (((listPtr)->typePtr == &tclListType) \ ? ((ListObjGetElements((listPtr), *(objcPtr), *(objvPtr))), TCL_OK)\ @@ -2217,6 +2229,9 @@ typedef struct List { ? ((ListObjLength((listPtr), *(lenPtr))), TCL_OK)\ : Tcl_ListObjLength((interp), (listPtr), (lenPtr))) +#define TclListObjIsCanonical(listPtr) \ + (((listPtr)->typePtr == &tclListType) ? ListObjIsCanonical((listPtr)) : 0) + /* * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere, * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints. @@ -2646,6 +2661,7 @@ MODULE_SCOPE void TclInitObjSubsystem(void); MODULE_SCOPE void TclInitSubsystems(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); MODULE_SCOPE int TclIsLocalScalar(const char *src, int len); +MODULE_SCOPE int TclIsSpaceProc(char byte); MODULE_SCOPE int TclJoinThread(Tcl_ThreadId id, int *result); MODULE_SCOPE void TclLimitRemoveAllHandlers(Tcl_Interp *interp); MODULE_SCOPE Tcl_Obj * TclLindexList(Tcl_Interp *interp, @@ -2669,9 +2685,8 @@ MODULE_SCOPE Tcl_Obj * TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *valuePtr); MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name, const EnsembleImplMap map[]); -MODULE_SCOPE int TclMarkList(Tcl_Interp *interp, const char *list, - const char *end, int *argcPtr, - const int **argszPtr, const char ***argvPtr); +MODULE_SCOPE int TclMaxListLength(CONST char *bytes, int numBytes, + CONST char **endPtr); MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr, int *codePtr, int *levelPtr); @@ -2791,6 +2806,10 @@ MODULE_SCOPE int TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr, int *clNextOuter, CONST char *outerScript); MODULE_SCOPE void TclTransferResult(Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); +MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes, + const char *trim, int numTrim); +MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes, + const char *trim, int numTrim); MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE Tcl_PackageInitProc *TclpFindSymbol(Tcl_Interp *interp, @@ -3507,6 +3526,13 @@ MODULE_SCOPE void TclpFreeAllocCache(void *); #else /* not PURIFY or USE_THREAD_ALLOC */ +#if defined(USE_TCLALLOC) && USE_TCLALLOC + MODULE_SCOPE void TclFinalizeAllocSubsystem(); + MODULE_SCOPE void TclInitAlloc(); +#else +# define USE_TCLALLOC 0 +#endif + #ifdef TCL_THREADS /* declared in tclObj.c */ MODULE_SCOPE Tcl_Mutex tclObjMutex; diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index 3bf181f..fb63ec0 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -1054,11 +1054,11 @@ typedef struct TclIntStubs { int magic; struct TclIntStubHooks *hooks; - void *reserved0; - void *reserved1; - void *reserved2; + VOID *reserved0; + VOID *reserved1; + VOID *reserved2; void (*tclAllocateFreeObjects) (void); /* 3 */ - void *reserved4; + VOID *reserved4; int (*tclCleanupChildren) (Tcl_Interp *interp, int numPids, Tcl_Pid *pidPtr, Tcl_Channel errorChan); /* 5 */ void (*tclCleanupCommand) (Command *cmdPtr); /* 6 */ int (*tclCopyAndCollapse) (int count, CONST char *src, char *dst); /* 7 */ @@ -1067,29 +1067,29 @@ typedef struct TclIntStubs { int (*tclCreateProc) (Tcl_Interp *interp, Namespace *nsPtr, CONST char *procName, Tcl_Obj *argsPtr, Tcl_Obj *bodyPtr, Proc **procPtrPtr); /* 10 */ void (*tclDeleteCompiledLocalVars) (Interp *iPtr, CallFrame *framePtr); /* 11 */ void (*tclDeleteVars) (Interp *iPtr, TclVarHashTable *tablePtr); /* 12 */ - void *reserved13; + VOID *reserved13; int (*tclDumpMemoryInfo) (ClientData clientData, int flags); /* 14 */ - void *reserved15; + VOID *reserved15; void (*tclExprFloatError) (Tcl_Interp *interp, double value); /* 16 */ - void *reserved17; - void *reserved18; - void *reserved19; - void *reserved20; - void *reserved21; + VOID *reserved17; + VOID *reserved18; + VOID *reserved19; + VOID *reserved20; + VOID *reserved21; int (*tclFindElement) (Tcl_Interp *interp, CONST char *listStr, int listLength, CONST char **elementPtr, CONST char **nextPtr, int *sizePtr, int *bracePtr); /* 22 */ Proc * (*tclFindProc) (Interp *iPtr, CONST char *procName); /* 23 */ int (*tclFormatInt) (char *buffer, long n); /* 24 */ void (*tclFreePackageInfo) (Interp *iPtr); /* 25 */ - void *reserved26; - void *reserved27; + VOID *reserved26; + VOID *reserved27; Tcl_Channel (*tclpGetDefaultStdChannel) (int type); /* 28 */ - void *reserved29; - void *reserved30; + VOID *reserved29; + VOID *reserved30; CONST char * (*tclGetExtension) (CONST char *name); /* 31 */ int (*tclGetFrame) (Tcl_Interp *interp, CONST char *str, CallFrame **framePtrPtr); /* 32 */ - void *reserved33; + VOID *reserved33; int (*tclGetIntForIndex) (Tcl_Interp *interp, Tcl_Obj *objPtr, int endValue, int *indexPtr); /* 34 */ - void *reserved35; + VOID *reserved35; int (*tclGetLong) (Tcl_Interp *interp, CONST char *str, long *longPtr); /* 36 */ int (*tclGetLoadedPackages) (Tcl_Interp *interp, char *targetName); /* 37 */ int (*tclGetNamespaceForQualName) (Tcl_Interp *interp, CONST char *qualName, Namespace *cxtNsPtr, int flags, Namespace **nsPtrPtr, Namespace **altNsPtrPtr, Namespace **actualCxtPtrPtr, CONST char **simpleNamePtr); /* 38 */ @@ -1097,74 +1097,74 @@ typedef struct TclIntStubs { int (*tclGetOpenMode) (Tcl_Interp *interp, CONST char *str, int *seekFlagPtr); /* 40 */ Tcl_Command (*tclGetOriginalCommand) (Tcl_Command command); /* 41 */ char * (*tclpGetUserHome) (CONST char *name, Tcl_DString *bufferPtr); /* 42 */ - void *reserved43; + VOID *reserved43; int (*tclGuessPackageName) (CONST char *fileName, Tcl_DString *bufPtr); /* 44 */ int (*tclHideUnsafeCommands) (Tcl_Interp *interp); /* 45 */ int (*tclInExit) (void); /* 46 */ - void *reserved47; - void *reserved48; - void *reserved49; + VOID *reserved47; + VOID *reserved48; + VOID *reserved49; void (*tclInitCompiledLocals) (Tcl_Interp *interp, CallFrame *framePtr, Namespace *nsPtr); /* 50 */ int (*tclInterpInit) (Tcl_Interp *interp); /* 51 */ - void *reserved52; + VOID *reserved52; int (*tclInvokeObjectCommand) (ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char **argv); /* 53 */ int (*tclInvokeStringCommand) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); /* 54 */ Proc * (*tclIsProc) (Command *cmdPtr); /* 55 */ - void *reserved56; - void *reserved57; + VOID *reserved56; + VOID *reserved57; Var * (*tclLookupVar) (Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, CONST char *msg, int createPart1, int createPart2, Var **arrayPtrPtr); /* 58 */ - void *reserved59; + VOID *reserved59; int (*tclNeedSpace) (CONST char *start, CONST char *end); /* 60 */ Tcl_Obj * (*tclNewProcBodyObj) (Proc *procPtr); /* 61 */ int (*tclObjCommandComplete) (Tcl_Obj *cmdPtr); /* 62 */ int (*tclObjInterpProc) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); /* 63 */ int (*tclObjInvoke) (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int flags); /* 64 */ - void *reserved65; - void *reserved66; - void *reserved67; - void *reserved68; + VOID *reserved65; + VOID *reserved66; + VOID *reserved67; + VOID *reserved68; char * (*tclpAlloc) (unsigned int size); /* 69 */ - void *reserved70; - void *reserved71; - void *reserved72; - void *reserved73; + VOID *reserved70; + VOID *reserved71; + VOID *reserved72; + VOID *reserved73; void (*tclpFree) (char *ptr); /* 74 */ unsigned long (*tclpGetClicks) (void); /* 75 */ unsigned long (*tclpGetSeconds) (void); /* 76 */ void (*tclpGetTime) (Tcl_Time *time); /* 77 */ int (*tclpGetTimeZone) (unsigned long time); /* 78 */ - void *reserved79; - void *reserved80; + VOID *reserved79; + VOID *reserved80; char * (*tclpRealloc) (char *ptr, unsigned int size); /* 81 */ - void *reserved82; - void *reserved83; - void *reserved84; - void *reserved85; - void *reserved86; - void *reserved87; + VOID *reserved82; + VOID *reserved83; + VOID *reserved84; + VOID *reserved85; + VOID *reserved86; + VOID *reserved87; char * (*tclPrecTraceProc) (ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags); /* 88 */ int (*tclPreventAliasLoop) (Tcl_Interp *interp, Tcl_Interp *cmdInterp, Tcl_Command cmd); /* 89 */ - void *reserved90; + VOID *reserved90; void (*tclProcCleanupProc) (Proc *procPtr); /* 91 */ int (*tclProcCompileProc) (Tcl_Interp *interp, Proc *procPtr, Tcl_Obj *bodyPtr, Namespace *nsPtr, CONST char *description, CONST char *procName); /* 92 */ void (*tclProcDeleteProc) (ClientData clientData); /* 93 */ - void *reserved94; - void *reserved95; + VOID *reserved94; + VOID *reserved95; int (*tclRenameCommand) (Tcl_Interp *interp, CONST char *oldName, CONST char *newName); /* 96 */ void (*tclResetShadowedCmdRefs) (Tcl_Interp *interp, Command *newCmdPtr); /* 97 */ int (*tclServiceIdle) (void); /* 98 */ - void *reserved99; - void *reserved100; + VOID *reserved99; + VOID *reserved100; char * (*tclSetPreInitScript) (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 */ - void *reserved105; - void *reserved106; - void *reserved107; + VOID *reserved105; + VOID *reserved106; + VOID *reserved107; void (*tclTeardownNamespace) (Namespace *nsPtr); /* 108 */ int (*tclUpdateReturnInfo) (Interp *iPtr); /* 109 */ - void *reserved110; + VOID *reserved110; void (*tcl_AddInterpResolvers) (Tcl_Interp *interp, CONST char *name, Tcl_ResolveCmdProc *cmdProc, Tcl_ResolveVarProc *varProc, Tcl_ResolveCompiledVarProc *compiledVarProc); /* 111 */ int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 112 */ Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, CONST char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 113 */ @@ -1188,13 +1188,13 @@ typedef struct TclIntStubs { void (*tcl_SetNamespaceResolvers) (Tcl_Namespace *namespacePtr, Tcl_ResolveCmdProc *cmdProc, Tcl_ResolveVarProc *varProc, Tcl_ResolveCompiledVarProc *compiledVarProc); /* 131 */ int (*tclpHasSockets) (Tcl_Interp *interp); /* 132 */ struct tm * (*tclpGetDate) (CONST time_t *time, int useGMT); /* 133 */ - void *reserved134; - void *reserved135; - void *reserved136; - void *reserved137; + VOID *reserved134; + VOID *reserved135; + VOID *reserved136; + VOID *reserved137; CONST84_RETURN char * (*tclGetEnv) (CONST char *name, Tcl_DString *valuePtr); /* 138 */ - void *reserved139; - void *reserved140; + VOID *reserved139; + VOID *reserved140; CONST84_RETURN char * (*tclpGetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 141 */ int (*tclSetByteCodeFromAny) (Tcl_Interp *interp, Tcl_Obj *objPtr, CompileHookProc *hookProc, ClientData clientData); /* 142 */ int (*tclAddLiteralObj) (struct CompileEnv *envPtr, Tcl_Obj *objPtr, LiteralEntry **litPtrPtr); /* 143 */ @@ -1208,13 +1208,13 @@ typedef struct TclIntStubs { void (*tclRegExpRangeUniChar) (Tcl_RegExp re, int index, int *startPtr, int *endPtr); /* 151 */ void (*tclSetLibraryPath) (Tcl_Obj *pathPtr); /* 152 */ Tcl_Obj * (*tclGetLibraryPath) (void); /* 153 */ - void *reserved154; - void *reserved155; + VOID *reserved154; + VOID *reserved155; void (*tclRegError) (Tcl_Interp *interp, CONST char *msg, int status); /* 156 */ Var * (*tclVarTraceExists) (Tcl_Interp *interp, CONST char *varName); /* 157 */ void (*tclSetStartupScriptFileName) (CONST char *filename); /* 158 */ CONST84_RETURN char * (*tclGetStartupScriptFileName) (void); /* 159 */ - void *reserved160; + VOID *reserved160; int (*tclChannelTransform) (Tcl_Interp *interp, Tcl_Channel chan, Tcl_Obj *cmdObjPtr); /* 161 */ void (*tclChannelEventScriptInvoker) (ClientData clientData, int flags); /* 162 */ VOID * (*tclGetInstructionTable) (void); /* 163 */ @@ -1228,32 +1228,32 @@ typedef struct TclIntStubs { int (*tclCheckExecutionTraces) (Tcl_Interp *interp, CONST char *command, int numChars, Command *cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *CONST objv[]); /* 171 */ int (*tclInThreadExit) (void); /* 172 */ int (*tclUniCharMatch) (CONST Tcl_UniChar *string, int strLen, CONST Tcl_UniChar *pattern, int ptnLen, int flags); /* 173 */ - void *reserved174; + VOID *reserved174; int (*tclCallVarTraces) (Interp *iPtr, Var *arrayPtr, Var *varPtr, CONST char *part1, CONST char *part2, int flags, int leaveErrMsg); /* 175 */ void (*tclCleanupVar) (Var *varPtr, Var *arrayPtr); /* 176 */ void (*tclVarErrMsg) (Tcl_Interp *interp, CONST char *part1, CONST char *part2, CONST char *operation, CONST char *reason); /* 177 */ void (*tcl_SetStartupScript) (Tcl_Obj *pathPtr, CONST char*encodingName); /* 178 */ Tcl_Obj * (*tcl_GetStartupScript) (CONST char **encodingNamePtr); /* 179 */ - void *reserved180; - void *reserved181; + VOID *reserved180; + VOID *reserved181; struct tm * (*tclpLocaltime) (CONST time_t *clock); /* 182 */ struct tm * (*tclpGmtime) (CONST time_t *clock); /* 183 */ - void *reserved184; - void *reserved185; - void *reserved186; - void *reserved187; - void *reserved188; - void *reserved189; - void *reserved190; - void *reserved191; - void *reserved192; - void *reserved193; - void *reserved194; - void *reserved195; - void *reserved196; - void *reserved197; + VOID *reserved184; + VOID *reserved185; + VOID *reserved186; + VOID *reserved187; + VOID *reserved188; + VOID *reserved189; + VOID *reserved190; + VOID *reserved191; + VOID *reserved192; + VOID *reserved193; + VOID *reserved194; + VOID *reserved195; + VOID *reserved196; + VOID *reserved197; int (*tclObjGetFrame) (Tcl_Interp *interp, Tcl_Obj *objPtr, CallFrame **framePtrPtr); /* 198 */ - void *reserved199; + VOID *reserved199; int (*tclpObjRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 200 */ int (*tclpObjCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 201 */ int (*tclpObjCreateDirectory) (Tcl_Obj *pathPtr); /* 202 */ @@ -1263,9 +1263,9 @@ typedef struct TclIntStubs { int (*tclpObjStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 206 */ int (*tclpObjAccess) (Tcl_Obj *pathPtr, int mode); /* 207 */ Tcl_Channel (*tclpOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions); /* 208 */ - void *reserved209; - void *reserved210; - void *reserved211; + VOID *reserved209; + VOID *reserved210; + VOID *reserved211; void (*tclpFindExecutable) (CONST char *argv0); /* 212 */ Tcl_Obj * (*tclGetObjNameOfExecutable) (void); /* 213 */ void (*tclSetObjNameOfExecutable) (Tcl_Obj *name, Tcl_Encoding encoding); /* 214 */ @@ -1273,11 +1273,11 @@ typedef struct TclIntStubs { void (*tclStackFree) (Tcl_Interp *interp, VOID *freePtr); /* 216 */ int (*tclPushStackFrame) (Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr, Tcl_Namespace *namespacePtr, int isProcCallFrame); /* 217 */ void (*tclPopStackFrame) (Tcl_Interp *interp); /* 218 */ - void *reserved219; - void *reserved220; - void *reserved221; - void *reserved222; - void *reserved223; + VOID *reserved219; + VOID *reserved220; + VOID *reserved221; + VOID *reserved222; + VOID *reserved223; TclPlatformType * (*tclGetPlatform) (void); /* 224 */ Tcl_Obj * (*tclTraceDictPath) (Tcl_Interp *interp, Tcl_Obj *rootPtr, int keyc, Tcl_Obj *CONST keyv[], int flags); /* 225 */ int (*tclObjBeingDeleted) (Tcl_Obj *objPtr); /* 226 */ @@ -1291,18 +1291,18 @@ typedef struct TclIntStubs { Var * (*tclVarHashCreateVar) (TclVarHashTable *tablePtr, CONST char *key, int *newPtr); /* 234 */ void (*tclInitVarHashTable) (TclVarHashTable *tablePtr, Namespace *nsPtr); /* 235 */ void (*tclBackgroundException) (Tcl_Interp *interp, int code); /* 236 */ - void *reserved237; - void *reserved238; - void *reserved239; - void *reserved240; - void *reserved241; - void *reserved242; + VOID *reserved237; + VOID *reserved238; + VOID *reserved239; + VOID *reserved240; + VOID *reserved241; + VOID *reserved242; void (*tclDbDumpActiveObjects) (FILE *outFile); /* 243 */ - void *reserved244; - void *reserved245; - void *reserved246; - void *reserved247; - void *reserved248; + VOID *reserved244; + VOID *reserved245; + VOID *reserved246; + VOID *reserved247; + VOID *reserved248; char* (*tclDoubleDigits) (double dv, int ndigits, int flags, int*decpt, int*signum, char**endPtr); /* 249 */ } TclIntStubs; diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index c616671..3c03015 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -381,7 +381,7 @@ typedef struct TclIntPlatStubs { Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 2 */ int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 3 */ int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 4 */ - void *reserved5; + VOID *reserved5; TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 6 */ TclFile (*tclpOpenFile) (CONST char *fname, int mode); /* 7 */ int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */ @@ -398,27 +398,27 @@ typedef struct TclIntPlatStubs { 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 */ HINSTANCE (*tclWinGetTclInstance) (void); /* 4 */ - void *reserved5; + VOID *reserved5; u_short (*tclWinNToHS) (u_short ns); /* 6 */ int (*tclWinSetSockOpt) (int 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 *reserved10; void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 11 */ int (*tclpCloseFile) (TclFile file); /* 12 */ Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 13 */ int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 14 */ int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 15 */ - void *reserved16; - void *reserved17; + VOID *reserved16; + VOID *reserved17; TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 18 */ TclFile (*tclpOpenFile) (CONST char *fname, int mode); /* 19 */ void (*tclWinAddProcess) (VOID *hProcess, unsigned long id); /* 20 */ - void *reserved21; + VOID *reserved21; TclFile (*tclpCreateTempFile) (CONST char *contents); /* 22 */ char * (*tclpGetTZName) (int isdst); /* 23 */ char * (*tclWinNoBackslash) (char *path); /* 24 */ - void *reserved25; + VOID *reserved25; void (*tclWinSetInterfaces) (int wide); /* 26 */ void (*tclWinFlushDirtyChannels) (void); /* 27 */ void (*tclWinResetInterfaces) (void); /* 28 */ @@ -430,7 +430,7 @@ typedef struct TclIntPlatStubs { Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 2 */ int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 3 */ int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 4 */ - void *reserved5; + VOID *reserved5; TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 6 */ TclFile (*tclpOpenFile) (CONST char *fname, int mode); /* 7 */ int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 8 */ @@ -711,5 +711,7 @@ extern TclIntPlatStubs *tclIntPlatStubsPtr; #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +#undef TclpLocaltime_unix +#undef TclpGmtime_unix #endif /* _TCLINTPLATDECLS */ diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 3c48a2f..17aa256 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -17,7 +17,9 @@ * Prototypes for functions defined later in this file: */ -static List * NewListIntRep(int objc, Tcl_Obj *CONST objv[]); +static List * AttemptNewList(Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[]); +static List * NewListIntRep(int objc, Tcl_Obj *CONST objv[], int p); static void DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); static void FreeListInternalRep(Tcl_Obj *listPtr); static int SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); @@ -49,16 +51,16 @@ Tcl_ObjType tclListType = { * * NewListIntRep -- * - * If objc>0 and objv!=NULL, this function creates a list internal rep - * with objc elements given in the array objv. If objc>0 and objv==NULL - * it creates the list internal rep of a list with 0 elements, where - * enough space has been preallocated to store objc elements. If objc<=0, - * it returns NULL. + * Creates a list internal rep with space for objc elements. objc + * must be > 0. If objv!=NULL, initializes with the first objc values + * in that array. If objv==NULL, initalize list internal rep to have + * 0 elements, with space to add objc more. Flag value "p" indicates + * how to behave on failure. * * Results: - * A new List struct is returned. If objc<=0 or if the allocation fails - * for lack of memory, NULL is returned. The list returned has refCount - * 0. + * A new List struct with refCount 0 is returned. If some failure + * prevents this then if p=0, NULL is returned and otherwise the + * routine panics. * * Side effects: * The ref counts of the elements in objv are incremented since the @@ -70,12 +72,13 @@ Tcl_ObjType tclListType = { static List * NewListIntRep( int objc, - Tcl_Obj *CONST objv[]) + Tcl_Obj *CONST objv[], + int p) { List *listRepPtr; if (objc <= 0) { - return NULL; + Tcl_Panic("NewListIntRep: expects postive element count"); } /* @@ -85,13 +88,21 @@ NewListIntRep( * requires API changes to fix. See [Bug 219196] for a discussion. */ - if ((size_t)objc > INT_MAX/sizeof(Tcl_Obj *)) { + if ((size_t)objc > LIST_MAX) { + if (p) { + Tcl_Panic("max length of a Tcl list (%d elements) exceeded", + LIST_MAX); + } return NULL; } listRepPtr = (List *) attemptckalloc(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *))); if (listRepPtr == NULL) { + if (p) { + Tcl_Panic("list creation failed: unable to alloc %u bytes", + (unsigned)(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *)))); + } return NULL; } @@ -118,6 +129,50 @@ NewListIntRep( /* *---------------------------------------------------------------------- * + * AttemptNewList -- + * + * Creates a list internal rep with space for objc elements. objc + * must be > 0. If objv!=NULL, initializes with the first objc values + * in that array. If objv==NULL, initalize list internal rep to have + * 0 elements, with space to add objc more. + * + * Results: + * A new List struct with refCount 0 is returned. If some failure + * prevents this then NULL is returned, and an error message is left + * in the interp result, unless interp is NULL. + * + * Side effects: + * The ref counts of the elements in objv are incremented since the + * resulting list now refers to them. + * + *---------------------------------------------------------------------- + */ + +static List * +AttemptNewList( + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[]) +{ + List *listRepPtr = NewListIntRep(objc, objv, 0); + + if (interp != NULL && listRepPtr == NULL) { + if (objc > LIST_MAX) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "max length of a Tcl list (%d elements) exceeded", + LIST_MAX)); + } else { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "list creation failed: unable to alloc %u bytes", + (unsigned)(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *))))); + } + } + return listRepPtr; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_NewListObj -- * * This function is normally called when not debugging: i.e., when @@ -172,21 +227,14 @@ Tcl_NewListObj( * Create the internal rep. */ - listRepPtr = NewListIntRep(objc, objv); - if (!listRepPtr) { - Tcl_Panic("Not enough memory to allocate list"); - } + listRepPtr = NewListIntRep(objc, objv, 1); /* * Now create the object. */ Tcl_InvalidateStringRep(listPtr); - listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; - listPtr->internalRep.twoPtrValue.ptr2 = NULL; - listPtr->typePtr = &tclListType; - listRepPtr->refCount++; - + ListSetIntRep(listPtr, listRepPtr); return listPtr; } #endif /* if TCL_MEM_DEBUG */ @@ -244,20 +292,14 @@ Tcl_DbNewListObj( * Create the internal rep. */ - listRepPtr = NewListIntRep(objc, objv); - if (!listRepPtr) { - Tcl_Panic("Not enough memory to allocate list"); - } + listRepPtr = NewListIntRep(objc, objv, 1); /* * Now create the object. */ Tcl_InvalidateStringRep(listPtr); - listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; - listPtr->internalRep.twoPtrValue.ptr2 = NULL; - listPtr->typePtr = &tclListType; - listRepPtr->refCount++; + ListSetIntRep(listPtr, listRepPtr); return listPtr; } @@ -326,14 +368,8 @@ Tcl_SetListObj( */ if (objc > 0) { - listRepPtr = NewListIntRep(objc, objv); - if (!listRepPtr) { - Tcl_Panic("Cannot allocate enough memory for Tcl_SetListObj"); - } - objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; - objPtr->internalRep.twoPtrValue.ptr2 = NULL; - objPtr->typePtr = &tclListType; - listRepPtr->refCount++; + listRepPtr = NewListIntRep(objc, objv, 1); + ListSetIntRep(objPtr, listRepPtr); } else { objPtr->bytes = tclEmptyStringRep; objPtr->length = 0; @@ -424,30 +460,19 @@ Tcl_ListObjGetElements( register List *listRepPtr; if (listPtr->typePtr != &tclListType) { - int result, length; + int result; - /* - * Don't get the string version of a dictionary; that transformation - * is not lossy, but is expensive. - */ - - if (listPtr->typePtr == &tclDictType) { - (void) Tcl_DictObjSize(NULL, listPtr, &length); - } else { - (void) TclGetStringFromObj(listPtr, &length); - } - if (!length) { + if (listPtr->bytes == tclEmptyStringRep) { *objcPtr = 0; *objvPtr = NULL; return TCL_OK; } - result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); *objcPtr = listRepPtr->elemCount; *objvPtr = &listRepPtr->elements; return TCL_OK; @@ -551,21 +576,19 @@ Tcl_ListObjAppendElement( Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendElement"); } if (listPtr->typePtr != &tclListType) { - int result, length; + int result; - (void) TclGetStringFromObj(listPtr, &length); - if (!length) { + if (listPtr->bytes == tclEmptyStringRep) { Tcl_SetListObj(listPtr, 1, &objPtr); return TCL_OK; } - result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); numElems = listRepPtr->elemCount; numRequired = numElems + 1 ; @@ -587,9 +610,9 @@ Tcl_ListObjAppendElement( List *oldListRepPtr = listRepPtr; Tcl_Obj **oldElems; - listRepPtr = NewListIntRep(newMax, NULL); - if (!listRepPtr) { - Tcl_Panic("Not enough memory to allocate list"); + listRepPtr = AttemptNewList(interp, newMax, NULL); + if (listRepPtr == NULL) { + return TCL_ERROR; } oldElems = &oldListRepPtr->elements; elemPtrs = &listRepPtr->elements; @@ -662,21 +685,19 @@ Tcl_ListObjIndex( register List *listRepPtr; if (listPtr->typePtr != &tclListType) { - int result, length; + int result; - (void) TclGetStringFromObj(listPtr, &length); - if (!length) { + if (listPtr->bytes == tclEmptyStringRep) { *objPtrPtr = NULL; return TCL_OK; } - result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); if ((index < 0) || (index >= listRepPtr->elemCount)) { *objPtrPtr = NULL; } else { @@ -717,21 +738,19 @@ Tcl_ListObjLength( register List *listRepPtr; if (listPtr->typePtr != &tclListType) { - int result, length; + int result; - (void) TclGetStringFromObj(listPtr, &length); - if (!length) { + if (listPtr->bytes == tclEmptyStringRep) { *intPtr = 0; return TCL_OK; } - result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); *intPtr = listRepPtr->elemCount; return TCL_OK; } @@ -792,10 +811,7 @@ Tcl_ListObjReplace( Tcl_Panic("%s called with shared object", "Tcl_ListObjReplace"); } if (listPtr->typePtr != &tclListType) { - int length; - - (void) TclGetStringFromObj(listPtr, &length); - if (!length) { + if (listPtr->bytes == tclEmptyStringRep) { if (objc) { Tcl_SetListObj(listPtr, objc, NULL); } else { @@ -818,7 +834,7 @@ Tcl_ListObjReplace( * Resist any temptation to optimize this case. */ - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); elemPtrs = &listRepPtr->elements; numElems = listRepPtr->elemCount; @@ -884,9 +900,9 @@ Tcl_ListObjReplace( newMax = listRepPtr->maxElemCount; } - listRepPtr = NewListIntRep(newMax, NULL); - if (!listRepPtr) { - Tcl_Panic("Not enough memory to allocate list"); + listRepPtr = AttemptNewList(interp, newMax, NULL); + if (listRepPtr == NULL) { + return TCL_ERROR; } listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; @@ -1339,8 +1355,10 @@ TclLsetFlat( if (index < 0 || index >= elemCount) { /* ...the index points outside the sublist. */ - Tcl_SetObjResult(interp, - Tcl_NewStringObj("list index out of range", -1)); + if (interp != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("list index out of range", -1)); + } break; } @@ -1488,12 +1506,13 @@ TclListObjSetElement( Tcl_Panic("%s called with shared object", "TclListObjSetElement"); } if (listPtr->typePtr != &tclListType) { - int length, result; + int result; - (void) TclGetStringFromObj(listPtr, &length); - if (!length) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("list index out of range", -1)); + if (listPtr->bytes == tclEmptyStringRep) { + if (interp != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("list index out of range", -1)); + } return TCL_ERROR; } result = SetListFromAny(interp, listPtr); @@ -1502,7 +1521,7 @@ TclListObjSetElement( } } - listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + listRepPtr = ListRepPtr(listPtr); elemCount = listRepPtr->elemCount; elemPtrs = &listRepPtr->elements; @@ -1527,9 +1546,9 @@ TclListObjSetElement( Tcl_Obj **oldElemPtrs = elemPtrs; int i; - listRepPtr = NewListIntRep(listRepPtr->maxElemCount, NULL); + listRepPtr = AttemptNewList(interp, listRepPtr->maxElemCount, NULL); if (listRepPtr == NULL) { - Tcl_Panic("Not enough memory to allocate list"); + return TCL_ERROR; } listRepPtr->canonicalFlag = oldListRepPtr->canonicalFlag; elemPtrs = &listRepPtr->elements; @@ -1587,22 +1606,21 @@ static void FreeListInternalRep( Tcl_Obj *listPtr) /* List object with internal rep to free. */ { - register List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; - register Tcl_Obj **elemPtrs = &listRepPtr->elements; - register Tcl_Obj *objPtr; - int numElems = listRepPtr->elemCount; - int i; + List *listRepPtr = ListRepPtr(listPtr); if (--listRepPtr->refCount <= 0) { + Tcl_Obj **elemPtrs = &listRepPtr->elements; + int i, numElems = listRepPtr->elemCount; + for (i = 0; i < numElems; i++) { - objPtr = elemPtrs[i]; - Tcl_DecrRefCount(objPtr); + Tcl_DecrRefCount(elemPtrs[i]); } ckfree((char *) listRepPtr); } listPtr->internalRep.twoPtrValue.ptr1 = NULL; listPtr->internalRep.twoPtrValue.ptr2 = NULL; + listPtr->typePtr = NULL; } /* @@ -1627,12 +1645,9 @@ DupListInternalRep( Tcl_Obj *srcPtr, /* Object with internal rep to copy. */ Tcl_Obj *copyPtr) /* Object with internal rep to set. */ { - List *listRepPtr = (List *) srcPtr->internalRep.twoPtrValue.ptr1; + List *listRepPtr = ListRepPtr(srcPtr); - listRepPtr->refCount++; - copyPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; - copyPtr->internalRep.twoPtrValue.ptr2 = NULL; - copyPtr->typePtr = &tclListType; + ListSetIntRep(copyPtr, listRepPtr); } /* @@ -1659,14 +1674,8 @@ SetListFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr) /* The object to convert. */ { - char *string, *s; - const char *elemStart, *nextElem; - int lenRemain, length, estCount, elemSize, hasBrace, i, j, result; - const char *limit; /* Points just after string's last byte. */ - register const char *p; - register Tcl_Obj **elemPtrs; - register Tcl_Obj *elemPtr; List *listRepPtr; + Tcl_Obj **elemPtrs; /* * Dictionaries are a special case; they have a string representation such @@ -1691,11 +1700,8 @@ SetListFromAny( */ Tcl_DictObjSize(NULL, objPtr, &size); - listRepPtr = NewListIntRep(size > 0 ? 2*size : 1, NULL); + listRepPtr = AttemptNewList(interp, size > 0 ? 2*size : 1, NULL); if (!listRepPtr) { - Tcl_SetResult(interp, - "insufficient memory to allocate list working space", - TCL_STATIC); return TCL_ERROR; } listRepPtr->elemCount = 2 * size; @@ -1706,113 +1712,71 @@ SetListFromAny( elemPtrs = &listRepPtr->elements; Tcl_DictObjFirst(NULL, objPtr, &search, &keyPtr, &valuePtr, &done); - i = 0; while (!done) { - elemPtrs[i++] = keyPtr; - elemPtrs[i++] = valuePtr; + *elemPtrs++ = keyPtr; + *elemPtrs++ = valuePtr; Tcl_IncrRefCount(keyPtr); Tcl_IncrRefCount(valuePtr); Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done); } + } else { + int estCount, length; + const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length); /* - * Swap the representations. + * Allocate enough space to hold a (Tcl_Obj *) for each + * (possible) list element. */ - goto commitRepresentation; - } - - /* - * Get the string representation. Make it up-to-date if necessary. - */ - - string = TclGetStringFromObj(objPtr, &length); - - /* - * Parse the string into separate string objects, and create a List - * structure that points to the element string objects. We use a modified - * version of Tcl_SplitList's implementation to avoid one malloc and a - * string copy for each list element. First, estimate the number of - * elements by counting the number of space characters in the list. - */ - - limit = string + length; - estCount = 1; - for (p = string; p < limit; p++) { - if (isspace(UCHAR(*p))) { /* INTL: ISO space. */ - estCount++; + estCount = TclMaxListLength(nextElem, length, &limit); + estCount += (estCount == 0); /* Smallest List struct holds 1 element. */ + listRepPtr = AttemptNewList(interp, estCount, NULL); + if (listRepPtr == NULL) { + return TCL_ERROR; } - } - - /* - * Allocate a new List structure with enough room for "estCount" elements. - * Each element is a pointer to a Tcl_Obj with the appropriate string rep. - * The initial "estCount" elements are set using the corresponding "argv" - * strings. - */ + elemPtrs = &listRepPtr->elements; - listRepPtr = NewListIntRep(estCount, NULL); - if (!listRepPtr) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "Not enough memory to allocate the list internal rep", -1)); - return TCL_ERROR; - } - elemPtrs = &listRepPtr->elements; + /* Each iteration, parse and store a list element */ + while (nextElem < limit) { + const char *elemStart; + int elemSize, literal; - for (p=string, lenRemain=length, i=0; - lenRemain > 0; - p=nextElem, lenRemain=limit-nextElem, i++) { - result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, - &elemSize, &hasBrace); - if (result != TCL_OK) { - for (j = 0; j < i; j++) { - elemPtr = elemPtrs[j]; - Tcl_DecrRefCount(elemPtr); + if (TCL_OK != TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal)) { + while (--elemPtrs >= &listRepPtr->elements) { + Tcl_DecrRefCount(*elemPtrs); + } + ckfree((char *) listRepPtr); + return TCL_ERROR; + } + if (elemStart == limit) { + break; } - ckfree((char *) listRepPtr); - return result; - } - if (elemStart >= limit) { - break; - } - if (i > estCount) { - Tcl_Panic("SetListFromAny: bad size estimate for list"); - } - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ + /* TODO: replace panic with error on alloc failure? */ + if (literal) { + TclNewStringObj(*elemPtrs, elemStart, elemSize); + } else { + TclNewObj(*elemPtrs); + (*elemPtrs)->bytes = ckalloc((unsigned) elemSize + 1); + (*elemPtrs)->length = TclCopyAndCollapse(elemSize, elemStart, + (*elemPtrs)->bytes); + } - s = ckalloc((unsigned) elemSize + 1); - if (hasBrace) { - memcpy(s, elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); + Tcl_IncrRefCount(*elemPtrs++);/* Since list now holds ref to it. */ } - TclNewObj(elemPtr); - elemPtr->bytes = s; - elemPtr->length = elemSize; - elemPtrs[i] = elemPtr; - Tcl_IncrRefCount(elemPtr); /* Since list now holds ref to it. */ + listRepPtr->elemCount = elemPtrs - &listRepPtr->elements; } - listRepPtr->elemCount = i; - /* * Free the old internalRep before setting the new one. We do this as late * as possible to allow the conversion code, in particular * Tcl_GetStringFromObj, to use that old internalRep. */ - commitRepresentation: - listRepPtr->refCount++; TclFreeIntRep(objPtr); - objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; - objPtr->internalRep.twoPtrValue.ptr2 = NULL; - objPtr->typePtr = &tclListType; + ListSetIntRep(objPtr, listRepPtr); return TCL_OK; } @@ -1843,12 +1807,11 @@ UpdateStringOfList( { # define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr = NULL; - List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; + List *listRepPtr = ListRepPtr(listPtr); int numElems = listRepPtr->elemCount; int i, length, bytesNeeded = 0; char *elem, *dst; Tcl_Obj **elemPtrs; - const int maxFlags = UINT_MAX / sizeof(int); /* * Mark the list as being canonical; although it will now have a string @@ -1872,9 +1835,8 @@ UpdateStringOfList( if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; - } else if (numElems > maxFlags) { - Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); } else { + /* We know numElems <= LIST_MAX, so this is safe. */ flagPtr = (int *) ckalloc((unsigned) numElems * sizeof(int)); } elemPtrs = &listRepPtr->elements; @@ -1883,11 +1845,11 @@ UpdateStringOfList( elem = TclGetStringFromObj(elemPtrs[i], &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i); if (bytesNeeded < 0) { - Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } } if (bytesNeeded > INT_MAX - numElems + 1) { - Tcl_Panic("UpdateStringOfList: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } bytesNeeded += numElems; diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 1747c99..5dbffc6 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -3007,7 +3007,7 @@ NamespaceCodeCmd( { Namespace *currNsPtr; Tcl_Obj *listPtr, *objPtr; - register char *arg, *p; + register char *arg; int length; if (objc != 3) { @@ -3017,21 +3017,17 @@ NamespaceCodeCmd( /* * If "arg" is already a scoped value, then return it directly. + * Take care to only check for scoping in precisely the style that + * [::namespace code] generates it. Anything more forgiving can have + * the effect of failing in namespaces that contain their own custom + " "namespace" command. [Bug 3202171]. */ arg = TclGetStringFromObj(objv[2], &length); - while (*arg == ':') { - arg++; - length--; - } - if (*arg=='n' && length>17 && strncmp(arg, "namespace", 9)==0) { - for (p=arg+9 ; isspace(UCHAR(*p)) ; p++) { - /* empty body: skip over whitespace */ - } - if (*p=='i' && (p+7 <= arg+length) && strncmp(p, "inscope", 7)==0) { - Tcl_SetObjResult(interp, objv[2]); - return TCL_OK; - } + if (*arg==':' && length > 20 + && strncmp(arg, "::namespace inscope ", 20) == 0) { + Tcl_SetObjResult(interp, objv[2]); + return TCL_OK; } /* @@ -4619,6 +4615,7 @@ FreeNsNameInternalRep( } ckfree((char *) resNamePtr); } + objPtr->typePtr = NULL; } /* @@ -4685,8 +4682,13 @@ SetNsNameFromAny( const char *dummy; Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; register ResolvedNsName *resNamePtr; - const char *name = TclGetString(objPtr); + const char *name; + + if (interp == NULL) { + return TCL_ERROR; + } + name = TclGetString(objPtr); TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); diff --git a/generic/tclObj.c b/generic/tclObj.c index d084692..5c17df2 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -4194,6 +4194,7 @@ FreeCmdNameInternalRep( ckfree((char *) resPtr); } } + objPtr->typePtr = NULL; } /* @@ -4264,6 +4265,10 @@ SetCmdNameFromAny( Namespace *currNsPtr; register ResolvedCmdName *resPtr; + if (interp == NULL) { + return TCL_ERROR; + } + /* * Find the Command structure, if any, that describes the command called * "name". Build a ResolvedCmdName that holds a cached pointer to this diff --git a/generic/tclParse.c b/generic/tclParse.c index 158ff42..96c2a10 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -433,7 +433,7 @@ Tcl_ParseCommand( } if (isLiteral) { - int elemCount = 0, code = TCL_OK, nakedbs = 0; + int elemCount = 0, code = TCL_OK, literal = 1; const char *nextElem, *listEnd, *elemStart; /* @@ -455,33 +455,24 @@ Tcl_ParseCommand( */ while (nextElem < listEnd) { - int size, brace; + int size; code = TclFindElement(NULL, nextElem, listEnd - nextElem, - &elemStart, &nextElem, &size, &brace); - if (code != TCL_OK) { + &elemStart, &nextElem, &size, &literal); + if ((code != TCL_OK) || !literal) { break; } - if (!brace) { - const char *s; - - for(s=elemStart;size>0;s++,size--) { - if ((*s)=='\\') { - nakedbs=1; - break; - } - } - } if (elemStart < listEnd) { elemCount++; } } - if ((code != TCL_OK) || nakedbs) { + if ((code != TCL_OK) || !literal) { /* - * Some list element could not be parsed, or contained - * naked backslashes. This means the literal string was - * not in fact a valid nor canonical list. Defer the + * Some list element could not be parsed, or is not + * present as a literal substring of the script. The + * compiler cannot handle list elements that get generated + * by a call to TclCopyAndCollapse(). Defer the * handling of this to compile/eval time, where code is * already in place to report the "attempt to expand a * non-list" error or expand lists that require @@ -505,6 +496,7 @@ Tcl_ParseCommand( * tokens representing the expanded list. */ + CONST char *listStart; int growthNeeded = wordIndex + 2*elemCount - parsePtr->numTokens; parsePtr->numWords += elemCount - 1; @@ -523,14 +515,12 @@ Tcl_ParseCommand( * word value. */ - nextElem = tokenPtr[1].start; - while (isspace(UCHAR(*nextElem))) { - nextElem++; - } + listStart = nextElem = tokenPtr[1].start; while (nextElem < listEnd) { + int quoted; + tokenPtr->type = TCL_TOKEN_SIMPLE_WORD; tokenPtr->numComponents = 1; - tokenPtr->start = nextElem; tokenPtr++; tokenPtr->type = TCL_TOKEN_TEXT; @@ -538,14 +528,13 @@ Tcl_ParseCommand( TclFindElement(NULL, nextElem, listEnd - nextElem, &(tokenPtr->start), &nextElem, &(tokenPtr->size), NULL); - if (tokenPtr->start + tokenPtr->size == listEnd) { - tokenPtr[-1].size = listEnd - tokenPtr[-1].start; - } else { - tokenPtr[-1].size = tokenPtr->start - + tokenPtr->size - tokenPtr[-1].start; - tokenPtr[-1].size += (isspace(UCHAR( - tokenPtr->start[tokenPtr->size])) == 0); - } + + quoted = (tokenPtr->start[-1] == '{' + || tokenPtr->start[-1] == '"') + && tokenPtr->start > listStart; + tokenPtr[-1].start = tokenPtr->start - quoted; + tokenPtr[-1].size = tokenPtr->start + tokenPtr->size + - tokenPtr[-1].start + quoted; tokenPtr++; } @@ -615,6 +604,30 @@ Tcl_ParseCommand( /* *---------------------------------------------------------------------- * + * TclIsSpaceProc -- + * + * Report whether byte is in the set of whitespace characters used by + * Tcl to separate words in scripts or elements in lists. + * + * Results: + * Returns 1, if byte is in the set, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclIsSpaceProc( + char byte) +{ + return CHAR_TYPE(byte) & (TYPE_SPACE) || byte == '\n'; +} + +/* + *---------------------------------------------------------------------- + * * ParseWhiteSpace -- * * Scans up to numBytes bytes starting at src, consuming white space @@ -1763,7 +1776,7 @@ Tcl_ParseBraces( openBrace = 0; break; case '#' : - if (openBrace && isspace(UCHAR(src[-1]))) { + if (openBrace && TclIsSpaceProc(src[-1])) { Tcl_AppendResult(parsePtr->interp, ": possible unbalanced brace in comment", NULL); goto error; diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index bb2c35d..da3b280 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -1154,7 +1154,6 @@ Tcl_FSConvertToPathType( UpdateStringOfFsPath(pathPtr); } FreeFsPathInternalRep(pathPtr); - pathPtr->typePtr = NULL; } return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType); @@ -1173,7 +1172,6 @@ Tcl_FSConvertToPathType( * UpdateStringOfFsPath(pathPtr); * } * FreeFsPathInternalRep(pathPtr); - * pathPtr->typePtr = NULL; * return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType); * } * } @@ -1963,7 +1961,6 @@ Tcl_FSGetNormalizedPath( UpdateStringOfFsPath(pathPtr); } FreeFsPathInternalRep(pathPtr); - pathPtr->typePtr = NULL; if (Tcl_ConvertToType(interp, pathPtr, &tclFsPathType) != TCL_OK) { return NULL; } @@ -2270,7 +2267,6 @@ TclFSEnsureEpochOk( UpdateStringOfFsPath(pathPtr); } FreeFsPathInternalRep(pathPtr); - pathPtr->typePtr = NULL; if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) { return TCL_ERROR; } @@ -2660,6 +2656,7 @@ FreeFsPathInternalRep( } ckfree((char *) fsPathPtr); + pathPtr->typePtr = NULL; } static void diff --git a/generic/tclProc.c b/generic/tclProc.c index 518ddb5..89bd0b9 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -320,8 +320,10 @@ Tcl_ProcObjCmd( } if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) { + int numBytes; + procArgs +=4; - while(*procArgs != '\0') { + while (*procArgs != '\0') { if (*procArgs != ' ') { goto done; } @@ -332,12 +334,9 @@ Tcl_ProcObjCmd( * The argument list is just "args"; check the body */ - procBody = TclGetString(objv[3]); - while (*procBody != '\0') { - if (!isspace(UCHAR(*procBody))) { - goto done; - } - procBody++; + procBody = Tcl_GetStringFromObj(objv[3], &numBytes); + if (TclParseAllWhiteSpace(procBody, numBytes) < numBytes) { + goto done; } /* @@ -1712,6 +1711,7 @@ TclObjInterpProcCore( } #endif /*TCL_COMPILE_DEBUG*/ +#ifdef USE_DTRACE if (TCL_DTRACE_PROC_ARGS_ENABLED()) { char *a[10]; int i = 0; @@ -1732,6 +1732,7 @@ TclObjInterpProcCore( TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1]); TclDecrRefCount(info); } +#endif /* USE_DTRACE */ /* * Invoke the commands in the procedure's body. @@ -1747,6 +1748,7 @@ TclObjInterpProcCore( procPtr->bodyPtr->internalRep.otherValuePtr; codePtr->refCount++; +#ifdef USE_DTRACE if (TCL_DTRACE_PROC_ENTRY_ENABLED()) { int l; @@ -1755,6 +1757,7 @@ TclObjInterpProcCore( iPtr->varFramePtr->objc - l, (Tcl_Obj **)(iPtr->varFramePtr->objv + l)); } +#endif /* USE_DTRACE */ result = TclExecuteByteCode(interp, codePtr); if (TCL_DTRACE_PROC_RETURN_ENABLED()) { TCL_DTRACE_PROC_RETURN(TclGetString(procNameObj), result); @@ -1825,6 +1828,7 @@ TclObjInterpProcCore( (void) 0; /* do nothing */ } +#ifdef USE_DTRACE if (TCL_DTRACE_PROC_RESULT_ENABLED()) { Tcl_Obj *r; @@ -1832,6 +1836,7 @@ TclObjInterpProcCore( TCL_DTRACE_PROC_RESULT(TclGetString(procNameObj), result, TclGetString(r), r); } +#endif /* USE_DTRACE */ procDone: /* @@ -2429,6 +2434,7 @@ FreeLambdaInternalRep( TclProcCleanupProc(procPtr); } TclDecrRefCount(nsObjPtr); + objPtr->typePtr = NULL; } static int @@ -2442,12 +2448,16 @@ SetLambdaFromAny( int objc, result; Proc *procPtr; + if (interp == NULL) { + return TCL_ERROR; + } + /* * Convert objPtr to list type first; if it cannot be converted, or if its * length is not 2, then it cannot be converted to lambdaType. */ - result = TclListObjGetElements(interp, objPtr, &objc, &objv); + result = TclListObjGetElements(NULL, objPtr, &objc, &objv); if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) { TclNewLiteralStringObj(errPtr, "can't interpret \""); Tcl_AppendObjToObj(errPtr, objPtr); diff --git a/generic/tclRegexp.c b/generic/tclRegexp.c index ed47dc9..d340f4c 100644 --- a/generic/tclRegexp.c +++ b/generic/tclRegexp.c @@ -756,6 +756,7 @@ FreeRegexpInternalRep( if (--(regexpRepPtr->refCount) <= 0) { FreeRegexp(regexpRepPtr); } + objPtr->typePtr = NULL; } /* diff --git a/generic/tclResult.c b/generic/tclResult.c index 556903c..7b58d44 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -959,12 +959,14 @@ ResetObjResult( TclNewObj(objResultPtr); Tcl_IncrRefCount(objResultPtr); iPtr->objResultPtr = objResultPtr; - } else if (objResultPtr->bytes != tclEmptyStringRep) { - if (objResultPtr->bytes != NULL) { - ckfree((char *) objResultPtr->bytes); + } else { + if (objResultPtr->bytes != tclEmptyStringRep) { + if (objResultPtr->bytes) { + ckfree((char *) objResultPtr->bytes); + } + objResultPtr->bytes = tclEmptyStringRep; + objResultPtr->length = 0; } - objResultPtr->bytes = tclEmptyStringRep; - objResultPtr->length = 0; TclFreeIntRep(objResultPtr); objResultPtr->typePtr = NULL; } diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c index d5c6e9c..e8b7538 100755 --- a/generic/tclStrToD.c +++ b/generic/tclStrToD.c @@ -536,7 +536,7 @@ TclParseNumber( * I, N, and whitespace. */ - if (isspace(UCHAR(c))) { + if (TclIsSpaceProc(c)) { if (flags & TCL_PARSE_NO_WHITESPACE) { goto endgame; } @@ -1050,7 +1050,7 @@ TclParseNumber( } /* FALLTHROUGH */ case sNANPAREN: - if (isspace(UCHAR(c))) { + if (TclIsSpaceProc(c)) { break; } if (numSigDigs < 13) { @@ -1101,7 +1101,7 @@ TclParseNumber( * Accept trailing whitespace. */ - while (len != 0 && isspace(UCHAR(*p))) { + while (len != 0 && TclIsSpaceProc(*p)) { p++; len--; } @@ -2668,7 +2668,7 @@ StrictQuickFormat(double d, /* Number to convert */ */ inline static char* -QuickConversion(double d, /* Number to format */ +QuickConversion(double e, /* 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: @@ -2686,11 +2686,13 @@ QuickConversion(double d, /* Number to format */ char* retval; /* Returned string */ char* end; /* Pointer to the terminal null byte in the * returned string */ + volatile double d; /* Workaround for a bug in mingw gcc 3.4.5 */ /* * Bring d into the range [1 .. 10) */ - ieps = AdjustRange(&d, k); + ieps = AdjustRange(&e, k); + d = e; /* * If the guessed value of k didn't get d into range, adjust it diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 7437ee4..13dda54 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -2758,6 +2758,7 @@ TclStringObjReverse( source[i++] = tmp; } Tcl_InvalidateStringRep(objPtr); + stringPtr->allocated = 0; return objPtr; } @@ -3055,6 +3056,7 @@ FreeStringInternalRep( Tcl_Obj *objPtr) /* Object with internal rep to free. */ { ckfree((char *) GET_STRING(objPtr)); + objPtr->typePtr = NULL; } /* diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 520847a..bc29ee6 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -31,6 +31,8 @@ #undef Tcl_ValidateAllMemory #undef Tcl_FindHashEntry #undef Tcl_CreateHashEntry +#define TclpLocaltime_unix TclpLocaltime +#define TclpGmtime_unix TclpGmtime /* * Keep a record of the original Notifier procedures, created in the diff --git a/generic/tclUtf.c b/generic/tclUtf.c index c545e66..00b652e 100644 --- a/generic/tclUtf.c +++ b/generic/tclUtf.c @@ -1526,7 +1526,7 @@ Tcl_UniCharIsSpace( */ if (ch < 0x80) { - return isspace(UCHAR(ch)); /* INTL: ISO space */ + return TclIsSpaceProc((char)ch); } else { category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK); return ((SPACE_BITS >> category) & 1); diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 8e295f4..b00489d 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -127,6 +127,309 @@ Tcl_ObjType tclEndOffsetType = { }; /* + * * STRING REPRESENTATION OF LISTS * * * + * + * The next several routines implement the conversions of strings to and + * from Tcl lists. To understand their operation, the rules of parsing + * and generating the string representation of lists must be known. Here + * we describe them in one place. + * + * A list is made up of zero or more elements. Any string is a list if + * it is made up of alternating substrings of element-separating ASCII + * whitespace and properly formatted elements. + * + * The ASCII characters which can make up the whitespace between list + * elements are: + * + * \u0009 \t TAB + * \u000A \n NEWLINE + * \u000B \v VERTICAL TAB + * \u000C \f FORM FEED + * \u000D \r CARRIAGE RETURN + * \u0020 SPACE + * + * NOTE: differences between this and other places where Tcl defines a role + * for "whitespace". + * + * * Unlike command parsing, here NEWLINE is just another whitespace + * character; its role as a command terminator in a script has no + * importance here. + * + * * Unlike command parsing, the BACKSLASH NEWLINE sequence is not + * considered to be a whitespace character. + * + * * Other Unicode whitespace characters (recognized by + * [string is space] or Tcl_UniCharIsSpace()) do not play any role + * as element separators in Tcl lists. + * + * * The NUL byte ought not appear, as it is not in strings properly + * encoded for Tcl, but if it is present, it is not treated as + * separating whitespace, or a string terminator. It is just + * another character in a list element. + * + * The interpretaton of a formatted substring as a list element follows + * rules similar to the parsing of the words of a command in a Tcl script. + * Backslash substitution plays a key role, and is defined exactly as it is + * in command parsing. The same routine, TclParseBackslash() is used in both + * command parsing and list parsing. + * + * NOTE: This means that if and when backslash substitution rules ever + * change for command parsing, the interpretation of strings as lists also + * changes. + * + * Backslash substitution replaces an "escape sequence" of one or more + * characters starting with + * \u005c \ BACKSLASH + * with a single character. The one character escape sequent case happens + * only when BACKSLASH is the last character in the string. In all other + * cases, the escape sequence is at least two characters long. + * + * The formatted substrings are interpreted as element values according to + * the following cases: + * + * * If the first character of a formatted substring is + * \u007b { OPEN BRACE + * then the end of the substring is the matching + * \u007d } CLOSE BRACE + * character, where matching is determined by counting nesting levels, + * and not including any brace characters that are contained within a + * backslash escape sequence in the nesting count. Having found the + * matching brace, all characters between the braces are the string + * value of the element. If no matching close brace is found before the + * end of the string, the string is not a Tcl list. If the character + * following the close brace is not an element separating whitespace + * character, or the end of the string, then the string is not a Tcl list. + * + * NOTE: this differs from a brace-quoted word in the parsing of a + * Tcl command only in its treatment of the backslash-newline sequence. + * In a list element, the literal characters in the backslash-newline + * sequence become part of the element value. In a script word, + * conversion to a single SPACE character is done. + * + * NOTE: Most list element values can be represented by a formatted + * substring using brace quoting. The exceptions are any element value + * that includes an unbalanced brace not in a backslash escape sequence, + * and any value that ends with a backslash not itself in a backslash + * escape sequence. + * + * * If the first character of a formatted substring is + * \u0022 " QUOTE + * then the end of the substring is the next QUOTE character, not counting + * any QUOTE characters that are contained within a backslash escape + * sequence. If no next QUOTE is found before the end of the string, the + * string is not a Tcl list. If the character following the closing QUOTE + * is not an element separating whitespace character, or the end of the + * string, then the string is not a Tcl list. Having found the limits + * of the substring, the element value is produced by performing backslash + * substitution on the character sequence between the open and close QUOTEs. + * + * NOTE: Any element value can be represented by this style of formatting, + * given suitable choice of backslash escape sequences. + * + * * All other formatted substrings are terminated by the next element + * separating whitespace character in the string. Having found the limits + * of the substring, the element value is produced by performing backslash + * substitution on it. + * + * NOTE: Any element value can be represented by this style of formatting, + * given suitable choice of backslash escape sequences, with one exception. + * The empty string cannot be represented as a list element without the use + * of either braces or quotes to delimit it. + * + * This collection of parsing rules is implemented in the routine + * TclFindElement(). + * + * In order to produce lists that can be parsed by these rules, we need + * the ability to distinguish between characters that are part of a list + * element value from characters providing syntax that define the structure + * of the list. This means that our code that generates lists must at a + * minimum be able to produce escape sequences for the 10 characters + * identified above that have significance to a list parser. + * + * * * CANONICAL LISTS * * * * * + * + * In addition to the basic rules for parsing strings into Tcl lists, there + * are additional properties to be met by the set of list values that are + * generated by Tcl. Such list values are often said to be in "canonical + * form": + * + * * When any canonical list is evaluated as a Tcl script, it is a script + * of either zero commands (an empty list) or exactly one command. The + * command word is exactly the first element of the list, and each argument + * word is exactly one of the following elements of the list. This means + * that any characters that have special meaning during script evaluation + * need special treatment when canonical lists are produced: + * + * * Whitespace between elements may not include NEWLINE. + * * The command terminating character, + * \u003b ; SEMICOLON + * must be BRACEd, QUOTEd, or escaped so that it does not terminate + * the command prematurely. + * * Any of the characters that begin substitutions in scripts, + * \u0024 $ DOLLAR + * \u005b [ OPEN BRACKET + * \u005c \ BACKSLASH + * need to be BRACEd or escaped. + * * In any list where the first character of the first element is + * \u0023 # HASH + * that HASH character must be BRACEd, QUOTEd, or escaped so that it + * does not convert the command into a comment. + * * Any list element that contains the character sequence + * BACKSLASH NEWLINE cannot be formatted with BRACEs. The + * BACKSLASH character must be represented by an escape + * sequence, and unless QUOTEs are used, the NEWLINE must + * be as well. + * + * * It is also guaranteed that one can use a canonical list as a building + * block of a larger script within command substitution, as in this example: + * set script "puts \[[list $cmd $arg]]"; eval $script + * To support this usage, any appearance of the character + * \u005d ] CLOSE BRACKET + * in a list element must be BRACEd, QUOTEd, or escaped. + * + * * Finally it is guaranteed that enclosing a canonical list in braces + * produces a new value that is also a canonical list. This new list has + * length 1, and its only element is the original canonical list. This + * same guarantee also makes it possible to construct scripts where an + * argument word is given a list value by enclosing the canonical form + * of that list in braces: + * set script "puts {[list $one $two $three]}"; eval $script + * This sort of coding was once fairly common, though it's become more + * idiomatic to see the following instead: + * set script [list puts [list $one $two $three]]; eval $script + * In order to support this guarantee, every canonical list must have + * balance when counting those braces that are not in escape sequences. + * + * Within these constraints, the canonical list generation routines + * TclScanElement() and TclConvertElement() attempt to generate the string + * for any list that is easiest to read. When an element value is itself + * acceptable as the formatted substring, it is usually used (CONVERT_NONE). + * When some quoting or escaping is required, use of BRACEs (CONVERT_BRACE) + * is usually preferred over the use of escape sequences (CONVERT_ESCAPE). + * There are some exceptions to both of these preferences for reasons of + * code simplicity, efficiency, and continuation of historical habits. + * Canonical lists never use the QUOTE formatting to delimit their elements + * because that form of quoting does not nest, which makes construction of + * nested lists far too much trouble. Canonical lists always use only a + * single SPACE character for element-separating whitespace. + * + * * * FUTURE CONSIDERATIONS * * * + * + * When a list element requires quoting or escaping due to a CLOSE BRACKET + * character or an internal QUOTE character, a strange formatting mode is + * recommended. For example, if the value "a{b]c}d" is converted by the + * usual modes: + * + * CONVERT_BRACE: a{b]c}d => {a{b]c}d} + * CONVERT_ESCAPE: a{b]c}d => a\{b\]c\}d + * + * we get perfectly usable formatted list elements. However, this is not + * what Tcl releases have been producing. Instead, we have: + * + * CONVERT_MASK: a{b]c}d => a{b\]c}d + * + * where the CLOSE BRACKET is escaped, but the BRACEs are not. The same + * effect can be seen replacing ] with " in this example. There does not + * appear to be any functional or aesthetic purpose for this strange + * additional mode. The sole purpose I can see for preserving it is to + * keep generating the same formatted lists programmers have become accustomed + * to, and perhaps written tests to expect. That is, compatibility only. + * The additional code complexity required to support this mode is significant. + * The lines of code supporting it are delimited in the routines below with + * #if COMPAT directives. This makes it easy to experiment with eliminating + * this formatting mode simply with "#define COMPAT 0" above. I believe + * this is worth considering. + * + * Another consideration is the treatment of QUOTE characters in list elements. + * TclConvertElement() must have the ability to produce the escape sequence + * \" so that when a list element begins with a QUOTE we do not confuse + * that first character with a QUOTE used as list syntax to define list + * structure. However, that is the only place where QUOTE characters need + * quoting. In this way, handling QUOTE could really be much more like + * the way we handle HASH which also needs quoting and escaping only in + * particular situations. Following up this could increase the set of + * list elements that can use the CONVERT_NONE formatting mode. + * + * More speculative is that the demands of canonical list form require brace + * balance for the list as a whole, while the current implementation achieves + * this by establishing brace balance for every element. + * + * Finally, a reminder that the rules for parsing and formatting lists are + * closely tied together with the rules for parsing and evaluating scripts, + * and will need to evolve in sync. + */ + +/* + *---------------------------------------------------------------------- + * + * TclMaxListLength -- + * + * Given 'bytes' pointing to 'numBytes' bytes, scan through them and + * count the number of whitespace runs that could be list element + * separators. If 'numBytes' is -1, scan to the terminating '\0'. + * Not a full list parser. Typically used to get a quick and dirty + * overestimate of length size in order to allocate space for an + * actual list parser to operate with. + * + * Results: + * Returns the largest number of list elements that could possibly + * be in this string, interpreted as a Tcl list. If 'endPtr' is not + * NULL, writes a pointer to the end of the string scanned there. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclMaxListLength( + CONST char *bytes, + int numBytes, + CONST char **endPtr) +{ + int count = 0; + + if ((numBytes == 0) || ((numBytes == -1) && (*bytes == '\0'))) { + /* Empty string case - quick exit */ + goto done; + } + + /* No list element before leading white space */ + count += 1 - TclIsSpaceProc(*bytes); + + /* Count white space runs as potential element separators */ + while (numBytes) { + if ((numBytes == -1) && (*bytes == '\0')) { + break; + } + if (TclIsSpaceProc(*bytes)) { + /* Space run started; bump count */ + count++; + do { + bytes++; + numBytes -= (numBytes != -1); + } while (numBytes && TclIsSpaceProc(*bytes)); + if (numBytes == 0) { + break; + } + /* (*bytes) is non-space; return to counting state */ + } + bytes++; + numBytes -= (numBytes != -1); + } + + /* No list element following trailing white space */ + count -= TclIsSpaceProc(bytes[-1]); + + done: + if (endPtr) { + *endPtr = bytes; + } + return count; +} + +/* *---------------------------------------------------------------------- * * TclFindElement -- @@ -146,13 +449,18 @@ Tcl_ObjType tclEndOffsetType = { * that's part of the element. If this is the last argument in the list, * then *nextPtr will point just after the last character in the list * (i.e., at the character at list+listLength). If sizePtr is non-NULL, - * *sizePtr is filled in with the number of characters in the element. If + * *sizePtr is filled in with the number of bytes in the element. If * the element is in braces, then *elementPtr will point to the character * after the opening brace and *sizePtr will not include either of the * braces. If there isn't an element in the list, *sizePtr will be zero, - * and both *elementPtr and *termPtr will point just after the last - * character in the list. Note: this function does NOT collapse backslash - * sequences. + * and both *elementPtr and *nextPtr will point just after the last + * character in the list. If literalPtr is non-NULL, *literalPtr is set + * to a boolean value indicating whether the substring returned as + * the values of **elementPtr and *sizePtr is the literal value of + * a list element. If not, a call to TclCopyAndCollapse() is needed + * to produce the actual value of the list element. Note: this function + * does NOT collapse backslash sequences, but uses *literalPtr to tell + * callers when it is required for them to do so. * * Side effects: * None. @@ -176,8 +484,12 @@ TclFindElement( * argument (next arg or end of list). */ int *sizePtr, /* If non-zero, fill in with size of * element. */ - int *bracePtr) /* If non-zero, fill in with non-zero/zero to - * indicate that arg was/wasn't in braces. */ + int *literalPtr) /* If non-zero, fill in with non-zero/zero to + * indicate that the substring of *sizePtr + * bytes starting at **elementPtr is/is not + * the literal list element and therefore + * does not/does require a call to + * TclCopyAndCollapse() by the caller. */ { CONST char *p = list; CONST char *elemStart; /* Points to first byte of first element. */ @@ -186,6 +498,7 @@ TclFindElement( int inQuotes = 0; int size = 0; /* lint. */ int numChars; + int literal = 1; CONST char *p2; /* @@ -195,7 +508,7 @@ TclFindElement( */ limit = (list + listLength); - while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ + while ((p < limit) && (TclIsSpaceProc(*p))) { p++; } if (p == limit) { /* no element found */ @@ -211,9 +524,6 @@ TclFindElement( p++; } elemStart = p; - if (bracePtr != 0) { - *bracePtr = openBraces; - } /* * Find element's end (a space, close brace, or the end of the string). @@ -243,8 +553,7 @@ TclFindElement( } else if (openBraces == 1) { size = (p - elemStart); p++; - if ((p >= limit) - || isspace(UCHAR(*p))) { /* INTL: ISO space. */ + if ((p >= limit) || TclIsSpaceProc(*p)) { goto done; } @@ -254,8 +563,7 @@ TclFindElement( if (interp != NULL) { p2 = p; - while ((p2 < limit) - && (!isspace(UCHAR(*p2))) /* INTL: ISO space. */ + while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } @@ -273,6 +581,15 @@ TclFindElement( */ case '\\': + if (openBraces == 0) { + /* + * A backslash sequence not within a brace quoted element + * means the value of the element is different from the + * substring we are parsing. A call to TclCopyAndCollapse() + * is needed to produce the element value. Inform the caller. + */ + literal = 0; + } TclParseBackslash(p, limit - p, &numChars, NULL); p += (numChars - 1); break; @@ -302,8 +619,7 @@ TclFindElement( if (inQuotes) { size = (p - elemStart); p++; - if ((p >= limit) - || isspace(UCHAR(*p))) { /* INTL: ISO space */ + if ((p >= limit) || TclIsSpaceProc(*p)) { goto done; } @@ -313,8 +629,7 @@ TclFindElement( if (interp != NULL) { p2 = p; - while ((p2 < limit) - && (!isspace(UCHAR(*p2))) /* INTL: ISO space */ + while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } @@ -351,7 +666,7 @@ TclFindElement( } done: - while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ + while ((p < limit) && (TclIsSpaceProc(*p))) { p++; } *elementPtr = elemStart; @@ -359,6 +674,9 @@ TclFindElement( if (sizePtr != 0) { *sizePtr = size; } + if (literalPtr != 0) { + *literalPtr = literal; + } return TCL_OK; } @@ -449,48 +767,31 @@ Tcl_SplitList( CONST char ***argvPtr) /* Pointer to place to store pointer to array * of pointers to list elements. */ { - CONST char **argv, *l, *element; + CONST char **argv, *end, *element; char *p; - int length, size, i, result, elSize, brace; + int length, size, i, result, elSize; /* - * Figure out how much space to allocate. There must be enough space for - * both the array of pointers and also for a copy of the list. To estimate - * the number of pointers needed, count the number of space characters in - * the list. + * Allocate enough space to work in. A (CONST char *) for each + * (possible) list element plus one more for terminating NULL, + * plus as many bytes as in the original string value, plus one + * more for a terminating '\0'. Space used to hold element separating + * white space in the original string gets re-purposed to hold '\0' + * characters in the argv array. */ - for (size = 2, l = list; *l != 0; l++) { - if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ - size++; - - /* - * Consecutive space can only count as a single list delimiter. - */ - - while (1) { - char next = *(l + 1); - - if (next == '\0') { - break; - } - ++l; - if (isspace(UCHAR(next))) { /* INTL: ISO space. */ - continue; - } - break; - } - } - } - length = l - list; + size = TclMaxListLength(list, -1, &end) + 1; + length = end - list; argv = (CONST char **) ckalloc((unsigned) ((size * sizeof(char *)) + length + 1)); + for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { CONST char *prevList = list; + int literal; result = TclFindElement(interp, list, length, &element, &list, - &elSize, &brace); + &elSize, &literal); length -= (list - prevList); if (result != TCL_OK) { ckfree((char *) argv); @@ -508,130 +809,18 @@ Tcl_SplitList( return TCL_ERROR; } argv[i] = p; - if (brace) { + if (literal) { memcpy(p, element, (size_t) elSize); p += elSize; *p = 0; p++; } else { - TclCopyAndCollapse(elSize, element, p); - p += elSize+1; - } - } - - argv[i] = NULL; - *argvPtr = argv; - *argcPtr = i; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TclMarkList -- - * - * Marks the locations within a string where list elements start and - * computes where they end. - * - * Results - * The return value is normally TCL_OK, which means that the list was - * successfully split up. If TCL_ERROR is returned, it means that "list" - * didn't have proper list structure; the interp's result will contain a - * more detailed error message. - * - * *argvPtr will be filled in with the address of an array whose elements - * point to the places where the elements of list start, in order. - * *argcPtr will get filled in with the number of valid elements in the - * array. *argszPtr will get filled in with the address of an array whose - * elements are the lengths of the elements of the list, in order. - * Note: *argvPtr, *argcPtr and *argszPtr are only modified if the - * function returns normally. - * - * Side effects: - * Memory is allocated. - * - *---------------------------------------------------------------------- - */ - -int -TclMarkList( - Tcl_Interp *interp, /* Interpreter to use for error reporting. If - * NULL, no error message is left. */ - CONST char *list, /* Pointer to string with list structure. */ - CONST char *end, /* Pointer to first char after the list. */ - int *argcPtr, /* Pointer to location to fill in with the - * number of elements in the list. */ - CONST int **argszPtr, /* Pointer to place to store length of list - * elements. */ - CONST char ***argvPtr) /* Pointer to place to store pointer to array - * of pointers to list elements. */ -{ - CONST char **argv, *l, *element; - int *argn, length, size, i, result, elSize, brace; - - /* - * Figure out how much space to allocate. There must be enough space for - * the array of pointers and lengths. To estimate the number of pointers - * needed, count the number of whitespace characters in the list. - */ - - for (size=2, l=list ; l!=end ; l++) { - if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ - size++; - - /* - * Consecutive space can only count as a single list delimiter. - */ - - while (1) { - char next = *(l + 1); - - if ((l+1) == end) { - break; - } - ++l; - if (isspace(UCHAR(next))) { /* INTL: ISO space. */ - continue; - } - break; - } - } - } - length = l - list; - argv = (CONST char **) ckalloc((unsigned) size * sizeof(char *)); - argn = (int *) ckalloc((unsigned) size * sizeof(int *)); - - for (i = 0; list != end; i++) { - CONST char *prevList = list; - - result = TclFindElement(interp, list, length, &element, &list, - &elSize, &brace); - length -= (list - prevList); - if (result != TCL_OK) { - ckfree((char *) argv); - ckfree((char *) argn); - return result; + p += 1 + TclCopyAndCollapse(elSize, element, p); } - if (*element == 0) { - break; - } - if (i >= size) { - ckfree((char *) argv); - ckfree((char *) argn); - if (interp != NULL) { - Tcl_SetResult(interp, "internal error in TclMarkList", - TCL_STATIC); - } - return TCL_ERROR; - } - argv[i] = element; - argn[i] = elSize; } argv[i] = NULL; - argn[i] = 0; *argvPtr = argv; - *argszPtr = argn; *argcPtr = i; return TCL_OK; } @@ -646,9 +835,9 @@ TclMarkList( * enclosing braces) to make the string into a valid Tcl list element. * * Results: - * The return value is an overestimate of the number of characters that + * The return value is an overestimate of the number of bytes that * will be needed by Tcl_ConvertElement to produce a valid list element - * from string. The word at *flagPtr is filled in with a value needed by + * from src. The word at *flagPtr is filled in with a value needed by * Tcl_ConvertElement when doing the actual conversion. * * Side effects: @@ -659,11 +848,11 @@ TclMarkList( int Tcl_ScanElement( - register CONST char *string,/* String to convert to list element. */ + register CONST char *src, /* String to convert to list element. */ register int *flagPtr) /* Where to store information to guide * Tcl_ConvertCountedElement. */ { - return Tcl_ScanCountedElement(string, -1, flagPtr); + return Tcl_ScanCountedElement(src, -1, flagPtr); } /* @@ -674,13 +863,13 @@ Tcl_ScanElement( * This function is a companion function to Tcl_ConvertCountedElement. It * scans a string to see what needs to be done to it (e.g. add * backslashes or enclosing braces) to make the string into a valid Tcl - * list element. If length is -1, then the string is scanned up to the - * first null byte. + * list element. If length is -1, then the string is scanned from src up + * to the first null byte. * * Results: - * The return value is an overestimate of the number of characters that + * The return value is an overestimate of the number of bytes that * will be needed by Tcl_ConvertCountedElement to produce a valid list - * element from string. The word at *flagPtr is filled in with a value + * element from src. The word at *flagPtr is filled in with a value * needed by Tcl_ConvertCountedElement when doing the actual conversion. * * Side effects: @@ -691,43 +880,83 @@ Tcl_ScanElement( int Tcl_ScanCountedElement( - CONST char *string, /* String to convert to Tcl list element. */ - int length, /* Number of bytes in string, or -1. */ + CONST char *src, /* String to convert to Tcl list element. */ + int length, /* Number of bytes in src, or -1. */ int *flagPtr) /* Where to store information to guide * Tcl_ConvertElement. */ { int flags = CONVERT_ANY; - int numBytes = TclScanElement(string, length, &flags); + int numBytes = TclScanElement(src, length, &flags); *flagPtr = flags; return numBytes; } + +/* + *---------------------------------------------------------------------- + * + * TclScanElement -- + * + * This function is a companion function to TclConvertElement. It + * scans a string to see what needs to be done to it (e.g. add + * backslashes or enclosing braces) to make the string into a valid Tcl + * list element. If length is -1, then the string is scanned from src up + * to the first null byte. A NULL value for src is treated as an + * empty string. The incoming value of *flagPtr is a report from the + * caller what additional flags it will pass to TclConvertElement(). + * + * Results: + * The recommended formatting mode for the element is determined and + * a value is written to *flagPtr indicating that recommendation. This + * recommendation is combined with the incoming flag values in *flagPtr + * set by the caller to determine how many bytes will be needed by + * TclConvertElement() in which to write the formatted element following + * the recommendation modified by the flag values. This number of bytes + * is the return value of the routine. In some situations it may be + * an overestimate, but so long as the caller passes the same flags + * to TclConvertElement(), it will be large enough. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ int TclScanElement( - CONST char *string, /* String to convert to Tcl list element. */ - int length, /* Number of bytes in string, or -1. */ + CONST char *src, /* String to convert to Tcl list element. */ + int length, /* Number of bytes in src, or -1. */ int *flagPtr) /* Where to store information to guide * Tcl_ConvertElement. */ { - CONST char *p = string; - int nestingLevel = 0; - int forbidNone = 0; - int requireEscape = 0; - int extra = 0; - int bytesNeeded; + CONST char *p = src; + int nestingLevel = 0; /* Brace nesting count */ + int forbidNone = 0; /* Do not permit CONVERT_NONE mode. Something + needs protection or escape. */ + int requireEscape = 0; /* Force use of CONVERT_ESCAPE mode. For some + * reason bare or brace-quoted form fails. */ + int extra = 0; /* Count of number of extra bytes needed for + * formatted element, assuming we use escape + * sequences in formatting. */ + int bytesNeeded; /* Buffer length computed to complete the + * element formatting in the selected mode. */ #if COMPAT - int preferEscape = 0; - int preferBrace = 0; - int braceCount = 0; + int preferEscape = 0; /* Use preferences to track whether to use */ + int preferBrace = 0; /* CONVERT_MASK mode. */ + int braceCount = 0; /* Count of all braces '{' '}' seen. */ #endif - if ((p == NULL) || (length == 0)) { + if ((p == NULL) || (length == 0) || ((*p == '\0') && (length == -1))) { + /* Empty string element must be brace quoted. */ *flagPtr = CONVERT_BRACE; return 2; } - if ((*p == '{') || (*p == '"') || ((*p == '\0') && (length == -1))) { + if ((*p == '{') || (*p == '"')) { + /* + * Must escape or protect so leading character of value is not + * misinterpreted as list element delimiting syntax. + */ forbidNone = 1; #if COMPAT preferBrace = 1; @@ -740,16 +969,17 @@ TclScanElement( #if COMPAT braceCount++; #endif - extra++; + extra++; /* Escape '{' => '\{' */ nestingLevel++; break; case '}': #if COMPAT braceCount++; #endif - extra++; + extra++; /* Escape '}' => '\}' */ nestingLevel--; if (nestingLevel < 0) { + /* Unbalanced braces! Cannot format with brace quoting. */ requireEscape = 1; } break; @@ -757,7 +987,7 @@ TclScanElement( case '"': #if COMPAT forbidNone = 1; - extra++; + extra++; /* Escapes all just prepend a backslash */ preferEscape = 1; break; #else @@ -773,26 +1003,28 @@ TclScanElement( case '\t': case '\v': forbidNone = 1; - extra++; + extra++; /* Escape sequences all one byte longer. */ #if COMPAT preferBrace = 1; #endif break; case '\\': - extra++; + extra++; /* Escape '\' => '\\' */ if ((length == 1) || ((length == -1) && (p[1] == '\0'))) { - requireEscape = 1; + /* Final backslash. Cannot format with brace quoting. */ + requireEscape = 1; break; } if (p[1] == '\n') { - extra++; + extra++; /* Escape newline => '\n', one byte longer */ + /* Backslash newline sequence. Brace quoting not permitted. */ requireEscape = 1; length -= (length > 0); p++; break; } if ((p[1] == '{') || (p[1] == '}') || (p[1] == '\\')) { - extra++; + extra++; /* Escape sequences all one byte longer. */ length -= (length > 0); p++; } @@ -814,20 +1046,35 @@ TclScanElement( endOfString: if (nestingLevel != 0) { + /* Unbalanced braces! Cannot format with brace quoting. */ requireEscape = 1; } - bytesNeeded = p - string; + /* We need at least as many bytes as are in the element value... */ + bytesNeeded = p - src; if (requireEscape) { + /* + * We must use escape sequences. Add all the extra bytes needed + * to have room to create them. + */ bytesNeeded += extra; - if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + /* Make room to escape leading #, if needed. */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } *flagPtr = CONVERT_ESCAPE; goto overflowCheck; } if (*flagPtr & CONVERT_ANY) { + /* + * The caller has not let us know what flags it will pass to + * TclConvertElement() so compute the max size we might need for + * any possible choice. Normally the formatting using escape + * sequences is the longer one, and a minimum "extra" value of 2 + * makes sure we don't request too small a buffer in those edge + * cases where that's not true. + */ if (extra < 2) { extra = 2; } @@ -835,12 +1082,26 @@ TclScanElement( *flagPtr |= TCL_DONT_USE_BRACES; } if (forbidNone) { + /* We must request some form of quoting of escaping... */ #if COMPAT if (preferEscape && !preferBrace) { + /* + * If we are quoting solely due to ] or internal " characters + * use the CONVERT_MASK mode where we escape all special + * characters except for braces. "extra" counted space needed + * to escape braces too, so substract "braceCount" to get our + * actual needs. + */ bytesNeeded += (extra - braceCount); - if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + /* Make room to escape leading #, if needed. */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } + /* + * If the caller reports it will direct TclConvertElement() to + * use full escapes on the element, add back the bytes needed to + * escape the braces. + */ if (*flagPtr & TCL_DONT_USE_BRACES) { bytesNeeded += braceCount; } @@ -849,18 +1110,26 @@ TclScanElement( } #endif if (*flagPtr & TCL_DONT_USE_BRACES) { + /* + * If the caller reports it will direct TclConvertElement() to + * use escapes, add the extra bytes needed to have room for them. + */ bytesNeeded += extra; - if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + /* Make room to escape leading #, if needed. */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } } else { + /* Add 2 bytes for room for the enclosing braces. */ bytesNeeded += 2; } *flagPtr = CONVERT_BRACE; goto overflowCheck; } - if ((*string == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + /* So far, no need to quote or escape anything. */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { + /* If we need to quote a leading #, make room to enclose in braces. */ bytesNeeded += 2; } *flagPtr = CONVERT_NONE; @@ -934,6 +1203,27 @@ Tcl_ConvertCountedElement( dst[numBytes] = '\0'; return numBytes; } + +/* + *---------------------------------------------------------------------- + * + * TclConvertElement -- + * + * This is a companion function to TclScanElement. Given the + * information produced by TclScanElement, this function converts + * a string to a list element equal to that string. + * + * Results: + * Information is copied to *dst in the form of a list element identical + * to src (i.e. if Tcl_SplitList is applied to dst it will produce a + * string identical to src). The return value is a count of the number of + * characters copied (not including the terminating NULL character). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ int TclConvertElement( register CONST char *src, /* Source information for list element. */ @@ -944,14 +1234,19 @@ int TclConvertElement( int conversion = flags & CONVERT_MASK; char *p = dst; + /* Let the caller demand we use escape sequences rather than braces. */ if ((flags & TCL_DONT_USE_BRACES) && (conversion & CONVERT_BRACE)) { conversion = CONVERT_ESCAPE; } - if ((src == NULL) || (length == 0)) { + + /* No matter what the caller demands, empty string must be braced! */ + if ((src == NULL) || (length == 0) || ((*src == '\0') && (length == -1))) { src = tclEmptyStringRep; length = 0; conversion = CONVERT_BRACE; } + + /* Escape leading hash as needed and requested. */ if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { if (conversion == CONVERT_ESCAPE) { p[0] = '\\'; @@ -963,6 +1258,8 @@ int TclConvertElement( conversion = CONVERT_BRACE; } } + + /* No escape or quoting needed. Copy the literal string value. */ if (conversion == CONVERT_NONE) { if (length == -1) { /* TODO: INT_MAX overflow? */ @@ -975,6 +1272,8 @@ int TclConvertElement( return length; } } + + /* Formatted string is original string enclosed in braces. */ if (conversion == CONVERT_BRACE) { *p = '{'; p++; @@ -991,8 +1290,10 @@ int TclConvertElement( p++; return p - dst; } + /* conversion == CONVERT_ESCAPE or CONVERT_MASK */ + /* Formatted string is original string converted to escape sequences. */ for ( ; length; src++, length -= (length > 0)) { switch (*src) { case ']': @@ -1125,7 +1426,7 @@ Tcl_Merge( * the size limits on the formatted string anyway, so just issue * that same panic early. */ - Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } else { flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int)); } @@ -1133,11 +1434,11 @@ Tcl_Merge( flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); bytesNeeded += TclScanElement(argv[i], -1, &flagPtr[i]); if (bytesNeeded < 0) { - Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } } if (bytesNeeded > INT_MAX - argc + 1) { - Tcl_Panic("Tcl_Merge: size requirement exceeds limits"); + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } bytesNeeded += argc; @@ -1198,6 +1499,141 @@ Tcl_Backslash( /* *---------------------------------------------------------------------- * + * TclTrimRight -- + * Takes two counted strings in the Tcl encoding which must both be + * null terminated. Conceptually trims from the right side of the + * first string all characters found in the second string. + * + * Results: + * The number of bytes to be removed from the end of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclTrimRight( + const char *bytes, /* String to be trimmed... */ + int numBytes, /* ...and its length in bytes */ + const char *trim, /* String of trim characters... */ + int numTrim) /* ...and its length in bytes */ +{ + const char *p = bytes + numBytes; + int pInc; + + if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) { + Tcl_Panic("TclTrimRight works only on null-terminated strings"); + } + + /* Empty strings -> nothing to do */ + if ((numBytes == 0) || (numTrim == 0)) { + return 0; + } + + /* Outer loop: iterate over string to be trimmed */ + do { + Tcl_UniChar ch1; + const char *q = trim; + int bytesLeft = numTrim; + + p = Tcl_UtfPrev(p, bytes); + pInc = TclUtfToUniChar(p, &ch1); + + /* Inner loop: scan trim string for match to current character */ + do { + Tcl_UniChar ch2; + int qInc = TclUtfToUniChar(q, &ch2); + + if (ch1 == ch2) { + break; + } + + q += qInc; + bytesLeft -= qInc; + } while (bytesLeft); + + if (bytesLeft == 0) { + /* No match; trim task done; *p is last non-trimmed char */ + p += pInc; + break; + } + } while (p > bytes); + + return numBytes - (p - bytes); +} + +/* + *---------------------------------------------------------------------- + * + * TclTrimLeft -- + * Takes two counted strings in the Tcl encoding which must both be + * null terminated. Conceptually trims from the left side of the + * first string all characters found in the second string. + * + * Results: + * The number of bytes to be removed from the start of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclTrimLeft( + const char *bytes, /* String to be trimmed... */ + int numBytes, /* ...and its length in bytes */ + const char *trim, /* String of trim characters... */ + int numTrim) /* ...and its length in bytes */ +{ + const char *p = bytes; + + if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) { + Tcl_Panic("TclTrimLeft works only on null-terminated strings"); + } + + /* Empty strings -> nothing to do */ + if ((numBytes == 0) || (numTrim == 0)) { + return 0; + } + + /* Outer loop: iterate over string to be trimmed */ + do { + Tcl_UniChar ch1; + int pInc = TclUtfToUniChar(p, &ch1); + const char *q = trim; + int bytesLeft = numTrim; + + /* Inner loop: scan trim string for match to current character */ + do { + Tcl_UniChar ch2; + int qInc = TclUtfToUniChar(q, &ch2); + + if (ch1 == ch2) { + break; + } + + q += qInc; + bytesLeft -= qInc; + } while (bytesLeft); + + if (bytesLeft == 0) { + /* No match; trim task done; *p is first non-trimmed char */ + break; + } + + p += pInc; + numBytes -= pInc; + } while (numBytes); + + return p - bytes; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_Concat -- * * Concatenate a set of strings into a single large string. @@ -1214,56 +1650,77 @@ Tcl_Backslash( *---------------------------------------------------------------------- */ +/* The whitespace characters trimmed during [concat] operations */ +#define CONCAT_WS " \f\v\r\t\n" +#define CONCAT_WS_SIZE (int) (sizeof(CONCAT_WS "") - 1) + char * Tcl_Concat( int argc, /* Number of strings to concatenate. */ CONST char * CONST *argv) /* Array of strings to concatenate. */ { - int totalSize, i; - char *p; - char *result; + int i, needSpace = 0, bytesNeeded = 0; + char *result, *p; - for (totalSize = 1, i = 0; i < argc; i++) { - totalSize += strlen(argv[i]) + 1; - } - result = (char *) ckalloc((unsigned) totalSize); + /* Dispose of the empty result corner case first to simplify later code */ if (argc == 0) { - *result = '\0'; + result = (char *) ckalloc(1); + result[0] = '\0'; return result; } - for (p = result, i = 0; i < argc; i++) { - CONST char *element; - int length; + /* First allocate the result buffer at the size required */ + for (i = 0; i < argc; i++) { + bytesNeeded += strlen(argv[i]); + if (bytesNeeded < 0) { + Tcl_Panic("Tcl_Concat: max size of Tcl value exceeded"); + } + } + if (bytesNeeded + argc - 1 < 0) { /* - * Clip white space off the front and back of the string to generate a - * neater result, and ignore any empty elements. + * Panic test could be tighter, but not going to bother for + * this legacy routine. */ + Tcl_Panic("Tcl_Concat: max size of Tcl value exceeded"); + } + /* All element bytes + (argc - 1) spaces + 1 terminating NULL */ + result = (char *) ckalloc((unsigned) (bytesNeeded + argc)); + for (p = result, i = 0; i < argc; i++) { + int trim, elemLength; + const char *element; + element = argv[i]; - while (isspace(UCHAR(*element))) { /* INTL: ISO space. */ - element++; - } - for (length = strlen(element); - (length > 0) - && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */ - && ((length < 2) || (element[length-2] != '\\')); - length--) { - /* Null loop body. */ - } - if (length == 0) { + elemLength = strlen(argv[i]); + + /* Trim away the leading whitespace */ + trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); + element += trim; + elemLength -= trim; + + /* + * Trim away the trailing whitespace. Do not permit trimming + * to expose a final backslash character. + */ + + trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); + trim -= trim && (element[elemLength - trim - 1] == '\\'); + elemLength -= trim; + + /* If we're left with empty element after trimming, do nothing */ + if (elemLength == 0) { continue; } - memcpy(p, element, (size_t) length); - p += length; - *p = ' '; - p++; - } - if (p != result) { - p[-1] = 0; - } else { - *p = 0; + + /* Append to the result with space if needed */ + if (needSpace) { + *p++ = ' '; + } + memcpy(p, element, (size_t) elemLength); + p += elemLength; + needSpace = 1; } + *p = '\0'; return result; } @@ -1290,35 +1747,25 @@ Tcl_ConcatObj( int objc, /* Number of objects to concatenate. */ Tcl_Obj *CONST objv[]) /* Array of objects to concatenate. */ { - int allocSize, finalSize, length, elemLength, i; - char *p; - char *element; - char *concatStr; + int i, elemLength, needSpace = 0, bytesNeeded = 0; + const char *element; Tcl_Obj *objPtr, *resPtr; /* * Check first to see if all the items are of list type or empty. If so, * we will concat them together as lists, and return a list object. This - * is only valid when the lists have no current string representation, - * since we don't know what the original type was. An original string rep - * may have lost some whitespace info when converted which could be - * important. + * is only valid when the lists are in canonical form. */ for (i = 0; i < objc; i++) { - List *listRepPtr; + int length; objPtr = objv[i]; - if (objPtr->typePtr != &tclListType) { - TclGetString(objPtr); - if (objPtr->length) { - break; - } else { - continue; - } + if (TclListObjIsCanonical(objPtr)) { + continue; } - listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1; - if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) { + Tcl_GetStringFromObj(objPtr, &length); + if (length > 0) { break; } } @@ -1338,7 +1785,7 @@ Tcl_ConcatObj( */ objPtr = objv[i]; - if (objPtr->bytes && !objPtr->length) { + if (objPtr->bytes && objPtr->length == 0) { continue; } TclListObjGetElements(NULL, objPtr, &listc, &listv); @@ -1361,79 +1808,55 @@ Tcl_ConcatObj( * the slow way, using the string representations. */ - allocSize = 0; + /* First try to pre-allocate the size required */ for (i = 0; i < objc; i++) { - objPtr = objv[i]; - element = TclGetStringFromObj(objPtr, &length); - if ((element != NULL) && (length > 0)) { - allocSize += (length + 1); + element = TclGetStringFromObj(objv[i], &elemLength); + bytesNeeded += elemLength; + if (bytesNeeded < 0) { + break; } } - if (allocSize == 0) { - allocSize = 1; /* enough for the NULL byte at end */ - } - /* - * Allocate storage for the concatenated result. Note that allocSize is - * one more than the total number of characters, and so includes room for - * the terminating NULL byte. + * Does not matter if this fails, will simply try later to build up + * the string with each Append reallocating as needed with the usual + * string append algorithm. When that fails it will report the error. */ + TclNewObj(resPtr); + Tcl_AttemptSetObjLength(resPtr, bytesNeeded + objc - 1); + Tcl_SetObjLength(resPtr, 0); - concatStr = ckalloc((unsigned) allocSize); + for (i = 0; i < objc; i++) { + int trim; + + element = TclGetStringFromObj(objv[i], &elemLength); - /* - * Now concatenate the elements. Clip white space off the front and back - * to generate a neater result, and ignore any empty elements. Also put a - * null byte at the end. - */ + /* Trim away the leading whitespace */ + trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); + element += trim; + elemLength -= trim; - finalSize = 0; - if (objc == 0) { - *concatStr = '\0'; - } else { - p = concatStr; - for (i = 0; i < objc; i++) { - objPtr = objv[i]; - element = TclGetStringFromObj(objPtr, &elemLength); - while ((elemLength > 0) && (UCHAR(*element) < 127) - && isspace(UCHAR(*element))) { /* INTL: ISO C space. */ - element++; - elemLength--; - } + /* + * Trim away the trailing whitespace. Do not permit trimming + * to expose a final backslash character. + */ - /* - * Trim trailing white space. But, be careful not to trim a space - * character if it is preceded by a backslash: in this case it - * could be significant. - */ + trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); + trim -= trim && (element[elemLength - trim - 1] == '\\'); + elemLength -= trim; - while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127) - && isspace(UCHAR(element[elemLength-1])) - /* INTL: ISO C space. */ - && ((elemLength < 2) || (element[elemLength-2] != '\\'))) { - elemLength--; - } - if (elemLength == 0) { - continue; /* nothing left of this element */ - } - memcpy(p, element, (size_t) elemLength); - p += elemLength; - *p = ' '; - p++; - finalSize += (elemLength + 1); + /* If we're left with empty element after trimming, do nothing */ + if (elemLength == 0) { + continue; } - if (p != concatStr) { - p[-1] = 0; - finalSize -= 1; /* we overwrote the final ' ' */ - } else { - *p = 0; + + /* Append to the result with space if needed */ + if (needSpace) { + Tcl_AppendToObj(resPtr, " ", 1); } + Tcl_AppendToObj(resPtr, element, elemLength); + needSpace = 1; } - - TclNewObj(objPtr); - objPtr->bytes = concatStr; - objPtr->length = finalSize; - return objPtr; + return resPtr; } /* @@ -2835,7 +3258,7 @@ TclGetIntForIndex( * Leading whitespace is acceptable in an index. */ - while (length && isspace(UCHAR(*bytes))) { /* INTL: ISO space. */ + while (length && TclIsSpaceProc(*bytes)) { bytes++; length--; } @@ -2848,7 +3271,7 @@ TclGetIntForIndex( if ((savedOp != '+') && (savedOp != '-')) { goto parseError; } - if (isspace(UCHAR(opPtr[1]))) { + if (TclIsSpaceProc(opPtr[1])) { goto parseError; } *opPtr = '\0'; @@ -2994,7 +3417,7 @@ SetEndOffsetFromAny( * after "end-" to Tcl_GetInt, then reverse for offset. */ - if (isspace(UCHAR(bytes[4]))) { + if (TclIsSpaceProc(bytes[4])) { return TCL_ERROR; } if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) { @@ -3059,7 +3482,7 @@ TclCheckBadOctal( * zero. Try to generate a meaningful error message. */ - while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ + while (TclIsSpaceProc(*p)) { p++; } if (*p == '+' || *p == '-') { @@ -3072,7 +3495,7 @@ TclCheckBadOctal( while (isdigit(UCHAR(*p))) { /* INTL: digit. */ p++; } - while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ + while (TclIsSpaceProc(*p)) { p++; } if (*p == '\0') { diff --git a/generic/tclVar.c b/generic/tclVar.c index 9815469..aaf1cb9 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -2554,13 +2554,14 @@ Tcl_AppendObjCmd( /* * Note that we do not need to increase the refCount of the Var * pointers: should a trace delete the variable, the return value - * of TclPtrSetVar will be NULL, and we will not access the - * variable again. + * of TclPtrSetVar will be NULL or emptyObjPtr, and we will not + * access the variable again. */ varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, objv[1], NULL, objv[i], TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG, -1); - if (varValuePtr == NULL) { + if ((varValuePtr == NULL) || + (varValuePtr == ((Interp *) interp)->emptyObjPtr)) { return TCL_ERROR; } } @@ -4775,6 +4776,7 @@ FreeLocalVarName( if (namePtr) { Tcl_DecrRefCount(namePtr); } + objPtr->typePtr = NULL; } static void @@ -4816,6 +4818,7 @@ FreeNsVarName( CleanupVar(varPtr, NULL); } } + objPtr->typePtr = NULL; } static void @@ -4855,6 +4858,7 @@ FreeParsedVarName( TclDecrRefCount(arrayPtr); ckfree(elem); } + objPtr->typePtr = NULL; } static void diff --git a/library/tzdata/Africa/Casablanca b/library/tzdata/Africa/Casablanca index 996dd5d..0eef1ac 100644 --- a/library/tzdata/Africa/Casablanca +++ b/library/tzdata/Africa/Casablanca @@ -27,4 +27,6 @@ set TZData(:Africa/Casablanca) { {1250809200 0 0 WET} {1272758400 3600 1 WEST} {1281222000 0 0 WET} + {1301788800 3600 1 WEST} + {1312066800 0 0 WET} } diff --git a/library/tzdata/America/Havana b/library/tzdata/America/Havana index 7fc6305..f37b98e 100644 --- a/library/tzdata/America/Havana +++ b/library/tzdata/America/Havana @@ -104,7 +104,7 @@ set TZData(:America/Havana) { {1256446800 -18000 0 CST} {1268542800 -14400 1 CDT} {1288501200 -18000 0 CST} - {1299992400 -14400 1 CDT} + {1300597200 -14400 1 CDT} {1319950800 -18000 0 CST} {1331442000 -14400 1 CDT} {1351400400 -18000 0 CST} diff --git a/library/tzdata/America/Juneau b/library/tzdata/America/Juneau index 88fe0ce..fead810 100644 --- a/library/tzdata/America/Juneau +++ b/library/tzdata/America/Juneau @@ -32,8 +32,9 @@ set TZData(:America/Juneau) { {278499600 -28800 0 PST} {294228000 -25200 1 PDT} {309949200 -28800 0 PST} - {325677600 -25200 1 PDT} - {341398800 -28800 0 PST} + {325677600 -32400 0 YST} + {325681200 -28800 1 YDT} + {341406000 -28800 0 PST} {357127200 -25200 1 PDT} {372848400 -28800 0 PST} {388576800 -25200 1 PDT} diff --git a/library/tzdata/America/Metlakatla b/library/tzdata/America/Metlakatla new file mode 100644 index 0000000..19337bf --- /dev/null +++ b/library/tzdata/America/Metlakatla @@ -0,0 +1,275 @@ +# created by tools/tclZIC.tcl - do not edit + +set TZData(:America/Metlakatla) { + {-9223372036854775808 54822 0 LMT} + {-3225366822 -31578 0 LMT} + {-2188955622 -28800 0 PST} + {-883584000 -28800 0 PST} + {-880207200 -25200 1 PWT} + {-769395600 -25200 1 PPT} + {-765385200 -28800 0 PST} + {-757353600 -28800 0 PST} + {-31507200 -28800 0 PST} + {-21477600 -25200 1 PDT} + {-5756400 -28800 0 PST} + {9972000 -25200 1 PDT} + {25693200 -28800 0 PST} + {41421600 -25200 1 PDT} + {57747600 -28800 0 PST} + {73476000 -25200 1 PDT} + {89197200 -28800 0 PST} + {104925600 -25200 1 PDT} + {120646800 -28800 0 PST} + {126698400 -25200 1 PDT} + {152096400 -28800 0 PST} + {162381600 -25200 1 PDT} + {183546000 -28800 0 PST} + {199274400 -25200 1 PDT} + {215600400 -28800 0 PST} + {230724000 -25200 1 PDT} + {247050000 -28800 0 PST} + {262778400 -25200 1 PDT} + {278499600 -28800 0 PST} + {294228000 -25200 1 PDT} + {309949200 -28800 0 PST} + {325677600 -25200 1 PDT} + {341398800 -28800 0 PST} + {357127200 -25200 1 PDT} + {372848400 -28800 0 PST} + {388576800 -25200 1 PDT} + {404902800 -28800 0 PST} + {420026400 -25200 1 PDT} + {436356000 -28800 0 MeST} + {452080800 -25200 1 MeST} + {467802000 -28800 0 MeST} + {483530400 -25200 1 MeST} + {499251600 -28800 0 MeST} + {514980000 -25200 1 MeST} + {530701200 -28800 0 MeST} + {544615200 -25200 1 MeST} + {562150800 -28800 0 MeST} + {576064800 -25200 1 MeST} + {594205200 -28800 0 MeST} + {607514400 -25200 1 MeST} + {625654800 -28800 0 MeST} + {638964000 -25200 1 MeST} + {657104400 -28800 0 MeST} + {671018400 -25200 1 MeST} + {688554000 -28800 0 MeST} + {702468000 -25200 1 MeST} + {720003600 -28800 0 MeST} + {733917600 -25200 1 MeST} + {752058000 -28800 0 MeST} + {765367200 -25200 1 MeST} + {783507600 -28800 0 MeST} + {796816800 -25200 1 MeST} + {814957200 -28800 0 MeST} + {828871200 -25200 1 MeST} + {846406800 -28800 0 MeST} + {860320800 -25200 1 MeST} + {877856400 -28800 0 MeST} + {891770400 -25200 1 MeST} + {909306000 -28800 0 MeST} + {923220000 -25200 1 MeST} + {941360400 -28800 0 MeST} + {954669600 -25200 1 MeST} + {972810000 -28800 0 MeST} + {986119200 -25200 1 MeST} + {1004259600 -28800 0 MeST} + {1018173600 -25200 1 MeST} + {1035709200 -28800 0 MeST} + {1049623200 -25200 1 MeST} + {1067158800 -28800 0 MeST} + {1081072800 -25200 1 MeST} + {1099213200 -28800 0 MeST} + {1112522400 -25200 1 MeST} + {1130662800 -28800 0 MeST} + {1143972000 -25200 1 MeST} + {1162112400 -28800 0 MeST} + {1173607200 -25200 1 MeST} + {1194166800 -28800 0 MeST} + {1205056800 -25200 1 MeST} + {1225616400 -28800 0 MeST} + {1236506400 -25200 1 MeST} + {1257066000 -28800 0 MeST} + {1268560800 -25200 1 MeST} + {1289120400 -28800 0 MeST} + {1300010400 -25200 1 MeST} + {1320570000 -28800 0 MeST} + {1331460000 -25200 1 MeST} + {1352019600 -28800 0 MeST} + {1362909600 -25200 1 MeST} + {1383469200 -28800 0 MeST} + {1394359200 -25200 1 MeST} + {1414918800 -28800 0 MeST} + {1425808800 -25200 1 MeST} + {1446368400 -28800 0 MeST} + {1457863200 -25200 1 MeST} + {1478422800 -28800 0 MeST} + {1489312800 -25200 1 MeST} + {1509872400 -28800 0 MeST} + {1520762400 -25200 1 MeST} + {1541322000 -28800 0 MeST} + {1552212000 -25200 1 MeST} + {1572771600 -28800 0 MeST} + {1583661600 -25200 1 MeST} + {1604221200 -28800 0 MeST} + {1615716000 -25200 1 MeST} + {1636275600 -28800 0 MeST} + {1647165600 -25200 1 MeST} + {1667725200 -28800 0 MeST} + {1678615200 -25200 1 MeST} + {1699174800 -28800 0 MeST} + {1710064800 -25200 1 MeST} + {1730624400 -28800 0 MeST} + {1741514400 -25200 1 MeST} + {1762074000 -28800 0 MeST} + {1772964000 -25200 1 MeST} + {1793523600 -28800 0 MeST} + {1805018400 -25200 1 MeST} + {1825578000 -28800 0 MeST} + {1836468000 -25200 1 MeST} + {1857027600 -28800 0 MeST} + {1867917600 -25200 1 MeST} + {1888477200 -28800 0 MeST} + {1899367200 -25200 1 MeST} + {1919926800 -28800 0 MeST} + {1930816800 -25200 1 MeST} + {1951376400 -28800 0 MeST} + {1962871200 -25200 1 MeST} + {1983430800 -28800 0 MeST} + {1994320800 -25200 1 MeST} + {2014880400 -28800 0 MeST} + {2025770400 -25200 1 MeST} + {2046330000 -28800 0 MeST} + {2057220000 -25200 1 MeST} + {2077779600 -28800 0 MeST} + {2088669600 -25200 1 MeST} + {2109229200 -28800 0 MeST} + {2120119200 -25200 1 MeST} + {2140678800 -28800 0 MeST} + {2152173600 -25200 1 MeST} + {2172733200 -28800 0 MeST} + {2183623200 -25200 1 MeST} + {2204182800 -28800 0 MeST} + {2215072800 -25200 1 MeST} + {2235632400 -28800 0 MeST} + {2246522400 -25200 1 MeST} + {2267082000 -28800 0 MeST} + {2277972000 -25200 1 MeST} + {2298531600 -28800 0 MeST} + {2309421600 -25200 1 MeST} + {2329981200 -28800 0 MeST} + {2341476000 -25200 1 MeST} + {2362035600 -28800 0 MeST} + {2372925600 -25200 1 MeST} + {2393485200 -28800 0 MeST} + {2404375200 -25200 1 MeST} + {2424934800 -28800 0 MeST} + {2435824800 -25200 1 MeST} + {2456384400 -28800 0 MeST} + {2467274400 -25200 1 MeST} + {2487834000 -28800 0 MeST} + {2499328800 -25200 1 MeST} + {2519888400 -28800 0 MeST} + {2530778400 -25200 1 MeST} + {2551338000 -28800 0 MeST} + {2562228000 -25200 1 MeST} + {2582787600 -28800 0 MeST} + {2593677600 -25200 1 MeST} + {2614237200 -28800 0 MeST} + {2625127200 -25200 1 MeST} + {2645686800 -28800 0 MeST} + {2656576800 -25200 1 MeST} + {2677136400 -28800 0 MeST} + {2688631200 -25200 1 MeST} + {2709190800 -28800 0 MeST} + {2720080800 -25200 1 MeST} + {2740640400 -28800 0 MeST} + {2751530400 -25200 1 MeST} + {2772090000 -28800 0 MeST} + {2782980000 -25200 1 MeST} + {2803539600 -28800 0 MeST} + {2814429600 -25200 1 MeST} + {2834989200 -28800 0 MeST} + {2846484000 -25200 1 MeST} + {2867043600 -28800 0 MeST} + {2877933600 -25200 1 MeST} + {2898493200 -28800 0 MeST} + {2909383200 -25200 1 MeST} + {2929942800 -28800 0 MeST} + {2940832800 -25200 1 MeST} + {2961392400 -28800 0 MeST} + {2972282400 -25200 1 MeST} + {2992842000 -28800 0 MeST} + {3003732000 -25200 1 MeST} + {3024291600 -28800 0 MeST} + {3035786400 -25200 1 MeST} + {3056346000 -28800 0 MeST} + {3067236000 -25200 1 MeST} + {3087795600 -28800 0 MeST} + {3098685600 -25200 1 MeST} + {3119245200 -28800 0 MeST} + {3130135200 -25200 1 MeST} + {3150694800 -28800 0 MeST} + {3161584800 -25200 1 MeST} + {3182144400 -28800 0 MeST} + {3193034400 -25200 1 MeST} + {3213594000 -28800 0 MeST} + {3225088800 -25200 1 MeST} + {3245648400 -28800 0 MeST} + {3256538400 -25200 1 MeST} + {3277098000 -28800 0 MeST} + {3287988000 -25200 1 MeST} + {3308547600 -28800 0 MeST} + {3319437600 -25200 1 MeST} + {3339997200 -28800 0 MeST} + {3350887200 -25200 1 MeST} + {3371446800 -28800 0 MeST} + {3382941600 -25200 1 MeST} + {3403501200 -28800 0 MeST} + {3414391200 -25200 1 MeST} + {3434950800 -28800 0 MeST} + {3445840800 -25200 1 MeST} + {3466400400 -28800 0 MeST} + {3477290400 -25200 1 MeST} + {3497850000 -28800 0 MeST} + {3508740000 -25200 1 MeST} + {3529299600 -28800 0 MeST} + {3540189600 -25200 1 MeST} + {3560749200 -28800 0 MeST} + {3572244000 -25200 1 MeST} + {3592803600 -28800 0 MeST} + {3603693600 -25200 1 MeST} + {3624253200 -28800 0 MeST} + {3635143200 -25200 1 MeST} + {3655702800 -28800 0 MeST} + {3666592800 -25200 1 MeST} + {3687152400 -28800 0 MeST} + {3698042400 -25200 1 MeST} + {3718602000 -28800 0 MeST} + {3730096800 -25200 1 MeST} + {3750656400 -28800 0 MeST} + {3761546400 -25200 1 MeST} + {3782106000 -28800 0 MeST} + {3792996000 -25200 1 MeST} + {3813555600 -28800 0 MeST} + {3824445600 -25200 1 MeST} + {3845005200 -28800 0 MeST} + {3855895200 -25200 1 MeST} + {3876454800 -28800 0 MeST} + {3887344800 -25200 1 MeST} + {3907904400 -28800 0 MeST} + {3919399200 -25200 1 MeST} + {3939958800 -28800 0 MeST} + {3950848800 -25200 1 MeST} + {3971408400 -28800 0 MeST} + {3982298400 -25200 1 MeST} + {4002858000 -28800 0 MeST} + {4013748000 -25200 1 MeST} + {4034307600 -28800 0 MeST} + {4045197600 -25200 1 MeST} + {4065757200 -28800 0 MeST} + {4076647200 -25200 1 MeST} + {4097206800 -28800 0 MeST} +} diff --git a/library/tzdata/America/North_Dakota/Beulah b/library/tzdata/America/North_Dakota/Beulah new file mode 100644 index 0000000..95407c6 --- /dev/null +++ b/library/tzdata/America/North_Dakota/Beulah @@ -0,0 +1,279 @@ +# created by tools/tclZIC.tcl - do not edit + +set TZData(:America/North_Dakota/Beulah) { + {-9223372036854775808 -24427 0 LMT} + {-2717643600 -25200 0 MST} + {-1633273200 -21600 1 MDT} + {-1615132800 -25200 0 MST} + {-1601823600 -21600 1 MDT} + {-1583683200 -25200 0 MST} + {-880210800 -21600 1 MWT} + {-769395600 -21600 1 MPT} + {-765388800 -25200 0 MST} + {-84380400 -21600 1 MDT} + {-68659200 -25200 0 MST} + {-52930800 -21600 1 MDT} + {-37209600 -25200 0 MST} + {-21481200 -21600 1 MDT} + {-5760000 -25200 0 MST} + {9968400 -21600 1 MDT} + {25689600 -25200 0 MST} + {41418000 -21600 1 MDT} + {57744000 -25200 0 MST} + {73472400 -21600 1 MDT} + {89193600 -25200 0 MST} + {104922000 -21600 1 MDT} + {120643200 -25200 0 MST} + {126694800 -21600 1 MDT} + {152092800 -25200 0 MST} + {162378000 -21600 1 MDT} + {183542400 -25200 0 MST} + {199270800 -21600 1 MDT} + {215596800 -25200 0 MST} + {230720400 -21600 1 MDT} + {247046400 -25200 0 MST} + {262774800 -21600 1 MDT} + {278496000 -25200 0 MST} + {294224400 -21600 1 MDT} + {309945600 -25200 0 MST} + {325674000 -21600 1 MDT} + {341395200 -25200 0 MST} + {357123600 -21600 1 MDT} + {372844800 -25200 0 MST} + {388573200 -21600 1 MDT} + {404899200 -25200 0 MST} + {420022800 -21600 1 MDT} + {436348800 -25200 0 MST} + {452077200 -21600 1 MDT} + {467798400 -25200 0 MST} + {483526800 -21600 1 MDT} + {499248000 -25200 0 MST} + {514976400 -21600 1 MDT} + {530697600 -25200 0 MST} + {544611600 -21600 1 MDT} + {562147200 -25200 0 MST} + {576061200 -21600 1 MDT} + {594201600 -25200 0 MST} + {607510800 -21600 1 MDT} + {625651200 -25200 0 MST} + {638960400 -21600 1 MDT} + {657100800 -25200 0 MST} + {671014800 -21600 1 MDT} + {688550400 -25200 0 MST} + {702464400 -21600 1 MDT} + {720000000 -25200 0 MST} + {733914000 -21600 1 MDT} + {752054400 -25200 0 MST} + {765363600 -21600 1 MDT} + {783504000 -25200 0 MST} + {796813200 -21600 1 MDT} + {814953600 -25200 0 MST} + {828867600 -21600 1 MDT} + {846403200 -25200 0 MST} + {860317200 -21600 1 MDT} + {877852800 -25200 0 MST} + {891766800 -21600 1 MDT} + {909302400 -25200 0 MST} + {923216400 -21600 1 MDT} + {941356800 -25200 0 MST} + {954666000 -21600 1 MDT} + {972806400 -25200 0 MST} + {986115600 -21600 1 MDT} + {1004256000 -25200 0 MST} + {1018170000 -21600 1 MDT} + {1035705600 -25200 0 MST} + {1049619600 -21600 1 MDT} + {1067155200 -25200 0 MST} + {1081069200 -21600 1 MDT} + {1099209600 -25200 0 MST} + {1112518800 -21600 1 MDT} + {1130659200 -25200 0 MST} + {1143968400 -21600 1 MDT} + {1162108800 -25200 0 MST} + {1173603600 -21600 1 MDT} + {1194163200 -25200 0 MST} + {1205053200 -21600 1 MDT} + {1225612800 -25200 0 MST} + {1236502800 -21600 1 MDT} + {1257062400 -25200 0 MST} + {1268557200 -21600 1 MDT} + {1289120400 -21600 0 CST} + {1300003200 -18000 1 CDT} + {1320562800 -21600 0 CST} + {1331452800 -18000 1 CDT} + {1352012400 -21600 0 CST} + {1362902400 -18000 1 CDT} + {1383462000 -21600 0 CST} + {1394352000 -18000 1 CDT} + {1414911600 -21600 0 CST} + {1425801600 -18000 1 CDT} + {1446361200 -21600 0 CST} + {1457856000 -18000 1 CDT} + {1478415600 -21600 0 CST} + {1489305600 -18000 1 CDT} + {1509865200 -21600 0 CST} + {1520755200 -18000 1 CDT} + {1541314800 -21600 0 CST} + {1552204800 -18000 1 CDT} + {1572764400 -21600 0 CST} + {1583654400 -18000 1 CDT} + {1604214000 -21600 0 CST} + {1615708800 -18000 1 CDT} + {1636268400 -21600 0 CST} + {1647158400 -18000 1 CDT} + {1667718000 -21600 0 CST} + {1678608000 -18000 1 CDT} + {1699167600 -21600 0 CST} + {1710057600 -18000 1 CDT} + {1730617200 -21600 0 CST} + {1741507200 -18000 1 CDT} + {1762066800 -21600 0 CST} + {1772956800 -18000 1 CDT} + {1793516400 -21600 0 CST} + {1805011200 -18000 1 CDT} + {1825570800 -21600 0 CST} + {1836460800 -18000 1 CDT} + {1857020400 -21600 0 CST} + {1867910400 -18000 1 CDT} + {1888470000 -21600 0 CST} + {1899360000 -18000 1 CDT} + {1919919600 -21600 0 CST} + {1930809600 -18000 1 CDT} + {1951369200 -21600 0 CST} + {1962864000 -18000 1 CDT} + {1983423600 -21600 0 CST} + {1994313600 -18000 1 CDT} + {2014873200 -21600 0 CST} + {2025763200 -18000 1 CDT} + {2046322800 -21600 0 CST} + {2057212800 -18000 1 CDT} + {2077772400 -21600 0 CST} + {2088662400 -18000 1 CDT} + {2109222000 -21600 0 CST} + {2120112000 -18000 1 CDT} + {2140671600 -21600 0 CST} + {2152166400 -18000 1 CDT} + {2172726000 -21600 0 CST} + {2183616000 -18000 1 CDT} + {2204175600 -21600 0 CST} + {2215065600 -18000 1 CDT} + {2235625200 -21600 0 CST} + {2246515200 -18000 1 CDT} + {2267074800 -21600 0 CST} + {2277964800 -18000 1 CDT} + {2298524400 -21600 0 CST} + {2309414400 -18000 1 CDT} + {2329974000 -21600 0 CST} + {2341468800 -18000 1 CDT} + {2362028400 -21600 0 CST} + {2372918400 -18000 1 CDT} + {2393478000 -21600 0 CST} + {2404368000 -18000 1 CDT} + {2424927600 -21600 0 CST} + {2435817600 -18000 1 CDT} + {2456377200 -21600 0 CST} + {2467267200 -18000 1 CDT} + {2487826800 -21600 0 CST} + {2499321600 -18000 1 CDT} + {2519881200 -21600 0 CST} + {2530771200 -18000 1 CDT} + {2551330800 -21600 0 CST} + {2562220800 -18000 1 CDT} + {2582780400 -21600 0 CST} + {2593670400 -18000 1 CDT} + {2614230000 -21600 0 CST} + {2625120000 -18000 1 CDT} + {2645679600 -21600 0 CST} + {2656569600 -18000 1 CDT} + {2677129200 -21600 0 CST} + {2688624000 -18000 1 CDT} + {2709183600 -21600 0 CST} + {2720073600 -18000 1 CDT} + {2740633200 -21600 0 CST} + {2751523200 -18000 1 CDT} + {2772082800 -21600 0 CST} + {2782972800 -18000 1 CDT} + {2803532400 -21600 0 CST} + {2814422400 -18000 1 CDT} + {2834982000 -21600 0 CST} + {2846476800 -18000 1 CDT} + {2867036400 -21600 0 CST} + {2877926400 -18000 1 CDT} + {2898486000 -21600 0 CST} + {2909376000 -18000 1 CDT} + {2929935600 -21600 0 CST} + {2940825600 -18000 1 CDT} + {2961385200 -21600 0 CST} + {2972275200 -18000 1 CDT} + {2992834800 -21600 0 CST} + {3003724800 -18000 1 CDT} + {3024284400 -21600 0 CST} + {3035779200 -18000 1 CDT} + {3056338800 -21600 0 CST} + {3067228800 -18000 1 CDT} + {3087788400 -21600 0 CST} + {3098678400 -18000 1 CDT} + {3119238000 -21600 0 CST} + {3130128000 -18000 1 CDT} + {3150687600 -21600 0 CST} + {3161577600 -18000 1 CDT} + {3182137200 -21600 0 CST} + {3193027200 -18000 1 CDT} + {3213586800 -21600 0 CST} + {3225081600 -18000 1 CDT} + {3245641200 -21600 0 CST} + {3256531200 -18000 1 CDT} + {3277090800 -21600 0 CST} + {3287980800 -18000 1 CDT} + {3308540400 -21600 0 CST} + {3319430400 -18000 1 CDT} + {3339990000 -21600 0 CST} + {3350880000 -18000 1 CDT} + {3371439600 -21600 0 CST} + {3382934400 -18000 1 CDT} + {3403494000 -21600 0 CST} + {3414384000 -18000 1 CDT} + {3434943600 -21600 0 CST} + {3445833600 -18000 1 CDT} + {3466393200 -21600 0 CST} + {3477283200 -18000 1 CDT} + {3497842800 -21600 0 CST} + {3508732800 -18000 1 CDT} + {3529292400 -21600 0 CST} + {3540182400 -18000 1 CDT} + {3560742000 -21600 0 CST} + {3572236800 -18000 1 CDT} + {3592796400 -21600 0 CST} + {3603686400 -18000 1 CDT} + {3624246000 -21600 0 CST} + {3635136000 -18000 1 CDT} + {3655695600 -21600 0 CST} + {3666585600 -18000 1 CDT} + {3687145200 -21600 0 CST} + {3698035200 -18000 1 CDT} + {3718594800 -21600 0 CST} + {3730089600 -18000 1 CDT} + {3750649200 -21600 0 CST} + {3761539200 -18000 1 CDT} + {3782098800 -21600 0 CST} + {3792988800 -18000 1 CDT} + {3813548400 -21600 0 CST} + {3824438400 -18000 1 CDT} + {3844998000 -21600 0 CST} + {3855888000 -18000 1 CDT} + {3876447600 -21600 0 CST} + {3887337600 -18000 1 CDT} + {3907897200 -21600 0 CST} + {3919392000 -18000 1 CDT} + {3939951600 -21600 0 CST} + {3950841600 -18000 1 CDT} + {3971401200 -21600 0 CST} + {3982291200 -18000 1 CDT} + {4002850800 -21600 0 CST} + {4013740800 -18000 1 CDT} + {4034300400 -21600 0 CST} + {4045190400 -18000 1 CDT} + {4065750000 -21600 0 CST} + {4076640000 -18000 1 CDT} + {4097199600 -21600 0 CST} +} diff --git a/library/tzdata/America/Santiago b/library/tzdata/America/Santiago index a3cd817..c631bd1 100644 --- a/library/tzdata/America/Santiago +++ b/library/tzdata/America/Santiago @@ -110,8 +110,8 @@ set TZData(:America/Santiago) { {1255233600 -10800 1 CLST} {1270350000 -14400 0 CLT} {1286683200 -10800 1 CLST} - {1299985200 -14400 0 CLT} - {1318132800 -10800 1 CLST} + {1304823600 -14400 0 CLT} + {1313899200 -10800 1 CLST} {1331434800 -14400 0 CLT} {1350187200 -10800 1 CLST} {1362884400 -14400 0 CLT} diff --git a/library/tzdata/America/Sitka b/library/tzdata/America/Sitka new file mode 100644 index 0000000..c096fc9 --- /dev/null +++ b/library/tzdata/America/Sitka @@ -0,0 +1,275 @@ +# created by tools/tclZIC.tcl - do not edit + +set TZData(:America/Sitka) { + {-9223372036854775808 -53927 0 LMT} + {-3225258073 -32473 0 LMT} + {-2188954727 -28800 0 PST} + {-883584000 -28800 0 PST} + {-880207200 -25200 1 PWT} + {-769395600 -25200 1 PPT} + {-765385200 -28800 0 PST} + {-757353600 -28800 0 PST} + {-31507200 -28800 0 PST} + {-21477600 -25200 1 PDT} + {-5756400 -28800 0 PST} + {9972000 -25200 1 PDT} + {25693200 -28800 0 PST} + {41421600 -25200 1 PDT} + {57747600 -28800 0 PST} + {73476000 -25200 1 PDT} + {89197200 -28800 0 PST} + {104925600 -25200 1 PDT} + {120646800 -28800 0 PST} + {126698400 -25200 1 PDT} + {152096400 -28800 0 PST} + {162381600 -25200 1 PDT} + {183546000 -28800 0 PST} + {199274400 -25200 1 PDT} + {215600400 -28800 0 PST} + {230724000 -25200 1 PDT} + {247050000 -28800 0 PST} + {262778400 -25200 1 PDT} + {278499600 -28800 0 PST} + {294228000 -25200 1 PDT} + {309949200 -28800 0 PST} + {325677600 -25200 1 PDT} + {341398800 -28800 0 PST} + {357127200 -25200 1 PDT} + {372848400 -28800 0 PST} + {388576800 -25200 1 PDT} + {404902800 -28800 0 PST} + {420026400 -25200 1 PDT} + {439030800 -32400 0 AKST} + {452084400 -28800 1 AKDT} + {467805600 -32400 0 AKST} + {483534000 -28800 1 AKDT} + {499255200 -32400 0 AKST} + {514983600 -28800 1 AKDT} + {530704800 -32400 0 AKST} + {544618800 -28800 1 AKDT} + {562154400 -32400 0 AKST} + {576068400 -28800 1 AKDT} + {594208800 -32400 0 AKST} + {607518000 -28800 1 AKDT} + {625658400 -32400 0 AKST} + {638967600 -28800 1 AKDT} + {657108000 -32400 0 AKST} + {671022000 -28800 1 AKDT} + {688557600 -32400 0 AKST} + {702471600 -28800 1 AKDT} + {720007200 -32400 0 AKST} + {733921200 -28800 1 AKDT} + {752061600 -32400 0 AKST} + {765370800 -28800 1 AKDT} + {783511200 -32400 0 AKST} + {796820400 -28800 1 AKDT} + {814960800 -32400 0 AKST} + {828874800 -28800 1 AKDT} + {846410400 -32400 0 AKST} + {860324400 -28800 1 AKDT} + {877860000 -32400 0 AKST} + {891774000 -28800 1 AKDT} + {909309600 -32400 0 AKST} + {923223600 -28800 1 AKDT} + {941364000 -32400 0 AKST} + {954673200 -28800 1 AKDT} + {972813600 -32400 0 AKST} + {986122800 -28800 1 AKDT} + {1004263200 -32400 0 AKST} + {1018177200 -28800 1 AKDT} + {1035712800 -32400 0 AKST} + {1049626800 -28800 1 AKDT} + {1067162400 -32400 0 AKST} + {1081076400 -28800 1 AKDT} + {1099216800 -32400 0 AKST} + {1112526000 -28800 1 AKDT} + {1130666400 -32400 0 AKST} + {1143975600 -28800 1 AKDT} + {1162116000 -32400 0 AKST} + {1173610800 -28800 1 AKDT} + {1194170400 -32400 0 AKST} + {1205060400 -28800 1 AKDT} + {1225620000 -32400 0 AKST} + {1236510000 -28800 1 AKDT} + {1257069600 -32400 0 AKST} + {1268564400 -28800 1 AKDT} + {1289124000 -32400 0 AKST} + {1300014000 -28800 1 AKDT} + {1320573600 -32400 0 AKST} + {1331463600 -28800 1 AKDT} + {1352023200 -32400 0 AKST} + {1362913200 -28800 1 AKDT} + {1383472800 -32400 0 AKST} + {1394362800 -28800 1 AKDT} + {1414922400 -32400 0 AKST} + {1425812400 -28800 1 AKDT} + {1446372000 -32400 0 AKST} + {1457866800 -28800 1 AKDT} + {1478426400 -32400 0 AKST} + {1489316400 -28800 1 AKDT} + {1509876000 -32400 0 AKST} + {1520766000 -28800 1 AKDT} + {1541325600 -32400 0 AKST} + {1552215600 -28800 1 AKDT} + {1572775200 -32400 0 AKST} + {1583665200 -28800 1 AKDT} + {1604224800 -32400 0 AKST} + {1615719600 -28800 1 AKDT} + {1636279200 -32400 0 AKST} + {1647169200 -28800 1 AKDT} + {1667728800 -32400 0 AKST} + {1678618800 -28800 1 AKDT} + {1699178400 -32400 0 AKST} + {1710068400 -28800 1 AKDT} + {1730628000 -32400 0 AKST} + {1741518000 -28800 1 AKDT} + {1762077600 -32400 0 AKST} + {1772967600 -28800 1 AKDT} + {1793527200 -32400 0 AKST} + {1805022000 -28800 1 AKDT} + {1825581600 -32400 0 AKST} + {1836471600 -28800 1 AKDT} + {1857031200 -32400 0 AKST} + {1867921200 -28800 1 AKDT} + {1888480800 -32400 0 AKST} + {1899370800 -28800 1 AKDT} + {1919930400 -32400 0 AKST} + {1930820400 -28800 1 AKDT} + {1951380000 -32400 0 AKST} + {1962874800 -28800 1 AKDT} + {1983434400 -32400 0 AKST} + {1994324400 -28800 1 AKDT} + {2014884000 -32400 0 AKST} + {2025774000 -28800 1 AKDT} + {2046333600 -32400 0 AKST} + {2057223600 -28800 1 AKDT} + {2077783200 -32400 0 AKST} + {2088673200 -28800 1 AKDT} + {2109232800 -32400 0 AKST} + {2120122800 -28800 1 AKDT} + {2140682400 -32400 0 AKST} + {2152177200 -28800 1 AKDT} + {2172736800 -32400 0 AKST} + {2183626800 -28800 1 AKDT} + {2204186400 -32400 0 AKST} + {2215076400 -28800 1 AKDT} + {2235636000 -32400 0 AKST} + {2246526000 -28800 1 AKDT} + {2267085600 -32400 0 AKST} + {2277975600 -28800 1 AKDT} + {2298535200 -32400 0 AKST} + {2309425200 -28800 1 AKDT} + {2329984800 -32400 0 AKST} + {2341479600 -28800 1 AKDT} + {2362039200 -32400 0 AKST} + {2372929200 -28800 1 AKDT} + {2393488800 -32400 0 AKST} + {2404378800 -28800 1 AKDT} + {2424938400 -32400 0 AKST} + {2435828400 -28800 1 AKDT} + {2456388000 -32400 0 AKST} + {2467278000 -28800 1 AKDT} + {2487837600 -32400 0 AKST} + {2499332400 -28800 1 AKDT} + {2519892000 -32400 0 AKST} + {2530782000 -28800 1 AKDT} + {2551341600 -32400 0 AKST} + {2562231600 -28800 1 AKDT} + {2582791200 -32400 0 AKST} + {2593681200 -28800 1 AKDT} + {2614240800 -32400 0 AKST} + {2625130800 -28800 1 AKDT} + {2645690400 -32400 0 AKST} + {2656580400 -28800 1 AKDT} + {2677140000 -32400 0 AKST} + {2688634800 -28800 1 AKDT} + {2709194400 -32400 0 AKST} + {2720084400 -28800 1 AKDT} + {2740644000 -32400 0 AKST} + {2751534000 -28800 1 AKDT} + {2772093600 -32400 0 AKST} + {2782983600 -28800 1 AKDT} + {2803543200 -32400 0 AKST} + {2814433200 -28800 1 AKDT} + {2834992800 -32400 0 AKST} + {2846487600 -28800 1 AKDT} + {2867047200 -32400 0 AKST} + {2877937200 -28800 1 AKDT} + {2898496800 -32400 0 AKST} + {2909386800 -28800 1 AKDT} + {2929946400 -32400 0 AKST} + {2940836400 -28800 1 AKDT} + {2961396000 -32400 0 AKST} + {2972286000 -28800 1 AKDT} + {2992845600 -32400 0 AKST} + {3003735600 -28800 1 AKDT} + {3024295200 -32400 0 AKST} + {3035790000 -28800 1 AKDT} + {3056349600 -32400 0 AKST} + {3067239600 -28800 1 AKDT} + {3087799200 -32400 0 AKST} + {3098689200 -28800 1 AKDT} + {3119248800 -32400 0 AKST} + {3130138800 -28800 1 AKDT} + {3150698400 -32400 0 AKST} + {3161588400 -28800 1 AKDT} + {3182148000 -32400 0 AKST} + {3193038000 -28800 1 AKDT} + {3213597600 -32400 0 AKST} + {3225092400 -28800 1 AKDT} + {3245652000 -32400 0 AKST} + {3256542000 -28800 1 AKDT} + {3277101600 -32400 0 AKST} + {3287991600 -28800 1 AKDT} + {3308551200 -32400 0 AKST} + {3319441200 -28800 1 AKDT} + {3340000800 -32400 0 AKST} + {3350890800 -28800 1 AKDT} + {3371450400 -32400 0 AKST} + {3382945200 -28800 1 AKDT} + {3403504800 -32400 0 AKST} + {3414394800 -28800 1 AKDT} + {3434954400 -32400 0 AKST} + {3445844400 -28800 1 AKDT} + {3466404000 -32400 0 AKST} + {3477294000 -28800 1 AKDT} + {3497853600 -32400 0 AKST} + {3508743600 -28800 1 AKDT} + {3529303200 -32400 0 AKST} + {3540193200 -28800 1 AKDT} + {3560752800 -32400 0 AKST} + {3572247600 -28800 1 AKDT} + {3592807200 -32400 0 AKST} + {3603697200 -28800 1 AKDT} + {3624256800 -32400 0 AKST} + {3635146800 -28800 1 AKDT} + {3655706400 -32400 0 AKST} + {3666596400 -28800 1 AKDT} + {3687156000 -32400 0 AKST} + {3698046000 -28800 1 AKDT} + {3718605600 -32400 0 AKST} + {3730100400 -28800 1 AKDT} + {3750660000 -32400 0 AKST} + {3761550000 -28800 1 AKDT} + {3782109600 -32400 0 AKST} + {3792999600 -28800 1 AKDT} + {3813559200 -32400 0 AKST} + {3824449200 -28800 1 AKDT} + {3845008800 -32400 0 AKST} + {3855898800 -28800 1 AKDT} + {3876458400 -32400 0 AKST} + {3887348400 -28800 1 AKDT} + {3907908000 -32400 0 AKST} + {3919402800 -28800 1 AKDT} + {3939962400 -32400 0 AKST} + {3950852400 -28800 1 AKDT} + {3971412000 -32400 0 AKST} + {3982302000 -28800 1 AKDT} + {4002861600 -32400 0 AKST} + {4013751600 -28800 1 AKDT} + {4034311200 -32400 0 AKST} + {4045201200 -28800 1 AKDT} + {4065760800 -32400 0 AKST} + {4076650800 -28800 1 AKDT} + {4097210400 -32400 0 AKST} +} diff --git a/library/tzdata/Atlantic/Stanley b/library/tzdata/Atlantic/Stanley index 70dc402..545b91c 100644 --- a/library/tzdata/Atlantic/Stanley +++ b/library/tzdata/Atlantic/Stanley @@ -72,8 +72,7 @@ set TZData(:Atlantic/Stanley) { {1252216800 -10800 1 FKST} {1271566800 -14400 0 FKT} {1283666400 -10800 1 FKST} - {1303016400 -14400 0 FKT} - {1315116000 -10800 1 FKST} + {1315112400 -10800 1 FKST} {1334466000 -14400 0 FKT} {1346565600 -10800 1 FKST} {1366520400 -14400 0 FKT} diff --git a/library/tzdata/Europe/Istanbul b/library/tzdata/Europe/Istanbul index 06b2f88..7737d75 100644 --- a/library/tzdata/Europe/Istanbul +++ b/library/tzdata/Europe/Istanbul @@ -122,7 +122,8 @@ set TZData(:Europe/Istanbul) { {1256432400 7200 0 EET} {1269738000 10800 1 EEST} {1288486800 7200 0 EET} - {1301187600 10800 1 EEST} + {1301187600 7200 0 EET} + {1301274000 10800 0 EEST} {1319936400 7200 0 EET} {1332637200 10800 1 EEST} {1351386000 7200 0 EET} diff --git a/library/tzdata/Pacific/Apia b/library/tzdata/Pacific/Apia index 2db52b6..25b047d 100644 --- a/library/tzdata/Pacific/Apia +++ b/library/tzdata/Pacific/Apia @@ -6,5 +6,5 @@ set TZData(:Pacific/Apia) { {-1861878784 -41400 0 SAMT} {-631110600 -39600 0 WST} {1285498800 -36000 1 WSDT} - {1301828400 -39600 0 WST} + {1301752800 -39600 0 WST} } diff --git a/library/tzdata/Pacific/Easter b/library/tzdata/Pacific/Easter index be661fc..f8e63a8 100644 --- a/library/tzdata/Pacific/Easter +++ b/library/tzdata/Pacific/Easter @@ -94,8 +94,8 @@ set TZData(:Pacific/Easter) { {1255233600 -18000 1 EASST} {1270350000 -21600 0 EAST} {1286683200 -18000 1 EASST} - {1299985200 -21600 0 EAST} - {1318132800 -18000 1 EASST} + {1304823600 -21600 0 EAST} + {1313899200 -18000 1 EASST} {1331434800 -21600 0 EAST} {1350187200 -18000 1 EASST} {1362884400 -21600 0 EAST} diff --git a/library/tzdata/Pacific/Honolulu b/library/tzdata/Pacific/Honolulu index f441a02..e24b096 100644 --- a/library/tzdata/Pacific/Honolulu +++ b/library/tzdata/Pacific/Honolulu @@ -2,11 +2,9 @@ set TZData(:Pacific/Honolulu) { {-9223372036854775808 -37886 0 LMT} - {-2208907714 -37800 0 HST} + {-2334101314 -37800 0 HST} {-1157283000 -34200 1 HDT} - {-1155472200 -34200 0 HST} - {-880201800 -34200 1 HWT} - {-769395600 -34200 1 HPT} - {-765376200 -37800 0 HST} + {-1155436200 -37800 0 HST} + {-880198200 -34200 1 HDT} {-712150200 -36000 0 HST} } diff --git a/libtommath/bn_mp_div_d.c b/libtommath/bn_mp_div_d.c index f2729d2..af18d0a 100644 --- a/libtommath/bn_mp_div_d.c +++ b/libtommath/bn_mp_div_d.c @@ -20,7 +20,7 @@ static int s_is_power_of_two(mp_digit b, int *p) int x; /* quick out - if (b & (b-1)) isn't zero, b isn't a power of two */ - if ((b & (b-1)) != 0) { + if ((b==0) || (b & (b-1))) { return 0; } for (x = 1; x < DIGIT_BIT; x++) { diff --git a/libtommath/bn_mp_montgomery_setup.c b/libtommath/bn_mp_montgomery_setup.c index 9bbe0c8..b8e1887 100644 --- a/libtommath/bn_mp_montgomery_setup.c +++ b/libtommath/bn_mp_montgomery_setup.c @@ -48,7 +48,7 @@ mp_montgomery_setup (mp_int * n, mp_digit * rho) #endif /* rho = -1/m mod b */ - *rho = (((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; return MP_OKAY; } diff --git a/libtommath/bn_mp_prime_next_prime.c b/libtommath/bn_mp_prime_next_prime.c index 3171d61..2433e8c 100644 --- a/libtommath/bn_mp_prime_next_prime.c +++ b/libtommath/bn_mp_prime_next_prime.c @@ -143,7 +143,7 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style) /* is this prime? */ for (x = 0; x < t; x++) { - mp_set(&b, ltm_prime_tab[t]); + mp_set(&b, ltm_prime_tab[x]); if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { goto LBL_ERR; } diff --git a/libtommath/bn_mp_shrink.c b/libtommath/bn_mp_shrink.c index 482ca48..bfdf93a 100644 --- a/libtommath/bn_mp_shrink.c +++ b/libtommath/bn_mp_shrink.c @@ -19,12 +19,17 @@ int mp_shrink (mp_int * a) { mp_digit *tmp; - if (a->alloc != a->used && a->used > 0) { - if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + int used = 1; + + if(a->used > 0) + used = a->used; + + if (a->alloc != used) { + if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * used)) == NULL) { return MP_MEM; } a->dp = tmp; - a->alloc = a->used; + a->alloc = used; } return MP_OKAY; } diff --git a/libtommath/changes.txt b/libtommath/changes.txt index 9498d36..4fc0913 100644 --- a/libtommath/changes.txt +++ b/libtommath/changes.txt @@ -1,3 +1,17 @@ +July 23rd, 2010 +v0.42.0 + -- Fix for mp_prime_next_prime() bug when checking generated prime + -- allow mp_shrink to shrink initialized, but empty MPI's + -- Added project and solution files for Visual Studio 2005 and Visual Studio 2008. + +March 10th, 2007 +v0.41 -- Wolfgang Ehrhardt suggested a quick fix to mp_div_d() which makes the detection of powers of two quicker. + -- [CRI] Added libtommath.dsp for Visual C++ users. + +December 24th, 2006 +v0.40 -- Updated makefile to properly support LIBNAME + -- Fixed bug in fast_s_mp_mul_high_digs() which overflowed (line 83), thanks Valgrind! + April 4th, 2006 v0.39 -- Jim Wigginton pointed out my Montgomery examples in figures 6.4 and 6.6 were off by one, k should be 9 not 8 -- Bruce Guenter suggested I use --tag=CC for libtool builds where the compiler may think it's C++. diff --git a/libtommath/etc/drprimes.txt b/libtommath/etc/drprimes.txt index 2c887ea..7c97f67 100644 --- a/libtommath/etc/drprimes.txt +++ b/libtommath/etc/drprimes.txt @@ -1,6 +1,9 @@ -280-bit prime: -p == 1942668892225729070919461906823518906642406839052139521251812409738904285204940164839 +300-bit prime: +p == 2037035976334486086268445688409378161051468393665936250636140449354381298610415201576637819 -532-bit prime: -p == 14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368691747 +540-bit prime: +p == 3599131035634557106248430806148785487095757694641533306480604458089470064537190296255232548883112685719936728506816716098566612844395439751206810991770626477344739 + +780-bit prime: +p == 6359114106063703798370219984742410466332205126109989319225557147754704702203399726411277962562135973685197744935448875852478791860694279747355800678568677946181447581781401213133886609947027230004277244697462656003655947791725966271167 diff --git a/libtommath/makefile b/libtommath/makefile index e08a888..70de306 100644 --- a/libtommath/makefile +++ b/libtommath/makefile @@ -3,7 +3,7 @@ #Tom St Denis #version of library -VERSION=0.39 +VERSION=0.42.0 CFLAGS += -I./ -Wall -W -Wshadow -Wsign-compare @@ -40,12 +40,13 @@ else USER=$(INSTALL_USER) endif -default: libtommath.a - #default files to install ifndef LIBNAME LIBNAME=libtommath.a endif + +default: ${LIBNAME} + HEADERS=tommath.h tommath_class.h tommath_superclass.h #LIBPATH-The directory for libtommath to be installed to. diff --git a/libtommath/makefile.shared b/libtommath/makefile.shared index 8522d44..f17bbbd 100644 --- a/libtommath/makefile.shared +++ b/libtommath/makefile.shared @@ -1,7 +1,7 @@ #Makefile for GCC # #Tom St Denis -VERSION=0:39 +VERSION=0:41 CC = libtool --mode=compile --tag=CC gcc diff --git a/libtommath/pre_gen/mpi.c b/libtommath/pre_gen/mpi.c index b7a5bed..d2224c0 100644 --- a/libtommath/pre_gen/mpi.c +++ b/libtommath/pre_gen/mpi.c @@ -553,7 +553,7 @@ int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) register mp_digit *tmpc; tmpc = c->dp + digs; - for (ix = digs; ix <= pa; ix++) { + for (ix = digs; ix < pa; ix++) { /* now extract the previous digit [below the carry] */ *tmpc++ = W[ix]; } @@ -2026,7 +2026,12 @@ static int s_is_power_of_two(mp_digit b, int *p) { int x; - for (x = 1; x < DIGIT_BIT; x++) { + /* fast return if no power of two */ + if ((b==0) || (b & (b-1))) { + return 0; + } + + for (x = 0; x < DIGIT_BIT; x++) { if (b == (((mp_digit)1)<alloc != a->used && a->used > 0) { - if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + int used = 1; + + if(a->used > 0) + used = a->used; + + if (a->alloc != used) { + if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * used)) == NULL) { return MP_MEM; } a->dp = tmp; - a->alloc = a->used; + a->alloc = used; } return MP_OKAY; } diff --git a/macosx/README b/macosx/README index 3496969..80bed14 100644 --- a/macosx/README +++ b/macosx/README @@ -17,16 +17,11 @@ before asking on the list, many questions have already been answered). http://groups.google.com/group/comp.lang.tcl/ - The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see - http://wiki.tcl.tk/references/3753! - http://wiki.tcl.tk/references/8361! + http://wiki.tcl.tk/_/ref?N=3753 + http://wiki.tcl.tk/_/ref?N=8361 - Please report bugs with Tcl or Tk on Mac OS X to the sourceforge bug trackers: - Tcl: http://sf.net/tracker/?func=add&group_id=10894&atid=110894 - Tk: http://sf.net/tracker/?func=add&group_id=12997&atid=112997 -please make sure that your report Tk specific bugs to the tktoolkit project bug -tracker rather than the tcl project bug tracker. -Mac OS X specific bugs should usually be assigned to 'das' or 'wolfsuit'. - + http://tcl.sourceforge.net/ 2. Using Tcl on Mac OS X ------------------------ diff --git a/macosx/tclMacOSXFCmd.c b/macosx/tclMacOSXFCmd.c index 8eb3e57..09ee96d 100644 --- a/macosx/tclMacOSXFCmd.c +++ b/macosx/tclMacOSXFCmd.c @@ -623,8 +623,10 @@ SetOSTypeFromAny( Tcl_UtfToExternalDString(encoding, string, length, &ds); if (Tcl_DStringLength(&ds) > 4) { - Tcl_AppendResult(interp, "expected Macintosh OS type but got \"", - string, "\": ", NULL); + if (interp) { + Tcl_AppendResult(interp, "expected Macintosh OS type but got \"", + string, "\": ", NULL); + } result = TCL_ERROR; } else { OSType osType; diff --git a/tests/namespace.test b/tests/namespace.test index 89f6759..504d532 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -24,6 +24,12 @@ if {[lsearch [namespace children] ::tcltest] == -1} { # Clear out any namespaces called test_ns_* catch {namespace delete {*}[namespace children :: test_ns_*]} +proc fq {ns} { + if {[string match ::* $ns]} {return $ns} + set current [uplevel 1 {namespace current}] + return [string trimright $current :]::[string trimleft $ns :] +} + test namespace-1.1 {TclInitNamespaces, GetNamespaceFromObj, NamespaceChildrenCmd} { namespace children :: test_ns_* } {} @@ -929,9 +935,8 @@ test namespace-21.7 {NamespaceChildrenCmd, glob-style pattern given} { } [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_foo}] test namespace-21.8 {NamespaceChildrenCmd, trivial pattern starting with ::} { namespace eval test_ns_1 {} - namespace children [namespace current] \ - [string trimright [namespace current] :]::test_ns_1 -} [string trimright [namespace current] :]::test_ns_1 + namespace children [namespace current] [fq test_ns_1] +} [fq test_ns_1] test namespace-22.1 {NamespaceCodeCmd, bad args} { catch {namespace delete {*}[namespace children :: test_ns_*]} @@ -942,11 +947,11 @@ test namespace-22.2 {NamespaceCodeCmd, arg is already scoped value} { namespace eval test_ns_1 { proc cmd {} {return "test_ns_1::cmd"} } - namespace code {namespace inscope ::test_ns_1 cmd} -} {namespace inscope ::test_ns_1 cmd} + namespace code {::namespace inscope ::test_ns_1 cmd} +} {::namespace inscope ::test_ns_1 cmd} test namespace-22.3 {NamespaceCodeCmd, arg is already scoped value} { namespace code {namespace inscope ::test_ns_1 cmd} -} {namespace inscope ::test_ns_1 cmd} +} {::namespace inscope :: {namespace inscope ::test_ns_1 cmd}} test namespace-22.4 {NamespaceCodeCmd, in :: namespace} { namespace code unknown } {::namespace inscope :: unknown} @@ -966,6 +971,12 @@ test namespace-22.6 {NamespaceCodeCmd, in other namespace} { namespace code {set v} }] } {42} +test namespace-22.7 {NamespaceCodeCmd, Bug 3202171} { + namespace eval demo { + proc namespace args {puts $args} + ::namespace code {namespace inscope foo} + } +} [list ::namespace inscope [fq demo] {namespace inscope foo}] test namespace-23.1 {NamespaceCurrentCmd, bad args} { catch {namespace delete {*}[namespace children :: test_ns_*]} diff --git a/tests/parse.test b/tests/parse.test index b5211e7..37c44d5 100644 --- a/tests/parse.test +++ b/tests/parse.test @@ -227,6 +227,18 @@ test parse-5.26 {Tcl_ParseCommand: {*} parsing} testparser { test parse-5.27 {Tcl_ParseCommand: {*} parsing} testparser { testparser "{*}\\\n foo bar" 0 } {- \{*\}\\\n\ foo\ bar 3 simple {{*}} 1 text * 0 simple foo 1 text foo 0 simple bar 1 text bar 0 {}} +test parse-5.28 {Tcl_ParseCommand: {*} parsing, expanded literals} testparser { + testparser {{*}{a b}} 0 +} {- {{*}{a b}} 2 simple a 1 text a 0 simple b 1 text b 0 {}} +test parse-5.29 {Tcl_ParseCommand: {*} parsing, expanded literals, naked backslashes} testparser { + testparser {{*}{a \n b}} 0 +} {- {{*}{a \n b}} 1 expand {{*}{a \n b}} 1 text {a \n b} 0 {}} +test parse-5.30 {Tcl_ParseCommand: {*} parsing, expanded literals} testparser { + testparser {{*}"a b"} 0 +} {- {{*}"a b"} 2 simple a 1 text a 0 simple b 1 text b 0 {}} +test parse-5.31 {Tcl_ParseCommand: {*} parsing, expanded literals, naked backslashes} testparser { + testparser {{*}"a \n b"} 0 +} {- {{*}"a \n b"} 1 expand {{*}"a \n b"} 3 text {a } 0 backslash {\n} 0 text { b} 0 {}} test parse-6.1 {ParseTokens procedure, empty word} testparser { testparser {""} 0 diff --git a/tests/string.test b/tests/string.test index 6b00f3a..c3cfc3c 100644 --- a/tests/string.test +++ b/tests/string.test @@ -601,18 +601,18 @@ test string-6.91 {string is double, bad doubles} { } set result } {1 1 0 0 0 1 0 0} -test string-6.92 {string is double, 32-bit overflow} { +test string-6.92 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 list [string is integer -failindex var $x] $var } {0 -1} -test string-6.93 {string is double, 32-bit overflow} { +test string-6.93 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 append x "" list [string is integer -failindex var $x] $var } {0 -1} -test string-6.94 {string is double, 32-bit overflow} { +test string-6.94 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 list [string is integer -failindex var [expr {$x}]] $var @@ -1608,6 +1608,11 @@ test string-24.11 {string reverse command - corner case} { set y \udead string reverse $x$y } \udead\ubeef +test string-24.12 {string reverse command - corner case} { + set x \ubeef + set y \udead + string is ascii [string reverse $x$y] +} 0 test string-25.1 {string is list} { string is list {a b c} diff --git a/tools/configure b/tools/configure index e8661fa..98b5867 100644 --- a/tools/configure +++ b/tools/configure @@ -1,9 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.57. +# Generated by GNU Autoconf 2.59. # -# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. +# Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## @@ -20,9 +19,10 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi +DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. -if (FOO=FOO; unset FOO) >/dev/null 2>&1; then +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false @@ -41,7 +41,7 @@ for as_var in \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do - if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var @@ -218,16 +218,17 @@ rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else + test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. -as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS @@ -630,7 +631,7 @@ done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ - localstatedir libdir includedir oldincludedir infodir mandir + localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in @@ -670,10 +671,10 @@ if test -z "$srcdir"; then # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$0" : 'X\(//\)[^/]' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } @@ -745,9 +746,9 @@ _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] + [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] + [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify @@ -817,12 +818,45 @@ case $srcdir in ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac -# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be -# absolute. -ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` -ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` -ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` -ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. @@ -833,7 +867,7 @@ ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || - test -f $ac_srcdir/configure.in; then + test -f $ac_srcdir/configure.in; then echo $ac_configure --help else @@ -847,8 +881,7 @@ test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 -Free Software Foundation, Inc. +Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -860,7 +893,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.57. Invocation command line was +generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -937,19 +970,19 @@ do 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. + ac_must_keep_next=false # Got value, back to normal. else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. @@ -983,12 +1016,12 @@ _ASBOX case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ - "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ - "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } @@ -1017,7 +1050,7 @@ _ASBOX for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` - echo "$ac_var='"'"'$ac_val'"'"'" + echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi @@ -1036,7 +1069,7 @@ _ASBOX echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 - rm -f core core.* *.core && + rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 @@ -1116,7 +1149,7 @@ fi # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | - sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" @@ -1133,13 +1166,13 @@ echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then - { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} - { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} - ac_cache_corrupted=: + ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. @@ -1188,6 +1221,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Recover information that Tcl computed with its configure script. #-------------------------------------------------------------------- @@ -1256,13 +1290,13 @@ _ACEOF # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ - "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | @@ -1292,13 +1326,13 @@ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ + ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; -s/^\([^=]*=[ ]*\):*/\1/; +s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; -s/^[^=]*=[ ]*$//; +s/^[^=]*=[ ]*$//; }' fi @@ -1312,13 +1346,13 @@ fi cat >confdef2opt.sed <<\_ACEOF t clear : clear -s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote -s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote -s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g @@ -1340,7 +1374,7 @@ ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | - sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' @@ -1384,9 +1418,10 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi +DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. -if (FOO=FOO; unset FOO) >/dev/null 2>&1; then +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false @@ -1405,7 +1440,7 @@ for as_var in \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do - if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var @@ -1584,16 +1619,17 @@ rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else + test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. -as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS @@ -1620,7 +1656,7 @@ _ASBOX cat >&5 <<_CSEOF This file was extended by $as_me, which was -generated by GNU Autoconf 2.57. Invocation command line was +generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -1664,7 +1700,7 @@ Usage: $0 [OPTIONS] [FILE]... -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] - instantiate the configuration file FILE + instantiate the configuration file FILE Configuration files: $config_files @@ -1675,11 +1711,10 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.57, +configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" -Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 -Free Software Foundation, Inc. +Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir @@ -1899,9 +1934,9 @@ _ACEOF (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then - ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else - ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end @@ -1919,21 +1954,21 @@ for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin - cat >$tmp/stdin - ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` - ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } @@ -1949,10 +1984,10 @@ echo X"$ac_file" | as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| \ - . : '\(.\)' 2>/dev/null || + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } @@ -1990,12 +2025,45 @@ case $srcdir in ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac -# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be -# absolute. -ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` -ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` -ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` -ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac @@ -2013,7 +2081,7 @@ echo "$as_me: creating $ac_file" >&6;} configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | - sed 's,.*/,,'` by configure." + sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. @@ -2022,24 +2090,24 @@ echo "$as_me: creating $ac_file" >&6;} case $f in -) echo $tmp/stdin ;; [\\/$]*) - # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } - echo $f;; + echo "$f";; *) # Relative - if test -f "$f"; then - # Build tree - echo $f - elif test -f "$srcdir/$f"; then - # Source tree - echo $srcdir/$f - else - # /dev/null tree - { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } - fi;; + fi;; esac done` || { (exit 1); exit 1; } _ACEOF diff --git a/tools/genStubs.tcl b/tools/genStubs.tcl index 01ae467..464ba50 100644 --- a/tools/genStubs.tcl +++ b/tools/genStubs.tcl @@ -304,7 +304,7 @@ proc genStubs::addPlatformGuard {plat iftxt {eltxt {}}} { proc genStubs::emitSlots {name textVar} { upvar $textVar text - forAllStubs $name makeSlot 1 text {" void *reserved$i;\n"} + forAllStubs $name makeSlot 1 text {" VOID *reserved$i;\n"} return } diff --git a/tools/tclZIC.tcl b/tools/tclZIC.tcl index 6169696..1b19d82 100755 --- a/tools/tclZIC.tcl +++ b/tools/tclZIC.tcl @@ -394,6 +394,9 @@ proc parseON {on} { #---------------------------------------------------------------------- proc onDayOfMonth {day year month} { + scan $day %d day + scan $year %d year + scan $month %d month set date [::tcl::clock::GetJulianDayFromEraYearMonthDay \ [dict create era CE year $year month $month dayOfMonth $day] \ 2361222] diff --git a/unix/.cvsignore b/unix/.cvsignore deleted file mode 100644 index ed12ed2..0000000 --- a/unix/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -autom4te.cache -config.status -Makefile -*.exe -*.sh -*.dll -*.a diff --git a/unix/Makefile.in b/unix/Makefile.in index 6f193f1..782a89b 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -944,11 +944,8 @@ regerror.o: $(REGHDRS) $(GENERIC_DIR)/regerrs.h $(GENERIC_DIR)/regerror.c tclAppInit.o: $(UNIX_DIR)/tclAppInit.c $(CC) -c $(APP_CC_SWITCHES) $(UNIX_DIR)/tclAppInit.c -# On Unix we want to use the normal malloc/free implementation, so we -# specifically set the USE_TCLALLOC flag. - tclAlloc.o: $(GENERIC_DIR)/tclAlloc.c - $(CC) -c $(CC_SWITCHES) -DUSE_TCLALLOC=0 $(GENERIC_DIR)/tclAlloc.c + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAlloc.c tclAsync.o: $(GENERIC_DIR)/tclAsync.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAsync.c diff --git a/unix/README b/unix/README index 96be762..87b151a 100644 --- a/unix/README +++ b/unix/README @@ -166,8 +166,3 @@ a test is failing consistently, please send us a bug report with as much detail as you can manage. Please use the online database at http://tcl.sourceforge.net/ -The Tcl test suite is very sensitive to proper implementation of ANSI C -library procedures such as sprintf and sscanf. If the test suite generates -errors, most likely they are due to non-conformance of your system's ANSI C -library; such problems are unlikely to affect any real applications so it's -probably safe to ignore them. diff --git a/unix/configure b/unix/configure index 8fbaebc..af64e51 100755 --- a/unix/configure +++ b/unix/configure @@ -6630,6 +6630,8 @@ fi # Step 3: set configuration options based on system name and version. do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] @@ -6754,9 +6756,6 @@ fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" @@ -6831,7 +6830,6 @@ fi BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -6913,7 +6911,6 @@ fi BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -6923,7 +6920,6 @@ fi BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -6934,7 +6930,6 @@ fi CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -6954,7 +6949,6 @@ fi Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" @@ -7126,7 +7120,6 @@ fi SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" - SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" @@ -7139,7 +7132,6 @@ fi if test "$GCC" = yes; then SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi @@ -7158,7 +7150,6 @@ fi # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' if test $doRpath = yes; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' @@ -7272,7 +7263,6 @@ fi IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7286,7 +7276,6 @@ fi IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7320,7 +7309,6 @@ fi IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7355,7 +7343,6 @@ fi ;; Linux*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" @@ -7462,7 +7449,6 @@ fi ;; GNU*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' @@ -7478,7 +7464,6 @@ fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' @@ -7516,7 +7501,6 @@ fi NetBSD-1.*|FreeBSD-[1-2].*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7578,11 +7562,11 @@ fi # Equivalent using configure option --disable-load # Step 4 will set the necessary variables DL_OBJS="" + SHLIB_LD_LIBS="" ;; *) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7661,7 +7645,6 @@ fi # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7695,7 +7678,6 @@ fi SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$@" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -7949,7 +7931,6 @@ echo "${ECHO_T}$tcl_cv_ld_single_module" >&6 fi - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" @@ -8239,6 +8220,7 @@ fi LD_SEARCH_FLAGS="" ;; OS/390-*) + SHLIB_LD_LIBS="" CFLAGS_OPTIMIZE="" # Optimizer is buggy cat >>confdefs.h <<\_ACEOF @@ -8289,7 +8271,6 @@ else fi - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -8411,11 +8392,6 @@ _ACEOF SHLIB_CFLAGS="-KPIC" - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -8704,11 +8680,6 @@ fi fi - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -18734,11 +18705,13 @@ cat >>conftest.$ac_ext <<_ACEOF int StackGrowsUp(int *parent) { int here; - return (&here < parent); + if (parent) + return (&here < parent); + else + return StackGrowsUp(&here); } int main (int argc, char *argv[]) { - int foo; - return StackGrowsUp(&foo); + return StackGrowsUp(0); } _ACEOF diff --git a/unix/configure.in b/unix/configure.in index 87731a1..473758d 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -705,11 +705,13 @@ AC_CACHE_CHECK([if the C stack grows upwards in memory], tcl_cv_stack_grows_up, AC_TRY_RUN([ int StackGrowsUp(int *parent) { int here; - return (&here < parent); + if (parent) + return (&here < parent); + else + return StackGrowsUp(&here); } int main (int argc, char *argv[]) { - int foo; - return StackGrowsUp(&foo); + return StackGrowsUp(0); } ], tcl_cv_stack_grows_up=yes, tcl_cv_stack_grows_up=no, tcl_cv_stack_grows_up=unknown)]) diff --git a/unix/dltest/.cvsignore b/unix/dltest/.cvsignore deleted file mode 100644 index 1c62620..0000000 --- a/unix/dltest/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -*.dylib -*.bundle -Makefile -*.dll -*.so diff --git a/unix/ldAix b/unix/ldAix index cf37d40..51b2995 100644 --- a/unix/ldAix +++ b/unix/ldAix @@ -1,5 +1,5 @@ #!/bin/sh -# +# # ldAix ldCmd ldArg ldArg ... # # This shell script provides a wrapper for ld under AIX in order to diff --git a/unix/tcl.m4 b/unix/tcl.m4 index 2f2f317..78eacd9 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -120,8 +120,7 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" - AC_MSG_WARN([Can't find Tcl configuration definitions]) - exit 0 + AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" @@ -251,8 +250,7 @@ AC_DEFUN([SC_PATH_TKCONFIG], [ if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" - AC_MSG_WARN([Can't find Tk configuration definitions]) - exit 0 + AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" @@ -307,7 +305,7 @@ AC_DEFUN([SC_LOAD_TCLCONFIG], [ elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works - # against Tcl.framework installed in an arbitary location. + # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then @@ -390,7 +388,7 @@ AC_DEFUN([SC_LOAD_TKCONFIG], [ elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works - # against Tk.framework installed in an arbitary location. + # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then @@ -1120,6 +1118,8 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ # Step 3: set configuration options based on system name and version. do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] @@ -1157,9 +1157,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" @@ -1210,7 +1207,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -1225,7 +1221,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -1235,7 +1230,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -1246,7 +1240,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -1266,7 +1259,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" @@ -1288,7 +1280,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" - SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" @@ -1298,7 +1289,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) @@ -1313,7 +1303,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' - SHLIB_LD_LIBS='${LIBS}' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} @@ -1345,7 +1334,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1356,7 +1344,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1382,7 +1369,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1405,7 +1391,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ;; Linux*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" @@ -1444,7 +1429,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ;; GNU*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' @@ -1457,7 +1441,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ;; Lynx*) SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' @@ -1492,7 +1475,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ NetBSD-1.*|FreeBSD-[[1-2]].*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1523,11 +1505,11 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ # Equivalent using configure option --disable-load # Step 4 will set the necessary variables DL_OBJS="" + SHLIB_LD_LIBS="" ;; *) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1572,7 +1554,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1600,7 +1581,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$[@]" - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1675,7 +1655,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" @@ -1769,6 +1748,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ LD_SEARCH_FLAGS="" ;; OS/390-*) + SHLIB_LD_LIBS="" CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) @@ -1806,7 +1786,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" @@ -1900,11 +1879,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -1994,11 +1968,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ use_sunmath=no ]) ]) - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" @@ -2398,7 +2367,7 @@ closedir(d); # # Results: # -# Sets the the following vars: +# Sets the following vars: # XINCLUDES # XLIBSW # diff --git a/unix/tclLoadDl.c b/unix/tclLoadDl.c index e9ff134..e38c280 100644 --- a/unix/tclLoadDl.c +++ b/unix/tclLoadDl.c @@ -19,17 +19,17 @@ /* * In some systems, like SunOS 4.1.3, the RTLD_NOW flag isn't defined and this - * argument to dlopen must always be 1. The RTLD_GLOBAL flag is needed on some - * systems (e.g. SCO and UnixWare) but doesn't exist on others; if it doesn't - * exist, set it to 0 so it has no effect. + * argument to dlopen must always be 1. The RTLD_LOCAL flag doesn't exist on + * some platforms; if it doesn't exist, set it to 0 so it has no effect. + * See [Bug #3216070] */ #ifndef RTLD_NOW # define RTLD_NOW 1 #endif -#ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 +#ifndef RTLD_LOCAL +# define RTLD_LOCAL 0 #endif /* @@ -73,7 +73,10 @@ TclpDlopen( */ native = Tcl_FSGetNativePath(pathPtr); - handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL); + /* + * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + */ + handle = dlopen(native, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { /* * Let the OS loader examine the binary search path for whatever @@ -85,7 +88,10 @@ TclpDlopen( char *fileName = Tcl_GetString(pathPtr); native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); - handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL); + /* + * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + */ + handle = dlopen(native, RTLD_NOW | RTLD_LOCAL); Tcl_DStringFree(&ds); } diff --git a/unix/tclLoadDyld.c b/unix/tclLoadDyld.c index 08d651c..0a36215 100644 --- a/unix/tclLoadDyld.c +++ b/unix/tclLoadDyld.c @@ -196,7 +196,10 @@ TclpDlopen( if (tclMacOSXDarwinRelease >= 8) #endif { - dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_GLOBAL); + /* + * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + */ + dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL); if (!dlHandle) { /* * Let the OS loader examine the binary search path for whatever @@ -206,7 +209,10 @@ TclpDlopen( fileName = Tcl_GetString(pathPtr); nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); - dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_GLOBAL); + /* + * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + */ + dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL); } if (dlHandle) { TclLoadDbgMsg("dlopen() successful"); diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 625b864..2639d59 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -82,7 +82,7 @@ TclpFindExecutable( */ while (1) { - while (isspace(UCHAR(*p))) { /* INTL: BUG */ + while (TclIsSpaceProc(*p)) { p++; } name = p; diff --git a/unix/tclUnixInit.c b/unix/tclUnixInit.c index a798ccb..5111746 100644 --- a/unix/tclUnixInit.c +++ b/unix/tclUnixInit.c @@ -1092,9 +1092,19 @@ TclpGetCStackParams( if (stackGrowsDown) { tsdPtr->stackBound = (int *) ((char *)tsdPtr->outerVarPtr - stackSize); + if (tsdPtr->stackBound > tsdPtr->outerVarPtr) { + /* Overflow, that should never happen, just set it to NULL. + * See [Bug #3166410] */ + tsdPtr->stackBound = NULL; + } } else { tsdPtr->stackBound = (int *) ((char *)tsdPtr->outerVarPtr + stackSize); + if (tsdPtr->stackBound < tsdPtr->outerVarPtr) { + /* Overflow, that should never happen, just set it to NULL. + * See [Bug #3166410] */ + tsdPtr->stackBound = NULL; + } } } diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index bc80e00..fd2cd8f 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -724,7 +724,7 @@ TclpFinalizeCondition( /* *---------------------------------------------------------------------- * - * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa -- + * TclpReaddir, TclpInetNtoa -- * * These procedures replace core C versions to be used in a threaded * environment. diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index cf730a2..b98f2e1 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -62,7 +62,7 @@ Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime; ClientData tclTimeClientData = NULL; /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TclpGetSeconds -- * @@ -75,7 +75,7 @@ ClientData tclTimeClientData = NULL; * Side effects: * None. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ unsigned long @@ -85,7 +85,7 @@ TclpGetSeconds(void) } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- * * TclpGetClicks -- * @@ -100,7 +100,7 @@ TclpGetSeconds(void) * Side effects: * None. * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ unsigned long @@ -431,17 +431,6 @@ TclpGmtime( return &(tsdPtr->gmtime_buf); } - -/* - * Forwarder for obsolete item in Stubs - */ - -struct tm * -TclpGmtime_unix( - CONST time_t *timePtr) -{ - return TclpGmtime(timePtr); -} /* *---------------------------------------------------------------------- @@ -482,15 +471,6 @@ TclpLocaltime( return &(tsdPtr->localtime_buf); } -/* - * Forwarder for obsolete item in Stubs - */ -struct tm* -TclpLocaltime_unix( - CONST time_t *timePtr) -{ - return TclpLocaltime(timePtr); -} /* *---------------------------------------------------------------------- diff --git a/win/.cvsignore b/win/.cvsignore deleted file mode 100644 index 04c3b08..0000000 --- a/win/.cvsignore +++ /dev/null @@ -1,27 +0,0 @@ -Debug -Release -*.opt -*.ncb -*.plg -*.00? -*.o -*.obj -*.i -*.asm -*.dll -*.exe -Makefile -tcl.hpj -tclConfig.sh -.#* -tcl.sln -tcl.suo -autom4te.cache -config.status -*.a -*.lib -*.exp -*.res -*.pch -*.x -*.vc diff --git a/win/README b/win/README index ccd1e7d..1929362 100644 --- a/win/README +++ b/win/README @@ -11,9 +11,6 @@ The information in this file is maintained on the web at: http://www.tcl.tk/doc/howto/compile.html#win -The above URL includes a lengthy discussion of compiler macros necessary -when compiling Tcl extensions that will be dynamically loaded. - 2. Compiling Tcl ---------------- diff --git a/win/configure b/win/configure index 099c1cb..c397e45 100755 --- a/win/configure +++ b/win/configure @@ -3550,6 +3550,75 @@ _ACEOF fi +# Check to see if struct _stat32i64 exists in mingw's sys/stat.h + +echo "$as_me:$LINENO: checking struct _stat32i64" >&5 +echo $ECHO_N "checking struct _stat32i64... $ECHO_C" >&6 +if test "${tcl_struct_stat32i64+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + + struct _stat32i64 foo; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + tcl_struct_stat32i64=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +tcl_struct_stat32i64=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $tcl_struct_stat32i64" >&5 +echo "${ECHO_T}$tcl_struct_stat32i64" >&6 +if test "$tcl_struct_stat32i64" = "yes" ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STRUCT_STAT32I64 1 +_ACEOF + +fi + # See if declarations like FINDEX_INFO_LEVELS are # missing from winbase.h. This is known to be @@ -4408,7 +4477,7 @@ _ACEOF EXTRA_CFLAGS="" CFLAGS_WARNING="-W3" - LDFLAGS_DEBUG="-debug:full" + LDFLAGS_DEBUG="-debug" LDFLAGS_OPTIMIZE="-release" # Specify the CC output file names based on the target name diff --git a/win/configure.in b/win/configure.in index bbd4cd5..c589018 100644 --- a/win/configure.in +++ b/win/configure.in @@ -241,6 +241,25 @@ if test "$tcl_cv_cast_to_union" = "yes"; then [Defined when compiler supports casting to union type.]) fi +# Check to see if struct _stat32i64 exists in mingw's sys/stat.h + +AC_CACHE_CHECK(struct _stat32i64, + tcl_struct_stat32i64, +AC_TRY_COMPILE([ +#include +#include +], +[ + struct _stat32i64 foo; +], + tcl_struct_stat32i64=yes, + tcl_struct_stat32i64=no) +) +if test "$tcl_struct_stat32i64" = "yes" ; then + AC_DEFINE(HAVE_STRUCT_STAT32I64, 1, + [Defined when sys/stat.h has struct_stat32i64]) +fi + # See if declarations like FINDEX_INFO_LEVELS are # missing from winbase.h. This is known to be diff --git a/win/makefile.vc b/win/makefile.vc index e38abe5..7dc96b7 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -208,6 +208,15 @@ TCLDDELIB = $(OUT_DIR)\$(TCLDDELIBNAME) TCLTEST = $(OUT_DIR)\$(PROJECT)test.exe CAT32 = $(OUT_DIR)\cat32.exe +# Can we run what we build? IX86 runs on all architectures. +!ifndef TCLSH_NATIVE +!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" +TCLSH_NATIVE = $(TCLSH) +!else +!error You must explicitly set TCLSH_NATIVE for cross-compilation +!endif +!endif + ### Make sure we use backslash only. LIB_INSTALL_DIR = $(_INSTALLDIR)\lib BIN_INSTALL_DIR = $(_INSTALLDIR)\bin @@ -452,11 +461,11 @@ STUB_CFLAGS = $(cflags) $(cdebug:-GL=) $(OPTDEFINES) #--------------------------------------------------------------------- !if $(DEBUG) -ldebug = -debug:full -debugtype:cv +ldebug = -debug -debugtype:cv !else ldebug = -release -opt:ref -opt:icf,3 !if $(SYMBOLS) -ldebug = $(ldebug) -debug:full -debugtype:cv +ldebug = $(ldebug) -debug -debugtype:cv !endif !endif @@ -715,7 +724,7 @@ $(OUT_DIR)\tclConfig.sh: $(WINDIR)\tclConfig.sh.in @DEFS@ $(TCL_CFLAGS) @CFLAGS_DEBUG@ -nologo -c -W3 -YX -Fp$(TMP_DIR)\ -MDd @CFLAGS_OPTIMIZE@ -nologo -c -W3 -YX -Fp$(TMP_DIR)\ -MD -@LDFLAGS_DEBUG@ -nologo -machine:$(MACHINE) -debug:full -debugtype:cv +@LDFLAGS_DEBUG@ -nologo -machine:$(MACHINE) -debug -debugtype:cv @LDFLAGS_OPTIMIZE@ -nologo -machine:$(MACHINE) -release -opt:ref -opt:icf,3 @TCL_DBGX@ $(SUFX) @TCL_LIB_FILE@ $(PROJECT)$(VERSION)$(SUFX).lib @@ -1015,13 +1024,13 @@ install-libraries: tclConfig install-msgs install-tzdata install-tzdata: @echo Installing time zone data @set TCL_LIBRARY=$(ROOT)/library - @$(TCLSH) "$(ROOT)/tools/installData.tcl" \ + @$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \ "$(ROOT)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata" install-msgs: @echo Installing message catalogs @set TCL_LIBRARY=$(ROOT)/library - @$(TCLSH) "$(ROOT)/tools/installData.tcl" \ + @$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \ "$(ROOT)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs" #--------------------------------------------------------------------- diff --git a/win/rules.vc b/win/rules.vc index 865b10d..e18dca9 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -27,18 +27,6 @@ _INSTALLDIR = C:\Program Files\Tcl _INSTALLDIR = $(INSTALLDIR:/=\) !endif -!ifndef MACHINE -!if "$(CPU)" == "" || "$(CPU)" == "i386" -MACHINE = IX86 -!else -MACHINE = $(CPU) -!endif -!endif - -!ifndef CFG_ENCODING -CFG_ENCODING = \"cp1252\" -!endif - #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right @@ -64,6 +52,50 @@ ERRNULL = >NUL # Win9x shell cannot redirect stderr !endif MKDIR = mkdir +#------------------------------------------------------------------------------ +# Determine the host and target architectures and compiler version. +#------------------------------------------------------------------------------ + +_HASH=^# +_VC_MANIFEST_EMBED_EXE= +_VC_MANIFEST_EMBED_DLL= +VCVER=0 +!if ![echo VCVERSION=_MSC_VER > vercl.x] \ + && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ + && ![echo ARCH=IX86 >> vercl.x] \ + && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ + && ![echo ARCH=AMD64 >> vercl.x] \ + && ![echo $(_HASH)endif >> vercl.x] \ + && ![cl -nologo -TC -P vercl.x $(ERRNULL)] +!include vercl.i +!if ![echo VCVER= ^\> vercl.vc] \ + && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] +!include vercl.vc +!endif +!endif +!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc] +!endif + +!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] +NATIVE_ARCH=IX86 +!else +NATIVE_ARCH=AMD64 +!endif + +# Since MSVC8 we must deal with manifest resources. +!if $(VCVERSION) >= 1400 +_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 +_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 +!endif + +!ifndef MACHINE +MACHINE=$(ARCH) +!endif + +!ifndef CFG_ENCODING +CFG_ENCODING = \"cp1252\" +!endif + !message =============================================================================== #---------------------------------------------------------- @@ -176,36 +208,6 @@ LINKERFLAGS =-ltcg !endif #---------------------------------------------------------- -# MSVC8 (ships with Visual Studio 2005) generates a manifest -# file that we should link into the binaries. This is how. -#---------------------------------------------------------- - -_VC_MANIFEST_EMBED_EXE= -_VC_MANIFEST_EMBED_DLL= -VCVER=0 -!if ![echo VCVERSION=_MSC_VER > vercl.x] \ - && ![cl -nologo -TC -P vercl.x $(ERRNULL)] -!include vercl.i -!if $(VCVERSION) >= 1600 -VCVER=10 -!elseif $(VCVERSION) >= 1500 -VCVER=9 -!elseif $(VCVERSION) >= 1400 -VCVER=8 -!elseif $(VCVERSION) >= 1300 -VCVER=7 -!elseif $(VCVERSION) >= 1200 -VCVER=6 -!endif -!endif - -# Since MSVC8 we must deal with manifest resources. -!if $(VCVERSION) >= 1400 -_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 -_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 -!endif - -#---------------------------------------------------------- # Decode the options requested. #---------------------------------------------------------- @@ -667,6 +669,7 @@ TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" !message *** Suffix for binaries will be '$(SUFX)' !message *** Optional defines are '$(OPTDEFINES)' !message *** Compiler version $(VCVER). Target machine is $(MACHINE) +!message *** Host architecture is $(NATIVE_ARCH) !message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)' !message *** Link options '$(LINKERFLAGS)' diff --git a/win/tcl.m4 b/win/tcl.m4 index feb3d0c..be22fac 100644 --- a/win/tcl.m4 +++ b/win/tcl.m4 @@ -755,7 +755,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ EXTRA_CFLAGS="" CFLAGS_WARNING="-W3" - LDFLAGS_DEBUG="-debug:full" + LDFLAGS_DEBUG="-debug" LDFLAGS_OPTIMIZE="-release" # Specify the CC output file names based on the target name diff --git a/win/tclWinFile.c b/win/tclWinFile.c index aa43495..0291a41 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -12,8 +12,9 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -/* #define _WIN32_WINNT 0x0500 */ - +#ifndef _WIN64 +# define _USE_32BIT_TIME_T +#endif #include "tclWinInt.h" #include "tclFileSystem.h" #include diff --git a/win/tclWinPort.h b/win/tclWinPort.h index 55b95c1..8fdf391 100644 --- a/win/tclWinPort.h +++ b/win/tclWinPort.h @@ -105,6 +105,31 @@ #endif /* + * Not all mingw32 versions have this struct. + */ +#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(_WIN64) && !defined(HAVE_STRUCT_STAT32I64) + struct _stat32i64 { + dev_t st_dev; + ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + dev_t st_rdev; + __int64 st_size; +#ifdef __CYGWIN__ + struct {long tv_sec;} st_atim; + struct {long tv_sec;} st_mtim; + struct {long tv_sec;} st_ctim; +#else + long st_atime; + long st_mtime; + long st_ctime; +#endif + }; +#endif + +/* * The following defines redefine the Windows Socket errors as * BSD errors so Tcl_PosixError can do the right thing. */ -- cgit v0.12