Введение

В ряде задач WEB-программинга требуется быстрое и легкое построение вебинтерфейсов без привлечения квалифицированных программистов.
Кроме того, при использовании компилируемых языков (C, C++) необходимо иметь возможность изменения дизайна проекта без пересборки самого кода. В обоих случаях для их реализации требуется разделение данных и их представления.
Шаблонизатор CT++ (произносится "Сити плас плас") отвечает описанным требованиям и предоставляет дополнительные возможности, как то:
  • API пользовательских функций
  • Логические операции в ветвлениях
  • Большие возможности построения циклов
Шаблонизатор обладает высокой скоростью работы даже при использовании больших массивов выводимых данных.

Синтаксис операторов шаблонизатора базируется на основе синтаксиса модуля HTML::Template языка Perl что упрощает портирование приложений OO Perl, на C++. Шаблонизатор полностью разделяет код проекта (выводимые данные) и представление данных.

Мы желаем Вам приятного кодинга с CTPP.
По всем вопросам обращайтесь к группе разработчиков шаблонизатора CTPP:

Электронная почта: shetuhin@corp.mail.ru

Адрес www: htpp://www.reki.ru/products/ctpp
Copyright © 2003 - 2005 CTPP Dev. Team | http://reki.ru/products/ctpp


Обозначения и терминология

<TMPL_var name> - Операторы шаблонизатора CTPP.

__CONTEXT_VARS__ - модификаторы операторов

Внимание! - Дополнительная и справочная информация.


Операторы

На данный момент в шаблонизаторе реализовано 6 операторов:
  • <TMPL_var ИМЯ_ПАРАМЕТРА> - непосредственный вывод параметра.
  • <TMPL_if ИМЯ_ПАРАМЕТРА> <TMPL_else> </TMPL_if> - условное ветвление.
  • <TMPL_unless ИМЯ_ПАРАМЕТРА> <TMPL_else> </TMPL_unless> - дополнительное условное ветвление.
  • <TMPL_loop МОДИФИКАТОР1 МОДИФИКАТОР2 ИМЯ_ПАРАМЕТРА> </TMPL_loop> - цикл.
  • <TMPL_udf ИМЯ_ФУНКЦИИ(ПАРАМЕТР1, "ПЕРЕМЕННАЯ1", ПАРАМЕТР2, "ПЕРЕМЕННАЯ2")> - выполнение пользовательской функции.
  • <TMPL_include имя_файла> - выполнение пользовательской функции.
Для упрощения верстки имена всех операторов в CT++ являются регистронезависимыми. Поэтому записи <TMPL_var , <TmPl_VaR и <tmpl_VAR являются эквивалентными.

Имена переменных в CT++ зависят от регистра. Поэтому записи <TMPL_var ABC>, <TMPL_var abc> и <TMPL_var Abc> являются различными.

Максимальная длина любого оператора задается при сборке библиотеки и по умолчанию составляет 64 байта. ИМЯ_ПАРАМЕТРА может состоять из любых символов за исключением '>', '(', ')' и пробела.

Важно! Параметры, имена которых начинаются с символа подчеркивания (например __FIRST__), являются зарезервированными именами и не должны использоваться пользователем.


Переменные

В шаблонизаторе CT++ есть два типа переменных: локальные переменные и глобальные.
Смысл этих двух понятий полностью совпадает с их смыслом в других алгоритмических языках, таких как C++ и Perl.
Для вывода переменных используется оператор <TMPL_var ИМЯ_ПЕРЕМЕННОЙ>

Пример 1.1
Шаблон: "Hello, <b><TMPL_var username></b>!"
Параметр: username => "Olga"
Результат: "Hello, Olga!"

При выводе переменных можно использовать пользовательские функции.

Пример 1.2
Шаблон: "<a href="/index.cgi?username=<TMPL_var URLESCAPE(username)>">"
Параметр: username => "Андрей"
Результат: "<a href="/index.cgi?username=%C0%ED%E4%F0%E5%E9">"

Важно! Имена функций и переменных не должны содержать символов '>', '(', ')', пробела и не могут начинаться с символа подчеркивания. При вызове из оператора TMPL_var можно указать только один параметр функции.

    Ссылки по теме:
  • пользовательские функции


Операторы ветвления

Операторы этого типа позволяют выводить заданные части шаблона в зависимости от значения выражения, расположенного в их правой части. В СT++ версии 1.7.5 есть два оператора ветвления: <TMPL_if ВЫРАЖЕНИЕ> и <TMPL_unless ВЫРАЖЕНИЕ>. Операторы <TMPL_if и <TMPL_unless вычисляют значение ВЫРАЖЕНИЯ и выполняют или не выполняют код, находящийся внутри них. Внутри операторов допустимо использование как переменных (локальных и глобальных), так и пользовательских функций.

