~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/megaco/src/text/megaco_text_parser_prev3c.hrl

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/.
 
6
%% 
 
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
 
10
%% under the License.
 
11
%% 
 
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.''
 
15
%% 
 
16
%%     $Id$
 
17
%%
 
18
%%----------------------------------------------------------------------
 
19
%% Purpose : Define semantic text parser actions
 
20
%%----------------------------------------------------------------------
 
21
 
 
22
 
 
23
-include_lib("megaco/include/megaco.hrl").
 
24
-include_lib("megaco/include/megaco_message_prev3c.hrl").
 
25
-include("megaco_text_tokens.hrl").
 
26
 
 
27
make_safe_token({_TokenTag, Line, Text}) ->
 
28
    {safeToken, Line, Text}.
 
29
 
 
30
ensure_value({safeToken, _Line, Text}) ->
 
31
    ensure_value(Text);
 
32
ensure_value({'QuotedChars', _Line, Text}) ->
 
33
    ensure_value(Text);
 
34
ensure_value(Text) when list(Text) ->
 
35
    Text. %% BUGBUG: ensure length
 
36
 
 
37
%% NAME       = ALPHA *63(ALPHA / DIGIT / "_" )
 
38
ensure_NAME({_TokenTag, _Line, Text}) ->
 
39
    Text.  %% BUGBUG: ensure length and chars
 
40
 
 
41
ensure_requestID({safeToken, _Line, "*"}) ->
 
42
    ?megaco_all_request_id;
 
43
ensure_requestID(RequestId) ->
 
44
    ensure_uint32(RequestId).
 
45
 
 
46
ensure_streamID(StreamId) ->
 
47
    ensure_uint16(StreamId).
 
48
 
 
49
ensure_auth_header(SpiToken, SnToken, AdToken) ->
 
50
    Spi = ensure_hex(SpiToken, 8,  8),
 
51
    Sn  = ensure_hex(SnToken,  8,  8), 
 
52
    Ad  = ensure_hex(AdToken, 24, 64),
 
53
    #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
 
54
 
 
55
%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
 
56
%% ContextID         = (UINT32 / "*" / "-" / "$")
 
57
ensure_contextID({_TokenTag, Line, Text}) ->
 
58
    case Text of
 
59
        "*"  -> ?megaco_all_context_id;
 
60
        "-"  -> ?megaco_null_context_id;
 
61
        "\$" -> ?megaco_choose_context_id;
 
62
        Int  ->
 
63
            CID = ensure_uint32(Int),
 
64
            if
 
65
                (CID =/= 0) and
 
66
                (CID =/= 16#FFFFFFFE) and
 
67
                (CID =/= 16#FFFFFFFF) ->
 
68
                    CID;
 
69
                true ->
 
70
                    return_error(Line, {bad_ContextID, CID})
 
71
            end
 
72
    end.
 
73
 
 
74
ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
 
75
    Addr = ensure_ip4addr(Addr0), 
 
76
    {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
 
77
ensure_domainAddress([colon,colon], Port) ->
 
78
    Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 
79
    {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
 
80
ensure_domainAddress(Addr0, Port) ->
 
81
    Addr = ensure_ip6addr(Addr0),
 
82
    {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
 
83
 
 
84
 
 
85
ensure_ip4addr({TokenTag, Line, Addr}) ->
 
86
    case string:tokens(Addr, [$.]) of
 
87
        [T1, T2, T3, T4] ->
 
88
            A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
 
89
            A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
 
90
            A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
 
91
            A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
 
92
            [A1, A2, A3, A4];
 
93
        _ ->
 
94
            return_error(Line, {bad_IP4address, Addr})
 
95
    end.
 
96
 
 
97
 
 
98
ensure_ip6addr([colon,colon|T]) ->
 
99
    [H1|T1] = lists:reverse(T),
 
100
    case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
 
101
        {true, A} when length(A) == 16 ->
 
102
            A;
 
103
        {true, B} when length(B) < 16 ->
 
104
            lists:duplicate(16 - length(B), 0) ++ B;
 
105
        {true, C} ->
 
106
            throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
 
107
    end;
 
108
ensure_ip6addr(L) ->
 
109
    case lists:reverse(L) of
 
110
        [colon, colon| T] ->
 
111
            case do_ensure_ip6addr(T, true, [], 1) of
 
112
                {true, A} when length(A) == 16 ->
 
113
                    A;
 
114
                {true, B} when length(B) < 16 ->
 
115
                    B ++ lists:duplicate(16 - length(B), 0);
 
116
                {true, C} ->
 
117
                    throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
 
118
            end;
 
119
        [H|L1] -> % A (last element) could be an ip4 address
 
120
            case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
 
121
                {false, A} when length(A) == 16 -> 
 
122
                    A;
 
123
                %% allow a pad even if the address is full (i.e. 16)
 
124
                {true, B} when length(B) =< 17 -> 
 
125
                    do_ensure_ip6addr_padding(B, 0);
 
126
                {Pad, C} ->
 
127
                    throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
 
128
            end
 
129
 
 
130
    end.
 
131
 
 
132
 
 
133
do_ensure_ip6addr([], Pad, Acc, _) ->
 
134
    {Pad, lists:flatten(Acc)};
 
135
do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
 
136
    do_ensure_ip6addr(T, true, [pad|Acc], Line);
 
137
do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
 
138
    return_error(Line, {bad_mid_duplicate_padding, T, Acc});
 
139
do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
 
140
    do_ensure_ip6addr(T, Pad, Acc, Line);
 
141
do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
 
142
    do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
 
143
 
 
144
do_ensure_ip6addr_padding([], _) ->
 
145
    [];
 
146
do_ensure_ip6addr_padding([pad|T], N) ->
 
147
    lists:duplicate(16 - (N + length(T)), 0) ++ T;
 
148
do_ensure_ip6addr_padding([H|T], N) ->
 
149
    [H|do_ensure_ip6addr_padding(T, N+1)].
 
150
 
 
151
ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
 
152
    case string:tokens(Addr, [$.]) of
 
153
        [T1, T2, T3, T4] ->
 
154
            A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
 
155
            A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
 
156
            A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
 
157
            A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
 
158
            [A1, A2, A3, A4];
 
159
        _ ->
 
160
            ensure_hex4(V)
 
161
            %%      %% BMK BMK BMK 
 
162
            %%      %% Here we should test for hexseq
 
163
            %%      return_error(Line, {bad_IP4address, Addr})
 
164
    end.
 
165
 
 
166
ensure_hex4({_TokenTag, Line, Hex4}) 
 
167
  when length(Hex4) =< 4, length(Hex4) > 0 ->
 
168
    case (catch do_ensure_hex4(Hex4)) of
 
169
        IL when list(IL), length(IL) == 2 ->
 
170
            IL;
 
171
        Error ->
 
172
            return_error(Line, {bad_hex4, Hex4, Error})
 
173
    end.
 
174
 
 
175
do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
 
176
    hex_to_int(H, []);
 
177
do_ensure_hex4([H2, H3, H4]) ->
 
178
    hex_to_int([$0, H2, H3, H4], []);
 
179
do_ensure_hex4([H3, H4]) ->
 
180
    hex_to_int([$0, $0, H3, H4], []);
 
181
do_ensure_hex4([H4]) ->
 
182
    hex_to_int([$0, $0, $0, H4], []).
 
183
 
 
184
ensure_domainName({_TokenTag, _Line, Name}, Port) ->
 
185
    %% BUGBUG: validate name
 
186
    {domainName, #'DomainName'{name = Name, portNumber = Port}}.
 
187
 
 
188
%% extensionParameter= "X"  ("-" / "+") 1*6(ALPHA / DIGIT)
 
189
ensure_extensionParameter({_TokenTag, Line, Text}) ->
 
190
    case Text of
 
191
        [X, S | _Chars] ->
 
192
            if
 
193
                X /= $X, X /= $x,
 
194
                S /= $+, S /= $- ->
 
195
                    return_error(Line, {bad_extension_parameter, Text});
 
196
                true ->
 
197
                    {extension_parameter, Text}
 
198
            end;
 
199
        _ ->
 
200
            return_error(Line, {bad_extension_parameter, Text})
 
201
    end.
 
202
 
 
203
ensure_message(MegacopToken,  MID, Body) ->
 
204
    #'ServiceChangeProfile'{profileName = Name,
 
205
                            version     = Version} = 
 
206
        ensure_profile(MegacopToken),
 
207
    case Name of
 
208
        "megaco" ->
 
209
            #'Message'{version = Version, mId = MID, messageBody = Body};
 
210
        [$!]  ->
 
211
            #'Message'{version = Version, mId = MID, messageBody = Body}
 
212
    end.
 
213
 
 
214
 
 
215
%% Corr1:
 
216
%% As of corr 1 ModemDescriptor has been deprecated.
 
217
%% and since this functon is only used when creating
 
218
%% a ModemDescriptor, iit is removed.
 
219
%% modemType         = (V32bisToken / V22bisToken / V18Token / 
 
220
%%                      V22Token / V32Token / V34Token / V90Token / 
 
221
%%                      V91Token / SynchISDNToken / extensionParameter)
 
222
%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
 
223
%%     case Text of
 
224
%%         "v32b"      -> v32bis;
 
225
%%         "v22b"      -> v22bis;
 
226
%%         "v18"       -> v18;
 
227
%%         "v22"       -> v22;
 
228
%%         "v32"       -> v32;
 
229
%%         "v34"       -> v34;
 
230
%%         "v90"       -> v90;
 
231
%%         "v91"       -> v91;
 
232
%%         "synchisdn" -> synchISDN;
 
233
%%         "sn"        -> synchISDN;
 
234
%%         [$x | _]               -> ensure_extensionParameter(Token)
 
235
%%     end.
 
236
 
 
237
%% An mtp address is five octets long
 
238
ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
 
239
    %% BUGBUG: validate address
 
240
    {mtpAddress, Addr}.
 
241
 
 
242
%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
 
243
ensure_muxType({_TokenTag, _Line, Text} = Token) ->
 
244
    case Text of
 
245
        "h221"  -> h221;
 
246
        "h223"  -> h223;
 
247
        "h226"  -> h226;
 
248
        "v76"   -> v76;
 
249
        "nx64k" -> nx64k; % v2
 
250
        [$x | _]          -> ensure_extensionParameter(Token)
 
251
    end.
 
252
 
 
253
%% packagesItem      = NAME "-" UINT16
 
254
%% NAME              = ALPHA *63(ALPHA / DIGIT / "_" )
 
255
ensure_packagesItem({TokenTag, Line, Text}) ->
 
256
    case string:tokens(Text, [$-]) of
 
257
        [Name, Version] ->
 
258
            #'PackagesItem'{packageName    = ensure_NAME({TokenTag, Line, Name}),
 
259
                            packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
 
260
        _ ->
 
261
            return_error(Line, {bad_PackagesItem, Text})
 
262
    end.
 
263
 
 
264
%% pkgdName          =  (PackageName / "*")  SLASH  (ItemID / "*" )
 
265
%% PackageName       = NAME
 
266
%% ItemID            = NAME
 
267
ensure_pkgdName({TokenTag, Line, Text}) ->
 
268
    case string:tokens(Text, [$/]) of
 
269
        [Name, Item] ->
 
270
            ensure_name_or_star({TokenTag, Line, Name}),
 
271
            ensure_name_or_star({TokenTag, Line, Item}),
 
272
            Text;
 
273
        _ ->
 
274
            return_error(Line, {bad_pkgdName, Text})
 
275
    end.
 
276
 
 
277
ensure_name_or_star({_, _, Name}) when Name == "*" ->
 
278
    Name;
 
279
ensure_name_or_star(Name) ->
 
280
    ensure_NAME(Name).
 
281
 
 
282
 
 
283
 
 
284
%% v2 - start
 
285
 
 
286
merge_indAudMediaDescriptor(Vals) ->
 
287
%%     d("merge_indAudMediaDescriptor -> entry with"
 
288
%%       "~n   Vals: ~p", [Vals]),
 
289
    merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}).
 
290
 
 
291
merge_indAudMediaDescriptor(
 
292
  [], #'IndAudMediaDescriptor'{streams = Streams1} = D) ->
 
293
%%     d("merge_indAudMediaDescriptor -> entry with"
 
294
%%       "~n   Streams1: ~p"
 
295
%%       "~n   D:        ~p", [Streams1, D]),
 
296
    Streams2 = 
 
297
        case Streams1 of
 
298
            {multiStream, Descs} ->
 
299
                {multiStream, lists:reverse(Descs)};
 
300
            _ ->
 
301
                Streams1
 
302
        end,
 
303
    D#'IndAudMediaDescriptor'{streams = Streams2};
 
304
merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D) 
 
305
  when D#'IndAudMediaDescriptor'.termStateDescr == asn1_NOVALUE ->
 
306
%%     d("merge_indAudMediaDescriptor(termStateDescr) -> entry with"
 
307
%%       "~n   Val: ~p"
 
308
%%       "~n   D:   ~p", [Val, D]),
 
309
    D2 = #'IndAudMediaDescriptor'{termStateDescr = Val},
 
310
    merge_indAudMediaDescriptor(Vals, D2);
 
311
merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D)  
 
312
  when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
 
313
%%     d("merge_indAudMediaDescriptor(streamParm) -> entry with"
 
314
%%       "~n   Val: ~p"
 
315
%%       "~n   D:   ~p", [Val, D]),
 
316
    D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}},
 
