Flexible HTML generation for EPOC
(C) 2000, 2001 David Rushall
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...
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.
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.
To install this software on your machine,just install the main application SIS file:
The software will be installed on the C: drive.
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.
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.
In order to use FlexHTML you will need the following...
Mix as follows...
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)
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.
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.
Template control characters | |
---|---|
+ |
##+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"). |
The main procedure of the control program is responsible for:
The following functions are provided by FlexHTML.opo for this purpose.
Functions for use in control procedure | |
---|---|
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)
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'.
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.
Functions to read template arguments | |
---|---|
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. |
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.
Function to embed other files | |
---|---|
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)
In addition to the basic functions for processing files and handling template arguments, FlexHTML provides a number of utility functions. These are summarised below.
Auxillary functions | |
---|---|
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.
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:
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).
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).
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.
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:
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