Random tools I've written for myself and I could not think of anywhere else to put them.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.3 KiB

{- Lifted straight from:
I believe this is the license:
All later commits under GPL v3
import System.Console.GetOpt
import System.IO
import System.Exit
import System.Environment
import Data.List
import Data.Char
import Control.Monad
import Text.Printf
main = do
(args, files) <- getArgs >>= parse
when (Unbuffered `elem` args) $ hSetBuffering stdout NoBuffering
mapM_ (cat args) files
withFile' s f = putStr . unlines . f . lines =<< open s
open f = if f == "-" then getContents else readFile f
cat [] f = withFile' f id
cat as f = withFile' f (newline . number . visible as)
number s = if Blanks `elem` as then numberSome s else ifset Number numberAll s
newline s = ifset Dollar (map (++"$")) s
visible as s = foldl' (flip render) s as
ifset a f = if a `elem` as then f else id
render Squeeze = map head. groupBy (\x y -> all (all isSpace) [x,y])
render Tabs = map $ concatMap (\c -> if c == '\t' then "^I" else [c])
render Invisible = map $ concatMap visible
visible c | c == '\t' || isPrint c = [c]
| otherwise = init . tail . show $ c
render _ = id
numberLine = printf "%6d %s"
numberAll s = zipWith numberLine [(1 :: Integer)..] s
numberSome s = reverse . snd $ foldl' draw (1,[]) s
draw (n,acc) s
| all isSpace s = (n, s : acc)
| otherwise = (n+1, numberLine n s : acc)
data Flag
= Blanks -- -b
| Dollar -- -e
| Squeeze -- -s
| Tabs -- -t
| Unbuffered -- -u
| Invisible -- -v
| Number -- -n
| Help -- --help
deriving (Eq,Ord,Enum,Show,Bounded)
flags =
[Option ['b'] [] (NoArg Blanks)
"Implies the -n option but doesn't count blank lines."
,Option ['e'] [] (NoArg Dollar)
"Implies the -v option and also prints a dollar sign (`$') at the end of each line."
,Option ['n'] [] (NoArg Number)
"Number the output lines, starting at 1."
,Option ['s'] [] (NoArg Squeeze)
"Squeeze multiple adjacent empty lines, causing the output to be single spaced."
,Option ['t'] [] (NoArg Tabs)
"Implies the -v option and also prints tab characters as `^I'."
,Option ['u'] [] (NoArg Unbuffered)
"The output is guaranteed to be unbuffered (see setbuf(3))."
,Option ['v'] [] (NoArg Invisible)
"Displays non-printing characters so they are visible."
,Option [] ["help"] (NoArg Help)
"Print this help message"
parse argv = case getOpt Permute flags argv of
(args,fs,[]) -> do
let files = if null fs then ["-"] else fs
if Help `elem` args
then do hPutStrLn stderr (usageInfo header flags)
exitWith ExitSuccess
else return (nub (concatMap set args), files)
(_,_,errs) -> do
hPutStrLn stderr (concat errs ++ usageInfo header flags)
exitWith (ExitFailure 1)
where header = "Usage: cat [-benstuv] [file ...]"
set Dollar = [Dollar, Invisible]
set Tabs = [Tabs, Invisible]
set f = [f]