317
    merge_indAudMediaDescriptor(Vals, D2);
 
318
merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D)  
 
319
  when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
 
320
%%     d("merge_indAudMediaDescriptor(streamDescr) -> entry with"
 
321
%%       "~n   Val: ~p"
 
322
%%       "~n   D:   ~p", [Val, D]),
 
323
    D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}},
 
324
    merge_indAudMediaDescriptor(Vals, D2);
 
325
merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], 
 
326
  #'IndAudMediaDescriptor'{streams = Streams1} = D1) ->
 
327
%%     d("merge_indAudMediaDescriptor() -> entry with"
 
328
%%       "~n   Val:      ~p"
 
329
%%       "~n   Streams1: ~p"
 
330
%%       "~n   D1:       ~p", [Val, Streams1, D1]),
 
331
    Streams2 = 
 
332
        case Streams1 of
 
333
            {multiStream, Descs} ->
 
334
                {multiStream, [Val|Descs]};
 
335
            _ ->
 
336
                return_error(0, {bad_IndAudMediaDescriptor_streamDescr, 
 
337
                                 Val, Streams1})
 
338
        end,
 
339
    D2 = D1#'IndAudMediaDescriptor'{streams = Streams2},
 
340
    merge_indAudMediaDescriptor(Vals, D2);
 
341
merge_indAudMediaDescriptor([{Tag, Val}|_], D) ->
 
342
%%     d("merge_indAudMediaDescriptor -> entry with"
 
343
%%       "~n   Tag: ~p"
 
344
%%       "~n   Val: ~p"
 
345
%%       "~n   D:   ~p", [Tag, Val, D]),
 
346
    case Tag of
 
347
        termStateDescr ->
 
348
            return_error(0, {bad_IndAudMediaDescriptor_termStateDescr, 
 
349
                             Val, D#'IndAudMediaDescriptor'.termStateDescr});
 
350
        streamParm ->
 
351
            return_error(0, {bad_IndAudMediaDescriptor_streamParm, 
 
352
                             Val, D#'IndAudMediaDescriptor'.streams});
 
353
        streamDescr ->
 
354
            return_error(0, {bad_IndAudMediaDescriptor_streamDescr, 
 
355
                             Val, D#'IndAudMediaDescriptor'.streams});
 
356
        _ ->
 
357
            return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val})
 
358
    end.
 
359
 
 
360
merge_indAudLocalControlDescriptor(Parms) ->
 
361
    merge_indAudLocalControlDescriptor(Parms, 
 
362
                                          #'IndAudLocalControlDescriptor'{},
 
363
                                          asn1_NOVALUE).
 
364
                                          
 
365
merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) 
 
366
  when (D#'IndAudLocalControlDescriptor'.streamMode    == asn1_NOVALUE) and 
 
367
       (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
 
368
%%     d("merge_indAudLocalControlDescriptor(modeToken,1) -> entry when"
 
369
%%       "~n   D:  ~p"
 
370
%%       "~n   PP: ~p", [D, PP]),
 
371
    D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
 
372
    merge_indAudLocalControlDescriptor(Parms, D2, PP);
 
373
 
 
374
merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP) 
 
375
  when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) ->
 
376
%%     d("merge_indAudLocalControlDescriptor(modeToken,2) -> entry when"
 
377
%%       "~n   D:  ~p"
 
378
%%       "~n   PP: ~p", [D, PP]),
 
379
    merge_indAudLocalControlDescriptor(Parms, D, PP);
 
380
 
 
381
merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) 
 
382
  when (D#'IndAudLocalControlDescriptor'.streamMode    == asn1_NOVALUE) and 
 
383
       (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
 
384
%%     d("merge_indAudLocalControlDescriptor(mode,1) -> entry when"
 
385
%%       "~n   Val: ~p"
 
386
%%       "~n   D:   ~p"
 
387
%%       "~n   PP:  ~p", [Val, D, PP]),
 
388
    D2 = 
 
389
        case Val of
 
390
            {equal, Val2} ->
 
391
                D#'IndAudLocalControlDescriptor'{streamModeSel = Val2};
 
392
            {inequal, Val2} ->
 
393
                D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}
 
394
        end,
 
395
    merge_indAudLocalControlDescriptor(Parms, D2, PP);
 
396
 
 
397
merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP) 
 
398
  when (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
 
399
%%     d("merge_indAudLocalControlDescriptor(mode,2) -> entry when"
 
400
%%       "~n   Val: ~p"
 
401
%%       "~n   D:   ~p"
 
402
%%       "~n   PP:  ~p", [Val, D, PP]),
 
403
    D2 = 
 
404
        case Val of
 
405
            {equal, Val2} ->
 
406
                D#'IndAudLocalControlDescriptor'{streamMode    = asn1_NOVALUE,
 
407
                                                 streamModeSel = Val2};
 
408
            {inequal, Val2} ->
 
409
                D#'IndAudLocalControlDescriptor'{streamMode    = asn1_NOVALUE,
 
410
                                                 streamModeSel = Val2}
 
411
        end,
 
412
    merge_indAudLocalControlDescriptor(Parms, D2, PP);
 
413
 
 
414
merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP) 
 
415
  when D#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
 
416
%%     d("merge_indAudLocalControlDescriptor(reservedGroupToken) -> entry when"
 
417
%%       "~n   D:  ~p"
 
418
%%       "~n   PP: ~p", [D, PP]),
 
419
    D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
 
420
    merge_indAudLocalControlDescriptor(Parms, D2, PP);
 
421
 
 
422
merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP) 
 
423
  when D#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
 
424
%%     d("merge_indAudLocalControlDescriptor(reservedValueToken) -> entry when"
 
425
%%       "~n   D:  ~p"
 
426
%%       "~n   PP: ~p", [D, PP]),
 
427
    D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
 
428
    merge_indAudLocalControlDescriptor(Parms, D2, PP);
 
429
 
 
430
%% This is really wierd in the standard, so at this point this is the
 
431
%% best I can do...  BUGBUG BUGBUG BUGBUG
 
432
%% 
 
433
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) ->
 
434
%%     d("merge_indAudLocalControlDescriptor(name) -> entry when"
 
435
%%       "~n   Val: ~p"
 
436
%%       "~n   D:   ~p", [Val, D]),
 
437
    PP = #'IndAudPropertyParm'{name = Val},
 
438
    merge_indAudLocalControlDescriptor(Parms, D, PP);
 
439
 
 
440
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) 
 
441
  when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
 
