txt2html Rexx Program

/*          ReXX       */
/*  #!/usr/local/bin/rexx  */

/*   Getting this running NOTES:
     ****************************

     For  IBM/Rexx standard interpreters, put
      /*   ReXX  */  as first in this script,
    For UNIX style systems, put the #!/...  'shebang' line
    as first in file, correcting the interpreter
    path/filename as needed.
    For variations from Rexx standard Library functions
    that need corrections (Lines, LineIn), see
    'Function Corrections' comments, way down there.
    These are known to be needed for OS/2 / AS400 interpreters,
    and somewhat current GPL Regina interpreters.
    If you printed this from an HTML web page and  experience
    traps for unmatched '/*' - '*/' pairs, check for a '*' and '/'
    pair split by an end-of-line, and rejoin them.
    It has been tested to 'auto process' itself into html
    that runs when processed back to plain text.
*/



/*     General Notes:
       ***************
       Based on prototype ReXX filter script
       from 'Teach Yourself ReXX in 21 DAYS'
       By Bill and Esther Schindler
       p. 271-272

       ReXX Language Association:  http://www.rexxla.org

       Delete #!/usr/local/bin/rexx  'shebang' line
       for use on non-UNIX-like systems.
       Make sure /* REXX */ comment is leftmost in
       the topmost line.

       (C) Copyright D.E. Legan,
       You may modify or use this program as you wish,
       as long as you do not remove my credit for
       originally writing it.
       If you make any juicy improvements,
       let me know! :-)
       If you figure out the full implications of the GPL,
       let me know.
       I assume no liability for the results of this program,
       legal or otherwise.

       D.E. Legan   12 Feb. 2001

       mailto:leganii@surfree.com

       http://www.lafn.org/~aw585/index.html

       http://www.lafn.org/~aw585/dlegan.html

       Thanks to Rollin White (mailto:rollin@scoug.com)
       for a few tweaks.

*/


/*   More General Notes:
     *******************

   txt2html   Text to HTML converter for text file input
              27 Jan 2001  d.e. legan
   __
   Help:
   ----
   txt2html -h

   Typical use, at the command line prompt:
   -----------
   txt2html < input.txt  >  output.htm

   To just output the HTML quick reference guide:

   txt2html -q
   __

   Purpose:  to do about 90% of the work in converting
   -------   a simple text file to HTML.

   Used 'HTML Visual Quick Reference' by Scharf / pub. Que
   as a reference
   __

   *Known* Limitations:
    ------------------
   1) Might want to add ability to do arbitrary inclusion of files
        or macro substitution.
   2) This was used as tool to learn HTML by me.
      Some of the features may seem foolish in retrospect,
      so bear with me.  :-)

   In short, this is tool that does not completely automate
   the process of converting raw text to HTML, but takes care
   of much of the dog work associated with the process.
   Derived as a simplification from the earlier
   'url2html' program.
   __

  D.E. Legan   03 Feb. 2001
  mailto:leganii@surfree.com

*/

/***********************************************************************
     Start of Actual Program
 ***********************************************************************/

/*  Since there shouldn't be any program errors,
    bunch up all the traps in one handler.
    This may not do much more than the defaults,
    but it puts in place a skeleton to customize it more
    if it is ever needed.
    D.E.L.  09/Aug./2001
*/

SIGNAL  ON   SYNTAX     NAME   Handler  ;
SIGNAL  ON   NOVALUE    NAME   Handler  ;
SIGNAL  ON   ERROR      NAME   Handler  ;
SIGNAL  ON   FAILURE    NAME   Handler  ;
SIGNAL  ON   HALT       NAME   Handler  ;
/*  SIGNAL  OFF  NOTREADY   NAME   Handler  ;  */
SIGNAL  OFF  NOTREADY    ;

/*
/*  Alternate if ever needed:  */
/*  only these conditions are valid with this type of handler:   */
/*  (one that returns after doing "it's thing")  */
CALL  ON  ERROR      NAME   HandlerR  ;
CALL  ON  FAILURE    NAME   HandlerR  ;
CALL  ON  HALT       NAME   HandlerR  ;
CALL  ON  NOTREADY   NAME   HandlerR  ;
*/

/*  For simplified exposing of these variables in functions:  */
basics  =  'myself STDIN STDOUT STDERR n nshadow  '  ,
             'clearscreen TRUE  FALSE  ON  OFF YES NO  '  ,
              'environment dirseperator helptest '  ,
              'hiddenstuff.'  ;

/* find out what the name of this program is:
    (This routine also sets some OS / interpreter specific
    parameters)
*/
myself  =  WhoAmI( )  ;

switches  =  '-hpPkbsgq'  ;  /*  switches are ON or OFF  */
parameters  = 'C'  ;         /*  parameters take arguments  */
options      =  switches  ||  parameters  ;
/*  And now the Biggie:  */

USAGE  =  ,
'USAGE:  'myself' ['switches'] [-C clonefile] [[<file.in>|-] [<file.out>|-]]'  ;

/*  ----By convention, 'USAGE' should be near the head of the program  */



/*   Handle command line & switches    ***************************/

PARSE ARG  infile  outfile  scratch  ;
infile  =  Strip( infile )  ;

IF   1 >< Verify( infile, helptest, 'M', 1 )  THEN
  CALL  Help  infile  ;   /*  First check for help  */

/*  Let's do this in one command:   :-)  */
PARSE VAR OFF  =1 autobreaking  =1 basichtml  =1 clonemode  =1 bracketparag  ,
               =1 paragraphing  =1 presets    =1 simpleguide  =1 debugmine

