{-# LANGUAGE OverloadedStrings #-}

module Development.NSIS.Library where

import Control.Monad
import Development.NSIS.Sugar


-- | Replace one string with another string, in a target string. As some examples:
--
-- > strReplace "t" "XX" "test" %== "XXesXX"
-- > strReplace "ell" "" "hello world" %== "ho world"
strReplace :: Exp String -> Exp String -> Exp String -> Exp String
strReplace :: Exp String -> Exp String -> Exp String -> Exp String
strReplace Exp String
from Exp String
to Exp String
str = do
    Exp String
from <- Exp String -> Action (Exp String)
forall t. Exp t -> Action (Exp t)
constant_ Exp String
from
    Exp String
to <- Exp String -> Action (Exp String)
forall t. Exp t -> Action (Exp t)
constant_ Exp String
to
    Exp String
str <- Exp String -> Action (Exp String)
forall t. Exp t -> Action (Exp t)
constant_ Exp String
str
    Exp String -> Exp String
forall a. Action a -> Action a
scope (Exp String -> Exp String) -> Exp String -> Exp String
forall a b. (a -> b) -> a -> b
$ do
        Exp String
rest <- String -> Exp String -> Action (Exp String)
forall t. Typeable t => String -> Exp t -> Action (Exp t)
mutable String
"REST" Exp String
str
        Exp String
res <- String -> Exp String -> Action (Exp String)
forall t. Typeable t => String -> Exp t -> Action (Exp t)
mutable String
"RES" Exp String
""
        Exp Bool -> Action () -> Action ()
while (Exp String
rest Exp String -> Exp String -> Exp Bool
forall a. Exp a -> Exp a -> Exp Bool
%/= Exp String
"") (Action () -> Action ()) -> Action () -> Action ()
forall a b. (a -> b) -> a -> b
$ do
            Exp Bool -> Action () -> Action () -> Action ()
iff (Exp String
from Exp String -> Exp String -> Exp Bool
`strIsPrefixOf` Exp String
rest)
                (do
                    Exp String
res Exp String -> Exp String -> Action ()
forall t. Exp t -> Exp t -> Action ()
@= Exp String
res Exp String -> Exp String -> Exp String
& Exp String
to
                    Exp String
rest Exp String -> Exp String -> Action ()
forall t. Exp t -> Exp t -> Action ()
@= Exp Int -> Exp String -> Exp String
strDrop (Exp String -> Exp Int
strLength Exp String
from) Exp String
rest)
                (do
                    Exp String
res Exp String -> Exp String -> Action ()
forall t. Exp t -> Exp t -> Action ()
@= Exp String
res Exp String -> Exp String -> Exp String
& Exp Int -> Exp String -> Exp String
strTake Exp Int
1 Exp String
rest
                    Exp String
rest Exp String -> Exp String -> Action ()
forall t. Exp t -> Exp t -> Action ()
@= Exp Int -> Exp String -> Exp String
strDrop Exp Int
1 Exp String
rest)
        Exp String
res

-- | NSIS (the underlying installer, not this library) uses fixed length string buffers,
--   defaulting to 1024 bytes. Any strings longer than
--   the limit may cause truncation or segfaults. You can get builds supporting longer strings
--   from <http://nsis.sourceforge.net/Special_Builds>.
--
--   Given @strCheck msg val@, if @val@ exceeds the limit it will 'abort' with @msg@, otherwise
--   it will return 'val'.
strCheck :: Exp String -> Exp String -> Exp String
strCheck :: Exp String -> Exp String -> Exp String
strCheck Exp String
msg Exp String
x = Exp String -> (Exp String -> Exp String) -> Exp String
forall t a. Exp t -> (Exp t -> Action a) -> Action a
share Exp String
x ((Exp String -> Exp String) -> Exp String)
-> (Exp String -> Exp String) -> Exp String
forall a b. (a -> b) -> a -> b
$ \Exp String
x -> do
    let special :: Exp String
special = Exp String
"@!!_NSIS"
    Exp Bool -> Action () -> Action ()
iff_ (Exp Bool -> Exp Bool
not_ (Exp Bool -> Exp Bool) -> Exp Bool -> Exp Bool
forall a b. (a -> b) -> a -> b
$ Exp String
special Exp String -> Exp String -> Exp Bool
`strIsSuffixOf` (Exp String
x Exp String -> Exp String -> Exp String
& Exp String
special)) (Action () -> Action ()) -> Action () -> Action ()
forall a b. (a -> b) -> a -> b
$ do
        Action (Exp String) -> Action ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Action (Exp String) -> Action ())
