<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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?
 4.1. Using HTPL from the shell.
 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
 5.8. Various useful macros
 5.9. Persistent objects
 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
 7. Extensions (To be written)
 7.1. Running as mod_perl
 7.2. HTPL database components
 7.3. HTPL report generator
 7.4. HTPL service compiler
 7.5. HTPL multiversion generator
 7.6. HTPL messages
 7.7. HTPL middleware server

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 Perl. 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.

* Check 7.1 for differences when running HTPL as a mod_perl extension.

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 an 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, nor the cookie functions). 
The perl file is then executed. (Unless you used the XSUB extensions,
in which case the page will be available once the XSUB extensions
finish compiling)  

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 newer 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. 

4.1. Using HTPL from the console

Beginning in version 2, you can write HTPL scripts which are not web
pages. These files start automatically with perl code. Example script:

#!/usr/local/bin/htplrun
print "Hello world\n!";
print "This is the " . &amp;increasefile("counter.txt") . "'th time you run me\n";

You can use the following commands:
htplc &lt;filename&gt; to convert a non web script to perl. Extension of the
output filename will be .ht.pl
htplu &lt;filename&gt; to convert an HTPL page to perl. This can be used to
force recompilation for the file if the web process doesn't succeed for
some reason.
htplrun &lt;filename&gt; to run a non web script. (Always compiles before
running)
htplcon &lt;filename&gt; to simulate running a page through the console.

I recommend naming non web scripts with the extension .htpr
Non web scripts will be compile into .ht.pl files and not .perl, and can
be run directly.
Other filenames are:
.htpm - HTPL module
.htpc - HTPL database component
.htps - HTPL service procedure
.app  - HTPL service aggregator
.pts  - HTPL middleware aggregator
And off course:
.htpl - HTPL page
.htpr - HTPL script
.ht.pl- Compiled HTPL script
.perl - Compiled HTPL page

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:

&lt;HTML&gt;
&lt;BODY&gt;
Hello world.
&lt;/BODY&gt;
&lt;/HTML&gt;

The results will be obvious.

5.2 Embedding simple Perl commands

Create the following file:
&lt;HTML&gt;
&lt;BODY&gt;
&lt;#
	@time = localtime;

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

The contents of the perl script between the &lt;# and &gt; 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:
&lt;A HREF="mailto:bill\@microsoft.com"&gt;

Beginning at version 2.60, you can immitate the CFML format of specifying
variables, for example:

&lt;#
$PI = 3.14159;
&gt;
PI is #PI#

Now, look at this:

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

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 doesn't need that kind of
complicated regular expressions. =-)
2) You can specify output using "print" if you don't want to escape to
HTML and back to PERL. 

5.3 Interpreting forms

Let's create the following form:
&lt;FORM ACTION="feedback.htpl"&gt;
Name: &lt;INPUT NAME="name"&gt;&lt;BR&gt;
Email: &lt;INPUT NAME="email"&gt;&lt;BR&gt;
&lt;INPUT TYPE=SUBMIT&gt;
&lt;/FORM&gt;

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

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 don't 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 url 
fields, or the %form hash to iterate over the POST fields.

5.4 Simple internet functions

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

&lt;#
&amp;sendmail (From =&gt; 'bill@microsoft.com', To =&gt; 
'president@whitehouse.gov', Subject =&gt; 'Hello!', Msg =&gt; &lt;&lt;EOM);
We received your order!
EOM
&gt;

This will send a one line message to bill@microsoft.com, with the
appropriate headers. You don't need to construct the headers.

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

&lt;#

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

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, let's create a document that gets a URL and redirects the browser, if
the URL exists: 

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

The function validurl checks if the URL exists, using the LWP module. The
function redirect 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 browser's hostname.
Next time the document is loaded, the values of $cookies{'last-visit'} and
$cookies{'last-ip'} will bset accordingly.
Note: %cookies is a tied hash. You can set and erase cookies by putting
values into it and erasing keys.
Example:

$x = $cookies{'counter'}++;
if ($x &gt; 10) {
    delete $cookies{'counter'};
    print "10 times is too much";
}

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

It's easy as that.

5.5 HTML generation functions

