Skip to content

Commit 5eb6319

Browse files
author
jan.nijtmans
committed
Rebase to trunk
2 parents 7a99945 + 0d064b8 commit 5eb6319

File tree

15 files changed

+206
-77
lines changed

15 files changed

+206
-77
lines changed

doc/ledit.n

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
.SH NAME
1212
ledit \- Replace elements of a list stored in variable
1313
.SH SYNOPSIS
14-
\fBledit \fIlistVar first last \fR?\fIvalue value ...\fR?
14+
\fBledit \fIlistVar\fR ?\fIfirst\fR? ?\fIlast\fR? ?\fIvalue value ...\fR?
1515
.BE
1616
.SH DESCRIPTION
1717
.PP

doc/lrange.n

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
.SH NAME
1414
lrange \- Return one or more adjacent elements from a list
1515
.SH SYNOPSIS
16-
\fBlrange \fIlist first last\fR
16+
\fBlrange \fIlist\fR ?\fIfirst\fR? ?\fIlast\fR?
1717
.BE
1818
.SH DESCRIPTION
1919
.PP
@@ -24,8 +24,8 @@ The index values \fIfirst\fR and \fIlast\fR are interpreted
2424
the same as index values for the command \fBstring index\fR,
2525
supporting simple index arithmetic and indices relative to the
2626
end of the list.
27-
If \fIfirst\fR is less than zero, it is treated as if it were zero.
28-
If \fIlast\fR is greater than or equal to the number of elements
27+
If \fIfirst\fR is missing or less than zero, it is treated as if it were zero.
28+
If \fIlast\fR is missing or greater than or equal to the number of elements
2929
in the list, then it is treated as if it were \fBend\fR.
3030
If \fIfirst\fR is greater than \fIlast\fR then an empty string
3131
is returned.

doc/lreplace.n

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
.SH NAME
1414
lreplace \- Replace elements in a list with new elements
1515
.SH SYNOPSIS
16-
\fBlreplace \fIlist first last \fR?\fIelement element ...\fR?
16+
\fBlreplace \fIlist\fR ?\fIfirst\fR? ?\fIlast\fR? ?\fIelement element ...\fR?
1717
.BE
1818
.SH DESCRIPTION
1919
.PP

