Note:
This documentation is outdated and contains error, yet it gives a good
description of HTPL.
To INSTALL, see the INSTALL document.

 1. What is HTPL?
 2. What are the requirements for using HTPL?
 3. How do I compile HTPL?
 4. How does HTPL work?
 5. Tutorial
 5.1. Writing simple HTML
 5.2. Embedding simple Perl commands
 5.3. Interpreting forms
 5.4. Simple internet functions
 5.5. HTML generation functions
 5.6. Reading a comma delimited file
 5.7. Integrating an SQL database
 6. Reference
 6.1. HTPL library functions
 6.2. HTPL result set
 6.3. HTPL macros
 6.4. HTPL directives
 6.5. Writing your own macros
 6.6. Additional information

1. What is HTPL?

HTPL (Hyper Text Programming Language, or just a lame monogram of HTML and
PERL) is a Perl based scripting tool for creating web content. It is
basically a wrapper to CGI. Anything HTPL can do can be basically done
with Perl and CGI, but HTPL provides rapid development tools. An HTPL file
is an HTML file with Embedded HTML. Additional commands can be added. (eg,
C, SQL), but all in all the web server runs a CGI script created from your
document.

Note: There are three other tools called HTPL. I have no connection with
them.

2. What are the requirements for using HTPL?

You must have CGI access on your account, be able to give local directives
to your web server (ie, .htaccess files on apache), be able to write
temporary files somewhere and preferably be able to install modules from
CPAN. (That can be done on your local directory. Modules can also be
transferred to the same path the HTPL binary resides in). Perl 5.004 or
later is required. 

3. How do I compile HTPL?

To install type:
./configure
make
make install
make build

If you are the superuser, consider importing modules from CPAN by:
make CPAN

*IMPORTANT* * IMPORTANT* IMPORTANT* *IMPORTANT*
If you intend to install htpl as root, run configure as root!
*IMPORTANT* * IMPORTANT* IMPORTANT* *IMPORTANT*

4. How does HTPL work?

Anytime you access a htpl file the web server activates htpl.cgi as a cgi
script. Htpl.cgi reads the htpl file specified and converts it into a perl
script with the extension perl. (The file created can be run as a stand
alone CGI script, but you will not be able to use the redirect function
for document redirection or mime type settings). The perl file is then
executed. (Unless you used the XSUB extensions)  
Once the perl file is created, htpl will not preprocess the source htpl
again but immediately execute the perl script; that is, unless the htpl
file is newer than the perl file, in which case the perl file will be
recreated according to the new version. 
If you need to force reprocessing, update the htpl file or just touch it.
When creating an htpl documented with inline C code, htpl.cgi dumps the
embedded XSUB functions into a file, creates an installation module for it
and activates the usual compilation procedure. This can take a long time,
therefore you better add you C code only once fully functional.
When the script runs, its output is captured to a file, and only then
sent. This allows using the redirect function to redirect the browser even
if the script has already yielded output. Same is true for sending HTTP
cookies. 

5. Tutorial

5.1 Writing simple HTML

Our first dcoument will display a very well known string.
Create the file hello.htpl in your web directory:

<HTML>
<BODY>
Goodbye, Friend.
</BODY>
</HTML>

The results will be obvious.

5.2 Embedding simple Perl commands

Create the following file:
<HTML>
<BODY>
<#
	@time = localtime;

	$d = $time[3];
	$m = $time[4] + 1;
$y = $time[5] + ($time[5] < 70 ? 2000 : 1900);
>
Today is $d/$m/$y!
</BODY>
</HTML>

The contents of the perl script between the <# and > tags will be
evaluated, and the variables inside the perl code will be substituted.
Remember: If you want to use the  @ symbol (eg, for specifying an email)
you must escape it with a backslash, for example:
<A HREF=mailto:bill\@microsoft.com>

Now, look at this:

<#
	@t = localtime;
	if ($t[6] == 6) {
>
Today is Shabbath, therefore this site is closed.<BR>
Please log out and log on on a working day.
<HR>
<#
	} else {
print `date`;
	}
>