Here is something no fun to type:
&lt;CENTER&gt;
&lt;TABLE WIDTH=400&gt;
	&lt;TR&gt;
		&lt;TD BGCOLOR=#C0C0C0&gt;
			&lt;B&gt;&lt;CENTER&gt;Hello&lt;/CENTER&gt;&lt;/B&gt;
		&lt;/TD&gt;
	&lt;/TR&gt;
&lt;/TABLE&gt;
&lt;/CENTER&gt;

And all this for one line!

Now:
&amp;html_format('Hello', 'CENTER| TABLE WIDTH=400|TR|TD|B|CENTER');
Will do the same.

If the function is called in scalar context, the HTML text will not be
printed but returned, for example:
$h = &amp;html_format("Heading", "B|I|U");
Instead of a pipe delimited list, you can use an array reference:
html_format("header", [qw(U I B)]);

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

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

Now, let's arrange these in columns:
&amp;html_table_cols(items =&gt; \@nums, cols =&gt; 10, 
	tattr =&gt; {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:

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


	&amp;html_table_cols(items =&gt; \@nums, cols =&gt; 10, 
		rattr =&gt; sub {($y % 2) ? "BGCOLOR=#C0C000" :
                           "BGCOLOR=#FFFFFF";},
		cattr =&gt; sub {"ALIGN=" . (($x &lt; 5) ? "RIGHT" : "LEFT"))});
&gt;

I recommend using the class HTML::HTPL::Table to create tables.
It goes like this:
$h = new_table(cols =&gt; 2); # Creates an object
$h-&gt;add({data =&gt; 'a', header =&gt; 1}, {data =&gt; 'b', header =&gt; 1});
# Adds a line with the elements 'a' and 'b', both will be &lt;TH&gt;
$h-&gt;add(1, 2);
$h-&gt;add(3, 2);
$h-&gt;add(4, 5);

print $h-&gt;as_html;

The OO interface just wraps the html_table functions.

5.6 Reading a comma delimited file

All of us CGI programmers have done it.

Let's 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: TEXT CSV

&lt;BODY&gt;
&lt;#

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

#FETCH users

print "$username is $name&lt;BR&gt;\n";

#LOOP


&gt;
&lt;/BODY&gt;

This doesn't look like perl!
Basically, the first macro, 'TEXT CSV' creates a result set called
'users'.
(which will be realized using  the variable $users. You can call methods
for this variable. See HTML::HTPL::Result manpage), 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. 
Its sources might be text files (delmited, fixed width, flat multiline)
DBI databases, LDAP directories, and more.

Now, the #FETCH macro starts a loop, which ends with the #LOOP macro.
Inside the loop, the fields are populated into the main namespace.
#LOOP is canonical with #END FETCH
Every macro that starts a block, can be ended with an END macro.
For example, if we have a macro called WEEK, we could do
#WEEK
print "Hello!\n";
#END WEEK

Or:
&lt;HTWEEK&gt;Hello!&lt;/HTWEEK&gt;
Inside the HTML paragraph.

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

Thus, the above example with the user file could be written as:

&lt;BODY&gt;

&lt;HTTEXT CSV users /etc/passwd : username password uid gid name&gt;

&lt;HTFETCH users&gt;

$username is $name&lt;B&gt;

&lt;/HTFETCH&gt;

&gt;
&lt;/BODY&gt;

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:
&lt;HTSQL MSQL mydb&gt;

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

&lt;BODY&gt;
&lt;#

	#SQL MSQL mydb

	#SQL CURSOR customers SELECT * FROM customers

	#IFNULL customers
	print "We are sorry, but no customers were found.&lt;BR&gt;";

	#ELSE
&gt;
&lt;TABLE&gt;
 	&lt;TR&gt;
		&lt;TH&gt;
			First name
		&lt;/TH&gt;
		&lt;TH&gt;
			Last name
		&lt;/TH&gt;
		&lt;TH&gt;
			Email
		&lt;/TH&gt;
	&lt;/TR&gt;
&lt;#

	#FETCH customers

&gt;

&lt;TR&gt;&lt;TD&gt;$firstname&lt;/TD&gt;&lt;TD&gt;$lastname&lt;/TD&gt;&lt;TD&gt;$email&lt;/TD&gt;
&lt;#
	#LOOP

	print "&lt;/TABLE&gt;\n";

	#ENDIF

&gt;

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

In this example you see you could reference variables in your namespace as
parameters to the query. Do not quote strings! DBI will do it for you.

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) 