442
%%     d("merge_indAudLocalControlDescriptor(name) -> entry when"
 
443
%%       "~n   Val: ~p"
 
444
%%       "~n   D:   ~p", [Val, D]),
 
445
    D2  = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]},
 
446
    PP2 = #'IndAudPropertyParm'{name = Val},
 
447
    merge_indAudLocalControlDescriptor(Parms, D2, PP2);
 
448
 
 
449
merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) ->
 
450
%%     d("merge_indAudLocalControlDescriptor(name) -> entry when"
 
451
%%       "~n   Val: ~p"
 
452
%%       "~n   D:   ~p", [Val, D]),
 
453
    PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
 
454
    D2  = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]},
 
455
    PP2 = #'IndAudPropertyParm'{name = Val},
 
456
    merge_indAudLocalControlDescriptor(Parms, D2, PP2);
 
457
 
 
458
%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with
 
459
%% just the prop (the mandatory name part is missing), so for now I
 
460
%% assume that it this has been used, then the name part
 
461
%% (pkgdName) must precide it? 
 
462
merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) 
 
463
  when (PP =/= asn1_NOVALUE) and 
 
464
       (D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE) ->
 
465
%%     d("merge_indAudLocalControlDescriptor(prop,1) -> entry when"
 
466
%%       "~n   Val: ~p"
 
467
%%       "~n   D:   ~p"
 
468
%%       "~n   PP:  ~p", [Val, D, PP]),
 
469
    PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
 
470
    D2  = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]},
 
471
    merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
 
472
 
 
473
merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP) 
 
474
  when (PP =/= asn1_NOVALUE) and 
 
475
       is_list(D#'IndAudLocalControlDescriptor'.propertyParms) ->
 
476
%%     d("merge_indAudLocalControlDescriptor(prop,2) -> entry when"
 
477
%%       "~n   Val: ~p"
 
478
%%       "~n   D:   ~p"
 
479
%%       "~n   PP:  ~p", [Val, D, PP]),
 
480
    PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
 
481
    PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
 
482
    D2  = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]},
 
483
    merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
 
484
 
 
485
merge_indAudLocalControlDescriptor([H | _T], _D, _PP) ->
 
486
    return_error(0, {bad_indAudLocalControlDescriptor_parm, H});
 
487
 
 
488
merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) 
 
489
  when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
 
490
%%     d("merge_indAudLocalControlDescriptor -> entry when done with"
 
491
%%       "~n   D:  ~p", [D]),
 
492
    D;
 
493
merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) ->
 
494
%%     d("merge_indAudLocalControlDescriptor -> entry when done with"
 
495
%%       "~n   D:  ~p", [D]),
 
496
    PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
 
497
    PropParms2 = lists:reverse(PPs),
 
498
    D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
 
499
merge_indAudLocalControlDescriptor([], D, PP) 
 
500
  when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
 
501
%%     d("merge_indAudLocalControlDescriptor -> entry when done with"
 
502
%%       "~n   D:  ~p"
 
503
%%       "~n   PP: ~p", [D, PP]),
 
504
    D#'IndAudLocalControlDescriptor'{propertyParms = [PP]};
 
505
merge_indAudLocalControlDescriptor([], D, PP) ->
 
506
%%     d("merge_indAudLocalControlDescriptor -> entry when done with"
 
507
%%       "~n   D:  ~p"
 
508
%%       "~n   PP: ~p", [D, PP]),
 
509
    PPs  = D#'IndAudLocalControlDescriptor'.propertyParms,
 
510
    PPs2 = lists:reverse([PP|PPs]),
 
511
    D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}.
 
512
 
 
513
 
 
514
merge_indAudTerminationStateDescriptor({name, Val}) ->
 
515
    PropParm = #'IndAudPropertyParm'{name = Val},
 
516
    #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
 
517
%% BUGBUG BUGBUG BUGBUG
 
518
merge_indAudTerminationStateDescriptor({prop, Val}) ->
 
519
    exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val});
 
520
merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
 
521
    #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
 
522
merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) ->
 
523
    #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
 
524
merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) ->
 
525
    #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
 
526
merge_indAudTerminationStateDescriptor(bufferToken) ->
 
527
    #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
 
528
 
 
529
 
 
530
merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
 
531
    IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
 
532
    do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
 
533
 
 
534
do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
 
535
    IAEBD;
 
536
do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
 
537
    IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
 
538
do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, 
 
539
                                     IAEBD) ->
 
540
    %% BUGBUG BUGBUG BUGBUG 
 
541
    %% This is an ugly hack to allow the eventParamName which only
 
542
    %% exists in the text encoding...
 
543
    IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
 
544
 
 
545
 
 
546
ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
 
547
    ensure_indAudSignal(SIG).
 
548
 
 
549
ensure_indAudSignal(#'Signal'{signalName       = SignalName,
 
550
                              streamID         = SID, 
 
551
                              sigType          = asn1_NOVALUE, 
 
552
                              duration         = asn1_NOVALUE, 
 
553
                              notifyCompletion = asn1_NOVALUE, 
 
554
                              keepActive       = asn1_NOVALUE, 
 
555
                              sigParList       = [],
 
556
                              requestID        = RID}) ->
 
557
    #'IndAudSignal'{signalName      = SignalName,
 
558
                    streamID        = SID,
 
559
                    signalRequestID = RID}.
 
560
    
 
561
 
 
562
ensure_IADMD({_TokenTag, _Line, 
 
563
              #'DigitMapDescriptor'{digitMapName  = Name,
 
564
                                    digitMapValue = asn1_NOVALUE}}) ->
 
565
    #'IndAudDigitMapDescriptor'{digitMapName = Name}.
 
566
 
 
567
 
 
568
merge_indAudPackagesDescriptor(#'PackagesItem'{packageName    = N,
 
569
                                               packageVersion = V}) ->
 
570
    #'IndAudPackagesDescriptor'{packageName    = N,
 
571
                                packageVersion = V}.
 
572
 
 
573
 
 
574
%% ensure_indAudTerminationStateParm(Token) ->
 
575
%%     case Token of
 
576
%%      {safeToken, _Line, "servicestates"} -> serviceStatesToken;
 
577
%%      {safeToken, _Line, "si"}            -> serviceStatesToken;
 
578
%%      {safeToken, _Line, "buffer"}        -> bufferToken;
 
579
%%      {safeToken, _Line, "bf"}            -> bufferToken;
 
580
%%      PkgdName                            -> {pkgdName,
 
581
%%                                              ensure_pkgdName(PkgdName)}
 
582
%%     end.
 
583
 
 
584
 
 
585
%% Types modified by v2:
 
586
 
 
587
merge_auditDescriptor([]) ->
 
588
    #'AuditDescriptor'{};
 
589
merge_auditDescriptor(Tokens) when list(Tokens) ->
 
590
    case lists:keysearch(terminationAudit, 1, Tokens) of
 
591
        {value, {terminationAudit, TA}} ->
 
592
            case lists:keydelete(terminationAudit, 1, Tokens) of
 
593
                [] ->
 
594
                    #'AuditDescriptor'{auditPropertyToken = TA};
 
595
                AuditTokens ->
 
596
                    #'AuditDescriptor'{auditToken         = AuditTokens,
 
597
                                       auditPropertyToken = TA}
 
598
            end;
 
599
        false ->
 
600
            #'AuditDescriptor'{auditToken = Tokens}
 
601
    end;
 
602
merge_auditDescriptor(_) ->
 
603
    #'AuditDescriptor'{}.
 
604
 
 
605
 
 
606
%% v2 - end
 
607
 
 
608
 
 
609
 
 
610
merge_ServiceChangeParm(Parms) ->
 
611
    Required = [serviceChangeReason, serviceChangeMethod],
 
612
    merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
 
613
 
 
614
merge_ServiceChangeParm([], SCP, []) ->
 
615
    SCP;
 
616
 
 
617
merge_ServiceChangeParm([], _SCP, Required) ->
 
618
    exit({missing_required_serviceChangeParm, Required});
 
619
 
 
620
merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req) 
 
621
  when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
 
622
       SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
 
623
    SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
 
624
    merge_ServiceChangeParm(Parms, SCP, Req);
 
625
merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req) 
 
626
  when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
 
627
    MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
 
628
    exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
 
629
 
 
630
merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req) 
 
631
  when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
 
632
       SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
 
633
    SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
 
634
    merge_ServiceChangeParm(Parms, SCP, Req);
 
635
merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req) 
 
636
  when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
 
637
    Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
 
638
    exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
 
639
 
 
640
merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req) 
 
641
  when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
 
642
    SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
 
643
    merge_ServiceChangeParm(Parms, SCP, Req);
 
644
 
 
645
merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req) 
 
646
  when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
 
647
    SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
 
648
    merge_ServiceChangeParm(Parms, SCP, Req);
 
649
 
 
650
%% REQUIRED (i.e. no default value)
 
651
merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0) 
 
652
  when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
 
653
    SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
 
654
    Req = lists:delete(serviceChangeReason, Req0),
 
655
    merge_ServiceChangeParm(Parms, SCP, Req);
 
656
 
 
657
merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req) 
 
658
  when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
 
659
    SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
 
660
    merge_ServiceChangeParm(Parms, SCP, Req);
 
661
 
 
662
%% REQUIRED (i.e. no default value)
 
663
merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0) 
 
664
  when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
 
665
    SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
 
666
    Req = lists:delete(serviceChangeMethod, Req0),
 
667
    merge_ServiceChangeParm(Parms, SCP, Req);
 
668
 
 
669
merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req) 
 
670
  when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
 
671
    SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
 
672
    merge_ServiceChangeParm(Parms, SCP, Req);
 
673
 
 
674
merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
 
675
    merge_ServiceChangeParm(Parms, SCP0, Req);
 
676
 
 
677
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) 
 
678
  when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE, atom(Val) ->
 
679
    SCI = #'AuditDescriptor'{auditToken = [Val]},
 
680
    SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
 
681
    merge_ServiceChangeParm(Parms, SCP, Req);
 
