= Double Quoted Strings

.Syntax
`"string"`

A double-quoted string allows escape sequences and
xref:xlat/index.adoc[dynamic expansions]. As with
xref:type/string/single.adoc[single-quoted strings], text within
double quotes can include spaces.

For normally quoted strings, the quotation character can be placed inside of
the string by escaping it with a backslash.

For triple quoted strings, the quotation character does not need to be
escaped.  However, if the string does contain an escaped quotation
character, the quotation character is unescaped, as with normally
quoted strings.

The main difference between the single and double quoted strings is
that the double quoted strings can be dynamically expanded. The syntax
`${...}` is used for parse-time expansion and `%{...}` is used for
run-time expansion. The difference between the two methods is that the
`${...}` form is expanded when the server loads the configuration
files and is valid anywhere in the configuration files. The `%{...}`
xref:xlat/index.adoc[dynamic expansion] form is valid only in conditional
expressions and attribute assignments.

The output of the dynamic expansion can be interpreted as a string,
a number, or an IP address, depending on its context.

Note that the interpretation of text _strongly_ depends on the
context.  The text `"0000"` can be interpreted as a data type
"integer", having value zero, or a data type "string", having value
`"0000"`.  In general when a particular piece of text is used, it is
used with the context of a known attribute.  That attribute has a
xref:type/index.adoc[data type], and the text will be interpreted as that
data type.

NOTE: Most values retrieved from external datastores will be treated implicitly
as double-quoted strings.

== Escape sequences

Escape sequences allow the inclusion of characters that may be difficult to
represent in datastores, or the FreeRADIUS configuration files.

.Escape sequences and their descriptions
[options="header", cols="15%,85%"]
|=====
| Escape sequence     | Character represented
| `\\`                | Literal backslash (0x5c)
| `\r`                | Carriage return (0x0d)
| `\n`                | Line feed (0x0a)
| `\t`                | Horizontal tab (0x09)
| `\"`                | Double quote (0x22)
| `\x<hex><hex>`      | A byte whose numerical value is given by `<hex><hex>` interpreted as a hexadecimal number.
| `\<oct><oct><oct>`  | A byte whose numerical value is given by `<oct><oct><oct>` interpreted as an octal number.
|=====

== Methods of Creating Strings

There are a few different ways in which double-quoted strings can be
created.  The simplest is just an in-line string, as in `"string"`.
However, strings can also be created via
xref:unlang/expression.adoc[expressions]. and
xref:xlat/index.adoc[dynamic expansions].

In general, creating strings via xref:xlat/index.adoc[dynamic
expansions] will result in the _printed_ version of the expansion
being used.

.Example of double-quoted string expansion
[source,unlang]
----
"User-Name is %{User-Name}"
"IP Address is %{reply.Framed-IP-Address}
----

Both of the above expansions will return the _printed_ version of the
expansion.  For `User-Name`, it will be the string version of the
users name, as would be expected.  However, for the
`Framed-IP-Address` example, the printed version will be an ASCII
string such as `192.0.2.1`, even though the actual IP address is a
32-bit number.

When a string is created via an
xref:unlang/expression.adoc[expression] using the `+` operator, the
resulting string can be quite different, depending on the inputs.

.Example of casting to 'string'
[source,unlang]
----
"User-Name is " + &User-Name
"IP Address is " + (string) &reply.Framed-IP-Address
----

The output strings here (with casting) are the same as for the
previous example.  Note that we do not have to cast `&User-Name`,
because it is already a string.

.Example of casting to 'octets'
[source,unlang]
----
"User-Name is " + (octets) &User-Name
"IP Address is " + (octets) &reply.Framed-IP-Address
----

The output strings here are completely different than for the previous
examples.  The output data type is `octets`, and not `string`.

If the goal is to have the _raw_ `octets` data inserted into a
`string`, you must cast the octets to a string value.  That process
will copy the input `octets` value to a the output, changing the data
type to `string`.  The value is left alone.

.Example of casting to raw 'octets'
[source,unlang]
----
"User-Name is %{Tmp-Octets-0}"
"User-Name is %{(string) &Tmp-Octets-0}"
----

if the `&Tmp-Octets-0` attribute has value `0x666f6f` (`foo`)

In the first expansion, the resulting output is `User-Name is
0x666f6f`.  In the second expansion, the resulting output is
`User-name is foo`.

Note that placing raw `octets` data into a string may allow for binary
data to be inserted into what should be a printable string.  Any uses
of the string will result in the non-printable data being escaped as
`\000` or other methods such a `\n`, depending on how and wheere the
string is being used.

.Examples

`"word"` +
`"a string"' +
`"foo\"bar\""` +
`"this is a long string"` +
`"this has embedded\ncharacters"` +
`"attribute\tvalue\nusername\t%{User-Name}\nreply-message\t%{reply.Reply-Message}"`
`"The result of 'SELECT * FROM foo WHERE 1' is: %sql(SELECT * FROM foo WHERE 1)"`
`"""this string has a "double quoted" string in the middle of it"""`

// Licenced under CC-by-NC 4.0.
// Copyright (C) 2019 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
// Copyright (C) 2019 The FreeRADIUS project.
// Copyright (C) 2021 Network RADIUS SAS.




