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

« back to all changes in this revision

Viewing changes to lib/megaco/src/text/megaco_text_mini_parser.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_v2.hrl").
 
25
-include("megaco_text_tokens.hrl").
 
26
 
 
27
-define(d(F,A), io:format("DBG:"++F++"~n",A)).
 
28
 
 
29
make_safe_token({_TokenTag, Line, Text}) ->
 
30
    {safeToken, Line, Text}.
 
31
 
 
32
% ensure_value({safeToken, _Line, Text}) ->
 
33
%     ensure_value(Text);
 
34
% ensure_value({'QuotedChars', _Line, Text}) ->
 
35
%     ensure_value(Text);
 
36
% ensure_value(Text) when list(Text) ->
 
37
%     Text. %% BUGBUG: ensure length
 
38
 
 
39
% %% NAME       = ALPHA *63(ALPHA / DIGIT / "_" )
 
40
% ensure_NAME({_TokenTag, _Line, Text}) ->
 
41
%     Text.  %% BUGBUG: ensure length and chars
 
42
 
 
43
% ensure_requestID({safeToken, _Line, "*"}) ->
 
44
%     ?megaco_all_request_id;
 
45
% ensure_requestID(RequestId) ->
 
46
%     ensure_uint32(RequestId).
 
47
 
 
48
% ensure_streamID(StreamId) ->
 
49
%     ensure_uint16(StreamId).
 
50
 
 
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}.
 
56
 
 
57
%% ContextID         = (UINT32 / "*" / "-" / "$")
 
58
% ensure_contextID({_TokenTag, _Line, Text}) ->
 
59
%     case Text of
 
60
%         "*"  -> ?megaco_all_context_id;
 
61
%         "-"  -> ?megaco_null_context_id;
 
62
%         "\$" -> ?megaco_choose_context_id;
 
63
%         Int  -> ensure_uint32(Int)
 
64
%     end.
 
65
 
 
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}}.
 
75
 
 
76
 
 
77
ensure_ip4addr({TokenTag, Line, Addr}) ->
 
78
    case string:tokens(Addr, [$.]) of
 
79
        [T1, T2, T3, T4] ->
 
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),
 
84
            [A1, A2, A3, A4];
 
85
        _ ->
 
86
            return_error(Line, {bad_IP4address, Addr})
 
87
    end.
 
88
 
 
89
 
 
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 ->
 
94
            A;
 
95
        {true, B} when length(B) < 16 ->
 
96
            lists:duplicate(16 - length(B), 0) ++ B;
 
97
        {true, C} ->
 
98
            throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
 
99
    end;
 
100
ensure_ip6addr(L) ->
 
101
    case lists:reverse(L) of
 
102
        [colon, colon| T] ->
 
103
            case do_ensure_ip6addr(T, true, [], 1) of
 
104
                {true, A} when length(A) == 16 ->
 
105
                    A;
 
106
                {true, B} when length(B) < 16 ->
 
107
                    B ++ lists:duplicate(16 - length(B), 0);
 
108
                {true, C} ->
 
109
                    throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
 
110
            end;
 
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 -> 
 
114
                    A;
 
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);
 
118
                {Pad, C} ->
 
119
                    throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
 
120
            end
 
121
 
 
122
    end.
 
123
 
 
124
 
 
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).
 
135
 
 
136
do_ensure_ip6addr_padding([], _) ->
 
137
    [];
 
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)].
 
142
 
 
143
ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
 
144
    case string:tokens(Addr, [$.]) of
 
145
        [T1, T2, T3, T4] ->
 
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),
 
150
            [A1, A2, A3, A4];
 
151
        _ ->
 
152
            ensure_hex4(V)
 
153
            %%      %% BMK BMK BMK 
 
154
            %%      %% Here we should test for hexseq
 
155
            %%      return_error(Line, {bad_IP4address, Addr})
 
156
    end.
 
157
 
 
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 ->
 
162
            IL;
 
163
        Error ->
 
164
            return_error(Line, {bad_hex4, Hex4, Error})
 
165
    end.
 
166
 
 
167
do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
 
168
    hex_to_int(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], []).
 