Two reveals:
1) You can escape to HTML in the middle of your code. HTPL will allow it
only after a block opening or closing, or an end of statement. Actually,
you can escape after the characters }, { and ;. Complicated regular
expressions might be a problem, but even Larry doesnt need that kind of
expressions. 
2) You can specify output using print if you dont want to escape to
HTML and back to PERL. 

5.3 Interpreting forms

Lets create the following form:
<FORM ACTION=feedback.htpl>
Name: <INPUT NAME=name><BR>
Email: <INPUT NAME=email><BR>
<INPUT TYPE=SUBMIT>
</FORM>

And put the following in the file feedback.htpl:
<BODY>
Hello $name &lt;$email&gt;
</BODY>

Try it for yourself!

For multiple checkboxes or select boxes you can refer to an array. For
example, if you had a series of checkboxes called item you can refer to
the array @item. For single inputs, an array with one element will be
created, so you dont need an additional check if the user checked only
one option.

You can use the %in hash array if you want to iterate over all the form fields.

5.4 Simple internet functions

HTPL comes with lots of prewritten plain perl functions.
Sending mail will be as the following:

<#
&sendmail (We received your order, From => bill@microsoft.com, To => 
president@whitehouse.gov, Subject => Hello!);
>

This will send a one line message to bill@microsoft.com, with the
appropriate headers. You dont needto construct the headers.

Now, we cant check for legal mail addresses, but we can check for the domain:

<#

unless (&validemail($mail)) {
>
<BODY>
The email $mail seems unreal!
</BODY>
<#
	exit(0);
>
	}
	&sendmail(<<EOM, From => sales\@microsoft.com , To => $mail, Subject => Hey!);
Hello $name,
Your order has been received.
EOM
>
<BODY>
Message sent.
</BODY>

First, we see we could exit the document when we found out we had to.
The validemail function works by validating the MX record and needs the
Net::DNS module installed. 

Now, lets create a document that gets a URL and redirects the browser, if
the URL exists: 

<BODY>
You will see this only if the URL $url is invalid.
<#
	if &validurl($url) &redirect($url);
>

The function validurl checks if the URL exists, using the LWP module. The
function redirects exits the script, and outputs the redirection location
instead of the script output. 

You can use the functions nslookup and revnslookup for name lookups.
To set a cookie, use the setcookie function, for examples:
Setcookie(last-visit, `date`, last-ip, $REMOTE_HOST);
The variable REMOTE_HOST is automatically set with the browsers hostname.
Next time the document is loaded, the values of $cookies{last-visit} and
$cookies{last-ip} will bset accordingly.

