diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+## 0.4.2
+
+_2022-07-26, Andreas Abel_
+
+- Fail parsing if the input is not completely consumed [#30](https://github.com/chrisdone/ini/pull/30)
+- Print global values as well [#28](https://github.com/chrisdone/ini/pull/28)
+
+Tested with GHC 7.0 - 9.4.1 RC1.
+
+## 0.4.1
+
+_2019-01-02, Chris Done_
+
+- Allow global section [#6](https://github.com/chrisdone/ini/issues/6)
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,63 @@
+[![Hackage](https://img.shields.io/hackage/v/ini.svg?color=informational)](https://hackage.haskell.org/package/ini)
+[![ini on Stackage Nightly](https://stackage.org/package/ini/badge/nightly)](https://stackage.org/nightly/package/ini)
+[![Stackage LTS version](https://www.stackage.org/package/ini/badge/lts?label=Stackage)](https://www.stackage.org/package/ini)
+[![Haskell CI](https://github.com/andreasabel/ini/actions/workflows/haskell.yml/badge.svg)](https://github.com/andreasabel/ini/actions/workflows/haskell.yml)
+
+ini
+===
+
+Quick and easy configuration files in the INI format for Haskell.
+
+Format rules and recommendations:
+
+* `foo: bar` or `foo=bar` are allowed.
+* The `:` syntax is space-sensitive.
+* Keys are case-sensitive.
+* Lower-case is recommended.
+* Values can be empty.
+* Keys cannot contain `:`, `=`, `[`, or `]`.
+* Comments must start at the beginning of the line with `;` or `#`.
+
+An example configuration file:
+
+``` ini
+# Some comment.
+[SERVER]
+port=6667
+hostname=localhost
+[AUTH]
+user=hello
+pass=world
+# Salt can be an empty string.
+salt=
+```
+
+Parsing example:
+
+``` haskell
+> parseIni "[SERVER]\nport: 6667\nhostname: localhost"
+Right (Ini {unIni = fromList [("SERVER",fromList [("hostname","localhost")
+                                                 ,("port","6667")])]})
+```
+
+Extracting values:
+
+``` haskell
+> parseIni "[SERVER]\nport: 6667\nhostname: localhost" >>=
+  lookupValue "SERVER" "hostname"
+Right "localhost"
+```
+
+Parsing:
+
+``` haskell
+> parseIni "[SERVER]\nport: 6667\nhostname: localhost" >>=
+  readValue "SERVER" "port" decimal
+Right 6667
+```
+
+Import `Data.Text.Read` to use `decimal`.
+
+## Related packages
+
+[`ini-qq`](https://hackage.haskell.org/package/ini-qq) provides a quasiquoter for INI.
diff --git a/ini.cabal b/ini.cabal
--- a/ini.cabal
+++ b/ini.cabal
@@ -1,30 +1,57 @@
+cabal-version:       >= 1.10
 name:                ini
-version:             0.4.1
-synopsis:            Quick and easy configuration files in the INI format.
+version:             0.4.2
+synopsis:            Configuration files in the INI format.
 description:         Quick and easy configuration files in the INI format.
 license:             BSD3
 license-file:        LICENSE
 author:              Chris Done
-maintainer:          chrisdone@gmail.com
-homepage:            http://github.com/chrisdone/ini
-bug-reports:         http://github.com/chrisdone/ini/issues
+maintainer:          Andreas Abel
+homepage:            https://github.com/andreasabel/ini
+bug-reports:         https://github.com/andreasabel/ini/issues
 copyright:           2013 Chris Done
 category:            Data, Configuration
 build-type:          Simple
-cabal-version:       >=1.8
 
+tested-with:
+  GHC == 9.4.1
+  GHC == 9.2.3
+  GHC == 9.0.2
+  GHC == 8.10.7
+  GHC == 8.8.4
+  GHC == 8.6.5
+  GHC == 8.4.4
+  GHC == 8.2.2
+  GHC == 8.0.2
+  GHC == 7.10.3
+  GHC == 7.8.4
+  GHC == 7.6.3
+  GHC == 7.4.2
+  GHC == 7.2.2
+  GHC == 7.0.4
+
+extra-source-files:
+  CHANGELOG.md
+  README.md
+
 library
   hs-source-dirs:    src/
-  ghc-options:       -Wall -O2
-  extensions:        OverloadedStrings
   exposed-modules:   Data.Ini
   build-depends:     base >= 4 && <5,
                      attoparsec,
                      text,
                      unordered-containers
   if !impl(ghc >= 8)
-    build-depends: semigroups >= 0.10 && < 0.19
+    build-depends: semigroups >= 0.10 && < 0.21
 
+  default-language:   Haskell98
+  default-extensions: OverloadedStrings
+                      TypeOperators
+
+  ghc-options:        -Wall
+  if impl(ghc >= 8)
+    ghc-options:      -Wcompat
+
 test-suite ini-test
   type: exitcode-stdio-1.0
   hs-source-dirs: test
@@ -34,6 +61,8 @@
                    , hspec
                    , unordered-containers
 
+  default-language:  Haskell98
+
 source-repository head
   type:     git
-  location: http://github.com/chrisdone/ini.git
+  location: https://github.com/andreasabel/ini.git
diff --git a/src/Data/Ini.hs b/src/Data/Ini.hs
--- a/src/Data/Ini.hs
+++ b/src/Data/Ini.hs
@@ -75,7 +75,6 @@
 import           Data.HashMap.Strict        (HashMap)
 import qualified Data.HashMap.Strict        as M
 import Data.Maybe
-import           Data.Monoid (Monoid)
 import           Data.Semigroup
 import           Data.Text                  (Text)
 import qualified Data.Text                  as T
@@ -91,13 +90,13 @@
   deriving (Show, Eq)
 
 instance Semigroup Ini where
-  (<>) = mappend
+  x <> y = Ini {iniGlobals = mempty, iniSections = iniSections x <> iniSections y}
 
 instance Monoid Ini where
   mempty = Ini {iniGlobals = mempty, iniSections = mempty}
-  mappend x y =
-    Ini {iniGlobals = mempty, iniSections = iniSections x <> iniSections y}
+  mappend = (<>)
 
+
 {-# DEPRECATED #-}
 unIni :: Ini -> HashMap Text (HashMap Text Text)
 unIni = fmap M.fromList . iniSections
@@ -230,7 +229,8 @@
 -- | Print an INI config.
 printIniWith :: WriteIniSettings -> Ini -> Text
 printIniWith wis i =
-  T.concat (map buildSection (M.toList (iniSections i)))
+  T.concat $ (map buildPair (iniGlobals i)) ++
+             (map buildSection (M.toList (iniSections i)))
   where buildSection (name,pairs) =
           "[" <> name <> "]\n" <>
           T.concat (map buildPair pairs)
@@ -245,7 +245,8 @@
 iniParser =
   (\kv secs -> Ini {iniSections = M.fromList secs, iniGlobals = kv}) <$>
   many keyValueParser <*>
-  many sectionParser
+  many sectionParser <*
+  (endOfInput <|> (fail . T.unpack =<< takeWhile (not . isControl)))
 
 -- | A section. Format: @[foo]@. Conventionally, @[FOO]@.
 sectionParser :: Parser (Text,[(Text, Text)])
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -64,4 +64,11 @@
                                ]
                          , iniGlobals =
                              [("port", "6667"), ("hostname", "localhost")]
-                         })))))
+                         })))
+              it
+                "File with invalid keys"
+                (shouldBe
+                   (parseIni
+                      "Name=Foo\n\
+                      \Name[en_GB]=Fubar")
+                   (Left "Failed reading: Name[en_GB]=Fubar"))))