175
 
 
176
ensure_domainName({_TokenTag, _Line, Name}, Port) ->
 
177
    %% BUGBUG: validate name
 
178
    {domainName, #'DomainName'{name = Name, portNumber = Port}}.
 
179
 
 
180
%% extensionParameter= "X"  ("-" / "+") 1*6(ALPHA / DIGIT)
 
181
% ensure_extensionParameter({_TokenTag, Line, Text}) ->
 
182
%     case Text of
 
183
%         [X, S | _Chars] ->
 
184
%             if
 
185
%                 X /= $X, X /= $x,
 
186
%                 S /= $+, S /= $- ->
 
187
%                     return_error(Line, {bad_extension_parameter, Text});
 
188
%                 true ->
 
189
%                     {extension_parameter, Text}
 
190
%             end;
 
191
%         _ ->
 
192
%             return_error(Line, {bad_extension_parameter, Text})
 
193
%     end.
 
194
 
 
195
ensure_message(MegacopToken,  MID) ->
 
196
    #'ServiceChangeProfile'{profileName = Name,
 
197
                            version     = Version} = 
 
198
        ensure_profile(MegacopToken),
 
199
    case Name of
 
200
        "megaco" ->
 
201
            #'Message'{version = Version, mId = MID};
 
202
        [$!]  ->
 
203
            #'Message'{version = Version, mId = MID}
 
204
    end.
 
205
 
 
206
 
 
207
%% modemType         = (V32bisToken / V22bisToken / V18Token / 
 
208
%%                      V22Token / V32Token / V34Token / V90Token / 
 
209
%%                      V91Token / SynchISDNToken / extensionParameter)
 
210
% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
 
211
%     case Text of
 
212
%         "v32b"      -> v32bis;
 
213
%         "v22b"      -> v22bis;
 
214
%         "v18"       -> v18;
 
215
%         "v22"       -> v22;
 
216
%         "v32"       -> v32;
 
217
%         "v34"       -> v34;
 
218
%         "v90"       -> v90;
 
219
%         "v91"       -> v91;
 
220
%         "synchisdn" -> synchISDN;
 
221
%         "sn"        -> synchISDN;
 
222
%         [$x | _]               -> ensure_extensionParameter(Token)
 
223
%     end.
 
224
 
 
225
%% An mtp address is five octets long
 
226
ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
 
227
    %% BUGBUG: validate address
 
228
    {mtpAddress, Addr}.
 
229
 
 
230
%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
 
231
% ensure_muxType({_TokenTag, _Line, Text} = Token) ->
 
232
%     case Text of
 
233
%         "h221"  -> h221;
 
234
%         "h223"  -> h223;
 
235
%         "h226"  -> h226;
 
236
%         "v76"   -> v76;
 
237
%         "nx64k" -> nx64k; % v2
 
238
%         [$x | _]          -> ensure_extensionParameter(Token)
 
239
%     end.
 
240
 
 
241
%% packagesItem      = NAME "-" UINT16
 
242
%% NAME              = ALPHA *63(ALPHA / DIGIT / "_" )
 
243
% ensure_packagesItem({TokenTag, Line, Text}) ->
 
244
%     case string:tokens(Text, [$-]) of
 
245
%         [Name, Version] ->
 
246
%             #'PackagesItem'{packageName    = ensure_NAME({TokenTag, Line, Name}),
 
247
%                             packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
 
248
%         _ ->
 
249
%             return_error(Line, {bad_PackagesItem, Text})
 
250
%     end.
 
251
 
 
252
%% pkgdName          =  (PackageName / "*")  SLASH  (ItemID / "*" )
 
253
%% PackageName       = NAME
 
254
%% ItemID            = NAME
 
255
% ensure_pkgdName({TokenTag, Line, Text}) ->
 
256
%     case string:tokens(Text, [$/]) of
 
257
%         [Name, Item] ->
 
258
%             ensure_name_or_star({TokenTag, Line, Name}),
 
259
%             ensure_name_or_star({TokenTag, Line, Item}),
 
260
%             Text;
 
261
%         _ ->
 
262
%             return_error(Line, {bad_pkgdName, Text})
 
