1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2000-2012. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(bs_match_misc_SUITE).
   21: 
   22: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   23: 	 init_per_testcase/2,end_per_testcase/2,
   24: 	 init_per_suite/1,end_per_suite/1,
   25: 	 bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1,
   26: 	 kenneth/1,encode_binary/1,native/1,happi/1,
   27: 	 size_var/1,wiger/1,x0_context/1,huge_float_field/1,
   28: 	 writable_binary_matched/1,otp_7198/1,
   29: 	 unordered_bindings/1,float_middle_endian/1]).
   30: 
   31: -include_lib("test_server/include/test_server.hrl").
   32: 
   33: suite() -> [{ct_hooks,[ts_install_cth]}].
   34: 
   35: all() -> 
   36:     [bound_var, bound_tail, t_float, little_float, sean,
   37:      kenneth, encode_binary, native, happi, size_var, wiger,
   38:      x0_context, huge_float_field, writable_binary_matched,
   39:      otp_7198, unordered_bindings, float_middle_endian].
   40: 
   41: groups() -> 
   42:     [].
   43: 
   44: init_per_group(_GroupName, Config) ->
   45:     Config.
   46: 
   47: end_per_group(_GroupName, Config) ->
   48:     Config.
   49: 
   50: init_per_suite(Config) when is_list(Config) ->
   51:     ?line test_lib:interpret(?MODULE),
   52:     ?line true = lists:member(?MODULE, int:interpreted()),
   53:     Config.
   54: 
   55: end_per_suite(Config) when is_list(Config) ->
   56:     ok.
   57: 
   58: init_per_testcase(_Case, Config) ->
   59:     test_lib:interpret(?MODULE),
   60:     Dog = test_server:timetrap(?t:minutes(15)),
   61:     [{watchdog,Dog}|Config].
   62: 
   63: end_per_testcase(_Case, Config) ->
   64:     Dog = ?config(watchdog, Config),
   65:     ?t:timetrap_cancel(Dog),
   66:     ok.
   67: 
   68: bound_var(doc) -> "Test matching of bound variables.";
   69: bound_var(Config) when is_list(Config) ->
   70:     ?line ok = bound_var(42, 13, <<42,13>>),
   71:     ?line nope = bound_var(42, 13, <<42,255>>),
   72:     ?line nope = bound_var(42, 13, <<154,255>>),
   73:     ok.
   74: 
   75: bound_var(A, B, <<A:8,B:8>>) -> ok;
   76: bound_var(_, _, _) -> nope.
   77: 
   78: bound_tail(doc) -> "Test matching of a bound tail.";
   79: bound_tail(Config) when is_list(Config) ->
   80:     ?line ok = bound_tail(<<>>, <<13,14>>),
   81:     ?line ok = bound_tail(<<2,3>>, <<1,1,2,3>>),
   82:     ?line nope = bound_tail(<<2,3>>, <<1,1,2,7>>),
   83:     ?line nope = bound_tail(<<2,3>>, <<1,1,2,3,4>>),
   84:     ?line nope = bound_tail(<<2,3>>, <<>>),
   85:     ok.
   86: 
   87: bound_tail(T, <<_:16,T/binary>>) -> ok;
   88: bound_tail(_, _) -> nope.
   89: 
   90: t_float(Config) when is_list(Config) ->
   91:     F = f1(),
   92:     G = f_one(),
   93: 
   94:     ?line G = match_float(<<63,128,0,0>>, 32, 0),
   95:     ?line G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0),
   96: 
   97:     ?line fcmp(F, match_float(<<F:32/float>>, 32, 0)),
   98:     ?line fcmp(F, match_float(<<F:64/float>>, 64, 0)),
   99:     ?line fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)),
  100:     ?line fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
  101:     ?line fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)),
  102:     ?line fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
  103: 
  104:     ?line {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16, 0)),
  105:     ?line {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16#7fffffff, 0)),
  106: 
  107:     ok.
  108: 
  109: float_middle_endian(Config) when is_list(Config) ->
  110:     F = 9007199254740990.0, % turns to -NaN when word-swapped
  111:     ?line fcmp(F, match_float(<<F:64/float>>, 64, 0)),
  112:     ?line fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
  113:     ?line fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
  114:     ok.
  115: 
  116: 
  117: fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok.
  118: 
  119: match_float(Bin0, Fsz, I) ->
  120:     Bin = make_sub_bin(Bin0),
  121:     Bsz = size(Bin) * 8,
  122:     Tsz = Bsz - Fsz - I,
  123:     <<_:I,F:Fsz/float,_:Tsz>> = Bin,
  124:     F.
  125: 
  126: little_float(Config) when is_list(Config) ->
  127:     F = f2(),
  128:     G = f_one(),
  129: 
  130:     ?line G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0),
  131:     ?line G = match_float_little(<<0,0,128,63>>, 32, 0),
  132: 
  133:     ?line fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)),
  134:     ?line fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)),
  135:     ?line fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)),
  136:     ?line fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)),
  137:     ?line fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)),
  138:     ?line fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)),
  139: 
  140:     ok.
  141: 
  142: match_float_little(Bin0, Fsz, I) ->
  143:     Bin = make_sub_bin(Bin0),
  144:     Bsz = size(Bin) * 8,
  145:     Tsz = Bsz - Fsz - I,
  146:     <<_:I,F:Fsz/float-little,_:Tsz>> = Bin,
  147:     F.
  148: 
  149: 
  150: make_sub_bin(Bin0) ->
  151:     Sz = size(Bin0),
  152:     Bin1 = <<37,Bin0/binary,38,39>>,
  153:     <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1,
  154:     Bin.
  155: 
  156: f1() ->
  157:     3.1415.
  158: 
  159: f2() ->
  160:     2.7133.
  161: 
  162: f_one() ->
  163:     1.0.
  164: 
  165: sean(Config) when is_list(Config) ->
  166:     ?line small = sean1(<<>>),
  167:     ?line small = sean1(<<1>>),
  168:     ?line small = sean1(<<1,2>>),
  169:     ?line small = sean1(<<1,2,3>>),
  170:     ?line large = sean1(<<1,2,3,4>>),
  171: 
  172:     ?line small = sean1(<<4>>),
  173:     ?line small = sean1(<<4,5>>),
  174:     ?line small = sean1(<<4,5,6>>),
  175:     ?line {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)),
  176:     ok.
  177: 
  178: sean1(<<B/binary>>) when byte_size(B) < 4 -> small;
  179: sean1(<<1, _B/binary>>) -> large.
  180: 
  181: kenneth(Config) when is_list(Config) ->
  182:     {ok,[145,148,113,129,0,0,0,0]} =
  183: 	msisdn_internal_storage(<<145,148,113,129,0,0,0,0>>, []).
  184: 
  185: msisdn_internal_storage(<<>>,MSISDN) ->
  186:     {ok,lists:reverse(MSISDN)};
  187: msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) ->
  188:     {ok,lists:reverse(MSISDN)};
  189: msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when
  190:     DigitN < 10 ->
  191:     {ok,lists:reverse([(DigitN bor 2#11110000)|MSISDN])};
  192: msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when
  193:     DigitNplus1 < 10,
  194:     DigitN < 10 ->
  195:     NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN],
  196:     msisdn_internal_storage(Rest,NewMSISDN);
  197: msisdn_internal_storage(_Rest,_MSISDN) ->
  198:     {fault}. %% Mandatory IE incorrect
  199: 
  200: encode_binary(Config) when is_list(Config) ->
  201:     "C2J2QiSc" = encodeBinary(<<11,98,118,66,36,156>>, []),
  202:     ok.
  203: 
  204: encodeBinary(<<>>, Output) ->
  205:     lists:reverse(Output);
  206: encodeBinary(<<Data:1/binary>>, Output) ->
  207:     <<DChar1:6, DChar2:2>> = Data,
  208:     Char1 = getBase64Char(DChar1),
  209:     Char2 = getBase64Char(DChar2),
  210:     Char3 = "=",
  211:     Char4 = "=",
  212:     NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
  213:     encodeBinary(<<>>, NewOutput);
  214: encodeBinary(<<Data:2/binary>>, Output) ->
  215:     <<DChar1:6, DChar2:6, DChar3:4>> = Data,
  216:     Char1 = getBase64Char(DChar1),
  217:     Char2 = getBase64Char(DChar2),
  218:     Char3 = getBase64Char(DChar3),
  219:     Char4 = "=",
  220:     NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
  221:     encodeBinary(<<>>, NewOutput);
  222: encodeBinary(<<Data:3/binary, Rest/binary>>, Output) ->
  223:     <<DChar1:6, DChar2:6, DChar3:6, DChar4:6>> = Data,
  224:     Char1 = getBase64Char(DChar1),
  225:     Char2 = getBase64Char(DChar2),
  226:     Char3 = getBase64Char(DChar3),
  227:     Char4 = getBase64Char(DChar4),
  228:     NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
  229:     encodeBinary(Rest, NewOutput);
  230: encodeBinary(_Data, _) ->
  231:     error.
  232: 
  233: getBase64Char(0)  -> "A";
  234: getBase64Char(1)  -> "B";
  235: getBase64Char(2)  -> "C";
  236: getBase64Char(3)  -> "D";
  237: getBase64Char(4)  -> "E";
  238: getBase64Char(5)  -> "F";
  239: getBase64Char(6)  -> "G";
  240: getBase64Char(7)  -> "H";
  241: getBase64Char(8)  -> "I";
  242: getBase64Char(9)  -> "J";
  243: getBase64Char(10) -> "K";
  244: getBase64Char(11) -> "L";
  245: getBase64Char(12) -> "M";
  246: getBase64Char(13) -> "N";
  247: getBase64Char(14) -> "O";
  248: getBase64Char(15) -> "P";
  249: getBase64Char(16) -> "Q";
  250: getBase64Char(17) -> "R";
  251: getBase64Char(18) -> "S";
  252: getBase64Char(19) -> "T";
  253: getBase64Char(20) -> "U";
  254: getBase64Char(21) -> "V";
  255: getBase64Char(22) -> "W";
  256: getBase64Char(23) -> "X";
  257: getBase64Char(24) -> "Y";
  258: getBase64Char(25) -> "Z";
  259: getBase64Char(26) -> "a";
  260: getBase64Char(27) -> "b";
  261: getBase64Char(28) -> "c";
  262: getBase64Char(29) -> "d";
  263: getBase64Char(30) -> "e";
  264: getBase64Char(31) -> "f";
  265: getBase64Char(32) -> "g";
  266: getBase64Char(33) -> "h";
  267: getBase64Char(34) -> "i";
  268: getBase64Char(35) -> "j";
  269: getBase64Char(36) -> "k";
  270: getBase64Char(37) -> "l";
  271: getBase64Char(38) -> "m";
  272: getBase64Char(39) -> "n";
  273: getBase64Char(40) -> "o";
  274: getBase64Char(41) -> "p";
  275: getBase64Char(42) -> "q";
  276: getBase64Char(43) -> "r";
  277: getBase64Char(44) -> "s";
  278: getBase64Char(45) -> "t";
  279: getBase64Char(46) -> "u";
  280: getBase64Char(47) -> "v";
  281: getBase64Char(48) -> "w";
  282: getBase64Char(49) -> "x";
  283: getBase64Char(50) -> "y";
  284: getBase64Char(51) -> "z";
  285: getBase64Char(52) -> "0";
  286: getBase64Char(53) -> "1";
  287: getBase64Char(54) -> "2";
  288: getBase64Char(55) -> "3";
  289: getBase64Char(56) -> "4";
  290: getBase64Char(57) -> "5";
  291: getBase64Char(58) -> "6";
  292: getBase64Char(59) -> "7";
  293: getBase64Char(60) -> "8";
  294: getBase64Char(61) -> "9";
  295: getBase64Char(62) -> "+";
  296: getBase64Char(63) -> "/";
  297: getBase64Char(_Else) ->
  298:     %% This is an illegal input.
  299: %    cgLogEM:log(error, ?MODULE, getBase64Char, [Else],
  300: %		"illegal input",
  301: %		?LINE, version()),
  302:     "**".
  303: 
  304: -define(M(F), <<F>> = <<F>>).
  305: 
  306: native(Config) when is_list(Config) ->
  307:     ?line ?M(3.14:64/native-float),
  308:     ?line ?M(333:16/native),
  309:     ?line ?M(38658345:32/native),
  310:     case <<1:16/native>> of
  311: 	<<0,1>> -> native_big();
  312: 	<<1,0>> -> native_little()
  313:     end.
  314: 
  315: native_big() ->
  316:     ?line <<37.33:64/native-float>> = <<37.33:64/big-float>>,
  317:     ?line <<3974:16/native-integer>> = <<3974:16/big-integer>>,
  318:     {comment,"Big endian"}.
  319: 
  320: native_little() ->
  321:     ?line <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>,
  322:     ?line <<7974:16/native-integer>> = <<7974:16/little-integer>>,
  323:     {comment,"Little endian"}.
  324: 
  325: happi(Config) when is_list(Config) ->
  326:     Bin = <<".123">>,
  327:     ?line <<"123">> = lex_digits1(Bin, 1, []),
  328:     ?line <<"123">> = lex_digits2(Bin, 1, []),
  329:     ok.
  330: 
  331: lex_digits1(<<$., Rest/binary>>,_Val,_Acc) ->
  332:     Rest;
  333: lex_digits1(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
  334:     lex_digits1(Rest,Val*10+dec(N),Acc);
  335: lex_digits1(_Other,_Val,_Acc) ->
  336:     not_ok.
  337: 
  338: lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
  339:     lex_digits2(Rest,Val*10+dec(N),Acc);
  340: lex_digits2(<<$., Rest/binary>>,_Val,_Acc) ->
  341:     Rest;
  342: lex_digits2(_Other,_Val,_Acc) ->
  343:     not_ok.
  344: 
  345: dec(A) ->
  346:     A-$0.
  347: 
  348: size_var(Config) when is_list(Config) ->
  349:     ?line {<<45>>,<<>>} = split(<<1:16,45>>),
  350:     ?line {<<45>>,<<46,47>>} = split(<<1:16,45,46,47>>),
  351:     ?line {<<45,46>>,<<47>>} = split(<<2:16,45,46,47>>),
  352: 
  353:     ?line {<<45,46,47>>,<<48>>} = split_2(<<16:8,3:16,45,46,47,48>>),
  354: 
  355:     ?line {<<45,46>>,<<47>>} = split(2, <<2:16,45,46,47>>),
  356:     ?line {'EXIT',{function_clause,_}} = (catch split(42, <<2:16,45,46,47>>)),
  357: 
  358:     ?line <<"cdef">> = skip(<<2:8,"abcdef">>),
  359: 
  360:     ok.
  361: 
  362: split(<<N:16,B:N/binary,T/binary>>) ->
  363:     {B,T}.
  364: 
  365: split(N, <<N:16,B:N/binary,T/binary>>) ->
  366:     {B,T}.
  367: 
  368: split_2(<<N0:8,N:N0,B:N/binary,T/binary>>) ->
  369:     {B,T}.
  370: 
  371: skip(<<N:8,_:N/binary,T/binary>>) -> T.
  372: 
  373: wiger(Config) when is_list(Config) ->
  374:     ?line ok1 = wcheck(<<3>>),
  375:     ?line ok2 = wcheck(<<1,2,3>>),
  376:     ?line ok3 = wcheck(<<4>>),
  377:     ?line {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
  378:     ?line {error,<<>>} = wcheck(<<>>),
  379:     ok.
  380: 
  381: wcheck(<<A>>) when A==3->
  382:     ok1;
  383: wcheck(<<_,_:2/binary>>) ->
  384:     ok2;
  385: wcheck(<<_>>) ->
  386:     ok3;
  387: wcheck(Other) ->
  388:     {error,Other}.
  389: 
  390: %% Test that having the match context in x(0) works.
  391: 
  392: x0_context(Config) when is_list(Config) ->
  393:     x0_0([], <<3.0:64/float,42:16,123456:32>>).
  394: 
  395: x0_0(_, Bin) ->
  396:     <<3.0:64/float,42:16,_/binary>> = Bin,
  397:     x0_1([], Bin, 64, 16, 2).
  398: 
  399: x0_1(_, Bin, FloatSz, IntSz, BinSz) ->
  400:     <<_:FloatSz/float,42:IntSz,B:BinSz/binary,C:1/binary,D/binary>> = Bin,
  401:     id({B,C,D}),
  402:     <<_:FloatSz/float,42:IntSz,B:BinSz/binary,_/binary>> = Bin,
  403:     x0_2([], Bin).
  404: 
  405: x0_2(_, Bin) ->
  406:     <<_:64,0:7,42:9,_/binary>> = Bin,
  407:     x0_3([], Bin).
  408: 
  409: x0_3(_, Bin) ->
  410:     case Bin of
  411: 	<<_:72,7:8,_/binary>> ->
  412: 	    ?line ?t:fail();
  413: 	<<_:64,0:16,_/binary>> ->
  414: 	    ?line ?t:fail();
  415: 	<<_:64,42:16,123456:32,_/binary>> ->
  416: 	    ok
  417:     end.
  418: 
  419: 
  420: huge_float_field(Config) when is_list(Config) ->
  421:     Sz = 1 bsl 27,
  422:     ?line Bin = <<0:Sz>>,
  423: 
  424:     ?line nomatch = overflow_huge_float_skip_32(Bin),
  425:     ?line nomatch = overflow_huge_float_32(Bin),
  426: 
  427:     ?line ok = overflow_huge_float(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
  428:     ?line ok = overflow_huge_float_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
  429:     ok.
  430: 
  431: overflow_huge_float_skip_32(<<_:4294967296/float,0,_/binary>>) -> 1; % 1 bsl 32
  432: overflow_huge_float_skip_32(<<_:33554432/float-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
  433: overflow_huge_float_skip_32(<<_:67108864/float-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
  434: overflow_huge_float_skip_32(<<_:134217728/float-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
  435: overflow_huge_float_skip_32(<<_:268435456/float-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
  436: overflow_huge_float_skip_32(<<_:536870912/float-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
  437: overflow_huge_float_skip_32(<<_:1073741824/float-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
  438: overflow_huge_float_skip_32(<<_:2147483648/float-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
  439: overflow_huge_float_skip_32(_) -> nomatch.
  440: 
  441: overflow_huge_float_32(<<F:4294967296/float,_/binary>>) -> {1,F}; % 1 bsl 32
  442: overflow_huge_float_32(<<F:33554432/float-unit:128,0,_/binary>>) -> {2,F}; % 1 bsl 25
  443: overflow_huge_float_32(<<F:67108864/float-unit:128,0,_/binary>>) -> {3,F}; % 1 bsl 26
  444: overflow_huge_float_32(<<F:134217728/float-unit:128,0,_/binary>>) -> {4,F}; % 1 bsl 27
  445: overflow_huge_float_32(<<F:268435456/float-unit:128,0,_/binary>>) -> {5,F}; % 1 bsl 28
  446: overflow_huge_float_32(<<F:536870912/float-unit:128,0,_/binary>>) -> {6,F}; % 1 bsl 29
  447: overflow_huge_float_32(<<F:1073741824/float-unit:128,0,_/binary>>) -> {7,F}; % 1 bsl 30
  448: overflow_huge_float_32(<<F:2147483648/float-unit:128,0,_/binary>>) -> {8,F}; % 1 bsl 31
  449: overflow_huge_float_32(_) -> nomatch.
  450: 
  451: 
  452: overflow_huge_float(Bin, [Sz0|Sizes]) ->
  453:     Sz = id(1 bsl Sz0),
  454:     case Bin of
  455: 	<<_:Sz/float-unit:8,0,_/binary>> ->
  456: 	    {error,Sz};
  457: 	_ ->
  458: 	    case Bin of
  459: 		<<Var:Sz/float-unit:8,0,_/binary>> ->
  460: 		    {error,Sz,Var};
  461: 		_ ->
  462: 		    overflow_huge_float(Bin, Sizes)
  463: 	    end
  464:     end;
  465: overflow_huge_float(_, []) -> ok.
  466: 
  467: overflow_huge_float_unit128(Bin, [Sz0|Sizes]) ->
  468:     Sz = id(1 bsl Sz0),
  469:     case Bin of
  470: 	<<_:Sz/float-unit:128,0,_/binary>> ->
  471: 	    {error,Sz};
  472: 	_ ->
  473: 	    case Bin of
  474: 		<<Var:Sz/float-unit:128,0,_/binary>> ->
  475: 		    {error,Sz,Var};
  476: 		_ ->
  477: 		    overflow_huge_float_unit128(Bin, Sizes)
  478: 	    end
  479:     end;
  480: overflow_huge_float_unit128(_, []) -> ok.
  481: 
  482: 
  483: %%
  484: %% Test that a writable binary can be safely matched.
  485: %%
  486: 
  487: writable_binary_matched(Config) when is_list(Config) ->
  488:     ?line WritableBin = create_writeable_binary(),
  489:     ?line writable_binary_matched(WritableBin, WritableBin, 500).
  490: 
  491: writable_binary_matched(<<0>>, _, N) ->
  492:     if
  493: 	N =:= 0 -> ok;
  494: 	true ->
  495: 	    put(grow_heap, [N|get(grow_heap)]),
  496: 	    ?line WritableBin = create_writeable_binary(),
  497: 	    ?line writable_binary_matched(WritableBin, WritableBin, N-1)
  498:     end;
  499: writable_binary_matched(<<B:8,T/binary>>, WritableBin0, N) ->
  500:     ?line WritableBin = writable_binary(WritableBin0, B),
  501:     writable_binary_matched(T, WritableBin, N).
  502: 
  503: writable_binary(WritableBin0, B) when is_binary(WritableBin0) ->
  504:     %% Heavy append to force the binary to move.
  505:     ?line WritableBin = <<WritableBin0/binary,0:(size(WritableBin0))/unit:8,B>>,
  506:     ?line id(<<(id(0)):128/unit:8>>),
  507:     WritableBin.
  508: 
  509: create_writeable_binary() ->
  510:   <<(id(<<>>))/binary,1,2,3,4,5,6,0>>.
  511: 
  512: otp_7198(Config) when is_list(Config) ->
  513:     %% When a match context was reused, and grown at the same time to
  514:     %% increase the number of saved positions, the thing word was not updated
  515:     %% to account for the new size. Therefore, if there was a garbage collection,
  516:     %% the new slots would be included in the garbage collection.
  517:     ?line [do_otp_7198(FillerSize) || FillerSize <- lists:seq(0, 256)],
  518:     ok.
  519: 
  520: do_otp_7198(FillerSize) ->
  521:     Filler = erlang:make_tuple(FillerSize, 42),
  522:     {Pid,Ref} = spawn_monitor(fun() -> do_otp_7198_test(Filler) end),
  523:     receive
  524: 	{'DOWN',Ref,process,Pid,normal} ->
  525: 	    ok;
  526: 	{'DOWN',Ref,process,Pid,Reason} ->
  527: 	    io:format("unexpected: ~p", [Reason]),
  528: 	    ?line ?t:fail()
  529:     end.
  530: 
  531: do_otp_7198_test(_) ->
  532:     [{'KEYWORD',114},
  533:      {'KEYWORD',101},
  534:      {'KEYWORD',103},
  535:      {'KEYWORD',105},
  536:      {'KEYWORD',111},
  537:      {'FIELD',110},
  538:      {'KEYWORD',119},
  539:      {'KEYWORD',104},
  540:      {'KEYWORD',97},
  541:      {'KEYWORD',116},
  542:      {'KEYWORD',101},
  543:      {'KEYWORD',118},
  544:      {'KEYWORD',101},
  545:      {'KEYWORD',114},
  546:      '$thats_all_folks$'] = otp_7198_scan(<<"region:whatever">>, []).
  547: 
  548: 
  549: otp_7198_scan(<<>>, TokAcc) ->
  550:         lists:reverse(['$thats_all_folks$' | TokAcc]);
  551: 
  552: otp_7198_scan(<<D, Z, Rest/binary>>, TokAcc) when
  553:                         (D =:= $D orelse D =:= $d) and
  554:                         ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
  555:         otp_7198_scan(<<Z, Rest/binary>>, ['AND' | TokAcc]);
  556: 
  557: otp_7198_scan(<<D>>, TokAcc) when
  558:                         (D =:= $D) or (D =:= $d) ->
  559:         otp_7198_scan(<<>>, ['AND' | TokAcc]);
  560: 
  561: otp_7198_scan(<<N, Z, Rest/binary>>, TokAcc) when
  562:                         (N =:= $N orelse N =:= $n) and
  563:                         ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
  564:         otp_7198_scan(<<Z, Rest/binary>>, ['NOT' | TokAcc]);
  565: 
  566: otp_7198_scan(<<C, Rest/binary>>, TokAcc) when
  567:                                 (C >= $A) and (C =< $Z);
  568:                                 (C >= $a) and (C =< $z);
  569:                                 (C >= $0) and (C =< $9) ->
  570:         case Rest of
  571:                 <<$:, R/binary>> ->
  572:                         otp_7198_scan(R, [{'FIELD', C} | TokAcc]);
  573:                 _ ->
  574:                         otp_7198_scan(Rest, [{'KEYWORD', C} | TokAcc])
  575:         end.
  576: 
  577: unordered_bindings(Config) when is_list(Config) ->
  578:     {<<1,2,3,4>>,<<42,42>>,<<3,3,3>>} =
  579: 	unordered_bindings(4, 2, 3, <<1,2,3,4, 42,42, 3,3,3, 3>>),
  580:     ok.
  581: 
  582: unordered_bindings(CompressedLength, HashSize, PadLength, T) ->
  583:     <<Content:CompressedLength/binary,Mac:HashSize/binary,
  584:      Padding:PadLength/binary,PadLength>> = T,
  585:     {Content,Mac,Padding}.
  586: 
  587: 
  588: id(I) -> I.