/*
/*  Initialize switch flags:  */
autobreaking     =  OFF  ;
basichtml        =  OFF  ;
clonemode        =  OFF  ;
bracketparag     =  OFF  ;
paragraphing     =  OFF  ;
presets          =  OFF  ;
simpleguide      =  OFF  ;
debugmine        =  OFF  ;
*/

/*  Have made the switch processing more ReXXcentric, should only
    require only one pass to process each freestanding
    clump of switches on the
    command line.
    D.E.L.  12/March/2001
*/
DO  WHILE( GetOpts( infile  )  )

  IF '--'  =  infile THEN  /*  End of switches with '--'  */
    DO
    PARSE VALUE  outfile scratch  WITH  infile outfile  scratch  ;
    infile  =  Strip( infile )  ;
    Leave  ;
    END

  IF '-'  ==  infile THEN   /*  '-' is a valid infile spec.  */
    Leave  ;


  /*  Start of processing 'parameters', 'options' with 'arguments'  */

  parameter  =  ''  ;

  cutpoint  = Verify( infile, parameters, 'MATCH', 1 )  ;
  IF  0 < cutpoint  THEN
      DO
      PARSE VAR infile    infile =(cutpoint) parameter +1 infile2  ;
      IF  '' << optarg  THEN
        infile  =  infile || infile2  ;
      ELSE
        optarg  =  infile2  ;
      END  ;

  IF  (( '' =  parameter )  &  ( '' >< optarg ))  THEN
    DO
    SAY  'Spurious argument 'optarg', with no parameter specified.'  ;
    infile  =  '-help'  ;
    CALL Help  ;
    END  ;


  IF  (( '' >< parameter )  &  ( '' =  optarg ))  THEN
    DO
    optarg  =  outfile  ;
    outfile   =  ''  ;
    IF  '' = optarg  THEN
      DO
      SAY 'Parameter 'parameter' must have an argument!'  ;
      infile  =  '-help'  ;
      CALL Help  ;
      END   ;
    END  ;   /*  parameter argument location/extraction  */


   CALL  Help  infile  ;  /*  First check for help   */
           /*  this had to be moved to after processing of
               optarg / parameter values.
            */

  IF  '' >< parameter  THEN   /* There is a parameter with argument  */
    SELECT
    /*  Process parameters, with ARGUMENTs   here   */
    /*  Should only be one parameter per option cluster */
    /*  with possible argument following either ':', '=' or a space  */
    WHEN  'C' == parameter  THEN
      DO
      /*  Must handle this before testing for unacceptable options.  */
      basichtml     =  ON  ;
      clonemode     =  ON  ;
      clonefile     =  optarg  ;
      END  ;
    OTHERWISE
      SAY 'Something seems to be wrong with parameter set up.'  ;
      infile  =  '-help'  ;
      CALL Help  ;
    END  ;


/*  Stop processing options with arguments here  */

/*  Start processing hidden switches here  */
  IF  Inside( '?', infile )  THEN     /*  hidden switch   */
    DO
    /*  CALL LineOut  outfile  ;  */
    infile  =  '-help'  ;
    CALL Help  ;
    END

  IF  Inside( 'd', infile )  THEN    /*  hidden switch  */
    DO
    debugmine     =  intent  ;
    END

  IF  Inside( 'Q',  infile )  THEN   /*  hidden switch  */
    DO
    CALL Whereami  ;
    END

/*  Stop processing hidden switches here  */

  IF Verify( infile, switches ) > 0  THEN  /*  check for invalid switches  */
    DO
    /*  CALL LineOut  outfile  ;  */
say 'infile=*'infile'*'
say 'switches=*'switches'*'
    infile  =  '-help'  ;
    CALL Help  ;
    END

/*  Start processing regular switches here:  */

  IF  Inside( 'h', infile )  THEN
    DO
    /*  CALL LineOut  outfile  ;  */
    infile  =  '-help'  ;
    CALL Help  ;
    END

  IF  Inside( 'p',  infile )  THEN
    DO
    paragraphing  =  intent  ;
    END

  IF  Inside( 'P',  infile )  THEN
    DO
    paragraphing  =  intent  ;
    bracketparag  =  intent  ;
    END

  IF  Inside( 'k',  infile )  THEN
    DO
    autobreaking  =  intent  ;
    END

  IF  Inside( 'b',  infile )  THEN
    DO
    basichtml     =  intent  ;
    END

  IF  Inside( 's',  infile )  THEN
    DO
    presets       =  intent  ;
    END

  IF  Inside( 'g',  infile )  THEN
    DO
    simpleguide   =  intent  ;
    END

  IF  Inside( 'q',  infile )  THEN
    DO
    CALL How  ;
    EXIT  ;
    END

/*  Stop processing regular switches here:  */


  PARSE VALUE  outfile scratch  WITH  infile outfile  scratch  ;
  infile  =  Strip( infile )  ;

END


/*  Set up I/O  */
SELECT
WHEN  outfile  =  ''  THEN
  outfile  =  STDOUT  ;
WHEN  outfile  =  '-'  THEN
  outfile  =  STDOUT  ;
OTHERWISE
  NOP  ;
END  /*  SELECT  */

SELECT
WHEN  infile  =  ''  THEN
  infile  =  STDIN  ;
WHEN  infile  =  '-'  THEN
  infile  =  STDIN  ;
OTHERWISE
  NOP  ;
