1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(bs_match_misc_SUITE).
22
23-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
24	 init_per_testcase/2,end_per_testcase/2,
25	 init_per_suite/1,end_per_suite/1,
26	 bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1,
27	 kenneth/1,encode_binary/1,native/1,happi/1,
28	 size_var/1,wiger/1,x0_context/1,huge_float_field/1,
29	 writable_binary_matched/1,otp_7198/1,
30	 unordered_bindings/1,float_middle_endian/1]).
31
32-include_lib("common_test/include/ct.hrl").
33
34suite() ->
35    [{ct_hooks,[ts_install_cth]},
36     {timetrap,{minutes,15}}].
37
38all() ->
39    [bound_var, bound_tail, t_float, little_float, sean,
40     kenneth, encode_binary, native, happi, size_var, wiger,
41     x0_context, huge_float_field, writable_binary_matched,
42     otp_7198, unordered_bindings, float_middle_endian].
43
44groups() ->
45    [].
46
47init_per_group(_GroupName, Config) ->
48    Config.
49
50end_per_group(_GroupName, Config) ->
51    Config.
52
53init_per_suite(Config) when is_list(Config) ->
54    test_lib:interpret(?MODULE),
55    true = lists:member(?MODULE, int:interpreted()),
56    Config.
57
58end_per_suite(Config) when is_list(Config) ->
59    ok.
60
61init_per_testcase(_Case, Config) ->
62    test_lib:interpret(?MODULE),
63    Config.
64
65end_per_testcase(_Case, _Config) ->
66    ok.
67
68%% Test matching of bound variables.
69bound_var(Config) when is_list(Config) ->
70    ok = bound_var(42, 13, <<42,13>>),
71    nope = bound_var(42, 13, <<42,255>>),
72    nope = bound_var(42, 13, <<154,255>>),
73    ok.
74
75bound_var(A, B, <<A:8,B:8>>) -> ok;
76bound_var(_, _, _) -> nope.
77
78%% Test matching of a bound tail.
79bound_tail(Config) when is_list(Config) ->
80    ok = bound_tail(<<>>, <<13,14>>),
81    ok = bound_tail(<<2,3>>, <<1,1,2,3>>),
82    nope = bound_tail(<<2,3>>, <<1,1,2,7>>),
83    nope = bound_tail(<<2,3>>, <<1,1,2,3,4>>),
84    nope = bound_tail(<<2,3>>, <<>>),
85    ok.
86
87bound_tail(T, <<_:16,T/binary>>) -> ok;
88bound_tail(_, _) -> nope.
89
90t_float(Config) when is_list(Config) ->
91    F = f1(),
92    G = f_one(),
93
94    G = match_float(<<63,128,0,0>>, 32, 0),
95    G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0),
96
97    fcmp(F, match_float(<<F:32/float>>, 32, 0)),
98    fcmp(F, match_float(<<F:64/float>>, 64, 0)),
99    fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)),
100    fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
101    fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)),
102    fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
103
104    {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16, 0)),
105    {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16#7fffffff, 0)),
106
107    ok.
108
109float_middle_endian(Config) when is_list(Config) ->
110    F = 9007199254740990.0, % turns to -NaN when word-swapped
111    fcmp(F, match_float(<<F:64/float>>, 64, 0)),
112    fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
113    fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
114    ok.
115
116
117fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok.
118
119match_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
126little_float(Config) when is_list(Config) ->
127    F = f2(),
128    G = f_one(),
129
130    G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0),
131    G = match_float_little(<<0,0,128,63>>, 32, 0),
132
133    fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)),
134    fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)),
135    fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)),
136    fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)),
137    fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)),
138    fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)),
139
140    ok.
141
142match_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
150make_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
156f1() ->
157    3.1415.
158
159f2() ->
160    2.7133.
161
162f_one() ->
163    1.0.
164
165sean(Config) when is_list(Config) ->
166    small = sean1(<<>>),
167    small = sean1(<<1>>),
168    small = sean1(<<1,2>>),
169    small = sean1(<<1,2,3>>),
170    large = sean1(<<1,2,3,4>>),
171
172    small = sean1(<<4>>),
173    small = sean1(<<4,5>>),
174    small = sean1(<<4,5,6>>),
175    {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)),
176    ok.
177
178sean1(<<B/binary>>) when byte_size(B) < 4 -> small;
179sean1(<<1, _B/binary>>) -> large.
180
181kenneth(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
185msisdn_internal_storage(<<>>,MSISDN) ->
186    {ok,lists:reverse(MSISDN)};
187msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) ->
188    {ok,lists:reverse(MSISDN)};
189msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when
190      DigitN < 10 ->
191    {ok,lists:reverse([(DigitN bor 2#11110000)|MSISDN])};
192msisdn_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);
197msisdn_internal_storage(_Rest,_MSISDN) ->
198    {fault}. %% Mandatory IE incorrect
199
200encode_binary(Config) when is_list(Config) ->
201    "C2J2QiSc" = encodeBinary(<<11,98,118,66,36,156>>, []),
202    ok.
203
204encodeBinary(<<>>, Output) ->
205    lists:reverse(Output);
206encodeBinary(<<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);
214encodeBinary(<<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);
222encodeBinary(<<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);
230encodeBinary(_Data, _) ->
231    error.
232
233getBase64Char(0)  -> "A";
234getBase64Char(1)  -> "B";
235getBase64Char(2)  -> "C";
236getBase64Char(3)  -> "D";
237getBase64Char(4)  -> "E";
238getBase64Char(5)  -> "F";
239getBase64Char(6)  -> "G";
240getBase64Char(7)  -> "H";
241getBase64Char(8)  -> "I";
242getBase64Char(9)  -> "J";
243getBase64Char(10) -> "K";
244getBase64Char(11) -> "L";
245getBase64Char(12) -> "M";
246getBase64Char(13) -> "N";
247getBase64Char(14) -> "O";
248getBase64Char(15) -> "P";
249getBase64Char(16) -> "Q";
250getBase64Char(17) -> "R";
251getBase64Char(18) -> "S";
252getBase64Char(19) -> "T";
253getBase64Char(20) -> "U";
254getBase64Char(21) -> "V";
255getBase64Char(22) -> "W";
256getBase64Char(23) -> "X";
257getBase64Char(24) -> "Y";
258getBase64Char(25) -> "Z";
259getBase64Char(26) -> "a";
260getBase64Char(27) -> "b";
261getBase64Char(28) -> "c";
262getBase64Char(29) -> "d";
263getBase64Char(30) -> "e";
264getBase64Char(31) -> "f";
265getBase64Char(32) -> "g";
266getBase64Char(33) -> "h";
267getBase64Char(34) -> "i";
268getBase64Char(35) -> "j";
269getBase64Char(36) -> "k";
270getBase64Char(37) -> "l";
271getBase64Char(38) -> "m";
272getBase64Char(39) -> "n";
273getBase64Char(40) -> "o";
274getBase64Char(41) -> "p";
275getBase64Char(42) -> "q";
276getBase64Char(43) -> "r";
277getBase64Char(44) -> "s";
278getBase64Char(45) -> "t";
279getBase64Char(46) -> "u";
280getBase64Char(47) -> "v";
281getBase64Char(48) -> "w";
282getBase64Char(49) -> "x";
283getBase64Char(50) -> "y";
284getBase64Char(51) -> "z";
285getBase64Char(52) -> "0";
286getBase64Char(53) -> "1";
287getBase64Char(54) -> "2";
288getBase64Char(55) -> "3";
289getBase64Char(56) -> "4";
290getBase64Char(57) -> "5";
291getBase64Char(58) -> "6";
292getBase64Char(59) -> "7";
293getBase64Char(60) -> "8";
294getBase64Char(61) -> "9";
295getBase64Char(62) -> "+";
296getBase64Char(63) -> "/";
297getBase64Char(_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
306native(Config) when is_list(Config) ->
307    ?M(3.14:64/native-float),
308    ?M(333:16/native),
309    ?M(38658345:32/native),
310    case <<1:16/native>> of
311	<<0,1>> -> native_big();
312	<<1,0>> -> native_little()
313    end.
314
315native_big() ->
316    <<37.33:64/native-float>> = <<37.33:64/big-float>>,
317    <<3974:16/native-integer>> = <<3974:16/big-integer>>,
318    {comment,"Big endian"}.
319
320native_little() ->
321    <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>,
322    <<7974:16/native-integer>> = <<7974:16/little-integer>>,
323    {comment,"Little endian"}.
324
325happi(Config) when is_list(Config) ->
326    Bin = <<".123">>,
327    <<"123">> = lex_digits1(Bin, 1, []),
328    <<"123">> = lex_digits2(Bin, 1, []),
329    ok.
330
331lex_digits1(<<$., Rest/binary>>,_Val,_Acc) ->
332    Rest;
333lex_digits1(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
334    lex_digits1(Rest,Val*10+dec(N),Acc);
335lex_digits1(_Other,_Val,_Acc) ->
336    not_ok.
337
338lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
339    lex_digits2(Rest,Val*10+dec(N),Acc);
340lex_digits2(<<$., Rest/binary>>,_Val,_Acc) ->
341    Rest;
342lex_digits2(_Other,_Val,_Acc) ->
343    not_ok.
344
345dec(A) ->
346    A-$0.
347
348size_var(Config) when is_list(Config) ->
349    {<<45>>,<<>>} = split(<<1:16,45>>),
350    {<<45>>,<<46,47>>} = split(<<1:16,45,46,47>>),
351    {<<45,46>>,<<47>>} = split(<<2:16,45,46,47>>),
352
353    {<<45,46,47>>,<<48>>} = split_2(<<16:8,3:16,45,46,47,48>>),
354
355    {<<45,46>>,<<47>>} = split(2, <<2:16,45,46,47>>),
356    {'EXIT',{function_clause,_}} = (catch split(42, <<2:16,45,46,47>>)),
357
358    <<"cdef">> = skip(<<2:8,"abcdef">>),
359
360    ok.
361
362split(<<N:16,B:N/binary,T/binary>>) ->
363    {B,T}.
364
365split(N, <<N:16,B:N/binary,T/binary>>) ->
366    {B,T}.
367
368split_2(<<N0:8,N:N0,B:N/binary,T/binary>>) ->
369    {B,T}.
370
371skip(<<N:8,_:N/binary,T/binary>>) -> T.
372
373wiger(Config) when is_list(Config) ->
374    ok1 = wcheck(<<3>>),
375    ok2 = wcheck(<<1,2,3>>),
376    ok3 = wcheck(<<4>>),
377    {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
378    {error,<<>>} = wcheck(<<>>),
379    ok.
380
381wcheck(<<A>>) when A==3->
382    ok1;
383wcheck(<<_,_:2/binary>>) ->
384    ok2;
385wcheck(<<_>>) ->
386    ok3;
387wcheck(Other) ->
388    {error,Other}.
389
390%% Test that having the match context in x(0) works.
391
392x0_context(Config) when is_list(Config) ->
393    x0_0([], <<3.0:64/float,42:16,123456:32>>).
394
395x0_0(_, Bin) ->
396    <<3.0:64/float,42:16,_/binary>> = Bin,
397    x0_1([], Bin, 64, 16, 2).
398
399x0_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
405x0_2(_, Bin) ->
406    <<_:64,0:7,42:9,_/binary>> = Bin,
407    x0_3([], Bin).
408
409x0_3(_, Bin) ->
410    case Bin of
411	<<_:72,7:8,_/binary>> ->
412	    ct:fail(failed);
413	<<_:64,0:16,_/binary>> ->
414	    ct:fail(failed);
415	<<_:64,42:16,123456:32,_/binary>> ->
416	    ok
417    end.
418
419
420huge_float_field(Config) when is_list(Config) ->
421    Sz = 1 bsl 27,
422    Bin = <<0:Sz>>,
423
424    nomatch = overflow_huge_float_skip_32(Bin),
425    nomatch = overflow_huge_float_32(Bin),
426
427    ok = overflow_huge_float(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
428    ok = overflow_huge_float_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
429    ok.
430
431overflow_huge_float_skip_32(<<_:4294967296/float,0,_/binary>>) -> 1; % 1 bsl 32
432overflow_huge_float_skip_32(<<_:33554432/float-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
433overflow_huge_float_skip_32(<<_:67108864/float-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
434overflow_huge_float_skip_32(<<_:134217728/float-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
435overflow_huge_float_skip_32(<<_:268435456/float-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
436overflow_huge_float_skip_32(<<_:536870912/float-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
437overflow_huge_float_skip_32(<<_:1073741824/float-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
438overflow_huge_float_skip_32(<<_:2147483648/float-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
439overflow_huge_float_skip_32(_) -> nomatch.
440
441overflow_huge_float_32(<<F:4294967296/float,_/binary>>) -> {1,F}; % 1 bsl 32
442overflow_huge_float_32(<<F:33554432/float-unit:128,0,_/binary>>) -> {2,F}; % 1 bsl 25
443overflow_huge_float_32(<<F:67108864/float-unit:128,0,_/binary>>) -> {3,F}; % 1 bsl 26
444overflow_huge_float_32(<<F:134217728/float-unit:128,0,_/binary>>) -> {4,F}; % 1 bsl 27
445overflow_huge_float_32(<<F:268435456/float-unit:128,0,_/binary>>) -> {5,F}; % 1 bsl 28
446overflow_huge_float_32(<<F:536870912/float-unit:128,0,_/binary>>) -> {6,F}; % 1 bsl 29
447overflow_huge_float_32(<<F:1073741824/float-unit:128,0,_/binary>>) -> {7,F}; % 1 bsl 30
448overflow_huge_float_32(<<F:2147483648/float-unit:128,0,_/binary>>) -> {8,F}; % 1 bsl 31
449overflow_huge_float_32(_) -> nomatch.
450
451
452overflow_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;
465overflow_huge_float(_, []) -> ok.
466
467overflow_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;
480overflow_huge_float_unit128(_, []) -> ok.
481
482
483%%
484%% Test that a writable binary can be safely matched.
485%%
486
487writable_binary_matched(Config) when is_list(Config) ->
488    WritableBin = create_writeable_binary(),
489    writable_binary_matched(WritableBin, WritableBin, 500).
490
491writable_binary_matched(<<0>>, _, N) ->
492    if
493	N =:= 0 -> ok;
494	true ->
495	    put(grow_heap, [N|get(grow_heap)]),
496	    WritableBin = create_writeable_binary(),
497	    writable_binary_matched(WritableBin, WritableBin, N-1)
498    end;
499writable_binary_matched(<<B:8,T/binary>>, WritableBin0, N) ->
500    WritableBin = writable_binary(WritableBin0, B),
501    writable_binary_matched(T, WritableBin, N).
502
503writable_binary(WritableBin0, B) when is_binary(WritableBin0) ->
504    %% Heavy append to force the binary to move.
505    WritableBin = <<WritableBin0/binary,0:(size(WritableBin0))/unit:8,B>>,
506    id(<<(id(0)):128/unit:8>>),
507    WritableBin.
508
509create_writeable_binary() ->
510    <<(id(<<>>))/binary,1,2,3,4,5,6,0>>.
511
512otp_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    [do_otp_7198(FillerSize) || FillerSize <- lists:seq(0, 256)],
518    ok.
519
520do_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	    ct:fail(failed)
529    end.
530
531do_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
549otp_7198_scan(<<>>, TokAcc) ->
550    lists:reverse(['$thats_all_folks$' | TokAcc]);
551
552otp_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
557otp_7198_scan(<<D>>, TokAcc) when
558      (D =:= $D) or (D =:= $d) ->
559    otp_7198_scan(<<>>, ['AND' | TokAcc]);
560
561otp_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
566otp_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
577unordered_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
582unordered_bindings(CompressedLength, HashSize, PadLength, T) ->
583    <<Content:CompressedLength/binary,Mac:HashSize/binary,
584      Padding:PadLength/binary,PadLength>> = T,
585    {Content,Mac,Padding}.
586
587
588id(I) -> I.
589