Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c1337af19 | ||
|
|
1316902df3 | ||
|
|
170c2e99c3 | ||
|
|
62a5728e7e | ||
|
|
f8cf535224 | ||
|
|
c0b4d70936 | ||
|
|
3b8a107562 | ||
|
|
228b96efc2 | ||
|
|
e8a4a7434f | ||
|
|
e212baf6fd | ||
|
|
ebcccacc43 | ||
|
|
96d253aab7 | ||
|
|
0e0dffb596 |
@@ -2687,6 +2687,10 @@ Tcl_LrangeObjCmd(
|
||||
if (result != TCL_OK) {
|
||||
return result;
|
||||
}
|
||||
if ((last == -1) && Tcl_GetString(objv[3])[0] == '\0') {
|
||||
/* TIP #615: empty string for 'last' means 'end' */
|
||||
last = listLen - 1;
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, TclListObjRange(objv[1], first, last));
|
||||
return TCL_OK;
|
||||
|
||||
+26
-8
@@ -1531,18 +1531,18 @@ StringIsCmd(
|
||||
static const char *const isClasses[] = {
|
||||
"alnum", "alpha", "ascii", "control",
|
||||
"boolean", "dict", "digit", "double",
|
||||
"entier", "false", "graph", "integer",
|
||||
"list", "lower", "print", "punct",
|
||||
"space", "true", "upper", "unicode",
|
||||
"wideinteger", "wordchar", "xdigit", NULL
|
||||
"entier", "false", "graph", "index",
|
||||
"integer", "list", "lower", "print",
|
||||
"punct", "space", "true", "upper",
|
||||
"unicode", "wideinteger", "wordchar", "xdigit", NULL
|
||||
};
|
||||
enum isClassesEnum {
|
||||
STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL,
|
||||
STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE,
|
||||
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT,
|
||||
STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT,
|
||||
STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER, STR_IS_UNICODE,
|
||||
STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
|
||||
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INDEX,
|
||||
STR_IS_INT, STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT,
|
||||
STR_IS_PUNCT, STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
|
||||
STR_IS_UNICODE, STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
|
||||
};
|
||||
static const char *const isOptions[] = {
|
||||
"-strict", "-failindex", NULL
|
||||
@@ -1710,6 +1710,16 @@ StringIsCmd(
|
||||
case STR_IS_GRAPH:
|
||||
chcomp = Tcl_UniCharIsGraph;
|
||||
break;
|
||||
case STR_IS_INDEX:
|
||||
if (TclHasInternalRep(objPtr, &tclIntType) ||
|
||||
TclHasInternalRep(objPtr, &tclEndOffsetType) ||
|
||||
TclHasInternalRep(objPtr, &tclBignumType)) {
|
||||
break;
|
||||
}
|
||||
if (Tcl_GetIntForIndex(NULL, objPtr, 0, &i) != TCL_OK) {
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
case STR_IS_INT:
|
||||
case STR_IS_ENTIER:
|
||||
if (TclHasInternalRep(objPtr, &tclIntType) ||
|
||||
@@ -2299,6 +2309,10 @@ StringRangeCmd(
|
||||
TclGetIntForIndexM(interp, objv[3], length, &last) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if ((last == -1) && Tcl_GetString(objv[3])[0] == '\0') {
|
||||
/* TIP #615: empty string for 'last' means 'end' */
|
||||
last = length;
|
||||
}
|
||||
|
||||
if (last >= 0) {
|
||||
Tcl_SetObjResult(interp, Tcl_GetRange(objv[1], first, last));
|
||||
@@ -2401,6 +2415,10 @@ StringRplcCmd(
|
||||
TclGetIntForIndexM(interp, objv[3], end, &last) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if ((last == -1) && Tcl_GetString(objv[3])[0] == '\0') {
|
||||
/* TIP #615: empty string for 'last' means 'end' */
|
||||
last = end;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following test screens out most empty substrings as candidates for
|
||||
|
||||
+10
-8
@@ -506,18 +506,18 @@ TclCompileStringIsCmd(
|
||||
static const char *const isClasses[] = {
|
||||
"alnum", "alpha", "ascii", "control",
|
||||
"boolean", "dict", "digit", "double",
|
||||
"entier", "false", "graph", "integer",
|
||||
"list", "lower", "print", "punct",
|
||||
"space", "true", "upper", "unicode",
|
||||
"wideinteger", "wordchar", "xdigit", NULL
|
||||
"entier", "false", "graph", "index",
|
||||
"integer", "list", "lower", "print",
|
||||
"punct", "space", "true", "upper",
|
||||
"unicode", "wideinteger", "wordchar", "xdigit", NULL
|
||||
};
|
||||
enum isClassesEnum {
|
||||
STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL,
|
||||
STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE,
|
||||
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT,
|
||||
STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT,
|
||||
STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER, STR_IS_UNICODE,
|
||||
STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
|
||||
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INDEX,
|
||||
STR_IS_INT, STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT,
|
||||
STR_IS_PUNCT, STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
|
||||
STR_IS_UNICODE, STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
|
||||
};
|
||||
int t, range, allowEmpty = 0, end;
|
||||
InstStringClassType strClassType;
|
||||
@@ -713,6 +713,8 @@ TclCompileStringIsCmd(
|
||||
FIXJUMP1( end);
|
||||
return TCL_OK;
|
||||
}
|
||||
case STR_IS_INDEX:
|
||||
return TCL_ERROR;
|
||||
|
||||
case STR_IS_INT:
|
||||
case STR_IS_WIDE:
|
||||
|
||||
@@ -2766,6 +2766,7 @@ MODULE_SCOPE const Tcl_ObjType tclBooleanType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclByteArrayType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclByteCodeType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclDoubleType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclEndOffsetType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclIntType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclListType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclDictType;
|
||||
|
||||
@@ -1441,11 +1441,12 @@ TclLsetList(
|
||||
/*
|
||||
* Determine whether the index arg designates a list or a single index.
|
||||
* We have to be careful about the order of the checks to avoid repeated
|
||||
* shimmering; see TIP #22 and #23 for details.
|
||||
* shimmering; see TIP #22 and #23 for details. Don't allow "" as single
|
||||
* index here, since it cannot be distinguished from an empty list.
|
||||
*/
|
||||
|
||||
ListGetInternalRep(indexArgPtr, listRepPtr);
|
||||
if (listRepPtr == NULL
|
||||
if (listRepPtr == NULL && Tcl_GetString(indexArgPtr)[0]
|
||||
&& TclGetIntForIndexM(NULL, indexArgPtr, INT_MAX - 1, &index) == TCL_OK) {
|
||||
/*
|
||||
* indexArgPtr designates a single index.
|
||||
|
||||
+26
-9
@@ -124,19 +124,31 @@ static int FindElement(Tcl_Interp *interp, const char *string,
|
||||
* performance optimization in Tcl_GetIntForIndex. The internal rep is
|
||||
* stored directly in the wideValue, so no memory management is required
|
||||
* for it. This is a caching internalrep, keeping the result of a parse
|
||||
* around. This type is only created from a pre-existing string, so an
|
||||
* updateStringProc will never be called and need not exist. The type
|
||||
* is unregistered, so has no need of a setFromAnyProc either.
|
||||
* around. The type is unregistered, so has no need of a setFromAnyProc.
|
||||
*/
|
||||
|
||||
static const Tcl_ObjType endOffsetType = {
|
||||
static void
|
||||
UpdateStringOfIndex(
|
||||
Tcl_Obj *objPtr) /* Index object whose string rep to update. */
|
||||
{
|
||||
/* The only situation that the string rep can be missing is when it
|
||||
* represents TCL_INDEX_NONE. In all other situations, the string
|
||||
* rep is never thrown away. See TclNewIndexObj() */
|
||||
if ((objPtr)->internalRep.wideValue != WIDE_MIN) {
|
||||
Tcl_Panic("String rep of index %" TCL_LL_MODIFIER "d cannot be generated",
|
||||
(long long)(objPtr)->internalRep.wideValue);
|
||||
}
|
||||
TclInitStringRep(objPtr, NULL, 0);
|
||||
}
|
||||
|
||||
const Tcl_ObjType tclEndOffsetType = {
|
||||
"end-offset", /* name */
|
||||
NULL, /* freeIntRepProc */
|
||||
NULL, /* dupIntRepProc */
|
||||
NULL, /* updateStringProc */
|
||||
UpdateStringOfIndex, /* updateStringProc */
|
||||
NULL /* setFromAnyProc */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* * STRING REPRESENTATION OF LISTS * * *
|
||||
*
|
||||
@@ -3758,7 +3770,7 @@ GetEndOffsetFromObj(
|
||||
Tcl_WideInt offset = -1; /* Offset in the "end-offset" expression - 1 */
|
||||
ClientData cd;
|
||||
|
||||
while ((irPtr = TclFetchInternalRep(objPtr, &endOffsetType)) == NULL) {
|
||||
while ((irPtr = TclFetchInternalRep(objPtr, &tclEndOffsetType)) == NULL) {
|
||||
Tcl_ObjInternalRep ir;
|
||||
int length;
|
||||
const char *bytes = TclGetStringFromObj(objPtr, &length);
|
||||
@@ -3770,6 +3782,11 @@ GetEndOffsetFromObj(
|
||||
|
||||
/* Value doesn't start with "e" */
|
||||
|
||||
if (length == 0) {
|
||||
offset = WIDE_MIN;
|
||||
goto parseOK;
|
||||
}
|
||||
|
||||
/* If we reach here, the string rep of objPtr exists. */
|
||||
|
||||
/*
|
||||
@@ -3944,7 +3961,7 @@ GetEndOffsetFromObj(
|
||||
parseOK:
|
||||
/* Success. Store the new internal rep. */
|
||||
ir.wideValue = offset;
|
||||
Tcl_StoreInternalRep(objPtr, &endOffsetType, &ir);
|
||||
Tcl_StoreInternalRep(objPtr, &tclEndOffsetType, &ir);
|
||||
}
|
||||
|
||||
offset = irPtr->wideValue;
|
||||
@@ -4049,7 +4066,7 @@ TclIndexEncode(
|
||||
int idx;
|
||||
|
||||
if (TCL_OK == GetWideForIndex(interp, objPtr, (unsigned)TCL_INDEX_END , &wide)) {
|
||||
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr, &endOffsetType);
|
||||
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr, &tclEndOffsetType);
|
||||
if (irPtr && irPtr->wideValue >= 0) {
|
||||
/* "int[+-]int" syntax, works the same here as "int" */
|
||||
irPtr = NULL;
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ test lpop-1.6 {error conditions} -returnCodes error -body {
|
||||
test lpop-1.7 {error conditions} -returnCodes error -body {
|
||||
set l "x y"
|
||||
lpop l {}
|
||||
} -match glob -result {bad index *}
|
||||
} -result {index "" out of range}
|
||||
test lpop-1.8 {error conditions} -returnCodes error -body {
|
||||
set l "x y"
|
||||
lpop l 0 0 0 0 1
|
||||
|
||||
+4
-3
@@ -529,10 +529,10 @@ test string-6.4.$noComp {string is, too many args} {
|
||||
} {1 {wrong # args: should be "string is class ?-strict? ?-failindex var? str"}}
|
||||
test string-6.5.$noComp {string is, class check} {
|
||||
list [catch {run {string is bogus str}} msg] $msg
|
||||
} {1 {bad class "bogus": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, unicode, wideinteger, wordchar, or xdigit}}
|
||||
} {1 {bad class "bogus": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, index, integer, list, lower, print, punct, space, true, upper, unicode, wideinteger, wordchar, or xdigit}}
|
||||
test string-6.6.$noComp {string is, ambiguous class} {
|
||||
list [catch {run {string is al str}} msg] $msg
|
||||
} {1 {ambiguous class "al": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, unicode, wideinteger, wordchar, or xdigit}}
|
||||
} {1 {ambiguous class "al": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, index, integer, list, lower, print, punct, space, true, upper, unicode, wideinteger, wordchar, or xdigit}}
|
||||
test string-6.7.$noComp {string is alpha, all ok} {
|
||||
run {string is alpha -strict -failindex var abc}
|
||||
} 1
|
||||
@@ -2031,6 +2031,7 @@ test string-23.1.$noComp {string is command with empty string} {
|
||||
[run {string is double $s}] \
|
||||
[run {string is false $s}] \
|
||||
[run {string is graph $s}] \
|
||||
[run {string is index $s}] \
|
||||
[run {string is integer $s}] \
|
||||
[run {string is lower $s}] \
|
||||
[run {string is print $s}] \
|
||||
@@ -2041,7 +2042,7 @@ test string-23.1.$noComp {string is command with empty string} {
|
||||
[run {string is wordchar $s}] \
|
||||
[run {string is xdigit $s}] \
|
||||
|
||||
} {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
|
||||
} {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
|
||||
test string-23.2.$noComp {string is command with empty string} {
|
||||
set s ""
|
||||
list \
|
||||
|
||||
+1
-1
@@ -696,7 +696,7 @@ test util-9.18 {Tcl_GetIntForIndex} {
|
||||
} b
|
||||
test util-9.19 {Tcl_GetIntForIndex} -body {
|
||||
string index a {}
|
||||
} -returnCodes error -match glob -result *
|
||||
} -result {}
|
||||
test util-9.20 {Tcl_GetIntForIndex} -body {
|
||||
string index a { }
|
||||
} -returnCodes error -match glob -result *
|
||||
|
||||
Reference in New Issue
Block a user