4 Copyright 2013 Louis-Guillaume Gagnon <louis.guillaume.gagnon@gmail.com>
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 import Data
.Char (isDigit)
25 import Data
.List
(intersperse)
26 import System
.Directory
(doesFileExist)
28 data Filter
= File
String
39 tryGetFilters
:: [String] -> IO (Either String ([String],[String]));
40 tryGetFilters argv
= case getFilters argv
of
41 Left msg
-> return $ Left msg
42 Right pairs
-> if anyDuplicates pairs
43 then return $ Left
"duplicated arguments"
47 Right _
-> return $ Right
$ pairFilters pairs
48 Left msg
-> return $ Left msg
50 areFiltersEqual
:: Filter
-> Filter
-> Bool
51 areFiltersEqual f1 f2
= f1
' == f2
'
52 where (f1
',_
) = break (==' ') $ show f1
53 (f2
',_
) = break (==' ') $ show f2
55 anyDuplicates
:: [Filter
] -> Bool
56 anyDuplicates
(f
:[]) = False
57 anyDuplicates
(f
:fs
) = if or $ map (areFiltersEqual f
) fs
59 else do anyDuplicates fs
61 checkFile
:: [Filter
] -> IO (Either String ())
62 checkFile fs
= case filter isPathFilter fs
of
63 [] -> return $ Right
()
64 ((File p
):_
) -> do exists
<- doesFileExist p
66 then do return $ Right
()
67 else do return $ Left
$ "File does not exists: " ++ p
69 isFilter
:: String -> Bool
70 isFilter f
= f `
elem`
["-f","-t","-a","-k","-j","-v","-y","-p","-b"]
72 isLikeFilter
:: String -> Bool
73 isLikeFilter f
= (length f
== 2) && (head f
== '-')
75 isPathFilter
:: Filter
-> Bool
76 isPathFilter f
= case f
of
80 isYear
:: String -> Bool
81 isYear s
= (length s
== 4) && (and $ map isDigit s
)
83 getFilters
:: [String] -> Either String [Filter
]
84 getFilters strs
= case getFilterPairs strs
of
86 Right pairs
-> mapToFilter pairs
88 getFilterPairs
:: [String] -> Either String [(String,[String])]
89 getFilterPairs strs
= worker
[] strs
90 where worker fs
[] = Right fs
91 worker fs
(x
:xs
) |
not (isFilter x
) = Left
$ "Invalid argument: " ++ x
92 |
otherwise = worker
((x
, values
):fs
) rest
93 where (values
,rest
) = break isLikeFilter xs
95 pairFilters
:: [Filter
] -> ([String],[String])
96 pairFilters fs
= worker
[] [] fs
97 where worker ks vs
[] = (ks
,vs
)
98 worker ks vs
(f
:fs
) = worker
(k
:ks
) (v
:vs
) fs
99 where (k
,v
') = break (==' ') $ show f
100 v
= filter (/='\"') (tail v
')
102 toFilter
:: (String,[String]) -> Either String Filter
103 toFilter
(f
,vs
) |
null vs
= if f
== "-b"
104 then Right
$ Bookmarked
"true"
105 else Left
"too few arguments"
106 |
otherwise = case f
of
107 "-f" -> Right
$ File
$ concat $ intersperse " " vs
108 "-t" -> Right
$ Title
$ concat $ intersperse " " vs
109 "-a" -> Right
$ Authors
$ concat $ intersperse " | " vs
110 "-k" -> Right
$ Keywords
$ concat $ intersperse " | " vs
111 "-j" -> Right
$ Journal
$ concat $ intersperse " " vs
112 "-v" -> if length vs
== 1
113 then if and $ map isDigit vs0
114 then Right
$ Volume vs0
115 else Left
$ "Invalid Volume: " ++ vs0
116 else Left
"too many arguments to -v"
117 "-y" -> if length vs
== 1
119 then Right
$ Year vs0
120 else Left
$ "Invalid year: " ++ vs0
121 else Left
"too many arguments to -y"
122 "-p" -> case length vs
of
123 1 -> if and $ map isDigit vs0
124 then Right
$ Pages vs0
125 else Left
$ "Invalid pages: " ++ vs0
126 2 -> if and $ map isDigit (vs0
++ vs1
)
127 then Right
$ Pages
(vs0
++ " " ++ vs1
)
128 else Left
$ "Invalid pages: " ++ (vs0
++ " " ++ vs1
)
129 _
-> Left
"too many arguments to -p"
131 then Right
$ Bookmarked
"true"
132 else Left
"too many arguments to -b"
136 mapToFilter
:: [(String,[String])] -> Either String [Filter
]
137 mapToFilter strs
= worker
[] strs
138 where worker fs
[] = Right fs
139 worker fs
(x
:xs
) = let f
= toFilter x
142 Right f
-> worker
(f
:fs
) xs
144 usageFilters
:: String
145 usageFilters
= "filters:\n\
151 \ -y <year> : <yyyy>\n\