Macro lines, as you could see, can be multiline if you append a backslash
to all the non terminal lines.

You can prepare a query (using whatever prepare mechanism your DBI driver
implements) and save it for later use.
For example.

#SQL DECLARE myquery SELECT id FROM workers WHERE employed_date = NOW

#LOAD myquery
#FETCH myquery
print "$id ";
#LOOP
sleep(2);
#LOAD myquery
#FETCH myquery
print "($id)";
#LOOP

If you expect a one line response, you can make the query and import the
variables immediately:

#SQL IMMEDIATE SELECT MAX(id) AS max FROM data
print "It is $max!";

If you have a one line resultset (not specifically from a database) you
can fetch it without a loop.
#FETCHIT cursor
(The resultset is called cursor here)

If you expect a series of lines with one field:
#PROJECT cursor array id
For a query stored in resultset cursor, all the values of the field id
will be stored in the array @array

5.8 Some more useful macros

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

&lt;BODY&gt;
&lt;HTCOUNTER mypage.dat&gt; people visited my page.
&lt;/BODY&gt;

Random quotes were never easier:

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

Or usual switch statement:
#SWITCH CASE $s
#CASE 'abc'
&amp;proc1();
#CASE 2 + $j
&amp;proc2();
#case 4, 9
&amp;proc3();
#END SWITCH

Or a random image:

&lt;HTIMG RND SRC="me.jpg,mygf.jpg" WIDTH=60 HEIGHT=60 BORDER=0&gt;

Exception handling:
#TRY
%h = %{[]};
#CATCH coerce array
    # Will catch the error "Can't coerce array into hash"
print "Dereference misusage";
#END TRY

Or maybe:

#TRY
if ($x = &amp;doit()) {
#THROW "yupi:$x"
}
#CATCH yupi:(.*)
&amp;handle($1);
#CATCH
print "Unexpected exception";
#END TRY

5.9 Persistent objects

Edit the htpl-config.pl file to assign a DB_File file for persistent
objects database.
Once enabled, the hashes %session and %application will hold values
(scalars or references to complicated objects) for sessions and the whole
application. 
In order to have objects different for various applications, edit the
htpl-site.pl for different database specification for different sites.

6. Reference

6.1 HTPL Library functions

Check ./doc and ./demos in the HTPL distribution for up to date
information.

As of version 2.61, all html_* functions will print the result if called
in null context, and return the result if called in scalar context.

These functions are contained in the module HTML::HTPL::Lib.

&amp;addheader(HTTP_HEADER)

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

&amp;closedoc(HANDLE)

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

&amp;doconnect(HANDLE, HOST, PORT)

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

&amp;doread(HANDLE)

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

&amp;dowrite(HANDLE, BUFFER)

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

&amp;expect(HANDLE, REGEXP)
&amp;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 $_


&amp;fileexists(FILENAME)

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

&amp;forkredirect
&amp;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.

&amp;getcc

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

&amp;getmailprog

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

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

TAGS is a cons delmited list of HTML tags to apply, with no &lt; &gt; 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.

&amp;html_header(TITLE)

Prints &lt;HTML&gt;, &lt;HEAD&gt; and &lt;TITLE&gt; tags according to the TITLE supplied.

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

Prints a hidden &lt;INPUT&gt; 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.


&amp;html_table_cols(ATTRIBUTES)
&amp;html_table_rows(ATTRIBUTES)

Formats a list of values in an HTML table.
ATTRIBUTES are given as key =&gt; 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.

&amp;include(FILENAME)

Dump a text file. FILENAME can be a URL.

&amp;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 =&gt; 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


&amp;isip(IP)

Returns true if IP is in IP address format. Doesn’t validate contents.

&amp;isurl(STRING)

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

&amp;max(LIST)

Returns the highest element of LIST, numeric wise.

&amp;min(LIST)

Returns the lowest element of LIST, numeric wise.

&amp;nslookup(HOSTNAME)

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

&amp;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 &amp;opendoc should be closed with &amp;closedoc to ensure 
erasure of temporary files.
The filename to use is given by &amp;tempfilename

&amp;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. 

&amp;readfile(FILENAME)

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

&amp;redirect(URL)

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

