--- Makefile.in
+++ Makefile.in
@@ -131,6 +131,14 @@ $(BEAMS): $(ERLBEHAVBEAMS)
 
 all-recursive: $(ERLBEHAVBEAMS)
 
+# Workaround for R11, that is not capable of compiling the new file:
+ram_file_io_server.beam:
+	-@ERLC@ -W $(EFLAGS) ram_file_io_server.erl
+ram_file_io_server_old.beam:
+	@ERLC@ -W $(EFLAGS) ram_file_io_server_old.erl
+	[ -f ram_file_io_server.beam ] \
+		|| cp ram_file_io_server_old.beam ram_file_io_server.beam
+
 %.beam:       %.erl
 	@ERLC@ -W $(EFLAGS) $<
 
--- ejabberd_loglevel.erl
+++ ejabberd_loglevel.erl
@@ -68,7 +68,8 @@ compile_string(Mod, Str) ->
     end.
    
 open_ram_file(Fname) ->
-    ram_file_io_server:start(self(), Fname, [read,write]).
+    RamModule = get_ram_module(),
+    RamModule:start(self(), Fname, [read,write]).
 
 close_ram_file(Fd) ->
     file:close(Fd).
@@ -85,6 +86,14 @@ load_logger(Forms, Mod, Loglevel) ->
             ?CRITICAL_MSG("Error ~p~n", [Error])
     end.
 
+%% Workaround for R11 and R12, that don't support the new module
+get_ram_module() ->
+    [AS, BS, _] = string:tokens(erlang:system_info(version), "."),
+    case (list_to_integer(AS) >= 5) and (list_to_integer(BS) >= 7) of
+	true -> ram_file_io_server;
+	false -> ram_file_io_server_old
+    end.
+
 %% --------------------------------------------------------------
 %% Code of the ejabberd logger, dynamically compiled and loaded
 %% This allows to dynamically change log level while keeping a
--- ram_file_io_server.erl
+++ ram_file_io_server.erl
@@ -25,7 +26,9 @@
 -export([format_error/1]).
 -export([start/3, start_link/3]).
 
--record(state, {handle,owner,mref,buf,read_mode}).
+-export([count_and_find/3]).
+
+-record(state, {handle,owner,mref,buf,read_mode,unic}).
 
 -define(PRIM_FILE, ram_file).
 -define(READ_SIZE_LIST, 128).
@@ -44,11 +47,11 @@ format_error(ErrorId) ->
     erl_posix_msg:message(ErrorId).
 
 start(Owner, FileName, ModeList) 
-  when pid(Owner), list(FileName), list(ModeList) ->
+  when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
     do_start(spawn, Owner, FileName, ModeList).
 
 start_link(Owner, FileName, ModeList) 
-  when pid(Owner), list(FileName), list(ModeList) ->
+  when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
     do_start(spawn_link, Owner, FileName, ModeList).
 
 %%%-----------------------------------------------------------------
@@ -61,27 +64,27 @@ do_start(Spawn, Owner, FileName, ModeList) ->
 	erlang:Spawn(
 	  fun() ->
 		  %% process_flag(trap_exit, true),
-		  {ReadMode,Opts} = 
-		      case lists:member(binary, ModeList) of
-			  true ->
-			      {binary,ModeList};
-			  false ->
-			      {list,[binary|ModeList]}
-		      end,
-		  case ?PRIM_FILE:open(FileName, Opts) of
-		      {error, Reason} = Error ->
-			  Self ! {Ref, Error},
-			  exit(Reason);
-		      {ok, Handle} ->
-			  %% XXX must I handle R6 nodes here?
-			  M = erlang:monitor(process, Owner),
-			  Self ! {Ref, ok},
-			  server_loop(
-			    #state{handle    = Handle,
-				   owner     = Owner, 
-				   mref      = M, 
-				   buf       = <<>>,
-				   read_mode = ReadMode})
+		  case parse_options(ModeList) of
+		      {ReadMode, UnicodeMode, Opts} ->
+			  case ?PRIM_FILE:open(FileName, Opts) of
+			      {error, Reason} = Error ->
+				  Self ! {Ref, Error},
+				  exit(Reason);
+			      {ok, Handle} ->
+				  %% XXX must I handle R6 nodes here?
+				  M = erlang:monitor(process, Owner),
+				  Self ! {Ref, ok},
+				  server_loop(
+				    #state{handle    = Handle,
+					   owner     = Owner, 
+					   mref      = M, 
+					   buf       = <<>>,
+					   read_mode = ReadMode,
+					   unic = UnicodeMode})
+			  end;
+		      {error,Reason1} = Error1 ->
+			  Self ! {Ref, Error1},
+			  exit(Reason1)
 		  end
 	  end),
     Mref = erlang:monitor(process, Pid),
@@ -102,9 +105,61 @@ do_start(Spawn, Owner, FileName, ModeList) ->
 	    {error, Reason}
     end.
 
