Skip to content

chore(string): Implement removeExtension() function for string classes and add find/reverseFind to UnicodeString#2635

Merged
xezon merged 3 commits intoTheSuperHackers:mainfrom
Mauller:Mauller/feat-string-remove-extensions
Apr 30, 2026
Merged

chore(string): Implement removeExtension() function for string classes and add find/reverseFind to UnicodeString#2635
xezon merged 3 commits intoTheSuperHackers:mainfrom
Mauller:Mauller/feat-string-remove-extensions

Conversation

@Mauller
Copy link
Copy Markdown

@Mauller Mauller commented Apr 19, 2026

Merge by rebase

This PR has a small chore to remove the unused static removeExtensions() function found in the gamestate.cpp file.
It also implements some missing functions within UnicodeString for find and reverseFind to give it parity with asciiString

Overall it implements the getExtension() and removeExtension() functions for AsciiString and UnicodeStrings within TheFileSystem.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 19, 2026

Greptile Summary

This PR removes the stale, locally-scoped removeExtension helper from both GameState.cpp copies, replaces it with proper FileSystem::removeExtension static methods for AsciiString and UnicodeString, and introduces a PathUtil.h utility header with inline getExtension overloads. It also adds find/reverseFind to UnicodeString for parity with AsciiString, and contributes maxPtr/minPtr pointer utilities to BaseType.h to safely handle the nullptr-vs-valid-pointer separator comparison that was flagged in the previous review round.

Confidence Score: 5/5

This PR is safe to merge — all previously flagged bugs have been addressed and no new issues were found.

The three prior P1 findings (sizeof truncation bug, null-pointer relational UB, ODR violation) are all resolved: pointer arithmetic is used correctly, maxPtr handles the nullptr case safely, and getExtension overloads are marked inline. No new logic, security, or correctness issues were identified.

No files require special attention.

Important Files Changed

Filename Overview
Core/Libraries/Include/Lib/PathUtil.h New utility header with inline getExtension overloads for char* and wchar_t*; functions are inline (ODR-safe), use maxPtr for safe null-safe separator comparison, and correctly handle paths with dots in directory components.
Core/Libraries/Include/Lib/BaseType.h Adds maxPtr/minPtr pointer templates with nullptr-safe semantics; used to replace unsafe relational comparison between a null and a non-null pointer that was flagged in the prior review.
Core/GameEngine/Source/Common/System/FileSystem.cpp Implements FileSystem::removeExtension for both string types using correct pointer-difference arithmetic (ext - path.str()) rather than the sizeof bug present in the earlier draft.
Core/GameEngine/Include/Common/FileSystem.h Adds static bool removeExtension declarations for AsciiString and UnicodeString overloads; change log comment uses a 2026 date consistent with the team's rule.
Core/GameEngine/Include/Common/UnicodeString.h Adds find/reverseFind inline methods wrapping wcschr/wcsrchr, giving UnicodeString parity with AsciiString; implementation is straightforward and correct.
Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Removes the static removeExtension helper that was unused dead code; no functional changes to live code paths.
GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp Same dead-code removal as the Generals variant; no functional changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["FileSystem::removeExtension(path)"] --> B["getExtension(path.str())"]
    B --> C{"strrchr for '.'"}
    C -- "no dot found" --> D["return nullptr"]
    C -- "dot found" --> E["maxPtr(strrchr '/' , strrchr '\\')"]
    E --> F{"lastSeparator &&\nlastDot < lastSeparator?"}
    F -- "yes (dot in dir name)" --> D
    F -- "no (dot in filename)" --> G["return pointer to dot"]
    G --> H["path.truncateTo(ext - path.str())"]
    H --> I["return true"]
    D --> J["return false"]
Loading

Reviews (19): Last reviewed commit: "chore(filesystem): Implement getExtensio..." | Re-trigger Greptile

Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/UnicodeString.cpp Outdated
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 19, 2026

will fix this tomorrow

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 663220e to 9e42c19 Compare April 19, 2026 22:51
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 19, 2026

Fixed before bed in the end, should be okay now and working as expected.

Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not like the implementation.

Comment thread Core/GameEngine/Include/Common/AsciiString.h Outdated
Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 9e42c19 to 385ccbb Compare April 20, 2026 17:44
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 20, 2026

updated based on feedback.

@Mauller Mauller changed the title feat(string): Implement removeExtensions() function in string classes and add find/reverseFind to UnicodeString feat(string): Implement removeExtension() function for string classes and add find/reverseFind to UnicodeString Apr 20, 2026
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 385ccbb to e8394f0 Compare April 22, 2026 19:03
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 22, 2026

Updated the implementation to take the dots position into account by checking if it appears before path seperators.

Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from e8394f0 to 9cfecdf Compare April 22, 2026 19:13
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 22, 2026

Appeasing the AI overMunkee

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 9cfecdf to 90d8760 Compare April 22, 2026 19:14
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 22, 2026

Helps when i do it properly.

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 90d8760 to 82c96c5 Compare April 22, 2026 19:24
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 22, 2026

This should be good now, speeling mistake corrected and pull number added to commits.

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 82c96c5 to a1f328f Compare April 23, 2026 17:27
Comment thread Core/GameEngine/Include/Common/UnicodeString.h Outdated
Comment thread Core/GameEngine/Source/Common/System/AsciiString.cpp Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from a1f328f to e388c1c Compare April 24, 2026 15:07
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 24, 2026