263
%     end.
 
264
 
 
265
% ensure_name_or_star({_, _, Name}) when Name == "*" ->
 
266
%     Name;
 
267
% ensure_name_or_star(Name) ->
 
268
%     ensure_NAME(Name).
 
269
 
 
270
 
 
271
 
 
272
%% v2 - start
 
273
 
 
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]}}.
 
280
 
 
281
% merge_indAudLocalControlDescriptor(Parms) ->
 
282
%     do_merge_indAudLocalControlDescriptor(Parms, 
 
283
%                                         #'IndAudLocalControlDescriptor'{}).
 
284
                                          
 
285
% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
 
286
%     case Parm of
 
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)
 
305
%     end;
 
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};
 
311
%       _ ->
 
312
%           Desc
 
313
%     end.
 
314
 
 
315
% ensure_indAudLocalParm(Token) ->
 
316
%     case Token of
 
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)}
 
325
%     end.
 
326
 
 
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'}.
 
334
 
 
335
 
 
336
% merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
 
337
%     IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
 
338
%     do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
 
339
 
 
340
% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
 
341
%     IAEBD;
 
342
% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
 
343
%     IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
 
344
% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN, 
 
345
%                                    IAEBD) ->
 
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}.
 
350
 
 
351
 
 
352
% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
 
353
%     ensure_indAudSignal(SIG).
 
354
 
 
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}.
 
363
    
 
364
 
 
365
% ensure_IADMD({_TokenTag, _Line, 
 
366
%             #'DigitMapDescriptor'{digitMapName  = Name,
 
367
%                                   digitMapValue = asn1_NOVALUE}}) ->
 
368
%     #'IndAudDigitMapDescriptor'{digitMapName = Name}.
 
369
 
 
370
 
 
371
% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName    = N,
 
372
%                                              packageVersion = V}) ->
 
373
%     #'IndAudPackagesDescriptor'{packageName    = N,
 
374
%                               packageVersion = V}.
 
375
 
 
376
 
 
377
% ensure_indAudTerminationStateParm(Token) ->
 
378
%     case Token of
 
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)}
 
385
%     end.
 
386
 
 
387
 
 
388
% %% Types modified by v2:
 
389
 
 
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
 
396
%               [] ->
 
397
%                   #'AuditDescriptor'{auditPropertyToken = TA};
 
398
%               AuditTokens ->
 
399
%                   #'AuditDescriptor'{auditToken         = AuditTokens,
 
400
%                                      auditPropertyToken = TA}
 
401
%           end;
 
402
%       false ->
 
403
%           #'AuditDescriptor'{auditToken = Tokens}
 
404
%     end;
 
405
% merge_auditDescriptor(_) ->
 
406
%     #'AuditDescriptor'{}.
 
407
 
 
408
 
 
409
% %% v2 - end
 
410
 
 
411
 
 
412
 
 
413
% merge_ServiceChangeParm(Parms) ->
 
414
%     Required = [serviceChangeReason, serviceChangeMethod],
 
415
%     merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
 
416
 
 
417
% merge_ServiceChangeParm([], SCP, []) ->
 
418
%     SCP;
 
419
 
 
420
% merge_ServiceChangeParm([], _SCP, Required) ->
 
421
%     exit({missing_required_serviceChangeParm, Required});
 
422
 
 
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});
 
432
 
 
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});
 
442
 
 
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);
 
447
 
 
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);
 
452
 
 
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);
 
459
 
 
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);
 
464
 
 
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);
 
471
 
 
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);
 
476
 
 
477
% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
 
478
%     merge_ServiceChangeParm(Parms, SCP0, Req);
 
479
 
 
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);
 
485
 
 
486
% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
 
487
%     Val2 = 
 
488
%       case Tag of
 
489
%           address -> 
 
490
%               SCP#'ServiceChangeParm'.serviceChangeAddress;
 
491
%           mgc_id     -> 
 
492
%               SCP#'ServiceChangeParm'.serviceChangeMgcId;
 
493
%           profile    -> 
 
494
%               SCP#'ServiceChangeParm'.serviceChangeProfile;
 