Общий вид операторов ветвления следующий:
<TMPL_if ВЫРАЖЕНИЕ>
Код, выполняющийся если условие истинно.
<TMPL_else>
Код, выполняющийся если условие ложно.
</TMPL_if>

<TMPL_unless ВЫРАЖЕНИЕ>
Код, выполняющийся если условие ложно.
<TMPL_else>
Код, выполняющийся если условие истинно.
</TMPL_unless>

Ветка <TMPL_else> явлвется необязательной, то есть допускается следующая запись: <TMPL_if ВЫРАЖЕНИЕ> Код </TMPL_if>. Таким образом, оператор <TMPL_unless отличается от оператора <TMPL_if тем, что выполняет код, если условие ложно. Пример 2.1:

Шаблон: "Hello, <b><TMPL_var username></b>!<TMPL_else>Не задано имя пользователя!</TMPL_if>
Параметр: username => "Vasya"
Результат: "Hello, Vasya!"

Пример 2.2:

Шаблон: "<TMPL_if username>Hello, <b><TMPL_var username>!<TMPL_else>Не задано имя пользователя!</TMPL_if>
Параметр: не задан.
Результат: "Не задано имя пользователя!"

Для второго варианта условного ветвления картина будет прямо противоположной:

Пример 2.3:

Шаблон: "<TMPL_unless username>Hello, <b><TMPL_var username></b>!<TMPL_else>Не задано имя пользователя!</TMPL_unless>
Параметр: "Vasya"
Результат: "Не задано имя пользователя!"

    Ссылки по теме:
  • пользовательские функции
  • переменные


Циклы

Цикл - процесс многократного повторения заданных действий.

В СT++ есть единственный тип циклов -- прямое прохождение по всему массиву данных. Оператором цикла являемся конструкция вида

<TMPL_loop МОДИФИКАТОРЫ ИМЯ_ЦИКЛА>
Внутренний код цикла.
</TMPL_loop>

В данный момент есть четыре модификатора оператора цикла:
  • __GLOBAL_VARS__ делает видимым внутри цикла глобальные переменные.
  • __NO_GLOBAL_VARS__ отменяет действие модификатора __GLOBAL_VARS__.
  • __CONTEXT_VARS__ создает внутри цикла контекстные переменные.
  • __NO_CONTEXT_VARS__ отменяет действие модификатора __CONTEXT_VARS__.

ВАЖНО! Изменение этих опций влияет не только на текущий цикл, но и на все вложенные внутрь него циклы.

Сделано это для того, чтобы при одновременном изменении __GLOBAL_VARS__ и __CONTEXT_VARS__ не возникало коллизий между вложенными циклами.

Пример 3.1:
Шаблон:

<table width="100%">
<TMPL_loop __CONTEXT_VARS__ EMPLOYEE_INFO>
<tr>
<td>#: <TMPL_var __COUNTER__></td>
<td>Имя: <TMPL_VAR NAME></td>
<td>Должность: <TMPL_VAR JOB></td>
</tr></TMPL_LOOP>
</table>

Параметры:
EMPLOYEE_INFO
[
{ NAME => "Иванов Иван", JOB => "Архитектор" },
{ NAME => "Петров Петр", JOB => "Строитель" }
]

Вывод:
<table width="100%">
<tr>
<td>1</td>
<td>Имя: Иванов Иван</td>
<td>Должность: Архитектор</td>
</tr>
<tr>
<td>2</td>
<td>Имя: Петров Петр</td>
<td>Должность: Строитель</td>
</tr>
</table>

    Ссылки по теме:
  • переменные
  • ветвления


Контекстные переменные

Если в цикле явно указано, что должны использоваться контекстные переменные, шаблонизатор CTPP вставляет внутрь цикла семь специальных переменных, называемых "контекстные переменные". Названия переменных начинаются с двойного символа подчеркивания, что говорит о том, что они являются системынми.

Значения переменных приводятся ниже:
  • __FIRST__ - установлена в "1" во время первой итерации цикла. Во всех остальных случаях не определена.
  • __LAST__ - содержит номер последней итерации во время последней итерации цикла. Во всех остальных случаях не определена.
  • __INNER__ - содержит номер итерации со второй по предпоследнюю. Во всех остальных случаях не определена.
  • __ODD__ - установлена, когда номер итерации нечетен. Содержит номер итерации. Для четных итераций неопределена.
  • __COUNTER__ - определена во всех итерациях и содержит текущий номер итерации.
  • __EVEN__ - установлена, когда номер итерации четен. Содержит номер итерации. Для нечетных итераций неопределена.
  • __SIZE__ - определена во всех итерациях внутри цикла и содержит полное количество итераций.

    Ссылки по теме:
  • пользовательские функции
  • переменные


