megaco_digit_map.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 773 行 · 第 1/2 页

ERL
773
字号
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%%%----------------------------------------------------------------------%% Purpose: Parse and evaluate digit maps%%----------------------------------------------------------------------%%%% digitMap           =  digitString%%                    /   LWSP "(" LWSP digitStringList LWSP ")" LWSP %% digitStringList    = digitString *( LWSP "|" LWSP digitString ) %% digitString        = 1*(digitStringElement) %% digitStringElement = digitPosition [DOT] %% digitPosition      = digitMapLetter / digitMapRange%% digitMapRange      = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)%% digitLetter        = *((DIGIT "-" DIGIT ) / digitMapLetter)%% digitMapLetter     = DIGIT   ; Basic event symbols %%                    / %x41-4B ; a-k%%                    / %x61-6B ; A-K %%                    / "T"     ; Start inter-event timers%%                    / "S"     ; Short inter-event timers%%                    / "L"     ; Long  inter-event timers, e.g. 16 sec%%                    / "Z"     ; Long duration modifier%% DIGIT              = %x30-39 ; 0-9 %%                   %%----------------------------------------------------------------------%% Example of a digit map:%% %% (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.) %% %% DM = "(0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)".%% DM = "xxx | xxL3 | xxS4".%% megaco:parse_digit_map(DM).%% megaco:test_digit_event(DM, "1234").%% megaco:test_digit_event(DM, "12ssss3").%% megaco:test_digit_event(DM, "12ssss4").%% megaco:test_digit_event(DM, "12ssss5").%% %%-----------------------------------------------------------------------module(megaco_digit_map).-export([parse/1, eval/1, eval/2, report/2, test/2]). % Public-export([test_eval/2]).                               % Internal-include_lib("megaco/src/app/megaco_internal.hrl").-include("megaco_message_internal.hrl").-include_lib("megaco/src/text/megaco_text_tokens.hrl").-record(state_transition, {mode, next, cont}).-record(timers, {mode       = state_dependent,		 start 	    = 0,		 short 	    = timer_to_millis(3), 		 long  	    = timer_to_millis(9),		 duration   = 100,      % (not used) 100 ms <-> 9.9 sec		 unexpected = reject}). % ignore | reject%%----------------------------------------------------------------------%% Parses a digit map body, represented as a list of chars,%% into a list of state transitions.%% %% Returns {ok, StateTransitionList} | {error, Reason}%% %%----------------------------------------------------------------------parse(DigitMapBody) when list(DigitMapBody) ->    ?d("parse -> entry with"       "~n   DigitMapBody: ~p", [DigitMapBody]),    case parse_digit_map(DigitMapBody) of	{ok, STL} ->	    {ok, duration_cleanup(STL, [])};	{error, Reason} ->	    {error, Reason}    end;parse(_DigitMapBody) ->    {error, not_a_digit_map_body}.duration_cleanup([], Acc) ->    Acc;duration_cleanup([STL|T], Acc) ->    #state_transition{cont = Events} = STL,    Events2 = duration_events_cleanup(Events, []),    duration_cleanup(T, [STL#state_transition{cont = Events2}|Acc]).duration_events_cleanup([], Acc) ->    lists:reverse(Acc);duration_events_cleanup([duration_event, Event|Events], Acc) ->    duration_events_cleanup(Events, [{duration_event, Event}|Acc]);duration_events_cleanup([Event|Events], Acc) ->    duration_events_cleanup(Events, [Event|Acc]).    parse_digit_map(Chars) ->    parse_digit_map(Chars, 1, [], []).parse_digit_map(Chars, Line, DS, STL) ->    ?d("parse_digit_map -> entry with"       "~n   Chars: ~p"       "~n   DS:    ~p", [Chars, DS]),    case megaco_text_scanner:skip_sep_chars(Chars, Line) of	{[], _Line2} when DS /= [] ->	    case parse_digit_string(DS) of		{ok, DS2} ->		    ST = #state_transition{mode = state_dependent,					   next = start,					   cont = DS2},		    STL2 = lists:reverse([ST | STL]),		    {ok, STL2};		{error, Reason} ->		    {error, Reason}	    end;	{[Char | Chars2], Line2} ->	    case Char of		$( when DS == [], STL == [] ->		    parse_digit_map(Chars2, Line2, DS, STL);		$) when DS /= [] ->		    case megaco_text_scanner:skip_sep_chars(Chars2, Line2) of			{[], _Line3} ->			    case parse_digit_string(DS) of				{ok, DS2} ->				    ST = #state_transition{mode = state_dependent,							   next = start,							   cont = DS2},				    STL2 = lists:reverse([ST | STL]),				    {ok, STL2};				{error, Reason} ->				    {error, Reason}			    end;			{Chars3, Line3} ->			    Trash =  lists:reverse(Chars3),			    {error, {round_bracket_mismatch, Trash, Line3}}		    end;		$| when DS /= [] ->		    case parse_digit_string(DS) of			{ok, DS2} ->			    ST = #state_transition{mode = state_dependent,						   next = start,						   cont = DS2},			    parse_digit_map(Chars2, Line2, [], [ST | STL]);			{error, Reason} ->			    {error, Reason}		    end;		_ when Char /= $(, Char /= $|, Char /= $) ->		    parse_digit_map(Chars2, Line2, [Char | DS], STL);		_ ->		    {error, {round_bracket_mismatch, Line2}}	    end;	{[], Line2} ->	    {error, {digit_string_expected, Line2}}    end.parse_digit_string(Chars) ->    ?d("parse_digit_string -> entry with"       "~n   Chars: ~p", [Chars]),    parse_digit_string(Chars, []).parse_digit_string([Char | Chars], DS) ->    ?d("parse_digit_string -> entry with"       "~n   Char:  ~p"       "~n   Chars: ~p"       "~n   DS:    ~p", [[Char], Chars, DS]),    case Char of	$] ->	    parse_digit_letter(Chars, [], DS);	$[ ->	    {error, square_bracket_mismatch};	$x ->	    parse_digit_string(Chars, [{range, $0, $9} | DS]);	$. ->	    parse_digit_string(Chars, [zero_or_more | DS]);	I when I >= $0, I =< $9 ->	    parse_digit_string(Chars, [{single, I} | DS]);	A when A >= $a, A =< $k ->	    parse_digit_string(Chars, [{single, A} | DS]);	A when A >= $A, A =< $K ->	    parse_digit_string(Chars, [{single, A} | DS]);	$S ->	    parse_digit_string(Chars, [use_short_timer | DS]);	$s ->	    parse_digit_string(Chars, [use_short_timer | DS]);	$L ->	    parse_digit_string(Chars, [use_long_timer | DS]);	$l ->	    parse_digit_string(Chars, [use_long_timer | DS]);        $Z when length(Chars) > 0 ->            parse_digit_string(Chars, [duration_event | DS]);        $z when length(Chars) > 0 ->            parse_digit_string(Chars, [duration_event | DS]);        $Z ->            {error, duration_not_allowed_as_last_char};        $z ->            {error, duration_not_allowed_as_last_char};	BadChar ->	    {error, {illegal_char_in_digit_string, BadChar}}    end;parse_digit_string([], DM) ->    ?d("parse_digit_string -> entry when done with"       "~n   DM: ~p", [DM]),    {ok, DM}.parse_digit_letter([Char | Chars], DL, DS) ->    ?d("parse_digit_letter -> entry with"       "~n   Char:  ~p"       "~n   Chars: ~p"       "~n   DL:    ~p"       "~n   DS:    ~p", [[Char], Chars, DL, DS]),    case Char of	$[ ->	    parse_digit_string(Chars, [DL | DS]);	$] ->	    {error, square_bracket_mismatch};	To when To >= $0, To =< $9 ->	    case Chars of		[$-, From | Chars2] when From >= $0, From =< $9 ->		    parse_digit_letter(Chars2, [{range, From, To} | DL], DS);		_ ->		    parse_digit_letter(Chars, [{single, To} | DL], DS)	    end;	A when A >= $a, A =< $k ->	    parse_digit_letter(Chars, [{single, A} | DL], DS);	A when A >= $A, A =< $K ->	    parse_digit_letter(Chars, [{single, A} | DL], DS);	$S ->	    parse_digit_letter(Chars, [use_short_timer | DL], DS);	$s ->	    parse_digit_letter(Chars, [use_short_timer | DL], DS);	$L ->	    parse_digit_letter(Chars, [use_long_timer | DL], DS);	$l ->	    parse_digit_letter(Chars, [use_long_timer | DL], DS);	$Z ->	    parse_digit_letter(Chars, [duration_event | DL], DS);	$z ->	    parse_digit_letter(Chars, [duration_event | DL], DS);	BadChar ->	    {error, {illegal_char_between_square_brackets, BadChar}}    end;parse_digit_letter([], _DL, _DS) ->    {error, square_bracket_mismatch}.%%----------------------------------------------------------------------%% Collect digit map letters according to digit map%% Returns {ok, Letters} | {error, Reason}%%----------------------------------------------------------------------     eval(DMV) when record(DMV, 'DigitMapValue') ->    case parse(DMV#'DigitMapValue'.digitMapBody) of	{ok, DigitMapBody} ->	    eval(DigitMapBody, DMV);	{error, Reason} ->	    {error, Reason}    end;eval(STL) when list(STL) ->     eval(STL, #timers{}).	eval(STL, #'DigitMapValue'{startTimer    = Start,			   shortTimer    = Short,			   longTimer     = Long,			   durationTimer = Duration}) ->    Timers = #timers{start    = timer_to_millis(Start),		     short    = timer_to_millis(Short),		     long     = timer_to_millis(Long),		     duration = duration_to_millis(Duration)},    eval(STL, Timers);eval(STL, {ignore, #'DigitMapValue'{startTimer    = Start,				    shortTimer    = Short,				    longTimer     = Long,				    durationTimer = Duration}}) ->    Timers = #timers{start      = timer_to_millis(Start),		     short      = timer_to_millis(Short),		     long       = timer_to_millis(Long),		     duration   = duration_to_millis(Duration),		     unexpected = ignore},    eval(STL, Timers);eval(STL, {reject, #'DigitMapValue'{startTimer    = Start,				    shortTimer    = Short,				    longTimer     = Long,				    durationTimer = Duration}}) ->    Timers = #timers{start      = timer_to_millis(Start),		     short      = timer_to_millis(Short),		     long       = timer_to_millis(Long),		     duration   = duration_to_millis(Duration),		     unexpected = reject},    eval(STL, Timers);eval(STL, Timers) when list(STL),		       record(hd(STL), state_transition),		       record(Timers, timers) ->    ?d("eval -> entry with"       "~n   STL:    ~p"       "~n   Timers: ~p", [STL, Timers]),    case collect(start, mandatory_event, Timers, lists:reverse(STL), []) of	{error, _} = Error ->	    ?d("eval -> error:"	       "~n   Error: ~p", [Error]),	    Error;	OK ->	    ?d("eval -> ok:"	       "~n   OK: ~p", [OK]),	    OK    end;eval(DigitMapBody, ignore) ->    eval(DigitMapBody, #timers{unexpected = ignore});eval(DigitMapBody, reject) ->    eval(DigitMapBody, #timers{unexpected = reject});eval(DigitMapBody, Timers) ->    case parse(DigitMapBody) of	{ok, STL} ->	    eval(STL, Timers);	{error, Reason} ->	    {error, Reason}    end.%% full | unambiguouscollect(Event, State, Timers, STL, Letters) ->    ?d("collect -> entry with"       "~n   Event:  ~p"       "~n   State:  ~p"       "~n   Timers: ~p"       "~n   STL:    ~p", [Event, State, Timers, STL]),    case handle_event(Event, State, Timers, STL, Letters) of	{completed_full, _Timers2, _STL2, Letters2} ->	    completed(full, Letters2);	{completed, _Timers2, _STL2, Letters2} ->	    completed(unambiguous, Letters2);	{State2, Timers2, STL2, Letters2} ->	    ?d("collect -> "	       "~n   State2:   ~p"	       "~n   Timers2:  ~p"	       "~n   Letters2: ~p", [State2, Timers2, Letters2]),	    MaxWait = choose_timer(State2, Event, Timers2),	    ?d("collect -> Timer choosen: "	       "~n   MaxWait: ~p", [MaxWait]),	    receive		{?MODULE, _FromPid, Event2} ->		    ?d("collect -> Got event: "		       "~n   ~p", [Event2]),		    collect(Event2, State2, Timers2, STL2, Letters2)	    after MaxWait ->		    ?d("collect -> timeout after ~w", [MaxWait]),		    collect(inter_event_timeout, 			    State2, Timers2, STL2, Letters2)	    end;	{error, Reason} ->	    ?d("collect -> error: "	       "~n   Reason: ~p", [Reason]),	    {error, Reason}    end.choose_timer(_State, start, #timers{start = 0}) ->    ?d("choose_timer(start) -> entry", []),    infinity;choose_timer(_State, start, #timers{start = T}) ->    ?d("choose_timer(start) -> entry with"       "~n   T: ~p", [T]),    T;choose_timer(State, _Event, T) ->    ?d("choose_timer(~p) -> entry with"

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?