summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2006-11-25 17:18:09 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2006-11-25 17:18:09 (GMT)
commit00c0664fd2487670b9bf12e3c2ba32fa4a5ea944 (patch)
treeb03d00f5b03a56fb252e681a3f513c0a188d6a2d
parentf8b1db93f84f1296cdc14b38c7de3c2538976f45 (diff)
downloadtcl-00c0664fd2487670b9bf12e3c2ba32fa4a5ea944.zip
tcl-00c0664fd2487670b9bf12e3c2ba32fa4a5ea944.tar.gz
tcl-00c0664fd2487670b9bf12e3c2ba32fa4a5ea944.tar.bz2
Finished coding part of TIP#174. Still have tests and docs to do.
-rw-r--r--ChangeLog8
-rw-r--r--generic/tclCompCmds.c1416
-rw-r--r--generic/tclMathOp.c2870
-rw-r--r--unix/Makefile.in347
-rw-r--r--win/Makefile.in120
-rw-r--r--win/makefile.bc1
-rw-r--r--win/makefile.vc3
7 files changed, 3127 insertions, 1638 deletions
diff --git a/ChangeLog b/ChangeLog
index 77ce434..a5cfee4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2006-11-25 Donal K. Fellows <dkf@users.sf.net>
+
+ 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 <dkf@users.sf.net>
* 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 <math.h>
-#include <float.h>
-
/*
* 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,142 +4690,6 @@ TclCompileDivOpCmd(
}
int
-TclLshiftOpCmd(
- 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;
- }
-
- /* 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));
- 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<<shift));
- return TCL_OK;
- }
-
- /* Handle shifts within the native wide range */
- if ((type1 != TCL_NUMBER_BIG)
- && ((size_t)shift < CHAR_BIT*sizeof(Tcl_WideInt))) {
- Tcl_WideInt w;
-
- Tcl_GetWideIntFromObj(NULL, objv[1], &w);
- if (!(((w>0) ? w : ~w) & -(((Tcl_WideInt)1)
- << (CHAR_BIT*sizeof(Tcl_WideInt)-1-shift)))) {
- Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w<<shift));
- return TCL_OK;
- }
- }
-
- {
- mp_int big, bigResult;
-
- if (Tcl_IsShared(objv[1])) {
- Tcl_GetBignumFromObj(NULL, objv[1], &big);
- } else {
- Tcl_GetBignumAndClearObj(NULL, objv[1], &big);
- }
-
- mp_init(&bigResult);
- mp_mul_2d(&big, shift, &bigResult);
- 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;
-}
-
-int
TclCompileLshiftOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -5005,173 +4709,6 @@ TclCompileLshiftOpCmd(
}
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;
-}
-
-int
TclCompileRshiftOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -5191,203 +4728,6 @@ TclCompileRshiftOpCmd(
}
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;
-}
-
-int
TclCompileModOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -5407,45 +4747,6 @@ TclCompileModOpCmd(
}
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,
@@ -5465,31 +4766,6 @@ TclCompileNeqOpCmd(
}
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,
@@ -5509,37 +4785,6 @@ TclCompileStrneqOpCmd(
}
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<len ; i++) {
- s2 = Tcl_GetStringFromObj(listObj[i], &s2len);
- if (s1len == s2len && !strcmp(s1, s2)) {
- Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
- return TCL_OK;
- }
- }
- Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0);
- return TCL_OK;
-}
-
-int
TclCompileInOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -5559,37 +4804,6 @@ TclCompileInOpCmd(
}
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 ; i<len ; i++) {
- s2 = Tcl_GetStringFromObj(listObj[i], &s2len);
- if (s1len == s2len && !strcmp(s1, s2)) {
- Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0);
- return TCL_OK;
- }
- }
- Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
- return TCL_OK;
-}
-
-int
TclCompileNiOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -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<objc-1 ; i++) {
- switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
- case TCL_ERROR:
- /*
- * Got a string
- */
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (TclpUtfNcmp2(str1, str2,
- (size_t) ((len1 < len2) ? len1 : len2)) >= 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<objc-1 ; i++) {
- switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
- case TCL_ERROR:
- /*
- * Got a string
- */
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (TclpUtfNcmp2(str1, str2,
- (size_t) ((len1 < len2) ? len1 : len2)) > 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<objc-1 ; i++) {
- switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
- case TCL_ERROR:
- /*
- * Got a string
- */
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (TclpUtfNcmp2(str1, str2,
- (size_t) ((len1 < len2) ? len1 : len2)) <= 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
TclCompileGreaterOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -5909,57 +4970,6 @@ TclCompileGreaterOpCmd(
}
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<objc-1 ; i++) {
- switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
- case TCL_ERROR:
- /*
- * Got a string
- */
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (TclpUtfNcmp2(str1, str2,
- (size_t) ((len1 < len2) ? len1 : len2)) < 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
TclCompileGeqOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -6009,56 +5019,6 @@ TclCompileGeqOpCmd(
}
int
-TclEqOpCmd(
- 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<objc-1 ; i++) {
- switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
- case TCL_ERROR:
- /*
- * Got a string
- */
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (len1 != len2 || strcmp(str1, str2)) {
- result = 0;
- i = objc;
- }
- continue;
- case TCL_OK:
- /*
- * Got proper numbers
- */
- if (cmp != MP_EQ) {
- 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
TclCompileEqOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -6108,32 +5068,6 @@ TclCompileEqOpCmd(
}
int
-TclStreqOpCmd(
- ClientData clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *const objv[])
-{
- int result = 1;
-
- if (objc > 2) {
- int i, len1, len2;
- const char *str1, *str2;
-
- for (i=1 ; i<objc-1 ; i++) {
- str1 = Tcl_GetStringFromObj(objv[i], &len1);
- str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
- if (len1 != len2 || strcmp(str1, str2)) {
- result = 0;
- break;
- }
- }
- }
- Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result);
- return TCL_OK;
-}
-
-int
TclCompileStreqOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
@@ -6182,308 +5116,6 @@ TclCompileStreqOpCmd(
return TCL_OK;
}
-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;
-}
-
/*
* 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 <math.h>
+#include <float.h>
+
+/*
+ * 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 <float.h>
+# else /* NO_FLOAT_H */
+# ifndef NO_VALUES_H
+# include <values.h>
+# 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<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntFloat(interp, sumPtr, INST_ADD,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(sumPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(sumPtr);
+ sumPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, sumPtr);
+ Tcl_DecrRefCount(sumPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclMulOpCmd --
+ *
+ * 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
+TclMulOpCmd(
+ ClientData clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const objv[])
+{
+ if (objc < 2) {
+ Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
+ 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_MULT,objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *prodPtr = objv[1];
+ int i;
+
+ Tcl_IncrRefCount(prodPtr);
+ for (i=2 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntFloat(interp, prodPtr, INST_MULT,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(prodPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(prodPtr);
+ prodPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, prodPtr);
+ Tcl_DecrRefCount(prodPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclAndOpCmd --
+ *
+ * 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
+TclAndOpCmd(
+ ClientData clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const objv[])
+{
+ if (objc < 2) {
+ Tcl_SetIntObj(Tcl_GetObjResult(interp), -1);
+ 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 = CombineIntOnly(interp, objv[1],INST_BITAND,objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *accumPtr = objv[1];
+ int i;
+
+ Tcl_IncrRefCount(accumPtr);
+ for (i=2 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntOnly(interp, accumPtr, INST_BITAND,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(accumPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(accumPtr);
+ accumPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, accumPtr);
+ Tcl_DecrRefCount(accumPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclOrOpCmd --
+ *
+ * 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
+TclOrOpCmd(
+ 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 = CombineIntOnly(interp, objv[1],INST_BITOR,objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *accumPtr = objv[1];
+ int i;
+
+ Tcl_IncrRefCount(accumPtr);
+ for (i=2 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntOnly(interp, accumPtr, INST_BITOR,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(accumPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(accumPtr);
+ accumPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, accumPtr);
+ Tcl_DecrRefCount(accumPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclXorOpCmd --
+ *
+ * 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
+TclXorOpCmd(
+ 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 = CombineIntOnly(interp, objv[1],INST_BITXOR,objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *accumPtr = objv[1];
+ int i;
+
+ Tcl_IncrRefCount(accumPtr);
+ for (i=2 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntOnly(interp, accumPtr, INST_BITXOR,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(accumPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(accumPtr);
+ accumPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, accumPtr);
+ Tcl_DecrRefCount(accumPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclPowOpCmd --
+ *
+ * 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
+TclPowOpCmd(
+ ClientData clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const objv[])
+{
+ if (objc < 2) {
+ Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
+ 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_EXPON,objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *powPtr = objv[objc-1];
+ int i;
+
+ Tcl_IncrRefCount(powPtr);
+ for (i=objc-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 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntFloat(interp, diffPtr, INST_SUB,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(diffPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(diffPtr);
+ diffPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, diffPtr);
+ Tcl_DecrRefCount(diffPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclDivOpCmd --
+ *
+ * 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
+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;
+ } else if (objc == 2) {
+ /*
+ * Only a single argument, so we compute the reciprocal.
+ */
+
+ Tcl_Obj *onePtr = Tcl_NewDoubleObj(1.0);
+ Tcl_Obj *resPtr;
+
+ Tcl_IncrRefCount(onePtr);
+ resPtr = CombineIntFloat(interp, onePtr, INST_DIV, objv[1]);
+ if (resPtr == NULL) {
+ TclDecrRefCount(onePtr);
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ TclDecrRefCount(onePtr);
+ 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_DIV, objv[2]);
+ if (resPtr == NULL) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, resPtr);
+ return TCL_OK;
+ } else {
+ Tcl_Obj *numeratorPtr = objv[1];
+ int i;
+
+ Tcl_IncrRefCount(numeratorPtr);
+ for (i=2 ; i<objc ; i++) {
+ Tcl_Obj *resPtr = CombineIntFloat(interp, numeratorPtr, INST_DIV,
+ objv[i]);
+
+ if (resPtr == NULL) {
+ TclDecrRefCount(numeratorPtr);
+ return TCL_ERROR;
+ }
+ Tcl_IncrRefCount(resPtr);
+ TclDecrRefCount(numeratorPtr);
+ numeratorPtr = resPtr;
+ }
+ Tcl_SetObjResult(interp, numeratorPtr);
+ Tcl_DecrRefCount(numeratorPtr); /* Public form since we know we won't
+ * be freeing this object now. */
+ return TCL_OK;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclLshiftOpCmd --
+ *
+ * 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
+TclLshiftOpCmd(
+ 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;
+ }
+
+ /* 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));
+ 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<<shift));
+ return TCL_OK;
+ }
+
+ /* Handle shifts within the native wide range */
+ if ((type1 != TCL_NUMBER_BIG)
+ && ((size_t)shift < CHAR_BIT*sizeof(Tcl_WideInt))) {
+ Tcl_WideInt w;
+
+ Tcl_GetWideIntFromObj(NULL, objv[1], &w);
+ if (!(((w>0) ? w : ~w) & -(((Tcl_WideInt)1)
+ << (CHAR_BIT*sizeof(Tcl_WideInt)-1-shift)))) {
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(w<<shift));
+ return TCL_OK;
+ }
+ }
+
+ {
+ mp_int big, bigResult;
+
+ if (Tcl_IsShared(objv[1])) {
+ Tcl_GetBignumFromObj(NULL, objv[1], &big);
+ } else {
+ Tcl_GetBignumAndClearObj(NULL, objv[1], &big);
+ }
+
+ mp_init(&bigResult);
+ mp_mul_2d(&big, shift, &bigResult);
+ 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclRshiftOpCmd --
+ *
+ * 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
+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<len ; i++) {
+ s2 = Tcl_GetStringFromObj(listObj[i], &s2len);
+ if (s1len == s2len && !strcmp(s1, s2)) {
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
+ return TCL_OK;
+ }
+ }
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclNiOpCmd --
+ *
+ * This procedure is invoked to process the "::tcl::mathop::ni" Tcl
+ * command. See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+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 ; i<len ; i++) {
+ s2 = Tcl_GetStringFromObj(listObj[i], &s2len);
+ if (s1len == s2len && !strcmp(s1, s2)) {
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0);
+ return TCL_OK;
+ }
+ }
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclLessOpCmd --
+ *
+ * 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
+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<objc-1 ; i++) {
+ switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
+ case TCL_ERROR:
+ /*
+ * Got a string
+ */
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (TclpUtfNcmp2(str1, str2,
+ (size_t) ((len1 < len2) ? len1 : len2)) >= 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<objc-1 ; i++) {
+ switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
+ case TCL_ERROR:
+ /*
+ * Got a string
+ */
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (TclpUtfNcmp2(str1, str2,
+ (size_t) ((len1 < len2) ? len1 : len2)) > 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<objc-1 ; i++) {
+ switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
+ case TCL_ERROR:
+ /*
+ * Got a string
+ */
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (TclpUtfNcmp2(str1, str2,
+ (size_t) ((len1 < len2) ? len1 : len2)) <= 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGeqOpCmd --
+ *
+ * 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
+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<objc-1 ; i++) {
+ switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
+ case TCL_ERROR:
+ /*
+ * Got a string
+ */
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (TclpUtfNcmp2(str1, str2,
+ (size_t) ((len1 < len2) ? len1 : len2)) < 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclEqOpCmd --
+ *
+ * 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
+TclEqOpCmd(
+ 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<objc-1 ; i++) {
+ switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
+ case TCL_ERROR:
+ /*
+ * Got a string
+ */
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (len1 != len2 || strcmp(str1, str2)) {
+ result = 0;
+ i = objc;
+ }
+ continue;
+ case TCL_OK:
+ /*
+ * Got proper numbers
+ */
+ if (cmp != MP_EQ) {
+ 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclStreqOpCmd --
+ *
+ * This procedure is invoked to process the "::tcl::mathop::eq" Tcl
+ * command. See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclStreqOpCmd(
+ ClientData clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const objv[])
+{
+ int result = 1;
+
+ if (objc > 2) {
+ int i, len1, len2;
+ const char *str1, *str2;
+
+ for (i=1 ; i<objc-1 ; i++) {
+ str1 = Tcl_GetStringFromObj(objv[i], &len1);
+ str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
+ if (len1 != len2 || strcmp(str1, str2)) {
+ result = 0;
+ break;
+ }
+ }
+ }
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), result);
+ return TCL_OK;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */
diff --git a/unix/Makefile.in b/unix/Makefile.in
index 1cbb050..e7b2207 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -1,30 +1,28 @@
#
-# 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.197 2006/11/09 16:52:30 dgp Exp $
+# RCS: @(#) $Id: Makefile.in,v 1.198 2006/11/25 17:18:10 dkf Exp $
VERSION = @TCL_VERSION@
MAJOR_VERSION = @TCL_MAJOR_VERSION@
MINOR_VERSION = @TCL_MINOR_VERSION@
PATCH_LEVEL = @TCL_PATCH_LEVEL@
-#----------------------------------------------------------------
-# 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. The *dir vars are standard configure
-# substitutions that are based off prefix and exec_prefix.
+# 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. The *dir vars
+# are standard configure substitutions that are based off prefix and
+# exec_prefix.
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -33,11 +31,10 @@ 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 = $(DESTDIR)
# Path for the platform independent Tcl scripting libraries:
@@ -70,12 +67,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
# Path to the html documentation dir:
@@ -109,39 +104,37 @@ LDFLAGS_DEBUG = @LDFLAGS_DEBUG@
LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@
LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@
-# To disable ANSI-C procedure prototypes reverse the comment characters
-# on the following lines:
+# To disable ANSI-C procedure prototypes reverse the comment characters on the
+# following lines:
PROTO_FLAGS =
#PROTO_FLAGS = -DNO_PROTOTYPE
-# If you use the setenv, putenv, or unsetenv procedures to modify
-# environment variables in your application and you'd like those
-# modifications to appear in the "env" Tcl variable, switch the
-# comments on the two lines below so that Tcl provides these
-# procedures instead of your standard C library.
+# If you use the setenv, putenv, or unsetenv procedures to modify environment
+# variables in your application and you'd like those modifications to appear
+# in the "env" Tcl variable, switch the comments on the two lines below so
+# that Tcl provides these procedures instead of your standard C library.
ENV_FLAGS =
#ENV_FLAGS = -DTclSetEnv=setenv -DTcl_PutEnv=putenv -DTclUnsetEnv=unsetenv
-# To compile for non-UNIX systems (so that only the non-UNIX-specific
-# commands are available), reverse the comment characters on the
-# following pairs of lines. In addition, you'll have to provide your
-# own replacement for the "panic" procedure (see panic.c for what
-# the current one does).
+# To compile for non-UNIX systems (so that only the non-UNIX-specific commands
+# are available), reverse the comment characters on the following pairs of
+# lines. In addition, you'll have to provide your own replacement for the
+# "panic" procedure (see panic.c for what the current one does).
GENERIC_FLAGS =
#GENERIC_FLAGS = -DTCL_GENERIC_ONLY
UNIX_OBJS = tclUnixChan.o tclUnixEvent.o tclUnixFCmd.o \
tclUnixFile.o tclUnixPipe.o tclUnixSock.o \
tclUnixTime.o tclUnixInit.o tclUnixThrd.o \
- tclUnixCompat.o
+ tclUnixCompat.o
#UNIX_OBJS =
NOTIFY_OBJS = tclUnixNotfy.o
#NOTIFY_OBJS =
# To enable memory debugging, call configure with --enable-symbols=mem
-# Warning: if you enable memory debugging, you must do it *everywhere*,
-# including all the code that calls Tcl, and you must use ckalloc and
-# ckfree everywhere instead of malloc and free.
+# Warning: if you enable memory debugging, you must do it *everywhere*,
+# including all the code that calls Tcl, and you must use ckalloc and ckfree
+# everywhere instead of malloc and free.
TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
#TCL_STUB_LIB_FILE = libtclstub.a
@@ -152,19 +145,19 @@ STUB_LIB_FILE = ${TCL_STUB_LIB_FILE}
TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
#TCL_STUB_LIB_FLAG = -ltclstub
-# To compile without backward compatibility and deprecated code
-# uncomment the following
+# To compile without backward compatibility and deprecated code uncomment the
+# following
NO_DEPRECATED_FLAGS =
#NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED
-# Some versions of make, like SGI's, use the following variable to
-# determine which shell to use for executing commands:
+# Some versions of make, like SGI's, use the following variable to determine
+# which shell to use for executing commands:
SHELL = /bin/sh
-# Tcl used to let the configure script choose which program to use
-# for installing, but there are just too many different versions of
-# "install" around; better to use the install-sh script that comes
-# with the distribution, which is slower but guaranteed to work.
+# Tcl used to let the configure script choose which program to use for
+# installing, but there are just too many different versions of "install"
+# around; better to use the install-sh script that comes with the
+# distribution, which is slower but guaranteed to work.
INSTALL_STRIP_PROGRAM = -s
INSTALL_STRIP_LIBRARY = -S -S
@@ -174,18 +167,16 @@ INSTALL_PROGRAM = ${INSTALL}
INSTALL_LIBRARY = ${INSTALL}
INSTALL_DATA = ${INSTALL} -m 644
-# 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
-# The symbols below provide support for dynamic loading and shared
-# libraries. See configure.in for a description of what the
-# symbols mean. The values of the symbols are normally set by the
-# configure script. You shouldn't normally need to modify any of
-# these definitions by hand.
+# The symbols below provide support for dynamic loading and shared libraries.
+# See configure.in for a description of what the symbols mean. The values of
+# the symbols are normally set by the configure script. You shouldn't normally
+# need to modify any of these definitions by hand.
STLIB_LD = @STLIB_LD@
SHLIB_LD = @SHLIB_LD@
@@ -198,17 +189,17 @@ SHLIB_SUFFIX = @SHLIB_SUFFIX@
DLTEST_TARGETS = dltest.marker
-# Additional search flags needed to find the various shared libraries
-# at run-time. The first symbol is for use when creating a binary
-# with cc, and the second is for use when running ld directly.
+# Additional search flags needed to find the various shared libraries at
+# run-time. The first symbol is for use when creating a binary with cc, and
+# the second is for use when running ld directly.
CC_SEARCH_FLAGS = @CC_SEARCH_FLAGS@
LD_SEARCH_FLAGS = @LD_SEARCH_FLAGS@
-# The following symbol is defined to "$(DLTEST_TARGETS)" if dynamic
-# loading is available; this causes everything in the "dltest"
-# subdirectory to be built when making "tcltest. If dynamic loading
-# isn't available, configure defines this symbol to an empty string,
-# in which case the shared libraries aren't built.
+# The following symbol is defined to "$(DLTEST_TARGETS)" if dynamic loading is
+# available; this causes everything in the "dltest" subdirectory to be built
+# when making "tcltest. If dynamic loading isn't available, configure defines
+# this symbol to an empty string, in which case the shared libraries aren't
+# built.
BUILD_DLTEST = @BUILD_DLTEST@
#BUILD_DLTEST =
@@ -227,11 +218,11 @@ TCL_BUILD_EXP_FILE = @TCL_BUILD_EXP_FILE@
# support for embedded libraries on Darwin / Mac OS X
DYLIB_INSTALL_DIR = ${LIB_RUNTIME_DIR}
-#----------------------------------------------------------------
-# The information below is modified by the configure script when
-# Makefile is generated from Makefile.in. You shouldn't normally
-# modify any of this stuff by hand.
-#----------------------------------------------------------------
+#--------------------------------------------------------------------------
+# The information below is modified by the configure script when Makefile is
+# generated from Makefile.in. You shouldn't normally modify any of this stuff
+# by hand.
+#--------------------------------------------------------------------------
COMPAT_OBJS = @LIBOBJS@
@@ -255,28 +246,27 @@ TCL_BUILDTIME_LIBRARY = @TCL_SRC_DIR@/library
CC = @CC@
#CC = purify -best-effort @CC@ -DPURIFY
-# Flags to be passed to installManPage to control how the manpages
-# should be installed (symlinks, compression, package name suffix).
+# Flags to be passed to installManPage to control how the manpages should be
+# installed (symlinks, compression, package name suffix).
MAN_FLAGS = @MAN_FLAGS@
# If non-empty, install the timezone files that are included with Tcl,
# otherwise use the ones that ship with the OS.
INSTALL_TZDATA = @INSTALL_TZDATA@
-#----------------------------------------------------------------
-# The information below is usually usable as is. The configure
-# script won't modify it and it only exists to make working
-# around selected rare system configurations easier.
-#----------------------------------------------------------------
+#--------------------------------------------------------------------------
+# The information below is usually usable as is. The configure script won't
+# modify it and it only exists to make working around selected rare system
+# configurations easier.
+#--------------------------------------------------------------------------
GDB = gdb
DDD = ddd
-#----------------------------------------------------------------
-# The information below should be usable as is. The configure
-# script won't modify it and you shouldn't need to modify it
-# either.
-#----------------------------------------------------------------
+#--------------------------------------------------------------------------
+# The information below should be usable as is. The configure script won't
+# modify it and you shouldn't need to modify it either.
+#--------------------------------------------------------------------------
CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \
@@ -300,7 +290,7 @@ TCLTEST_OBJS = tclTestInit.o tclTest.o tclTestObj.o tclTestProcBodyObj.o \
tclThreadTest.o tclUnixTest.o
XTTEST_OBJS = xtTestInit.o tclTest.o tclTestObj.o tclTestProcBodyObj.o \
- tclThreadTest.o tclUnixTest.o tclXtNotify.o tclXtTest.o
+ tclThreadTest.o tclUnixTest.o tclXtNotify.o tclXtTest.o
GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \
tclAsync.o tclBasic.o tclBinary.o tclCkalloc.o tclClock.o \
@@ -309,7 +299,7 @@ GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \
tclEnv.o tclEvent.o tclExecute.o tclFCmd.o tclFileName.o tclGet.o \
tclHash.o tclHistory.o tclIndexObj.o tclInterp.o tclIO.o tclIOCmd.o \
tclIORChan.o tclIOGT.o tclIOSock.o tclIOUtil.o tclLink.o tclListObj.o \
- tclLiteral.o tclLoad.o tclMain.o tclNamesp.o tclNotify.o \
+ tclLiteral.o tclLoad.o tclMain.o tclMathOp.o tclNamesp.o tclNotify.o \
tclObj.o tclPanic.o tclParse.o tclPathObj.o tclPipe.o \
tclPkg.o tclPkgConfig.o tclPosixStr.o \
tclPreserve.o tclProc.o tclRegexp.o \
@@ -406,6 +396,7 @@ GENERIC_SRCS = \
$(GENERIC_DIR)/tclLiteral.c \
$(GENERIC_DIR)/tclLoad.c \
$(GENERIC_DIR)/tclMain.c \
+ $(GENERIC_DIR)/tclMathOp.c \
$(GENERIC_DIR)/tclNamesp.c \
$(GENERIC_DIR)/tclNotify.c \
$(GENERIC_DIR)/tclObj.c \
@@ -539,9 +530,9 @@ MAC_OSX_SRCS = \
$(MAC_OSX_DIR)/tclMacOSXFCmd.c \
$(MAC_OSX_DIR)/tclMacOSXNotify.c
-# Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those
-# files won't compile on the current machine, and they will cause
-# problems for things like "make depend".
+# Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those files
+# won't compile on the current machine, and they will cause problems for
+# things like "make depend".
SRCS = $(GENERIC_SRCS) $(TOMMATH_SRCS) \
$(UNIX_SRCS) $(NOTIFY_SRCS) $(STUB_SRCS) \
@@ -555,8 +546,8 @@ libraries:
doc:
-# The following target is configured by autoconf to generate either
-# a shared library or non-shared library for Tcl.
+# The following target is configured by autoconf to generate either a shared
+# library or non-shared library for Tcl.
${LIB_FILE}: ${OBJS} ${STUB_LIB_FILE}
rm -f $@
@MAKE_LIB@
@@ -565,15 +556,14 @@ ${STUB_LIB_FILE}: ${STUB_LIB_OBJS}
rm -f $@
@MAKE_STUB_LIB@
-# Make target which outputs the list of the .o contained in the Tcl lib
-# usefull to build a single big shared library containing Tcl and other
-# extensions. used for the Tcl Plugin. -- dl
-# The dependency on OBJS is not there because we just want the list
-# of objects here, not actually building them
+# Make target which outputs the list of the .o contained in the Tcl lib useful
+# to build a single big shared library containing Tcl and other extensions.
+# Used for the Tcl Plugin. -- dl
+# The dependency on OBJS is not there because we just want the list of objects
+# here, not actually building them
tclLibObjs:
@echo ${OBJS}
-# This targets actually build the objects needed for the lib in the above
-# case
+# This targets actually build the objects needed for the lib in the above case
objs: ${OBJS}
@@ -581,10 +571,10 @@ tclsh: ${TCLSH_OBJS} ${TCL_LIB_FILE}
${CC} ${CFLAGS} ${LDFLAGS} ${TCLSH_OBJS} @TCL_BUILD_LIB_SPEC@ ${LIBS} \
${CC_SEARCH_FLAGS} -o tclsh
-# Resetting the LIB_RUNTIME_DIR below is required so that
-# the generated tcltest executable gets the build directory
-# burned into its ld search path. This keeps tcltest from
-# picking up an already installed version of the Tcl library.
+# Resetting the LIB_RUNTIME_DIR below is required so that the generated
+# tcltest executable gets the build directory burned into its ld search path.
+# This keeps tcltest from picking up an already installed version of the Tcl
+# library.
tcltest: ${TCLTEST_OBJS} ${TCL_LIB_FILE} ${BUILD_DLTEST}
$(MAKE) tcltest-real LIB_RUNTIME_DIR=`pwd`
@@ -593,11 +583,12 @@ tcltest-real:
${CC} ${CFLAGS} ${LDFLAGS} ${TCLTEST_OBJS} @TCL_BUILD_LIB_SPEC@ ${LIBS} \
${CC_SEARCH_FLAGS} -o tcltest
-# Note, in the target below TCL_LIBRARY needs to be set or else
-# "make test" won't work in the case where the compilation directory
-# isn't the same as the source directory.
-# Specifying TESTFLAGS on the command line is the standard way to pass
-# args to tcltest, ie:
+# Note, in the targets below TCL_LIBRARY needs to be set or else "make test"
+# won't work in the case where the compilation directory isn't the same as the
+# source directory.
+#
+# Specifying TESTFLAGS on the command line is the standard way to pass args to
+# tcltest, ie:
# % make test TESTFLAGS="-verbose bps -file fileName.test"
test: tcltest
@@ -658,21 +649,21 @@ valgrindshell: tclsh
TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \
valgrind $(VALGRINDARGS) ./tclsh $(SCRIPT)
-# The following target outputs the name of the top-level source directory
-# for Tcl (it is used by Tk's configure script, for example). The
-# .NO_PARALLEL line is needed to avoid problems under Sun's "pmake".
-# Note: this target is now obsolete (use the autoconf variable
-# TCL_SRC_DIR from tclConfig.sh instead).
+# The following target outputs the name of the top-level source directory for
+# Tcl (it is used by Tk's configure script, for example). The .NO_PARALLEL
+# line is needed to avoid problems under Sun's "pmake". Note: this target is
+# now obsolete (use the autoconf variable TCL_SRC_DIR from tclConfig.sh
+# instead).
.NO_PARALLEL: topDirName
topDirName:
@cd $(TOP_DIR); pwd
-# 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 \
@@ -691,20 +682,19 @@ gendate:
# <y.tab.c >$(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=<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=<distdir> package-quick
#
-# <distdir> 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.
+# <distdir> 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 \