# 
# patch "file_io.cc"
#  from [442fc17a140ef95f024c4aa58a22aa4a924a3cb8]
#    to [a0aa2132890ab180c6d3f3b7c6f0fd0651d22561]
# 
# patch "file_io.hh"
#  from [5712c71aa04e18828ae63e33ed0e0030d4d40e8d]
#    to [ed8b36e3af207cbe71e958a69ea2ad6bf27aaf91]
# 
# patch "lua.cc"
#  from [77f81c504baafa54e376a9eba1ae9d6257d398e7]
#    to [8e3dc407fa0118177ced26e34d0d6c76d74b3398]
# 
# patch "std_hooks.lua"
#  from [fd05c10e0f76992b9d421714d4430c9ae5c341f8]
#    to [e594ad7641a3682a3d92c1209374beb6dfb30de7]
# 
--- file_io.cc
+++ file_io.cc
@@ -1,3 +1,4 @@
+// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
 // copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
 // all rights reserved.
 // licensed to the public under the terms of the GNU GPL (>= 2)
@@ -276,15 +277,44 @@
   return true;
 }
 
-bool guess_binary(string const & s)
+static bool did_char_is_binary_init;
+static bool char_is_binary[256];
+
+void
+set_char_is_binary(char c, bool is_binary)
 {
+    char_is_binary[c] = is_binary;
+}
+
+static void
+init_char_is_binary()
+{
   // these do not occur in ASCII text files
   // FIXME: this heuristic is (a) crap and (b) hardcoded. fix both these.
-  if (s.find_first_of('\x00') != string::npos ||
-      s.find_first_of("\x01\x02\x03\x04\x05\x06\x0e\x0f"
-                      "\x10\x11\x12\x13\x14\x15\x16\x17\x18"
-                      "\x19\x1a\x1c\x1d\x1e\x1f") != string::npos)
-    return true;
+  // Should be calling a lua hook here that can use set_char_is_binary()
+  // That will at least fix (b)
+  string nontext_chars("\x01\x02\x03\x04\x05\x06\x0e\x0f"
+		       "\x10\x11\x12\x13\x14\x15\x16\x17\x18"
+		       "\x19\x1a\x1c\x1d\x1e\x1f");
+  set_char_is_binary('\0',true);
+  for(int i=0;i<nontext_chars.size();++i) 
+    {
+      set_char_is_binary(nontext_chars[i],true);
+    }
+}
+
+bool guess_binary(string const & s)
+{
+  if (did_char_is_binary_init == false) 
+    {
+      init_char_is_binary();
+    }
+
+  for(int i = 0;i<s.size(); ++i) 
+    {
+      if (char_is_binary[s[i]])
+        return true;
+    }
   return false;
 }
 
--- file_io.hh
+++ file_io.hh
@@ -61,8 +61,9 @@
 
 bool ident_existing_file(file_path const & p, file_id & ident, lua_hooks & lua);
 
-// returns true if the string content is binary according to monotone euristic
+// returns true if the string content is binary according to monotone heuristic
 bool guess_binary(std::string const & s);
+void set_char_is_binary(char c, bool is_binary);
 
 void mkdir_p(local_path const & path);
 void mkdir_p(file_path const & path);
--- lua.cc
+++ lua.cc
@@ -1,3 +1,4 @@
+// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
 // copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
 // all rights reserved.
 // licensed to the public under the terms of the GNU GPL (>= 2)
@@ -22,6 +23,7 @@
 
 #include <set>
 #include <map>
+#include <fstream>
 
 #include "app_state.hh"
 #include "file_io.hh"
@@ -495,11 +497,31 @@
   }
 
   static int
-  monotone_guess_binary_for_lua(lua_State *L)
+  monotone_guess_binary_filename_for_lua(lua_State *L)
   {
     const char *path = lua_tostring(L, -1);
     N(path, F("guess_binary called with an invalid parameter"));
-    lua_pushboolean(L, guess_binary(std::string(path, lua_strlen(L, -1))));
+
+    std::ifstream file(path);
+    if (!file) 
+      {
+        lua_pushnil(L);
+        return 1;
+      }
+    const int bufsize = 8192;
+    string buf;
+    while(file.good()) 
+      {
+        buf.resize(bufsize);
+        file.read(&buf[0],bufsize);
+        buf.resize(file.gcount());
+        if (guess_binary(buf)) 
+          {
+            lua_pushboolean(L, true);
+            return 1;
+          }
+      }
+    lua_pushboolean(L, false);
     return 1;
   }
   
@@ -578,7 +600,7 @@
   lua_register(st, "wait", monotone_wait_for_lua);
   lua_register(st, "kill", monotone_kill_for_lua);
   lua_register(st, "sleep", monotone_sleep_for_lua);
-  lua_register(st, "guess_binary", monotone_guess_binary_for_lua);
+  lua_register(st, "guess_binary_filename", monotone_guess_binary_filename_for_lua);
   lua_register(st, "include", monotone_include_for_lua);
   lua_register(st, "includedir", monotone_includedir_for_lua);
 }
--- std_hooks.lua
+++ std_hooks.lua
@@ -130,10 +130,7 @@
    if (string.find(lowname, "%.sql$")) then return false end
    -- unknown - read file and use the guess-binary 
    -- monotone built-in function
-   filedata=read_contents_of_file(name, "rb")
-   if (filedata ~= nil) then return guess_binary(filedata) end
-   -- still unknown (file empty or unreadable) - report it as nil
-   return nil
+   return guess_binary_filename(name)
 end
 
 function edit_comment(basetext, user_log_message)