-> Action (Exp String) -> Action ()
forall a b. (a -> b) -> a -> b
$ [MessageBoxType] -> Exp String -> Action (Exp String)
messageBox [MessageBoxType
MB_ICONSTOP] (Exp String -> Action (Exp String))
-> Exp String -> Action (Exp String)
forall a b. (a -> b) -> a -> b
$ Exp String
"ERROR: String limit exceeded,\n" Exp String -> Exp String -> Exp String
& Exp String
msg
        Exp String -> Action ()
abort (Exp String -> Action ()) -> Exp String -> Action ()
forall a b. (a -> b) -> a -> b
$ Exp String
"ERROR: String limit exceeded, " Exp String -> Exp String -> Exp String
& Exp String
msg
    Exp String
x


-- | Is the first string a prefix of the second.
strIsPrefixOf :: Exp String -> Exp String -> Exp Bool
strIsPrefixOf :: Exp String -> Exp String -> Exp Bool
strIsPrefixOf Exp String
x Exp String
y = Exp String -> (Exp String -> Exp Bool) -> Exp Bool
forall t a. Exp t -> (Exp t -> Action a) -> Action a
share Exp String
x ((Exp String -> Exp Bool) -> Exp Bool)
-> (Exp String -> Exp Bool) -> Exp Bool
forall a b. (a -> b) -> a -> b
$ \Exp String
x -> Exp String -> (Exp String -> Exp Bool) -> Exp Bool
forall t a. Exp t -> (Exp t -> Action a) -> Action a
share Exp String
y ((Exp String -> Exp Bool) -> Exp Bool)
-> (Exp String -> Exp Bool) -> Exp Bool
forall a b. (a -> b) -> a -> b
$ \Exp String
y ->
    Exp Int -> Exp String -> Exp String
strTake (Exp String -> Exp Int
strLength Exp String
x) Exp String
y Exp String -> Exp String -> Exp Bool
forall a. Exp a -> Exp a -> Exp Bool
%== Exp String
x

-- | Is the first string a prefix of the second.
strIsSuffixOf :: Exp String -> Exp String -> Exp Bool
strIsSuffixOf :: Exp String -> Exp String -> Exp Bool
strIsSuffixOf Exp String
x Exp String
y = Exp String -> (Exp String -> Exp Bool) -> Exp Bool
forall t a. Exp t -> (Exp t -> Action a) -> Action a
share Exp String
x ((Exp String -> Exp Bool) -> Exp Bool)
-> (Exp String -> Exp Bool) -> Exp Bool
forall a b. (a -> b) -> a -> b
$ \Exp String
x -> Exp String -> (Exp String -> Exp Bool) -> Exp Bool
forall t a. Exp t -> (Exp t -> Action a) -> Action a
share Exp String
y ((Exp String -> Exp Bool) -> Exp Bool)
-> (Exp String -> Exp Bool) -> Exp Bool
forall a b. (a -> b) -> a -> b
$ \Exp String
y ->
    Exp Int -> Exp String -> Exp String
strDrop (Exp String -> Exp Int
strLength Exp String
y Exp Int -> Exp Int -> Exp Int
forall a. Num a => a -> a -> a
- Exp String -> Exp Int
strLength Exp String
x) Exp String
y Exp String -> Exp String -> Exp Bool
forall a. Exp a -> Exp a -> Exp Bool
%== Exp String
x