Updated to move the functionality into the file system

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from e388c1c to c9d9d86 Compare April 24, 2026 15:13
Comment thread Core/GameEngine/Source/Common/System/FileSystem.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/FileSystem.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/FileSystem.cpp Outdated
Comment thread Core/GameEngine/Source/Common/System/FileSystem.cpp Outdated
Comment thread Core/GameEngine/Include/Common/FileSystem.h Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from c9d9d86 to af0605e Compare April 24, 2026 21:11
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 24, 2026

Just a rebase with Main since BaseType is updated on main

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from af0605e to 76e0c2c Compare April 24, 2026 21:19
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 24, 2026

Edited based on majority of recent feedback, just waiting on discussion on two points.

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 76e0c2c to 873e16b Compare April 27, 2026 19:17
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 873e16b to 7813d5d Compare April 27, 2026 19:21
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 7813d5d to eea4264 Compare April 28, 2026 20:19
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 28, 2026

Updated based on feedback and implemented pointer comparison template functions.

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from eea4264 to 6e205b1 Compare April 28, 2026 20:24
Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks correct.

Maybe there can be a follow up in the future where former extension searches are replaced with the new functions.

Comment thread Core/Libraries/Include/Lib/PathUtil.h Outdated
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 6e205b1 to 3f2c744 Compare April 29, 2026 20:17
@xezon
Copy link
Copy Markdown

xezon commented Apr 29, 2026

Greptile says:

Comment:
"Must be C compliant" comment contradicts file contents

The comment states the file must be C-compliant, but the file uses several C++ features: function overloading (two getExtension overloads), nullptr (a C++11 keyword), and #include "BaseType.h" which is a C++ header. None of these are valid in standard C. The comment should be updated or removed to avoid misleading maintainers.

@xezon xezon changed the title feat(string): Implement removeExtension() function for string classes and add find/reverseFind to UnicodeString chore(string): Implement removeExtension() function for string classes and add find/reverseFind to UnicodeString Apr 29, 2026
@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 3f2c744 to 0c60fdb Compare April 29, 2026 20:46
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 29, 2026

Greptile says:

Comment:
"Must be C compliant" comment contradicts file contents

The comment states the file must be C-compliant, but the file uses several C++ features: function overloading (two getExtension overloads), nullptr (a C++11 keyword), and #include "BaseType.h" which is a C++ header. None of these are valid in standard C. The comment should be updated or removed to avoid misleading maintainers.

Ah missed that when copying the header.
Fixed now.

@xezon
Copy link
Copy Markdown

xezon commented Apr 29, 2026

Greptile has another comment

Comment:
Unconstrained template parameter for pointer-only helpers

maxPtr/minPtr are documented as "should only ever be used with pointers" but the template accepts any type. Instantiating with an arithmetic or class type compiles but produces meaningless results (e.g. comparing against nullptr always falls through to an arithmetic > comparison). A static_assert would catch misuse at the point of instantiation.

template <typename PTR>
inline PTR maxPtr(PTR x, PTR y) noexcept
{
    static_assert(std::is_pointer<PTR>::value, "maxPtr is for pointer types only");
    // ...
}

Same for minPtr.

@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 30, 2026

Greptile has another comment

Comment: Unconstrained template parameter for pointer-only helpers

maxPtr/minPtr are documented as "should only ever be used with pointers" but the template accepts any type. Instantiating with an arithmetic or class type compiles but produces meaningless results (e.g. comparing against nullptr always falls through to an arithmetic > comparison). A static_assert would catch misuse at the point of instantiation.

template <typename PTR>
inline PTR maxPtr(PTR x, PTR y) noexcept
{
    static_assert(std::is_pointer<PTR>::value, "maxPtr is for pointer types only");
    // ...
}

Same for minPtr.

Had to double check if that would work with VC6 since is_pointer() is C++11. But static_assert gets defined out for VC6

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 0c60fdb to 0d6d58d Compare April 30, 2026 16:49
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 30, 2026

updated with static asserts.

Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commits are titled as "feat" which implies that a new feature was added. But isn't this more a chore than feature? Because user facing nothing changes.

Comment thread Core/Libraries/Include/Lib/BaseType.h Outdated
return static_cast<NUM>(y & ~(y >> 1));
}

// TheSuperHackers @info The max and min pointer template functions should only ever be used with pointers!
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can now be removed because the static assert already documents and enforces it sufficiently.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 30, 2026

The commits are titled as "feat" which implies that a new feature was added. But isn't this more a chore than feature? Because user facing nothing changes.

I didn't think it needed to be considered user facing in context of the game itself. will change it to chore.

@Mauller Mauller force-pushed the Mauller/feat-string-remove-extensions branch from 0d6d58d to f85f88b Compare April 30, 2026 19:33
@Mauller
Copy link
Copy Markdown
Author

Mauller commented Apr 30, 2026

cleaned up the commit titles a touch as well

@xezon
Copy link
Copy Markdown

xezon commented Apr 30, 2026

I didn't think it needed to be considered user facing in context of the game itself. will change it to chore.

I am not sure either. But typically we would expect a feature as something the user can see. Adding a few new functions that do not really change the game behavior are probably not recognized as a new feature.

@xezon xezon merged commit 4eac616 into TheSuperHackers:main Apr 30, 2026
17 checks passed
@xezon xezon deleted the Mauller/feat-string-remove-extensions branch April 30, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Is new feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants