https://git.reactos.org/?p=reactos.git;a=commitdiff;h=58092fb4da352491e2f87fecc52ff5a652ab6669

commit 58092fb4da352491e2f87fecc52ff5a652ab6669
Author:     Mark Jansen <[email protected]>
AuthorDate: Sun Sep 6 21:30:23 2020 +0200
Commit:     Mark Jansen <[email protected]>
CommitDate: Mon Sep 7 22:13:43 2020 +0200

    [ATL][ATL_APITEST] Add CString::Tokenize + testcase
---
 modules/rostests/apitests/atl/CString.cpp |  3 ++
 modules/rostests/apitests/atl/CString.inl | 87 +++++++++++++++++++++++++++++++
 sdk/lib/atl/cstringt.h                    | 64 +++++++++++++++++++++++
 3 files changed, 154 insertions(+)

diff --git a/modules/rostests/apitests/atl/CString.cpp 
b/modules/rostests/apitests/atl/CString.cpp
index 89782499521..fdb9d55020f 100644
--- a/modules/rostests/apitests/atl/CString.cpp
+++ b/modules/rostests/apitests/atl/CString.cpp
@@ -190,4 +190,7 @@ START_TEST(CString)
 
     test_bstrW();
     test_bstrA();
+
+    test_tokenizeW();
+    test_tokenizeA();
 }
diff --git a/modules/rostests/apitests/atl/CString.inl 
b/modules/rostests/apitests/atl/CString.inl
index 193d8d40ba7..c0d661cfb8e 100644
--- a/modules/rostests/apitests/atl/CString.inl
+++ b/modules/rostests/apitests/atl/CString.inl
@@ -439,3 +439,90 @@ TEST_NAMEX(bstr)
         ::SysFreeString(bstr);
     }
 }
+
+TEST_NAMEX(tokenize)
+{
+    CStringX str(_X("%#First Second#Third"));
+    const XCHAR* Tokens = _X("% #");
+    CStringX res;
+
+    int nCurPos = 0;
+
+    // All 'current' tokens are skipped
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X("First"), "Expected str to be 'First', was: %s\n", 
dbgstrx(res));
+    ok_dec(nCurPos, 8);
+
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X("Second"), "Expected str to be 'Second', was: %s\n", 
dbgstrx(res));
+    ok_dec(nCurPos, 15);
+
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X("Third"), "Expected str to be 'Third', was: %s\n", 
dbgstrx(res));
+    ok_dec(nCurPos, 21);
+
+    // The final 'token' is empty, and nCurPos is set to -1
+    // (Calling with nCurPos=-1 will assert)
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+
+    str =_X("StartWithToken#%#");
+    nCurPos = 0;
+
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X("StartWithToken"), "Expected str to be 'StartWithToken', was: 
%s\n", dbgstrx(res));
+    ok_dec(nCurPos, 15);
+
+    // Ending with tokens acts as if there were no tokens at the end
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+
+
+    str = _X("");
+    nCurPos = 0;
+
+    // Calling with an empty string returns 'no tokens'
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+
+    str = _X("");
+    nCurPos = 20;
+
+    // Calling with a current position outside the strings acts the same as 
'no tokens left'
+    res = str.Tokenize(Tokens, nCurPos);
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+
+
+    str = _X("test");
+    nCurPos = 2;
+
+    // Calling with a NULL pszTokens returns a substring starting at 
'nCurPos', but not updating nCurPos!
+    res = str.Tokenize(NULL, nCurPos);
+    ok(res == _X("st"), "Expected str to be 'st', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, 2);
+
+
+    // Calling with an empty pszTokens behaves exactly the same
+    res = str.Tokenize(_X(""), nCurPos);
+    ok(res == _X("st"), "Expected str to be 'st', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, 2);
+
+    nCurPos = 8;
+
+    // Calling with a NULL pszTokens and an nCurPos out of bounds returns 'no 
tokens left'
+    res = str.Tokenize(NULL, nCurPos);
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+
+    nCurPos = 8;
+
+    // Calling with an empty pszTokens behaves exactly the same
+    res = str.Tokenize(_X(""), nCurPos);
+    ok(res == _X(""), "Expected str to be 'st', was: %s\n", dbgstrx(res));
+    ok(res == _X(""), "Expected str to be '', was: %s\n", dbgstrx(res));
+    ok_dec(nCurPos, -1);
+}
diff --git a/sdk/lib/atl/cstringt.h b/sdk/lib/atl/cstringt.h
index ad89dc6270a..0afe3f4763f 100644
--- a/sdk/lib/atl/cstringt.h
+++ b/sdk/lib/atl/cstringt.h
@@ -140,6 +140,20 @@ public:
         return ::_wcsicmp(psz1, psz2);
     }
 
+    static int __cdecl StringSpanIncluding(
+        _In_z_ LPCWSTR pszBlock,
+        _In_z_ LPCWSTR pszSet)
+    {
+        return (int)::wcsspn(pszBlock, pszSet);
+    }
+
+    static int __cdecl StringSpanExcluding(
+        _In_z_ LPCWSTR pszBlock,
+        _In_z_ LPCWSTR pszSet)
+    {
+        return (int)::wcscspn(pszBlock, pszSet);
+    }
+
     static int __cdecl FormatV(
         _In_opt_z_ LPWSTR pszDest,
         _In_z_ LPCWSTR pszFormat,
@@ -289,6 +303,20 @@ public:
         return ::_stricmp(psz1, psz2);
     }
 
+    static int __cdecl StringSpanIncluding(
+        _In_z_ LPCSTR pszBlock,
+        _In_z_ LPCSTR pszSet)
+    {
+        return (int)::strspn(pszBlock, pszSet);
+    }
+
+    static int __cdecl StringSpanExcluding(
+        _In_z_ LPCSTR pszBlock,
+        _In_z_ LPCSTR pszSet)
+    {
+        return (int)::strcspn(pszBlock, pszSet);
+    }
+
     static int __cdecl FormatV(
         _In_opt_z_ LPSTR pszDest,
         _In_z_ LPCSTR pszFormat,
@@ -804,6 +832,42 @@ public:
     }
 
 
+    CStringT Tokenize(_In_z_ PCXSTR pszTokens, _Inout_ int& iStart) const
+    {
+        ATLASSERT(iStart >= 0);
+
+        if (iStart < 0)
+            AtlThrow(E_INVALIDARG);
+
+        if (!pszTokens || !pszTokens[0])
+        {
+            if (iStart < CThisSimpleString::GetLength())
+            {
+                return Mid(iStart);
+            }
+            iStart = -1;
+            return CStringT();
+        }
+
+        if (iStart < CThisSimpleString::GetLength())
+        {
+            int iRangeOffset = 
StringTraits::StringSpanIncluding(CThisSimpleString::GetString() + iStart, 
pszTokens);
+
+            if (iRangeOffset + iStart < CThisSimpleString::GetLength())
+            {
+                int iNewStart = iStart + iRangeOffset;
+                int nCount = 
StringTraits::StringSpanExcluding(CThisSimpleString::GetString() + iNewStart, 
pszTokens);
+
+                iStart = iNewStart + nCount + 1;
+
+                return Mid(iNewStart, nCount);
+            }
+        }
+
+        iStart = -1;
+        return CStringT();
+    }
+
     static PCXSTR DefaultTrimChars()
     {
         static XCHAR str[] = { ' ', '\t', '\r', '\n', 0 };

Reply via email to