move set() to new file
diff --git a/read.go b/read.go
index a2b5220..32b2743 100644
--- a/read.go
+++ b/read.go
@@ -5,7 +5,6 @@
 	"fmt"
 	"io"
 	"os"
-	"reflect"
 	"regexp"
 	"strings"
 )
@@ -21,83 +20,6 @@
 	reVarDflt = regexp.MustCompile(`^\s*\b(.*)\b\s*$`)
 )
 
-const (
-	// Default value string in case a value for a variable isn't provided.
-	defaultValue = "true"
-)
-
-func fieldFold(v reflect.Value, name string) reflect.Value {
-	n := strings.Replace(name, "-", "_", -1)
-	return v.FieldByNameFunc(func(fieldName string) bool {
-		return strings.EqualFold(n, fieldName)
-	})
-}
-
-func set(cfg interface{}, sect, sub, name, value string) error {
-	vPCfg := reflect.ValueOf(cfg)
-	if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct {
-		panic(fmt.Errorf("config must be a pointer to a struct"))
-	}
-	vCfg := vPCfg.Elem()
-	vSect := fieldFold(vCfg, sect)
-	if !vSect.IsValid() {
-		return fmt.Errorf("invalid section: section %q", sect)
-	}
-	if vSect.Kind() == reflect.Map {
-		vst := vSect.Type()
-		if vst.Key().Kind() != reflect.String ||
-			vst.Elem().Kind() != reflect.Ptr ||
-			vst.Elem().Elem().Kind() != reflect.Struct {
-			panic(fmt.Errorf("map field for section must have string keys and "+
-				" pointer-to-struct values: section %q", sect))
-		}
-		if vSect.IsNil() {
-			vSect.Set(reflect.MakeMap(vst))
-		}
-		k := reflect.ValueOf(sub)
-		pv := vSect.MapIndex(k)
-		if !pv.IsValid() {
-			vType := vSect.Type().Elem().Elem()
-			pv = reflect.New(vType)
-			vSect.SetMapIndex(k, pv)
-		}
-		vSect = pv.Elem()
-	} else if vSect.Kind() != reflect.Struct {
-		panic(fmt.Errorf("field for section must be a map or a struct: "+
-			"section %q", sect))
-	} else if sub != "" {
-		return fmt.Errorf("invalid subsection: "+
-			"section %q subsection %q", sect, sub)
-	}
-	vName := fieldFold(vSect, name)
-	if !vName.IsValid() {
-		return fmt.Errorf("invalid variable: "+
-			"section %q subsection %q variable %q", sect, sub, name)
-	}
-	vAddr := vName.Addr().Interface()
-	switch v := vAddr.(type) {
-	case *string:
-		*v = value
-		return nil
-	case *bool:
-		vAddr = (*gbool)(v)
-	}
-	// attempt to read an extra rune to make sure the value is consumed
-	var r rune
-	n, err := fmt.Sscanf(value, "%v%c", vAddr, &r)
-	switch {
-	case n < 1 || n == 1 && err != io.EOF:
-		return fmt.Errorf("failed to parse %q as %#v: parse error %v", value,
-			vName.Type(), err)
-	case n > 1:
-		return fmt.Errorf("failed to parse %q as %#v: extra characters", value,
-			vName.Type())
-	case n == 1 && err == io.EOF:
-		return nil
-	}
-	panic("never reached")
-}
-
 // ReadInto reads gcfg formatted data from reader and sets the values into the
 // corresponding fields in config.
 //
diff --git a/set.go b/set.go
new file mode 100644
index 0000000..935a7a9
--- /dev/null
+++ b/set.go
@@ -0,0 +1,85 @@
+package gcfg
+
+import (
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+)
+
+const (
+	// Default value string in case a value for a variable isn't provided.
+	defaultValue = "true"
+)
+
+func fieldFold(v reflect.Value, name string) reflect.Value {
+	n := strings.Replace(name, "-", "_", -1)
+	return v.FieldByNameFunc(func(fieldName string) bool {
+		return strings.EqualFold(n, fieldName)
+	})
+}
+
+func set(cfg interface{}, sect, sub, name, value string) error {
+	vPCfg := reflect.ValueOf(cfg)
+	if vPCfg.Kind() != reflect.Ptr || vPCfg.Elem().Kind() != reflect.Struct {
+		panic(fmt.Errorf("config must be a pointer to a struct"))
+	}
+	vCfg := vPCfg.Elem()
+	vSect := fieldFold(vCfg, sect)
+	if !vSect.IsValid() {
+		return fmt.Errorf("invalid section: section %q", sect)
+	}
+	if vSect.Kind() == reflect.Map {
+		vst := vSect.Type()
+		if vst.Key().Kind() != reflect.String ||
+			vst.Elem().Kind() != reflect.Ptr ||
+			vst.Elem().Elem().Kind() != reflect.Struct {
+			panic(fmt.Errorf("map field for section must have string keys and "+
+				" pointer-to-struct values: section %q", sect))
+		}
+		if vSect.IsNil() {
+			vSect.Set(reflect.MakeMap(vst))
+		}
+		k := reflect.ValueOf(sub)
+		pv := vSect.MapIndex(k)
+		if !pv.IsValid() {
+			vType := vSect.Type().Elem().Elem()
+			pv = reflect.New(vType)
+			vSect.SetMapIndex(k, pv)
+		}
+		vSect = pv.Elem()
+	} else if vSect.Kind() != reflect.Struct {
+		panic(fmt.Errorf("field for section must be a map or a struct: "+
+			"section %q", sect))
+	} else if sub != "" {
+		return fmt.Errorf("invalid subsection: "+
+			"section %q subsection %q", sect, sub)
+	}
+	vName := fieldFold(vSect, name)
+	if !vName.IsValid() {
+		return fmt.Errorf("invalid variable: "+
+			"section %q subsection %q variable %q", sect, sub, name)
+	}
+	vAddr := vName.Addr().Interface()
+	switch v := vAddr.(type) {
+	case *string:
+		*v = value
+		return nil
+	case *bool:
+		vAddr = (*gbool)(v)
+	}
+	// attempt to read an extra rune to make sure the value is consumed
+	var r rune
+	n, err := fmt.Sscanf(value, "%v%c", vAddr, &r)
+	switch {
+	case n < 1 || n == 1 && err != io.EOF:
+		return fmt.Errorf("failed to parse %q as %#v: parse error %v", value,
+			vName.Type(), err)
+	case n > 1:
+		return fmt.Errorf("failed to parse %q as %#v: extra characters", value,
+			vName.Type())
+	case n == 1 && err == io.EOF:
+		return nil
+	}
+	panic("never reached")
+}