Author: Jan Nijtmans <jan.nijtmans@gmail.com>
State: Final
Type: Project
Vote: Done
Created: 09-Dec-2021
Post-History:
Keywords: Tcl Tcl_GetIndexFromObj() Tcl_GetIndexFromObjStruct()
Tcl-Version: 8.7
Tcl-Branch: tip-613
Vote-Summary: Accepted 7/0/0
Votes-For: BG, FV, JD, JN, KW, MC, SL
Votes-Against: none
Votes-Present: none
Abstract
This TIP proposes a new INDEX_NULL_OK
flag for Tcl_GetIndexFromObj*()
as TCL_INDEX_NULL_OK
,
and allow other variable types (like enum
, short
, long
, long long
, both signed and unsigned)
for the indexPtr
variable.
It also proposes to implement the TK_OPTION_NULL_OK
flag in Tk for the
options TK_OPTION_BOOLEAN
, TK_OPTION_JUSTIFY
and TK_OPTION_ANCHOR
, in
the same way as already present for TK_OPTION_RELIEF
, and for TK_OPTION_INT
in the same way as already present for TK_OPTION_DOUBLE
.
Rationale
In Tk, serveral options allow the empty string, but since Tcl_GetIndexFromObjStruct()
cannot handle
the empty string as input well, this results in special code in Tk to handle that. This is
not always done correctly, e.g.:
$ wish8.6 % text .t .t % .t tag configure dummy -relief {} % .t tag configure dummy -relief xxx bad relief "xxx": must be flat, groove, raised, ridge, solid, or sunken % .t tag configure dummy -wrap {} % .t tag configure dummy -wrap foo bad wrap "foo": must be char, none, word, or %So, the error-message doesn't even mention that "" is a valid value, or it forgets to quote the empty value.
The cause of the problem is here:
the empty string is made part of a string array used by Tcl_GetIndexFromObj*()
.
The meaning of TCL_INDEX_NULL_OK
is that Tcl_GetIndexFromObj*()
no longer
gives an error when indexPtr is supplied a NULL or "" argument, but it will return TCL_OK
and provide the index "-1". This functionality can then be used by Tk:
$ wish8.7 % text .t .t % .t tag configure dummy -wrap {} % .t tag configure dummy -wrap foo bad wrap "foo": must be char, none, word, or "" %
The indexPtr
parameter of Tcl_GetIndexFromObj*()
always had to point to
an integer variable, but this TIP changes the parameter to type void *
which can point to almost anything. This is done by using a wrapper macro,
which makes the sizeof()
of the variable available to the function.
So any scalar value, being an enum or some kind of integer (1-, 2-, 4- or 8-byte)
will work. indexPtr
can also be (int *)NULL
, then nothing will be written to it.
For Tk, the enum's Tk_Anchor
and Tk_Justify
will get new members
TK_ANCHOR_NULL
resp. TK_JUSTIFY_NULL
with value -1, equivalent with
the already existing TK_RELIEF_NULL
(which is not an enum for historical reasons).
Without the TK_OPTION_NULL_OK
flag in the TK_OPTION_JUSTIFY
and TK_OPTION_ANCHOR
config information, everything functions as before, but when using the
TK_OPTION_NULL_OK
flag, the new enum values become valid values for those configuration options.
For TK_OPTION_BOOLEAN
, the new possible value, when using the TK_OPTION_NULL_OK
flag, is -1. This would allow the -elide
, -overstrike
and -underline
options for text tags, currently implemented using TK_OPTION_STRING
,
to be re-implemented without the need for extra error-checking in the code,
since TK_OPTION_BOOLEAN
already takes care of that. This rewrite is not
done in the tip-613
,
branch in order to demonstrate that this TIP does not break current code.
For TK_OPTION_DOUBLE
, using the TK_OPTION_NULL_OK
flag will mean that
the NULL value will be translated to the internal value NaN
(Was: 0.0).
The reason for this change is that this makes it possible to distinguish
the empty string from 0.0, without storing the original Tcl_Obj in
the widget structure.
For TK_OPTION_INT
, using the TK_OPTION_NULL_OK
flag means that
the NULL value will be translated to internal value INT_MIN
. Also,
TK_OPTION_PIXEL
is changed the same way as TK_OPTION_INT
.
The change in TK_OPTION_DOUBLE
/TK_OPTION_INT
would allow the
-width
/-relWidth
/-height
/-relHeight
options to be re-written
such that the flags (CHILD_WIDTH et al.) are not needed any more. This
rewrite is not done in the tip-613
,
branch in order to demonstrate that this TIP does not break current code.
Caveat
Some extensions might have set the TK_OPTION_NULL_OK
flag already, even
though it never worked. This might result in "" as possible option value, which was
previously impossible, and what might lead to new unexpected behavior. Examples
are this bug in Tk menu's and
this bug in Themed Tk.
Solution: the extension should no longer use the TK_OPTION_NULL_OK
flag,
or expect Tcl 8.7 as a minimum and take care that the value -1 is handled properly.
One extension known to be broken this way is 3dcanvas.
The change in the TK_OPTION_NULL_OK
for TK_OPTION_DOUBLE
(using NaN as
internal representation in stead of 0.0) and for TK_OPTION_INT
/TK_OPTION_PIXEL
(using INT_MIN as internal representation in stead of 0) is a potential incompatibility
if the Tcl_Obj is not stored in the widget structure. In Tk, there is no code
affected (it is used only in -width
/-height
/-relWidth
/-relHeight
for the place
command).
Implementation
Available in the tip-613
branch.
There's a tip-613
branch in Tk as
well, implementing the TK_OPTION_NULL_OK
flag for TK_OPTION_BOOLEAN
,
TK_OPTION_JUSTIFY
and TK_OPTION_ANCHOR
, using Tcl's TCL_INDEX_NULL_OK
flag.
Finally there's a tip-613-demo
branch in Tk as well. This branch changes the "place" command and the implementation
for the -elide
, -overstrike
and -underline
text tags, to use the new functionality.
This branch targets 8.7.
Copyright
This document has been placed in the public domain.