4818: Add str_startswith_nocase and str_endswith_nocase r=def- a=ChillerDragon

Gets rid of the more complex str_comp_nocase_num usage

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [x] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: ChillerDragon <ChillerDragon@gmail.com>
This commit is contained in:
bors[bot] 2022-03-20 10:27:18 +00:00 committed by GitHub
commit f49afca3dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 9 deletions

View file

@ -2912,6 +2912,19 @@ int str_comp_filenames(const char *a, const char *b)
return *a - *b;
}
const char *str_startswith_nocase(const char *str, const char *prefix)
{
int prefixl = str_length(prefix);
if(str_comp_nocase_num(str, prefix, prefixl) == 0)
{
return str + prefixl;
}
else
{
return 0;
}
}
const char *str_startswith(const char *str, const char *prefix)
{
int prefixl = str_length(prefix);
@ -2925,6 +2938,26 @@ const char *str_startswith(const char *str, const char *prefix)
}
}
const char *str_endswith_nocase(const char *str, const char *suffix)
{
int strl = str_length(str);
int suffixl = str_length(suffix);
const char *strsuffix;
if(strl < suffixl)
{
return 0;
}
strsuffix = str + strl - suffixl;
if(str_comp_nocase(strsuffix, suffix) == 0)
{
return strsuffix;
}
else
{
return 0;
}
}
const char *str_endswith(const char *str, const char *suffix)
{
int strl = str_length(str);

View file

@ -1347,9 +1347,26 @@ int str_comp_num(const char *a, const char *b, int num);
*/
int str_comp_filenames(const char *a, const char *b);
/*
Function: str_startswith_nocase
Checks case insensitive whether the string begins with a certain prefix.
Parameter:
str - String to check.
prefix - Prefix to look for.
Returns:
A pointer to the string str after the string prefix, or 0 if
the string prefix isn't a prefix of the string str.
Remarks:
- The strings are treated as zero-terminated strings.
*/
const char *str_startswith_nocase(const char *str, const char *prefix);
/*
Function: str_startswith
Checks whether the string begins with a certain prefix.
Checks case sensitive whether the string begins with a certain prefix.
Parameter:
str - String to check.
@ -1364,9 +1381,26 @@ int str_comp_filenames(const char *a, const char *b);
*/
const char *str_startswith(const char *str, const char *prefix);
/*
Function: str_endswith_nocase
Checks case insensitive whether the string ends with a certain suffix.
Parameter:
str - String to check.
suffix - Suffix to look for.
Returns:
A pointer to the beginning of the suffix in the string str, or
0 if the string suffix isn't a suffix of the string str.
Remarks:
- The strings are treated as zero-terminated strings.
*/
const char *str_endswith_nocase(const char *str, const char *suffix);
/*
Function: str_endswith
Checks whether the string ends with a certain suffix.
Checks case sensitive whether the string ends with a certain suffix.
Parameter:
str - String to check.

View file

@ -1763,7 +1763,7 @@ bool IsBlockInfectionZ(const CServerInfo *pInfo)
bool IsBlockWorlds(const CServerInfo *pInfo)
{
return (str_comp_nocase_num(pInfo->m_aGameType, "bw ", 4) == 0) || (str_comp_nocase(pInfo->m_aGameType, "bw") == 0);
return (str_startswith(pInfo->m_aGameType, "bw ")) || (str_comp_nocase(pInfo->m_aGameType, "bw") == 0);
}
bool IsCity(const CServerInfo *pInfo)

View file

@ -2853,7 +2853,7 @@ static int GetAuthLevel(const char *pLevel)
int Level = -1;
if(!str_comp_nocase(pLevel, "admin"))
Level = AUTHED_ADMIN;
else if(!str_comp_nocase_num(pLevel, "mod", 3))
else if(str_startswith(pLevel, "mod"))
Level = AUTHED_MOD;
else if(!str_comp_nocase(pLevel, "helper"))
Level = AUTHED_HELPER;

View file

@ -382,7 +382,7 @@ bool CChat::OnInput(IInput::CEvent Event)
auto &Command = m_Commands[Index];
if(str_comp_nocase_num(Command.pName, pCommandStart, str_length(pCommandStart)) == 0)
if(str_startswith(Command.pName, pCommandStart))
{
pCompletionCommand = &Command;
m_CompletionChosen = Index + SearchType * NumCommands;

View file

@ -1790,25 +1790,25 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
if(pMsg->m_pMessage[0] == '/')
{
if(str_comp_nocase_num(pMsg->m_pMessage + 1, "w ", 2) == 0)
if(str_startswith(pMsg->m_pMessage + 1, "w "))
{
char aWhisperMsg[256];
str_copy(aWhisperMsg, pMsg->m_pMessage + 3, 256);
Whisper(pPlayer->GetCID(), aWhisperMsg);
}
else if(str_comp_nocase_num(pMsg->m_pMessage + 1, "whisper ", 8) == 0)
else if(str_startswith(pMsg->m_pMessage + 1, "whisper "))
{
char aWhisperMsg[256];
str_copy(aWhisperMsg, pMsg->m_pMessage + 9, 256);
Whisper(pPlayer->GetCID(), aWhisperMsg);
}
else if(str_comp_nocase_num(pMsg->m_pMessage + 1, "c ", 2) == 0)
else if(str_startswith(pMsg->m_pMessage + 1, "c "))
{
char aWhisperMsg[256];
str_copy(aWhisperMsg, pMsg->m_pMessage + 3, 256);
Converse(pPlayer->GetCID(), aWhisperMsg);
}
else if(str_comp_nocase_num(pMsg->m_pMessage + 1, "converse ", 9) == 0)
else if(str_startswith(pMsg->m_pMessage + 1, "converse "))
{
char aWhisperMsg[256];
str_copy(aWhisperMsg, pMsg->m_pMessage + 10, 256);

View file

@ -141,6 +141,25 @@ TEST(Str, Startswith)
EXPECT_EQ(str_startswith(ABCDEFG, ABC) - ABCDEFG, str_length(ABC));
}
TEST(Str, StartswithNocase)
{
EXPECT_TRUE(str_startswith_nocase("Abcdef", "abc"));
EXPECT_FALSE(str_startswith_nocase("aBc", "abcdef"));
EXPECT_TRUE(str_startswith_nocase("xYz", ""));
EXPECT_FALSE(str_startswith_nocase("", "xYz"));
EXPECT_FALSE(str_startswith_nocase("house", "home"));
EXPECT_FALSE(str_startswith_nocase("Blackboard", "board"));
EXPECT_TRUE(str_startswith_nocase("поплавать", "по"));
EXPECT_FALSE(str_startswith_nocase("плавать", "по"));
static const char ABCDEFG[] = "aBcdefg";
static const char ABC[] = "abc";
EXPECT_EQ(str_startswith_nocase(ABCDEFG, ABC) - ABCDEFG, str_length(ABC));
}
TEST(Str, Endswith)
{
EXPECT_TRUE(str_endswith("abcdef", "def"));
@ -161,6 +180,26 @@ TEST(Str, Endswith)
str_length(ABCDEFG) - str_length(DEFG));
}
TEST(Str, EndswithNocase)
{
EXPECT_TRUE(str_endswith_nocase("abcdef", "deF"));
EXPECT_FALSE(str_endswith_nocase("def", "abcdef"));
EXPECT_TRUE(str_endswith_nocase("xyz", ""));
EXPECT_FALSE(str_endswith_nocase("", "xyz"));
EXPECT_FALSE(str_endswith_nocase("rhyme", "minE"));
EXPECT_FALSE(str_endswith_nocase("blackboard", "black"));
EXPECT_TRUE(str_endswith_nocase("люди", "юди"));
EXPECT_FALSE(str_endswith_nocase("люди", "любовь"));
static const char ABCDEFG[] = "abcdefG";
static const char DEFG[] = "defg";
EXPECT_EQ(str_endswith_nocase(ABCDEFG, DEFG) - ABCDEFG,
str_length(ABCDEFG) - str_length(DEFG));
}
TEST(Str, HexDecode)
{
char aOut[5] = {'a', 'b', 'c', 'd', 0};