Skip to content

Commit 4d7787a

Browse files
committed
fix: harden cli help handling
1 parent fab8aae commit 4d7787a

8 files changed

Lines changed: 54 additions & 10 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,5 @@ modules/
8484
.agents/
8585
/bin/*.cmds
8686
/dist/
87+
*.log
88+
/issues/

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [v1.4] - 2026-06-21
4+
5+
### Fixed
6+
7+
- Added non-mutating `--help` and `/?` handling so help requests cannot fall through to file scanning.
8+
- Added CLI safety regression coverage to keep unknown options as non-mutating parse failures.
9+
310
## [v1.3] - 2026-06-16
411

512
### Added

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ EncodingFixTool ext="*.pas,*.dpr, .dfm"
4949

5050
| Param | Aliases | Values | Default | Meaning |
5151
| ------------- | ------- | -------------------------- | ----------- | ---------------------------------------------------------------------------------------------- |
52-
| `help` | `-h` | || Prints extended help and exits. |
52+
| `help` | `-h`, `--help`, `/?` ||| Prints extended help and exits without scanning or writing files. |
5353
| `dry` ||| off | Dry run: analyze and report what **would** change; no writes. |
5454
| `s`/`silent` ||| off | No console output. (Overrides `verbose`.) |
5555
| `v`/`verbose` ||| off | More output: “OK” lines etc. (Ignored if `silent`.) |
@@ -262,7 +262,7 @@ CLI arguments override preset values, so a one-off narrower run stays explicit:
262262
EncodingFixTool path=.\src preset=project-agent ext=pas,inc scope=git-changed format=json
263263
```
264264

265-
Invalid preset names, malformed JSON, and invalid preset option values fail before file rewriting starts.
265+
Invalid preset names, malformed JSON, invalid preset option values, and unknown command-line options fail before file rewriting starts.
266266

267267
## Related MaxLogic Delphi tooling
268268

src/EncodingFixTool.dproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,19 @@
9090
<SanitizedProjectName>EncodingFixTool</SanitizedProjectName>
9191
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
9292
<VerInfo_MajorVer>1</VerInfo_MajorVer>
93-
<VerInfo_MinorVer>3</VerInfo_MinorVer>
93+
<VerInfo_MinorVer>4</VerInfo_MinorVer>
9494
<VerInfo_Release>0</VerInfo_Release>
9595
<VerInfo_Build>0</VerInfo_Build>
9696
<VerInfo_Locale>1045</VerInfo_Locale>
97-
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.3.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.3.0.0;Comments=;CFBundleName=</VerInfo_Keys>
97+
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.4.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.4.0.0;Comments=;CFBundleName=</VerInfo_Keys>
9898
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
9999
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
100100
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
101101
<DCC_ExeOutput>..\bin</DCC_ExeOutput>
102102
<CfgDependentOn>..\..\MaxLogicFoundation\MaxLogicDefault.optset</CfgDependentOn>
103103
</PropertyGroup>
104104
<PropertyGroup Condition="'$(Base_Android)'!=''">
105-
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.3.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34</VerInfo_Keys>
105+
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34</VerInfo_Keys>
106106
<BT_BuildType>Debug</BT_BuildType>
107107
<Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
108108
<Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
@@ -141,13 +141,13 @@
141141
<PropertyGroup Condition="'$(Base_Win32)'!=''">
142142
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
143143
<BT_BuildType>Debug</BT_BuildType>
144-
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.3.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.3.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
144+
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.4.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.4.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
145145
<VerInfo_Locale>1033</VerInfo_Locale>
146146
</PropertyGroup>
147147
<PropertyGroup Condition="'$(Base_Win64)'!=''">
148148
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
149149
<BT_BuildType>Debug</BT_BuildType>
150-
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.3.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.3.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
150+
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.4.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.4.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
151151
<VerInfo_Locale>1033</VerInfo_Locale>
152152
</PropertyGroup>
153153
<PropertyGroup Condition="'$(Cfg_1)'!=''">
@@ -177,7 +177,7 @@
177177
</PropertyGroup>
178178
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
179179
<VerInfo_Locale>1033</VerInfo_Locale>
180-
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.3.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.3.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
180+
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.4.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.4.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName)</VerInfo_Keys>
181181
<Manifest_File>(None)</Manifest_File>
182182
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
183183
</PropertyGroup>

src/EncodingFixTool.res

0 Bytes
Binary file not shown.

src/EncodingFixToolCore.pas

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,7 +1081,7 @@ function TEncodingFixTool.ShowHelp: integer;
10811081
' EncodingFixTool [params]' + sLineBreak +
10821082
sLineBreak +
10831083
'Params:' + sLineBreak +
1084-
' help : Show this help text.' + sLineBreak +
1084+
' help | -h | --help | /? : Show this help text.' + sLineBreak +
10851085
' dry : Dry run (no files are changed).' + sLineBreak +
10861086
' s | silent : No console output.' + sLineBreak +
10871087
' v | verbose : More output (not compatible with silent).' + sLineBreak +
@@ -1168,8 +1168,14 @@ function TEncodingFixTool.ParseCommandLine(out aOptions: TOptions): integer;
11681168
begin
11691169
p := Trim(ParamStr(aIndex));
11701170

1171-
if startsStr('-', p) {$IFDEF MsWindows}or StartsStr('/', p){$ENDIF} then
1171+
while (p <> '') and ((p[1] = '-') {$IFDEF MsWindows}or (p[1] = '/'){$ENDIF}) do
1172+
begin
11721173
delete(p, 1, 1);
1174+
end;
1175+
if p = '?' then
1176+
begin
1177+
p := 'help';
1178+
end;
11731179
if p = '' then
11741180
begin
11751181
aKey := '';

tests/EncodingFixTool.Tests.res

96 Bytes
Binary file not shown.

tests/Invoke-EncodingFixTool.Tests.ps1

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,35 @@ function Invoke-Tool {
3535

3636
Assert-True (Test-Path -LiteralPath $ToolPath) "Tool not found: $ToolPath"
3737

38+
$lSafetyRoot = Initialize-TestRoot
39+
try {
40+
$lSafetyFile = Join-Path $lSafetyRoot 'sample.pas'
41+
[System.IO.File]::WriteAllBytes(
42+
$lSafetyFile,
43+
[System.Text.Encoding]::ASCII.GetBytes("unit sample;`nend.")
44+
)
45+
$lOriginalBytes = [System.IO.File]::ReadAllBytes($lSafetyFile)
46+
47+
$lResult = Invoke-Tool @('--help')
48+
Assert-True ($lResult.ExitCode -eq 0) "--help should show help and exit 0."
49+
Assert-True ($lResult.Output -match 'Usage:') "--help output should include usage text."
50+
Assert-True ([Convert]::ToBase64String($lOriginalBytes) -eq [Convert]::ToBase64String([System.IO.File]::ReadAllBytes($lSafetyFile))) "--help must not rewrite files."
51+
52+
$lResult = Invoke-Tool @('/?')
53+
Assert-True ($lResult.ExitCode -eq 0) "/? should show help and exit 0."
54+
Assert-True ($lResult.Output -match 'Usage:') "/? output should include usage text."
55+
Assert-True ([Convert]::ToBase64String($lOriginalBytes) -eq [Convert]::ToBase64String([System.IO.File]::ReadAllBytes($lSafetyFile))) "/? must not rewrite files."
56+
57+
$lResult = Invoke-Tool @("path=$lSafetyRoot", '--definitely-not-valid')
58+
Assert-True ($lResult.ExitCode -ne 0) "Unknown options should fail before scanning."
59+
Assert-True ($lResult.Output -match 'ERROR: unknown parameter:') "Unknown options should explain the parse failure."
60+
Assert-True ([Convert]::ToBase64String($lOriginalBytes) -eq [Convert]::ToBase64String([System.IO.File]::ReadAllBytes($lSafetyFile))) "Unknown options must not rewrite files."
61+
} finally {
62+
if (Test-Path -LiteralPath $lSafetyRoot) {
63+
Remove-Item -LiteralPath $lSafetyRoot -Recurse -Force
64+
}
65+
}
66+
3867
$lRoot = Initialize-TestRoot
3968
try {
4069
$lReadOnlyFile = Join-Path $lRoot 'readonly.pas'

0 commit comments

Comments
 (0)