diff --git a/Cargo.toml b/Cargo.toml
index 6a80786399c8707baba7bfca68fa732e7a45d973..e316b7ec5d41f95977e0c5b2753634dbf5672b95 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,4 +13,4 @@ publish = false
 clap = "2.20.5"
 libc = "0.2.21"
 threadpool = "1.3.2"
-
+bytes = "0.4.6"
diff --git a/src/main.rs b/src/main.rs
index f33b63d0bb1475972e28bf30862339f89b542993..e53905aadf7b3a5fd8bd512105fe6bde6846c16b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,9 +21,12 @@ General Public License for more details.
 extern crate clap;
 extern crate libc;
 extern crate threadpool;
+extern crate bytes;
 
 use clap::{Arg, App};
 use std::os::unix::fs::{FileTypeExt, MetadataExt};
+use std::ffi::OsStr;
+use std::os::unix::ffi::OsStrExt;
 use std::fs::{Metadata};
 use std::path::{Path, PathBuf};
 use std::sync::mpsc::{channel, Receiver, Sender};
@@ -37,6 +40,8 @@ use libc::{c_int, time_t};
 use std::result::Result;
 use std::io::Error as IOError;
 use std::io::{self, Write};
+use bytes::BytesMut;
+use std::ops::Deref;
 
 mod libhash;
 use libhash::{FLAGS_CLEAR_XATTR, FLAGS_READ_XATTR, FLAGS_WRITE_XATTR,
@@ -47,8 +52,17 @@ use hash::{md5_file, md5_symlink, sha512_file, sha512_symlink};
 mod walk;
 
 macro_rules! reportln {
-    () => (writeln!(io::stderr()).unwrap_or(()));
-    ($($arg:tt)*) => (writeln!(io::stderr(), $($arg)*).unwrap_or(()));
+    () => (writeln!(io::stderr()).unwrap());
+    ($($arg:tt)*) => (writeln!(io::stderr(), $($arg)*).unwrap());
+}
+
+macro_rules! bprint {
+    ($($arg : tt)*) =>
+        (io::stdout().write_fmt(format_args!($($arg)*)).unwrap());
+}
+
+macro_rules! bwrite {
+    ($($arg : tt)+) => (io::stdout().write_all($($arg)+).unwrap());
 }
 
 // Extract clap optin as an Option<t>
@@ -58,7 +72,7 @@ macro_rules! option_t_or_exit {
             match v.trim().parse::<$t>() {
                 Ok(val) => Option::Some(val),
                 Err(_)  => {
-                    println!("Argument '--{} {}' cant be parsed as '{}'",
+                    reportln!("Argument '--{} {}' cant be parsed as '{}'",
                              $v, v, stringify!($t));
                     exit(1);
                 }
@@ -264,6 +278,34 @@ fn file_type_to_flag(file_type: &std::fs::FileType) -> char {
     else                                { unreachable!() }
 }
 
+fn check_name(name : &OsStr) -> bool {
+    let mut error = false;
+    // Check for control characters
+    for c in name.as_bytes() {
+        if c < &32u8 {
+            error = true;
+        }
+    }
+    let mut sane_name = BytesMut::from(name.as_bytes());
+    if error {
+        // Replace control chararcters for reporting
+        for c in sane_name.iter_mut() {
+            if *c < 32u8 {
+                *c = '?' as u8;
+            }
+        }
+    }
+    let p: &OsStr = OsStrExt::from_bytes(sane_name.deref());
+    error |= match p.to_str() {
+        Some(_) => false,
+        None => true,
+    };
+    if error {
+        reportln!("Invalid path {}", p.to_string_lossy());
+    }
+    ! error
+}
+
 fn dispatcher(options: clap::ArgMatches,
               from_walker: Receiver<WalkerMessage>) {
     let jobs = option_t_or_exit!(options, "jobs", usize).unwrap_or(1);
@@ -272,13 +314,24 @@ fn dispatcher(options: clap::ArgMatches,
     let calc_md5 = options.is_present("md5");
     let calc_sha512 = options.is_present("sha512");
     let (flags, maxage) = options_to_flags(&options);
+    let zero_terminated = options.is_present("zero-terminated");
+    macro_rules! zprintln {
+        () => (
+            if zero_terminated {
+                write!(io::stdout(), "\0").unwrap();
+            } else {
+                writeln!(io::stdout()).unwrap();
+            }
+        )
+    }
     let mut pool = WorkerPool::<WorkerMessage>::new(jobs);
     let mut worklist = WorkList::new();
     let mut done = false;
-    print!("#fields: size:mtime:uid:gid:mode:");
-    if calc_md5 { print!("md5:"); }
-    if calc_sha512 { print!("sha512:"); }
-    println!("kind:name");
+    bprint!("#fields: size:mtime:uid:gid:mode:");
+    if calc_md5 { bprint!("md5:"); }
+    if calc_sha512 { bprint!("sha512:"); }
+    bprint!("kind:name");
+    zprintln!();
     loop {
         // reportln!("XXX {} {} {}", done, pending, worklist.used());
         if done && worklist.used() == 0 {
@@ -445,34 +498,39 @@ fn dispatcher(options: clap::ArgMatches,
                         _ => ()
                     }
                 };
+                if ! (zero_terminated ||
+                      check_name(front.inode.path.as_os_str())) {
+                    continue
+                }
                 match front.kind {
                     ' ' => {
                         // Start of new path
-                        println!("#path: {}", front.inode.path.display());
+                        bprint!("#path: {}", front.inode.path.display());
+                        zprintln!();
                         continue
                     },
                     'F' | 'L' => {
                         let m = &front.inode.metadata.unwrap();
-                        print!("{}:{}:{}:{}:{:o}:",
+                        bprint!("{}:{}:{}:{}:{:o}:",
                                m.size(), m.mtime(), m.uid(), m.gid(),
                                m.mode() & 0o7777);
                     },
                     _ => {
                         let m = &front.inode.metadata.unwrap();
-                        print!("::{}:{}:{:o}:",
+                        bprint!("::{}:{}:{:o}:",
                                m.uid(), m.gid(), m.mode() & 0o7777);
                     }
                 }
                 use HashOption::{None,Some,Unused};
                 match *front.md5.borrow() {
-                    None => print!(":"),
-                    Some(ref hash) => print!("{}:", hash),
+                    None => bprint!(":"),
+                    Some(ref hash) => bprint!("{}:", hash),
                     Unused => (),
                     _ => unreachable!()
                 }
                 match *front.sha512.borrow() {
-                    None => print!(":"),
-                    Some(ref hash) => print!("{}:", hash),
+                    None => bprint!(":"),
+                    Some(ref hash) => bprint!("{}:", hash),
                     Unused => (),
                     _ => unreachable!()
                 }                
@@ -483,11 +541,14 @@ fn dispatcher(options: clap::ArgMatches,
                         _ => break
                     }
                 }
-                println!("{}:{}", front.kind, path.display());
+                bprint!("{}", front.kind);
+                bwrite!(path.as_os_str().as_bytes());
+                zprintln!();
             }
         }
     }
-    println!("#endTOC")
+    bprint!("#endTOC");
+    zprintln!();
 }
 
 fn main() {
@@ -541,6 +602,9 @@ fn main() {
              .short("q")
              .conflicts_with("verbose")
              .help("Sets the level of verbosity"))
+        .arg(Arg::with_name("zero-terminated")
+             .short("z")
+             .help("End lines with NULL character"))
         .arg(Arg::with_name("max_age")
              .short("m")
              .long("max-age")