+%%% Returns {ReadMode, UnicodeMode, RealOpts}
+parse_options(List) ->
+    parse_options(expand_encoding(List), list, latin1, []).
+
+parse_options([],list,Uni,Acc) ->
+    {list,Uni,[binary|lists:reverse(Acc)]};
+parse_options([],binary,Uni,Acc) ->
+    {binary,Uni,lists:reverse(Acc)};
+parse_options([{encoding, Encoding}|T],RMode,_,Acc) ->
+    case valid_enc(Encoding) of 
+	{ok, ExpandedEnc} ->
+	    parse_options(T,RMode,ExpandedEnc,Acc);
+	{error,Reason} ->
+	    {error,Reason}
+    end;
+parse_options([binary|T],_,Uni,Acc) ->
+    parse_options(T,binary,Uni,[binary|Acc]);
+parse_options([H|T],R,U,Acc) ->
+    parse_options(T,R,U,[H|Acc]).
+
+expand_encoding([]) ->
+    [];
+expand_encoding([latin1 | T]) ->
+    [{encoding,latin1} | expand_encoding(T)];
+expand_encoding([unicode | T]) ->
+    [{encoding,unicode} | expand_encoding(T)];
+expand_encoding([H|T]) ->
+    [H|expand_encoding(T)].
+
+valid_enc(latin1) ->
+    {ok,latin1};
+valid_enc(utf8) ->
+    {ok,unicode};
+valid_enc(unicode) ->
+    {ok,unicode};
+valid_enc(utf16) ->
+    {ok,{utf16,big}};
+valid_enc({utf16,big}) ->
+    {ok,{utf16,big}};
+valid_enc({utf16,little}) ->
+    {ok,{utf16,little}};
+valid_enc(utf32) ->
+    {ok,{utf32,big}};
+valid_enc({utf32,big}) ->
+    {ok,{utf32,big}};
+valid_enc({utf32,little}) ->
+    {ok,{utf32,little}};
+valid_enc(_Other) ->
+    {error,badarg}.
+
+
+
 server_loop(#state{mref = Mref} = State) ->
     receive
-	{file_request, From, ReplyAs, Request} when pid(From) ->
+	{file_request, From, ReplyAs, Request} when is_pid(From) ->
 	    case file_request(Request, State) of
 		{reply, Reply, NewState} ->
 		    file_reply(From, ReplyAs, Reply),
@@ -118,7 +173,7 @@ server_loop(#state{mref = Mref} = State) ->
 		    file_reply(From, ReplyAs, Reply),
 		    exit(Reason)
 	    end;
-	{io_request, From, ReplyAs, Request} when pid(From) ->
+	{io_request, From, ReplyAs, Request} when is_pid(From) ->
 	    case io_request(Request, State) of
 		{reply, Reply, NewState} ->
 		    io_reply(From, ReplyAs, Reply),
@@ -152,7 +207,7 @@ file_request({pread,At,Sz},
     case position(Handle, At, Buf) of
 	{ok,_Offs} ->
 	    case ?PRIM_FILE:read(Handle, Sz) of
-		{ok,Bin} when ReadMode==list ->
+		{ok,Bin} when ReadMode =:= list ->
 		    std_reply({ok,binary_to_list(Bin)}, State);
 		Reply ->
 		    std_reply(Reply, State)
@@ -203,42 +258,61 @@ std_reply(Reply, State) ->
 %%%-----------------------------------------------------------------
 %%% I/O request 
 
-io_request({put_chars,Chars}, % binary(Chars) new in R9C
+%% New protocol with encoding tags (R13)
+io_request({put_chars, Enc, Chars}, 
 	   #state{buf= <<>>}=State) ->
-    put_chars(Chars, State);
-io_request({put_chars,Chars}, % binary(Chars) new in R9C
+    put_chars(Chars, Enc, State);
+io_request({put_chars, Enc, Chars}, 
 	   #state{handle=Handle,buf=Buf}=State) ->
     case position(Handle, cur, Buf) of
 	{error,_}=Reply ->
 	    {stop,normal,Reply,State#state{buf= <<>>}};
 	_ ->
-	    put_chars(Chars, State#state{buf= <<>>})
+	    put_chars(Chars, Enc, State#state{buf= <<>>})
     end;
-io_request({put_chars,Mod,Func,Args}, 
+io_request({put_chars,Enc,Mod,Func,Args}, 
 	   #state{}=State) ->
     case catch apply(Mod, Func, Args) of
-	Chars when list(Chars); binary(Chars) ->
-	    io_request({put_chars,Chars}, State);
+	Chars when is_list(Chars); is_binary(Chars) ->
+	    io_request({put_chars,Enc,Chars}, State);
 	_ ->
 	    {error,{error,Func},State}
     end;
-io_request({get_until,_Prompt,Mod,Func,XtraArgs}, 
-	   #state{}=State) ->
-    get_chars(io_lib, get_until, {Mod, Func, XtraArgs}, State);
-io_request({get_chars,_Prompt,N}, % New in R9C
+
+
+io_request({get_until,Enc,_Prompt,Mod,Func,XtraArgs}, 
 	   #state{}=State) ->
-    get_chars(N, State);
-io_request({get_chars,_Prompt,Mod,Func,XtraArg}, % New in R9C
+    get_chars(io_lib, get_until, {Mod, Func, XtraArgs}, Enc, State);
+io_request({get_chars,Enc,_Prompt,N}, 
 	   #state{}=State) ->
-    get_chars(Mod, Func, XtraArg, State);
-io_request({get_line,_Prompt}, % New in R9C
+    get_chars(N, Enc, State);
+io_request({get_line,Enc,_Prompt}, 
 	   #state{}=State) ->
-    get_chars(io_lib, collect_line, [], State);
-io_request({setopts, Opts}, % New in R9C
-	   #state{}=State) when list(Opts) ->
+    get_chars(io_lib, collect_line, [], Enc, State);
+
+
+io_request({setopts, Opts}, 
+	   #state{}=State) when is_list(Opts) ->
     setopts(Opts, State);
+
+io_request(getopts, 
+	   #state{}=State) ->
+    getopts(State);
+
+%% BC with pre-R13 nodes
+io_request({put_chars, Chars},#state{}=State) ->
+    io_request({put_chars, latin1, Chars},State);
+io_request({put_chars,Mod,Func,Args}, #state{}=State) ->
+    io_request({put_chars,latin1,Mod,Func,Args}, State);
+io_request({get_until,_Prompt,Mod,Func,XtraArgs}, #state{}=State) ->
+    io_request({get_until,latin1,_Prompt,Mod,Func,XtraArgs}, State);
+io_request({get_chars,_Prompt,N}, #state{}=State) ->
+    io_request({get_chars,latin1,_Prompt,N}, State);
+io_request({get_line,_Prompt}, #state{}=State) ->
+    io_request({get_line,latin1,_Prompt}, State);
+
 io_request({requests,Requests}, 
-	   #state{}=State) when list(Requests) ->
+	   #state{}=State) when is_list(Requests) ->
     io_request_loop(Requests, {reply,ok,State});
 io_request(Unknown, 
 	   #state{}=State) ->
@@ -265,76 +339,213 @@ io_request_loop([Request|Tail],
 
 %% I/O request put_chars
 %%
-put_chars(Chars, #state{handle=Handle}=State) ->
+put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) ->
     case ?PRIM_FILE:write(Handle, Chars) of
 	{error,_}=Reply ->
 	    {stop,normal,Reply,State};
 	Reply ->
 	    {reply,Reply,State}
+    end;
+put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) ->
+    case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of
+	Bin when is_binary(Bin) ->
+	    case ?PRIM_FILE:write(Handle, Bin) of
+		{error,_}=Reply ->
+		    {stop,normal,Reply,State};
+		Reply ->
+		    {reply,Reply,State}
+	    end;
+	{error,_,_} ->
+	    {stop,normal,{error,{no_translation, InEncoding, OutEncoding}},State}
     end.
 
 
 %% Process the I/O request get_chars
 %%
-get_chars(0, #state{read_mode=ReadMode}=State) ->
-    {reply,cast(<<>>, ReadMode),State};
-get_chars(N, #state{buf=Buf,read_mode=ReadMode}=State) 
-  when integer(N), N > 0, N =< size(Buf) ->
+get_chars(0, Enc, #state{read_mode=ReadMode,unic=InEncoding}=State) ->
+    {reply,cast(<<>>, ReadMode,InEncoding, Enc),State};
+get_chars(N, Enc, #state{buf=Buf,read_mode=ReadMode,unic=latin1}=State) 
+  when is_integer(N), N > 0, N =< byte_size(Buf) ->
+    {B1,B2} = split_binary(Buf, N),
+    {reply,cast(B1, ReadMode,latin1,Enc),State#state{buf=B2}};
+get_chars(N, Enc, #state{buf=Buf,read_mode=ReadMode,unic=latin1}=State) 
+  when is_integer(N), N > 0, N =< byte_size(Buf) ->
     {B1,B2} = split_binary(Buf, N),
-    {reply,cast(B1, ReadMode),State#state{buf=B2}};
-get_chars(N, #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) 
-  when integer(N), N > 0 ->
-    BufSize = size(Buf),
+    {reply,cast(B1, ReadMode,latin1,Enc),State#state{buf=B2}};
+get_chars(N, OutEnc,#state{handle=Handle,buf=Buf,read_mode=ReadMode,unic=latin1}=State) 
+  when is_integer(N), N > 0 ->
+    BufSize = byte_size(Buf),
     NeedSize = N-BufSize,
-    Size = max(NeedSize, ?READ_SIZE_BINARY),
+    Size = erlang:max(NeedSize, ?READ_SIZE_BINARY),
     case ?PRIM_FILE:read(Handle, Size) of
 	{ok, B} ->
-	    if BufSize+size(B) < N ->
-		    std_reply(cat(Buf, B, ReadMode), State);
+	    if BufSize+byte_size(B) < N ->
+		    std_reply(cat(Buf, B, ReadMode,latin1,OutEnc), State);
 	       true ->
 		    {B1,B2} = split_binary(B, NeedSize),
-		    {reply,cat(Buf, B1, ReadMode),State#state{buf=B2}}
+		    {reply,cat(Buf, B1, ReadMode, latin1,OutEnc),State#state{buf=B2}}
 	    end;
-	eof when BufSize==0 ->
+	eof when BufSize =:= 0 ->
 	    {reply,eof,State};
 	eof ->
-	    std_reply(cast(Buf, ReadMode), State);
+	    std_reply(cast(Buf, ReadMode,latin1,OutEnc), State);
 	{error,Reason}=Error ->
 	    {stop,Reason,Error,State#state{buf= <<>>}}
     end;
-get_chars(_N, #state{}=State) ->
+get_chars(N, OutEnc,#state{handle=Handle,buf=Buf,read_mode=ReadMode,unic=InEncoding}=State) 
+  when is_integer(N), N > 0 ->
+    try
+	%% This is rather tricky, we need to count the actual number of characters 
+	%% in the buffer first as unicode characters are not constant in length
+	{BufCount, SplitPos} = count_and_find(Buf,N,InEncoding),
+	case BufCount >= N of
+	    true ->
+		{B1,B2} = case SplitPos of
+			      none -> {Buf,<<>>};
+			      _ ->split_binary(Buf,SplitPos)
+			  end,
+		{reply,cast(B1, ReadMode,InEncoding,OutEnc),State#state{buf=B2}};
+	    false ->
+		%% Need more, Try to read 4*needed in bytes...
+		NeedSize = (N - BufCount) * 4,
+		Size = erlang:max(NeedSize, ?READ_SIZE_BINARY),
+		case ?PRIM_FILE:read(Handle, Size) of
+		    {ok, B} ->
+			NewBuf = list_to_binary([Buf,B]),
+			{NewCount,NewSplit} = count_and_find(NewBuf,N,InEncoding),
+			case NewCount >= N of
+			    true ->
+				{B01,B02} = case NewSplit of
+						none -> {NewBuf,<<>>};
+						_ ->split_binary(NewBuf, NewSplit)
+					    end,
+				{reply,cast(B01, ReadMode,InEncoding,OutEnc),
+				 State#state{buf=B02}};
+			    false ->
+				%% Reached end of file
+				std_reply(cast(NewBuf, ReadMode,InEncoding,OutEnc), 
+					  State#state{buf = <<>>})
+			end;
+		    eof when BufCount =:= 0 ->
+			{reply,eof,State};
+		    eof ->
+			std_reply(cast(Buf, ReadMode,InEncoding,OutEnc), State#state{buf = <<>>});
+		    {error,Reason}=Error ->
+			{stop,Reason,Error,State#state{buf = <<>>}}
+		end
+	end
+    catch
+	exit:ExError ->
+	    {stop,ExError,{error,ExError},State#state{buf= <<>>}}
+    end;
+
+get_chars(_N, _, #state{}=State) ->
     {error,{error,get_chars},State}.
 
-get_chars(Mod, Func, XtraArg, #state{buf= <<>>}=State) ->
-    get_chars_empty(Mod, Func, XtraArg, start, State);
-get_chars(Mod, Func, XtraArg, #state{buf=Buf}=State) ->
-    get_chars_apply(Mod, Func, XtraArg, start, State#state{buf= <<>>}, Buf).
+get_chars(Mod, Func, XtraArg, OutEnc, #state{buf= <<>>}=State) ->
+    get_chars_empty(Mod, Func, XtraArg, start, OutEnc, State);
+get_chars(Mod, Func, XtraArg, OutEnc, #state{buf=Buf}=State) ->
+    get_chars_apply(Mod, Func, XtraArg, start, OutEnc, State#state{buf= <<>>}, Buf).
 
-get_chars_empty(Mod, Func, XtraArg, S, 
+get_chars_empty(Mod, Func, XtraArg, S, latin1,
+		#state{handle=Handle,read_mode=ReadMode, unic=latin1}=State) ->
+    case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+	{ok,Bin} ->
+	    get_chars_apply(Mod, Func, XtraArg, S, latin1, State, Bin);
+	eof ->
+	    get_chars_apply(Mod, Func, XtraArg, S, latin1, State, eof);
+	{error,Reason}=Error ->
+	    {stop,Reason,Error,State}
+    end;
+get_chars_empty(Mod, Func, XtraArg, S, OutEnc,
 		#state{handle=Handle,read_mode=ReadMode}=State) ->
     case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
 	{ok,Bin} ->
-	    get_chars_apply(Mod, Func, XtraArg, S, State, Bin);
+	    get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, Bin);
+	eof ->
+	    get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, eof);
+	{error,Reason}=Error ->
+	    {stop,Reason,Error,State}
+    end.
+get_chars_notempty(Mod, Func, XtraArg, S, OutEnc,
+		   #state{handle=Handle,read_mode=ReadMode,buf = B}=State) ->
+    case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+	{ok,Bin} ->
+	    get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, list_to_binary([Bin,B]));
 	eof ->
-	    get_chars_apply(Mod, Func, XtraArg, S, State, eof);
+	    case B of
+		<<>> ->
+		    get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, eof);
+		_ ->
+		    {stop,invalid_unicode,{error,invalid_unicode},State}
+	    end;
 	{error,Reason}=Error ->
 	    {stop,Reason,Error,State}
     end.
 
-get_chars_apply(Mod, Func, XtraArg, S0, 
-		#state{read_mode=ReadMode}=State, Data0) ->
+
+get_chars_apply(Mod, Func, XtraArg, S0, latin1,
+		#state{read_mode=ReadMode,unic=latin1}=State, Data0) ->
     Data1 = case ReadMode of
-	       list when binary(Data0) -> binary_to_list(Data0);
+	       list when is_binary(Data0) -> binary_to_list(Data0);
 	       _ -> Data0
 	    end,
-    case catch Mod:Func(S0, Data1, XtraArg) of
+    case catch Mod:Func(S0, Data1, latin1, XtraArg) of
 	{stop,Result,Buf} ->
 	    {reply,Result,State#state{buf=cast_binary(Buf)}};
 	{'EXIT',Reason} ->
 	    {stop,Reason,{error,err_func(Mod, Func, XtraArg)},State};
 	S1 ->
-	    get_chars_empty(Mod, Func, XtraArg, S1, State)
+	    get_chars_empty(Mod, Func, XtraArg, S1, latin1, State)
+    end;
+get_chars_apply(Mod, Func, XtraArg, S0, OutEnc,
+		#state{read_mode=ReadMode,unic=InEnc}=State, Data0) ->
+    try 
+	{Data1,NewBuff} = case ReadMode of
+			      list when is_binary(Data0) -> 
+				  case unicode:characters_to_list(Data0,InEnc) of
+				      {Tag,Decoded,Rest} when Decoded =/= [], Tag =:= error; Decoded =/= [], Tag =:= incomplete ->
+					  {Decoded,erlang:iolist_to_binary(Rest)};
+				      {Tag, [], _} when Tag =:= error; Tag =:= incomplete -> 
+					  exit(invalid_unicode);
+				      List when is_list(List) ->
+					  {List,<<>>}
+				  end;
+			      binary when is_binary(Data0) ->
+				  case unicode:characters_to_binary(Data0,InEnc,OutEnc) of
+				      {Tag2,Decoded2,Rest2} when Decoded2 =/= <<>>, Tag2 =:= error; Decoded2 =/= <<>>, Tag2 =:= incomplete ->
+					  {Decoded2,erlang:iolist_to_binary(Rest2)};
+				      {Tag2, <<>>, _} when Tag2 =:= error; Tag2 =:= incomplete ->
+					  exit(invalid_unicode);
+				      Binary when is_binary(Binary) ->
+					  {Binary,<<>>}
+				  end;
+			      _ -> %i.e. eof
+				  {Data0,<<>>}
+			  end,
+	case catch Mod:Func(S0, Data1, OutEnc, XtraArg) of
+	    {stop,Result,Buf} ->
+		{reply,Result,State#state{buf = (if
+						     is_binary(Buf) ->
+							 unicode:characters_to_binary(Buf,OutEnc,InEnc);
+						     is_list(Buf) ->
+							 unicode:characters_to_binary(Buf,unicode,InEnc);
+						     true ->
+							 <<>>
+						end)}};
+	    {'EXIT',Reason} ->
+		{stop,Reason,{error,err_func(Mod, Func, XtraArg)},State};
+	    S1 ->
+		get_chars_notempty(Mod, Func, XtraArg, S1, OutEnc, State#state{buf=NewBuff})
+	end
+    catch
+	exit:ExReason ->
+	   {stop,ExReason,{error,err_func(Mod, Func, XtraArg)},State};
+	error:ErrReason ->
+	   {stop,ErrReason,{error,err_func(Mod, Func, XtraArg)},State}
     end.
+	    
+
 
 %% Convert error code to make it look as before
 err_func(io_lib, get_until, {_,F,_}) ->
@@ -347,35 +558,100 @@ err_func(_, F, _) ->
 %% Process the I/O request setopts
 %%
 %% setopts
-setopts(Opts0, State) ->
-    Opts = proplists:substitute_negations([{list,binary}], Opts0),
-    case proplists:get_value(binary, Opts) of
+setopts(Opts0,State) ->
+    Opts = proplists:unfold(
+	     proplists:substitute_negations(
+	       [{list,binary}], 
+	       expand_encoding(Opts0))),
+    case check_valid_opts(Opts) of
 	true ->
-	    {ok,ok,State#state{read_mode=binary}};
+	    do_setopts(Opts,State);
 	false ->
-	    {ok,ok,State#state{read_mode=list}};
+	    {error,{error,enotsup},State}
+    end.
+check_valid_opts([]) ->
+    true;
+check_valid_opts([{binary,_}|T]) ->
+    check_valid_opts(T);
+check_valid_opts([{encoding,_Enc}|T]) ->
+    check_valid_opts(T);
+check_valid_opts(_) ->
+    false.
+do_setopts(Opts, State) ->
+    case valid_enc(proplists:get_value(encoding, Opts, State#state.unic)) of
+	{ok,NewUnic} ->
+	    case proplists:get_value(binary, Opts) of
+		true ->
+		    {reply,ok,State#state{read_mode=binary, unic=NewUnic}};
+		false ->
+		    {reply,ok,State#state{read_mode=list, unic=NewUnic}};
+		undefined ->
+		    {reply,ok,State#state{unic=NewUnic}}
+	    end;
 	_ ->
-	    {error,{error,badarg},State}
+	    {error,{error,badarg},State} 
     end.
 
-
+getopts(#state{read_mode=RM, unic=Unic} = State) ->
+    Bin = {binary, case RM of
+		       binary ->
+			   true;
+		       _ ->
+			   false
+		   end},
+    Uni = {encoding, Unic},
+    {reply,[Bin,Uni],State}.
+    
 
 %% Concatenate two binaries and convert the result to list or binary
-cat(B1, B2, binary) ->
+cat(B1, B2, binary,latin1,latin1) ->
     list_to_binary([B1,B2]);
-cat(B1, B2, list) ->
+cat(B1, B2, binary,InEncoding,OutEncoding) ->
+    case unicode:characters_to_binary([B1,B2],InEncoding,OutEncoding) of
+	Good when is_binary(Good) ->
+	    Good;
+	_ ->
+	    exit({no_translation,InEncoding,OutEncoding})
+    end;
+%% Dialyzer finds this is never used...                                                       
+%% cat(B1, B2, list, InEncoding, OutEncoding) when InEncoding =/= latin1 ->
+%%     % Catch i.e. unicode -> latin1 errors by using the outencoding although otherwise
+%%     % irrelevant for lists...
+%%     try
+%% 	unicode:characters_to_list(unicode:characters_to_binary([B1,B2],InEncoding,OutEncoding),
+%% 				   OutEncoding)
+%%     catch
+%% 	error:_ ->
+%% 	    exit({no_translation,InEncoding,OutEncoding})
+%%     end.
+cat(B1, B2, list, latin1,_) ->
     binary_to_list(B1)++binary_to_list(B2).
 
 %% Cast binary to list or binary
-cast(B, binary) ->
+cast(B, binary, latin1, latin1) ->
     B;
-cast(B, list) ->
-    binary_to_list(B).
+cast(B, binary, InEncoding, OutEncoding) ->
+    case unicode:characters_to_binary(B,InEncoding,OutEncoding) of
+	Good when is_binary(Good) ->
+	    Good;
+	_ ->
+	    exit({no_translation,InEncoding,OutEncoding})
+    end;
+cast(B, list, latin1, _) ->
+    binary_to_list(B);
+cast(B, list, InEncoding, OutEncoding) ->
+    try
+	unicode:characters_to_list(unicode:characters_to_binary(B,InEncoding,OutEncoding),
+				   OutEncoding)
+    catch
+	error:_ ->
+	    exit({no_translation,InEncoding,OutEncoding})
+    end.
 
 %% Convert buffer to binary
-cast_binary(Binary) when binary(Binary) ->
+cast_binary(Binary) when is_binary(Binary) ->
     Binary;
-cast_binary(List) when list(List) ->
+cast_binary(List) when is_list(List) ->
     list_to_binary(List);
 cast_binary(_EOF) ->
     <<>>.
@@ -386,10 +662,150 @@ read_size(binary) ->
 read_size(list) ->
     ?READ_SIZE_LIST.
 
-max(A, B) when A >= B ->
-    A;
-max(_, B) ->
-    B.
+%% Utf utility
+count_and_find(Bin,N,Encoding) ->
+    cafu(Bin,N,0,0,none,case Encoding of 
+			   unicode -> utf8;
+			   Oth -> Oth
+			end).
+
+cafu(<<>>,0,Count,ByteCount,_SavePos,_) ->
+    {Count,ByteCount};
+cafu(<<>>,_N,Count,_ByteCount,SavePos,_) ->
+    {Count,SavePos};
+cafu(<<_/utf8,Rest/binary>>, 0, Count, ByteCount, _SavePos, utf8) ->
+    cafu(Rest,-1,Count+1,0,ByteCount,utf8);
+cafu(<<_/utf8,Rest/binary>>, N, Count, _ByteCount, SavePos, utf8) when N < 0 ->
+    cafu(Rest,-1,Count+1,0,SavePos,utf8);
+cafu(<<_/utf8,Rest/binary>> = Whole, N, Count, ByteCount, SavePos, utf8) ->
+    Delta = byte_size(Whole) - byte_size(Rest),
+    cafu(Rest,N-1,Count+1,ByteCount+Delta,SavePos,utf8);
+cafu(<<_/utf16-big,Rest/binary>>, 0, Count, ByteCount, _SavePos, {utf16,big}) ->
+    cafu(Rest,-1,Count+1,0,ByteCount,{utf16,big});
+cafu(<<_/utf16-big,Rest/binary>>, N, Count, _ByteCount, SavePos, {utf16,big}) when N < 0 ->
+    cafu(Rest,-1,Count+1,0,SavePos,{utf16,big});
+cafu(<<_/utf16-big,Rest/binary>> = Whole, N, Count, ByteCount, SavePos, {utf16,big}) ->
+    Delta = byte_size(Whole) - byte_size(Rest),
+    cafu(Rest,N-1,Count+1,ByteCount+Delta,SavePos,{utf16,big});
+cafu(<<_/utf16-little,Rest/binary>>, 0, Count, ByteCount, _SavePos, {utf16,little}) ->
+    cafu(Rest,-1,Count+1,0,ByteCount,{utf16,little});
+cafu(<<_/utf16-little,Rest/binary>>, N, Count, _ByteCount, SavePos, {utf16,little}) when N < 0 ->
+    cafu(Rest,-1,Count+1,0,SavePos,{utf16,little});
+cafu(<<_/utf16-little,Rest/binary>> = Whole, N, Count, ByteCount, SavePos, {utf16,little}) ->
+    Delta = byte_size(Whole) - byte_size(Rest),
+    cafu(Rest,N-1,Count+1,ByteCount+Delta,SavePos,{utf16,little});
+cafu(<<_/utf32-big,Rest/binary>>, 0, Count, ByteCount, _SavePos, {utf32,big}) ->
+    cafu(Rest,-1,Count+1,0,ByteCount,{utf32,big});
+cafu(<<_/utf32-big,Rest/binary>>, N, Count, _ByteCount, SavePos, {utf32,big}) when N < 0 ->
+    cafu(Rest,-1,Count+1,0,SavePos,{utf32,big});
+cafu(<<_/utf32-big,Rest/binary>> = Whole, N, Count, ByteCount, SavePos, {utf32,big}) ->
+    Delta = byte_size(Whole) - byte_size(Rest),
+    cafu(Rest,N-1,Count+1,ByteCount+Delta,SavePos,{utf32,big});
+cafu(<<_/utf32-little,Rest/binary>>, 0, Count, ByteCount, _SavePos, {utf32,little}) ->
+    cafu(Rest,-1,Count+1,0,ByteCount,{utf32,little});
+cafu(<<_/utf32-little,Rest/binary>>, N, Count, _ByteCount, SavePos, {utf32,little}) when N < 0 ->
+    cafu(Rest,-1,Count+1,0,SavePos,{utf32,little});
+cafu(<<_/utf32-little,Rest/binary>> = Whole, N, Count, ByteCount, SavePos, {utf32,little}) ->
+    Delta = byte_size(Whole) - byte_size(Rest),
+    cafu(Rest,N-1,Count+1,ByteCount+Delta,SavePos,{utf32,little});
+cafu(_Other,0,Count,ByteCount,_,_) -> % Non Unicode character, 
+                                     % but found our point, OK this time
+    {Count,ByteCount};
+cafu(Other,_N,Count,0,_SavePos,Enc) -> % Not enough, but valid chomped unicode
+                                       % at end.
+    case cbv(Enc,Other) of
+	false ->
+	    exit(invalid_unicode);
+	_ ->
+	    {Count,none}
+    end;
+cafu(Other,_N,Count,ByteCount,none,Enc) -> % Return what we'we got this far
+					   % although not complete, 
+					   % it's not (yet) in error
+    case cbv(Enc,Other) of
+	false ->
+	    exit(invalid_unicode);
+	_ ->
+	    {Count,ByteCount}
+    end;
+cafu(Other,_N,Count,_ByteCount,SavePos,Enc) -> % As above but we have 
+					       % found a position
+    case cbv(Enc,Other) of
+	false ->
+	    exit(invalid_unicode);
+	_ ->
+	    {Count,SavePos}
+    end.
+
+%%
+%% Bluntly stolen from stdlib/unicode.erl (cbv means can be valid?)
+%%
+cbv(utf8,<<1:1,1:1,0:1,_:5>>) -> 
+    1;
+cbv(utf8,<<1:1,1:1,1:1,0:1,_:4,R/binary>>) -> 
+    case R of
+	<<>> ->
+	    2;
+	<<1:1,0:1,_:6>> ->
+	    1;
+	_ ->
+	    false
+    end;
+cbv(utf8,<<1:1,1:1,1:1,1:1,0:1,_:3,R/binary>>) ->
+    case R of
+	<<>> ->
+	    3;
+	<<1:1,0:1,_:6>> ->
+	    2;
+	<<1:1,0:1,_:6,1:1,0:1,_:6>> ->
+	    1;
+	_ ->
+	    false
+    end;
+cbv(utf8,_) ->
+    false;
+
+cbv({utf16,big},<<A:8>>) when A =< 215; A >= 224 ->
+    1;
+cbv({utf16,big},<<54:6,_:2>>) ->
+    3;
+cbv({utf16,big},<<54:6,_:10>>) ->
+    2;
+cbv({utf16,big},<<54:6,_:10,55:6,_:2>>) ->
+    1;
+cbv({utf16,big},_) ->
+    false;
+cbv({utf16,little},<<_:8>>) ->
+    1; % or 3, we'll see
+cbv({utf16,little},<<_:8,54:6,_:2>>) ->
+    2;
+cbv({utf16,little},<<_:8,54:6,_:2,_:8>>) ->
+    1;
+cbv({utf16,little},_) ->
+    false;
+
+
+cbv({utf32,big}, <<0:8>>) ->
+    3;
+cbv({utf32,big}, <<0:8,X:8>>) when X =< 16 ->
+    2;
+cbv({utf32,big}, <<0:8,X:8,Y:8>>) 
+  when X =< 16, ((X > 0) or ((Y =< 215) or (Y >= 224))) ->
+    1;
+cbv({utf32,big},_) ->
+    false;
+cbv({utf32,little},<<_:8>>) ->
+    3;
+cbv({utf32,little},<<_:8,_:8>>) -> 
+    2;
+cbv({utf32,little},<<X:8,255:8,0:8>>) when X =:= 254; X =:= 255 ->
+    false;
+cbv({utf32,little},<<_:8,Y:8,X:8>>) 
+  when X =< 16, ((X > 0) or ((Y =< 215) or (Y >= 224))) ->
+    1;
+cbv({utf32,little},_) ->
+    false.
+
 
 %%%-----------------------------------------------------------------
 %%% ?PRIM_FILE helpers
@@ -399,10 +815,10 @@ max(_, B) ->
 
 position(Handle, cur, Buf) ->
     position(Handle, {cur, 0}, Buf);
-position(Handle, {cur, Offs}, Buf) when list(Buf) ->
+position(Handle, {cur, Offs}, Buf) when is_list(Buf) ->
     ?PRIM_FILE:position(Handle, {cur, Offs-length(Buf)});
-position(Handle, {cur, Offs}, Buf) when binary(Buf) ->
-    ?PRIM_FILE:position(Handle, {cur, Offs-size(Buf)});
+position(Handle, {cur, Offs}, Buf) when is_binary(Buf) ->
+    ?PRIM_FILE:position(Handle, {cur, Offs-byte_size(Buf)});
 position(Handle, At, _Buf) ->
     ?PRIM_FILE:position(Handle, At).
 
--- /dev/null
+++ ram_file_io_server_old.erl
@@ -0,0 +1,408 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%% 
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%% 
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%% 
+%%     $Id$
+%% 
+%% This file is mostly copied from Erlang file_io_server.erl
+%% See: http://www.erlang.org/ml-archive/erlang-questions/200607/msg00080.html
+%% for details on ram_file_io_server.erl (Erlang OTP R11B-2)
+-module(ram_file_io_server_old).
+
+%% A simple file server for io to one file instance per server instance.
+
+-export([format_error/1]).
+-export([start/3, start_link/3]).
+
+-record(state, {handle,owner,mref,buf,read_mode}).
+
+-define(PRIM_FILE, ram_file).
+-define(READ_SIZE_LIST, 128).
+-define(READ_SIZE_BINARY, (8*1024)).
+
+-define(eat_message(M, T), receive M -> M after T -> timeout end).
+
+%%%-----------------------------------------------------------------
+%%% Exported functions
+
+format_error({_Line, ?MODULE, Reason}) ->
+    io_lib:format("~w", [Reason]);
+format_error({_Line, Mod, Reason}) ->
+    Mod:format_error(Reason);
+format_error(ErrorId) ->
+    erl_posix_msg:message(ErrorId).
+
+start(Owner, FileName, ModeList) 
+  when pid(Owner), list(FileName), list(ModeList) ->
+    do_start(spawn, Owner, FileName, ModeList).
+
+start_link(Owner, FileName, ModeList) 
+  when pid(Owner), list(FileName), list(ModeList) ->
+    do_start(spawn_link, Owner, FileName, ModeList).
+
+%%%-----------------------------------------------------------------
+%%% Server starter, dispatcher and helpers
+
+do_start(Spawn, Owner, FileName, ModeList) ->
+    Self = self(),
+    Ref = make_ref(),
+    Pid = 
+	erlang:Spawn(
+	  fun() ->
+		  %% process_flag(trap_exit, true),
+		  {ReadMode,Opts} = 
+		      case lists:member(binary, ModeList) of
+			  true ->
+			      {binary,ModeList};
+			  false ->
+			      {list,[binary|ModeList]}
+		      end,
+		  case ?PRIM_FILE:open(FileName, Opts) of
+		      {error, Reason} = Error ->
+			  Self ! {Ref, Error},
+			  exit(Reason);
+		      {ok, Handle} ->
+			  %% XXX must I handle R6 nodes here?
+			  M = erlang:monitor(process, Owner),
+			  Self ! {Ref, ok},
+			  server_loop(
+			    #state{handle    = Handle,
+				   owner     = Owner, 
+				   mref      = M, 
+				   buf       = <<>>,
+				   read_mode = ReadMode})
+		  end
+	  end),
+    Mref = erlang:monitor(process, Pid),
+    receive
+	{Ref, {error, _Reason} = Error} ->
+	    erlang:demonitor(Mref),
+	    receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+	    Error;
+	{Ref, ok} ->
+	    erlang:demonitor(Mref),
+	    receive
+		{'DOWN', Mref, _, _, Reason} ->
+		    {error, Reason}
+	    after 0 ->
+		    {ok, Pid}
+	    end;
+	{'DOWN', Mref, _, _, Reason} ->
+	    {error, Reason}
+    end.
+
+server_loop(#state{mref = Mref} = State) ->
+    receive
+	{file_request, From, ReplyAs, Request} when pid(From) ->
+	    case file_request(Request, State) of
+		{reply, Reply, NewState} ->
+		    file_reply(From, ReplyAs, Reply),
+		    server_loop(NewState);
+		{error, Reply, NewState} ->
+		    %% error is the same as reply, except that
+		    %% it breaks the io_request_loop further down
+		    file_reply(From, ReplyAs, Reply),
+		    server_loop(NewState);
+		{stop, Reason, Reply, _NewState} ->
+		    file_reply(From, ReplyAs, Reply),
+		    exit(Reason)
+	    end;
+	{io_request, From, ReplyAs, Request} when pid(From) ->
+	    case io_request(Request, State) of
+		{reply, Reply, NewState} ->
+		    io_reply(From, ReplyAs, Reply),
+		    server_loop(NewState);
+		{error, Reply, NewState} ->
+		    %% error is the same as reply, except that
+		    %% it breaks the io_request_loop further down
+		    io_reply(From, ReplyAs, Reply),
+		    server_loop(NewState);
+		{stop, Reason, Reply, _NewState} ->
+		    io_reply(From, ReplyAs, Reply),
+		    exit(Reason)
+	    end;
+	{'DOWN', Mref, _, _, Reason} ->
+	    exit(Reason);
+	_ ->
+	    server_loop(State)
+    end.
+
+file_reply(From, ReplyAs, Reply) ->
+    From ! {file_reply, ReplyAs, Reply}.
+
+io_reply(From, ReplyAs, Reply) ->
+    From ! {io_reply, ReplyAs, Reply}.
+
+%%%-----------------------------------------------------------------
+%%% file requests
+
+file_request({pread,At,Sz}, 
+	     #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
+    case position(Handle, At, Buf) of
+	{ok,_Offs} ->
+	    case ?PRIM_FILE:read(Handle, Sz) of
+		{ok,Bin} when ReadMode==list ->
+		    std_reply({ok,binary_to_list(Bin)}, State);
+		Reply ->
+		    std_reply(Reply, State)
+	    end;
+	Reply ->
+	    std_reply(Reply, State)
+    end;
+file_request({pwrite,At,Data}, 
+	     #state{handle=Handle,buf=Buf}=State) ->
+    case position(Handle, At, Buf) of
+	{ok,_Offs} ->
+	    std_reply(?PRIM_FILE:write(Handle, Data), State);
+	Reply ->
+	    std_reply(Reply, State)
+    end;
+file_request(sync, 
+	     #state{handle=Handle}=State) ->
+    case ?PRIM_FILE:sync(Handle) of
+	{error,_}=Reply ->
+	    {stop,normal,Reply,State};
+	Reply ->
+	    {reply,Reply,State}
+    end;
+file_request(close, 
+	     #state{handle=Handle}=State) ->
+    {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}};
+file_request({position,At}, 
+	     #state{handle=Handle,buf=Buf}=State) ->
+    std_reply(position(Handle, At, Buf), State);
+file_request(truncate, 
+	     #state{handle=Handle}=State) ->
+    case ?PRIM_FILE:truncate(Handle) of
+	{error,_Reason}=Reply ->
+	    {stop,normal,Reply,State#state{buf= <<>>}};
+	Reply ->
+	    {reply,Reply,State}
+    end;
+file_request(Unknown, 
+	     #state{}=State) ->
+    Reason = {request, Unknown},
+    {error,{error,Reason},State}.
+
+std_reply({error,_}=Reply, State) ->
+    {error,Reply,State#state{buf= <<>>}};
+std_reply(Reply, State) ->
+    {reply,Reply,State#state{buf= <<>>}}.
+
+%%%-----------------------------------------------------------------
+%%% I/O request 
+
+io_request({put_chars,Chars}, % binary(Chars) new in R9C
+	   #state{buf= <<>>}=State) ->
+    put_chars(Chars, State);
+io_request({put_chars,Chars}, % binary(Chars) new in R9C
+	   #state{handle=Handle,buf=Buf}=State) ->
+    case position(Handle, cur, Buf) of
+	{error,_}=Reply ->
+	    {stop,normal,Reply,State#state{buf= <<>>}};
+	_ ->
+	    put_chars(Chars, State#state{buf= <<>>})
+    end;
+io_request({put_chars,Mod,Func,Args}, 
+	   #state{}=State) ->
+    case catch apply(Mod, Func, Args) of
+	Chars when list(Chars); binary(Chars) ->
+	    io_request({put_chars,Chars}, State);
+	_ ->
+	    {error,{error,Func},State}
+    end;
+io_request({get_until,_Prompt,Mod,Func,XtraArgs}, 
+	   #state{}=State) ->
+    get_chars(io_lib, get_until, {Mod, Func, XtraArgs}, State);
+io_request({get_chars,_Prompt,N}, % New in R9C
+	   #state{}=State) ->
+    get_chars(N, State);
+io_request({get_chars,_Prompt,Mod,Func,XtraArg}, % New in R9C
+	   #state{}=State) ->
+    get_chars(Mod, Func, XtraArg, State);
+io_request({get_line,_Prompt}, % New in R9C
+	   #state{}=State) ->
+    get_chars(io_lib, collect_line, [], State);
+io_request({setopts, Opts}, % New in R9C
+	   #state{}=State) when list(Opts) ->
+    setopts(Opts, State);
+io_request({requests,Requests}, 
+	   #state{}=State) when list(Requests) ->
+    io_request_loop(Requests, {reply,ok,State});
+io_request(Unknown, 
+	   #state{}=State) ->
+    Reason = {request,Unknown},
+    {error,{error,Reason},State}.
+
+
+
+%% Process a list of requests as long as the results are ok.
+
+io_request_loop([], Result) ->
+    Result;
+io_request_loop([_Request|_Tail], 
+		{stop,_Reason,_Reply,_State}=Result) ->
+    Result;
+io_request_loop([_Request|_Tail],
+		{error,_Reply,_State}=Result) ->
+    Result;
+io_request_loop([Request|Tail], 
+		{reply,_Reply,State}) ->
+    io_request_loop(Tail, io_request(Request, State)).
+
+
+
+%% I/O request put_chars
+%%
+put_chars(Chars, #state{handle=Handle}=State) ->
+    case ?PRIM_FILE:write(Handle, Chars) of
+	{error,_}=Reply ->
+	    {stop,normal,Reply,State};
+	Reply ->
+	    {reply,Reply,State}
+    end.
+
+
+%% Process the I/O request get_chars
+%%
+get_chars(0, #state{read_mode=ReadMode}=State) ->
+    {reply,cast(<<>>, ReadMode),State};
+get_chars(N, #state{buf=Buf,read_mode=ReadMode}=State) 
+  when integer(N), N > 0, N =< size(Buf) ->
+    {B1,B2} = split_binary(Buf, N),
+    {reply,cast(B1, ReadMode),State#state{buf=B2}};
+get_chars(N, #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) 
+  when integer(N), N > 0 ->
+    BufSize = size(Buf),
+    NeedSize = N-BufSize,
+    Size = max(NeedSize, ?READ_SIZE_BINARY),
+    case ?PRIM_FILE:read(Handle, Size) of
+	{ok, B} ->
+	    if BufSize+size(B) < N ->
+		    std_reply(cat(Buf, B, ReadMode), State);
+	       true ->
+		    {B1,B2} = split_binary(B, NeedSize),
+		    {reply,cat(Buf, B1, ReadMode),State#state{buf=B2}}
+	    end;
+	eof when BufSize==0 ->
+	    {reply,eof,State};
+	eof ->
+	    std_reply(cast(Buf, ReadMode), State);
+	{error,Reason}=Error ->
+	    {stop,Reason,Error,State#state{buf= <<>>}}
+    end;
+get_chars(_N, #state{}=State) ->
+    {error,{error,get_chars},State}.
+
+get_chars(Mod, Func, XtraArg, #state{buf= <<>>}=State) ->
+    get_chars_empty(Mod, Func, XtraArg, start, State);
+get_chars(Mod, Func, XtraArg, #state{buf=Buf}=State) ->
+    get_chars_apply(Mod, Func, XtraArg, start, State#state{buf= <<>>}, Buf).
+
+get_chars_empty(Mod, Func, XtraArg, S, 
+		#state{handle=Handle,read_mode=ReadMode}=State) ->
+    case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of
+	{ok,Bin} ->
+	    get_chars_apply(Mod, Func, XtraArg, S, State, Bin);
+	eof ->
+	    get_chars_apply(Mod, Func, XtraArg, S, State, eof);
+	{error,Reason}=Error ->
+	    {stop,Reason,Error,State}
+    end.
+
+get_chars_apply(Mod, Func, XtraArg, S0, 
+		#state{read_mode=ReadMode}=State, Data0) ->
+    Data1 = case ReadMode of
+	       list when binary(Data0) -> binary_to_list(Data0);
+	       _ -> Data0
+	    end,
+    case catch Mod:Func(S0, Data1, XtraArg) of
+	{stop,Result,Buf} ->
+	    {reply,Result,State#state{buf=cast_binary(Buf)}};
+	{'EXIT',Reason} ->
+	    {stop,Reason,{error,err_func(Mod, Func, XtraArg)},State};
+	S1 ->
+	    get_chars_empty(Mod, Func, XtraArg, S1, State)
+    end.
+
+%% Convert error code to make it look as before
+err_func(io_lib, get_until, {_,F,_}) ->
+    F;
+err_func(_, F, _) ->
+    F.
+
+
+
+%% Process the I/O request setopts
+%%
+%% setopts
+setopts(Opts0, State) ->
+    Opts = proplists:substitute_negations([{list,binary}], Opts0),
+    case proplists:get_value(binary, Opts) of
+	true ->
+	    {ok,ok,State#state{read_mode=binary}};
+	false ->
+	    {ok,ok,State#state{read_mode=list}};
+	_ ->
+	    {error,{error,badarg},State}
+    end.
+
+
+
+%% Concatenate two binaries and convert the result to list or binary
+cat(B1, B2, binary) ->
+    list_to_binary([B1,B2]);
+cat(B1, B2, list) ->
+    binary_to_list(B1)++binary_to_list(B2).
+
+%% Cast binary to list or binary
+cast(B, binary) ->
+    B;
+cast(B, list) ->
+    binary_to_list(B).
+
+%% Convert buffer to binary
+cast_binary(Binary) when binary(Binary) ->
+    Binary;
+cast_binary(List) when list(List) ->
+    list_to_binary(List);
+cast_binary(_EOF) ->
+    <<>>.
+
+%% Read size for different read modes
+read_size(binary) ->
+    ?READ_SIZE_BINARY;
+read_size(list) ->
+    ?READ_SIZE_LIST.
+
+max(A, B) when A >= B ->
+    A;
+max(_, B) ->
+    B.
+
+%%%-----------------------------------------------------------------
+%%% ?PRIM_FILE helpers
+
+%% Compensates ?PRIM_FILE:position/2 for the number of bytes 
+%% we have buffered
+
+position(Handle, cur, Buf) ->
+    position(Handle, {cur, 0}, Buf);
+position(Handle, {cur, Offs}, Buf) when list(Buf) ->
+    ?PRIM_FILE:position(Handle, {cur, Offs-length(Buf)});
+position(Handle, {cur, Offs}, Buf) when binary(Buf) ->
+    ?PRIM_FILE:position(Handle, {cur, Offs-size(Buf)});
+position(Handle, At, _Buf) ->
+    ?PRIM_FILE:position(Handle, At).
+