495
%           version    -> 
 
496
%               SCP#'ServiceChangeParm'.serviceChangeVersion;
 
497
%           reason     -> 
 
498
%               SCP#'ServiceChangeParm'.serviceChangeReason;
 
499
%           delay      -> 
 
500
%               SCP#'ServiceChangeParm'.serviceChangeDelay;
 
501
%           method     -> 
 
502
%               SCP#'ServiceChangeParm'.serviceChangeMethod;
 
503
%           time_stamp -> 
 
504
%               SCP#'ServiceChangeParm'.timeStamp;
 
505
%           audit_item -> 
 
506
%               SCP#'ServiceChangeParm'.serviceChangeInfo
 
507
%       end,
 
508
%     exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
 
509
 
 
510
 
 
511
% merge_ServiceChangeResParm(Parms) ->
 
512
%     merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
 
513
 
 
514
% merge_ServiceChangeResParm([], SCRP) ->
 
515
%     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});
 
525
 
 
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});
 
535
 
 
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);
 
540
 
 
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);
 
545
 
 
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);
 
550
 
 
551
% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
 
552
%     Val2 = 
 
553
%       case Tag of
 
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
 
559
%       end,
 
560
%     exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
 
561
 
 
562
 
 
563
% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
 
564
%     failover;
 
565
% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
 
566
%     failover;
 
567
% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) -> 
 
568
%     forced;
 
569
% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
 
570
%     forced;
 
571
% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
 
572
%     graceful;
 
573
% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
 
574
%     graceful;
 
575
% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
 
576
%     restart;
 
577
% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
 
578
%     restart;
 
579
% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
 
580
%     disconnected;
 
581
% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
 
582
%     disconnected;
 
583
% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
 
584
%     handOff;
 
585
% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
 
586
%     handOff;
 
587
% ensure_serviceChangeMethod({safeToken, Line, Text}) ->
 
588
%     return_error(Line, {bad_serviceChangeMethod, Text}).
 
589
 
 
590
 
 
591
ensure_profile({_TokenTag, Line, Text}) ->
 
592
    case string:tokens(Text, [$/]) of
 
593
        [Name, Version] ->
 
594
            Version2 = ensure_version(Version),
 
595
            #'ServiceChangeProfile'{profileName = Name, version = Version2};
 
596
        _ ->
 
597
            return_error(Line, {bad_profile, Text})
 
598
    end.
 
599
 
 
600
ensure_version(Version) ->
 
601
    ensure_uint(Version, 0, 99).
 
602
 
 
603
% merge_signalRequest(SignalName, PropertyParms) ->
 
604
%     Sig = #'Signal'{signalName = SignalName},
 
605
%     SPL = [],
 
606
%     do_merge_signalRequest(Sig, PropertyParms, SPL).
 
607
 
 
608
% do_merge_signalRequest(Sig, [H | T], SPL) ->
 
609
%     case H of
 
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]);
 
625
%         _ ->
 
626
%             return_error(0, {bad_sigParm, H})
 
627
%     end;
 
628
% do_merge_signalRequest(Sig, [], SPL) ->
 
629
%     Sig#'Signal'{sigParList = lists:reverse(SPL)} .
 
630
 
 
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,
 
643
%                          value              = Value},
 
644
%     {other, EP}.
 
645
 
 
646
% ensure_eventDM({_TokenTag, Line, DMD}) 
 
647
%   when record(DMD, 'DigitMapDescriptor') ->
 
648
%     Name = DMD#'DigitMapDescriptor'.digitMapName,
 
649
%     Val  = DMD#'DigitMapDescriptor'.digitMapValue,
 
650
%     if
 
651
%         Name  == asn1_NOVALUE, Val /= asn1_NOVALUE ->
 
652
%           {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
 
653
%           DMV = #'DigitMapValue'{startTimer    = Start, 
 
654
%                                  shortTimer    = Short, 
 
655
%                                  longTimer     = Long, 
 
656
%                                  digitMapBody  = Body,
 
657
%                                  durationTimer = Duration},
 
658
%             {eventDM, {digitMapValue, DMV}};
 
