diff options
author | dgp <dgp@users.sourceforge.net> | 2016-11-08 02:56:11 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2016-11-08 02:56:11 (GMT) |
commit | cad330bea5eb1c5fa6958b11506b10529846eb00 (patch) | |
tree | e1ef2f40fc3b0408147198398113220f4f9d7eb4 /generic/tclStringObj.c | |
parent | b1c86e9055e5384cf165f8e509583067d4b32796 (diff) | |
download | tcl-cad330bea5eb1c5fa6958b11506b10529846eb00.zip tcl-cad330bea5eb1c5fa6958b11506b10529846eb00.tar.gz tcl-cad330bea5eb1c5fa6958b11506b10529846eb00.tar.bz2 |
Route all [string last] operations through a common implementation.
Diffstat (limited to 'generic/tclStringObj.c')
-rw-r--r-- | generic/tclStringObj.c | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index edba881..f7791fe 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -2860,7 +2860,7 @@ int TclStringFind( Tcl_Obj *needle, Tcl_Obj *haystack, - unsigned int start) + int start) { int lh, ln = Tcl_GetCharLength(needle); @@ -2938,6 +2938,110 @@ TclStringFind( /* *--------------------------------------------------------------------------- * + * TclStringLast -- + * + * Implements the [string last] operation. + * + * Results: + * If needle is found as a substring of haystack, the index of the + * last instance of such a find is returned. If needle is not present + * as a substring of haystack, -1 is returned. + * + * Side effects: + * needle and haystack may have their Tcl_ObjType changed. + * + *--------------------------------------------------------------------------- + */ + +int +TclStringLast( + Tcl_Obj *needle, + Tcl_Obj *haystack, + int last) +{ + int lh, ln = Tcl_GetCharLength(needle); + + if (ln == 0) { + /* + * We don't find empty substrings. Bizarre! + * + * TODO: When we one day make this a true substring + * finder, change this to "return 0" + */ + return -1; + } + + if (ln > last + 1) { + return -1; + } + + if (TclIsPureByteArray(needle) && TclIsPureByteArray(haystack)) { + unsigned char *try, *bh; + unsigned char *bn = Tcl_GetByteArrayFromObj(needle, &ln); + + bh = Tcl_GetByteArrayFromObj(haystack, &lh); + + if (last + 1 > lh) { + last = lh - 1; + } + try = bh + last + 1 - ln; + while (try >= bh) { + if ((*try == bn[0]) + && (0 == memcmp(try+1, bn+1, ln-1))) { + return (try - bh); + } + try--; + } + return -1; + } + + lh = Tcl_GetCharLength(haystack); + if (last + 1 > lh) { + last = lh - 1; + } + if (haystack->bytes && (lh == haystack->length)) { + /* haystack is all single-byte chars */ + + if (needle->bytes && (ln == needle->length)) { + /* needle is also all single-byte chars */ + + char *try = haystack->bytes + last + 1 - ln; + while (try >= haystack->bytes) { + if ((*try == needle->bytes[0]) + && (0 == memcmp(try+1, needle->bytes + 1, ln - 1))) { + return (try - haystack->bytes); + } + try--; + } + return -1; + } else { + /* + * Cannot find substring with a multi-byte char inside + * a string with no multi-byte chars. + */ + return -1; + } + } else { + Tcl_UniChar *try, *uh; + Tcl_UniChar *un = Tcl_GetUnicodeFromObj(needle, &ln); + + uh = Tcl_GetUnicodeFromObj(haystack, &lh); + + try = uh + last + 1 - ln; + while (try >= uh) { + if ((*try == un[0]) + && (0 == memcmp(try+1, un+1, (ln-1)*sizeof(Tcl_UniChar)))) { + return (try - uh); + } + try--; + } + return -1; + } +} + +/* + *--------------------------------------------------------------------------- + * * TclStringObjReverse -- * * Implements the [string reverse] operation. |