# The CT++ template language (2.8 version)

Contents

- Templates
  - Comments
  - Formatting
  - Including
- Variables
  - Arrays
  - Mappings
- Control flow
  - Choice
  - Loops
- Functions
- Blocks
- Library reference
  - _ (msgid[, msgid_plural, n][, domain])
  - AVG (flag, a[, b, ...])
  - BASE64_DECODE (x)
  - BASE64_ENCODE (x)
  - CAST (flag, x)
  - CONCAT (a[, b, ...])
  - CONTEXT ()
  - DATE_FORMAT (x, format)
  - DEFAULT (x, y)
  - DEFINED (a[, b, ...])
  - ERROR ()
  - FORM_PARAM (x, y)
  - GETTEXT (msgid[, msgid_plural, n][, domain])
  - GET_TYPE (x)
  - HASH_KEYS (x)
  - HMAC_MD5 (x, key)
  - HOSTNAME ()
  - HREF_PARAM (x, y)
  - HTMLESCAPE (a[, b, ...])
  - ICONV (x, src, dst[, flags])
  - IN_ARRAY (x, array)
  - IN_SET (x, a[, b, ...])
  - JSONESCAPE (a[, b, ...])
  - JSON (x)
  - LIST_ELEMENT (a[, b, ...], x)
  - LIST ([a, b, ...])
  - LOG (x[, base])
  - MAX (a[, b, ...])
  - MB_SIZE (x)
  - MB_SUBSTR (x, offset[, bytes[, y]]])
  - MB_TRUNCATE (x, offest[, addon])
  - MD5 (a[, b, ...])
  - MIN (a[, b, ...])
  - NUM_FORMAT (x, y)
  - OBJ_DUMP ([a, b, ...])
  - RANDOM ([[min,] max])
  - SIZE (x)
  - SPRINTF (format, a[, b, ...])
  - SUBSTR (x, offset[, bytes[, y]]])
  - TRUNCATE (x, offest[, addon])
  - URIESCAPE (a[, b, ...])
  - URLESCAPE (a[, b, ...])
  - VERSION ([x])
  - WMLESCAPE (a[, b, ...])
  - XMLESCAPE (a[, b, ...])

# Templates

> A template is a text file, that is marked-up using the CT++ template language. It used to separate content from presentation in web design.

> A template can contain CT++ tags. All CT++ tags have HTML-like syntax and they start with TMPL_. Names of CT++ tags are case insensetive (for example, TMPL_var, tmpl_var, or TmPl_VaR).

> CT++ supports the next tags: TMPL_var, TMPL_if, TMPL_elsif, TMPL_else, TMPL_unless, TMPL_foreach, TMPL_include, TMPL_comment, TMPL_block, TMPL_call, and TMPL_verbose.

> Example of a template:

>     <!DOCTYPE html>
>     <TMPL_include 'includes/html_lang.tmpl'>
>     <TMPL_include 'includes/html_head.tmpl'>
>         <link rel="stylesheet" href="/static/css/m.posts.css">
>     </head>
>     <body class="posts">
>         <div id="body-wrapper" class="body-wrapper">
>             <div id="content-wrapper" class="content-wrapper">
>                 <TMPL_include 'includes/header.tmpl'>
>                 <section role="main" class="content-column">
>                     <h1><TMPL_var _("Welcome to")> <TMPL_var project_name>, <TMPL_verbose>
>                     <TMPL_if logged>
>                         <TMPL_var HTMLESCAPE(DEFAULT(user_info.name, user_info.username))>
>                     <TMPL_else>
>                         <TMPL_var _("Anonymous")>
>                     </TMPL_if></h1>
>                     </TMPL_verbose>

>                     <TMPL_verbose>
>                     <TMPL_foreach users as user>
>                         <h3><a class="user-page-link" href="/user/<TMPL_var URLESCAPE(user.username)>" title="
>                             <TMPL_var HTMLESCAPE(DEFAULT(user.name, user.username))>">
>                             <TMPL_var HTMLESCAPE(DEFAULT(user.name, user.username))>
>                             </a></h3>
>                     </TMPL_foreach>
>                     </TMPL_verbose>

