From d188b37cd075af70aeaf7eb04451cfb48553c566 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Feb 2026 00:14:27 +0000 Subject: [PATCH 01/17] Decouple UI from disc image processing library for CLI support - Remove unused ExtCtrls and HTTPProtocol dependencies from DiscImage.pas - Add conditional compilation to Utils.pas to exclude GUI code when NO_GUI defined - Create DiscImageContext.pas: shared context for disc image operations - Create CLICommands.pas: standalone CLI command processor without GUI dependencies - Create DiscImageManagerCLI.lpr: CLI-only console application entry point - Create DiscImageManagerCLI.lpi: Lazarus project file for CLI version - Create UtilsCLI.pas: CLI-compatible subset of utility functions This enables building a command-line version of the tool that does not require an X server or GUI toolkits, suitable for headless server use. https://claude.ai/code/session_01H1suvkNPi2MVsX1y9Qy86P --- LazarusSource/CLICommands.pas | 1114 +++++++++++++++++++++++++ LazarusSource/DiscImage.pas | 4 +- LazarusSource/DiscImageContext.pas | 360 ++++++++ LazarusSource/DiscImageManagerCLI.lpi | 234 ++++++ LazarusSource/DiscImageManagerCLI.lpr | 262 ++++++ LazarusSource/Utils.pas | 16 +- LazarusSource/UtilsCLI.pas | 163 ++++ 7 files changed, 2149 insertions(+), 4 deletions(-) create mode 100644 LazarusSource/CLICommands.pas create mode 100644 LazarusSource/DiscImageContext.pas create mode 100644 LazarusSource/DiscImageManagerCLI.lpi create mode 100644 LazarusSource/DiscImageManagerCLI.lpr create mode 100644 LazarusSource/UtilsCLI.pas diff --git a/LazarusSource/CLICommands.pas b/LazarusSource/CLICommands.pas new file mode 100644 index 0000000..3c13e17 --- /dev/null +++ b/LazarusSource/CLICommands.pas @@ -0,0 +1,1114 @@ +unit CLICommands; + +{ +CLI Command Processor - Command-line interface for disc image operations. +This unit provides command processing without requiring any GUI dependencies. + +Copyright (C) 2018-2025 Gerald Holdsworth gerald@hollypops.co.uk + +This source is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public Licence as published by the Free +Software Foundation; either version 3 of the Licence, or (at your option) +any later version. + +This code is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public Licence for more +details. + +A copy of the GNU General Public Licence is available on the World Wide Web +at . You can also obtain it by writing +to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1335, USA. +} + +{$MODE objFPC}{$H+} + +interface + +uses + Classes, SysUtils, DiscImage, DiscImageContext; + +type + { TCLICommandProcessor - Processes CLI commands } + TCLICommandProcessor = class + private + FContext: TDiscImageContext; + FSettings: TRegistrySettings; + FOwnsContext: Boolean; + FOwnsSettings: Boolean; + FConsoleWidth: Integer; + // ANSI style modifiers + FUseColors: Boolean; + procedure WriteColored(const S: String; const Color: String = ''); + procedure WriteLnColored(const S: String; const Color: String = ''); + function GetCurrentPath: String; + function ValidFile(const Filename: String; out Dir, Entry: Cardinal): Boolean; + function BuildFilename(const AFile: TDirEntry): String; + function GetListOfFiles(const FileSearch: String): TSearchResults; + procedure ReportFreeSpace; + function Confirm: Boolean; + function GetDriveSize(const GivenSize: String): Cardinal; + procedure ShowHelp; + procedure ShowImageInfo; + procedure ListCatalogue(ShowAll: Boolean); + // Command handlers + procedure CmdAccess(const Params: TStringArray); + procedure CmdAdd(const Params: TStringArray); + procedure CmdCat(const Params: TStringArray); + procedure CmdCreate(const Params: TStringArray); + procedure CmdDelete(const Params: TStringArray); + procedure CmdDir(const Params: TStringArray); + procedure CmdExtract(const Params: TStringArray); + procedure CmdFree(const Params: TStringArray); + procedure CmdInfo(const Params: TStringArray); + procedure CmdInsert(const Params: TStringArray); + procedure CmdNew(const Params: TStringArray); + procedure CmdOpt(const Params: TStringArray); + procedure CmdRename(const Params: TStringArray); + procedure CmdSave(const Params: TStringArray); + procedure CmdTitle(const Params: TStringArray); + procedure CmdConfig(const Params: TStringArray); + procedure CmdStatus(const Params: TStringArray); + procedure CmdSearch(const Params: TStringArray); + public + constructor Create; overload; + constructor Create(AContext: TDiscImageContext; ASettings: TRegistrySettings); overload; + destructor Destroy; override; + + function ProcessCommand(const Command: TStringArray): Boolean; + function ParseInput(const Input: String): TStringArray; + + property Context: TDiscImageContext read FContext; + property Settings: TRegistrySettings read FSettings; + property UseColors: Boolean read FUseColors write FUseColors; + property ConsoleWidth: Integer read FConsoleWidth write FConsoleWidth; + end; + + // ANSI color constants +const + clNormal = #$1B'[0m'; + clBold = #$1B'[1m'; + clRed = #$1B'[91m'; + clGreen = #$1B'[92m'; + clYellow = #$1B'[93m'; + clBlue = #$1B'[94m'; + clMagenta = #$1B'[95m'; + clCyan = #$1B'[96m'; + + // Disc format strings + DiscFormats = + 'DFSS80 DFSS40 DFSD80 DFSD40 WDFSS80 WDFSS40 WDFSD80 WDFSD40 ADFSS ADFSM ' + + 'ADFSL ADFSD ADFSE ADFSE+ ADFSF ADFSF+ C1541 C1571 C1581 AMIGADD ' + + 'AMIGAHD CFS DOS+640 DOS+800 DOS360 DOS720 DOS1440 DOS2880 '; + + DiscNumber: array[1..28] of Integer = ( + $001, $000, $011, $010, $021, $020, $031, $030, $100, $110, + $120, $130, $140, $150, $160, $170, $200, $210, $220, $400, + $410, $500, $A00, $A01, $A02, $A03, $A04, $A05); + + BootOptions: array[0..3] of String = ('none', 'load', 'run', 'exec'); + Interleaves: array[0..3] of String = ('auto', 'seq', 'int', 'mux'); + +implementation + +{ TCLICommandProcessor } + +constructor TCLICommandProcessor.Create; +begin + inherited Create; + FContext := TDiscImageContext.Create; + FSettings := TRegistrySettings.Create('DiscImageManager'); + FOwnsContext := True; + FOwnsSettings := True; + FConsoleWidth := 80; + FUseColors := True; +end; + +constructor TCLICommandProcessor.Create(AContext: TDiscImageContext; + ASettings: TRegistrySettings); +begin + inherited Create; + FContext := AContext; + FSettings := ASettings; + FOwnsContext := False; + FOwnsSettings := False; + FConsoleWidth := 80; + FUseColors := True; +end; + +destructor TCLICommandProcessor.Destroy; +begin + if FOwnsContext then + FContext.Free; + if FOwnsSettings then + FSettings.Free; + inherited Destroy; +end; + +procedure TCLICommandProcessor.WriteColored(const S: String; const Color: String); +begin + if FUseColors and (Color <> '') then + Write(Color + S + clNormal) + else + Write(S); +end; + +procedure TCLICommandProcessor.WriteLnColored(const S: String; const Color: String); +begin + WriteColored(S, Color); + WriteLn; +end; + +function TCLICommandProcessor.GetCurrentPath: String; +begin + if FContext.Image.FormatNumber <> diInvalidImg then + Result := FContext.Image.GetParent(FContext.CurrentDir) + else + Result := ''; +end; + +function TCLICommandProcessor.ValidFile(const Filename: String; + out Dir, Entry: Cardinal): Boolean; +var + Temp: String; +begin + if FContext.Image.FileExists(Filename, Dir, Entry) then + Result := True + else + begin + Temp := FContext.Image.GetParent(FContext.CurrentDir) + + FContext.Image.GetDirSep(FContext.Image.Disc[FContext.CurrentDir].Partition) + + Filename; + Result := FContext.Image.FileExists(Temp, Dir, Entry); + end; +end; + +function TCLICommandProcessor.BuildFilename(const AFile: TDirEntry): String; +begin + Result := ''; + if AFile.Parent <> '' then + Result := AFile.Parent + + FContext.Image.GetDirSep(FContext.Image.Disc[FContext.CurrentDir].Partition); + Result := Result + AFile.Filename; +end; + +function TCLICommandProcessor.GetListOfFiles(const FileSearch: String): TSearchResults; +var + FileDetails: TDirEntry; +begin + ResetDirEntry(FileDetails); + FileDetails.Filename := FileSearch; + FileDetails.Parent := FContext.Image.GetParent(FContext.CurrentDir); + Result := FContext.Image.FileSearch(FileDetails); +end; + +procedure TCLICommandProcessor.ReportFreeSpace; +var + Free, Used, Total: QWord; +begin + Free := FContext.Image.FreeSpace(FContext.Image.Disc[FContext.CurrentDir].Partition); + Total := FContext.Image.DiscSize(FContext.Image.Disc[FContext.CurrentDir].Partition); + Used := Total - Free; + WriteColored(IntToStr(Free), clBold); + Write(' bytes free. '); + WriteColored(IntToStr(Used), clBold); + Write(' bytes used. '); + WriteColored(IntToStr(Total), clBold); + WriteLn(' bytes total.'); +end; + +function TCLICommandProcessor.Confirm: Boolean; +var + Response: String; +begin + Result := True; + if FContext.HasChanged then + begin + Result := False; + WriteLn('Image has been modified.'); + Write('Are you sure you want to continue? (yes/no): '); + ReadLn(Response); + if (Length(Response) > 0) and (LowerCase(Response[1]) = 'y') then + Result := True; + end; +end; + +function TCLICommandProcessor.GetDriveSize(const GivenSize: String): Cardinal; +begin + Result := StrToIntDef(GivenSize, 0); + if UpperCase(RightStr(GivenSize, 1)) = 'M' then + Result := StrToIntDef(LeftStr(GivenSize, Length(GivenSize) - 1), 0) * 1024; +end; + +procedure TCLICommandProcessor.ShowHelp; +begin + WriteLnColored('Disc Image Manager CLI Help', clBlue + clBold); + WriteLn; + WriteLn('Image Commands:'); + WriteLn(' insert - Open a disc image'); + WriteLn(' new - Create a new disc image'); + WriteLn(' save [file] - Save the current image'); + WriteLn(' info - Show image information'); + WriteLn; + WriteLn('Navigation:'); + WriteLn(' dir - Change current directory'); + WriteLn(' cat [all|root] - Show catalogue listing'); + WriteLn(' free - Show free space'); + WriteLn; + WriteLn('File Operations:'); + WriteLn(' add - Add file(s) to image'); + WriteLn(' extract - Extract file(s) from image'); + WriteLn(' delete - Delete file(s) from image'); + WriteLn(' rename - Rename a file'); + WriteLn(' access - Change file attributes'); + WriteLn(' search - Search for files'); + WriteLn; + WriteLn('Directory Operations:'); + WriteLn(' create - Create a new directory'); + WriteLn; + WriteLn('Disc Properties:'); + WriteLn(' title - Change disc title'); + WriteLn(' opt