682
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) 
 
683
  when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE,tuple(Val) ->
 
684
    SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
 
685
    SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
 
686
    merge_ServiceChangeParm(Parms, SCP, Req);
 
687
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) 
 
688
  when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
 
689
       atom(Val) ->
 
690
    SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
 
691
    L    = SCI0#'AuditDescriptor'.auditToken,
 
692
    SCI  = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
 
693
    SCP  = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
 
694
    merge_ServiceChangeParm(Parms, SCP, Req);
 
695
merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req) 
 
696
  when record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor'),
 
697
       tuple(Val) ->
 
698
    SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
 
699
    L    = SCI0#'AuditDescriptor'.auditPropertyToken,
 
700
    SCI  = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
 
701
    SCP  = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
 
702
    merge_ServiceChangeParm(Parms, SCP, Req);
 
703
 
 
704
merge_ServiceChangeParm([incomplete|Parms], SCP0, Req) 
 
705
  when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
 
706
    SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
 
707
    merge_ServiceChangeParm(Parms, SCP, Req);
 
708
 
 
709
merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
 
710
    Val2 = 
 
711
        case Tag of
 
712
            address -> 
 
713
                SCP#'ServiceChangeParm'.serviceChangeAddress;
 
714
            mgc_id     -> 
 
715
                SCP#'ServiceChangeParm'.serviceChangeMgcId;
 
716
            profile    -> 
 
717
                SCP#'ServiceChangeParm'.serviceChangeProfile;
 
718
            version    -> 
 
719
                SCP#'ServiceChangeParm'.serviceChangeVersion;
 
720
            reason     -> 
 
721
                SCP#'ServiceChangeParm'.serviceChangeReason;
 
722
            delay      -> 
 
723
                SCP#'ServiceChangeParm'.serviceChangeDelay;
 
724
            method     -> 
 
725
                SCP#'ServiceChangeParm'.serviceChangeMethod;
 
726
            time_stamp -> 
 
727
                SCP#'ServiceChangeParm'.timeStamp;
 
728
            audit_item -> 
 
729
                SCP#'ServiceChangeParm'.serviceChangeInfo
 
730
        end,
 
731
    exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
 
732
merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
 
733
    Parm2 = 
 
734
        case Parm of
 
735
            incomplete -> 
 
736
                SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
 
737
        end,
 
738
    exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
 
739
 
 
740
 
 
741
merge_ServiceChangeResParm(Parms) ->
 
742
    merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
 
743
 
 
744
merge_ServiceChangeResParm([], SCRP) ->
 
745
    SCRP;
 
746
merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0) 
 
747
  when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
 
748
       SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
 
749
    SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
 
750
    merge_ServiceChangeResParm(Parms, SCRP);
 
751
merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0) 
 
752
  when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
 
753
    MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
 
754
    exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
 
755
 
 
756
merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
 
757
  when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
 
758
       SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE -> 
 
759
    SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
 
760
    merge_ServiceChangeResParm(Parms, SCRP);
 
761
merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
 
762
  when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE -> 
 
763
    Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
 
764
    exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
 
765
 
 
766
merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
 
767
  when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
 
768
    SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
 
769
    merge_ServiceChangeResParm(Parms, SCRP);
 
770
 
 
771
merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
 
772
  when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
 
773
    SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
 
774
    merge_ServiceChangeResParm(Parms, SCRP);
 
775
 
 
776
merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
 
777
  when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
 
778
    SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
 
779
    merge_ServiceChangeResParm(Parms, SCRP);
 
780
 
 
781
merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
 
782
    Val2 = 
 
783
        case Tag of
 
784
            address    -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
 
785
            mgc_id     -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
 
786
            profile    -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
 
787
            version    -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
 
788
            time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
 
789
        end,
 
790
    exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
 
791
 
 
792
 
 
793
ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
 
794
    failover;
 
795
ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
 
796
    failover;
 
797
ensure_serviceChangeMethod({safeToken, _Line, "fo"}) -> 
 
798
    forced;
 
799
ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
 
800
    forced;
 
801
ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
 
802
    graceful;
 
803
ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
 
804
    graceful;
 
805
ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
 
806
    restart;
 
807
ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
 
808
    restart;
 
809
ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
 
810
    disconnected;
 
811
ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
 
812
    disconnected;
 
813
ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
 
814
    handOff;
 
815
ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
 
816
    handOff;
 
817
ensure_serviceChangeMethod({safeToken, Line, Text}) ->
 
818
    return_error(Line, {bad_serviceChangeMethod, Text}).
 
819
 
 
820
 
 
821
merge_topologyDescriptor(Components) ->
 
822
    merge_topologyDescriptor(Components, #'TopologyRequest'{}, []).
 
823
 
 
824
merge_topologyDescriptor([], TR, TRs) ->
 
825
    lists:reverse([ensure_TopologyRequest(TR)|TRs]);
 
826
merge_topologyDescriptor(
 
827
  [{tid, From}|Comps], 
 
828
  #'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) ->
 
829
%%     d("merge_topologyDescriptor(1) -> entry with"
 
830
%%       "~n   From: ~p"
 
831
%%       "~n   TR1:  ~p", [From, TR1]),
 
832
    TR2 = TR1#'TopologyRequest'{terminationFrom = From},
 
833
    merge_topologyDescriptor(Comps, TR2, TRs);
 
834
merge_topologyDescriptor(
 
835
  [{tid, To}|Comps], 
 
836
  #'TopologyRequest'{terminationTo = undefined} = TR1, 
 
837
  TRs) ->
 
838
%%     d("merge_topologyDescriptor(2) -> entry with"
 
839
%%       "~n   To:  ~p"
 
840
%%       "~n   TR1: ~p", [To, TR1]),
 
841
    TR2 = TR1#'TopologyRequest'{terminationTo = To},
 
842
    merge_topologyDescriptor(Comps, TR2, TRs);
 
843
merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) ->
 
844
%%     d("merge_topologyDescriptor(3) -> entry with"
 
845
%%       "~n   From: ~p"
 
846
%%       "~n   TR1:  ~p", [From, TR1]),
 
847
    TR2 = #'TopologyRequest'{terminationFrom = From},
 
848
    merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]);
 
849
merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) ->
 
850
%%     d("merge_topologyDescriptor -> entry with"
 
851
%%       "~n   Dir: ~p"
 
852
%%       "~n   TR1: ~p", [Dir, TR1]),
 
853
    TR2 = TR1#'TopologyRequest'{topologyDirection = Dir},
 
854
    merge_topologyDescriptor(Comps, TR2, TRs);
 
855
merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) ->
 
856
%%     d("merge_topologyDescriptor -> entry with"
 
857
%%       "~n   SID: ~p"
 
858
%%       "~n   TR1: ~p", [SID, TR1]),
 
859
    TR2 = TR1#'TopologyRequest'{streamID = SID},
 
860
    merge_topologyDescriptor(Comps, TR2, TRs);
 
861
merge_topologyDescriptor(
 
862
  [{direction_ext, EDir}|Comps], 
 
863
  #'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) ->
 
864
%%     d("merge_topologyDescriptor -> entry with"
 
865
%%       "~n   EDir: ~p"
 
866
%%       "~n   TR1:  ~p", [EDir, TR1]),
 
867
    TR2 = TR1#'TopologyRequest'{topologyDirection          = oneway,
 
868
                                topologyDirectionExtension = EDir},
 
869
    merge_topologyDescriptor(Comps, TR2, TRs);
 
870
merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) ->
 
871
%%     d("merge_topologyDescriptor -> entry with"
 
872
%%       "~n   EDir: ~p"
 
873
%%       "~n   TR1:  ~p", [EDir, TR1]),
 
874
    TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir},
 
875
    merge_topologyDescriptor(Comps, TR2, TRs);
 
876
merge_topologyDescriptor(Comps, TR, TRs) ->
 
877
%%     d("merge_topologyDescriptor -> entry with"
 
878
%%       "~n   Comps: ~p"
 
879
%%       "~n   TR:    ~p"
 
880
%%       "~n   TRs:   ~p", [Comps, TR, TRs]),
 
881
    return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}).
 
882
 
 
883
 
 
884
%% merge_topologyDescriptor([{tid,       From}, 
 
885
%%                        {tid,       To},
 
886
%%                        {direction, Dir},
 
887
%%                        {sid,       SID}|Comps], TRs) ->
 
888
%%     d("merge_topologyDescriptor -> entry with"
 
889
%%       "~n   From: ~p"
 
890
%%       "~n   To:   ~p"
 
891
%%       "~n   Dir:  ~p"
 
892
%%       "~n   SID:  ~p", [From, To, Dir, SID]),
 
893
%%     TR = make_TopologyRequest(From, To, Dir, SID),
 
894
%%     merge_topologyDescriptor(Comps, [TR | TRs]);
 
895
%% merge_topologyDescriptor([{tid,       From}, 
 
896
%%                        {tid,       To},
 
897
%%                        {direction, Dir}|Comps], TRs) ->
 
898
%%     d("merge_topologyDescriptor -> entry with"
 
899
%%       "~n   From: ~p"
 
900
%%       "~n   To:   ~p"
 
901
%%       "~n   Dir:  ~p", [From, To, Dir]),
 
902
%%     TR = make_TopologyRequest(From, To, Dir),
 
903
%%     merge_topologyDescriptor(Comps, [TR | TRs]);
 
904
%% merge_topologyDescriptor(Comps, TRs) ->
 
905
%%     d("merge_topologyDescriptor -> entry with"
 
906
%%       "~n   Comps: ~p"
 
907
%%       "~n   TRs:   ~p", [Comps, TRs]),
 
908
%%     return_error(0, {bad_topologyDescriptor, Comps, TRs}).
 
909
 
 
910
 
 
911
ensure_TopologyRequest(#'TopologyRequest'{terminationFrom   = From,
 
912
                                          terminationTo     = To,
 
913
                                          topologyDirection = Dir} = R)
 
914
  when (From =/= asn1_NOVALUE) and
 
