--- /dev/null
+import qualified Data.Char as DC
+import qualified Data.List as DL
+import qualified Numeric as N
+import System.Exit (exitFailure)
+import Text.Regex.Posix
+
+splitWith :: (a -> Bool) -> [a] -> [[a]]
+splitWith p xs =
+ ys : case zs of
+ [] -> []
+ _:ws -> splitWith p ws
+ where (ys,zs) = break p xs
+
+
+octets :: String -> [Int]
+octets cidr = map read (take 4 (splitWith (`elem` "./") cidr))
+
+maskbits :: String -> Int
+maskbits cidr = read ((splitWith (`elem` "/") cidr) !! 1)
+
+
+pad_left_to :: Int -> a -> [a] -> [a]
+pad_left_to len pad_elem xs =
+ if (length xs) >= len then
+ xs
+ else
+ (replicate padcount pad_elem) ++ xs
+ where
+ padcount = len - (length xs)
+
+pad_right_to :: Int -> a -> [a] -> [a]
+pad_right_to len pad_elem xs =
+ if (length xs) >= len then
+ xs
+ else
+ xs ++ (replicate padcount pad_elem)
+ where
+ padcount = len - (length xs)
+
+
+base_two :: Int -> String
+base_two n = N.showIntAtBase 2 DC.intToDigit n ""
+
+ip_base_two :: [Int] -> String
+ip_base_two octet_list =
+ DL.concatMap ((pad_left_to 8 '0') .base_two) octet_list
+
+min_base_two_address :: String -> String
+min_base_two_address cidr =
+ pad_right_to 32 '0' netpart
+ where
+ netpart = take (maskbits cidr) (ip_base_two (octets cidr))
+
+max_base_two_address :: String -> String
+max_base_two_address cidr =
+ pad_right_to 32 '1' netpart
+ where
+ netpart = take (maskbits cidr) (ip_base_two (octets cidr))
+
+min_base_two_octets :: String -> [String]
+min_base_two_octets cidr =
+ [octet1, octet2, octet3, octet4]
+ where
+ addr = min_base_two_address cidr
+ octet1 = fst (DL.splitAt 8 addr)
+ octet2 = fst (DL.splitAt 8 (snd (DL.splitAt 8 addr)))
+ octet3 = fst (DL.splitAt 8 (snd (DL.splitAt 16 addr)))
+ octet4 = snd (DL.splitAt 24 addr)
+
+max_base_two_octets :: String -> [String]
+max_base_two_octets cidr =
+ [octet1, octet2, octet3, octet4]
+ where
+ addr = max_base_two_address cidr
+ octet1 = fst (DL.splitAt 8 addr)
+ octet2 = fst (DL.splitAt 8 (snd (DL.splitAt 8 addr)))
+ octet3 = fst (DL.splitAt 8 (snd (DL.splitAt 16 addr)))
+ octet4 = snd (DL.splitAt 24 addr)
+
+
+min_octets :: String -> [Int]
+min_octets cidr =
+ map base_two_to_base_ten (min_base_two_octets cidr)
+
+max_octets :: String -> [Int]
+max_octets cidr =
+ map base_two_to_base_ten (max_base_two_octets cidr)
+
+is_binary_digit :: Char -> Bool
+is_binary_digit c =
+ if c `elem` ['0','1'] then
+ True
+ else
+ False
+
+base_two_to_base_ten :: String -> Int
+base_two_to_base_ten s =
+ if (length parsed) == 0 then
+ 0
+ else
+ fst (parsed !! 0)
+ where
+ parsed = N.readInt 2 is_binary_digit DC.digitToInt s
+
+
+cidr_to_regex :: String -> String
+cidr_to_regex cidr =
+ range1 ++ "\\." ++ range2 ++ "\\." ++ range3 ++ "\\." ++ range4
+ where
+ range1 = numeric_range min1 max1
+ range2 = numeric_range min2 max2
+ range3 = numeric_range min3 max3
+ range4 = numeric_range min4 max4
+ min1 = (min_octets cidr) !! 0
+ min2 = (min_octets cidr) !! 1
+ min3 = (min_octets cidr) !! 2
+ min4 = (min_octets cidr) !! 3
+ max1 = (max_octets cidr) !! 0
+ max2 = (max_octets cidr) !! 1
+ max3 = (max_octets cidr) !! 2
+ max4 = (max_octets cidr) !! 3
+
+
+is_valid_cidr :: String -> Bool
+is_valid_cidr cidr = cidr =~ "([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}"
+
+alternate :: [String] -> String
+alternate terms = "(" ++ (concat (DL.intersperse "|" terms)) ++ ")"
+
+numeric_range :: Int -> Int -> String
+numeric_range x y =
+ alternate (map show [lower..upper])
+ where
+ lower = minimum [x,y]
+ upper = maximum [x,y]
+
+main :: IO ()
+main = do
+ line <- getLine
+
+ if (is_valid_cidr line)
+ then do
+ putStrLn (cidr_to_regex line)
+ else do
+ putStrLn "Error: not valid CIDR notation."
+ exitFailure
+