1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
18
%%----------------------------------------------------------------------
19
%% Purpose : Define semantic text parser actions
20
%%----------------------------------------------------------------------
23
-include_lib("megaco/include/megaco.hrl").
24
-include_lib("megaco/include/megaco_message_v2.hrl").
25
-include("megaco_text_tokens.hrl").
27
-define(d(F,A), io:format("DBG:"++F++"~n",A)).
29
make_safe_token({_TokenTag, Line, Text}) ->
30
{safeToken, Line, Text}.
32
% ensure_value({safeToken, _Line, Text}) ->
34
% ensure_value({'QuotedChars', _Line, Text}) ->
36
% ensure_value(Text) when list(Text) ->
37
% Text. %% BUGBUG: ensure length
39
% %% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
40
% ensure_NAME({_TokenTag, _Line, Text}) ->
41
% Text. %% BUGBUG: ensure length and chars
43
% ensure_requestID({safeToken, _Line, "*"}) ->
44
% ?megaco_all_request_id;
45
% ensure_requestID(RequestId) ->
46
% ensure_uint32(RequestId).
48
% ensure_streamID(StreamId) ->
49
% ensure_uint16(StreamId).
51
ensure_auth_header(SpiToken, SnToken, AdToken) ->
52
Spi = ensure_hex(SpiToken, 8, 8),
53
Sn = ensure_hex(SnToken, 8, 8),
54
Ad = ensure_hex(AdToken, 24, 64),
55
#'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
57
%% ContextID = (UINT32 / "*" / "-" / "$")
58
% ensure_contextID({_TokenTag, _Line, Text}) ->
60
% "*" -> ?megaco_all_context_id;
61
% "-" -> ?megaco_null_context_id;
62
% "\$" -> ?megaco_choose_context_id;
63
% Int -> ensure_uint32(Int)
66
ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
67
Addr = ensure_ip4addr(Addr0),
68
{ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
69
ensure_domainAddress([colon,colon], Port) ->
70
Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
71
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
72
ensure_domainAddress(Addr0, Port) ->
73
Addr = ensure_ip6addr(Addr0),
74
{ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
77
ensure_ip4addr({TokenTag, Line, Addr}) ->
78
case string:tokens(Addr, [$.]) of
80
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
81
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
82
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
83
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
86
return_error(Line, {bad_IP4address, Addr})
90
ensure_ip6addr([colon,colon|T]) ->
91
[H1|T1] = lists:reverse(T),
92
case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
93
{true, A} when length(A) == 16 ->
95
{true, B} when length(B) < 16 ->
96
lists:duplicate(16 - length(B), 0) ++ B;
98
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
101
case lists:reverse(L) of
103
case do_ensure_ip6addr(T, true, [], 1) of
104
{true, A} when length(A) == 16 ->
106
{true, B} when length(B) < 16 ->
107
B ++ lists:duplicate(16 - length(B), 0);
109
throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
111
[H|L1] -> % A (last element) could be an ip4 address
112
case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
113
{false, A} when length(A) == 16 ->
115
%% allow a pad even if the address is full (i.e. 16)
116
{true, B} when length(B) =< 17 ->
117
do_ensure_ip6addr_padding(B, 0);
119
throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
125
do_ensure_ip6addr([], Pad, Acc, _) ->
126
{Pad, lists:flatten(Acc)};
127
do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
128
do_ensure_ip6addr(T, true, [pad|Acc], Line);
129
do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
130
return_error(Line, {bad_mid_duplicate_padding, T, Acc});
131
do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
132
do_ensure_ip6addr(T, Pad, Acc, Line);
133
do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
134
do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
136
do_ensure_ip6addr_padding([], _) ->
138
do_ensure_ip6addr_padding([pad|T], N) ->
139
lists:duplicate(16 - (N + length(T)), 0) ++ T;
140
do_ensure_ip6addr_padding([H|T], N) ->
141
[H|do_ensure_ip6addr_padding(T, N+1)].
143
ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
144
case string:tokens(Addr, [$.]) of
146
A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
147
A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
148
A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
149
A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
154
%% %% Here we should test for hexseq
155
%% return_error(Line, {bad_IP4address, Addr})
158
ensure_hex4({_TokenTag, Line, Hex4})
159
when length(Hex4) =< 4, length(Hex4) > 0 ->
160
case (catch do_ensure_hex4(Hex4)) of
161
IL when list(IL), length(IL) == 2 ->
164
return_error(Line, {bad_hex4, Hex4, Error})
167
do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
169
do_ensure_hex4([H2, H3, H4]) ->
170
hex_to_int([$0, H2, H3, H4], []);
171
do_ensure_hex4([H3, H4]) ->
172
hex_to_int([$0, $0, H3, H4], []);
173
do_ensure_hex4([H4]) ->
174
hex_to_int([$0, $0, $0, H4], []).
176
ensure_domainName({_TokenTag, _Line, Name}, Port) ->
177
%% BUGBUG: validate name
178
{domainName, #'DomainName'{name = Name, portNumber = Port}}.
180
%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
181
% ensure_extensionParameter({_TokenTag, Line, Text}) ->
186
% S /= $+, S /= $- ->
187
% return_error(Line, {bad_extension_parameter, Text});
189
% {extension_parameter, Text}
192
% return_error(Line, {bad_extension_parameter, Text})
195
ensure_message(MegacopToken, MID) ->
196
#'ServiceChangeProfile'{profileName = Name,
198
ensure_profile(MegacopToken),
201
#'Message'{version = Version, mId = MID};
203
#'Message'{version = Version, mId = MID}
207
%% modemType = (V32bisToken / V22bisToken / V18Token /
208
%% V22Token / V32Token / V34Token / V90Token /
209
%% V91Token / SynchISDNToken / extensionParameter)
210
% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
220
% "synchisdn" -> synchISDN;
222
% [$x | _] -> ensure_extensionParameter(Token)
225
%% An mtp address is five octets long
226
ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
227
%% BUGBUG: validate address
230
%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
231
% ensure_muxType({_TokenTag, _Line, Text} = Token) ->
237
% "nx64k" -> nx64k; % v2
238
% [$x | _] -> ensure_extensionParameter(Token)
241
%% packagesItem = NAME "-" UINT16
242
%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
243
% ensure_packagesItem({TokenTag, Line, Text}) ->
244
% case string:tokens(Text, [$-]) of
246
% #'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}),
247
% packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
249
% return_error(Line, {bad_PackagesItem, Text})
252
%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
253
%% PackageName = NAME
255
% ensure_pkgdName({TokenTag, Line, Text}) ->
256
% case string:tokens(Text, [$/]) of
258
% ensure_name_or_star({TokenTag, Line, Name}),
259
% ensure_name_or_star({TokenTag, Line, Item}),
262
% return_error(Line, {bad_pkgdName, Text})
265
% ensure_name_or_star({_, _, Name}) when Name == "*" ->
267
% ensure_name_or_star(Name) ->
274
% merge_indAudMediaDescriptor({termStateDescr, Val}) ->
275
% #'IndAudMediaDescriptor'{termStateDescr = Val};
276
% merge_indAudMediaDescriptor({streamParm, Val}) ->
277
% #'IndAudMediaDescriptor'{streams = {oneStream, Val}};
278
% merge_indAudMediaDescriptor({streamDescr, Val}) ->
279
% #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}.
281
% merge_indAudLocalControlDescriptor(Parms) ->
282
% do_merge_indAudLocalControlDescriptor(Parms,
283
% #'IndAudLocalControlDescriptor'{}).
285
% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
287
% modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE ->
288
% Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
289
% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
290
% reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
291
% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
292
% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
293
% reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
294
% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
295
% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
296
% {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
297
% PropParms = [#'IndAudPropertyParm'{name = Val}],
298
% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
299
% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
300
% {pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
301
% PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
302
% PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
303
% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
304
% do_merge_indAudLocalControlDescriptor(Parms, Desc2)
306
% do_merge_indAudLocalControlDescriptor([], Desc) ->
307
% case Desc#'IndAudLocalControlDescriptor'.propertyParms of
308
% [_ | _] = PropParms -> % List has more then one element
309
% PropParms2= lists:reverse(PropParms),
310
% Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
315
% ensure_indAudLocalParm(Token) ->
317
% {safeToken, _Line, "mode"} -> modeToken;
318
% {safeToken, _Line, "mo"} -> modeToken;
319
% {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
320
% {safeToken, _Line, "rg"} -> reservedGroupToken;
321
% {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
322
% {safeToken, _Line, "rv"} -> reservedValueToken;
323
% PkgdName -> {pkgdName,
324
% ensure_pkgdName(PkgdName)}
327
% merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
328
% PropParm = #'IndAudPropertyParm'{name = Val},
329
% #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
330
% merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
331
% #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
332
% merge_indAudTerminationStateDescriptor(bufferToken) ->
333
% #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
336
% merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
337
% IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
338
% do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
340
% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
342
% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
343
% IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
344
% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
346
% %% BUGBUG BUGBUG BUGBUG
347
% %% This is an ugly hack to allow the eventParamName which only
348
% %% exists in the text encoding...
349
% IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
352
% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
353
% ensure_indAudSignal(SIG).
355
% ensure_indAudSignal(#'Signal'{signalName = SignalName,
356
% streamID = asn1_NOVALUE,
357
% sigType = asn1_NOVALUE,
358
% duration = asn1_NOVALUE,
359
% notifyCompletion = asn1_NOVALUE,
360
% keepActive = asn1_NOVALUE,
361
% sigParList = []}) ->
362
% #'IndAudSignal'{signalName = SignalName}.
365
% ensure_IADMD({_TokenTag, _Line,
366
% #'DigitMapDescriptor'{digitMapName = Name,
367
% digitMapValue = asn1_NOVALUE}}) ->
368
% #'IndAudDigitMapDescriptor'{digitMapName = Name}.
371
% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
372
% packageVersion = V}) ->
373
% #'IndAudPackagesDescriptor'{packageName = N,
374
% packageVersion = V}.
377
% ensure_indAudTerminationStateParm(Token) ->
379
% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
380
% {safeToken, _Line, "si"} -> serviceStatesToken;
381
% {safeToken, _Line, "buffer"} -> bufferToken;
382
% {safeToken, _Line, "bf"} -> bufferToken;
383
% PkgdName -> {pkgdName,
384
% ensure_pkgdName(PkgdName)}
388
% %% Types modified by v2:
390
% merge_auditDescriptor([]) ->
391
% #'AuditDescriptor'{};
392
% merge_auditDescriptor(Tokens) when list(Tokens) ->
393
% case lists:keysearch(terminationAudit, 1, Tokens) of
394
% {value, {terminationAudit, TA}} ->
395
% case lists:keydelete(terminationAudit, 1, Tokens) of
397
% #'AuditDescriptor'{auditPropertyToken = TA};
399
% #'AuditDescriptor'{auditToken = AuditTokens,
400
% auditPropertyToken = TA}
403
% #'AuditDescriptor'{auditToken = Tokens}
405
% merge_auditDescriptor(_) ->
406
% #'AuditDescriptor'{}.
413
% merge_ServiceChangeParm(Parms) ->
414
% Required = [serviceChangeReason, serviceChangeMethod],
415
% merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
417
% merge_ServiceChangeParm([], SCP, []) ->
420
% merge_ServiceChangeParm([], _SCP, Required) ->
421
% exit({missing_required_serviceChangeParm, Required});
423
% merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
424
% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
425
% SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
426
% SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
427
% merge_ServiceChangeParm(Parms, SCP, Req);
428
% merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
429
% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
430
% MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
431
% exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
433
% merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
434
% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
435
% SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
436
% SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
437
% merge_ServiceChangeParm(Parms, SCP, Req);
438
% merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
439
% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
440
% Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
441
% exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
443
% merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
444
% when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
445
% SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
446
% merge_ServiceChangeParm(Parms, SCP, Req);
448
% merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
449
% when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
450
% SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
451
% merge_ServiceChangeParm(Parms, SCP, Req);
453
% %% REQUIRED (i.e. no default value)
454
% merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
455
% when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
456
% SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
457
% Req = lists:delete(serviceChangeReason, Req0),
458
% merge_ServiceChangeParm(Parms, SCP, Req);
460
% merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
461
% when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
462
% SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
463
% merge_ServiceChangeParm(Parms, SCP, Req);
465
% %% REQUIRED (i.e. no default value)
466
% merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
467
% when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
468
% SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
469
% Req = lists:delete(serviceChangeMethod, Req0),
470
% merge_ServiceChangeParm(Parms, SCP, Req);
472
% merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
473
% when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
474
% SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
475
% merge_ServiceChangeParm(Parms, SCP, Req);
477
% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
478
% merge_ServiceChangeParm(Parms, SCP0, Req);
480
% merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
481
% when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE ->
482
% SCI = #'AuditDescriptor'{auditToken = [Val]},
483
% SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
484
% merge_ServiceChangeParm(Parms, SCP, Req);
486
% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
490
% SCP#'ServiceChangeParm'.serviceChangeAddress;
492
% SCP#'ServiceChangeParm'.serviceChangeMgcId;
494
% SCP#'ServiceChangeParm'.serviceChangeProfile;
496
% SCP#'ServiceChangeParm'.serviceChangeVersion;
498
% SCP#'ServiceChangeParm'.serviceChangeReason;
500
% SCP#'ServiceChangeParm'.serviceChangeDelay;
502
% SCP#'ServiceChangeParm'.serviceChangeMethod;
504
% SCP#'ServiceChangeParm'.timeStamp;
506
% SCP#'ServiceChangeParm'.serviceChangeInfo
508
% exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
511
% merge_ServiceChangeResParm(Parms) ->
512
% merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
514
% merge_ServiceChangeResParm([], SCRP) ->
516
% merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
517
% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
518
% SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
519
% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
520
% merge_ServiceChangeResParm(Parms, SCRP);
521
% merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
522
% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
523
% MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
524
% exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
526
% merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
527
% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
528
% SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
529
% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
530
% merge_ServiceChangeResParm(Parms, SCRP);
531
% merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
532
% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
533
% Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
534
% exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
536
% merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
537
% when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
538
% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
539
% merge_ServiceChangeResParm(Parms, SCRP);
541
% merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
542
% when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
543
% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
544
% merge_ServiceChangeResParm(Parms, SCRP);
546
% merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
547
% when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
548
% SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
549
% merge_ServiceChangeResParm(Parms, SCRP);
551
% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
554
% address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
555
% mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
556
% profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
557
% version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
558
% time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
560
% exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
563
% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
565
% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
567
% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) ->
569
% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
571
% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
573
% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
575
% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
577
% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
579
% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
581
% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
583
% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
585
% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
587
% ensure_serviceChangeMethod({safeToken, Line, Text}) ->
588
% return_error(Line, {bad_serviceChangeMethod, Text}).
591
ensure_profile({_TokenTag, Line, Text}) ->
592
case string:tokens(Text, [$/]) of
594
Version2 = ensure_version(Version),
595
#'ServiceChangeProfile'{profileName = Name, version = Version2};
597
return_error(Line, {bad_profile, Text})
600
ensure_version(Version) ->
601
ensure_uint(Version, 0, 99).
603
% merge_signalRequest(SignalName, PropertyParms) ->
604
% Sig = #'Signal'{signalName = SignalName},
606
% do_merge_signalRequest(Sig, PropertyParms, SPL).
608
% do_merge_signalRequest(Sig, [H | T], SPL) ->
610
% {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE ->
611
% do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL);
612
% {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
613
% do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
614
% {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
615
% do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
616
% {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
617
% do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
618
% keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
619
% do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
620
% {other, Name, PP} ->
621
% SP = #'SigParameter'{sigParameterName = Name,
622
% value = PP#'PropertyParm'.value,
623
% extraInfo = PP#'PropertyParm'.extraInfo},
624
% do_merge_signalRequest(Sig, T, [SP | SPL]);
626
% return_error(0, {bad_sigParm, H})
628
% do_merge_signalRequest(Sig, [], SPL) ->
629
% Sig#'Signal'{sigParList = lists:reverse(SPL)} .
631
% %% eventStream = StreamToken EQUAL StreamID
632
% %% eventOther = eventParameterName parmValue
633
% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
634
% {stream, ensure_uint16(Value)};
635
% select_stream_or_other("st", Value) ->
636
% {stream, ensure_uint16(Value)};
637
% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
638
% {stream, ensure_uint16(Value)};
639
% select_stream_or_other("stream", Value) ->
640
% {stream, ensure_uint16(Value)};
641
% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
642
% EP = #'EventParameter'{eventParameterName = Name,
646
% ensure_eventDM({_TokenTag, Line, DMD})
647
% when record(DMD, 'DigitMapDescriptor') ->
648
% Name = DMD#'DigitMapDescriptor'.digitMapName,
649
% Val = DMD#'DigitMapDescriptor'.digitMapValue,
651
% Name == asn1_NOVALUE, Val /= asn1_NOVALUE ->
652
% {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
653
% DMV = #'DigitMapValue'{startTimer = Start,
654
% shortTimer = Short,
656
% digitMapBody = Body,
657
% durationTimer = Duration},
658
% {eventDM, {digitMapValue, DMV}};
659
% Name /= asn1_NOVALUE, Val == asn1_NOVALUE ->
660
% {eventDM, {digitMapName, Name}};
662
% return_error(Line, {bad_eventDM, DMD})
665
% ensure_DMD({_TokenTag, _Line, DMD})
666
% when record(DMD, 'DigitMapDescriptor') ->
668
% case DMD#'DigitMapDescriptor'.digitMapValue of
669
% %% Note that the values of the digitMapBody and durationTimers
670
% %% are swapped by the scanner (this is done because of a
671
% %% problem in the flex scanner).
672
% #'DigitMapValue'{durationTimer = Body,
673
% digitMapBody = Duration} = DMV ->
674
% %% Convert to version 1 DigitMapValue
675
% DMV#'DigitMapValue'{digitMapBody = Body,
676
% durationTimer = Duration};
680
% DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
683
% merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
684
% StreamId = asn1_NOVALUE,
686
% do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
688
% do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
689
% do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
690
% do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
691
% do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
692
% do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
693
% #'ObservedEvent'{eventName = EventName,
694
% timeNotation = TimeStamp,
695
% streamID = StreamID,
696
% eventParList = lists:reverse(EPL)}.
698
% merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
699
% OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
700
% #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
701
% streamID = OE#'ObservedEvent'.streamID,
702
% eventParList = OE#'ObservedEvent'.eventParList};
703
% merge_eventSpec(OE) ->
704
% return_error(0, {bad_event_spec, OE}).
706
% merge_eventParameters(Params) ->
707
% StreamId = asn1_NOVALUE,
709
% RA = #'RequestedActions'{},
711
% do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
713
% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
715
% keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
716
% RA2 = RA#'RequestedActions'{keepActive = true},
717
% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
718
% {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
719
% RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
720
% secondEvent = SED},
721
% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
722
% {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
723
% RA2 = RA#'RequestedActions'{eventDM = DM},
724
% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
725
% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
726
% do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
727
% {other, PP} when record(PP, 'PropertyParm') ->
728
% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
729
% value = PP#'PropertyParm'.value,
730
% extraInfo = PP#'PropertyParm'.extraInfo},
731
% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
732
% {other, EP} when record(EP, 'EventParameter') ->
733
% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
735
% return_error(0, {bad_eventParameter, H})
737
% do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
738
% #'RequestedEvent'{streamID = StreamId,
740
% evParList = lists:reverse(EPL)};
741
% do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
742
% #'RequestedEvent'{streamID = StreamId,
743
% eventAction = asn1_NOVALUE,
744
% evParList = lists:reverse(EPL)}.
746
% merge_secondEventParameters(Params) ->
747
% StreamId = asn1_NOVALUE,
749
% SRA = #'SecondRequestedActions'{},
751
% do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
753
% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
755
% keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
756
% SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
757
% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
758
% {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
759
% SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
760
% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
761
% {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
762
% SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
763
% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
764
% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
765
% do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
766
% {other, PP} when record(PP, 'PropertyParm') ->
767
% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
768
% value = PP#'PropertyParm'.value,
769
% extraInfo = PP#'PropertyParm'.extraInfo},
770
% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
771
% {other, EP} when record(EP, 'EventParameter') ->
772
% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
774
% return_error(0, {bad_secondEventParameter, H})
776
% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
777
% #'SecondRequestedEvent'{streamID = StreamId,
779
% evParList = lists:reverse(EPL)};
780
% do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
781
% #'SecondRequestedEvent'{streamID = StreamId,
782
% eventAction = asn1_NOVALUE,
783
% evParList = lists:reverse(EPL)}.
785
% %% terminationID = "ROOT" / pathName / "$" / "*"
786
% %% Total length of pathName must not exceed 64 chars.
787
% %% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
788
% %% ["@" pathDomainName ]
789
% %% ABNF allows two or more consecutive "." although it is meaningless
790
% %% in a path domain name.
791
% %% pathDomainName = (ALPHA / DIGIT / "*" )
792
% %% *63(ALPHA / DIGIT / "-" / "*" / ".")
793
% ensure_terminationID({safeToken, _Line, LowerText}) ->
794
% %% terminationID = "ROOT" / pathName / "$" / "*"
795
% decode_term_id(LowerText, false, [], []).
797
% decode_term_id([H | T], Wild, Id, Component) ->
799
% $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
800
% $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
801
% $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
802
% _ -> decode_term_id(T, Wild, Id, [H | Component])
804
% decode_term_id([], Wild, Id, Component) ->
805
% Id2 = [lists:reverse(Component) | Id],
806
% #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
808
ensure_pathName({_TokenTag, _Line, Text}) ->
809
Text. %% BUGBUG: ensure values
811
%% TimeStamp = Date "T" Time ; per ISO 8601:1988
812
%% Date = 8(DIGIT) ; Date = yyyymmdd
813
%% Time = 8(DIGIT) ; Time = hhmmssss
814
% ensure_timeStamp({'TimeStampToken', Line, Text}) ->
815
% case string:tokens(Text, [$T, $t]) of
817
% #'TimeNotation'{date = Date, time = Time};
819
% return_error(Line, {bad_timeStamp, Text})
822
% ensure_transactionID(TransId) ->
823
% ensure_uint32(TransId).
825
% %% transactionAck = transactionID / (transactionID "-" transactionID)
826
% ensure_transactionAck({safeToken, _Line, Text}) ->
827
% case string:tokens(Text, [$-]) of
829
% #'TransactionAck'{firstAck = ensure_transactionID(Id)};
831
% #'TransactionAck'{firstAck = ensure_transactionID(Id),
832
% lastAck = ensure_transactionID(Id2)}
835
% merge_action_requests(CtxId, Items) ->
836
% CtxReq = #'ContextRequest'{},
837
% CtxAuditReq = asn1_NOVALUE,
840
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
842
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
844
% _ when record(H, 'CommandRequest') ->
845
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
847
% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
848
% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
849
% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
851
% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
852
% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
853
% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
855
% {topology, Desc} ->
856
% TopReq2 = Desc ++ TopReq, %% OTP-4088
857
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq,
860
% {contextAudit, CAs} ->
861
% CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs),
862
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq,
866
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) ->
867
% #'ActionRequest'{contextId = CtxId,
868
% contextRequest = strip_contextRequest(CtxReq, TopReq),
869
% contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq),
870
% commandRequests = lists:reverse(CmdReq)}.
873
% merge_context_attr_audit_request(asn1_NOVALUE, CAs) ->
874
% merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs);
875
% merge_context_attr_audit_request(CAAR, [H|T]) ->
878
% priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
879
% CAAR#'ContextAttrAuditRequest'{priority = 'NULL'};
882
% Prio = CAAR#'ContextAttrAuditRequest'.priority,
883
% exit({only_once, priorityAudit, Prio});
885
% emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
886
% CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'};
889
% Em = CAAR#'ContextAttrAuditRequest'.emergency,
890
% exit({only_once, emergencyAudit, Em});
892
% topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
893
% CAAR#'ContextAttrAuditRequest'{topology = 'NULL'};
896
% Top = CAAR#'ContextAttrAuditRequest'.topology,
897
% exit({only_once, topologyAudit, Top})
900
% merge_context_attr_audit_request(CAAR2, T);
901
% merge_context_attr_audit_request(CAAR, []) ->
905
% %% In order to solve a problem in the parser, the error descriptor
906
% %% has been put last in the non-empty commandReplyList, if it is not
908
% merge_action_reply(ReplyList) ->
909
% CtxReq = #'ContextRequest'{},
912
% case lists:reverse(ReplyList) of
913
% [ED|RL2] when record(ED, 'ErrorDescriptor') ->
914
% AR = do_merge_action_reply(lists:reverse(RL2),
915
% CtxReq, TopReq, CmdList),
916
% AR#'ActionReply'{errorDescriptor = ED};
918
% do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList)
921
% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
924
% do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
927
% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
928
% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
929
% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
930
% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
931
% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
932
% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
933
% {topology, Desc} ->
934
% TopReq2 = Desc ++ TopReq, %% OTP-4088
935
% do_merge_action_reply(T, CtxReq, TopReq2, CmdList)
938
% do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
939
% #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
940
% commandReply = lists:reverse(CmdList)}.
942
% strip_contextRequest(R, TopReq)
943
% when R#'ContextRequest'.priority == asn1_NOVALUE,
944
% R#'ContextRequest'.emergency == asn1_NOVALUE,
947
% strip_contextRequest(R, []) ->
948
% R#'ContextRequest'{topologyReq = asn1_NOVALUE};
949
% strip_contextRequest(R, TopReq) ->
950
% R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
953
% strip_contextAttrAuditRequest(R)
954
% when R#'ContextAttrAuditRequest'.priority == asn1_NOVALUE,
955
% R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE,
956
% R#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
958
% strip_contextAttrAuditRequest(R) ->
961
% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
962
% Req = #'CommandRequest'{command = {CmdTag, Cmd}},
965
% Req#'CommandRequest'{wildcardReturn = 'NULL'};
966
% [$o, $-, $w, $- | _] ->
967
% Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
969
% Req#'CommandRequest'{optional = 'NULL'};
974
% merge_terminationAudit(AuditReturnParameters) ->
975
% lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
977
% do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
979
% {auditReturnItem, AuditItem} ->
980
% do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
981
% AuditReturnParameter ->
982
% do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
984
% do_merge_terminationAudit([], AuditReturnParameters, []) ->
985
% AuditReturnParameters;
986
% do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
987
% AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
988
% AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
989
% [AuditReturnParameter | AuditReturnParameters].
991
% merge_mediaDescriptor(MediaParms) ->
992
% do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
994
% do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
996
% {streamParm, Parm} when Multi == [] ->
997
% do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
998
% {streamDescriptor, Desc} when One == [] ->
999
% do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
1000
% {termState, TS2} when TS == asn1_NOVALUE ->
1001
% do_merge_mediaDescriptor(T, TS2, One, Multi);
1003
% return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
1005
% do_merge_mediaDescriptor([], TS, One, Multi) ->
1007
% One == [], Multi == [] ->
1008
% #'MediaDescriptor'{streams = asn1_NOVALUE,
1009
% termStateDescr = TS};
1010
% One /= [], Multi == [] ->
1011
% #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
1012
% termStateDescr = TS};
1013
% One == [], Multi /= [] ->
1014
% #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
1015
% termStateDescr = TS}
1018
% merge_streamParms(TaggedStreamParms) ->
1019
% SP = #'StreamParms'{},
1020
% do_merge_streamParms(TaggedStreamParms, SP).
1022
% do_merge_streamParms([{Tag, D} | T] = All, SP) ->
1024
% local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE ->
1025
% do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
1026
% remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
1027
% do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
1030
% case SP#'StreamParms'.localControlDescriptor of
1032
% #'LocalControlDescriptor'{propertyParms = []};
1036
% LCD2 = do_merge_control_streamParms(D, LCD),
1037
% do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
1039
% return_error(0, {do_merge_streamParms, [All, SP]})
1041
% do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
1042
% LCD = SP#'StreamParms'.localControlDescriptor,
1043
% PP = LCD#'LocalControlDescriptor'.propertyParms,
1044
% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
1045
% SP#'StreamParms'{localControlDescriptor = LCD2};
1046
% do_merge_streamParms([], SP) ->
1050
% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
1052
% group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
1053
% LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
1054
% do_merge_control_streamParms(T, LCD2);
1055
% value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
1056
% LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
1057
% do_merge_control_streamParms(T, LCD2);
1058
% mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
1059
% LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
1060
% do_merge_control_streamParms(T, LCD2);
1062
% PP = LCD#'LocalControlDescriptor'.propertyParms,
1063
% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
1064
% do_merge_control_streamParms(T, LCD2);
1066
% return_error(0, {do_merge_control_streamParms, [All, LCD]})
1068
% do_merge_control_streamParms([], LCD) ->
1071
% merge_terminationStateDescriptor(Parms) ->
1072
% TSD = #'TerminationStateDescriptor'{propertyParms = []},
1073
% do_merge_terminationStateDescriptor(Parms, TSD).
1075
% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
1077
% serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
1078
% TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
1079
% do_merge_terminationStateDescriptor(T, TSD2);
1080
% eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
1081
% TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
1082
% do_merge_terminationStateDescriptor(T, TSD2);
1084
% PP = TSD#'TerminationStateDescriptor'.propertyParms,
1085
% TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
1086
% do_merge_terminationStateDescriptor(T, TSD2)
1088
% do_merge_terminationStateDescriptor([], TSD) ->
1089
% PP = TSD#'TerminationStateDescriptor'.propertyParms,
1090
% TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
1092
% ensure_prop_groups({_TokenTag, _Line, Text}) ->
1095
% parse_prop_name(Text, Group, Groups).
1097
% parse_prop_name([Char | Rest] = All, Group, Groups) ->
1098
% case ?classify_char(Char) of
1100
% parse_prop_name(Rest, Group, Groups);
1102
% parse_prop_name(Rest, Group, Groups);
1105
% do_parse_prop_name(All, Name, Group, Groups)
1107
% parse_prop_name([] = All, Group, Groups) ->
1109
% do_parse_prop_name(All, Name, Group, Groups).
1111
% do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
1112
% case ?classify_char(Char) of
1114
% do_parse_prop_name(Rest, [Char | Name], Group, Groups);
1115
% rest_char when Char == $=, Name /= [] ->
1116
% %% Now we have a complete name
1118
% Name == "v", Group /= [] ->
1119
% %% v= is a property group delimiter,
1120
% %% lets create yet another property group.
1121
% Groups2 = [lists:reverse(Group) | Groups],
1123
% parse_prop_value(Rest, Name, Group2, Groups2);
1125
% %% Use current property group
1126
% parse_prop_value(Rest, Name, Group, Groups)
1129
% return_error(0, {bad_prop_name, lists:reverse(Name), Char})
1131
% do_parse_prop_name([], [], [], Groups) ->
1132
% lists:reverse(Groups);
1133
% do_parse_prop_name([], [], Group, Groups) ->
1134
% Group2 = lists:reverse(Group),
1135
% lists:reverse([Group2 | Groups]);
1136
% do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
1137
% %% Assume end of line
1139
% PP = make_prop_parm(Name, Value),
1140
% Group2 = lists:reverse([PP | Group]),
1141
% lists:reverse([Group2 | Groups]).
1143
% parse_prop_value(Chars, Name, Group, Groups) ->
1145
% do_parse_prop_value(Chars, Name, Value, Group, Groups).
1147
% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
1148
% case ?classify_char(Char) of
1150
% %% Now we have a complete "name=value" pair
1151
% PP = make_prop_parm(Name, Value),
1152
% parse_prop_name(Rest, [PP | Group], Groups);
1154
% do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
1156
% do_parse_prop_value([], Name, Value, Group, Groups) ->
1157
% %% Assume end of line
1158
% PP = make_prop_parm(Name, Value),
1159
% Group2 = lists:reverse([PP | Group]),
1160
% lists:reverse([Group2 | Groups]).
1162
% make_prop_parm(Name, Value) ->
1163
% #'PropertyParm'{name = lists:reverse(Name),
1164
% value = [lists:reverse(Value)]}.
1166
ensure_uint({_TokenTag, Line, Val}, Min, Max) when integer(Val) ->
1168
integer(Min), Val >= Min ->
1170
integer(Max), Val =< Max ->
1175
return_error(Line, {too_large_integer, Val, Max})
1178
return_error(Line, {too_small_integer, Val, Min})
1180
ensure_uint({TokenTag, Line, Text}, Min, Max) ->
1181
case catch list_to_integer(Text) of
1183
return_error(Line, {not_an_integer, Text});
1184
Val when integer(Val) ->
1185
ensure_uint({TokenTag, Line, Val}, Min, Max)
1187
ensure_uint(Val, Min, Max) ->
1188
ensure_uint({uint, 0, Val}, Min, Max).
1190
ensure_uint16(Int) ->
1191
ensure_uint(Int, 0, 65535).
1193
% ensure_uint32(Int) ->
1194
% ensure_uint(Int, 0, 4294967295) .
1197
ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
1198
ensure_uint(length(Chars), Min, Max),
1199
hex_to_int(Chars, []);
1200
ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
1201
ensure_uint(length(Chars), Min, Max),
1202
hex_to_int(Chars, []);
1203
ensure_hex([$0, $x |Chars], Min, Max) ->
1204
ensure_uint(length(Chars), Min, Max),
1205
hex_to_int(Chars, []);
1206
ensure_hex([$0, $X |Chars], Min, Max) ->
1207
ensure_uint(length(Chars), Min, Max),
1208
hex_to_int(Chars, []).
1211
hex_to_int([], Acc) ->
1213
hex_to_int([Char1,Char2|Tail], Acc) ->
1214
Int1 = hchar_to_int(Char1),
1215
Int2 = hchar_to_int(Char2),
1216
Val = Int2 bor (Int1 bsl 4),
1217
hex_to_int(Tail, [Val| Acc]);
1218
hex_to_int([Char], Acc) ->
1219
Int = hchar_to_int(Char),
1220
lists:reverse([Int|Acc]).
1222
hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
1224
hchar_to_int(Char) when $A =< Char, Char =< $F ->
1225
Char - $A + 10; % OTP-4710
1226
hchar_to_int(Char) when $a =< Char, Char =< $f ->
1227
Char - $a + 10. % OTP-4710
1229
% value_of({_TokenTag, _Line, Text}) ->
1237
% d(get(dbg), F, A).
1240
% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);