doc/string.n

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,16 +298,16 @@ the special interpretation of the characters \fB*?[]\e\fR in
298298
.RE
299299
.\" METHOD: range
300300
.TP
301-
\fBstring range \fIstring first last\fR
301+
\fBstring range \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR?
302302
.
303303
Returns a range of consecutive characters from \fIstring\fR, starting
304304
with the character whose index is \fIfirst\fR and ending with the
305305
character whose index is \fIlast\fR (using the forms described in
306306
\fBSTRING INDICES\fR). An index of \fB0\fR refers to the first
307307
character of the string; an index of \fBend\fR refers to last
308308
character of the string. \fIfirst\fR and \fIlast\fR may be specified
309-
as for the \fBindex\fR method. If \fIfirst\fR is less than zero then
310-
it is treated as if it were zero, and if \fIlast\fR is greater than or
309+
as for the \fBindex\fR method. If \fIfirst\fR is missing or less than zero then
310+
it is treated as if it were zero, and if \fIlast\fR is missing or greater than or
311311
equal to the length of the string then it is treated as if it were
312312
\fBend\fR. If \fIfirst\fR is greater than \fIlast\fR then an empty
313313
string is returned.
@@ -320,7 +320,7 @@ Returns a string consisting of \fIstring\fR concatenated with itself
320320
returned.
321321
.\" METHOD: replace
322322
.TP
323-
\fBstring replace \fIstring first last\fR ?\fInewstring\fR?
323+
\fBstring replace \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? ?\fInewstring\fR?
324324
.
325325
Removes a range of consecutive characters from \fIstring\fR, starting
326326
with the character whose index is \fIfirst\fR and ending with the
@@ -348,7 +348,7 @@ characters in the reverse order.
348348
Returns a value equal to \fIstring\fR except that all upper (or title)
349349
case letters have been converted to lower case. If \fIfirst\fR is
350350
specified, it refers to the first char index in the string to start
351-
modifying. If \fIlast\fR is not specified, only the character at position
351+
modifying. If \fIlast\fR is not specified or the empty string, only the character at position
352352
\fIfirst\fR is converted, otherwise \fIlast\fR refers to the char index
353353
in the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be
354354
specified using the forms described in \fBSTRING INDICES\fR.
@@ -361,7 +361,7 @@ in \fIstring\fR is converted to its Unicode title case variant (or
361361
upper case if there is no title case variant) and the rest of the
362362
string is converted to lower case. If \fIfirst\fR is specified, it
363363
refers to the first char index in the string to start modifying. If
364-
\fIlast\fR is not specified, only the character at position \fIfirst\fR
364+
\fIlast\fR is not specified or the empty string, only the character at position \fIfirst\fR
365365
is converted, otherwise \fIlast\fR refers to the char index in
366366
the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be
367367
specified using the forms described in \fBSTRING INDICES\fR.
@@ -372,7 +372,7 @@ specified using the forms described in \fBSTRING INDICES\fR.
372372
Returns a value equal to \fIstring\fR except that all lower (or title)
373373
case letters have been converted to upper case. If \fIfirst\fR is
374374
specified, it refers to the first char index in the string to start
375-
modifying. If \fIlast\fR is not specified, only the character at position
375+
modifying. If \fIlast\fR is not specified or the empty string, only the character at position
376376
\fIfirst\fR is converted, otherwise \fIlast\fR refers to the char index
377377
in the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be
378378
specified using the forms described in \fBSTRING INDICES\fR.
@@ -430,11 +430,16 @@ these.
430430
When referring to indices into a string (e.g., for \fBstring index\fR
431431
or \fBstring range\fR) the following formats are supported:
432432
.IP \fIinteger\fR 10
433-
For any index value that passes \fBstring is integer \-strict\fR,
433+
For any index value that passes \fBstring is integer\fR,
434434
the char specified at this integral index (e.g., \fB2\fR would refer to the
435435
.QW c
436436
in
437-
.QW abcd ).
437+
.QW abcd
438+
). A negative value or the empty string refers to a position
439+
outside the range of the string. When referring to the last index
440+
in a range, the empty string means that the range only consists
441+
of a single character, except when \fBstart\fR is the empty string
442+
too: In that case, it's equivalent to \fBend\fR
438443
.IP \fBend\fR 10
439444
The last char of the string (e.g., \fBend\fR would refer to the
440445
.QW d

generic/tclCmdIL.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2717,9 +2717,9 @@ Tcl_LrangeObjCmd(
27172717
Tcl_Obj *const objv[]) /* Argument objects. */
27182718
{
27192719
int result;
2720-
Tcl_Size listLen, first, last;
2721-
if (objc != 4) {
2722-
Tcl_WrongNumArgs(interp, 1, objv, "list first last");
2720+
Tcl_Size listLen, first = 0, last;
2721+
if (objc < 2 || objc > 4) {
2722+
Tcl_WrongNumArgs(interp, 1, objv, "list ?first? ?last?");
27232723
return TCL_ERROR;
27242724
}
27252725

@@ -2728,16 +2728,26 @@ Tcl_LrangeObjCmd(
27282728
return result;
27292729
}
27302730

2731-
result = TclGetIntForIndexM(interp, objv[2], /*endValue*/ listLen - 1,
2732-
&first);
2733-
if (result != TCL_OK) {
2734-
return result;
2731+
if (objc > 2) {
2732+
result = TclGetIntForIndexM(interp, objv[2], /*endValue*/ listLen - 1,
2733+
&first);
2734+
if (result != TCL_OK) {
2735+
return result;
2736+
}
27352737
}
27362738

2739+
if (objc > 3) {
27372740
result = TclGetIntForIndexM(interp, objv[3], /*endValue*/ listLen - 1,
27382741
&last);
2739-
if (result != TCL_OK) {
2740-
return result;
2742+
if (result != TCL_OK) {
2743+
return result;
2744+
}
2745+
if ((last == -1) && Tcl_IsEmpty(objv[3])) {
2746+
/* TIP #615: empty string for 'last' means 'end' */
2747+
last = listLen - 1;
2748+
}
2749+
} else {
2750+
last = listLen - 1;
27412751
}
27422752

27432753
Tcl_Obj *resultObj;
@@ -2994,6 +3004,10 @@ Tcl_LreplaceObjCmd(
29943004
if (result != TCL_OK) {
29953005
return result;
29963006
}
3007+
if ((last == -1) && Tcl_IsEmpty(objv[3])) {
3008+
/* TIP #615: empty string for 'last' means 'end' */
3009+
last = listLen - 1;
3010+
}
29973011

29983012
if (first < 0) {
29993013
first = 0;
@@ -4915,6 +4929,10 @@ Tcl_LeditObjCmd(
49154929
if (result != TCL_OK) {
49164930
return result;
49174931
}
4932+
if ((last == -1) && Tcl_IsEmpty(objv[3])) {
4933+
/* TIP #615: empty string for 'last' means 'end' */
4934+
last = listLen - 1;
4935+
}
49184936

49194937
if (first < 0) {
49204938
first = 0;

generic/tclCmdMZ.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

generic/tclCompCmdsSZ.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -510,17 +510,17 @@ TclCompileStringIsCmd(
510510
static const char *const isClasses[] = {
511511
"alnum", "alpha", "ascii", "control",
512512
"boolean", "dict", "digit", "double",
513-
"entier", "false", "graph", "integer",
514-
"list", "lower", "print", "punct",
515-
"space", "true", "upper",
513+
"entier", "false", "graph", "index",
514+
"integer", "list", "lower", "print",
515+
"punct", "space", "true", "upper",
516516
"wideinteger", "wordchar", "xdigit", NULL
517517
};
518518
enum isClassesEnum {
519519
STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL,
520520
STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE,
521-
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT,
522-
STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT,
523-
STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
521+
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INDEX,
522+
STR_IS_INT, STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT,
523+
STR_IS_PUNCT, STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
524524
STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
525525
} t;
526526
int allowEmpty = 0;
@@ -712,6 +712,8 @@ TclCompileStringIsCmd(
712712
FWDLABEL( end);
713713
return TCL_OK;
714714
}
715+
case STR_IS_INDEX:
716+
return TCL_ERROR;
715717

716718
case STR_IS_INT:
717719
case STR_IS_WIDE:

0 commit comments

Comments
 (0)