aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src/text/megaco_text_scanner.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/src/text/megaco_text_scanner.erl')
-rw-r--r--lib/megaco/src/text/megaco_text_scanner.erl869
1 files changed, 869 insertions, 0 deletions
diff --git a/lib/megaco/src/text/megaco_text_scanner.erl b/lib/megaco/src/text/megaco_text_scanner.erl
new file mode 100644
index 0000000000..8559941e5f
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_scanner.erl
@@ -0,0 +1,869 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% 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 online 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.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose : Scanner for text encoded Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module('megaco_text_scanner').
+
+-export([scan/1, skip_sep_chars/2]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include("megaco_text_tokens.hrl").
+
+-define(LOWER1(Char),
+ if
+ (Char >= $A) andalso (Char =< $Z) ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+%% This is used when we _know_ it to be upper case
+-define(LOWER2(Char), Char - ($A - $a)).
+
+scan(Bin) when is_binary(Bin) ->
+ Chars = erlang:binary_to_list(Bin),
+ tokens1(Chars, 1, []);
+scan(Chars) when is_list(Chars) ->
+ tokens1(Chars, 1, []).
+
+%% As long as we dont know the version, we will loop in this function
+tokens1(Chars, Line, Acc) ->
+ case any_chars(Chars, Line, 1) of
+ {token, Token, [], LatestLine} ->
+ %% We got to the end without actually getting a version token.
+ Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc],
+ {error, no_version_found, lists:reverse(Tokens), Line};
+
+ %% -- Version token for version 1 --
+ {token, {'SafeChars',_,"!/1"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 1, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/1"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 1, [Token | Acc]);
+
+
+ %% -- Version token for version 2 --
+ {token, {'SafeChars',_,"!/2"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 2, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/2"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 2, [Token | Acc]);
+
+
+ %% -- Version token for version 3 --
+ {token, {'SafeChars',_,"!/3"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 3, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/3"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 3, [Token | Acc]);
+
+
+ %% -- Version token for version X --
+ {token, {'SafeChars',_,[$!,$/| Vstr]} = Token, Rest, LatestLine} ->
+ case guess_version(Vstr) of
+ {ok, V} ->
+ tokens2(Rest, LatestLine, V, [Token | Acc]);
+ {error, Reason} ->
+ {error, Reason, LatestLine}
+ end;
+
+ {token, {'SafeChars',_,[$m,$e,$g,$a,$c,$o,$/|Vstr]} = Token, Rest, LatestLine} ->
+ case guess_version(Vstr) of
+ {ok, V} ->
+ tokens2(Rest, LatestLine, V, [Token | Acc]);
+ {error, Reason} ->
+ {error, Reason, LatestLine}
+ end;
+
+ %% -- Other tokens --
+ {token, Token, Rest, LatestLine} ->
+ tokens1(Rest, LatestLine, [Token | Acc]);
+
+ {bad_token, Token, _Rest, _LatestLine} ->
+ {error, {bad_token, [Token, Acc]}, Line}
+ end.
+
+tokens2(Chars, Line0, Version, Tokens0) ->
+ case tokens3(Chars, Line0, Tokens0, Version) of
+ {ok, Tokens, Line} ->
+ {ok, Tokens, Version, Line};
+ Error ->
+ Error
+ end.
+
+tokens3(Chars, Line, Acc, Version) ->
+ %% d("tokens2 -> entry with"
+ %% "~n Chars: ~s"
+ %% "~n Line: ~p", [Chars, Line]),
+ case any_chars(Chars, Line, Version) of
+ {token, Token, [], LatestLine} ->
+ %% d("tokens2 -> Token: ~n~p", [Token]),
+ Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc],
+ {ok, lists:reverse(Tokens), Line};
+
+ {token, Token, Rest, LatestLine} ->
+ %% d("tokens2 -> Token: ~n~p", [Token]),
+ tokens3(Rest, LatestLine, [Token | Acc], Version);
+
+ {bad_token, Token, _Rest, _LatestLine} ->
+ {error, {bad_token, [Token, Acc]}, Line}
+ end.
+
+
+guess_version([C]) when (48 =< C) and (C =< 57) ->
+ {ok, C-48};
+guess_version(Str) when is_list(Str) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) ->
+ {ok, I};
+ _ ->
+ {error, {invalid_version, Str}}
+ end.
+
+
+%% Returns {token, Token, Rest, LatestLine}
+%% Returns {bad_token, Token, Rest, LatestLine}
+any_chars([Char | Rest], Line, Version) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ safe_chars(Rest, [Char], [?LOWER2(Char)], Line, Version);
+ safe_char ->
+ safe_chars(Rest, [Char], [Char], Line, Version);
+ rest_char ->
+ case Char of
+ ?SemiColonToken ->
+ comment_chars(Rest, Line);
+ _ ->
+ rest_chars(Rest, [Char], Line)
+ end;
+ double_quote ->
+ quoted_chars(Rest, [], Line);
+ white_space ->
+ sep_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line);
+ bad_char ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'AnyChars', Line, Char}, Rest, Line}
+ end;
+any_chars([] = All, Line, _Version) ->
+ {token, {'SEP', Line, end_of_input}, All, Line}.
+
+comment_chars([Char | Rest], Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ comment_chars(Rest, Line);
+ safe_char ->
+ comment_chars(Rest, Line);
+ rest_char ->
+ comment_chars(Rest, Line);
+ white_space ->
+ comment_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line);
+ _ when Char =:= 22 ->
+ comment_chars(Rest, Line);
+ _ ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'CommentChars', Line, Char}, Rest, Line}
+ end;
+comment_chars([] = All, Line) ->
+ {token, {'SEP', Line}, All, Line}.
+
+sep_chars([Char | Rest] = All, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ {token, {'SEP', Line}, All, Line};
+ safe_char ->
+ {token, {'SEP', Line}, All, Line};
+ rest_char when Char =:= ?SemiColonToken ->
+ comment_chars(Rest, Line);
+ rest_char ->
+ rest_chars(Rest, [Char], Line);
+ white_space ->
+ sep_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line + 1);
+ _ ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'SepChars', Line, Char}, Rest, Line}
+ end;
+sep_chars([] = All, Line) ->
+ {token, {'SEP', Line}, All, Line}.
+
+rest_chars(Rest, [?ColonToken], Line) ->
+ {token, {'COLON', Line}, Rest, Line};
+rest_chars(Rest, [AccChar], Line) ->
+ TokenTag =
+ case AccChar of
+ ?EqualToken -> 'EQUAL';
+ ?NequalToken -> 'NEQUAL';
+ ?LesserToken -> 'LESSER';
+ ?GreaterToken -> 'GREATER';
+ ?LbrktToken -> 'LBRKT';
+ ?RbrktToken -> 'RBRKT';
+ ?LsbrktToken -> 'LSBRKT';
+ ?RsbrktToken -> 'RSBRKT';
+ ?LparToken -> 'LPAR';
+ ?RparToken -> 'RPAR';
+ ?VbarToken -> 'VBAR';
+ ?CommaToken -> 'COMMA'
+ end,
+ {Rest2, Line2} = skip_sep_chars(Rest, Line),
+ {token, {TokenTag, Line}, Rest2, Line2}.
+
+skip_sep_chars([Char | Rest] = All, Line) ->
+ case ?classify_char2(Char) of
+ rest_char when Char =:= ?SemiColonToken ->
+ skip_comment_chars(Rest, Line);
+ white_space ->
+ skip_sep_chars(Rest, Line);
+ end_of_line ->
+ skip_sep_chars(Rest, Line + 1);
+ _ ->
+ {All, Line}
+ end;
+skip_sep_chars([] = All, Line) ->
+ {All, Line}.
+
+skip_comment_chars([Char | Rest] = All, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ skip_comment_chars(Rest, Line);
+ safe_char ->
+ skip_comment_chars(Rest, Line);
+ rest_char ->
+ skip_comment_chars(Rest, Line);
+ double_quote ->
+ skip_comment_chars(Rest, Line);
+ white_space ->
+ skip_comment_chars(Rest, Line);
+ end_of_line ->
+ skip_sep_chars(Rest, Line + 1);
+ _ ->
+ {All, Line}
+ end;
+skip_comment_chars([] = All, Line) ->
+ {All, Line}.
+
+quoted_chars([Char | Rest], Acc, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ safe_char ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ rest_char ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ white_space ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ double_quote ->
+ {token, {'QuotedChars', Line, lists:reverse(Acc)}, Rest, Line};
+ _ ->
+ {bad_token, {'QuotedChars', Line, Char}, Rest, Line}
+ end;
+quoted_chars([] = All, _Acc, Line) ->
+ {bad_token, {'QuotedChars', Line, end_of_input}, All, Line}.
+
+safe_chars([Char | Rest] = All, Acc, LowerAcc, Line, Version) ->
+ %% d("safe_chars -> entry with"
+ %% "~n Char: ~p"
+ %% "~n LowerAcc: ~p", [Char, LowerAcc]),
+ case ?classify_char3(Char) of
+ safe_char_upper ->
+ safe_chars(Rest, [Char | Acc],
+ [?LOWER2(Char) | LowerAcc], Line, Version);
+ safe_char ->
+ safe_chars(Rest, [Char | Acc], [Char | LowerAcc], Line, Version);
+ _ ->
+ LowerSafeChars = lists:reverse(LowerAcc),
+ TokenTag = select_token(LowerSafeChars, Version),
+ SafeChars = lists:reverse(Acc),
+ case TokenTag of
+ 'MtpToken' ->
+ %% 'MtpToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, LowerSafeChars, Line, TokenTag);
+ 'LocalToken' ->
+ %% 'LocalToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, SafeChars, Line, TokenTag);
+ 'RemoteToken' ->
+ %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, SafeChars, Line, TokenTag);
+ 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ %% 'DigitMapToken' 'EQUAL' Name
+ %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' Value 'RBRKT'
+ %% 'DigitMapToken' 'EQUAL' 'LBRKT' Value 'RBRKT'
+ %% 'DigitMapToken' 'LBRKT' Value 'RBRKT'
+ special_chars(All, LowerSafeChars, Line, TokenTag);
+ _ ->
+ {token, {TokenTag, Line, LowerSafeChars}, All, Line}
+ end
+ end;
+safe_chars([] = All, _Acc, LowerAcc, Line, Version) ->
+ LowerSafeChars = lists:reverse(LowerAcc),
+ TokenTag = select_token(LowerSafeChars, Version),
+ %%SafeChars = lists:reverse(Acc),
+ {token, {TokenTag, Line, LowerSafeChars}, All, Line}.
+
+collect_safe_chars([Char | Rest] = All, LowerAcc) ->
+ case ?classify_char3(Char) of
+ safe_char_upper ->
+ collect_safe_chars(Rest, [?LOWER2(Char) | LowerAcc]);
+ safe_char ->
+ collect_safe_chars(Rest, [Char | LowerAcc]);
+ _ ->
+ {All, lists:reverse(LowerAcc)}
+ end;
+collect_safe_chars([] = Rest, LowerAcc) ->
+ {Rest, lists:reverse(LowerAcc)}.
+
+special_chars(All, SafeChars, Line, TokenTag) ->
+ {Rest, Line2} = skip_sep_chars(All, Line),
+ case Rest of
+ [?LbrktToken | Rest2] ->
+ {token, {'OctetString', _, OctetString}, Rest4, Line4} =
+ octet_string(Rest2, Line2),
+ case Rest4 of
+ [?RbrktToken | Rest6] ->
+ Token =
+ case TokenTag of
+ 'MtpToken' ->
+ %% 'MtpToken' 'LBRKT' OctetString 'RBRKT'
+ {'MtpAddressToken', Line, OctetString};
+ 'LocalToken' ->
+ %% 'LocalToken' 'LBRKT' OctetString 'RBRKT'
+ PGs = property_groups(OctetString),
+ {'LocalDescriptorToken', Line, PGs};
+ 'RemoteToken' ->
+ %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT'
+ PGs = property_groups(OctetString),
+ {'RemoteDescriptorToken', Line, PGs};
+ 'DigitMapToken' ->
+ %% 'DigitMapToken' 'LBRKT' OctetString 'RBRKT'
+ DMV = digit_map_value(OctetString),
+ DMD = #'DigitMapDescriptor'{digitMapValue = DMV},
+ {'DigitMapDescriptorToken', Line, DMD}
+ end,
+ {token, Token, Rest6, Line4};
+ _ when TokenTag =:= 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line};
+ _ ->
+ {token, {'SafeChars', Line, SafeChars}, All, Line}
+ end;
+ [?EqualToken | Rest2] when TokenTag =:= 'DigitMapToken' ->
+ {Rest3, Line3} = skip_sep_chars(Rest2, Line2),
+ {Rest4, DigitMapName} = collect_safe_chars(Rest3, []),
+ {Rest6, Line6, DMD} =
+ if
+ DigitMapName =:= [] ->
+ {Rest3, Line3, #'DigitMapDescriptor'{}};
+ true ->
+ {Rest5, Line5} = skip_sep_chars(Rest4, Line3),
+ {Rest5, Line5, #'DigitMapDescriptor'{digitMapName = DigitMapName}}
+ end,
+ case Rest6 of
+ [?LbrktToken | Rest7] ->
+ {token, {'OctetString', _, OctetString}, Rest8, Line8} =
+ octet_string(Rest7, Line6),
+ case Rest8 of
+ [?RbrktToken | Rest10] ->
+ %% 'DigitMapToken' 'EQUAL' 'LBRKT' OctetString 'RBRKT'
+ %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' OctetString 'RBRKT'
+ {Rest11, Line11} = skip_sep_chars(Rest10, Line8),
+ DMV = digit_map_value(OctetString),
+ DMD2 = DMD#'DigitMapDescriptor'{digitMapValue = DMV},
+ {token, {'DigitMapDescriptorToken', Line, DMD2}, Rest11, Line11};
+ _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE ->
+ %% 'DigitMapToken' 'EQUAL' Name
+ {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line}
+ end;
+ _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE ->
+ %% 'DigitMapToken' 'EQUAL' Name
+ {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line}
+ end;
+ _ when TokenTag =:= 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'SafeChars', Line, SafeChars}, All, Line}
+ end.
+
+octet_string(Chars, Line) ->
+ {Chars2, Line2} = skip_sep_chars(Chars, Line),
+ Acc = [],
+ {Rest, RevChars, RestLine} = octet_string(Chars2, Acc, Line2),
+ {RevChars2, _} = skip_sep_chars(RevChars, RestLine),
+ OctetString = lists:reverse(RevChars2),
+ {token, {'OctetString', Line, OctetString}, Rest, RestLine}.
+
+
+octet_string([Char | Rest] = All, Acc, Line) ->
+ if
+ (Char =:= ?CrToken) ->
+ octet_string(Rest, [Char | Acc], Line + 1);
+ (Char =:= ?LfToken) ->
+ octet_string(Rest, [Char | Acc], Line + 1);
+ (Char >= 8#1) andalso (Char =< 8#174) ->
+ octet_string(Rest, [Char | Acc], Line);
+ (Char >= 8#176) andalso (Char =< 8#377) ->
+ octet_string(Rest, [Char | Acc], Line);
+ (Char =:= ?BackslashToken) ->
+ case Rest of
+ [?RbrktToken | _Rest2] ->
+ %% OTP-4357
+ octet_string(Rest,
+ [?RbrktToken, ?BackslashToken | Acc], Line);
+ _ ->
+ octet_string(Rest, [Char | Acc], Line)
+ end;
+ true ->
+ {All, Acc, Line}
+ end;
+octet_string([] = All, Acc, Line) ->
+ {All, Acc, Line}.
+
+
+%% digitMapValue = ["T" COLON Timer COMMA]
+%% ["S" COLON Timer COMMA]
+%% ["L" COLON Timer COMMA]
+%% ["Z" COLON Timer COMMA] digitMap
+digit_map_value(Chars) ->
+ digit_map_value(Chars, #'DigitMapValue'{}).
+
+%% NOTE: The swap of the digitMapBody and the durationTimer is
+%% intentional. The reason is a problem with the flex scanner.
+%% Hopefully this is temporary...
+%% The values are swapped back later by the parser...
+digit_map_value([Char, ?ColonToken | Rest] = All, DMV) ->
+ case ?LOWER1(Char) of
+ $t -> digit_map_timer(All, Rest, #'DigitMapValue'.startTimer, DMV);
+ $s -> digit_map_timer(All, Rest, #'DigitMapValue'.shortTimer, DMV);
+ $l -> digit_map_timer(All, Rest, #'DigitMapValue'.longTimer, DMV);
+% $z -> digit_map_timer(All, Rest, #'DigitMapValue'.durationTimer, DMV);
+% _ -> DMV#'DigitMapValue'{digitMapBody = All}
+ $z -> digit_map_timer(All, Rest, #'DigitMapValue'.digitMapBody, DMV);
+ _ -> DMV#'DigitMapValue'{durationTimer = All}
+ end;
+digit_map_value(Chars, DMV) ->
+ DMV#'DigitMapValue'{durationTimer = Chars}.
+
+digit_map_timer(All, Chars, TimerPos, DMV) ->
+ {Rest, Digits} = collect_safe_chars(Chars, []),
+ {Rest2, _} = skip_sep_chars(Rest, 0),
+ case {Rest2, catch list_to_integer(Digits)} of
+ {[?CommaToken | Rest3], Int} when is_integer(Int) andalso
+ (Int >= 0) andalso
+ (element(TimerPos, DMV) =:= asn1_NOVALUE) ->
+ {Rest4, _} = skip_sep_chars(Rest3, 0),
+ DMV2 = setelement(TimerPos, DMV, Int),
+ digit_map_value(Rest4, DMV2);
+ _ ->
+ DMV#'DigitMapValue'{digitMapBody = All}
+ end.
+
+%% ============================================================================
+%% <prev-parser-stuff>
+%%
+%% This stuff was originally in the parser(s), but was,
+%% for performance reasons, moved to the scanner(s). This
+%% scanner does not make it faster, but the flex scanner
+%% does, which is why the move was made.
+%%
+
+property_groups(OctetString) ->
+ Group = [],
+ Groups = [],
+ property_name(OctetString, Group, Groups).
+
+property_name([Char | Rest] = All, Group, Groups) ->
+ if
+ ?white_space(Char) ->
+ property_name(Rest, Group, Groups);
+ ?end_of_line(Char) ->
+ property_name(Rest, Group, Groups);
+ true ->
+ Name = [],
+ do_property_name(All, Name, Group, Groups)
+ end;
+property_name([] = All, Group, Groups) ->
+ Name = [],
+ do_property_name(All, Name, Group, Groups).
+
+do_property_name([Char | Rest], Name, Group, Groups)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ Groups2 = [lists:reverse(Group) | Groups],
+ Group2 = [],
+ property_value(Rest, Name, Group2, Groups2);
+ true ->
+ %% Use current property group
+ property_value(Rest, Name, Group, Groups)
+ end;
+do_property_name([Char | Rest], Name, Group, Groups) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_property_name(Rest, [Char | Name], Group, Groups);
+ safe_char ->
+ do_property_name(Rest, [Char | Name], Group, Groups);
+ _ ->
+ throw({error, {bad_prop_name, lists:reverse(Name), Char}})
+ end;
+do_property_name([], [], [], Groups) ->
+ lists:reverse(Groups);
+do_property_name([], [], Group, Groups) ->
+ Group2 = lists:reverse(Group),
+ lists:reverse([Group2 | Groups]);
+do_property_name([], Name, Group, Groups) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_property_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_scanner_inline).
+-compile({inline,[{property_value,4}]}).
+-endif.
+property_value(Chars, Name, Group, Groups) ->
+ Value = [],
+ do_property_value(Chars, Name, Value, Group, Groups).
+
+do_property_value([Char | Rest], Name, Value, Group, Groups) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_property_parm(Name, Value),
+ property_name(Rest, [PP | Group], Groups);
+ true ->
+ do_property_value(Rest, Name, [Char | Value], Group, Groups)
+ end;
+do_property_value([], Name, Value, Group, Groups) ->
+ %% Assume end of line
+ PP = make_property_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_scanner_inline).
+-compile({inline,[{make_property_parm,2}]}).
+-endif.
+make_property_parm(Name, Value) ->
+ %% Record name, name field, value field, extraInfo field
+ {'PropertyParm',
+ lists:reverse(Name),
+ [lists:reverse(Value)],
+ asn1_NOVALUE}.
+
+
+%% </prev-parser-stuff>
+%% ===========================================================================
+
+select_token([$o, $- | LowerText], Version) ->
+ select_token(LowerText, Version);
+select_token([$w, $- | LowerText], Version) ->
+ select_token(LowerText, Version);
+select_token(LowerText, Version) ->
+ case LowerText of
+ "add" -> 'AddToken';
+ "a" -> 'AddToken';
+ "andlgc" when (Version >= 3) -> 'AndAUDITSelectToken'; % v3
+ "audit" -> 'AuditToken';
+ "at" -> 'AuditToken';
+ "auditcapability" -> 'AuditCapToken';
+ "ac" -> 'AuditCapToken';
+ "auditvalue" -> 'AuditValueToken';
+ "av" -> 'AuditValueToken';
+ "authentication" -> 'AuthToken';
+ "au" -> 'AuthToken';
+ "both" when (Version >= 3) -> 'BothToken'; % v3
+ "b" when (Version >= 3) -> 'BothToken'; % v3
+ "bothway" -> 'BothwayToken';
+ "bw" -> 'BothwayToken';
+ "brief" -> 'BriefToken';
+ "br" -> 'BriefToken';
+ "buffer" -> 'BufferToken';
+ "bf" -> 'BufferToken';
+ "context" -> 'CtxToken';
+ "c" -> 'CtxToken';
+ "contextattr" when (Version >= 3) -> 'ContextAttrToken'; % v3
+ "ct" when (Version >= 3) -> 'ContextAttrToken'; % v3
+ "contextlist" when (Version >= 3) -> 'ContextListToken'; % v3
+ "clt" when (Version >= 3) -> 'ContextListToken'; % v3
+ "contextaudit" -> 'ContextAuditToken';
+ "ca" -> 'ContextAuditToken';
+ "digitmap" -> 'DigitMapToken';
+ "dm" -> 'DigitMapToken';
+ "spadirection" when (Version >= 3) -> 'DirectionToken'; % v3
+ "direction" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b)
+ "spadi" when (Version >= 3) -> 'DirectionToken'; % v3
+ "di" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b)
+ "discard" -> 'DiscardToken';
+ "ds" -> 'DiscardToken';
+ "disconnected" -> 'DisconnectedToken';
+ "dc" -> 'DisconnectedToken';
+ "delay" -> 'DelayToken';
+ "dl" -> 'DelayToken';
+ "delete" -> 'DeleteToken';
+ "de" -> 'DeleteToken';
+ "duration" -> 'DurationToken';
+ "dr" -> 'DurationToken';
+ "embed" -> 'EmbedToken';
+ "em" -> 'EmbedToken';
+ "emergency" -> 'EmergencyToken';
+ "eg" -> 'EmergencyToken';
+ "emergencyofftoken" -> 'EmergencyOffToken';
+ "emergencyoff" when (Version >= 3) -> 'EmergencyOffToken'; % v3 (as of prev3c)
+ "ego" -> 'EmergencyOffToken';
+ "emergencyvalue" when (Version >= 3) -> 'EmergencyValueToken'; % v3
+ "egv" when (Version >= 3) -> 'EmergencyValueToken'; % v3
+ "error" -> 'ErrorToken';
+ "er" -> 'ErrorToken';
+ "eventbuffer" -> 'EventBufferToken';
+ "eb" -> 'EventBufferToken';
+ "events" -> 'EventsToken';
+ "e" -> 'EventsToken';
+ "external" when (Version >= 3) -> 'ExternalToken'; % v3
+ "ex" when (Version >= 3) -> 'ExternalToken'; % v3
+ "failover" -> 'FailoverToken';
+ "fl" -> 'FailoverToken';
+ "forced" -> 'ForcedToken';
+ "fo" -> 'ForcedToken';
+ "graceful" -> 'GracefulToken';
+ "gr" -> 'GracefulToken';
+ "h221" -> 'H221Token';
+ "h223" -> 'H223Token';
+ "h226" -> 'H226Token';
+ "handoff" -> 'HandOffToken';
+ "ho" -> 'HandOffToken';
+ "iepscall" when (Version >= 3) -> 'IEPSToken'; % v3
+ "ieps" when (Version >= 3) -> 'IEPSToken'; % v3
+ "inactive" -> 'InactiveToken';
+ "in" -> 'InactiveToken';
+ "internal" when (Version >= 3) -> 'InternalToken'; % v3
+ "it" when (Version >= 3) -> 'InternalToken'; % v3
+ "immackrequired" -> 'ImmAckRequiredToken';
+ "ia" -> 'ImmAckRequiredToken';
+ "inservice" -> 'InSvcToken';
+ "intersignal" when (Version >= 3) -> 'IntsigDelayToken'; % v3
+ "spais" when (Version >= 3) -> 'IntsigDelayToken'; % v3
+ "intbyevent" -> 'InterruptByEventToken';
+ "ibe" -> 'InterruptByEventToken';
+ "intbysigdescr" -> 'InterruptByNewSignalsDescrToken';
+ "ibs" -> 'InterruptByNewSignalsDescrToken';
+ "iv" -> 'InSvcToken';
+ "isolate" -> 'IsolateToken';
+ "is" -> 'IsolateToken';
+ "iterationtoken" when (Version >= 3) -> 'IterationToken'; % v3
+ "ir" when (Version >= 3) -> 'IterationToken'; % v3
+ "keepactive" -> 'KeepActiveToken';
+ "ka" -> 'KeepActiveToken';
+ "local" -> 'LocalToken';
+ "l" -> 'LocalToken';
+ "localcontrol" -> 'LocalControlToken';
+ "lockstep" -> 'LockStepToken';
+ "sp" -> 'LockStepToken';
+ "o" -> 'LocalControlToken';
+ "loopback" -> 'LoopbackToken';
+ "lb" -> 'LoopbackToken';
+ "media" -> 'MediaToken';
+ "m" -> 'MediaToken';
+ %% "megaco" -> 'MegacopToken';
+ %% "!" -> 'megacoptoken';
+ "segment" when (Version >= 3) -> 'MessageSegmentToken'; % v3
+ "sm" when (Version >= 3) -> 'MessageSegmentToken'; % v3
+ "method" -> 'MethodToken';
+ "mt" -> 'MethodToken';
+ "mtp" -> 'MtpToken';
+ "mgcidtotry" -> 'MgcIdToken';
+ "mg" -> 'MgcIdToken';
+ "mode" -> 'ModeToken';
+ "mo" -> 'ModeToken';
+ "modify" -> 'ModifyToken';
+ "mf" -> 'ModifyToken';
+ "modem" -> 'ModemToken';
+ "md" -> 'ModemToken';
+ "move" -> 'MoveToken';
+ "mv" -> 'MoveToken';
+ "mux" -> 'MuxToken';
+ "mx" -> 'MuxToken';
+ "nevernotify" when (Version >= 3) -> 'NeverNotifyToken'; % v3
+ "nbnn" when (Version >= 3) -> 'NeverNotifyToken'; % v3
+ "notify" -> 'NotifyToken';
+ "n" -> 'NotifyToken';
+ "notifycompletion" -> 'NotifyCompletionToken';
+ "nc" -> 'NotifyCompletionToken';
+ "immediatenotify" when (Version >= 3) -> 'NotifyImmediateToken'; % v3
+ "nbin" when (Version >= 3) -> 'NotifyImmediateToken'; % v3
+ "regulatednotify" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3
+ "nbrn" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3
+ "nx64kservice" when (Version >= 2) -> 'Nx64kToken'; % v2
+ "n64" when (Version >= 2) -> 'Nx64kToken'; % v2
+ "observedevents" -> 'ObservedEventsToken';
+ "oe" -> 'ObservedEventsToken';
+ "oneway" -> 'OnewayToken';
+ "ow" -> 'OnewayToken';
+ "onewayboth" when (Version >= 3) -> 'OnewayBothToken'; % v3
+ "owb" when (Version >= 3) -> 'OnewayBothToken'; % v3
+ "onewayexternal" when (Version >= 3) -> 'OnewayExternalToken'; % v3
+ "owe" when (Version >= 3) -> 'OnewayExternalToken'; % v3
+ "off" -> 'OffToken';
+ "on" -> 'OnToken';
+ "onoff" -> 'OnOffToken';
+ "oo" -> 'OnOffToken';
+ "orlgc" when (Version >= 3) -> 'OrAUDITselectToken'; % v3
+ "otherreason" -> 'OtherReasonToken';
+ "or" -> 'OtherReasonToken';
+ "outofservice" -> 'OutOfSvcToken';
+ "os" -> 'OutOfSvcToken';
+ "packages" -> 'PackagesToken';
+ "pg" -> 'PackagesToken';
+ "pending" -> 'PendingToken';
+ "pn" -> 'PendingToken';
+ "priority" -> 'PriorityToken';
+ "pr" -> 'PriorityToken';
+ "profile" -> 'ProfileToken';
+ "pf" -> 'ProfileToken';
+ "reason" -> 'ReasonToken';
+ "re" -> 'ReasonToken';
+ "receiveonly" -> 'RecvonlyToken';
+ "requestid" when (Version >= 3) -> 'RequestIDToken'; % v3
+ "rq" when (Version >= 3) -> 'RequestIDToken'; % v3
+ "rc" -> 'RecvonlyToken';
+ "reply" -> 'ReplyToken';
+ "p" -> 'ReplyToken';
+ "reseteventsdescriptor" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3
+ "rse" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3
+ "transactionresponseack"-> 'ResponseAckToken';
+ "k" -> 'ResponseAckToken';
+ "restart" -> 'RestartToken';
+ "rs" -> 'RestartToken';
+ "remote" -> 'RemoteToken';
+ "r" -> 'RemoteToken';
+ "sparequestid" -> 'RequestIDToken';
+ "sparq" -> 'RequestIDToken';
+ "reservedgroup" -> 'ReservedGroupToken';
+ "rg" -> 'ReservedGroupToken';
+ "reservedvalue" -> 'ReservedValueToken';
+ "rv" -> 'ReservedValueToken';
+ "end" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3
+ "&" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3
+ "sendonly" -> 'SendonlyToken';
+ "so" -> 'SendonlyToken';
+ "sendreceive" -> 'SendrecvToken';
+ "sr" -> 'SendrecvToken';
+ "services" -> 'ServicesToken';
+ "sv" -> 'ServicesToken';
+ "servicestates" -> 'ServiceStatesToken';
+ "si" -> 'ServiceStatesToken';
+ "servicechange" -> 'ServiceChangeToken';
+ "sc" -> 'ServiceChangeToken';
+ "servicechangeaddress" -> 'ServiceChangeAddressToken';
+ "ad" -> 'ServiceChangeAddressToken';
+ "servicechangeinc" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3
+ "sic" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3
+ "signallist" -> 'SignalListToken';
+ "sl" -> 'SignalListToken';
+ "signals" -> 'SignalsToken';
+ "sg" -> 'SignalsToken';
+ "signaltype" -> 'SignalTypeToken';
+ "sy" -> 'SignalTypeToken';
+ "statistics" -> 'StatsToken';
+ "sa" -> 'StatsToken';
+ "stream" -> 'StreamToken';
+ "st" -> 'StreamToken';
+ "subtract" -> 'SubtractToken';
+ "s" -> 'SubtractToken';
+ "synchisdn" -> 'SynchISDNToken';
+ "sn" -> 'SynchISDNToken';
+ "terminationstate" -> 'TerminationStateToken';
+ "ts" -> 'TerminationStateToken';
+ "test" -> 'TestToken';
+ "te" -> 'TestToken';
+ "timeout" -> 'TimeOutToken';
+ "to" -> 'TimeOutToken';
+ "topology" -> 'TopologyToken';
+ "tp" -> 'TopologyToken';
+ "transaction" -> 'TransToken';
+ "t" -> 'TransToken';
+ "v18" -> 'V18Token';
+ "v22" -> 'V22Token';
+ "v22b" -> 'V22bisToken';
+ "v32" -> 'V32Token';
+ "v32b" -> 'V32bisToken';
+ "v34" -> 'V34Token';
+ "v76" -> 'V76Token';
+ "v90" -> 'V90Token';
+ "v91" -> 'V91Token';
+ "version" -> 'VersionToken';
+ "v" -> 'VersionToken';
+ [_,_,_,_,_,_,_,_,$t,_,_,_,_,_,_,_,_] -> % Could be a time-stamp
+ [D1,D2,D3,D4,D5,D6,D7,D8,_,T1,T2,T3,T4,T5,T6,T7,T8] = LowerText,
+ select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8,
+ T1,T2,T3,T4,T5,T6,T7,T8);
+ _ -> 'SafeChars'
+ end.
+
+select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8,
+ T1,T2,T3,T4,T5,T6,T7,T8)
+ when ($0 =< D1) andalso (D1 =< $9) andalso
+ ($0 =< D2) andalso (D2 =< $9) andalso
+ ($0 =< D3) andalso (D3 =< $9) andalso
+ ($0 =< D4) andalso (D4 =< $9) andalso
+ ($0 =< D5) andalso (D5 =< $9) andalso
+ ($0 =< D6) andalso (D6 =< $9) andalso
+ ($0 =< D7) andalso (D7 =< $9) andalso
+ ($0 =< D8) andalso (D8 =< $9) andalso
+ ($0 =< T1) andalso (T1 =< $9) andalso
+ ($0 =< T2) andalso (T2 =< $9) andalso
+ ($0 =< T3) andalso (T3 =< $9) andalso
+ ($0 =< T4) andalso (T4 =< $9) andalso
+ ($0 =< T5) andalso (T5 =< $9) andalso
+ ($0 =< T6) andalso (T6 =< $9) andalso
+ ($0 =< T7) andalso (T7 =< $9) andalso
+ ($0 =< T8) andalso (T8 =< $9) ->
+ 'TimeStampToken';
+select_TimeStampToken(_D1,_D2,_D3,_D4,_D5,_D6,_D7,_D8,
+ _T1,_T2,_T3,_T4,_T5,_T6,_T7,_T8) ->
+ 'SafeChars'.
+
+
+%% d(F) ->
+%% d(F, []).
+
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.