diff --git a/erlang/msgpack.erl b/erlang/msgpack.erl
index aab07b72..e862cad1 100644
--- a/erlang/msgpack.erl
+++ b/erlang/msgpack.erl
@@ -19,9 +19,8 @@
 -author('kuenishi+msgpack@gmail.com').
 
 %% tuples, atoms are not supported. lists, integers, double, and so on.
-%% see http://msgpack.sourceforge.jp/spec for
-%% supported formats. APIs are almost compatible
-%% for C API (http://msgpack.sourceforge.jp/c:doc)
+%% see http://msgpack.sourceforge.jp/spec for supported formats.
+%% APIs are almost compatible with C API (http://msgpack.sourceforge.jp/c:doc)
 %% except buffering functions (both copying and zero-copying).
 -export([pack/1, unpack/1, unpack_all/1]).
 -export([pack_map/1]).
@@ -30,51 +29,40 @@
 % erl> c(msgpack).
 % erl> S = <some term>.
 % erl> {S, <<>>} = msgpack:unpack( msgpack:pack(S) ).
--type reason() ::  enomem | badarg | no_code_matches.
+-type reason() ::  enomem | badarg | no_code_matches | undefined.
 -type msgpack_term() :: [msgpack_term()]
 		      | {[{msgpack_term(),msgpack_term()}]}
 		      | integer() | float() | binary().
 
 % ===== external APIs ===== %
--spec pack(Term::msgpack_term()) -> binary().
-pack(I) when is_integer(I) andalso I < 0 ->
-    pack_int_(I);
-pack(I) when is_integer(I) ->
-    pack_uint_(I);
-pack(F) when is_float(F) ->
-    pack_double(F);
-pack(nil) ->
-    << 16#C0:8 >>;
-pack(true) ->
-    << 16#C3:8 >>;
-pack(false) ->
-    << 16#C2:8 >>;
-pack(Bin) when is_binary(Bin) ->
-    pack_raw(Bin);
-pack(List)  when is_list(List) ->
-    pack_array(List);
-pack({Map}) when is_list(Map) ->
-    pack_map(Map);
-pack(Map) when is_tuple(Map), element(1,Map)=:=dict ->
-    pack_map(dict:to_list(Map));
-pack(_Other) ->
-    {error, undefined}.
+-spec pack(Term::msgpack_term()) -> binary() | {error, reason()}.
+pack(Term)->
+    try
+	pack_(Term)
+    catch
+	error:Error when is_tuple(Error), element(1, Error) =:= error ->
+	    Error;
+	throw:Exception ->
+	    erlang:display(Exception),
+	    {error, Exception}
+    end.
 
 % unpacking.
 % if failed in decoding and not end, get more data
 % and feed more Bin into this function.
 % TODO: error case for imcomplete format when short for any type formats.
--spec unpack( Bin::binary() )-> {msgpack_term(), binary()} |
-				{more, non_neg_integer()} | {more, undefined} |
-				{error, reason()}.
-unpack(Bin) when not is_binary(Bin)->
+-spec unpack( Bin::binary() )-> {msgpack_term(), binary()} | {error, reason()}.
+unpack(Bin) when not is_binary(Bin) ->
     {error, badarg};
-unpack(Bin) when bit_size(Bin) >= 8 ->
-    unpack_(Bin);
-unpack(<<>>)->
-    {more, 1};
-unpack(_) ->
-    {more, undefined}.
+unpack(Bin) ->
+    try
+	unpack_(Bin)
+    catch
+	error:Error when is_tuple(Error), element(1, Error) =:= error ->
+	    Error;
+	throw:Exception ->
+	    {error, Exception}
+    end.
 
 -spec unpack_all( binary() ) -> [msgpack_term()].
 unpack_all(Data)->
@@ -85,7 +73,7 @@ unpack_all(Data)->
 	    [Term|unpack_all(Binary)]
     end.
 
--spec pack_map(M::[{msgpack_term(),msgpack_term()}])-> binary().
+-spec pack_map(M::[{msgpack_term(),msgpack_term()}])-> binary() | {error, badarg}.
 pack_map(M)->
     case length(M) of
 	Len when Len < 16 ->
@@ -98,6 +86,31 @@ pack_map(M)->
 
 % ===== internal APIs ===== %
 
+% pack them all
+-spec pack_(msgpack_term()) -> binary() | no_return().
+pack_(I) when is_integer(I) andalso I < 0 ->
+    pack_int_(I);
+pack_(I) when is_integer(I) ->
+    pack_uint_(I);
+pack_(F) when is_float(F) ->
+    pack_double(F);
+pack_(nil) ->
+    << 16#C0:8 >>;
+pack_(true) ->
+    << 16#C3:8 >>;
+pack_(false) ->
+    << 16#C2:8 >>;
+pack_(Bin) when is_binary(Bin) ->
+    pack_raw(Bin);
+pack_(List)  when is_list(List) ->
+    pack_array(List);
+pack_({Map}) when is_list(Map) ->
+    pack_map(Map);
+pack_(Map) when is_tuple(Map), element(1,Map)=:=dict ->
+    pack_map(dict:to_list(Map));
+pack_(_Other) ->
+    throw({error, undefined}).
+
 % positive fixnum
 pack_uint_(N) when N < 128 ->
     << 2#0:1, N:7 >>;
@@ -115,7 +128,7 @@ pack_uint_(N) ->
     << 16#CF:8, N:64/big-unsigned-integer-unit:1 >>.
 
 % negative fixnum
-pack_int_(N) when is_integer(N) , N >= -32->
+pack_int_(N) when N >= -32->
     << 2#111:3, N:5 >>;
 % int 8
 pack_int_(N) when N > -128 ->
@@ -131,7 +144,7 @@ pack_int_(N) ->
     << 16#D3:8, N:64/big-signed-integer-unit:1 >>.
 
 % float : erlang's float is always IEEE 754 64bit format.
-%pack_float(F) when is_float(F)->
+% pack_float(F) when is_float(F)->
 %    << 16#CA:8, F:32/big-float-unit:1 >>.
 %    pack_double(F).
 % double
@@ -149,53 +162,44 @@ pack_raw(Bin) ->
 	    << 16#DB:8, Len:32/big-unsigned-integer-unit:1, Bin/binary >>
     end.
 
-% list / tuple
+% list
 pack_array(L) ->
     case length(L) of
  	Len when Len < 16 ->
  	    << 2#1001:4, Len:4/integer-unit:1, (pack_array_(L, <<>>))/binary >>;
 	Len when Len < 16#10000 -> % 65536
-	    << 16#DC:8, Len:16/big-unsigned-integer-unit:1,(pack_array_(L, <<>>))/binary >>;
+	    << 16#DC:8, Len:16/big-unsigned-integer-unit:1, (pack_array_(L, <<>>))/binary >>;
 	Len ->
-	    << 16#DD:8, Len:32/big-unsigned-integer-unit:1,(pack_array_(L, <<>>))/binary >>
+	    << 16#DD:8, Len:32/big-unsigned-integer-unit:1, (pack_array_(L, <<>>))/binary >>
     end.
+
 pack_array_([], Acc) -> Acc;
 pack_array_([Head|Tail], Acc) ->
-    pack_array_(Tail, <<Acc/binary,  (pack(Head))/binary>>).
+    pack_array_(Tail, <<Acc/binary,  (pack_(Head))/binary>>).
 
-% FIXME! this should be without lists:reverse/1
-unpack_array_(<<>>, 0, RetList)   -> {lists:reverse(RetList), <<>>};
-unpack_array_(Remain, 0, RetList) when is_binary(Remain)-> {lists:reverse(RetList), Remain};
-unpack_array_(<<>>, RestLen, _RetList) when RestLen > 0 ->  {more, undefined};
-unpack_array_(Bin, RestLen, RetList) when is_binary(Bin)->
-    case unpack(Bin) of
-	{more, _} -> {more, undefined};
-	{Term, Rest}-> unpack_array_(Rest, RestLen-1, [Term|RetList])
-    end.
+% Users SHOULD NOT send too long list: this uses lists:reverse/1
+unpack_array_(Bin, 0,   Acc) -> {lists:reverse(Acc), Bin};
+unpack_array_(Bin, Len, Acc) ->
+    {Term, Rest} = unpack_(Bin),
+    unpack_array_(Rest, Len-1, [Term|Acc]).
 
 pack_map_([], Acc) -> Acc;
 pack_map_([{Key,Value}|Tail], Acc) ->
-    pack_map_(Tail, << Acc/binary, (pack(Key))/binary, (pack(Value))/binary>>).
+    pack_map_(Tail, << Acc/binary, (pack_(Key))/binary, (pack_(Value))/binary>>).
 
-% FIXME! this should be without lists:reverse/1
--spec unpack_map_(binary(), non_neg_integer(), [{term(), msgpack_term()}])->
-    {more, non_neg_integer()} | { any(), binary()}.
-unpack_map_(Bin,  0,  Acc) -> {{lists:reverse(Acc)}, Bin};
+% Users SHOULD NOT send too long list: this uses lists:reverse/1
+-spec unpack_map_(binary(), non_neg_integer(), [{msgpack_term(), msgpack_term()}])->
+			 {[{msgpack_term(), msgpack_term()}], binary()} | no_return().
+unpack_map_(Bin, 0,   Acc) -> {{lists:reverse(Acc)}, Bin};
 unpack_map_(Bin, Len, Acc) ->
-    case unpack(Bin) of
-	{more, _} -> {more, undefined};
-	{Key, Rest} ->
-	    case unpack(Rest) of
-		{more, _} -> {more, undefined};
-		{Value, Rest2} ->
-		    unpack_map_(Rest2,Len-1,[{Key,Value}|Acc])
-	    end
-    end.
+    {Key, Rest} = unpack_(Bin),
+    {Value, Rest2} = unpack_(Rest),
+    unpack_map_(Rest2, Len-1, [{Key,Value}|Acc]).
 
--spec unpack_(Payload::binary()) -> 
-		     {more, pos_integer()} | {msgpack_term(), binary()} | {error, reason()}.
-unpack_(Binary)->
-    case Binary of
+% unpack them all
+-spec unpack_(Bin::binary()) -> {msgpack_term(), binary()} | {error, reason()} | no_return().
+unpack_(Bin) ->
+    case Bin of
 % ATOMS
 	<<16#C0, Rest/binary>> -> {nil, Rest};
 	<<16#C2, Rest/binary>> -> {false, Rest};
@@ -229,48 +233,34 @@ unpack_(Binary)->
 	<<2#101:3, L:5, V:L/binary, Rest/binary>> -> {V, Rest};                  % raw bytes
 	<<2#1001:4, L:4, Rest/binary>> ->            unpack_array_(Rest, L, []); % array
 	<<2#1000:4, L:4, Rest/binary>> ->            unpack_map_(Rest, L, []);   % map
-	
-% Incomplete / invalid data
-	<<16#CA, Rest/binary>> -> {more, 4-byte_size(Rest)};
-	<<16#CB, Rest/binary>> -> {more, 8-byte_size(Rest)};
-	<<16#CC>> ->              {more, 1};
-	<<16#CD, Rest/binary>> -> {more, 2-byte_size(Rest)};
-	<<16#CE, Rest/binary>> -> {more, 4-byte_size(Rest)};
-	<<16#CF, Rest/binary>> -> {more, 8-byte_size(Rest)};
-	<<16#D0>> ->              {more, 1};
-	<<16#D1, Rest/binary>> -> {more, 2-byte_size(Rest)};
-	<<16#D2, Rest/binary>> -> {more, 4-byte_size(Rest)};
-	<<16#D3, Rest/binary>> -> {more, 8-byte_size(Rest)};
-	<<16#DA, Rest/binary>> -> {more, 16-byte_size(Rest)};
-	<<16#DB, Rest/binary>> -> {more, 32-byte_size(Rest)};
-	<<16#DC, Rest/binary>> -> {more, 2-byte_size(Rest)};
-	<<16#DD, Rest/binary>> -> {more, 4-byte_size(Rest)};
-	<<16#DE, Rest/binary>> -> {more, 2-byte_size(Rest)};
-	<<16#DF, Rest/binary>> -> {more, 4-byte_size(Rest)};
-	<<2#101:3, L:5, Rest/binary>> ->  {more, L-byte_size(Rest)};
 
-	<<>> ->                  {more, 1};
-	<<2#101:3, _/binary>> -> {more, undefined};
-	<<F:8, Rest/binary>> when F==16#C1;
-				  F==16#C7; F==16#C8; F==16#C9; F==16#D5;
-				  F==16#D6; F==16#D7; F==16#D8; F==16#D9->
-	    {error, {badarg, <<F, Rest/binary>>}};
-	Other ->
-	    {error, {badarg, Other}}
+% Invalid data
+	<<F, _/binary>> when F==16#C1;
+	                     F==16#C4; F==16#C5; F==16#C6; F==16#C7; F==16#C8; F==16#C9;
+	                     F==16#D4; F==16#D5; F==16#D6; F==16#D7; F==16#D8; F==16#D9 ->
+	    throw(badarg);
+% Incomplete data (we've covered every complete/invalid case; anything left is incomplete)
+	_ ->
+	    throw(short)
     end.
 
-
 % ===== test codes ===== %
 -include_lib("eunit/include/eunit.hrl").
 -ifdef(EUNIT).
 
 compare_all([], [])-> ok;
-compare_all([], R)-> {toomuchrhs, R};
-compare_all(L, [])-> {toomuchlhs, L};
+compare_all([],  R)-> {toomuchrhs, R};
+compare_all(L,  [])-> {toomuchlhs, L};
 compare_all([LH|LTL], [RH|RTL]) ->
-    LH=RH,
+    ?assertEqual(LH, RH),
     compare_all(LTL, RTL).
 
+test_([]) -> 0;
+test_([Term|Rest])->
+    Pack = msgpack:pack(Term),
+    ?assertEqual({Term, <<>>}, msgpack:unpack( Pack )),
+    1+test_(Rest).
+
 test_data()->
     [true, false, nil,
      0, 1, 2, 123, 512, 1230, 678908, 16#FFFFFFFFFF,
@@ -290,12 +280,13 @@ basic_test()->
     Passed = length(Tests).
 
 port_test()->
-    Tests = test_data(),
-    {[Tests],<<>>} = msgpack:unpack(msgpack:pack([Tests])),
     Port = open_port({spawn, "ruby ../test/crosslang.rb"}, [binary]),
-    true = port_command(Port, msgpack:pack(Tests) ),
+    Tests = test_data(),
+    S=msgpack:pack([Tests]),
+    true = port_command(Port, S),
+    {[Tests],<<>>} = msgpack:unpack(S),
     receive
-	{Port, {data, Data}}->  {Tests, <<>>}=msgpack:unpack(Data)
+	{Port, {data, Data}}->  {[Tests], <<>>}=msgpack:unpack(Data)
     after 1024-> ?assert(false)   end,
     port_close(Port).
 
@@ -303,12 +294,7 @@ test_p(Len,Term,OrigBin,Len) ->
     {Term, <<>>}=msgpack:unpack(OrigBin);
 test_p(I,_,OrigBin,Len) when I < Len->
     <<Bin:I/binary, _/binary>> = OrigBin,
-    case msgpack:unpack(Bin) of
-	{more, N} when not is_integer(N) ->
-	    ?assertEqual(undefined, N);
-	{more, N} ->
-	    ?assert( N < Len )
-    end.
+    ?assertEqual({error,short}, msgpack:unpack(Bin)).
 
 partial_test()-> % error handling test.
     Term = lists:seq(0, 45),
@@ -318,10 +304,7 @@ partial_test()-> % error handling test.
 
 long_test()->
     Longer = lists:seq(0, 655),
-%    Longest = lists:seq(0,12345),
-    {Longer, <<>>} = msgpack:unpack(msgpack:pack(Longer)),
-%    {Longest, <<>>} = msgpack:unpack(msgpack:pack(Longest)).
-    ok.
+    {Longer, <<>>} = msgpack:unpack(msgpack:pack(Longer)).
 
 map_test()->
     Ints = lists:seq(0, 65),
@@ -331,6 +314,7 @@ map_test()->
     ok.
 
 unknown_test()->
+    Port = open_port({spawn, "ruby testcase_generator.rb"}, [binary]),
     Tests = [0, 1, 2, 123, 512, 1230, 678908,
 	     -1, -23, -512, -1230, -567898,
 	     <<"hogehoge">>, <<"243546rf7g68h798j">>,
@@ -338,25 +322,22 @@ unknown_test()->
 	     -234.4355, 1.0e-34, 1.0e64,
 	     [23, 234, 0.23],
 	     [0,42,<<"sum">>, [1,2]], [1,42, nil, [3]],
-	     {[{1,2},{<<"hoge">>,nil}]},
+	     {[{1,2},{<<"hoge">>,nil}]}, % map
 	     -234, -50000,
 	     42
 	    ],
-    Port = open_port({spawn, "ruby testcase_generator.rb"}, [binary]),
     receive
-	{Port, {data, Data}}->
-	    compare_all(Tests, msgpack:unpack_all(Data))
-    after 1024-> ?assert(false)   end,
+	{Port, {data, Data}}-> compare_all(Tests, msgpack:unpack_all(Data))
+    after 1024-> ?assert(false)  end,
     port_close(Port).
 
-test_([]) -> 0;
-test_([Before|Rest])->
-    Pack = msgpack:pack(Before),
-    {After, <<>>} = msgpack:unpack( Pack ),
-    ?assertEqual(Before, After),
-    1+test_(Rest).
-
 other_test()->
-    {more,1}=msgpack:unpack(<<>>).
+    ?assertEqual({error,short},msgpack:unpack(<<>>)).
+
+benchmark_test()->
+    Data=[test_data() || _ <- lists:seq(0, 10000)],
+    S=?debugTime("  serialize", msgpack:pack(Data)),
+    {Data,<<>>}=?debugTime("deserialize", msgpack:unpack(S)),
+    ?debugFmt("for ~p KB test data.", [byte_size(S) div 1024]).
 
 -endif.
diff --git a/perl/Changes b/perl/Changes
index b03a9d0c..f32d5f49 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,7 @@
+0.13
+
+    - clearly specify requires_c99(), because msgpack C header requires C99.
+
 0.12
 
     - PERL_NO_GET_CONTEXT makes horrible dTHXs. remove it.
diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index 58ab7c79..e9f9618a 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -1,4 +1,6 @@
 use inc::Module::Install;
+use Config;
+
 name 'Data-MessagePack';
 all_from 'lib/Data/MessagePack.pm';
 readme_from('lib/Data/MessagePack.pm');
@@ -11,6 +13,8 @@ tests 't/*.t';
 recursive_author_tests('xt');
 use_ppport 3.19;
 
+requires_c99(); # msgpack C library requires C99.
+
 clean_files qw{
     *.stackdump
     *.gcov *.gcda *.gcno
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index dcc713d5..ee07d35f 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -4,7 +4,7 @@ use warnings;
 use XSLoader;
 use 5.008001;
 
-our $VERSION = '0.12';
+our $VERSION = '0.13';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };