anchor.diff:  %% *(R)   = 0*inifinity(R) i.e. rule R may be applied any number of
   %%          times
   %% [R]    = *1(R), i.e. apply this rule 0-1 times
  -%% "string" = quoted strings are case insensetive
  +%% "string" = quoted strings are case insensitive
   %% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   
   %% RFC 2234 and RFC 3261 - - - - - - - - - - - - - - - - - - - - - - -
  
positive.code:     %% qvalue = 0 - 1 | 0.000 - 1.000 | 0. - 1.
      QVal = string:strip(Str, right, $.),
      case sipparse_util:is_qval(QVal) of
  	true -> 
  	    Float = sipparse_util:str_to_qval(QVal),
  	    lists:flatten(io_lib:format("~.3f",[Float]));
  	false -> 
  	    throw({error, malformed_qvalue})
      end.
  
  %% return: true if first and last char is a $" - strings of length < 2 -> false as well
  %% Note: does not check data inside quotes
  is_quoted([$\" | R]) ->
      case lists:reverse(R) of
  	[$\" | _] -> true;
  	_ -> false
  	end;
  	 is_quoted(_Str) ->
  		false.
  
  %% may contain a display name
  parse_name_addr(Str) ->
      %% remove any spaces around Str data in "Contact : ... ,Str, ...."
      Stripped = sipparse_util:strip(Str, both, [?SP,?HTAB]),
      %% Check for optional display name
      %% XXX what if there is a '<' in a quoted display name? Is that valid or invalid?
      %% The string:tokens() will fail on it.
      {DisplayName, Rest} =
  	case string:tokens(Stripped, "<") of
  	    [DispName, R] ->
  		%% unquote
  		%% strict conformance to BNF requires DispName to end on a LWS
  		%% - we don't check for this
  		DispNameNoWhiteSpaces = sipparse_util:strip(DispName, both, [?SP,?HTAB]),
  		StrippedName =
  		    case DispNameNoWhiteSpaces of
  			[34 | _] ->	%% 34 is "
  			    %% quoted display name
  			    %% XXX remove the quotes but leave any escaped quotes untouched!
  			    string:strip(DispNameNoWhiteSpaces, both, 34);	%% 34 is "
  			_ ->
  			    %% not quoted - check if it is a token
  			    true = sipparse_util:is_token(DispNameNoWhiteSpaces),
  			    DispNameNoWhiteSpaces
  		    end,
  		{StrippedName, R};
  	    [R] ->
  		{none, R}
  	end,
      %% get the xxx contents of "<xxx>"
      [AddrSpec] = string:tokens(Rest, ">"),
      SipUrl = AddrSpec, %% sipurl:parse(AddrSpec),
      {DisplayName, SipUrl}.
  
  
  parse_addr_spec(Str) ->
      %% remove any spaces around xxxx data in "Contact : ... , xxxx , ...."
      Stripped = sipparse_util:strip(Str, both, [?SP,?HTAB]),
  
      %% XXX does not handle absoluteURI
      SipUrl = Stripped, %% sipurl:parse(Stripped),
      {none, SipUrl}.
  
  
  %% strip_preceding(Str, CharList)
  %%
  strip_preceding("", _CharList) ->
      "";
  strip_preceding([C | R] = Str, CharList) ->
      case lists:member(C, CharList) of
  	true ->
  	    strip_preceding(R, CharList);
  	false ->
  	    Str
      end.
  
  %%--------------------------------------------------------------------
  %% Function: print(Contact)
  
negative.code: %% (Note that display_name is optional)
  %% Code assumes that ";" isn't used as anything but a parameter separator inside the contact-param rule
  parse_contact(Str) ->
      StrippedStr = sipparse_util:strip(Str, both, [?SP, ?HTAB]),
  
      {Set_DisplayName, Set_UrlStr, Set_Params} =
  	%% look for quoted display-name
  	try sipparse_util:split_quoted_string(StrippedStr) of
  	    {ok, DisplayNameStr, Rest} ->
  		DisplayName = case DisplayNameStr of
  				  "" -> none;
  				  _ -> DisplayNameStr
  			      end,
  		%% Ok, display-name part finished, now look if there are any parameters
  
  		{URLstr1, Params} = parse_addr_and_param(Rest),
  		{DisplayName, URLstr1, Params}
  	catch
  	    error: does_not_start_with_quote ->
  		parse_contact_no_quoted_displayname(StrippedStr)
  	end,
  
      %% process the Params and build the final contact record
      #contact{
  	  display_name = Set_DisplayName,
  	  urlstr = Set_UrlStr,
  	  contact_param = parse_params(Set_Params)
  	 }.
  
  %% Returns : {DisplayName, URLstr, Params}
  %%           DisplayName = string() | none
  %%           URLstr      = string(), URL as string, without enclosing <>
  %%           Params      = string(), contact parameters
  parse_contact_no_quoted_displayname(StrippedStr) ->
      %% If there is a display-name there, it isn't quoted
      case catch sipparse_util:split_fields(StrippedStr, $<) of
  	{DisplayNameStr, Rest} when is_list(DisplayNameStr), is_list(Rest) ->
  	    DisplayName = sipparse_util:strip(DisplayNameStr, right, [?SP, ?HTAB]),
  	    %% Verify that un-quoted DisplayName is a valid token. We are extra lenient
  	    %% here, and allow spaces too (since it is a common error to put
  	    %% Firstname Lastname in contacts without quotes). What is really important
  	    %% is to not be fooled by contacts such as
  	    %%   "Foo <sip:bar@example.org> <sip:other@example.org">
  	    DisplayNameNoSpaces = lists:append(string:tokens(DisplayName, " ")),
  	    case sipparse_util:is_token(DisplayNameNoSpaces) of
  		true -> ok;
  		false -> throw({error, {unquoted_displayname_is_not_a_valid_token, DisplayName}})
  	    end,
  	    {URLstr1, Params} = parse_addr_and_param("<" ++ Rest),
  	    {DisplayName, URLstr1, Params};
  	{_Foo} ->
  	    %% No "<" in StrippedStr, look for parameters (everything after ";")
  	    {AddrSpec, Params} =
  		case sipparse_util:split_fields(StrippedStr, $;) of
  		    {AddrSpec2, Params2} ->
  			{sipparse_util:strip(AddrSpec2, right, [?SP, ?HTAB]),
  			 Params2};
  		    {AddrSpec2} ->
  			{sipparse_util:strip(AddrSpec2, right, [?SP, ?HTAB]),
  			 ""}
  		end,
  	    %% Since we did not have even a "<" to tell us where the addr-spec
  	    %% started, we verify that what we found is a parseable SIP URI
  	    case sipurl:parse(AddrSpec) of
  		URI when is_record(URI, sipurl) -> ok;
  		_ -> throw({error, {unparseable_uri_without_brackets, AddrSpec}})
  	    end,
  	    {none, AddrSpec, Params};
  	{error, no_first_part} ->
  	    %% Nothing found before the "<"
  	    {URLstr1, Params} = parse_addr_and_param(StrippedStr),
  	    {none, URLstr1, Params}
      end.
  
  %% Returns : {URLstr, Params}
  %%           URLstr = string()
  %%           Params = string()
  parse_addr_and_param(In) ->
      Stripped = sipparse_util:strip(In, both, [?SP, ?HTAB]),
      case Stripped of
  	"<" ++ Rest ->
  	    %% There is a "<" after the display-name, split at the ">" that we
  	    %% can expect to be there (or crash on if it isn't)
  	    case string:tokens(Rest, ">") of
  		[AddrSpec, Params] ->
  		    {sipparse_util:strip(AddrSpec, both, [?SP, ?HTAB]),
  		     sipparse_util:strip(Params, both, [?SP, ?HTAB])};
  		[AddrSpec] ->
  		    {sipparse_util:strip(AddrSpec, both, [?SP, ?HTAB]),
  		     ""}
  	    end;
  	_ ->
  	    %% No "<", Stripped is an addr-spec
  	    case sipparse_util:split_fields(Stripped, $;) of
  		{AddrSpec, Params2} ->
  		    {sipparse_util:strip(AddrSpec, right, [?SP, ?HTAB]),
  		     Params2};
  		{AddrSpec} ->
  		    {sipparse_util:strip(AddrSpec, right, [?SP, ?HTAB]),
  		     ""}
  	    end
      end.
  
  
  %% input = data after first ";"
  %% return: contact_param record()
  %%
  parse_params([]) ->
      contact_param:to_norm([]);
  