diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs
index 3a3117ee93e6abea5e3c14239a5462ad39b4d9b5..d134b7b18eb9b075028c3b9c16954f7a70da3880 100644
--- a/src/bindgen/config.rs
+++ b/src/bindgen/config.rs
@@ -12,7 +12,14 @@ pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
 
 #[derive(Debug, Clone, Deserialize)]
 #[serde(rename_all = "kebab-case")]
-pub enum Curly {
+pub enum Language {
+    Cxx,
+    C,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum Braces {
     SameLine,
     NextLine,
 }
@@ -25,20 +32,56 @@ pub enum Layout {
     Auto,
 }
 
-#[derive(Default, Debug, Clone, Deserialize)]
+#[derive(Debug, Clone, Deserialize)]
 #[serde(rename_all = "kebab-case")]
 #[serde(deny_unknown_fields)]
 #[serde(default)]
 pub struct Config {
-    pub file: FileConfig,
+    /// Optional text to output at the beginning of the file
+    pub header: Option<String>,
+    /// Optional text to output at the end of the file
+    pub trailer: Option<String>,
+    /// Optional text to output at major sections to deter manual editing
+    pub autogen_warning: Option<String>,
+    /// Include a comment with the version of cbindgen used to generate the file
+    pub include_version: bool,
+    /// The style to use for braces
+    pub braces: Braces,
+    /// The preferred length of a line, used for auto breaking function arguments
+    pub line_length: u32,
+    /// The amount of spaces in a tab
+    pub tab_width: u32,
+    /// The language to output bindings for
+    pub language: Language,
+    /// The configuration options for functions
     #[serde(rename = "fn")]
     pub function: FunctionConfig,
+    /// The configuration options for structs
     #[serde(rename = "struct")]
     pub structure: StructConfig,
+    /// The configuration options for enums
     #[serde(rename = "enum")]
     pub enumeration: EnumConfig,
 }
 
+impl Default for Config {
+    fn default() -> Config {
+        Config {
+            header: None,
+            trailer: None,
+            autogen_warning: None,
+            include_version: true,
+            braces: Braces::SameLine,
+            line_length: 100,
+            tab_width: 2,
+            language: Language::C,
+            function: FunctionConfig::default(),
+            structure: StructConfig::default(),
+            enumeration: EnumConfig::default(),
+        }
+    }
+}
+
 impl Config {
     pub fn from_file(file_name: &str) -> Result<Config, String> {
         fn read(file_name: &str) -> io::Result<String> {
@@ -77,29 +120,29 @@ impl Config {
  * then run `cbindgen -c wr gfx/webrender_bindings/ gfx/webrender_bindings/webrender_ffi_generated.h` */"###;
 
         Config {
-            file: FileConfig {
-                header: Some(String::from(license)),
-                trailer: None,
-                autogen_warning: Some(String::from(autogen)),
-                include_version: Some(true),
-            },
+            header: Some(String::from(license)),
+            trailer: None,
+            autogen_warning: Some(String::from(autogen)),
+            include_version: true,
+            braces: Braces::SameLine,
+            line_length: 100,
+            tab_width: 2,
+            language: Language::Cxx,
             function: FunctionConfig {
                 prefix: Some(String::from("WR_INLINE")),
                 postfix: Some(String::from("WR_FUNC")),
-                args: Some(Layout::Horizontal),
+                args: Layout::Horizontal,
             },
             structure: StructConfig {
-                derive_eq: Some(true),
-                derive_neq: Some(false),
-                derive_lt: Some(false),
-                derive_lte: Some(false),
-                derive_gt: Some(false),
-                derive_gte: Some(false),
-                braces: Some(Curly::SameLine),
+                derive_eq: true,
+                derive_neq: false,
+                derive_lt: false,
+                derive_lte: false,
+                derive_gt: false,
+                derive_gte: false,
             },
             enumeration: EnumConfig {
-                add_sentinel: Some(true),
-                braces: Some(Curly::SameLine),
+                add_sentinel: true,
             },
         }
     }
@@ -113,22 +156,7 @@ impl Config {
     }
 }
 
-#[derive(Default, Debug, Clone, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-#[serde(deny_unknown_fields)]
-#[serde(default)]
-pub struct FileConfig {
-    /// Optional text to output at the beginning of the file
-    pub header: Option<String>,
-    /// Optional text to output at the end of the file
-    pub trailer: Option<String>,
-    /// Optional text to output at major sections to deter manual editing
-    pub autogen_warning: Option<String>,
-    /// Include a comment with the version of cbindgen used to generate the file
-    pub include_version: Option<bool>,
-}
-
-#[derive(Default, Debug, Clone, Deserialize)]
+#[derive(Debug, Clone, Deserialize)]
 #[serde(rename_all = "kebab-case")]
 #[serde(deny_unknown_fields)]
 #[serde(default)]
@@ -138,7 +166,17 @@ pub struct FunctionConfig {
     /// Optional text to output after each function declaration
     pub postfix: Option<String>,
     /// The style to layout the args
-    pub args: Option<Layout>,
+    pub args: Layout,
+}
+
+impl Default for FunctionConfig {
+    fn default() -> FunctionConfig {
+        FunctionConfig {
+            prefix: None,
+            postfix: None,
+            args: Layout::Auto,
+        }
+    }
 }
 
 impl FunctionConfig {
@@ -163,25 +201,36 @@ impl FunctionConfig {
     }
 }
 
-#[derive(Default, Debug, Clone, Deserialize)]
+#[derive(Debug, Clone, Deserialize)]
 #[serde(rename_all = "kebab-case")]
 #[serde(deny_unknown_fields)]
 #[serde(default)]
 pub struct StructConfig {
     /// Whether to generate a piecewise equality operator
-    pub derive_eq: Option<bool>,
+    pub derive_eq: bool,
     /// Whether to generate a piecewise inequality operator
-    pub derive_neq: Option<bool>,
+    pub derive_neq: bool,
     /// Whether to generate a less than operator on structs with one field
-    pub derive_lt: Option<bool>,
+    pub derive_lt: bool,
     /// Whether to generate a less than or equal to operator on structs with one field
-    pub derive_lte: Option<bool>,
+    pub derive_lte: bool,
     /// Whether to generate a greater than operator on structs with one field
-    pub derive_gt: Option<bool>,
+    pub derive_gt: bool,
     /// Whether to generate a greater than or equal to operator on structs with one field
-    pub derive_gte: Option<bool>,
-    /// The style to use for braces
-    pub braces: Option<Curly>,
+    pub derive_gte: bool,
+}
+
+impl Default for StructConfig {
+    fn default() -> StructConfig {
+        StructConfig {
+            derive_eq: false,
+            derive_neq: false,
+            derive_lt: false,
+            derive_lte: false,
+            derive_gt: false,
+            derive_gte: false,
+        }
+    }
 }
 
 impl StructConfig {
@@ -192,7 +241,7 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-eq") {
             return x;
         }
-        self.derive_eq.unwrap_or(false)
+        self.derive_eq
     }
     pub fn derive_neq(&self, directives: &DirectiveSet) -> bool {
         if let Some(x) = directives.bool("struct-gen-op-neq") {
@@ -201,7 +250,7 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-neq") {
             return x;
         }
-        self.derive_neq.unwrap_or(false)
+        self.derive_neq
     }
     pub fn derive_lt(&self, directives: &DirectiveSet) -> bool {
         if let Some(x) = directives.bool("struct-gen-op-lt") {
@@ -210,7 +259,7 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-lt") {
             return x;
         }
-        self.derive_lt.unwrap_or(false)
+        self.derive_lt
     }
     pub fn derive_lte(&self, directives: &DirectiveSet) -> bool {
         if let Some(x) = directives.bool("struct-gen-op-lte") {
@@ -219,7 +268,7 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-lte") {
             return x;
         }
-        self.derive_lte.unwrap_or(false)
+        self.derive_lte
     }
     pub fn derive_gt(&self, directives: &DirectiveSet) -> bool {
         if let Some(x) = directives.bool("struct-gen-op-gt") {
@@ -228,7 +277,7 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-gt") {
             return x;
         }
-        self.derive_gt.unwrap_or(false)
+        self.derive_gt
     }
     pub fn derive_gte(&self, directives: &DirectiveSet) -> bool {
         if let Some(x) = directives.bool("struct-gen-op-gte") {
@@ -237,20 +286,26 @@ impl StructConfig {
         if let Some(x) = directives.bool("derive-gte") {
             return x;
         }
-        self.derive_gte.unwrap_or(false)
+        self.derive_gte
     }
 }
 
-#[derive(Default, Debug, Clone, Deserialize)]
+#[derive( Debug, Clone, Deserialize)]
 #[serde(rename_all = "kebab-case")]
 #[serde(deny_unknown_fields)]
 #[serde(default)]
 pub struct EnumConfig {
     /// Whether to add a `Sentinel` value at the end of every enum
     /// This is useful in Gecko for IPC serialization
-    pub add_sentinel: Option<bool>,
-    /// The style to use for braces
-    pub braces: Option<Curly>,
+    pub add_sentinel: bool,
+}
+
+impl Default for EnumConfig {
+    fn default() -> EnumConfig {
+        EnumConfig {
+            add_sentinel: false,
+        }
+    }
 }
 
 impl EnumConfig {
@@ -261,6 +316,6 @@ impl EnumConfig {
         if let Some(x) = directives.bool("add-sentinel") {
             return x;
         }
-        self.add_sentinel.unwrap_or(false)
+        self.add_sentinel
     }
 }
diff --git a/src/bindgen/items.rs b/src/bindgen/items.rs
index 3b2162b4bf95aee3890d79e52ee3958226ab7555..3173a8944899b64113f51da350c4ca8e0970be24 100644
--- a/src/bindgen/items.rs
+++ b/src/bindgen/items.rs
@@ -7,6 +7,7 @@ use bindgen::config::Config;
 use bindgen::directive::*;
 use bindgen::library::*;
 use bindgen::syn_helpers::*;
+use bindgen::writer::*;
 
 #[derive(Debug, Clone)]
 pub enum PrimitiveType {
@@ -188,81 +189,80 @@ impl Type {
         }
     }
 
-    fn write<F: Write>(&self, out: &mut F) {
+    fn write<F: Write>(&self, out: &mut Writer<F>) {
         match self {
             &Type::ConstPtr(ref t) => {
-                write!(out, "const ").unwrap();
+                out.write("const ");
                 t.write(out);
-                write!(out, "*").unwrap();
+                out.write("*");
             }
             &Type::Ptr(ref t) => {
                 t.write(out);
-                write!(out, "*").unwrap();
+                out.write("*");
             }
             &Type::Path(ref p) => {
-                write!(out, "{}", p).unwrap();
+                out.write(p);
             }
             &Type::Primitive(ref p) => {
-                write!(out, "{}", p).unwrap();
+                out.write(&format!("{}", p));
             }
             &Type::Array(ref t, ref sz) => {
                 t.write(out);
-                write!(out, "[{}]", sz).unwrap();
+                out.write(&format!("[{}]", sz));
             }
             &Type::FuncPtr(ref ret, ref args) => {
                 if let &Some(ref ret) = ret {
                     ret.write(out);
                 } else {
-                    write!(out, "void").unwrap();
+                    out.write("void");
                 }
-                write!(out, " (*)(").unwrap();
+                out.write(" (*)(");
                 for (i, arg) in args.iter().enumerate() {
                     if i != 0 {
-                        write!(out, ", ").unwrap();
+                        out.write(", ");
                     }
                     arg.write(out);
                 }
-                write!(out, ")").unwrap();
+                out.write(")");
             }
         }
     }
 
-    fn write_with_ident<F: Write>(&self, ident: &str, out: &mut F) {
+    fn write_with_ident<F: Write>(&self, ident: &str, out: &mut Writer<F>) {
         match self {
             &Type::ConstPtr(ref t) => {
-                write!(out, "const ").unwrap();
+                out.write("const ");
                 t.write(out);
-                write!(out, "* {}", ident).unwrap();
-
+                out.write(&format!("* {}", ident));
             }
             &Type::Ptr(ref t) => {
                 t.write(out);
-                write!(out, "* {}", ident).unwrap();
+                out.write(&format!("* {}", ident));
             }
             &Type::Path(ref p) => {
-                write!(out, "{} {}", p, ident).unwrap();
+                out.write(&format!("{} {}", p, ident));
             }
             &Type::Primitive(ref p) => {
-                write!(out, "{} {}", p, ident).unwrap();
+                out.write(&format!("{} {}", p, ident));
             }
             &Type::Array(ref t, ref sz) => {
                 t.write(out);
-                write!(out, " {}[{}]", ident, sz).unwrap();
+                out.write(&format!(" {}[{}]", ident, sz));
             }
             &Type::FuncPtr(ref ret, ref args) => {
                 if let &Some(ref ret) = ret {
                     ret.write(out);
                 } else {
-                    write!(out, "void").unwrap();
+                    out.write("void");
                 }
-                write!(out, " (*{})(", ident).unwrap();
+                out.write(&format!(" (*{})(", ident));
                 for (i, arg) in args.iter().enumerate() {
                     if i != 0 {
-                        write!(out, ", ").unwrap();
+                        out.write(", ");
                     }
                     arg.write(out);
                 }
-                write!(out, ")").unwrap();
+                out.write(")");
             }
         }
     }
@@ -305,29 +305,31 @@ impl Function {
         }
     }
 
-    pub fn write<F: Write>(&self, config: &Config, out: &mut F) {
+    pub fn write<F: Write>(&self, config: &Config, out: &mut Writer<F>) {
         if let Some(ref f) = config.function.prefix(&self.directives) {
-            write!(out, "{} ", f).unwrap();
+            out.write(&format!("{} ", f));
         }
 
         match self.ret.as_ref() {
             Some(ret) => ret.write(out),
-            None => write!(out, "void").unwrap(),
+            None => out.write("void"),
         }
 
-        write!(out, "\n{}(", self.name).unwrap();
+        out.new_line();
+        out.write(&format!("{}(", self.name));
         for (i, arg) in self.args.iter().enumerate() {
             if i != 0 {
-                write!(out, ",\n    ").unwrap();
+                out.write(",\n    ");
             }
             arg.1.write_with_ident(&arg.0, out);
         }
-        write!(out, ")").unwrap();
+        out.write(")");
 
         if let Some(ref f) = config.function.postfix(&self.directives) {
-            write!(out, "\n{}", f).unwrap();
+            out.new_line();
+            out.write(f)
         }
-        write!(out, ";").unwrap()
+        out.write(";");
     }
 }
 
@@ -383,11 +385,10 @@ impl Struct {
         }
     }
 
-    pub fn write<F: Write>(&self, config: &Config, out: &mut F) {
+    pub fn write<F: Write>(&self, config: &Config, out: &mut Writer<F>) {
         assert!(self.generic_params.is_empty());
 
-        writeln!(out, "struct {} {{", self.name).unwrap();
-
+        // Calculate overriden fields, should be done in convert
         let fields = match self.directives.list("field-names") {
             Some(overrides) => {
                 let mut fields = Vec::new();
@@ -405,102 +406,64 @@ impl Struct {
             _ => self.fields.clone(),
         };
 
+        out.write(&format!("struct {}", self.name));
+        out.open_brace();
+
         for (i, &(ref name, ref ty)) in fields.iter().enumerate() {
             if i != 0 {
-                write!(out, "\n").unwrap();
+                out.new_line()
             }
-            write!(out, "  ").unwrap();
             ty.write_with_ident(name, out);
-            write!(out, ";").unwrap();
+            out.write(";");
         }
 
-        write!(out, "\n").unwrap();
+        out.new_line();
 
-        if config.structure.derive_eq(&self.directives) && !self.fields.is_empty() {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator==(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " &&\n      ").unwrap();
-                }
-                write!(out, "{} == aOther.{}", field.0, field.0).unwrap();
-            }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
-        }
+        {
+            let mut emit_op = |op, conjuc| {
+                out.new_line();
 
-        if config.structure.derive_neq(&self.directives) && !self.fields.is_empty() {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator!=(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " ||\n      ").unwrap();
+                out.write(&format!("bool operator{}(const {}& aOther) const", op, self.name));
+                out.open_brace();
+                out.write("return ");
+                for (i, field) in fields.iter().enumerate() {
+                    if i == 1 {
+                        out.push_tab();
+                    }
+                    if i != 0 {
+                        out.write(&format!(" {}", conjuc));
+                        out.new_line();
+                    }
+                    out.write(&format!("{} {} aOther.{}", field.0, op, field.0));
                 }
-                write!(out, "{} != aOther.{}", field.0, field.0).unwrap();
-            }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
-        }
-
-        if config.structure.derive_lt(&self.directives) && self.fields.len() == 1 {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator<(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " &&\n      ").unwrap();
+                out.write(";");
+                if fields.len() > 1 {
+                    out.pop_tab();
                 }
-                write!(out, "{} < aOther.{}", field.0, field.0).unwrap();
-            }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
-        }
+                out.close_brace(false);
+            };
 
-        if config.structure.derive_lte(&self.directives) && self.fields.len() == 1 {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator<=(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " &&\n      ").unwrap();
-                }
-                write!(out, "{} <= aOther.{}", field.0, field.0).unwrap();
+            if config.structure.derive_eq(&self.directives) && !self.fields.is_empty() {
+                emit_op("==", "&&");
             }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
-        }
-
-        if config.structure.derive_gt(&self.directives) && self.fields.len() == 1 {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator>(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " &&\n      ").unwrap();
-                }
-                write!(out, "{} > aOther.{}", field.0, field.0).unwrap();
+            if config.structure.derive_neq(&self.directives) && !self.fields.is_empty() {
+                emit_op("!=", "||");
             }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
-        }
-
-        if config.structure.derive_gte(&self.directives) && self.fields.len() == 1 {
-            write!(out, "\n").unwrap();
-            write!(out, "  bool operator>=(const {}& aOther) const {{\n", self.name).unwrap();
-            write!(out, "    return ").unwrap();
-            for (i, field) in fields.iter().enumerate() {
-                if i != 0 {
-                    write!(out, " &&\n      ").unwrap();
-                }
-                write!(out, "{} > aOther.{}", field.0, field.0).unwrap();
+            if config.structure.derive_lt(&self.directives) && self.fields.len() == 1 {
+                emit_op("<", "&&");
+            }
+            if config.structure.derive_lte(&self.directives) && self.fields.len() == 1 {
+                emit_op("<=", "&&");
+            }
+            if config.structure.derive_gt(&self.directives) && self.fields.len() == 1 {
+                emit_op(">", "&&");
+            }
+            if config.structure.derive_gte(&self.directives) && self.fields.len() == 1 {
+                emit_op(">=", "&&");
             }
-            write!(out, ";\n  }}").unwrap();
-            write!(out, "\n").unwrap();
         }
 
-        write!(out, "}};").unwrap();
+        out.close_brace(true);
     }
 }
 
@@ -519,8 +482,8 @@ impl OpaqueStruct {
         }
     }
 
-    pub fn write<F: Write>(&self, out: &mut F) {
-        write!(out, "struct {};", self.name).unwrap();
+    pub fn write<F: Write>(&self, out: &mut Writer<F>) {
+        out.write(&format!("struct {};", self.name));
     }
 }
 
@@ -588,7 +551,7 @@ impl Enum {
         })
     }
 