Now, suppose we want to read a document from the web:
<BODY>
<#
	unless (&validurl($url)) &redirect(http://www.disney.com);
	opendoc(INP, $url);
	while (<INP>) {
		if (/disney/I) $count++;
	}
>
$count line(s) contained Disney.
</BODY>

Its easy as that.

5.5 HTML generation functions

Here is something no fun to type:
<CENTER>
<TABLE WIDTH=400>
	<TR>
		<TD BGCOLOR=#C0C0C0>
			<B><CENTER>Hello</CENTER></B>
		</TD>
	</TR>
</TABLE>
</CENTER>

And all this for one line!

Now.
&html_format(Hello, CENTER| TABLE WIDTH=400|TR|TD|B|CENTER);

Will do the same.
The third argument can be set to a true value to have all the tags yielded
in one line, and the fourth argument can be set to true value to have the
HTML code returned but not printed. 

Now, arranging a list of elements in a table was never easier:
Create a list first.

@nums = map {&html_format($_, I|U, undef, 1);} (1 .. 100);

Now, lets arrange these in columns:
&html_table_cols(items => \@nums, cols => 10, 
	tattr => WIDTH = 100%);

The tags tattr, cattr and rattr contain extra information for TABLE, TR
and TD tags.

Now, the eval tag causes the table functions to evaluate the strings given
for tattr, cattr and rattr instead of plain using them.
Try this:

<#
	
@nums = map {&html_format($_, "B|I|U", undef, 1);} (1 .. 100);


	&html_table_cols(items => \@nums, cols => 10, 
		rattr => '($y % 2) ? "BGCOLOR=#C0C000" : "BGCOLOR=#FFFFFF"',
		cattr => '"ALIGN=" . (($x < 5) ? "RIGHT" : "LEFT")',
	eval => 1);
>

5.6 Reading a comma delimited file

All of us CGI programmers have done it.

Lets use the /etc/passwd as input. (Yes, it is wrong to use it for a web page)

We are going to now use one of the HTPL bundled macros: CSV

<BODY>
<#

#TEXT CSV users /etc/passwd : username password uid gid name

#FETCH users

print "$username is $name<BR>\"n;

#LOOP


>
</BODY>

This doesnt look like perl!
Basically, the first macro, TEXT CSV creates a result set called users
(which will be realized using  the variable $users), reading the file
/etc/passwd, with the delimiter : while the rest of the parameters are the
field names. 

An HTPL result set is always a table with field names and rows. The
retrieval macros always load the result set with all the information and
then proceed. 

Now, the #FETCH macro starts a loop, which ends with the #LOOP macro.
Inside the loop, the fields are populated into the main namespace.

The HTPL macros get converted by htpl.cgi into plain Perl code.

The same page could be written as:

<BODY>

<HTTEXT CSV users /etc/passwd : username password uid gid name>

<HTFETCH users>

$username is $name<B>

</HTFETCH>

>
</BODY>

5.7 Integrating an SQL database

HTPL uses DBI to link external databases. You can connect to any dbi data
source with the SQL CONNECT macro, for example:

#SQL CONNECT dbi:Oracle:test sysdba secret

There are simplified statements for connecting to several popular databases.
In this example we will use a local mSQL database called mydb, and we will
connect by: 

#SQL MSQL mydb

This can be also written inside the HTML code as:
<HTSQL MSQL mydb>

Now, lets do a simple SELECT.
We'll assume the database mydb contains a table called customers with th 
fields firstname, lastname  and email.

<BODY>
<#

	#SQL MSQL mydb

	#SQL CURSOR customers SELECT * FROM customers

	#IFNULL customers
	print We are sorry, but no customers were found.<BR>;

	#ELSE
>
<TABLE>
 	<TR>
		<TH>
			First name
		</TH>
		<TH>
			Last name
		</TH>
		<TH>
			Email
		</TH>
	</TR>
<#

	#FETCH customers

		print <TR><TD>$firstname</TD><TD>$lastname</TD><TD>$email</TD>;
	#LOOP

	print </TABLE>\n;

	#ENDIF

>

What happened here?
We connected to the database, and performed a SELECT query, into a result
set called customers. 
We checked if the result set was empty. If it was not, we dumped the results.

According to the broad trend, you can access the database without writing
SQL code. (Obviously writing SQL code will provide many more options)

For example:

#SQL QUERY myquery mytable firstname lastname

Will provide the same as:

#SQL CURSOR myquery SELECT * FROM mytable WHERE firstname = $firstname AND 
lastname = $lastname

Important: HTPL assumes the new versions of DBI, therefore when using the
non script SQL access, you save the need to quote strings and to escape
quotes. 

#SQL INSERT mytable firstname lastname email

Will be the same as:

#SQL EXEC INSERT INTO mytable (firstname, lastname, email) VALUES ($firstname,$lastname, $email)

5.8 Some more useful macros

Integrating a textual counter to your page as as easy as this:

<BODY>
<HTCOUNTER mypage.dat> people visited my page.
</BODY>

Random quotes were never easier:

<HTSWITCH RND>
<CASE>Man existence must be some form of mistake.
<CASE>Where do you want to go today
<CASE><A HREF="http://www.microsoft.com">One world, no languages</A>
</HTSWITCH>

Or usual switch statement:
#SWITCH CASE $s
#CASE 'abc'
&proc1();
#CASE 2 + $j
&proc2();
#END SWITCH

Or a random image:

<HTIMG RND SRC="me.jpg,mygf.jpg" WIDTH=60 HEIGHT=60 BORDER=0>

6. Reference

6.1 HTPL Library functions

The source code for these functions is in the file htpl-lib.pl

&addheader(HTTP_HEADER)

Adds an HTTP header. Unavailable for converted scripts executed outside htpl.cgi.

&closedoc(HANDLE)

Closes file handle HANDLE and disposes the local copy if needed. To be used with &opendoc.

&doconnect(HANDLE, HOST, PORT)

Opens socket to HOST:PORT on handle HANDLE.
HANDLE should be used with &doread and &dowrite and not standard input/output funcation.

&doread(HANDLE)

Reads all the incoming data on a socket and returns as a scalar value.

&dowrite(HANDLE, BUFFER)

Writes the data on the scalar value BUFFER to the socket HANDLE.

&expect(HANDLE, REGEXP)
&expect(HANDLE, REGEXP, CODE)

Reads incoming data and matches against REGEXP. If successful, returns the regular expression 
results. If not, calls the subroutine referenced by CODE where the input packet is passed to $_


&fileexists(FILENAME)

Checks if FILENAME exists. If FILENAME is a valid URL, checks if the URL exists.

&forkredirect
&forkredirect(LOCATION)

Redirects the browser to LOCATION while keeping the script running in background. Useful for batch 
processing.
Redirection unavailable for converted scripts executed outside htpl.cgi.
If LCOATION is omitted, exits and returns the script output, while background copy still runs.

&getcc

Attempts to find the C compiler. Tries in the usual locations, unless the default has been edited in 
htpl-config.pl.

&getmailprog

Attempts to find the mail program. Same mechanism as getcc.

&html_format(TEXT, TAGS)
&html_format(TEXT, TAGS, NONL, NOOUTPUT)

TAGS is a cons delmited list of HTML tags to apply, with no < > chars. TEXT is formatted with the 
TAGS, while closing tags are added automatically.
Set NONL to true if you want all the output in one line. 
Normally html_format yields the HTML code. Setting NOOUTPUT to true will make it only return the 
code.

&html_header(TITLE)

Prints <HTML>, <HEAD> and <TITLE> tags according to the TITLE supplied.

&html_hidden(FIELD)
&html_hidden(FIELD, VALUE)
&html_hidden(FIELD, VALUE, NOOUT)

Prints a hidden <INPUT> field. Usually used to transfer parameters between pages. If VALUE is 
omitted, the value of the scalar variable with the name of FIELD is used.
Set NOOUT to true to get the code returned without printing it.


&html_table_cols(ATTRIBUTES)
&html_table_rows(ATTRIBUTES)

Formats a list of values in an HTML table.
ATTRIBUTES are given as key => value pairs.
Attributes are case insensitive.
For columns divided table, attribute cols should contain the column number. For rows divided table, 
the attribute rows should be supplied.

The attributes tattr, rattr and cattr are used to specify the extra code for TABLE, TR and TD tags in the 
table, to control alignment, etc. Normally, they contain the string to include.

If the attribute eval is set to true, the contents of the attributes above are evaluate. The code can use the 
variables $x, $y, $data to inspect the cell before returning values.

Individual cells can be given different values, by using a hash reference instead of a scalar value ad the 
cell value.
The hash should contain: 
 ? Data  the real cell data
 ? Header  true if the cell should be formatted with TH and not TD
 ? cattr  alternative attributes for the cell. Ignored if not set or if null.

At last, the attribute noout can be set, so the html code is returned without being printed.

&include(FILENAME)

Dump a text file. FILENAME can be a URL.

&inputlist(ARRAYREF, ATTRIBUTES)

Returns a reference to an array of HTML code entries rendering a list of checkboxes or radio buttons.
ARRAYREF should point to an array of referenced hash tables, for each the following attributes have 
to appear:
 ? value  Value for the VALUE attribute of the INPUT tag
 ? text  text to put near the input element
ATTRBIUTES are pairs of key => value that describe the input list. The possible attributes are:
 ? name  Name of input fields. Mandatory.
 ? Default  Value or a reference to an array of values of input fields that will be marked as 
CHECKED
 ? OnCheck  Javascript code for onCheck event
 ? Attr  Additional attributes for INPUT tag


&isip(IP)

Returns true if IP is in IP address format. Doesnt validate contents.

&isurl(STRING)

Checks is STRING is composed as a URL. To check validity of the URL use &validurl.

&max(LIST)

Returns the highest element of LIST, numeric wise.

&min(LIST)

Returns the lowest element of LIST, numeric wise.

&nslookup(HOSTNAME)

Uses gethostbyname() to resolve HOSTNAME. Returns undef if lookup fails.

&opendoc(HANDLE, FILENAME)

Opens HANDLE to read FILENAME. If FILENAME is a URL, the document is fetched and then 
opened from a local copy. Handles opened with &opendoc should be closed with &closedoc to ensure 
erasure of temporary files.
The filename to use is given by &tempfilename

&publish(HASH)

For each in HASH, the value is copied to variables in the main namespaces with names identical to the 
key; both scalar and array values. 
In htpl.head, this brings the CGI variables to the main namespace. 

&readfile(FILENAME)

Reads the file named FILENAME into a scalar value. FILENAME may be a URL.

&redirect(URL)

Erases the output of the script and redirects the client. Any data sent to the HTTP headers (cookies etc) 
wont be erased except MIME TYPE info.
Unavailable for converted scripts executed outside htpl.cgi.

&rewind

Clear the output of the script.
Unavailable when script runs outside of htpl.cgi.


&revnslookup(IP)

Attempts to find hostname for IP.

&selectbox(DEFAULT, PAIRS)
&selectbox(HASHREF, PAIRS)

Prints <OPTION> tags .
If the first argument is a scalar, &selectbox only prints <OPTION> tags and not <SELECT> tags. 
PAIRS contains VALUE values for the tags and content information in pairs. The option with value 
equivalent to DEFAULT is marked SELECTED. DEFAULT can be undef if no default is required. 
(undef and not a blank string)
DEFAULT can an array reference, to select several options as default for multiple select boxes.

If the first argument is a hash reference, it should contain the following fields:
 ? Default  default values. Can be ommited.
 ? Name  Name of the field. <SELECT> tag will be printed
 ? Attr  Additional attributes for SELECT tag
 ? Noout  If set to true, HTML code will be returned but not printed


&sendmail(TEXT, ATTRIBUTES)
Sends a mail message by spawning a sendmail client process.
TEXT is the message, without ARPA mail message headers. Headers will be created automatically by 
the program.

ATTRIBUTES is a list of key => value pairs, as follows:
 ? To: Address of recipent. Can be either user@host, user@host name or name user@host
 ? From: Address of sender. Same format.
 ? Subject: Subject.
 ? Reply-To: Reply to address. Optional.
Any other attributes will be added as mail message headers.

The location of sendmail is taken from the function &getmailprog.

&setcookie(PAIRS)

Adds persistent cookies. PAIRS is an array of pairs of cookie names and values.
Unavailable when script runs outside of htpl.cgi.

&setmimetype(STRING)

Changes the MIME type of the document.  
Unavailable when script runs outside of htpl.cgi.
To write a script that returns images, use &setmimetype, then &rewind and after that 
binmode STDOUT and send the image to STDOUT.

&takelog(STRING)

Write a log entry to the default log file. The default log file for a
script is the script name with the extension log, unless the variable
$default_log_file points to a lof file name.

&tempfilename

Creates a temporary filename, unified by the script name, the PID, parent PID, time, index of calls and 
per session. That should completely suffice. The filename is preceded by ~~ to note a disposable file.
If the environment variable TEMP is set, the directory information contained in it is preceded to the 
filename.

&trim(STRING)

Cuts leading and trailing spaces, and removes double spaces. Returns the modified string.

&txt2html(TEXT)

Formats a string with line breaks, ampersands, > and < signs, and double quotes to HTML code.

&urldecode(STRING)

Decodes a string from an HTTP query.

&urlencode(STRING)

Encodes a string for HTTP queries.

&validemail(ADDRESS)

Checks if an email address is formed correctly, and if so, checks for the availability of a mail 
exchanger for the address. Returns undef if fails, true if succeeds.

&validurl(ADDRESS)

Checks if a URL is formed correctly, if so, checks for its existence. Returns undef if fails, true if 
succeeds.

6.2 HTPL result set

All the HTPL macros for information retrieval return their values via the HTPL result set class. This 
class is defined in the file htpl_result.pm

The information retrieval macros are implemented with packages creating an instance of htpl_result
Interface follows.

Class htpl_result {
constructor new(String Fields[]); 	# Gets the list of columns in the result set.
			 	# Returns a blessed reference
void addrow(String cells[]); 		# Gets a list of values, ordered according to
				# the field list. Adds a row to the result set.
bool isnone();			# Returns true if there are no rows in the result set
bool fetch();			# Populates the main namespace with scalar
				# variables named like the result set fields
				# with values from the current row. Then advances 1 row
				# Returns undef if past end of result set.
bool unfetch();			# Simillar to fetch, but moves backwards.
bool access(int row);		# Accesses a specific row. Returns undef if row does not 
# exist
	bool eof();			# Returns true if cursor is past end of result set.
	bool bof();			# Returns true if cursor is past the beginning of result set.
I	int index();			# Returns the index of current row
	int rows();			# Returns the number of rows
	String cols()[];			# Returns the names of the fields
	String getcol(int colnumber);	# Returns one value of the current row.
					# The number of the field is zero based
	String get(String colname);	# Returns one value, based on field name.
	void rewind();			# Sets the cursor on the first row and retrieves it
	htpl_result filter(bool code());	# Creates a subset of the result set for rows where
					# the code referenced returns true
}

HTPL comes with a class called htpl_db.pm used for SQL access. The class is used with the bundled 
SQL macros. There are also experimental classes for LDAP and XML  htpl_dir.pm and htpl_xml.pm.
The classes for text files  htpl_csv.pm for comma delimited files and htpl_flat.pm for text files are 
also supported.
A class for WAIS access is under development.

6.3 HTPL macros

Macros are specified in HTPL source as pseudo comments.
Lines beginning with a # and no spaces following before alphanumeric content will be matched for 
macros. If a macro was matched, the perl output file will be commented accordingly and the macro will 
be resolved.
If the macro instance does not contain a > (greater-than) sign or an odd number of double quotes,
it can be written inside a tag:
<#
	#MACRO
>
becomes
<HTMACRO>

For example:
<HTQUERY crs tbl>
<HTFETCH crs>
$name
<HTLOOP>

You can define as many macros as you like. See section 6.5.

The following macros are bundled with HTPL:

1. SQL
1.1 CONNECT
#SQL CONNECT <dbi-dsn> <username> <password>
Connects to a database.
Specific database:
1.2 MYSQL 
#SQL MYSQL <database> <username> <password>
1.3 MSQL
#SQL MSQL <database>
1.4 XBASE
#SQL XBASE <directory>
Uses the dbi::xbase module
1.5 POSTGRESQL
#SQL POSTGRESQL <database> <username> <password>
1.6 EXEC / EXECUTE
#SQL EXECUTE <dml or ddl>
Executes the SQL statements.
1.7 CURSOR / SEARCH
#SQL CURSOR <result set name> <sql query>
Runs a query, creates a result set object.
1.8 INSERT / ADD
#SQL INSERT <table name> <list of columns>
Inserts a new row.  Values are taken from the corresponding scalar variables. Uses type casting 
of new DBI modules.
1.9 QUERY
#SQL QUERY <result set name> <table> <list of constraint columns>
Retrieves a table with a simple filter  each column that appears in the constraint list is 
matched against the corresponding scalar variable in the main namespace.
1.10 UPDATE / MODIFY
#SQL UPDATE <table name> <list of columns> WHERE  <list of constraint columns>
Updates the specified fields, using the specified constraints to match the record.
2. TEXT
All text operations can receive a URL for a filename.
2.1 CSV
#TEXT CSV <result set name> <source text file> <delimiter> <list of field names>
Reads a delimited file, using the module Text::ParseWords. Tokens can be quoted, which 
escapes the delimiter, and quotes can be escaped.
If the list of fields is not supplied, the first line of the file is read and represents the field names.
2.2 FLAT
#TEXT FLAT <result set name> <source text file> <list of field names>
Reads a flat file in which every record is terminated by a blank line. Each line in each record is 
a field.
2.3 CUBE
#TEXT CUBE <result set name> <source text file> <column delimiter> <row delimiter> <list 
of field names>
Parses a text file with both kinds of delimiters.
2.4 READ
#TEXT READ <variable> <filename>
Reads the file into the scalar variable.
3. Result set aliases
3.1 FETCH, LOOP
#FETCH <result set name>
 code 
#LOOP
Generates a loop over the code block for each row in the result set. The fields are published 
into the main namespace.
3.2 FETCHIT
#FETCHIT <result set name>
Publishes the fields without generating a loop. Useful for queries that need to retrieve only one 
row.
3.3 FETCHCOLS
#FETCHCOLS <result set name> <var name>
The variable (notated with no $ sign) is iterated via all the column names.
3.4 FETCHCELL
#FETCHCELL <result set name> <field name> <var>
Fetches one cell. Note, if the field name is stored in a variable, use a $ to evaluate it.
3.5 IFNULL, IFNOTNULL, ENDIF, ELSE
#IFNULL <result set name>
#ENDIF
#IFNOTNULL <result set name>
#ELSE
#ENDIF
Open conditional blocks depending on whether there are any rows on the result set.
3.6 FILTER <source result set> <target result set> <condition source code>
Creates a subset of the result set. The condition is supplied as a string and contains a boolean 
check.



6.4 HTPL directives

Several HTPL meta commands are hard coded into the source.
The LDAP meta commands are experimental:
#LDAP CONNECT SERVER <server> [PORT <port>] [BIND <bind dn>] [PASSWORD <pass>]
#LDAP SEARCH [SCOPE <scope>] [FILTER <filter>] [START <start dn>] [SORT <sortkey>] 
[ATTRIBUTES <attribute list>]  [SIZE <sizelimit>]

To include HTPL source, (usually with the extension hh):
#INCLUDE filename

To embed XSUB code:
#XSUB
 C functions 
#ENDXSUB
You dont need to create module definition.
If you include XSUB code, you will have to compile the document offline by accessing it and 
letting the system compile it on the background.

Example:

<#

void
hello
CODE:
	printf(Shalom chaver!\n);

#ENDXSUB

&hello;


6.5 Writing your own macros

The file htpl.subs contain an XML tree of the macros.
The father node is called HTPL. The children are the macro names. 
Macros that are related are grouped, like the SQL and TEXT macros. Those will have nodes with the 
group names with children for the macros.

Example:
<HTPL>
<HELLO>$s = Goodbye, friend;</HELLO>
<WORLD>print $s\n;</WORLD>
</HTPL>

This macro tree will enable us to write the code:
#HELLO
#WORLD

And have it subsituted for:
$s = Goodbye, friend;
print $s\n;

Example:
<HTPL>
<HELLO>
<WORLD>$s = Goodbye, friend;</WORLD>
<BAMBA>$s = Father, mother, bamba;</BAMBA>
</HELLO>
</HTPL>

Now we have the macros:
#HELLO WORLD
#HELLO BAMBA

Macros with parameters:

The tokens that follow the macro unification are used as arguments at run time.
Arguemnts are number 1 based.
References to arguments are by numbers inside %s.

<PRINT>print %1%<BR>\n;</PRINT>

Now we can command:
#PRINT Hello
Which will be substituted for:
print Hello<BR>\n;

We can also capture a row of arguments from a specific one until the last one, for example:

<SHOW>print %1% >> %2*%;</SHOW>

#SHOW 1 2 3
Will be equal to: print 1 >> 2 3;

Some macro groups have prerequisites. For example, the SQL macros must have the htpl_db package 
loaded.

We can define a prerequisite this way:

<LOOKUP>($%1%) = gethostbyname(%2%);
<__PRE>use Socket;</__PRE></LOOKUP>

All the tags that begin with two underscores are special.

Sometimes we might want to alias a macro:
<PRINT>die %1*%\n unless ($fork);</PRINT>
<HELLO><__ALIAS>PRINT Good bye, friend!</__ALIAS></HELLO>

#HELLO will be the same as:
die Good bye, friend! unless ($fork);

We can also define a macro with several steps:
<COUNT>
	<__DO>printf  1;</__DO>
	<__DO>printf  2;</__DO>
</COUNT>

In such a macro we can include other macros 

<COUNT>
	<__DO>printf  1;</__DO>
	<__DO>printf  2;</__DO>
	<__INCLUDE>HELLO</__INCLUDE>
</COUNT>

We might want some macros to be available only inside the aliasing system,
so we can define them as private:

<PRINT PRIVATE="">die %1*%;</PRINT>
<HELLO><__ALIAS>PRINT end of all</__ALIAS></HELLO>

We might want to define a non operational macro, for example just to hold
a prerequisite: 

<INCLUDEDBI NOOP=""><__PRE>use DBI;</__PRE></INCLUDEDBI>
<ORA>
	<__INCLUDE>INCLUDEDBI</__INCLUDE>
	<__DO>print Doh!\n;</__DO>
</ORA>

If we want to define variables, we can use the SCOPE attribute to ease
adding of brackets before and after the code, for scoping needs:
<YEAR SCOPE="1">my @t = localtime; my $y = $t[5]; 
my $yy = $y + 1900 + ($y < 70 ? 100 : 0);
print $yy</YEAR>

Using macros as HTML tags:
A macro defined as
<X>perl commands</X>
can be called either by writing
#X
in the middle of your perl code, or by embedding the psudo HTML tag
<HTX> inside your HTML code. The disadvantage of the second option is that
the < and > signs may not be used, as they would confuse the parser.
Tags beginnig with HTX can be "broken" among lines.
Closing tags can also be implementing. 
</HTX> would be the same as #END X
The END macro is bundled with HTPL.
If you want to define a tag X with both an opener and a closer, do:
<X AREA="1">
  <__FWD>print "begin tag\n";</__FWD>
  <__REV>print "end tag\n";</__REV>
</X>

In order to process attributes of SGML tags, use the PARAMS attribute. For
example:
<PRINT PARAMS="1">print $text;</PRINT>

And use like: <HTPRINT TEXT="text here">
In order to check for mandatory attributes, use the MANDATORY attribute.
For example:
<MYIMG PARAMS="1" MANDATORY="SRC, BORDER">

Areas of HTPL code can be scoped with tags. You can capture the HTPL
output between tags with the &begintransaction and &gettransaction
functions.
For example:
<BEGIN>&amp;begintransaction();</BEGIN>
<STOP>$txt = &amp;endtransaction; print uc($txt);</STOP>

And use like:
<BEGIN>This is going to be in upper case</BEGIN>

In order to make sure tag scopes are not overlapping, you can make a tag
demand being in a scope, using a scope stack.
For example:
<BEGIN PUSH="begin end">print "begin";</BEGIN>
<END POP="begin end">print "end";</END>

The begin tag would push a "begin end" state to the scope stack. The end
tag would make sure we are in that state, and pop it from the stack.

It can be easier if we just define a pair of <HTX> - </HTX> or #X - #END X
<X BLOCK="x scope" AREA="1">
  <__FWD>&amp;beginx;</__FWD>
  <__REV>&amp;endx;</__REV>
</X>

Escaping:

You should escape ampersands in the htpl.subs as &amp;, < as &lt; and > as
&gt; as with any XML file. If you wish the % sign to appear literally in
the expanded macro, double it, for example:
&amp;myproc() if (power(%%hash) &gt; 0);

6.6 Additional information

 ? Any script initializes with the form variables brought to the main namespace.
 ? The variables REMOTE_HOST and REMOTE_USER contain the corresponding CGI variables.
 ? The file htpl-config.pl resides in the binary directory and contains miscellaneous site oriented 
configurations. If the functions getcc and getmailprog fail at your site, you can edit defaults at the 
configuration file. Same for maximum size for HTTP upload file.
 ? If the directory holding the document has a plain Perl file called htpl-glob.pl, it will be consulted 
for application based configuration.
 ? If the directory contains an HTPL file called htpl-glob.hh, it will be included, to supply application 
based functions.
 ? Incoming HTTP cookies will be stored in the %cookies hash table.
 ? Debug information can be displayed by simply accessing the htpl.cgi binary
 ? A binary called htpldbg is created that only converts the document to a perl script and dumps the 
scrip to the standard output. It can be useful to convert your script to pure CGI if you need to 
immigrate, and for debugging your scripts.
 ? If you cant write in /tmp but can write somewhere else, edit the TEMP entry in the Makefile.
 ? When the perl script fails, htpl.cgi captures the error dump, and displays a page with the output 
dump, temporary filenames, error dump and convert source, to help keep track of line numbers. After 
you finished working on your application and are not interested in the source to appear with error 
dumps, create a file called htpl.nodbg with no content in the source dir. Scripts in that dir will not have 
source attached when failing.

