diff options
author | dgp <dgp@users.sourceforge.net> | 2018-11-13 15:52:23 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2018-11-13 15:52:23 (GMT) |
commit | 372c35b657ebdfb9f06d9eb30e9f61bce40b021f (patch) | |
tree | 03c3665212d6e29b2ecc4073652708f2aa369646 | |
parent | a08f5d57e07e920f8addbab949fadd29fcbe0adb (diff) | |
download | tcl-372c35b657ebdfb9f06d9eb30e9f61bce40b021f.zip tcl-372c35b657ebdfb9f06d9eb30e9f61bce40b021f.tar.gz tcl-372c35b657ebdfb9f06d9eb30e9f61bce40b021f.tar.bz2 |
Adapted TIP 501
-rw-r--r-- | doc/string.n | 14 | ||||
-rw-r--r-- | generic/tclCmdMZ.c | 69 | ||||
-rw-r--r-- | generic/tclCompCmdsSZ.c | 18 | ||||
-rw-r--r-- | tests/string.test | 79 |
4 files changed, 160 insertions, 20 deletions
diff --git a/doc/string.n b/doc/string.n index 439f3b7..cc3fc54 100644 --- a/doc/string.n +++ b/doc/string.n @@ -20,7 +20,7 @@ Performs one of several string operations, depending on \fIoption\fR. The legal \fIoption\fRs (which may be abbreviated) are: .TP \fBstring cat\fR ?\fIstring1\fR? ?\fIstring2...\fR? -.VS 8.6.2 +. Concatenate the given \fIstring\fRs just like placing them directly next to each other and return the resulting compound string. If no \fIstring\fRs are present, the result is an empty string. @@ -32,7 +32,6 @@ of a concatenation without resorting to \fBreturn\fR \fB\-level 0\fR, and is more efficient than building a list of arguments and using \fBjoin\fR with an empty join string. .RE -.VE .TP \fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length\fI length\fR? \fIstring1 string2\fR . @@ -111,17 +110,24 @@ Any character with a value less than \eu0080 (those that are in the Any of the forms allowed to \fBTcl_GetBoolean\fR. .IP \fBcontrol\fR 12 Any Unicode control character. +.IP \fBdict\fR 12 +.VS TIP501 +Any proper dict structure, with optional surrounding whitespace. In +case of improper dict structure, 0 is returned and the \fIvarname\fR +will contain the index of the +.QW element +where the dict parsing fails, or \-1 if this cannot be determined. +.VE TIP501 .IP \fBdigit\fR 12 Any Unicode digit character. Note that this includes characters outside of the [0\-9] range. .IP \fBdouble\fR 12 Any of the forms allowed to \fBTcl_GetDoubleFromObj\fR. .IP \fBentier\fR 12 -.VS 8.6 +. Any of the valid string formats for an integer value of arbitrary size in Tcl, with optional surrounding whitespace. The formats accepted are exactly those accepted by the C routine \fBTcl_GetBignumFromObj\fR. -.VE .IP \fBfalse\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is false. diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index ff14d96..16d5bb7 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -1493,19 +1493,19 @@ StringIsCmd( static const char *const isClasses[] = { "alnum", "alpha", "ascii", "control", - "boolean", "digit", "double", "entier", - "false", "graph", "integer", "list", - "lower", "print", "punct", "space", - "true", "upper", "wideinteger", "wordchar", - "xdigit", NULL + "boolean", "dict", "digit", "double", + "entier", "false", "graph", "integer", + "list", "lower", "print", "punct", + "space", "true", "upper", "wideinteger", + "wordchar", "xdigit", NULL }; enum isClasses { STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL, - STR_IS_BOOL, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_ENTIER, - STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT, STR_IS_LIST, - STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT, STR_IS_SPACE, - STR_IS_TRUE, STR_IS_UPPER, STR_IS_WIDE, STR_IS_WORD, - STR_IS_XDIGIT + STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE, + STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT, + STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT, + STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER, STR_IS_WIDE, + STR_IS_WORD, STR_IS_XDIGIT }; static const char *const isOptions[] = { "-strict", "-failindex", NULL @@ -1590,6 +1590,55 @@ StringIsCmd( case STR_IS_CONTROL: chcomp = Tcl_UniCharIsControl; break; + case STR_IS_DICT: { + int dresult, dsize; + + dresult = Tcl_DictObjSize(interp, objPtr, &dsize); + Tcl_ResetResult(interp); + result = (dresult == TCL_OK) ? 1 : 0; + if (dresult != TCL_OK && failVarObj != NULL) { + /* + * Need to figure out where the list parsing failed, which is + * fairly expensive. This is adapted from the core of + * SetDictFromAny(). + */ + + const char *elemStart, *nextElem; + int lenRemain; + size_t elemSize; + register const char *p; + + string1 = TclGetStringFromObj(objPtr, &length1); + end = string1 + length1; + failat = -1; + for (p=string1, lenRemain=length1; lenRemain > 0; + p=nextElem, lenRemain=end-nextElem) { + if (TCL_ERROR == TclFindElement(NULL, p, lenRemain, + &elemStart, &nextElem, &elemSize, NULL)) { + Tcl_Obj *tmpStr; + + /* + * This is the simplest way of getting the number of + * characters parsed. Note that this is not the same as + * the number of bytes when parsing strings with non-ASCII + * characters in them. + * + * Skip leading spaces first. This is only really an issue + * if it is the first "element" that has the failure. + */ + + while (TclIsSpaceProc(*p)) { + p++; + } + TclNewStringObj(tmpStr, string1, p-string1); + failat = Tcl_GetCharLength(tmpStr); + TclDecrRefCount(tmpStr); + break; + } + } + } + break; + } case STR_IS_DIGIT: chcomp = Tcl_UniCharIsDigit; break; diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index bcdaa78..08b523c 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -461,7 +461,7 @@ TclCompileStringIsCmd( Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); static const char *const isClasses[] = { "alnum", "alpha", "ascii", "control", - "boolean", "digit", "double", "entier", + "boolean", "dict", "digit", "double", "entier", "false", "graph", "integer", "list", "lower", "print", "punct", "space", "true", "upper", "wideinteger", "wordchar", @@ -469,7 +469,7 @@ TclCompileStringIsCmd( }; enum isClasses { STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL, - STR_IS_BOOL, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_ENTIER, + STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT, STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT, STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER, STR_IS_WIDE, STR_IS_WORD, @@ -703,7 +703,19 @@ TclCompileStringIsCmd( } FIXJUMP1( end); return TCL_OK; - + case STR_IS_DICT: + range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr); + OP4( BEGIN_CATCH4, range); + ExceptionRangeStarts(envPtr, range); + OP( DUP); + OP( DICT_VERIFY); + ExceptionRangeEnds(envPtr, range); + ExceptionRangeTarget(envPtr, range, catchOffset); + OP( POP); + OP( PUSH_RETURN_CODE); + OP( END_CATCH); + OP( LNOT); + return TCL_OK; case STR_IS_LIST: range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr); OP4( BEGIN_CATCH4, range); diff --git a/tests/string.test b/tests/string.test index 79f25fc..9bceb37 100644 --- a/tests/string.test +++ b/tests/string.test @@ -515,10 +515,10 @@ test string-6.4.$noComp {string is, too many args} { } {1 {wrong # args: should be "string is class ?-strict? ?-failindex var? str"}} test string-6.5.$noComp {string is, class check} { list [catch {run {string is bogus str}} msg] $msg -} {1 {bad class "bogus": must be alnum, alpha, ascii, control, boolean, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, wideinteger, wordchar, or xdigit}} +} {1 {bad class "bogus": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, wideinteger, wordchar, or xdigit}} test string-6.6.$noComp {string is, ambiguous class} { list [catch {run {string is al str}} msg] $msg -} {1 {ambiguous class "al": must be alnum, alpha, ascii, control, boolean, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, wideinteger, wordchar, or xdigit}} +} {1 {ambiguous class "al": must be alnum, alpha, ascii, control, boolean, dict, digit, double, entier, false, graph, integer, list, lower, print, punct, space, true, upper, wideinteger, wordchar, or xdigit}} test string-6.7.$noComp {string is alpha, all ok} { run {string is alpha -strict -failindex var abc} } 1 @@ -2306,6 +2306,7 @@ test string-29.15.$noComp {string cat, efficiency} -setup { tcl::unsupported::representation [run {string cat $e $f $e $f [list x]}] } -match glob -result {*no string representation} } + test string-30.1.1.$noComp {[Bug ba921a8d98]: string cat} { run {string cat [set data [binary format a* hello]] [encoding convertto $data] [unset data]} } hellohello @@ -2313,8 +2314,80 @@ test string-30.1.2.$noComp {[Bug ba921a8d98]: inplace cat by subst (compiled to run {set x "[set data [binary format a* hello]][encoding convertto $data][unset data]"} } hellohello -} +test string-31.1.$noComp {string is dict} { + string is dict {a b c d} +} 1 +test string-31.1a.$noComp {string is dict} { + string is dict {a b c} +} 0 +test string-31.2.$noComp {string is dict} { + string is dict "a \{b c" +} 0 +test string-31.3.$noComp {string is dict} { + string is dict {a {b c}d e} +} 0 +test string-31.4.$noComp {string is dict} { + string is dict {} +} 1 +test string-31.5.$noComp {string is dict} { + string is dict -strict {a b c d} +} 1 +test string-31.5a.$noComp {string is dict} { + string is dict -strict {a b c} +} 0 +test string-31.6.$noComp {string is dict} { + string is dict -strict "a \{b c" +} 0 +test string-31.7.$noComp {string is dict} { + string is dict -strict {a {b c}d e} +} 0 +test string-31.8.$noComp {string is dict} { + string is dict -strict {} +} 1 +test string-31.9.$noComp {string is dict} { + set x {} + list [string is dict -failindex x {a b c d}] $x +} {1 {}} +test string-31.9a.$noComp {string is dict} { + set x {} + list [string is dict -failindex x {a b c}] $x +} {0 -1} +test string-31.10.$noComp {string is dict} { + set x {} + list [string is dict -failindex x "a \{b c d"] $x +} {0 2} +test string-31.10a.$noComp {string is dict} { + set x {} + list [string is dict -failindex x "a \{b c"] $x +} {0 2} +test string-31.11.$noComp {string is dict} { + set x {} + list [string is dict -failindex x {a b {b c}d e}] $x +} {0 4} +test string-31.12.$noComp {string is dict} { + set x {} + list [string is dict -failindex x {}] $x +} {1 {}} +test string-31.13.$noComp {string is dict} { + set x {} + list [string is dict -failindex x { {b c}d e}] $x +} {0 2} +test string-31.14.$noComp {string is dict} { + set x {} + list [string is dict -failindex x "\uabcd {b c}d e"] $x +} {0 2} +test string-31.15.$noComp {string is dict, valid dict} { + string is dict {a b c d e f} +} 1 +test string-31.16.$noComp {string is dict, invalid dict} { + string is dict a +} 0 +test string-31.17.$noComp {string is dict, valid dict packed in invalid dict} { + string is dict {{a b c d e f g h}} +} 0 +}; # foreach noComp {0 1} + # cleanup rename MemStress {} rename makeByteArray {} |