packages feed

AutoForms-0.4.0: src/Examples/HCron/Entry3rdCrontab.hs

-- http://en.wikipedia.org/wiki/Cron

module Entry3rdCrontab
    ( Crontab(Crontab), Entry(Entry), Comment(CommentLine, BlankLine)
    , Field(List, Range, All, EveryNth)
    )
where

import Text.ParserCombinators.Parsec
import List(intersperse)

data Crontab = Crontab { entries :: [Entry], endOfCrontabComments :: [Comment] } deriving Eq
data Entry = Entry { comment    :: [Comment]
                   , minutes    :: Field
                   , hours      :: Field
                   , dayOfMonth :: Field
                   , month      :: Field
                   , dayOfWeek  :: Field
                   , command    :: String
                   } deriving Eq
data Comment = CommentLine String
             | BlankLine
               deriving Eq

data Field = List [Int]           -- 1,2,6
           | Range Int Int        -- 3-6
           | All                  -- *
           | EveryNth Int         -- */3
             deriving Eq

-------------- Show instances --------------------------------
instance Show Crontab where
    show (Crontab es cs) = unlines $ map show es ++ map show cs

instance Show Entry where
    show e = (concat $ map (++ "\n") $ map show (comment e))
             ++ (concat $ intersperse "\t" $ map show [minutes e, hours e, dayOfMonth e, month e, dayOfWeek e])
             ++ "\t" ++ command e

instance Show Comment where
    show (CommentLine s) = '#':s
    show BlankLine       = ""

instance Show Field where
    show (List xs)    = concat $ intersperse "," (map show xs)
    show (Range l r)  = show l ++ "-" ++ show r
    show All          = "*"
    show (EveryNth x) = "*/" ++ show x


------------- Parser and Read instance ------------------------
instance Read Crontab where
    readsPrec _ serialzedText = [crontabParser serialzedText]

crontabParser xs = let (Right (crontab, unconsumed)) = parse parsecParser "" xs
                   in (crontab, unconsumed)
    where
      parsecParser = do xs         <- many (try crontabEntry)
                        endComment <- many parseComment
                        unconsumed <- many anyChar
                        return (Crontab xs endComment, unconsumed)

crontabEntry = do comment'   <- many parseComment
                  minute     <- parseField
                  hour       <- parseField
                  dayOfMonth <- parseField
                  month      <- parseField
                  dayOfWeek  <- parseField
                  command    <- untilEOL
                  return $ Entry comment' minute hour dayOfMonth month dayOfWeek command


-- Field functions
parseField = let tryAll []     = pzero
                 tryAll (x:xs) = try (do x' <- x
                                         whitespace
                                         return x')
                                 <|> tryAll xs
             in tryAll [range, star, everyNth, list]

list = do x <- digits
          xs <- many (do char ','
                         digits)
          return $ List $ map read (x:xs)

range = do low  <- digits
           char '-'
           high <- digits
           return $ Range (read low) (read high)

star = do char '*'
          return All

everyNth = do char '*'
              char '/'
              digits >>= return . EveryNth . read

digits = many1 digit

whitespace = many1 $ oneOf " \t"

--

parseComment = do char '#'
                  untilEOL >>= return . CommentLine
               <|>
               do blanks <- whitespace
                  char '\n'
                  return BlankLine

untilEOL = manyTill anyChar ((do char '\n' >> return ()) <|> eof)