*** xref:xlat/log.adoc[Logging Functions]
*** xref:xlat/protocol.adoc[Protocol Encoding and Decoding]
*** xref:xlat/string.adoc[String Handling]
+**** xref:xlat/concat.adoc[Concatenation]
+**** xref:xlat/explode.adoc[Split strings]
+**** xref:xlat/length.adoc[Length]
+**** xref:xlat/lpad.adoc[Left pad]
+**** xref:xlat/pairs.adoc[Print attributes]
+**** xref:xlat/rpad.adoc[Right pad]
+**** xref:xlat/randstr.adoc[Random strings]
+**** xref:xlat/tolower.adoc[Conver to lowercase]
+**** xref:xlat/toupper.adoc[Convert to uppercase]
*** xref:xlat/builtin.adoc[Built-in Expansions]
*** xref:xlat/character.adoc[Single Letter Expansions]
*** xref:xlat/attribute.adoc[Attribute References]
--- /dev/null
+= %concat(<&ref:[idx]>, <delim>)
+
+Used to join two or more attributes, separated by an optional delimiter.
+
+This expansion is the inverse of xref:xlat/explode.adoc[explode].
+
+.Return: _string_
+
+In most cases, `%concat(...)` is only useful inside of a dynamically
+expanded string. If you need to concatenate strings together in a policy, just use `+`.
+
+.Example
+
+[source,unlang]
+----
+&control += {
+ &Tmp-String-0 = "aaa"
+ &Tmp-String-0 = "bb"
+ &Tmp-String-0 = "c"
+}
+
+&reply += {
+ &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
+ &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
+}
+----
+
+.Output
+
+```
+aaa, bb, c
+aaa,bb,c
+```
+
+.Using "+"
+[source,unlang]
+----
+string foo
+
+&foo += { "a", "c", "c", "d" } # abcd
+
+&foo += &control.Tmp-String-0[*]
+----
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= Dictionary Lookups
+
+The following functions perform lookups based on dictionary names and numbers.
+
+The functions are defined in the `dict` module. It must be listed in
+the `mods-enabled/` directory in order for the expansions to work.
+
+== %concat(<&ref:[idx]>, <delim>)
+
+Used to join two or more attributes, separated by an optional delimiter.
+
+.Return: _string_
+
+In most cases, `%concat(...)` is only useful inside of a dynamically
+expanded string. If you need to concatenate strings together in a policy, just use `+`.
+
+.Example
+
+[source,unlang]
+----
+&control += {
+ &Tmp-String-0 = "aaa"
+ &Tmp-String-0 = "bb"
+ &Tmp-String-0 = "c"
+}
+
+&reply += {
+ &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
+ &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
+}
+----
+
+.Output
+
+```
+aaa, bb, c
+aaa,bb,c
+```
+
+.Using "+"
+[source,unlang]
+----
+string foo
+
+&foo += { "a", "c", "c", "d" } # abcd
+
+&foo += &control.Tmp-String-0[*]
+----
+
+== %explode(<&ref>, <delim>)
+
+Split an string into multiple new strings based on a delimiter.
+
+This expansion is the opposite of `%concat( ... )`.
+
+.Return: _the number exploded list of strings_.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "bob.toba@domain.com"
+
+&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
+
+&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
+----
+
+.Output
+
+```
+Welcome bob.toba
+```
+
+== %lpad(<string>, <val>, <char>)
+
+Left-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 00000000123
+```
+
+== %rpad(<string>, <val>, <char>)
+
+Right-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 12300000000
+```
+
+== %pairs(<list>.[*])
+
+Serialize attributes as comma-delimited string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := { "This is a string", "This is another one" }
+&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
+----
+
+.Output
+
+```
+Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
+```
+
+== %randstr( ...)
+
+Get random string built from character classes.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
+----
+
+.Output
+
+```
+The random string output is 4Uq0gPyG
+```
+
+== %tolower( ... )
+
+Dynamically expands the string and returns the lowercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "CAIPIRINHA"
+&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+tolower of CAIPIRINHA is caipirinha
+```
+
+== %toupper( ... )
+
+Dynamically expands the string and returns the uppercase version of
+it. This definition is only available in version 2.1.10 and later.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "caipirinha"
+&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
+----
+
+.Output
+
+```
+toupper of caipirinha is CAIPIRINHA
+```
+
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %explode(<&ref>, <delim>)
+
+Split an string into multiple new strings based on a delimiter.
+
+This expansion is the inverse of xref:xlat/concat.adoc[concat].
+
+.Return: _the list of strings_.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "bob.toba@domain.com"
+
+&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
+
+&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
+----
+
+.Output
+
+```
+Welcome bob.toba
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %lpad(<string>, <val>, <char>)
+
+Left-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 00000000123
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %pairs(<list>.[*])
+
+Serialize a list of attributes as comma-delimited string.
+
+.Return: _string_
+
+Note that there is no "convert string to pairs" function. Instead, you can simply assign the string to a structural attribute (`group`, `tlv`, etc.) and the string will be parsed as pairs.
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := { "This is a string", "This is another one" }
+&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
+----
+
+.Output
+
+```
+Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %randstr( <format> )
+
+Get random string built from input character classes.
+
+.Return: _string_
+
+Build strings of random chars, useful for generating tokens and passcodes
+Format similar to the Perl module `String::Random`.
+
+Format characters may include the following, and may be
+preceeded by an integer repetition count:
+
+.Character Classes
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Character | Description
+| c | lowercase letters `[a-z]`
+| C | uppercase letters `[A-Z]`
+| n | numbers `[0-9]`
+| a | alphanumeric
+| ! | punctuation `!"#$%&'()*+,-./:;<=>?@[\\]^_{\|}~``
+| . | alphanumeric + punctuation
+| s | alphanumeric + `.` and `/`
+| o | characters suitable for OTP (visually similar characters removed)
+| b | binary data
+|=====
+
+There is no `h` for "hex". Instead, use `b` to create binary data, followed by the `%hex(..)` function to convert it to hex.
+
+.Example
+
+[source,unlang]
+----
+&reply.Reply-Message := "The random string output is %randstr(8a)"
+----
+
+.Output
+
+```
+The random string output is 4Uq0gPyG
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %rpad(<string>, <val>, <char>)
+
+Right-pad a string.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "123"
+
+&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
+----
+
+.Output
+
+```
+Maximum should be 12300000000
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
The following functions perform string manipulation.
-== %concat(<&ref:[idx]>, <delim>)
-
-Used to join two or more attributes, separated by an optional delimiter.
-
-.Return: _string_
-
-In most cases, `%concat(...)` is only useful inside of a dynamically
-expanded string. If you need to concatenate strings together in a policy, just use `+`.
-
-.Example
-
-[source,unlang]
-----
-&control += {
- &Tmp-String-0 = "aaa"
- &Tmp-String-0 = "bb"
- &Tmp-String-0 = "c"
-}
-
-&reply += {
- &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ', ')"
- &Reply-Message = "%concat(%{control.Tmp-String-0[*]}, ',')"
-}
-----
-
-.Output
-
-```
-aaa, bb, c
-aaa,bb,c
-```
-
-.Using "+"
-[source,unlang]
-----
-string foo
-
-&foo += { "a", "c", "c", "d" } # abcd
-
-&foo += &control.Tmp-String-0[*]
-----
-
-== %explode(<&ref>, <delim>)
-
-Split an string into multiple new strings based on a delimiter.
-
-This expansion is the opposite of `%concat( ... )`.
-
-.Return: _the number exploded list of strings_.
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "bob.toba@domain.com"
-
-&control.Tmp-String-1 := "%explode(&control.Tmp-String-0, '@')"
-
-&reply.Reply-Message := "Welcome %{control.Tmp-String-1[0]}"
-----
-
-.Output
-
-```
-Welcome bob.toba
-```
-
-== %lpad(<string>, <val>, <char>)
-
-Left-pad a string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "123"
-
-&reply.Reply-Message := "Maximum should be %lpad(%{control.Tmp-String-0}, 11, '0')"
-----
-
-.Output
-
-```
-Maximum should be 00000000123
-```
-
-== %rpad(<string>, <val>, <char>)
-
-Right-pad a string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "123"
-
-&reply.Reply-Message := "Maximum should be %rpad(%{control.Tmp-String-0}, 11, '0')"
-----
-
-.Output
-
-```
-Maximum should be 12300000000
-```
-
-== %pairs(<list>.[*])
-
-Serialize attributes as comma-delimited string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := { "This is a string", "This is another one" }
-&reply.Reply-Message := "Serialize output: %pairs(&control.[*])"
-----
-
-.Output
-
-```
-Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
-```
-
-== %randstr( ...)
-
-Get random string built from character classes.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&reply.Reply-Message := "The random string output is %randstr(aaaaaaaa}"
-----
-
-.Output
-
-```
-The random string output is 4Uq0gPyG
-```
-
-== %tolower( ... )
-
-Dynamically expands the string and returns the lowercase version of
-it. This definition is only available in version 2.1.10 and later.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "CAIPIRINHA"
-&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
-----
-
-.Output
-
-```
-tolower of CAIPIRINHA is caipirinha
-```
-
-== %toupper( ... )
-
-Dynamically expands the string and returns the uppercase version of
-it. This definition is only available in version 2.1.10 and later.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-&control.Tmp-String-0 := "caipirinha"
-&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
-----
-
-.Output
-
-```
-toupper of caipirinha is CAIPIRINHA
-```
-
-// Copyright (C) 2021 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+.String manipulation
+[options="header"]
+[cols="30%,70%"]
+|=====
+| Function | Description
+| xref:xlat/concat.adoc[concat] | Concatenate strings with delimiters
+| xref:xlat/explode.adoc[explode] | Split a string based on delimiters
+| xref:xlat/length.adoc[length] | Get the length of a string
+| xref:xlat/lpad.adoc[lpad] | Left pad a string
+| xref:xlat/pairs.adoc[pairs] | Serialize a list of attributes to a string
+| xref:xlat/rpad.adoc[rpad] | Right pad a string
+| xref:xlat/randstr.adoc[randstr] | Return a random string based on input format
+| xref:xlat/tolower.adoc[tolower] | Convert the input string to lowercase.
+| xref:xlat/toupper.adoc[toupper] | Convert the input string to uppercase
+|=====
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %tolower( ... )
+
+Dynamically expands the string and returns the lowercase version of
+it.
+
+The lowercase operation is done using the current locale.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "CAIPIRINHA"
+&reply.Reply-Message := "tolower of %{control.Tmp-String-0} is %tolower(%{control.Tmp-String-0})"
+----
+
+.Output
+
+```
+tolower of CAIPIRINHA is caipirinha
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= %toupper( ... )
+
+Dynamically expands the string and returns the uppercase version of
+it.
+
+The uppercasecase operation is done using the current locale.
+
+.Return: _string_
+
+.Example
+
+[source,unlang]
+----
+&control.Tmp-String-0 := "caipirinha"
+&reply.Reply-Message := "toupper of %{control.Tmp-String-0} is " + %toupper(%{control.Tmp-String-0})
+----
+
+.Output
+
+```
+toupper of caipirinha is CAIPIRINHA
+```
+
+// Copyright (C) 2023 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.