%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2000-2009. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions 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. %% ============================================================================ %% %% %% 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}. %% %% =========================================================================== 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.