packages feed

crackNum 3.31 → 4.0

raw patch · 6 files changed

+164/−27 lines, 6 files

Files

CHANGES.md view
@@ -1,9 +1,42 @@ * Hackage: <http://hackage.haskell.org/package/crackNum> * GitHub:  <http://github.com/LeventErkok/crackNum/> -* Latest Hackage released version: 3.30, 2026-08-21+* Latest Hackage released version: 4.0, 2026-08-24 -### Version 3.31, Not yet released+### Version 4.0, 2026-08-24++  * The Windows GUI now carries the CrackNum icon instead of the stock WinForms+    one. The artwork is rendered by the same generator that produces the macOS+    AppIcon.icns, so the two platforms cannot drift apart.++  * Note on numbering: 3.32 was tagged and published as a GitHub release, but never+    uploaded to Hackage. So for anyone installing from Hackage, this is the first+    version to support Windows -- see the 3.32 entry below for what that involves.++### Version 3.32, 2026-08-24++  * Windows is now a supported platform, with a prebuilt bundle+    (`crackNum-<version>-windows-x86_64.zip`) alongside the Mac and Linux ones. It+    carries the CLI, a native GUI, and a copy of z3, and needs nothing installed:+    the GUI targets .NET Framework 4.8, which ships with Windows 10 and 11, and z3+    brings its own Microsoft C runtime. The binaries are not code-signed, so+    SmartScreen warns on first run; the bundled README says how to get past it.++  * The Windows GUI (`GUI/winGUI/`) is a native WinForms application rather than a+    port of the Tcl/Tk script that serves Linux. Reusing the Tcl would have been a+    far smaller change, but it would have required users to install a Tcl+    distribution before `--gui` did anything, and a GUI behind a prerequisite that+    most people will not clear is worth less than the code it saves.++  * `--version` and the usage text no longer print the executable's `.exe`+    extension on Windows, where `getProgName` keeps it.++  * The golden test suite writes its temporary files with newline translation+    turned off, so the golds stay LF everywhere. Previously, running the suite on+    Windows compared CRLF output against LF golds, and `--accept` there would have+    rewritten every gold in the process.++### Version 3.31, 2026-08-22    * The Hackage description now shows a screenshot of the GUI, and points at the     releases page for the prebuilt Mac and Linux bundles. The screenshot was dropped
README.md view
@@ -24,6 +24,7 @@ | --- | --- | --- | | Linux (x86_64) | `crackNum-<version>-linux-x86_64.tar.gz` | Statically linked, so there is no glibc or distribution requirement: it runs as-is on any x86_64 Linux, old or new. | | macOS (Apple Silicon) | `crackNum-<version>-macos-arm64.tar.gz` | Includes `CrackNum.app`. Ad-hoc signed rather than notarized, so clear the quarantine flag as shown below. |+| Windows (x86_64) | `crackNum-<version>-windows-x86_64.zip` | Includes `CrackNumGUI.exe`. Unsigned, so SmartScreen warns on first run; see below. |  Unpack the bundle anywhere you like, then put the files somewhere on your `PATH`. `z3` has to go there too, since crackNum shells out to it for every operation.@@ -53,9 +54,24 @@ $ export PATH=$HOME/bin:$PATH        # put this in your login shell's startup file ``` -Either way, check with:+**Windows** — keep the files together in one folder; `crackNum.exe` looks beside+itself for the GUI and the solver before consulting your `PATH`:  ```+> Expand-Archive crackNum-<version>-windows-x86_64.zip -DestinationPath .+> cd crackNum-<version>-windows-x86_64+> New-Item -ItemType Directory -Force $env:USERPROFILE\bin+> Copy-Item * $env:USERPROFILE\bin+```++Then add that folder to your `PATH` and open a new terminal, since a `PATH` change+does not reach terminals that are already running. The binaries are not code-signed,+so the first run may raise a SmartScreen prompt; choose "More info" then "Run+anyway", or tick "Unblock" in the .zip's Properties before extracting.++Any of the three, check with:++``` $ crackNum -fsp 3.5 $ crackNum --gui ```@@ -411,7 +427,7 @@ the same formats.  If you installed from a [release bundle](#prebuilt-binaries-nothing-to-build-no-haskell-toolchain)-the GUI is already in it, and there is nothing to build on either platform. The rest+the GUI is already in it, and there is nothing to build on any of the three. The rest of this section is for installing from Hackage or from a source checkout.  **macOS** — a native Swift/AppKit app (`GUI/swiftGUI/`). It is not part of the@@ -437,7 +453,21 @@ script, either put it on your PATH as `crackNum.tcl`, or point at it directly with `CRACKNUM_TCL=/path/to/crackNum.tcl`. -On both platforms, launch the GUI from the command line via the `--gui` option,+**Windows** — a native WinForms app (`GUI/winGUI/`). It targets .NET Framework 4.8,+which ships as part of Windows 10 and 11, so the built executable needs no runtime+install. Like the macOS app it is not part of the Hackage package; building it+needs a clone and the .NET SDK:++```+> git clone https://github.com/LeventErkok/crackNum.git+> cd crackNum\GUI\winGUI+> dotnet build -c Release+```++Put the resulting `CrackNumGUI.exe` next to `crackNum.exe`, or point at it with+`CRACKNUM_GUI=C:\path\to\CrackNumGUI.exe`.++On all three platforms, launch the GUI from the command line via the `--gui` option, which forwards any format/rounding flags and value to the app:  ```
crackNum.cabal view
@@ -1,15 +1,15 @@ Cabal-version      : 2.2 Name               : crackNum-Version            : 3.31+Version            : 4.0 Synopsis           : Crack various integer and floating-point data formats Description        : Crack IEEE-754 and other float formats and arbitrary sized words and integers, showing the layout.-                     Along with a command-line interface on any platform, native MacOS and Tcl-based Linux GUIs are available as well:+                     Along with a command-line interface on any platform, native MacOS and Windows GUIs and a Tcl-based Linux GUI are available as well:                      .                      <<https://raw.githubusercontent.com/LeventErkok/crackNum/master/crackNumGUI.png>>                      .                      For details, please see: <http://github.com/LeventErkok/crackNum/>. See the                      <https://github.com/LeventErkok/crackNum/releases releases page>-                     for binary releases for Mac and Linux.+                     for binary releases for Mac, Linux, and Windows. License            : BSD-3-Clause License-file       : LICENSE Author             : Levent Erkok
src/CrackNum/GUI.hs view
@@ -19,7 +19,7 @@ import System.Environment (lookupEnv, getExecutablePath) import System.Exit        (ExitCode(..)) import System.FilePath    (takeDirectory, (</>))-import System.Process     (rawSystem)+import System.Process     (rawSystem, spawnProcess) import qualified System.Info as Info  import Paths_crackNum (getDataFileName)@@ -31,6 +31,26 @@ tclRelPath :: FilePath tclRelPath = "GUI/tclGUI/crackNum.tcl" +-- | The Windows GUI executable. Note the name: Windows file systems are+-- case-insensitive, so calling it CrackNum.exe would make it the very same file as+-- the crackNum.exe it drives, and the two cannot share a directory.+winGUIExe :: FilePath+winGUIExe = "CrackNumGUI.exe"++-- | Where a file would sit if it were next to the running executable.+--+-- NB. getExecutablePath resolves symlinks, so this finds the file even when the+-- binary is reached through a link from elsewhere on the PATH.+besideExe :: FilePath -> IO FilePath+besideExe f = do exe <- getExecutablePath+                 pure (takeDirectory exe </> f)++-- | The first candidate that exists; if none do, die with the given message.+search :: [FilePath] -> [String] -> IO FilePath+search []     onFail = die onFail+search (c:cs) onFail = do ok <- doesFileExist c+                          if ok then pure c else search cs onFail+ -- | Locate the Tcl/Tk GUI script. Normally it is installed together with the -- binary, so this just works; we look in four places, in order: --@@ -50,22 +70,13 @@                                            , ""                                            , "    " ++ p                                            ]-                 Nothing -> do beside    <- besideExe+                 Nothing -> do beside    <- besideExe "crackNum.tcl"                                installed <- getDataFileName tclRelPath                                mbPath    <- findExecutable "crackNum.tcl"                                case mbPath of                                  Just p  -> pure p                                  Nothing -> search [beside, installed] (noTcl beside installed)-  where -- NB. getExecutablePath resolves symlinks, so this finds the script even-        -- when the binary is reached through a link from elsewhere on the PATH.-        besideExe = do exe <- getExecutablePath-                       pure (takeDirectory exe </> "crackNum.tcl")--        search []     onFail = die onFail-        search (c:cs) onFail = do ok <- doesFileExist c-                                  if ok then pure c else search cs onFail--        noTcl beside installed =+  where noTcl beside installed =              [ "Cannot find the CrackNum GUI script (crackNum.tcl)."              , ""              , "Looked in:"@@ -87,13 +98,58 @@              , "    git clone http://github.com/LeventErkok/crackNum.git"              ] +-- | Locate the Windows GUI executable, mirroring 'locateTcl'. We look in three+-- places, in order:+--+--   1. $CRACKNUM_GUI, if set: an explicit override, as on macOS.+--   2. Next to the executable itself, which is how the binary zip is laid out.+--   3. The PATH, for an installation that puts the two elsewhere.+locateWinGUI :: IO FilePath+locateWinGUI = do mbEnv <- lookupEnv "CRACKNUM_GUI"+                  case mbEnv of+                    Just p  -> do ok <- doesFileExist p+                                  if ok+                                     then pure p+                                     else die [ "The CRACKNUM_GUI environment variable is set, but does not name a file:"+                                              , ""+                                              , "    " ++ p+                                              ]+                    Nothing -> do beside <- besideExe winGUIExe+                                  ok     <- doesFileExist beside+                                  if ok+                                     then pure beside+                                     else do mbPath <- findExecutable winGUIExe+                                             case mbPath of+                                               Just p  -> pure p+                                               Nothing -> die (noGUI beside)+  where noGUI beside =+             [ "Cannot find the CrackNum GUI (" ++ winGUIExe ++ ")."+             , ""+             , "Looked in:"+             , "  %CRACKNUM_GUI%                (not set)"+             , "  " ++ beside+             , "  " ++ winGUIExe ++ " on your PATH  (not found)"+             , ""+             , "The GUI ships in the same zip as crackNum.exe, so seeing this means the"+             , "copy next to the binary is missing or the binary has been moved."+             , ""+             , "Get the Windows bundle from:"+             , ""+             , "    https://github.com/LeventErkok/crackNum/releases"+             , ""+             , "Or point at a copy directly:"+             , ""+             , "    $env:CRACKNUM_GUI = \"C:\\path\\to\\" ++ winGUIExe ++ "\""+             ]+ -- | Launch the graphical interface, forwarding all remaining arguments -- (format flags, rounding mode, and/or the value to crack) so the GUI can preselect -- them. The GUI itself calls back into this executable to do the actual cracking. -- -- On macOS the GUI is a Swift/AppKit app; CRACKNUM_GUI can override the .app bundle -- location. On Linux the GUI is a Tcl/Tk script; 'wish' is located via PATH, and--- 'crackNum.tcl' via 'locateTcl'.+-- 'crackNum.tcl' via 'locateTcl'. On Windows it is a WinForms app located by+-- 'locateWinGUI', with CRACKNUM_GUI overriding as it does on macOS. launchGUI :: [String] -> IO () launchGUI vals   | Info.os == "darwin"@@ -134,6 +190,13 @@                               , ""                               , "Tried: " ++ wish ++ " " ++ tcl                               ]+  | Info.os == "mingw32"+  = do gui <- locateWinGUI+       -- Spawned rather than run through rawSystem: the GUI outlives this process,+       -- matching what 'open -n' gives us on macOS. Waiting would pin the console+       -- for as long as the window stayed open.+       _   <- spawnProcess gui vals+       pure ()   | True   = die [ "The --gui option is not supported on this platform (" ++ Info.os ++ ")."         , "Use crackNum directly from the command line."
src/CrackNum/Main.hs view
@@ -21,6 +21,7 @@ import qualified Control.Exception as C  import System.Environment    (getArgs, getProgName, withArgs)+import System.FilePath       (dropExtension) import System.Console.GetOpt (ArgOrder(Permute), getOpt) import System.Exit           (exitFailure) @@ -42,7 +43,11 @@ -- | main entry point to crackNum main :: IO () main = do argv <- getArgs-          pn   <- getProgName++          -- dropExtension: on Windows getProgName keeps the .exe, which would put+          -- "crackNum.exe" in the --version banner and every usage message, where+          -- the other platforms say "crackNum".+          pn   <- dropExtension <$> getProgName            let rt = "--runTests" 
src/CrackNum/TestSuite.hs view
@@ -22,6 +22,7 @@ import System.FilePath  import System.Directory (removeFile)+import System.IO (IOMode(WriteMode), hPutStr, hSetNewlineMode, noNewlineTranslation, withFile) import System.Process (readProcessWithExitCode)  import Data.List (intercalate)@@ -35,12 +36,17 @@          args = words as +        -- NB. Written with newline translation off, so the temp file uses LF on+        -- every platform. The golds are LF; plain writeFile would emit CRLF on+        -- Windows, and --accept there would rewrite every gold in the process.+        write f s = withFile f WriteMode $ \h -> hSetNewlineMode h noNewlineTranslation >> hPutStr h s+         run = do (ec, so, se) <- readProcessWithExitCode "crackNum" args ""-                 writeFile gfTmp $ intercalate "\n" $ [ "Arguments: " ++ as-                                                      , "Exit code: " ++ show ec-                                                      , so-                                                      ]-                                                      ++ concat [["STDERR:", se] | not (null se)]+                 write gfTmp $ intercalate "\n" $ [ "Arguments: " ++ as+                                                  , "Exit code: " ++ show ec+                                                  , so+                                                  ]+                                                  ++ concat [["STDERR:", se] | not (null se)]          diff ref new = ["diff", "-w", "-u", ref, new]