txt2html README
===============

 txt2html - Text to HTML converter - Korn Shell 93 Script Function
 Copyright (C) 2006 Dana French <dfrench@mtxia.com>
 Home Page: http://www.mtxia.com/fancyIndex/Tools/Scripts/Korn/K93_Unix/


Intro
-----

txt2html is a plain text to HTML converter written as a Korn Shell 93
script function. It succesfully converts subtle text markup to lists,
bold, italics, tables and headings to their corresponding HTML markup
without having to write unreadable source text files.

No installation is necessary, txt2html can be utilized from the
command line or as a function called from another shell script.  The
program "txt2html" is itself a Korn Shell 93 script.

	$ txt2html someFile.txt

txt2html includes several command-line arguments; see them using

	$ txt2html -?

This README file contains all the marks that txt2html is able to
understand so that it serves also as a demo. So, to see how this file will
look after being converted by txt2html, you can just do

	$ txt2html < txt2html.README > README.html

and see its effects.

Text paragraphs
---------------

A text paragraph is any group of lines containing text delimited by one or
more blank lines, provided that none of them beings with a blank space.
So, you just write lines as usual (wrapping or not), and separates
paragraphs as in a word processor.

Headings
--------

A line is understand as a heading if it's immediately followed by another
one that contains only a repetition of a special character (see 'Text
paragraphs' and 'Headings' for an example). There are three heading
levels depending on this special character: if it's a line of = (equal
sign), it's a first level heading, used for titles and tagged with h1 HTML
tags. If it's - (hyphen), it's a second level heading, and if it's ~
(tilde), a third level one. This document shows the three heading levels.
It's suggested that the first level heading is used only once, as it's
magically taken as the title for the HTML page, if one is not overriden as
a command line argument.

Text effects
------------

If some text is surrounded by asterisks, as *this one*, it's marked as
bold (you probably wrote text this way in email to emphasize something).
As well, text surrounded by the _ symbol (underscore), as _this one_, is
marked as italic. Bold can also be marked up surrounding the text with three
apostrophes ('''this way''') and italics with two (''this way''). If you ever
used a WikiWikiWeb system you'll be familiar with these ones.