915
       (To   =/= asn1_NOVALUE) and
 
916
       (Dir  =/= asn1_NOVALUE) ->
 
917
    R;
 
918
ensure_TopologyRequest(R) ->
 
919
    return_error(0, {bad_TopologyRequest, R}).
 
920
 
 
921
       
 
922
%% make_TopologyRequest(From, To, Dir, SID) ->
 
923
%%     TR = #'TopologyRequest'{terminationFrom = From,
 
924
%%                          terminationTo   = To,
 
925
%%                          streamID        = SID},
 
926
%%     make_TopologyRequest(TR, Dir).
 
927
 
 
928
%% make_TopologyRequest(From, To, Dir) ->
 
929
%%     TR = #'TopologyRequest'{terminationFrom = From,
 
930
%%                          terminationTo   = To},
 
931
%%     make_TopologyRequest(TR, Dir).
 
932
 
 
933
%% make_TopologyRequest(TR, bothway = Dir) ->
 
934
%%     TR#'TopologyRequest'{topologyDirection = Dir};
 
935
%% make_TopologyRequest(TR, isolate = Dir) ->
 
936
%%     TR#'TopologyRequest'{topologyDirection = Dir};
 
937
%% make_TopologyRequest(TR, oneway = Dir) ->
 
938
%%     TR#'TopologyRequest'{topologyDirection = Dir};
 
939
%% make_TopologyRequest(TR, onewayexternal = Dir) ->
 
940
%%     TR#'TopologyRequest'{topologyDirection          = oneway,
 
941
%%                       topologyDirectionExtension = Dir};
 
942
%% make_TopologyRequest(TR, onewayboth = Dir) ->
 
943
%%     TR#'TopologyRequest'{topologyDirection          = oneway,
 
944
%%                       topologyDirectionExtension = Dir}.
 
945
 
 
946
ensure_profile({_TokenTag, Line, Text}) ->
 
947
    case string:tokens(Text, [$/]) of
 
948
        [Name, Version] ->
 
949
            Version2 = ensure_version(Version),
 
950
            #'ServiceChangeProfile'{profileName = Name, version = Version2};
 
951
        _ ->
 
952
            return_error(Line, {bad_profile, Text})
 
953
    end.
 
954
 
 
955
ensure_version(Version) ->
 
956
    ensure_uint(Version, 0, 99).
 
957
 
 
958
merge_signalRequest(SignalName, PropertyParms) ->
 
959
%%     d("merge_signalRequest -> entry with"
 
960
%%       "~n   SignalName:    ~p"
 
961
%%       "~n   PropertyParms: ~p", [SignalName, PropertyParms]),
 
962
    Sig = #'Signal'{signalName = SignalName},
 
963
    SPL = [],
 
964
    do_merge_signalRequest(Sig, PropertyParms, SPL).
 
965
 
 
966
do_merge_signalRequest(Sig, [H | T], SPL) ->
 
967
%%     d("do_merge_signalRequest -> entry with"
 
968
%%       "~n   Sig: ~p"
 
969
%%       "~n   H:   ~p"
 
970
%%       "~n   SPL: ~p", [Sig, H, SPL]),
 
971
    case H of
 
972
        {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
 
973
            do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
 
974
        {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
 
975
            do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
 
976
        {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
 
977
            do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
 
978
        {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
 
979
            do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
 
980
        keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE ->
 
981
            do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
 
982
        {other, Name, PP} ->
 
983
            SP = #'SigParameter'{sigParameterName = Name, 
 
984
                                 value            = PP#'PropertyParm'.value,
 
985
                                 extraInfo        = PP#'PropertyParm'.extraInfo},
 
986
            do_merge_signalRequest(Sig, T, [SP | SPL]);
 
987
        {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE ->
 
988
            do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
 
989
        {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE ->
 
990
            do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
 
991
        {intersigDelay, ISD} when Sig#'Signal'.intersigDelay == asn1_NOVALUE ->
 
992
            do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL);
 
993
        _ ->
 
994
            return_error(0, {bad_sigParm, H})
 
995
    end;
 
996
do_merge_signalRequest(Sig, [], SPL) ->
 
997
    Sig#'Signal'{sigParList = lists:reverse(SPL)} .
 
998
 
 
999
%% eventStream = StreamToken EQUAL StreamID
 
1000
%% eventOther  = eventParameterName parmValue
 
1001
select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
 
1002
    {stream, ensure_uint16(Value)};
 
1003
select_stream_or_other("st", Value) ->
 
1004
    {stream, ensure_uint16(Value)};
 
1005
select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
 
1006
    {stream, ensure_uint16(Value)};
 
1007
select_stream_or_other("stream", Value) ->
 
1008
    {stream, ensure_uint16(Value)};
 
1009
select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
 
1010
    EP = #'EventParameter'{eventParameterName = Name,
 
1011
                           value              = Value},
 
1012
    {other, EP}.
 
1013
 
 
1014
ensure_eventDM({_TokenTag, Line, DMD}) 
 
1015
  when record(DMD, 'DigitMapDescriptor') ->
 
1016
    Name = DMD#'DigitMapDescriptor'.digitMapName,
 
1017
    Val  = DMD#'DigitMapDescriptor'.digitMapValue,
 
1018
    if
 
1019
        Name  == asn1_NOVALUE, Val /= asn1_NOVALUE ->
 
1020
            {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
 
1021
            DMV = #'DigitMapValue'{startTimer    = Start, 
 
1022
                                   shortTimer    = Short, 
 
1023
                                   longTimer     = Long, 
 
1024
                                   digitMapBody  = Body,
 
1025
                                   durationTimer = Duration},
 
1026
            {eventDM, {digitMapValue, DMV}};
 
1027
        Name  /= asn1_NOVALUE, Val == asn1_NOVALUE ->
 
1028
            {eventDM, {digitMapName, Name}};
 
1029
        true ->
 
1030
            return_error(Line, {bad_eventDM, DMD})
 
1031
    end.
 
1032
    
 
1033
ensure_DMD({_TokenTag, _Line, DMD}) 
 
1034
  when record(DMD, 'DigitMapDescriptor') ->
 
1035
    Val2 = 
 
1036
        case DMD#'DigitMapDescriptor'.digitMapValue of
 
1037
            %% Note that the values of the digitMapBody and durationTimers
 
1038
            %% are swapped by the scanner (this is done because of a 
 
1039
            %% problem in the flex scanner).
 
1040
            #'DigitMapValue'{durationTimer = Body,
 
1041
                             digitMapBody  = Duration} = DMV ->
 
1042
                %% Convert to version 1 DigitMapValue
 
1043
                DMV#'DigitMapValue'{digitMapBody  = Body,
 
1044
                                    durationTimer = Duration};
 
1045
            Other ->
 
1046
                Other
 
1047
        end,
 
1048
    DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
 
1049
 
 
1050
 
 
1051
merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
 
1052
    StreamId = asn1_NOVALUE,
 
1053
    EPL = [],
 
1054
    do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
 
1055
 
 
1056
do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
 
1057
    do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
 
1058
do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
 
1059
    do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
 
1060
do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
 
1061
    #'ObservedEvent'{eventName    = EventName,
 
1062
                     timeNotation = TimeStamp,
 
1063
                     streamID     = StreamID,
 
1064
                     eventParList = lists:reverse(EPL)}.
 
1065
 
 
1066
merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
 
1067
                         OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
 
1068
    #'EventSpec'{eventName     = OE#'ObservedEvent'.eventName,
 
1069
                 streamID      = OE#'ObservedEvent'.streamID,
 
1070
                 eventParList  = OE#'ObservedEvent'.eventParList};
 
1071
merge_eventSpec(OE) ->
 
1072
    return_error(0, {bad_event_spec, OE}).
 
1073
 
 
1074
make_RegulatedEmbeddedDescriptor({embed, SD, SED}) ->
 
1075
%%     d("make_RegulatedEmbeddedDescriptor(embed) -> entry with"
 
1076
%%       "~n   SD:  ~p"
 
1077
%%       "~n   SED: ~p", [SD, SED]),
 
1078
    #'RegulatedEmbeddedDescriptor'{secondEvent       = SED,
 
1079
                                   signalsDescriptor = SD}.
 
1080
 
 
1081
merge_eventParameters(Params) ->
 
1082
%%     d("merge_eventParameters -> entry with"
 
1083
%%       "~n   Params: ~p", [Params]),
 
1084
    SID  = asn1_NOVALUE,
 
1085
    EPL  = [],
 
1086
    RA   = #'RequestedActions'{},
 
1087
    HasA = no,
 
1088
    do_merge_eventParameters(Params, SID, EPL, RA, HasA) .
 
1089
                                   
 
1090
do_merge_eventParameters([H | T], SID, EPL, RA, HasA) ->
 
1091
%%     d("do_merge_eventParameters -> entry with"
 
1092
%%       "~n   H:    ~p"
 
1093
%%       "~n   SID:  ~p"
 
1094
%%       "~n   EPL:  ~p"
 
1095
%%       "~n   RA:  ~p"
 
1096
%%       "~n   HasA: ~p", [H, SID, EPL, RA, HasA]),
 
1097
    case H of
 
1098
        keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
 
1099
            RA2 = RA#'RequestedActions'{keepActive = true},
 
1100
            do_merge_eventParameters(T, SID, EPL, RA2, yes);
 
1101
        resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor == asn1_NOVALUE ->
 
1102
            RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'},
 
1103
            do_merge_eventParameters(T, SID, EPL, RA2, yes);
 
1104
        {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
 
1105
            RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
 
1106
                                        secondEvent       = SED},
 
1107
            do_merge_eventParameters(T, SID, EPL, RA2, yes);
 
