@@ -1537,17 +1537,17 @@ StringIsCmd(
15371537 static const char * const isClasses [] = {
15381538 "alnum" , "alpha" , "ascii" , "control" ,
15391539 "boolean" , "dict" , "digit" , "double" ,
1540- "entier" , "false" , "graph" , "integer " ,
1541- "list " , "lower " , "print " , "punct " ,
1542- "space" , "true" , "upper" ,
1540+ "entier" , "false" , "graph" , "index " ,
1541+ "integer " , "list " , "lower " , "print " ,
1542+ "punct" , " space" , "true" , "upper" ,
15431543 "wideinteger" , "wordchar" , "xdigit" , NULL
15441544 };
15451545 enum isClassesEnum {
15461546 STR_IS_ALNUM , STR_IS_ALPHA , STR_IS_ASCII , STR_IS_CONTROL ,
15471547 STR_IS_BOOL , STR_IS_DICT , STR_IS_DIGIT , STR_IS_DOUBLE ,
1548- STR_IS_ENTIER , STR_IS_FALSE , STR_IS_GRAPH , STR_IS_INT ,
1549- STR_IS_LIST , STR_IS_LOWER , STR_IS_PRINT , STR_IS_PUNCT ,
1550- STR_IS_SPACE , STR_IS_TRUE , STR_IS_UPPER ,
1548+ STR_IS_ENTIER , STR_IS_FALSE , STR_IS_GRAPH , STR_IS_INDEX ,
1549+ STR_IS_INT , STR_IS_LIST , STR_IS_LOWER , STR_IS_PRINT ,
1550+ STR_IS_PUNCT , STR_IS_SPACE , STR_IS_TRUE , STR_IS_UPPER ,
15511551 STR_IS_WIDE , STR_IS_WORD , STR_IS_XDIGIT
15521552 } index ;
15531553 static const char * const isOptions [] = {
@@ -1715,6 +1715,17 @@ StringIsCmd(
17151715 case STR_IS_GRAPH :
17161716 chcomp = Tcl_UniCharIsGraph ;
17171717 break ;
1718+ case STR_IS_INDEX : {
1719+ Tcl_Size idx ;
1720+ if ((strict && Tcl_IsEmpty (objPtr ))
1721+ || (!TclHasInternalRep (objPtr , & tclIntType )
1722+ && !TclHasInternalRep (objPtr , & tclEndOffsetType )
1723+ && !TclHasInternalRep (objPtr , & tclBignumType )
1724+ && TclGetIntForIndexM (NULL , objPtr , 0 , & idx ) != TCL_OK )) {
1725+ result = 0 ;
1726+ }
1727+ break ;
1728+ }
17181729 case STR_IS_INT :
17191730 case STR_IS_ENTIER :
17201731 if (TclHasInternalRep (objPtr , & tclIntType ) ||
@@ -2290,10 +2301,10 @@ StringRangeCmd(
22902301 int objc , /* Number of arguments. */
22912302 Tcl_Obj * const objv []) /* Argument objects. */
22922303{
2293- Tcl_Size first , last , end ;
2304+ Tcl_Size first = 0 , last , end ;
22942305
2295- if (objc != 4 ) {
2296- Tcl_WrongNumArgs (interp , 1 , objv , "string first last" );
2306+ if (objc < 2 || objc > 4 ) {
2307+ Tcl_WrongNumArgs (interp , 1 , objv , "string ? first? ? last? " );
22972308 return TCL_ERROR ;
22982309 }
22992310
@@ -2302,12 +2313,16 @@ StringRangeCmd(
23022313 * 'end' refers to the last character, not one past it.
23032314 */
23042315
2305- end = Tcl_GetCharLength (objv [1 ]) - 1 ;
2316+ last = end = Tcl_GetCharLength (objv [1 ]) - 1 ;
23062317
2307- if (TclGetIntForIndexM (interp , objv [2 ], end , & first ) != TCL_OK ||
2308- TclGetIntForIndexM (interp , objv [3 ], end , & last ) != TCL_OK ) {
2318+ if ((( objc > 2 ) && TclGetIntForIndexM (interp , objv [2 ], end , & first ) != TCL_OK )
2319+ || (( objc > 3 ) && TclGetIntForIndexM (interp , objv [3 ], end , & last ) != TCL_OK ) ) {
23092320 return TCL_ERROR ;
23102321 }
2322+ if ((last == -1 ) && (objc > 3 ) && Tcl_IsEmpty (objv [3 ])) {
2323+ /* TIP #615: empty string for 'last' means 'end' */
2324+ last = end ;
2325+ }
23112326
23122327 if (last >= 0 ) {
23132328 Tcl_SetObjResult (interp , Tcl_GetRange (objv [1 ], first , last ));
@@ -2396,19 +2411,23 @@ StringRplcCmd(
23962411 int objc , /* Number of arguments. */
23972412 Tcl_Obj * const objv []) /* Argument objects. */
23982413{
2399- Tcl_Size first , last , end ;
2414+ Tcl_Size first = 0 , last , end ;
24002415
2401- if (objc < 4 || objc > 5 ) {
2402- Tcl_WrongNumArgs (interp , 1 , objv , "string first last ?string?" );
2416+ if (objc < 2 || objc > 5 ) {
2417+ Tcl_WrongNumArgs (interp , 1 , objv , "string ? first? ? last? ?string?" );
24032418 return TCL_ERROR ;
24042419 }
24052420
2406- end = Tcl_GetCharLength (objv [1 ]) - 1 ;
2421+ last = end = Tcl_GetCharLength (objv [1 ]) - 1 ;
24072422
2408- if (TclGetIntForIndexM (interp , objv [2 ], end , & first ) != TCL_OK ||
2409- TclGetIntForIndexM (interp , objv [3 ], end , & last ) != TCL_OK ) {
2423+ if ((( objc > 2 ) && TclGetIntForIndexM (interp , objv [2 ], end , & first ) != TCL_OK )
2424+ || (( objc > 3 ) && TclGetIntForIndexM (interp , objv [3 ], end , & last ) != TCL_OK ) ) {
24102425 return TCL_ERROR ;
24112426 }
2427+ if ((last == -1 ) && (objc > 3 ) && Tcl_IsEmpty (objv [3 ])) {
2428+ /* TIP #615: empty string for 'last' means 'end' */
2429+ last = end ;
2430+ }
24122431
24132432 /*
24142433 * The following test screens out most empty substrings as candidates for
@@ -2437,7 +2456,7 @@ StringRplcCmd(
24372456 }
24382457
24392458 resultPtr = TclStringReplace (interp , objv [1 ], first ,
2440- last + 1 - first , (objc == 5 ) ? objv [4 ] : NULL ,
2459+ last + 1 - first , (objc > 4 ) ? objv [4 ] : NULL ,
24412460 TCL_STRING_IN_PLACE );
24422461
24432462 if (resultPtr == NULL ) {
@@ -2923,11 +2942,19 @@ StringLowerCmd(
29232942 first = 0 ;
29242943 }
29252944 last = first ;
2945+ if (Tcl_IsEmpty (objv [2 ])) {
2946+ /* TIP #615: empty string for 'first' means until 'end' */
2947+ last = length1 ;
2948+ }
29262949
2927- if ((objc == 4 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
2950+ if ((objc > 3 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
29282951 & last ) != TCL_OK )) {
29292952 return TCL_ERROR ;
29302953 }
2954+ if ((last == -1 ) && (objc > 3 ) && Tcl_IsEmpty (objv [3 ])) {
2955+ /* TIP #615: empty string for 'last' means 'end' */
2956+ last = length1 ;
2957+ }
29312958
29322959 if (last >= length1 ) {
29332960 last = length1 ;
@@ -3008,11 +3035,19 @@ StringUpperCmd(
30083035 first = 0 ;
30093036 }
30103037 last = first ;
3038+ if (Tcl_IsEmpty (objv [2 ])) {
3039+ /* TIP #615: empty string for 'first' means until 'end' */
3040+ last = length1 ;
3041+ }
30113042
3012- if ((objc == 4 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
3043+ if ((objc > 3 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
30133044 & last ) != TCL_OK )) {
30143045 return TCL_ERROR ;
30153046 }
3047+ if ((last == -1 ) && (objc > 3 ) && Tcl_IsEmpty (objv [3 ])) {
3048+ /* TIP #615: empty string for 'last' means 'end' */
3049+ last = length1 ;
3050+ }
30163051
30173052 if (last >= length1 ) {
30183053 last = length1 ;
@@ -3093,11 +3128,19 @@ StringTitleCmd(
30933128 first = 0 ;
30943129 }
30953130 last = first ;
3131+ if (Tcl_IsEmpty (objv [2 ])) {
3132+ /* TIP #615: empty string for 'first' means until 'end' */
3133+ last = length1 ;
3134+ }
30963135
3097- if ((objc == 4 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
3136+ if ((objc > 3 ) && (TclGetIntForIndexM (interp , objv [3 ], length1 ,
30983137 & last ) != TCL_OK )) {
30993138 return TCL_ERROR ;
31003139 }
3140+ if ((last == -1 ) && (objc > 3 ) && Tcl_IsEmpty (objv [3 ])) {
3141+ /* TIP #615: empty string for 'last' means 'end' */
3142+ last = length1 ;
3143+ }
31013144
31023145 if (last >= length1 ) {
31033146 last = length1 ;
0 commit comments