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