-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIOHandler.hs
More file actions
137 lines (108 loc) · 4.21 KB
/
Copy pathIOHandler.hs
File metadata and controls
137 lines (108 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
module IOHandler (handleIO)
where
import System.IO (hPutStrLn, hPutStr, stderr)
import System.Environment (getArgs)
import System.Exit (exitWith, ExitCode(ExitFailure), exitSuccess)
import Control.Monad (unless)
import System.Console.GetOpt (OptDescr(Option)
, ArgDescr(ReqArg, NoArg)
, usageInfo
, getOpt
, ArgOrder(RequireOrder))
import qualified Types as T (Err)
import qualified Options as O (PureMain, PureMultiMain, Options(..))
import qualified Lisp as L (readLisp', fromSexp, mapcar')
handleIO :: O.PureMain -> IO ()
handleIO = handleIO' . toMulti
handleIO' :: O.PureMultiMain -> IO ()
handleIO' m = do
args <- getArgs
let (actions, nonOptions, errors) = getOpt RequireOrder options args
unless (null errors && length nonOptions <= 2) (handleInvalidOptions errors)
opts <- foldl (>>=) (return startOptions) actions
let (nonOptions', inputHandler) = getInputHandler nonOptions
let outputHandler = getOutputHandler nonOptions'
input <- inputHandler
let inputs = [input]
let outputs = m opts inputs
let output = fmap head outputs
outputHandler output
where
getInputHandler :: [String] -> ([String], IO String)
getInputHandler [] = ([], getContents)
getInputHandler ("-":r) = (r, getContents)
getInputHandler (i:r) = (r, readFile i)
getOutputHandler :: [String] -> T.Err String -> IO ()
getOutputHandler [] (Right s) = putStr s
getOutputHandler [o] (Right s) = writeFile o s
getOutputHandler args (Right _) = error $ "getOutputHandler with args " ++ show args ++ "?"
getOutputHandler _ (Left err) = do
hPutStrLn stderr $ "ERROR: " ++ err
exitWith $ ExitFailure 1
collectErrors :: [T.Err String] -> T.Err [String]
collectErrors [] = error "collectErrors on []"
collectErrors [Right x] = Right [x]
collectErrors [Left x] = Left x
collectErrors _ = error "collectErrors on list longer than 1"
toMulti :: O.PureMain -> O.PureMultiMain
toMulti m opts = collectErrors . map (m opts)
startOptions :: O.Options
startOptions = O.Options { O.optVerbose = False
, O.optInputFormat = "sf"
, O.optOutputFormat = "enp"
, O.optMaxDiv = [8]
, O.optForbiddenDivs = [[]]
, O.optTimeSignatures = L.readLisp' "((4 4))"
, O.optMetronomes = L.readLisp' "((4 60))"
, O.optMeasureSiblingMerge = False
}
options :: [ OptDescr (O.Options -> IO O.Options) ]
options =
[ Option "r" ["read", "from"]
(ReqArg
(\arg opt -> return opt { O.optInputFormat = arg })
"FORMAT")
"Input format"
, Option "w" ["write", "to"]
(ReqArg
(\arg opt -> return opt { O.optOutputFormat = arg })
"FORMAT")
"Output format"
, Option "m" ["max-div"]
(ReqArg
(\arg opt -> return opt { O.optMaxDiv = [read arg] })
"DIV")
"Maximum division"
, Option "" ["forbidden-divs"]
(ReqArg
(\arg opt -> return opt { O.optForbiddenDivs = [L.mapcar' L.fromSexp (L.readLisp' arg)] })
"DIVS")
"Forbidden divisions"
, Option "" ["measure-sibling-merge"]
(NoArg
(\opt -> return opt { O.optMeasureSiblingMerge = True }))
"Enable measureSiblingMerge"
, Option "v" ["verbose"]
(NoArg
(\opt -> return opt { O.optVerbose = True }))
"Enable verbose messages"
, Option "V" ["version"]
(NoArg
(\_ -> do
hPutStrLn stderr "KSQuant2 0.2.1"
exitSuccess))
"Print version"
, Option "h" ["help"]
(NoArg
(\_ -> do
hPutStrLn stderr (usageInfo usageHeader options)
exitSuccess))
"Show help"
]
usageHeader :: String
usageHeader = "Usage: ksquant2 [OPTIONS]"
handleInvalidOptions :: [String] -> IO ()
handleInvalidOptions errors = do
hPutStrLn stderr $ concat errors
hPutStr stderr $ usageInfo usageHeader options
exitWith $ ExitFailure 1