FlexHTML

Flexible HTML generation for EPOC
(C) 2000, 2001 David Rushall


1 What is FlexHTML?

FlexHTML is a simple OPM to process text files and apply template macros. As a file is processed, special template commands invoke user-written OPL functions to generate a block of output.

It was originally designed to aid the development and maintenance of my web site, where the OPL templates are used to...

...all from source held in OPL Program editor files for convenience of editing. When the time comes to give the site a new look, some changes to the OPL templates can be easily propagated to all pages on the site.

With a little work the module could be applied to other scenarios, such as extracting a database of bookmarks to form an HTML links page or generating both an HTML and Help/Data version of an application's user manual from a single source. Advanced HTML applications could also employ temporary outputs and multiple passes to build a table of contents of automatically numbered sections, or float footnotes to the end of the document.

Using FlexHTML requires some effort, basic knowledge of OPL and knowledge of HTML (and any other desired output formats) - but then the result is a far more flexible than other HTML generation tools for the EPOC platform and it is easier than editing all your complex but repetitive HTML tagging by hand.

1.1 How does FlexHTML fit with CSS?

You might say that Cascading Style Sheets (CSS) are the best way to control the presentation of HTML documents, and you'd be right.

You might say that if all the presentation information is in the CSS then you you don't need a tool to help write the HTML. I say you should think again.

A tool like FlexHTML is a compliment and not a competitor to CSS.


2 Installation

To install this software on your machine,just install the main application SIS file:

FlexHTML.sis
FlexHTML SIS installation file.

The software will be installed on the C: drive.

C:\System\OPM\FlexHTML.opm
The FlexHTML OPM module.
C:\System\OPL\FlexHTML.oph
The FlexHTML OPL header file.
C:\FlexHTML\
This directory contains example files and documentation for developers. You may move this folder but you will have to update the examples accordingly, if you wish to use them.

You can test the FlexHTML installation by running the C:\FlexHTML\Runme.opo example file. See below for more details.

Note: Please consult the manuals for your device for details of installing applications packaged in SIS files. You will require a PC or Mac running your EPOC connect software (i.e. PsiWin 2 or equivalent) or the "Add/Remove" icon on the control panel of your EPOC device. Double-clicking on the SIS file either on the EPOC device or on the PC/Mac connected to the EPOC device should do the trick.


3 Usage notes

3.1 What is a FlexHTML template?

A FlexHTML template consists of an OPL procedure which is invoked when the FlexHTML processor finds a template call in the source file it is processing. The OPL function is responsible for generating any output that should replace the template call in the output file, accessing any global state variables it requires.

Consider the following simple example:

 proc hello$:
   lprint "Hello ";flexgetarg$:(1);"!"
 endp

This template, hello, writes a single line to the output stream; a greeting to the person named by the templates first argument.

To invoke the template, one would include something like the following in the input file:

 ##+hello
 World
 ##-

This would be simply replaced in the output, by:

 Hello World!

That's pretty much it - simple but effective, as we shall see.

3.2 Putting it together

In order to use FlexHTML you will need the following...

Mix as follows...

  1. Put your source files in a suitable directory (use C:\FlexHTML\ for now).
  2. Edit the controlling procedure (e.g. "build:" in Runme.opl) to ensure that the path is correct for:
  3. Translate and run the program.

If all goes well, an HTML version of the document will have been generated. The remaining sections of this document should give some clues about how it all works. Look at the Runme.opl and Readme.flx files to get some ideas about what you can do.

Note: My use of the ".flx" extension is arbitrary. You may use any file name extension that you wish (e.g. ".txt" or none)

3.3 Source formats

The input to FlexHTML must either be a ASCII text file or an OPL Program file. In the case of the latter, we're simply misusing the OPL editor as a convenient text editor; removing the requirement for you to export from Word or Program as plain text, or find another text editor.

Note: You can also use FlexHTML to export OPL Program files to plain text in batches. If the Program file contains no templates the the output will be a simple plain text version of the input.

The input file contains a mixture of text to be copied to the output file and template calls. When the file is processed, the input is copied to the output and any template calls replaced with the result of their invocation.

Note: If you wish, the input file may consist entirely of templates. All that would remain of the input file in the output stream would be any blank lines you left between the templates.

3.4 FlexHTML template syntax

FlexHTML uses a simple syntax. Any line starting with '##' (no preceding white space) is a control line, and anything else is pretty much ignored.

The character immediately following the '##' indicates the type of control line.

