{- | * This is the fifth assignment for IB016, semester spring 2015. * Name: Name Surname * UID: 123456 == Windows initialization files parser/canonizer Your task is to implement a parser and pretty-printer for Windows initialization files (.INI). The structure of these files is not fully standardized, so the form of a valid file is described below. However, the provided rules are based on actual informal specification, so you should be able to successfully parse INI files from your system. Basic examples can be seen at The INI structure is given below in extended Bacus-Naur form. This is often used to describe the sytax in computer science. More datails about the formalism can be found at and . If unsure about the meaning, feel free to drop us an email or ask at the duscussion forum. @ ini-file = ( \
| \ ) * empty-line = \ \ section = \ ( \ | \ ) * section-header = \ "[" \ \ \ "]" \ \ section-name = \ value-assignment = \ \ \ "=" \ \ \ \ property-name = \ value = ( \ | \ ) comment = \ ";" \ [ \ ] \ line-ending = [ \ ] \ space = ( \ | " " ) * string-without-brackets-and-equal = ? as string, but (not escaped) characters \'[\', \']\', and \'=\' are forbidden ? string = ? zero or more characters or escapes, must not start and end with a \, must not contain unescaped '\n', '\r', \'"\', and ';' ? quoted-string = ? a string enclosed in quotation marks ("), can contain newlines but must not contain un-escaped quotation marks (") the only allowed escape sequence is \'\\"\' ? escape = ( \'\\\\\' | \'\\=\' | \'\\;\' | \'\\[\' | \'\\]\' | \'\\"\' ) ? the last one is escaped quotation mark, the single quotes are used only to delimit the escape sequence, they are not part of it ? @ The single quotes (\') are used to delimit a a character or an escape sequence, they are not a part of the syntax. Please note that, compared to common INI files, there are two extensions (quotes and escapes) and the syntax is restricted a bit to limit ambiguity. * Values can be quoted (but unquoted values are still possible). Quoted values are used verbatim, including spaces and newlines. If you want to use quotation marks in quoted values, you can use @\\"@. Newlines in quotes are allowed and will be a part of the value. * The whole value must be delimited with quotation mark, or contain no non-escaped quotation mark. * Any string can contain escaped special characters, special characters are @';'@, @'='@, @'\'@, and @'"'@ and are escaped using @'\'@. * In (not quoted) value, both @\'\\='@ and @'='@ are the same, the same holds for @\'\['@ and @\']'@ and their escape sequences. * Backslash (@'\'@) which is not part of escape sequence is parsed verbatim. * If a value ends with @'\'@ immediatelly followed by newline, in continues on the next line, skipping the spaces at the beginning, and neither the @'\'@ nor the newline is part of the value. * You can choose not to implement escape sequences, in this case the maximum number of points is 15, you are still expected to implement quoted values, in this case quotation marks inside values are not allowed at all. For example, and extended INI file can look like this: @ ; comment [some section] weird\\;\\=key = a part of the key \\; not a comment \\ continuation of the key ; comment Another key = "quoted value can contain even newlines which are present in the result, but the quotations marks are not" [ Section2] ; comment three c= " quoted values can also contain whitespace at beginning or end and many weird characters: ; \\ = " @ this example defines the following keys (without quotation marks): @"weird;=key"@, @"Another key"@, and @"c"@; and following values (again without quotes, in Haskell string syntax): * @"a part of the key ; not a comment continuation of the key"@ * @"quoted value can contain even \\nnewlines which are present in the result, but the quotations marks are not"@ * @" quoted values can also contain whitespace at beginning or end and many weird characters: ; \\ = "@ For simplicity, you may assume we are using common 'String' as input, @()@ as the user state and 'Identity' as the underlying monad -- that is, you can use the 'Parser' type provided by module @Text.Parsec.String@. If the provided input holds a valid INI file (terminated with end-of-file), the parser should return it as a INI structure in your own user-defined data type. If the input is invalid, the parse error should be returned. Even though you are only prescribed the behaviour of the 'main', 'iniParser', and 'prettyPrint' functions, try to have a reasonable (flexible, modular) design of the module. Any documentation for your own internal functions is very welcome. == Implementation notes * You are only allowed to used modules from packages 'base' and 'parsec'. * Adhere strictly to the specification provided in this task. The structure of INI files is not standardized, so grammars found on the Internet may deviate from the specification here. * You can specify the 'IniFile' data type as you see fit. It is recommended to lay out the data stuctures before writing the actual parsers. If you are implementing support for escape sequences the internal representation must contain strings without escape sequences. * Make sure you adhere to the pretty-print specification precisely. The task will be graded in a partly automated way based on produced output. * The pretty-printer should not be the @Show@ instance (this instance should be derived automatically to retain all metadata of the used types). -} module Main ( main, iniParser, prettyPrint ) where import Text.Parsec.String ( Parser ) data IniFile = Undefined {- | Pretty printer for 'IniFile' structure. The output is standardized in a following way: * Output is a valid INI file losing only information in comments. * Each line contains the section name in brackets, a single declaration or is empty. * There is one blank line between the sections. * There are no comments. * The section names are enclosed in brackets, the equality sign in declarations is separated by single space on each side. * There are no extra spaces or blank lines. * The order of sections and declarations within the sections is the same as in the original file. * The section names, keys and values in the declarations have the same case as in the original file. * The output ends with a single newline character. * Special characters should be properly escaped, but only if it is needed to ensure correctness (if they are not allowed at this position by the grammer). * Quoted strings must be used only when necessary (that is, you are only allowed to use quotes string if the value cannot be represented using unquoted string with possible escape sequences). For example the following file @ ; comment [ Section name ] s = a ;another comment here Another key = "New value" [ Section2] ; comment three c=something d = " with whitespace " @ produces the following output @ [Section name] s = a Another key = New value [Section2] c = something d = " with whitespace " @ -} prettyPrint :: IniFile -> String prettyPrint = undefined -- | The @parsec@ parser of INI files which is used in @main@. You are not -- allowed to use any validation routine after this parser returns. All -- validation of the input must be handled by the parser directly (that is, it -- cannot happen that the parser will succeed but and you output the error message -- because of wrong input format). iniParser :: Parser IniFile iniParser = undefined -- | Parse the given file as INI printing the result. -- In case of successful parse, print the parsed INI object using 'prettyPrint' -- (don't put the second newline at the end!). -- In case of parse failure, print the error. -- The filename is given as the only command line argument. -- If there are less/more arguments, display short usage info and exit. -- You do not have to check if the file exists. main :: IO () main = undefined