Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
sf_fmt(3)		 BSD Library Functions Manual		     sf_fmt(3)

     format_init, format_free, format_metarule,	formatf, format_lastresult,
     format_lastsize, format_detach -- template	formatting functions.

     #include <strfunc.h>

     fmt_base *

     format_free(fmt_base *base);

     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);

     format_lastsize(fmt_base *base);

     char *
     format_detach(fmt_base *base, size_t *optReturnSize);

     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 ran-
     domly 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 ob-
     tain the pointer to the buffer and	its size without invoking formatf()
     once more.

     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.

     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 "${pass-
     word}", 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 re-
     turned by handler.	 Values	are counted from zero, so zero index will rep-
     resent 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 re-
     turn 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

     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.

     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);

     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 */

	     return 0;

     char **
     handler1(char *found, void	*optKeyPassed) {
	     static char *arr[3] = { NULL, NULL, NULL };


	     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 };


	     if(strcasecmp(found, status) == 0)	{
		     arr[0] = "busy";
		     return arr;

	     return NULL;

     strfunc(3), cfgread(3).

     Lev Walkin	<>

BSD				October	1, 2000				   BSD


Want to link to this manual page? Use this URL:

home | help