Index: CHANGES.txt ================================================================== --- CHANGES.txt +++ CHANGES.txt @@ -2,10 +2,11 @@ [Feature] On Windows, Ghostscript replaced pdfroff (thanks @wysardry). [Bugfix] The groff detection logic was not as logical as it should have been. [Feature] There is an option to keep both the .ps and the .pdf file now. [Feature] Non-Windows users can choose to use Ghostscript (if installed) or pdfroff. +[Feature] The installed Ghostscript version is now displayed in the settings. ------------------------------- Version 0.13.2 2024-04-30 Index: src/buildoutputwindow.pas ================================================================== --- src/buildoutputwindow.pas +++ src/buildoutputwindow.pas @@ -29,32 +29,32 @@ TBuildStatusWindow = class(TForm) Label1: TLabel; private public - function BuildDocument(CommandLine: String; LogFile: String): Boolean; + function BuildDocument(CommandLine: string; LogFile: string): boolean; end; var - OutputText: String; + OutputText: string; implementation {$R *.lfm} -function TBuildStatusWindow.BuildDocument(CommandLine: String; LogFile: String): Boolean; +function TBuildStatusWindow.BuildDocument(CommandLine: string; LogFile: string): boolean; var - str: String; + str: string; lh: TextFile; - ret: Boolean; + ret: boolean; begin -{$IFDEF WINDOWS} + {$IFDEF WINDOWS} ret := RunCommand('cmd', ['/c', CommandLine], str, [], swoHIDE); {$ELSE} ret := RunCommand('sh', ['-c', CommandLine], str, [], swoHIDE); -{$ENDIF} + {$ENDIF} if Length(str) = 0 then str := 'No problems have occurred. :-)'; if LogFile <> '' then begin @@ -72,6 +72,5 @@ Result := ret; end; end. - Index: src/groffstudio.lpi ================================================================== --- src/groffstudio.lpi +++ src/groffstudio.lpi @@ -21,11 +21,11 @@ - + Index: src/groffstudio.lpr ================================================================== --- src/groffstudio.lpr +++ src/groffstudio.lpr @@ -18,24 +18,27 @@ {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, - {$ENDIF} +{$ENDIF} {$IFDEF HASAMIGA} athreads, - {$ENDIF} +{$ENDIF} Interfaces, - Forms, lazcontrols, Unit1, Helpers, BuildOutputWindow; + Forms, + lazcontrols, + Unit1, + Helpers, + BuildOutputWindow; -{$R *.res} + {$R *.res} begin - RequireDerivedFormResource:=True; - Application.Scaled:=True; + RequireDerivedFormResource := True; + Application.Scaled := True; Application.Initialize; - + Application.CreateForm(TMainForm, MainForm); Application.Run; end. - Index: src/helpers.pas ================================================================== --- src/helpers.pas +++ src/helpers.pas @@ -23,41 +23,41 @@ Classes, SysUtils; type TGroffHelpers = class public - procedure VerStrCompare(newVersion, oldVersion: String; out comp: Integer); -end; + procedure VerStrCompare(newVersion, oldVersion: string; out comp: integer); + end; implementation -procedure TGroffHelpers.VerStrCompare(newVersion, oldVersion: String; out comp: Integer); -var - nE1, nE2, nV1, nV2: Integer; - -begin - if (Length(newVersion) > 0) or (Length(oldVersion) > 0) then begin - nE1 := Pos('.', newVersion + '.'); - nE2 := Pos('.', oldVersion + '.'); - if nE1 > 1 then - nV1 := StrToInt(Copy(newVersion,1,(nE1-1))) - else - nV1 := 0; - - if nE2 > 1 then - nV2 := StrToInt(Copy(oldVersion,1,(nE2-1))) - else - nV2 := 0; - - if nV1 = nV2 then - VerStrCompare(Copy(newVersion, nE1 + 1, Length(newVersion)), Copy(oldVersion, nE2 + 1, Length(oldVersion)), comp) - else if nV1 > nV2 then - comp := 1 - else if nV1 < nV2 then - comp := -1; - end - else - comp := 0; +procedure TGroffHelpers.VerStrCompare(newVersion, oldVersion: string; out comp: integer); +var + nE1, nE2, nV1, nV2: integer; +begin + if (Length(newVersion) > 0) or (Length(oldVersion) > 0) then + begin + nE1 := Pos('.', newVersion + '.'); + nE2 := Pos('.', oldVersion + '.'); + if nE1 > 1 then + nV1 := StrToInt(Copy(newVersion, 1, (nE1 - 1))) + else + nV1 := 0; + + if nE2 > 1 then + nV2 := StrToInt(Copy(oldVersion, 1, (nE2 - 1))) + else + nV2 := 0; + + if nV1 = nV2 then + VerStrCompare(Copy(newVersion, nE1 + 1, Length(newVersion)), + Copy(oldVersion, nE2 + 1, Length(oldVersion)), comp) + else if nV1 > nV2 then + comp := 1 + else if nV1 < nV2 then + comp := -1; + end + else + comp := 0; end; end. - Index: src/unit1.lfm ================================================================== --- src/unit1.lfm +++ src/unit1.lfm @@ -6,11 +6,10 @@ Caption = 'groffstudio' ClientHeight = 692 ClientWidth = 847 DefaultMonitor = dmPrimary Position = poScreenCenter - LCLVersion = '3.99.0.0' OnClose = FormClose OnCreate = FormCreate object MainStatusBar: TStatusBar Left = 0 Height = 23 @@ -34,14 +33,14 @@ object ExtendedNotebook1: TExtendedNotebook Left = 8 Height = 662 Top = 8 Width = 827 - ActivePage = tsSettings + ActivePage = tsEdit Anchors = [akTop, akLeft, akRight, akBottom] Style = tsFlatButtons - TabIndex = 1 + TabIndex = 0 TabOrder = 1 object tsEdit: TTabSheet Caption = 'edit a groff document' ClientHeight = 631 ClientWidth = 819 @@ -879,11 +878,11 @@ TabOrder = 1 end object lblTroffCommandNotFound: TLabel Left = 8 Height = 45 - Top = 112 + Top = 130 Width = 806 Anchors = [akTop, akLeft, akRight] Caption = 'groff was not found. in order to use groffstudio, you absolutely need groff in your PATH variable. on unix and unix-like systems, you''ll need to edit the $PATH variable. on windows, i warmly recommend the Rapid Environment Editor for that.'#13#10'please exit groffstudio at your nearest convenience and adjust your PATH variables. then try again.' Font.Color = clRed ParentColor = False @@ -906,10 +905,27 @@ Height = 15 Top = 77 Width = 103 Caption = 'groffstudio version:' ParentColor = False + end + object Label15: TLabel + Left = 8 + Height = 15 + Top = 98 + Width = 103 + Caption = 'ghostscript version:' + end + object edtGhostscriptInstalledVersion: TEdit + Left = 144 + Height = 15 + Top = 98 + Width = 671 + Anchors = [akTop, akLeft, akRight] + BorderStyle = bsNone + Enabled = False + TabOrder = 3 end end object tsAbout: TTabSheet Caption = 'about groffstudio' ClientHeight = 631 Index: src/unit1.pas ================================================================== --- src/unit1.pas +++ src/unit1.pas @@ -21,17 +21,17 @@ uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, StdCtrls, ExtCtrls, Buttons, ExtendedNotebook, SynEdit, fphttpclient, RegExpr, LCLIntf, LCLType, IniPropStorage, ComboEx, Process, Helpers, fileinfo, - {$IF DEFINED(WINDOWS)} +{$IF DEFINED(WINDOWS)} winpeimagereader, opensslsockets, - {$ELSEIF DEFINED(DARWIN)} +{$ELSEIF DEFINED(DARWIN)} machoreader, ssockets, sslsockets, sslbase, opensslsockets, - {$ELSEIF DEFINED(LINUX)} +{$ELSEIF DEFINED(LINUX)} elfreader, - {$ENDIF} +{$ENDIF} BuildOutputWindow; type { TMainForm } @@ -50,10 +50,11 @@ chkLogFile: TCheckBox; chkAutoSaveBuildSettings: TCheckBox; cmbMacro: TComboBox; edtGroffInstalledVersion: TEdit; edtGroffstudioInstalledVersion: TEdit; + edtGhostscriptInstalledVersion: TEdit; edtOnlineGroffVersionWindows: TEdit; ExtendedNotebook1: TExtendedNotebook; GroupBox1: TGroupBox; GroupBox2: TGroupBox; GroupBox3: TGroupBox; @@ -62,10 +63,11 @@ Label10: TLabel; Label11: TLabel; Label12: TLabel; Label13: TLabel; Label14: TLabel; + Label15: TLabel; lblGithubRepo: TLabel; lblFossilRepo: TLabel; lblWebsite: TLabel; Label2: TLabel; Label3: TLabel; @@ -98,21 +100,21 @@ procedure FormCreate(Sender: TObject); procedure lblFossilRepoClick(Sender: TObject); procedure lblGithubRepoClick(Sender: TObject); procedure lblWebsiteClick(Sender: TObject); procedure SynEdit1Change(Sender: TObject); - {$IFDEF DARWIN} +{$IFDEF DARWIN} procedure GetSocketHandler(Sender: TObject; const UseSSL: Boolean; out AHandler: TSocketHandler); - {$ENDIF} +{$ENDIF} private var currentGroffFilePath: string; currentGroffFileName: string; unsavedChanges: boolean; - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} latestGroffWindowsUrl: String; - {$ENDIF} +{$ENDIF} // Settings: storeBuildSettings: boolean; updateCheck: boolean; public @@ -130,10 +132,11 @@ BuildWindow: TBuildStatusWindow; hasGroff: boolean; hasGhostscript: boolean; GroffOutputVersion: string; ps2pdfOutput: string; + GhostscriptOutputVersion: string; implementation {$R *.lfm} @@ -157,62 +160,73 @@ end; // Try to find ps2pdf: if pos('ps2pdf', ps2pdfOutput) = 0 then begin - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} // ps2pdf is mandatory on Windows. ShowMessage('On Windows, for creating PDF files, you need Ghostscript installed.' + LineEnding + 'Sadly, groffstudio could not find ps2pdf.bat in your %PATH%, so ' + 'writing PDF files will not be supported. Please install Ghostscript and make sure ' + 'that the folder that contains ps2pdf.bat is in your %PATH%.'); MainForm.rdPdf.Enabled := False; - {$ENDIF} +{$ENDIF} hasGhostscript := False; MainForm.chkUseGhostscript.Checked := False; MainForm.chkUseGhostscript.Enabled := False; - end else begin + end + else + begin hasGhostscript := True; - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} MainForm.rdPdf.Enabled := True; MainForm.chkUseGhostscript.Checked := True; - {$ENDIF} +{$ENDIF} MainForm.chkUseGhostscript.Enabled := True; end; + + // Try to find Ghostscript, just for displaying the version: + if hasGhostscript then + MainForm.edtGhostscriptInstalledVersion.Text := GhostscriptOutputVersion + else + MainForm.edtGhostscriptInstalledVersion.Text := 'n/a'; end; procedure TDetectGroffThread.Execute; begin FreeOnTerminate := True; - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} RunCommand('cmd', ['/c', 'troff --version'], GroffOutputVersion, [], swoHIDE); + RunCommand('cmd', ['/c', 'gs --version'], GhostscriptOutputVersion, [], swoHIDE); RunCommand('cmd', ['/c', 'ps2pdf'], ps2pdfOutput, [], swoHIDE); - {$ELSE} +{$ELSE} RunCommand('/bin/sh', ['-c', 'troff --version'], GroffOutputVersion, [], swoHIDE); + RunCommand('/bin/sh', ['-c', 'gs --version'], GhostscriptOutputVersion, + [], swoHIDE); RunCommand('/bin/sh', ['-c', 'ps2pdf'], ps2pdfOutput, [], swoHIDE); - {$ENDIF} +{$ENDIF} Synchronize(@UpdateUI); end; { TMainForm } procedure TMainForm.FormCreate(Sender: TObject); var OnlineVersionsFile: string; - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} reGroffVersion: TRegExpr; - {$ENDIF} +{$ENDIF} reGroffStudioVersion: TRegExpr; FileVerInfo: TFileVersionInfo; HasVersionUpdate: integer; GroffHelpers: TGroffHelpers; ResStream: TResourceStream; - {$IFDEF DARWIN} +{$IFDEF DARWIN} HTTPClient: TFPHttpClient; - {$ENDIF} +{$ENDIF} begin // What's the current running groff version? TDetectGroffThread.Create(False); // Default file name @@ -224,29 +238,29 @@ mLicense.Lines.LoadFromStream(ResStream); finally ResStream.Free; end; - {$IFNDEF WINDOWS} +{$IFNDEF WINDOWS} // Ghostscript is not optional on Windows. // On other platforms, let's use the stored setting. chkUseGhostscript.Checked := iniStorage.ReadBoolean('UseGhostscript', False); - {$ENDIF} +{$ENDIF} // Restore the settings iniStorage.Restore; storeBuildSettings := iniStorage.ReadBoolean('AutoSaveBuildSettings', False); chkAutoSaveBuildSettings.Checked := storeBuildSettings; - {$IF DEFINED(LINUX) OR DEFINED(BSD)} +{$IF DEFINED(LINUX) OR DEFINED(BSD)} // On platforms which probably use a package manager (currently, Linux and // BSDs), the "update check" checkbox is disabled. chkUpdateCheckOnStart.Enabled := False; - {$ELSE} +{$ELSE} updateCheck := iniStorage.ReadBoolean('UpdateCheckOnStart', False); chkUpdateCheckOnStart.Checked := updateCheck; - {$ENDIF} +{$ENDIF} if storeBuildSettings then begin chkLogFile.Checked := iniStorage.ReadBoolean('BuildLogFile', False); cmbMacro.Text := iniStorage.ReadString('BuildChosenMacro', '[ select ]'); @@ -272,11 +286,11 @@ lblAboutProductName.Caption := FileVerInfo.VersionStrings.Values['ProductName'] + ' ' + FileVerInfo.VersionStrings.Values['FileVersion']; MainStatusBar.Panels[2].Text := ''; - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} if updateCheck then begin OnlineVersionsFile := TFPCustomHTTPClient.SimpleGet('https://groff.tuxproject.de/updates/versions.txt'); // 1. groff update check @@ -303,11 +317,11 @@ end; end else begin edtOnlineGroffVersionWindows.Text := 'n/a'; btnDownloadGroffWindows.Enabled := False; end; - {$ELSE} +{$ELSE} // Non-Windows platforms won't need some of that. {$IFDEF DARWIN} // What's the latest available version? try if updateCheck then @@ -335,11 +349,11 @@ if updateCheck then HTTPClient.Free; end; {$ENDIF} edtOnlineGroffVersionWindows.Text := 'n/a'; btnDownloadGroffWindows.Enabled := False; - {$ENDIF} +{$ENDIF} finally FileVerInfo.Free; end; // Loaded file display @@ -371,14 +385,14 @@ unsavedChanges := True; end; procedure TMainForm.btnDownloadGroffWindowsClick(Sender: TObject); begin - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} // On other systems, the button is disabled anyway. OpenURL(latestGroffWindowsUrl); - {$ENDIF} +{$ENDIF} end; procedure TMainForm.btnBuildClick(Sender: TObject); var buildSuccess: boolean; @@ -410,11 +424,11 @@ if chkBoxPreprocessors.Checked[5] then buildOpts := buildOpts + ' -tbl'; if chkBoxExtras.Checked[0] then buildOpts := buildOpts + ' -mhdtbl'; // - PDF-specifics: - {$IFNDEF WINDOWS} +{$IFNDEF WINDOWS} // On Windows, we use a two-step program: // 1) Output to PostScript, // 2) ps2pdf to PDF. // This is because there is no pdfroff.exe. Requires Ghostscript. if rdPdf.Checked and not chkUseGhostscript.Checked then @@ -422,11 +436,11 @@ buildOpts := buildOpts + ' -Tpdf'; if chkBoxExtras.Checked[1] then buildOpts := buildOpts + ' -mpdfmark'; outputFileName := currentGroffFilePath + '.pdf'; end else - {$ENDIF} +{$ENDIF} outputFileName := currentGroffFilePath + '.ps'; // - Input file: buildOpts := buildOpts + ' ' + currentGroffFilePath; buildOpts := buildOpts + ' > ' + outputFileName; @@ -435,25 +449,25 @@ if chkLogFile.Checked then logFileName := currentGroffFilePath + '.log'; // Build: buildSuccess := BuildWindow.BuildDocument(buildOpts, logFileName); - {$IFDEF WINDOWS} +{$IFDEF WINDOWS} if buildSuccess and hasGhostscript and rdPdf.Checked then - {$ELSE} +{$ELSE} // On non-Windows systems, Ghostscript is entirely optional. if buildSuccess and hasGhostscript and chkUseGhostscript.Checked and rdPdf.Checked then - {$ENDIF} +{$ENDIF} begin // Invoke ps2pdf: buildOpts := 'ps2pdf'; // outputFileName is still the .ps file. Just use it as the input name. buildOpts := buildOpts + ' ' + outputFileName; buildSuccess := BuildWindow.BuildDocument(buildOpts, logFileName); - if buildSuccess and not chkKeepPostscriptFile.Checked then; - DeleteFile(outputFileName); // get rid of the .ps fil + if buildSuccess and not chkKeepPostscriptFile.Checked then + DeleteFile(outputFileName); // get rid of the .ps file end; if buildSuccess then MainStatusBar.Panels[1].Text := 'build successful' else