do quoting in INI and help
diff --git a/convert.go b/convert.go
index be8de39..e805e1f 100644
--- a/convert.go
+++ b/convert.go
@@ -294,6 +294,14 @@
 	return nil
 }
 
+func quoteIfNeeded(s string) string {
+	if strconv.CanBackquote(s) {
+		return s
+	}
+
+	return strconv.Quote(s)
+}
+
 func wrapText(s string, l int, prefix string) string {
 	// Basic text wrapping of s at spaces to fit in l
 	var ret string
diff --git a/help.go b/help.go
index d16f3b1..208e936 100644
--- a/help.go
+++ b/help.go
@@ -171,7 +171,17 @@
 				def, _ = convertToString(option.value, option.tag)
 			}
 		} else if len(defs) != 0 {
-			def = strings.Join(defs, ", ")
+			if option.field.Type.Kind() == reflect.String {
+				l := len(defs) - 1
+
+				for i := 0; i < l; i++ {
+					def += quoteIfNeeded(defs[i]) + ", "
+				}
+
+				def += quoteIfNeeded(defs[l])
+			} else {
+				def = strings.Join(defs, ", ")
+			}
 		}
 
 		var envDef string
@@ -188,8 +198,7 @@
 		var desc string
 
 		if def != "" {
-			desc = fmt.Sprintf("%s (%v)%s", option.Description, def,
-				envDef)
+			desc = fmt.Sprintf("%s (%v)%s", option.Description, def, envDef)
 		} else {
 			desc = option.Description + envDef
 		}
diff --git a/help_test.go b/help_test.go
index def3043..6ce55ed 100644
--- a/help_test.go
+++ b/help_test.go
@@ -15,7 +15,7 @@
 	PtrSlice         []*string    `long:"ptrslice" description:"A slice of pointers to string"`
 	EmptyDescription bool         `long:"empty-description"`
 
-	Default      string            `long:"default" default:"Some value" description:"Test default value"`
+	Default      string            `long:"default" default:"Some\nvalue" description:"Test default value"`
 	DefaultArray []string          `long:"default-array" default:"Some value" default:"Another value" description:"Test default array value"`
 	DefaultMap   map[string]string `long:"default-map" default:"some:value" default:"another:value" description:"Testdefault map value"`
 	EnvDefault1  string            `long:"env-default1" default:"Some value" env:"ENV_DEFAULT" description:"Test env-default1 value"`
@@ -79,7 +79,7 @@
   /c:                      Call phone number
       /ptrslice:           A slice of pointers to string
       /empty-description
-      /default:            Test default value (Some value)
+      /default:            Test default value ("Some\nvalue")
       /default-array:      Test default array value (Some value, Another value)
       /default-map:        Testdefault map value (some:value, another:value)
       /env-default1:       Test env-default1 value (Some value) [%ENV_DEFAULT%]
@@ -115,7 +115,7 @@
   -c=                      Call phone number
       --ptrslice=          A slice of pointers to string
       --empty-description
-      --default=           Test default value (Some value)
+      --default=           Test default value ("Some\nvalue")
       --default-array=     Test default array value (Some value, Another value)
       --default-map=       Testdefault map value (some:value, another:value)
       --env-default1=      Test env-default1 value (Some value) [$ENV_DEFAULT]
diff --git a/ini_private.go b/ini_private.go
index 2e72b87..b35cffb 100644
--- a/ini_private.go
+++ b/ini_private.go
@@ -7,16 +7,21 @@
 	"os"
 	"reflect"
 	"sort"
+	"strconv"
 	"strings"
 )
 
 type iniValue struct {
-	Name  string
-	Value string
+	Name       string
+	Value      string
+	LineNumber uint
 }
 
 type iniSection []iniValue