>                 </section>
>                 <TMPL_include 'includes/noscript_alert.tmpl'>
>             </div>
>         </div>
>         <TMPL_include 'includes/footer.tmpl'>
>     </body>
>     </html>

## Comments

> Use the TMPL_comment tag to comment-out part of a template.

> For example:

>     <TMPL_comment><h3>Hello, <TMPL_var username>!</h3></TMPL_comment>

## Formatting

> The TMPL_verbose tag removes white-space characters (space, form-feed, newline, carriage return, horizontal tab, and vertical tab) between CT++ tags.

> For example:

>     <TMPL_verbose>
>         foo: <TMPL_var foo> some text
>         bar: <TMPL_var bar> baz: <TMPL_var baz> <TMPL_var spam>
>     </TMPL_verbose>

> For instance, variables foo, bar, baz, and spam are respectively "{FOO}", "{BAR}", "{BAZ}", and "{SPAM}". The template would be rendered as:

>     foo:{FOO}some text
>         bar:{BAR}baz:{BAZ}{SPAM}

> Also, a dash could be used instead the TMPL_verbose tag:

>     foo: <TMPL_var foo-> some text
>         bar: <-TMPL_var bar-> baz: <-TMPL_var baz-> <-TMPL_var spam>

> There will same output.

## Including

> The TMPL_include tag loads another template within the template. The tag has the one attribute only. The attribute can't be a variable. It's a filename in quotes:

>     <TMPL_include "filename.tmpl">

> It is impossible to break conditions and loops between templates.

# Variables

> The CT++ template engine evaluates variable and replaces it with the result. The TMPL_var tag is used for evaluating variables.

> The types of variables are undefined variable, string, integer, floating-point number, mapping, and array. For undefined variables result is an empty string.

> The TMPL_var evaluates expressions: variables, operators, and functions. For example:

>     <TMPL_var foo>
>     <TMPL_var (foo + bar + 1)>
>     <TMPL_var HTMLESCAPE(baz)>

## Arrays

> An array is a data type consisting of a collection of elements, each identified by one array index. The first element of the array is indexed by subscript of 0.

> Examples:

>     <TMPL_var foo[0]>   <- foo must be an array!
>     <TMPL_var foo[bar]> <- bar must be an integer!

## Mappings

> A mapping is a data type composed of a collection of (key,value) pairs, such that each possible key appears at most once in the collection.

> Examples:

>     <TMPL_var foo.key> = <TMPL_var foo["key"]> <- foo must be a mapping
>     <TMPL_var foo.bar.baz> <- the mapping foo has the key "bar" with mapping value, that has the key "baz"

> Use a dot to access attributes of a variable.

# Control flow

## Choice

> The TMPL_if tag and the TMPL_unless tag evaluate a condition. A condition can be variable, function calls, arithmetic and logic expressions. Arithmetic and logic expressions must be inside of parentheses.

> Examples:

>     <TMPL_if foo>
>         Some text with <TMPL_var foo>
>     </TMPL_if>

>     <TMPL_unless DEFINED(bar)>
>         Some text
>     <TMPL_else>
>         Some text with <TMPL_var bar>
>     </TMPL_unless>

>     <TMPL_if (x < 1)>
>         eeny
>     <TMPL_elsif (x < 2)>
>         meeny
>     <TMPL_elsif (x < 3)>
>         miny
>     <TMPL_else>
>         moe
>     </TMPL_if>

> The following table summarizes the operator precedences, from highest precedence to lowest precedence:

