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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
module CASS.RCFile
( readRCFile, updateProperty )
where
import Control.Monad ( unless )
import Data.Either ( rights )
import Data.List ( sort )
import Numeric ( readInt )
import System.IO ( hPutStrLn, stderr )
import Analysis.Logging ( DLevel(..), debugMessage )
import Data.PropertyFile ( readPropertyFile, updatePropertyFile )
import System.FilePath ( FilePath, (</>), (<.>) )
import System.Directory ( doesDirectoryExist, doesFileExist, getHomeDirectory
, renameFile )
import CASS.Configuration (CConfig(..), ccProps, setDebugLevel)
defaultRCProps :: [Either String (String,String)]
defaultRCProps =
[ Left "# Configuration file for 'cass' (Curry Analysis Server System)"
, Left ""
, Left "# The initial default path when the system is started:"
, Left "# (this path is added at the end of an existing CURRYPATH value)"
, Right ("path", "")
, Left ""
, Left "# The number of workers (if 0, no further processes are started):"
, Right ("numberOfWorkers", "0")
, Left ""
, Left "# Use the tool `curry-info` to import existing analysis infos?"
, Left "# no : do not use it"
, Left "# yes : use the local installation of `curry-info`"
, Left "# cgi : use the CGI web server of `curry-info`"
, Right ("curryinfo", "no")
, Left ""
, Left "# The method to compute the fixpoint in dependency analyses. Values:"
, Left "# simple : simple fixpoint iteration"
, Left "# wlist : fixpoint iteration with working lists"
, Left "# wlistscc : fixpoint iteration with working lists where strongly connected"
, Left "# components are computed to guide the individual iterations"
, Right ("fixpoint", "wlist")
, Left ""
, Left "# The command used to wrap the server when the system is started"
, Left "# in server mode:"
, Right ("terminalCommand", "gnome-terminal -e")
, Left ""
, Left "# The debugging level (between 0 and 4) to show more infos."
, Left "# Meaning of the debug level:"
, Left "# 0 : show nothing"
, Left "# 1 : show worker activity, e.g., timings"
, Left "# 2 : show server communication"
, Left "# 3 : ...and show read/store information"
, Left "# 4 : ...show also stored/computed analysis data"
, Right ("debugLevel", "0")
, Left ""
, Left "# Should the prelude be analyzed? Usually, it should be 'yes'."
, Left "# The value 'no' is only reasonable for experimental purposes"
, Left "# (e.g., to test new analyses on small programs)."
, Right ("prelude", "yes")
]
defaultRC :: String
defaultRC = unlines $
map (either id (\ (k,v) -> k ++ "=" ++ v)) defaultRCProps
propertyFileName :: IO String
propertyFileName = (</> ".cassrc") `fmap` getHomeDirectory
installPropertyFile :: IO ()
installPropertyFile = do
fname <- propertyFileName
pfexists <- doesFileExist fname
unless pfexists $ do
writeFile fname defaultRC
hPutStrLn stderr $
"New analysis configuration file '" ++ fname ++ "' installed."
readRCFile :: IO CConfig
readRCFile = do
hashomedir <- getHomeDirectory >>= doesDirectoryExist
if not hashomedir
then readPropertiesAndStoreLocally
else do
installPropertyFile
cc@(CConfig userprops dl) <- readPropertiesAndStoreLocally
let distprops = rights defaultRCProps
unless (rcKeys userprops == rcKeys distprops) $ do
rcName <- propertyFileName
debugMessage dl 1 $ "Updating '" ++ rcName ++ "'..."
renameFile rcName $ rcName <.> "bak"
writeFile rcName defaultRC
mapM_ (\ (n, v) -> maybe (return ())
(\uv -> if uv == v then return ()
else updatePropertyFile rcName n uv)
(lookup n userprops))
distprops
return cc
where
rcKeys = sort . map fst
readPropertiesAndStoreLocally :: IO CConfig
readPropertiesAndStoreLocally = do
userpfn <- propertyFileName
hasuserpfn <- doesFileExist userpfn
props <- if hasuserpfn
then readPropertyFile userpfn
else return $ rights defaultRCProps
return $ updateDebugLevel (CConfig props Quiet)
updateDebugLevel :: CConfig -> CConfig
updateDebugLevel cc =
case lookup "debugLevel" (ccProps cc) of
Just value -> case readInt value of
[(dl,_)] -> setDebugLevel dl cc
_ -> cc
Nothing -> cc
updateProperty :: String -> String -> CConfig -> CConfig
updateProperty pn pv cc = cc { ccProps = replaceKeyValue pn pv (ccProps cc) }
replaceKeyValue :: Eq a => a -> b -> [(a,b)] -> [(a,b)]
replaceKeyValue k v [] = [(k,v)]
replaceKeyValue k v ((k1,v1):kvs) =
if k == k1 then (k,v) : kvs
else (k1,v1) : replaceKeyValue k v kvs
|