#!/usr/local/bin/kermit + # # Converts a plain text file to HTML. # Handles paragraphs and single-level numbered and bullet lists. # Works best with block-style text. # # F. da Cruz, Columbia University, Jan 2004. # Requires C-Kermit 8.0 or Kermit 95 2.1. # Last update: Mon Jan 12 10:34:50 2004 # # Usage: # html.ksc inputfilename [ "title" ] # # Illustrates: # . File i/o # . String functions # . Modularization # # Assumes: # . Bullet or numbered list items are indented by at least one space. # . Bullet characters can be "." "-" "+" "o". # . Numbered lists are numbered 1, 2, 3, ... 99. # . A list is terminated by a line that is not indented. # . If first text line is followed by a blank line it is to be the title. # # Paragraphs are separated by blank lines. Some attempt is made to also # handle paragraphs marked by indentation alone, but these don't mix well # with lists. # # Does not handle: # . multilevel lists # . description lists # . ordered lists numbered with anything but consecutive numbers # . blockquotes # . preformatted text # . tables, etc # . headings within the text # . anchors and links # . email (add an otion to handle mail headers) # # Result file will need some hand-tuning if it contains any of the # elements listed just above. define badversion echo C-Kermit 8.0 or K95 2.0 required, exit if LLT \v(version) 80000 badversion if not def \%1 exit 1 "Usage: \%0 filename [ title ]" # Open input and output files fopen /read \%i \%1 # Input file if fail exit 1 .oname := \fstripx(\fcontents(\%1)).html # Name of output file fopen /write \%o \m(oname) # Try to open it if fail exit 1 # Major states: # 0 start # 1 in a paragraph # 2 between paragraphs .state = 0 # State .\%n = 0 # Input line count .oldlen = 0 # Length of previous output line .inol = 0 # In ordered list .inul = 0 # In unordered list .cset = utf-8 # Change if necessary # Macro Definitions... def putout { # File output routine local out # Avoids consecutive blank lines .out := \fcontents(\%1) .\%9 := \flen(\m(out)) if ( == \%9 0 && == \m(oldlen) 0 ) end 0 fwrite /line \%o \m(out) if fail exit 1 "FILE WRITE ERROR: \m(oname)" .oldlen := \%9 } def getline { # Read input line .prev := \m(line) # with lookahead and lookback .line := \m(next) undef next fread /line \%i next if fail end 1 incr \%n asg next \freplace(\ftrim(\m(next)),\9,\32) } def putback { # "Rewind" the current record .next := \m(line) # (works only once for any given line) .line := \m(prev) undef prev } def putline { # Write current data line local bullet .out := \freplace(\m(line),&,&) .out := \freplace(\m(out),<,<) .out := \freplace(\m(out),>,>) .tmp := \fltrim(\m(out)) if not def tmp { putout, end 0 } .bullet = 0 .number = 0 if ( equal "\s(out[1:1])" "\32" ) { # Line starts with blank if ( eq "\s(tmp[2:1])" "\32" ) { # Unordered list item? .\%9 := \fleft(\m(tmp),1) # Bullet candidate if \findex(\%9,.-+o) { # If valid bullet character .bullet = 1 # It's a bullet item if not \m(inul) { # If new list start it. putout "" # If in unordered list close it. putout "

" putout .inul := 0 } else if \m(inol) { putout "" # If in ordered list close it. putout "

" putout .inol := 0 } if \m(bullet) { # This line has bullet .out :=

  • \s(tmp[3]) } else if \m(number) { # This line has a number .\%9 := \findex(.\32,\m(tmp)) .out :=
  • \s(tmp[\%9+2]) } else if \m(inul) { # Continuation line of list item .out := \m(tmp) } else if \m(inol) { # Ditto .out := \m(tmp) } else if ( > \flen(\m(tmp)) 8 && == 0 \fverify(-,\m(tmp)) ) { # Rule .out = "
    " } putout "\m(out)" } def dump { # For debugging echo DUMP \%1: echo PREV=[\m(prev)] echo LINE=[\m(line)] echo NEXT=[\m(next)] echo n=\%n } # Begin actions putout {} putout "" while not def line { # Get first nonblank line getline if fail break } getline # Get line after first nonblank line if not def \%2 { # No Title given if ( def prev && not def line ) { # If top line followed by blank line .\%2 := \m(prev) # use it as the title getline # and read another line } else { # Otherwise .\%2 = "Untitled" # use "Untitled" putback # and put this line back } } else { # Title given on command line putback # Save this line for next time } # Write rest of prolog... putout "\%2" putout {} putout "" putout {} putout "

    \%2

    " putout .first = 1 # Start loop with first = 1 while true { # Loop for each line in file. if not \m(first) { # Get next line if not first trip. getline if fail break } .first = 0 if ( > \%n 1 && not \flen(\m(line)) ) { # Blank line if ( == \m(state) 2 ) continue # Ignore extra ones if ( \m(inul) || \m(inol) ) { # Watch out for end of list if not eq "\fleft(\m(next),1)" "\32" continue } putout # Emit paragraph separator. putout "

    " putout .state = 2 # State becomes "between paragraphs" continue } else if ( eq "\fleft(\m(line),1)" "\32" ) { # Line is indented .\%8 := \fcode(\m(prev)) # Check previous and next lines if not def \%8 .\%8 = 32 .\%9 := \fcode(\m(next)) if not def \%9 .\%9 = 32 if ( > \%8 32 && > \%9 32 ) { # Previous and next line not indented putout # So this is a new paragraph putout "

    " # but not separated by blank lines. putout } } .state = 1 # State become "in paragraph" if \%n putline # If we have a line write it out } if > \%n 0 { # Last lookahead line (if any) putline putout putout "

    " } putout "


    " # Write out the epilog putout "
    " putout "\m(oname): \v(date) \v(time)" putout "
    " putout "" fclose \%i # And close the files fclose \%o exit