summaryrefslogtreecommitdiff
path: root/Utility/Format.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Utility/Format.hs')
-rw-r--r--Utility/Format.hs46
1 files changed, 31 insertions, 15 deletions
diff --git a/Utility/Format.hs b/Utility/Format.hs
index a2470fa..466988c 100644
--- a/Utility/Format.hs
+++ b/Utility/Format.hs
@@ -1,6 +1,6 @@
{- Formatted string handling.
-
- - Copyright 2010, 2011 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
@@ -9,8 +9,10 @@ module Utility.Format (
Format,
gen,
format,
+ formatContainsVar,
decode_c,
encode_c,
+ encode_c',
prop_encode_c_decode_c_roundtrip
) where
@@ -29,9 +31,14 @@ type FormatString = String
{- A format consists of a list of fragments. -}
type Format = [Frag]
-{- A fragment is either a constant string,
- - or a variable, with a justification. -}
-data Frag = Const String | Var String Justify
+{- A fragment is either a constant string, or a variable. -}
+data Frag
+ = Const String
+ | Var
+ { varName :: String
+ , varJustify :: Justify
+ , varEscaped :: Bool
+ }
deriving (Show)
data Justify = LeftJustified Int | RightJustified Int | UnJustified
@@ -45,10 +52,8 @@ format :: Format -> Variables -> String
format f vars = concatMap expand f
where
expand (Const s) = s
- expand (Var name j)
- | "escaped_" `isPrefixOf` name =
- justify j $ encode_c_strict $
- getvar $ drop (length "escaped_") name
+ expand (Var name j esc)
+ | esc = justify j $ encode_c' isSpace $ getvar name
| otherwise = justify j $ getvar name
getvar name = fromMaybe "" $ M.lookup name vars
justify UnJustified s = s
@@ -61,6 +66,8 @@ format f vars = concatMap expand f
- format string, such as "${foo} ${bar;10} ${baz;-10}\n"
-
- (This is the same type of format string used by dpkg-query.)
+ -
+ - Also, "${escaped_foo}" will apply encode_c to the value of variable foo.
-}
gen :: FormatString -> Format
gen = filter (not . empty) . fuse [] . scan [] . decode_c
@@ -94,12 +101,24 @@ gen = filter (not . empty) . fuse [] . scan [] . decode_c
| i < 0 = LeftJustified (-1 * i)
| otherwise = RightJustified i
novar v = "${" ++ reverse v
- foundvar f v p = scan (Var (reverse v) p : f)
+ foundvar f varname_r p =
+ let varname = reverse varname_r
+ var = if "escaped_" `isPrefixOf` varname
+ then Var (drop (length "escaped_") varname) p True
+ else Var varname p False
+ in scan (var : f)
empty :: Frag -> Bool
empty (Const "") = True
empty _ = False
+{- Check if a Format contains a variable with a specified name. -}
+formatContainsVar :: String -> Format -> Bool
+formatContainsVar v = any go
+ where
+ go (Var v' _ _) | v' == v = True
+ go _ = False
+
{- Decodes a C-style encoding, where \n is a newline (etc),
- \NNN is an octal encoded character, and \xNN is a hex encoded character.
-}
@@ -144,10 +163,7 @@ decode_c s = unescape ("", s)
encode_c :: String -> FormatString
encode_c = encode_c' (const False)
-{- Encodes more strictly, including whitespace. -}
-encode_c_strict :: String -> FormatString
-encode_c_strict = encode_c' isSpace
-
+{- Encodes special characters, as well as any matching the predicate. -}
encode_c' :: (Char -> Bool) -> String -> FormatString
encode_c' p = concatMap echar
where
@@ -165,8 +181,8 @@ encode_c' p = concatMap echar
| ord c < 0x20 = e_asc c -- low ascii
| ord c >= 256 = e_utf c -- unicode
| ord c > 0x7E = e_asc c -- high ascii
- | p c = e_asc c -- unprintable ascii
- | otherwise = [c] -- printable ascii
+ | p c = e_asc c
+ | otherwise = [c]
-- unicode character is decomposed to individual Word8s,
-- and each is shown in octal
e_utf c = showoctal =<< (Codec.Binary.UTF8.String.encode [c] :: [Word8])