From 690df67c55150b2cef37c6559471bb07f24e2524 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 29 May 2024 15:20:31 +0000 Subject: Let's [9c258a841a|fix] the %p/%z/%t type specifiers, so they behave like C in scripts, and document them --- doc/format.n | 5 ++++- generic/tclStringObj.c | 13 ++++++++++--- tests/format.test | 6 +++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/doc/format.n b/doc/format.n index eb64491..b647349 100644 --- a/doc/format.n +++ b/doc/format.n @@ -133,7 +133,7 @@ it must be a numeric string. .SS "OPTIONAL SIZE MODIFIER" .PP The fifth part of a conversion specifier is a size modifier, -which must be \fBll\fR, \fBh\fR, \fBl\fR, or \fBL\fR. +which must be \fBll\fR, \fBh\fR, \fBl\fR, \fBz\fR, \fBt\fR, or \fBL\fR. If it is \fBll\fR it specifies that an integer value is taken without truncation for conversion to a formatted substring. If it is \fBh\fR it specifies that an integer value is @@ -141,6 +141,9 @@ truncated to a 16-bit range before converting. This option is rarely useful. If it is \fBl\fR it specifies that the integer value is truncated to the same range as that produced by the \fBwide()\fR function of the \fBexpr\fR command (at least a 64-bit range). +If it is \fBz\fR or \fBt\fR it specifies that the integer value is +truncated to the range determined by the value of the \fBpointerSize\fR +element of the \fBtcl_platform\fR array. If it is \fBL\fR it specifies that an integer or double value is taken without truncation for conversion to a formatted substring. If neither \fBh\fR nor \fBl\fR nor \fBL\fR are present, the integer value is diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 980bf22..494451d 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -2457,8 +2457,15 @@ Tcl_AppendFormatToObj( format += step; step = TclUtfToUniChar(format, &ch); } - } else if ((ch == 't') || (ch == 'z') || (ch == 'q') || (ch == 'j') - || (ch == 'L')) { + } else if ((ch == 't') || (ch == 'z')) { + format += step; + step = TclUtfToUniChar(format, &ch); +#ifndef TCL_WIDE_INT_IS_LONG + if (sizeof(void *) > sizeof(int)) { + useWide = 1; + } +#endif + } else if ((ch == 'q') || (ch == 'j') || (ch == 'L')) { format += step; step = TclUtfToUniChar(format, &ch); useBig = 1; @@ -2534,7 +2541,7 @@ Tcl_AppendFormatToObj( Tcl_Size toAppend; #ifndef TCL_WIDE_INT_IS_LONG - if (ch == 'p') { + if ((ch == 'p') && (sizeof(void *) > sizeof(int))) { useWide = 1; } #endif diff --git a/tests/format.test b/tests/format.test index 4accb33..9f69fc0 100644 --- a/tests/format.test +++ b/tests/format.test @@ -389,17 +389,17 @@ test format-8.23 {error conditions} { test format-8.24 {Undocumented formats} -body { format "%zd %td %d" [expr {2**30}] [expr {2**30}] [expr {2**30}] } -result {1073741824 1073741824 1073741824} -test format-8.25 {Undocumented formats} -constraints pointerIs64bit -body { +test format-8.25 {Other formats} -constraints pointerIs64bit -body { format "%zd %td %lld" [expr {2**33}] [expr {2**33}] [expr {2**33}] } -result {8589934592 8589934592 8589934592} # Since "%p" is equivalent to "%#llx" in 64-bit platforms and equivalent # to "%#x" in 32-bit platforms, it are really not useful in scripts, # therefore they are not documented. It's intended use is through the # function Tcl_AppendPrintfToObj (et al). -test format-8.26 {Undocumented formats} -body { +test format-8.26 {Other formats} -body { format "%p %#x" [expr {2**31}] [expr {2**31}] } -result {0x80000000 0x80000000} -test format-8.27 {Undocumented formats} -constraints pointerIs64bit -body { +test format-8.27 {Other formats} -constraints pointerIs64bit -body { format "%p %#llx" [expr {2**33}] [expr {2**33}] } -result {0x200000000 0x200000000} test format-8.28 {Internal use of TCL_COMBINE flag should not be visible at script level} { -- cgit v0.12