From 00c0664fd2487670b9bf12e3c2ba32fa4a5ea944 Mon Sep 17 00:00:00 2001 From: dkf Date: Sat, 25 Nov 2006 17:18:09 +0000 Subject: Finished coding part of TIP#174. Still have tests and docs to do. --- ChangeLog | 8 + generic/tclCompCmds.c | 1544 ++------------------------ generic/tclMathOp.c | 2870 +++++++++++++++++++++++++++++++++++++++++++++++++ unix/Makefile.in | 347 +++--- win/Makefile.in | 120 +-- win/makefile.bc | 1 + win/makefile.vc | 3 +- 7 files changed, 3191 insertions(+), 1702 deletions(-) create mode 100644 generic/tclMathOp.c diff --git a/ChangeLog b/ChangeLog index 77ce434..a5cfee4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-11-25 Donal K. Fellows + + TIP#269 IMPLEMENTATION + + * generic/tclMathOp.c (new file): Completed the implementation of the + interpreted versions of all the tcl::mathop commands. Moved to a new + file to make tclCompCmds.c more focussed in purpose. + 2006-11-23 Donal K. Fellows * generic/tclCompCmds.c (Tcl*OpCmd, TclCompile*OpCmd): diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 152597b..aa522c0 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -1,27 +1,23 @@ /* * tclCompCmds.c -- * - * This file contains compilation procedures that compile various - * Tcl commands into a sequence of instructions ("bytecodes"). + * This file contains compilation procedures that compile various Tcl + * commands into a sequence of instructions ("bytecodes"). * * Copyright (c) 1997-1998 Sun Microsystems, Inc. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2002 ActiveState Corporation. - * Copyright (c) 2004-2005 by Donal K. Fellows. + * Copyright (c) 2004-2006 by Donal K. Fellows. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompCmds.c,v 1.91 2006/11/24 15:34:23 dkf Exp $ + * RCS: @(#) $Id: tclCompCmds.c,v 1.92 2006/11/25 17:18:09 dkf Exp $ */ #include "tclInt.h" #include "tclCompile.h" -#include "tommath.h" -#include -#include - /* * Macro that encapsulates an efficiency trick that avoids a function call for * the simplest of compiles. The ANSI C "prototype" for this macro is: @@ -126,8 +122,6 @@ static int PushVarName(Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr); -static int CompareNumbers(Tcl_Interp *interp, Tcl_Obj *numObj1, - Tcl_Obj *numObj2, int *resultPtr); /* * Flags bits used by PushVarName. @@ -4449,59 +4443,23 @@ PushVarName( return TCL_OK; } -int -TclInvertOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - ClientData val; - int type; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "number"); - return TCL_ERROR; - } - if (TclGetNumberFromObj(interp, objv[1], &val, &type) != TCL_OK) { - return TCL_ERROR; - } - switch (type) { - case TCL_NUMBER_LONG: { - long l = *((const long *) val); - - Tcl_SetLongObj(Tcl_GetObjResult(interp), ~l); - return TCL_OK; - } -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: { - Tcl_WideInt w = *((const Tcl_WideInt *) val); - - Tcl_SetWideIntObj(Tcl_GetObjResult(interp), ~w); - return TCL_OK; - } -#endif - default: { - mp_int big; - - if (Tcl_IsShared(objv[1])) { - Tcl_GetBignumFromObj(NULL, objv[1], &big); - } else { - Tcl_GetBignumAndClearObj(NULL, objv[1], &big); - } - /* ~a = - a - 1 */ - mp_neg(&big, &big); - mp_sub_d(&big, 1, &big); - if (Tcl_IsShared(objv[1])) { - Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big)); - } else { - Tcl_SetBignumObj(objv[1], &big); - Tcl_SetObjResult(interp, objv[1]); - } - return TCL_OK; - } - } -} +/* + *---------------------------------------------------------------------- + * + * TclCompileInvertOpCmd -- + * + * Procedure called to compile the "::tcl::mathop::~" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "::tcl::mathop::~" + * command at runtime. + * + *---------------------------------------------------------------------- + */ int TclCompileInvertOpCmd( @@ -4521,26 +4479,6 @@ TclCompileInvertOpCmd( } int -TclNotOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - int b; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "boolean"); - return TCL_ERROR; - } - if (Tcl_GetBooleanFromObj(interp, objv[1], &b) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), !b); - return TCL_OK; -} - -int TclCompileNotOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4558,17 +4496,6 @@ TclCompileNotOpCmd( } int -TclAddOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileAddOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4592,17 +4519,6 @@ TclCompileAddOpCmd( } int -TclMulOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileMulOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4626,17 +4542,6 @@ TclCompileMulOpCmd( } int -TclAndOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileAndOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4660,17 +4565,6 @@ TclCompileAndOpCmd( } int -TclOrOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileOrOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4694,17 +4588,6 @@ TclCompileOrOpCmd( } int -TclXorOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileXorOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4728,17 +4611,6 @@ TclCompileXorOpCmd( } int -TclPowOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompilePowOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4764,22 +4636,6 @@ TclCompilePowOpCmd( } int -TclMinusOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "value ?value ...?"); - return TCL_ERROR; - } - - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileMinusOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4806,22 +4662,6 @@ TclCompileMinusOpCmd( } int -TclDivOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "value ?value ...?"); - return TCL_ERROR; - } - - Tcl_AppendResult(interp, "not yet implemented", NULL); - return TCL_ERROR; -} - -int TclCompileDivOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -4833,7 +4673,7 @@ TclCompileDivOpCmd( if (parsePtr->numWords == 1) { return TCL_ERROR; } else if (parsePtr->numWords == 2) { - PushLiteral(envPtr, "1", 1); + PushLiteral(envPtr, "1.0", 3); tokenPtr = TokenAfter(parsePtr->tokenPtr); CompileWord(envPtr, tokenPtr, interp); TclEmitOpcode(INST_DIV, envPtr); @@ -4850,143 +4690,45 @@ TclCompileDivOpCmd( } int -TclLshiftOpCmd( - ClientData clientData, +TclCompileLshiftOpCmd( Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) + Tcl_Parse *parsePtr, + CompileEnv *envPtr) { - ClientData ptr1, ptr2; - int invalid, shift, type1, type2, idx; - const char *description; - long l1; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value value"); - return TCL_ERROR; - } + Tcl_Token *tokenPtr; - if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) - || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) { - idx = 1; - goto illegalOperand; - } - if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK) - || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) { - idx = 2; - goto illegalOperand; - } - - /* reject negative shift argument */ - switch (type2) { - case TCL_NUMBER_LONG: - invalid = (*((const long *)ptr2) < (long)0); - break; -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: - invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0); - break; -#endif - case TCL_NUMBER_BIG: - /* TODO: const correctness ? */ - invalid = (mp_cmp_d((mp_int *)ptr2, 0) == MP_LT); - break; - default: - /* Unused, here to silence compiler warning */ - invalid = 0; - } - if (invalid) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("negative shift argument", -1)); + if (parsePtr->numWords != 3) { return TCL_ERROR; } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + TclEmitOpcode(INST_LSHIFT, envPtr); + return TCL_OK; +} + +int +TclCompileRshiftOpCmd( + Tcl_Interp *interp, + Tcl_Parse *parsePtr, + CompileEnv *envPtr) +{ + Tcl_Token *tokenPtr; - /* Zero shifted any number of bits is still zero */ - if ((type1 == TCL_NUMBER_LONG) && (*((const long *)ptr1) == (long)0)) { - Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); - return TCL_OK; - } - - /* Large left shifts create integer overflow */ - if (Tcl_GetIntFromObj(NULL, objv[2], &shift) != TCL_OK) { - /* - * Technically, we could hold the value (1 << (INT_MAX+1)) in an - * mp_int, but since we're using mp_mul_2d() to do the work, and it - * takes only an int argument, that's a good place to draw the line. - */ - - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "integer value too large to represent", -1)); + if (parsePtr->numWords != 3) { return TCL_ERROR; } - - /* Handle shifts within the native long range */ - if ((type1 == TCL_NUMBER_LONG) && ((size_t)shift < CHAR_BIT*sizeof(long)) - && (l1 = *((CONST long *)ptr1)) && - !(((l1>0) ? l1 : ~l1) & -(1L<<(CHAR_BIT*sizeof(long)-1-shift)))) { - Tcl_SetObjResult(interp, Tcl_NewLongObj(l1<0) ? w : ~w) & -(((Tcl_WideInt)1) - << (CHAR_BIT*sizeof(Tcl_WideInt)-1-shift)))) { - Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w<tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + TclEmitOpcode(INST_RSHIFT, envPtr); return TCL_OK; - - illegalOperand: - if (TclGetNumberFromObj(NULL, objv[idx], &ptr1, &type1) != TCL_OK) { - int numBytes; - const char *bytes = Tcl_GetStringFromObj(objv[idx], &numBytes); - if (numBytes == 0) { - description = "empty string"; - } else if (TclCheckBadOctal(NULL, bytes)) { - description = "invalid octal number"; - } else { - description = "non-numeric string"; - } - } else if (type1 == TCL_NUMBER_NAN) { - description = "non-numeric floating-point value"; - } else { - description = "floating-point value"; - } - - Tcl_SetObjResult(interp, - Tcl_ObjPrintf("can't use %s as operand of \"<<\"", description)); - return TCL_ERROR; } - + int -TclCompileLshiftOpCmd( +TclCompileModOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) @@ -5000,179 +4742,50 @@ TclCompileLshiftOpCmd( CompileWord(envPtr, tokenPtr, interp); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_LSHIFT, envPtr); + TclEmitOpcode(INST_MOD, envPtr); return TCL_OK; } int -TclRshiftOpCmd( - ClientData clientData, +TclCompileNeqOpCmd( Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) + Tcl_Parse *parsePtr, + CompileEnv *envPtr) { - ClientData ptr1, ptr2; - int invalid, shift, type1, type2, idx; - const char *description; - long l1; + Tcl_Token *tokenPtr; - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value value"); + if (parsePtr->numWords != 3) { return TCL_ERROR; } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + TclEmitOpcode(INST_NEQ, envPtr); + return TCL_OK; +} + +int +TclCompileStrneqOpCmd( + Tcl_Interp *interp, + Tcl_Parse *parsePtr, + CompileEnv *envPtr) +{ + Tcl_Token *tokenPtr; - if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) - || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) { - idx = 1; - goto illegalOperand; - } - if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK) - || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) { - idx = 2; - goto illegalOperand; - } - - /* reject negative shift argument */ - switch (type2) { - case TCL_NUMBER_LONG: - invalid = (*((const long *)ptr2) < (long)0); - break; -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: - invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0); - break; -#endif - case TCL_NUMBER_BIG: - /* TODO: const correctness ? */ - invalid = (mp_cmp_d((mp_int *)ptr2, 0) == MP_LT); - break; - default: - /* Unused, here to silence compiler warning */ - invalid = 0; - } - if (invalid) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("negative shift argument", -1)); + if (parsePtr->numWords != 3) { return TCL_ERROR; } - - /* Zero shifted any number of bits is still zero */ - if ((type1 == TCL_NUMBER_LONG) && (*((const long *)ptr1) == (long)0)) { - Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); - return TCL_OK; - } - - /* Quickly force large right shifts to 0 or -1 */ - if ((type2 != TCL_NUMBER_LONG) - || (*((const long *)ptr2) > INT_MAX)) { - /* - * Again, technically, the value to be shifted could be an mp_int so - * huge that a right shift by (INT_MAX+1) bits could not take us to - * the result of 0 or -1, but since we're using mp_div_2d to do the - * work, and it takes only an int argument, we draw the line there. - */ - - int zero; - - switch (type1) { - case TCL_NUMBER_LONG: - zero = (*((const long *)ptr1) > (long)0); - break; -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: - zero = (*((const Tcl_WideInt *)ptr1) > (Tcl_WideInt)0); - break; -#endif - case TCL_NUMBER_BIG: - /* TODO: const correctness ? */ - zero = (mp_cmp_d((mp_int *)ptr1, 0) == MP_GT); - break; - default: - /* Unused, here to silence compiler warning. */ - zero = 0; - } - Tcl_SetObjResult(interp, Tcl_NewIntObj(zero ? 0 : -1)); - return TCL_OK; - } - - shift = (int)(*((const long *)ptr2)); - /* Handle shifts within the native long range */ - if (type1 == TCL_NUMBER_LONG) { - l1 = *((const long *)ptr1); - if ((size_t)shift >= CHAR_BIT*sizeof(long)) { - Tcl_SetObjResult(interp, Tcl_NewIntObj(l1 >= (long)0 ? 0 : -1)); - } else { - Tcl_SetObjResult(interp, Tcl_NewIntObj(l1 >> shift)); - } - return TCL_OK; - } - -#ifndef NO_WIDE_TYPE - /* Handle shifts within the native wide range */ - if (type1 == TCL_NUMBER_WIDE) { - Tcl_WideInt w = *((const Tcl_WideInt *)ptr1); - if ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideInt)) { - Tcl_SetObjResult(interp, - Tcl_NewIntObj(w >= (Tcl_WideInt)0 ? 0 : -1)); - } else { - Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w >> shift)); - } - return TCL_OK; - } -#endif - - { - mp_int big, bigResult, bigRemainder; - - if (Tcl_IsShared(objv[1])) { - Tcl_GetBignumFromObj(NULL, objv[1], &big); - } else { - Tcl_GetBignumAndClearObj(NULL, objv[1], &big); - } - - mp_init(&bigResult); - mp_init(&bigRemainder); - mp_div_2d(&big, shift, &bigResult, &bigRemainder); - if (mp_cmp_d(&bigRemainder, 0) == MP_LT) { - /* Convert to Tcl's integer division rules */ - mp_sub_d(&bigResult, 1, &bigResult); - } - mp_clear(&bigRemainder); - mp_clear(&big); - - if (!Tcl_IsShared(objv[1])) { - Tcl_SetBignumObj(objv[1], &bigResult); - Tcl_SetObjResult(interp, objv[1]); - } else { - Tcl_SetObjResult(interp, Tcl_NewBignumObj(&bigResult)); - } - } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp); + TclEmitOpcode(INST_STR_NEQ, envPtr); return TCL_OK; - - illegalOperand: - if (TclGetNumberFromObj(NULL, objv[idx], &ptr1, &type1) != TCL_OK) { - int numBytes; - const char *bytes = Tcl_GetStringFromObj(objv[idx], &numBytes); - if (numBytes == 0) { - description = "empty string"; - } else if (TclCheckBadOctal(NULL, bytes)) { - description = "invalid octal number"; - } else { - description = "non-numeric string"; - } - } else if (type1 == TCL_NUMBER_NAN) { - description = "non-numeric floating-point value"; - } else { - description = "floating-point value"; - } - - Tcl_SetObjResult(interp, - Tcl_ObjPrintf("can't use %s as operand of \">>\"", description)); - return TCL_ERROR; } - + int -TclCompileRshiftOpCmd( +TclCompileInOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) @@ -5186,419 +4799,20 @@ TclCompileRshiftOpCmd( CompileWord(envPtr, tokenPtr, interp); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_RSHIFT, envPtr); + TclEmitOpcode(INST_LIST_IN, envPtr); return TCL_OK; } int -TclModOpCmd( - ClientData clientData, +TclCompileNiOpCmd( Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) + Tcl_Parse *parsePtr, + CompileEnv *envPtr) { - Tcl_Obj *argObj; - ClientData ptr1, ptr2; - int type1, type2; - long l1, l2 = 0; - const char *description; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value value"); - return TCL_ERROR; - } + Tcl_Token *tokenPtr; - if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) - || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) { - argObj = objv[1]; - goto badArg; - } - if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK) - || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) { - argObj = objv[2]; - goto badArg; - } - - if (type2 == TCL_NUMBER_LONG) { - l2 = *((CONST long *)ptr2); - if (l2 == 0) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1)); - Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", - NULL); - return TCL_ERROR; - } - if ((l2 == 1) || (l2 == -1)) { - Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); - return TCL_OK; - } - } - if (type1 == TCL_NUMBER_LONG) { - l1 = *((CONST long *)ptr1); - if (l1 == 0) { - Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); - return TCL_OK; - } - if (type2 == TCL_NUMBER_LONG) { - /* Both operands are long; do native calculation */ - long lRemainder, lQuotient = l1 / l2; - - /* Force Tcl's integer division rules */ - /* TODO: examine for logic simplification */ - if (((lQuotient < 0) || ((lQuotient == 0) && - ((l1 < 0 && l2 > 0) || (l1 > 0 && l2 < 0)))) && - ((lQuotient * l2) != l1)) { - lQuotient -= 1; - } - lRemainder = l1 - l2*lQuotient; - Tcl_SetLongObj(Tcl_GetObjResult(interp), lRemainder); - return TCL_OK; - } - /* - * First operand fits in long; second does not, so the second has - * greater magnitude than first. No need to divide to determine the - * remainder. - */ -#ifndef NO_WIDE_TYPE - if (type2 == TCL_NUMBER_WIDE) { - Tcl_WideInt w2 = *((CONST Tcl_WideInt *)ptr2); - - if ((l1 > 0) ^ (w2 > (Tcl_WideInt)0)) { - /* Arguments are opposite sign; remainder is sum */ - Tcl_SetObjResult(interp, - Tcl_NewWideIntObj(w2+(Tcl_WideInt)l1)); - return TCL_OK; - } - /* Arguments are same sign; remainder is first operand */ - Tcl_SetObjResult(interp, objv[1]); - return TCL_OK; - } -#endif - { - mp_int big2; - if (Tcl_IsShared(objv[2])) { - Tcl_GetBignumFromObj(NULL, objv[2], &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, objv[2], &big2); - } - - /* TODO: internals intrusion */ - if ((l1 > 0) ^ (big2.sign == MP_ZPOS)) { - /* Arguments are opposite sign; remainder is sum */ - mp_int big1; - TclBNInitBignumFromLong(&big1, l1); - mp_add(&big2, &big1, &big2); - Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big2)); - } else { - /* Arguments are same sign; remainder is first operand */ - Tcl_SetObjResult(interp, objv[1]); - /* TODO: free big2? */ - } - } - return TCL_OK; - } -#ifndef NO_WIDE_TYPE - if (type1 == TCL_NUMBER_WIDE) { - Tcl_WideInt w1 = *((CONST Tcl_WideInt *)ptr1); - if (type2 != TCL_NUMBER_BIG) { - Tcl_WideInt w2, wQuotient, wRemainder; - - Tcl_GetWideIntFromObj(NULL, objv[2], &w2); - wQuotient = w1 / w2; - - /* Force Tcl's integer division rules */ - /* TODO: examine for logic simplification */ - if (((wQuotient < ((Tcl_WideInt) 0)) - || ((wQuotient == ((Tcl_WideInt) 0)) && ( - (w1 < ((Tcl_WideInt) 0) && w2 > ((Tcl_WideInt) 0)) - || (w1 > ((Tcl_WideInt) 0) && w2 < ((Tcl_WideInt) 0))) - )) && ((wQuotient * w2) != w1)) { - wQuotient -= (Tcl_WideInt) 1; - } - wRemainder = w1 - w2*wQuotient; - Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wRemainder)); - } else { - mp_int big2; - if (Tcl_IsShared(objv[2])) { - Tcl_GetBignumFromObj(NULL, objv[2], &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, objv[2], &big2); - } - - /* TODO: internals intrusion */ - if ((w1 > ((Tcl_WideInt) 0)) ^ (big2.sign == MP_ZPOS)) { - /* Arguments are opposite sign; remainder is sum */ - mp_int big1; - TclBNInitBignumFromWideInt(&big1, w1); - mp_add(&big2, &big1, &big2); - Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big2)); - } else { - /* Arguments are same sign; remainder is first operand */ - Tcl_SetObjResult(interp, objv[1]); - } - } - return TCL_OK; - } -#endif - { - mp_int big1, big2, bigResult, bigRemainder; - - Tcl_GetBignumFromObj(NULL, objv[1], &big1); - Tcl_GetBignumFromObj(NULL, objv[2], &big2); - mp_init(&bigResult); - mp_init(&bigRemainder); - mp_div(&big1, &big2, &bigResult, &bigRemainder); - if (!mp_iszero(&bigRemainder) && (bigRemainder.sign != big2.sign)) { - /* Convert to Tcl's integer division rules */ - mp_sub_d(&bigResult, 1, &bigResult); - mp_add(&bigRemainder, &big2, &bigRemainder); - } - mp_copy(&bigRemainder, &bigResult); - mp_clear(&bigRemainder); - mp_clear(&big1); - mp_clear(&big2); - if (Tcl_IsShared(objv[1])) { - Tcl_SetObjResult(interp, Tcl_NewBignumObj(&bigResult)); - } else { - Tcl_SetBignumObj(objv[1], &bigResult); - Tcl_SetObjResult(interp, objv[1]); - } - return TCL_OK; - } - - badArg: - if (TclGetNumberFromObj(NULL, argObj, &ptr1, &type1) != TCL_OK) { - int numBytes; - CONST char *bytes = Tcl_GetStringFromObj(argObj, &numBytes); - if (numBytes == 0) { - description = "empty string"; - } else if (TclCheckBadOctal(NULL, bytes)) { - description = "invalid octal number"; - } else { - description = "non-numeric string"; - } - } else if (type1 == TCL_NUMBER_NAN) { - description = "non-numeric floating-point value"; - } else { - description = "floating-point value"; - } - - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't use %s as operand of \"%%\"", description)); - return TCL_ERROR; -} - -int -TclCompileModOpCmd( - Tcl_Interp *interp, - Tcl_Parse *parsePtr, - CompileEnv *envPtr) -{ - Tcl_Token *tokenPtr; - - if (parsePtr->numWords != 3) { - return TCL_ERROR; - } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - tokenPtr = TokenAfter(tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_MOD, envPtr); - return TCL_OK; -} - -int -TclNeqOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - int result = 1, cmp, len1, len2; - const char *str1, *str2; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value value"); - return TCL_ERROR; - } - - switch (CompareNumbers(NULL, objv[1], objv[2], &cmp)) { - case TCL_ERROR: - /* - * Got a string - */ - str1 = Tcl_GetStringFromObj(objv[1], &len1); - str2 = Tcl_GetStringFromObj(objv[2], &len2); - if (len1 == len2 && !strcmp(str1, str2)) { - result = 0; - } - case TCL_BREAK: /* Deliberate fallthrough */ - break; - case TCL_OK: - /* - * Got proper numbers - */ - if (cmp != MP_EQ) { - result = 0; - } - } - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); - return TCL_OK; -} - -int -TclCompileNeqOpCmd( - Tcl_Interp *interp, - Tcl_Parse *parsePtr, - CompileEnv *envPtr) -{ - Tcl_Token *tokenPtr; - - if (parsePtr->numWords != 3) { - return TCL_ERROR; - } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - tokenPtr = TokenAfter(tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_NEQ, envPtr); - return TCL_OK; -} - -int -TclStrneqOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - const char *s1, *s2; - int s1len, s2len; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value value"); - return TCL_ERROR; - } - - s1 = Tcl_GetStringFromObj(objv[1], &s1len); - s2 = Tcl_GetStringFromObj(objv[2], &s2len); - if (s1len == s2len && !strcmp(s1, s2)) { - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0); - } else { - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1); - } - return TCL_OK; -} - -int -TclCompileStrneqOpCmd( - Tcl_Interp *interp, - Tcl_Parse *parsePtr, - CompileEnv *envPtr) -{ - Tcl_Token *tokenPtr; - - if (parsePtr->numWords != 3) { - return TCL_ERROR; - } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - tokenPtr = TokenAfter(tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_STR_NEQ, envPtr); - return TCL_OK; -} - -int -TclInOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - const char *s1, *s2; - int s1len, s2len, i, len; - Tcl_Obj **listObj; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value list"); - return TCL_ERROR; - } - - if (Tcl_ListObjGetElements(interp, objv[2], &len, &listObj) != TCL_OK) { - return TCL_ERROR; - } - s1 = Tcl_GetStringFromObj(objv[1], &s1len); - for (i=0 ; inumWords != 3) { - return TCL_ERROR; - } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - tokenPtr = TokenAfter(tokenPtr); - CompileWord(envPtr, tokenPtr, interp); - TclEmitOpcode(INST_LIST_IN, envPtr); - return TCL_OK; -} - -int -TclNiOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - const char *s1, *s2; - int s1len, s2len, i, len; - Tcl_Obj **listObj; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "value list"); - return TCL_ERROR; - } - - if (Tcl_ListObjGetElements(interp, objv[2], &len, &listObj) != TCL_OK) { - return TCL_ERROR; - } - s1 = Tcl_GetStringFromObj(objv[1], &s1len); - for (i=0 ; inumWords != 3) { - return TCL_ERROR; + if (parsePtr->numWords != 3) { + return TCL_ERROR; } tokenPtr = TokenAfter(parsePtr->tokenPtr); CompileWord(envPtr, tokenPtr, interp); @@ -5609,57 +4823,6 @@ TclCompileNiOpCmd( } int -TclLessOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - int result = 1; - - if (objc > 2) { - int i, cmp, len1, len2; - const char *str1, *str2; - - for (i=1 ; i= 0) { - result = 0; - i = objc; - } - continue; - case TCL_OK: - /* - * Got proper numbers - */ - if (cmp != MP_LT) { - result = 0; - i = objc; - } - continue; - case TCL_BREAK: - /* - * Got a NaN (which is different from everything, including - * itself) - */ - result = 0; - i = objc; - continue; - } - } - } - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); - return TCL_OK; -} - -int TclCompileLessOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -5709,57 +4872,6 @@ TclCompileLessOpCmd( } int -TclLeqOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - int result = 1; - - if (objc > 2) { - int i, cmp, len1, len2; - const char *str1, *str2; - - for (i=1 ; i 0) { - result = 0; - i = objc; - } - continue; - case TCL_OK: - /* - * Got proper numbers - */ - if (cmp == MP_GT) { - result = 0; - i = objc; - } - continue; - case TCL_BREAK: - /* - * Got a NaN (which is different from everything, including - * itself) - */ - result = 0; - i = objc; - continue; - } - } - } - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); - return TCL_OK; -} - -int TclCompileLeqOpCmd( Tcl_Interp *interp, Tcl_Parse *parsePtr, @@ -5809,57 +4921,6 @@ TclCompileLeqOpCmd( } int -TclGreaterOpCmd( - ClientData clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - int result = 1; - - if (objc > 2) { - int i, cmp, len1, len2; - const char *str1, *str2; - - for (i=1 ; i 2) { - int i, cmp, len1, len2; - const char *str1, *str2; - - for (i=1 ; i 2) { - int i, cmp, len1, len2; - const char *str1, *str2; - - for (i=1 ; i 2) { - int i, len1, len2; - const char *str1, *str2; - - for (i=1 ; i CHAR_BIT*sizeof(long)) - || (l1 == (long) d1) || (modf(d2, &tmp) != 0.0)) { - goto doubleCompare; - } - - /* - * Otherwise, to make comparision based on full precision, need to - * convert the double to a suitably sized integer. - * - * Need this to get comparsions like - * expr 20000000000000003 < 20000000000000004.0 - * right. Converting the first argument to double will yield two - * double values that are equivalent within double precision. - * Converting the double to an integer gets done exactly, then - * integer comparison can tell the difference. - */ - - if (d2 < (double)LONG_MIN) { - *resultPtr = MP_GT; - return TCL_OK; - } - if (d2 > (double)LONG_MAX) { - *resultPtr = MP_LT; - return TCL_OK; - } - l2 = (long) d2; - goto longCompare; - case TCL_NUMBER_BIG: - if (Tcl_IsShared(numObj2)) { - Tcl_GetBignumFromObj(NULL, numObj2, &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); - } - if (mp_cmp_d(&big2, 0) == MP_LT) { - *resultPtr = MP_GT; - } else { - *resultPtr = MP_LT; - } - mp_clear(&big2); - } - return TCL_OK; - -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: - w1 = *((CONST Tcl_WideInt *)ptr1); - switch (type2) { - case TCL_NUMBER_WIDE: - w2 = *((CONST Tcl_WideInt *)ptr2); - goto wideCompare; - case TCL_NUMBER_LONG: - l2 = *((CONST long *)ptr2); - w2 = (Tcl_WideInt)l2; - goto wideCompare; - case TCL_NUMBER_DOUBLE: - d2 = *((CONST double *)ptr2); - d1 = (double) w1; - if ((DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)) - || (w1 == (Tcl_WideInt) d1) || (modf(d2, &tmp) != 0.0)) { - goto doubleCompare; - } - if (d2 < (double)LLONG_MIN) { - *resultPtr = MP_GT; - return TCL_OK; - } - if (d2 > (double)LLONG_MAX) { - *resultPtr = MP_LT; - return TCL_OK; - } - w2 = (Tcl_WideInt) d2; - goto wideCompare; - case TCL_NUMBER_BIG: - if (Tcl_IsShared(numObj2)) { - Tcl_GetBignumFromObj(NULL, numObj2, &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); - } - if (mp_cmp_d(&big2, 0) == MP_LT) { - *resultPtr = MP_GT; - } else { - *resultPtr = MP_LT; - } - mp_clear(&big2); - } - return TCL_OK; -#endif - - case TCL_NUMBER_DOUBLE: - d1 = *((CONST double *)ptr1); - switch (type2) { - case TCL_NUMBER_DOUBLE: - d2 = *((CONST double *)ptr2); - goto doubleCompare; - case TCL_NUMBER_LONG: - l2 = *((CONST long *)ptr2); - d2 = (double) l2; - - if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) - || (l2 == (long) d2) || (modf(d1, &tmp) != 0.0)) { - goto doubleCompare; - } - if (d1 < (double)LONG_MIN) { - *resultPtr = MP_LT; - return TCL_OK; - } - if (d1 > (double)LONG_MAX) { - *resultPtr = MP_GT; - return TCL_OK; - } - l1 = (long) d1; - goto longCompare; -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: - w2 = *((CONST Tcl_WideInt *)ptr2); - d2 = (double) w2; - if ((DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)) - || (w2 == (Tcl_WideInt) d2) || (modf(d1, &tmp) != 0.0)) { - goto doubleCompare; - } - if (d1 < (double)LLONG_MIN) { - *resultPtr = MP_LT; - return TCL_OK; - } - if (d1 > (double)LLONG_MAX) { - *resultPtr = MP_GT; - return TCL_OK; - } - w1 = (Tcl_WideInt) d1; - goto wideCompare; -#endif - case TCL_NUMBER_BIG: - if (TclIsInfinite(d1)) { - *resultPtr = (d1 > 0.0) ? MP_GT : MP_LT; - return TCL_OK; - } - if (Tcl_IsShared(numObj2)) { - Tcl_GetBignumFromObj(NULL, numObj2, &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); - } - if ((d1 < (double)LONG_MAX) && (d1 > (double)LONG_MIN)) { - if (mp_cmp_d(&big2, 0) == MP_LT) { - *resultPtr = MP_GT; - } else { - *resultPtr = MP_LT; - } - mp_clear(&big2); - return TCL_OK; - } - if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) - && (modf(d1, &tmp) != 0.0)) { - d2 = TclBignumToDouble(&big2); - mp_clear(&big2); - goto doubleCompare; - } - Tcl_InitBignumFromDouble(NULL, d1, &big1); - goto bigCompare; - } - return TCL_OK; - - case TCL_NUMBER_BIG: - if (Tcl_IsShared(numObj1)) { - Tcl_GetBignumFromObj(NULL, numObj1, &big1); - } else { - Tcl_GetBignumAndClearObj(NULL, numObj1, &big1); - } - switch (type2) { -#ifndef NO_WIDE_TYPE - case TCL_NUMBER_WIDE: -#endif - case TCL_NUMBER_LONG: - *resultPtr = mp_cmp_d(&big1, 0); - mp_clear(&big1); - return TCL_OK; - case TCL_NUMBER_DOUBLE: - d2 = *((CONST double *)ptr2); - if (TclIsInfinite(d2)) { - *resultPtr = (d2 > 0.0) ? MP_LT : MP_GT; - mp_clear(&big1); - return TCL_OK; - } - if ((d2 < (double)LONG_MAX) && (d2 > (double)LONG_MIN)) { - *resultPtr = mp_cmp_d(&big1, 0); - mp_clear(&big1); - return TCL_OK; - } - if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) - && (modf(d2, &tmp) != 0.0)) { - d1 = TclBignumToDouble(&big1); - mp_clear(&big1); - goto doubleCompare; - } - Tcl_InitBignumFromDouble(NULL, d2, &big2); - goto bigCompare; - case TCL_NUMBER_BIG: - if (Tcl_IsShared(numObj2)) { - Tcl_GetBignumFromObj(NULL, numObj2, &big2); - } else { - Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); - } - goto bigCompare; - } - } - - /* - * Should really be impossible to get here - */ - - return TCL_OK; - - /* - * The real core comparison rules. - */ - - longCompare: - *resultPtr = (l1 < l2) ? MP_LT : ((l1 > l2) ? MP_GT : MP_EQ); - return TCL_OK; -#ifndef NO_WIDE_TYPE - wideCompare: - *resultPtr = (w1 < w2) ? MP_LT : ((w1 > w2) ? MP_GT : MP_EQ); - return TCL_OK; -#endif - doubleCompare: - *resultPtr = (d1 < d2) ? MP_LT : ((d1 > d2) ? MP_GT : MP_EQ); - return TCL_OK; - bigCompare: - *resultPtr = mp_cmp(&big1, &big2); - mp_clear(&big1); - mp_clear(&big2); - return TCL_OK; -} - /* * Local Variables: * mode: c diff --git a/generic/tclMathOp.c b/generic/tclMathOp.c new file mode 100644 index 0000000..8836da5 --- /dev/null +++ b/generic/tclMathOp.c @@ -0,0 +1,2870 @@ +/* + * tclMathOp.c -- + * + * This file contains normal command versions of the contents of the + * tcl::mathop namespace. + * + * Copyright (c) 2006 by Donal K. Fellows. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclMathOp.c,v 1.1 2006/11/25 17:18:10 dkf Exp $ + */ + +#include "tclInt.h" +#include "tclCompile.h" +#include "tommath.h" +#include +#include + +/* + * Hack to determine whether we may expect IEEE floating point. The hack is + * formally incorrect in that non-IEEE platforms might have the same precision + * and range, but VAX, IBM, and Cray do not; are there any other floating + * point units that we might care about? + */ + +#if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MAX_EXP == 1024) +#define IEEE_FLOATING_POINT +#endif + +/* + * The stuff below is a bit of a hack so that this file can be used in + * environments that include no UNIX. + * TODO: Does this serve any purpose anymore? + */ + +#ifdef TCL_GENERIC_ONLY +# ifndef NO_FLOAT_H +# include +# else /* NO_FLOAT_H */ +# ifndef NO_VALUES_H +# include +# endif /* !NO_VALUES_H */ +# endif /* !NO_FLOAT_H */ +#endif /* !TCL_GENERIC_ONLY */ + +/* + * Prototypes for helper functions defined in this file: + */ + +static Tcl_Obj * CombineIntFloat(Tcl_Interp *interp, Tcl_Obj *valuePtr, + int opcode, Tcl_Obj *value2Ptr); +static Tcl_Obj * CombineIntOnly(Tcl_Interp *interp, Tcl_Obj *valuePtr, + int opcode, Tcl_Obj *value2Ptr); +static int CompareNumbers(Tcl_Interp *interp, Tcl_Obj *numObj1, + Tcl_Obj *numObj2, int *resultPtr); + +/* + *---------------------------------------------------------------------- + * + * CombineIntFloat -- + * + * Parses and combines two numbers (either entier() or double()) + * according to the specified operation. + * + * Results: + * Returns the resulting number object (or NULL on failure). + * + * Side effects: + * None. + * + * Notes: + * This code originally extracted from tclExecute.c. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +CombineIntFloat( + Tcl_Interp *interp, /* Place to write error messages. */ + Tcl_Obj *valuePtr, /* First value to combine. */ + int opcode, /* Operation to use to combine the + * values. Must be one of INST_ADD, INST_SUB, + * INST_MULT, INST_DIV or INST_EXPON. */ + Tcl_Obj *value2Ptr) /* Second value to combine. */ +{ + ClientData ptr1, ptr2; + int type1, type2; + Tcl_Obj *errPtr; + + if ((TclGetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) +#ifndef ACCEPT_NAN + || (type1 == TCL_NUMBER_NAN) +#endif + ) { + errPtr = valuePtr; + goto illegalOperand; + } + +#ifdef ACCEPT_NAN + if (type1 == TCL_NUMBER_NAN) { + /* NaN first argument -> result is also NaN */ + NEXT_INST_F(1, 1, 0); + } +#endif + + if ((TclGetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) +#ifndef ACCEPT_NAN + || (type2 == TCL_NUMBER_NAN) +#endif + ) { + errPtr = value2Ptr; + goto illegalOperand; + } + +#ifdef ACCEPT_NAN + if (type2 == TCL_NUMBER_NAN) { + /* NaN second argument -> result is also NaN */ + return value2Ptr; + NEXT_INST_F(1, 2, 1); + } +#endif + + if ((type1 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_DOUBLE)) { + /* + * At least one of the values is floating-point, so perform floating + * point calculations. + */ + + double d1, d2, dResult; + Tcl_GetDoubleFromObj(NULL, valuePtr, &d1); + Tcl_GetDoubleFromObj(NULL, value2Ptr, &d2); + + switch (opcode) { + case INST_ADD: + dResult = d1 + d2; + break; + case INST_SUB: + dResult = d1 - d2; + break; + case INST_MULT: + dResult = d1 * d2; + break; + case INST_DIV: +#ifndef IEEE_FLOATING_POINT + if (d2 == 0.0) { + goto divideByZero; + } +#endif + /* + * We presume that we are running with zero-divide unmasked if + * we're on an IEEE box. Otherwise, this statement might cause + * demons to fly out our noses. + */ + + dResult = d1 / d2; + break; + case INST_EXPON: + if (d1==0.0 && d2<0.0) { + goto exponOfZero; + } + dResult = pow(d1, d2); + break; + default: + /* Unused, here to silence compiler warning. */ + dResult = 0; + } + +#ifndef ACCEPT_NAN + /* + * Check now for IEEE floating-point error. + */ + + if (TclIsNaN(dResult)) { + TclExprFloatError(interp, dResult); + return NULL; + } +#endif + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewDoubleObj(dResult); + } + Tcl_SetDoubleObj(valuePtr, dResult); + return valuePtr; + } + + if ((sizeof(long) >= 2*sizeof(int)) && (opcode == INST_MULT) + && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) { + long l1 = *((CONST long *)ptr1); + long l2 = *((CONST long *)ptr2); + if ((l1 <= INT_MAX) && (l1 >= INT_MIN) + && (l2 <= INT_MAX) && (l2 >= INT_MIN)) { + long lResult = l1 * l2; + + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewLongObj(lResult); + } + Tcl_SetLongObj(valuePtr, lResult); + return valuePtr; + } + } + + if ((sizeof(Tcl_WideInt) >= 2*sizeof(long)) && (opcode == INST_MULT) + && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) { + Tcl_WideInt w1, w2, wResult; + Tcl_GetWideIntFromObj(NULL, valuePtr, &w1); + Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2); + + wResult = w1 * w2; + + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewWideIntObj(wResult); + } + Tcl_SetWideIntObj(valuePtr, wResult); + return valuePtr; + } + + /* TODO: Attempts to re-use unshared operands on stack */ + if (opcode == INST_EXPON) { + long l1, l2 = 0; + int oddExponent = 0, negativeExponent = 0; + if (type2 == TCL_NUMBER_LONG) { + l2 = *((CONST long *)ptr2); + if (l2 == 0) { + /* Anything to the zero power is 1 */ + return Tcl_NewIntObj(1); + } + } + switch (type2) { + case TCL_NUMBER_LONG: { + negativeExponent = (l2 < 0); + oddExponent = (int) (l2 & 1); + break; + } +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: { + Tcl_WideInt w2 = *((CONST Tcl_WideInt *)ptr2); + negativeExponent = (w2 < 0); + oddExponent = (int) (w2 & (Tcl_WideInt)1); + break; + } +#endif + case TCL_NUMBER_BIG: { + mp_int big2; + if (Tcl_IsShared(value2Ptr)) { + Tcl_GetBignumFromObj(NULL, value2Ptr, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, value2Ptr, &big2); + } + negativeExponent = (mp_cmp_d(&big2, 0) == MP_LT); + mp_mod_2d(&big2, 1, &big2); + oddExponent = !mp_iszero(&big2); + mp_clear(&big2); + break; + } + } + + if (negativeExponent) { + if (type1 == TCL_NUMBER_LONG) { + l1 = *((CONST long *)ptr1); + switch (l1) { + case 0: + /* zero to a negative power is div by zero error */ + goto exponOfZero; + case -1: + if (oddExponent) { + return Tcl_NewIntObj(-1); + } else { + return Tcl_NewIntObj(1); + } + case 1: + /* 1 to any power is 1 */ + return Tcl_NewIntObj(1); + } + } + /* + * Integers with magnitude greater than 1 raise to a negative + * power yield the answer zero (see TIP 123) + */ + return Tcl_NewIntObj(0); + } + + if (type1 == TCL_NUMBER_LONG) { + l1 = *((CONST long *)ptr1); + switch (l1) { + case 0: + /* zero to a positive power is zero */ + return Tcl_NewIntObj(0); + case 1: + /* 1 to any power is 1 */ + return Tcl_NewIntObj(1); + case -1: + if (oddExponent) { + return Tcl_NewIntObj(-1); + } else { + return Tcl_NewIntObj(1); + } + } + } + if (type2 == TCL_NUMBER_BIG) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("exponent too large", -1)); + return NULL; + } + /* TODO: Perform those computations that fit in native types */ + goto overflow; + } + + if ((opcode != INST_MULT) + && (type1 != TCL_NUMBER_BIG) && (type2 != TCL_NUMBER_BIG)) { + Tcl_WideInt w1, w2, wResult; + Tcl_GetWideIntFromObj(NULL, valuePtr, &w1); + Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2); + + switch (opcode) { + case INST_ADD: + wResult = w1 + w2; +#ifndef NO_WIDE_TYPE + if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) +#endif + { + /* Check for overflow */ + if (((w1 < 0) && (w2 < 0) && (wResult > 0)) + || ((w1 > 0) && (w2 > 0) && (wResult < 0))) { + goto overflow; + } + } + break; + + case INST_SUB: + wResult = w1 - w2; +#ifndef NO_WIDE_TYPE + if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) +#endif + { + /* Must check for overflow */ + if (((w1 < 0) && (w2 > 0) && (wResult > 0)) + || ((w1 > 0) && (w2 < 0) && (wResult < 0))) { + goto overflow; + } + } + break; + + case INST_DIV: + if (w2 == 0) { + goto divideByZero; + } + + /* Need a bignum to represent (LLONG_MIN / -1) */ + if ((w1 == LLONG_MIN) && (w2 == -1)) { + goto overflow; + } + wResult = w1 / w2; + + /* Force Tcl's integer division rules */ + /* TODO: examine for logic simplification */ + if (((wResult < 0) || ((wResult == 0) && + ((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) && + ((wResult * w2) != w1)) { + wResult -= 1; + } + break; + default: + /* Unused, here to silence compiler warning. */ + wResult = 0; + } + + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewWideIntObj(wResult); + } + Tcl_SetWideIntObj(valuePtr, wResult); + return valuePtr; + } + + overflow: + { + mp_int big1, big2, bigResult, bigRemainder; + if (Tcl_IsShared(valuePtr)) { + Tcl_GetBignumFromObj(NULL, valuePtr, &big1); + } else { + Tcl_GetBignumAndClearObj(NULL, valuePtr, &big1); + } + if (Tcl_IsShared(value2Ptr)) { + Tcl_GetBignumFromObj(NULL, value2Ptr, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, value2Ptr, &big2); + } + mp_init(&bigResult); + switch (opcode) { + case INST_ADD: + mp_add(&big1, &big2, &bigResult); + break; + case INST_SUB: + mp_sub(&big1, &big2, &bigResult); + break; + case INST_MULT: + mp_mul(&big1, &big2, &bigResult); + break; + case INST_DIV: + if (mp_iszero(&big2)) { + mp_clear(&big1); + mp_clear(&big2); + goto divideByZero; + } + mp_init(&bigRemainder); + mp_div(&big1, &big2, &bigResult, &bigRemainder); + /* TODO: internals intrusion */ + if (!mp_iszero(&bigRemainder) + && (bigRemainder.sign != big2.sign)) { + /* Convert to Tcl's integer division rules */ + mp_sub_d(&bigResult, 1, &bigResult); + mp_add(&bigRemainder, &big2, &bigRemainder); + } + mp_clear(&bigRemainder); + break; + case INST_EXPON: + if (big2.used > 1) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("exponent too large", -1)); + mp_clear(&big1); + mp_clear(&big2); + return NULL; + } + mp_expt_d(&big1, big2.dp[0], &bigResult); + break; + } + mp_clear(&big1); + mp_clear(&big2); + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewBignumObj(&bigResult); + } + Tcl_SetBignumObj(valuePtr, &bigResult); + return valuePtr; + } + + { + const char *description, *operator; + + illegalOperand: + switch (opcode) { + case INST_ADD: operator = "+"; break; + case INST_SUB: operator = "-"; break; + case INST_MULT: operator = "*"; break; + case INST_DIV: operator = "/"; break; + case INST_EXPON: operator = "**"; break; + default: + operator = "???"; + } + + if (TclGetNumberFromObj(NULL, errPtr, &ptr1, &type1) != TCL_OK) { + int numBytes; + CONST char *bytes = Tcl_GetStringFromObj(errPtr, &numBytes); + if (numBytes == 0) { + description = "empty string"; + } else if (TclCheckBadOctal(NULL, bytes)) { + description = "invalid octal number"; + } else { + description = "non-numeric string"; + } + } else if (type1 == TCL_NUMBER_NAN) { + description = "non-numeric floating-point value"; + } else if (type1 == TCL_NUMBER_DOUBLE) { + description = "floating-point value"; + } else { + /* TODO: No caller needs this. Eliminate? */ + description = "(big) integer"; + } + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't use %s as operand of \"%s\"", description, operator)); + return NULL; + } + + divideByZero: + Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1)); + Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL); + return NULL; + + exponOfZero: + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "exponentiation of zero by negative power", -1)); + Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", + "exponentiation of zero by negative power", NULL); + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * CombineIntOnly -- + * + * Parses and combines two numbers (must be entier()) according to the + * specified operation. + * + * Results: + * Returns the resulting number object (or NULL on failure). + * + * Side effects: + * None. + * + * Notes: + * This code originally extracted from tclExecute.c. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +CombineIntOnly( + Tcl_Interp *interp, /* Place to write error messages. */ + Tcl_Obj *valuePtr, /* First value to combine. */ + int opcode, /* Operation to use to combine the + * values. Must be one of INST_BITAND, + * INST_BITOR or INST_BITXOR. */ + Tcl_Obj *value2Ptr) /* Second value to combine. */ +{ + ClientData ptr1, ptr2; + int type1, type2; + Tcl_Obj *errPtr; + + if ((TclGetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) + || (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) { + errPtr = valuePtr; + goto illegalOperand; + } + if ((TclGetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) + || (type2 == TCL_NUMBER_NAN) || (type2 == TCL_NUMBER_DOUBLE)) { + errPtr = value2Ptr; + goto illegalOperand; + } + + if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) { + mp_int big1, big2, bigResult; + mp_int *First, *Second; + int numPos; + + if (Tcl_IsShared(valuePtr)) { + Tcl_GetBignumFromObj(NULL, valuePtr, &big1); + } else { + Tcl_GetBignumAndClearObj(NULL, valuePtr, &big1); + } + if (Tcl_IsShared(value2Ptr)) { + Tcl_GetBignumFromObj(NULL, value2Ptr, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, value2Ptr, &big2); + } + + /* + * Count how many positive arguments we have. If only one of the + * arguments is negative, store it in 'Second'. + */ + + if (mp_cmp_d(&big1, 0) != MP_LT) { + numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT); + First = &big1; + Second = &big2; + } else { + First = &big2; + Second = &big1; + numPos = (mp_cmp_d(First, 0) != MP_LT); + } + mp_init(&bigResult); + + switch (opcode) { + case INST_BITAND: + switch (numPos) { + case 2: + /* Both arguments positive, base case */ + mp_and(First, Second, &bigResult); + break; + case 1: + /* First is positive; Second negative + * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */ + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_xor(First, Second, &bigResult); + mp_and(First, &bigResult, &bigResult); + break; + case 0: + /* Both arguments negative + * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */ + mp_neg(First, First); + mp_sub_d(First, 1, First); + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_or(First, Second, &bigResult); + mp_neg(&bigResult, &bigResult); + mp_sub_d(&bigResult, 1, &bigResult); + break; + } + break; + + case INST_BITOR: + switch (numPos) { + case 2: + /* Both arguments positive, base case */ + mp_or(First, Second, &bigResult); + break; + case 1: + /* First is positive; Second negative + * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */ + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_xor(First, Second, &bigResult); + mp_and(Second, &bigResult, &bigResult); + mp_neg(&bigResult, &bigResult); + mp_sub_d(&bigResult, 1, &bigResult); + break; + case 0: + /* Both arguments negative + * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */ + mp_neg(First, First); + mp_sub_d(First, 1, First); + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_and(First, Second, &bigResult); + mp_neg(&bigResult, &bigResult); + mp_sub_d(&bigResult, 1, &bigResult); + break; + } + break; + + case INST_BITXOR: + switch (numPos) { + case 2: + /* Both arguments positive, base case */ + mp_xor(First, Second, &bigResult); + break; + case 1: + /* First is positive; Second negative + * P^N = ~(P^~N) = -(P^(-N-1))-1 */ + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_xor(First, Second, &bigResult); + mp_neg(&bigResult, &bigResult); + mp_sub_d(&bigResult, 1, &bigResult); + break; + case 0: + /* Both arguments negative + * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */ + mp_neg(First, First); + mp_sub_d(First, 1, First); + mp_neg(Second, Second); + mp_sub_d(Second, 1, Second); + mp_xor(First, Second, &bigResult); + break; + } + break; + } + + mp_clear(&big1); + mp_clear(&big2); + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewBignumObj(&bigResult); + } + Tcl_SetBignumObj(valuePtr, &bigResult); + return valuePtr; + } +#ifndef NO_WIDE_TYPE + else if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) { + Tcl_WideInt wResult, w1, w2; + Tcl_GetWideIntFromObj(NULL, valuePtr, &w1); + Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2); + + switch (opcode) { + case INST_BITAND: + wResult = w1 & w2; + break; + case INST_BITOR: + wResult = w1 | w2; + break; + case INST_BITXOR: + wResult = w1 ^ w2; + break; + default: + /* Unused, here to silence compiler warning. */ + wResult = 0; + } + + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewWideIntObj(wResult); + } + Tcl_SetWideIntObj(valuePtr, wResult); + return valuePtr; + } +#endif + else { + long lResult, l1 = *((const long *)ptr1); + long l2 = *((const long *)ptr2); + + switch (opcode) { + case INST_BITAND: + lResult = l1 & l2; + break; + case INST_BITOR: + lResult = l1 | l2; + break; + case INST_BITXOR: + lResult = l1 ^ l2; + break; + default: + /* Unused, here to silence compiler warning. */ + lResult = 0; + } + + if (Tcl_IsShared(valuePtr)) { + return Tcl_NewLongObj(lResult); + } + TclSetLongObj(valuePtr, lResult); + return valuePtr; + } + + { + const char *description, *operator; + + illegalOperand: + switch (opcode) { + case INST_BITAND: operator = "&"; break; + case INST_BITOR: operator = "|"; break; + case INST_BITXOR: operator = "^"; break; + default: + operator = "???"; + } + + if (TclGetNumberFromObj(NULL, errPtr, &ptr1, &type1) != TCL_OK) { + int numBytes; + CONST char *bytes = Tcl_GetStringFromObj(errPtr, &numBytes); + if (numBytes == 0) { + description = "empty string"; + } else if (TclCheckBadOctal(NULL, bytes)) { + description = "invalid octal number"; + } else { + description = "non-numeric string"; + } + } else if (type1 == TCL_NUMBER_NAN) { + description = "non-numeric floating-point value"; + } else if (type1 == TCL_NUMBER_DOUBLE) { + description = "floating-point value"; + } else { + /* TODO: No caller needs this. Eliminate? */ + description = "(big) integer"; + } + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't use %s as operand of \"%s\"", description, operator)); + return NULL; + } +} + +/* + *---------------------------------------------------------------------- + * + * CompareNumbers -- + * + * Parses and compares two numbers (may be either entier() or double()). + * + * Results: + * TCL_OK if the numbers parse correctly, TCL_ERROR if one is not numeric + * at all, and TCL_BREAK if one or the other is "NaN". The resultPtr + * argument is used to update a variable with how the numbers relate to + * each other in the TCL_OK case. + * + * Side effects: + * None. + * + * Notes: + * This code originally extracted from tclExecute.c. + * + *---------------------------------------------------------------------- + */ + +static int +CompareNumbers( + Tcl_Interp *interp, /* Where to write error messages if any. */ + Tcl_Obj *numObj1, /* First number to compare. */ + Tcl_Obj *numObj2, /* Second number to compare. */ + int *resultPtr) /* Pointer to a variable to write the outcome + * of the comparison into. Must not be + * NULL. */ +{ + ClientData ptr1, ptr2; + int type1, type2; + double d1, d2, tmp; + long l1, l2; + mp_int big1, big2; +#ifndef NO_WIDE_TYPE + Tcl_WideInt w1, w2; +#endif + + if (TclGetNumberFromObj(interp, numObj1, &ptr1, &type1) != TCL_OK) { + return TCL_ERROR; + } + if (TclGetNumberFromObj(interp, numObj2, &ptr2, &type2) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Selected special cases. NaNs are not equal to *everything*, otherwise + * objects are equal to themselves. + */ + + if (type1 == TCL_NUMBER_NAN) { + /* NaN first arg: NaN != to everything, other compares are false */ + return TCL_BREAK; + } + if (numObj1 == numObj2) { + *resultPtr = MP_EQ; + return TCL_OK; + } + if (type2 == TCL_NUMBER_NAN) { + /* NaN 2nd arg: NaN != to everything, other compares are false */ + return TCL_BREAK; + } + + /* + * Big switch to pick apart the type rules and choose how to compare the + * two numbers. Also handles a few special cases along the way. + */ + + switch (type1) { + case TCL_NUMBER_LONG: + l1 = *((CONST long *)ptr1); + switch (type2) { + case TCL_NUMBER_LONG: + l2 = *((CONST long *)ptr2); + goto longCompare; +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: + w2 = *((CONST Tcl_WideInt *)ptr2); + w1 = (Tcl_WideInt)l1; + goto wideCompare; +#endif + case TCL_NUMBER_DOUBLE: + d2 = *((CONST double *)ptr2); + d1 = (double) l1; + + /* + * If the double has a fractional part, or if the long can be + * converted to double without loss of precision, then compare as + * doubles. + */ + + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) + || (l1 == (long) d1) || (modf(d2, &tmp) != 0.0)) { + goto doubleCompare; + } + + /* + * Otherwise, to make comparision based on full precision, need to + * convert the double to a suitably sized integer. + * + * Need this to get comparsions like + * expr 20000000000000003 < 20000000000000004.0 + * right. Converting the first argument to double will yield two + * double values that are equivalent within double precision. + * Converting the double to an integer gets done exactly, then + * integer comparison can tell the difference. + */ + + if (d2 < (double)LONG_MIN) { + *resultPtr = MP_GT; + return TCL_OK; + } + if (d2 > (double)LONG_MAX) { + *resultPtr = MP_LT; + return TCL_OK; + } + l2 = (long) d2; + goto longCompare; + case TCL_NUMBER_BIG: + if (Tcl_IsShared(numObj2)) { + Tcl_GetBignumFromObj(NULL, numObj2, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); + } + if (mp_cmp_d(&big2, 0) == MP_LT) { + *resultPtr = MP_GT; + } else { + *resultPtr = MP_LT; + } + mp_clear(&big2); + } + return TCL_OK; + +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: + w1 = *((CONST Tcl_WideInt *)ptr1); + switch (type2) { + case TCL_NUMBER_WIDE: + w2 = *((CONST Tcl_WideInt *)ptr2); + goto wideCompare; + case TCL_NUMBER_LONG: + l2 = *((CONST long *)ptr2); + w2 = (Tcl_WideInt)l2; + goto wideCompare; + case TCL_NUMBER_DOUBLE: + d2 = *((CONST double *)ptr2); + d1 = (double) w1; + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)) + || (w1 == (Tcl_WideInt) d1) || (modf(d2, &tmp) != 0.0)) { + goto doubleCompare; + } + if (d2 < (double)LLONG_MIN) { + *resultPtr = MP_GT; + return TCL_OK; + } + if (d2 > (double)LLONG_MAX) { + *resultPtr = MP_LT; + return TCL_OK; + } + w2 = (Tcl_WideInt) d2; + goto wideCompare; + case TCL_NUMBER_BIG: + if (Tcl_IsShared(numObj2)) { + Tcl_GetBignumFromObj(NULL, numObj2, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); + } + if (mp_cmp_d(&big2, 0) == MP_LT) { + *resultPtr = MP_GT; + } else { + *resultPtr = MP_LT; + } + mp_clear(&big2); + } + return TCL_OK; +#endif + + case TCL_NUMBER_DOUBLE: + d1 = *((CONST double *)ptr1); + switch (type2) { + case TCL_NUMBER_DOUBLE: + d2 = *((CONST double *)ptr2); + goto doubleCompare; + case TCL_NUMBER_LONG: + l2 = *((CONST long *)ptr2); + d2 = (double) l2; + + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) + || (l2 == (long) d2) || (modf(d1, &tmp) != 0.0)) { + goto doubleCompare; + } + if (d1 < (double)LONG_MIN) { + *resultPtr = MP_LT; + return TCL_OK; + } + if (d1 > (double)LONG_MAX) { + *resultPtr = MP_GT; + return TCL_OK; + } + l1 = (long) d1; + goto longCompare; +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: + w2 = *((CONST Tcl_WideInt *)ptr2); + d2 = (double) w2; + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)) + || (w2 == (Tcl_WideInt) d2) || (modf(d1, &tmp) != 0.0)) { + goto doubleCompare; + } + if (d1 < (double)LLONG_MIN) { + *resultPtr = MP_LT; + return TCL_OK; + } + if (d1 > (double)LLONG_MAX) { + *resultPtr = MP_GT; + return TCL_OK; + } + w1 = (Tcl_WideInt) d1; + goto wideCompare; +#endif + case TCL_NUMBER_BIG: + if (TclIsInfinite(d1)) { + *resultPtr = (d1 > 0.0) ? MP_GT : MP_LT; + return TCL_OK; + } + if (Tcl_IsShared(numObj2)) { + Tcl_GetBignumFromObj(NULL, numObj2, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); + } + if ((d1 < (double)LONG_MAX) && (d1 > (double)LONG_MIN)) { + if (mp_cmp_d(&big2, 0) == MP_LT) { + *resultPtr = MP_GT; + } else { + *resultPtr = MP_LT; + } + mp_clear(&big2); + return TCL_OK; + } + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) + && (modf(d1, &tmp) != 0.0)) { + d2 = TclBignumToDouble(&big2); + mp_clear(&big2); + goto doubleCompare; + } + Tcl_InitBignumFromDouble(NULL, d1, &big1); + goto bigCompare; + } + return TCL_OK; + + case TCL_NUMBER_BIG: + if (Tcl_IsShared(numObj1)) { + Tcl_GetBignumFromObj(NULL, numObj1, &big1); + } else { + Tcl_GetBignumAndClearObj(NULL, numObj1, &big1); + } + switch (type2) { +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: +#endif + case TCL_NUMBER_LONG: + *resultPtr = mp_cmp_d(&big1, 0); + mp_clear(&big1); + return TCL_OK; + case TCL_NUMBER_DOUBLE: + d2 = *((CONST double *)ptr2); + if (TclIsInfinite(d2)) { + *resultPtr = (d2 > 0.0) ? MP_LT : MP_GT; + mp_clear(&big1); + return TCL_OK; + } + if ((d2 < (double)LONG_MAX) && (d2 > (double)LONG_MIN)) { + *resultPtr = mp_cmp_d(&big1, 0); + mp_clear(&big1); + return TCL_OK; + } + if ((DBL_MANT_DIG > CHAR_BIT*sizeof(long)) + && (modf(d2, &tmp) != 0.0)) { + d1 = TclBignumToDouble(&big1); + mp_clear(&big1); + goto doubleCompare; + } + Tcl_InitBignumFromDouble(NULL, d2, &big2); + goto bigCompare; + case TCL_NUMBER_BIG: + if (Tcl_IsShared(numObj2)) { + Tcl_GetBignumFromObj(NULL, numObj2, &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, numObj2, &big2); + } + goto bigCompare; + } + } + + /* + * Should really be impossible to get here + */ + + return TCL_OK; + + /* + * The real core comparison rules. + */ + + longCompare: + *resultPtr = (l1 < l2) ? MP_LT : ((l1 > l2) ? MP_GT : MP_EQ); + return TCL_OK; +#ifndef NO_WIDE_TYPE + wideCompare: + *resultPtr = (w1 < w2) ? MP_LT : ((w1 > w2) ? MP_GT : MP_EQ); + return TCL_OK; +#endif + doubleCompare: + *resultPtr = (d1 < d2) ? MP_LT : ((d1 > d2) ? MP_GT : MP_EQ); + return TCL_OK; + bigCompare: + *resultPtr = mp_cmp(&big1, &big2); + mp_clear(&big1); + mp_clear(&big2); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclInvertOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::~" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclInvertOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + ClientData val; + int type; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "number"); + return TCL_ERROR; + } + if (TclGetNumberFromObj(interp, objv[1], &val, &type) != TCL_OK) { + return TCL_ERROR; + } + switch (type) { + case TCL_NUMBER_LONG: { + long l = *((const long *) val); + + Tcl_SetLongObj(Tcl_GetObjResult(interp), ~l); + return TCL_OK; + } +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: { + Tcl_WideInt w = *((const Tcl_WideInt *) val); + + Tcl_SetWideIntObj(Tcl_GetObjResult(interp), ~w); + return TCL_OK; + } +#endif + default: { + mp_int big; + + if (Tcl_IsShared(objv[1])) { + Tcl_GetBignumFromObj(NULL, objv[1], &big); + } else { + Tcl_GetBignumAndClearObj(NULL, objv[1], &big); + } + /* ~a = - a - 1 */ + mp_neg(&big, &big); + mp_sub_d(&big, 1, &big); + if (Tcl_IsShared(objv[1])) { + Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big)); + } else { + Tcl_SetBignumObj(objv[1], &big); + Tcl_SetObjResult(interp, objv[1]); + } + return TCL_OK; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TclNotOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::!" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclNotOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int b; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "boolean"); + return TCL_ERROR; + } + if (Tcl_GetBooleanFromObj(interp, objv[1], &b) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), !b); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclAddOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::+" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclAddOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc < 2) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); + return TCL_OK; + } else if (objc == 2) { + Tcl_SetObjResult(interp, objv[1]); + return TCL_OK; + } else if (objc == 3) { + /* + * This is a special case of the version with the loop that allows for + * better memory management of objects in some cases. + */ + + Tcl_Obj *resPtr = CombineIntFloat(interp, objv[1], INST_ADD, objv[2]); + if (resPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resPtr); + return TCL_OK; + } else { + Tcl_Obj *sumPtr = objv[1]; + int i; + + Tcl_IncrRefCount(sumPtr); + for (i=2 ; i=1 ; i--) { + Tcl_Obj *resPtr = CombineIntFloat(interp, objv[i], INST_EXPON, + powPtr); + + if (resPtr == NULL) { + TclDecrRefCount(powPtr); + return TCL_ERROR; + } + Tcl_IncrRefCount(resPtr); + TclDecrRefCount(powPtr); + powPtr = resPtr; + } + Tcl_SetObjResult(interp, powPtr); + Tcl_DecrRefCount(powPtr); /* Public form since we know we won't + * be freeing this object now. */ + return TCL_OK; + } +} + +/* + *---------------------------------------------------------------------- + * + * TclMinusOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::-" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclMinusOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "value ?value ...?"); + return TCL_ERROR; + } else if (objc == 2) { + /* + * Only a single argument, so we compute the negation. + */ + + Tcl_Obj *zeroPtr = Tcl_NewIntObj(0); + Tcl_Obj *resPtr; + + Tcl_IncrRefCount(zeroPtr); + resPtr = CombineIntFloat(interp, zeroPtr, INST_SUB, objv[1]); + if (resPtr == NULL) { + TclDecrRefCount(zeroPtr); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resPtr); + TclDecrRefCount(zeroPtr); + return TCL_OK; + } else if (objc == 3) { + /* + * This is a special case of the version with the loop that allows for + * better memory management of objects in some cases. + */ + + Tcl_Obj *resPtr = CombineIntFloat(interp, objv[1], INST_SUB, objv[2]); + if (resPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resPtr); + return TCL_OK; + } else { + Tcl_Obj *diffPtr = objv[1]; + int i; + + Tcl_IncrRefCount(diffPtr); + for (i=2 ; i0) ? l1 : ~l1) & -(1L<<(CHAR_BIT*sizeof(long)-1-shift)))) { + Tcl_SetObjResult(interp, Tcl_NewLongObj(l1<0) ? w : ~w) & -(((Tcl_WideInt)1) + << (CHAR_BIT*sizeof(Tcl_WideInt)-1-shift)))) { + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w<>" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclRshiftOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + ClientData ptr1, ptr2; + int invalid, shift, type1, type2, idx; + const char *description; + long l1; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "value value"); + return TCL_ERROR; + } + + if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) + || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) { + idx = 1; + goto illegalOperand; + } + if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK) + || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) { + idx = 2; + goto illegalOperand; + } + + /* reject negative shift argument */ + switch (type2) { + case TCL_NUMBER_LONG: + invalid = (*((const long *)ptr2) < (long)0); + break; +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: + invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0); + break; +#endif + case TCL_NUMBER_BIG: + /* TODO: const correctness ? */ + invalid = (mp_cmp_d((mp_int *)ptr2, 0) == MP_LT); + break; + default: + /* Unused, here to silence compiler warning */ + invalid = 0; + } + if (invalid) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("negative shift argument", -1)); + return TCL_ERROR; + } + + /* Zero shifted any number of bits is still zero */ + if ((type1 == TCL_NUMBER_LONG) && (*((const long *)ptr1) == (long)0)) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); + return TCL_OK; + } + + /* Quickly force large right shifts to 0 or -1 */ + if ((type2 != TCL_NUMBER_LONG) + || (*((const long *)ptr2) > INT_MAX)) { + /* + * Again, technically, the value to be shifted could be an mp_int so + * huge that a right shift by (INT_MAX+1) bits could not take us to + * the result of 0 or -1, but since we're using mp_div_2d to do the + * work, and it takes only an int argument, we draw the line there. + */ + + int zero; + + switch (type1) { + case TCL_NUMBER_LONG: + zero = (*((const long *)ptr1) > (long)0); + break; +#ifndef NO_WIDE_TYPE + case TCL_NUMBER_WIDE: + zero = (*((const Tcl_WideInt *)ptr1) > (Tcl_WideInt)0); + break; +#endif + case TCL_NUMBER_BIG: + /* TODO: const correctness ? */ + zero = (mp_cmp_d((mp_int *)ptr1, 0) == MP_GT); + break; + default: + /* Unused, here to silence compiler warning. */ + zero = 0; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(zero ? 0 : -1)); + return TCL_OK; + } + + shift = (int)(*((const long *)ptr2)); + /* Handle shifts within the native long range */ + if (type1 == TCL_NUMBER_LONG) { + l1 = *((const long *)ptr1); + if ((size_t)shift >= CHAR_BIT*sizeof(long)) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(l1 >= (long)0 ? 0 : -1)); + } else { + Tcl_SetObjResult(interp, Tcl_NewIntObj(l1 >> shift)); + } + return TCL_OK; + } + +#ifndef NO_WIDE_TYPE + /* Handle shifts within the native wide range */ + if (type1 == TCL_NUMBER_WIDE) { + Tcl_WideInt w = *((const Tcl_WideInt *)ptr1); + if ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideInt)) { + Tcl_SetObjResult(interp, + Tcl_NewIntObj(w >= (Tcl_WideInt)0 ? 0 : -1)); + } else { + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w >> shift)); + } + return TCL_OK; + } +#endif + + { + mp_int big, bigResult, bigRemainder; + + if (Tcl_IsShared(objv[1])) { + Tcl_GetBignumFromObj(NULL, objv[1], &big); + } else { + Tcl_GetBignumAndClearObj(NULL, objv[1], &big); + } + + mp_init(&bigResult); + mp_init(&bigRemainder); + mp_div_2d(&big, shift, &bigResult, &bigRemainder); + if (mp_cmp_d(&bigRemainder, 0) == MP_LT) { + /* Convert to Tcl's integer division rules */ + mp_sub_d(&bigResult, 1, &bigResult); + } + mp_clear(&bigRemainder); + mp_clear(&big); + + if (!Tcl_IsShared(objv[1])) { + Tcl_SetBignumObj(objv[1], &bigResult); + Tcl_SetObjResult(interp, objv[1]); + } else { + Tcl_SetObjResult(interp, Tcl_NewBignumObj(&bigResult)); + } + } + return TCL_OK; + + illegalOperand: + if (TclGetNumberFromObj(NULL, objv[idx], &ptr1, &type1) != TCL_OK) { + int numBytes; + const char *bytes = Tcl_GetStringFromObj(objv[idx], &numBytes); + if (numBytes == 0) { + description = "empty string"; + } else if (TclCheckBadOctal(NULL, bytes)) { + description = "invalid octal number"; + } else { + description = "non-numeric string"; + } + } else if (type1 == TCL_NUMBER_NAN) { + description = "non-numeric floating-point value"; + } else { + description = "floating-point value"; + } + + Tcl_SetObjResult(interp, + Tcl_ObjPrintf("can't use %s as operand of \">>\"", description)); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TclModOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::%" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclModOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_Obj *argObj; + ClientData ptr1, ptr2; + int type1, type2; + long l1, l2 = 0; + const char *description; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "value value"); + return TCL_ERROR; + } + + if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) + || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) { + argObj = objv[1]; + goto badArg; + } + if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK) + || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) { + argObj = objv[2]; + goto badArg; + } + + if (type2 == TCL_NUMBER_LONG) { + l2 = *((CONST long *)ptr2); + if (l2 == 0) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1)); + Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", + NULL); + return TCL_ERROR; + } + if ((l2 == 1) || (l2 == -1)) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); + return TCL_OK; + } + } + if (type1 == TCL_NUMBER_LONG) { + l1 = *((CONST long *)ptr1); + if (l1 == 0) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); + return TCL_OK; + } + if (type2 == TCL_NUMBER_LONG) { + /* Both operands are long; do native calculation */ + long lRemainder, lQuotient = l1 / l2; + + /* Force Tcl's integer division rules */ + /* TODO: examine for logic simplification */ + if (((lQuotient < 0) || ((lQuotient == 0) && + ((l1 < 0 && l2 > 0) || (l1 > 0 && l2 < 0)))) && + ((lQuotient * l2) != l1)) { + lQuotient -= 1; + } + lRemainder = l1 - l2*lQuotient; + Tcl_SetLongObj(Tcl_GetObjResult(interp), lRemainder); + return TCL_OK; + } + /* + * First operand fits in long; second does not, so the second has + * greater magnitude than first. No need to divide to determine the + * remainder. + */ +#ifndef NO_WIDE_TYPE + if (type2 == TCL_NUMBER_WIDE) { + Tcl_WideInt w2 = *((CONST Tcl_WideInt *)ptr2); + + if ((l1 > 0) ^ (w2 > (Tcl_WideInt)0)) { + /* Arguments are opposite sign; remainder is sum */ + Tcl_SetObjResult(interp, + Tcl_NewWideIntObj(w2+(Tcl_WideInt)l1)); + return TCL_OK; + } + /* Arguments are same sign; remainder is first operand */ + Tcl_SetObjResult(interp, objv[1]); + return TCL_OK; + } +#endif + { + mp_int big2; + if (Tcl_IsShared(objv[2])) { + Tcl_GetBignumFromObj(NULL, objv[2], &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, objv[2], &big2); + } + + /* TODO: internals intrusion */ + if ((l1 > 0) ^ (big2.sign == MP_ZPOS)) { + /* Arguments are opposite sign; remainder is sum */ + mp_int big1; + TclBNInitBignumFromLong(&big1, l1); + mp_add(&big2, &big1, &big2); + Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big2)); + } else { + /* Arguments are same sign; remainder is first operand */ + Tcl_SetObjResult(interp, objv[1]); + /* TODO: free big2? */ + } + } + return TCL_OK; + } +#ifndef NO_WIDE_TYPE + if (type1 == TCL_NUMBER_WIDE) { + Tcl_WideInt w1 = *((CONST Tcl_WideInt *)ptr1); + if (type2 != TCL_NUMBER_BIG) { + Tcl_WideInt w2, wQuotient, wRemainder; + + Tcl_GetWideIntFromObj(NULL, objv[2], &w2); + wQuotient = w1 / w2; + + /* Force Tcl's integer division rules */ + /* TODO: examine for logic simplification */ + if (((wQuotient < ((Tcl_WideInt) 0)) + || ((wQuotient == ((Tcl_WideInt) 0)) && ( + (w1 < ((Tcl_WideInt) 0) && w2 > ((Tcl_WideInt) 0)) + || (w1 > ((Tcl_WideInt) 0) && w2 < ((Tcl_WideInt) 0))) + )) && ((wQuotient * w2) != w1)) { + wQuotient -= (Tcl_WideInt) 1; + } + wRemainder = w1 - w2*wQuotient; + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wRemainder)); + } else { + mp_int big2; + if (Tcl_IsShared(objv[2])) { + Tcl_GetBignumFromObj(NULL, objv[2], &big2); + } else { + Tcl_GetBignumAndClearObj(NULL, objv[2], &big2); + } + + /* TODO: internals intrusion */ + if ((w1 > ((Tcl_WideInt) 0)) ^ (big2.sign == MP_ZPOS)) { + /* Arguments are opposite sign; remainder is sum */ + mp_int big1; + TclBNInitBignumFromWideInt(&big1, w1); + mp_add(&big2, &big1, &big2); + Tcl_SetObjResult(interp, Tcl_NewBignumObj(&big2)); + } else { + /* Arguments are same sign; remainder is first operand */ + Tcl_SetObjResult(interp, objv[1]); + } + } + return TCL_OK; + } +#endif + { + mp_int big1, big2, bigResult, bigRemainder; + + Tcl_GetBignumFromObj(NULL, objv[1], &big1); + Tcl_GetBignumFromObj(NULL, objv[2], &big2); + mp_init(&bigResult); + mp_init(&bigRemainder); + mp_div(&big1, &big2, &bigResult, &bigRemainder); + if (!mp_iszero(&bigRemainder) && (bigRemainder.sign != big2.sign)) { + /* Convert to Tcl's integer division rules */ + mp_sub_d(&bigResult, 1, &bigResult); + mp_add(&bigRemainder, &big2, &bigRemainder); + } + mp_copy(&bigRemainder, &bigResult); + mp_clear(&bigRemainder); + mp_clear(&big1); + mp_clear(&big2); + if (Tcl_IsShared(objv[1])) { + Tcl_SetObjResult(interp, Tcl_NewBignumObj(&bigResult)); + } else { + Tcl_SetBignumObj(objv[1], &bigResult); + Tcl_SetObjResult(interp, objv[1]); + } + return TCL_OK; + } + + badArg: + if (TclGetNumberFromObj(NULL, argObj, &ptr1, &type1) != TCL_OK) { + int numBytes; + CONST char *bytes = Tcl_GetStringFromObj(argObj, &numBytes); + if (numBytes == 0) { + description = "empty string"; + } else if (TclCheckBadOctal(NULL, bytes)) { + description = "invalid octal number"; + } else { + description = "non-numeric string"; + } + } else if (type1 == TCL_NUMBER_NAN) { + description = "non-numeric floating-point value"; + } else { + description = "floating-point value"; + } + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't use %s as operand of \"%%\"", description)); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TclNeqOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::!=" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclNeqOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int result = 1, cmp, len1, len2; + const char *str1, *str2; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "value value"); + return TCL_ERROR; + } + + switch (CompareNumbers(NULL, objv[1], objv[2], &cmp)) { + case TCL_ERROR: + /* + * Got a string + */ + str1 = Tcl_GetStringFromObj(objv[1], &len1); + str2 = Tcl_GetStringFromObj(objv[2], &len2); + if (len1 == len2 && !strcmp(str1, str2)) { + result = 0; + } + case TCL_BREAK: /* Deliberate fallthrough */ + break; + case TCL_OK: + /* + * Got proper numbers + */ + if (cmp != MP_EQ) { + result = 0; + } + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclStrneqOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::ne" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclStrneqOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + const char *s1, *s2; + int s1len, s2len; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "value value"); + return TCL_ERROR; + } + + s1 = Tcl_GetStringFromObj(objv[1], &s1len); + s2 = Tcl_GetStringFromObj(objv[2], &s2len); + if (s1len == s2len && !strcmp(s1, s2)) { + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0); + } else { + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclInOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::in" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclInOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + const char *s1, *s2; + int s1len, s2len, i, len; + Tcl_Obj **listObj; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "value list"); + return TCL_ERROR; + } + + if (Tcl_ListObjGetElements(interp, objv[2], &len, &listObj) != TCL_OK) { + return TCL_ERROR; + } + s1 = Tcl_GetStringFromObj(objv[1], &s1len); + for (i=0 ; i 2) { + int i, cmp, len1, len2; + const char *str1, *str2; + + for (i=1 ; i= 0) { + result = 0; + i = objc; + } + continue; + case TCL_OK: + /* + * Got proper numbers + */ + if (cmp != MP_LT) { + result = 0; + i = objc; + } + continue; + case TCL_BREAK: + /* + * Got a NaN (which is different from everything, including + * itself) + */ + result = 0; + i = objc; + continue; + } + } + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclLeqOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::<=" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclLeqOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int result = 1; + + if (objc > 2) { + int i, cmp, len1, len2; + const char *str1, *str2; + + for (i=1 ; i 0) { + result = 0; + i = objc; + } + continue; + case TCL_OK: + /* + * Got proper numbers + */ + if (cmp == MP_GT) { + result = 0; + i = objc; + } + continue; + case TCL_BREAK: + /* + * Got a NaN (which is different from everything, including + * itself) + */ + result = 0; + i = objc; + continue; + } + } + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclGreaterOpCmd -- + * + * This procedure is invoked to process the "::tcl::mathop::>" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclGreaterOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int result = 1; + + if (objc > 2) { + int i, cmp, len1, len2; + const char *str1, *str2; + + for (i=1 ; i=" Tcl + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +TclGeqOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int result = 1; + + if (objc > 2) { + int i, cmp, len1, len2; + const char *str1, *str2; + + for (i=1 ; i 2) { + int i, cmp, len1, len2; + const char *str1, *str2; + + for (i=1 ; i 2) { + int i, len1, len2; + const char *str1, *str2; + + for (i=1 ; i$(GENERIC_DIR)/tclDate.c # rm y.tab.c -# The following target generates the file generic/tclTomMath.h. -# It needs to be run (and the results checked) after updating -# to a new release of libtommath. +# The following target generates the file generic/tclTomMath.h. It needs to be +# run (and the results checked) after updating to a new release of libtommath. gentommath_h: $(TCL_EXE) "$(TOP_DIR)/tools/fix_tommath_h.tcl" \ "$(TOMMATH_DIR)/tommath.h" \ > "$(GENERIC_DIR)/tclTomMath.h" -# The following target generates the shared libraries in dltest/ that -# are used for testing; they are included as part of the "tcltest" -# target (via the BUILD_DLTEST variable) if dynamic loading is supported -# on this platform. The Makefile in the dltest subdirectory creates -# the dltest.marker file in this directory after a successful build. +# The following target generates the shared libraries in dltest/ that are used +# for testing; they are included as part of the "tcltest" target (via the +# BUILD_DLTEST variable) if dynamic loading is supported on this platform. The +# Makefile in the dltest subdirectory creates the dltest.marker file in this +# directory after a successful build. dltest.marker: cd dltest ; $(MAKE) @@ -718,9 +708,9 @@ install-strip: INSTALL_PROGRAM="$(INSTALL_PROGRAM) ${INSTALL_STRIP_PROGRAM}" \ INSTALL_LIBRARY="$(INSTALL_LIBRARY) ${INSTALL_STRIP_LIBRARY}" -# Note: before running ranlib below, must cd to target directory because -# some ranlibs write to current directory, and this might not always be -# possible (e.g. if installing as root). +# Note: before running ranlib below, must cd to target directory because some +# ranlibs write to current directory, and this might not always be possible +# (e.g. if installing as root). install-binaries: binaries @for i in $(LIB_INSTALL_DIR) $(BIN_INSTALL_DIR) ; \ @@ -899,10 +889,10 @@ distclean: clean depend: makedepend -- $(DEPEND_SWITCHES) -- $(SRCS) -# Test binaries. The rules for tclTestInit.o and xtTestInit.o are -# complicated because they are compiled from tclAppInit.c. Can't use -# the "-o" option because this doesn't work on some strange compilers -# (e.g. UnixWare). +# Test binaries. The rules for tclTestInit.o and xtTestInit.o are complicated +# because they are compiled from tclAppInit.c. Can't use the "-o" option +# because this doesn't work on some strange compilers (e.g. UnixWare). +# # To enable concurrent parallel make of tclsh and tcltest resp xttest, these # targets have to depend on tclsh, this ensures that linking of tclsh with # tclAppInit.o does not execute concurrently with the renaming and recompiling @@ -963,7 +953,7 @@ regerror.o: $(REGHDRS) $(GENERIC_DIR)/regerrs.h $(GENERIC_DIR)/regerror.c tclAppInit.o: $(UNIX_DIR)/tclAppInit.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclAppInit.c -# On unix we want to use the normal malloc/free implementation, so we +# 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 @@ -1104,6 +1094,9 @@ tclLoadShl.o: $(UNIX_DIR)/tclLoadShl.c tclMain.o: $(GENERIC_DIR)/tclMain.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclMain.c +tclMathOp.o: $(GENERIC_DIR)/tclMathOp.c $(MATHHDRS) + $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclMathOp.c + tclNamesp.o: $(GENERIC_DIR)/tclNamesp.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNamesp.c @@ -1127,12 +1120,11 @@ tclPkg.o: $(GENERIC_DIR)/tclPkg.c # TIP #59, embedding of configuration information into the binary library. # -# Part of Tcl's configuration information are the paths where it was -# installed and where it will look for its libraries (which can be -# different). We derive this information from the variables which can -# be overridden by the user. As every path can be configured -# separately we do not remember one general prefix/exec_prefix but all -# the different paths individually. +# Part of Tcl's configuration information are the paths where it was installed +# and where it will look for its libraries (which can be different). We derive +# this information from the variables which can be overridden by the user. As +# every path can be configured separately we do not remember one general +# prefix/exec_prefix but all the different paths individually. tclPkgConfig.o: $(GENERIC_DIR)/tclPkgConfig.c $(CC) -c $(CC_SWITCHES) \ @@ -1453,9 +1445,9 @@ tclMacOSXFCmd.o: $(MAC_OSX_DIR)/tclMacOSXFCmd.c tclMacOSXNotify.o: $(MAC_OSX_DIR)/tclMacOSXNotify.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXNotify.c -# The following targets are not completely general. They are provide -# purely for documentation purposes so people who are interested in -# the Xt based notifier can modify them to suit their own installation. +# The following targets are not completely general. They are provide purely +# for documentation purposes so people who are interested in the Xt based +# notifier can modify them to suit their own installation. xttest: ${XTTEST_OBJS} ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS} \ @DL_OBJS@ ${BUILD_DLTEST} @@ -1471,10 +1463,10 @@ tclXtTest.o: $(UNIX_DIR)/tclXtTest.c $(CC) -c $(CC_SWITCHES) -I/usr/openwin/include \ $(UNIX_DIR)/tclXtTest.c -# compat binaries, these must be compiled for use in a shared library -# even though they may be placed in a static executable or library. Since -# they are included in both the tcl library and the stub library, they -# need to be relocatable. +# Compat binaries, these must be compiled for use in a shared library even +# though they may be placed in a static executable or library. Since they are +# included in both the tcl library and the stub library, they need to be +# relocatable. fixstrtod.o: $(COMPAT_DIR)/fixstrtod.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/fixstrtod.c @@ -1555,9 +1547,8 @@ checkstubs: $(TCL_LIB_FILE) done # -# Target to check that all public APIs which are not command -# implementations have an entry in section three of the distributed -# manpages. +# Target to check that all public APIs which are not command implementations +# have an entry in section three of the distributed manpages. # checkdoc: $(TCL_LIB_FILE) @@ -1580,8 +1571,7 @@ checkuchar: -egrep isalnum\|isalpha\|iscntrl\|isdigit\|islower\|isprint\|ispunct\|isspace\|isupper\|isxdigit\|toupper\|tolower $(SRCS) | grep -v UCHAR # -# Target to make sure that only symbols with "Tcl" prefixes are -# exported. +# Target to make sure that only symbols with "Tcl" prefixes are exported. # checkexports: $(TCL_LIB_FILE) @@ -1590,7 +1580,7 @@ checkexports: $(TCL_LIB_FILE) | sort -n | grep -E -v '^[Tt]cl' || true # -# Target to create a Tcl RPM for Linux. Requires that you be on a Linux +# Target to create a Tcl RPM for Linux. Requires that you be on a Linux # system. # @@ -1605,9 +1595,9 @@ rpm: all /bin/rpm rm -rf RPMS THIS.TCL.SPEC # -# Target to create a proper Tcl distribution from information in the -# master source directory. DISTDIR must be defined to indicate where -# to put the distribution. DISTDIR must be an absolute path name. +# Target to create a proper Tcl distribution from information in the master +# source directory. DISTDIR must be defined to indicate where to put the +# distribution. DISTDIR must be an absolute path name. # DISTROOT = /tmp/dist @@ -1721,8 +1711,8 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(DISTDIR)/libtommath # -# The following target can only be used for non-patch releases. Use -# the "allpatch" target below for patch releases. +# The following target can only be used for non-patch releases. Use the +# "allpatch" target below for patch releases. # alldist: dist @@ -1731,11 +1721,11 @@ alldist: dist gzip -9 $(DISTNAME)-src.tar; zip -qr8 $(ZIPNAME) $(DISTNAME) # -# The target below is similar to "alldist" except it works for patch -# releases. It is needed because patch releases are peculiar: the -# patch designation appears in the name of the compressed file -# (e.g. tcl8.0p1.tar.gz) but the extracted source directory doesn't -# include the patch designation (e.g. tcl8.0). +# The target below is similar to "alldist" except it works for patch releases. +# It is needed because patch releases are peculiar: the patch designation +# appears in the name of the compressed file (e.g. tcl8.0p1.tar.gz) but the +# extracted source directory doesn't include the patch designation (e.g., +# tcl8.0). # allpatch: dist @@ -1748,11 +1738,10 @@ allpatch: dist mv $(DISTROOT)/old $(DISTROOT)/tcl${VERSION} # -# This target creates the HTML folder for Tcl & Tk and places it -# in DISTDIR/html. It uses the tcltk-man2html.tcl tool from -# the Tcl group's tool workspace. It depends on the Tcl & Tk being -# in directories called tcl8.* & tk8.* up two directories from the -# TOOL_DIR. +# This target creates the HTML folder for Tcl & Tk and places it in +# DISTDIR/html. It uses the tcltk-man2html.tcl tool from the Tcl group's tool +# workspace. It depends on the Tcl & Tk being in directories called tcl8.* & +# tk8.* up two directories from the TOOL_DIR. # html: @@ -1773,23 +1762,21 @@ BUILD_HTML = \ # # Targets to build Solaris package of the distribution for the current -# architecture. To build stream packages for both sun4 and i86pc -# architectures: +# architecture. To build stream packages for both sun4 and i86pc +# architectures: # # On the sun4 machine, execute the following: # make distclean; ./configure # make DISTDIR= package # -# Once the build is complete, execute the following on the i86pc -# machine: +# Once the build is complete, execute the following on the i86pc machine: # make DISTDIR= package-quick # -# is the absolute path to a directory where the build should -# take place. These steps will generate the $(PACKAGE).sun4 and -# $(PACKAGE).i86pc stream packages. It is important that the packages be -# built in this fashion in order to ensure that the architecture -# independent files are exactly the same, including timestamps, in -# both packages. +# is the absolute path to a directory where the build should take +# place. These steps will generate the $(PACKAGE).sun4 and $(PACKAGE).i86pc +# stream packages. It is important that the packages be built in this fashion +# in order to ensure that the architecture independent files are exactly the +# same, including timestamps, in both packages. # PACKAGE=SCRPtcl @@ -1828,7 +1815,7 @@ package-common: # Build and install the architecture specific files in the dist directory. # -package-binaries: +package-binaries: cd $(DISTDIR)/unix/`arch`; \ $(MAKE); \ $(MAKE) install-binaries prefix=$(DISTDIR)/$(PACKAGE)/$(VERSION) \ diff --git a/win/Makefile.in b/win/Makefile.in index 861a395..b8bdbfd 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -1,26 +1,23 @@ # -# This file is a Makefile for Tcl. If it has the name "Makefile.in" -# then it is a template for a Makefile; to generate the actual Makefile, -# run "./configure", which is a configuration script generated by the -# "autoconf" program (constructs like "@foo@" will get replaced in the -# actual Makefile. +# This file is a Makefile for Tcl. If it has the name "Makefile.in" then it +# is a template for a Makefile; to generate the actual Makefile, run +# "./configure", which is a configuration script generated by the "autoconf" +# program (constructs like "@foo@" will get replaced in the actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.109 2006/11/09 16:52:31 dgp Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.110 2006/11/25 17:18:10 dkf Exp $ VERSION = @TCL_VERSION@ -#---------------------------------------------------------------- -# Things you can change to personalize the Makefile for your own -# site (you can make these changes in either Makefile.in or -# Makefile, but changes to Makefile will get lost if you re-run -# the configuration script). -#---------------------------------------------------------------- +#-------------------------------------------------------------------------- +# Things you can change to personalize the Makefile for your own site (you can +# make these changes in either Makefile.in or Makefile, but changes to +# Makefile will get lost if you re-run the configuration script). +#-------------------------------------------------------------------------- -# Default top-level directories in which to install architecture- -# specific files (exec_prefix) and machine-independent files such -# as scripts (prefix). The values specified here may be overridden -# at configure-time with the --exec-prefix and --prefix options -# to the "configure" script. +# Default top-level directories in which to install architecture-specific +# files (exec_prefix) and machine-independent files such as scripts (prefix). +# The values specified here may be overridden at configure-time with the +# --exec-prefix and --prefix options to the "configure" script. prefix = @prefix@ exec_prefix = @exec_prefix@ @@ -29,16 +26,15 @@ libdir = @libdir@ includedir = @includedir@ mandir = @mandir@ -# The following definition can be set to non-null for special systems -# like AFS with replication. It allows the pathnames used for installation -# to be different than those used for actually reference files at -# run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix -# when installing files. +# The following definition can be set to non-null for special systems like AFS +# with replication. It allows the pathnames used for installation to be +# different than those used for actually reference files at run-time. +# INSTALL_ROOT is prepended to $prefix and $exec_prefix when installing files. INSTALL_ROOT = -# Directory from which applications will reference the library of Tcl -# scripts (note: you can set the TCL_LIBRARY environment variable at -# run-time to override this value): +# Directory from which applications will reference the library of Tcl scripts +# (note: you can set the TCL_LIBRARY environment variable at run-time to +# override this value): TCL_LIBRARY = $(prefix)/lib/tcl$(VERSION) # Path to use at runtime to refer to LIB_INSTALL_DIR: @@ -65,12 +61,10 @@ MAN_INSTALL_DIR = $(INSTALL_ROOT)$(mandir) # Directory in which to install manual entry for tclsh: MAN1_INSTALL_DIR = $(MAN_INSTALL_DIR)/man1 -# Directory in which to install manual entries for Tcl's C library -# procedures: +# Directory in which to install manual entries for Tcl's C library procedures: MAN3_INSTALL_DIR = $(MAN_INSTALL_DIR)/man3 -# Directory in which to install manual entries for the built-in -# Tcl commands: +# Directory in which to install manual entries for the built-in Tcl commands: MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann # Libraries built with optimization switches have this additional extension @@ -90,8 +84,8 @@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ #CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE) CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ -# To enable compilation debugging reverse the comment characters on -# one of the following lines. +# To enable compilation debugging reverse the comment characters on one of the +# following lines. COMPILE_DEBUG_FLAGS = #COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG #COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS @@ -140,11 +134,10 @@ SHARED_LIBRARIES = $(TCL_DLL_FILE) $(TCL_STUB_LIB_FILE) \ $(DDE_DLL_FILE) $(REG_DLL_FILE) $(PIPE_DLL_FILE) STATIC_LIBRARIES = $(TCL_LIB_FILE) $(REG_LIB_FILE) $(DDE_LIB_FILE) -# TCL_EXE is the name of a tclsh executable that is available *BEFORE* -# running make for the first time. Certain build targets (make genstubs) -# need it to be available on the PATH. This executable should *NOT* be -# required just to do a normal build although it can be required to run -# make dist. +# TCL_EXE is the name of a tclsh executable that is available *BEFORE* running +# make for the first time. Certain build targets (make genstubs) need it to be +# available on the PATH. This executable should *NOT* be required just to do a +# normal build although it can be required to run make dist. TCL_EXE = tclsh TCLSH = tclsh$(VER)${EXESUFFIX} @@ -154,9 +147,8 @@ MAN2TCL = man2tcl$(EXEEXT) @SET_MAKE@ -# Setting the VPATH variable to a list of paths will cause the -# makefile to look into these paths when resolving .c to .obj -# dependencies. +# Setting the VPATH variable to a list of paths will cause the Makefile to +# look into these paths when resolving .c to .obj dependencies. VPATH = $(GENERIC_DIR):$(TOMMATH_DIR):$(WIN_DIR):$(COMPAT_DIR) @@ -250,6 +242,7 @@ GENERIC_OBJS = \ tclListObj.$(OBJEXT) \ tclLoad.$(OBJEXT) \ tclMain.$(OBJEXT) \ + tclMathOp.$(OBJEXT) \ tclNamesp.$(OBJEXT) \ tclNotify.$(OBJEXT) \ tclObj.$(OBJEXT) \ @@ -359,7 +352,7 @@ WIN_OBJS = \ tclWinPipe.$(OBJEXT) \ tclWinSock.$(OBJEXT) \ tclWinThrd.$(OBJEXT) \ - tclWinTime.$(OBJEXT) + tclWinTime.$(OBJEXT) COMPAT_OBJS = \ strtoll.$(OBJEXT) strtoull.$(OBJEXT) @@ -410,8 +403,8 @@ cat32.$(OBJEXT): cat.c $(CAT32): cat32.$(OBJEXT) $(CC) $(CFLAGS) cat32.$(OBJEXT) $(CC_EXENAME) $(LIBS) $(LDFLAGS_CONSOLE) -# The following targets are configured by autoconf to generate either -# a shared library or static library +# The following targets are configured by autoconf to generate either a shared +# library or static library ${TCL_STUB_LIB_FILE}: ${STUB_OBJS} @$(RM) ${TCL_STUB_LIB_FILE} @@ -443,14 +436,13 @@ ${REG_LIB_FILE}: ${REG_OBJS} ${TCL_LIB_FILE} @$(RM) ${REG_LIB_FILE} @MAKE_LIB@ ${REG_OBJS} ${TCL_LIB_FILE} -# PIPE_DLL_FILE is actually an executable, don't build it -# like a DLL. +# PIPE_DLL_FILE is actually an executable, don't build it like a DLL. ${PIPE_DLL_FILE}: ${PIPE_OBJS} @$(RM) ${PIPE_DLL_FILE} @MAKE_EXE@ $(CFLAGS) ${PIPE_OBJS} $(LIBS) $(LDFLAGS_CONSOLE) -# Add the object extension to the implicit rules. By default .obj is not +# Add the object extension to the implicit rules. By default .obj is not # automatically added. .SUFFIXES: .${OBJEXT} @@ -491,12 +483,11 @@ tclWinDde.${OBJEXT} : tclWinDde.c # TIP #59, embedding of configuration information into the binary library. # -# Part of Tcl's configuration information are the paths where it was -# installed and where it will look for its libraries (which can be -# different). We derive this information from the variables which can -# be overridden by the user. As every path can be configured -# separately we do not remember one general prefix/exec_prefix but all -# the different paths individually. +# Part of Tcl's configuration information are the paths where it was installed +# and where it will look for its libraries (which can be different). We derive +# this information from the variables which can be overridden by the user. As +# every path can be configured separately we do not remember one general +# prefix/exec_prefix but all the different paths individually. tclPkgConfig.${OBJEXT}: tclPkgConfig.c $(CC) -c $(CC_SWITCHES) \ @@ -514,8 +505,8 @@ tclPkgConfig.${OBJEXT}: tclPkgConfig.c -DBUILD_tcl \ @DEPARG@ $(CC_OBJNAME) -# The following objects are part of the stub library and should not -# be built as DLL objects but none of the symbols should be exported +# The following objects are part of the stub library and should not be built +# as DLL objects but none of the symbols should be exported tclStubLib.${OBJEXT}: tclStubLib.c $(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME) @@ -529,11 +520,11 @@ tclStubLib.${OBJEXT}: tclStubLib.c .rc.$(RES): $(RC) @RC_OUT@ $@ @RC_TYPE@ @RC_DEFINES@ @RC_INCLUDE@ "$(GENERIC_DIR_NATIVE)" @RC_INCLUDE@ "$(WIN_DIR_NATIVE)" @DEPARG@ -# The following target generates the file generic/tclDate.c -# from the yacc grammar found in generic/tclGetDate.y. This is -# only run by hand as yacc is not available in all environments. -# The name of the .c file is different than the name of the .y file -# so that make doesn't try to automatically regenerate the .c file. +# The following target generates the file generic/tclDate.c from the yacc +# grammar found in generic/tclGetDate.y. This is only run by hand as yacc is +# not available in all environments. The name of the .c file is different than +# the name of the .y file so that make doesn't try to automatically regenerate +# the .c file. gendate: bison --output-file=$(GENERIC_DIR)/tclDate.c \ @@ -541,9 +532,8 @@ gendate: --no-lines \ $(GENERIC_DIR)/tclGetDate.y -# The following target generates the file generic/tclTomMath.h. -# It needs to be run (and the results checked) after updating -# to a new release of libtommath. +# The following target generates the file generic/tclTomMath.h. It needs to be +# run (and the results checked) after updating to a new release of libtommath. gentommath_h: $(TCL_EXE) "$(ROOT_DIR_NATIVE)\tools\fix_tommath_h.tcl" \ @@ -691,8 +681,8 @@ install-private-headers: libraries $(COPY) "$$i" "$(PRIVATE_INCLUDE_INSTALL_DIR)"; \ done; -# Specifying TESTFLAGS on the command line is the standard way to pass -# args to tcltest, ie: +# Specifying TESTFLAGS on the command line is the standard way to pass args to +# tcltest, i.e.: # % make test TESTFLAGS="-verbose bps -file fileName.test" test: binaries $(TCLTEST) @@ -707,8 +697,8 @@ runtest: binaries $(TCLTEST) ./$(TCLTEST) $(TESTFLAGS) -load "set ::ddelib [file normalize ${DDE_DLL_FILE}]; \ set ::reglib [file normalize ${REG_DLL_FILE}]" $(SCRIPT) -# This target can be used to run tclsh from the build directory -# via `make shell SCRIPT=foo.tcl` +# This target can be used to run tclsh from the build directory via +# `make shell SCRIPT=foo.tcl` shell: binaries @TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ ./$(TCLSH) $(SCRIPT) diff --git a/win/makefile.bc b/win/makefile.bc index 75d7ca4..0a847a0 100644 --- a/win/makefile.bc +++ b/win/makefile.bc @@ -231,6 +231,7 @@ TCLOBJS = \ $(TMPDIR)\tclListObj.obj \ $(TMPDIR)\tclLoad.obj \ $(TMPDIR)\tclMain.obj \ + $(TMPDIR)\tclMathOp.obj \ $(TMPDIR)\tclNamesp.obj \ $(TMPDIR)\tclNotify.obj \ $(TMPDIR)\tclObj.obj \ diff --git a/win/makefile.vc b/win/makefile.vc index d30fb0b..1a5bb27 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -12,7 +12,7 @@ # Copyright (c) 2001-2004 David Gravereaux. # #------------------------------------------------------------------------------ -# RCS: @(#) $Id: makefile.vc,v 1.155 2006/11/09 16:52:31 dgp Exp $ +# RCS: @(#) $Id: makefile.vc,v 1.156 2006/11/25 17:18:10 dkf Exp $ #------------------------------------------------------------------------------ # Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) @@ -291,6 +291,7 @@ TCLOBJS = \ $(TMP_DIR)\tclLiteral.obj \ $(TMP_DIR)\tclLoad.obj \ $(TMP_DIR)\tclMain.obj \ + $(TMP_DIR)\tclMathOp.obj \ $(TMP_DIR)\tclNamesp.obj \ $(TMP_DIR)\tclNotify.obj \ $(TMP_DIR)\tclObj.obj \ -- cgit v0.12