END  /*  SELECT  */


IF  debugmine  THEN
  DO
  SAY 'infile is *'infile'*'  ;
  SAY 'outfile is *'outfile'*'  ;
  IF  clonemode  THEN
    SAY 'clonefile is *'clonefile'*'  ;
  END

/*    End of switch command line processing ***********************/

/*****************************************************************/

CALL  DataStructures   ;  /*  VERY Important call here  */

/*****************************************************************/


IF  clonemode  THEN
  CALL  CloneIt  clonefile  ;

/*   Preliminary Steps now complete - Begin generating HTML  */

IF  basichtml  THEN
  CALL  Header  ;

IF  presets  THEN
  CALL LineOut outfile, '<PRE>'  ;

IF  simpleguide  THEN
  CALL  How  ;




/*  Main Processing Loop  */
lastline  =  ''  ;


DO  WHILE  Lines( infile )

/*
See the Function Corrections section below.
See Daney, Lines() is not
generally Boolean
only for OS/2 and Regina
therefore, the test

Also in Regina Lines only seems to work after a read at the
end of the file returns a null string.
Previously, I tried a Blines() function that tried to deal
with this, but some variations of this failed with OS/2,
and also it seemed excessively complex.
So the LineIn() call was moved to the end of the loop,
and then these tests seemed to work fine, were reasonably fast
and fairly simple.

It also seems to be critical if the NOTREADY trap is set or not.

 */

  linethat  =  LineIn( infile )  ;

  linethat  =  Strip( linethat, 'T' )  ;  /*  remove trailing blanks  */

  /*  Here, look at each possibility, and process appropriately  */
  IF  '' >< linethat  THEN
    DO

    /*  Handle the paragraphing here  */
    IF  '' =  lastline THEN
      IF  paragraphing  THEN
        CALL LineOut outfile, '<P>'  ;


    IF  autobreaking  THEN
      linethat  =  linethat  ||  '<BR>'  ;


    END   /*  IF  */
  ELSE
    DO

    /*  Handle the bracketed paragraphing here  */
    IF  '' ><  lastline THEN
      IF  bracketparag  THEN
        CALL LineOut outfile, '</P>'  ;

    END   /*  ELSE  */



  CALL LineOut outfile, linethat  ;
  lastline  =  linethat  ;

END       /*  while  */
/*  SIGNAL  ON  NOTREADY   NAME   Handler  ;  */

/*  Handle the last of bracketed paragraphing here  */
IF  '' ><  lastline THEN
  IF  bracketparag  THEN
    CALL LineOut outfile, '</P>'  ;

IF  presets  THEN
  CALL LineOut outfile, '</PRE>'  ;

IF  basichtml  THEN
  CALL Footer  ;


EXIT

/******************************************************************
*******************************************************************
          END OF MAIN PROGRAM
          START OF SUBROUTINES
*******************************************************************
******************************************************************/



WhoAmI:  PROCEDURE  EXPOSE  (basics)  ;

/*
    Here take care of interpreter specific stuff:
    Borrowing some ideas from Rexxtry ;-)
*/

PARSE version  particular '_'  .

IF 'REXX-Regina'  ==  particular  THEN
  DO
  /*  Some defaults for Regina:   */
  STDIN   =  ''  ;
  STDOUT  =  ''  ;
  STDERR  =  ''  ;
  /*       These are handled where more specificly attributable:
  STDIN   =  '/dev/stdin'  ;
  STDOUT  =  '/dev/stdout'  ;
  STDERR  =  '/dev/stderr'  ;
  /*  Or possibly:
  STDIN   =  '/dev/fd/0'  ;
  STDOUT  =  '/dev/fd/1'  ;
  STDERR  =  '/dev/fd/2'  ;
  */
  */
  END
ELSE
  DO
  STDIN   =  'STDIN:'   ;
  STDOUT  =  'STDOUT:'  ;
  STDERR  =  'STDERR:'  ;
  END

TRUE   =  1  ;
FALSE  =  0  ;
ON     =  TRUE    ;
OFF    =  FALSE   ;
YES    =  TRUE  ;
NO     =  FALSE  ;

environment  =  address()  ;
/* Storing the original environment for future use,
   such as possible retreival of of environmental variables,
   with value()
   Where appropriate below, this should be overridden.
 */

/*  Find out what is being executed!  */
PARSE  SOURCE  os . pgmName  ;

/*
   n will be the end of line character for various OSs for 'here' documents.
   See Help, Header, Footer and How functions for examples.
   clearscreen  will clear the screnn
*/

/*  os  =  Translate( os )  ;  */
PARSE UPPER VAR os  os  ;

SELECT
WHEN  'OS/2'  = os  THEN
  DO
  n  =  '0D 0A'x  ;
  clearscreen  =  'CLS'  ;
  environment  =  'OS2ENVIRONMENT'  ;
  END
WHEN abbrev( os,  'Windows' ) THEN
  DO
  n  =  '0D 0A'x  ;
  clearscreen  =  'CLS'  ;
  END
WHEN  'DOS'  = os  THEN
  DO
  n  =  '0D 0A'x  ;
  clearscreen  =  'CLS'  ;
  END
WHEN  'UNIX'  = os  THEN
  DO
  n  =  '0A'x  ;
  clearscreen  =  'clear'  ;
  STDIN   =  '/dev/stdin'  ;
  STDOUT  =  '/dev/stdout'  ;
  STDERR  =  '/dev/stderr'  ;
  /*  Or possibly:
  STDIN   =  '/dev/fd/0'  ;
  STDOUT  =  '/dev/fd/1'  ;
  STDERR  =  '/dev/fd/2'  ;
  */
  END