+ ##+hello
Begin a new template argument. If this the first argument of the template, then the template name follows the '+'.
- ##-
End the last argument of the template.
! ##!footer
Call template without providing arguments (i.e. a short-hand for '##+footer' followed by '##-').
; ##; Comment text
A comment line - the remaining text on the line is ignored and no output is generated. You can also use the ";" character to insert a comment at the end of a control line (e.g. "##+hello ;say hello").

3.5 Writing the control procedure

The main procedure of the control program is responsible for:

The following functions are provided by FlexHTML.opo for this purpose.

flexVerChk: flexVerChk:(kFlexVersion)
Ensure loaded FlexHTML OPM is compatible with the version required (i.e. the version of the header against which the user-written code has been translated).
flex: flex:("c:\example.flx", "c:\", "example.htm", kFlexFlags_None&)
Process named file to produce named output on named output path.

Note: My use of the ".flx" extension is arbitrary. You may use any file name extension that you wish (e.g. ".txt" or none)

3.6 Template basics

For each template used in the source file, you must provide an OPL procedure for the template. The name of the procedure must be the template name with a '$' suffix (i.e. return a string) and it must have no arguments.

Note: Please do not start template names with the letters 'flex'.

To generate the template's output, simply LPRINT whatever you want. Your LPRINTed text will appear in the output stream where the template invocation appeared in the input stream.

The return string of a template is any error message. If the template is sucessful, you should return an empty string. If a non-empty error message is returned, FlexHTML will display an error report including your message.

Note: You can pass information between templates (e.g. section counters) via OPL global variables, which must be declared by your control program and which must not start with the letters 'flex'.

3.7 Using template arguments

Templates are most useful when they are given arguments. Templates may have up to 8 (kMaxArgs%) arguments of up to 8192 (kMaxArgLength%) characters each. The constants for these values are provided in FlexHTML.oph. Any arguments not supplied in the template invocation in the source file will be empty (i.e. have zero length).

Arguments are numbered from 1 to 8 and can be retrieved by the following functions.

flexArgLen% flexArgLen%:(arg%)
Returns length of numbered argument.
flexGetArg$ flexGetArg$:(arg%)
Returns contents of the numbered argument, as a string. The argument must be no more than 255 characters in length, in order to fit into an OPL string.
flexInsertArg flexInsertArg:(arg%)
Copy the numbered argument into the output stream, with no changes. The argument may be of any length (up to the maximum length of 8192 characters) as it does not have to be stored into an OPL string.

3.8 Embedding further source files

FlexHTML includes the ability to combine multiple source files to form a single output, thus enabling common features such as scripts and navigation areas to be maintained from a single source and embedded on every page.

The processing of embedded inputs is truely recursive; templates in the embedded source will be processed and may embed still further sources, as required.

flexInclude flexInclude:("another_file.flx")
Process named file and insert output into current output stream.

Note: If you want to declare a global variable to be available for the processing of the single embedded source, declare the global in the OPL procedure that calls the include function.

Note: My use of the ".flx" extension is arbitrary. You may use any file name extension that you wish (e.g. ".txt" or none)

3.9 Other template functions

In addition to the basic functions for processing files and handling template arguments, FlexHTML provides a number of utility functions. These are summarised below.

flexVer$ flexVer$:
Returns a version string identifing FlexHTML, suitable for inclusion in an HTTP GENERATOR header.
flexInsertBoilerplate flexInsertBoilerplate:("")
Inserts a standard "made with FlexHTML"-style string into the output stream. If you use FlexHTML, please consider using function as part of your document footer. The argument string to this function is reserved for future use and must be empty for now.
flexOutFile flexOutFile$:
Returns the name (not path) of the current output file. This can be useful to generate correct include document URLs in footers, for example.
flexKeyword flexKeyword$:(flexGetArg$(arg%),allowEmpty%)
Analyse supplied string to find a keyword, consisting of alphanumeric and '-' characters. Leading and trailing spaces are removed but other spaces will raise an error. Result is always returned in upper case.
flexError flexError:(-1,"Something broke")
Halt document processing with given error code and message.

See below for a complete listing of FlexHTML.oph with more details of these functions.

3.10 More examples

This document is an example use of FlexHTML. Take a look at the Example.opl and Example.flx files used to generate it. For example, see how:


4 Notes and Limitations

4.1 File formats

Most text-based formats and languages can be contained in the input stream provided that they do not require the use of '##' as the first two characters on a line. However, since FlexHTML replaces blocks of lines with other blocks of lines, it is not possible to insert variables in the middle of a line (as the C macro pre-processor does, for example).

4.2 Text formatting

FlexHTML currently knows nothing (or at least very little) of the data it is handling. This may be a concern if you wish to both target an output stream that can handle word-wrapping (e.g. HTML) and one that cannot (e.g. plain text).

4.3 Escape characters

Another problem with generating multiple output formats lies in the conventions for escape character sequence. For example, if I write '&', this would appear as an ampersand character in formatted HTML/XML/etc, but would appear as the raw escape sequence in a text output. However, in the absense of built in support for such differences in a potential future version of FlexHTML, there are potential work arounds via the cunning use of templates.


5 Disclaimer and copyright

  1. FlexHTML is freeware and copyright; it is not public domain. The rights to this package remain the property of the author.
  2. You may use this software for your own use, free of charge, for an indefinite period and at no obligation to the author.
  3. Permission is given to publicly distribute this software provided the ownership of the rights to this software is clearly stated and any fee charged is extremely nominal. Distributions of this software must always consist of the the unaltered SIS file distribution.
  4. If you wish to use and distribute this module as part of your own application you may do so provided that you:
  5. Use of this software is entirely at the user's own risk. The user must accept responsibility for any direct or indirect loss or damage arising from the use (or misuse) of the package. This software is supplied "as-is".

  6. 6 Contacts

    If you have any problems, comments or suggestions about this software, you can contact me at the following email addresses:

    This application is distributed in association with FreEPOC:

    For the latest news of this an my other software, also visit:


    7 FlexHTML.oph

    The contents of the OPL header file for FlexHTML have been included below for reference.

    rem ====================================================
    rem = FlexHTML.oph - FlexHTML OPM header file
    rem = (C) 2000, 2001 David Rushall
    rem = In association with FreEPOC
    rem = All rights reserved.
    rem = See associated documentation for details of use
    rem = --------------------------------------------------
    rem = Please consider using standard FlexHTML footer
    rem = 'boilerplate' on public HTML pages generated with
    rem = this OPM. See "flexInsertBoilerplate:" below.
    rem = --------------------------------------------------
    rem = Free your plamtop...   Free yourself...    FreEPOC
    rem = Web                        http://www.freepoc.org/
    rem = Email                             dave@freepoc.org
    rem = --------------------------------------------------
    rem = Dave Rushall       http://www.piecafe.demon.co.uk/
    rem ====================================================
    
    rem ----------------------------------------------------
    rem - Constants
    rem -
    const kMaxArgs%=8         : rem number of template args
    const kMaxArgLength%=8192 : rem template argument length
    const kMaxLineLength%=255 : rem input line length
    
    const kFlexVersion=1.11   : rem FlexHTML version number
    const kFlexHTMLUID&=&10003934 : rem ...and UID
    
    rem - Flags for flex:() calls
    const kFlexFlags_None&=0  : rem standard operation
    rem (other flags reseved for future use)
    
    rem ----------------------------------------------------
    rem - flexVerChk - Version check
    rem -  Args:   version,  header version identifier
    rem -  Return: Nothing
    rem -  Notes:  Confirms FlexHTML OPM is compatible with
    rem -          supplied FlexHTML version number.
    rem -          Completes only if compatible (else STOPs)
    rem -          Use in main code body thus...
    rem -            flexVerChk:(kFlexVersion)
    rem -          May be called at any time
    external flexVerChk:(version)
    
    rem ----------------------------------------------------
    rem - flex - do template processing for a single input
    rem -  Args:   inFile$, input file name (inc path)
    rem -          outPath$, local output file directory
    rem -          outFile$, output file name
    rem -          flags&, proceessing flags
    rem -  Return: Nothing
    rem -  Notes:  Opens input and output files and copies
    rem -          input to output, line by line. If a
    rem -          template sequence is encountered, the
    rem -          arguments are collected (with nothing
    rem -          written to output) and the user template
    rem -          function called. The template function
    rem -          is then free to make calls to other
    rem -          library functions and generates required
    rem -          output via LPRINT statements.
    rem -          Input file may be either plain text file
    rem -          or produced with the OPL program editor.
    rem -          Output is plain text file.
    rem -          See constants above for valid flags.
    rem -          Completes only if succesful (i.e. no
    rem -          errors were detected or raised by user
    rem -          templates)
    rem -          May NOT be called within a user template
    rem -
    external flex:(inFile$,outPath$,outFile$,flags&)
    
    rem ----------------------------------------------------
    rem - flexInclude - embed another input in output
    rem -  Args:   inFile$, input file name (inc path)
    rem -  Return: Nothing
    rem -  Notes:  Input file may be either plain text file
    rem -          or produced with the OPL program editor,
    rem -          and may include templates for processing.
    rem -          Completes only if succesful (i.e. no
    rem -          errors were detected or raised by user
    rem -          templates)
    rem -          May ONLY be called within a user template
    rem -
    external flexInclude:(inFile$)
    
    rem ----------------------------------------------------
    rem - flexver$ - return FlexHTML version string
    rem -  Args:   None
    rem -  Return: Version string
    rem -  Notes:  Output suitable for HTTP 'GENERATOR'
    rem -          header, etc.
    rem -          May ONLY be called within a user template
    rem -
    external flexver$:
    
    rem ----------------------------------------------------
    rem - flexArgLen% - get template argument length
    rem -  Args:   a%, argument number
    rem -  Return: Argument length
    rem -  Notes:  Length of indicated template argument
    rem -          is returned
    rem -          May ONLY be called within a user template
    rem -
    external flexarglen%:(a%)
    
    rem ----------------------------------------------------
    rem - flexGetArg$ - get template argument as string
    rem -  Args:   a%, argument number
    rem -  Return: Argument sting
    rem -  Notes:  Contents of indicated template argument
    rem -          is returned as a string. If argument is
    rem -          longer than 255 and processing is
    rem -          terminated.
    rem -          May ONLY be called within a user template
    rem -
    external flexGetArg$:(a%)
    
    rem ----------------------------------------------------
    rem - flexInsertArg - send template argument to output
    rem -  Args:   a%, argument number
    rem -  Return: Nothing
    rem -  Notes:  Contents of indicated template argument
    rem -          is placed into output stream. Argument
    rem -          may be of any length (up to maximum).
    rem -          May ONLY be called within a user template
    rem -
    external flexInsertArg:(a%)
    
    rem ----------------------------------------------------
    rem - flexInsertBoilerplate - FlexHTML footer to output
    rem -  Args:   empty$, reserved (must be "" for now)
    rem -  Return: Nothing
    rem -  Notes:  Standard FlexHTML HTML footer insert
    rem -          is placed into output stream.
    rem -          Reserved parameter, empty$, MUSt be ""
    rem -          May ONLY be called within a user template
    rem -
    rem -          Please consider using this footer at
    rem -          the end of all public HTML documents
    rem -          generated with the help of FlexHTML.
    rem -
    external flexInsertBoilerplate:(empty$)
    
    rem ----------------------------------------------------
    rem - flexOutFile$ - returns name of current output file
    rem -  Args:   None
    rem -  Return: Value of outFile$ specified on flex: call
    rem -  Notes:  May ONLY be called within a user template
    rem -
    external flexOutFile$:
    
    rem ----------------------------------------------------
    rem - flexKeyword$ - extract keyword from string
    rem -  Args:   s$, string in which to look
    rem -          allowNull%, if zero an error is raised if
    rem -              no keyword was found in string
    rem -  Return: Value of keyword, in upper case
    rem -  Notes:  Given a string, this function trims all
    rem -          leading and trailing white space and
    rem -          returns the remainder, folded to upper
    rem -          case.
    rem -          If the remainder contains any characters
    rem -          other than 'A' to 'Z', '0' to '9' or '-'
    rem -          then an error is raised and the function
    rem -          does not return.
    rem -          An error is also raised if the remainder
    rem -          is the empty string and allowNull% is
    rem -          false.
    rem -          May ONLY be called within a user template
    rem -
    external flexKeyword$:(s$,allowNull%)
    
    
    rem ----------------------------------------------------
    rem - flexError - test for and report error
    rem -  Args:   ec%, standard OPL error code
    rem -          msg$, error message string
    rem -  Return: Nothing
    rem -  Notes:  If ec% is non zero, an error report is
    rem -          generated (including line number, error
    rem -          description and supplied message text)
    rem -          and processing is terminated.
    rem -          Returns immediately if ec% is zero.
    rem -          May ONLY be called within a user template
    rem -
    external flexError:(ec%,msg$)
    
    rem ====================================================
    rem End of FlexHTML.oph
    rem ====================================================
    
    


    Generated with help from FlexHTML for EPOC