-    pub fn write<F: Write>(&self, config: &Config, out: &mut F) {
+    pub fn write<F: Write>(&self, config: &Config, out: &mut Writer<F>) {
         let size = match self.repr {
             Repr::U32 => "uint32_t",
             Repr::U16 => "uint16_t",
@@ -596,17 +559,19 @@ impl Enum {
             _ => unreachable!(),
         };
 
-        writeln!(out, "enum class {} : {} {{", self.name, size).unwrap();
+        out.write(&format!("enum class {} : {} {{", self.name, size));
+        out.new_line();
         for (i, value) in self.values.iter().enumerate() {
             if i != 0 {
-                write!(out, "\n").unwrap();
+                out.new_line()
             }
-            write!(out, "  {} = {},", value.0, value.1).unwrap();
+            out.write(&format!("  {} = {},", value.0, value.1));
         }
         if config.enumeration.add_sentinel(&self.directives) {
-            write!(out, "\n\n  Sentinel /* this must be last for serialization purposes. */").unwrap();
+            out.write("\n\n  Sentinel /* this must be last for serialization purposes. */");
         }
-        write!(out, "\n}};").unwrap();
+        out.new_line();
+        out.write("};");
     }
 }
 
@@ -733,9 +698,9 @@ impl Typedef {
         self.aliased.add_deps(library, out);
     }
 
-    pub fn write<F: Write>(&self, out: &mut F) {
-        write!(out, "typedef ").unwrap();
+    pub fn write<F: Write>(&self, out: &mut Writer<F>) {
+        out.write("typedef ");
         self.aliased.write_with_ident(&self.name, out);
-        write!(out, ";").unwrap();
+        out.write(";");
     }
 }
diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs
index 748f962ce2bcbf30a277a1ee6c26292cb535aa6a..d40a1291b02d372100d81ff73886929537a7a1f1 100644
--- a/src/bindgen/library.rs
+++ b/src/bindgen/library.rs
@@ -11,6 +11,7 @@ use bindgen::directive::*;
 use bindgen::items::*;
 use bindgen::rust_lib;
 use bindgen::syn_helpers::*;
+use bindgen::writer::Writer;
 
 pub type ConvertResult<T> = Result<T, String>;
 pub type GenerateResult<T> = Result<T, String>;
@@ -371,33 +372,42 @@ impl<'a> GeneratedLibrary<'a> {
         self.write(&mut File::create(path).unwrap());
     }
 
-    pub fn write<F: Write>(&self, out: &mut F) {
-        if let Some(ref f) = self.config.file.header {
-            write!(out, "{}\n", f).unwrap();
+    pub fn write<F: Write>(&self, file: &mut F) {
+        let mut out = Writer::new(file, self.config);
+
+        if let Some(ref f) = self.config.header {
+            out.write(&f);
+            out.new_line();
         }
-        if self.config.file.include_version.unwrap_or(false) {
-            write!(out, "\n/* Generated with cbindgen:{} */\n", config::VERSION).unwrap();
+        if self.config.include_version {
+            out.new_line();
+            out.write(&format!("/* Generated with cbindgen:{} */", config::VERSION));
+            out.new_line();
         }
-        if let Some(ref f) = self.config.file.autogen_warning {
-            write!(out, "\n{}\n", f).unwrap();
+        if let Some(ref f) = self.config.autogen_warning {
+            out.new_line();
+            out.write(&f);
+            out.new_line();
         }
 
         for item in &self.items {
-            write!(out, "\n").unwrap();
+            out.new_line();
             match item {
-                &PathValue::Enum(ref x) => x.write(self.config, out),
-                &PathValue::Struct(ref x) => x.write(self.config, out),
-                &PathValue::OpaqueStruct(ref x) => x.write(out),
-                &PathValue::Typedef(ref x) => x.write(out),
+                &PathValue::Enum(ref x) => x.write(self.config, &mut out),
+                &PathValue::Struct(ref x) => x.write(self.config, &mut out),
+                &PathValue::OpaqueStruct(ref x) => x.write(&mut out),
+                &PathValue::Typedef(ref x) => x.write(&mut out),
                 &PathValue::Specialization(_) => {
                     panic!("should not encounter a specialization in a built library")
                 }
             }
-            write!(out, "\n").unwrap();
+            out.new_line();
         }
 
-        if let Some(ref f) = self.config.file.autogen_warning {
-            write!(out, "\n{}\n", f).unwrap();
+        if let Some(ref f) = self.config.autogen_warning {
+            out.new_line();
+            out.write(&f);
+            out.new_line();
         }
 
         for function in &self.functions {
@@ -405,16 +415,20 @@ impl<'a> GeneratedLibrary<'a> {
                 continue;
             }
 
-            write!(out, "\n").unwrap();
-            function.write(self.config, out);
-            write!(out, "\n").unwrap();
+            out.new_line();
+            function.write(self.config, &mut out);
+            out.new_line();
         }
 
-        if let Some(ref f) = self.config.file.autogen_warning {
-            write!(out, "\n{}\n", f).unwrap();
+        if let Some(ref f) = self.config.autogen_warning {
+            out.new_line();
+            out.write(&f);
+            out.new_line();
         }
-        if let Some(ref f) = self.config.file.trailer {
-            write!(out, "\n{}\n", f).unwrap();
+        if let Some(ref f) = self.config.trailer {
+            out.new_line();
+            out.write(&f);
+            out.new_line();
         }
     }
 }
diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs
index 88c43e7aaab41b7ae773eacb393ba1c87c9e79cb..c944378536eec164e02ede55e3179a9c2e467ddd 100644
--- a/src/bindgen/mod.rs
+++ b/src/bindgen/mod.rs
@@ -4,6 +4,7 @@ mod items;
 mod library;
 mod rust_lib;
 mod syn_helpers;
+mod writer;
 
 pub use self::config::*;
 pub use self::library::Library;
diff --git a/src/bindgen/writer.rs b/src/bindgen/writer.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f13dd64e7b0519156df65e14de86d6e402c2c747
--- /dev/null
+++ b/src/bindgen/writer.rs
@@ -0,0 +1,86 @@
+use bindgen::config::{Config, Braces};
+use std::io::Write;
+
+pub struct Writer<'a, 'f, F: 'f + Write> {
+    out: &'f mut F,
+    config: &'a Config,
+    tabs: Vec<u32>,
+    pending_spaces: u32,
+    has_written: bool,
+}
+
+impl<'a, 'f, F: Write> Writer<'a, 'f, F> {
+    pub fn new(out: &'f mut F, config: &'a Config) -> Writer<'a, 'f, F> {
+        Writer {
+            out: out,
+            config: config,
+            tabs: vec![0],
+            pending_spaces: 0,
+            has_written: false,
+        }
+    }
+
+    fn tabs(&mut self) -> u32 {
+        *self.tabs.last().unwrap()
+    }
+
+    pub fn push_tab(&mut self) {
+        let tabs = self.tabs() + 1;
+        self.tabs.push(tabs);
+
+        if !self.has_written {
+            self.pending_spaces = self.tabs() * self.config.tab_width;
+        }
+    }
+
+    pub fn pop_tab(&mut self) {
+        assert!(!self.tabs.is_empty());
+        self.tabs.pop();
+
+        if !self.has_written {
+            self.pending_spaces = self.tabs() * self.config.tab_width;
+        }
+    }
+
+    pub fn new_line(&mut self) {
+        write!(self.out, "\n").unwrap();
+        self.pending_spaces = self.tabs() * self.config.tab_width;
+        self.has_written = false;
+    }
+
+    pub fn open_brace(&mut self) {
+        match self.config.braces {
+            Braces::SameLine => {
+                write!(self.out, " {{").unwrap();
+                self.push_tab();
+                self.new_line();
+            }
+            Braces::NextLine => {
+                self.new_line();
+                write!(self.out, "{{").unwrap();
+                self.push_tab();
+                self.new_line();
+            }
+        }
+    }
+
+    pub fn close_brace(&mut self, semicolon: bool) {
+        self.pop_tab();
+        self.new_line();
+        if semicolon {
+            self.write("};");
+        } else {
+            self.write("}");
+        }
+    }
+
+    pub fn write(&mut self, text: &str) {
+        for _ in 0..self.pending_spaces {
+            write!(self.out, " ").unwrap();
+        }
+        self.pending_spaces = 0;
+        self.has_written = true;
+
+        write!(self.out, "{}", text).unwrap()
+    }
+}