Пользовательские функции

В ряде случаев бывает необходимо изменить вид выводимых данных в зависимости от каких-либо условий.
Для упрощения этой задачи в шаблонизаторе CT++ предусмотрен механизм пользовательских функций.
Функции могут быть вызваны как из операторов (<TMPL_if, <TMPL_unless и <TMPL_var) так и непосредственно при помощи оператора <TMPL_udf

Для операторов вызов функции производится следующим образом:

<TMPL_var HTMLESCAPE(name)>

или

<TMPL_if IN_SET(name, "1", "2", "3")>
Переменная "name" имеет значение "1", "2" или "3".
</TMPL_if>

Список встроенных функций шаблонизатора достаточно обширен:
  • URLESCAPE
  • HTMLESCAPE
  • NUM_FORMAT
  • IN_SET
  • HREF_PARAM
  • FORM_PARAM
  • ISEMAIL
  • ISALPHA
  • ISNUM
  • ISALNUM
  • ISINT
  • ISFLOAT

    Ссылки по теме:
  • переменные
  • ветвления


URLESCAPE

Функция производит замену символов на последоватльности вида %XX, где XX - шестнадцатеричный код символа.

Пример вызова функции:
<TMPL_var URLESCAPE(name)>

<TMPL_udf URLESCAPE(name)>

    Ссылки по теме:
  • пользовательские функции


URLESCAPE

HTMLESCAPE

Функция заменяет символы <, >, ", ' и & на &lt;, &gt;, &quot;, &#039; и &amp; соответственно.

Пример вызова функции:
<TMPL_var HTMLESCAPE(name)>

<TMPL_udf HTMLESCAPE(name)>

    Ссылки по теме:
  • пользовательские функции


NUM_FORMAT

Функция форматирует целое число, проставляя знак периода (1234567 -> 1,234,567).

Пример вызова функции:
<TMPL_var NUM_FORMAT(variable)>

<TMPL_udf NUM_FORMAT(variable)>

    Ссылки по теме:
  • пользовательские функции


IN_SET

Функция сравнивает первый аргумент с остальными аргументами.
Возвращает истину, если найдено хоть одно совпадение. Пример вызова функции:
<TMPL_if IN_SET(variable, "1", "2", "3")>

Агрументами функции могут быть как переменные, так и строки: <TMPL_if IN_SET(variable, variable1, "2", variable2)>

    Ссылки по теме:
  • пользовательские функции


HREF_PARAM

Функция служит для упрощения вывода параметров в ссылках.
Заменяет собой конструкцию вида <a href=/abc?<TMPL_if a>param_a=<TMPL_var URLESCAPE(a)></TMPL_if>... на <a href=/abc?<TMPL_udf HREF_PARAM("param_a", a)> Функция принимает на вход два или три параметра.
Первый параметр - имя параметра в ссылке. Второй параметр - его значение. Третий (необязательный) параметр указывает, необходимо ли выводить результат при отсутствии второго параметра. Может принимать значения "y", "yes", "n", "no" (по умолчанию - "y").

Пример вызова функции:
<TMPL_udf HREF_PARAM("param_name", param, "yes")>

<TMPL_udf HREF_PARAM("param_name", param)> (эквивалентен предыдущему)

<TMPL_udf HREF_PARAM("param_name", param, "n")>

    Ссылки по теме:
  • пользовательские функции


FORM_PARAM

Алгоритм работы функции аналогичен HREF_PARAM.

Предназначена для вывода в формах полей типа "hidden".

Заменяет собой конструкцию вида <TMPL_if a><input type="hidden" name="param_a" value=<TMPL_var URLESCAPE(a)"></TMPL_if> на <TMPL_udf FORM_PARAM("param_a", a)>

Пример вызова функции:
<TMPL_udf FORM_PARAM("param_name", param, "yes")>

<TMPL_udf FORM_PARAM("param_name", param)> (эквивалентен предыдущему)

<TMPL_udf FORM_PARAM("param_name", param, "n")>

    Ссылки по теме:
  • пользовательские функции
  • HREF_PARAM


Функции семейства ISXXX.

Все функции семейства ISXXX предназначены для проверки типов данных. Функции принимают на вход неограниченное количество параметров и возвращают "1" в случае соответствия всех переданных параметров проверяемому типу.

ISEMAIL

Проверяет параметры на соответствие упрощенному шаблону почтового адреса.

Пример вызова функции:
<TMPL_if ISEMAIL("abc@example.com", email)>

