diff options
Diffstat (limited to 'lib/megaco/src/text/megaco_text_scanner.erl')
-rw-r--r-- | lib/megaco/src/text/megaco_text_scanner.erl | 869 |
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. |