Support {n}>&1 named file descriptors.
This commit is contained in:
parent
c808c9b6fe
commit
0f00de80fd
|
@ -582,6 +582,7 @@ prop_checkBashisms24= verifyNot checkBashisms "trap mything int term"
|
|||
prop_checkBashisms25= verify checkBashisms "cat < /dev/tcp/host/123"
|
||||
prop_checkBashisms26= verify checkBashisms "trap mything ERR SIGTERM"
|
||||
prop_checkBashisms27= verify checkBashisms "echo *[^0-9]*"
|
||||
prop_checkBashisms28= verify checkBashisms "exec {n}>&2"
|
||||
checkBashisms _ = bashism
|
||||
where
|
||||
errMsg id s = err id 2040 $ "In sh, " ++ s ++ " not supported, even when sh is actually bash."
|
||||
|
@ -607,6 +608,7 @@ checkBashisms _ = bashism
|
|||
warnMsg id $ filter (/= '|') op ++ " is"
|
||||
bashism (TA_Binary id "**" _ _) = warnMsg id "exponentials are"
|
||||
bashism (T_FdRedirect id "&" (T_IoFile _ (T_Greater _) _)) = warnMsg id "&> is"
|
||||
bashism (T_FdRedirect id ('{':_) _) = warnMsg id "named file descriptors are"
|
||||
bashism (T_IoFile id _ word) | isNetworked =
|
||||
warnMsg id "/dev/{tcp,udp} is"
|
||||
where
|
||||
|
@ -1459,6 +1461,7 @@ isQuoteFreeNode strict tree t =
|
|||
isQuoteFreeElement t =
|
||||
case t of
|
||||
T_Assignment {} -> return True
|
||||
T_FdRedirect {} -> return True
|
||||
_ -> Nothing
|
||||
|
||||
-- Are any subnodes inherently self-quoting?
|
||||
|
@ -2037,6 +2040,7 @@ prop_subshellAssignmentCheck14 = verifyNotTree subshellAssignmentCheck "#!/bin/k
|
|||
prop_subshellAssignmentCheck15 = verifyNotTree subshellAssignmentCheck "#!/bin/ksh\ncat foo | while read bar; do a=$bar; done\necho \"$a\""
|
||||
prop_subshellAssignmentCheck16 = verifyNotTree subshellAssignmentCheck "(set -e); echo $@"
|
||||
prop_subshellAssignmentCheck17 = verifyNotTree subshellAssignmentCheck "foo=${ { bar=$(baz); } 2>&1; }; echo $foo $bar"
|
||||
prop_subshellAssignmentCheck18 = verifyTree subshellAssignmentCheck "( exec {n}>&2; ); echo $n"
|
||||
subshellAssignmentCheck params t =
|
||||
let flow = variableFlow params
|
||||
check = findSubshelled flow [("oops",[])] Map.empty
|
||||
|
@ -2055,7 +2059,7 @@ data StackData =
|
|||
data DataType = DataString DataSource | DataArray DataSource
|
||||
deriving (Show)
|
||||
|
||||
data DataSource = SourceFrom [Token] | SourceExternal | SourceDeclaration
|
||||
data DataSource = SourceFrom [Token] | SourceExternal | SourceDeclaration | SourceInteger
|
||||
deriving (Show)
|
||||
|
||||
data VariableState = Dead Token String | Alive deriving (Show)
|
||||
|
@ -2095,6 +2099,12 @@ leadType shell parents t =
|
|||
Sh -> True
|
||||
Ksh -> False
|
||||
|
||||
isClosingFileOp op =
|
||||
case op of
|
||||
T_IoFile _ (T_GREATAND _) (T_NormalWord _ [T_Literal _ "-"]) -> True
|
||||
T_IoFile _ (T_LESSAND _) (T_NormalWord _ [T_Literal _ "-"]) -> True
|
||||
_ -> False
|
||||
|
||||
getModifiedVariables t =
|
||||
case t of
|
||||
T_SimpleCommand _ vars [] ->
|
||||
|
@ -2117,8 +2127,11 @@ getModifiedVariables t =
|
|||
name <- getLiteralString lhs
|
||||
return (t, t, name, DataString $ SourceFrom [rhs])
|
||||
|
||||
t@(T_FdRedirect _ ('{':var) op) -> -- {foo}>&2 modifies foo
|
||||
[(t, t, takeWhile (/= '}') var, DataString SourceInteger) | not $ isClosingFileOp op]
|
||||
|
||||
t@(T_CoProc _ name _) ->
|
||||
[(t, t, fromMaybe "COPROC" name, DataArray SourceExternal)]
|
||||
[(t, t, fromMaybe "COPROC" name, DataArray SourceInteger)]
|
||||
|
||||
--Points to 'for' rather than variable
|
||||
T_ForIn id str words _ -> [(t, t, str, DataString $ SourceFrom words)]
|
||||
|
@ -2292,6 +2305,9 @@ getReferencedVariables t =
|
|||
|
||||
TC_Unary id _ "-v" token -> getIfReference t token
|
||||
TC_Unary id _ "-R" token -> getIfReference t token
|
||||
|
||||
t@(T_FdRedirect _ ('{':var) op) -> -- {foo}>&- references and closes foo
|
||||
[(t, t, takeWhile (/= '}') var) | isClosingFileOp op]
|
||||
x -> getReferencedVariableCommand x
|
||||
where
|
||||
-- Try to reduce false positives for unused vars only referenced from evaluated vars
|
||||
|
@ -2426,6 +2442,9 @@ prop_checkSpacefulness24= verifyTree checkSpacefulness "a='a b'; cat <<< $a"
|
|||
prop_checkSpacefulness25= verifyTree checkSpacefulness "a='s/[0-9]//g'; sed $a"
|
||||
prop_checkSpacefulness26= verifyTree checkSpacefulness "a='foo bar'; echo {1,2,$a}"
|
||||
prop_checkSpacefulness27= verifyNotTree checkSpacefulness "echo ${a:+'foo'}"
|
||||
prop_checkSpacefulness28= verifyNotTree checkSpacefulness "exec {n}>&1; echo $n"
|
||||
prop_checkSpacefulness29= verifyNotTree checkSpacefulness "n=$(stuff); exec {n}>&-;"
|
||||
prop_checkSpacefulness30= verifyTree checkSpacefulness "file='foo bar'; echo foo > $file;"
|
||||
|
||||
checkSpacefulness params t =
|
||||
doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)
|
||||
|
@ -2451,9 +2470,8 @@ checkSpacefulness params t =
|
|||
where
|
||||
warning = "Double quote to prevent globbing and word splitting."
|
||||
|
||||
writeF _ _ name (DataString SourceExternal) = do
|
||||
setSpaces name True
|
||||
return []
|
||||
writeF _ _ name (DataString SourceExternal) = setSpaces name True >> return []
|
||||
writeF _ _ name (DataString SourceInteger) = setSpaces name False >> return []
|
||||
|
||||
writeF _ _ name (DataString (SourceFrom vals)) = do
|
||||
map <- get
|
||||
|
|
|
@ -1401,6 +1401,13 @@ readIoFile = called "redirection" $ do
|
|||
file <- readFilename
|
||||
return $ T_FdRedirect id "" $ T_IoFile id op file
|
||||
|
||||
readIoVariable = try $ do
|
||||
char '{'
|
||||
x <- readVariableName
|
||||
char '}'
|
||||
lookAhead readIoFileOp
|
||||
return $ "{" ++ x ++ "}"
|
||||
|
||||
readIoNumber = try $ do
|
||||
x <- many1 digit <|> string "&"
|
||||
lookAhead readIoFileOp
|
||||
|
@ -1410,9 +1417,11 @@ prop_readIoNumberRedirect = isOk readIoNumberRedirect "3>&2"
|
|||
prop_readIoNumberRedirect2 = isOk readIoNumberRedirect "2> lol"
|
||||
prop_readIoNumberRedirect3 = isOk readIoNumberRedirect "4>&-"
|
||||
prop_readIoNumberRedirect4 = isOk readIoNumberRedirect "&> lol"
|
||||
prop_readIoNumberRedirect5 = isOk readIoNumberRedirect "{foo}>&2"
|
||||
prop_readIoNumberRedirect6 = isOk readIoNumberRedirect "{foo}<&-"
|
||||
readIoNumberRedirect = do
|
||||
id <- getNextId
|
||||
n <- readIoNumber
|
||||
n <- readIoVariable <|> readIoNumber
|
||||
op <- readHereString <|> readHereDoc <|> readIoFile
|
||||
let actualOp = case op of T_FdRedirect _ "" x -> x
|
||||
spacing
|
||||
|
@ -2326,6 +2335,10 @@ readScript = do
|
|||
isWarning p s = parsesCleanly p s == Just False
|
||||
isOk p s = parsesCleanly p s == Just True
|
||||
|
||||
testParse string = runIdentity $ do
|
||||
(res, _) <- runParser (mockedSystemInterface []) readScript "-" string
|
||||
return res
|
||||
|
||||
parsesCleanly parser string = runIdentity $ do
|
||||
(res, sys) <- runParser (mockedSystemInterface [])
|
||||
(parser >> eof >> getState) "-" string
|
||||
|
|
Loading…
Reference in New Issue