feat: api: quoteForCommandLine: some very shady CLI escaping
This commit is contained in:
		
							parent
							
								
									d2f0077254
								
							
						
					
					
						commit
						442ef9361c
					
				| @ -10,6 +10,7 @@ module Hledger.Utils.String ( | |||||||
|  -- quoting |  -- quoting | ||||||
|  quoteIfNeeded, |  quoteIfNeeded, | ||||||
|  singleQuoteIfNeeded, |  singleQuoteIfNeeded, | ||||||
|  |  quoteForCommandLine, | ||||||
|  -- quotechars, |  -- quotechars, | ||||||
|  -- whitespacechars, |  -- whitespacechars, | ||||||
|  words', |  words', | ||||||
| @ -118,15 +119,44 @@ quoteIfNeeded s | any (`elem` s) (quotechars++whitespacechars++redirectchars) = | |||||||
|     escapeQuotes (c:cs)   x = showChar c        $ escapeQuotes cs x |     escapeQuotes (c:cs)   x = showChar c        $ escapeQuotes cs x | ||||||
| 
 | 
 | ||||||
| -- | Single-quote this string if it contains whitespace or double-quotes. | -- | Single-quote this string if it contains whitespace or double-quotes. | ||||||
| -- No good for strings containing single quotes. | -- Does not work for strings containing single quotes. | ||||||
| singleQuoteIfNeeded :: String -> String | singleQuoteIfNeeded :: String -> String | ||||||
| singleQuoteIfNeeded s | any (`elem` s) (quotechars++whitespacechars) = "'"++s++"'" | singleQuoteIfNeeded s | any (`elem` s) (quotechars++whitespacechars) = singleQuote s | ||||||
|                       | otherwise = s |                       | otherwise = s | ||||||
| 
 | 
 | ||||||
| quotechars, whitespacechars, redirectchars :: [Char] | -- | Prepend and append single quotes to a string. | ||||||
|  | singleQuote :: String -> String | ||||||
|  | singleQuote s = "'"++s++"'" | ||||||
|  | 
 | ||||||
|  | -- | Try to single- and backslash-quote a string as needed to make it usable | ||||||
|  | -- as an argument on a (sh/bash) shell command line. At least, well enough  | ||||||
|  | -- to handle common currency symbols, like $. Probably broken in many ways. | ||||||
|  | -- | ||||||
|  | -- >>> quoteForCommandLine "a" | ||||||
|  | -- "a" | ||||||
|  | -- >>> quoteForCommandLine "\"" | ||||||
|  | -- "'\"'" | ||||||
|  | -- >>> quoteForCommandLine "$" | ||||||
|  | -- "'\\$'" | ||||||
|  | -- | ||||||
|  | quoteForCommandLine :: String -> String | ||||||
|  | quoteForCommandLine s | ||||||
|  |   | any (`elem` s) (quotechars++whitespacechars++shellchars) = singleQuote $ quoteShellChars s | ||||||
|  |   | otherwise = s | ||||||
|  | 
 | ||||||
|  | -- | Try to backslash-quote common shell-significant characters in this string. | ||||||
|  | -- Doesn't handle single quotes, & probably others. | ||||||
|  | quoteShellChars :: String -> String | ||||||
|  | quoteShellChars = concatMap escapeShellChar | ||||||
|  |   where | ||||||
|  |     escapeShellChar c | c `elem` shellchars = ['\\',c] | ||||||
|  |     escapeShellChar c = [c] | ||||||
|  | 
 | ||||||
|  | quotechars, whitespacechars, redirectchars, shellchars :: [Char] | ||||||
| quotechars      = "'\"" | quotechars      = "'\"" | ||||||
| whitespacechars = " \t\n\r" | whitespacechars = " \t\n\r" | ||||||
| redirectchars   = "<>" | redirectchars   = "<>" | ||||||
|  | shellchars      = "<>(){}[]$7?#!~`" | ||||||
| 
 | 
 | ||||||
| -- | Quote-aware version of words - don't split on spaces which are inside quotes. | -- | Quote-aware version of words - don't split on spaces which are inside quotes. | ||||||
| -- NB correctly handles "a'b" but not "''a''". Can raise an error if parsing fails. | -- NB correctly handles "a'b" but not "''a''". Can raise an error if parsing fails. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user