summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2016-12-21 12:59:30 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2016-12-21 12:59:30 (GMT)
commit70346ccd7b408b992402ed59d6264eefcd83f8d6 (patch)
tree6205a7c7efe574d1e320fe1681ea1f171892e320
parentdd3012b0b5620ad001fc666e42e5bc27760fc514 (diff)
downloadtcl-70346ccd7b408b992402ed59d6264eefcd83f8d6.zip
tcl-70346ccd7b408b992402ed59d6264eefcd83f8d6.tar.gz
tcl-70346ccd7b408b992402ed59d6264eefcd83f8d6.tar.bz2
Experimental (partial) fix for [39f6304c2e90549c209cd11a7920dc9921b9f48e|39f6304c2e]: Tcl_LinkVar is not tolerant to minus, plus, dot.
This handled minus and plus only, not other possible errors. Will need a TIP, because the boolean type is extended to consider '-', '+' and 'o' (necessary for being able to type 'on' or 'off') as valid booleans Dot, and integer prefixes (such as 0x) not handled yet, should be handled completely different.
-rw-r--r--doc/GetInt.34
-rw-r--r--generic/tclGet.c2
-rw-r--r--generic/tclLink.c156
-rw-r--r--generic/tclObj.c28
-rw-r--r--tests/link.test12
5 files changed, 131 insertions, 71 deletions
diff --git a/doc/GetInt.3 b/doc/GetInt.3
index 5a3304a..99dd030 100644
--- a/doc/GetInt.3
+++ b/doc/GetInt.3
@@ -89,10 +89,10 @@ as a decimal point is not supported nor should any other sort of
inter-digit separator be present.
.PP
\fBTcl_GetBoolean\fR expects \fIsrc\fR to specify a boolean
-value. If \fIsrc\fR is any of \fB0\fR, \fBfalse\fR,
+value. If \fIsrc\fR is any of \fB0\fR, \fB-\fR, \fBfalse\fR,
\fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero
value at \fI*boolPtr\fR.
-If \fIsrc\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR,
+If \fIsrc\fR is any of \fB1\fR, \fB+\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR,
then 1 is stored at \fI*boolPtr\fR.
Any of these values may be abbreviated, and upper-case spellings
are also acceptable.
diff --git a/generic/tclGet.c b/generic/tclGet.c
index 97e8c7b..8898a0f 100644
--- a/generic/tclGet.c
+++ b/generic/tclGet.c
@@ -125,7 +125,7 @@ int
Tcl_GetBoolean(
Tcl_Interp *interp, /* Interpreter used for error reporting. */
const char *src, /* String containing one of the boolean values
- * 1, 0, true, false, yes, no, on, off. */
+ * 1, 0, +, -, true, false, yes, no, on, off. */
int *boolPtr) /* Place to store converted result, which will
* be 0 or 1. */
{
diff --git a/generic/tclLink.c b/generic/tclLink.c
index e6dc657..8a0cb57 100644
--- a/generic/tclLink.c
+++ b/generic/tclLink.c
@@ -259,7 +259,8 @@ LinkTraceProc(
int flags) /* Miscellaneous additional information. */
{
Link *linkPtr = clientData;
- int changed, valueLength;
+ int changed;
+ size_t valueLength;
const char *value;
char **pp;
Tcl_Obj *valueObj;
@@ -380,9 +381,12 @@ LinkTraceProc(
case TCL_LINK_INT:
if (Tcl_GetIntFromObj(NULL, valueObj, &linkPtr->lastValue.i)
!= TCL_OK) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &linkPtr->lastValue.i)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
TCL_GLOBAL_ONLY);
- return (char *) "variable must have integer value";
+ return (char *) "variable must have integer or boolean value";
+ }
}
LinkedVar(int) = linkPtr->lastValue.i;
break;
@@ -390,9 +394,13 @@ LinkTraceProc(
case TCL_LINK_WIDE_INT:
if (Tcl_GetWideIntFromObj(NULL, valueObj, &linkPtr->lastValue.w)
!= TCL_OK) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
TCL_GLOBAL_ONLY);
- return (char *) "variable must have integer value";
+ return (char *) "variable must have integer or boolean value";
+ }
+ linkPtr->lastValue.w = (Tcl_WideInt) valueInt;
}
LinkedVar(Tcl_WideInt) = linkPtr->lastValue.w;
break;
@@ -403,12 +411,17 @@ LinkTraceProc(
#ifdef ACCEPT_NAN
if (valueObj->typePtr != &tclDoubleType) {
#endif
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL,
- ObjValue(linkPtr), TCL_GLOBAL_ONLY);
- return (char *) "variable must have real value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have real or boolean value";
+ }
+ linkPtr->lastValue.d = (double) valueInt;
#ifdef ACCEPT_NAN
+ } else {
+ linkPtr->lastValue.d = valueObj->internalRep.doubleValue;
}
- linkPtr->lastValue.d = valueObj->internalRep.doubleValue;
#endif
}
LinkedVar(double) = linkPtr->lastValue.d;
@@ -425,79 +438,106 @@ LinkTraceProc(
break;
case TCL_LINK_CHAR:
- if (Tcl_GetIntFromObj(interp, valueObj, &valueInt) != TCL_OK
+ if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK
|| valueInt < SCHAR_MIN || valueInt > SCHAR_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have char value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have char or boolean value";
+ }
}
linkPtr->lastValue.c = (char)valueInt;
LinkedVar(char) = linkPtr->lastValue.c;
break;
case TCL_LINK_UCHAR:
- if (Tcl_GetIntFromObj(interp, valueObj, &valueInt) != TCL_OK
+ if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK
|| valueInt < 0 || valueInt > UCHAR_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have unsigned char value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have unsigned char or boolean value";
+ }
}
linkPtr->lastValue.uc = (unsigned char) valueInt;
LinkedVar(unsigned char) = linkPtr->lastValue.uc;
break;
case TCL_LINK_SHORT:
- if (Tcl_GetIntFromObj(interp, valueObj, &valueInt) != TCL_OK
+ if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK
|| valueInt < SHRT_MIN || valueInt > SHRT_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have short value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have short or boolean value";
+ }
}
linkPtr->lastValue.s = (short)valueInt;
LinkedVar(short) = linkPtr->lastValue.s;
break;
case TCL_LINK_USHORT:
- if (Tcl_GetIntFromObj(interp, valueObj, &valueInt) != TCL_OK
+ if (Tcl_GetIntFromObj(NULL, valueObj, &valueInt) != TCL_OK
|| valueInt < 0 || valueInt > USHRT_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have unsigned short value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have unsigned short or boolean value";
+ }
}
linkPtr->lastValue.us = (unsigned short)valueInt;
LinkedVar(unsigned short) = linkPtr->lastValue.us;
break;
case TCL_LINK_UINT:
- if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK
+ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK
|| valueWide < 0 || valueWide > UINT_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have unsigned int value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have unsigned int or boolean value";
+ }
+ linkPtr->lastValue.ui = (unsigned int)valueInt;
+ } else {
+ linkPtr->lastValue.ui = (unsigned int)valueWide;
}
- linkPtr->lastValue.ui = (unsigned int)valueWide;
LinkedVar(unsigned int) = linkPtr->lastValue.ui;
break;
case TCL_LINK_LONG:
- if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK
+ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK
|| valueWide < LONG_MIN || valueWide > LONG_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have long value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have long or boolean value";
+ }
+ linkPtr->lastValue.l = (long)valueInt;
+ } else {
+ linkPtr->lastValue.l = (long)valueWide;
}
- linkPtr->lastValue.l = (long)valueWide;
LinkedVar(long) = linkPtr->lastValue.l;
break;
case TCL_LINK_ULONG:
- if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK
+ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK
|| valueWide < 0 || (Tcl_WideUInt) valueWide > ULONG_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have unsigned long value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have unsigned long or boolean value";
+ }
+ linkPtr->lastValue.ul = (unsigned long)valueInt;
+ } else {
+ linkPtr->lastValue.ul = (unsigned long)valueWide;
}
- linkPtr->lastValue.ul = (unsigned long)valueWide;
LinkedVar(unsigned long) = linkPtr->lastValue.ul;
break;
@@ -505,33 +545,43 @@ LinkTraceProc(
/*
* FIXME: represent as a bignum.
*/
- if (Tcl_GetWideIntFromObj(interp, valueObj, &valueWide) != TCL_OK) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have unsigned wide int value";
+ if (Tcl_GetWideIntFromObj(NULL, valueObj, &valueWide) != TCL_OK) {
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have unsigned wide int or boolean value";
+ }
+ linkPtr->lastValue.uw = (Tcl_WideUInt)valueInt;
+ } else {
+ linkPtr->lastValue.uw = (Tcl_WideUInt)valueWide;
}
- linkPtr->lastValue.uw = (Tcl_WideUInt)valueWide;
LinkedVar(Tcl_WideUInt) = linkPtr->lastValue.uw;
break;
case TCL_LINK_FLOAT:
- if (Tcl_GetDoubleFromObj(interp, valueObj, &valueDouble) != TCL_OK
+ if (Tcl_GetDoubleFromObj(NULL, valueObj, &valueDouble) != TCL_OK
|| valueDouble < -FLT_MAX || valueDouble > FLT_MAX) {
- Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
- TCL_GLOBAL_ONLY);
- return (char *) "variable must have float value";
+ if (Tcl_GetBooleanFromObj(NULL, valueObj, &valueInt)
+ != TCL_OK) {
+ Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, ObjValue(linkPtr),
+ TCL_GLOBAL_ONLY);
+ return (char *) "variable must have float or boolean value";
+ }
+ linkPtr->lastValue.f = (float)valueInt;
+ } else {
+ linkPtr->lastValue.f = (float)valueDouble;
}
- linkPtr->lastValue.f = (float)valueDouble;
LinkedVar(float) = linkPtr->lastValue.f;
break;
case TCL_LINK_STRING:
- value = TclGetStringFromObj(valueObj, &valueLength);
- valueLength++;
+ value = TclGetString(valueObj);
+ valueLength = valueObj->length + 1;
pp = (char **) linkPtr->addr;
*pp = ckrealloc(*pp, valueLength);
- memcpy(*pp, value, (unsigned) valueLength);
+ memcpy(*pp, value, valueLength);
break;
default:
diff --git a/generic/tclObj.c b/generic/tclObj.c
index 416e5ed..0c95e7c 100644
--- a/generic/tclObj.c
+++ b/generic/tclObj.c
@@ -2004,9 +2004,10 @@ static int
ParseBoolean(
register Tcl_Obj *objPtr) /* The object to parse/convert. */
{
- int i, length, newBool;
+ int newBool;
char lowerCase[6];
- const char *str = TclGetStringFromObj(objPtr, &length);
+ const char *str = TclGetString(objPtr);
+ size_t i, length = objPtr->length;
if ((length == 0) || (length > 5)) {
/*
@@ -2029,6 +2030,18 @@ ParseBoolean(
goto numericBoolean;
}
return TCL_ERROR;
+ case '-':
+ if (length == 1) {
+ newBool = 0;
+ goto goodBoolean;
+ }
+ return TCL_ERROR;
+ case '+':
+ if (length == 1) {
+ newBool = 1;
+ goto goodBoolean;
+ }
+ return TCL_ERROR;
}
/*
@@ -2082,15 +2095,12 @@ ParseBoolean(
}
return TCL_ERROR;
case 'o':
- if (length < 2) {
- return TCL_ERROR;
- }
- if (strncmp(lowerCase, "on", (size_t) length) == 0) {
- newBool = 1;
- goto goodBoolean;
- } else if (strncmp(lowerCase, "off", (size_t) length) == 0) {
+ if (strncmp(lowerCase, "off", (size_t) length) == 0) {
newBool = 0;
goto goodBoolean;
+ } else if (strncmp(lowerCase, "on", (size_t) length) == 0) {
+ newBool = 1;
+ goto goodBoolean;
}
return TCL_ERROR;
default:
diff --git a/tests/link.test b/tests/link.test
index 00e490c..0ea7cf6 100644
--- a/tests/link.test
+++ b/tests/link.test
@@ -67,14 +67,14 @@ test link-2.2 {writing bad values into variables} -setup {
testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
list [catch {set int 09a} msg] $msg $int
-} -result {1 {can't set "int": variable must have integer value} 43}
+} -result {1 {can't set "int": variable must have integer or boolean value} 43}
test link-2.3 {writing bad values into variables} -setup {
testlink delete
} -constraints {testlink} -body {
testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
list [catch {set real 1.x3} msg] $msg $real
-} -result {1 {can't set "real": variable must have real value} 1.23}
+} -result {1 {can't set "real": variable must have real or boolean value} 1.23}
test link-2.4 {writing bad values into variables} -setup {
testlink delete
} -constraints {testlink} -body {
@@ -88,7 +88,7 @@ test link-2.5 {writing bad values into variables} -setup {
testlink set 43 1.23 4 - 56785678 64 250 30000 60000 0xbeefbabe 12321 32123 3.25 1231231234
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
list [catch {set wide gorp} msg] $msg $bool
-} -result {1 {can't set "wide": variable must have integer value} 1}
+} -result {1 {can't set "wide": variable must have integer or boolean value} 1}
test link-3.1 {read-only variables} -constraints {testlink} -setup {
testlink delete
@@ -225,7 +225,7 @@ test link-7.4 {access to linked variables via upvar} -setup {
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
testlink set -4 {} {} {} {} {} {} {} {} {} {} {} {} {}
list [catch x msg] $msg $int
-} -result {1 {can't set "y": variable must have integer value} -4}
+} -result {1 {can't set "y": variable must have integer or boolean value} -4}
test link-7.5 {access to linked variables via upvar} -setup {
testlink delete
} -constraints {testlink} -body {
@@ -236,7 +236,7 @@ test link-7.5 {access to linked variables via upvar} -setup {
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
testlink set -4 16.75 {} {} {} {} {} {} {} {} {} {} {} {}
list [catch x msg] $msg $real
-} -result {1 {can't set "y": variable must have real value} 16.75}
+} -result {1 {can't set "y": variable must have real or boolean value} 16.75}
test link-7.6 {access to linked variables via upvar} -setup {
testlink delete
} -constraints {testlink} -body {
@@ -258,7 +258,7 @@ test link-7.7 {access to linked variables via upvar} -setup {
testlink create 1 1 1 1 1 1 1 1 1 1 1 1 1 1
testlink set -4 16.3 1 {} 778899 {} {} {} {} {} {} {} {} {}
list [catch x msg] $msg $wide
-} -result {1 {can't set "y": variable must have integer value} 778899}
+} -result {1 {can't set "y": variable must have integer or boolean value} 778899}
test link-8.1 {Tcl_UpdateLinkedVar procedure} {testlink} {
proc x args {