659
%         Name  /= asn1_NOVALUE, Val == asn1_NOVALUE ->
 
660
%             {eventDM, {digitMapName, Name}};
 
661
%         true ->
 
662
%             return_error(Line, {bad_eventDM, DMD})
 
663
%     end.
 
664
    
 
665
% ensure_DMD({_TokenTag, _Line, DMD}) 
 
666
%   when record(DMD, 'DigitMapDescriptor') ->
 
667
%     Val2 = 
 
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};
 
677
%           Other ->
 
678
%               Other
 
679
%       end,
 
680
%     DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
 
681
 
 
682
 
 
683
% merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
 
684
%     StreamId = asn1_NOVALUE,
 
685
%     EPL = [],
 
686
%     do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
 
687
 
 
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)}.
 
697
 
 
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}).
 
705
 
 
706
% merge_eventParameters(Params) ->
 
707
%     StreamId = asn1_NOVALUE,
 
708
%     EPL      = [],
 
709
%     RA       = #'RequestedActions'{},
 
710
%     HasA     = no,
 
711
%     do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
 
712
                                   
 
713
% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
 
714
%     case H of
 
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);
 
734
%         _ ->
 
735
%             return_error(0, {bad_eventParameter, H})
 
736
%     end;
 
737
% do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
 
738
%     #'RequestedEvent'{streamID    = StreamId,
 
739
%                       eventAction = RA, 
 
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)}.
 
745
 
 
746
% merge_secondEventParameters(Params) ->
 
747
%     StreamId = asn1_NOVALUE,
 
748
%     EPL      = [],
 
749
%     SRA      = #'SecondRequestedActions'{},
 
750
%     HasA     = no,
 
751
%     do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
 
752
                                   
 
753
% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
 
754
%     case H of
 
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);
 
773
%         _ ->
 
774
%             return_error(0, {bad_secondEventParameter, H})
 
775
%     end;
 
776
% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
 
777
%     #'SecondRequestedEvent'{streamID    = StreamId,
 
778
%                             eventAction = SRA, 
 
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)}.
 
784
 
 
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, [], []).
 
796
 
 
797
% decode_term_id([H | T], Wild, Id, Component) ->
 
798
%     case H of
 
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])
 
803
%     end;
 
804
% decode_term_id([], Wild, Id, Component) ->
 
805
%     Id2 = [lists:reverse(Component) | Id],
 
806
%     #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
 
807
            
 
808
ensure_pathName({_TokenTag, _Line, Text}) ->
 
809
    Text.  %% BUGBUG: ensure values
 
810
 
 
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
 
816
%         [Date, Time] ->
 
817
%             #'TimeNotation'{date = Date, time = Time};
 
818
%         _ ->
 
819
%             return_error(Line, {bad_timeStamp, Text})
 
820
%     end.
 
821
 
 
822
% ensure_transactionID(TransId) ->
 
823
%     ensure_uint32(TransId).
 
824
 
 
825
% %% transactionAck       = transactionID / (transactionID "-" transactionID)
 
826
% ensure_transactionAck({safeToken, _Line, Text}) ->
 
827
%     case string:tokens(Text, [$-]) of
 
828
%         [Id] ->
 
829
%             #'TransactionAck'{firstAck = ensure_transactionID(Id)};
 
830
%         [Id, Id2] ->
 
831
%             #'TransactionAck'{firstAck = ensure_transactionID(Id),
 
832
%                             lastAck  = ensure_transactionID(Id2)}
 
833
%     end.
 
834
 
 
835
% merge_action_requests(CtxId, Items) ->
 
836
%     CtxReq      = #'ContextRequest'{},
 
837
%     CtxAuditReq = asn1_NOVALUE, 
 
838
%     CmdReq      = [],
 
839
%     TopReq      = [],
 
840
%     do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
 
841
 
 
842
% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
 
843
%     case H of
 
844
%         _ when record(H, 'CommandRequest') ->
 
845
%             do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
 
846
 
 
847
%         {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
 
848
%             CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
 
849
%             do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, 
 
850
%                                    TopReq, T);
 
851
%         {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
 
852
%             CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
 
853
%             do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq, 
 
854
%                                    TopReq, T);
 
