This page describes macros available both for thalassa
(the
static content generator) and thalcgi.cgi
(the CGI program).
Please note that the colon char “:
” is used hereinafter as
the delimiter, but in fact any ASCII punctuation char (except for
“_
” and “*
”) can be used in this role.
trim
macrocollapsews
macro:
collapse whitespacermlf
macro:
remove linefeedslhead
and lhead
macros: list splittinglindex
macro:
access list items by indiceslsort
macroltgt
macro:
HTML protectionurlenc
macro:
URL-encodingq
macro:
quote string as HTML attributeiffile
macrofilesize
macroreadfile
macrodir
macroimgdim
macro:
dimensions for img
tagThis section describes macros that allow to choose one of the two (or more) alternatives depending on certain conditions.
WARNING: Please make sure you read and understood the section devoted to eager computational model and its consequences. It is important to understand that all arguments of any nesting macro call are always computed (unconditionally), and conditional macros only choose one of the results of these computations, simply dropping the results that aren't choosen.
if
macroSynopsis:
%[if:condition:then_text:else_text]
The first argument (condition) is trimmed off any leading and trailing whitespace; in case the result of this trimming is not empty, the condition is assumed true, and then_text is returned; otherwise, else_text is returned.
The third argument may be omitted; in this case, if the condition is empty (false), the macro call expands to an empty string.
ifeq
macroSynopsis:
%[ifeq:str1:str2:then_text:else_text]
The first two arguments (str1 and str2) are trimmed off any leading and trailing whitespace, and the results are compared; in case they are equal, then_text is returned; otherwise, else_text is returned.
The fourth argument may be omitted; in this case, if the strings are not equal, the macro call expands to an empty string.
ifbelongs
macroSynopsis:
%[ifbelongs:str1:list:then_text:else_text]
The first argument (str) is trimmed off any leading and trailing whitespace. The second argument (list) is broken down to words (that is, using whitespace as separators); then, check is performed whether str equals any of the words. In case the word is found, then_text is returned; otherwise, else_text is returned.
The fourth argument may be omitted; in this case, if the given word isn't found in the list, the macro call expands to an empty string.
or
macroSynopsis:
%[or:str1:str2: ... ]
The arguments (str1, str2 etc.) are checked one by one, whether they turn into an empty string after trimming off leading and trailing whitespace. The first argument that doesn't become empty (which effectively means it contains any non-whitespace characters) is returned as it was in the call, before trimming.
If no suitable argument is found, an empty string is returned.
switch
macroSynopsis:
%[switch:expr:v1:r1:v2:r2 ... ]
The first argument, expr, after stripping off all leading and trainling whitespace, is compared, one by one, with values v1, v2 etc., also with spaces stripped off; in case one of them equals to the expr, the work is immediately finished and the corresponding result (r1, r2...) is returned. In case none of the values match, an empty string is returned.
In the present version of Thalassa CMS, there's only one macro resembling a
loop construct. In reality it is not a loop, it is a mapper. It might
look somewhat bad practice to provide anything loop-like in such an
environment; unfortunately, it seems hard to invent anything else to
build, e.g., a list of <option>
items for the
<select>
HTML form input — and, generally
speaking, having an arbitrary list of items, to build an HTML
representation for it.
Anyway, the mapper is not intended to be used as a general purpose loop construct, and it definitely should not be abused this way. Remember, all these Thalassa CMS ini files are not programs. If you feel you need a general purpose loop, it means you're doing something wrong.
foreach
macroSynopsis:
%[foreach:list:name:a1:a2: ... ]
The first argument (list) is broken down to words (using whitespace for delimiting). Then for each word, the macro named name is invoked with arguments a1, a2, ..., and with the word as the last argument.
The results of all invocations are concatenated (with no chars inserted in between the items — that is, a real concatenation is done), and the concatenated string is returned.
For example, consider the following call:
%[foreach:alpha beta gamma:m1:pp:qq:rr]
The result will be precisely the same as if we did
%[m1:pp:qq:rr:alpha]%[m1:pp:qq:rr:beta]%[m1:pp:qq:rr:gamma]
In most cases, the
html
macro is used as the second argument to foreach
, and the
HTML snippet name is passed as the third argument.
Consider, for example, you've got a list of certain words and you want to create an HTML enumerated list out of them. The following two snippets will do the thing:
[html] words2ol = <ol>%[foreach:%0%:html:li_enclose]</ol> li_enclose = <li>%0%</li>
Having these two snippets, it is sufficient to write
%[html:words2ol:put your list here]
to
get the HTML list.
In the present version, the set of string manipulation functions doesn't look very powerful. However, once again, this macro system is not a programming language, so we shouldn't ever want things like indexing a string, getting substrings and the like.
trim
macroSynopsis: %[trim:string]
The argument is stripped off any leading and trailing whitespace; the result is returned.
collapsews
macro: collapse whitespaceSynopsis: %[collapsews:string]
The argument is stripped off any leading and trailing whitespace; within the rest, any non-empty sequence of whitespace chars (space, tab, carriage return and newline) is replaced with exactly one space. The result is returned.
rmlf
macro: remove linefeedsSynopsis: %[rmlf:string]
All carriage return and newline chars are removed from the argument, the result is returned.
Please note the argument is not stripped nor modified in any other way, only the CR and LF chars are removed.
lhead
and lhead
macros: list splittingSynopsis:
%[lhead:list:delimiter]
%[ltail:list:delimiter]
The two macros allow to split a string, treated as a list, down to the head
and the tail. The delimiter argument may be omitted or left
empty; the string is then considered as a list of words, separated
by arbitrary amounts of whitespace. If a non-empty delimiter is
specified, it is trimmed off any leading and trailing whitespace, and the
remaining string (as a whole) is used as the delimiter: the first occurence
of it is found within the first argument, and lhead
returns
everything before the delimiter, while ltail
returns
everything after the delimiter.
If the specified delimiter is not found within the first agrument,
lhead
returns the whole agrument, and ltail
returns an empty string. If delimiter is not specified, and there's only
one word, lhead
returns the word (trimmed off surrounding
whitespace), and ltail
returns an empty string. If the first
argument is empty, both macros return an empty string.
lindex
macro:
access list items by indicesSynopsis:
%[lindex:list:template:delims]
The lindex
macro treats its first argument
(list
) as a list and provides access to its first 10
elements by their indices; it is possible to access several elements in one
call, building a new string according to the given
template
.
The third argument (delims
)
controls how the string is broken to list elements. The argument can be
omitted or left empty; in this case the string is broken down to
words using whitespace chars as delimiters, producing no empty
words (that is, any amount of whitespace in a row it considered equal
to a single space). If the argument consists of non-whitespace chars
only, all the chars become delimiters; in this case, the string is
broken down to elements using the delimiters, and empty elements become
possible. Adding a trailing whitespace instructs the macro to
trim off any leading and trailing whitespace from every element.
Please be warned that, as the macroprocessor is encoding-agnostic, using a non-ascii char as a delimiter will not work for UTF-8.
If the third argument starts with one or more whitespace chars and contains non-whitespace chars as well, it means one of the predefined special cases; the argument in this case is stripped off any leading and trailing whitespace, and the rest identifies how the list must be broken down to elements. In the present version, there are two such cases:
n
means to use the newline char as the only delimiter,
stripping carriage returns (leading and trailing), if any, andN
works similarly, but trims any leading and trailing
whitespace from every line.We leave it unspecified what happens if the delims
argument has leading spaces and is not listed as a special case above; in
future versions, some additional functionality may be implemented.
The template
is first striped off any leading and
trailing whitespace; what happens afterwards depends on whether its first
non-space char is a digit or not, and may sound complicated. Before giving
the full description, let's note that in the simplest case it is
just a digit from 0
to 9
, causing the
macro to return the respective element of the list, numbered from zero.
For example, %[lindex:foo bar bazz:1]
will return
bar
.
In case the first character of the template is a digit, the template is
traversed from left to right, and digits from 0
to
9
are replaced with the respective elements of the
list, while all other characters are left intact. For example, a call
%[lindex:foo bar bazz:2-0+1]
will expand to bazz-foo+bar
.
If the first non-space char of the template is not a digit, it becomes the local escape char. The rest of the template, not including its first char, is traversed from left to right, and escape chars immediately followed by digits are replaced with the respective list elements. If the escape char is followed by another escape char, a single escape char is put into the resulting string; we intentinally leave unspecified what happens in case the escape char is followed by anything but a digit and the escape char. All the other stuff is left intact. For example,
%[lindex:foo bar bazz:=AAA=2BBB=0==0CCC=1DDD]
will turn into AAAbazzBBBfoo=0CCCbarDDD
. This mode allows
including literal digits into the result.
lsort
macroSynopsis:
%[lsort:list:delims:glue]
The lsort
macro sorts the given list of strings.
The first argument (list) is a string to be broken down to list items, and the second argument (delims) determines how the string is broken down; see the the lindex macro's delims argument description for details, it works exactly the same way.
The last argument (glue) is the string to put between each two elements after they are sorted; one might want to call this a separator, but we use the term glue to avoid confusion with how the initial separation is done. If this argument is omitted, a single space char is used. If the argument is empty, the elements within the resulting string are not separated from each other at all.
Hence, if both delims and glue are omitted (that is, the macro is called with only one argument), the list is assumed to consist of words (any amount of whitespace is considered a separator), and after the sorting is done, the list is reassembled into the string of words, separated with exactly one space.
The sorting is done lexicographically in respect to the ASCII codepage. Please note however that Thalassa is mostly encoding-agnostic, so with strings containing non-ascii chars, the result may be far from what you expect.
Furthermore, please be aware that, despite the quicksort algorithm
is used internally, the whole thing can be way too slow for lenghty lists,
just because performing the lsort
involves, first, tokenizing
a large string (which means a lot of memory allocation operations and
copying), and, second, rejoining the sorted elements back to a single
string. It is strongly recommended to avoid sorting as long as you
can. For example, in the well-known Smoky template this macro is
used only once (!), for the /thalcgi.cgi/cmtadmin
page,
because being left unsorted, that list of all existing discussions looks
too messy to handle.
ltgt
macro: HTML protectionSynopsis: %[ltgt:string]
Within the argument, HTML active characters — namely “<”,
“>” and “&” — are replaced with, respectively,
“<
”, “>
” and
“&
”, making the text safe to be included into an
HTML document.
urlenc
macro: URL-encodingSynopsis: %[urlenc:string]
The argument is URL-encoded and returned.
Precisely speaking, ASCII alphanumeric characters as well as punctuation
chars -_~.
are left as they are, spaces are replaced with
+
, and any other byte is percent-encoded,
that is, replaced with the percent char and the 2-digit hexadecimal code.
Upper-case chars are uses as hexadecimal digits.
The macro is codepage-agnostic, just like almost all Thalassa CMS.
q
macro: quote string as HTML attributeSynopsis: %[q:string]
If the argument contains no doublequote char, it is returned being
surrounded by doublequotes. If it contains doublequotes but doesn't contain
apostrophes, it is returned surrounded by apostrophes. In case it contains
both apostrophes and doublequotes, it is returned surrounded by
doublequotes, with each doublequote char inside the argument replaced with
“"
”.
The macro is useful when you need to give an attrubute to an HTML tag, and you're not sure it will not contain doublequote chars at the generation time. Actually, it seems to be a good practice to use this macro for all attribute values that contain any macro calls.
iffile
macroSynopsis:
%[iffile:filename:then_text:else_text]
The first argument (filename) is trimmed off any leading and trailing whitespace, and the result is used as a file name; if the file with given name exists, then_text is returned; otherwise, else_text is returned.
The third argument may be omitted; in this case, if the file doesn't exist, the call expands to an empty string.
filesize
macroSynopsis: %[filesize:filename]
The first argument (filename) is trimmed off any leading and trailing whitespace, and the result is used as a file name; if the file with given name exists and is a regular file, its size (in bytes, as a decimal number) is returned; otherwise, the macro returns an empty string.
readfile
macroSynopsis: %[readfile:filename]
The first argument (filename) is trimmed off any leading and trailing whitespace, and the result is used as a file name; if the file with given name exists and is readable, the macro returns the whole contents of the file (as a string, so you probably shouldn't apply this macro to binary files). In case of any error, an empty string is returned.
In case the argument is empty or becomes empty after trimming, no attempts
will be made to open any files or to do anything else; the macro will
immediately return the empty string. This property can be used for
conditional reading of files: instead of placing the readfile
call in one of branches of any conditional checkers (in which case the
reading attempt will be
performed regardless of the condition), better check for the condition
within the readfile
's argument and return an empty string in
case the file is not to be read.
dir
macroSynopsis: %[dir:dirname:flags]
The dir
macro allows to extract file names from a given
directory. By default, filenames starting with
“.
” and “_
” are ignored;
this behaviour can be modified with flags (see below). It is important to
note that file names containing any whitespace are always
ignored and there's no way to override this rule.
The first argument (dirname) is trimmed off any leading and trailing whitespace, and the result is used as the directory name.
The second argument may contain the following chars:
h
: don't ignore hidden files (those with leading
“.
” in names);H
: extract hidden files only;u
: don't ignore file names that start with the underscore
char “_
”;U
: extract only file names starting with
underscore.If the second argument is empty, it can be omitted altogether.
The macro returns a string containing the extracted file names, separated by a single space char.
imgdim
macro: dimensions for img
tagSynopsis: %[imgdim:filename]
The first argument (filename) is trimmed off any leading and trailing whitespace, and the result is used as a file name; the file should contain a valid image in PNG, JPEG or GIF format. In case the file doesn't exist, not readable or its format is not recognized, the macro returns an empty string.
In case of successful image parsing, a string with HTML attributes,
suitable for use within the img
HTML tag, is returned. The
string looks like this:
width="305" height="500"
The file format is detected by its content, not by its name.
now
macro: current timeSynopsis: %now%
No arguments are accepted. Macro call is replaced with the current time as a Unix datetime value (a decimal integer equal to the amount of seconds passed since Jan 01, 1970).
rfcdate
macroSynopsis: %[rfcdate:unix_datetime]
The first argument (unix_datetime) is trimmed off any leading and
trailing whitespace; the result, which must be a decimal number, is taken
as a Unix date/time value. The macro returns the same date in a
human-readable form as defined by rfc2822, something like “29 Mar
2023 19:15:00 +0000
”.
Sometimes it becomes necessary to provide a template for file names that form a kind of an array with a main page and some numbered additional pages. For such cases, Thalassa provides a family of index macros; being used within a file name template, they are replaced with the indicies as necessary, thus forming file name series containing numbers.
The “main” page is always meant to have zero as its index; however,
there's often no page with index 1
(it is not present in lists
that have a native order, while is present in reversed lists).
The following macros are used in “indexed” file name templates:
%idx%
is substituted with the index number, but empty
string for zero;%_idx%
is substituted with the underscore char and the
index number (like “_12
”, but empty string for zero;%idx0%
is substituted with the index number, even if it is
zero.Please note these macros are not universally available, they only work for file name templates where numbered additional pages are involved. Parameters using these macros are explicitly declared as such.
Synopsis: %[thalassa_version:function]
If the argument is omitted, empty or contains whitespace only, the short
version string is returned. It looks like 0.2.00
.
Otherwise, the argument (function name) is trimmed off leading and trailing
whitespace; as of the current version,
%[thalassa_version:full]
returns longer string, like
Thalassa CMS v. 0.2.00 (built Feb 27 2024)
%[thalassa_version:id]
returns short decimal number
identifying the version; for 0.2.00, this number is 200
, and
for later versons the number is guaranteed to be greater.
%[thalassa_version:built]
returns the build date, as given by
the __DATE__
macro in gcc, like Feb 27 2024
.