aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src/text/megaco_text_mini_parser.hrl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/src/text/megaco_text_mini_parser.hrl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco/src/text/megaco_text_mini_parser.hrl')
-rw-r--r--lib/megaco/src/text/megaco_text_mini_parser.hrl1246
1 files changed, 1246 insertions, 0 deletions
diff --git a/lib/megaco/src/text/megaco_text_mini_parser.hrl b/lib/megaco/src/text/megaco_text_mini_parser.hrl
new file mode 100644
index 0000000000..bb6ee43247
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_mini_parser.hrl
@@ -0,0 +1,1246 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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 : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-include("megaco_text_tokens.hrl").
+
+-define(d(F,A), io:format("DBG:"++F++"~n",A)).
+
+make_safe_token({_TokenTag, Line, Text}) ->
+ {safeToken, Line, Text}.
+
+% ensure_value({safeToken, _Line, Text}) ->
+% ensure_value(Text);
+% ensure_value({'QuotedChars', _Line, Text}) ->
+% ensure_value(Text);
+% ensure_value(Text) when list(Text) ->
+% Text. %% BUGBUG: ensure length
+
+% %% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+% ensure_NAME({_TokenTag, _Line, Text}) ->
+% Text. %% BUGBUG: ensure length and chars
+
+% ensure_requestID({safeToken, _Line, "*"}) ->
+% ?megaco_all_request_id;
+% ensure_requestID(RequestId) ->
+% ensure_uint32(RequestId).
+
+% ensure_streamID(StreamId) ->
+% ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% ContextID = (UINT32 / "*" / "-" / "$")
+% ensure_contextID({_TokenTag, _Line, Text}) ->
+% case Text of
+% "*" -> ?megaco_all_context_id;
+% "-" -> ?megaco_null_context_id;
+% "\$" -> ?megaco_choose_context_id;
+% Int -> ensure_uint32(Int)
+% end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr({TokenTag, Line, Addr}) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when (length(Hex4) =< 4) andalso (length(Hex4) > 0) ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+ensure_domainName({_TokenTag, _Line, Name}, Port) ->
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+% ensure_extensionParameter({_TokenTag, Line, Text}) ->
+% case Text of
+% [X, S | _Chars] ->
+% if
+% X /= $X, X /= $x,
+% S /= $+, S /= $- ->
+% return_error(Line, {bad_extension_parameter, Text});
+% true ->
+% {extension_parameter, Text}
+% end;
+% _ ->
+% return_error(Line, {bad_extension_parameter, Text})
+% end.
+
+ensure_message(MegacopToken, MID) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version} =
+ ensure_profile(MegacopToken),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version, mId = MID};
+ [$!] ->
+ #'Message'{version = Version, mId = MID}
+ end.
+
+
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+% case Text of
+% "v32b" -> v32bis;
+% "v22b" -> v22bis;
+% "v18" -> v18;
+% "v22" -> v22;
+% "v32" -> v32;
+% "v34" -> v34;
+% "v90" -> v90;
+% "v91" -> v91;
+% "synchisdn" -> synchISDN;
+% "sn" -> synchISDN;
+% [$x | _] -> ensure_extensionParameter(Token)
+% end.
+
+%% An mtp address is five octets long
+ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+% ensure_muxType({_TokenTag, _Line, Text} = Token) ->
+% case Text of
+% "h221" -> h221;
+% "h223" -> h223;
+% "h226" -> h226;
+% "v76" -> v76;
+% "nx64k" -> nx64k; % v2
+% [$x | _] -> ensure_extensionParameter(Token)
+% end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+% ensure_packagesItem({TokenTag, Line, Text}) ->
+% case string:tokens(Text, [$-]) of
+% [Name, Version] ->
+% #'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}),
+% packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
+% _ ->
+% return_error(Line, {bad_PackagesItem, Text})
+% end.
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+% ensure_pkgdName({TokenTag, Line, Text}) ->
+% case string:tokens(Text, [$/]) of
+% [Name, Item] ->
+% ensure_name_or_star({TokenTag, Line, Name}),
+% ensure_name_or_star({TokenTag, Line, Item}),
+% Text;
+% _ ->
+% return_error(Line, {bad_pkgdName, Text})
+% end.
+
+% ensure_name_or_star({_, _, Name}) when Name == "*" ->
+% Name;
+% ensure_name_or_star(Name) ->
+% ensure_NAME(Name).
+
+
+
+%% v2 - start
+
+% merge_indAudMediaDescriptor({termStateDescr, Val}) ->
+% #'IndAudMediaDescriptor'{termStateDescr = Val};
+% merge_indAudMediaDescriptor({streamParm, Val}) ->
+% #'IndAudMediaDescriptor'{streams = {oneStream, Val}};
+% merge_indAudMediaDescriptor({streamDescr, Val}) ->
+% #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}.
+
+% merge_indAudLocalControlDescriptor(Parms) ->
+% do_merge_indAudLocalControlDescriptor(Parms,
+% #'IndAudLocalControlDescriptor'{}).
+
+% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
+% case Parm of
+% modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+% PropParms = [#'IndAudPropertyParm'{name = Val}],
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% {pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
+% PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
+% PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2)
+% end;
+% do_merge_indAudLocalControlDescriptor([], Desc) ->
+% case Desc#'IndAudLocalControlDescriptor'.propertyParms of
+% [_ | _] = PropParms -> % List has more then one element
+% PropParms2= lists:reverse(PropParms),
+% Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+% _ ->
+% Desc
+% end.
+
+% ensure_indAudLocalParm(Token) ->
+% case Token of
+% {safeToken, _Line, "mode"} -> modeToken;
+% {safeToken, _Line, "mo"} -> modeToken;
+% {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
+% {safeToken, _Line, "rg"} -> reservedGroupToken;
+% {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
+% {safeToken, _Line, "rv"} -> reservedValueToken;
+% PkgdName -> {pkgdName,
+% ensure_pkgdName(PkgdName)}
+% end.
+
+% merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
+% PropParm = #'IndAudPropertyParm'{name = Val},
+% #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+% merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+% #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+% merge_indAudTerminationStateDescriptor(bufferToken) ->
+% #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+% merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+% IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+% do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+% IAEBD;
+% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+% IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+% IAEBD) ->
+% %% BUGBUG BUGBUG BUGBUG
+% %% This is an ugly hack to allow the eventParamName which only
+% %% exists in the text encoding...
+% IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
+% ensure_indAudSignal(SIG).
+
+% ensure_indAudSignal(#'Signal'{signalName = SignalName,
+% streamID = asn1_NOVALUE,
+% sigType = asn1_NOVALUE,
+% duration = asn1_NOVALUE,
+% notifyCompletion = asn1_NOVALUE,
+% keepActive = asn1_NOVALUE,
+% sigParList = []}) ->
+% #'IndAudSignal'{signalName = SignalName}.
+
+
+% ensure_IADMD({_TokenTag, _Line,
+% #'DigitMapDescriptor'{digitMapName = Name,
+% digitMapValue = asn1_NOVALUE}}) ->
+% #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
+% packageVersion = V}) ->
+% #'IndAudPackagesDescriptor'{packageName = N,
+% packageVersion = V}.
+
+
+% ensure_indAudTerminationStateParm(Token) ->
+% case Token of
+% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+% {safeToken, _Line, "si"} -> serviceStatesToken;
+% {safeToken, _Line, "buffer"} -> bufferToken;
+% {safeToken, _Line, "bf"} -> bufferToken;
+% PkgdName -> {pkgdName,
+% ensure_pkgdName(PkgdName)}
+% end.
+
+
+% %% Types modified by v2:
+
+% merge_auditDescriptor([]) ->
+% #'AuditDescriptor'{};
+% merge_auditDescriptor(Tokens) when list(Tokens) ->
+% case lists:keysearch(terminationAudit, 1, Tokens) of
+% {value, {terminationAudit, TA}} ->
+% case lists:keydelete(terminationAudit, 1, Tokens) of
+% [] ->
+% #'AuditDescriptor'{auditPropertyToken = TA};
+% AuditTokens ->
+% #'AuditDescriptor'{auditToken = AuditTokens,
+% auditPropertyToken = TA}
+% end;
+% false ->
+% #'AuditDescriptor'{auditToken = Tokens}
+% end;
+% merge_auditDescriptor(_) ->
+% #'AuditDescriptor'{}.
+
+
+% %% v2 - end
+
+
+
+% merge_ServiceChangeParm(Parms) ->
+% Required = [serviceChangeReason, serviceChangeMethod],
+% merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+% merge_ServiceChangeParm([], SCP, []) ->
+% SCP;
+
+% merge_ServiceChangeParm([], _SCP, Required) ->
+% exit({missing_required_serviceChangeParm, Required});
+
+% merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
+% SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+% merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+% MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+% exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+% merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
+% SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+% merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+% exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+% merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% %% REQUIRED (i.e. no default value)
+% merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+% when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+% Req = lists:delete(serviceChangeReason, Req0),
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% %% REQUIRED (i.e. no default value)
+% merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+% when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+% Req = lists:delete(serviceChangeMethod, Req0),
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+% merge_ServiceChangeParm(Parms, SCP0, Req);
+
+% merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE ->
+% SCI = #'AuditDescriptor'{auditToken = [Val]},
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+% Val2 =
+% case Tag of
+% address ->
+% SCP#'ServiceChangeParm'.serviceChangeAddress;
+% mgc_id ->
+% SCP#'ServiceChangeParm'.serviceChangeMgcId;
+% profile ->
+% SCP#'ServiceChangeParm'.serviceChangeProfile;
+% version ->
+% SCP#'ServiceChangeParm'.serviceChangeVersion;
+% reason ->
+% SCP#'ServiceChangeParm'.serviceChangeReason;
+% delay ->
+% SCP#'ServiceChangeParm'.serviceChangeDelay;
+% method ->
+% SCP#'ServiceChangeParm'.serviceChangeMethod;
+% time_stamp ->
+% SCP#'ServiceChangeParm'.timeStamp;
+% audit_item ->
+% SCP#'ServiceChangeParm'.serviceChangeInfo
+% end,
+% exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
+
+
+% merge_ServiceChangeResParm(Parms) ->
+% merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+% merge_ServiceChangeResParm([], SCRP) ->
+% SCRP;
+% merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
+% SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+% merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+% MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+% exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+% merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
+% SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+% merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+% exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+% merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+% Val2 =
+% case Tag of
+% address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+% mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+% profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+% version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+% time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+% end,
+% exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
+% failover;
+% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
+% failover;
+% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) ->
+% forced;
+% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
+% forced;
+% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
+% graceful;
+% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
+% graceful;
+% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
+% restart;
+% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
+% restart;
+% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
+% disconnected;
+% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
+% disconnected;
+% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
+% handOff;
+% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
+% handOff;
+% ensure_serviceChangeMethod({safeToken, Line, Text}) ->
+% return_error(Line, {bad_serviceChangeMethod, Text}).
+
+
+ensure_profile({_TokenTag, Line, Text}) ->
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+% merge_signalRequest(SignalName, PropertyParms) ->
+% Sig = #'Signal'{signalName = SignalName},
+% SPL = [],
+% do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+% do_merge_signalRequest(Sig, [H | T], SPL) ->
+% case H of
+% {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL);
+% {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+% {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+% {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+% keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+% do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+% {other, Name, PP} ->
+% SP = #'SigParameter'{sigParameterName = Name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_signalRequest(Sig, T, [SP | SPL]);
+% _ ->
+% return_error(0, {bad_sigParm, H})
+% end;
+% do_merge_signalRequest(Sig, [], SPL) ->
+% Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+% %% eventStream = StreamToken EQUAL StreamID
+% %% eventOther = eventParameterName parmValue
+% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("st", Value) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("stream", Value) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+% EP = #'EventParameter'{eventParameterName = Name,
+% value = Value},
+% {other, EP}.
+
+% ensure_eventDM({_TokenTag, Line, DMD})
+% when record(DMD, 'DigitMapDescriptor') ->
+% Name = DMD#'DigitMapDescriptor'.digitMapName,
+% Val = DMD#'DigitMapDescriptor'.digitMapValue,
+% if
+% Name == asn1_NOVALUE, Val /= asn1_NOVALUE ->
+% {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+% DMV = #'DigitMapValue'{startTimer = Start,
+% shortTimer = Short,
+% longTimer = Long,
+% digitMapBody = Body,
+% durationTimer = Duration},
+% {eventDM, {digitMapValue, DMV}};
+% Name /= asn1_NOVALUE, Val == asn1_NOVALUE ->
+% {eventDM, {digitMapName, Name}};
+% true ->
+% return_error(Line, {bad_eventDM, DMD})
+% end.
+
+% ensure_DMD({_TokenTag, _Line, DMD})
+% when record(DMD, 'DigitMapDescriptor') ->
+% Val2 =
+% case DMD#'DigitMapDescriptor'.digitMapValue of
+% %% Note that the values of the digitMapBody and durationTimers
+% %% are swapped by the scanner (this is done because of a
+% %% problem in the flex scanner).
+% #'DigitMapValue'{durationTimer = Body,
+% digitMapBody = Duration} = DMV ->
+% %% Convert to version 1 DigitMapValue
+% DMV#'DigitMapValue'{digitMapBody = Body,
+% durationTimer = Duration};
+% Other ->
+% Other
+% end,
+% DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
+
+
+% merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+% do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+% do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+% do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+% do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+% do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+% #'ObservedEvent'{eventName = EventName,
+% timeNotation = TimeStamp,
+% streamID = StreamID,
+% eventParList = lists:reverse(EPL)}.
+
+% merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
+% OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
+% #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+% streamID = OE#'ObservedEvent'.streamID,
+% eventParList = OE#'ObservedEvent'.eventParList};
+% merge_eventSpec(OE) ->
+% return_error(0, {bad_event_spec, OE}).
+
+% merge_eventParameters(Params) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% RA = #'RequestedActions'{},
+% HasA = no,
+% do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+% case H of
+% keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{keepActive = true},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+% secondEvent = SED},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{eventDM = DM},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+% do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+% {other, PP} when record(PP, 'PropertyParm') ->
+% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+% {other, EP} when record(EP, 'EventParameter') ->
+% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+% _ ->
+% return_error(0, {bad_eventParameter, H})
+% end;
+% do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+% #'RequestedEvent'{streamID = StreamId,
+% eventAction = RA,
+% evParList = lists:reverse(EPL)};
+% do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+% #'RequestedEvent'{streamID = StreamId,
+% eventAction = asn1_NOVALUE,
+% evParList = lists:reverse(EPL)}.
+
+% merge_secondEventParameters(Params) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% SRA = #'SecondRequestedActions'{},
+% HasA = no,
+% do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+% case H of
+% keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+% do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+% {other, PP} when record(PP, 'PropertyParm') ->
+% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+% {other, EP} when record(EP, 'EventParameter') ->
+% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+% _ ->
+% return_error(0, {bad_secondEventParameter, H})
+% end;
+% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+% #'SecondRequestedEvent'{streamID = StreamId,
+% eventAction = SRA,
+% evParList = lists:reverse(EPL)};
+% do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+% #'SecondRequestedEvent'{streamID = StreamId,
+% eventAction = asn1_NOVALUE,
+% evParList = lists:reverse(EPL)}.
+
+% %% terminationID = "ROOT" / pathName / "$" / "*"
+% %% Total length of pathName must not exceed 64 chars.
+% %% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+% %% ["@" pathDomainName ]
+% %% ABNF allows two or more consecutive "." although it is meaningless
+% %% in a path domain name.
+% %% pathDomainName = (ALPHA / DIGIT / "*" )
+% %% *63(ALPHA / DIGIT / "-" / "*" / ".")
+% ensure_terminationID({safeToken, _Line, LowerText}) ->
+% %% terminationID = "ROOT" / pathName / "$" / "*"
+% decode_term_id(LowerText, false, [], []).
+
+% decode_term_id([H | T], Wild, Id, Component) ->
+% case H of
+% $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+% $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+% $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+% _ -> decode_term_id(T, Wild, Id, [H | Component])
+% end;
+% decode_term_id([], Wild, Id, Component) ->
+% Id2 = [lists:reverse(Component) | Id],
+% #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+ensure_pathName({_TokenTag, _Line, Text}) ->
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+% ensure_timeStamp({'TimeStampToken', Line, Text}) ->
+% case string:tokens(Text, [$T, $t]) of
+% [Date, Time] ->
+% #'TimeNotation'{date = Date, time = Time};
+% _ ->
+% return_error(Line, {bad_timeStamp, Text})
+% end.
+
+% ensure_transactionID(TransId) ->
+% ensure_uint32(TransId).
+
+% %% transactionAck = transactionID / (transactionID "-" transactionID)
+% ensure_transactionAck({safeToken, _Line, Text}) ->
+% case string:tokens(Text, [$-]) of
+% [Id] ->
+% #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+% [Id, Id2] ->
+% #'TransactionAck'{firstAck = ensure_transactionID(Id),
+% lastAck = ensure_transactionID(Id2)}
+% end.
+
+% merge_action_requests(CtxId, Items) ->
+% CtxReq = #'ContextRequest'{},
+% CtxAuditReq = asn1_NOVALUE,
+% CmdReq = [],
+% TopReq = [],
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
+
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
+% case H of
+% _ when record(H, 'CommandRequest') ->
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
+
+% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+% TopReq, T);
+% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+% TopReq, T);
+% {topology, Desc} ->
+% TopReq2 = Desc ++ TopReq, %% OTP-4088
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq,
+% TopReq2, T);
+
+% {contextAudit, CAs} ->
+% CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs),
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq,
+% TopReq, T)
+
+% end;
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) ->
+% #'ActionRequest'{contextId = CtxId,
+% contextRequest = strip_contextRequest(CtxReq, TopReq),
+% contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq),
+% commandRequests = lists:reverse(CmdReq)}.
+
+
+% merge_context_attr_audit_request(asn1_NOVALUE, CAs) ->
+% merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs);
+% merge_context_attr_audit_request(CAAR, [H|T]) ->
+% CAAR2 =
+% case H of
+% priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{priority = 'NULL'};
+
+% priorityAudit ->
+% Prio = CAAR#'ContextAttrAuditRequest'.priority,
+% exit({only_once, priorityAudit, Prio});
+
+% emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'};
+
+% emergencyAudit ->
+% Em = CAAR#'ContextAttrAuditRequest'.emergency,
+% exit({only_once, emergencyAudit, Em});
+
+% topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{topology = 'NULL'};
+
+% topologyAudit ->
+% Top = CAAR#'ContextAttrAuditRequest'.topology,
+% exit({only_once, topologyAudit, Top})
+
+% end,
+% merge_context_attr_audit_request(CAAR2, T);
+% merge_context_attr_audit_request(CAAR, []) ->
+% CAAR.
+
+% %% OTP-5085:
+% %% In order to solve a problem in the parser, the error descriptor
+% %% has been put last in the non-empty commandReplyList, if it is not
+% %% asn1_NOVALUE
+% merge_action_reply(ReplyList) ->
+% CtxReq = #'ContextRequest'{},
+% TopReq = [],
+% CmdList = [],
+% case lists:reverse(ReplyList) of
+% [ED|RL2] when record(ED, 'ErrorDescriptor') ->
+% AR = do_merge_action_reply(lists:reverse(RL2),
+% CtxReq, TopReq, CmdList),
+% AR#'ActionReply'{errorDescriptor = ED};
+% _ ->
+% do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList)
+% end.
+
+% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
+% case H of
+% {command, Cmd} ->
+% do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
+% {context, Ctx} ->
+% case Ctx of
+% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+% {topology, Desc} ->
+% TopReq2 = Desc ++ TopReq, %% OTP-4088
+% do_merge_action_reply(T, CtxReq, TopReq2, CmdList)
+% end
+% end;
+% do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
+% #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
+% commandReply = lists:reverse(CmdList)}.
+
+% strip_contextRequest(R, TopReq)
+% when R#'ContextRequest'.priority == asn1_NOVALUE,
+% R#'ContextRequest'.emergency == asn1_NOVALUE,
+% TopReq == [] ->
+% asn1_NOVALUE;
+% strip_contextRequest(R, []) ->
+% R#'ContextRequest'{topologyReq = asn1_NOVALUE};
+% strip_contextRequest(R, TopReq) ->
+% R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
+
+
+% strip_contextAttrAuditRequest(R)
+% when R#'ContextAttrAuditRequest'.priority == asn1_NOVALUE,
+% R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE,
+% R#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+% asn1_NOVALUE;
+% strip_contextAttrAuditRequest(R) ->
+% R.
+
+% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+% Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+% case Text of
+% [$w, $- | _] ->
+% Req#'CommandRequest'{wildcardReturn = 'NULL'};
+% [$o, $-, $w, $- | _] ->
+% Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+% [$o, $- | _] ->
+% Req#'CommandRequest'{optional = 'NULL'};
+% _ ->
+% Req
+% end.
+
+% merge_terminationAudit(AuditReturnParameters) ->
+% lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+% do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+% case H of
+% {auditReturnItem, AuditItem} ->
+% do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+% AuditReturnParameter ->
+% do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+% end;
+% do_merge_terminationAudit([], AuditReturnParameters, []) ->
+% AuditReturnParameters;
+% do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+% AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+% AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+% [AuditReturnParameter | AuditReturnParameters].
+
+% merge_mediaDescriptor(MediaParms) ->
+% do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+% do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+% case H of
+% {streamParm, Parm} when Multi == [] ->
+% do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+% {streamDescriptor, Desc} when One == [] ->
+% do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+% {termState, TS2} when TS == asn1_NOVALUE ->
+% do_merge_mediaDescriptor(T, TS2, One, Multi);
+% _ ->
+% return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+% end;
+% do_merge_mediaDescriptor([], TS, One, Multi) ->
+% if
+% One == [], Multi == [] ->
+% #'MediaDescriptor'{streams = asn1_NOVALUE,
+% termStateDescr = TS};
+% One /= [], Multi == [] ->
+% #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
+% termStateDescr = TS};
+% One == [], Multi /= [] ->
+% #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
+% termStateDescr = TS}
+% end.
+
+% merge_streamParms(TaggedStreamParms) ->
+% SP = #'StreamParms'{},
+% do_merge_streamParms(TaggedStreamParms, SP).
+
+% do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+% case Tag of
+% local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE ->
+% do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+% remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
+% do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+% control ->
+% LCD =
+% case SP#'StreamParms'.localControlDescriptor of
+% asn1_NOVALUE ->
+% #'LocalControlDescriptor'{propertyParms = []};
+% PrevLCD ->
+% PrevLCD
+% end,
+% LCD2 = do_merge_control_streamParms(D, LCD),
+% do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+% _ ->
+% return_error(0, {do_merge_streamParms, [All, SP]})
+% end;
+% do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
+% LCD = SP#'StreamParms'.localControlDescriptor,
+% PP = LCD#'LocalControlDescriptor'.propertyParms,
+% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+% SP#'StreamParms'{localControlDescriptor = LCD2};
+% do_merge_streamParms([], SP) ->
+% SP.
+
+
+% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+% case SubTag of
+% group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+% do_merge_control_streamParms(T, LCD2);
+% value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+% do_merge_control_streamParms(T, LCD2);
+% mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+% do_merge_control_streamParms(T, LCD2);
+% prop ->
+% PP = LCD#'LocalControlDescriptor'.propertyParms,
+% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+% do_merge_control_streamParms(T, LCD2);
+% _ ->
+% return_error(0, {do_merge_control_streamParms, [All, LCD]})
+% end;
+% do_merge_control_streamParms([], LCD) ->
+% LCD.
+
+% merge_terminationStateDescriptor(Parms) ->
+% TSD = #'TerminationStateDescriptor'{propertyParms = []},
+% do_merge_terminationStateDescriptor(Parms, TSD).
+
+% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+% case Tag of
+% serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
+% TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+% do_merge_terminationStateDescriptor(T, TSD2);
+% eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
+% TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+% do_merge_terminationStateDescriptor(T, TSD2);
+% propertyParm ->
+% PP = TSD#'TerminationStateDescriptor'.propertyParms,
+% TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+% do_merge_terminationStateDescriptor(T, TSD2)
+% end;
+% do_merge_terminationStateDescriptor([], TSD) ->
+% PP = TSD#'TerminationStateDescriptor'.propertyParms,
+% TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+% ensure_prop_groups({_TokenTag, _Line, Text}) ->
+% Group = [],
+% Groups = [],
+% parse_prop_name(Text, Group, Groups).
+
+% parse_prop_name([Char | Rest] = All, Group, Groups) ->
+% case ?classify_char(Char) of
+% white_space ->
+% parse_prop_name(Rest, Group, Groups);
+% end_of_line ->
+% parse_prop_name(Rest, Group, Groups);
+% _ ->
+% Name = [],
+% do_parse_prop_name(All, Name, Group, Groups)
+% end;
+% parse_prop_name([] = All, Group, Groups) ->
+% Name = [],
+% do_parse_prop_name(All, Name, Group, Groups).
+
+% do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
+% case ?classify_char(Char) of
+% safe_char ->
+% do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+% rest_char when Char == $=, Name /= [] ->
+% %% Now we have a complete name
+% if
+% Name == "v", Group /= [] ->
+% %% v= is a property group delimiter,
+% %% lets create yet another property group.
+% Groups2 = [lists:reverse(Group) | Groups],
+% Group2 = [],
+% parse_prop_value(Rest, Name, Group2, Groups2);
+% true ->
+% %% Use current property group
+% parse_prop_value(Rest, Name, Group, Groups)
+% end;
+% _ ->
+% return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+% end;
+% do_parse_prop_name([], [], [], Groups) ->
+% lists:reverse(Groups);
+% do_parse_prop_name([], [], Group, Groups) ->
+% Group2 = lists:reverse(Group),
+% lists:reverse([Group2 | Groups]);
+% do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
+% %% Assume end of line
+% Value = [],
+% PP = make_prop_parm(Name, Value),
+% Group2 = lists:reverse([PP | Group]),
+% lists:reverse([Group2 | Groups]).
+
+% parse_prop_value(Chars, Name, Group, Groups) ->
+% Value = [],
+% do_parse_prop_value(Chars, Name, Value, Group, Groups).
+
+% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
+% case ?classify_char(Char) of
+% end_of_line ->
+% %% Now we have a complete "name=value" pair
+% PP = make_prop_parm(Name, Value),
+% parse_prop_name(Rest, [PP | Group], Groups);
+% _ ->
+% do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
+% end;
+% do_parse_prop_value([], Name, Value, Group, Groups) ->
+% %% Assume end of line
+% PP = make_prop_parm(Name, Value),
+% Group2 = lists:reverse([PP | Group]),
+% lists:reverse([Group2 | Groups]).
+
+% make_prop_parm(Name, Value) ->
+% #'PropertyParm'{name = lists:reverse(Name),
+% value = [lists:reverse(Value)]}.
+
+ensure_uint({_TokenTag, Line, Val}, Min, Max) when is_integer(Val) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end;
+ensure_uint({TokenTag, Line, Text}, Min, Max) ->
+ case catch list_to_integer(Text) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint({TokenTag, Line, Val}, Min, Max)
+ end;
+ensure_uint(Val, Min, Max) ->
+ ensure_uint({uint, 0, Val}, Min, Max).
+
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+% ensure_uint32(Int) ->
+% ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
+ Char - $0;
+hchar_to_int(Char) when $A =< Char, Char =< $F ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when $a =< Char, Char =< $f ->
+ Char - $a + 10. % OTP-4710
+
+% value_of({_TokenTag, _Line, Text}) ->
+% Text.
+
+
+% d(F) ->
+% d(F, []).
+
+% d(F, A) ->
+% d(get(dbg), F, A).
+
+% d(true, F, A) ->
+% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
+% d(_, _, _) ->
+% ok.
+