&amp;rewind

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


&amp;revnslookup(IP)

Attempts to find hostname for IP.

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

Prints &lt;OPTION&gt; tags .
If the first argument is a scalar, &amp;selectbox only prints &lt;OPTION&gt; tags and not &lt;SELECT&gt; 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. &lt;SELECT&gt; tag will be printed
 ? Attr - Additional attributes for SELECT tag
 ? Noout - If set to true, HTML code will be returned but not printed


&amp;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 =&gt; 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 &amp;getmailprog.

&amp;setcookie(PAIRS)

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

&amp;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 &amp;setmimetype, then &amp;rewind and after that 
binmode STDOUT and send the image to STDOUT.

&amp;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.

&amp;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.

&amp;trim(STRING)

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

&amp;txt2html(TEXT)

Formats a string with line breaks, ampersands, &gt; and &lt; signs, and double quotes to HTML code.

&amp;urldecode(STRING)

Decodes a string from an HTTP query.

&amp;urlencode(STRING)

Encodes a string for HTTP queries.

&amp;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.

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

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 &gt; (greater-than) sign or an odd number of double quotes,
it can be written inside a tag:
&lt;#
	#MACRO
&gt;
becomes
&lt;HTMACRO&gt;

For example:
&lt;HTQUERY crs tbl&gt;
&lt;HTFETCH crs&gt;
$name
&lt;HTLOOP&gt;

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 &lt;dbi-dsn&gt; &lt;username&gt; &lt;password&gt;
Connects to a database.
Specific database:
1.2 MYSQL 
#SQL MYSQL &lt;database&gt; &lt;username&gt; &lt;password&gt;
1.3 MSQL
#SQL MSQL &lt;database&gt;
1.4 XBASE
#SQL XBASE &lt;directory&gt;
Uses the dbi::xbase module
1.5 POSTGRESQL
#SQL POSTGRESQL &lt;database&gt; &lt;username&gt; &lt;password&gt;
1.6 EXEC / EXECUTE
#SQL EXECUTE &lt;dml or ddl&gt;
Executes the SQL statements.
1.7 CURSOR / SEARCH
#SQL CURSOR &lt;result set name&gt; &lt;sql query&gt;
Runs a query, creates a result set object.
1.8 INSERT / ADD
#SQL INSERT &lt;table name&gt; &lt;list of columns&gt;
Inserts a new row.  Values are taken from the corresponding scalar variables. Uses type casting 
of new DBI modules.
1.9 QUERY
#SQL QUERY &lt;result set name&gt; &lt;table&gt; &lt;list of constraint columns&gt;
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 &lt;table name&gt; &lt;list of columns&gt; WHERE  &lt;list of constraint columns&gt;
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 &lt;result set name&gt; &lt;source text file&gt; &lt;delimiter&gt; &lt;list of field names&gt;
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 &lt;result set name&gt; &lt;source text file&gt; &lt;list of field names&gt;
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 &lt;result set name&gt; &lt;source text file&gt; &lt;column delimiter&gt; &lt;row delimiter&gt; &lt;list 
of field names&gt;
Parses a text file with both kinds of delimiters.
2.4 READ
#TEXT READ &lt;variable&gt; &lt;filename&gt;
Reads the file into the scalar variable.
3. Result set aliases
3.1 FETCH, LOOP
#FETCH &lt;result set name&gt;
* 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 &lt;result set name&gt;
Publishes the fields without generating a loop. Useful for queries that
need to retrieve only one  row.
3.3 FETCHCOLS
#FETCHCOLS &lt;result set name&gt; &lt;var name&gt;
The variable (notated with no $ sign) is iterated via all the column names.
3.4 FETCHCELL
#FETCHCELL &lt;result set name&gt; &lt;field name&gt; &lt;var&gt;
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 &lt;result set name&gt;
#ENDIF
#IFNOTNULL &lt;result set name&gt;
#ELSE
#ENDIF
Open conditional blocks depending on whether there are any rows on the result set.
3.6 FILTER &lt;source result set&gt; &lt;target result set&gt; &lt;condition source code&gt;
Creates a subset of the result set. The condition is supplied as a string and contains a boolean 
check.

Version 2.81 is bundled with 143 nodes in the macro tree. See ./doc and
./demos in the htpl distribution for updates.