> Operators | Assoc | Description
> --- | --- | ---
> (expression) |  | parentheses used for grouping
> () | LR | parentheses used for a function call
> . | LR | member selection
> [] | LR | array/mapping element access
> !, +, - | RL | logical not, unary plus, unary minus
> *, /, mod, div | LR | multiplication and division
> +, - | LR | addition and subtraction
> <, <=, >, >= | LR | inequality relational
> ==, != | LR | equality relational
> && | LR | logical and
> || | LR | logical or

> CT++ defines keywords to act as aliases for a number of operators: lt (<), le (<=), gt (>), ge (>=), eq (==), ne (!=), and (&&), or (||).

## Loops

> CT++ supports the TMPL_foreach only. It use an explicit iterator, in which the loop variable takes on each of the values in an array or a mapping.

> An iterator has special attributes:

> Attribute | Description
> --- | ---
> __index__ | index of array's element
> __key__ | key in mapping
> __first__ | "true" for first iteration
> __last__ | "true" for last iteration
> __inner__ | "true" if not first and not last iteration
> __even__ | "true" for even iteration
> __odd__ | "true" for odd iteration
> __value__ | value of element

> Example of usage:

>     <TMPL_foreach array as a>
>         value: <TMPL_var a> or <TMPL_var a.__value__>
>         index: <TMPL_var a.__index__>
>         <TMPL_if a.__first__>#first#</TMPL_if>
>         <TMPL_if a.__even__>#even#<TMPL_else>#odd#</TMPL_if>
>     </TMPL_foreach>

>     <TMPL_foreach map as m>
>         value: <TMPL_var m> or <TMPL_var m.__value__>
>         key: <TMPL_var m.__key__>
>         <TMPL_if m.__last__>#last#</TMPL_if>
>     </TMPL_foreach>

> The TMPL_break tag breaks the iteration of loop:

>     <TMPL_verbose>
>     <TMPL_foreach LIST("a", "b", "c") as char>
>         <TMPL_var char>
>         <TMPL_if (char == "b")><TMPL_break></TMPL_if>
>     </TMPL_foreach>
>     </TMPL_verbose>

> Output of the template is "ab".

# Functions

> CT++ has built-in functions, that is described in Library reference. CT++ tags, that support it: TMPL_var, TMPL_if, TMPL_unless, TMPL_elsif, and TMPL_foreach. For example:

>     <TMPL_var SPRINTF(GETTEXT("%d minutes ago", min), min)>

>     <TMPL_var DEFAULT(HTMLESCAPE(url), "http://ctpp.havoc.ru")>

>     <TMPL_if (GET_TYPE(var) == "STRING")>
>         <TMPL_var GETTEXT("var is string")>
>     </TMPL_if>

>     <TMPL_foreach LIST("eeny", "meeny", "miny", "moe") as item>
>         <TMPL_var item>
>     </TMPL_foreach>

# Blocks

> A block is reusable piece of a template called by name.

> Example of usage:

>     <TMPL_block "simple-block">
>         Some text
>     </TMPL_block>

> The TMPL_call tag is used for calling a block:

>     <TMPL_call "simple-block">
>     <TMPL_call some_var>

> A block can have arguments:

>     <TMPL_block 'some-block' args(a, b, c)>
>         <TMPL_var a>, <TMPL_var b>, and <TMPL_var c>
>     </TMPL_block>

>     <TMPL_call 'some-block' args(foo, bar, baz)>

> Definition blocks inside another blocks is forbidden.

# Library reference

## _ (msgid[, msgid_plural, n][, domain])

See GETTEXT.

## AVG (flag, a[, b, ...])

> Return average of a[, b, ...], according to chosen algorithm by flag. The values of flag are 'a' for arithmetic mean, 'g' for geometric mean, 'h' for harmonic mean, and 'q' for quadratic mean.

> Examples:

>     AVG('a', 1, 2, 3) -> 2
>     AVG('g', 1, 2, 3) -> 1.81712059283
>     AVG('h', 1, 2, 3) -> 1.63636363636
>     AVG('q', 1, 2, 3) -> 2.16024689947

## BASE64_DECODE (x)

