anchor.diff:                      info(<<"http://www.example.com/alice/">>, [{purpose, info}, {param, <<"value">>}])],
                      parse('call-info', <<"<http://wwww.example.com/alice/photo.jpg> ;purpose=icon, <http://www.example.com/alice/> ;purpose=info;param=\"value\"">>)),
        ?_assertEqual(<<"<http://wwww.example.com/alice/photo.jpg>;purpose=icon, <http://www.example.com/alice/>;purpose=info;param=value">>,
  -                   format('alert-info',
  +                   format('call-info',
                             [info(<<"http://wwww.example.com/alice/photo.jpg">>, [{purpose, icon}]),
                              info(<<"http://www.example.com/alice/">>, [{purpose, info}, {param, <<"value">>}])])),
   
  
positive.code:     end,
      {Params, Rest} = parse_params(ParamsBin, fun parse_q_param/2),
      {TokenBin, Params, Rest}.
  
  %% @doc Format header value into the binary.
  %% @end
  -spec format(atom() | binary(), binary() | term()) -> binary().
  format(_Name, Value) when is_binary(Value) ->
      % already formatted to binary
      Value;
  % generalized multi-value headers handling
  format(Name, [Value]) -> format(Name, Value);
  format(Name, [Top | Rest]) ->
      Joiner = fun (Elem, Bin) ->
                        ElemBin = format(Name, Elem),
                        <<Bin/binary, ?COMMA, ?SP, ElemBin/binary>>
               end,
      TopBin = format(Name, Top),
      lists:foldl(Joiner, TopBin, Rest);
  
  %% ```
  %% Accept         =  "Accept" HCOLON
  %%                    [ accept-range *(COMMA accept-range) ]
  %% accept-range   =  media-range *(SEMI accept-param)
  %% media-range    =  ( "*/*"
  %%                   / ( m-type SLASH "*" )
  %%                   / ( m-type SLASH m-subtype )
  %%                   ) *( SEMI m-parameter )
  %% accept-param   =  ("q" EQUAL qvalue) / generic-param
  %% qvalue         =  ( "0" [ "." 0*3DIGIT ] )
  %%                   / ( "1" [ "." 0*3("0") ] )
  %% generic-param  =  token [ EQUAL gen-value ]
  %% gen-value      =  token / host / quoted-string
  %% media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
  %% m-type           =  discrete-type / composite-type
  %% discrete-type    =  "text" / "image" / "audio" / "video"
  %%                     / "application" / extension-token
  %% composite-type   =  "message" / "multipart" / extension-token
  %% extension-token  =  ietf-token / x-token
  %% ietf-token       =  token
  %% x-token          =  "x-" token
  %% m-subtype        =  extension-token / iana-token
  %% m-parameter      =  m-attribute EQUAL m-value
  %% m-attribute      =  token
  %% m-value          =  token / quoted-string
  %% '''
  format('accept', Accept) when is_record(Accept, sip_hdr_mediatype) ->
      Type = sip_binary:any_to_binary(Accept#sip_hdr_mediatype.type),
      SubType = sip_binary:any_to_binary(Accept#sip_hdr_mediatype.subtype),
      append_params(<<Type/binary, ?SLASH, SubType/binary>>, Accept#sip_hdr_mediatype.params);
  
  %% ```
  %% Accept-Encoding  =  "Accept-Encoding" HCOLON
  %%                      [ encoding *(COMMA encoding) ]
  %% encoding         =  codings *(SEMI accept-param)
  %% codings          =  content-coding / "*"
  %% content-coding   =  token
  %% '''
  format('accept-encoding', Accept) when is_record(Accept, sip_hdr_encoding) ->
      Encoding = sip_binary:any_to_binary(Accept#sip_hdr_encoding.encoding),
      append_params(Encoding, Accept#sip_hdr_encoding.params);
  
  %% ```
  %% Accept-Language  =  "Accept-Language" HCOLON
  %%                      [ language *(COMMA language) ]
  %% language         =  language-range *(SEMI accept-param)
  %% language-range   =  ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
  %% '''
  format('accept-language', Accept) when is_record(Accept, sip_hdr_language) ->
      LangBin = sip_binary:any_to_binary(Accept#sip_hdr_language.lang),
      Bin =
          case Accept#sip_hdr_language.sublang of
              undefined ->
                  LangBin;
              SubLang ->
                  SublangBin = sip_binary:any_to_binary(SubLang),
                  <<LangBin/binary, $-, SublangBin/binary>>
          end,
      append_params(Bin, Accept#sip_hdr_language.params);
  
  %% ```
  %% Alert-Info   =  "Alert-Info" HCOLON alert-param *(COMMA alert-param)
  %% alert-param  =  LAQUOT absoluteURI RAQUOT *( SEMI generic-param )
  %%
  %% Call-Info   =  "Call-Info" HCOLON info *(COMMA info)
  %% info        =  LAQUOT absoluteURI RAQUOT *( SEMI info-param)
  %% info-param  =  ( "purpose" EQUAL ( "icon" / "info"
  %%                / "card" / token ) ) / generic-param
  %% '''
  format(Name, Info) when (Name =:= 'alert-info' orelse Name =:= 'call-info'),
    is_record(Info, sip_hdr_info) ->
      URI = sip_uri:format(Info#sip_hdr_info.uri),
      Bin = <<?LAQUOT, URI/binary, ?RAQUOT>>,
      append_params(Bin, Info#sip_hdr_info.params);
  
  %% ```
  %% Authentication-Info  =  "Authentication-Info" HCOLON ainfo
  %%                         *(COMMA ainfo)
  %% ainfo                =  nextnonce / message-qop
  %%                          / response-auth / cnonce
  %%                          / nonce-count
  %% nextnonce            =  "nextnonce" EQUAL nonce-value
  %% nonce-value          =  quoted-string
  %% response-auth        =  "rspauth" EQUAL response-digest
  %% response-digest      =  LDQUOT *LHEX RDQUOT
  %% message-qop          =  "qop" EQUAL qop-value
  %% qop-value            =  "auth" / "auth-int" / token
  %% nonce-count          =  "nc" EQUAL nc-value
  %% nc-value             =  8LHEX
  %% cnonce               =  "cnonce" EQUAL cnonce-value
  %% cnonce-value         =  nonce-value
  %% '''
  format('authentication-info', Pair) ->
      format_auth(Pair);
  
  %% ```
  %% Authorization     =  "Authorization" HCOLON credentials
  %% credentials       =  ("Digest" LWS digest-response)
  %%                     / other-response
  %% digest-response   =  dig-resp *(COMMA dig-resp)
  %% dig-resp          =  username / realm / nonce / digest-uri
  %%                       / dresponse / algorithm / cnonce
  %%                       / opaque / message-qop
  %%                       / nonce-count / auth-param
  %% username          =  "username" EQUAL username-value
  %% username-value    =  quoted-string
  %% digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
  %% digest-uri-value  =  rquest-uri ; Equal to request-uri as specified by HTTP/1.1
  %% other-response    =  auth-scheme LWS auth-param
  %%                     *(COMMA auth-param)
  %% auth-scheme       =  token
  %% auth-param        =  auth-param-name EQUAL
  %%                      ( token / quoted-string )
  %% auth-param-name   =  token
  %% '''
  format('authorization', Auth) when is_record(Auth, sip_hdr_auth) ->
      SchemeBin = sip_binary:any_to_binary(Auth#sip_hdr_auth.scheme),
      [First | Rest] = Auth#sip_hdr_auth.params,
      FirstBin = format_auth(First),
      Fun = fun (Val, Acc) -> <<Acc/binary, ?COMMA, ?SP, (format_auth(Val))/binary>> end,
      lists:foldl(Fun, <<SchemeBin/binary, ?SP, FirstBin/binary>>, Rest);
  
  %% Via               =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
  %% via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
  %% via-params        =  via-ttl / via-maddr
  %%                      / via-received / via-branch
  %%                      / via-extension
  %% sent-protocol     =  protocol-name SLASH protocol-version
  %%                      SLASH transport
  format('via', Via) when is_record(Via, sip_hdr_via) ->
      Version = Via#sip_hdr_via.version,
      Transport = sip_binary:to_upper(atom_to_binary(Via#sip_hdr_via.transport, latin1)),
      Bin = <<"SIP/", Version/binary, $/, Transport/binary>>,
      Host = sip_binary:addr_to_binary(Via#sip_hdr_via.host),
      Bin2 = case Via#sip_hdr_via.port of
          undefined ->
              <<Bin/binary, ?SP, Host/binary>>;
          Port ->
              <<Bin/binary, ?SP, Host/binary, ?HCOLON, (sip_binary:integer_to_binary(Port))/binary>>
      end,
      append_params(Bin2, Via#sip_hdr_via.params);
  
  %% Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
  format('content-length', Length) when is_integer(Length) ->
      sip_binary:integer_to_binary(Length);
  
  %% CSeq  =  "CSeq" HCOLON 1*DIGIT LWS Method
  format('cseq', CSeq) when is_record(CSeq, sip_hdr_cseq) ->
      SequenceBin = sip_binary:integer_to_binary(CSeq#sip_hdr_cseq.sequence),
      MethodBin = sip_binary:any_to_binary(CSeq#sip_hdr_cseq.method),
      <<SequenceBin/binary, " ", MethodBin/binary>>;
  
  %% Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
  format('max-forwards', Hops) when is_integer(Hops) ->
      sip_binary:integer_to_binary(Hops);
  
  %% Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
  %% Call id is always a binary, so handled by first case
  
  %% ```
  %% To             =  ( "To" / "t" ) HCOLON ( name-addr / addr-spec ) *( SEMI to-param )
  %% to-param       =  tag-param / generic-param
  %%
  %% From           =  ( "From" / "f" ) HCOLON from-spec
  %% from-spec      =  ( name-addr / addr-spec ) *( SEMI from-param )
  %% from-param     =  tag-param / generic-param
  %%
  %% Contact        =  ("Contact" / "m" ) HCOLON
  %%                  ( STAR / (contact-param *(COMMA contact-param)))
  %% contact-param  =  (name-addr / addr-spec) *(SEMI contact-params)
  %% contact-params     =  c-p-q / c-p-expires
  %%                      / contact-extension
  %% c-p-q              =  "q" EQUAL qvalue
  %% c-p-expires        =  "expires" EQUAL delta-seconds
  %% contact-extension  =  generic-param
  %% delta-seconds      =  1*DIGIT
  %%
  %% Route              =  "Route" HCOLON route-param *(COMMA route-param)
  %% route-param        =  name-addr *( SEMI rr-param )
  %% rr-param           =  generic-param
  %%
  %% Record-Route       =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
  %% rec-route          =  name-addr *( SEMI rr-param )
  %%
  %% name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
  %% addr-spec      =  SIP-URI / SIPS-URI / absoluteURI
  %% display-name   =  *(token LWS)/ quoted-string
  %% '''
  format('contact', '*') -> <<"*">>;
  format(Name, #sip_hdr_address{} = Addr) when
    Name =:= 'from';
    Name =:= 'to';
    Name =:= 'contact';
    Name =:= 'route';
    Name =:= 'record-route' ->
  
      URIBin = sip_uri:format(Addr#sip_hdr_address.uri),
      Bin = case Addr#sip_hdr_address.display_name of
                <<>> -> <<?LAQUOT, URIBin/binary, ?RAQUOT>>;
                DisplayName ->
                    Quoted = sip_binary:quote_string(DisplayName),
                    <<Quoted/binary, " ", ?LAQUOT, URIBin/binary, ?RAQUOT>>
            end,
      append_params(Bin, Addr#sip_hdr_address.params);
  
  %% Any other header
  format(_Name, Value) ->
      sip_binary:any_to_binary(Value).
  
  %% @doc Append parameters to the binary
  %% @end
  
negative.code:     Info = info(URI, Params),
      parse_list(Name, Info, Rest).
  
  %% Parse Accept-Encoding/Accept-Language grammar
  parse_accept(Bin) ->
      {TokenBin, ParamsBin} =
          case sip_binary:trim_leading(Bin) of
  