6.4 HTPL directives

Several HTPL meta commands are hard coded into the source.

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

To embed XSUB code:
#XSUB
* C functions *
#ENDXSUB
You don't 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:

&lt;#

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

#ENDXSUB

&amp;hello;


6.5 Writing your own macros

The file htpl.subs (or macros.xpl, as of version 2.79) contain an XML tree
of the macros.

I recommend that instead of modifying this file, create a file called
/usr/local/share/htpl-site.xpl with all your local macros. This way,
everytime you recompile a new version of HTPL, your own macroes will be
compiled in.

As of version 2.81, stardatized XML was engaged. All the tags begin with
__ (to keep compatible with prior versions), and the tag to define a mcaro
is __MACRO. ALl tags and attributes are in upper case.
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.
The root tag must be HTPL.

Example:
&lt;HTPL&gt;
&lt;__MACRO NAME="HELLO"&gt;$s = "Goodbye, friend";&lt;/__MACRO&gt;
&lt;__MACRO NAME="WORLD"&gt;print "$s\n";&lt;/__MACRO&gt;
&lt;/HTPL&gt;

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

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

Example:
&lt;HTPL&gt;
&lt;__MACRO ID="HELLO"&gt;&lt;!-- ID and NAME do the same --&gt;
&lt;__MACRO ID="WORLD"&gt;$s = "Goodbye, friend";&lt;/__MACRO&gt;
&lt;__MACRO ID="BAMBA"&gt;$s = "Father, mother, bamba";&lt;/__MACRO&gt;
&lt;/__MACRO&gt;
&lt;/HTPL&gt;

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

Macros with parameters:

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

&lt;__MACRO NAME="PRINT"&gt;print "%1%&lt;BR&gt;\n";&lt;/__MACRO&gt;

Now we can command:
#PRINT Hello
Which will be substituted for:
print "Hello&lt;BR&gt;\n";

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

&lt;__MACRO NAME="SHOW"&gt;print "%1% &gt;&gt; %2*%";&lt;/__MACRO&gt;

#SHOW 1 2 3
Will be equal to: print "1 &gt;&gt; 2 3";

&lt;__MACRO NAME="DUMP"&gt;print join(".", %1!%);&lt;/__MACRO&gt;
#DUMP a b c d 
Will be: print join(".", $a, $b, $c, $d);

Instead of %1*% we could say "%1", "*%"
In this case, the delimiter between the parameters will be ", "
In this example, double quotes will be added before and after the string.

Last, but not least, we can dereference a token in a delimited string:
%1,3% means the first argument will be delimited by commas, take the third
token. %2|1% means - the second argument will be delimited by pipes, take
the first token.

Some macro groups have prerequisites. For example, the SQL macros must
have the HTML::HTPL::Db package loaded.

We can define a prerequisite this way:

&lt;__MACRO NAME="LOOKUP"&gt;($%1%) = gethostbyname("%2%");
&lt;__PRE&gt;use Socket;&lt;/__PRE&gt;&lt;/__MACRO&gt;

Sometimes we might want to alias a macro:
&lt;__MACRO ID="PRINT"&gt;die "%1*%\n" unless (fork());&lt;/__MACRO&gt;
&lt;__MACRO ID="HELLO"&gt;&lt;__ALIAS&gt;PRINT Good bye, friend!&lt;/__ALIAS&gt;&lt;/__MACRO&gt;

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

We can also define a macro with several steps:
&lt;__MACRO NAME="COUNT"&gt;
	&lt;__DO&gt;printf  "1";&lt;/__DO&gt;
	&lt;__DO&gt;printf  "2";&lt;/__DO&gt;
&lt;/__MACRO&gt;

In such a macro we can include other macros:

&lt;__MACRO NAME="COUNT"&gt;
	&lt;__DO&gt;printf  "1";&lt;/__DO&gt;
	&lt;__DO&gt;printf  "2";&lt;/__DO&gt;
	&lt;__INCLUDE&gt;HELLO&lt;/__INCLUDE&gt;
&lt;/__MACRO&gt;

Aliasing and including are not the same!

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

&lt;__MACRO NAME="PRINT" PRIVATE="1"&gt;die "%1*%";&lt;/__MACRO&gt;
&lt;__MACRO NAME="HELLO"&gt;&lt;__ALIAS&gt;PRINT end of all&lt;/__ALIAS&gt;&lt;/__MACRO&gt;

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