> Decode the Base64 encoded string x.

## BASE64_ENCODE (x)

> Encode the string x use Base64.

## CAST (flag, x)

> Convert the type of x to a type specified by flag. The values of flag are "i[nteger]", "o[ctal]", "h[exadecimal]", "f[loat]", and "s[tring]".

> For x starts with 0x or 0X, "integer" flag behaves as "hexadecimal" flag. For x starts with 0, "integer" flag behaves as "octal" flag.

> Examples:

>     CAST("int", 1.345) -> 1
>     CAST("dec", "010") -> 10
>     CAST("hex", "010") -> 16

## CONCAT (a[, b, ...])

> Return a string which is the concatenation of the values a[, b, ...].

> Example:

>     CONCAT('a', 1, 2, 3) -> a123

## CONTEXT ()

> Return a mapping of the rendered context.

## DATE_FORMAT (x, format)

> Formats x according to the format specification format (see 'man 3 strftime'). The argument x is the number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).

> Example:

>     DATE_FORMAT(1200490323, "%Y-%m-%d %H:%M:%S") -> 2008-01-16 16:32:03

## DEFAULT (x, y)

> If x is nonzero return x else return y.

> Examples:

>     DEFAULT("", "default_string")   -> default_string
>     DEFAULT(nonexistent, "default") -> default
>     DEFAULT(0, 1)                   -> 1

## DEFINED (a[, b, ...])

> If all of a[, b, ...] exist return 1 else return 0.

## ERROR ()

> Create runtime error.

## FORM_PARAM (x, y)

> With name x and value y, output a hidden field of HTML form.

> It is equivalent to the next:

>     <TMPL_verbose>
>     <TMPL_if y>
>         <input type="hidden" name="x" value="<TMPL_var URLESCAPE(y)>">
>     </TMPL_if>
>     </TMPL_verbose>

## GETTEXT (msgid[, msgid_plural, n][, domain])

> Translate a text string msgid into the user's native language, by looking up the translation in a message catalog.

> If a translation was found, the message is converted to the locale's codeset and returned. Otherwise msgid or msgid_plural is returned.

> The appropriate plural form depends on the number n and the language of the message catalog where the translation was found.

> The argument domain is a set of translatable messages.

> The function _() is alias of GETTEXT().

> Examples:

>     GETTEXT("Hello, World!")                                -> Привет, Мир!
>     _("Hello, World!")                                      -> Привет, Мир!
>     _("Hello, World!", "mydomain")                          -> Привет, Другой Мир!
>     SPRINTF(_("%d hour", "%d hours", 1), 1)                 -> 1 час
>     SPRINTF(_("%d minute", "%d minutes", 2, "mydomain"), 2) -> 2 минуты

## GET_TYPE (x)

> Return a printable type of x. The types are "*UNDEF*" for undefined variables, "STRING" for strings, "INTEGER" for integers, "REAL" for floating-point numbers, "HASH" for mappings, and "ARRAY" for arrays.

## HASH_KEYS (x)

> Return an array of x's keys. The argument x should be mapping.

## HMAC_MD5 (x, key)

> Compute a hash value for the specified x using the supplied key.

## HOSTNAME ()

> Return the hostname of the current processor.

## HREF_PARAM (x, y)

> With name x and value y, output parameters of HTML links.

> It is equivalent to the next:

>     <TMPL_if a>x=<TMPL_var URLESCAPE(y)></TMPL_if>

## HTMLESCAPE (a[, b, ...])

> Escape &, <, ', ", and > in the strings of data a[, b, ...].

> HTMLESCAPE() returns result of concatenation of the strings a[, b, ...].

## ICONV (x, src, dst[, flags])

> Convert the string x from the coded character set src to dst.

> The argument flags are 'i' or 'I' for discarding illegal sequence, and 't' or 'T' for enabling transliteration in the conversion. The argument flags works in FreeBSD only.

> See 'iconv -l` for list which contains all the coded character sets known.