WHEN  'LINUX' = os  THEN
  DO
  n  =  '0A'x  ;
  clearscreen  =  'clear'  ;
  STDIN   =  '/dev/stdin'  ;
  STDOUT  =  '/dev/stdout'  ;
  STDERR  =  '/dev/stderr'  ;
  /*  Or possibly:
  STDIN   =  '/dev/fd/0'  ;
  STDOUT  =  '/dev/fd/1'  ;
  STDERR  =  '/dev/fd/2'  ;
  */
  END
WHEN  'AIX'   = os  THEN
  DO
  n  =  '0A'x  ;
  clearscreen  =  'clear'  ;
  STDIN   =  '/dev/stdin'  ;
  STDOUT  =  '/dev/stdout'  ;
  STDERR  =  '/dev/stderr'  ;
  /*  Or possibly:
  STDIN   =  '/dev/fd/0'  ;
  STDOUT  =  '/dev/fd/1'  ;
  STDERR  =  '/dev/fd/2'  ;
  */
  END
WHEN  'CMS'   = os  THEN
  DO
  /* n  =  ' ' || D2C( 10 )  ;  /* Does anyone really know?  */  */
  n  =  ' ' || '85'x      ;  /* According to some UUASC e-list traffic  */
  clearscreen  =  'VMFCLEAR'  ;
  END
WHEN  'MAC'   = os  THEN    /*  and various 8 bit machines :-)  */
  DO
  n  =  '0D'x  ;
  /*  ??? clearscreen  =  'clear'  ;  */
  END
OTHERWISE
  DO
  n  =  '0D 0A'x  ;
  clearscreen  =  'clear'  ;    /*  ?????  */
  END
END  /* SELECT */


/*  where  =  directory()  ;  */
where  =  pgmName  ;