ISALPHA

Проверяет параметры на наличие только алфавитных ([a-zA-Z]) символов. Пример вызова функции:
<TMPL_if ISALPHA("example")>

ISNUM

Проверяет параметры на наличие только цифровых ([0-9]) символов. Пример вызова функции:
<TMPL_if ISNUM(some_value, "12345678")>

ISALNUM

Проверяет параметры на наличие только алфавитно-цифровых ([a-zA-Z0-9]) символов. Пример вызова функции:
<TMPL_if ISALNUM("mode123")>

ISINT

Проверяет параметры на соответствие целому числу. Пример вызова функции:
<TMPL_if ISINT("-890")>

ISFLOAT

Проверяет параметры на соответствие вещественному числу. Пример вызова функции:
<TMPL_if ISFLOAT("1.234E+3")>

    Ссылки по теме:
  • пользовательские функции


Вставка других шаблонов

В ряде случаев бывает удобно выделить одинаковые части в нескольких шаблонах (например, заголовок или меню на HTML странице)и вынести их в один файл.

В СT++ для этой цели служит оператор <TMPL_include файл_шаблона.tmpl>.

Общий вид оператора следующий:
<TMPL_include файл_шаблона.tmpl>

По умолчанию, файл ищется в текущем каталоге, но также возможно явно указать полный путь к вставляемому файлу шаблону.

Внимание! Недопустимо разбивать условия и циклы между подключаемыми шаблонами.
То есть такая конструкция работать не будет:
main.tmpl:
<TMPL_if foo>
<TMPL_include abc.tmpl>

abc.tmpl:
</TMPL_if>


Введение

Шаблонизатор CT++ написан на языке высокого уровня C++ с использованием STL. Для успешной сборки шаблонизатора требуется компилятор gcc версии 2.95.4 или более старшей или MS Visual C++ версии 6 или старше.

Шаблонизатор представляет простой С++ интерфейс для создания пользовательских функций.

Также предоставляется упрощенное C API.


Алгоритм работы

Процесс работы шаблонизатора можно условно разделить на четыре части:
  1. Инициализация
  2. Создание дерева синтаксического разбора текста шаблона
  3. Наложение параметров (первый проход)
  4. Наложение параметров (второй проход) и вывод результатов
В первой стадии происходит загрузка текста шаблона, автоматическая подгрузка стандартных функций и инициализация необходимых переменных.

Вторая стадия - это построение дерева синтаксического разбора шаблона. Все синтаксические ошибки генерируюся именно на этой стадии.

Во время первого прохода (третья стадия) происходит наложение параметров, находящихся вне циклов. Это дает выигрыш для простых шаблонов, в которых преобладает простой вывод параметров (без ветвлений и циклов).

Последняя стадия - наложение параметров на структуры циклов и ветвлений и дальнейший вывод результатов.


Пример кода

Здесь мы рассмотрим наиболее сложный пример из поставляемых вместе с библиотекой шаблонизатора. Имя файла примера: test_3_1.cpp.
Все остальные примеры находятся в каталоге tests.

Исходный текст программы:

// C++ Includes
#include <iostream>
// Local Includes
#include <ctpp/ctpp.hpp>

int main(void)
{
using namespace template_parser_ns;
using namespace std;

// Создаем структуру данных
param_data * pData = new param_data(param_data::HASH);
// Вставляем глобальный параметр
pData -> hash_insert_new_var("global_param", "Global Parameter");

// Вставляем цикл
param_data * pArray = pData -> hash_insert_new_array("EMPLOYEE_INFO");

// Внутри цикла - хеш с параметрами
param_data * pHash = pArray -> array_insert_new_hash();
// Параметр "NAME"
pHash -> hash_insert_new_var("NAME", "Иванов Иван");
// Параметр "JOB"
pHash -> hash_insert_new_var("JOB", "Архитектор");

pHash = pArray -> array_insert_new_hash();
pHash -> hash_insert_new_var("NAME", "Петров Петр");
pHash -> hash_insert_new_var("JOB", "Строитель");
// Подменяем глобальный параметр
pHash -> hash_insert_new_var("global_param", "Replaced Parameter");

try
{
// Шаблонизатор
template_text oTemplate;

// Загрузчик вложений
loader_base * pLoaderBase = new loader_base();

// Каталог для вложений
v_include_dir vIncludeDir;
vIncludeDir.push_back("./tmpl");
oTemplate.set_include_dir(vIncludeDir);
// Текст шаблона
pLoaderBase -> load_file("./tmpl/3_1.tmpl");
// Парзим шаблон
oTemplate.parse(pLoaderBase -> get_data());
// Накладываем параметры на шаблон
oTemplate.param(pData);
string sOutput;
// Получаем результат
sOutput.assign(oTemplate.output());
cout << sOutput << endl;
}
catch(exception &e) { cout << e.what() << endl; exit(1); }
return 0;
}