&lt;__MACRO NAME="INCLUDEDBI" NOOP="1"&gt;&lt;__PRE&gt;use DBI;&lt;/__PRE&gt;&lt;/__MACRO&gt;
&lt;__MACRO NAME="ORA"&gt;
	&lt;__INCLUDE&gt;INCLUDEDBI&lt;/__INCLUDE&gt;
	&lt;__DO&gt;print "D'oh!\n";&lt;/__DO&gt;
&lt;/__MACRO&gt;

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:
&lt;__MACRO ID="YEAR" SCOPE="1"&gt;my @t = localtime; my $y = $t[5]; 
my $yy = $y + 1900 + ($y &lt; 70 ? 100 : 0);
print $yy;&lt;/__MACRO&gt;

Will resolve to:
{
my @t = localtime; my $y = $t[5];
my $yy = $y + 1900 + ($y &lt; 70 ? 100 : 0);
print $yy;
}

When using SCOPE="1" with block macros (see just below here), brackets
will be added upon all the area.

Block macros:
Using macros as HTML tags:
A macro defined as
&lt;__MACRO ID="X"&gt; ... perl commands ... &lt;/__MACRO&gt;
can be called either by writing
#X
in the middle of your perl code, or by embedding the psudo HTML tag
&lt;HTX&gt; inside your HTML code. The disadvantage of the second option is that
the &lt; and &gt; 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. 
&lt;/HTX&gt; would be the same as #END X
The END macro is bundled with HTPL.

To make this much simpler, here is an example:
If you want to define a tag X with both an opener and a closer, do:
&lt;__MACRO NAME="X" AREA="1"&gt;
  &lt;__FWD&gt;print "begin tag\n";&lt;/__FWD&gt;
  &lt;__REV&gt;print "end tag\n";&lt;/__REV&gt;
&lt;/__MACRO&gt;

As you can see, we need to set AREA="1", then define the actions under
__FWD and __REV sections.

In order to process attributes of SGML tags, use the PARAMS attribute. For
example:
&lt;__MACRO NAME="PRINT" PARAMS="1"&gt;print $TEXT;&lt;/PRINT&gt;

And use like: &lt;HTPRINT TEXT="text here"&gt;
In order to check for mandatory attributes, use the MANDATORY attribute.
For example:
&lt;__MACRO NAME="MYIMG" PARAMS="1" MANDATORY="SRC, BORDER"&gt;

Areas of HTPL code can be scoped with tags. You can capture the HTPL
output between tags with the &amp;begintransaction and &amp;gettransaction
functions.
For example:
&lt;__MACRO NAME="TXT" AREA="1"&gt;
&lt;__FWD&gt;&amp;amp;begintransaction();&lt;/__FWD&gt;
&lt;__REV&gt;$txt = &amp;amp;endtransaction; print uc($txt);&lt;/REV&gt;
&lt;/__MACRO&gt;

And use like:
&lt;TXT&gt;This is going to be in upper case&lt;/TXT&gt;

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:
&lt;__MACRO NAME="TXT" AREA="1"&gt;
&lt;__FWD PUSH="begin end"&gt;&amp;amp;begintransaction();&lt;/__FWD&gt;
&lt;__REV POP="begin end"&gt;$txt = &amp;amp;endtransaction; print uc($txt);&lt;/REV&gt;
&lt;/__MACRO&gt;

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 &lt;HTX&gt; - &lt;/HTX&gt; or #X - #END X
&lt;__MACRO NAME="X" BLOCK="x scope" AREA="1"&gt;
  &lt;__FWD&gt;&amp;amp;beginx;&lt;/__FWD&gt;
  &lt;__REV&gt;&amp;amp;endx;&lt;/__REV&gt;
&lt;/__MACRO&gt;

In order to have a macro verify it is inside a scope but not pop it:

&lt;__MACRO NAME="inside" BROTHER="x scope"&gt;

In order for a macro to change the uppermost scope:
&lt;__MACRO NAME="inside" BROTHER="x scope" CHANGE="y scope"&gt;