855
%         {topology, Desc} ->
 
856
%             TopReq2 = Desc ++ TopReq, %% OTP-4088
 
857
%             do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, 
 
858
%                                    TopReq2, T);
 
859
 
 
860
%       {contextAudit, CAs} ->
 
861
%           CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs),
 
862
%           do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq, 
 
863
%                                    TopReq, T)
 
864
            
 
865
%     end;
 
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)}.
 
871
 
 
872
 
 
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]) ->
 
876
%     CAAR2 = 
 
877
%       case H of
 
878
%           priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
 
879
%               CAAR#'ContextAttrAuditRequest'{priority = 'NULL'};
 
880
 
 
881
%           priorityAudit ->
 
882
%               Prio = CAAR#'ContextAttrAuditRequest'.priority,
 
883
%               exit({only_once, priorityAudit, Prio});
 
884
 
 
885
%           emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
 
886
%               CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'};
 
887
 
 
888
%           emergencyAudit ->
 
889
%               Em = CAAR#'ContextAttrAuditRequest'.emergency,
 
890
%               exit({only_once, emergencyAudit, Em});
 
891
 
 
892
%           topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
 
893
%               CAAR#'ContextAttrAuditRequest'{topology = 'NULL'};
 
894
            
 
895
%           topologyAudit ->
 
896
%               Top = CAAR#'ContextAttrAuditRequest'.topology,
 
897
%               exit({only_once, topologyAudit, Top})
 
898
 
 
899
%     end,
 
900
%     merge_context_attr_audit_request(CAAR2, T);
 
901
% merge_context_attr_audit_request(CAAR, []) ->
 
902
%     CAAR.
 
903
 
 
904
% %% OTP-5085: 
 
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 
 
907
% %% asn1_NOVALUE
 
908
% merge_action_reply(ReplyList) ->
 
909
%     CtxReq  = #'ContextRequest'{},
 
910
%     TopReq  = [],
 
911
%     CmdList = [],
 
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};
 
917
%       _ ->
 
918
%           do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList)
 
919
%     end.
 
920
 
 
921
% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
 
922
%     case H of
 
923
%         {command, Cmd} ->
 
924
%             do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
 
925
%         {context, Ctx} ->
 
926
%             case Ctx of
 
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)
 
936
%             end
 
937
%     end;
 
938
% do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
 
939
%     #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
 
940
%                    commandReply = lists:reverse(CmdList)}.
 
941
 
 
942
% strip_contextRequest(R, TopReq)
 
943
%   when R#'ContextRequest'.priority    == asn1_NOVALUE,
 
944
%        R#'ContextRequest'.emergency   == asn1_NOVALUE,
 
945
%        TopReq == [] ->
 
946
%     asn1_NOVALUE;
 
947
% strip_contextRequest(R, []) ->
 
948
%     R#'ContextRequest'{topologyReq = asn1_NOVALUE};
 
949
% strip_contextRequest(R, TopReq) ->
 
950
%     R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
 
951
 
 
952
 
 
953
% strip_contextAttrAuditRequest(R)
 
954
%   when R#'ContextAttrAuditRequest'.priority  == asn1_NOVALUE,
 
955
%        R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE,
 
956
%        R#'ContextAttrAuditRequest'.topology  == asn1_NOVALUE ->
 
957
%     asn1_NOVALUE;
 
958
% strip_contextAttrAuditRequest(R) ->
 
959
%     R.
 
960
 
 
961
% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
 
962
%     Req = #'CommandRequest'{command  = {CmdTag, Cmd}},
 
963
%     case Text of
 
964
%         [$w, $- | _] ->
 
965
%             Req#'CommandRequest'{wildcardReturn = 'NULL'};
 
966
%         [$o, $-, $w, $- | _] ->
 
967
%             Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
 
968
%         [$o, $- | _] ->
 
969
%             Req#'CommandRequest'{optional = 'NULL'};
 
970
%         _ -> 
 
971
%             Req
 
972
%     end.
 
973
 
 
974
% merge_terminationAudit(AuditReturnParameters) ->
 
975
%     lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
 