1108
        {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
 
1109
            RA2 = RA#'RequestedActions'{eventDM = DM},
 
1110
            do_merge_eventParameters(T, SID, EPL, RA2, yes);
 
1111
        {stream, NewSID} when SID == asn1_NOVALUE ->
 
1112
            do_merge_eventParameters(T, NewSID, EPL, RA, HasA);
 
1113
        {other, PP} when record(PP, 'PropertyParm') ->
 
1114
            EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
 
1115
                                   value              = PP#'PropertyParm'.value,
 
1116
                                   extraInfo          = PP#'PropertyParm'.extraInfo},
 
1117
            do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
 
1118
        {other, EP} when record(EP, 'EventParameter') ->
 
1119
            do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
 
1120
        {notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour == asn1_NOVALUE ->
 
1121
            RA2 = RA#'RequestedActions'{notifyBehaviour = NB},
 
1122
            do_merge_eventParameters(T, SID, EPL, RA2, yes);
 
1123
        _ ->
 
1124
            return_error(0, {bad_eventParameter, H})
 
1125
    end;
 
1126
do_merge_eventParameters([], SID, EPL, RA, yes) ->
 
1127
    #'RequestedEvent'{streamID    = SID,
 
1128
                      eventAction = RA, 
 
1129
                      evParList   = lists:reverse(EPL)};
 
1130
do_merge_eventParameters([], SID, EPL, _RA, no) ->
 
1131
    #'RequestedEvent'{streamID    = SID,
 
1132
                      eventAction = asn1_NOVALUE, 
 
1133
                      evParList   = lists:reverse(EPL)}.
 
1134
 
 
1135
merge_secondEventParameters(Params) ->
 
1136
%%     d("merge_secondEventParameters -> entry with"
 
1137
%%       "~n   Params: ~p", [Params]),
 
1138
    SID  = asn1_NOVALUE,
 
1139
    EPL  = [],
 
1140
    SRA  = #'SecondRequestedActions'{},
 
1141
    HasA = no,
 
1142
    do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) .
 
1143
                                   
 
1144
do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) ->
 
1145
%%     d("do_merge_secondEventParameters -> entry with"
 
1146
%%       "~n   H:    ~p"
 
1147
%%       "~n   SID:  ~p"
 
1148
%%       "~n   EPL:  ~p"
 
1149
%%       "~n   SRA:  ~p"
 
1150
%%       "~n   HasA: ~p", [H, SID, EPL, SRA, HasA]),
 
1151
    case H of
 
1152
        keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
 
1153
            SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
 
1154
            do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
 
1155
        resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor == asn1_NOVALUE ->
 
1156
            SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'},
 
1157
            do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
 
1158
        {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
 
1159
            SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
 
1160
            do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
 
1161
        {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
 
1162
            SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
 
1163
            do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
 
1164
        {stream, NewSID} when SID == asn1_NOVALUE ->
 
1165
            do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA);
 
1166
        {other, PP} when record(PP, 'PropertyParm') ->
 
1167
            EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
 
1168
                                   value              = PP#'PropertyParm'.value,
 
1169
                                   extraInfo          = PP#'PropertyParm'.extraInfo},
 
1170
            do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
 
1171
        {other, EP} when record(EP, 'EventParameter') ->
 
1172
            do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
 
1173
        {notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour == asn1_NOVALUE ->
 
1174
            SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB},
 
1175
            do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
 
1176
        _ ->
 
1177
            return_error(0, {bad_secondEventParameter, H})
 
1178
    end;
 
1179
do_merge_secondEventParameters([], SID, EPL, SRA, yes) ->
 
1180
    #'SecondRequestedEvent'{streamID    = SID,
 
1181
                            eventAction = SRA, 
 
1182
                            evParList   = lists:reverse(EPL)};
 
1183
do_merge_secondEventParameters([], SID, EPL, _SRA, no) ->
 
1184
    #'SecondRequestedEvent'{streamID    = SID,
 
1185
                            eventAction = asn1_NOVALUE, 
 
1186
                            evParList   = lists:reverse(EPL)}.
 
1187
 
 
1188
%% terminationID     = "ROOT" / pathName / "$" / "*"
 
1189
%% Total length of pathName must not exceed 64 chars.
 
1190
%% pathName          = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
 
1191
%%                     ["@" pathDomainName ]
 
1192
%% ABNF allows two or more consecutive "." although it is meaningless
 
1193
%% in a path domain name.
 
1194
%% pathDomainName    = (ALPHA / DIGIT / "*" )
 
1195
%%                        *63(ALPHA / DIGIT / "-" / "*" / ".")
 
1196
ensure_terminationID({safeToken, _Line, LowerText}) ->
 
1197
    %% terminationID     = "ROOT" / pathName / "$" / "*"
 
1198
    decode_term_id(LowerText, false, [], []).
 
1199
 
 
1200
decode_term_id([H | T], Wild, Id, Component) ->
 
1201
    case H of
 
1202
        $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
 
1203
        $* -> decode_term_id(T, true, Id, [?megaco_all    | Component]);
 
1204
        $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
 
1205
        _  -> decode_term_id(T, Wild, Id, [H | Component])
 
1206
    end;
 
1207
decode_term_id([], Wild, Id, Component) ->
 
1208
    Id2 = [lists:reverse(Component) | Id],
 
1209
    #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
 
1210
            
 
1211
ensure_pathName({_TokenTag, _Line, Text}) ->
 
1212
    Text.  %% BUGBUG: ensure values
 
1213
 
 
1214
%% TimeStamp            = Date "T" Time ; per ISO 8601:1988
 
1215
%% Date                 = 8(DIGIT) ; Date = yyyymmdd
 
1216
%% Time                 = 8(DIGIT) ; Time = hhmmssss
 
1217
ensure_timeStamp({'TimeStampToken', Line, Text}) ->
 
1218
    case string:tokens(Text, [$T, $t]) of
 
1219
        [Date, Time] ->
 
1220
            #'TimeNotation'{date = Date, time = Time};
 
1221
        _ ->
 
1222
            return_error(Line, {bad_timeStamp, Text})
 
1223
    end.
 
1224
 
 
1225
ensure_transactionID(TransId) ->
 
1226
    ensure_uint32(TransId).
 
1227
 
 
1228
%% transactionAck       = transactionID / (transactionID "-" transactionID)
 
1229
ensure_transactionAck({safeToken, _Line, Text}) ->
 
1230
    case string:tokens(Text, [$-]) of
 
1231
        [Id] ->
 
1232
            #'TransactionAck'{firstAck = ensure_transactionID(Id)};
 
1233
        [Id, Id2] ->
 
1234
            #'TransactionAck'{firstAck = ensure_transactionID(Id),
 
1235
                              lastAck  = ensure_transactionID(Id2)}
 
1236
    end.
 
1237
 
 
1238
merge_context_request(asn1_NOVALUE, Prop) ->
 
1239
    merge_context_request(#'ContextRequest'{}, Prop);
 
1240
 
 
1241
merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR, 
 
1242
                      {priority, Int}) ->
 
1243
    CR#'ContextRequest'{priority = Int};
 
1244
 
 
1245
merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR, 
 
1246
                      {emergency, Bool}) ->
 
1247
    CR#'ContextRequest'{emergency = Bool};
 
1248
 
 
1249
merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR, 
 
1250
                      {topology, Desc}) ->
 
1251
    CR#'ContextRequest'{topologyReq = Desc};
 
1252
 
 
1253
merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR, 
 
1254
                      {iepsCallind, Ind}) ->
 
1255
    CR#'ContextRequest'{iepscallind = Ind};
 
1256
 
 
1257
merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
 
1258
                      {contextProp, Props}) ->
 
1259
    CR#'ContextRequest'{contextProp = Props};
 
1260
 
 
1261
merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR, 
 
1262
                      {contextList, IDs}) -> 
 
1263
    CR#'ContextRequest'{contextList = IDs};
 
1264
 
 
1265
merge_context_request(CR, {Tag, Val}) ->
 
1266
    Val2 = 
 
1267
        case Tag of
 
1268
            priority    -> CR#'ContextRequest'.priority;
 
1269
            emergency   -> CR#'ContextRequest'.emergency;
 
1270
            topology    -> CR#'ContextRequest'.topologyReq;
 
1271
            iepsCallind -> CR#'ContextRequest'.iepscallind;
 
1272
            contextProp -> CR#'ContextRequest'.contextProp;
 
1273
            contextList -> CR#'ContextRequest'.contextList
 
1274
        end,
 
1275
    exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
 
1276
            
 
1277
 
 
1278
merge_context_attr_audit_request(
 
1279
  #'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) ->
 
1280
    
 
1281
    CAAR;
 
1282
merge_context_attr_audit_request(
 
1283
  #'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) ->
 
1284
    
 
1285
    CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)};
 
1286
merge_context_attr_audit_request(CAAR, [H|T]) ->
 
1287
    case H of
 
1288
        priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
 
1289
            CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
 
1290
            merge_context_attr_audit_request(CAAR2, T);
 
1291
 
 
1292
        emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
 
1293
            CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
 
1294
            merge_context_attr_audit_request(CAAR2, T);
 
1295
 
 
1296
        topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
 
1297
            CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
 
1298
            merge_context_attr_audit_request(CAAR2, T);
 
1299
 
 
1300
        iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE ->
 
1301
            CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
 
1302
            merge_context_attr_audit_request(CAAR2, T);
 
