summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2024-06-17 14:54:07 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2024-06-17 14:54:07 (GMT)
commit88bb88f1c0482d4e2c732f02264ed845620fc467 (patch)
tree488579b6d6fed04b2dba99334f5783fde92cdb31
parente90d5d75f806f750d6cf2a302f1d66c2e3dda72a (diff)
downloadtcl-88bb88f1c0482d4e2c732f02264ed845620fc467.zip
tcl-88bb88f1c0482d4e2c732f02264ed845620fc467.tar.gz
tcl-88bb88f1c0482d4e2c732f02264ed845620fc467.tar.bz2
Implement %z/%t/%q/%j size modifiers for 'scan'. Part of TIP #697, which is suitable for 8.7 too.
-rw-r--r--doc/scan.n7
-rw-r--r--generic/tclScan.c36
2 files changed, 28 insertions, 15 deletions
diff --git a/doc/scan.n b/doc/scan.n
index c01a305..46bfb91 100644
--- a/doc/scan.n
+++ b/doc/scan.n
@@ -74,12 +74,13 @@ one of Tcl's integer values. The size modifier field dictates the
integer range acceptable to be stored in a variable, or, for the inline
case, in a position in the result list.
The syntactically valid values for the size modifier are \fBh\fR, \fBL\fR,
-\fBl\fR, and \fBll\fR. The \fBh\fR size modifier value is equivalent
+\fBl\fR, \fBz\fR, \fBt\fR, and \fBll\fR. The \fBh\fR size
+modifier value is equivalent
to the absence of a size modifier in the the conversion specifier.
Either one indicates the integer range to be stored is limited to the range
determined by the value of the \fBwordSize\fR element of the \fBtcl_platform\fR
-array). The \fBL\fR size modifier is equivalent to the \fBl\fR size
-modifier. Either one indicates the integer range to be stored is
+array). The \fBL\fR, \fBq\fR or \fBj\fR size modifiers are equivalent to the
+\fBl\fR size modifier. Either of them indicates the integer range to be stored is
limited to the same range produced by the \fBwide()\fR function of
the \fBexpr\fR command. The \fBll\fR size modifier indicates that
the integer range to be stored is unlimited.
diff --git a/generic/tclScan.c b/generic/tclScan.c
index 8969240..e852d63 100644
--- a/generic/tclScan.c
+++ b/generic/tclScan.c
@@ -319,7 +319,7 @@ ValidateFormat(
if (ul == 0 || ul >= INT_MAX) {
goto badIndex;
}
- objIndex = (int) ul - 1;
+ objIndex = (int)ul - 1;
if (numVars && (objIndex >= numVars)) {
goto badIndex;
} else if (numVars == 0) {
@@ -361,6 +361,13 @@ ValidateFormat(
*/
switch (ch) {
+ case 'z':
+ case 't':
+ if (sizeof(void *) > sizeof(int)) {
+ flags |= SCAN_LONGER;
+ }
+ format += TclUtfToUniChar(format, &ch);
+ break;
case 'l':
if (*format == 'l') {
flags |= SCAN_BIG;
@@ -370,6 +377,8 @@ ValidateFormat(
}
/* FALLTHRU */
case 'L':
+ case 'j':
+ case 'q':
flags |= SCAN_LONGER;
/* FALLTHRU */
case 'h':
@@ -567,7 +576,7 @@ ValidateFormat(
int
Tcl_ScanObjCmd(
- TCL_UNUSED(ClientData),
+ TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
@@ -578,7 +587,8 @@ Tcl_ScanObjCmd(
long value;
const char *string, *end, *baseString;
char op = 0;
- int width, underflow = 0;
+ int underflow = 0;
+ Tcl_Size width;
Tcl_WideInt wideValue;
Tcl_UniChar ch = 0, sch = 0;
Tcl_Obj **objs = NULL, *objPtr = NULL;
@@ -677,7 +687,7 @@ Tcl_ScanObjCmd(
if (*formatEnd == '$') {
format = formatEnd+1;
format += TclUtfToUniChar(format, &ch);
- objIndex = (int) value - 1;
+ objIndex = (int)value - 1;
}
}
@@ -686,7 +696,7 @@ Tcl_ScanObjCmd(
*/
if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */
- width = (int) strtoul(format-1, (char **) &format, 10);/* INTL: "C" locale. */
+ width = (int)strtoul(format-1, (char **)&format, 10);/* INTL: "C" locale. */
format += TclUtfToUniChar(format, &ch);
} else {
width = 0;
@@ -899,7 +909,7 @@ Tcl_ScanObjCmd(
width = ~0;
}
if (TCL_OK != TclParseNumber(NULL, objPtr, NULL, string, width,
- &end, TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_UNDERSCORE | parseFlag)) {
+ &end, TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_UNDERSCORE | parseFlag)) {
Tcl_DecrRefCount(objPtr);
if (width < 0) {
if (*end == '\0') {
@@ -918,7 +928,7 @@ Tcl_ScanObjCmd(
break;
}
if (flags & SCAN_LONGER) {
- if (Tcl_GetWideIntFromObj(NULL, objPtr, &wideValue) != TCL_OK) {
+ if (TclGetWideIntFromObj(NULL, objPtr, &wideValue) != TCL_OK) {
if (TclGetString(objPtr)[0] == '-') {
wideValue = WIDE_MIN;
} else {
@@ -1070,22 +1080,24 @@ Tcl_ScanObjCmd(
} else {
/*
* Here no vars were specified, we want a list returned (inline scan)
+ * We create an empty Tcl_Obj to fill missing values rather than
+ * allocating a new Tcl_Obj every time.
*/
-
+ Tcl_Obj *emptyObj = NULL;
TclNewObj(objPtr);
for (i = 0; i < totalVars; i++) {
if (objs[i] != NULL) {
Tcl_ListObjAppendElement(NULL, objPtr, objs[i]);
Tcl_DecrRefCount(objs[i]);
} else {
- Tcl_Obj *obj;
/*
* More %-specifiers than matching chars, so we just spit out
* empty strings for these.
*/
-
- TclNewObj(obj);
- Tcl_ListObjAppendElement(NULL, objPtr, obj);
+ if (!emptyObj) {
+ TclNewObj(emptyObj);
+ }
+ Tcl_ListObjAppendElement(NULL, objPtr, emptyObj);
}
}
}