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 + -
显示快捷键?