System.Info.MAC.Fetchの実装がMacのifconfigを読んでくれないのでちょっとParsecの勉強ついでに調べてみる。
ifconfigの内容をparsecでパースする。Parserの中でparse関数を読んでいるのは筋が悪い気がするし、こういう分野は正規表現が得意な気がする。
最初に各NICのセクションを分けて、それぞれの中をさらにパースして結果とする。
parse_ifconfig.hs
before :: Parser a -> Parser Bool
before p = try (lookAhead p *> return True) <|> (eof *> return False) <|>(anyChar *> before p)
nicSection :: Parser (String, Maybe MAC)
nicSection = do
name <- many1 alphaNum
r <- manyTill anyChar (try $ lookAhead $ (void (char '\n' *> alphaNum)) <|> eof)
let mac = case (parse macAddr "macaddr parse" r) of
Left _ -> Nothing
Right mac -> mac
ret = (name, mac)
(char '\n' *> return ret) <|> return ret
-- Skip next char if it's '\n'. However, the below doesn't work
-- try $ char '\n'
-- return ret
nicSections :: Parser [(String, Maybe MAC)]
nicSections = many1 nicSection
macAddr :: Parser (Maybe MAC)
macAddr = do
found <- before markers
if found
then do
markers
spaces
parseMAC ':' >>= return
else return Nothing
where
markers = choice $ map (try . string) [ "ether", "HWaddr" ]
parseNICs' :: Parser [(String, MAC)]
parseNICs' = (foldr macAddrOnOnly []) <$> nicSections
where
macAddrOnOnly (_, Nothing) p = p
macAddrOnOnly (n, Just x) p = (n, x) : p
main:: IO ()
main=do
let u = parse parseNICs' "ifconfig mac" mac
putStrLn $ show u
nicSectionの最後の行あたりはもっといい方法がありそうな気がする。「もし今読んでいるところが'\n'なら一文字読む」ということがやりたい。