-- | Join together a list of strings with @\\r\\n@ after each line. Note that unlike standard 'unlines',
--   we use the Windows convention line separator.
strUnlines :: [Exp String] -> Exp String
strUnlines :: [Exp String] -> Exp String
strUnlines = [Exp String] -> Exp String
strConcat ([Exp String] -> Exp String)
-> ([Exp String] -> [Exp String]) -> [Exp String] -> Exp String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Exp String -> Exp String) -> [Exp String] -> [Exp String]
forall a b. (a -> b) -> [a] -> [b]
map (Exp String -> Exp String -> Exp String
& Exp String
"\r\n")


-- | Write a file comprising of a set of lines.
writeFileLines :: Exp FilePath -> [Exp String] -> Action ()
writeFileLines :: Exp String -> [Exp String] -> Action ()
writeFileLines Exp String
a [Exp String]
b = FileMode
-> Exp String -> (Exp FileHandle -> Action ()) -> Action ()
withFile' FileMode
ModeWrite Exp String
a ((Exp FileHandle -> Action ()) -> Action ())
-> (Exp FileHandle -> Action ()) -> Action ()
forall a b. (a -> b) -> a -> b
$ \Exp FileHandle
hdl ->
    [Exp String] -> (Exp String -> Action ()) -> Action ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Exp String]
b ((Exp String -> Action ()) -> Action ())
-> (Exp String -> Action ()) -> Action ()
forall a b. (a -> b) -> a -> b
$ \Exp String
s -> Exp FileHandle -> Exp String -> Action ()
fileWrite Exp FileHandle
hdl (Exp String -> Action ()) -> Exp String -> Action ()
forall a b. (a -> b) -> a -> b
$ Exp String
s Exp String -> Exp String -> Exp String
& Exp String
"\r\n"


infixr 3 %&&
infixr 2 %||

-- | Short circuiting boolean operators, equivalent to '&&' and '||' but on 'Exp'.
(%&&), (%||) :: Exp Bool -> Exp Bool -> Exp Bool
%&& :: Exp Bool -> Exp Bool -> Exp Bool
(%&&) Exp Bool
a Exp Bool
b = Exp Bool
a Exp Bool -> (Exp Bool, Exp Bool) -> Exp Bool
forall t. Exp Bool -> (Exp t, Exp t) -> Exp t
? (Exp Bool
b, Exp Bool
false)
%|| :: Exp Bool -> Exp Bool -> Exp Bool
(%||) Exp Bool
a Exp Bool
b = Exp Bool
a Exp Bool -> (Exp Bool, Exp Bool) -> Exp Bool
forall t. Exp Bool -> (Exp t, Exp t) -> Exp t
? (Exp Bool
true, Exp Bool
b)


-- | With a 'fileOpen' perform some action, then automatically call 'fileClose'.
--   If the action argument jumps out of the section then the 'fileClose' call will be missed.
withFile' :: FileMode -> Exp FilePath -> (Exp FileHandle -> Action ()) -> Action ()
withFile' :: FileMode
-> Exp String -> (Exp FileHandle -> Action ()) -> Action ()
withFile' FileMode
mode Exp String
name Exp FileHandle -> Action ()
act = do
    Exp FileHandle
hdl <- FileMode -> Exp String -> Action (Exp FileHandle)
fileOpen FileMode
mode Exp String
name
    Exp FileHandle -> Action ()
act Exp FileHandle
hdl
    Exp FileHandle -> Action ()
fileClose Exp FileHandle
hdl

-- | Write a file, like 'writeFile'.
writeFile' :: Exp FilePath -> Exp String -> Action ()
writeFile' :: Exp String -> Exp String -> Action ()
writeFile' Exp String
name Exp String
contents = FileMode
-> Exp String -> (Exp FileHandle -> Action ()) -> Action ()
withFile' FileMode
ModeWrite Exp String
name ((Exp FileHandle -> Action ()) -> Action ())
-> (Exp FileHandle -> Action ()) -> Action ()
forall a b. (a -> b) -> a -> b
$ \Exp FileHandle
hdl -> Exp FileHandle -> Exp String -> Action ()
fileWrite Exp FileHandle
hdl Exp String
contents