-type ini map[string]iniSection
+type ini struct {
+	File     string
+	Sections map[string]iniSection
+}
 
 func readFullLine(reader *bufio.Reader) (string, error) {
 	var line []byte
@@ -76,6 +81,18 @@
 	sectionwritten := false
 	comments := (options & IniIncludeComments) != IniNone
 
+	printOption := func(commentOption string, optionName string, optionType reflect.Kind, optionKey string, optionValue string) {
+		if optionType == reflect.String {
+			optionValue = quoteIfNeeded(optionValue)
+		}
+
+		if optionKey == "" {
+			fmt.Fprintf(writer, "%s%s = %s\n", commentOption, optionName, optionValue)
+		} else {
+			fmt.Fprintf(writer, "%s%s = %s:%s\n", commentOption, optionName, optionKey, optionValue)
+		}
+	}
+
 	for _, option := range group.options {
 		if option.isFunc() {
 			continue
@@ -107,11 +124,12 @@
 			commentOption = "; "
 		}
 
-		switch val.Type().Kind() {
+		kind := val.Type().Kind()
+		switch kind {
 		case reflect.Slice:
 			for idx := 0; idx < val.Len(); idx++ {
 				v, _ := convertToString(val.Index(idx), option.tag)
-				fmt.Fprintf(writer, "%s%s = %s\n", commentOption, oname, v)
+				printOption(commentOption, oname, val.Type().Elem().Kind(), "", v)
 			}
 
 			if val.Len() == 0 {
@@ -132,7 +150,7 @@
 			for _, k := range keys {
 				v, _ := convertToString(val.MapIndex(kkmap[k]), option.tag)
 
-				fmt.Fprintf(writer, "%s%s = %s:%s\n", commentOption, oname, k, v)
+				printOption(commentOption, oname, val.Type().Elem().Kind(), k, v)
 			}
 
 			if val.Len() == 0 {
@@ -142,7 +160,7 @@
 			v, _ := convertToString(val, option.tag)
 
 			if len(v) != 0 {
-				fmt.Fprintf(writer, "%s%s = %s\n", commentOption, oname, v)
+				printOption(commentOption, oname, kind, "", v)
 			} else {
 				fmt.Fprintf(writer, "%s%s =\n", commentOption, oname)
 			}
@@ -194,7 +212,7 @@
 	return nil
 }
 
-func readIniFromFile(filename string) (ini, error) {
+func readIniFromFile(filename string) (*ini, error) {
 	file, err := os.Open(filename)
 
 	if err != nil {
@@ -206,8 +224,11 @@
 	return readIni(file, filename)
 }
 
-func readIni(contents io.Reader, filename string) (ini, error) {
-	ret := make(ini)
+func readIni(contents io.Reader, filename string) (*ini, error) {
+	ret := &ini{
+		File:     filename,
+		Sections: make(map[string]iniSection),
+	}
 
 	reader := bufio.NewReader(contents)
 
@@ -215,7 +236,7 @@
 	section := make(iniSection, 0, 10)
 	sectionname := ""
 
-	ret[sectionname] = section
+	ret.Sections[sectionname] = section
 
 	var lineno uint
 
@@ -256,11 +277,11 @@
 			}
 
 			sectionname = name
-			section = ret[name]
+			section = ret.Sections[name]
 
 			if section == nil {
 				section = make(iniSection, 0, 10)
-				ret[name] = section
+				ret.Sections[name] = section
 			}
 
 			continue
@@ -280,12 +301,25 @@
 		name := strings.TrimSpace(keyval[0])
 		value := strings.TrimSpace(keyval[1])
 
+		if len(value) != 0 && value[0] == '"' {
+			if v, err := strconv.Unquote(value); err == nil {
+				value = v
+			} else {
+				return nil, &IniError{
+					Message:    err.Error(),
+					File:       filename,
+					LineNumber: lineno,
+				}
+			}
+		}
+
 		section = append(section, iniValue{
-			Name:  name,
-			Value: value,
+			Name:       name,
+			Value:      value,
+			LineNumber: lineno,
 		})
 
-		ret[sectionname] = section
+		ret.Sections[sectionname] = section
 	}
 
 	return ret, nil
@@ -311,10 +345,10 @@
 	return nil
 }
 
-func (i *IniParser) parse(ini ini) error {
+func (i *IniParser) parse(ini *ini) error {
 	p := i.parser
 
-	for name, section := range ini {
+	for name, section := range ini.Sections {
 		groups := i.matchingGroups(name)
 
 		if len(groups) == 0 {
@@ -343,10 +377,11 @@
 
 			if opt == nil {
 				if (p.Options & IgnoreUnknown) == None {
-					return newError(
-						ErrUnknownFlag,
-						fmt.Sprintf("unknown option: %s", inival.Name),
-					)
+					return &IniError{
+						Message:    fmt.Sprintf("unknown option: %s", inival.Name),
+						File:       ini.File,
+						LineNumber: inival.LineNumber,
+					}
 				}
 
 				continue
@@ -356,10 +391,35 @@
 
 			if !opt.canArgument() && len(inival.Value) == 0 {
 				pval = nil
+			} else {
+				if opt.value.Type().Kind() == reflect.Map {
+					parts := strings.SplitN(inival.Value, ":", 2)
+
+					// only handle unquoting
+					if len(parts) == 2 && parts[1][0] == '"' {
+						if v, err := strconv.Unquote(parts[1]); err == nil {
+							parts[1] = v
+						} else {
+							return &IniError{
+								Message:    err.Error(),
+								File:       ini.File,
+								LineNumber: inival.LineNumber,
+							}
+						}
+
+						s := parts[0] + ":" + parts[1]
+
+						pval = &s
+					}
+				}
 			}
 
 			if err := opt.set(pval); err != nil {
-				return wrapError(err)
+				return &IniError{
+					Message:    err.Error(),
+					File:       ini.File,
+					LineNumber: inival.LineNumber,
+				}
 			}
 
 			opt.tag.Set("_read-ini-name", inival.Name)
diff --git a/ini_test.go b/ini_test.go
index e2b5cdc..888e56c 100644
--- a/ini_test.go
+++ b/ini_test.go
@@ -5,6 +5,7 @@
 	"fmt"
 	"io/ioutil"
 	"os"
+	"reflect"
 	"strings"
 	"testing"
 )
@@ -54,7 +55,7 @@
 EmptyDescription = false
 
 ; Test default value
-Default = Some value
+Default = "Some\nvalue"
 
 ; Test default array value
 DefaultArray = Some value
@@ -109,7 +110,7 @@
 ; EmptyDescription = false
 
 ; Test default value
-; Default = Some value
+; Default = "Some\nvalue"
 
 ; Test default array value
 ; DefaultArray = Some value
@@ -242,16 +243,23 @@
 verbose = true
 verbose = true
 
+DefaultMap = another:"value\n1"
+DefaultMap = some:value 2
+
 [Application Options]
 ; A slice of pointers to string
 ; PtrSlice =
 
 ; Test default value
-Default = Some value
+Default = "New\nvalue"
+
+; Test env-default1 value
+EnvDefault1 = New value
 
 [Other Options]
 # A slice of strings
-# StringSlice =
+StringSlice = "some\nvalue"
+StringSlice = another value
 
 ; A map from string to int
 int-map = a:2
@@ -268,6 +276,16 @@
 
 	assertBoolArray(t, opts.Verbose, []bool{true, true})
 
+	if v := map[string]string{"another": "value\n1", "some": "value 2"}; !reflect.DeepEqual(opts.DefaultMap, v) {
+		t.Fatalf("Expected %#v for DefaultMap but got %#v", v, opts.DefaultMap)
+	}
+
+	assertString(t, opts.Default, "New\nvalue")
+
+	assertString(t, opts.EnvDefault1, "New value")
+
+	assertStringArray(t, opts.Other.StringSlice, []string{"some\nvalue", "another value"})
+
 	if v, ok := opts.Other.IntMap["a"]; !ok {
 		t.Errorf("Expected \"a\" in Other.IntMap")
 	} else if v != 2 {
@@ -281,6 +299,60 @@
 	}
 }
 
+func TestReadIniWrongQuoting(t *testing.T) {
+	var tests = []struct {
+		iniFile    string
+		lineNumber uint
+	}{
+		{
+			iniFile:    `Default = "New\nvalue`,
+			lineNumber: 1,
+		},
+		{
+			iniFile:    `StringSlice = "New\nvalue`,
+			lineNumber: 1,
+		},
+		{
+			iniFile: `StringSlice = "New\nvalue"
+			StringSlice = "Second\nvalue`,
+			lineNumber: 2,
+		},
+		{
+			iniFile:    `DefaultMap = some:"value`,
+			lineNumber: 1,
+		},
+		{
+			iniFile: `DefaultMap = some:value
+			DefaultMap = another:"value`,
+			lineNumber: 2,
+		},
+	}
+
+	for _, test := range tests {
+		var opts helpOptions
+
+		p := NewNamedParser("TestIni", Default)
+		p.AddGroup("Application Options", "The application options", &opts)
+
+		inip := NewIniParser(p)
+
+		inic := test.iniFile
+
+		b := strings.NewReader(inic)
+		err := inip.Parse(b)
+
+		if err == nil {
+			t.Fatalf("Expect error")
+		}
+
+		iniError := err.(*IniError)
+
+		if iniError.LineNumber != test.lineNumber {
+			t.Fatalf("Expect error on line %d", test.lineNumber)
+		}
+	}
+}
+
 func TestIniCommands(t *testing.T) {
 	var opts struct {
 		Value string `short:"v" long:"value"`
@@ -354,7 +426,15 @@
 		t.Fatalf("Expected error")
 	}
 
-	assertError(t, err, ErrUnknownFlag, "unknown option: value")
+	iniError := err.(*IniError)
+
+	if v := uint(2); iniError.LineNumber != v {
+		t.Errorf("Expected opts.Add.Name to be %d, but got %d", v, iniError.LineNumber)
+	}
+
+	if v := "unknown option: value"; iniError.Message != v {
+		t.Errorf("Expected opts.Add.Name to be %s, but got %s", v, iniError.Message)
+	}
 }
 
 func TestIniParse(t *testing.T) {