Шаблон:

<TMPL_include header.tmpl>
<TMPL_var global_param>
<TMPL_loop __CONTEXT_VARS__ __GLOBAL_VARS__ EMPLOYEE_INFO>
<TMPL_var NAME> - <TMPL_var JOB>
<TMPL_var global_param>
<TMPL_unless IN_SET(NAME, "Иванов Иван")>
TEST_ANY_PARAM
</TMPL_unless>
</TMPL_loop>
<TMPL_include footer.tmpl>

Параметры:

global_param => "Global Parameter"
EMPLOYEE_INFO
[
{ NAME => "Иванов Иван", JOB => "Архитектор" },
{ NAME => "Петров Петр", JOB => "Строитель", global_param => "Replaced Parameter" }
]

Вывод:
<!-- Copyright (c) 2004 Andrei V. Shetuhin -->
<html>
<head>
<title>Sample</title>
</head>
<body>
Global Parameter

Иванов Иван - Архитектор
Global Parameter

Петров Петр - Строитель
Replaced Parameter

TEST_ANY_PARAM

</body>
</html>
<!-- Footer End -->

Сборка:

gcc -c test_3_1.cpp -I /usr/local/include/ctpp

Для динамической линковки:
gcc test_3_1.o -L /usr/local/lib -o test_3_1 -lctpp

Для статической сборки:
gcc -static test_3_1.o -L /usr/local/lib -o test_3_1 -lctpp -lstdc++


API шаблонизатора

Класс template_text

// Конструктор
template_text(udf_fn_factory * pFactory = NULL,
const int iLine = 1,
const int iPos = 1,
const int iTabLength = 9,
const bool bDebug = false,
const bool bStrict = true,
const bool bLoopContextVars = false,
const bool bGlobalVars = false);

 где:
pFactory - фабрика объектов пользовательских функций

iLine - номер строки шаблона (по умолчанию - 1)
iPos - позиция в строке шаблона (по умолчанию - 1)
iTabLength - размер символа табуляции в пробелах (по умолчанию 9)

Эти три параметра используются для задания начальных значений в системе синтаксического контроля шаблона.

bDebug - параметр, отвечающй за вывод дополнительной отладочной информации (по умолчанию отладка отключена)
bStrict - состояние строгой проверки синтаксиса шаблона (после конструкции <TMPL_ обязательно должен следовать оператор шаблонизатора CT++, по умолчанию включено)

bLoopContextVars - использование контекстных переменных в цикле (по умолчанию отключено)
bGlobalVars - спользование глобальных переменных в цикле (по умолчанию отключено)

// Получение Factory
udf_fn_factory * get_fn_factory();

 Получение фабрики объектов. Если объект шаблонизатора создается без фабрики объектов, объект самостоятельно создает свою внутреннюю фабрику с набором стандартных функций.
Метод get_fn_factory служит для получения указателя на фабрику.

// Установка IncludeDir
void set_include_dir(const v_include_dir &vIncludeDir);

 где:
vIncludeDir - список каталогов для подключения вложений через <TMPL_include имя_файла.tmpl>

В случае, если путь к имени файла не начинается со слеша, файл последовательно ищется во всех каталогах из vIncludeDir. Если же путь начинается со слеша, путь проверяется на вхождение в vIncludeDir. В случае, если путь не найден в vIncludeDir или невозможно открыть файл, генерируется исключение std::logic_error.

// Парзинг текста
void parse(const std::string & sData);

void parse(std::string::const_iterator & sDataBegin, std::string::const_iterator & sDataEnd);

 Перегруженный метод. На вход получает начало и конец последовательности символов, являющихся шаблоном, либо строку символов.

// Вставка параметров
void param(param_data * pParamData);

 Вставка параметров в шаблон.

// Вывод данных
std::string & output();

 Вывод данных пользователю.

// Очистка шаблона
void clear_template();

 Очистка шаблона.

// Деструктор
~template_text() throw();

Класс loader_base

Базовый класс для создания собственного загрузчика вложений.
Используется по умолчанию и открывает файлы с диска.

// Загрузка файла
virtual void load_file(const std::string &sFileName);

Метод получает полное имя файла в виде аргумента.

// Получение данных
virtual std::string & get_data();

Отдает содержимое открытого файла.

// Деструктор
virtual ~loader_base() throw();

Класс udf_fn_factory

Класс-инсталлятор функций, определенных пользователем.

