1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%%---------------------------------------------------------------------- 22%% Purpose : Scanner for text encoded Megaco/H.248 messages 23%%---------------------------------------------------------------------- 24 25-module('megaco_text_scanner'). 26 27-export([scan/1, skip_sep_chars/2]). 28 29-include_lib("megaco/include/megaco.hrl"). 30-include_lib("megaco/src/engine/megaco_message_internal.hrl"). 31-include("megaco_text_tokens.hrl"). 32 33-define(LOWER1(Char), 34 if 35 (Char >= $A) andalso (Char =< $Z) -> 36 Char - ($A - $a); 37 true -> 38 Char 39 end). 40 41%% This is used when we _know_ it to be upper case 42-define(LOWER2(Char), Char - ($A - $a)). 43 44scan(Bin) when is_binary(Bin) -> 45 Chars = erlang:binary_to_list(Bin), 46 tokens1(Chars, 1, []); 47scan(Chars) when is_list(Chars) -> 48 tokens1(Chars, 1, []). 49 50%% As long as we dont know the version, we will loop in this function 51tokens1(Chars, Line, Acc) -> 52 case any_chars(Chars, Line, 1) of 53 {token, Token, [], LatestLine} -> 54 %% We got to the end without actually getting a version token. 55 Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc], 56 {error, no_version_found, lists:reverse(Tokens), Line}; 57 58 %% -- Version token for version 1 -- 59 {token, {'SafeChars',_,"!/1"} = Token, Rest, LatestLine} -> 60 tokens2(Rest, LatestLine, 1, [Token | Acc]); 61 62 {token, {'SafeChars',_,"megaco/1"} = Token, Rest, LatestLine} -> 63 tokens2(Rest, LatestLine, 1, [Token | Acc]); 64 65 66 %% -- Version token for version 2 -- 67 {token, {'SafeChars',_,"!/2"} = Token, Rest, LatestLine} -> 68 tokens2(Rest, LatestLine, 2, [Token | Acc]); 69 70 {token, {'SafeChars',_,"megaco/2"} = Token, Rest, LatestLine} -> 71 tokens2(Rest, LatestLine, 2, [Token | Acc]); 72 73 74 %% -- Version token for version 3 -- 75 {token, {'SafeChars',_,"!/3"} = Token, Rest, LatestLine} -> 76 tokens2(Rest, LatestLine, 3, [Token | Acc]); 77 78 {token, {'SafeChars',_,"megaco/3"} = Token, Rest, LatestLine} -> 79 tokens2(Rest, LatestLine, 3, [Token | Acc]); 80 81 82 %% -- Version token for version X -- 83 {token, {'SafeChars',_,[$!,$/| Vstr]} = Token, Rest, LatestLine} -> 84 case guess_version(Vstr) of 85 {ok, V} -> 86 tokens2(Rest, LatestLine, V, [Token | Acc]); 87 {error, Reason} -> 88 {error, Reason, LatestLine} 89 end; 90 91 {token, {'SafeChars',_,[$m,$e,$g,$a,$c,$o,$/|Vstr]} = Token, Rest, LatestLine} -> 92 case guess_version(Vstr) of 93 {ok, V} -> 94 tokens2(Rest, LatestLine, V, [Token | Acc]); 95 {error, Reason} -> 96 {error, Reason, LatestLine} 97 end; 98 99 %% -- Other tokens -- 100 {token, Token, Rest, LatestLine} -> 101 tokens1(Rest, LatestLine, [Token | Acc]); 102 103 {bad_token, Token, _Rest, _LatestLine} -> 104 {error, {bad_token, [Token, Acc]}, Line} 105 end. 106 107tokens2(Chars, Line0, Version, Tokens0) -> 108 case tokens3(Chars, Line0, Tokens0, Version) of 109 {ok, Tokens, Line} -> 110 {ok, Tokens, Version, Line}; 111 Error -> 112 Error 113 end. 114 115tokens3(Chars, Line, Acc, Version) -> 116 %% d("tokens2 -> entry with" 117 %% "~n Chars: ~s" 118 %% "~n Line: ~p", [Chars, Line]), 119 case any_chars(Chars, Line, Version) of 120 {token, Token, [], LatestLine} -> 121 %% d("tokens2 -> Token: ~n~p", [Token]), 122 Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc], 123 {ok, lists:reverse(Tokens), Line}; 124 125 {token, Token, Rest, LatestLine} -> 126 %% d("tokens2 -> Token: ~n~p", [Token]), 127 tokens3(Rest, LatestLine, [Token | Acc], Version); 128 129 {bad_token, Token, _Rest, _LatestLine} -> 130 {error, {bad_token, [Token, Acc]}, Line} 131 end. 132 133 134guess_version([C]) when (48 =< C) and (C =< 57) -> 135 {ok, C-48}; 136guess_version(Str) when is_list(Str) -> 137 case (catch list_to_integer(Str)) of 138 I when is_integer(I) -> 139 {ok, I}; 140 _ -> 141 {error, {invalid_version, Str}} 142 end. 143 144 145%% Returns {token, Token, Rest, LatestLine} 146%% Returns {bad_token, Token, Rest, LatestLine} 147any_chars([Char | Rest], Line, Version) -> 148 case ?classify_char(Char) of 149 safe_char_upper -> 150 safe_chars(Rest, [Char], [?LOWER2(Char)], Line, Version); 151 safe_char -> 152 safe_chars(Rest, [Char], [Char], Line, Version); 153 rest_char -> 154 case Char of 155 ?SemiColonToken -> 156 comment_chars(Rest, Line); 157 _ -> 158 rest_chars(Rest, [Char], Line) 159 end; 160 double_quote -> 161 quoted_chars(Rest, [], Line); 162 white_space -> 163 sep_chars(Rest, Line); 164 end_of_line -> 165 sep_chars(Rest, Line); 166 bad_char -> 167 %% {bad_token, {'SEP', Line, Char}, Rest, Line} 168 {bad_token, {'AnyChars', Line, Char}, Rest, Line} 169 end; 170any_chars([] = All, Line, _Version) -> 171 {token, {'SEP', Line, end_of_input}, All, Line}. 172 173comment_chars([Char | Rest], Line) -> 174 case ?classify_char(Char) of 175 safe_char_upper -> 176 comment_chars(Rest, Line); 177 safe_char -> 178 comment_chars(Rest, Line); 179 rest_char -> 180 comment_chars(Rest, Line); 181 white_space -> 182 comment_chars(Rest, Line); 183 end_of_line -> 184 sep_chars(Rest, Line); 185 _ when Char =:= 22 -> 186 comment_chars(Rest, Line); 187 _ -> 188 %% {bad_token, {'SEP', Line, Char}, Rest, Line} 189 {bad_token, {'CommentChars', Line, Char}, Rest, Line} 190 end; 191comment_chars([] = All, Line) -> 192 {token, {'SEP', Line}, All, Line}. 193 194sep_chars([Char | Rest] = All, Line) -> 195 case ?classify_char(Char) of 196 safe_char_upper -> 197 {token, {'SEP', Line}, All, Line}; 198 safe_char -> 199 {token, {'SEP', Line}, All, Line}; 200 rest_char when Char =:= ?SemiColonToken -> 201 comment_chars(Rest, Line); 202 rest_char -> 203 rest_chars(Rest, [Char], Line); 204 white_space -> 205 sep_chars(Rest, Line); 206 end_of_line -> 207 sep_chars(Rest, Line + 1); 208 _ -> 209 %% {bad_token, {'SEP', Line, Char}, Rest, Line} 210 {bad_token, {'SepChars', Line, Char}, Rest, Line} 211 end; 212sep_chars([] = All, Line) -> 213 {token, {'SEP', Line}, All, Line}. 214 215rest_chars(Rest, [?ColonToken], Line) -> 216 {token, {'COLON', Line}, Rest, Line}; 217rest_chars(Rest, [AccChar], Line) -> 218 TokenTag = 219 case AccChar of 220 ?EqualToken -> 'EQUAL'; 221 ?NequalToken -> 'NEQUAL'; 222 ?LesserToken -> 'LESSER'; 223 ?GreaterToken -> 'GREATER'; 224 ?LbrktToken -> 'LBRKT'; 225 ?RbrktToken -> 'RBRKT'; 226 ?LsbrktToken -> 'LSBRKT'; 227 ?RsbrktToken -> 'RSBRKT'; 228 ?LparToken -> 'LPAR'; 229 ?RparToken -> 'RPAR'; 230 ?VbarToken -> 'VBAR'; 231 ?CommaToken -> 'COMMA' 232 end, 233 {Rest2, Line2} = skip_sep_chars(Rest, Line), 234 {token, {TokenTag, Line}, Rest2, Line2}. 235 236skip_sep_chars([Char | Rest] = All, Line) -> 237 case ?classify_char2(Char) of 238 rest_char when Char =:= ?SemiColonToken -> 239 skip_comment_chars(Rest, Line); 240 white_space -> 241 skip_sep_chars(Rest, Line); 242 end_of_line -> 243 skip_sep_chars(Rest, Line + 1); 244 _ -> 245 {All, Line} 246 end; 247skip_sep_chars([] = All, Line) -> 248 {All, Line}. 249 250skip_comment_chars([Char | Rest] = All, Line) -> 251 case ?classify_char(Char) of 252 safe_char_upper -> 253 skip_comment_chars(Rest, Line); 254 safe_char -> 255 skip_comment_chars(Rest, Line); 256 rest_char -> 257 skip_comment_chars(Rest, Line); 258 double_quote -> 259 skip_comment_chars(Rest, Line); 260 white_space -> 261 skip_comment_chars(Rest, Line); 262 end_of_line -> 263 skip_sep_chars(Rest, Line + 1); 264 _ -> 265 {All, Line} 266 end; 267skip_comment_chars([] = All, Line) -> 268 {All, Line}. 269 270quoted_chars([Char | Rest], Acc, Line) -> 271 case ?classify_char(Char) of 272 safe_char_upper -> 273 quoted_chars(Rest, [Char | Acc], Line); 274 safe_char -> 275 quoted_chars(Rest, [Char | Acc], Line); 276 rest_char -> 277 quoted_chars(Rest, [Char | Acc], Line); 278 white_space -> 279 quoted_chars(Rest, [Char | Acc], Line); 280 double_quote -> 281 {token, {'QuotedChars', Line, lists:reverse(Acc)}, Rest, Line}; 282 _ -> 283 {bad_token, {'QuotedChars', Line, Char}, Rest, Line} 284 end; 285quoted_chars([] = All, _Acc, Line) -> 286 {bad_token, {'QuotedChars', Line, end_of_input}, All, Line}. 287 288safe_chars([Char | Rest] = All, Acc, LowerAcc, Line, Version) -> 289 %% d("safe_chars -> entry with" 290 %% "~n Char: ~p" 291 %% "~n LowerAcc: ~p", [Char, LowerAcc]), 292 case ?classify_char3(Char) of 293 safe_char_upper -> 294 safe_chars(Rest, [Char | Acc], 295 [?LOWER2(Char) | LowerAcc], Line, Version); 296 safe_char -> 297 safe_chars(Rest, [Char | Acc], [Char | LowerAcc], Line, Version); 298 _ -> 299 LowerSafeChars = lists:reverse(LowerAcc), 300 TokenTag = select_token(LowerSafeChars, Version), 301 SafeChars = lists:reverse(Acc), 302 case TokenTag of 303 'MtpToken' -> 304 %% 'MtpToken' 'LBRKT' OctetString 'RBRKT' 305 special_chars(All, LowerSafeChars, Line, TokenTag); 306 'LocalToken' -> 307 %% 'LocalToken' 'LBRKT' OctetString 'RBRKT' 308 special_chars(All, SafeChars, Line, TokenTag); 309 'RemoteToken' -> 310 %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT' 311 special_chars(All, SafeChars, Line, TokenTag); 312 'DigitMapToken' -> 313 %% 'DigitMapToken' 314 %% 'DigitMapToken' 'EQUAL' Name 315 %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' Value 'RBRKT' 316 %% 'DigitMapToken' 'EQUAL' 'LBRKT' Value 'RBRKT' 317 %% 'DigitMapToken' 'LBRKT' Value 'RBRKT' 318 special_chars(All, LowerSafeChars, Line, TokenTag); 319 _ -> 320 {token, {TokenTag, Line, LowerSafeChars}, All, Line} 321 end 322 end; 323safe_chars([] = All, _Acc, LowerAcc, Line, Version) -> 324 LowerSafeChars = lists:reverse(LowerAcc), 325 TokenTag = select_token(LowerSafeChars, Version), 326 %%SafeChars = lists:reverse(Acc), 327 {token, {TokenTag, Line, LowerSafeChars}, All, Line}. 328 329collect_safe_chars([Char | Rest] = All, LowerAcc) -> 330 case ?classify_char3(Char) of 331 safe_char_upper -> 332 collect_safe_chars(Rest, [?LOWER2(Char) | LowerAcc]); 333 safe_char -> 334 collect_safe_chars(Rest, [Char | LowerAcc]); 335 _ -> 336 {All, lists:reverse(LowerAcc)} 337 end; 338collect_safe_chars([] = Rest, LowerAcc) -> 339 {Rest, lists:reverse(LowerAcc)}. 340 341special_chars(All, SafeChars, Line, TokenTag) -> 342 {Rest, Line2} = skip_sep_chars(All, Line), 343 case Rest of 344 [?LbrktToken | Rest2] -> 345 {token, {'OctetString', _, OctetString}, Rest4, Line4} = 346 octet_string(Rest2, Line2), 347 case Rest4 of 348 [?RbrktToken | Rest6] -> 349 Token = 350 case TokenTag of 351 'MtpToken' -> 352 %% 'MtpToken' 'LBRKT' OctetString 'RBRKT' 353 {'MtpAddressToken', Line, OctetString}; 354 'LocalToken' -> 355 %% 'LocalToken' 'LBRKT' OctetString 'RBRKT' 356 PGs = property_groups(OctetString), 357 {'LocalDescriptorToken', Line, PGs}; 358 'RemoteToken' -> 359 %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT' 360 PGs = property_groups(OctetString), 361 {'RemoteDescriptorToken', Line, PGs}; 362 'DigitMapToken' -> 363 %% 'DigitMapToken' 'LBRKT' OctetString 'RBRKT' 364 DMV = digit_map_value(OctetString), 365 DMD = #'DigitMapDescriptor'{digitMapValue = DMV}, 366 {'DigitMapDescriptorToken', Line, DMD} 367 end, 368 {token, Token, Rest6, Line4}; 369 _ when TokenTag =:= 'DigitMapToken' -> 370 %% 'DigitMapToken' 371 {token, {'DigitMapToken', Line, SafeChars}, All, Line}; 372 _ -> 373 {token, {'SafeChars', Line, SafeChars}, All, Line} 374 end; 375 [?EqualToken | Rest2] when TokenTag =:= 'DigitMapToken' -> 376 {Rest3, Line3} = skip_sep_chars(Rest2, Line2), 377 {Rest4, DigitMapName} = collect_safe_chars(Rest3, []), 378 {Rest6, Line6, DMD} = 379 if 380 DigitMapName =:= [] -> 381 {Rest3, Line3, #'DigitMapDescriptor'{}}; 382 true -> 383 {Rest5, Line5} = skip_sep_chars(Rest4, Line3), 384 {Rest5, Line5, #'DigitMapDescriptor'{digitMapName = DigitMapName}} 385 end, 386 case Rest6 of 387 [?LbrktToken | Rest7] -> 388 {token, {'OctetString', _, OctetString}, Rest8, Line8} = 389 octet_string(Rest7, Line6), 390 case Rest8 of 391 [?RbrktToken | Rest10] -> 392 %% 'DigitMapToken' 'EQUAL' 'LBRKT' OctetString 'RBRKT' 393 %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' OctetString 'RBRKT' 394 {Rest11, Line11} = skip_sep_chars(Rest10, Line8), 395 DMV = digit_map_value(OctetString), 396 DMD2 = DMD#'DigitMapDescriptor'{digitMapValue = DMV}, 397 {token, {'DigitMapDescriptorToken', Line, DMD2}, Rest11, Line11}; 398 _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE -> 399 %% 'DigitMapToken' 'EQUAL' Name 400 {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3}; 401 _ -> 402 %% 'DigitMapToken' 403 {token, {'DigitMapToken', Line, SafeChars}, All, Line} 404 end; 405 _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE -> 406 %% 'DigitMapToken' 'EQUAL' Name 407 {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3}; 408 _ -> 409 %% 'DigitMapToken' 410 {token, {'DigitMapToken', Line, SafeChars}, All, Line} 411 end; 412 _ when TokenTag =:= 'DigitMapToken' -> 413 %% 'DigitMapToken' 414 {token, {'DigitMapToken', Line, SafeChars}, All, Line}; 415 _ -> 416 %% 'DigitMapToken' 417 {token, {'SafeChars', Line, SafeChars}, All, Line} 418 end. 419 420octet_string(Chars, Line) -> 421 {Chars2, Line2} = skip_sep_chars(Chars, Line), 422 Acc = [], 423 {Rest, RevChars, RestLine} = octet_string(Chars2, Acc, Line2), 424 {RevChars2, _} = skip_sep_chars(RevChars, RestLine), 425 OctetString = lists:reverse(RevChars2), 426 {token, {'OctetString', Line, OctetString}, Rest, RestLine}. 427 428 429octet_string([Char | Rest] = All, Acc, Line) -> 430 if 431 (Char =:= ?CrToken) -> 432 octet_string(Rest, [Char | Acc], Line + 1); 433 (Char =:= ?LfToken) -> 434 octet_string(Rest, [Char | Acc], Line + 1); 435 (Char >= 8#1) andalso (Char =< 8#174) -> 436 octet_string(Rest, [Char | Acc], Line); 437 (Char >= 8#176) andalso (Char =< 8#377) -> 438 octet_string(Rest, [Char | Acc], Line); 439 (Char =:= ?BackslashToken) -> 440 case Rest of 441 [?RbrktToken | _Rest2] -> 442 %% OTP-4357 443 octet_string(Rest, 444 [?RbrktToken, ?BackslashToken | Acc], Line); 445 _ -> 446 octet_string(Rest, [Char | Acc], Line) 447 end; 448 true -> 449 {All, Acc, Line} 450 end; 451octet_string([] = All, Acc, Line) -> 452 {All, Acc, Line}. 453 454 455%% digitMapValue = ["T" COLON Timer COMMA] 456%% ["S" COLON Timer COMMA] 457%% ["L" COLON Timer COMMA] 458%% ["Z" COLON Timer COMMA] digitMap 459digit_map_value(Chars) -> 460 digit_map_value(Chars, #'DigitMapValue'{}). 461 462%% NOTE: The swap of the digitMapBody and the durationTimer is 463%% intentional. The reason is a problem with the flex scanner. 464%% Hopefully this is temporary... 465%% The values are swapped back later by the parser... 466digit_map_value([Char, ?ColonToken | Rest] = All, DMV) -> 467 case ?LOWER1(Char) of 468 $t -> digit_map_timer(All, Rest, #'DigitMapValue'.startTimer, DMV); 469 $s -> digit_map_timer(All, Rest, #'DigitMapValue'.shortTimer, DMV); 470 $l -> digit_map_timer(All, Rest, #'DigitMapValue'.longTimer, DMV); 471% $z -> digit_map_timer(All, Rest, #'DigitMapValue'.durationTimer, DMV); 472% _ -> DMV#'DigitMapValue'{digitMapBody = All} 473 $z -> digit_map_timer(All, Rest, #'DigitMapValue'.digitMapBody, DMV); 474 _ -> DMV#'DigitMapValue'{durationTimer = All} 475 end; 476digit_map_value(Chars, DMV) -> 477 DMV#'DigitMapValue'{durationTimer = Chars}. 478 479digit_map_timer(All, Chars, TimerPos, DMV) -> 480 {Rest, Digits} = collect_safe_chars(Chars, []), 481 {Rest2, _} = skip_sep_chars(Rest, 0), 482 case {Rest2, catch list_to_integer(Digits)} of 483 {[?CommaToken | Rest3], Int} when is_integer(Int) andalso 484 (Int >= 0) andalso 485 (element(TimerPos, DMV) =:= asn1_NOVALUE) -> 486 {Rest4, _} = skip_sep_chars(Rest3, 0), 487 DMV2 = setelement(TimerPos, DMV, Int), 488 digit_map_value(Rest4, DMV2); 489 _ -> 490 DMV#'DigitMapValue'{digitMapBody = All} 491 end. 492 493%% ============================================================================ 494%% <prev-parser-stuff> 495%% 496%% This stuff was originally in the parser(s), but was, 497%% for performance reasons, moved to the scanner(s). This 498%% scanner does not make it faster, but the flex scanner 499%% does, which is why the move was made. 500%% 501 502property_groups(OctetString) -> 503 Group = [], 504 Groups = [], 505 property_name(OctetString, Group, Groups). 506 507property_name([Char | Rest] = All, Group, Groups) -> 508 if 509 ?white_space(Char) -> 510 property_name(Rest, Group, Groups); 511 ?end_of_line(Char) -> 512 property_name(Rest, Group, Groups); 513 true -> 514 Name = [], 515 do_property_name(All, Name, Group, Groups) 516 end; 517property_name([] = All, Group, Groups) -> 518 Name = [], 519 do_property_name(All, Name, Group, Groups). 520 521do_property_name([Char | Rest], Name, Group, Groups) 522 when (Char =:= $=) andalso (Name =/= []) -> 523 %% Now we have a complete name 524 if 525 (Name =:= "v") andalso (Group =/= []) -> 526 %% v= is a property group delimiter, 527 %% lets create yet another property group. 528 Groups2 = [lists:reverse(Group) | Groups], 529 Group2 = [], 530 property_value(Rest, Name, Group2, Groups2); 531 true -> 532 %% Use current property group 533 property_value(Rest, Name, Group, Groups) 534 end; 535do_property_name([Char | Rest], Name, Group, Groups) -> 536 case ?classify_char4(Char) of 537 safe_char_upper -> 538 do_property_name(Rest, [Char | Name], Group, Groups); 539 safe_char -> 540 do_property_name(Rest, [Char | Name], Group, Groups); 541 _ -> 542 throw({error, {bad_prop_name, lists:reverse(Name), Char}}) 543 end; 544do_property_name([], [], [], Groups) -> 545 lists:reverse(Groups); 546do_property_name([], [], Group, Groups) -> 547 Group2 = lists:reverse(Group), 548 lists:reverse([Group2 | Groups]); 549do_property_name([], Name, Group, Groups) when Name =/= [] -> 550 %% Assume end of line 551 Value = [], 552 PP = make_property_parm(Name, Value), 553 Group2 = lists:reverse([PP | Group]), 554 lists:reverse([Group2 | Groups]). 555 556-ifdef(megaco_scanner_inline). 557-compile({inline,[{property_value,4}]}). 558-endif. 559property_value(Chars, Name, Group, Groups) -> 560 Value = [], 561 do_property_value(Chars, Name, Value, Group, Groups). 562 563do_property_value([Char | Rest], Name, Value, Group, Groups) -> 564 if 565 ?end_of_line(Char) -> 566 %% Now we have a complete "name=value" pair 567 PP = make_property_parm(Name, Value), 568 property_name(Rest, [PP | Group], Groups); 569 true -> 570 do_property_value(Rest, Name, [Char | Value], Group, Groups) 571 end; 572do_property_value([], Name, Value, Group, Groups) -> 573 %% Assume end of line 574 PP = make_property_parm(Name, Value), 575 Group2 = lists:reverse([PP | Group]), 576 lists:reverse([Group2 | Groups]). 577 578-ifdef(megaco_scanner_inline). 579-compile({inline,[{make_property_parm,2}]}). 580-endif. 581make_property_parm(Name, Value) -> 582 %% Record name, name field, value field, extraInfo field 583 {'PropertyParm', 584 lists:reverse(Name), 585 [lists:reverse(Value)], 586 asn1_NOVALUE}. 587 588 589%% </prev-parser-stuff> 590%% =========================================================================== 591 592select_token([$o, $- | LowerText], Version) -> 593 select_token(LowerText, Version); 594select_token([$w, $- | LowerText], Version) -> 595 select_token(LowerText, Version); 596select_token(LowerText, Version) -> 597 case LowerText of 598 "add" -> 'AddToken'; 599 "a" -> 'AddToken'; 600 "andlgc" when (Version >= 3) -> 'AndAUDITSelectToken'; % v3 601 "audit" -> 'AuditToken'; 602 "at" -> 'AuditToken'; 603 "auditcapability" -> 'AuditCapToken'; 604 "ac" -> 'AuditCapToken'; 605 "auditvalue" -> 'AuditValueToken'; 606 "av" -> 'AuditValueToken'; 607 "authentication" -> 'AuthToken'; 608 "au" -> 'AuthToken'; 609 "both" when (Version >= 3) -> 'BothToken'; % v3 610 "b" when (Version >= 3) -> 'BothToken'; % v3 611 "bothway" -> 'BothwayToken'; 612 "bw" -> 'BothwayToken'; 613 "brief" -> 'BriefToken'; 614 "br" -> 'BriefToken'; 615 "buffer" -> 'BufferToken'; 616 "bf" -> 'BufferToken'; 617 "context" -> 'CtxToken'; 618 "c" -> 'CtxToken'; 619 "contextattr" when (Version >= 3) -> 'ContextAttrToken'; % v3 620 "ct" when (Version >= 3) -> 'ContextAttrToken'; % v3 621 "contextlist" when (Version >= 3) -> 'ContextListToken'; % v3 622 "clt" when (Version >= 3) -> 'ContextListToken'; % v3 623 "contextaudit" -> 'ContextAuditToken'; 624 "ca" -> 'ContextAuditToken'; 625 "digitmap" -> 'DigitMapToken'; 626 "dm" -> 'DigitMapToken'; 627 "spadirection" when (Version >= 3) -> 'DirectionToken'; % v3 628 "direction" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b) 629 "spadi" when (Version >= 3) -> 'DirectionToken'; % v3 630 "di" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b) 631 "discard" -> 'DiscardToken'; 632 "ds" -> 'DiscardToken'; 633 "disconnected" -> 'DisconnectedToken'; 634 "dc" -> 'DisconnectedToken'; 635 "delay" -> 'DelayToken'; 636 "dl" -> 'DelayToken'; 637 "delete" -> 'DeleteToken'; 638 "de" -> 'DeleteToken'; 639 "duration" -> 'DurationToken'; 640 "dr" -> 'DurationToken'; 641 "embed" -> 'EmbedToken'; 642 "em" -> 'EmbedToken'; 643 "emergency" -> 'EmergencyToken'; 644 "eg" -> 'EmergencyToken'; 645 "emergencyofftoken" -> 'EmergencyOffToken'; 646 "emergencyoff" when (Version >= 3) -> 'EmergencyOffToken'; % v3 647 "ego" -> 'EmergencyOffToken'; 648 "emergencyvalue" when (Version >= 3) -> 'EmergencyValueToken'; % v3 649 "egv" when (Version >= 3) -> 'EmergencyValueToken'; % v3 650 "error" -> 'ErrorToken'; 651 "er" -> 'ErrorToken'; 652 "eventbuffer" -> 'EventBufferToken'; 653 "eb" -> 'EventBufferToken'; 654 "events" -> 'EventsToken'; 655 "e" -> 'EventsToken'; 656 "external" when (Version >= 3) -> 'ExternalToken'; % v3 657 "ex" when (Version >= 3) -> 'ExternalToken'; % v3 658 "failover" -> 'FailoverToken'; 659 "fl" -> 'FailoverToken'; 660 "forced" -> 'ForcedToken'; 661 "fo" -> 'ForcedToken'; 662 "graceful" -> 'GracefulToken'; 663 "gr" -> 'GracefulToken'; 664 "h221" -> 'H221Token'; 665 "h223" -> 'H223Token'; 666 "h226" -> 'H226Token'; 667 "handoff" -> 'HandOffToken'; 668 "ho" -> 'HandOffToken'; 669 "iepscall" when (Version >= 3) -> 'IEPSToken'; % v3 670 "ieps" when (Version >= 3) -> 'IEPSToken'; % v3 671 "inactive" -> 'InactiveToken'; 672 "in" -> 'InactiveToken'; 673 "internal" when (Version >= 3) -> 'InternalToken'; % v3 674 "it" when (Version >= 3) -> 'InternalToken'; % v3 675 "immackrequired" -> 'ImmAckRequiredToken'; 676 "ia" -> 'ImmAckRequiredToken'; 677 "inservice" -> 'InSvcToken'; 678 "intersignal" when (Version >= 3) -> 'IntsigDelayToken'; % v3 679 "spais" when (Version >= 3) -> 'IntsigDelayToken'; % v3 680 "intbyevent" -> 'InterruptByEventToken'; 681 "ibe" -> 'InterruptByEventToken'; 682 "intbysigdescr" -> 'InterruptByNewSignalsDescrToken'; 683 "ibs" -> 'InterruptByNewSignalsDescrToken'; 684 "iv" -> 'InSvcToken'; 685 "isolate" -> 'IsolateToken'; 686 "is" -> 'IsolateToken'; 687 "iterationtoken" when (Version >= 3) -> 'IterationToken'; % v3 688 "ir" when (Version >= 3) -> 'IterationToken'; % v3 689 "keepactive" -> 'KeepActiveToken'; 690 "ka" -> 'KeepActiveToken'; 691 "local" -> 'LocalToken'; 692 "l" -> 'LocalToken'; 693 "localcontrol" -> 'LocalControlToken'; 694 "lockstep" -> 'LockStepToken'; 695 "sp" -> 'LockStepToken'; 696 "o" -> 'LocalControlToken'; 697 "loopback" -> 'LoopbackToken'; 698 "lb" -> 'LoopbackToken'; 699 "media" -> 'MediaToken'; 700 "m" -> 'MediaToken'; 701 %% "megaco" -> 'MegacopToken'; 702 %% "!" -> 'megacoptoken'; 703 "segment" when (Version >= 3) -> 'MessageSegmentToken'; % v3 704 "sm" when (Version >= 3) -> 'MessageSegmentToken'; % v3 705 "method" -> 'MethodToken'; 706 "mt" -> 'MethodToken'; 707 "mtp" -> 'MtpToken'; 708 "mgcidtotry" -> 'MgcIdToken'; 709 "mg" -> 'MgcIdToken'; 710 "mode" -> 'ModeToken'; 711 "mo" -> 'ModeToken'; 712 "modify" -> 'ModifyToken'; 713 "mf" -> 'ModifyToken'; 714 "modem" -> 'ModemToken'; 715 "md" -> 'ModemToken'; 716 "move" -> 'MoveToken'; 717 "mv" -> 'MoveToken'; 718 "mux" -> 'MuxToken'; 719 "mx" -> 'MuxToken'; 720 "nevernotify" when (Version >= 3) -> 'NeverNotifyToken'; % v3 721 "nbnn" when (Version >= 3) -> 'NeverNotifyToken'; % v3 722 "notify" -> 'NotifyToken'; 723 "n" -> 'NotifyToken'; 724 "notifycompletion" -> 'NotifyCompletionToken'; 725 "nc" -> 'NotifyCompletionToken'; 726 "immediatenotify" when (Version >= 3) -> 'NotifyImmediateToken'; % v3 727 "nbin" when (Version >= 3) -> 'NotifyImmediateToken'; % v3 728 "regulatednotify" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3 729 "nbrn" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3 730 "nx64kservice" when (Version >= 2) -> 'Nx64kToken'; % v2 731 "n64" when (Version >= 2) -> 'Nx64kToken'; % v2 732 "observedevents" -> 'ObservedEventsToken'; 733 "oe" -> 'ObservedEventsToken'; 734 "oneway" -> 'OnewayToken'; 735 "ow" -> 'OnewayToken'; 736 "onewayboth" when (Version >= 3) -> 'OnewayBothToken'; % v3 737 "owb" when (Version >= 3) -> 'OnewayBothToken'; % v3 738 "onewayexternal" when (Version >= 3) -> 'OnewayExternalToken'; % v3 739 "owe" when (Version >= 3) -> 'OnewayExternalToken'; % v3 740 "off" -> 'OffToken'; 741 "on" -> 'OnToken'; 742 "onoff" -> 'OnOffToken'; 743 "oo" -> 'OnOffToken'; 744 "orlgc" when (Version >= 3) -> 'OrAUDITselectToken'; % v3 745 "otherreason" -> 'OtherReasonToken'; 746 "or" -> 'OtherReasonToken'; 747 "outofservice" -> 'OutOfSvcToken'; 748 "os" -> 'OutOfSvcToken'; 749 "packages" -> 'PackagesToken'; 750 "pg" -> 'PackagesToken'; 751 "pending" -> 'PendingToken'; 752 "pn" -> 'PendingToken'; 753 "priority" -> 'PriorityToken'; 754 "pr" -> 'PriorityToken'; 755 "profile" -> 'ProfileToken'; 756 "pf" -> 'ProfileToken'; 757 "reason" -> 'ReasonToken'; 758 "re" -> 'ReasonToken'; 759 "receiveonly" -> 'RecvonlyToken'; 760 "requestid" when (Version >= 3) -> 'RequestIDToken'; % v3 761 "rq" when (Version >= 3) -> 'RequestIDToken'; % v3 762 "rc" -> 'RecvonlyToken'; 763 "reply" -> 'ReplyToken'; 764 "p" -> 'ReplyToken'; 765 "reseteventsdescriptor" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3 766 "rse" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3 767 "transactionresponseack"-> 'ResponseAckToken'; 768 "k" -> 'ResponseAckToken'; 769 "restart" -> 'RestartToken'; 770 "rs" -> 'RestartToken'; 771 "remote" -> 'RemoteToken'; 772 "r" -> 'RemoteToken'; 773 "sparequestid" -> 'RequestIDToken'; 774 "sparq" -> 'RequestIDToken'; 775 "reservedgroup" -> 'ReservedGroupToken'; 776 "rg" -> 'ReservedGroupToken'; 777 "reservedvalue" -> 'ReservedValueToken'; 778 "rv" -> 'ReservedValueToken'; 779 "end" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3 780 "&" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3 781 "sendonly" -> 'SendonlyToken'; 782 "so" -> 'SendonlyToken'; 783 "sendreceive" -> 'SendrecvToken'; 784 "sr" -> 'SendrecvToken'; 785 "services" -> 'ServicesToken'; 786 "sv" -> 'ServicesToken'; 787 "servicestates" -> 'ServiceStatesToken'; 788 "si" -> 'ServiceStatesToken'; 789 "servicechange" -> 'ServiceChangeToken'; 790 "sc" -> 'ServiceChangeToken'; 791 "servicechangeaddress" -> 'ServiceChangeAddressToken'; 792 "ad" -> 'ServiceChangeAddressToken'; 793 "servicechangeinc" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3 794 "sic" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3 795 "signallist" -> 'SignalListToken'; 796 "sl" -> 'SignalListToken'; 797 "signals" -> 'SignalsToken'; 798 "sg" -> 'SignalsToken'; 799 "signaltype" -> 'SignalTypeToken'; 800 "sy" -> 'SignalTypeToken'; 801 "statistics" -> 'StatsToken'; 802 "sa" -> 'StatsToken'; 803 "stream" -> 'StreamToken'; 804 "st" -> 'StreamToken'; 805 "subtract" -> 'SubtractToken'; 806 "s" -> 'SubtractToken'; 807 "synchisdn" -> 'SynchISDNToken'; 808 "sn" -> 'SynchISDNToken'; 809 "terminationstate" -> 'TerminationStateToken'; 810 "ts" -> 'TerminationStateToken'; 811 "test" -> 'TestToken'; 812 "te" -> 'TestToken'; 813 "timeout" -> 'TimeOutToken'; 814 "to" -> 'TimeOutToken'; 815 "topology" -> 'TopologyToken'; 816 "tp" -> 'TopologyToken'; 817 "transaction" -> 'TransToken'; 818 "t" -> 'TransToken'; 819 "v18" -> 'V18Token'; 820 "v22" -> 'V22Token'; 821 "v22b" -> 'V22bisToken'; 822 "v32" -> 'V32Token'; 823 "v32b" -> 'V32bisToken'; 824 "v34" -> 'V34Token'; 825 "v76" -> 'V76Token'; 826 "v90" -> 'V90Token'; 827 "v91" -> 'V91Token'; 828 "version" -> 'VersionToken'; 829 "v" -> 'VersionToken'; 830 [_,_,_,_,_,_,_,_,$t,_,_,_,_,_,_,_,_] -> % Could be a time-stamp 831 [D1,D2,D3,D4,D5,D6,D7,D8,_,T1,T2,T3,T4,T5,T6,T7,T8] = LowerText, 832 select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8, 833 T1,T2,T3,T4,T5,T6,T7,T8); 834 _ -> 'SafeChars' 835 end. 836 837select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8, 838 T1,T2,T3,T4,T5,T6,T7,T8) 839 when ($0 =< D1) andalso (D1 =< $9) andalso 840 ($0 =< D2) andalso (D2 =< $9) andalso 841 ($0 =< D3) andalso (D3 =< $9) andalso 842 ($0 =< D4) andalso (D4 =< $9) andalso 843 ($0 =< D5) andalso (D5 =< $9) andalso 844 ($0 =< D6) andalso (D6 =< $9) andalso 845 ($0 =< D7) andalso (D7 =< $9) andalso 846 ($0 =< D8) andalso (D8 =< $9) andalso 847 ($0 =< T1) andalso (T1 =< $9) andalso 848 ($0 =< T2) andalso (T2 =< $9) andalso 849 ($0 =< T3) andalso (T3 =< $9) andalso 850 ($0 =< T4) andalso (T4 =< $9) andalso 851 ($0 =< T5) andalso (T5 =< $9) andalso 852 ($0 =< T6) andalso (T6 =< $9) andalso 853 ($0 =< T7) andalso (T7 =< $9) andalso 854 ($0 =< T8) andalso (T8 =< $9) -> 855 'TimeStampToken'; 856select_TimeStampToken(_D1,_D2,_D3,_D4,_D5,_D6,_D7,_D8, 857 _T1,_T2,_T3,_T4,_T5,_T6,_T7,_T8) -> 858 'SafeChars'. 859 860 861%% d(F) -> 862%% d(F, []). 863 864%% d(F, A) -> 865%% d(get(dbg), F, A). 866 867%% d(true, F, A) -> 868%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]); 869%% d(_, _, _) -> 870%% ok. 871