976
 
 
977
% do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
 
978
%     case H of
 
979
%       {auditReturnItem, AuditItem} ->
 
980
%           do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
 
981
%       AuditReturnParameter ->
 
982
%           do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
 
983
%     end;
 
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].
 
990
        
 
991
% merge_mediaDescriptor(MediaParms) ->
 
992
%     do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
 
993
 
 
994
% do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
 
995
%     case H of
 
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);
 
1002
%         _ ->
 
1003
%             return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
 
1004
%     end;
 
1005
% do_merge_mediaDescriptor([], TS, One, Multi) ->
 
1006
%     if
 
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}
 
1016
%     end.
 
1017
  
 
1018
% merge_streamParms(TaggedStreamParms) ->
 
1019
%     SP = #'StreamParms'{},
 
1020
%     do_merge_streamParms(TaggedStreamParms, SP).
 
1021
 
 
1022
% do_merge_streamParms([{Tag, D} | T] = All, SP) ->
 
1023
%     case Tag of
 
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});
 
1028
%         control ->
 
1029
%             LCD = 
 
1030
%                 case SP#'StreamParms'.localControlDescriptor of
 
1031
%                     asn1_NOVALUE ->
 
1032
%                         #'LocalControlDescriptor'{propertyParms = []};
 
1033
%                     PrevLCD ->
 
1034
%                         PrevLCD
 
1035
%                 end,
 
1036
%             LCD2 = do_merge_control_streamParms(D, LCD),
 
1037
%             do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
 
1038
%         _ ->
 
1039
%             return_error(0, {do_merge_streamParms, [All, SP]})
 
1040
%     end;
 
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) ->
 
1047
%     SP.
 
1048
 
 
1049
 
 
1050
% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
 
1051
%     case SubTag of
 
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);
 
1061
%         prop ->
 
1062
%             PP = LCD#'LocalControlDescriptor'.propertyParms,
 
1063
%             LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
 
1064
%             do_merge_control_streamParms(T, LCD2);
 
1065
%         _ ->
 
1066
%             return_error(0, {do_merge_control_streamParms, [All, LCD]})
 
1067
%   end;
 
1068
% do_merge_control_streamParms([], LCD) ->
 
1069
%     LCD.
 
1070
 
 
1071
% merge_terminationStateDescriptor(Parms) ->
 
1072
%     TSD = #'TerminationStateDescriptor'{propertyParms = []},
 
1073
%     do_merge_terminationStateDescriptor(Parms, TSD).
 
1074
 
 
1075
% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
 
1076
%     case Tag of
 
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);
 
1083
%         propertyParm ->
 
1084
%             PP = TSD#'TerminationStateDescriptor'.propertyParms,
 
1085
%             TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
 
1086
%             do_merge_terminationStateDescriptor(T, TSD2)
 
1087
%     end;
 
1088
% do_merge_terminationStateDescriptor([], TSD) ->
 
1089
%     PP = TSD#'TerminationStateDescriptor'.propertyParms,
 
1090
%     TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
 
1091
 
 
1092
% ensure_prop_groups({_TokenTag, _Line, Text}) ->
 
1093
%     Group  = [],
 
1094
%     Groups = [],
 
1095
%     parse_prop_name(Text, Group, Groups).
 
1096
 
 
1097
% parse_prop_name([Char | Rest] = All, Group, Groups) ->
 
1098
%     case ?classify_char(Char) of
 
1099
%         white_space ->
 
1100
%             parse_prop_name(Rest, Group, Groups);
 
1101
%         end_of_line ->
 
1102
%             parse_prop_name(Rest, Group, Groups);
 
1103
%         _ ->
 
1104
%             Name = [],
 
1105
%             do_parse_prop_name(All, Name, Group, Groups)
 
1106
%     end;
 
1107
% parse_prop_name([] = All, Group, Groups) ->
 
1108
%     Name = [],
 
1109
%     do_parse_prop_name(All, Name, Group, Groups).
 
1110
 
 
1111
% do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
 
1112
%     case ?classify_char(Char) of
 
1113
%         safe_char ->
 
1114
%             do_parse_prop_name(Rest, [Char | Name], Group, Groups);
 