SELECT
WHEN  Inside( '\', where )  THEN
  dirseperator  =  '\'  ;    /*  PC proprietary  */
WHEN  Inside( '/', where )  THEN
  dirseperator  =  '/'  ;   /*   UNIX   */
WHEN  Inside( '.', where )  THEN
  dirseperator  =  '.'  ;    /* some IBM mainframes  */
WHEN  Inside( ':', where )  THEN
  dirseperator  =  ':'  ;    /* some Macs?  */
OTHERWISE
  NOP  ;
END  ;

helptest  =  '-+'  ;
IF ( '/' >< dirseperator )  Then
  helptest  =  helptest'/'  ;

nshadow  =  Translate( n, , n, ' ' )  ;
/* ....for use with record/line oriented functions   */


pgmName  =  Translate( pgmName, '  ', '/\' )  ;  /*  typical dir. seperators */
              /*  Note that this may not work on certain IBM mainframe
                  OSs where '.' is effectively the directory seperator
               */

nameCnt  =  Words( pgmName )  ;   /* count spaced words and  */

pgmName  =  Word( pgmName, nameCnt )  ;  /* get the last one  */

pgmName  =  Translate( pgmName, ' ', '.' )  ;  /*  Now strip extensions  */

PARSE  VAR  pgmName  pgmName  .  ;

RETURN  pgmName  ;




HandlerR:

/*  Type 2 Exception handler - returns to program  */
/*  By default this is inactive in this program, just here
    for possible future use, as needed.
*/
/*  Basicly ripped off of Daney p. 205    */
/*  "Programming in REXX", (c) 1992, Charles Daney,
     J. Ranade IBM Series, McGraw-Hill, Inc.
 */

ttype         =  Condition( 'C' )  ;

IF  'SYNTAX'  =  ttype  THEN
  SAY 'REXX error 'rc' ('errortext( rc )' ) occured in line 'sigl'.'  ;

IF  'ERROR' = ttype  |  'FAILURE' = ttype  THEN
  SAY 'Command return code: 'rc' occured in line 'sigl'.'  ;

IF  SourceLine() > 0  THEN
  SAY  '=====> 'sourceline( sigl )  ;

SAY  'Of 'sourceline()' total lines.'  ;

/*
signal on syntax
signal restart
*/

tdescription  =  Condition( 'D' )  ;
tinstruction  =  Condition( 'I' )  ;
tstate        =  Condition( 'S' )  ;

SAY 'Trap type: 'ttype  ;
SAY 'Trap description: 'tdescription  ;
SAY 'Trap instruction: 'tinstruction ;
SAY 'Trap state: 'tstate  ;

/*  EXIT  ;    /*   HandlerR   */   */
RETURN   ;     /*   HandlerR    */


Handler:

/*  Type 1 Exception handler  - No Return   */
/*  Basicly ripped off of Daney p. 205    */
/*  "Programming in REXX", (c) 1992, Charles Daney,
     J. Ranade IBM Series, McGraw-Hill, Inc.
 */

ttype         =  Condition( 'C' )  ;

IF  'FAILURE' = ttype  THEN
  SAY 'Command return code: 'rc' occured in line 'sigl'.'  ;

IF  SourceLine() > 0  THEN
  SAY  '=====> 'sourceline( sigl )  ;

SAY  'Of 'sourceline()' total lines.'  ;

/*
signal on syntax
signal restart
*/

tdescription  =  Condition( 'D' )  ;
tinstruction  =  Condition( 'I' )  ;
tstate        =  Condition( 'S' )  ;

SAY 'Trap type: 'ttype  ;
SAY 'Trap description: 'tdescription  ;
SAY 'Trap instruction: 'tinstruction ;
SAY 'Trap state: 'tstate  ;

EXIT  ;    /*   Handler   */




Whereami:  PROCEDURE  EXPOSE  (basics)   ;


/*  Here take care of interpreter specific stuff:  */
/*  Borrowing some ideas from Rexxtry ;-)  */

PARSE VERSION  version  ;

PARSE  SOURCE  source  ;

clearscreen  ;

SAY  ,
''n,
version n,
''n,
source n,
''n  ;            /*  end of 'HERE' document  */

EXIT  ;


RETURN  ;


/*
Lowercase:

PARSE ARG casetarget  ;

  casegoal  =  Translate( casetarget, lowers, uppers )  ;
                           / *  ( string, to, from )    * /

return casegoal  ;

EXIT  ;
*/




Inside:   Procedure  ;

/*  This returns a TRUE / FALSE value if string 'letter'
    is inside ( a substring ) of string 'string'.
    It is used mainly for processing command line switches.
    It uses the same 'needle' in 'haystack' ordering
    of parameters as ReXX's Pos command.
*/

/*
PARSE ARG  letter, string  ;

RETURN  Pos( letter, string )  >  0  ;

New style:  */

PARSE ARG  needle,  haystack  =1  subhaystack (needle) .  ;

RETURN  subhaystack << haystack  ;


GetOpts:
PROCEDURE   EXPOSE  infile  intent optarg  (basics)  ;

PARSE ARG   optclump  ;

/*  a default value:  */
optarg  =  ''  ;
intent  =  OFF  ;
IF  1 >< Verify( optclump, helptest, 'M', 1 )  THEN
  RETURN OFF  ;


cutpoint  =  Verify( optclump, ':=', 'M', 1 )  ;
IF 0 < cutpoint  THEN
  PARSE VAR optclump   optclump  =(cutpoint) . +1  optarg  ;

SELECT
WHEN  '' = optclump  THEN
  RETURN OFF  ;
WHEN  Abbrev( optclump, '-', 1 )  THEN
  DO
  intent  =  ON  ;
  infile    =  optclump  ;
  END  ;
WHEN  Abbrev( optclump, '+', 1 )  THEN
  DO
  intent  =  OFF  ;
  infile    =  optclump  ;
  END  ;
WHEN  ( Abbrev( optclump, '/', 1 )  & ( '/' >< dirseperator ) )  THEN
  DO
  intent  =  ON  ;
  infile    =  optclump  ;
  END  ;
OTHERWISE
  RETURN  OFF  ;
END  ;


RETURN  ON  ;




Help:  PROCEDURE  EXPOSE  USAGE  infile (basics)  ;
/*  Be flexible accepting help  */


rescueCry  =  Translate( infile, '-', '/' )  ;
                           /*  Translate( string, to, from )  */
rescueCry   =  Strip( rescueCry, 'L', '-' )  ;

PARSE UPPER VAR rescueCry  =1 rescueCry  =5 .  ;

rescueCry = Strip( rescueCry )  ;



IF  Abbrev( 'HELP', rescueCry, 1 ) | ,
    Abbrev( 'HHHH', rescueCry, 1 ) | ,
    Abbrev( '????', rescueCry, 1 )
THEN
  DO

  /*
  clearscreen  ;
  */

  CALL  LineOut  STDERR,  ,
  USAGE n,
  ''n,
  ' 'myself', a simple tool to aid converting flat text to HTML.'n,
  '   Typical use: 'myself' -pkC cloned.html < input.txt  >  output.htm'n,
  '   Switches:'n,
  '    -h  -  Help (this) message'n,
  '           Boilerplating:'n,
  '    -p  -  Auto paragraphing (<P>)'n,
  '    -P  -  Auto bracketed paragraphing (<P>...</P>)'n,
  '    -k  -  Auto break all lines of text (<BR>)'n,
  '    -b  -  Frame output with basic HTML header/footer tags'n,
  '    -C  -  Clone header/footer from another file'n,
  '    -s  -  Frame output with Preset tags(<PRESET>...</PRESET>)'n,
  '           Training wheels for HTML newbies:'n,
  '    -g  -  Include HTML quick reference in document as a comment'n,
  '    -q  -  Print HTML quick reference.',
      ;   /*  end of 'Here' document  */


  EXIT  ;

  END  /*  IF  */


RETURN  ;


Header:  PROCEDURE  EXPOSE  outfile n  headplate ;

/*  HTML header boiler plate.
    Researched colors for best color-blindness
    mix according to suggestions.
    This was done on request of one viewer who had
    trouble.
    Although they seem to present trouble when projected
    some of the letter colors seem hard for normal veiwers
    to see.

    This section could easily be customized if you need
    some standard heading frequently.
*/

CALL LineOut  outfile,  headplate  ;

RETURN  ;

Footer:  PROCEDURE  EXPOSE  outfile  n  bracketparag footplate  ;

/*  Generate HTML footer boilerplate.

    This section could easily be customized if you need
    some standard footer frequently.
*/

CALL  LineOut  outfile,  footplate  ;


RETURN  ;

How:  PROCEDURE  EXPOSE  outfile n  ;

/*  To dump out a quick guide to basic HTML for newbies like me  */

/*  This section is intended for cut and paste use
    after injecting it into a file for a project.
    When completed you can delete it,
    though if left in in simply slows down the
    page retreival, and consumes extra memory in the browser.
*/

   /*  <body bgcolor="#" text="#" link="#" vlink="#">  */

CALL LineOut outfile, ,
''n,
'<!--   - Begining of comment block.                                     --'n,
''n,
'--      ** A Simple Guide to HTML **                                    --'n,
''n,
'--      Relative Type Styles:                                           --'n,
'--        <H1>Heading Level 1 (These 6)</H1>                            --'n,
'--        <H2>Heading Level 2 (auto para. break)</H2>                   --'n,
'--        <H3>Heading Level 3 (after they end</H3>                      --'n,
'--        <H4>Heading Level 4 (these last 3)</H4>                       --'n,
'--        <H5>Heading Level 5 (are not)</H5>                            --'n,
'--        <H6>Heading Level 6 (recommended)</H6>                        --'n,
'--        <ADDRESS>email, phone#s,                                      --'n,
'--             postal address,                                          --'n,
'--             often italics</ADDRESS>                                  --'n,
'--        <EM>Emphasis,                                                 --'n,
'--             often bold or italic</EM>                                --'n,
'--        <STRONG>often bold or italic</STRONG>                         --'n,
'--        <CODE>monospaced font often Courier</CODE>                    --'n,
'--        <SAMP>Sample, like CODE</SAMP>                                --'n,
'--        <KBD>Keyboard, like CODE</KBD>                                --'n,
'--        <CITE>Citation , usually italic</CITE>                        --'n,
''n,
'--      Fixed Type Styles:                                              --'n,
'--        <B>Bold</B>                                                   --'n,
'--        <I>Italic</I>                                                 --'n,
'--        <U>Underscore</U>                                             --'n,
'--        <TT>Tupewriter</TT>                                           --'n,
''n,
'--      Breaks:                                                         --'n,
'--        Line of text<BR>                                              --'n,
'--        <P>Start of paragraph                                         --'n,
'--        End of paragraph</P>                                          --'n,
''n,
'--      <BLOCKQUOTE>                                                    --'n,
'--        This will indent text.<BR>                                    --'n,
'--        <P>But still recongnizes the Breaks<BR>                       --'n,
'--      </BLOCKQUOTE>                                                   --'n,
''n,
'--       Dividing rule (horizontal line across screen):                 --'n,
'--       <HR>                                                           --'n,
''n,
'--       <OL>                                                           --'n,
'--       <LI> Ordered list                                              --'n,
'--       <LI> Automaticly numbered                                      --'n,
'--       </OL>                                                          --'n,
''n,
'--       <UL>                                                           --'n,
'--       <LI> Unordered list                                            --'n,
'--       <LI> Automaticly bulleted                                      --'n,
'--       </UL>                                                          --'n,
''n,
'--       <PRE>                                                          --'n,
'--          Put preformatted                                            --'n,
'--          text in these tags                                          --'n,
'--       </PRE>                                                         --'n,
''n,
'--       <DL>                                                           --'n,
'--       <DT>Definition List                                            --'n,
'--       <DD>This is ideal for                                          --'n,
'--       lists of definitions                                           --'n,
'--       <DT>Some other term                                            --'n,
'--       <DD>could be defined                                           --'n,
'--       as the second item in this definition list                     --'n,
'--       <DT>Named Entity                                               --'n,
'--       <DD> &<name>;                                                  --'n,
'--       A type of Special or Reserved Character;                       --'n,
'--       <DT>Numbered Entity                                            --'n,
'--       <DD> &#<ascii code here>;                                      --'n,
'--       A type of Special or Reserved Character;                       --'n,
'--       </DL>                                                          --'n,
''n,
'--      Links:                                                          --'n,
''n,
'--        <A HREF="Path/file.html">Click here for text file.</A>        --'n,
'--        <A HREF="Path/file.html"><IMG SRC="clickfortextfile.gif"></A> --'n,
'--        <A HREF="Path/file.html"><IMG SRC="clickfortextfile.gif"      --'n,
'--           ALT="[Tell Lynx/W3M User image is here]"></A>              --'n,
'--        <A HREF="#XMARKS">Link within document</A>                    --'n,
'--            <A NAME="XMARKS">X Marks the spot</A>                     --'n,
'--        <IMG SRC="Imagetosee.gif">                                    --'n,
'--        <IMG ALIGN=top SRC="Pic2C.gif">Align2text                     --'n,
'--        <IMG ALIGN=middle SRC="Pic2C.gif">Align2text                  --'n,
'--        <IMG ALIGN=bottom SRC="Pic2C.gif">Align2text                  --'n,
''n,
'--      <A HREF="SoundRvideo.mpg">TagTitle(format, #k</A>               --'n,
''n,
'--      Image Maps:                                                     --'n,
''n,
'--      <A HREF="../cgi-bin/imagemap/script.map">                       --'n,
'--        <IMG SRC="Imagetosee.gif" ISMAP></A>                          --'n,
'--        CERN Standard:                                                --'n,
'--        polygon (150,46) (193,46) (146,93) (46,93)                    --'n,
'--        http://myDomain/myfolder/top.html                              --'n,
'--        NCSA Standard:                                                --'n,
'--        polygon http://myDomain/myfolder/top.html                      --'n,
'--        150,46 193,46 146,93 46,93                                    --'n,
''n,
'--      Forms:                                                          --'n,
''n,
'--        <FORM METHOD="POST" ACTION="/bin/who">                        --'n,
'--        Name:<input type="text" size=40 name="Name">                  --'n,
'--        <input type="text" size="20" name="Name" maxlength="10"       --'n,
'--          value="Last name">                                          --'n,
'--        <input type="password" size="20" name="pass" maxlength="5">   --'n,
'--        <UL>                                                          --'n,
'--        <input type="radio" name="card" value="Visa"checked>Visa<BR>  --'n,
'--        <input type="radio" name="card" value="MC">MasterCard<BR>     --'n,
'--        <input type="radio" name="card" value="AmEx">Am. Express<BR>  --'n,
'--        </UL>                                                         --'n,
'--        <UL>                                                          --'n,
'--        <input type="checkbx" name="Bk1" value="Yes"checked>Book 1<BR>--'n,
'--        <input type="checkbx" name="Bk2" value="Yes">Book 2<BR>       --'n,
'--        <input type="checkbx" name="Bk3" value="Yes">Book 3<BR>       --'n,
'--        </UL>                                                         --'n,
'--        <select name="level">                                         --'n,
'--        <option>Beginner                                              --'n,
'--        <option selected>Intermediate                                 --'n,
'--        <option>Expert                                                --'n,
'--        </select>                                                     --'n,
'--        <select multiple name="tests" size="3">                       --'n,
'--        <option>History                                               --'n,
'--        <option selected>Math                                         --'n,
'--        <option>English                                               --'n,
'--        <option>Science                                               --'n,
'--        </select>                                                     --'n,
'--        <input type=submit value="Submit">                            --'n,
'--        <input type=reset value="Clear">                              --'n,
'--        </FORM>                                                       --'n,
''n,
'--      Ending of comment block:                                        -->'n,
''  ;    /*  End of Here   */

/*  And so on..........       */



RETURN  ;

/****************************************************************/
/*    Function Corrections **************************************/
/*    Uncomment as appropriate  *********************************/
/****************************************************************/

/*  */
/*  For OS/2, AS400, and somtimes Regina:  */
Lines:
PROCEDURE   ;

PARSE ARG  infile  ;

RETURN  0 < 'LINES'( infile )  ;
/* These calls to the built-in functions must be in upper case.  */

/*  END OS/2, AS400 special function defs.  */
/*  */

/*
/*  Sometimes needed for Regina if lines() acts up:  */
Lines:
PROCEDURE  EXPOSE  (basics)  ;

PARSE ARG  infile  ;

hiddenstuff.infile.line  =  'LINEIN'( infile )  ;
/* These calls to the built-in functions must be in upper case.  */

IF  '' == hiddenstuff.infile.line  THEN
  IF  0 = 'LINES'( infile )  THEN
/* These calls to the built-in functions must be in upper case.  */
    RETURN  FALSE  ;

RETURN  TRUE  ;

LineIn:
PROCEDURE  EXPOSE  (basics)  ;

PARSE ARG  infile  ;


RETURN  hiddenstuff.infile.line  ;

/*  End Regina special function defs.  */
*/


CloneIt:

PROCEDURE  EXPOSE (basics)  headplate footplate  ;

PARSE ARG  clonefile  ;

/*  First, analyze the file name:   */
PARSE VAR clonefile    =1 firstchar =2 secondchar  =3  .  ,
               =1          firsttwo  =3  .   ,
               =1        firstthree  =4  .   ;

/*  ... and get a working directory in a standard format:  */
wd  =  Directory()  ;   /*  Working Directory  */
wd  =  Strip( wd, 'T', dirseperator )  ;

/*  Now, get the name of the Clone file, that the
    header and footer will be copied from,
    in as standard a format as possible:
*/
SELECT
/*  FQN  ==  Fully Qualified Name  (full path name)  */
WHEN  firstchar = dirseperator  THEN
   /*  filename is reasonably close to an absolute FQN  */
   DO
   PARSE VAR wd  wdchar1 =2 wdchar2 =3  .  ,
           =1   wd2char  =3  .    ;
   IF  ':' = wdchar2  THEN
      clonefile  =  wd2char || clonefile  ;
   END
WHEN  secondchar = ':'  &  dirseperator = '\'  THEN
   NOP  ;   /*   filename is reasonably close to PC/Proprietary FQN  */
WHEN  '.'dirseperator = firsttwo  THEN
  DO
  clonefile  =  Strip( clonefile, 'L', '.' )  ;
  clonefile  =  Strip( clonefile, 'L', dirseperator )  ;
  clonefile  =  wd || dirseperator || clonefile  ;
  END
WHEN  '..'dirseperator = firstthree  THEN
  DO
  clonefile  =  Strip( clonefile, 'L', '.' )  ;
  clonefile  =  Strip( clonefile, 'L', dirseperator )  ;
  clippoint  =  LastPos( dirseperator, wd )  ;
  PARSE VAR wd  wd =(clippoint)  .  ;
  clonefile  =  wd || dirseperator || clonefile  ;
  END
WHEN  '~/' = firsttwo  THEN   /*  UNIX shell land  */
  DO
  PARSE VAR clonefile   '~/' clonefile  ;
  td  =  Value( 'HOME', , environment ) ;
  td  =  Strip( tc, 'T', dirseperator )  ;
  clonefile  =  td || dirseperator || clonefile  ;
  END
OTHERWISE    /* It's just a plain file name.  */
  clonefile  =  wd || dirseperator || clonefile  ;
END  ;

/*  Finished analyzing file name.  (At last!)  */

fstatus  =  Stream( clonefile, 'C', 'READ' )  ;
IF 'NOTREADY' == fstatus  THEN
  DO
  SAY  'File 'clonefile' is not ready for cloning.'  ;
  EXIT  ;
  END  ;

examplehtml  =  ''  ;
DO    UNTIL '' = chunk
  chunk  =  CharIn( clonefile, , 14336 )
  examplehtml  =  examplehtml  ||  chunk  ;
END  ;

fstatus  =  Stream( clonefile, 'C', 'CLOSE' )  ;

/*
<!-- *** EOH *** ... -->
<!-- *** SOF *** ... -->
*/
/*  for auto processing, that is running this program through itself:  */
eoh  =  ' <!-- *** EOH ***'  ;
sof  =  ' <!-- *** SOF ***'  ;

PARSE VAR examplehtml  . (eoh) . '-->'  fatchunk  ,
                   =1  headplate  (fatchunk)    ;
/*   -- allowing as much variability as practicle in the header
        boilerplate marker.
 */

if  headplate \<< examplehtml  THEN
  DO
  SAY 'Something is wrong with the examplefile:' clonefile  ;
  EXIT  ;
  END  ;

/*  Note: for the header, could search for end of '</Hx'
          (x = 1-6 etc.), the first heading, seems to be a good
          key for locating the end of boilerplate,
          doing the same for the footer seems hopeless.
          so to maintain symmetry, I require a special marker
          to delimit both.
 */

PARSE VAR examplehtml  fatchunk  (sof) . '-->'  .  ,
                =1     (fatchunk)  footplate  ;
/*  -- Again, trying to allow as much variation as possible, while
       keeping things reasonably simple.
 */
if  footplate \<< examplehtml  THEN
  DO
  SAY 'Something is wrong with the examplefile:' clonefile  ;
  EXIT  ;
  END  ;


headplate  =  headplate || n || n  ;
footplate  =  n || n || footplate  ;


RETURN  ;


/****************************************************************/
/*    Initialize Data *********************************/
/****************************************************************/

DataStructures:   /*  PROCEDURE   ......not!   */

/* What would be known in FORTRAN as the BLOCK DATA   */
/*    or was that DATA BLOCK?  Been a long time ago...... */



/*  lowers  =  Xrange( 'a', 'z' )  ;  */
/*  uppers  =  Xrange( 'A', 'Z' )  ;  */
/*
/*  See  Daney p.xxx  -  This is portable across ASCII to EBCIDC:  */
lowers  =  Xrange( 'a', 'i' ) || Xrange( 'j', 'r') || Xrange( 's', 'z' )  ;
/*  uppers  =  Translate( lowers )  ;  */
/*  Faster:  */
PARSE UPPERS VAR lowers  uppers  ;
*/


headplate  =  ,
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'n,
'<!-- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"> -->'n,
''n,
'<HTML>'n,
''n,
'<HEAD>'n,
''n,
'<BASE HREF="http://zzz.baseURL.INVALID/">'n,
''n,
'<META HTTP-EQUIV="Refresh"'n,
'  CONTENT="0; URL=http://zzz.redirct2URL.INVALID/">'n,
'<META HTTP-EQUIV="Content-Type"'n,
'  CONTENT="text/html; charset=iso-8859-1">'n,
'<META NAME="GENERATOR" 'n,
'  CONTENT="Lynx/2.8.3 [en] (X11; U; SunOS 5.5 sun4m) [Netscape]">'n,
'<META NAME="Author" CONTENT="Dallas E. Legan">'n,
'<META NAME="Description" CONTENT="WWW page I am writing">'n,
'<META NAME="Keywords" CONTENT="word list you want to be searched on">'n,
''n,
'<TITLE>'n,
'Text You Want to Appear in Title Bar of the Browser'n,
'</TITLE>'n,
''n,
'</HEAD>'n,
''n,
'<BODY TEXT="black" BGCOLOR="white" LINK="blue" 'n,
'   VLINK="yellow" ALINK="gray" >'n,
''n,
''n,
'<H1>'n,
'Put the First Level Heading Here'n,
'</H1>'n,
''n,
''n,
'<!-- *** EOH *** txt2html End Of Header Cloning label -->'n ;
          /*  end of 'HERE'  document  */

/*  EOH == END of Header  */

footplate  =  ,
''n,
''n,
'<!-- *** SOF *** txt2html Start Of Footer Cloning label -->'n,
''n,
''n,
'<P>'n,
'<A HREF="Previous.html">Previous Page</A>'n,
'<A HREF="Next.html">Next Page</A>'n,
'<A HREF="Home.html">Home Page</A>'n  ;

IF  bracketparag  THEN
  footplate  =  footplate || ' </P>'n  ;

footplate  =  footplate ||  ,
''n,
'<P>'n,
' <A HREF="mailto:aw585@lafn.org">mailto:aw585@lafn.org</A>'n,
''n,
' <P>'n,
'   <A HREF="HTTP://VALIDATOR.W3.ORG/CHECK/REFERER"><IMG BORDER="0"'n,
'       SRC="HTTP://WWW.W3.ORG/iCONS/VALID-HTML401"'n,
'       ALT="Valid HTML 4.01!" height="31" width="88"></A>'n  ;

IF  bracketparag  THEN
  footplate  =  footplate || ' </P>'n  ;

footplate  =  footplate ||  ,
''n,
'</BODY>'n,
''n,
'</HTML>'  ;    /*  End of 'HERE' document  */


RETURN  ;

Dallas E. Legan

mailto:aw585@lafn.org

Valid HTML 4.01!