1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2010-2017. 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%% This module turns a dictionary file into the orddict that
23%% diameter_codegen.erl in turn morphs into .erl and .hrl files for
24%% encode and decode of Diameter messages and AVPs.
25%%
26
27-module(diameter_dict_util).
28
29-export([parse/2,
30         format_error/1,
31         format/1]).
32
33-include("diameter_vsn.hrl").
34
35-define(RETURN(T), throw({T, ?MODULE, ?LINE})).
36-define(RETURN(T, Args), ?RETURN({T, Args})).
37
38-define(A, list_to_atom).
39-define(L, atom_to_list).
40-define(I, integer_to_list).
41-define(F, io_lib:format).
42
43%% ===========================================================================
44%% parse/2
45%% ===========================================================================
46
47-spec parse(File, Opts)
48   -> {ok, orddict:orddict()}
49    | {error, term()}
50 when File :: {path, file:name_all()}
51            | iolist()
52            | binary(),
53      Opts :: list().
54
55parse(File, Opts) ->
56    putr(verbose, lists:member(verbose, Opts)),
57    try
58        {ok, do_parse(File, Opts)}
59    catch
60        {Reason, ?MODULE, _Line} ->
61            {error, Reason}
62    after
63        eraser(verbose)
64    end.
65
66%% ===========================================================================
67%% format_error/1
68%% ===========================================================================
69
70format_error({read, Reason}) ->
71    file:format_error(Reason);
72format_error({scan, Reason}) ->
73    diameter_dict_scanner:format_error(Reason);
74format_error({parse, {Line, _Mod, Reason}}) ->
75    lists:flatten(["Line ", ?I(Line), ", ", Reason]);
76
77format_error(T) ->
78    {Fmt, As} = fmt(T),
79    lists:flatten(io_lib:format(Fmt, As)).
80
81fmt({avp_code_already_defined = E, [Code, false, Name, Line, L]}) ->
82    {fmt(E), [Code, "", Name, Line, L]};
83fmt({avp_code_already_defined = E, [Code, Vid, Name, Line, L]}) ->
84    {fmt(E), [Code, ?F("/~p", [Vid]), Name, Line, L]};
85
86fmt({uint32_out_of_range = E, [id | T]}) ->
87    {fmt(E), ["@id", "application identifier" | T]};
88fmt({uint32_out_of_range = E, [K | T]})
89  when K == vendor;
90       K == avp_vendor_id ->
91    {fmt(E), [?F("@~p", [K]), "vendor id" | T]};
92fmt({uint32_out_of_range = E, [K, Name | T]})
93  when K == enum;
94       K == define ->
95    {fmt(E), [?F("@~p ~s", [K, Name]), "value" | T]};
96fmt({uint32_out_of_range = E, [avp_types, Name | T]}) ->
97    {fmt(E), ["AVP " ++ Name, "AVP code" | T]};
98fmt({uint32_out_of_range = E, [grouped, Name | T]}) ->
99    {fmt(E), ["Grouped AVP " ++ Name | T]};
100fmt({uint32_out_of_range = E, [messages, Name | T]}) ->
101    {fmt(E), ["Message " ++ Name, "command code" | T]};
102
103fmt({Reason, As}) ->
104    {fmt(Reason), As};
105
106fmt(avp_code_already_defined) ->
107    "AVP ~p~s (~s) at line ~p already defined at line ~p";
108
109fmt(uint32_out_of_range) ->
110    "~s specifies ~s ~p at line ~p that is out of range for a value of "
111    "Diameter type Unsigned32";
112
113fmt(imported_avp_already_defined) ->
114    "AVP ~s imported by @inherits ~p at line ~p defined at line ~p";
115fmt(duplicate_import) ->
116    "AVP ~s is imported by more than one @inherits, both at line ~p "
117    "and at line ~p";
118
119fmt(duplicate_section) ->
120    "Section @~s at line ~p already declared at line ~p";
121
122fmt(already_declared) ->
123    "Section @~p ~s at line ~p already declared at line ~p";
124
125fmt(inherited_avp_already_defined) ->
126    "AVP ~s inherited at line ~p defined in @avp_types at line ~p";
127fmt(avp_already_defined) ->
128    "AVP ~s at line ~p already in @~p at line ~p";
129fmt(key_already_defined) ->
130    "Value for ~s:~s in @~p at line ~p already provided at line ~p";
131
132fmt(messages_without_id) ->
133    "@messages at line ~p but @id not declared";
134
135fmt(avp_name_already_defined) ->
136    "AVP ~s at line ~p already defined at line ~p";
137fmt(avp_has_unknown_type) ->
138    "AVP ~s at line ~p defined with unknown type ~s";
139fmt(avp_has_invalid_flag) ->
140    "AVP ~s at line ~p specifies invalid flag ~c";
141fmt(avp_has_duplicate_flag) ->
142    "AVP ~s at line ~p specifies duplicate flag ~c";
143fmt(avp_has_vendor_id) ->
144    "AVP ~s at line ~p does not specify V flag "
145    "but is assigned vendor id ~p at line ~p";
146fmt(avp_has_no_vendor) ->
147    "AVP ~s at line ~p specifies V flag "
148    "but neither @vendor_avp_id nor @vendor supplies a value";
149
150fmt(group_already_defined) ->
151    "Group ~s at line ~p already defined at line ~p";
152fmt(grouped_avp_code_mismatch) ->
153    "AVP ~s at line ~p has with code ~p "
154    "but @avp_types specifies ~p at line ~p";
155fmt(grouped_avp_has_wrong_type) ->
156    "Grouped AVP ~s at line ~p defined with type ~s at line ~p";
157fmt(grouped_avp_not_defined) ->
158    "Grouped AVP ~s on line ~p not defined in @avp_types";
159fmt(grouped_avp_not_grouped) ->
160    "Grouped AVP ~s on line ~p not defined in @grouped";
161fmt(grouped_vendor_id_without_flag) ->
162    "Grouped AVP ~s at line ~p has vendor id "
163    "but definition at line ~p does not specify V flag";
164fmt(grouped_vendor_id_mismatch) ->
165    "Grouped AVP ~s at line ~p has vendor id ~p "
166    "but ~p specified at line ~p";
167
168fmt(message_name_already_defined) ->
169    "Message ~s at line ~p already defined at line ~p";
170fmt(message_code_already_defined) ->
171    "~s message with code ~p at line ~p already defined at line ~p";
172fmt(message_has_duplicate_flag) ->
173    "Message ~s has duplicate flag ~s at line ~p";
174fmt(message_application_id_mismatch) ->
175    "Message ~s has application id ~p at line ~p "
176    "but @id specifies ~p at line ~p";
177
178fmt(invalid_avp_order) ->
179    "AVP reference ~c~s~c at line ~p breaks fixed/required/optional order";
180fmt(required_avp_has_zero_max_arity) ->
181    "Required AVP has maximum arity 0 at line ~p";
182fmt(required_avp_has_zero_min_arity) ->
183    "Required AVP has minimum arity 0 at line ~p";
184fmt(optional_avp_has_nonzero_min_arity) ->
185    "Optional AVP has non-zero minimum arity at line ~p";
186fmt(qualifier_has_min_greater_than_max) ->
187    "Qualifier ~p*~p at line ~p has Min > Max";
188fmt(avp_already_referenced) ->
189    "AVP ~s at line ~p already referenced at line ~p";
190
191fmt(message_missing) ->
192    "~s message at line ~p but no ~s message is defined";
193
194fmt(requested_avp_not_found) ->
195    "@inherit ~s at line ~p requests AVP ~s at line ~p "
196    "but module does not define that AVP";
197
198fmt(enumerated_avp_has_wrong_local_type) ->
199    "Enumerated AVP ~s in @enum at line ~p defined with type ~s at line ~p";
200fmt(enumerated_avp_has_wrong_inherited_type) ->
201    "Enumerated AVP ~s in @enum at line ~p "
202    "inherited with type ~s from module ~s at line ~p";
203fmt(enumerated_avp_not_defined) ->
204    "Enumerated AVP ~s in @enum at line ~p neither defined nor inherited";
205
206fmt(avp_not_defined) ->
207    "AVP ~s referenced at line ~p neither defined nor inherited";
208
209fmt(recompile) ->
210    "Module ~p appears to have been compiler with an incompatible "
211    "version of the dictionary compiler and must be recompiled";
212fmt(not_loaded) ->
213    "Module ~p is not on the code path or could not be loaded";
214fmt(no_dict) ->
215    "Module ~p does not appear to be a diameter dictionary".
216
217%% ===========================================================================
218%% format/1
219%%
220%% Turn dict/0 output back into a dictionary file (with line ending = $\n).
221
222-spec format(Dict)
223   -> iolist()
224 when Dict :: orddict:orddict().
225
226-define(KEYS, [id, name, prefix, vendor,
227               inherits, codecs, custom_types,
228               avp_types,
229               messages,
230               grouped,
231               enum, define]).
232
233format(Dict) ->
234    Io = orddict:fold(fun io/3, [], Dict),
235    [S || {_,S} <- lists:sort(fun keysort/2, Io)].
236
237keysort({A,_}, {B,_}) ->
238    [HA, HB] = [H || K <- [A,B],
239                     H <- [lists:takewhile(fun(X) -> X /= K end, ?KEYS)]],
240    HA < HB.
241
242%% ===========================================================================
243
244-define(INDENT, "    ").
245-define(SP, " ").
246-define(NL, $\n).
247
248%% io/3
249
250io(K, _, Acc)
251  when K == command_codes;
252       K == import_avps;
253       K == import_groups;
254       K == import_enums ->
255    Acc;
256
257io(Key, Body, Acc) ->
258    [{Key, io(Key, Body)} | Acc].
259
260%% io/2
261
262io(K, Id)
263  when K == id;
264       K == name;
265       K == prefix ->
266    [?NL, section(K), ?SP, tok(Id)];
267
268io(vendor = K, {Id, Name}) ->
269    [?NL, section(K) | [[?SP, tok(X)] || X <- [Id, Name]]];
270
271io(_, []) ->
272    [];
273
274io(avp_types = K, Body) ->
275    [?NL, ?NL, section(K), ?NL, [body(K,A) || A <- Body]];
276
277io(K, Body)
278  when K == messages;
279       K == grouped ->
280    [?NL, ?NL, section(K), [body(K,A) || A <- Body]];
281
282io(K, Body)
283  when K == avp_vendor_id;
284       K == inherits;
285       K == custom_types;
286       K == codecs;
287       K == enum;
288       K == define ->
289    [[?NL, pairs(K, T)] || T <- Body].
290
291pairs(K, {Id, Avps}) ->
292    [?NL, section(K), ?SP, tok(Id), ?NL, [[?NL, body(K, A)] || A <- Avps]].
293
294body(K, AvpName)
295  when K == avp_vendor_id;
296       K == inherits;
297       K == custom_types;
298       K == codecs ->
299    [?INDENT, word(AvpName)];
300
301body(K, {Name, N})
302  when K == enum;
303       K == define ->
304    [?INDENT, word(Name), ?SP, ?I(N)];
305
306body(avp_types = K, {Name, Code, Type, ""}) ->
307    body(K, {Name, Code, Type, "-"});
308body(avp_types, {Name, Code, Type, Flags}) ->
309    [?NL, ?INDENT, word(Name),
310     [[?SP, ?SP, S] || S <- [?I(Code), Type, Flags]]];
311
312body(messages, {"answer-message", _, _, [], Avps}) ->
313    [?NL, ?NL, ?INDENT,
314     "answer-message ::= < Diameter Header: code, ERR [PXY] >",
315     f_avps(Avps)];
316body(messages, {Name, Code, Flags, ApplId, Avps}) ->
317    [?NL, ?NL, ?INDENT, word(Name), " ::= ", header(Code, Flags, ApplId),
318     f_avps(Avps)];
319
320body(grouped, {Name, Code, Vid, Avps}) ->
321    [?NL, ?NL, ?INDENT, word(Name), " ::= ", avp_header(Code, Vid),
322     f_avps(Avps)].
323
324header(Code, Flags, ApplId) ->
325    ["< Diameter Header: ",
326     ?I(Code),
327     [[", ", ?L(F)] || F <- Flags],
328     [[" ", ?I(N)] || N <- ApplId],
329     " >"].
330
331avp_header(Code, Vid) ->
332    ["< AVP Header: ",
333     ?I(Code),
334     [[" ", ?I(V)] || V <- Vid],
335     " >"].
336
337f_avps(L) ->
338    [[?NL, ?INDENT, ?INDENT, f_avp(A)] || A <- L].
339
340f_avp({Q, A}) ->
341    [D | _] = Avp = f_delim(A),
342    f_avp(f_qual(D, Q), Avp);
343f_avp(A) ->
344    f_avp("", f_delim(A)).
345
346f_delim({{A}}) ->
347    [$<, word(A), $>];
348f_delim({A}) ->
349    [${, word(A), $}];
350f_delim([A]) ->
351    [$[, word(A), $]].
352
353f_avp(Q, [L, Avp, R]) ->
354    Len = length(lists:flatten([Q])),
355    [io_lib:format("~*s", [-1*max(Len+1, 6) , Q]), L, " ", Avp, " ", R].
356
357f_qual(${, '*') ->
358    "1*";  %% Equivalent to "*" but the more common/obvious rendition
359f_qual(_, '*') ->
360    "*";
361f_qual(_, {'*', N}) ->
362    [$*, ?I(N)];
363f_qual(_, {N, '*'}) ->
364    [?I(N), $*];
365f_qual(_, {M,N}) ->
366    [?I(M), $*, ?I(N)].
367
368section(Key) ->
369    ["@", ?L(Key)].
370
371tok(N)
372  when is_integer(N) ->
373    ?I(N);
374tok(N) ->
375    word(N).
376
377word(Str) ->
378    word(diameter_dict_scanner:is_name(Str), Str).
379
380word(true, Str) ->
381    Str;
382word(false, Str) ->
383    [$', Str, $'].
384
385%% ===========================================================================
386
387do_parse(File, Opts) ->
388    Bin  = do([fun read/1, File], read),
389    Toks = do([fun diameter_dict_scanner:scan/1, Bin], scan),
390    Tree = do([fun diameter_dict_parser:parse/1, Toks], parse),
391    make_dict(Tree, Opts).
392
393do([F|A], E) ->
394    case apply(F,A) of
395        {ok, T} ->
396            T;
397        {error, Reason} ->
398            ?RETURN({E, Reason})
399    end.
400
401read({path, Path}) ->
402    file:read_file(Path);
403read(File) ->
404    {ok, iolist_to_binary([File])}.
405
406make_dict(Parse, Opts) ->
407    Dict = pass3(pass2(pass1(reset(make_dict(Parse), Opts))), Opts),
408    ok = examine(Dict),
409    make_orddict(Dict).
410
411%% make_orddict/1
412
413make_orddict(Dict) ->
414    dict:fold(fun mo/3,
415              orddict:from_list([{K,[]} || K <- [avp_types,
416                                                 messages,
417                                                 grouped,
418                                                 inherits,
419                                                 custom_types,
420                                                 codecs,
421                                                 avp_vendor_id,
422                                                 enum,
423                                                 define]]),
424              Dict).
425
426mo(K, Sects, Dict)
427  when is_atom(K) ->
428    orddict:store(K, make(K, Sects), Dict);
429
430mo(_, _, Dict) ->
431    Dict.
432
433make(K, [[_Line, {_, _, X}]])
434  when K == id;
435       K == name;
436       K == prefix ->
437    X;
438
439make(vendor, [[_Line, {_, _, Id}, {_, _, Name}]]) ->
440    {Id, Name};
441
442make(K, T)
443  when K == command_codes;
444       K == import_avps;
445       K == import_groups;
446       K == import_enums ->
447    T;
448
449make(K, Sects) ->
450    post(K, foldl(fun([_L|B], A) -> make(K,B,A) end,
451                  [],
452                  Sects)).
453
454post(avp_types, L) ->
455    lists:sort(L);
456
457post(K, L)
458  when K == grouped;
459       K == messages;
460       K == enum;
461       K == define ->
462    lists:reverse(L);
463
464post(_, L) ->
465    L.
466
467make(K, [{_,_,Name} | Body], Acc)
468  when K == enum;
469       K == define;
470       K == avp_vendor_id;
471       K == custom_types;
472       K == inherits;
473       K == codecs ->
474    [{Name, mk(K, Body)} | Acc];
475
476make(K, Body, Acc) ->
477    foldl(fun(T,A) -> [mk(K, T) | A] end, Acc, Body).
478
479mk(avp_types, [{_,_,Name}, {_,_,Code}, {_,_,Type}, {_,_,Flags}]) ->
480    {Name, Code, type(Type), Flags};
481
482mk(messages, [{'answer-message' = A, _}, false | Avps]) ->
483    {?L(A), -1, ['ERR', 'PXY'], [], make_body(Avps)};
484
485mk(messages, [{_,_,Name}, [{_,_,Code}, Flags, ApplId] | Avps]) ->
486    {Name,
487     Code,
488     lists:map(fun({F,_}) -> F end, Flags),
489     opt(ApplId),
490     make_body(Avps)};
491
492mk(grouped, [{_,_,Name}, [{_,_,Code}, Vid] | Avps]) ->
493    {Name, Code, opt(Vid), make_body(Avps)};
494
495mk(K, Body)
496  when K == enum;
497       K == define ->
498    lists:map(fun([{_,_,Name}, {_,_,Value}]) -> {Name, Value} end, Body);
499
500mk(K, Avps)
501  when K == avp_vendor_id;
502       K == custom_types;
503       K == inherits;
504       K == codecs ->
505    lists:map(fun({_,_,N}) -> N end, Avps).
506
507opt(false) ->
508    [];
509opt({_,_,X}) ->
510    [X].
511
512make_body(Avps) ->
513    lists:map(fun avp/1, Avps).
514
515avp([false, D, Avp]) ->
516    avp(D, Avp);
517avp([Q, D, Avp]) ->
518    case {qual(D, Q), avp(D, Avp)} of
519        {{0,1}, A} when D == $[ ->
520            A;
521        {{1,1}, A} ->
522            A;
523        T ->
524            T
525    end.
526%% Could just store the qualifier as a pair in all cases but the more
527%% compact form is easier to parse visually so live with a bit of
528%% mapping. Ditto the use of '*'.
529
530avp(D, {'AVP', _}) ->
531    delim(D, "AVP");
532avp(D, {_, _, Name}) ->
533    delim(D, Name).
534
535delim($<, N) ->
536    {{N}};
537delim(${, N) ->
538    {N};
539delim($[, N) ->
540    [N].
541
542%% There's a difference between max = 0 and not specifying an AVP:
543%% reception of an AVP with max = 0 will always be an error, otherwise
544%% it depends on the existence of 'AVP' and the M flag.
545
546qual(${, {{_,L,0}, _}) ->
547    ?RETURN(required_avp_has_zero_min_arity, [L]);
548qual(${, {_, {_,L,0}}) ->
549    ?RETURN(required_avp_has_zero_max_arity, [L]);
550
551qual($[, {{_,L,N}, _})
552  when 0 < N ->
553    ?RETURN(optional_avp_has_nonzero_min_arity, [L]);
554
555qual(_, {{_,L,Min}, {_,_,Max}})
556  when Min > Max ->
557    ?RETURN(qualifier_has_min_greater_than_max, [Min, Max, L]);
558
559qual(_, true) ->
560    '*';
561
562qual(${, {true, {_,_,N}}) ->
563    {1, N};
564qual(_, {true, {_,_,N}}) ->
565    {0, N};
566
567qual(D, {{_,_,N}, true})
568  when D == ${, N == 1;
569       D /= ${, N == 0 ->
570    '*';
571qual(_, {{_,_,N}, true}) ->
572    {N, '*'};
573
574qual(_, {{_,_,Min}, {_,_,Max}}) ->
575    {Min, Max}.
576
577%% Optional reports when running verbosely.
578report(What, [F | A])
579  when is_function(F) ->
580    report(What, apply(F, A));
581report(What, Data) ->
582    report(getr(verbose), What, Data).
583
584report(true, Tag, Data) ->
585    io:format("##~n## ~p ~p~n", [Tag, Data]);
586report(false, _, _) ->
587    ok.
588
589%% ------------------------------------------------------------------------
590%% make_dict/1
591%%
592%% Turn a parsed dictionary into an dict.
593
594make_dict(Parse) ->
595    foldl(fun(T,A) ->
596                  report(section, T),
597                  section(T,A)
598          end,
599          dict:new(),
600          Parse).
601
602section([{T, L} | Rest], Dict)
603  when T == name;
604       T == prefix;
605       T == id;
606       T == vendor ->
607    case find(T, Dict) of
608        [] ->
609            dict:store(T, [[L | Rest]], Dict);
610        [[Line | _]] ->
611            ?RETURN(duplicate_section, [T, L, Line])
612    end;
613
614section([{T, L} | Rest], Dict)
615  when T == avp_types;
616       T == messages;
617       T == grouped;
618       T == inherits;
619       T == custom_types;
620       T == codecs;
621       T == avp_vendor_id;
622       T == enum;
623       T == define ->
624    dict:append(T, [L | Rest], Dict).
625
626%% ===========================================================================
627%% reset/2
628%%
629%% Reset sections from options.
630
631reset(Dict, Opts) ->
632    foldl([fun reset/3, Opts], Dict, [name, prefix, inherits]).
633
634reset(K, Dict, Opts) ->
635    foldl(fun opt/2, Dict, [T || {A,_} = T <- Opts, A == K]).
636
637opt({inherits = Key, "-"}, Dict) ->
638    dict:erase(Key, Dict);
639
640opt({inherits = Key, Mod}, Dict) ->
641    case lists:splitwith(fun(C) -> C /= $/ end, Mod) of
642        {Mod, ""} ->
643            dict:append(Key, [0, {word, 0, Mod}], Dict);
644        {From, [$/|To]} ->
645            dict:store(Key,
646                       [reinherit(From, To, M) || M <- find(Key, Dict)],
647                       Dict)
648    end;
649
650opt({Key, Val}, Dict) ->
651    dict:store(Key, [[0, {word, 0, Val}]], Dict);
652
653opt(_, Dict) ->
654    Dict.
655
656reinherit(From, To, [L, {word, _, From} = T | Avps]) ->
657    [L, setelement(3, T, To) | Avps];
658reinherit(_, _, T) ->
659    T.
660
661%% ===========================================================================
662%% pass1/1
663%%
664%% Explode sections into additional dictionary entries plus semantic
665%% checks.
666
667pass1(Dict) ->
668    true = no_messages_without_id(Dict),
669
670    foldl(fun(K,D) -> foldl([fun p1/3, K], D, find(K,D)) end,
671          Dict,
672          [id,
673           vendor,
674           avp_types,  %% must precede inherits, grouped, enum
675           avp_vendor_id,
676           custom_types,
677           codecs,
678           inherits,
679           grouped,
680           messages,
681           enum,
682           define]).
683
684%% Multiple sections are allowed as long as their bodies don't
685%% overlap. (Except enum/define.)
686
687p1([_Line, N], Dict, id = K) ->
688    true = is_uint32(N, [K]),
689    Dict;
690
691p1([_Line, Id, _Name], Dict, vendor = K) ->
692    true = is_uint32(Id, [K]),
693    Dict;
694
695p1([_Line, X | Body], Dict, K)
696  when K == avp_vendor_id;
697       K == custom_types;
698       K == codecs;
699       K == inherits ->
700    foldl([fun explode/4, X, K], Dict, Body);
701
702p1([_Line, X | Body], Dict, K)
703  when K == define;
704       K == enum ->
705    {_, L, Name} = X,
706    foldl([fun explode2/4, X, K],
707          store_new({K, Name},
708                    [L, Body],
709                    Dict,
710                    [K, Name, L],
711                    already_declared),
712          Body);
713
714p1([_Line | Body], Dict, K)
715  when K == avp_types;
716       K == grouped;
717       K == messages ->
718    foldl([fun explode/3, K], Dict, Body).
719
720no_messages_without_id(Dict) ->
721    case find(messages, Dict) of
722        [] ->
723            true;
724        [[Line | _] | _] ->
725            [] /= find(id, Dict) orelse ?RETURN(messages_without_id, [Line])
726    end.
727
728%% Note that the AVP's in avp_vendor_id, custom_types, codecs and
729%% enum can all be inherited, as can the AVP content of messages and
730%% grouped AVP's. Check that the referenced AVP's exist after
731%% importing definitions.
732
733%% explode/4
734%%
735%% {avp_vendor_id, AvpName}    -> [Lineno, Id::integer()]
736%% {custom|inherits,  AvpName} -> [Lineno, Mod::string()]
737
738explode({_, Line, AvpName}, Dict, {_, _, X} = T, K) ->
739    true = K /= avp_vendor_id orelse is_uint32(T, [K]),
740    true = K /= inherits orelse avp_not_local(AvpName, Line, Dict),
741
742    store_new({key(K), AvpName},
743              [Line, X],
744              Dict,
745              [AvpName, Line, K],
746              avp_already_defined).
747
748%% explode2/4
749
750%% {define, {Name, Key}} -> [Lineno, Value::integer(), enum|define]
751
752explode2([{_, Line, Key}, {_, _, Value} = T], Dict, {_, _, Name}, K) ->
753    true = is_uint32(T, [K, Name]),
754
755    store_new({key(K), {Name, Key}},
756              [Line, Value, K],
757              Dict,
758              [Name, Key, K, Line],
759              key_already_defined).
760
761%% key/1
762%%
763%% Conflate keys that are equivalent as far as uniqueness of
764%% definition goes.
765
766key(K)
767  when K == enum;
768       K == define ->
769    define;
770key(K)
771  when K == custom_types;
772       K == codecs ->
773    custom;
774key(K) ->
775    K.
776
777%% explode/3
778
779%% {avp_types, AvpName}       -> [Line | Toks]
780%% {avp_types, {Code, IsReq}} -> [Line, AvpName]
781%%
782%% where AvpName = string()
783%%       Code    = integer()
784%%       IsReq   = boolean()
785
786explode([{_, Line, Name} | Toks], Dict0, avp_types = K) ->
787    %% Each AVP can be defined only once.
788    Dict = store_new({K, Name},
789                     [Line | Toks],
790                     Dict0,
791                     [Name, Line],
792                     avp_name_already_defined),
793
794    [{number, _, _Code} = C, {word, _, Type}, {word, _, _Flags}] = Toks,
795
796    true = avp_type_known(Type, Name, Line),
797    true = is_uint32(C, [K, Name]),
798
799    Dict;
800
801%% {grouped, Name}            -> [Line, HeaderTok | AvpToks]
802%% {grouped, {Name, AvpName}} -> [Line, Qual, Delim]
803%%
804%% where Name  = string()
805%%       AvpName = string()
806%%       Qual  = {Q, Q} | boolean()
807%%       Q     = true | NumberTok
808%%       Delim = $< | ${ | $[
809
810explode([{_, Line, Name}, Header | Avps], Dict0, grouped = K) ->
811    Dict = store_new({K, Name},
812                     [Line, Header | Avps],
813                     Dict0,
814                     [Name, Line],
815                     group_already_defined),
816
817    [{_,_, Code} = C, Vid] = Header,
818    {DefLine, {_, _, Flags}} = grouped_flags(Name, Code, Dict0, Line),
819    V = lists:member($V, Flags),
820
821    true = is_uint32(C, [K, Name, "AVP code"]),
822    true = is_uint32(Vid, [K, Name, "vendor id"]),
823    false = vendor_id_mismatch(Vid, V, Name, Dict0, Line, DefLine),
824
825    explode_avps(Avps, Dict, K, Name);
826
827%% {messages, Name}            -> [Line, HeaderTok | AvpToks]
828%% {messages, {Code, IsReq}}   -> [Line, NameTok]
829%% {messages, Code}            -> [[Line, NameTok, IsReq]]
830%% {messages, {Name, Flag}}    -> [Line]
831%% {messages, {Name, AvpName}} -> [Line, Qual, Delim]
832%%
833%% where Name  = string()
834%%       Code  = integer()
835%%       IsReq = boolean()
836%%       Flag  = 'REQ' | 'PXY'
837%%       AvpName = string()
838%%       Qual  = true | {Q,Q}
839%%       Q     = true | NumberTok
840%%       Delim = $< | ${ | ${
841
842explode([{'answer-message' = A, Line}, false = H | Avps],
843        Dict0,
844        messages = K) ->
845    Name = ?L(A),
846    Dict1 = store_new({K, Name},
847                      [Line, H, Avps],
848                      Dict0,
849                      [Name, Line],
850                      message_name_already_defined),
851
852    explode_avps(Avps, Dict1, K, Name);
853
854explode([{_, Line, MsgName} = M, Header | Avps],
855        Dict0,
856        messages = K) ->
857    %% There can be at most one message with a given name.
858    Dict1 = store_new({K, MsgName},
859                      [Line, Header | Avps],
860                      Dict0,
861                      [MsgName, Line],
862                      message_name_already_defined),
863
864    [{_, _, Code} = C, Bits, ApplId] = Header,
865
866    %% Don't check any application id since it's required to be
867    %% the same as @id.
868    true = is_uint32(C, [K, MsgName]),
869
870    %% An application id specified as part of the message definition
871    %% has to agree with @id. The former is parsed just because RFC
872    %% 3588 specifies it.
873    false = application_id_mismatch(ApplId, Dict1, MsgName),
874
875    IsReq = lists:keymember('REQ', 1, Bits),
876
877    %% For each command code, there can be at most one request and
878    %% one answer.
879    Dict2 = store_new({K, {Code, IsReq}},
880                      [Line, M],
881                      Dict1,
882                      [choose(IsReq, "Request", "Answer"), Code, Line],
883                      message_code_already_defined),
884
885    %% For each message, each flag can occur at most once.
886    Dict3 = foldl(fun({F,L},D) ->
887                          store_new({K, {MsgName, F}},
888                                    [L],
889                                    D,
890                                    [MsgName, ?L(F)],
891                                    message_has_duplicate_flag)
892                  end,
893                  Dict2,
894                  Bits),
895
896    dict:append({K, Code},
897                [Line, M, IsReq],
898                explode_avps(Avps, Dict3, K, MsgName)).
899
900%% explode_avps/4
901%%
902%% Ensure required AVP order and sane qualifiers. Can't check for AVP
903%% names until after they've been imported.
904%%
905%% RFC 3588 allows a trailing fixed while 3588bis doesn't. Parse the
906%% former.
907
908explode_avps(Avps, Dict, Key, Name) ->
909    xa("<{[<", Avps, Dict, Key, Name).
910
911xa(_, [], Dict, _, _) ->
912    Dict;
913
914xa(Ds, [[Qual, D, {'AVP', Line}] | Avps], Dict, Key, Name) ->
915    xa(Ds, [[Qual, D, {word, Line, "AVP"}] | Avps], Dict, Key, Name);
916
917xa([], [[_Qual, D, {_, Line, Name}] | _], _, _, _) ->
918    ?RETURN(invalid_avp_order, [D, Name, close(D), Line]);
919
920xa([D|_] = Ds, [[Qual, D, {_, Line, AvpName}] | Avps], Dict, Key, Name) ->
921    xa(Ds,
922       Avps,
923       store_new({Key, {Name, AvpName}},
924                 [Line, Qual, D],
925                 Dict,
926                 [AvpName, Line],
927                 avp_already_referenced),
928       Key,
929       Name);
930
931xa([_|Ds], Avps, Dict, Key, Name) ->
932    xa(Ds, Avps, Dict, Key, Name).
933
934close($<) -> $>;
935close(${) -> $};
936close($[) -> $].
937
938%% is_uint32/2
939
940is_uint32(false, _) ->
941    true;
942is_uint32({Line, _, N}, Args) ->
943    N < 1 bsl 32 orelse ?RETURN(uint32_out_of_range, Args ++ [N, Line]).
944%% Can't call diameter_types here since it may not exist yet.
945
946%% application_id_mismatch/3
947
948application_id_mismatch({number, Line, Id}, Dict, MsgName) ->
949    [[_, {_, L, I}]] = dict:fetch(id, Dict),
950
951    I /= Id andalso ?RETURN(message_application_id_mismatch,
952                            [MsgName, Id, Line, I, L]);
953
954application_id_mismatch(false = No, _, _) ->
955    No.
956
957%% avp_not_local/3
958
959avp_not_local(Name, Line, Dict) ->
960    A = find({avp_types, Name}, Dict),
961
962    [] == A orelse ?RETURN(inherited_avp_already_defined,
963                           [Name, Line, hd(A)]).
964
965%% avp_type_known/3
966
967avp_type_known(Type, Name, Line) ->
968    false /= type(Type)
969        orelse ?RETURN(avp_has_unknown_type, [Name, Line, Type]).
970
971%% vendor_id_mismatch/6
972%%
973%% Require a vendor id specified on a group to match any specified
974%% in @avp_vendor_id. Note that both locations for the value are
975%% equivalent, both in the value being attributed to a locally
976%% defined AVP and ignored when imported from another dictionary.
977
978vendor_id_mismatch({_,_,_}, false, Name, _, Line, DefLine) ->
979    ?RETURN(grouped_vendor_id_without_flag, [Name, Line, DefLine]);
980
981vendor_id_mismatch({_, _, I}, true, Name, Dict, Line, _) ->
982    case vendor_id(Name, Dict) of
983        {avp_vendor_id, L, N} ->
984            I /= N andalso
985                ?RETURN(grouped_vendor_id_mismatch, [Name, Line, I, N, L]);
986        _ ->
987            false
988    end;
989
990vendor_id_mismatch(_, _, _, _, _, _) ->
991    false.
992
993%% grouped_flags/4
994
995grouped_flags(Name, Code, Dict, Line) ->
996    case find({avp_types, Name}, Dict) of
997        [L, {_, _, Code}, {_, _, "Grouped"}, Flags] ->
998            {L, Flags};
999        [_, {_, L, C}, {_, _, "Grouped"}, _Flags] ->
1000            ?RETURN(grouped_avp_code_mismatch, [Name, Line, Code, C, L]);
1001        [_, _Code, {_, L, T}, _] ->
1002            ?RETURN(grouped_avp_has_wrong_type, [Name, Line, T, L]);
1003        [] ->
1004            ?RETURN(grouped_avp_not_defined, [Name, Line])
1005    end.
1006
1007%% vendor_id/2
1008
1009%% Look for a vendor id in @avp_vendor_id, then @vendor.
1010vendor_id(Name, Dict) ->
1011    case find({avp_vendor_id, Name}, Dict) of
1012        [Line, Id] when is_integer(Id) ->
1013            {avp_vendor_id, Line, Id};
1014        [] ->
1015            vendor(Dict)
1016    end.
1017
1018vendor(Dict) ->
1019    case find(vendor, Dict) of
1020        [[_Line, {_, _, Id}, {_, _, _}]] ->
1021            {vendor, Id};
1022        [] ->
1023            false
1024    end.
1025
1026%% find/2
1027
1028find(Key, Dict) ->
1029    case dict:find(Key, Dict) of
1030        {ok, L} when is_list(L) ->
1031            L;
1032        error ->
1033            []
1034    end.
1035
1036%% store_new/5
1037
1038store_new(Key, Value, Dict, Args, Err) ->
1039    case dict:find(Key, Dict) of
1040        {ok, [L | _]} ->
1041            ?RETURN(Err, Args ++ [L]);
1042        error ->
1043            dict:store(Key, Value, Dict)
1044    end.
1045
1046%% type/1
1047
1048type("DiamIdent") ->
1049    "DiameterIdentity";
1050type("DiamURI") ->
1051    "DiameterURI";
1052type(T)
1053  when T == "OctetString";
1054       T == "Integer32";
1055       T == "Integer64";
1056       T == "Unsigned32";
1057       T == "Unsigned64";
1058       T == "Float32";
1059       T == "Float64";
1060       T == "Grouped";
1061       T == "Enumerated";
1062       T == "Address";
1063       T == "Time";
1064       T == "UTF8String";
1065       T == "DiameterIdentity";
1066       T == "DiameterURI";
1067       T == "IPFilterRule";
1068       T == "QoSFilterRule" ->
1069    T;
1070type(_) ->
1071    false.
1072
1073%% ===========================================================================
1074%% pass2/1
1075%%
1076%% More explosion, but that requires the previous pass to write its
1077%% entries.
1078
1079pass2(Dict) ->
1080    foldl(fun(K,D) -> foldl([fun p2/3, K], D, find(K,D)) end,
1081          Dict,
1082          [avp_types]).
1083
1084p2([_Line | Body], Dict, avp_types) ->
1085    foldl(fun explode_avps/2, Dict, Body);
1086
1087p2([], Dict, _) ->
1088    Dict.
1089
1090explode_avps([{_, Line, Name} | Toks], Dict) ->
1091    [{number, _, Code}, {word, _, _Type}, {word, _, Flags}] = Toks,
1092
1093    true = avp_flags_valid(Flags, Name, Line),
1094
1095    Vid = avp_vendor_id(Flags, Name, Line, Dict),
1096
1097    %% An AVP is uniquely defined by its AVP code and vendor id (if any).
1098    %% Ensure there are no duplicates.
1099    store_new({avp_types, {Code, Vid}},
1100              [Line, Name],
1101              Dict,
1102              [Code, Vid, Name, Line],
1103              avp_code_already_defined).
1104
1105%% avp_flags_valid/3
1106
1107avp_flags_valid(Flags, Name, Line) ->
1108    Bad = lists:filter(fun(C) -> not lists:member(C, "MVP") end, Flags),
1109    [] == Bad
1110        orelse ?RETURN(avp_has_invalid_flag, [Name, Line, hd(Bad)]),
1111
1112    Dup = Flags -- "MVP",
1113    [] == Dup
1114        orelse ?RETURN(avp_has_duplicate_flag, [Name, Line, hd(Dup)]).
1115
1116%% avp_vendor_id/4
1117
1118avp_vendor_id(Flags, Name, Line, Dict) ->
1119    V = lists:member($V, Flags),
1120
1121    case vendor_id(Name, Dict) of
1122        {avp_vendor_id, _, I} when V ->
1123            I;
1124        {avp_vendor_id, L, I} ->
1125            ?RETURN(avp_has_vendor_id, [Name, Line, I, L]);
1126        {vendor, I} when V ->
1127            I;
1128        false when V ->
1129            ?RETURN(avp_has_no_vendor, [Name, Line]);
1130        _ ->
1131            false
1132    end.
1133
1134%% ===========================================================================
1135%% pass3/2
1136%%
1137%% Import AVPs.
1138
1139pass3(Dict, Opts) ->
1140    import_enums(import_groups(import_avps(insert_codes(Dict), Opts))).
1141
1142%% insert_codes/1
1143%%
1144%% command_codes -> [{Code, ReqNameTok, AnsNameTok}]
1145
1146insert_codes(Dict) ->
1147    dict:store(command_codes,
1148               dict:fold(fun make_code/3, [], Dict),
1149               Dict).
1150
1151make_code({messages, Code}, Names, Acc)
1152  when is_integer(Code) ->
1153    [mk_code(Code, Names) | Acc];
1154make_code(_, _, Acc) ->
1155    Acc.
1156
1157mk_code(Code, [[_, _, false] = Ans, [_, _, true] = Req]) ->
1158    mk_code(Code, [Req, Ans]);
1159
1160mk_code(Code, [[_, {_,_,Req}, true], [_, {_,_,Ans}, false]]) ->
1161    {Code, Req, Ans};
1162
1163mk_code(_Code, [[Line, _Name, IsReq]]) ->
1164    ?RETURN(message_missing, [choose(IsReq, "Request", "Answer"),
1165                              Line,
1166                              choose(IsReq, "answer", "request")]).
1167
1168%% import_avps/2
1169
1170import_avps(Dict, Opts) ->
1171    Import = inherit(Dict, Opts),
1172    report(imported, Import),
1173
1174    %% examine/1 tests that all referenced AVP's are either defined
1175    %% or imported.
1176
1177    dict:store(import_avps,
1178               lists:map(fun({M, _, As}) -> {M, [A || {_,A} <- As]} end,
1179                         lists:reverse(Import)),
1180               foldl(fun explode_imports/2, Dict, Import)).
1181
1182explode_imports({Mod, Line, Avps}, Dict) ->
1183    foldl([fun xi/4, Mod, Line], Dict, Avps).
1184
1185xi({L, {Name, _Code, _Type, _Flags} = A}, Dict, Mod, Line) ->
1186    store_new({avp_types, Name},
1187              [0, Mod, Line, L, A],
1188              store_new({import, Name},
1189                        [Line],
1190                        Dict,
1191                        [Name, Line],
1192                        duplicate_import),
1193              [Name, Mod, Line],
1194              imported_avp_already_defined).
1195
1196%% import_groups/1
1197%% import_enums/1
1198%%
1199%% For each inherited module, store the content of imported AVP's of
1200%% type grouped/enumerated in a new key.
1201
1202import_groups(Dict) ->
1203    dict:store(import_groups, import(grouped, Dict), Dict).
1204
1205import_enums(Dict) ->
1206    dict:store(import_enums, import(enum, Dict), Dict).
1207
1208import(Key, Dict) ->
1209    flatmap([fun import_key/2, Key], dict:fetch(import_avps, Dict)).
1210
1211import_key({Mod, Avps}, Key) ->
1212    As = lists:flatmap(fun(T) ->
1213                               N = element(1,T),
1214                               choose(lists:keymember(N, 1, Avps), [T], [])
1215                       end,
1216                       orddict:fetch(Key, dict(Mod))),
1217    if As == [] ->
1218            [];
1219       true ->
1220            [{Mod, As}]
1221    end.
1222
1223%% ------------------------------------------------------------------------
1224%% inherit/2
1225%%
1226%% Return a {Mod, Line, [{Lineno, Avp}]} list, where Mod is a module
1227%% name, Line points to the corresponding @inherit and each Avp is
1228%% from Mod:dict(). Lineno is 0 if the import is implicit.
1229
1230inherit(Dict, Opts) ->
1231    code:add_pathsa([D || {include, D} <- Opts]),
1232    foldl(fun inherit_avps/2, [], find(inherits, Dict)).
1233%% Note that the module order of the returned lists is reversed
1234%% relative to @inherits.
1235
1236inherit_avps([Line, {_,_,M} | Names], Acc) ->
1237    Mod = ?A(M),
1238    report(inherit_from, Mod),
1239    case find_avps(Names, avps_from_module(Mod)) of
1240        {_, [{_, L, N} | _]} ->
1241            ?RETURN(requested_avp_not_found, [Mod, Line, N, L]);
1242        {Found, []} ->
1243            [{Mod, Line, lists:sort(Found)} | Acc]
1244    end.
1245
1246%% Import everything not defined locally ...
1247find_avps([], Avps) ->
1248    {[{0, A} || A <- Avps], []};
1249
1250%% ... or specified AVPs.
1251find_avps(Names, Avps) ->
1252    foldl(fun acc_avp/2, {[], Names}, Avps).
1253
1254acc_avp({Name, _Code, _Type, _Flags} = A, {Found, Not} = Acc) ->
1255    case lists:keyfind(Name, 3, Not) of
1256        {_, Line, Name} ->
1257            {[{Line, A} | Found], lists:keydelete(Name, 3, Not)};
1258        false ->
1259            Acc
1260    end.
1261
1262%% avps_from_module/2
1263
1264avps_from_module(Mod) ->
1265    orddict:fetch(avp_types, dict(Mod)).
1266
1267dict(Mod) ->
1268    try Mod:dict() of
1269        [?VERSION | Dict] ->
1270            Dict;
1271        _ ->
1272            ?RETURN(recompile, [Mod])
1273    catch
1274        error: _ ->
1275            ?RETURN(choose(false == code:is_loaded(Mod),
1276                           not_loaded,
1277                           no_dict),
1278                    [Mod])
1279    end.
1280
1281%% ===========================================================================
1282%% examine/1
1283%%
1284%% Sanity checks.
1285
1286examine(Dict) ->
1287    dict:fold(fun(K, V, _) -> x(K, V, Dict) end, ok, Dict),
1288    ok.
1289
1290%% Ensure enum AVP's have type Enumerated.
1291x({enum, Name}, [Line | _], Dict)
1292  when is_list(Name) ->
1293    true = is_enumerated_avp(Name, Dict, Line);
1294
1295%% Ensure all referenced AVP's are either defined locally or imported.
1296x({K, {Name, AvpName}}, [Line | _], Dict)
1297  when (K == grouped orelse K == messages),
1298       is_list(Name),
1299       is_list(AvpName),
1300       AvpName /= "AVP" ->
1301    true = avp_is_defined(AvpName, Dict, Line);
1302
1303%% Ditto.
1304x({K, AvpName}, [Line | _], Dict)
1305  when K == avp_vendor_id;
1306       K == custom ->
1307    true = avp_is_defined(AvpName, Dict, Line);
1308
1309%% Ensure that all local AVP's of type Grouped are also present in @grouped.
1310x({avp_types, Name}, [Line | Toks], Dict)
1311  when 0 < Line, is_list(Name) ->
1312    [{number, _, _Code}, {word, _, Type}, {word, _, _Flags}] = Toks,
1313    "Grouped" == Type
1314        andalso error == dict:find({grouped, Name}, Dict)
1315        andalso ?RETURN(grouped_avp_not_grouped, [Name, Line]),
1316    ok;
1317
1318x(_, _, _) ->
1319    ok.
1320
1321%% has_enumerated_type/3
1322
1323is_enumerated_avp(Name, Dict, Line) ->
1324    case find({avp_types, Name}, Dict) of
1325        [_Line, _Code, {_, _, "Enumerated"}, _Flags] ->   %% local
1326            true;
1327        [_Line, _Code, {_, L, T}, _] ->
1328            ?RETURN(enumerated_avp_has_wrong_local_type,
1329                    [Name, Line, T, L]);
1330        [0, _, _, _, {_Name, _Code, "Enumerated", _Flags}] ->   %% inherited
1331            true;
1332        [0, Mod, LM, LA, {_Name, _Code, Type, _Flags}] ->
1333            ?RETURN(enumerated_avp_has_wrong_inherited_type,
1334                    [Name, Line, Type, Mod, choose(0 == LA, LM, LA)]);
1335        [] ->
1336            ?RETURN(enumerated_avp_not_defined, [Name, Line])
1337    end.
1338
1339avp_is_defined(Name, Dict, Line) ->
1340    case find({avp_types, Name}, Dict) of
1341        [_Line, _Code, _Type, _Flags] ->   %% local
1342            true;
1343        [0, _, _, _, {Name, _Code, _Type, _Flags}] ->  %% inherited
1344            true;
1345        [] ->
1346            ?RETURN(avp_not_defined, [Name, Line])
1347    end.
1348
1349%% ===========================================================================
1350
1351putr(Key, Value) ->
1352    put({?MODULE, Key}, Value).
1353
1354getr(Key) ->
1355    get({?MODULE, Key}).
1356
1357eraser(Key) ->
1358    erase({?MODULE, Key}).
1359
1360choose(true, X, _)  -> X;
1361choose(false, _, X) -> X.
1362
1363foldl(F, Acc, List) ->
1364    lists:foldl(fun(T,A) -> eval([F,T,A]) end, Acc, List).
1365
1366flatmap(F, List) ->
1367    lists:flatmap(fun(T) -> eval([F,T]) end, List).
1368
1369eval([[F|X] | A]) ->
1370    eval([F | A ++ X]);
1371eval([F|A]) ->
1372    apply(F,A).
1373