1115
%         rest_char when Char == $=, Name /= [] ->
 
1116
%             %% Now we have a complete name
 
1117
%             if
 
1118
%                 Name == "v", Group /= [] ->
 
1119
%                     %% v= is a property group delimiter,
 
1120
%                     %% lets create yet another property group.
 
1121
%                     Groups2 = [lists:reverse(Group) | Groups],
 
1122
%                     Group2 = [],
 
1123
%                     parse_prop_value(Rest, Name, Group2, Groups2);
 
1124
%                 true ->
 
1125
%                     %% Use current property group
 
1126
%                     parse_prop_value(Rest, Name, Group, Groups)
 
1127
%             end;
 
1128
%         _ ->
 
1129
%             return_error(0, {bad_prop_name, lists:reverse(Name), Char})
 
1130
%     end;
 
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
 
1138
%     Value = [],
 
1139
%     PP = make_prop_parm(Name, Value),
 
1140
%     Group2 = lists:reverse([PP | Group]),
 
1141
%     lists:reverse([Group2 | Groups]).
 
1142
                   
 
1143
% parse_prop_value(Chars, Name, Group, Groups) ->
 
1144
%     Value = [],
 
1145
%     do_parse_prop_value(Chars, Name, Value, Group, Groups).
 
1146
 
 
1147
% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
 
1148
%     case ?classify_char(Char) of
 
1149
%         end_of_line ->
 
1150
%             %% Now we have a complete "name=value" pair
 
1151
%             PP = make_prop_parm(Name, Value),
 
1152
%             parse_prop_name(Rest, [PP | Group], Groups);
 
1153
%         _ ->
 
1154
%             do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
 
1155
%     end;
 
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]).
 
1161
 
 
1162
% make_prop_parm(Name, Value) ->
 
1163
%     #'PropertyParm'{name  = lists:reverse(Name),
 
1164
%                     value = [lists:reverse(Value)]}.
 
1165
 
 
1166
ensure_uint({_TokenTag, Line, Val}, Min, Max) when integer(Val) ->
 
1167
    if
 
1168
        integer(Min), Val >= Min ->
 
1169
            if
 
1170
                integer(Max), Val =< Max ->
 
1171
                    Val;
 
1172
                Max == infinity ->
 
1173
                    Val;
 
1174
                true ->
 
1175
                    return_error(Line, {too_large_integer, Val, Max})
 
1176
            end;
 
1177
        true ->
 
1178
            return_error(Line, {too_small_integer, Val, Min})
 
1179
    end;
 
1180
ensure_uint({TokenTag, Line, Text}, Min, Max) ->
 
1181
    case catch list_to_integer(Text) of
 
1182
        {'EXIT', _} ->
 
1183
            return_error(Line, {not_an_integer, Text});
 
1184
        Val when integer(Val) ->
 
1185
            ensure_uint({TokenTag, Line, Val}, Min, Max)
 
1186
   end;
 
1187
ensure_uint(Val, Min, Max) ->
 
1188
    ensure_uint({uint, 0, Val}, Min, Max).
 
1189
 
 
1190
ensure_uint16(Int) ->
 
1191
    ensure_uint(Int, 0, 65535).
 
1192
 
 
1193
% ensure_uint32(Int) ->
 
1194
%     ensure_uint(Int, 0, 4294967295) .
 
1195
 
 
1196
%% OTP-4710
 
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, []).
 
1209
 
 
1210
%% OTP-4710
 
1211
hex_to_int([], Acc) ->
 
1212
    lists:reverse(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]).
 
1221
 
 
1222
hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
 
1223
    Char - $0;
 
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
 
1228
 
 
1229
% value_of({_TokenTag, _Line, Text}) ->
 
1230
%     Text.
 
1231
 
 
1232
 
 
1233
% d(F) ->
 
1234
%     d(F, []).
 
1235
 
 
1236
% d(F, A) ->
 
1237
%     d(get(dbg), F, A).
 
1238
 
 
1239
% d(true, F, A) ->
 
1240
%     io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
 
1241
% d(_, _, _) ->
 
1242
%     ok.
 
1243