diff options
Diffstat (limited to 'generic/tclStringObj.c')
-rw-r--r-- | generic/tclStringObj.c | 127 |
1 files changed, 89 insertions, 38 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index d5dedc2..74b6f83 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -33,9 +33,10 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStringObj.c,v 1.48 2005/09/15 16:58:24 dgp Exp $ */ + * RCS: @(#) $Id: tclStringObj.c,v 1.49 2005/10/08 14:42:45 dgp Exp $ */ #include "tclInt.h" +#include "tommath.h" /* * Prototypes for functions defined later in this file: @@ -386,6 +387,8 @@ Tcl_GetCharLength(objPtr) * string to count continuous ascii characters before resorting to the * Tcl_NumUtfChars call. This is a long form of: stringPtr->numChars = Tcl_NumUtfChars(objPtr->bytes,objPtr->length); + * + * TODO: Consider macro-izing this. */ while (i && (*str < 0xC0)) { @@ -1722,7 +1725,7 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) while (*format != '\0') { char *end; int gotMinus, gotHash, gotZero, gotSpace, gotPlus, sawFlag; - int width, gotPrecision, precision, useShort, useWide; + int width, gotPrecision, precision, useShort, useWide, useBig; int newXpg, numChars, allocSegment = 0; Tcl_Obj *segment; Tcl_UniChar ch; @@ -1865,17 +1868,23 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) /* 5. Length modifier */ - useShort = useWide = 0; + useShort = useWide = useBig = 0; if (ch == 'h') { useShort = 1; format += step; step = Tcl_UtfToUniChar(format, &ch); } else if (ch == 'l') { + format += step; + step = Tcl_UtfToUniChar(format, &ch); + if (ch == 'l') { + useBig = 1; + format += step; + step = Tcl_UtfToUniChar(format, &ch); + } else { #ifndef TCL_WIDE_INT_IS_LONG useWide = 1; #endif - format += step; - step = Tcl_UtfToUniChar(format, &ch); + } } format += step; @@ -1913,6 +1922,10 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) } case 'u': + if (useBig) { + msg = "unsigned bignum format is invalid"; + goto errorMsg; + } case 'd': case 'o': case 'x': @@ -1920,26 +1933,54 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) short int s; long l; Tcl_WideInt w; + mp_int big; int isNegative = 0; - if (useWide) { - if (Tcl_GetWideIntFromObj(interp, segment, &w) != TCL_OK) { - goto error; - } - } else if (Tcl_GetLongFromObj(NULL, segment, &l) != TCL_OK) { - if (Tcl_GetWideIntFromObj(interp, segment, &w) != TCL_OK) { + if (useBig) { + if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) { goto error; } - l = Tcl_WideAsLong(w); - } - - if (useShort) { - s = (short int) l; - isNegative = (s < (short int)0); + isNegative = (mp_cmp_d(&big, 0) == MP_LT); } else if (useWide) { + if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { + Tcl_Obj *objPtr; + if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) { + goto error; + } + mp_mod_2d(&big, (int) CHAR_BIT * sizeof(Tcl_WideInt), &big); + objPtr = Tcl_NewBignumObj(&big); + Tcl_IncrRefCount(objPtr); + Tcl_GetWideIntFromObj(NULL, objPtr, &w); + Tcl_DecrRefCount(objPtr); + } isNegative = (w < (Tcl_WideInt)0); + } else if (Tcl_GetLongFromObj(NULL, segment, &l) != TCL_OK) { + if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { + Tcl_Obj *objPtr; + if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) { + goto error; + } + mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big); + objPtr = Tcl_NewBignumObj(&big); + Tcl_IncrRefCount(objPtr); + Tcl_GetLongFromObj(NULL, objPtr, &l); + Tcl_DecrRefCount(objPtr); + } else { + l = Tcl_WideAsLong(w); + } + if (useShort) { + s = (short int) l; + isNegative = (s < (short int)0); + } else { + isNegative = (l < (long)0); + } } else { - isNegative = (l < (long)0); + if (useShort) { + s = (short int) l; + isNegative = (s < (short int)0); + } else { + isNegative = (l < (long)0); + } } segment = Tcl_NewObj(); @@ -1947,7 +1988,7 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) Tcl_IncrRefCount(segment); if (isNegative || gotPlus) { - if (ch == 'd') { + if (useBig || (ch == 'd')) { if (isNegative) { Tcl_AppendToObj(segment, "-", 1); } else { @@ -1975,26 +2016,18 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) Tcl_Obj *pure; CONST char *bytes; - if (isNegative) { - if (useShort) { - pure = Tcl_NewIntObj((int)(-s)); - } else if (useWide) { - pure = Tcl_NewWideIntObj(-w); - } else { - pure = Tcl_NewLongObj(-l); - } + if (useShort) { + pure = Tcl_NewIntObj((int)(s)); + } else if (useWide) { + pure = Tcl_NewWideIntObj(w); + } else if (useBig) { + pure = Tcl_NewBignumObj(&big); } else { - if (useShort) { - pure = Tcl_NewIntObj((int)(s)); - } else if (useWide) { - pure = Tcl_NewWideIntObj(w); - } else { - pure = Tcl_NewLongObj(l); - } + pure = Tcl_NewLongObj(l); } Tcl_IncrRefCount(pure); bytes = Tcl_GetStringFromObj(pure, &length); - /* Handle things like -INT_MIN == INT_MIN */ + /* Already did the sign above */ if (*bytes == '-') { length--; bytes++; } @@ -2024,8 +2057,9 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) case 'o': case 'x': case 'X': { - Tcl_WideUInt bits; - int length, numDigits = 0, base = 16; + Tcl_WideUInt bits = (Tcl_WideUInt)0; + int length, numBits = 4, numDigits = 0, base = 16; + int index = 0, shift = 0; Tcl_Obj *pure; char *bytes; @@ -2034,6 +2068,7 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) } if (ch == 'o') { base = 8; + numBits = 3; } if (useShort) { unsigned short int us = (unsigned short int) s; @@ -2049,6 +2084,14 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) numDigits++; uw /= base; } + } else if (useBig) { + int leftover = (big.used * DIGIT_BIT) % numBits; + mp_digit mask = (~(mp_digit)0) << (DIGIT_BIT-leftover); + numDigits = 1 + ((big.used * DIGIT_BIT) / numBits); + while ((mask & big.dp[big.used-1]) == 0) { + numDigits--; + mask >>= numBits; + } } else { unsigned long int ul = (unsigned long int) l; bits = (Tcl_WideUInt) ul; @@ -2066,7 +2109,15 @@ TclAppendFormattedObjs(interp, appendObj, format, objc, objv) bytes = Tcl_GetString(pure); length = numDigits; while (numDigits--) { - int digitOffset = (int) (bits % base); + int digitOffset; + if (useBig) { + if (shift<CHAR_BIT*sizeof(Tcl_WideUInt)-DIGIT_BIT) { + bits |= (((Tcl_WideUInt)big.dp[index++]) << shift); + shift += DIGIT_BIT; + } + shift -= numBits; + } + digitOffset = (int) (bits % base); if (digitOffset > 9) { bytes[numDigits] = 'a' + digitOffset - 10; } else { |