// Установка пользовательской функции
void install_udf_fn(const std::string &sFunctionName, udf_fn * pUDFFn);

 Вставляет созданный ранее объект функции в фабрику объектов. Первый параметр - имя функции в шаблоне. Второй параметр - указатель на объект функции.

// Удаление пользовательской функции
void remove_udf_fn(const std::string &sFunctionName);

 Удаление функции из фабрики объектов. Первый параметр - имя функции в шаблоне.

// Получение ссылки на функцию
udf_fn * get(const std::string &sFunctionName);

 Первый параметр - имя функции в шаблоне.

// Удаление всех функций
void clear();

 Удаляет все, в том числе и стандартные функции из фабрики объектов.

// Деструктор
virtual ~udf_fn_factory();

Класс param_data

Данный класс используется для передачи параметьров в шаблонизатор.

Определения сущностей.
В шаблонизаторе CTPP есть три типа данных: строка, массив и хэш. Ниже приведены определения этих типов:
// Строка
typedef std::string t_param_str;

// Массив
typedef std::vector<param_data *> t_param_array;

// Хэш
typedef std::map<std::string, param_data *> t_param_hash;

Для указания типа объекта служит перечисляемое множество e_value_type:
enum e_value_type { VAR, ARRAY, HASH };

 // Конструктор
param_data(e_value_type eIType = VAR);

 Создает объект в заданным типом.

// Указатель на переменную типа VAL
t_param_str * val();

 Возвращает указатель на объект типа "строка". Если этот метод запрашивается у объекта с типом, отличным от VAR, генерируется исключение std::logic_error.

// Указатель на переменную типа ARRAY
t_param_array * array();

 Возвращает указатель на объект типа "массив". Если этот метод запрашивается у объекта с типом, отличным от ARRAY, генерируется исключение std::logic_error.

// Указатель на переменную типа HASH
t_param_hash * hash();

 Возвращает указатель на объект типа "хэш". Если этот метод запрашивается у объекта с типом, отличным от HASH, генерируется исключение std::logic_error.

// Тип переменной
e_value_type get_value_type();

 Получение типа объекта.

// Вставка переменной в хеш
param_data * hash_insert_new_var(const std::string &sKey, const std::string &sValue);

 Вставка пары "ключ => значение" в хэш. Возвращает указатель на созданную строку.

// Вставка массива в хеш
param_data * hash_insert_new_array(const std::string &sKey);

 Вставка пары "ключ => массив" в хэш. Возвращает указатель на созданный массив.

// Вставка переменной в массив
param_data * array_insert_new_var(const std::string &sKey);

 // Вставка хеша в массив
param_data * array_insert_new_hash();

 // Удаление переменной из хеша
void param_data::hash_erase_var(const std::string &sKey);

 // Деструктор
~param_data();


API пользовательских функций

В данный момент все пользовательские функции реализуются посредством наследования от абстрактного класса udf_fn (User Defined FuNction) из пространства имен template_parser_ns.

Для передачи данных у класса предусмотрен перегруженный метод param. Метод принимает на вход один, два или три параметра типа std::string, либо один параметр типа std::vector<std::string>.

Класс должен информировать вызывающий процесс о количестве необходимых принимаемых переменных. Для этого служит метод accept_params(). Метод должен возвращать одно из четырех значений: ONE_PARAM (один параметр), TWO_PARAMS (два параметра), THREE_PARAMS (три параметра) или ANY_PARAMS (вектор с неограниченным количеством параметров).

Интерфейс класса приведен ниже:
namespace template_parser_ns
{
//
// Параметры, передаваемые функции
//
typedef std::vector<std::string> udf_fn_param;

//
// Функция, определяемая пользоваталем
//
class udf_fn
{
public:
// Количество принимаемых параметров
enum e_accept_params {ONE_PARAM, TWO_PARAMS, THREE_PARAMS, ANY_PARAMS};

// Передача параметров
// Произвольное число параметров
virtual void param(udf_fn_param * pParam);

// Один параметр
virtual void param(const std::string &sParam);

// Два параметра
virtual void param(const std::string &sParam1, const std::string &sParam2);

// Три параметра
virtual void param(const std::string &sParam1, const std::string &sParam2, const std::string &sParam3);

// Количество принимаемых параметров
virtual e_accept_params accept_params() = 0;

// Вычисление
virtual void handler() = 0;

// Результат вычислений
virtual std::string & result() = 0;

// Деструктор
virtual ~udf_fn() { ;; }

};

} // namespace template_parser_ns

Для подключения новой пользовательской функции необходимо внести созданный класс в фабрику объектов. Есть два метода использования фабрики объектов: создание новой и использование текущей из объекта шаблонизатора. Для создания новой фабрики объектов используется класс udf_fn_factory из пространства имен template_parser_ns:

