From f28a2f9051d585c53ea6447e068e0fc8eafb7e07 Mon Sep 17 00:00:00 2001 From: eihrul Date: Thu, 17 Mar 2022 22:11:40 +0100 Subject: [PATCH] svn r6533 --- Makefile | 2 +- README.md | 5 - patches/better_console.patch | 174 +++------------------------------ patches/parseplayer.patch | 63 ------------ src/engine/console.cpp | 96 +++++++++--------- src/fpsgame/client.cpp | 26 +++-- src/p1xbraten/namecomplete.cpp | 26 ++--- src/shared/stream.cpp | 28 ++++++ src/shared/tools.h | 3 + src/vcpp/sauerbraten.vcxproj | 12 +-- 10 files changed, 124 insertions(+), 311 deletions(-) delete mode 100644 patches/parseplayer.patch diff --git a/Makefile b/Makefile index ab6bd82..5524c52 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ apply-patches: $(PATCH) < patches/managed_games.patch $(PATCH) < patches/better_console.patch $(PATCH) < patches/autoauthdomains.patch - $(PATCH) < patches/parseplayer.patch + # $(PATCH) < patches/parseplayer.patch $(PATCH) < patches/nextfollowteam.patch $(PATCH) < patches/proxy_setip.patch $(PATCH) < patches/server_demo_name.patch diff --git a/README.md b/README.md index 3f56bec..da7209c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ This repository contains the source for my client mod, as well as the patches ap - [colored_weapon_trails.patch](#colored_weapon_trailspatch) - [crosshairreloadfade.patch](#crosshairreloadfadepatch) - [better_console.patch](#better_consolepatch) - - [parseplayer.patch](#parseplayerpatch) - [nextfollowteam.patch](#nextfollowteampatch) - [Server Patches](#server-patches) - [authservers.patch](#authserverspatch) @@ -267,10 +266,6 @@ bind "BACKSLASH" [inputcommand "" [servcmd $commandbuf] "#"] // works for #comma bind "HASH" [inputcommand "" [servcmd $commandbuf] "#"] // only works with German keyboard layout ``` -### [parseplayer.patch](./patches/parseplayer.patch) - -- improves player name matching in `setmaster`, `setteam`, `ignore`, `kick`, `spectator`, `follow` and `goto` commands: after the normal full matching, if three or more characters are given, the argument is tried to be matched as a case-insensitive prefix, then a case-insensitive substring of a player's name - ### [nextfollowteam.patch](./patches/nextfollowteam.patch) - "fixes" `nextfollow` to start at the first/last player when cycling forwards/backwards, instead of second or second to last respectively diff --git a/patches/better_console.patch b/patches/better_console.patch index 55f4c1f..e5dd764 100644 --- a/patches/better_console.patch +++ b/patches/better_console.patch @@ -60,93 +60,7 @@ index 3664668..ffe61ef 100644 else if(action) { alias("commandbuf", buf); -@@ -444,8 +444,10 @@ bool consolekey(int code, bool isdown) - - #ifdef __APPLE__ - #define MOD_KEYS (KMOD_LGUI|KMOD_RGUI) -+ #define SKIPWORD_KEYS (KMOD_LALT|KMOD_RALT) - #else - #define MOD_KEYS (KMOD_LCTRL|KMOD_RCTRL) -+ #define SKIPWORD_KEYS (KMOD_LCTRL|KMOD_RCTRL) - #endif - - if(isdown) -@@ -468,7 +470,15 @@ bool consolekey(int code, bool isdown) - { - int len = (int)strlen(commandbuf); - if(commandpos<0) break; -- memmove(&commandbuf[commandpos], &commandbuf[commandpos+1], len - commandpos); -+ int end = commandpos+1; -+ if(SDL_GetModState()&SKIPWORD_KEYS) -+ { -+ // extend range to the end of the next word -+ const char *space = strchr(commandbuf+end, ' '); -+ if(!space) end = len; -+ else end = space-commandbuf+1; -+ } -+ memmove(&commandbuf[commandpos], &commandbuf[end], len - end + 1); - resetcomplete(); - if(commandpos>=len-1) commandpos = -1; - break; -@@ -476,22 +486,50 @@ bool consolekey(int code, bool isdown) - - case SDLK_BACKSPACE: - { -- int len = (int)strlen(commandbuf), i = commandpos>=0 ? commandpos : len; -- if(i<1) break; -- memmove(&commandbuf[i-1], &commandbuf[i], len - i + 1); -+ int len = (int)strlen(commandbuf), end = commandpos>=0 ? commandpos : len; -+ if(end<1) break; -+ int start = end-1; -+ if(SDL_GetModState()&SKIPWORD_KEYS) -+ { -+ int prevpos = start; char prevchar = commandbuf[start]; commandbuf[start] = 0; // temporarily shorten commandbuf to end-1 -+ // extend range to beginning of the previous word -+ const char *space = strrchr(commandbuf, ' '); -+ if(!space) start = 0; -+ else start = space-commandbuf+1; -+ commandbuf[prevpos] = prevchar; -+ } -+ memmove(&commandbuf[start], &commandbuf[end], len - end + 1); - resetcomplete(); -- if(commandpos>0) commandpos--; -+ if(commandpos>0) commandpos = start; - else if(!commandpos && len<=1) commandpos = -1; - break; - } - - case SDLK_LEFT: -- if(commandpos>0) commandpos--; -- else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1; -+ if(SDL_GetModState()&SKIPWORD_KEYS && commandpos!=0) -+ { -+ int prevpos = 0; char prevchar = ' '; // temporarily shorten commandbuf to commandpos-1 -+ if(commandpos>0) { prevpos = commandpos-1; prevchar = commandbuf[prevpos]; commandbuf[prevpos] = 0; } -+ const char *space = strrchr(commandbuf, ' '); -+ if(!space) commandpos = 0; -+ else commandpos = space-commandbuf+1; -+ if(prevpos>0) commandbuf[prevpos] = prevchar; -+ } -+ else -+ { -+ if(commandpos>0) commandpos--; -+ else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1; -+ } - break; - - case SDLK_RIGHT: -- if(commandpos>=0 && ++commandpos>=(int)strlen(commandbuf)) commandpos = -1; -+ if(SDL_GetModState()&SKIPWORD_KEYS && commandpos>=0) -+ { -+ const char *space = strchr(commandbuf+commandpos+1, ' '); -+ if(!space) commandpos = -1; -+ else commandpos = space-commandbuf; -+ } -+ else if(commandpos>=0 && ++commandpos>=(int)strlen(commandbuf)) commandpos = -1; - break; - - case SDLK_UP: -@@ -504,9 +542,15 @@ bool consolekey(int code, bool isdown) +@@ -504,9 +504,15 @@ bool consolekey(int code, bool isdown) break; case SDLK_TAB: @@ -164,7 +78,7 @@ index 3664668..ffe61ef 100644 if(commandpos>=0 && commandpos>=(int)strlen(commandbuf)) commandpos = -1; } break; -@@ -536,12 +580,14 @@ bool consolekey(int code, bool isdown) +@@ -536,12 +540,14 @@ bool consolekey(int code, bool isdown) } histpos = history.length(); inputcommand(NULL); @@ -179,7 +93,7 @@ index 3664668..ffe61ef 100644 } } -@@ -668,7 +714,7 @@ static hashtable completions; +@@ -668,7 +676,7 @@ static hashtable completions; int completesize = 0; char *lastcomplete = NULL; @@ -244,17 +158,15 @@ new file mode 100644 index 0000000..90dc855 --- /dev/null +++ src/p1xbraten/namecomplete.cpp -@@ -0,0 +1,98 @@ +@@ -0,0 +1,92 @@ +#include "game.h" -+#ifdef WIN32 -+#include // for StrStrIA (= strcasestr) -+#endif + +namespace game +{ + char *completeword = NULL; // substring of commandbuf/s to be completed + const char *lastcompletealphanum = NULL; // points to alphanum version of last suggested ci->name + size_t lastcompletelen = 0; // strlen of last suggested ci->name ++ extern int playersearch; // same threshold as parseplayer() + + void complete(char *s, int cursor, int maxlen) // completes client names + { @@ -267,8 +179,8 @@ index 0000000..90dc855 + char prevchar; + if(cursor>=0) { prevchar = s[cursor]; s[cursor] = 0; } // temporarily shorten s to end at cursor + completeword = strrchr(s, ' '); -+ if(!completeword) completeword = s; // no space in front of cursor -> use whole commandbuf -+ else completeword++; // move to first char, behind the space we found ++ if(!completeword) completeword = s; // no space in front of cursor -> use whole commandbuf ++ else completeword++; // move to first char, behind the space we found + lastcompletelen = strlen(completeword); // we will replace this many chars with our first suggestion + filternonalphanum(alphanumword, completeword, maxlen); // used for matching + comparelen = strlen(alphanumword); // used for matching @@ -281,9 +193,9 @@ index 0000000..90dc855 + { + fpsent *ci = clients[i]; + if(!ci) continue; -+ if(strncasecmp(ci->alphanumname, alphanumword, comparelen)==0 && // match prefix -+ (!lastcompletealphanum || strcasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion -+ (!nextcompletealphanum || strcasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick ++ if(cubecaseequal(ci->alphanumname, alphanumword, comparelen) && // match prefix ++ (!lastcompletealphanum || cubecasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion ++ (!nextcompletealphanum || cubecasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick + ) + { + nextcompletealphanum = ci->alphanumname; @@ -291,18 +203,14 @@ index 0000000..90dc855 + } + } + if(!skipprefixcheck) lastcompletealphanum = NULL; -+ if(!nextcomplete && comparelen>=2) loopv(clients) // only if prefix matching didn't produce a new suggestion, and 2 or more chars given: try matching substring (ignoring case) ++ if(!nextcomplete && (int)comparelen>=playersearch) loopv(clients) // only if prefix matching didn't produce a new suggestion, and enough chars given: try matching substring (ignoring case) + { + fpsent *ci = clients[i]; + if(!ci) continue; + if( -+#ifdef WIN32 -+ StrStrIA(ci->alphanumname, alphanumword) && -+#else -+ strcasestr(ci->alphanumname, alphanumword) && // match substring -+#endif -+ (!lastcompletealphanum || strcasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion -+ (!nextcompletealphanum || strcasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick ++ cubecasefind(ci->alphanumname, alphanumword) && // match substring ++ (!lastcompletealphanum || cubecasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion ++ (!nextcompletealphanum || cubecasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick + ) + { + nextcompletealphanum = ci->alphanumname; @@ -360,60 +268,6 @@ diff --git src/vcpp/sauerbraten.vcxproj src/vcpp/sauerbraten.vcxproj index 7d46df0..b18b8dd 100644 --- src/vcpp/sauerbraten.vcxproj +++ src/vcpp/sauerbraten.vcxproj -@@ -165,7 +165,7 @@ - - - /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib;%(AdditionalLibraryDirectories) - false -@@ -215,7 +215,7 @@ - - - /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib64;%(AdditionalLibraryDirectories) - false -@@ -257,7 +257,7 @@ - - - /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;SDL2_mixer.lib;ws2_32.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib;%(AdditionalLibraryDirectories) - false -@@ -296,7 +296,7 @@ - - - /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;SDL2_mixer.lib;ws2_32.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib64;%(AdditionalLibraryDirectories) - false -@@ -342,7 +342,7 @@ - - - /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib;%(AdditionalLibraryDirectories) - false -@@ -388,7 +388,7 @@ - - - /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) -- enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) -+ enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) - true - ..\lib64;%(AdditionalLibraryDirectories) - false @@ -1309,6 +1309,20 @@ $(IntDir)game.pch $(IntDir)game.pch diff --git a/patches/parseplayer.patch b/patches/parseplayer.patch deleted file mode 100644 index afe3718..0000000 --- a/patches/parseplayer.patch +++ /dev/null @@ -1,63 +0,0 @@ -this patch depends on the Shlwapi.lib changes from better_console.patch! - -diff --git src/fpsgame/client.cpp src/fpsgame/client.cpp -index 6cf20f3..5a10e62 100644 ---- src/fpsgame/client.cpp -+++ src/fpsgame/client.cpp -@@ -1,6 +1,8 @@ - #include "game.h" - #include "weaponstats.h" -- -+#ifdef WIN32 -+#include // for StrStrIA (= strcasestr) -+#endif - namespace game - { - VARP(minradarscale, 0, 384, 10000); -@@ -380,12 +382,31 @@ namespace game - fpsent *o = players[i]; - if(!strcmp(arg, o->name)) return o->clientnum; - } -- // nothing found, try case insensitive -+ // try case insensitive - loopv(players) - { - fpsent *o = players[i]; - if(!strcasecmp(arg, o->name)) return o->clientnum; - } -+ if(strlen(arg)>2) -+ { -+ // try case insensitive prefix -+ loopv(players) -+ { -+ fpsent *o = players[i]; -+ if(!strncasecmp(arg, o->name, strlen(arg))) return o->clientnum; -+ } -+ // try case insensitive substring -+ loopv(players) -+ { -+ fpsent *o = players[i]; -+#ifdef WIN32 -+ if(StrStrIA(o->name, arg)) return o->clientnum; -+#else -+ if(strcasestr(o->name, arg)) return o->clientnum; -+#endif -+ } -+ } - return -1; - } - ICOMMAND(getclientnum, "s", (char *name), intret(name[0] ? parseplayer(name) : player1->clientnum)); -@@ -504,10 +525,10 @@ namespace game - } - }); - -- void setteam(const char *arg1, const char *arg2) -+ void setteam(const char *playername, const char *teamname) - { -- int i = parseplayer(arg1); -- if(i>=0) addmsg(N_SETTEAM, "ris", i, arg2); -+ int i = parseplayer(playername); -+ if(i>=0) addmsg(N_SETTEAM, "ris", i, teamname); - } - COMMAND(setteam, "ss"); - diff --git a/src/engine/console.cpp b/src/engine/console.cpp index 84a2cce..dd0171c 100644 --- a/src/engine/console.cpp +++ b/src/engine/console.cpp @@ -438,16 +438,38 @@ bool consoleinput(const char *str, int len) return true; } +static char *skipword(char *s) +{ + while(int c = *s++) if(!iscubespace(c)) + { + while(int c = *s++) if(iscubespace(c)) break; + break; + } + return s-1; +} + +static char *skipwordrev(char *s, int n = -1) +{ + char *e = s + strlen(s); + if(n >= 0) e = min(e, &s[n]); + while(--e >= s) if(!iscubespace(*e)) + { + while(--e >= s && !iscubespace(*e)); + break; + } + return e+1; +} + bool consolekey(int code, bool isdown) { if(commandmillis < 0) return false; #ifdef __APPLE__ #define MOD_KEYS (KMOD_LGUI|KMOD_RGUI) - #define SKIPWORD_KEYS (KMOD_LALT|KMOD_RALT) + #define SKIP_KEYS (KMOD_LALT|KMOD_RALT) #else #define MOD_KEYS (KMOD_LCTRL|KMOD_RCTRL) - #define SKIPWORD_KEYS (KMOD_LCTRL|KMOD_RCTRL) + #define SKIP_KEYS (KMOD_LCTRL|KMOD_RCTRL) #endif if(isdown) @@ -459,7 +481,7 @@ bool consolekey(int code, bool isdown) break; case SDLK_HOME: - if(strlen(commandbuf)) commandpos = 0; + if(commandbuf[0]) commandpos = 0; break; case SDLK_END: @@ -471,14 +493,8 @@ bool consolekey(int code, bool isdown) int len = (int)strlen(commandbuf); if(commandpos<0) break; int end = commandpos+1; - if(SDL_GetModState()&SKIPWORD_KEYS) - { - // extend range to the end of the next word - const char *space = strchr(commandbuf+end, ' '); - if(!space) end = len; - else end = space-commandbuf+1; - } - memmove(&commandbuf[commandpos], &commandbuf[end], len - end + 1); + if(SDL_GetModState()&SKIP_KEYS) end = skipword(&commandbuf[commandpos]) - commandbuf; + memmove(&commandbuf[commandpos], &commandbuf[end], len + 1 - end); resetcomplete(); if(commandpos>=len-1) commandpos = -1; break; @@ -486,19 +502,11 @@ bool consolekey(int code, bool isdown) case SDLK_BACKSPACE: { - int len = (int)strlen(commandbuf), end = commandpos>=0 ? commandpos : len; - if(end<1) break; - int start = end-1; - if(SDL_GetModState()&SKIPWORD_KEYS) - { - int prevpos = start; char prevchar = commandbuf[start]; commandbuf[start] = 0; // temporarily shorten commandbuf to end-1 - // extend range to beginning of the previous word - const char *space = strrchr(commandbuf, ' '); - if(!space) start = 0; - else start = space-commandbuf+1; - commandbuf[prevpos] = prevchar; - } - memmove(&commandbuf[start], &commandbuf[end], len - end + 1); + int len = (int)strlen(commandbuf), i = commandpos>=0 ? commandpos : len; + if(i<1) break; + int start = i-1; + if(SDL_GetModState()&SKIP_KEYS) start = skipwordrev(commandbuf, i) - commandbuf; + memmove(&commandbuf[start], &commandbuf[i], len - i + 1); resetcomplete(); if(commandpos>0) commandpos = start; else if(!commandpos && len<=1) commandpos = -1; @@ -506,39 +514,37 @@ bool consolekey(int code, bool isdown) } case SDLK_LEFT: - if(SDL_GetModState()&SKIPWORD_KEYS && commandpos!=0) - { - int prevpos = 0; char prevchar = ' '; // temporarily shorten commandbuf to commandpos-1 - if(commandpos>0) { prevpos = commandpos-1; prevchar = commandbuf[prevpos]; commandbuf[prevpos] = 0; } - const char *space = strrchr(commandbuf, ' '); - if(!space) commandpos = 0; - else commandpos = space-commandbuf+1; - if(prevpos>0) commandbuf[prevpos] = prevchar; - } - else - { - if(commandpos>0) commandpos--; - else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1; - } + if(SDL_GetModState()&SKIP_KEYS) commandpos = skipwordrev(commandbuf, commandpos) - commandbuf; + else if(commandpos>0) commandpos--; + else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1; break; case SDLK_RIGHT: - if(SDL_GetModState()&SKIPWORD_KEYS && commandpos>=0) + if(commandpos>=0) { - const char *space = strchr(commandbuf+commandpos+1, ' '); - if(!space) commandpos = -1; - else commandpos = space-commandbuf; + if(SDL_GetModState()&SKIP_KEYS) commandpos = skipword(&commandbuf[commandpos]) - commandbuf; + else ++commandpos; + if(commandpos>=(int)strlen(commandbuf)) commandpos = -1; } - else if(commandpos>=0 && ++commandpos>=(int)strlen(commandbuf)) commandpos = -1; break; case SDLK_UP: if(histpos > history.length()) histpos = history.length(); - if(histpos > 0) history[--histpos]->restore(); + if(histpos > 0) + { + if(SDL_GetModState()&SKIP_KEYS) histpos = 0; + else --histpos; + history[histpos]->restore(); + } break; case SDLK_DOWN: - if(histpos + 1 < history.length()) history[++histpos]->restore(); + if(histpos + 1 < history.length()) + { + if(SDL_GetModState()&SKIP_KEYS) histpos = history.length()-1; + else ++histpos; + history[histpos]->restore(); + } break; case SDLK_TAB: diff --git a/src/fpsgame/client.cpp b/src/fpsgame/client.cpp index 5a10e62..c5ae27e 100644 --- a/src/fpsgame/client.cpp +++ b/src/fpsgame/client.cpp @@ -1,8 +1,6 @@ #include "game.h" #include "weaponstats.h" -#ifdef WIN32 -#include // for StrStrIA (= strcasestr) -#endif + namespace game { VARP(minradarscale, 0, 384, 10000); @@ -367,6 +365,7 @@ namespace game } ICOMMAND(isai, "ii", (int *cn, int *type), intret(isai(*cn, *type) ? 1 : 0)); + VARP(playersearch, 0, 3, 10); int parseplayer(const char *arg) { char *end; @@ -382,29 +381,26 @@ namespace game fpsent *o = players[i]; if(!strcmp(arg, o->name)) return o->clientnum; } - // try case insensitive + // nothing found, try case insensitive loopv(players) { fpsent *o = players[i]; - if(!strcasecmp(arg, o->name)) return o->clientnum; + if(cubecaseequal(o->name, arg)) return o->clientnum; } - if(strlen(arg)>2) + int len = strlen(arg); + if(playersearch && len >= playersearch) { // try case insensitive prefix loopv(players) { fpsent *o = players[i]; - if(!strncasecmp(arg, o->name, strlen(arg))) return o->clientnum; + if(cubecaseequal(o->name, arg, len)) return o->clientnum; } // try case insensitive substring loopv(players) { fpsent *o = players[i]; -#ifdef WIN32 - if(StrStrIA(o->name, arg)) return o->clientnum; -#else - if(strcasestr(o->name, arg)) return o->clientnum; -#endif + if(cubecasefind(o->name, arg)) return o->clientnum; } } return -1; @@ -525,10 +521,10 @@ namespace game } }); - void setteam(const char *playername, const char *teamname) + void setteam(const char *arg1, const char *arg2) { - int i = parseplayer(playername); - if(i>=0) addmsg(N_SETTEAM, "ris", i, teamname); + int i = parseplayer(arg1); + if(i>=0) addmsg(N_SETTEAM, "ris", i, arg2); } COMMAND(setteam, "ss"); diff --git a/src/p1xbraten/namecomplete.cpp b/src/p1xbraten/namecomplete.cpp index 6da2bde..efeb26f 100644 --- a/src/p1xbraten/namecomplete.cpp +++ b/src/p1xbraten/namecomplete.cpp @@ -1,13 +1,11 @@ #include "game.h" -#ifdef WIN32 -#include // for StrStrIA (= strcasestr) -#endif namespace game { char *completeword = NULL; // substring of commandbuf/s to be completed const char *lastcompletealphanum = NULL; // points to alphanum version of last suggested ci->name size_t lastcompletelen = 0; // strlen of last suggested ci->name + extern int playersearch; // same threshold as parseplayer() void complete(char *s, int cursor, int maxlen) // completes client names { @@ -20,8 +18,8 @@ namespace game char prevchar; if(cursor>=0) { prevchar = s[cursor]; s[cursor] = 0; } // temporarily shorten s to end at cursor completeword = strrchr(s, ' '); - if(!completeword) completeword = s; // no space in front of cursor -> use whole commandbuf - else completeword++; // move to first char, behind the space we found + if(!completeword) completeword = s; // no space in front of cursor -> use whole commandbuf + else completeword++; // move to first char, behind the space we found lastcompletelen = strlen(completeword); // we will replace this many chars with our first suggestion filternonalphanum(alphanumword, completeword, maxlen); // used for matching comparelen = strlen(alphanumword); // used for matching @@ -34,9 +32,9 @@ namespace game { fpsent *ci = clients[i]; if(!ci) continue; - if(strncasecmp(ci->alphanumname, alphanumword, comparelen)==0 && // match prefix - (!lastcompletealphanum || strcasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion - (!nextcompletealphanum || strcasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick + if(cubecaseequal(ci->alphanumname, alphanumword, comparelen) && // match prefix + (!lastcompletealphanum || cubecasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion + (!nextcompletealphanum || cubecasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick ) { nextcompletealphanum = ci->alphanumname; @@ -44,18 +42,14 @@ namespace game } } if(!skipprefixcheck) lastcompletealphanum = NULL; - if(!nextcomplete && comparelen>=2) loopv(clients) // only if prefix matching didn't produce a new suggestion, and 2 or more chars given: try matching substring (ignoring case) + if(!nextcomplete && (int)comparelen>=playersearch) loopv(clients) // only if prefix matching didn't produce a new suggestion, and enough chars given: try matching substring (ignoring case) { fpsent *ci = clients[i]; if(!ci) continue; if( -#ifdef WIN32 - StrStrIA(ci->alphanumname, alphanumword) && -#else - strcasestr(ci->alphanumname, alphanumword) && // match substring -#endif - (!lastcompletealphanum || strcasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion - (!nextcompletealphanum || strcasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick + cubecasefind(ci->alphanumname, alphanumword) && // match substring + (!lastcompletealphanum || cubecasecmp(ci->alphanumname, lastcompletealphanum) > 0) && // ensure it (alphabetically) comes after last suggestion + (!nextcompletealphanum || cubecasecmp(ci->alphanumname, nextcompletealphanum) < 0) // only pick as next suggestion when it comes before current pick ) { nextcompletealphanum = ci->alphanumname; diff --git a/src/shared/stream.cpp b/src/shared/stream.cpp index c5ba2a7..87232a3 100644 --- a/src/shared/stream.cpp +++ b/src/shared/stream.cpp @@ -247,6 +247,34 @@ size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srcl return dst - dstbuf; } +int cubecasecmp(const char *s1, const char *s2, int n) +{ + if(!s1 || !s2) return !s2 - !s1; + while(n-- > 0) + { + int c1 = cubelower(*s1++), c2 = cubelower(*s2++); + if(c1 != c2) return c1 - c2; + if(!c1) break; + } + return 0; +} + +char *cubecasefind(const char *haystack, const char *needle) +{ + if(haystack && needle) for(const char *h = haystack, *n = needle;;) + { + int hc = cubelower(*h++), nc = cubelower(*n++); + if(!nc) return (char*)h - (n - needle); + if(hc != nc) + { + if(!hc) break; + n = needle; + h = ++haystack; + } + } + return NULL; +} + ///////////////////////// file system /////////////////////// #ifdef WIN32 diff --git a/src/shared/tools.h b/src/shared/tools.h index 1d0015c..1f7c842 100644 --- a/src/shared/tools.h +++ b/src/shared/tools.h @@ -1348,6 +1348,9 @@ static inline uchar cubeupper(uchar c) } extern size_t decodeutf8(uchar *dst, size_t dstlen, const uchar *src, size_t srclen, size_t *carry = NULL); extern size_t encodeutf8(uchar *dstbuf, size_t dstlen, const uchar *srcbuf, size_t srclen, size_t *carry = NULL); +extern int cubecasecmp(const char *s1, const char *s2, int n = INT_MAX); +static inline bool cubecaseequal(const char *s1, const char *s2, int n = INT_MAX) { return !cubecasecmp(s1, s2, n); } +extern char *cubecasefind(const char *haystack, const char *needle); extern string homedir; diff --git a/src/vcpp/sauerbraten.vcxproj b/src/vcpp/sauerbraten.vcxproj index b713960..0dbabbf 100644 --- a/src/vcpp/sauerbraten.vcxproj +++ b/src/vcpp/sauerbraten.vcxproj @@ -165,7 +165,7 @@ /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib;%(AdditionalLibraryDirectories) false @@ -215,7 +215,7 @@ /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib64;%(AdditionalLibraryDirectories) false @@ -257,7 +257,7 @@ /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;SDL2_mixer.lib;ws2_32.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib;%(AdditionalLibraryDirectories) false @@ -296,7 +296,7 @@ /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;SDL2_mixer.lib;ws2_32.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib64;%(AdditionalLibraryDirectories) false @@ -342,7 +342,7 @@ /MACHINE:I386 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib;%(AdditionalLibraryDirectories) false @@ -388,7 +388,7 @@ /MACHINE:X64 /SAFESEH:NO %(AdditionalOptions) - enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;Shlwapi.lib;%(AdditionalDependencies) + enet.lib;zdll.lib;opengl32.lib;SDL2.lib;SDL2_image.lib;ws2_32.lib;SDL2_mixer.lib;winmm.lib;dbghelp.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true ..\lib64;%(AdditionalLibraryDirectories) false