Skip to content

Commit 67002e0

Browse files
committed
Merge branch 'maint'
2 parents 8fb9b41 + 8583dd5 commit 67002e0

File tree

10 files changed

+1659
-28
lines changed

10 files changed

+1659
-28
lines changed

lib/diameter/bin/diameterc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ usage() ->
4343
"~n"
4444
" options:~n"
4545
"~n"
46-
" --name name = set @name~n"
47-
" --prefix prefix = set @prefix~n"
48-
" --inherits dict|- = set/clear @inherits~n"
46+
" --name name = set @name~n"
47+
" --prefix prefix = set @prefix~n"
48+
" --inherits dict|- = set/clear @inherits~n"
49+
" --indirect-inherits = enable indirect_inherits option~n"
4950
"~n"
5051
" -h = print this message~n"
5152
" -v = verbose output~n"
@@ -125,6 +126,9 @@ arg(["--prefix", Name | Args], #argv{options = Opts} = A) ->
125126
arg(["--inherits", Dict | Args], #argv{options = Opts} = A) ->
126127
arg(Args, A#argv{options = Opts ++ [{inherits, Dict}]});
127128

129+
arg(["--indirect-inherits" | Args], #argv{options = Opts} = A) ->
130+
arg(Args, A#argv{options = [indirect_inherits | Opts]});
131+
128132
arg(["-E" | Args], #argv{output = Output} = A) ->
129133
arg(Args, A#argv{output = lists:delete(erl, Output)});
130134

lib/diameter/doc/references/diameter_dict.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,57 @@ order in which sections are specified is unimportant.
163163
@inherits diameter_gen_base_rfc6733
164164
```
165165

166+
When using the `indirect_inherits` option from [codec/2](`diameter_make:codec/2`),
167+
only `@vendor` from the dictionary that defined the AVPs and `@avp_vendor_id`
168+
in the currently compiled dictionary is used. All other dictionaries along the
169+
chain are ignored, so for example:
170+
171+
`a.dia`:
172+
```text
173+
@vendor 1 A
174+
@avp_types
175+
AAA 111 Unsigned32 V
176+
BBB 222 Unsigned32 V
177+
```
178+
`a.dia` will see:
179+
- AAA vendor_id = 1
180+
- BBB vendor_id = 1
181+
182+
`b.dia`:
183+
```text
184+
@vendor 2 B
185+
@avp_types
186+
CCC 333 Unsigned32 V
187+
@inherits diameter_a
188+
@avp_vendor_id 4
189+
AAA
190+
```
191+
192+
`b.dia` will see:
193+
- AAA vendor_id = 4
194+
- BBB vendor_id = 1
195+
- CCC vendor_id = 2
196+
197+
`c.dia`:
198+
```text
199+
@vendor 3 C
200+
@avp_types
201+
DDD 444 Unsigned32 V
202+
@inherits diameter_b
203+
@avp_vendor_id 5
204+
BBB
205+
CCC
206+
```
207+
208+
`c.dia` will see:
209+
- AAA vendor_id = 1
210+
- BBB vendor_id = 5
211+
- CCC vendor_id = 5
212+
- DDD vendor_id = 3
213+
214+
In particular `b.dia`'s override of `AAA` to vendor_id = 4 is ignored by `c.dia` and `AAA` is
215+
back to having vendor_id = 1.
216+
166217
- **`@avp_types`{: #avp_types }** - Defines the name, code, type and flags of
167218
individual AVPs. The section consists of definitions of the form
168219

@@ -291,6 +342,56 @@ order in which sections are specified is unimportant.
291342
REMOVE_SIP_SERVER 3
292343
```
293344

345+
If `indirect_inherits` option from [codec/2](`diameter_make:codec/2`) is used,
346+
new enum values can also be added in each `.dia` file along the inheritance chain,
347+
example:
348+
349+
`a.dia`:
350+
```text
351+
@avp_types
352+
AAA 111 Enumerated V
353+
@enum AAA
354+
A 0
355+
B 1
356+
```
357+
358+
`a.dia` will see following enum values:
359+
- A 0
360+
- B 1
361+
362+
`b.dia`:
363+
```text
364+
@inherits diameter_a
365+
@enum AAA
366+
C 2
367+
D 3
368+
```
369+
370+
`b.dia` will see following enum values:
371+
- A 0
372+
- B 1
373+
- C 2
374+
- D 3
375+
376+
`c.dia`:
377+
```text
378+
@inherits diameter_b
379+
@enum AAA
380+
E 4
381+
F 5
382+
```
383+
384+
`c.dia` will see:
385+
- A 0
386+
- B 1
387+
- C 2
388+
- D 3
389+
- E 4
390+
- F 5
391+
392+
Warning: messages are not shown in this example, but it is required to add
393+
enum AVPs to messages in order for the code to encode/decode them to be generated!
394+
294395
- **`@end`{: #end }** - Causes parsing of the dictionary to terminate: any
295396
remaining content is ignored.
296397

lib/diameter/doc/references/diameterc_cmd.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ source. Valid options are as follows.
4545

4646
- **\-i <dir>** - Prepend the specified directory to the code path. Use to
4747
point at beam files compiled from inherited dictionaries,
48-
`[@inherits](diameter_dict.md#inherits)` in a dictionary file creating a
48+
[@inherits](diameter_dict.md#inherits) in a dictionary file creating a
4949
beam dependency, not an erl/hrl dependency.
5050

5151
Multiple `-i` options can be specified.
@@ -60,11 +60,11 @@ source. Valid options are as follows.
6060
- **\--name <name>** - Name the output module.
6161

6262
- **\--prefix <prefix>** - Transform the input dictionary before compilation,
63-
setting `[@name](diameter_dict.md#name)` or
64-
`[@prefix](diameter_dict.md#prefix)` to the specified string.
63+
setting [@name](diameter_dict.md#name) or
64+
[@prefix](diameter_dict.md#prefix) to the specified string.
6565

6666
- **\--inherits <arg>** - Transform the input dictionary before compilation,
67-
appending `[@inherits](diameter_dict.md#inherits)` of the specified string.
67+
appending [@inherits](diameter_dict.md#inherits) of the specified string.
6868

6969
Two forms of `--inherits` have special meaning:
7070

@@ -80,6 +80,9 @@ source. Valid options are as follows.
8080

8181
Multiple `--inherits` options can be specified.
8282

83+
- **\--indirect-inherits** - Enables indirect inherits feature, see more
84+
[here](`diameter_make:codec/2`).
85+
8386
# EXIT STATUS
8487

8588
Returns 0 on success, non-zero on failure.

lib/diameter/src/compiler/diameter_codegen.erl

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,24 @@ f_enumerated_avp(ParseD) ->
594594

595595
enumerated_avp(ParseD) ->
596596
Enums = get_value(enum, ParseD),
597-
lists:flatmap(fun cs_enumerated_avp/1, Enums)
598-
++ lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end,
599-
get_value(import_enums, ParseD)).
597+
CurrentEnums = lists:flatmap(fun cs_enumerated_avp/1, Enums),
598+
ImportedEnums = lists:flatmap(fun({M,Es}) -> enumerated_avp(M, Es, Enums) end,
599+
get_value(import_enums, ParseD)),
600+
%% Remove duplicate clauses in the imported enums. This is important to generate correct
601+
%% code when multiple dictionaries in the inheritance chain add values to the same
602+
%% enumerated AVP. The last in the list is the one that is closest to the current module
603+
%% in the inheritance chain and the one which should be kept.
604+
Fun = fun({_, Id, [_, {_, _, Name}, _], _, _} = Elem, AccIn) ->
605+
case lists:search(fun({_, SId, [_, {_, _, SName}, _], _, _}) ->
606+
Id == SId andalso Name == SName end, AccIn) of
607+
{value, Previous} ->
608+
lists:delete(Previous, AccIn) ++ [Elem];
609+
false ->
610+
AccIn ++ [Elem]
611+
end
612+
end,
613+
FilteredEnums = lists:foldl(Fun, [], ImportedEnums),
614+
CurrentEnums ++ FilteredEnums.
600615

601616
enumerated_avp(Mod, Es, Enums) ->
602617
lists:flatmap(fun({N,_}) ->
@@ -734,7 +749,19 @@ empty_value(ParseD) ->
734749
Enums = [T || {N,_} = T <- get_value(enum, ParseD),
735750
not lists:keymember(N, 1, Imported)]
736751
++ Imported,
737-
lists:map(fun c_empty_value/1, Groups ++ Enums)
752+
%% Here we need to remove duplicate empty_value clauses that are generated when
753+
%% multiple dictionaries in the inheritance chain define values for the same
754+
%% enumerated AVP.
755+
lists:foldl(fun(Elem, AccIn) ->
756+
Name = element(1, Elem),
757+
case lists:any(fun({clause, _, [{_, _, SearchName}, _], _, _}) ->
758+
?A(Name) == SearchName end, AccIn) of
759+
true ->
760+
AccIn;
761+
false ->
762+
AccIn ++ [c_empty_value(Elem)]
763+
end
764+
end, [], Groups ++ Enums)
738765
++ [{?clause, [?VAR('Name'), ?VAR('Opts')],
739766
[],
740767
[?CALL(empty, [?VAR('Name'), ?VAR('Opts')])]}].

0 commit comments

Comments
 (0)