// Создаем фабрику объектов
template_parser_ns::udf_fn_factory * pFactory = new udf_fn_factory();

// Создаем объект пользовательской функци
template_parser_ns::udf_fn * pFunction = new user_function();
// Создаем функцию в фабрике объектов
pFactory -> install_udf_fn("FOOBAR", pFunction);

// Создаем объект шаблонизатора
template_text * pTemplate = new template_text(pFactory);

В случае использования текущей фабрики объектов код будет примерно следующим:

// Создаем фабрику объектов
template_parser_ns::udf_fn_factory * pFactory = pTemplate -> get_fn_factory();

// Создаем объект пользовательской функци
template_parser_ns::udf_fn * pFunction = new user_function();
// Создаем функцию в фабрике объектов
pFactory -> install_udf_fn("FOOBAR", pFunction);

// Создаем объект шаблонизатора
template_text * pTemplate = new template_text(pFactory);


Сообщения об ошибках

Шаблонизатор CT++ может работать в двух режимах: со строгим контролем синтаксиса (включен по умолчанию) и без. В случае строгого контроля синтаксиса генерируется исключение std::logic_error в следующих случаях:
  • Превышена максимальная длина оператора (по умолчанию длина оператора ограничена 64 байтами).
  • Обнаружена синтаксическая ошибка в имени оператора. После конструкции <TMPL_ или </TMPL_ не следует ни одно из допустимых названий токенов (var, include, loop, if, else, unless, udf).
Диагностическое сообщение имеет следующий вид: "Syntax error in <TMPL_имя_оперетора ИМЯ_ПАРАМЕТРА at line НОМЕР_СТРОКИ column НОМЕР_СТОЛБЦА."