1303
 
 
1304
        {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
 
1305
            CPA = [#'IndAudPropertyParm'{name = Name}],
 
1306
            CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
 
1307
            merge_context_attr_audit_request(CAAR2, T);
 
1308
 
 
1309
        {prop, Name} ->
 
1310
            CPA   = CAAR#'ContextAttrAuditRequest'.contextPropAud,
 
1311
            CPA2  = [#'IndAudPropertyParm'{name = Name}|CPA],
 
1312
            CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
 
1313
            merge_context_attr_audit_request(CAAR2, T);
 
1314
 
 
1315
        {select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority == asn1_NOVALUE ->
 
1316
            CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio},
 
1317
            merge_context_attr_audit_request(CAAR2, T);
 
1318
 
 
1319
        {select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency == asn1_NOVALUE ->
 
1320
            CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV},
 
1321
            merge_context_attr_audit_request(CAAR2, T);
 
1322
 
 
1323
        {select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind == asn1_NOVALUE ->
 
1324
            CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV},
 
1325
            merge_context_attr_audit_request(CAAR2, T);
 
1326
 
 
1327
        {select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic == asn1_NOVALUE ->
 
1328
            CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL},
 
1329
            merge_context_attr_audit_request(CAAR2, T);
 
1330
 
 
1331
        %% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
 
1332
        %% 
 
1333
        %% For some strange reason, contextAttrDescriptor was added
 
1334
        %% to contextAuditSelector. But there is no place for this
 
1335
        %% info in the ContextAttrAuditRequest. Since contextAttrDescriptor
 
1336
        %% can also be found in contextProperty (which correspond to
 
1337
        %% ContextRequest), the question is if this info should go there
 
1338
        %% or if we shall just drop it. For now we drop it.
 
1339
        %% 
 
1340
        {contextProp, _PPs} ->
 
1341
            merge_context_attr_audit_request(CAAR, T);
 
1342
 
 
1343
        {contextList, _IDs} ->
 
1344
            merge_context_attr_audit_request(CAAR, T);
 
1345
 
 
1346
        _ ->
 
1347
            exit({unexpected_contextAttrAudit_item, H})
 
1348
    
 
1349
    end.
 
1350
 
 
1351
merge_action_request(CtxId, Items) ->
 
1352
    do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
 
1353
 
 
1354
do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
 
1355
    case H of
 
1356
        {commandRequest, CmdReq} ->
 
1357
            do_merge_action_request(T, [CmdReq|CmdReqs], 
 
1358
                                    CtxReq, CtxAuditReq, CtxId);
 
1359
 
 
1360
        {contextProp, ContextProp} ->
 
1361
            do_merge_action_request(T, CmdReqs, 
 
1362
                                    merge_context_request(CtxReq, ContextProp),
 
1363
                                    CtxAuditReq, CtxId);
 
1364
 
 
1365
        {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
 
1366
            do_merge_action_request(T, CmdReqs, 
 
1367
                                    CtxReq, ContextAuditReq, CtxId)
 
1368
    end;
 
1369
do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
 
1370
    #'ActionRequest'{contextId           = CtxId,
 
1371
                     contextRequest      = strip_ContextRequest(CtxReq),
 
1372
                     contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
 
1373
                     commandRequests     = lists:reverse(CmdReqs)}.
 
1374
 
 
1375
 
 
1376
%% OTP-5085: 
 
1377
%% In order to solve a problem in the parser, the error descriptor
 
1378
%% has been put last in the non-empty commandReplyList, if it is not 
 
1379
%% asn1_NOVALUE
 
1380
merge_action_reply(Items) ->
 
1381
    do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
 
1382
 
 
1383
do_merge_action_reply([], Err, Ctx, Cmds) ->
 
1384
    #'ActionReply'{errorDescriptor = Err,
 
1385
                   contextReply    = strip_ContextRequest(Ctx),
 
1386
                   commandReply    = lists:reverse(Cmds)};
 
1387
do_merge_action_reply([H|T], Err0, CR, Cmds) ->
 
1388
    case H of
 
1389
        {error, Err1} when Err0 == asn1_NOVALUE ->
 
1390
            do_merge_action_reply(T, Err1, CR, Cmds);
 
1391
        {command, Cmd} ->
 
1392
            do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
 
1393
        {context, CtxProp} ->
 
1394
            do_merge_action_reply(T, Err0, 
 
1395
                                  merge_context_request(CR, CtxProp), Cmds)
 
1396
    end.
 
1397
 
 
1398
merge_auditOther([TID], TAR) ->
 
1399
    {auditResult, 
 
1400
     #'AuditResult'{terminationID          = TID,
 
1401
                    terminationAuditResult = TAR}};
 
1402
merge_auditOther(TIDs, TAR) ->
 
1403
    {auditResultTermList,
 
1404
     #'TermListAuditResult'{terminationIDList      = TIDs,
 
1405
                            terminationAuditResult = TAR}}.
 
1406
 
 
1407
strip_ContextRequest(#'ContextRequest'{priority    = asn1_NOVALUE,
 
1408
                                       emergency   = asn1_NOVALUE,
 
1409
                                       topologyReq = asn1_NOVALUE,
 
1410
                                       iepscallind = asn1_NOVALUE,
 
1411
                                       contextProp = asn1_NOVALUE,
 
1412
                                       contextList = asn1_NOVALUE}) ->
 
1413
    asn1_NOVALUE;
 
1414
strip_ContextRequest(#'ContextRequest'{priority    = asn1_NOVALUE,
 
1415
                                       emergency   = asn1_NOVALUE,
 
1416
                                       topologyReq = asn1_NOVALUE,
 
1417
                                       iepscallind = asn1_NOVALUE,
 
1418
                                       contextProp = [],
 
1419
                                       contextList = asn1_NOVALUE}) ->
 
1420
    asn1_NOVALUE;
 
1421
%% strip_ContextRequest(asn1_NOVALUE) ->
 
1422
%%     asn1_NOVALUE;
 
1423
strip_ContextRequest(R) ->
 
1424
    R.
 
1425
 
 
1426
strip_ContextAttrAuditRequest(
 
1427
  #'ContextAttrAuditRequest'{priority          = asn1_NOVALUE,
 
1428
                             emergency         = asn1_NOVALUE,
 
1429
                             topology          = asn1_NOVALUE,
 
1430
                             iepscallind       = asn1_NOVALUE,
 
1431
                             contextPropAud    = asn1_NOVALUE,
 
1432
                             selectpriority    = asn1_NOVALUE,
 
1433
                             selectemergency   = asn1_NOVALUE,
 
1434
                             selectiepscallind = asn1_NOVALUE, 
 
1435
                             selectLogic       = asn1_NOVALUE}) ->
 
1436
    asn1_NOVALUE;
 
1437
strip_ContextAttrAuditRequest(
 
1438
  #'ContextAttrAuditRequest'{priority          = asn1_NOVALUE,
 
1439
                             emergency         = asn1_NOVALUE,
 
1440
                             topology          = asn1_NOVALUE,
 
1441
                             iepscallind       = asn1_NOVALUE,
 
1442
                             contextPropAud    = [],
 
1443
                             selectpriority    = asn1_NOVALUE,
 
1444
                             selectemergency   = asn1_NOVALUE,
 
1445
                             selectiepscallind = asn1_NOVALUE, 
 
1446
                             selectLogic       = asn1_NOVALUE}) ->
 
1447
    asn1_NOVALUE;
 
1448
strip_ContextAttrAuditRequest(R) ->
 
1449
    R.
 
1450
 
 
1451
merge_AmmRequest_descriptors([], Acc) ->
 
1452
    lists:reverse(Acc);
 
1453
merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
 
1454
    merge_AmmRequest_descriptors(Descs, Acc);
 
1455
merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
 
1456
    merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
 
1457
 
 
1458
make_auditRequest([TID], AD) ->
 
1459
    #'AuditRequest'{terminationID   = TID,
 
1460
                    auditDescriptor = AD};
 
1461
make_auditRequest([TID|_] = TIDList, AD) ->
 
1462
    #'AuditRequest'{terminationID     = TID,
 
1463
                    auditDescriptor   = AD,
 
1464
                    terminationIDList = TIDList}.
 
1465
    
 
1466
make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
 
1467
    Req = #'CommandRequest'{command  = {CmdTag, Cmd}},
 
1468
    case Text of
 
1469
        [$w, $- | _] ->
 
1470
            Req#'CommandRequest'{wildcardReturn = 'NULL'};
 
1471
        [$o, $-, $w, $- | _] ->
 
1472
            Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
 
1473
        [$o, $- | _] ->
 
1474
            Req#'CommandRequest'{optional = 'NULL'};
 
1475
        _ -> 
 
1476
            Req
 
1477
    end.
 
1478
 
 
1479
merge_terminationAudit(AuditReturnParameters) ->
 
1480
    lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
 
1481
 
 
1482
do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
 
1483
    case H of
 
1484
        {auditReturnItem, AuditItem} ->
 
1485
            do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
 
1486
        AuditReturnParameter ->
 
1487
            do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
 
1488
    end;
 
1489
do_merge_terminationAudit([], AuditReturnParameters, []) ->
 
1490
    AuditReturnParameters;
 
1491
do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
 
1492
    AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
 
1493
    AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
 
1494
    [AuditReturnParameter | AuditReturnParameters].
 
1495
        
 
1496
merge_mediaDescriptor(MediaParms) ->
 
1497
    do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
 
1498
 
 
1499
do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
 
1500
    case H of
 
1501
        {streamParm, Parm} when Multi == [] ->
 
1502
            do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
 
1503
        {streamDescriptor, Desc} when One == [] ->
 
1504
            do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
 
1505
        {termState, TS2} when TS  == asn1_NOVALUE ->
 
1506
            do_merge_mediaDescriptor(T, TS2, One, Multi);
 
1507
        _ ->
 
1508
            return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
 
1509
    end;
 
1510
do_merge_mediaDescriptor([], TS, One, Multi) ->
 
1511
    if
 
1512
        One == [], Multi == [] ->
 
1513
            #'MediaDescriptor'{streams = asn1_NOVALUE,
 
1514
                               termStateDescr = TS};
 
1515
        One /= [], Multi == [] ->
 
1516
            #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
 
1517
                               termStateDescr = TS};
 
1518
        One == [], Multi /= [] ->
 
1519
            #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
 
1520
                               termStateDescr = TS}
 
1521
    end.
 
1522
  
 
1523
merge_streamParms(TaggedStreamParms) ->
 
1524
    SP = #'StreamParms'{},
 
1525
    do_merge_streamParms(TaggedStreamParms, SP).
 
1526
 
 
1527
do_merge_streamParms([{Tag, D} | T] = All, SP) ->
 
1528
    case Tag of
 
1529
        local when SP#'StreamParms'.localDescriptor  == asn1_NOVALUE ->
 
1530
            do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
 
1531
        remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
 
1532
            do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
 