Other special text is automatically recognized, as URLs (so that the URL
http://www.mtxia.com should be clickable). Text beginning with ./ is
interpreted as relative URLs, so ./index.html should also be clickable.

txt2html can also be useful when documenting source code, as function names
like printf() or variables like $username are also highlighted. There are
command line arguments to make the parenthesis and / or leading dollar to
disappear from the output document.

URLs are simply substituted as shown above; if an URL is followed by a
phrase surrounded by parentheses (just like you naturally would do to
explain the contents of a web), this phrase is used as the link text, as
in this example pointing to
http://www.mtxia.com/fancyIndex/Tools/Scripts/Korn/K93_Unix/txt2html.html
(the txt2html Home Page).

Lists
-----

txt2html is powerful rendering lists. There are three types of lists:
unnumbered ones (bulleted), numbered ones and definition lists. They are
recognized as lines starting with a blank (space or tab) immediately
followed by an special character.

 * Unnumbered lists start with some blanks, followed by an asterisk,
   followed by another blank. If the following lines are space indented,
   they are assumed as part of the same list element. The asterisk can
   also be a - (hyphen).
 * Lists can have multiple levels. To add another level,
   * Just indent a bit deeper,
     * and have hours of fun
       * nesting.
     * unindent 1 level
   * unindent a 2nd level
 * Numbered lists are marked up almost the same, just by substuting the
   asterisk by a # (sharp) or 1 (number one).
 * Definition lists are marked up almost the same, but delimiting the
   definition term from the definition itself by a colon.

List examples
~~~~~~~~~~~~~

Unnumbered list:

 * First element. Elements at the same level must be indented
   by the same number of spaces.
 * The second one.
   * The second element has one sub-element.
   * And another...
      * that, itself, has another one
   * unindent 1 level
 * The third one...
   * Has another extremely long sub-element to show that long
     ones are rendered correctly. Please note that the elements
     of a list cannot be separated by blank lines or they will
     be interpreted as different lists.
 * The 4th and final one...
   * And its final child.

Ordered list:

 # First element.
 # The second one.
   # The second element has one sub-element.
   # And another...
      # that, itself, has another one
   # unindent 1 level
 # The third one...
   # Has another extremely long sub-element to show that long
     ones are rendered correctly. Please note that the elements
     of a list cannot be separated by blank lines or they will
     be interpreted as different lists.
   # And another sub-element, to show this is not a cut & paste
     from the unsorted example.
 # The 4th and final one. Note also that ordered and unsorted
   lists cannot be combined.

Definition list:

 * first: the first element and
          this is the second line of the first 
          definition list and it will wrap around the full line
          of the browser so that it is visible across multiple
          lines
 * second: the second element
 * third: the third element

Preformatted text
-----------------

A text that should be rendered as is should be written with at least a
blank in the beginning of all lines. This can be an example:

 int main(int argc, char * argv[])
 {
	/* an example of useless C code */
	return(0);
 }

If you ever wrote any Perl POD documentation, you'll be familiar with this.

If you write preformatted text and its first line collisions with list
definitions (i.e. text with lines beginning with blanks and an asterisk or
sharp) just insert a line containing only spaces before it.

Cites
-----

If you want to quote a (possibly long) paragraph of text, use a blank
followed by a " (double quote) in its first line, as in the following
example:

 "BRAIN, n. An apparatus with which we think what we think. That which 
 distinguishes the man who is content to _be_ something from the man 
 who wishes to _do_ something. A man of great wealth, or one who has 
 been pitchforked into high station, has commonly such a headful of 
 brain that his neighbors cannot keep their hats on. In our 
 civilization, and under our republican form of government, brain is so 
 highly honored that it is rewarded by exemption from the cares of 
 office." -- Ambrose Bierce

The leading double quote remains as part of the cited paragraph.

HTML
----

If you need to insert HTML as is (for rendering, say, images or
complicated layouts), you can also do it. Anything between two < symbols
and two > symbols will be passed without any further processing. So, to
insert an image, just do this:

&lt;&lt;
<BR>&lt;center&gt;
<BR>&lt;img src=http://www.mtxia.com/icons/mtxia.gif alt="Mt Xia Logo"&gt;
<BR>&lt;/center&gt;
<BR>&gt;&gt;


<<
<center>
<img src='http://www.mtxia.com/icons/mtxia.gif' alt="Mt Xia Logo">
</center>
>>

Passthrough code can also be inline as in << <sup>this</sup> >> example.

Any other HTML outside this boundaries is escaped.

Tables
------

But where txt2html is really awesome is rendering tables. They are created
using the + (plus) sign for corners, the - (hyphen) for horizontal lines
and the | (pipe) for vertical lines. So this is a table:

+-------------------------+----------------------+-----------------+
|  Band Name              | Album Name           | Number of Songs |
|  second Band Name       | second Album Name    | second    Songs |
|  third Band Name        | third  Album Name    | third     Songs |
+-------------------------+----------------------+-----------------+
| Dead Can Dance          | A Passage in Time    | 16              |
| second line             | second passage       | 216             |
+-------------------------+----------------------+-----------------+
| Bel Canto               | White-Out Conditions | 10              |
+-------------------------+----------------------+-----------------+
| Depeche Mode            | Speak and Spell      | 16              |
+-------------------------+----------------------+-----------------+
| Love Spirals Downwards  | Temporal             | 13              |
+-------------------------+----------------------+-----------------+

One or more header rows can be imbedded in a table by marking the header
row with an exclamation point (!) immediately following the first pipe
"|!" designating a data row.  Only one "!" is necessary in the first
cell, however every cell in a header row may be designated using a "!"
for consistency, if desired.  A header row may also be marked by using
an asterisk (*) instead of a plus sign (+) to mark the cell divisions
on the table border line above each data cell.

*-------------------------*----------------------*-----------------*
|  Band Name              | Album Name           | Number of Songs |
|  second Band Name       | second Album Name    | second    Songs |
|  third Band Name        | third  Album Name    | third     Songs |
+-------------------------+----------------------+-----------------+
| Dead Can Dance          | A Passage in Time    | 16              |
+-------------------------+----------------------+-----------------+
| Bel Canto               | White-Out Conditions | 10              |
+-------------------------+----------------------+-----------------+
| Depeche Mode            | Speak and Spell      | 16              |
+-------------------------+----------------------+-----------------+
| Love Spirals Downwards  | Temporal             | 13              |
+-------------------------+----------------------+-----------------+

The following is a table with multiple header lines identified.

*------------*-------------*-------------*-----------*
|  Head 1    | Head 2      | Head 3      | Head 4    |
+------------+-------------+-------------+-----------+
| Cell 1-1   | Cell 1-2    | Cell 1-3    | Cell 1-4  |
+------------+-------------+-------------+-----------+
| Cell 2-1   | Cell 2-2    | Cell 2-3    | Cell 2-4  |
+------------+-------------+-------------+-----------+
| Cell 3-1   | Cell 3-2    | Cell 3-3    | Cell 3-4  |
*------------*-------------*-------------*-----------*
|! Head 5    |! Head 6     |! Head 7     |! Head 8   |
+------------+-------------+-------------+-----------+
| Cell 4-1   | Cell 4-2    | Cell 4-3    | Cell 4-4  |
+------------+-------------+-------------+-----------+
| Cell 5-1   | Cell 5-2    | Cell 5-3    | Cell 5-4  |
+------------+-------------+-------------+-----------+
| Cell 6-1   | Cell 6-2    | Cell 6-3    | Cell 6-4  |
+------------+-------------+-------------+-----------+

Separators
----------

A separator line (horizontal ruler) can be inserted by typing four or
more hash marks (#) on a line.  To the end of this document there should
be a separator, above my signature.

####
Dana French http://www.mtxia.com


#!/usr/bin/ksh93
################################################################
function usagemsg_txt2html_k93 {
  print "
Program: txt2html_k93

Convert preformatted text into HTML.  Similar in function to the
"Grutatxt" Perl module. txt2html_k93 is a shell script function to
process text documents in a special markup format (also called
Grutatxt), very similar to plain ASCII text. These documents can be
easily converted to HTML.

Usage: ${1##*/} [-?] [-a left|center|right] [-A top|middle|bottom]
                     [-b color] [-B color] [-d color] [-D color]
                     [-o AI1ai] [-w #] [-C] [-H] [-vV] [file...]
    Where:                                                     Default
        -a align = Table data cell alignment                   (left)
        -A vertAlign = Table data cell vertical alignment      (middle)
        -b color = Table data cell background color            (white)
        -B color = Table header cell background color          (lightgrey)
        -d color = Table data cell font color                  (black)
        -D color = Table header cell font color                (black)
        -w #     = Table border width (0-99)                   (1)
        -o list  = Ordered list numbering scheme               (1aiAI)
        -C = Center all tables on the page                     (left)
        -H = Mark the first row of all tables as a header row
        -v = Verbose Mode
        -V = Very Verbose Mode

Author: Dana French (dfrench@mtxia.com)
        Copyright 2006, All Rights Reserved

\"AutoContent\" enabled
"
  return 0
}
################################################################
####
#### Description:
#### 
#### Convert preformatted text into HTML.  Similar in
#### function to the "Grutatxt" Perl module. txt2html_k93 is
#### a shell script function to process text documents in a
#### special markup format (also called Grutatxt), very
#### similar to plain ASCII text. These documents can be
#### easily converted to HTML.
#### 
#### The markup is designed to be fairly intuitive and
#### straightforward and can include headings, bold and
#### italic text effects, bulleted, numbered and definition
#### lists, URLs, function and variable names, preformatted
#### text, horizontal separators and tables. Special marks
#### can be inserted in the text and a heading-based
#### structural index can be obtained from it.
#### 
#### Assumptions:
####
#### Dependencies:
####
#### Products:
####
#### Configured Usage:
####
#### Details:
####
################################################################
function txt2html_k93 {
  typeset VERSION="1.0"
  typeset TRUE="0"
  typeset FALSE="1"
  typeset VERBOSE="${FALSE}"
  typeset VERYVERB="${FALSE}"
  typeset ULFLAG="${FALSE}"
  typeset DLFLAG="${FALSE}"
  typeset PREFLAG="${FALSE}"
  typeset CITEFLAG="${FALSE}"
  typeset CODEFLAG="${FALSE}"
  typeset HTMLFLAG="${FALSE}"
  typeset SIZ_TBLBDR="1"
  typeset TBLHDRROW="${FALSE}"
  typeset TBLCENTER="${FALSE}"
  typeset OLSCHEME="1aiAI"
  typeset -l CLR_TDBG="white"
  typeset -l CLR_THBG="lightgrey"
  typeset -l CLR_TDFG="black"
  typeset -l CLR_THFG="darkblue"
  typeset -l TBLALIGN="left"
  typeset -l TBLVALIGN="middle"
  typeset SPACES=$'\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20'

  while getopts ":vVa:A:b:B:d:D:o:w#CH" OPTION
  do
    case "${OPTION}" in
        'a') typeset -l TBLALIGN="${OPTARG}";;
        'A') typeset -l TBLVALIGN="${OPTARG}";;
        'b') typeset -l CLR_TDBG="${OPTARG}";;
        'B') typeset -l CLR_THBG="${OPTARG}";;
        'd') typeset -l CLR_TDFG="${OPTARG}";;
        'D') typeset -l CLR_THFG="${OPTARG}";;
        'w') SIZ_TBLBDR="${OPTARG}";;
        'o') OLSCHEME="${OPTARG}";;
        'C') TBLCENTER="${TRUE}";;
        'H') TBLHDRROW="${TRUE}";;
        'v') VERBOSE="${TRUE}";;
        'V') VERYVERB="${TRUE}";;
      [?:#]) usagemsg_txt2html_k93 "${0}" && return 1 ;;
    esac
  done

  shift $(( ${OPTIND} - 1 ))

  (( VERYVERB == TRUE )) && set -x

################################################################

  typeset OLTYPE="0"
  typeset ICNT=0
  for (( ICNT=0; ICNT<=10; ++ICNT ))
  do 
      OLTYPE="${OLTYPE}${OLSCHEME}"
  done

################################################################
#### Checking command line options and arguments for improper values.

  trap "usagemsg_txt2html_k93 ${0}" EXIT

  if [[ "${TBLALIGN}" != @(left|center|right) ]]
  then  
      print -u 2 -- "# ERROR: Invalid table cell alignment value: ${TBLALIGN}"
      return 2
  fi
  if [[ "${TBLVALIGN}" != @(top|middle|bottom) ]]
  then  
      print -u 2 -- "# ERROR: Invalid table cell verticle alignment value: ${TBLVALIGN}"
      return 3
  fi
  if [[ "_${SIZ_TBLBDR}" == "_" ]] ||
     (( SIZ_TBLBDR < 0 )) ||
     (( SIZ_TBLBDR > 99 ))
  then  
      print -u 2 -- "# ERROR: Invalid table border width value: ${SIZ_TBLBDR}"
      return 4
  fi

  trap "-" EXIT

################################################################

  typeset STDIN="${1:+${FALSE}}"
  [[ "_${1}" == '_-' ]] && STDIN="${TRUE}"
  STDIN="${STDIN:-${TRUE}}"

#### Read in the data either from STDIN or one or more files
  if (( STDIN == TRUE ))
  then
      set -- -
  fi

#### Loop through each file name specified on the command line
#### or standard input if no file names

  for FNAME in "${@}"
  do
      if (( STDIN == FALSE )) && [[ ! -e "${FNAME}" ]]
      then
          print -u 2 "${0##*/}: ${FNAME}: No such file or directory"
          continue
      fi

#### Loop through each line of the current input stream or file and
#### determine the HTML type to assign to each line.  The HTML type
#### will be used later to insert the appropriate HTML tags for
#### rendering the line.

      unset TXTARRY
      LCNT="0"
      cat_k93 -- "${FNAME}" |
      while IFS="" read -r -- LINE
      do

#### Save each line of the input stream to an array. This array will
#### be used to display the original text and to associate various
#### parameters with each array element position.

          TXTARRY[LCNT]="${LINE}"

#### If the line is blank, mark the line as a "paragraph" separator line

          if [[ "_${LINE}" == "_" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Paragraph"
              ULFLAG="${FALSE}"
              TAGTYPE[LCNT]="P"
          fi

#### If the line begins with 4 or more hash (#) characters, mark it
#### as a horizontal rule separator line

          if [[ "_${LINE}" == _\#\#\#\#*(\#) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Horizontal Rule"
              TAGTYPE[LCNT]="HR"
          fi


#### If the first non-blank character of the line is an equal sign, dash,
#### or tilde, mark the previous line (if non-blank) as a header line.

          if (( LCNT > 0 ))
          then
            if [[ "_${LINE}" == _*([[:blank:]])+([=]) ]]
            then
                (( VERBOSE == TRUE )) && print -u 2 -- "# Header 1"
                TAGTYPE[LCNT-1]="H1"
            fi
            if [[ "_${LINE}" == _*([[:blank:]])+([-]) ]]
            then
                (( VERBOSE == TRUE )) && print -u 2 -- "# Header 2"
                TAGTYPE[LCNT-1]="H2"
            fi
            if [[ "_${LINE}" == _*([[:blank:]])+([\~]) ]]
            then
                (( VERBOSE == TRUE )) && print -u 2 -- "# Header 3"
                TAGTYPE[LCNT-1]="H3"
            fi
            if [[ "_${LINE}" == _*([[:blank:]])+([=\~-]) ]]
            then
                (( VERBOSE == TRUE )) && print -u 2 -- "# DELETE"
                TAGTYPE[LCNT]="DELETE"
            fi
          fi

####
#### Imbedded HTML
####

          if (( HTMLFLAG == TRUE ))
          then
             (( VERBOSE == TRUE )) && print -u 2 -- "#     Imbedded HTML"
             TAGTYPE[LCNT]="HTML"
          fi

          if [[ "_${LINE}" == _*@('<<'|'>>')* ]]
          then
              if [[ "_${LINE}" == _*'<<'* ]]
              then
                  (( VERBOSE == TRUE )) && print -u 2 -- "# Begin Imbedded HTML"
                  HTMLFLAG="${TRUE}"
                  TAGTYPE[LCNT]="HTML"
              fi

              if [[ "_${LINE}" == _*'>>'* ]]
              then
                  (( VERBOSE == TRUE )) && print -u 2 -- "# End Imbedded HTML"
                  HTMLFLAG="${FALSE}"
                  TAGTYPE[LCNT]="HTML"
              fi
          fi

####
#### Preformatted Text segments
####

          if (( ULFLAG == FALSE )) && (( DLFLAG == FALSE )) &&
             [[ "_${LINE}" == _+([[:blank:]])[!*\#\"]* ]]
          then
              TAGTYPE[LCNT]="PRE"
              if [[ "${TAGTYPE[LCNT-1]}" == "CITE" ]]
              then 
                  (( VERBOSE == TRUE )) && print -u 2 -- "#     CITE"
                  TAGTYPE[LCNT]="CITE"
              else
                  (( VERBOSE == TRUE )) && print -u 2 -- "# Preformatted"
              fi

          fi

####
#### Cite Text segments
####

          if [[ "_${LINE}" == _+([[:blank:]])\"* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Begin CITE"
              TAGTYPE[LCNT]="CITE"
          fi

####
#### Programming Code segments
####

          if [[ "_${LINE}" == _*([[:blank:]])\$* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# CODE "
              TAGTYPE[LCNT]="CODE"
          fi

####
#### Unordered/Ordered Lists
####

          if (( ULFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#     List line"
              TAGTYPE[LCNT]="LI"
              LSTTYPE[LCNT]="${TAGTYPE[LCNT-1]}"
              ULSPACE[LCNT]="${ULSPACE[LCNT-1]:-0}"
              ULLEVEL[LCNT]="${ULLEVEL[LCNT-1]:-0}"
          fi

          if [[ "_${LINE}" == _*([[:blank:]])[*\#][!-]* ]]
          then
              ULFLAG="${TRUE}"

#### *([[:blank:]])\*[!\*]* = Zero or more blank characters,
#### followed by literal asterisk (*),
#### followed by any single non-asterisk(*) character,
#### followed by zero or more characters

              if [[ "_${LINE}" == _*([[:blank:]])[*][!*]* ]]
              then
                  (( VERBOSE == TRUE )) && print -u 2 -- "# Unordered list"
                  TAGTYPE[LCNT]="UL"
              fi

              if [[ "_${LINE}" == _*([[:blank:]])\#[!\#]* ]]
              then
                  (( VERBOSE == TRUE )) && print -u 2 -- "# Ordered list"
                  TAGTYPE[LCNT]="OL"
              fi

              TMPNBR="${LINE%%[!$' \t\n']*}"
              ULSPACE[LCNT]="${#TMPNBR}"

              ULDELTA="0"
              (( ${ULSPACE[LCNT]} > ${ULSPACE[LCNT-1]:-0} )) && ULDELTA="+1"
              (( ${ULSPACE[LCNT]} < ${ULSPACE[LCNT-1]:-0} )) && ULDELTA="-1"
              ULLEVEL[LCNT]="$(( ${ULLEVEL[LCNT-1]:-0} + ${ULDELTA} ))"
              LSTTYPE[LCNT]="${TAGTYPE[LCNT]}"
          fi

####
#### Definition Lists
####

          if (( DLFLAG == TRUE )) && [[ "${TAGTYPE[LCNT-1]}" == @(DL|DD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#     Definition list data"
             TAGTYPE[LCNT]="DD"
          fi

          if [[ "_${LINE}" == _*([[:blank:]])[*]*:* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Begin Definition list"
              TAGTYPE[LCNT]="DL"
              DLFLAG="${TRUE}"
              ULFLAG="${FALSE}"
              LSTTYPE[LCNT]=""
              ULSPACE[LCNT]=""
              ULLEVEL[LCNT]=""
          fi

          if (( DLFLAG == TRUE )) && [[ "${TAGTYPE[LCNT]}" != @(DL|DD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# End Definition list"
              DLFLAG="${FALSE}"
          fi

####
#### Tables and rows
####

          if [[ "_${LINE}" == _*([[:blank:]])[+]-* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Table data cell border"
              TAGTYPE[LCNT]="TABLETD"
          fi
          if [[ "_${LINE}" == _*([[:blank:]])[*]-* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "# Table header cell border"
              TAGTYPE[LCNT]="TABLETH"
          fi
          if [[ "_${LINE}" == _*([[:blank:]])\|* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#     Table data cell"
              TAGTYPE[LCNT]="ROW"
              if [[ "${TAGTYPE[LCNT-1]}" == @(TABLETH|HEADER) ]]
              then
                  TAGTYPE[LCNT]="HEADER"
              fi
          fi
          if [[ "_${LINE}" == _*([[:blank:]])\|\!* ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#     Table header cell"
              TAGTYPE[LCNT]="HEADER"
          fi


#### Array element counter for lines read in

          (( ++LCNT ))

      done

################################################################

      TABLEFLAG="${FALSE}"
      print -- "<P>"
      for IDX in "${!TXTARRY[@]}"
      do

          TEXTLINE="${TXTARRY[IDX]}"

####
#### Imbedded HTML
####

          if [[ "${TAGTYPE[IDX]}" == "HTML" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#01 ${TAGTYPE[IDX]}"
              TEXTLINE="${TEXTLINE//'<<'/}"
              TEXTLINE="${TEXTLINE//'>>'/}"
          fi

####
#### CODE HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == "CODE" ]] && (( CODEFLAG == FALSE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#02 ${TAGTYPE[IDX]}"
              print -- "\n<BLOCKQUOTE><${TAGTYPE[IDX]}><PRE>"
              CODEFLAG="${TRUE}"
          fi

          if [[ "${TAGTYPE[IDX]}" == "CODE" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#03 ${TAGTYPE[IDX]}"
              TEXTLINE="${TEXTLINE/#*([[:blank:]])\$*([[:blank:]])}"
          fi

          if [[ "${TAGTYPE[IDX]}" != "CODE" ]] && (( CODEFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#04 ${TAGTYPE[IDX]}"
              print -- "</PRE></${TAGTYPE[IDX]}></BLOCKQUOTE>"
              CODEFLAG="${FALSE}"
          fi

####
#### CITE Text HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == "CITE" ]] && (( CITEFLAG == FALSE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#05 ${TAGTYPE[IDX]}"
              print -- "<CITE>"
              CITEFLAG="${TRUE}"
          fi

          if [[ "${TAGTYPE[IDX]}" != "CITE" ]] && (( CITEFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#06 ${TAGTYPE[IDX]}"
              print -- "</CITE>"
              CITEFLAG="${FALSE}"
          fi

####
#### Preformatted Text HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == "PRE" ]] && (( PREFLAG == FALSE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#07 ${TAGTYPE[IDX]}"
              print -- "<PRE>"
              PREFLAG="${TRUE}"
          fi

          if [[ "${TAGTYPE[IDX]}" != "PRE" ]] && (( PREFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#08 ${TAGTYPE[IDX]}"
              print -- "</PRE>"
              PREFLAG="${FALSE}"
          fi

####
#### Horizontal Rule HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == "HR" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#09 ${TAGTYPE[IDX]}"
              print -- "<${TAGTYPE[IDX]}>"
              continue
          fi

####
#### Table and Row HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == @(TABLETH|TABLETD) ]]
          then
              if (( TABLEFLAG == FALSE ))
              then
                  if (( TBLCENTER == TRUE ))
                  then
                      (( VERBOSE == TRUE )) && print -u 2 -- "#10 ${TAGTYPE[IDX]}"
                      print -- "<CENTER>"
                  fi
                  (( VERBOSE == TRUE )) && print -u 2 -- "#11 ${TAGTYPE[IDX]}"
                  print -- "<TABLE Border=\"${SIZ_TBLBDR}\">"
                  TBLROW="0"
              fi
              TABLEFLAG="${TRUE}"
#               print -- "<P>\n  <TR>"
#               continue
          fi

#### If the current line is not a TABLE, HEADER, or ROW line
#### but the TABLEFLAG variable is set to true, then end the
#### table and set the TABLEFLAG variable to false.

          if [[ "${TAGTYPE[IDX]}" != @(TABLETH|TABLETD|HEADER|ROW) ]]
          then
              (( TABLEFLAG == TRUE )) && print -- "  </TR>\n</P>\n</TABLE>"
              if (( TBLCENTER == TRUE ))
              then
                  (( VERBOSE == TRUE )) && print -u 2 -- "#13 ${TAGTYPE[IDX]}"
                  print -- "</CENTER>"
              fi
              TABLEFLAG="${FALSE}"
          fi

#### Determine if this is the first row of the table and if it should
#### be marked as a HEADER row

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "TABLETD" ]] &&
             [[ "${TAGTYPE[IDX]}" == "ROW" ]] &&
             (( TBLHDRROW == TRUE )) &&
             (( TBLROW == 0 ))
          then
              TAGTYPE[IDX-1]="TABLETH"
              TAGTYPE[IDX]="HEADER"
          fi

          if [[ "${TAGTYPE[IDX]}" == "ROW" ]] &&
             (( TBLHDRROW == TRUE )) &&
             (( TBLROW == 0 ))
          then
              TAGTYPE[IDX]="HEADER"
          fi

#### If the table row is a header row, incapsulate the cell contents
#### using table header tags "TH".

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "TABLETH" ]] &&
             [[ "${TAGTYPE[IDX]}"   == "HEADER" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#14 ${TAGTYPE[IDX]}"
              IFS=$'|'
              THROW=( ${TEXTLINE#\|} )
              IFS=$' \t\n'
              continue
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "HEADER" ]] &&
             [[ "${TAGTYPE[IDX]}"   == "HEADER" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#15 ${TAGTYPE[IDX]}"
              IFS=$'|'
              THNXT=( ${TEXTLINE#\|} )
              IFS=$' \t\n'
              for IDX in "${!THNXT[@]}"
              do
                  THROW[IDX]="${THROW[IDX]}<BR>${THNXT[IDX]}"
              done
              continue
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "HEADER" ]] &&
             [[ "${TAGTYPE[IDX]}"   == @(TABLETH|TABLETD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#16 ${TAGTYPE[IDX]}"
              IFS=$'|'
              TEXTLINE="${THROW[*]}"
              IFS=$' \t\n'

TEXTLINE="${TEXTLINE//\|?(!)/$'\n'    \</FONT></TH\>$'\n'    \<TH Bgcolor=\"${CLR_THBG}\"\><FONT Color=\"${CLR_THFG}\">$'\n'}"

TEXTLINE="<P>
  <TR>
    <TH Bgcolor=\"${CLR_THBG}\"><FONT Color=\"${CLR_THFG}\">
${TEXTLINE}
    </FONT></TH>
  </TR>
</P>"
              (( ++TBLROW ))
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" != @(ROW|HEADER) ]] &&
             [[ "${TAGTYPE[IDX]}"   == @(TABLETH|TABLETD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#17 ${TAGTYPE[IDX]}"
              continue
          fi

#### If the table row is a data row, incapsulate the cell contents
#### using table header tags "TD".

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "TABLETD" ]] &&
             [[ "${TAGTYPE[IDX]}"   == "ROW" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#18 ${TAGTYPE[IDX]}"
              IFS=$'|'
              TDROW=( ${TEXTLINE#\|} )
              IFS=$' \t\n'
              continue
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "ROW" ]] &&
             [[ "${TAGTYPE[IDX]}"   == "ROW" ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#19 ${TAGTYPE[IDX]}"
              IFS=$'|'
              TDNXT=( ${TEXTLINE#\|} )
              IFS=$' \t\n'
              for IDX in "${!TDNXT[@]}"
              do
                  TDROW[IDX]="${TDROW[IDX]}<BR>${TDNXT[IDX]}"
              done
              continue
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" == "ROW" ]] &&
             [[ "${TAGTYPE[IDX]}"   == @(TABLETH|TABLETD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#20 ${TAGTYPE[IDX]}"
              IFS=$'|'
              TEXTLINE="${TDROW[*]}"
              IFS=$' \t\n'

TEXTLINE="${TEXTLINE//\|?(!)/$'\n'    \</FONT></TD\>$'\n'    \<TD Bgcolor=\"${CLR_TDBG}\"\><FONT Color=\"${CLR_TDFG}\">$'\n'}"

TEXTLINE="<P>
  <TR>
    <TD Bgcolor=\"${CLR_TDBG}\"><FONT Color=\"${CLR_TDFG}\">
${TEXTLINE}
    </FONT></TD>
  </TR>
</P>"
              (( ++TBLROW ))
          fi

          if (( IDX > 0 )) &&
             [[ "${TAGTYPE[IDX-1]}" != @(ROW|HEADER) ]] &&
             [[ "${TAGTYPE[IDX]}"   == @(TABLETH|TABLETD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#21 ${TAGTYPE[IDX]}"
              continue
          fi

####
#### Ordered/Unordered list HTML TAG output
####

          if [[ "${TAGTYPE[IDX]}" == @(UL|OL) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#22 ${TAGTYPE[IDX]}"
              TEXTLINE="${TXTARRY[IDX]#*[*\#]}"
              if (( ${ULLEVEL[IDX]} > ${ULLEVEL[IDX-1]:-0} ))
              then
                  print -n -- "\n${SPACES:0:${ULLEVEL[IDX]}}<${TAGTYPE[IDX]}"
                  if [[ "${TAGTYPE[IDX]}" == "OL" ]]
                  then
                      print -n -- " Type=\"${OLTYPE:${ULLEVEL[IDX]}:1}\""
                  fi
                  print -- ">"
              fi
              if (( ${ULLEVEL[IDX]} <= ${ULLEVEL[IDX-1]:-0} ))
              then
                  print -- "${SPACES:0:${ULLEVEL[IDX]}}</LI>"
              fi
              if (( ${ULLEVEL[IDX]} < ${ULLEVEL[IDX-1]:-0} ))
              then
                  print -- "\n${SPACES:0:${ULLEVEL[IDX-1]}}</${TAGTYPE[IDX]}>"
              fi
              print -- "${SPACES:0:${ULLEVEL[IDX]}}<LI>"
          fi

####
#### Definition List output
####

          if [[ "${TAGTYPE[IDX]}" == "DL" ]] && (( DLFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#23 ${TAGTYPE[IDX]}"
              print -- "</FONT></DD></DT></DL>"
              TMPTEXT="${TEXTLINE#*\*}"
              print -- "<DL><DT><FONT Color=\"${CLR_THFG}\"><STRONG>${TMPTEXT%%:*}</STRONG></FONT><DD><FONT Color=\"${CLR_TDFG}\">"
              DLFLAG="${TRUE}"
          fi

          if [[ "${TAGTYPE[IDX]}" == "DL" ]] && (( DLFLAG == FALSE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#24 ${TAGTYPE[IDX]}"
              TMPTEXT="${TEXTLINE#*\*}"
              print -- "<DL><DT><FONT Color=\"${CLR_THFG}\"><STRONG>${TMPTEXT%%:*}</STRONG></FONT><DD><FONT Color=\"${CLR_TDFG}\">"
              DLFLAG="${TRUE}"
          fi

          if [[ "${TAGTYPE[IDX]}" == @(DL|DD) ]]
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#25 ${TAGTYPE[IDX]}"
              TEXTLINE="${TEXTLINE#*:}"
          fi

          if [[ "${TAGTYPE[IDX]}" != @(DL|DD) ]] && (( DLFLAG == TRUE ))
          then
              (( VERBOSE == TRUE )) && print -u 2 -- "#26 ${TAGTYPE[IDX]}"
              print -- "</FONT></DD></DT></DL>"
              DLFLAG="${FALSE}"
          fi

####
#### Header line HTML TAG output
####

          [[ "${TAGTYPE[IDX]}" == "DELETE" ]] && continue
          [[ "${TAGTYPE[IDX]}" == "H1" ]] && print -- "\n<${TAGTYPE[IDX]}>"
          [[ "${TAGTYPE[IDX]}" == "H2" ]] && print -- "\n<${TAGTYPE[IDX]}>"
          [[ "${TAGTYPE[IDX]}" == "H3" ]] && print -- "\n<${TAGTYPE[IDX]}>"

####
#### Text effects - bold, italics, URL's
####

if [[ "${TAGTYPE[IDX]}" != @(PRE|CITE|CODE|HTML) ]]
then
    TEXTLINE="${TEXTLINE//\*([![:blank:]]+(?)[![:blank:]])\*/\<STRONG\>\1\</STRONG\>}"
    TEXTLINE="${TEXTLINE//_([![:blank:]]+(?)[![:blank:]])_/\<I\>\1\</I\>}"
    TEXTLINE="${TEXTLINE//\'\'\'([![:blank:]]+(?)[![:blank:]])\'\'\'/\<STRONG\>\1\</STRONG\>}"
    TEXTLINE="${TEXTLINE//\'\'([![:blank:]]+(?)[![:blank:]])\'\'/\<I\>\1\</I\>}"
    TEXTLINE="${TEXTLINE//(http:\/\/+([![:blank:]]))/\<A Href=\"\1\"\>\1\</A\>}"
    TEXTLINE="${TEXTLINE//([[:space:]])(.\/+([![:space:]]))/\1\<A Href=\"\2\"\>\2\</A\>}"
fi

################################################################
#### Original text output

          [[ "_${TXTARRY[IDX]}" != "_" ]] && print -r -- "${TEXTLINE}"

################################################################

####
#### Ordered/Unordered List HTML TAG completion
####

          if [[ "${TAGTYPE[IDX]}" != @(UL|OL|LI) ]] &&
             (( IDX > 0 )) && (( ${ULLEVEL[IDX-1]:-0} > 0 ))
          then
              for (( i=${ULLEVEL[IDX-1]}; i>0; --i ))
              do
                  print -- "${SPACES:0:${i}}</LI>"
                  print -- "${SPACES:0:${i}}</${LSTTYPE[IDX-1]}>"
              done
          fi

####
#### Header HTML TAG completion
####

#           [[ "${TAGTYPE[IDX]}" == @(ROW|HEADER) ]] && print -- "  </TR>\n</P>"
          [[ "${TAGTYPE[IDX]}" == "H3"    ]] && print -- "</${TAGTYPE[IDX]}>"
          [[ "${TAGTYPE[IDX]}" == "H2"    ]] && print -- "</${TAGTYPE[IDX]}>"
          [[ "${TAGTYPE[IDX]}" == "H1"    ]] && print -- "</${TAGTYPE[IDX]}>"
          [[ "${TAGTYPE[IDX]}" == "P"     ]] && print -- "</${TAGTYPE[IDX]}><${TAGTYPE[IDX]}>"
      done | uniq
      print -- "</P>"
  done
  return 0

}
################################################################
################################################################
function cat_k93 {
  typeset TRUE="0"
  typeset FALSE="1"
  typeset VERBOSE="${FALSE}"
  typeset VERYVERB="${FALSE}"
  typeset FNAME

  while getopts ":vV" OPTION
  do
    case "${OPTION}" in
        'v') VERBOSE="${TRUE}";;
        'V') VERYVERB="${TRUE}";;
        '?') print "Syntax: cat_k93 [FILE]..." && return 1 ;;
    esac
  done
 
  shift $(( ${OPTIND} - 1 ))

  typeset STDIN="${1:+${FALSE}}"
  [[ "_${1}" == '_-' ]] && STDIN="${TRUE}"
  STDIN="${STDIN:-${TRUE}}"

#### Read in the data either from STDIN or one or more files
  if (( STDIN == TRUE ))
  then
      while IFS="" read -r -- LINE
      do
        print -r -- "${LINE}"
      done
  else
      for FNAME in "${@}"
      do
        if [[ -e "${FNAME}" ]]
        then
            while IFS="" read -r -- LINE
            do
              print -r -- "${LINE}"
            done < "${FNAME}"
        else
            print -u 2 "${0##*/}: ${FNAME}: No such file or directory"
            return 1
        fi
      done
  fi

  return 0
}
################################################################

txt2html_k93 "${@}"