iCalendar (empty) → 0.0
raw patch · 4 files changed
+442/−0 lines, 4 filesdep +basedep +haskell98dep +parsecsetup-changed
Dependencies added: base, haskell98, parsec
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- Text/ICalendar/Parser.hs +377/−0
- iCalendar.cabal +33/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2008, Tupil++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Tupil nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Text/ICalendar/Parser.hs view
@@ -0,0 +1,377 @@+{-|++Parser for the iCalendar format (version 2.0, RFC2445).+ +Features:++ * Unfolds folded lines (see RFC)+ + * Supports all IANA iCalendar tokens++/Warning!/ This is version 0.0, important things are missing+ + * Property and parameter values are not parsed, but kept as in the file.++ * There are no restrictions on the properties components can have.+ + * Line unfolding causes error messages to report the wrong line.+ +This package is meant to grow to a full-fledged data definition, printer and+parser for the iCalendar format. But that will probably take some time. So,+if you've come here because you need this, please e-mail me (Eelco Lempsink).++-}++module Text.ICalendar.Parser + (+ -- * Tokens from RFC2445+ ComponentName(..)+ , PropertyName(..)+ , ParamName(..)+ , ParamValue(..)+ -- * Data definitions+ , Property+ , Value+ , ICalendar(..)+ , Component(..)+ , Param(..)+ -- * Parser+ , parser+ ) where++------------------------------------------------------------+-- Imports+------------------------------------------------------------++import Data.Char+import Control.Monad++import Control.Applicative+import Control.Monad (MonadPlus(..), ap)+-- Hide Parsec's definitions of some Applicative functions.+import Text.ParserCombinators.Parsec hiding (many, optional, (<|>))++-- Every Monad is an Applicative.+instance Applicative (GenParser s a) where+ pure = return+ (<*>) = ap++-- Every MonadPlus is an Alternative.+instance Alternative (GenParser s a) where+ empty = mzero+ (<|>) = mplus++------------------------------------------------------------+-- Tokens, as defined in RFC2445.+------------------------------------------------------------++-- | Calendar Component names (4.6)+data ComponentName =+ VEVENT -- ^ Event Component (4.6.1)+ | VTODO -- ^ To-do Component (4.6.2)+ | VJOURNAL -- ^ Journal Component (4.6.3)+ | VFREEBUSY -- ^ Free/Busy Component (4.6.4)+ | VTIMEZONE -- ^ Time Zone Component (4.6.5)+ | X_c String -- ^ Non-standard/Experimental Component+ -- Time Zone subcomponents+ | STANDARD -- ^ Standard Time Sub-component (4.6.5)+ | DAYLIGHT -- ^ Daylight Saving Time Sub-component (4.6.5)+ -- Event and To-do subcomponent+ | VALARM -- ^ Alarm Sub-component (4.6.6)+ deriving (Eq, Show)++-- | Property names for Calendar Properties (4.7) and Component Properties (4.8)+data PropertyName = + -- Calendar properties (4.7)+ CALSCALE -- ^ Calendar Scale (4.7.1)+ | METHOD -- ^ Method (4.7.2)+ | PRODID -- ^ Product Identifier (4.7.3)+ | VERSION -- ^ Version (4.7.4)+ + -- Component properties (4.8.1)+ | ATTACH -- ^ Attachment (4.8.1.1)+ | CATEGORIES -- ^ Categories (4.8.1.2)+ | CLASS -- ^ Classification (4.8.1.3)+ | COMMENT -- ^ Comment (4.8.1.4)+ | DESCRIPTION -- ^ Description (4.8.1.5)+ | GEO -- ^ Geographic Position (4.8.1.6)+ | LOCATION -- ^ Location (4.8.1.7)+ | PERCENT_COMPLETE -- ^ Percent Complete (4.8.1.8)+ | PRIORITY -- ^ Priority (4.8.1.9)+ | RESOURCES -- ^ Resources (4.8.1.10)+ | STATUS -- ^ Status (4.8.1.11)+ | SUMMARY -- ^ Summary (4.8.1.12)+ + -- Date and Time Component properties (4.8.2)+ | COMPLETED -- ^ Date/Time Completed (4.8.2.1) + | DTEND -- ^ Date/Time End (4.8.2.2) + | DUE -- ^ Date/Time Due (4.8.2.3)+ | DTSTART -- ^ Date/Time Start (4.8.2.4) + | DURATION -- ^ Duration (4.8.2.5) + | FREEBUSY -- ^ Free/Busy Time (4.8.2.6) + | TRANSP -- ^ Time Transparency (4.8.2.7) + + -- Time Zone Component properties (4.8.3)+ | TZID -- ^ Time Zone Identifier (4.8.3.1) + | TZNAME -- ^ Time Zone Name (4.8.3.2) + | TZOFFSETFROM -- ^ Time Zone Offset From (4.8.3.3) + | TZOFFSETTO -- ^ Time Zone Offset To (4.8.3.4) + | TZURL -- ^ Time Zone URL (4.8.3.5) + + -- Relationship Component properties (4.8.4)+ | ATTENDEE -- ^ Attendee (4.8.4.1) + | CONTACT -- ^ Contact (4.8.4.2)+ | ORGANIZER -- ^ Organizer (4.8.4.3) + | RECURRENCE_ID -- ^ Recurrence ID (4.8.4.4) + | RELATED_TO -- ^ Related To (4.8.4.5) + | URL -- ^ Uniform Resource Locator (4.8.4.6) + | UID -- ^ Unique Identfier (4.8.4.7) + + -- Recurrence Component properties (4.8.5)+ | EXDATE -- ^ Exception Date/Times (4.8.5.1) + | EXRULE -- ^ Exception Rule (4.8.5.2) + | RDATE -- ^ Recurrence Date/Times (4.8.5.3) + | RRULE -- ^ Recurrence Rule (4.8.5.4) + + -- Alarm Component properties (4.8.6)+ | ACTION -- ^ Action (4.8.6.1) + | REPEAT -- ^ Repeat Count (4.8.6.2) + | TRIGGER -- ^ Trigger (4.8.6.3) + + -- Change Management Component properties (4.8.7)+ | CREATED -- ^ Date/Time Created (4.8.7.1) + | DTSTAMP -- ^ Date/Time Stamp (4.8.7.2) + | LAST_MODIFIED -- ^ Last Modified (4.8.7.3) + | SEQUENCE -- ^ Sequence Number (4.8.7.4) + + -- Miscellaneous Component properties (4.8.8)+ | X_ String -- ^ Non-standard Properties (4.8.8.1)+ | REQUEST_STATUS -- ^ Request Status (4.8.8.2)+ deriving (Eq, Show)++-- | Parameter names (4.2)+data ParamName = ALTREP -- ^ Alternate Text Represenation (4.2.1) + | CN -- ^ Common Name (4.2.2) + | CUTYPE -- ^ Calendar User Type (4.2.3) + | DELEGATED_FROM -- ^ Delegators (4.2.4) + | DELEGATED_TO -- ^ Delegatees (4.2.5) + | DIR -- ^ Directory Entry Reference (4.2.6) + | ENCODING -- ^ Inline Encoding (4.2.7) + | FMTYPE -- ^ Format Type (4.2.8) + | FBTYPE -- ^ Free/Busy Time Type (4.2.9) + | LANGUAGE -- ^ Language (4.2.10) + | MEMBER -- ^ Group or List Membership (4.2.11) + | PARTSTAT -- ^ Participation Status (4.2.12) + | RANGE -- ^ Recurrence Identfier Range (4.2.13) + | RELATED -- ^ Alarm Trigger Relationship (4.2.14) + | RELTYPE -- ^ Relationship Type (4.2.15) + | ROLE -- ^ Participation Role (4.2.16) + | RSVP -- ^ RSVP Expectation (4.2.17) + | SENT_BY -- ^ Sent By (4.2.18) + | TZIDp -- ^ Time Zone Identifier (4.2.19) + | VALUE -- ^ Value Data Types (4.2.20) + | X_p String -- ^ Non-standard Parameter (4.2.21) + deriving (Eq, Show) ++data ParamValue = Paramtext String+ | QuotedString String+ deriving (Eq, Show)++------------------------------------------------------------+-- Parsed datastructers and helper functions+------------------------------------------------------------++type Value = String+type Property = (PropertyName, [Param], Value)++-- | iCalendar data+data ICalendar = ICalendar { calendarProperties :: [Property]+ , components :: [Component]+ } deriving (Eq, Show)++mkICalendar = ICalendar [] [] ++addCalendarProperty prop calendar = calendar { calendarProperties = prop : calendarProperties calendar }+addComponent comp calendar = calendar { components = comp : components calendar }++-- | Component data+data Component = Component { cName :: ComponentName+ , properties :: [Property]+ , subcomponents :: [Component]+ } deriving (Eq, Show)++mkComponent name = Component name [] []++addProperty prop component = component { properties = prop : properties component }+addSubcomponent comp component = component { subcomponents = comp : subcomponents component }++-- | Parameter data+data Param = Param { pName :: ParamName+ , pValues :: [ParamValue]+ } deriving (Eq, Show)++------------------------------------------------------------+-- Parser helpers+------------------------------------------------------------++-- | Case insensitive string matching. Also wrapped in a 'try' so the matching+-- will fail as a whole and not mid-string.+ciString = try . sequence . (map (\c -> char (toUpper c) <|> char (toLower c)))++crlf = string "\r\n"++-- | Parses any character except controls and double quotation marks+pQsafeChar = oneOf $ wsp ++ map chr (0x21 : [0x23..0x7e]) ++ nonUsAscii++-- | Parses any character except controls, double quotation marks, ";", ":", ","+pSafeChar = oneOf $ wsp ++ map chr (0x21 : [0x23..0x2b] ++ [0x2d..0x39] ++ [0x3c..0x7e]) ++ nonUsAscii++-- | Parses any textual character+pValueChar = oneOf $ wsp ++ map chr [0x21..0x7e] ++ nonUsAscii++-- | Non US-ASCII characters+nonUsAscii = map chr [0x80..0xF8]++-- | Linear white space+wsp = " \t"++------------------------------------------------------------+-- Scanner, creating a tokenstream+------------------------------------------------------------++-- TODO folding the lines should keep the original positions+-- | Parses a "String" to an "ICalendar". Will unfold folded lines, so error messages might be off.+parser = do input <- getInput+ setInput (foldLines input)+ pICalendar++-- | Remove crlf's followed by space or tab, this is called "line folding".+foldLines [] = []+foldLines ('\r':'\n':' ' :lines) = foldLines lines+foldLines ('\r':'\n':'\t':lines) = foldLines lines+foldLines (l:lines) = l : foldLines lines++pICalendar = pBegin <* pVCalendar + *> pCalendarPropertiesAndComponents+ <* eof++pVCalendar = ciString "VCALENDAR" <* crlf++pCalendarPropertiesAndComponents =+ addCalendarProperty <$> pProperty <*> pCalendarPropertiesAndComponents+ <|> addComponent <$> pComponent <*> pCalendarPropertiesAndComponents+ <|> mkICalendar <$ pEnd <* pVCalendar++pComponent = do component <- pComponentBegin+ pPropertiesAndSubcomponents component++pComponentBegin = mkComponent <$ pBegin <*> pComponentName++pPropertiesAndSubcomponents component =+ addProperty <$> pProperty <*> pPropertiesAndSubcomponents component+ <|> addSubcomponent <$> pComponent <*> pPropertiesAndSubcomponents component+ <|> component <$ pComponentEnd component++pProperty = (,,) <$> pPropertyName <*> many pParam <*> pValue++pParam = Param <$ char ';' <*> pParamName <*> sepBy pParamValue (char ',')++-- NOTE: pQuotedString has to go first, because the value may be empty+pParamValue = pQuotedString <|> pParamtext +pParamtext = Paramtext <$> many pSafeChar+pQuotedString = QuotedString <$ char '"' <*> many pQsafeChar <* char '"'++pValue = char ':' *> many pValueChar <* crlf++-- TODO: This will disappear once every component has its own parser+pComponentEnd c = do pEnd+ component <- pComponentName+ if component == cName c+ then return component+ else unexpected $ "END:" ++ show (cName c)++pBegin = ciString "BEGIN:"+pEnd = ciString "END:"++pComponentName = ( VEVENT <$ ciString "VEVENT"+ <|> VTODO <$ ciString "VTODO"+ <|> VJOURNAL <$ ciString "VJOURNAL"+ <|> VFREEBUSY <$ ciString "VFREEBUSY"+ <|> VTIMEZONE <$ ciString "VTIMEZONE"+ <|> X_c <$ ciString "X-" <*> many1 (alphaNum <|> char '-')+ <|> STANDARD <$ ciString "STANDARD"+ <|> DAYLIGHT <$ ciString "DAYLIGHT"+ <|> VALARM <$ ciString "VALARM"+ ) <* crlf+ +pPropertyName = CALSCALE <$ ciString "CALSCALE"+ <|> METHOD <$ ciString "METHOD"+ <|> PRODID <$ ciString "PRODID"+ <|> VERSION <$ ciString "VERSION"+ <|> ATTACH <$ ciString "ATTACH"+ <|> CATEGORIES <$ ciString "CATEGORIES"+ <|> CLASS <$ ciString "CLASS"+ <|> COMMENT <$ ciString "COMMENT"+ <|> DESCRIPTION <$ ciString "DESCRIPTION"+ <|> GEO <$ ciString "GEO"+ <|> LOCATION <$ ciString "LOCATION"+ <|> PERCENT_COMPLETE <$ ciString "PERCENT-COMPLETE"+ <|> PRIORITY <$ ciString "PRIORITY"+ <|> RESOURCES <$ ciString "RESOURCES"+ <|> STATUS <$ ciString "STATUS"+ <|> SUMMARY <$ ciString "SUMMARY"+ <|> COMPLETED <$ ciString "COMPLETED"+ <|> DTEND <$ ciString "DTEND"+ <|> DUE <$ ciString "DUE"+ <|> DTSTART <$ ciString "DTSTART"+ <|> DURATION <$ ciString "DURATION"+ <|> FREEBUSY <$ ciString "FREEBUSY"+ <|> TRANSP <$ ciString "TRANSP"+ <|> TZID <$ ciString "TZID"+ <|> TZNAME <$ ciString "TZNAME"+ <|> TZOFFSETFROM <$ ciString "TZOFFSETFROM"+ <|> TZOFFSETTO <$ ciString "TZOFFSETTO"+ <|> TZURL <$ ciString "TZURL"+ <|> ATTENDEE <$ ciString "ATTENDEE"+ <|> CONTACT <$ ciString "CONTACT"+ <|> ORGANIZER <$ ciString "ORGANIZER"+ <|> RECURRENCE_ID <$ ciString "RECURRENCE-ID"+ <|> RELATED_TO <$ ciString "RELATED-TO"+ <|> URL <$ ciString "URL"+ <|> UID <$ ciString "UID"+ <|> EXDATE <$ ciString "EXDATE"+ <|> EXRULE <$ ciString "EXRULE"+ <|> RDATE <$ ciString "RDATE"+ <|> RRULE <$ ciString "RRULE"+ <|> ACTION <$ ciString "ACTION"+ <|> REPEAT <$ ciString "REPEAT"+ <|> TRIGGER <$ ciString "TRIGGER"+ <|> CREATED <$ ciString "CREATED"+ <|> DTSTAMP <$ ciString "DTSTAMP"+ <|> LAST_MODIFIED <$ ciString "LAST-MODIFIED"+ <|> SEQUENCE <$ ciString "SEQUENCE"+ <|> X_ <$ ciString "X-" <*> many1 (alphaNum <|> char '-')+ <|> REQUEST_STATUS <$ ciString "REQUEST-STATUS"++pParamName = ( ALTREP <$ ciString "ALTREP"+ <|> CN <$ ciString "CN"+ <|> CUTYPE <$ ciString "CUTYPE"+ <|> DELEGATED_FROM <$ ciString "DELEGATED-FROM"+ <|> DELEGATED_TO <$ ciString "DELEGATED-TO"+ <|> DIR <$ ciString "DIR"+ <|> ENCODING <$ ciString "ENCODING"+ <|> FMTYPE <$ ciString "FMTYPE"+ <|> FBTYPE <$ ciString "FBTYPE"+ <|> LANGUAGE <$ ciString "LANGUAGE"+ <|> MEMBER <$ ciString "MEMBER"+ <|> PARTSTAT <$ ciString "PARTSTAT"+ <|> RANGE <$ ciString "RANGE"+ <|> RELATED <$ ciString "RELATED"+ <|> RELTYPE <$ ciString "RELTYPE"+ <|> ROLE <$ ciString "ROLE"+ <|> RSVP <$ ciString "RSVP"+ <|> SENT_BY <$ ciString "SENT-BY"+ <|> TZIDp <$ ciString "TZID"+ <|> VALUE <$ ciString "VALUE"+ <|> X_p <$ ciString "X-" <*> many1 (alphaNum <|> char '-')+ ) <* char '='
+ iCalendar.cabal view
@@ -0,0 +1,33 @@+Name: iCalendar+Version: 0.0+Synopsis: Parser for iCalendar format (RFC2445)++Description: Parser for the iCalendar format (version 2.0, RFC2445).+ . + Features:+ .+ * Unfolds folded lines (see RFC)+ . + * Supports all IANA iCalendar tokens+ .+ /Warning!/ This is version 0.0, important things are missing+ . + * Property and parameter values are not parsed, but kept as in the file.+ . + * There are no restrictions on the properties components can have.+ . + * Line unfolding causes error messages to report the wrong line.+ . + This package is meant to grow to a full-fledged data definition, printer and+ parser for the iCalendar format. But that will probably take some time. So,+ if you've come here because you need this, please e-mail me (Eelco Lempsink).++Category: Text+License: BSD3+License-file: LICENSE+Copyright: (c) Tupil+Author: Eelco Lempsink <eml+hackage@tupil.com>+Maintainer: Eelco Lempsink <eml+hackage@tupil.com>+Exposed-Modules: Text.ICalendar.Parser+Build-Type: Simple+Build-Depends: base, haskell98, parsec >=2 && <3