import Text.ParserCombinators.Parsec import qualified Text.ParserCombinators.Parsec.Token as Token import Text.ParserCombinators.Parsec.Language (emptyDef) import System.CPUTime import System.Environment data Bounds = Bounds { minlat, maxlat, minlon, maxlon :: Double } deriving (Show) update_lat lat bnd = Bounds { minlat = min lat (minlat bnd), maxlat = max lat (maxlat bnd), minlon = minlon bnd, maxlon = maxlon bnd } update_lon lon bnd = Bounds { minlat = minlat bnd, maxlat = maxlat bnd, minlon = min lon (minlon bnd), maxlon = max lon (maxlon bnd) } lexer = Token.makeTokenParser emptyDef p_positive_float = Token.float lexer p_float = try (char '-' >> p_positive_float >>= return . negate) <|> p_positive_float latlon name updater = do string (name ++ "=\"") f <- p_float char '"' updateState (updater f) p_param = do many1 letter string "=\"" many $ noneOf "\"" char '"' return () p_node_param = try (latlon "lat" update_lat) <|> try (latlon "lon" update_lon) <|> p_param p_endnode = try (string "/>") <|> manyTill anyChar (try (string "")) p_ws = many $ oneOf " \t\n" p_node = do string "> p_node_param) p_endnode p_tag = between (char '<') (char '>') (many (noneOf ">")) p_osm = do many $ (try p_node <|> p_tag) >> p_ws bnd <- getState return $ show bnd bnd0 = Bounds 1000.0 (-1000.0) 1000.0 (-1000.0) parse_osm_file fname = do input <- readFile fname case runParser p_osm bnd0 fname input of Right str -> putStrLn str Left err -> do putStr "parse error at " print err main = do args <- getArgs case args of [] -> putStrLn "usage: bounds osmfile" fname:_ -> do t0 <- getCPUTime parse_osm_file fname t1 <- getCPUTime putStrLn $ show $ 1.0e-12 * (fromInteger $ t1 - t0)