packages feed

shell-escape 0.1.2 → 0.2.0

raw patch · 15 files changed

+265/−248 lines, 15 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.ByteString.ShellEscape: bash :: ByteString -> Bash
+ Data.ByteString.ShellEscape: bytes :: Escape t => t -> ByteString
+ Data.ByteString.ShellEscape: class Escape t
+ Data.ByteString.ShellEscape: data Bash
+ Data.ByteString.ShellEscape: data Sh
+ Data.ByteString.ShellEscape: escape :: Escape t => ByteString -> t
+ Data.ByteString.ShellEscape: sh :: ByteString -> Sh
+ Data.ByteString.ShellEscape: unescape :: Escape t => t -> ByteString

Files

+ Data/ByteString/ShellEscape.hs view
@@ -0,0 +1,16 @@++{-| Typed shell escaping for Bourne Shell and Bash.+ -}++module Data.ByteString.ShellEscape+  ( Data.ByteString.ShellEscape.Escape.Escape(..)+  , Data.ByteString.ShellEscape.Sh.Sh()+  , Data.ByteString.ShellEscape.Sh.sh+  , Data.ByteString.ShellEscape.Bash.Bash()+  , Data.ByteString.ShellEscape.Bash.bash+  ) where++import Data.ByteString.ShellEscape.Escape+import Data.ByteString.ShellEscape.Sh+import Data.ByteString.ShellEscape.Bash+
+ Data/ByteString/ShellEscape/Bash.hs view
@@ -0,0 +1,78 @@++module Data.ByteString.ShellEscape.Bash where++import Data.Maybe+import Data.Char+import Text.Printf+import Data.ByteString (ByteString)++import qualified Data.Vector as Vector++import Data.ByteString.ShellEscape.Escape+import qualified Data.ByteString.ShellEscape.Put as Put+import Data.ByteString.ShellEscape.EscapeVector++{-| A Bash escaped 'ByteString'. The strings are wrapped in @$\'...\'@ if any+    bytes within them must be escaped; otherwise, they are left as is.+    Newlines and other control characters are represented as ANSI escape+    sequences. High bytes are represented as hex codes. Thus Bash escaped+    strings will always fit on one line and never contain non-ASCII bytes.+ -}+newtype Bash                 =  Bash (EscapeVector EscapingMode)+ deriving (Eq, Ord, Show)++{-| Construct a Bash escaped intermediate form.+ -}+bash                        ::  ByteString -> Bash+bash                         =  escape++instance Escape Bash where+  escape                     =  Bash . escWith classify+  unescape (Bash v)          =  stripEsc v+  bytes (Bash v) | literal v =  stripEsc v+                 | otherwise =  interpretEsc v renderANSI' end (begin, Literal)+   where+    literal                  =  isNothing . Vector.find ((/= Literal) . snd)+    begin                    =  [      Put.putString "$'"]+    end                      =  const (Put.putChar '\'')+    renderANSI' _ (c, e)     =  (renderANSI c, e)+++{-| Bash escaping modes.+ -}+data EscapingMode            =  ANSIHex | ANSIBackslash | Literal | Quoted+ deriving (Eq, Ord, Show)++renderANSI c =+  case classify c of+    Literal                 ->  Put.putChar     c+    Quoted                  ->  Put.putChar     c+    ANSIHex                 ->  Put.putString $ hexify c+    ANSIBackslash           ->  Put.putString $ backslashify c++backslashify                ::  Char -> String+backslashify c               =  (take 2 . drop 1 . show) c++hexify                      ::  Char -> String+hexify                       =  printf "\\x%02X" . ord++classify                    ::  Char -> EscapingMode+classify c | c <= '\ACK'     =  ANSIHex+           | c <= '\r'       =  ANSIBackslash+           | c <= '\US'      =  ANSIHex+           | c <= '&'        =  Quoted+           | c == '\''       =  ANSIBackslash+           | c <= '+'        =  Quoted+           | c <= '9'        =  Literal+           | c <= '?'        =  Quoted+           | c <= 'Z'        =  Literal+           | c == '['        =  Quoted+           | c == '\\'       =  ANSIBackslash+           | c <= ']'        =  Quoted+           | c == '_'        =  Literal+           | c <= '`'        =  Quoted+           | c <= 'z'        =  Literal+           | c <= '~'        =  Quoted+           | c == '\DEL'     =  ANSIHex+           | otherwise       =  ANSIHex+
+ Data/ByteString/ShellEscape/Escape.hs view
@@ -0,0 +1,21 @@++module Data.ByteString.ShellEscape.Escape where++import Data.ByteString++{-| A type class for objects that represent an intermediate state of+    escaping.+ -}+class Escape t where+  -- |    Transform a 'ByteString' into the escaped intermediate form.+  escape                    ::  ByteString -> t+  -- |    Recover the original 'ByteString'.+  unescape                  ::  t -> ByteString+  -- |    Yield the escaped 'ByteString'.+  bytes                     ::  t -> ByteString++instance Escape ByteString where+  escape                     =  id+  unescape                   =  id+  bytes                      =  id+
+ Data/ByteString/ShellEscape/EscapeVector.hs view
@@ -0,0 +1,39 @@++module Data.ByteString.ShellEscape.EscapeVector where++import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as ByteString++import Data.Vector (Vector)+import qualified Data.Vector as Vector+import qualified Data.Vector.Mutable as Vector (new, write)++import qualified Data.ByteString.ShellEscape.Put as Put+++type EscapeVector escapingMode = Vector (Char, escapingMode)++escWith :: (Char -> escapingMode) -> ByteString -> EscapeVector escapingMode+escWith cf b                 =  Vector.create $ do+  v                         <-  Vector.new (ByteString.length b)+  sequence_ . snd $ ByteString.foldl' (f v) (0, []) b+  return v+ where+  f v (i, ops) c             =  (i + 1, Vector.write v i (c, cf c) : ops)+++stripEsc                    ::  Vector (Char, escapingMode) -> ByteString+stripEsc v                   =  ByteString.unfoldr f . fst $ Vector.unzip v+ where+  f v | Vector.null v        =  Nothing+      | otherwise            =  Just (Vector.unsafeHead v, Vector.unsafeTail v)++interpretEsc v f finish init =  (eval . (finish lastMode :)) instructions+ where+  eval                       =  Put.runPut' . sequence_ . reverse+  (instructions, lastMode)   =  Vector.foldl' f' init v+   where+    f' (list, mode) (c, e)   =  (put:list, mode')+     where+      (put, mode')           =  f mode (c, e)+
+ Data/ByteString/ShellEscape/Put.hs view
@@ -0,0 +1,24 @@++module Data.ByteString.ShellEscape.Put+  ( module Data.Binary.Put+  , putChar+  , putString+  , runPut'+  ) where++import Prelude hiding (putChar)+import Data.Binary.Put+import Data.Char+import Data.ByteString.Lazy+import Data.ByteString+import Data.ByteString.Char8++putChar                     ::  Char -> Put+putChar                      =  putWord8 . toEnum . fromEnum++putString                   ::  String -> Put+putString                    =  putByteString . Data.ByteString.Char8.pack++runPut'                     ::  Put -> Data.ByteString.ByteString+runPut' = Data.ByteString.concat . Data.ByteString.Lazy.toChunks . runPut +
+ Data/ByteString/ShellEscape/Sh.hs view
@@ -0,0 +1,69 @@++module Data.ByteString.ShellEscape.Sh where++import Data.ByteString (ByteString)++import Data.ByteString.ShellEscape.Escape+import qualified Data.ByteString.ShellEscape.Put as Put+import Data.ByteString.ShellEscape.EscapeVector+++{-| A Bourne Shell escaped 'ByteString'. An oddity of Bourne shell escaping is+    the absence of escape codes for newline and other ASCII control+    characters. These bytes are simply placed literally in single quotes; the+    effect is that a Bourne Shell escaped string may cover several lines and+    contain non-ASCII bytes. Runs of bytes that must be escaped are wrapped in+    @\'...\'@; bytes that are acceptable as literals in Bourne Shell are left+    as is.+ -}+newtype Sh                   =  Sh (EscapeVector EscapingMode)+ deriving (Eq, Ord, Show)++{-| Construct a Bourne Shell escaped intermediate form.+ -}+sh                          ::  ByteString -> Sh+sh                           =  escape++instance Escape Sh where+  escape                     =  Sh . escWith classify+  unescape (Sh v)            =  stripEsc v+  bytes (Sh v)               =  interpretEsc v act finish ([], Literal)+   where+    finish Quote             =  Put.putChar '\''+    finish Backslash         =  Put.putChar '\\'+    finish Literal           =  return ()+++{-| Accept the present escaping mode and desired escaping mode and yield an+    action and the resulting mode.+ -}+act :: EscapingMode -> (Char, EscapingMode) -> (Put.Put, EscapingMode)+act Quote (c, Quote)         =  (Put.putChar c                 , Quote)+act Quote (c, Literal)       =  (Put.putChar c                 , Quote)+act Quote (c, Backslash)     =  (Put.putString ['\'', '\\', c] , Literal)+act Backslash (c, Backslash) =  (Put.putChar c                 , Literal)+act Backslash (c, Quote)     =  (Put.putString ['\\', '\'', c] , Quote)+act Backslash (c, Literal)   =  (Put.putString ['\\', c]       , Literal)+act Literal (c, Literal)     =  (Put.putChar c                 , Literal)+act Literal (c, Backslash)   =  (Put.putString ['\\', c]       , Literal)+act Literal (c, Quote)       =  (Put.putString ['\'', c]       , Quote)++classify                    ::  Char -> EscapingMode+classify c | c <= '&'        =  Quote           --  0x00..0x26+           | c == '\''       =  Backslash       --  0x27+           | c <= ','        =  Quote           --  0x28..0x2c+           | c <= '9'        =  Literal         --  0x2d..0x39+           | c <= '?'        =  Quote           --  0x3a..0x3f+           | c <= 'Z'        =  Literal         --  0x40..0x5a+           | c <= '^'        =  Quote           --  0x5b..0x5e+           | c == '_'        =  Literal         --  0x5f+           | c == '`'        =  Quote           --  0x60+           | c <= 'z'        =  Literal         --  0x61..0x7a+           | c <= '\DEL'     =  Quote           --  0x7b..0x7f+           | otherwise       =  Quote           --  0x80..0xff++{-| Bourne Shell escaping modes. + -}+data EscapingMode            =  Backslash | Literal | Quote+ deriving (Eq, Ord, Show)+
Text/ShellEscape.hs view
@@ -3,14 +3,14 @@  -}  module Text.ShellEscape-  ( Text.ShellEscape.Escape.Escape(..)-  , Text.ShellEscape.Sh.Sh()-  , Text.ShellEscape.Sh.sh-  , Text.ShellEscape.Bash.Bash()-  , Text.ShellEscape.Bash.bash+  ( Data.ByteString.ShellEscape.Escape.Escape(..)+  , Data.ByteString.ShellEscape.Sh.Sh()+  , Data.ByteString.ShellEscape.Sh.sh+  , Data.ByteString.ShellEscape.Bash.Bash()+  , Data.ByteString.ShellEscape.Bash.bash   ) where -import Text.ShellEscape.Escape-import Text.ShellEscape.Sh-import Text.ShellEscape.Bash+import Data.ByteString.ShellEscape.Escape+import Data.ByteString.ShellEscape.Sh+import Data.ByteString.ShellEscape.Bash 
− Text/ShellEscape/Bash.hs
@@ -1,78 +0,0 @@--module Text.ShellEscape.Bash where--import Data.Maybe-import Data.Char-import Text.Printf-import Data.ByteString (ByteString)--import qualified Data.Vector as Vector--import Text.ShellEscape.Escape-import qualified Text.ShellEscape.Put as Put-import Text.ShellEscape.EscapeVector--{-| A Bash escaped 'ByteString'. The strings are wrapped in @$\'...\'@ if any-    bytes within them must be escaped; otherwise, they are left as is.-    Newlines and other control characters are represented as ANSI escape-    sequences. High bytes are represented as hex codes. Thus Bash escaped-    strings will always fit on one line and never contain non-ASCII bytes.- -}-newtype Bash                 =  Bash (EscapeVector EscapingMode)- deriving (Eq, Ord, Show)--{-| Construct a Bash escaped intermediate form.- -}-bash                        ::  ByteString -> Bash-bash                         =  escape--instance Escape Bash where-  escape                     =  Bash . escWith classify-  unescape (Bash v)          =  stripEsc v-  bytes (Bash v) | literal v =  stripEsc v-                 | otherwise =  interpretEsc v renderANSI' end (begin, Literal)-   where-    literal                  =  isNothing . Vector.find ((/= Literal) . snd)-    begin                    =  [      Put.putString "$'"]-    end                      =  const (Put.putChar '\'')-    renderANSI' _ (c, e)     =  (renderANSI c, e)---{-| Bash escaping modes.- -}-data EscapingMode            =  ANSIHex | ANSIBackslash | Literal | Quoted- deriving (Eq, Ord, Show)--renderANSI c =-  case classify c of-    Literal                 ->  Put.putChar     c-    Quoted                  ->  Put.putChar     c-    ANSIHex                 ->  Put.putString $ hexify c-    ANSIBackslash           ->  Put.putString $ backslashify c--backslashify                ::  Char -> String-backslashify c               =  (take 2 . drop 1 . show) c--hexify                      ::  Char -> String-hexify                       =  printf "\\x%02X" . ord--classify                    ::  Char -> EscapingMode-classify c | c <= '\ACK'     =  ANSIHex-           | c <= '\r'       =  ANSIBackslash-           | c <= '\US'      =  ANSIHex-           | c <= '&'        =  Quoted-           | c == '\''       =  ANSIBackslash-           | c <= '+'        =  Quoted-           | c <= '9'        =  Literal-           | c <= '?'        =  Quoted-           | c <= 'Z'        =  Literal-           | c == '['        =  Quoted-           | c == '\\'       =  ANSIBackslash-           | c <= ']'        =  Quoted-           | c == '_'        =  Literal-           | c <= '`'        =  Quoted-           | c <= 'z'        =  Literal-           | c <= '~'        =  Quoted-           | c == '\DEL'     =  ANSIHex-           | otherwise       =  ANSIHex-
− Text/ShellEscape/Escape.hs
@@ -1,21 +0,0 @@--module Text.ShellEscape.Escape where--import Data.ByteString--{-| A type class for objects that represent an intermediate state of-    escaping.- -}-class Escape t where-  -- |    Transform a 'ByteString' into the escaped intermediate form.-  escape                    ::  ByteString -> t-  -- |    Recover the original 'ByteString'.-  unescape                  ::  t -> ByteString-  -- |    Yield the escaped 'ByteString'.-  bytes                     ::  t -> ByteString--instance Escape ByteString where-  escape                     =  id-  unescape                   =  id-  bytes                      =  id-
− Text/ShellEscape/EscapeVector.hs
@@ -1,39 +0,0 @@--module Text.ShellEscape.EscapeVector where--import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Char8 as ByteString--import Data.Vector (Vector)-import qualified Data.Vector as Vector-import qualified Data.Vector.Mutable as Vector (new, write)--import qualified Text.ShellEscape.Put as Put---type EscapeVector escapingMode = Vector (Char, escapingMode)--escWith :: (Char -> escapingMode) -> ByteString -> EscapeVector escapingMode-escWith cf b                 =  Vector.create $ do-  v                         <-  Vector.new (ByteString.length b)-  sequence_ . snd $ ByteString.foldl' (f v) (0, []) b-  return v- where-  f v (i, ops) c             =  (i + 1, Vector.write v i (c, cf c) : ops)---stripEsc                    ::  Vector (Char, escapingMode) -> ByteString-stripEsc v                   =  ByteString.unfoldr f . fst $ Vector.unzip v- where-  f v | Vector.null v        =  Nothing-      | otherwise            =  Just (Vector.unsafeHead v, Vector.unsafeTail v)--interpretEsc v f finish init =  (eval . (finish lastMode :)) instructions- where-  eval                       =  Put.runPut' . sequence_ . reverse-  (instructions, lastMode)   =  Vector.foldl' f' init v-   where-    f' (list, mode) (c, e)   =  (put:list, mode')-     where-      (put, mode')           =  f mode (c, e)-
− Text/ShellEscape/Put.hs
@@ -1,24 +0,0 @@--module Text.ShellEscape.Put-  ( module Data.Binary.Put-  , putChar-  , putString-  , runPut'-  ) where--import Prelude hiding (putChar)-import Data.Binary.Put-import Data.Char-import Data.ByteString.Lazy-import Data.ByteString-import Data.ByteString.Char8--putChar                     ::  Char -> Put-putChar                      =  putWord8 . toEnum . fromEnum--putString                   ::  String -> Put-putString                    =  putByteString . Data.ByteString.Char8.pack--runPut'                     ::  Put -> Data.ByteString.ByteString-runPut' = Data.ByteString.concat . Data.ByteString.Lazy.toChunks . runPut -
− Text/ShellEscape/Sh.hs
@@ -1,69 +0,0 @@--module Text.ShellEscape.Sh where--import Data.ByteString (ByteString)--import Text.ShellEscape.Escape-import qualified Text.ShellEscape.Put as Put-import Text.ShellEscape.EscapeVector---{-| A Bourne Shell escaped 'ByteString'. An oddity of Bourne shell escaping is-    the absence of escape codes for newline and other ASCII control-    characters. These bytes are simply placed literally in single quotes; the-    effect is that a Bourne Shell escaped string may cover several lines and-    contain non-ASCII bytes. Runs of bytes that must be escaped are wrapped in-    @\'...\'@; bytes that are acceptable as literals in Bourne Shell are left-    as is.- -}-newtype Sh                   =  Sh (EscapeVector EscapingMode)- deriving (Eq, Ord, Show)--{-| Construct a Bourne Shell escaped intermediate form.- -}-sh                          ::  ByteString -> Sh-sh                           =  escape--instance Escape Sh where-  escape                     =  Sh . escWith classify-  unescape (Sh v)            =  stripEsc v-  bytes (Sh v)               =  interpretEsc v act finish ([], Literal)-   where-    finish Quote             =  Put.putChar '\''-    finish Backslash         =  Put.putChar '\\'-    finish Literal           =  return ()---{-| Accept the present escaping mode and desired escaping mode and yield an-    action and the resulting mode.- -}-act :: EscapingMode -> (Char, EscapingMode) -> (Put.Put, EscapingMode)-act Quote (c, Quote)         =  (Put.putChar c                 , Quote)-act Quote (c, Literal)       =  (Put.putChar c                 , Quote)-act Quote (c, Backslash)     =  (Put.putString ['\'', '\\', c] , Literal)-act Backslash (c, Backslash) =  (Put.putChar c                 , Literal)-act Backslash (c, Quote)     =  (Put.putString ['\\', '\'', c] , Quote)-act Backslash (c, Literal)   =  (Put.putString ['\\', c]       , Literal)-act Literal (c, Literal)     =  (Put.putChar c                 , Literal)-act Literal (c, Backslash)   =  (Put.putString ['\\', c]       , Literal)-act Literal (c, Quote)       =  (Put.putString ['\'', c]       , Quote)--classify                    ::  Char -> EscapingMode-classify c | c <= '&'        =  Quote           --  0x00..0x26-           | c == '\''       =  Backslash       --  0x27-           | c <= ','        =  Quote           --  0x28..0x2c-           | c <= '9'        =  Literal         --  0x2d..0x39-           | c <= '?'        =  Quote           --  0x3a..0x3f-           | c <= 'Z'        =  Literal         --  0x40..0x5a-           | c <= '^'        =  Quote           --  0x5b..0x5e-           | c == '_'        =  Literal         --  0x5f-           | c == '`'        =  Quote           --  0x60-           | c <= 'z'        =  Literal         --  0x61..0x7a-           | c <= '\DEL'     =  Quote           --  0x7b..0x7f-           | otherwise       =  Quote           --  0x80..0xff--{-| Bourne Shell escaping modes. - -}-data EscapingMode            =  Backslash | Literal | Quote- deriving (Eq, Ord, Show)-
bench/Bench.hs view
@@ -6,7 +6,7 @@  import Criterion.Main -import Text.ShellEscape+import Data.ByteString.ShellEscape   strings                     ::  [ByteString]
shell-escape.cabal view
@@ -1,5 +1,5 @@ name                          : shell-escape-version                       : 0.1.2+version                       : 0.2.0 category                      : Text license                       : BSD3 license-file                  : LICENSE@@ -24,10 +24,11 @@                               , containers                               , vector >= 0.6.0.2                               , bytestring >= 0.9-  exposed-modules             : Text.ShellEscape-  other-modules               : Text.ShellEscape.Escape-                                Text.ShellEscape.EscapeVector-                                Text.ShellEscape.Sh-                                Text.ShellEscape.Bash-                                Text.ShellEscape.Put+  exposed-modules             : Data.ByteString.ShellEscape+                                Text.ShellEscape+  other-modules               : Data.ByteString.ShellEscape.Escape+                                Data.ByteString.ShellEscape.EscapeVector+                                Data.ByteString.ShellEscape.Sh+                                Data.ByteString.ShellEscape.Bash+                                Data.ByteString.ShellEscape.Put 
test/Echo.hs view
@@ -18,7 +18,7 @@ import Test.QuickCheck import Test.QuickCheck.Monadic -import Text.ShellEscape hiding (sh, bash)+import Data.ByteString.ShellEscape hiding (sh, bash)   --  It is best to implement the echo test with `printf':