## IN_ARRAY (x, array)

> Return 1 if x was found in array, else return 0.

## IN_SET (x, a[, b, ...])

> Return 1 if x was found in a[, b, ...], else return 0.

## JSONESCAPE (a[, b, ...])

> Escape ", \, /, \b, \f, \n, \r, \t, ', \v, and \0 in the strings of data a[, b, ...]. If character's value is smaller than \u0032, it is encoded with \uXXXX format for hex digits XXXX.

> JSONESCAPE() returns result of concatenation of the strings a[, b, ...].

## JSON (x)

> Serialize x to the JavaScript Object Notation (JSON).

## LIST_ELEMENT (a[, b, ...], x)

> Return an element from a[, b, ...] by the index x.

## LIST ([a, b, ...])

> Return an array of [a, b, ...]. It can be empty.

## LOG (x[, base])

> With one argument, return the natural logarithm of x (to base e).

> With two arguments, return the logarithm of x to the given base, calculated as LOG(x) / LOG(base).

## MAX (a[, b, ...])

> Return the largest item of a[, b, ...].

## MB_SIZE (x)

> MB_ prefix marks function, which works with multibyte strings.

> See SIZE.

## MB_SUBSTR (x, offset[, bytes[, y]]])

> MB_ prefix marks function, which works with multibyte strings.

> See SUBSTR.

## MB_TRUNCATE (x, offest[, addon])

> MB_ prefix marks function, which works with multibyte strings.

> See TRUNCATE.

## MD5 (a[, b, ...])

> Return the MD5 hash of a[, b, ...].

## MIN (a[, b, ...])

> Return the smallest item of a[, b, ...].

## NUM_FORMAT (x, y)

> Return the formatted integer x with period y.

> Example:

>     NUM_FORMAT(1234567, ",") -> 1,234,567

## OBJ_DUMP ([a, b, ...])

> Return dump of the arguments [a, b, ...]. Return dump of all variables if no arguments.

## RANDOM ([[min,] max])

> Return a random number in the range (min, max]. The range (min, max] equals to 0 .. RAND_MAX, if no arguments.

## SIZE (x)

> Return the number of items of a sequence x.

## SPRINTF (format, a[, b, ...])

> Produce output according to a format. After the argument format, it expects at least as many additional arguments as specified in format.

> The argument format can optionaly contain embedded format tags that are substituted by the values specified in a[, b, ...].

> See 'man 3 printf' for more information.

## SUBSTR (x, offset[, bytes[, y]]])

> Return the characters in the string x starting at a specified position offset and continuing for a specified number of characters bytes. If the argument y exists, then return the string x with replaced the characters with y.

## TRUNCATE (x, offest[, addon])

> Return the string x, if it is less than or equal to offset characters long. If it is longer, it truncates the string.

> Return the string with addon, if the argument addon exists.

## URIESCAPE (a[, b, ...])

> Convert characters of the strings a[, b, ...] into their corresponding escape sequences.

> URIESCAPE() returns result of concatenation of the strings a[, b, ...].

## URLESCAPE (a[, b, ...])

> Convert characters of the strings a[, b, ...] into their corresponding escape sequences. It replaces spaces with "+" instead of "%20".

> URLESCAPE() returns result of concatenation of the strings a[, b, ...].

## VERSION ([x])

> Return the current version of CT++.

> Return extended information if x equals to "full".

## WMLESCAPE (a[, b, ...])

> Replace < with &gt;, > with &lt;, " with &quot;, ' with &apos;, $ with $$, and & with &amp; in the strings of data a[, b, ...].

> WMLESCAPE() returns result of concatenation of the strings a[, b, ...].

## XMLESCAPE (a[, b, ...])

> Replace < with &gt;, > with &lt;, " with &quot;, ' with &apos;, and & with &amp; in the strings of data a[, b, ...].

> XMLESCAPE() returns result of concatenation of the strings a[, b, ...].