Пример:
Syntax error in <TMPL_var too_long_dataaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa at line 132 column 116.
Исключение std::logic_error всегда генерируется независимо от режима проверки синтаксиса шаблона в следующих случаях:
  • Обнаружено пересечение операторов. Пример:
    <TMPL_loop loop_var>
    <TMPL_if condition>
    |---> пересечение операторов TMPL_if и TMPL_loop
    </TMPL_loop>
    </TMPL_if>

    Диагностическое сообщение имеет следующий вид: "Fatal: Logic error near at line НОМЕР_СТРОКИ. Expected </TMPL_имя_оперетора> but found </TMPL_имя_оперетора>."

    Пример:
    Fatal: Logic error near at line 123. Expected /TMPL_IF, but found /TMPL_LOOP.

  • Обнаружена синтаксическая ошибка в имени функции, либо запрашиваемая функция не существует.
    Пример:
    Line 140 column 66: User defined function `FOOBAR' not found.

  • Обнаружены неправильно введенные параметры. В этом случае исключения генерирутся классом param_data.
Имена функций и переменных не должны содержать символов '>', '(', ')', пробела и не могут начинаться с символа подчеркивания. При вызове из оператора TMPL_var можно указать только один параметр функции.


Сборка из исходных кодов

Сборка из исходных кодов не представляет трудностей:
wget http://reki.ru/products/ctpp/download/ctpp-1.7.5.tar.gz
tar -xvzf ctpp-1.7.5.tar.gz
cd ctpp-1.7.5
./configure
make
make install
(для ОС семейства *BSD - gmake)

Для ОС FreeBSD возможна установка из портов:

cd /usr/ports/textproc/ctpp
make install clean

Для RPM-based дистрибутивов Linux (SuSe, RedHat...) есть RPM и Source RPM.
Сборка из source RPM (на примере Linux RedHat 8.0):

cd /usr/src/redhat/SRPMS
wget http://reki.ru/products/ctpp/download/ctpp-1.7.5.src.rpm
rpm -i ctpp-1.7.5.src.rpm
cd /usr/src/redhat/SPECS
rpmbuild -bb ctpp.spec
cd /usr/src/redhat/RPMS/i386

rpm -U ctpp-1.7.5-1.i386.rpm

Если же используется Gentoo Linux, сборка выглядит так:

wget http://reki.ru/products/ctpp/download/Linux/gentoo/ctpp-1.7.5.ebuild
ebuild ctpp-1.7.5.ebuild digest
emerge ctpp-1.7.5.ebuild


Лицензия

Шаблонизатор CT++ поставляется по лицензии BSD. Текст лицензии приведен ниже:

Copyright (c) 2004, CTPP Dev. Team

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Русский перевод (НЕ ЯВЛЯЮЩИЙСЯ ОФИЦИАЛЬНЫМ ТЕКСТОМ ЛИЦЕНЗИИ) размещен здесь исключительно для ознакомления.

Авторское право (с) 2004, команда разработчиков шаблонизатора CTPP.

Разрешается повторное распространение и использование как в виде исходных текстов, так и в двоичной форме, с модификациями или без, при соблюдении следующих условий:

- При повторном распространении исходного кода должно оставаться указанное выше уведомление об авторском праве, этот список условий и нижеследующий отказ от гарантий.

- При повторном распространении двоичного кода должно воспроизводиться указанное выше уведомление об авторском праве, этот список условий и нижеследующий отказ от гарантий в документации и/или в других материалах, поставляемых при распространении.

ЭТО ПРОГРАММА ПРЕДОСТАВЛЕНА БЕСПЛАТНО ДЕРЖАТЕЛЯМИ АВТОРСКИХ ПРАВ И/ИЛИ ДРУГИМИ СТОРОНАМИ "КАК ОНА ЕСТЬ" БЕЗ КАКОГО-ЛИБО ВИДА ГАРАНТИЙ, ВЫРАЖЕННЫХ ЯВНО ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ, ПОДРАЗУМЕВАЕМЫМИ ГАРАНТИЯМИ КОММЕРЧЕСКОЙ ЦЕННОСТИ И ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. НИ В КОЕМ СЛУЧАЕ, ЕСЛИ НЕ ТРЕБУЕТСЯ СООТВЕТСТВУЮЩИМ ЗАКОНОМ, ИЛИ НЕ УСТАНОВЛЕНО В УСТНОЙ ФОРМЕ, НИ ОДИН ДЕРЖАТЕЛЬ АВТОРСКИХ ПРАВ И НИ ОДНО ДРУГОЕ ЛИЦО, КОТОРОЕ МОЖЕТ ИЗМЕНЯТЬ И/ИЛИ ПОВТОРНО РАСПРОСТРАНЯТЬ ПРОГРАММУ, КАК БЫЛО РАЗРЕШЕНО ВЫШЕ, НЕ ОТВЕТСТВЕННЫ ПЕРЕД ВАМИ ЗА УБЫТКИ, ВКЛЮЧАЯ ЛЮБЫЕ ОБЩИЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ ИЛИ ПОСЛЕДОВАВШИЕ УБЫТКИ, ПРОИСТЕКАЮЩИЕ ИЗ ИСПОЛЬЗОВАНИЯ ИЛИ НЕВОЗМОЖНОСТИ ИСПОЛЬЗОВАНИЯ ПРОГРАММЫ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ПОТЕРЕЙ ДАННЫХ, ИЛИ ДАННЫМИ, СТАВШИМИ НЕПРАВИЛЬНЫМИ, ИЛИ ПОТЕРЯМИ ПРИНЕСЕННЫМИ ИЗ-ЗА ВАС ИЛИ ТРЕТЬИХ ЛИЦ, ИЛИ ОТКАЗОМ ПРОГРАММЫ РАБОТАТЬ СОВМЕСТНО С ДРУГИМИ ПРОГРАММАМИ), ДАЖЕ ЕСЛИ ТАКОЙ ДЕРЖАТЕЛЬ ИЛИ ДРУГОЕ ЛИЦО БЫЛИ ИЗВЕЩЕНЫ О ВОЗМОЖНОСТИ ТАКИХ УБЫТКОВ.


Благодарности

Sam Tregar -- за начало пути (HTML::Template 0.04 - 2.7)

Александру Макарову -- за ценные замечания и советы по API

Андрею Федоровскому -- за постоянный скепсис

Суханову Вадиму -- за Perl XS

Алёне - за то, что на свете есть такие люди, как она


CT++

Алёне, светлому ангелу,
посвящается.

CT++

Быстрый C++ шаблонизатор

Copyright © 2003 - 2005 CTPP Dev. Team | http://reki.ru/products/ctpp


RE

Выполняет поиск и/или замену значения соответственно заданному регулярному выражению.
Синтаксис регулярных выражений совпадает с синтаксисом решулярных выражений языка Perl.

Пример вызова функции:
<TMPL_udf RE(time, "/([0-9]{2}):([0-9]{2})/", "$1 - $2")>

<TMPL_if RE(name, "/([a-zA-z]+)/")>

    Ссылки по теме:
  • пользовательские функции


SPRINTF

Форматирует список параметров в соответствии с заданным шаблоном.
Спецификации формата вывода полностью соответствет стандарту sprintf(3) ISO/IEC 9899:1990 (ISO C89).

Пример вызова функции:
<TMPL_udf SPRINTF("%s %d", email, count)>

    Ссылки по теме:
  • пользовательские функции