1533
        control ->
 
1534
            LCD = 
 
1535
                case SP#'StreamParms'.localControlDescriptor of
 
1536
                    asn1_NOVALUE ->
 
1537
                        #'LocalControlDescriptor'{propertyParms = []};
 
1538
                    PrevLCD ->
 
1539
                        PrevLCD
 
1540
                end,
 
1541
            LCD2 = do_merge_control_streamParms(D, LCD),
 
1542
            do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
 
1543
        statistics when SP#'StreamParms'.statisticsDescriptor == asn1_NOVALUE ->
 
1544
            do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
 
1545
        _ ->
 
1546
            return_error(0, {do_merge_streamParms, [All, SP]})
 
1547
    end;
 
1548
do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
 
1549
    LCD  = SP#'StreamParms'.localControlDescriptor,
 
1550
    PP   = LCD#'LocalControlDescriptor'.propertyParms,
 
1551
    LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
 
1552
    SP#'StreamParms'{localControlDescriptor = LCD2};
 
1553
do_merge_streamParms([], SP) ->
 
1554
    SP.
 
1555
 
 
1556
 
 
1557
do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
 
1558
    case SubTag of
 
1559
        group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
 
1560
            LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
 
1561
            do_merge_control_streamParms(T, LCD2);
 
1562
        value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
 
1563
            LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
 
1564
            do_merge_control_streamParms(T, LCD2);
 
1565
        mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
 
1566
            LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
 
1567
            do_merge_control_streamParms(T, LCD2);
 
1568
        prop ->
 
1569
            PP = LCD#'LocalControlDescriptor'.propertyParms,
 
1570
            LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
 
1571
            do_merge_control_streamParms(T, LCD2);
 
1572
        _ ->
 
1573
            return_error(0, {do_merge_control_streamParms, [All, LCD]})
 
1574
  end;
 
1575
do_merge_control_streamParms([], LCD) ->
 
1576
    LCD.
 
1577
 
 
1578
merge_terminationStateDescriptor(Parms) ->
 
1579
    TSD = #'TerminationStateDescriptor'{propertyParms = []},
 
1580
    do_merge_terminationStateDescriptor(Parms, TSD).
 
1581
 
 
1582
do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
 
1583
    case Tag of
 
1584
        serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
 
1585
            TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
 
1586
            do_merge_terminationStateDescriptor(T, TSD2);
 
1587
        eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
 
1588
            TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
 
1589
            do_merge_terminationStateDescriptor(T, TSD2);
 
1590
        propertyParm ->
 
1591
            PP = TSD#'TerminationStateDescriptor'.propertyParms,
 
1592
            TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
 
1593
            do_merge_terminationStateDescriptor(T, TSD2)
 
1594
    end;
 
1595
do_merge_terminationStateDescriptor([], TSD) ->
 
1596
    PP = TSD#'TerminationStateDescriptor'.propertyParms,
 
1597
    TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
 
1598
 
 
1599
ensure_prop_groups({_TokenTag, _Line, Text}) ->
 
1600
    Group  = [],
 
1601
    Groups = [],
 
1602
    parse_prop_name(Text, Group, Groups).
 
1603
 
 
1604
parse_prop_name([Char | Rest] = All, Group, Groups) ->
 
1605
    case ?classify_char(Char) of
 
1606
        white_space ->
 
1607
            parse_prop_name(Rest, Group, Groups);
 
1608
        end_of_line ->
 
1609
            parse_prop_name(Rest, Group, Groups);
 
1610
        _ ->
 
1611
            Name = [],
 
1612
            do_parse_prop_name(All, Name, Group, Groups)
 
1613
    end;
 
1614
parse_prop_name([] = All, Group, Groups) ->
 
1615
    Name = [],
 
1616
    do_parse_prop_name(All, Name, Group, Groups).
 
1617
 
 
1618
do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
 
1619
    case ?classify_char(Char) of
 
1620
        safe_char ->
 
1621
            do_parse_prop_name(Rest, [Char | Name], Group, Groups);
 
1622
        rest_char when Char == $=, Name /= [] ->
 
1623
            %% Now we have a complete name
 
1624
            if
 
1625
                Name == "v", Group /= [] ->
 
1626
                    %% v= is a property group delimiter,
 
1627
                    %% lets create yet another property group.
 
1628
                    Groups2 = [lists:reverse(Group) | Groups],
 
1629
                    Group2 = [],
 
1630
                    parse_prop_value(Rest, Name, Group2, Groups2);
 
1631
                true ->
 
1632
                    %% Use current property group
 
1633
                    parse_prop_value(Rest, Name, Group, Groups)
 
1634
            end;
 
1635
        _ ->
 
1636
            return_error(0, {bad_prop_name, lists:reverse(Name), Char})
 
1637
    end;
 
1638
do_parse_prop_name([], [], [], Groups) ->
 
1639
    lists:reverse(Groups);
 
1640
do_parse_prop_name([], [], Group, Groups) ->
 
1641
    Group2 = lists:reverse(Group),
 
1642
    lists:reverse([Group2 | Groups]);
 
1643
do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
 
1644
    %% Assume end of line
 
1645
    Value = [],
 
1646
    PP = make_prop_parm(Name, Value),
 
1647
    Group2 = lists:reverse([PP | Group]),
 
1648
    lists:reverse([Group2 | Groups]).
 
1649
                   
 
1650
parse_prop_value(Chars, Name, Group, Groups) ->
 
1651
    Value = [],
 
1652
    do_parse_prop_value(Chars, Name, Value, Group, Groups).
 
1653
 
 
1654
do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
 
1655
    case ?classify_char(Char) of
 
1656
        end_of_line ->
 
1657
            %% Now we have a complete "name=value" pair
 
1658
            PP = make_prop_parm(Name, Value),
 
1659
            parse_prop_name(Rest, [PP | Group], Groups);
 
1660
        _ ->
 
1661
            do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
 
1662
    end;
 
1663
do_parse_prop_value([], Name, Value, Group, Groups) ->
 
1664
    %% Assume end of line
 
1665
    PP = make_prop_parm(Name, Value),
 
1666
    Group2 = lists:reverse([PP | Group]),
 
1667
    lists:reverse([Group2 | Groups]).
 
1668
 
 
1669
make_prop_parm(Name, Value) ->
 
1670
    #'PropertyParm'{name  = lists:reverse(Name),
 
1671
                    value = [lists:reverse(Value)]}.
 
1672
 
 
1673
ensure_uint({_TokenTag, Line, Val}, Min, Max) when integer(Val) ->
 
1674
    if
 
1675
        integer(Min), Val >= Min ->
 
1676
            if
 
1677
                integer(Max), Val =< Max ->
 
1678
                    Val;
 
1679
                Max == infinity ->
 
1680
                    Val;
 
1681
                true ->
 
1682
                    return_error(Line, {too_large_integer, Val, Max})
 
1683
            end;
 
1684
        true ->
 
1685
            return_error(Line, {too_small_integer, Val, Min})
 
1686
    end;
 
1687
ensure_uint({TokenTag, Line, Text}, Min, Max) ->
 
1688
    case catch list_to_integer(Text) of
 
1689
        {'EXIT', _} ->
 
1690
            return_error(Line, {not_an_integer, Text});
 
1691
        Val when integer(Val) ->
 
1692
            ensure_uint({TokenTag, Line, Val}, Min, Max)
 
1693
   end;
 
1694
ensure_uint(Val, Min, Max) ->
 
1695
    ensure_uint({uint, 0, Val}, Min, Max).
 
1696
 
 
1697
ensure_uint16(Int) ->
 
1698
    ensure_uint(Int, 0, 65535).
 
1699
 
 
1700
ensure_uint32(Int) ->
 
1701
    ensure_uint(Int, 0, 4294967295) .
 
1702
 
 
1703
%% OTP-4710
 
1704
ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
 
1705
    ensure_uint(length(Chars), Min, Max),
 
1706
    hex_to_int(Chars, []);
 
1707
ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
 
1708
    ensure_uint(length(Chars), Min, Max),
 
1709
    hex_to_int(Chars, []);
 
1710
ensure_hex([$0, $x |Chars], Min, Max) ->
 
1711
    ensure_uint(length(Chars), Min, Max),
 
1712
    hex_to_int(Chars, []);
 
1713
ensure_hex([$0, $X |Chars], Min, Max) ->
 
1714
    ensure_uint(length(Chars), Min, Max),
 
1715
    hex_to_int(Chars, []).
 
1716
 
 
1717
%% OTP-4710
 
1718
hex_to_int([], Acc) ->
 
1719
    lists:reverse(Acc);
 
1720
hex_to_int([Char1,Char2|Tail], Acc) ->
 
1721
    Int1 = hchar_to_int(Char1),
 
1722
    Int2 = hchar_to_int(Char2),
 
1723
    Val  = Int2 bor (Int1 bsl 4),
 
1724
    hex_to_int(Tail, [Val| Acc]);
 
1725
hex_to_int([Char], Acc) ->
 
1726
    Int = hchar_to_int(Char),
 
1727
    lists:reverse([Int|Acc]).
 
1728
 
 
1729
hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
 
1730
    Char - $0;
 
1731
hchar_to_int(Char) when $A =< Char, Char =< $F ->
 
1732
    Char - $A + 10; % OTP-4710
 
1733
hchar_to_int(Char) when $a =< Char, Char =< $f ->
 
1734
    Char - $a + 10. % OTP-4710
 
1735
 
 
1736
value_of({_TokenTag, _Line, Text}) ->
 
1737
    Text.
 
1738
 
 
1739
 
 
1740
%% -------------------------------------------------------------------
 
1741
 
 
1742
%% d(F) ->
 
1743
%%     d(F,[]).
 
1744
%% d(F, A) ->
 
1745
%%     %% d(true, F, A).
 
1746
%%     d(get(dbg), F, A).
 
1747
 
 
1748
%% d(true, F, A) ->
 
1749
%%     io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);
 
1750
%% d(_, _, _) ->
 
1751
%%     ok.
 
1752