DragonFly On-Line Manual Pages
sf_fmt(3) DragonFly Library Functions Manual sf_fmt(3)
NAME
format_init, format_free, format_metarule, formatf, format_lastresult,
format_lastsize, format_detach - template formatting functions.
SYNOPSIS
#include <strfunc.h>
fmt_base *
format_init();
void
format_free(fmt_base *base);
int
format_metarule(fmt_base *base, char leftBrace, char rightBrace,
char **(*function)(char *found, void *optKeyPassed));
char *
formatf(fmt_base *base, char *template, void *optKeyToPass);
char *
format_lastresult(fmt_base *base, size_t *optSize);
size_t
format_lastsize(fmt_base *base);
char *
format_detach(fmt_base *base, size_t *optReturnSize);
DESCRIPTION
It is widely used for programs to read a template and display the data
according to it.
Those functions forms a powerful solution to work with a kind of "active"
templates. The term "active" means that some operations, like a test of
existence of a keyword, or equality tests, can be placed directly to the
template and no special handling needed in an application to support it.
strfunc(3) library will automagically do the dirty work for you.
The internal language of defining the template is powerful yet simple.
Before we run into detailed explanation, let's talk about programming.
First, programmer needed to initialize the formatting engine by defining
the formatting rules. Formatting rules are stored inside the special
structure fmt_base. format_init() creates an empty structure and returns
the pointer to it. One may define a numerous formatting bases and
randomly use them. Formatting base may be freed using
format_free(fmt_base *). Please note that format_init() will never
return the NULL pointer.
Second, there is a need to fill this empty structure with some formatting
rules using the format_metarule() function. Formatting rules are defined
by specifiyng a braces and the function which will handle the data inside
the braces.
Say, we have a template "abc${def}ghi". Programmer should call the
format_metarule(fb, '{', '}', handler), where fb is the pointer to the
formatting base returned by format_init(). If two braces are equal, the
result is undefined. handler is the function which should be defined as
char ** handler(char *found, void *optKeyPassed).
It is possible to define a number of such a rules for the single
fmt_base. The handler function should return the pointer to the internal
char ** data when it is possible, and NULL pointer otherwise. Please NOTE
that this pointer is never modified or freed and probably it should be
the semi-static structure inside the handler function.
When you're finished to fill the fmt_base with the rules, the function
formatf() can be used multiple times to convert the specified template to
the destination text. The optional optKeyToPass argument may be specified
to pass some additional data, if necessary.
formatf() will place the output to the buffer located in the fmt_base and
return a pointer to it. The pointer will never be NULL, and is not to be
freed. If you need this buffer to be completely yours and do not want to
strdup(3) it, there is a function called format_detach(fmt_base *, size_t
*optReturnSize) to achive this.
Two other functions, char * format_lastresult(fmt_base *, size_t
*optSize) and size_t format_lastsize(fmt_base *), are to be used to
obtain the pointer to the buffer and its size without invoking formatf()
once more.
ACTIVE TEMPLATE DEFINITION
If a template is not containing the special tokens it will considered as
plain text and returned unmodified.
Special token and the whole template are defined in the following BNF:
<template> := *(*<string> *<token> *<string>)
<token> := <simple> | <join> | <index> | <choice> | <equality>
<simple> := '$' <LB> <param> <RB>
<join> := '$' <LB> <param> '+' <delimiter> <RB>
<index> := '$' <LB> <param> '[' <number> ']' <RB>
<choice> := '$' <LB> <param> '?' <iftrue> ':' <iffalse> <RB>
<equality> := '$' <LB> <param> { "==" | "!=" } *<string> '?' <iftrue> ':' <iffalse> <RB>
<LB> := <the second argument of format_metarule()>
<RB> := <the third argument of format_metarule()>
<param> := <string>
<delimiter> := <string>
<iftrue> := <template>
<iffalse> := <template>
<string> := *<CHAR>
<number> := 1*<character from '0' to '9'>
The word param defined above, will be passed as the first argument to the
handler function.
ACTIVE TEMPLATE EXAMPLE
The following is an example of the typical template. It may be placed to
a file, then read and passed to formatf(). It is also can be defined as
the argument's value within the configuration file read by cfgread(3).
Login: ${login[0]}
Password: ${password}
Username: ${name?${name}:Unknown name}
Comments: ${comment+, }
$<status==Busy?User is busy>
You can see the index token "${login[0]}", the simple token
"${password}", the join token right after the "Comments: ", and equality
token is the whole last string. Please note that the last token is formed
using the angle braces: you should specify an additional handler function
to handle this case. Refer to the PROGRAMMING EXAMPLE section.
Simple tokens are used to display the data returned by the handler()
function almost without the modification. One exception from this rule
exists: if handler return multiple values they are joined together with
the string ", " as the separator.
Join tokens are used to join the multiple values. As mentioned above, the
handler function return the string array. In this case all values will be
joined together separated by the specified delimiter. For this primer the
delimiter is ", " (comma followed by single space).
Index token used to get the specified value from the string array
returned by handler. Values are counted from zero, so zero index will
represent the first available string.
Choice token used to give the dynamic behavior to the templates. The
<iftrue> section will be placed to the output buffer if the handler
return the valid non-NULL pointer to the non-empty array. This form can
be used to rule the output if the expected parameter is not present or
empty.
Equality token used to test the array returned by the handler against the
string value. The <iftrue> section will be placed to the output buffer if
this string match at least one of the array's elements. All comparisons
are canse-insensitive.
PROGRAMMING EXAMPLE
Here's how to implement the above template example's parsing.
#include <strfunc.h>
char **handler1(char *found, void *optKeyPassed);
char **handler2(char *found, void *optKeyPassed);
int
main() {
fmt_base *fb;
char *template = "Login: ${login[0]}\nPassword: ${password}\nUsername: ${name?${name}:Unknown name}\nComments: ${comment+, }\n$<status==Busy?User is busy>\n";
char *s;
/* Create empty structure */
fb = format_init();
/* Add one formatting rule */
format_metarule(fb, '{', '}', handler1);
/* Add another formatting rule to parse angle braces */
format_metarule(fb, '<', '>', handler1);
/* Format the template */
s = formatf(fb, template, NULL);
/* Print out the result */
printf("%s", s);
/* Free the formatting structure */
format_free(fb);
return 0;
};
char **
handler1(char *found, void *optKeyPassed) {
static char *arr[3] = { NULL, NULL, NULL };
(void)optKeyPassed;
arr[1] = NULL;
if(strcasecmp(found, "login") == 0) {
arr[0] = "john";
return arr;
};
if(strcasecmp(found, "name") == 0) {
arr[0] = "John Smith";
return arr;
};
if(strcasecmp(found, "password") == 0) {
arr[0] = "123";
return arr;
};
if(strcasecmp(found, "comment") == 0) {
arr[0] = "Comment value #1";
arr[1] = "Comment value #2";
return arr;
};
return NULL;
};
char **
handler2(char *found, void *optKeyPassed) {
static char *arr[] = { NULL, NULL };
(void)optKeyPassed;
if(strcasecmp(found, status) == 0) {
arr[0] = "busy";
return arr;
};
return NULL;
};
SEE ALSO
strfunc(3), cfgread(3).
AUTHORS
Lev Walkin <vlm@lionet.info>
DragonFly 6.5-DEVELOPMENT October 1, 2000 DragonFly 6.5-DEVELOPMENT