You can also push and pop scopes in the middle of a macro:
&lt;__MACRO NAME="x"&gt;
&lt;__PUSH SCOPE="x scope"/&gt;
&lt;__INCLUDE&gt;END X&lt;/__INCLUDE&gt;
&lt;__PUSH SCOPE="x scope"/&gt;
&lt;__INCLUDE DIR="__REV"&gt;X&lt;/__INCLUDE&gt;
&lt;/__MACRO&gt;
Notice the different methods to call the closing tag of X.

Conditional blocks, and macro schema:

You can define a macro the demands a mimimum of 2 parameters and a maximum
of 4:
&lt;__MACRO NAME="I" MIN="2" MAX="4"&gt;

You can define a macro which will behave differently with one parameter or
none:
&lt;__MACRO NAME="I" MAX="1"&gt;
&lt;__DO MAX="0"&gt;print "No param!\n";&lt;/__DO&gt;
&lt;__DO MAX="1"&gt;print "Param = %1%!\n";&lt;/__DO&gt;
&lt;/__MACRO&gt;

You can make string checks:
&lt;__DO ASSERT="%1% = %2% or %1.2% &gt; 'word'"&gt;

Or check context:
&lt;__DO BROTHER="scope1,scope2"&gt; .. do things if we are in scope1 or scope2
.. &lt;/__DO&gt;
&lt;__DO BROTHER="scope2,scope3"&gt; .. do things if we are in scope2 or scope3
.. &lt;/__DO&gt;
&lt;__DO BROTHER="!scope1,scope2,scope3"&gt; .. otherwise do .. &lt;/__DO&gt;

Reporting error:
&lt;__CROAK MSG="message"/&gt;

Example: Check that we are in scope inner inside scope outter:

&lt;__MACRO NAME="inside"&gt;
&lt;__POP SCOPE="inner"/&gt;
&lt;__CROAK BROTHER="!outter" MSG="inside must be inside inner inside outter"/&gt;
&lt;__PUSH SCOPE="inner"/&gt;
... do things
&lt;/__MACRO&gt;

Everytime you are inside a scope, the substitution of %id% has a unique
id. Another useful substitution is %random% in order to create unique
names.
You can store variables while parsing a macro and use them from other
macros in the same scope:
&lt;__SET VAR="name" VALUE="value"&gt;
For example:
&lt;__MACRO NAME="setit" BROTHER="scopex" MIN="1" MAX="1"&gt;
&lt;__SET VAR="varname" VALUE="$%1%_%id%_%random%"&gt;
&lt;__DO&gt;%$varname% = time;&lt;/__DO&gt;
&lt;/__MACRO&gt;
&lt;__MACRO NAME="getit" BROTHER="scopex"&gt;
print "Value is %$varname%";
&lt;/__MACRO&gt;

The variable name comes between %$ and % to be derefferenced. This
examples stores a perl variable name in the macro variable, but the macro
var could store a subroutine name or anything.

Escaping:

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

6.6 Additional information

 ? Any script initializes with the form and variables brought to the main
namespace. 
 ? The variables REMOTE_HOST, REMOTE_USER, HTTP_REFERER, QUERY_STRING,
SCRIPT_NAME, SERVER_NAME and SERVER_PORT contain the corresponding CGI
variables. 
 ? The variable SELF_URL contains a reflextion to the script. The variable
SELF reflects the script with the same URL parameters.
 ? The file htpl-config.pl resides in the binary directory and contains
miscellaneous site oriented configurations. 
You can override its defaults per directory by creating a local file
called htpl-site.pl with the same format.
 ? 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.
 ? If the directory contains a file called htsource.pre, HTPL will read
one line from this file containing a filter. All HTPL sources will be
passed through this filter. The filter will get the source filename as an
appended parameter. You can include the string %s to represent the source
filename in the filter line to override it. For example: cat %s | expand
 ? If the directory contains a filed called htout.pre, output from the
HTPL script will be passed through it. (CGI mode only)
 ? Incoming HTTP cookies will be stored in the %cookies hash table.
 ? %application and %session contain the persistent objects, if enabled.
 ? 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. 
 ? 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. 
Another strategy is to create a file called htpl.dbg containing the
subnets to allow debug information to, each line in the format of:
a.b.c.d e.f.g.h
Subnet first and then netmask. Localhost will automatically be authorized.

</pre></body></html>