--- a/String.st Wed Jul 18 15:28:49 2018 +0200
+++ b/String.st Thu Jul 19 11:37:30 2018 +0200
@@ -2466,6 +2466,88 @@
"
!
+sameAs:aString
+ "Compare the receiver with the argument like =, but ignore case differences.
+ Return true or false."
+
+%{ /* NOCONTEXT */
+ OBJ slf = self;
+ OBJ arg = aString;
+
+ if (__qIsStringLike(slf) &&__isStringLike(arg)) {
+ unsigned char *src1, *src2;
+ int len;
+
+ len = __stringSize(slf);
+ if (len != __stringSize(arg)) {
+ RETURN ( false );
+ }
+
+ src1 = __stringVal(slf);
+ src2 = __stringVal(arg);
+
+ // fast skip over same chars
+ while (len >= sizeof(int)) {
+ if ( ((int*)src1)[0] != ((int*)src2)[0] ) break;
+ len -= sizeof(int);
+ src1 += sizeof(int);
+ src2 += sizeof(int);
+ }
+ while (len > 0) {
+ if ( src1[0] != src2[0] ) break;
+ len--;
+ src1++;
+ src2++;
+ }
+
+ while (len > 0) {
+ // the trouble is, that it is not as easy as we might thing on first thought;
+ // for plain ascii (i.e. 7bits), we can check for chars being letters and then ignore the 0x20 bit.
+ // this even works for the national characters except for 0xFF / 0xDF
+ unsigned char ch1 = src1[0];
+ unsigned char ch2 = src2[0];
+ if (ch1 != ch2) {
+ unsigned char Uch1 = ch1 & ~0x20; // upper cased
+ unsigned char Uch2 = ch2 & ~0x20; // uppÞer cased
+ if ( (Uch1 >= 'A') && (Uch1 <= 'Z') ) {
+ // letter
+ if (Uch1 != Uch2) {
+ RETURN(false);
+ }
+ } else {
+ if ( (Uch1 >= 0xC0) && (Uch1 <= 0xDE) ) {
+ // national letter
+ if (Uch1 != Uch2) {
+ RETURN(false);
+ }
+ } else {
+ // other
+ RETURN(false);
+ }
+ }
+ }
+ len--;
+ src1++;
+ src2++;
+ }
+ RETURN (true);
+ }
+%}.
+ "use fallback for wide strings"
+ ^ super sameAs:aString
+
+ "
+ 'hello' sameAs:'hello'
+ 'hello' sameAs:'Hello'
+ 'hello' sameAs:''
+ '' sameAs:'Hello'
+ 'hello' sameAs:'hellO'
+ 'hello' sameAs:'Hellx'
+ "
+
+ "Created: / 19-07-2018 / 10:44:07 / Claus Gittinger"
+!
+
startsWith:aStringOrChar
"return true, if the receiver starts with something, aStringOrChar.
If the argument is empty, true is returned.