Index: doc/BoolObj.3 ================================================================== --- doc/BoolObj.3 +++ doc/BoolObj.3 @@ -7,11 +7,11 @@ '\" .TH Tcl_BooleanObj 3 8.5 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME -Tcl_NewBooleanObj, Tcl_SetBooleanObj, Tcl_GetBooleanFromObj \- store/retrieve boolean value in a Tcl_Obj +Tcl_NewBooleanObj, Tcl_SetBooleanObj, Tcl_GetBooleanFromObj, Tcl_GetBoolFromObj \- store/retrieve boolean value in a Tcl_Obj .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * @@ -19,10 +19,13 @@ .sp \fBTcl_SetBooleanObj\fR(\fIobjPtr, intValue\fR) .sp int \fBTcl_GetBooleanFromObj\fR(\fIinterp, objPtr, intPtr\fR) +.sp +int +\fBTcl_GetBoolFromObj\fR(\fIinterp, objPtr, flags. charPtr\fR) .SH ARGUMENTS .AS Tcl_Interp intValue in/out .AP int intValue in Integer value to be stored as a boolean value in a Tcl_Obj. .AP Tcl_Obj *objPtr in/out @@ -33,10 +36,17 @@ an error message is left in the interpreter's result value unless \fIinterp\fR is NULL. .AP int *intPtr out Points to place where \fBTcl_GetBooleanFromObj\fR stores the boolean value (0 or 1) obtained from \fIobjPtr\fR. +.AP char *charPtr out +Points to place where \fBTcl_GetBoolFromObj\fR +stores the boolean value (0 or 1) obtained from \fIobjPtr\fR. +.AP int flags in +0 or TCL_NULL_OK. If TCL_NULL_OK +is used, then the empty string or NULL will result in \fBTcl_GetBoolFromObj\fR +return TCL_OK, the *charPtr filled with the value \fB'\exFF'\fR; .BE .SH DESCRIPTION .PP These procedures are used to pass boolean values to and from @@ -73,10 +83,15 @@ left in the interpreter's result unless \fIinterp\fR is NULL. \fBTcl_GetBooleanFromObj\fR may also make changes to the internal fields of \fI*objPtr\fR so that future calls to \fBTcl_GetBooleanFromObj\fR on the same \fIobjPtr\fR can be performed more efficiently. +.PP +\fBTcl_GetBoolFromObj\fR functions almost the same as +\fBTcl_GetBooleanFromObj\fR, but it has an additional parameter +\fBflags\fR, which can be used to specify whether the empty +string or NULL is accepted as valid. .PP Note that the routines \fBTcl_GetBooleanFromObj\fR and \fBTcl_GetBoolean\fR are not functional equivalents. The set of values for which \fBTcl_GetBooleanFromObj\fR will return \fBTCL_OK\fR is strictly larger than Index: doc/GetIndex.3 ================================================================== --- doc/GetIndex.3 +++ doc/GetIndex.3 @@ -52,11 +52,11 @@ Null-terminated string describing what is being looked up, such as \fBoption\fR. This string is included in error messages. .AP int flags in OR-ed combination of bits providing additional information for operation. The only bits that are currently defined are \fBTCL_EXACT\fR -, \fBTCL_INDEX_TEMP_TABLE\fR, and \fBTCL_INDEX_NULL_OK\fR. +, \fBTCL_INDEX_TEMP_TABLE\fR, and \fBTCL_NULL_OK\fR. .AP enum|char|short|int|long *indexPtr out If not (int *)NULL, the index of the string in \fItablePtr\fR that matches the value of \fIobjPtr\fR is returned here. The variable can be any integer type, signed or unsigned, char, short, long or long long. It can also be an enum. @@ -91,11 +91,11 @@ the matching index immediately without having to redo the lookup operation. Note: \fBTcl_GetIndexFromObj\fR assumes that the entries in \fItablePtr\fR are static: they must not change between invocations. This caching mechanism can be disallowed by specifying the \fBTCL_INDEX_TEMP_TABLE\fR flag. -If the \fBTCL_INDEX_NULL_OK\fR flag was specified, objPtr is allowed +If the \fBTCL_NULL_OK\fR flag was specified, objPtr is allowed to be NULL or the empty string. The resulting index is -1. Otherwise, if the value of \fIobjPtr\fR is the empty string, \fBTcl_GetIndexFromObj\fR will treat it as a non-matching value and return \fBTCL_ERROR\fR. .PP Index: doc/GetInt.3 ================================================================== --- doc/GetInt.3 +++ doc/GetInt.3 @@ -20,10 +20,13 @@ int \fBTcl_GetDouble\fR(\fIinterp, src, doublePtr\fR) .sp int \fBTcl_GetBoolean\fR(\fIinterp, src, intPtr\fR) +.sp +int +\fBTcl_GetBool\fR(\fIinterp, src, flags, charPtr\fR) .SH ARGUMENTS .AS Tcl_Interp *doublePtr out .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP "const char" *src in @@ -31,10 +34,16 @@ .AP int *intPtr out Points to place to store integer value converted from \fIsrc\fR. .AP double *doublePtr out Points to place to store double-precision floating-point value converted from \fIsrc\fR. +.AP char *charPtr out +Points to place to store boolean value (0 or 1) value converted from \fIsrc\fR. +.AP int flags in +0 or TCL_NULL_OK. If TCL_NULL_OK +is used, then the empty string or NULL will result in \fBTcl_GetBool\fR +return TCL_OK, the *charPtr filled with the value \fB'\exFF'\fR; .BE .SH DESCRIPTION .PP These procedures convert from strings to integers or double-precision @@ -95,8 +104,12 @@ value at \fI*intPtr\fR. If \fIsrc\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, then 1 is stored at \fI*intPtr\fR. Any of these values may be abbreviated, and upper-case spellings are also acceptable. +.PP +\fBTcl_GetBool\fR functions almost the same as \fBTcl_GetBoolean\fR, +but it has an additional parameter \fBflags\fR, which can be used +to specify whether the empty string or NULL is accepted as valid. .SH KEYWORDS boolean, conversion, double, floating-point, integer Index: doc/ledit.n ================================================================== --- doc/ledit.n +++ doc/ledit.n @@ -16,11 +16,11 @@ .SH DESCRIPTION .PP The command fetches the list value in variable \fIlistVar\fR and replaces the elements in the range given by indices \fIfirst\fR to \fIlast\fR (inclusive) with the \fIvalue\fR arguments. The resulting list is then stored back in -\fIlistVar\fR and returned as the result of the command. +\fIlistVar\fR and returned as the result of the command. .PP Arguments \fIfirst\fR and \fIlast\fR are index values specifying the first and last elements of the range to replace. They are interpreted the same as index values for the command \fBstring index\fR, supporting simple index arithmetic and indices relative to the Index: generic/tcl.decls ================================================================== --- generic/tcl.decls +++ generic/tcl.decls @@ -2500,12 +2500,18 @@ } declare 673 { int TclGetUniChar(Tcl_Obj *objPtr, int index) } -# slot 674 and 675 are reserved for TIP #618 - +declare 674 { + int Tcl_GetBool(Tcl_Interp *interp, const char *src, int flags, + char *charPtr) +} +declare 675 { + int Tcl_GetBoolFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, + int flags, char *charPtr) +} declare 676 { Tcl_Command Tcl_CreateObjCommand2(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc) Index: generic/tcl.h ================================================================== --- generic/tcl.h +++ generic/tcl.h @@ -987,18 +987,18 @@ #define TCL_DONT_QUOTE_HASH 8 /* * Flags that may be passed to Tcl_GetIndexFromObj. * TCL_EXACT disallows abbreviated strings. - * TCL_INDEX_NULL_OK allows the empty string or NULL to return TCL_OK. + * TCL_NULL_OK allows the empty string or NULL to return TCL_OK. * The returned value will be -1; * TCL_INDEX_TEMP_TABLE disallows caching of lookups. A possible use case is * a table that will not live long enough to make it worthwhile. */ #define TCL_EXACT 1 -#define TCL_INDEX_NULL_OK 32 +#define TCL_NULL_OK 32 #define TCL_INDEX_TEMP_TABLE 64 /* * Flags that may be passed to Tcl_UniCharToUtf. * TCL_COMBINE Combine surrogates (default in Tcl 8.x) Index: generic/tclDecls.h ================================================================== --- generic/tclDecls.h +++ generic/tclDecls.h @@ -1977,12 +1977,16 @@ EXTERN const char * TclUtfAtIndex(const char *src, int index); /* 672 */ EXTERN Tcl_Obj * TclGetRange(Tcl_Obj *objPtr, int first, int last); /* 673 */ EXTERN int TclGetUniChar(Tcl_Obj *objPtr, int index); -/* Slot 674 is reserved */ -/* Slot 675 is reserved */ +/* 674 */ +EXTERN int Tcl_GetBool(Tcl_Interp *interp, const char *src, + int flags, char *charPtr); +/* 675 */ +EXTERN int Tcl_GetBoolFromObj(Tcl_Interp *interp, + Tcl_Obj *objPtr, int flags, char *charPtr); /* 676 */ EXTERN Tcl_Command Tcl_CreateObjCommand2(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); @@ -2712,12 +2716,12 @@ int (*tclNumUtfChars) (const char *src, int length); /* 669 */ int (*tclGetCharLength) (Tcl_Obj *objPtr); /* 670 */ const char * (*tclUtfAtIndex) (const char *src, int index); /* 671 */ Tcl_Obj * (*tclGetRange) (Tcl_Obj *objPtr, int first, int last); /* 672 */ int (*tclGetUniChar) (Tcl_Obj *objPtr, int index); /* 673 */ - void (*reserved674)(void); - void (*reserved675)(void); + int (*tcl_GetBool) (Tcl_Interp *interp, const char *src, int flags, char *charPtr); /* 674 */ + int (*tcl_GetBoolFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, char *charPtr); /* 675 */ Tcl_Command (*tcl_CreateObjCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 676 */ Tcl_Trace (*tcl_CreateObjTrace2) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc2 *objProc2, void *clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 677 */ Tcl_Command (*tcl_NRCreateCommand2) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc2 *proc, Tcl_ObjCmdProc2 *nreProc2, void *clientData, Tcl_CmdDeleteProc *deleteProc); /* 678 */ int (*tcl_NRCallObjProc2) (Tcl_Interp *interp, Tcl_ObjCmdProc2 *objProc2, void *clientData, size_t objc, Tcl_Obj *const objv[]); /* 679 */ void (*reserved680)(void); @@ -4099,12 +4103,14 @@ (tclStubsPtr->tclUtfAtIndex) /* 671 */ #define TclGetRange \ (tclStubsPtr->tclGetRange) /* 672 */ #define TclGetUniChar \ (tclStubsPtr->tclGetUniChar) /* 673 */ -/* Slot 674 is reserved */ -/* Slot 675 is reserved */ +#define Tcl_GetBool \ + (tclStubsPtr->tcl_GetBool) /* 674 */ +#define Tcl_GetBoolFromObj \ + (tclStubsPtr->tcl_GetBoolFromObj) /* 675 */ #define Tcl_CreateObjCommand2 \ (tclStubsPtr->tcl_CreateObjCommand2) /* 676 */ #define Tcl_CreateObjTrace2 \ (tclStubsPtr->tcl_CreateObjTrace2) /* 677 */ #define Tcl_NRCreateCommand2 \ Index: generic/tclGet.c ================================================================== --- generic/tclGet.c +++ generic/tclGet.c @@ -108,11 +108,11 @@ * * Given a string, return a 0/1 boolean value corresponding to the * string. * * Results: - * The return value is normally TCL_OK; in this case *intPtr will be set + * The return value is normally TCL_OK; in this case *charPtr will be set * to the 0/1 value equivalent to src. If src is improperly formed then * TCL_ERROR is returned and an error message will be left in the * interp's result. * * Side effects: @@ -119,21 +119,26 @@ * None. * *---------------------------------------------------------------------- */ +#undef Tcl_GetBool int -Tcl_GetBoolean( +Tcl_GetBool( Tcl_Interp *interp, /* Interpreter used for error reporting. */ const char *src, /* String containing one of the boolean values * 1, 0, true, false, yes, no, on, off. */ - int *intPtr) /* Place to store converted result, which will + int flags, + char *charPtr) /* Place to store converted result, which will * be 0 or 1. */ { Tcl_Obj obj; int code; + if ((src == NULL) || (*src == '\0')) { + return (Tcl_GetBoolFromObj)(interp, NULL, flags, charPtr); + } obj.refCount = 1; obj.bytes = (char *) src; obj.length = strlen(src); obj.typePtr = NULL; @@ -140,17 +145,34 @@ code = TclSetBooleanFromAny(interp, &obj); if (obj.refCount > 1) { Tcl_Panic("invalid sharing of Tcl_Obj on C stack"); } if (code == TCL_OK) { - TclGetBooleanFromObj(NULL, &obj, intPtr); + (Tcl_GetBoolFromObj)(NULL, &obj, flags, charPtr); } return code; } + +#undef Tcl_GetBoolean +int +Tcl_GetBoolean( + Tcl_Interp *interp, /* Interpreter used for error reporting. */ + const char *src, /* String containing one of the boolean values + * 1, 0, true, false, yes, no, on, off. */ + int *intPtr) /* Place to store converted result, which will + * be 0 or 1. */ +{ + char charValue; + int result = Tcl_GetBool(interp, src, 0, &charValue); + if (intPtr) { + *intPtr = charValue; + } + return result; +} /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ Index: generic/tclIndexObj.c ================================================================== --- generic/tclIndexObj.c +++ generic/tclIndexObj.c @@ -261,11 +261,11 @@ * etc. The last entry must be NULL and there * must not be duplicate entries. */ int offset, /* The number of bytes between entries */ const char *msg, /* Identifying word to use in error * messages. */ - int flags, /* 0, TCL_EXACT, TCL_INDEX_TEMP_TABLE or TCL_INDEX_NULL_OK */ + int flags, /* 0, TCL_EXACT, TCL_INDEX_TEMP_TABLE or TCL_NULL_OK */ void *indexPtr) /* Place to store resulting index. */ { int index, idx, numAbbrev; const char *key, *p1; const char *p2; @@ -302,11 +302,11 @@ key = objPtr ? TclGetString(objPtr) : ""; index = -1; numAbbrev = 0; - if (!*key && (flags & TCL_INDEX_NULL_OK)) { + if (!*key && (flags & TCL_NULL_OK)) { goto uncachedDone; } /* * Scan the table looking for one of: * - An exact match (always preferred) @@ -410,20 +410,20 @@ } else { Tcl_AppendStringsToObj(resultPtr, "\": must be ", *entryPtr, NULL); entryPtr = NEXT_ENTRY(entryPtr, offset); while (*entryPtr != NULL) { - if ((*NEXT_ENTRY(entryPtr, offset) == NULL) && !(flags & TCL_INDEX_NULL_OK)) { + if ((*NEXT_ENTRY(entryPtr, offset) == NULL) && !(flags & TCL_NULL_OK)) { Tcl_AppendStringsToObj(resultPtr, (count > 0 ? "," : ""), " or ", *entryPtr, NULL); } else if (**entryPtr) { Tcl_AppendStringsToObj(resultPtr, ", ", *entryPtr, NULL); count++; } entryPtr = NEXT_ENTRY(entryPtr, offset); } - if ((flags & TCL_INDEX_NULL_OK)) { + if ((flags & TCL_NULL_OK)) { Tcl_AppendStringsToObj(resultPtr, ", or \"\"", NULL); } } Tcl_SetObjResult(interp, resultPtr); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", msg, key, NULL); Index: generic/tclObj.c ================================================================== --- generic/tclObj.c +++ generic/tclObj.c @@ -2139,11 +2139,11 @@ #endif /* TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------- * - * Tcl_GetBooleanFromObj -- + * Tcl_GetBoolFromObj, Tcl_GetBooleanFromObj -- * * Attempt to return a boolean from the Tcl object "objPtr". This * includes conversion from any of Tcl's numeric types. * * Results: @@ -2155,24 +2155,40 @@ * The internalrep of *objPtr may be changed. * *---------------------------------------------------------------------- */ +#undef Tcl_GetBoolFromObj int -Tcl_GetBooleanFromObj( +Tcl_GetBoolFromObj( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr, /* The object from which to get boolean. */ - int *intPtr) /* Place to store resulting boolean. */ + int flags, + char *charPtr) /* Place to store resulting boolean. */ { + int result; + + if ((flags & TCL_NULL_OK) && (objPtr == NULL || Tcl_GetString(objPtr)[0] == '\0')) { + result = -1; + goto boolEnd; + } else if (objPtr == NULL) { + if (interp) { + TclNewObj(objPtr); + TclParseNumber(interp, objPtr, (flags & TCL_NULL_OK) + ? "boolean value or \"\"" : "boolean value", NULL, -1, NULL, 0); + Tcl_DecrRefCount(objPtr); + } + return TCL_ERROR; + } do { if (objPtr->typePtr == &tclIntType) { - *intPtr = (objPtr->internalRep.wideValue != 0); - return TCL_OK; + result = (objPtr->internalRep.wideValue != 0); + goto boolEnd; } if (objPtr->typePtr == &tclBooleanType) { - *intPtr = objPtr->internalRep.longValue != 0; - return TCL_OK; + result = objPtr->internalRep.longValue != 0; + goto boolEnd; } if (objPtr->typePtr == &tclDoubleType) { /* * Caution: Don't be tempted to check directly for the "double" * Tcl_ObjType and then compare the internalrep to 0.0. This isn't @@ -2184,22 +2200,42 @@ double d; if (Tcl_GetDoubleFromObj(interp, objPtr, &d) != TCL_OK) { return TCL_ERROR; } - *intPtr = (d != 0.0); - return TCL_OK; + result = (d != 0.0); + goto boolEnd; } if (objPtr->typePtr == &tclBignumType) { - *intPtr = 1; + result = 1; + boolEnd: + if (charPtr != NULL) { + *charPtr = result; + } return TCL_OK; } } while ((ParseBoolean(objPtr) == TCL_OK) || (TCL_OK == - TclParseNumber(interp, objPtr, "boolean value", NULL,-1,NULL,0))); + TclParseNumber(interp, objPtr, (flags & TCL_NULL_OK) + ? "boolean value or \"\"" : "boolean value", NULL,-1,NULL,0))); return TCL_ERROR; } +#undef Tcl_GetBooleanFromObj +int +Tcl_GetBooleanFromObj( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr, /* The object from which to get boolean. */ + int *intPtr) /* Place to store resulting boolean. */ +{ + char charValue; + int result = Tcl_GetBoolFromObj(interp, objPtr, 0, &charValue); + if (intPtr) { + *intPtr = charValue; + } + return result; +} + /* *---------------------------------------------------------------------- * * TclSetBooleanFromAny -- * Index: generic/tclStubInit.c ================================================================== --- generic/tclStubInit.c +++ generic/tclStubInit.c @@ -2037,12 +2037,12 @@ TclNumUtfChars, /* 669 */ TclGetCharLength, /* 670 */ TclUtfAtIndex, /* 671 */ TclGetRange, /* 672 */ TclGetUniChar, /* 673 */ - 0, /* 674 */ - 0, /* 675 */ + Tcl_GetBool, /* 674 */ + Tcl_GetBoolFromObj, /* 675 */ Tcl_CreateObjCommand2, /* 676 */ Tcl_CreateObjTrace2, /* 677 */ Tcl_NRCreateCommand2, /* 678 */ Tcl_NRCallObjProc2, /* 679 */ 0, /* 680 */ Index: generic/tclTest.c ================================================================== --- generic/tclTest.c +++ generic/tclTest.c @@ -2324,20 +2324,20 @@ TestEvent *ev = (TestEvent *) event; Tcl_Interp *interp = ev->interp; Tcl_Obj *command = ev->command; int result = Tcl_EvalObjEx(interp, command, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT); - int retval; + char retval; if (result != TCL_OK) { Tcl_AddErrorInfo(interp, " (command bound to \"testevent\" callback)"); Tcl_BackgroundException(interp, TCL_ERROR); return 1; /* Avoid looping on errors */ } - if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp), - &retval) != TCL_OK) { + if (Tcl_GetBoolFromObj(interp, Tcl_GetObjResult(interp), + 0, &retval) != TCL_OK) { Tcl_AddErrorInfo(interp, " (return value from \"testevent\" callback)"); Tcl_BackgroundException(interp, TCL_ERROR); return 1; } @@ -5528,11 +5528,12 @@ Tcl_Interp *interp,/* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { Interp* iPtr = (Interp*) interp; - int discard, result, index; + int result, index; + char discard; Tcl_SavedResult state; Tcl_Obj *objPtr; static const char *const optionStrings[] = { "append", "dynamic", "free", "object", "small", NULL }; @@ -5550,11 +5551,11 @@ } if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } - if (Tcl_GetBooleanFromObj(interp, objv[3], &discard) != TCL_OK) { + if (Tcl_GetBoolFromObj(interp, objv[3], 0, &discard) != TCL_OK) { return TCL_ERROR; } freeCount = 0; objPtr = NULL;