WBT2HTML v3.13
Download: WBT2HTML v3.13 and more as zip package
;==========================================================================================================================================
; WBT2HTML v3.13b  20110327
;==========================================================================================================================================
; This WinBatch script converts a WinBatch script to syntax coloured HTML output.
;
; Read Changelog at end of file.
; Read Inifile section [USERINFO] for explanations of the options.
;
; (c)Detlev Dalitz.20010729/20110327.
;==========================================================================================================================================


;==========================================================================================================================================
:Main
;------------------------------------------------------------------------------------------------------------------------------------------
IntControl (73, 1, 0, 0, 0)    ; On Error Goto Label :WBERRORHANDLER
IntControl (12, 5, 0, 0, 0)    ; Terminate silently.
IntControl (50, 0, 0, 0, 0)    ; Remove "Go to web page" button from error boxes.
IntControl (53, 1, 0, 0, 0)    ; Set line terminator for FileWrite. p1: 0=None, 1=@CRLF, 2=@LF, 3=@CR, 4=@TAB.
IntControl (65, 8192, 0, 0, 0) ; Set size of internal FileRead buffer, affects subsequent FileOpen commands.
IntControl (1000, 1, 0, 0, 0)  ; Preset exit code different from zero in case of cancelling.

strFolderStart = DirGet ()
DirChange (DirScript ())

GoSub CheckProgVersions
GoSub DefineUDF
GoSub CheckProgIni

arrFIO = udfGetParams (strAppIni)  ; Get input and output filenames.
If arrFIO[0] == "" Then Goto CANCEL

strFolderTemp = udfGetTempFolder () ; Get temp folder.
If strFolderTemp == "" Then Goto CANCEL

strFolderLog = udfGetLogFolder (strFolderTemp, strAppProduct) ; Get log folder.
If strFolderLog == "" Then Goto CANCEL

strFileTmp = strFolderTemp : strAppProduct : "." : udfGetGUID () : ".txt" ; ; Create temporary unique filename.

If OptVerbose
   WinPlaceSet (@NORMAL, "", OptWinPlaceSetBox)   ; For example "100 100 800 300".
   BoxOpen (strAppLogoLong, "")
   BoxColor (1, "248,248,248", 0)
   BoxDataTag (1, 1)
Else
   WinPlaceSet (@NORMAL, "", OptWinPlaceSetTitle) ; For example "000 000 800 000".
   WinActivate ("")
EndIf

GoSub WriteLog
GoSub LoadTableKeywords
GoSub CreateTableColors
GoSub ConvertSourceFile
If OptLineNumberLen Then GoSub AddLineNumber
GoSub WriteLog
GoSub DefineHtmlMasks
GoSub CreateWriteTargetFile

If OptVerbose
   strMsgText = udfPathFold (arrFIO[1], OptPathFold) : @LF : "Ready."
   BoxText (strMsgText)
EndIf

If OptHtmlToClipboard Then GoSub PutHtmlToClipboard

If OptRunOutput
   If FileSizeEx (arrFIO[1]) > 0
      ShellExecute (arrFIO[1], "", "", @NORMAL, "") ; Run standard browser application.
      TimeDelay (3) ; Give browser some time to load the file.
   EndIf
EndIf

IntControl (1000, 0, 0, 0, 0) ; Set exit code to zero, which is to say, all has been done right.

:CANCEL
If IsDefined (strFileTmp) Then If FileExist (strFileTmp) == 1 Then FileDelete (strFileTmp)
If IsDefined (OptVerbose) Then If OptVerbose Then BoxShut ()
DirChange (strFolderStart)
Exit
;==========================================================================================================================================



;==========================================================================================================================================
:CheckProgVersions
;------------------------------------------------------------------------------------------------------------------------------------------
; Current script version.
strAppProduct = "WBT2HTML"
strAppVersion = "3.13"
strAppVersionDate = "20110327"

; Needed WinBatch version.
strWBVersionMin = "2011A"
strWBVersionDLLMin = "6.11aka"
strWBVersionDateMin = "WB 2011A Jan 18 2011"

WinTitle ("", strAppProduct)

; Notify the user to make sure to have a proper WinBatch version, because of the newly introduced array functions.
Terminate (Version () < strWBVersionMin, strAppProduct : " v" : strAppVersion : " - Terminate", "This WinBatch script needs minimum WinBatch version '" : strWBVersionMin : "'.")

Drop (strWBVersionMin, strWBVersionDLLMin, strWBVersionDateMin)
Return
;==========================================================================================================================================



;==========================================================================================================================================
:DefineUDF
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetColorValue (arrColors, strColorName)
If strColorName == "" Then strColorName = "Default Text"
intRow = ArraySearch (arrColors, strColorname, 3) ; Binary search option 3 needs the array to be sorted.
If intRow != -1 Then Return arrColors[intRow, 1]
Pause (strAppProduct : " - Warning - udfGetColorValue", "Cannot find color value in Color Table for color name:" : @LF : '"' : strColorName : '"' : @LF : @LF : "Check color setting in Ini-File.")
Return "#000000"
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfPathFold (strString, blnOpt)
If blnOpt Then Return StrReplace (strString, "\", "\" : @LF) : @LF
Return strString : @LF
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfItemPut (strItem, strList, strDelimiter)
If !ItemLocate (strItem, strList, strDelimiter) Then strList = ItemInsert (strItem, -1, strList, strDelimiter)
Return strList
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfPathNameLong (strPath)
If DirExist (strPath) Then Return FileNameLong (strPath : ".") : "\"
Return FileNameLong (strPath)
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetGUID ()
intBBSizeHex = 16
hdlBB = BinaryAlloc (intBBSizeHex)
BinaryEodSet (hdlBB, intBBSizeHex)
DllCall (DirWindows (1) : "OLE32.DLL", long : "CoCreateGuid", lpbinary : hdlBB)
strGUIDHex = BinaryPeekHex (hdlBB, 0, intBBSizeHex)
hdlBB = BinaryFree (hdlBB)
Return strGUIDHex
;..........................................................................................................................................
; Returns a 128-bit-GUID as a string of 16 hex values, i. e. 32 ansi chars, e. g. "402380BC5856214AA956C7EE6D4A084A".
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetPathToWilKeywords ()
strFileWilKeywords = "WIL.CLR" ; Default.
strRegKeySub = "Software\Wilson WindowWare\WinBatch Studio\Settings\File types\WIL Files"
If RegExistKey (@REGCURRENT, strRegKeySub)
   hdlRegKey = RegOpenKeyEx (@REGCURRENT, strRegKeySub, 1, "", "") ; Mode=1=KEY_QUERY_VALUE=Permission to query subkey data ; We only need read access.
   strRegKeySub = "[Keywords]"
   If RegExistValue (hdlRegKey, strRegKeySub) Then strFileWilKeywords = RegQueryStr (hdlRegKey, strRegKeySub)
   RegCloseKey (hdlRegKey)
EndIf
If FilePath (strFileWilKeywords) != "" Then Return strFileWilKeywords ; Just for the case, if there is already a full filepath.

strRegKeySub = "Software\Wilson WindowWare\WinBatch\CurrentVersion"
If RegExistKey (@REGMACHINE, strRegKeySub)
   hdlRegKey = RegOpenKeyEx (@REGMACHINE, strRegKeySub, 1, "", "") ; Mode=1=KEY_QUERY_VALUE=Permission to query subkey data ; We only need read access.
   If RegExistValue (hdlRegKey, "") Then strDirHome = RegQueryStr (hdlRegKey, "")
   RegCloseKey (hdlRegKey)
EndIf
strDirHome = strDirHome : StrSub ("\", StrSub (strDirHome, StrLen (strDirHome), 1) != "\", 1) : "System\" ; Check Backslash delimiter for sure.
Return strDirHome : strFileWilKeywords
;..........................................................................................................................................
; This UDF "udfGetFileWilClr" extracts from the registry the current filename of WinBatch Studio's keyword file for WIL files.
; The return value is the full filepath to the keyword file, usually it is the same as 'DirHome() : "WIL.CLR"'.
;
; (c)Detlev Dalitz.20110301.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfAskYesNo (strAYN_Title, strAYN_Question)
Return AskYesNo (strAYN_Title, strAYN_Question)
:CANCEL
Return -1 ; Return integer -1 if Dialog has been cancelled resp. closed by escape key.
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------------------
#DefineFunction udfAskFileName (strAFN_Title, strAFN_Folder, strAFN_Filetypes, strAFN_DefaultMask, intAFN_Flag)
Return AskFilename (strAFN_Title, strAFN_Folder, strAFN_Filetypes, strAFN_DefaultMask, intAFN_Flag)
:CANCEL
Return "" ; Return empty string if Dialog has been cancelled resp. closed by escape key.
#EndFunction
;----------------------------------------------------------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------------------
#DefineFunction udfAskDirectory (strAD_Prompt, strAD_FolderRoot, strAD_FolderStart, strAD_PromptConfirm, intAD_flags)
Return AskDirectory (strAD_Prompt, strAD_FolderRoot, strAD_FolderStart, strAD_PromptConfirm, intAD_flags)
:CANCEL
Return "" ; Return empty string if Dialog has been cancelled resp. closed by escape key.
;..........................................................................................................................................
; intAD_flags (combined using the binary OR "|" operator, or 0 if none are desired).
;  0 ... None of the following apply.
;  1 ... Display an edit field in the dialog box, in which the user can type the name of a directory which may or may not exist. This name will be relative to the currently selected directory name in the browse list.
;  2 ... If the user types a name in the edit field (see flag #1), of a directory which does not exist, this flag causes a confirmation message box to be displayed, showing the name of the directory that would be returned by the function, and containing three buttons: Yes, No, and Cancel.
;        If the user selects 'Yes', the function returns. If the user selects 'No', the directory browse dialog remains displayed, and the user can re-edit the name or select a different directory. 'Cancel' causes the function to return, and standard WIL ":cancel" processing to be performed.
;  4 ... Use the new user interface. Setting this flag provides the user with a larger dialog box that can be resized. The dialog box has several new capabilities including: drag and drop capability within the dialog box, shortcut menus, new folders, delete, and other shortcut menu commands.
;  8 ... Do not include the "New Folder" button in the browse dialog box.
;        NOTE: This is supported only in Windows XP or newer. In older versions of Windows, this flag is ignored.
; 16 ... Suppress "Drive not ready" errors.
;..........................................................................................................................................
#EndFunction
;----------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetParams (strAppIni)
; The function returns a dim-1 array with two elements.
; In case of success both elements hold valid filenames, A[0] = strFileIn, A[1] = strFileOut.
; In case of failure both elements are empty.
; The last used strFileIn filepath will be written to the given ini file.

strMsgTitle = IniReadPvt ("WBT2HTML", "ProductName", "", strAppIni) : " - Warning"
blnGetParam = @FALSE

; Get parameter from commandline, if any.
ParseData (IntControl (1006, 0, 0, 0, 0)) ; Full commandline.
If Param0 == 2 Then strFileIn = Param2
   Else GoSub AskParams ; Ask for filename.
DropWild ("Param*")
If strFileIn == "" Then Return Arrayize (@TAB, @TAB)

Switch @TRUE
Case FileExist (strFileIn) == 0
   strMsgText = udfPathFold (strFileIn, 1) : @LF : "Cannot handle input file." : @LF : "File does not exist."
   Message (strMsgTitle, strMsgText)
   Break
Case @TRUE
   strFileIn = udfPathNameLong (strFileIn) ; We need to have an existing file to get a long pathname.
   Continue
Case FileSizeEx (strFileIn) == 0
   strMsgText = udfPathFold (strFileIn, 1) : @LF : "Cannot handle input file." : @LF : "FileSize may be zero."
   Message (strMsgTitle, strMsgText)
   Break
Case !ItemLocate (StrLower (FileExtension (strFileIn)), "wbt|web", "|")
   strMsgText = udfPathFold (strFileIn, 1) : @LF : "Cannot handle input file." : @LF : "Filename has wrong extension." : @LF : "Must be '.wbt' or '.web'."
   Message (strMsgTitle, strMsgText)
   Break
Case @TRUE
   If StrLower (FileExtension (strFileIn)) != "htm" Then strFileOut = strFileIn : ".htm" ; Force appending file extension ".htm" to existing filename.
   Continue
Case FileExist (strFileOut) == 2
   strMsgText = udfPathFold (strFileOut, 1) : @LF : "Cannot handle output file." : @LF : "File is currently open by another application."
   Message (strMsgTitle, strMsgText)
   Break
Case FileSizeEx (strFileOut) > 0
   If !IniReadPvt ("Options", "OptAllowOverwrite", 0, strAppIni)
      strMsgText = udfPathFold (strFileOut, 1) : @LF : "Cannot handle output file." : @LF : "File may exist." : @LF : "Allow to overwrite?"
      If @YES != udfAskYesNo (strMsgTitle, strMsgText) Then Break
   EndIf
   FileAttrSet (strFileOut, "rash")
   blnGetParam = @TRUE
   Break
Case FileExist (strFileOut) == 0
   FilePut (strFileOut, "") ; Create zero byte file.
   If FileExist (strFileOut) == 0
      strMsgText = udfPathFold (strFileOut, 1) : @LF : "Cannot handle output file." : @LF : "File cannot be created."
      Message (strMsgTitle, strMsgText)
      Break
   EndIf
   FileDelete (strFileOut)
   blnGetParam = @TRUE
   Break
Case FileExist (strFileOut) != 0
   FileDelete (strFileOut)
   If FileExist (strFileOut) != 0
      strMsgText = udfPathFold (strFileOut, 1) : @LF : "Cannot handle output file." : @LF : "Existing file cannot be deleted."
      Message (strMsgTitle, strMsgText)
      Break
   EndIf
   blnGetParam = @TRUE
   Break
EndSwitch

If !blnGetParam Then Return Arrayize (@TAB, @TAB)

; If we arrive here without error, then input and output filenames seem to be useful.
IniWritePvt ("Options", "OptLastFileIn", strFileIn, strAppIni)
IniWritePvt ("Options", "OptLastFileOut", strFileOut, strAppIni)
IniWritePvt ("", "", "", strAppIni)
Return Arrayize (strFileIn : @TAB : strFileOut, @TAB)

;------------------------------------------------------------------------------------------------------------------------------------------
:AskParams
;------------------------------------------------------------------------------------------------------------------------------------------
AF_Folder    = FilePath (IniReadPvt ("Options", "OptLastFileIn", "", strAppIni))
AF_Title     = "WBT2HTML - Select WBT or WEB File to convert to HTM"
AF_Filetypes = "WIL Files|*.wbt;*.web|HTML Files|*.htm;*.html|All Files|*.*|"
AF_Default   = "*.wbt;*.web"
AF_Default   = FileBaseName (IniReadPvt ("Options", "OptLastFileIn", AF_Default, strAppIni))
AF_Flag      = 1  ; Open single file.
strFileIn    = udfAskFileName (AF_Title, AF_Folder, AF_Filetypes, AF_Default, AF_flag)
If strFileIn != ""
   IniWritePvt ("Options", "OptLastFileIn", strFileIn, strAppIni)
   IniWritePvt ("", "", "", strAppIni)
EndIf
DropWild ("AF_*")
Return ; from GoSub "AskParams".
;------------------------------------------------------------------------------------------------------------------------------------------
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetTempFolder ()
intEMLast = ErrorMode (@OFF)
LastError ()
strFileTemp = FileCreateTemp ("")
intLastError = LastError ()
ErrorMode (intEMLast)
If !intLastError
   strFolderTemp = FileNameLong (FilePath (strFileTemp) : ".") : "\" ; Return folderpath as long name.
   If FileExist (strFileTemp) == 1 Then FileDelete (strFileTemp)
   Return strFolderTemp
EndIf
strAD_Prompt = "The standard temp folder was not found, please select a folder for temporary files."
strAD_PromptConfirm = "Do you want to use this name to create a new folder?"
strAD_Flags = 1 | 2 | 4 | 16
strAD_FolderRoot = ""
strAD_FolderStart = Environment ("TEMP")
While @TRUE
   strFolderPath = udfAskDirectory (strAD_Prompt, strAD_FolderRoot, strAD_FolderStart, strAD_PromptConfirm, strAD_Flags)
   If strFolderPath == "" Then Return ""
   If DirMake (strFolderPath) Then Return strFolderPath
   strAD_Prompt = "There was a problem with the last selected folder, please select another folder for temporary files."
EndWhile
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetLogFolder (strFolderTemp, strAppProduct)
strFolderLog = strFolderTemp : strAppProduct : "\"
If DirMake (strFolderLog) Then Return strFolderLog
strAD_Prompt = "Cannot create the '" : strAppProduct : "' folder for the logfile. Please select or create another folder for the log file."
strAD_PromptConfirm = "Do you want to use this name to create a new folder?"
strAD_Flags = 1 | 2 | 4 | 16
strAD_FolderRoot = ""
strAD_FolderStart = strFolderTemp
While @TRUE
   strFolderPath = udfAskDirectory (strAD_Prompt, strAD_FolderRoot, strAD_FolderStart, strAD_PromptConfirm, strAD_Flags)
   If strFolderPath == "" Then Return ""
   If DirMake (strFolderPath) Then Return strFolderPath
   strAD_Prompt = "There was a problem with the last selected folder, please select another folder for temporary files."
EndWhile
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfGetListColorsUsed (arrColors, strListColorNamesUsed)
; Create a list of used colors to embed in htm output file, for information purpose only.
strListColorsUsed = ""
intCount = ItemCount (strListColorNamesUsed, @TAB)
For intI = 1 To intCount
   strColorName = ItemExtract (intI, strListColorNamesUsed, @TAB)
   strColorValue = udfGetColorValue (arrColors, strColorName)
   strListColorsUsed = ItemInsert ('"' : strColorName : '"="' : strColorValue : '"', -1, strListColorsUsed, ";")
Next
Return strListColorsUsed
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

Return ; from "GoSub DefineUDF".
;==========================================================================================================================================



;==========================================================================================================================================
:ConvertSourceFile
;------------------------------------------------------------------------------------------------------------------------------------------
intInputLines = ArrInfo (ArrayFileGet (arrFIO[0]), 1)
;------------------------------------------------------------------------------------------------------------------------------------------
strMaskMsg1 = udfPathFold (arrFIO[0], OptPathFold) : @LF : "Converting ... line # {1}/{2}"
strMaskMsg2 = strAppProduct : '  [' : FileBaseName (arrFIO[0]) : ']  Converting line # {1}/{2}' : '   (ShortComment=' : OptHtmlShortComment : ', ClipBoard=' : OptHtmlToClipBoard : ')'
strMaskMsg3 = @LF : "Colorizing ({1}) ..." : @LF : "{2}"
;strMaskMsg3 = udfPathFold (arrFIO[0], OptPathFold) : @LF : "Colorizing ({1}) ..." : @LF : "{2}"
;------------------------------------------------------------------------------------------------------------------------------------------
; Note: Ampersand char is mostly a safe char, but it is not safe when encoding of named entities is done by global StrReplace.
strSafeChars = "&0123456789@$_/\!?,.;:=-+*'()[]# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ; Included ampersand.
strEncChars = "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"
strEncChars = strEncChars : "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"
strEncChars = strEncChars : "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
strEncChars = strEncChars : "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
strEncChars = ChrHexToString (strEncChars) ; Codepoints ANSI 1..255.
strEncChars = StrClean (strEncChars, strSafeChars, "", @TRUE, 1)
strEncChars = "&" : strEncChars ; Note: Ampersand at the first position.
;------------------------------------------------------------------------------------------------------------------------------------------
strOperatorChars = "=<>!*/+-&|^~"
strQuoteChars = """'`"
strBracketChars = "()[]{}"
strSpecialChars = ",@#:%%"
strNumberChars = "0123456789"
strCommentChar = ";"
; strAlphaChars  = All chars from the ANSI charset excluding the above defined subsets.
strStopChars = " =,:()[]!*/+-&|^~<>@#:." ; Space char at the first position.
;------------------------------------------------------------------------------------------------------------------------------------------
If OptHtmlSpan
   strFontPoint        = '<span style="color:' : udfGetColorValue (arrColors, "Default Text") : ';">.</span>'
   strMaskFontDefault  = '<span style="color:' : udfGetColorValue (arrColors, "Default Text") : ';">{1}</span>'
   strMaskFontOperator = '<span style="color:' : udfGetColorValue (arrColors, "Operator") : ';">{1}</span>'
   strMaskFontComment  = '<span style="color:' : udfGetColorValue (arrColors, "Comment") : ';">{1}</span>'
   strMaskFontSpecial  = '<span style="color:' : udfGetColorValue (arrColors, "Special") : ';">{1}</span>'
   strMaskFontBracket  = '<span style="color:' : udfGetColorValue (arrColors, "Bracket") : ';">{1}</span>'
   strMaskFontNumber   = '<span style="color:' : udfGetColorValue (arrColors, "Number") : ';">{1}</span>'
   strMaskFontQuote    = '<span style="color:' : udfGetColorValue (arrColors, "Quote") : ';">{1}</span>'
   strMaskFontName     = '<span style="color:{1};">{2}</span>'
Else
   strFontPoint        = '<font color="' : udfGetColorValue (arrColors, "Default Text") : '">.</font>'
   strMaskFontDefault  = '<font color="' : udfGetColorValue (arrColors, "Default Text") : '">{1}</font>'
   strMaskFontOperator = '<font color="' : udfGetColorValue (arrColors, "Operator") : '">{1}</font>'
   strMaskFontComment  = '<font color="' : udfGetColorValue (arrColors, "Comment") : '">{1}</font>'
   strMaskFontSpecial  = '<font color="' : udfGetColorValue (arrColors, "Special") : '">{1}</font>'
   strMaskFontBracket  = '<font color="' : udfGetColorValue (arrColors, "Bracket") : '">{1}</font>'
   strMaskFontNumber   = '<font color="' : udfGetColorValue (arrColors, "Number") : '">{1}</font>'
   strMaskFontQuote    = '<font color="' : udfGetColorValue (arrColors, "Quote") : '">{1}</font>'
   strMaskFontName     = '<font color="{1}">{2}</font>'
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (arrFIO[0], OptPathFold) : @LF : "Reading Source File ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
hdlFR = FileOpen (arrFIO[0], "READ")
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (strFileTmp, OptPathFold) : @LF : "Writing Temp File ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
hdlFW = FileOpen (strFileTmp, "WRITE")
;------------------------------------------------------------------------------------------------------------------------------------------

intMsgStep = IniReadPvt ("Options", "OptMsgStep", 10, strAppIni)
If intInputLines < 30 Then intMsgStep = 1

strCurrent = ""            ; Current line to scan.
intCountLine = 0           ; Linecounter.
strListColorNamesUsed = "" ; List of used color names.

intLastExclusive = Exclusive (@ON)

While @TRUE
   strCurrent = FileRead (hdlFR)
   ; If intCountLine > 100 Then strCurrent="*EOF*" ; Debug.

   If strCurrent == ";;;" Then Break ; My Breaker.
   If strCurrent == "*EOF*" Then Break
   ; Note: If a line in the input file begins with the text "*EOF*", then the loop ends at this line.
   ; That can make the file not read entirely.

   intCountLine = intCountLine + 1

   If strCurrent == ""
      FileWrite (hdlFW, "")
      Continue
   EndIf

   ; Replace tabs with white spaces.
   strCurrent = StrReplace (strCurrent, @TAB, StrFill (" ", OptTabReplaceSize))

   ; Always trim right and optional trim left.
   strCurrent = ItemRemove (1, StrTrim (@LF : strCurrent), @LF)
   If OptNoIndentation Then strCurrent = StrTrim (strCurrent)

   If strCurrent == ""
      FileWrite (hdlFW, "")
      Continue
   EndIf

   ; Display loop status in steps.
   If !(intCountLine mod intMsgStep)
      If OptVerbose
         BoxDataClear (1, 1)
         strMsgText = StrReplace (StrReplace (strMaskMsg1, "{1}", intInputLines), "{2}", intCountLine)
         BoxText (strMsgText)
      Else
         strMsgText = StrReplace (StrReplace (strMaskMsg2, "{1}", intInputLines), "{2}", intCountLine)
         WinTitle ("", strMsgText)
      EndIf
   EndIf

   strOut = ""
   arrCurrent = ArrayFromStr (" " : strCurrent)
   intCount = ArrInfo (arrCurrent, 1)

   intCurrent = 1
   While intCurrent < intCount
      Switch @TRUE

         ; Operators.
      Case !!StrIndex (strOperatorChars, arrCurrent[intCurrent], 1, @FWDSCAN)
         Switch StrIndex ("<>&", arrCurrent[intCurrent], 1, @FWDSCAN)
         Case 1
            strTemp = StrReplace (strMaskFontOperator, "{1}", "&#60;")
            Break
         Case 2
            strTemp = StrReplace (strMaskFontOperator, "{1}", "&#62;")
            Break
         Case 3
            strTemp = StrReplace (strMaskFontOperator, "{1}", "&#38;")
            Break
         Case 0
            strTemp = StrReplace (strMaskFontOperator, "{1}", arrCurrent[intCurrent])
            Break
         EndSwitch

         intCurrent = intCurrent + 1

         strListColorNamesUsed = udfItemPut ("Operator", strListColorNamesUsed, @TAB)
         Break

         ; Quotes.
      Case !!StrIndex (strQuoteChars, arrCurrent[intCurrent], 1, @FWDSCAN)
         strQuote = arrCurrent[intCurrent]
         intCurrent = intCurrent + 1
         intScanStart = intCurrent
         intCurrent = StrIndex (strCurrent, strQuote, intScanStart, @FWDSCAN)

         If intCurrent
            strTemp = StrSub (strCurrent, intScanStart, intCurrent - intScanStart)

            If StrTrim (strTemp) != ""
               ; Encode named entities.
               strCleaned = StrClean (strEncChars, strTemp, "", @TRUE, 2)
               intCleanCount = StrLen (strCleaned)
               For intClean = 1 To intCleanCount
                  strChar = StrSub (strCleaned, intClean, 1)
                  strTemp = StrReplace (strTemp, strChar, StrReplace ("&#n;", "n", Char2Num (strChar)))
               Next

               strTemp = StrReplace (strMaskFontQuote, "{1}", strTemp)
            EndIf

            strQuote = StrReplace (strMaskFontDefault, "{1}", strQuote)
            strTemp = strQuote : strTemp : strQuote
         Else
            strTemp = StrReplace (strMaskFontDefault, "{1}", strQuote)
         EndIf

         intCurrent = intCurrent + 1

         strListColorNamesUsed = udfItemPut ("Quote", strListColorNamesUsed, @TAB)
         Break

         ; Comments.
      Case !!StrIndex (strCommentChar, arrCurrent[intCurrent], 1, @FWDSCAN)
         strTemp = StrSub (strCurrent, intCurrent, -1)

         ; Encode named entities.
         strCharsToEnc = StrClean (strEncChars, strTemp, "", @TRUE, 2)
         intCleanCount = StrLen (strCharsToEnc)
         For intI = 1 To intCleanCount
            strChar = StrSub (strCharsToEnc, intI, 1)
            strTemp = StrReplace (strTemp, strChar, StrReplace ("&#n;", "n", Char2Num (strChar)))
         Next

         strTemp = StrReplace (strMaskFontComment, "{1}", strTemp)

         intCurrent = intCount

         strListColorNamesUsed = udfItemPut ("Comment", strListColorNamesUsed, @TAB)
         Break

         ; Blank char needs no colorizing.
      Case " " == arrCurrent[intCurrent]
         strTemp = " "
         intCurrent = intCurrent + 1
         Break

         ; Numbers, integer and float including decimal point.
      Case !!StrIndex (strNumberChars, arrCurrent[intCurrent], 1, @FWDSCAN)
         blnPoint = @FALSE
         intScanStart = intCurrent
         intCurrent = intCurrent + 1
         While intCurrent < intCount
            If !StrIndex (strNumberChars, arrCurrent[intCurrent], 1, @FWDSCAN)
               If "." == arrCurrent[intCurrent] Then blnPoint = @TRUE
                  Else Break
            EndIf
            intCurrent = intCurrent + 1
         EndWhile

         strTemp = StrSub (strCurrent, intScanStart, intCurrent - intScanStart)

         If blnPoint
            strNum1 = ItemExtract (1, strTemp, ".")
            strNum2 = ItemExtract (2, strTemp, ".")
            strNum1 = StrReplace (strMaskFontNumber, "{1}", strNum1)
            If strNum2 != ""
               strNum2 = StrReplace (strMaskFontNumber, "{1}", strNum2)
               strTemp = strNum1 : strFontPoint : strNum2
            Else
               strTemp = strNum1 : strFontPoint
            EndIf
         Else
            strTemp = StrReplace (strMaskFontNumber, "{1}", strTemp)
         EndIf

         strListColorNamesUsed = udfItemPut ("Number", strListColorNamesUsed, @TAB)
         Break

         ; Brackets.
      Case !!StrIndex (strBracketChars, arrCurrent[intCurrent], 1, @FWDSCAN)
         strTemp = StrReplace (strMaskFontBracket, "{1}", arrCurrent[intCurrent])
         intCurrent = intCurrent + 1
         strListColorNamesUsed = udfItemPut ("Bracket", strListColorNamesUsed, @TAB)
         Break

         ; Special chars.
      Case !!StrIndex (strSpecialChars, arrCurrent[intCurrent], 1, @FWDSCAN)
         strTemp = StrReplace (strMaskFontSpecial, "{1}", arrCurrent[intCurrent])
         intCurrent = intCurrent + 1
         strListColorNamesUsed = udfItemPut ("Special", strListColorNamesUsed, @TAB)
         Break

         ; All other chars are variable names and keywords.
      Case @TRUE
         intScanStart = intCurrent + 1
         intCurrent = StrScan (strCurrent, strStopChars, intScanStart, @FWDSCAN)
         If intCurrent
            strTemp = StrSub (strCurrent, intScanStart - 1, intCurrent - intScanStart + 1)
         Else
            strTemp = StrSub (strCurrent, intScanStart - 1, -1)
            intCurrent = intCount
         EndIf

         If strTemp != ""
            ; Find keyword in the keyword table, get standard notation and color name.
            strKeyword = ""
            strColorName = "Default Text"
            intRow = ArraySearch (arrKeywords, strTemp, 3) ; Binary search option 3 needs the array to be sorted.
            If intRow != -1
               strKeyword = arrKeywords[intRow, 0]
               strColorName = arrKeywords[intRow, 1]
            EndIf

            If strKeyword != ""
               Switch OptCase
               Case 4
                  strTemp = strKeyword
                  Break
               Case 3
                  strTemp = StrUpper (strTemp)
                  Break
               Case 2
                  strTemp = StrLower (strTemp)
                  Break
               Case 1
                  ; strTemp = strTemp ; Freestyle, no change.
                  Break
               EndSwitch
            EndIf

            If OptVerbose > 2
               strMsgText2 = strMsgText : StrReplace (StrReplace (strMaskMsg3, "{1}", strColorName), "{2}", strTemp)
               BoxText (strMsgText2)
            EndIf

            strColorValue = udfGetColorValue (arrColors, strColorName)
            strTemp = StrReplace (StrReplace (strMaskFontName, "{1}", strColorValue), "{2}", strTemp)
         EndIf

         strListColorNamesUsed = udfItemPut (strColorName, strListColorNamesUsed, @TAB)
         Break

      EndSwitch

      strOut = strOut : strTemp
   EndWhile

   FileWrite (hdlFW, strOut)
EndWhile

; Display loop end status.
If OptVerbose
   strMsgText = StrReplace (StrReplace (strMaskMsg1, "{1}", intInputLines), "{2}", intCountLine)
   BoxText (strMsgText)
Else
   strMsgText = StrReplace (StrReplace (strMaskMsg2, "{1}", intInputLines), "{2}", intCountLine)
   WinTitle ("", strMsgText)
EndIf

Exclusive (intLastExclusive)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (strFileTmp, OptPathFold) : @LF : "Closing Temp File ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
FileClose (hdlFW)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (arrFIO[0], OptPathFold) : @LF : "Closing Source File ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
FileClose (hdlFR)
;------------------------------------------------------------------------------------------------------------------------------------------
Drop (strTemp, strStopChars, strSpecialChars, strSafeChars, strQuoteChars, strQuote, strOut, strOperatorChars)
Drop (strNumberChars, strNum2, strNum1, strMsgTitle, strMsgText2, strMsgText, strMaskFontSpecial, strMaskFontQuote)
Drop (strMaskFontOperator, strMaskFontNumber, strMaskFontName, strMaskFontDefault, strMaskFontComment, strMaskFontBracket)
Drop (strKeywordValue, strKeyword, strFontPoint, strEncChars, strCurrent, strCommentChar, strColorValue, strColorName)
Drop (strCharsToEnc, strChar, strBracketChars, strCleaned, intScanStart, intRow, intLastExclusive)
Drop (intI, intCurrent, intCount, intCleanCount, intClean, hdlFW, hdlFR, blnPoint, arrCurrent)
Return ; from GoSub ConvertSourceFile.
;==========================================================================================================================================



;==========================================================================================================================================
:DefineHtmlMasks
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (arrFIO[1], OptPathFold) : @LF : "Waiting ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose >= 1
   ; Primitive dialog.
   BoxButtonDraw (1, 1, 'HTML  <!-- ', "020,700,480,950")
   BoxButtonDraw (1, 2, 'WB BBS  <! ', "520,700,980,950")
   BoxButtonWait ()
   OptHtmlShortComment = BoxButtonStat (1, 2)
   BoxButtonKill (1, 1)
   BoxButtonKill (1, 2)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
strHtmlComment = "<!--" ; Standard HTML comment opening tag.
If OptHtmlShortComment Then strHtmlComment = "<!" ; Shortened tag for use in WinBatch forum.
Drop (OptHtmlShortComment)
;------------------------------------------------------------------------------------------------------------------------------------------
strMaskHtmlPre = strHtmlComment : ' [{1}] Colorized HTML by {2} v{3} {4} -->' : @CRLF
strMaskHtmlPre = strMaskHtmlPre : strHtmlComment : ' {5} -->' : @CRLF
strMaskHtmlPre = strMaskHtmlPre : '<pre id="GUID_{17}_MD5_{16}" style="{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}" title="Colorized by {2} v{3}">' : @CRLF
strMaskHtmlPre = strMaskHtmlPre : '{18}'
;strMaskHtmlPre = StrCat (strMaskHtmlPre, '<script type="text/javascript">function CopyParentToClipboard(oObject){var r=document.body.createControlRange();r.add(oObject.parentElement);r.execCommand("Copy");}</script>', @CRLF)
;strMaskHtmlPre = StrCat (strMaskHtmlPre, '<input style="border:1pt dashed #dddddd; background-color:#fafafa; width:150px; color:navy; cursor:hand; " ')
;strMaskHtmlPre = StrCat (strMaskHtmlPre, 'type="button" title="Copy script to clipboard" alt="Copy script to clipboard" value="Copy script to clipboard" onclick="CopyParentToClipboard(this);">', @CRLF)
strMaskHtmlPre = strMaskHtmlPre : '</pre>' : @CRLF
Drop (strHtmlComment)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptMakeHtmlTag Then strMaskHtmlPre = '<html>' : @CRLF : '<head></head>' : @CRLF : '<body>' : @CRLF : strMaskHtmlPre : '</body>' : @CRLF : '</html>' : @CRLF
Drop (OptMakeHtmlTag)
; {1}  TimeYmdHms ()
; {2}  strAppProduct
; {3}  strAppVersion
; {4}  strAppCopyright
; {5}  strListColorsUsed
; {6}  strStyleImageBg
; {7}  strStyleColorBg
; {8}  strStyleBorder
; {9}  strStylePadding
; {10} strStyleWidth
; {11} strStyleFontFamily
; {12} strStyleFontSize
; {13} strStyleFontWeight
; {14} strStyleFontStyle
; {15} strStyleColorFg
; {16} MD5 checksum number of the input file, used as part of the id attribute.
; {17} GUID, used as part of the id attribute.
; {18} Content of strFileTmp
;------------------------------------------------------------------------------------------------------------------------------------------
strStyleBorder  = 'border:1pt solid #dddddd; '
strStylePadding = 'padding:3pt; '
strStyleWidth   = 'width:100%%; '
;------------------------------------------------------------------------------------------------------------------------------------------
strMaskStyleFontFamily = "font-family:'{1}'; "
strMaskStyleFontSize   = "font-size:{1}pt; "
strMaskStyleFontWeight = "font-weight:{1}; "
strMaskStyleFontStyle  = "font-style:{1}; "
strMaskStyleColorBg    = "background-color:{1}; "
strMaskStyleColorFg    = "color:{1}; "
strMaskStyleImageBg    = "background-image:url({1}); "
;------------------------------------------------------------------------------------------------------------------------------------------
; Set background image from inifile entry, e. g. "OptImageBg=../images/gif/grid.gif".
strStyleImageBg = ""
strImageBg = IniReadPvt ("Options", "OptImageBg", "", strAppIni)
If strImageBg != "" Then strStyleImageBg = StrReplace (strMaskStyleImageBg, "{1}", strImageBg)
Drop (strImageBg)
;------------------------------------------------------------------------------------------------------------------------------------------
; Get font attributes for WIL files.

; Set default font style attributes.
strFontFamily = "Courier New"
strFontSize   = "9"
strFontWeight = "400"
strFontStyle  = "0"

; Read font attributes for WIL files from WinBatch Studio Registry.
strRegKeySub = "Software\Wilson WindowWare\WinBatch Studio\Settings\File types\WIL Files"
If RegExistKey (@REGCURRENT, strRegKeySub)
   hdlRegKey = RegOpenKeyEx (@REGCURRENT, strRegKeySub, 1, "", "") ; Mode=1=KEY_QUERY_VALUE=Permission to query subkey data ; We only need read access.
   strRegKeySub = "[Font name]"
   If RegExistValue (hdlRegKey, strRegKeySub) Then strFontFamily = RegQueryValue (hdlRegKey, strRegKeySub)
   strRegKeySub = "[Font size]"
   If RegExistValue (hdlRegKey, strRegKeySub) Then strFontSize = RegQueryValue (hdlRegKey, strRegKeySub)
   strRegKeySub = "[Font weight]"
   If RegExistValue (hdlRegKey, strRegKeySub) Then strFontWeight = RegQueryValue (hdlRegKey, strRegKeySub)
   strRegKeySub = "[Font Italic]"
   If RegExistValue (hdlRegKey, strRegKeySub) Then strFontStyle = RegQueryValue (hdlRegKey, strRegKeySub)
   RegCloseKey (hdlRegKey)
   Drop (hdlRegKey, strRegKeySub)
EndIf
strFontStyle = ItemExtract (1 + strFontStyle, "normal, italic", ",") ; Translate number to string.
;------------------------------------------------------------------------------------------------------------------------------------------
strStyleFontStyle = StrReplace (strMaskStyleFontStyle, "{1}", strFontStyle)
strStyleFontFamily = StrReplace (strMaskStyleFontFamily, "{1}", strFontFamily)
strStyleFontSize = StrReplace (strMaskStyleFontSize, "{1}", strFontSize)
strStyleFontWeight = StrReplace (strMaskStyleFontWeight, "{1}", strFontWeight)
;------------------------------------------------------------------------------------------------------------------------------------------
strStyleColorBg = StrReplace (strMaskStyleColorBg, "{1}", udfGetColorValue (arrColors, "Background"))
strStyleColorFg = StrReplace (strMaskStyleColorFg, "{1}", udfGetColorValue (arrColors, "Default Text"))
;------------------------------------------------------------------------------------------------------------------------------------------
Return ; from GoSub DefineHtmlMasks.
;==========================================================================================================================================



;==========================================================================================================================================
:AddLineNumber
;------------------------------------------------------------------------------------------------------------------------------------------
OptHtmlSpan = IniReadPvt ("Options", "OptHtmlSpan", 1, strAppIni)
If OptHtmlSpan
   strMaskFont = '<span style="color:{1};">{2}</span>'
Else
   strMaskFont = '<font color="{1}">{2}</font>'
EndIf
Drop (OptHtmlSpan)
;------------------------------------------------------------------------------------------------------------------------------------------
strColorName = "LineNumber"
strColorValue = udfGetColorValue (arrColors, strColorName)
;------------------------------------------------------------------------------------------------------------------------------------------
intLineNrLen = IniReadPvt ("Options", "OptLineNumberLen", 0, strAppIni)
If intLineNrLen < 0 Then intLineNrLen = StrLen (intInputLines)
;------------------------------------------------------------------------------------------------------------------------------------------
Switch OptLineNumberLink
Case 2
   strMaskAnchorId = '<a id="L{1}" href="#L{1}">{2}</a>'
   Break
Case 1
   strMaskAnchorId = '<a id="L{1}">{2}</a>'
   Break
Case 0
   strMaskAnchorId = ''
   Break
EndSwitch
;------------------------------------------------------------------------------------------------------------------------------------------
; Get the full temporary html file into an array and prepend line numbers to each line.
intLastExclusive = Exclusive (@ON)

arrText = ArrayFileGet (strFileTmp) ; Array counts from 0. Line number counts from 1.
intLast = ArrInfo (arrText, 1) - 1
For intI = 0 To intLast
   strCurrent = arrText[intI]
   strLineNr = StrFixLeft (intI + 1, OptLineNumberFiller, intLineNrLen)
   strLineNr = StrReplace (StrReplace (strMaskFont, "{1}", strColorValue), "{2}", strLineNr)
   Switch OptLineNumberLink
   Case 2
   Case 1
      strAnchorId = StrReplace (strMaskAnchorId, "{1}", intI + 1)
      strAnchorId = StrReplace (strAnchorId, "{2}", strLineNr)
      arrText[intI] = strAnchorId : "  " : arrText[intI]
      Break
   Case 0
      arrText[intI] = strLineNr : "  " : arrText[intI]
      Break
   EndSwitch
Next
ArrayFilePut (strFileTmp, arrText)

Exclusive (intLastExclusive)

Drop (strMaskAnchorId, strLineNr, strCurrent, strColorValue, strColorName, strAnchorId, intLineNrLen, intLastExclusive, intLast, intI, arrText)
Return ; from GoSub AddLineNumber.
;==========================================================================================================================================



;==========================================================================================================================================
:CreateWriteTargetFile
;------------------------------------------------------------------------------------------------------------------------------------------
; Create the HTML output from previously defined template.
strHtmlPre = strMaskHtmlPre
strHtmlPre = StrReplace (strHtmlPre, "{1}", TimeYmdHms ())
strHtmlPre = StrReplace (strHtmlPre, "{2}", strAppProduct)
strHtmlPre = StrReplace (strHtmlPre, "{3}", strAppVersion)
strHtmlPre = StrReplace (strHtmlPre, "{4}", strAppCopyright)
strHtmlPre = StrReplace (strHtmlPre, "{5}", udfGetListColorsUsed (arrColors, strListColorNamesUsed))
strHtmlPre = StrReplace (strHtmlPre, "{6}", strStyleImageBg)
strHtmlPre = StrReplace (strHtmlPre, "{7}", strStyleColorBg)
strHtmlPre = StrReplace (strHtmlPre, "{8}", strStyleBorder)
strHtmlPre = StrReplace (strHtmlPre, "{9}", strStylePadding)
strHtmlPre = StrReplace (strHtmlPre, "{10}", strStyleWidth)
strHtmlPre = StrReplace (strHtmlPre, "{11}", strStyleFontFamily)
strHtmlPre = StrReplace (strHtmlPre, "{12}", strStyleFontSize)
strHtmlPre = StrReplace (strHtmlPre, "{13}", strStyleFontWeight)
strHtmlPre = StrReplace (strHtmlPre, "{14}", strStyleFontStyle)
strHtmlPre = StrReplace (strHtmlPre, "{15}", strStyleColorFg)
strHtmlPre = StrReplace (strHtmlPre, "{16}", FileDigest (arrFIO[0], "MD5", 0)) ; MD5.
strHtmlPre = StrReplace (strHtmlPre, "{17}", udfGetGUID ()) ; GUID.
strHtmlPre = StrReplace (strHtmlPre, "{18}", FileGet (strFileTmp))
;------------------------------------------------------------------------------------------------------------------------------------------
FilePut (arrFIO[1], strHtmlPre)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = udfPathFold (arrFIO[1], OptPathFold) : @LF : "Closing Target File ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
DropWild ("strMask*")
DropWild ("strFont*")
DropWild ("strStyle*")
Return
;==========================================================================================================================================



;==========================================================================================================================================
:PutHtmlToClipboard
;------------------------------------------------------------------------------------------------------------------------------------------
ClipPut (strHtmlPre)
If OptVerbose >= 1
   ; Primitive dialog.
   strMsgText = udfPathFold (arrFIO[1], OptPathFold) : @LF : "Output HTML is on the Clipboard now."
   BoxText (strMsgText)
   BoxButtonDraw (1, 1, "OK", "200,700,800,950")
   BoxButtonWait ()
   BoxButtonKill (1, 1)
   ClipPut (strHtmlPre)
   Drop (strHtmlPre, strMsgText)
EndIf
Return
;==========================================================================================================================================



;==========================================================================================================================================
:WriteLog
;------------------------------------------------------------------------------------------------------------------------------------------
; Start performance test.
If !IsDefined (intPerfStart)
   intPerfStart = GetTickCount ()
   Return
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
; Stop performance test.
intPerfStop = GetTickCount ()
intPerfLinesIn = ItemCount (FileGet (arrFIO[0]), @LF)
intPerfLinesOut = intCountLine
intPerfSecs = (intPerfStop - intPerfStart) / 1000.0
intPerfLinesOutPerSec = intPerfLinesOut / intPerfSecs
;------------------------------------------------------------------------------------------------------------------------------------------
If !OptWriteLogfile Then Return
;------------------------------------------------------------------------------------------------------------------------------------------
Decimals (2)
strPerfIni = strFolderLog : strAppProduct : ".log.txt"
strPerfSection = TimeYmdHms () : "|" : StrFixLeft (GetTickCount (), " ", 10)

strPerfKey = "Version"
strPerfValue = strAppVersion
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "FileIn"
strPerfValue = arrFIO[0]
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "FileOut"
strPerfValue = arrFIO[1]
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "LinesIn"
strPerfValue = intPerfLinesIn
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "LinesOut"
strPerfValue = intPerfLinesOut
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "Seconds"
strPerfValue = intPerfSecs
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

strPerfKey = "LinesOutPerSecond"
strPerfValue = intPerfLinesOutPerSec
IniWritePvt (strPerfSection, strPerfKey, strPerfValue, strPerfIni)

DropWild ("intPerf*")
DropWild ("strPerf*")
Return
;==========================================================================================================================================



;==========================================================================================================================================
:LoadTableKeywords
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = "Loading Keyword Table ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
strFileKeywords = IniReadPvt ("TableKeywords", "URL", "", strAppIni)
Terminate (FileSizeEx (strFileKeywords) == 0, "Terminate - LoadTableKeywords", "Cannot access Keyword Table file:" : @LF : strFileKeywords)
If !IsDefined (arrKeywords)
   arrKeywords = ArrayFileGetCSV (strFileKeywords, 0)
   Terminate (!(ArrInfo (arrKeywords, -1) && ArrInfo (arrKeywords, 1)), "Terminate - LoadTableKeywords", "This Keyword Table file seems not to be usable:" : @LF : strFileKeywords)
   ArraySort (arrKeywords) ; For sure, again, sort search array for later binary search access.
EndIf
Return
;==========================================================================================================================================



;==========================================================================================================================================
:CreateTableKeywords
;------------------------------------------------------------------------------------------------------------------------------------------
strMsgText = "Creating Keyword Table ... be patient ..."
If OptVerbose >= 1
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
If !IsDefined (arrKeywords)
   ; Read section from inifile into array.
   arrKeywords = Arrayize (IniItemizePvt ("KEYWORDS", strFileWilClr), @TAB) ; Keywords mixed case, as defined in WIL.CLR file.
   ArrayRedim (arrKeywords, -1, 2)
   intLast = ArrInfo (arrKeywords, 1) - 1
   For intI = 0 To intLast
      arrKeywords[intI, 1] = IniReadPvt ("KEYWORDS", arrKeywords[intI, 0], "", strFileWilClr) ; Get colorname.
      If arrKeywords[intI, 1] == "1" Then arrKeywords[intI, 1] = "Keyword"  ; "Repair" entry as defined in Registry.
      ;------
      If !(intI mod 100)
         If OptVerbose >= 1
            strMsgText2 = strMsgText : @LF : "Reading ... " : intI : " of " : intLast
            BoxText (strMsgText2)
         EndIf
      EndIf
      ;------
   Next
   ; Sort search array for later binary search access.
   ArraySort (arrKeywords)

   Drop (intLast, intI, strMsgText2)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = "Saving Keyword Table ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
; Save keywords to textfile for later usage into the same folder as the script.
strFileKeywords = IniReadPvt ("WBT2HTML", "InstallPath", ".\", strAppIni) : strAppProduct : ".keywords.txt"

intTermBool = !ArrayFilePutCSV (strFileKeywords, arrKeywords)
If intTermBool
   strTermTitle = "Terminate"
   strTermText = "Cannot write Keyword Table file:" : @LF : "{1}"
   strTermText = StrReplace (strTermText, "{1}", strFileKeywords)
   Terminate (intTermBool, strTermTitle, strTermText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
; Write keyword table data to my inifile.
IniWritePvt ("TableKeywords", "URL", strFileKeywords, strAppIni)
IniWritePvt ("TableKeywords", "FileYmdHms", FileYmdHms (strFileKeywords), strAppIni)
IniWritePvt ("TableKeywords", "MD5", FileDigest (strFileKeywords, "MD5", 0), strAppIni)
IniWritePvt ("", "", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Write keywords data to my inifile.
IniWritePvt ("WilKeywords", "URL", strFileWilClr, strAppIni)
IniWritePvt ("WilKeywords", "FileYmdHms", FileYmdHms (strFileWilClr), strAppIni)
IniWritePvt ("WilKeywords", "MD5", FileDigest (strFileWilClr, "MD5", 0), strAppIni)
IniWritePvt ("", "", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   If FileSizeEx (strFileKeywords) > 0
      strMsgText = "Saving Keyword Table ... OK"
      BoxText (strMsgText)
   EndIf
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
Drop (intTermBool, strMsgText, strTermText, strTermTitle)
Return
;==========================================================================================================================================



;==========================================================================================================================================
:CreateTableColors
;------------------------------------------------------------------------------------------------------------------------------------------
strMsgText = "Creating Color Table ... be patient ..."
If OptVerbose >= 1
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
; Collect names and rgb color values.
; We use the default rgb color values as defined in WSINIT.DLL
; and try to update them from the Current User Registry.
strListColorNames = "Keyword|Quote|Comment|Default Text|Background"
strListColorValues = "0,0,255|255,0,0|0,128,0|0,0,0|255,255,255"
strListColorNames = StrReplace (strListColorNames, "|", @TAB)
strListColorValues = StrReplace (strListColorValues, "|", @TAB)

;--- Read colors for WIL files from WinBatch Studio Registry.
strRegKeySub = "Software\Wilson WindowWare\WinBatch Studio\Settings\File types\WIL Files"
If RegExistKey (@REGCURRENT, strRegKeySub)
   hdlRegKey = RegOpenKeyEx (@REGCURRENT, strRegKeySub, 1, "", "") ; Mode=1=KEY_QUERY_VALUE=Permission to query subkey data ; We only need read access.
   intCount = ItemCount (strListColorNames, @TAB)
   For intI = 1 To intCount
      strColorName = ItemExtract (intI, strListColorNames, @TAB)
      strRegKeySub = "[" : strColorName : "]"
      If RegExistValue (hdlRegKey, strRegKeySub)
         strColorValue = RegQueryValue (hdlRegKey, strRegKeySub)
         strListColorValues = ItemReplace (strColorValue, intI, strListColorValues, @TAB)
      EndIf
   Next
   RegCloseKey (hdlRegKey)
EndIf
Drop (strRegKeySub, strColorValue, strColorName, intI, intCount, hdlRegKey)


;--- Additional colors from WIL.CLR.
; For example: CON=128,0,128; EXT=255,0,255; CONSTANT=0,128,255; WED=0,128,0; UDF=128,096,048; OPERATOR=0,48,128

strFileIni = strFileWilClr
strIniSection = "Colors"
strIniKeys = IniItemizePvt (strIniSection, strFileIni)
intCount = ItemCount (strIniKeys, @TAB)
For intI = 1 To intCount
   strIniKey = ItemExtract (intI, strIniKeys, @TAB)
   strIniValue = IniReadPvt (strIniSection, strIniKey, "0,0,0", strFileIni)
   strListColorNames = ItemInsert (strIniKey, -1, strListColorNames, @TAB)
   strListColorValues = ItemInsert (strIniValue, -1, strListColorValues, @TAB)
Next
Drop (strIniValue, strIniSection, strIniKeys, strIniKey, strFileIni, intI, intCount)


;--- Additional colors from my own inspiration.
; Note: The color settings in the WBT2HTML.ini file have the highest priority against all other previous color settings.

strFileIni = strAppIni
strIniSection = "Colors"
strIniKeys = IniItemizePvt (strIniSection, strFileIni)
intCount = ItemCount (strIniKeys, @TAB)
For intI = 1 To intCount
   strIniKey = ItemExtract (intI, strIniKeys, @TAB)
   strIniValue = IniReadPvt (strIniSection, strIniKey, "0,0,0", strFileIni)
   strListColorNames = ItemInsert (strIniKey, -1, strListColorNames, @TAB)
   strListColorValues = ItemInsert (strIniValue, -1, strListColorValues, @TAB)
Next
Drop (strIniValue, strIniSection, strIniKeys, strIniKey, strFileIni, intI, intCount)


;------------------------------------------------------------------------------------------------------------------------------------------
; Set all color name items to lower case is not needed any longer, ArraySearch can ignore case.
; Delete duplicates, last item in list will win.
; Prepare a new array to collect the unique entries. Array will be re-dimed later as needed.
; Must have at least one cell to avoid error "1710 Array is empty" when first time use ArrayLocate.

arrColors = ArrDimension (1, 2) ; Start array with one row.

intCount = ItemCount (strListColorNames, @TAB)
For intI = 1 To intCount
   strColorName = ItemExtract (intI, strListColorNames, @TAB)
   intRow = ArraySearch (arrColors, strColorName, 2)
   If intRow == -1
      intRow = ArrInfo (arrColors, 1) - 1
      ArrayRedim (arrColors, intRow + 2, -1) ; Prepare one more row for possible next entry.
   EndIf
   arrColors[intRow, 0] = strColorName
   arrColors[intRow, 1] = ItemExtract (intI, strListColorValues, @TAB)
Next
ArrayRemove (arrColors, ArrInfo (arrColors, 1) - 1, 1) ; Remove last unused cell.
Drop (intI, intCount, intRow, strListColorNames, strListColorValues, strColorName)

; 1. If OptRGB==1 Then format as rgb(r,g,b).
; 2. If OptRGB==0 Then format as hex #rrggbb.

intLast = ArrInfo (arrColors, 1) - 1
If OptRGB
   For intI = 0 To intLast
      arrRGB = Arrayize (arrColors[intI, 1], ",")
      arrColors[intI, 1] = "rgb(" : Int (arrRGB[0]) : "," : Int (arrRGB[1]) : "," : Int (arrRGB[2]) : ")"
   Next
Else
   hdlBB = BinaryAlloc (3) ; Binary buffer for conversion from byte to hex.
   For intI = 0 To intLast
      arrRGB = Arrayize (arrColors[intI, 1], ",")
      arrColors[intI, 1] = "#000000"
      If (arrRGB[0] | arrRGB[1] | arrRGB[2])
         BinaryPoke (hdlBB, 0, Int (arrRGB[0])) ; R
         BinaryPoke (hdlBB, 1, Int (arrRGB[1])) ; G
         BinaryPoke (hdlBB, 2, Int (arrRGB[2])) ; B
         arrColors[intI, 1] = "#" : BinaryPeekHex (hdlBB, 0, 3)
      EndIf
   Next
   hdlBB = BinaryFree (hdlBB)
EndIf
Drop (intI, intLast, hdlBB, arrRGB)

ArraySort (arrColors) ; Array needs to be sorted for later binary search access.

;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   strMsgText = "Saving Color Table ..."
   BoxText (strMsgText)
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
; Save colors to textfile for later usage into the same folder as the script.
strFileColors = IniReadPvt ("WBT2HTML", "InstallPath", ".\", strAppIni) : strAppProduct : ".colors.txt"

intBytes = ArrayFilePutCSV (strFileColors, arrColors)
Terminate (!intBytes, "Terminate - CreateTableColors", "Cannot write Color Table file:" : @LF : strFileColors)
;------------------------------------------------------------------------------------------------------------------------------------------
; Write colors table data to my inifile.
IniWritePvt ("TableColors", "URL", strFileColors, strAppIni)
IniWritePvt ("TableColors", "FileYmdHms", FileYmdHms (strFileColors), strAppIni)
IniWritePvt ("TableColors", "MD5", FileDigest (strFileColors, "MD5", 0), strAppIni)
IniWritePvt ("", "", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
If OptVerbose > 1
   If FileSizeEx (strFileColors) > 0
      strMsgText = "Saving Color Table ... OK"
      BoxText (strMsgText)
   EndIf
EndIf
;------------------------------------------------------------------------------------------------------------------------------------------
Drop (intTermBool, strMsgText, strTermText, strTermTitle, strFileColors, intBytes)
Return
;==========================================================================================================================================



;==========================================================================================================================================
:CheckProgIni
;------------------------------------------------------------------------------------------------------------------------------------------
; The inifile must reside in the same folder as the script.
strAppIni = strAppProduct : ".ini" ; Associated inifile.

strFolderProgHome = udfPathNameLong (FilePath (IntControl (1004, 0, 0, 0, 0)))
If DirExist (strFolderProgHome) Then strAppIni = strFolderProgHome : strAppIni

If "" == IniReadPvt ("WBT2HTML", "YmdHms", "", strAppIni)
   If 1 != udfAskYesNo ("Welcome to WBT2HTML", "Start initial setup now?") Then Goto CANCEL ; Exit immediately.
   OptVerbose = 1
   GoSub SetProgIni
   GoSub ReadProgIni
   GoSub CreateTableKeywords
   GoSub CreateTableColors
Else
   GoSub ReadProgIni

   blnForceUpdate = @FALSE
   blnSetProgIni = @FALSE

   Switch @TRUE
   Case @TRUE
      strSection = "WilKeywords"
      strURL = IniReadPvt (strSection, "URL", "", strAppIni)
      blnCase1 = @FALSE
      Switch @TRUE
      Case strURL == ""
      Case FileSizeEx (strURL) == 0
      Case IniReadPvt (strSection, "FileYmdHms", "", strAppIni) != FileYmdHms (strURL)
      Case IniReadPvt (strSection, "MD5", "", strAppIni) != FileDigest (strURL, "MD5", 0)
         blnForceUpdate = @TRUE
         blnCase1 = @TRUE
      EndSwitch
      Continue
   Case @TRUE
      strSection = "TableKeywords"
      strURL = IniReadPvt (strSection, "URL", "", strAppIni)
      blnCase2 = @FALSE
      Switch @TRUE
      Case strURL == ""
      Case FileSizeEx (strURL) == 0
      Case IniReadPvt (strSection, "FileYmdHms", "", strAppIni) != FileYmdHms (strURL)
      Case IniReadPvt (strSection, "MD5", "", strAppIni) != FileDigest (strURL, "MD5", 0)
         blnForceUpdate = @TRUE
         blnCase2 = @TRUE
      EndSwitch
      Continue
   Case @TRUE
      strSection = "WBT2HTML"
      blnCase3 = @FALSE
      Switch @TRUE
      Case IniReadPvt (strSection, "FileVersion", "", strAppIni) != strAppVersion
      Case IniReadPvt (strSection, "FileVersionDate", "", strAppIni) != strAppVersionDate
      Case IniReadPvt (strSection, "ProductName", "", strAppIni) != strAppProduct
         blnSetProgIni = @TRUE
         blnForceUpdate = @TRUE
         blnCase3 = @TRUE
      EndSwitch
      Continue
   EndSwitch

   If blnCase1 || blnCase2 || blnCase3
      strMsgText = "External changes have been detected, related to ..."
      If blnCase1 Then strMsgText = strMsgText : @LF : "- WIL.CLR Keywords"
      If blnCase2 Then strMsgText = strMsgText : @LF : "- WBT2HTML Keyword Table"
      If blnCase3 Then strMsgText = strMsgText : @LF : "- WBT2HTML Application"
      strMsgText = strMsgText : @LF : @LF : "Installation is going to be refreshed now ..."
      Pause (strAppProduct : " - Refresh", strMsgText)
      WinActivate ("")

      If blnSetProgIni Then GoSub SetProgIni
      If blnForceUpdate
         GoSub CreateTableKeywords
         GoSub CreateTableColors
      EndIf
   EndIf
   Drop (blnForceUpdate, blnSetProgIni, blnCase1, blnCase2, blnCase3)
EndIf
Drop (strFolderProgHome)
Return
;==========================================================================================================================================



;==========================================================================================================================================
:ReadProgIni
;------------------------------------------------------------------------------------------------------------------------------------------
strFileWilClr       = IniReadPvt ("WilKeywords", "URL", "", strAppIni)
strAppCopyright     = IniReadPvt (strAppProduct, "LegalCopyright", "", strAppIni)
OptAllowOverwrite   = IniReadPvt ("Options", "OptAllowOverwrite", 0, strAppIni)
OptCase             = IniReadPvt ("Options", "OptCase", 4, strAppIni)
OptHtmlShortComment = IniReadPvt ("Options", "OptHtmlShortComment", 0, strAppIni)
OptHtmlSpan         = IniReadPvt ("Options", "OptHtmlSpan", 1, strAppIni)
OptHtmlToClipboard  = IniReadPvt ("Options", "OptHtmlToClipboard", 1, strAppIni)
OptImageBg          = IniReadPvt ("Options", "OptImageBg", "", strAppIni)
OptLastFileIn       = IniReadPvt ("Options", "OptLastFileIn", "", strAppIni)
OptLastFileOut      = IniReadPvt ("Options", "OptLastFileOut", "", strAppIni)
OptLineNumberFiller = IniReadPvt ("Options", "OptLineNumberFiller", " ", strAppIni)
OptLineNumberLen    = IniReadPvt ("Options", "OptLineNumberLen", -1, strAppIni)
OptLineNumberLink   = IniReadPvt ("Options", "OptLineNumberLink", 0, strAppIni)
OptMakeHtmlTag      = IniReadPvt ("Options", "OptMakeHtmlTag", 0, strAppIni)
OptMsgStep          = IniReadPvt ("Options", "OptMsgStep", 10, strAppIni)
OptNoIndentation    = IniReadPvt ("Options", "OptNoIndentation", 0, strAppIni)
OptRGB              = IniReadPvt ("Options", "OptRGB", 0, strAppIni)
OptRunOutput        = IniReadPvt ("Options", "OptRunOutput", 1, strAppIni)
OptPathFold         = IniReadPvt ("Options", "OptPathFold", 0, strAppIni)
OptTabReplaceSize   = IniReadPvt ("Options", "OptTabReplaceSize", 3, strAppIni)
OptVerbose          = IniReadPvt ("Options", "OptVerbose", 0, strAppIni)
OptWinPlaceSetBox   = IniReadPvt ("Options", "OptWinPlaceSetBox", "", strAppIni)
OptWinPlaceSetTitle = IniReadPvt ("Options", "OptWinPlaceSetTitle", "", strAppIni)
OptWriteLogfile     = IniReadPvt ("Options", "OptWriteLogfile", 1, strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
strAppLogoLong = "{1} v{2} {3}          {4}"
strAppLogoLong = StrReplace (strAppLogoLong, "{1}", strAppProduct)
strAppLogoLong = StrReplace (strAppLogoLong, "{2}", strAppVersion)
strAppLogoLong = StrReplace (strAppLogoLong, "{3}", strAppVersionDate)
strAppLogoLong = StrReplace (strAppLogoLong, "{4}", strAppCopyright)
Return
;==========================================================================================================================================



;==========================================================================================================================================
:SetProgIni ; Initialize ini file.
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section WBT2HTML.
strAppCreationDate = "20010729"
strAppCompanyName = "Detlev Dalitz"
strAppCopyright = "(c)" : strAppCreationDate : " " : strAppCompanyName
IniDeletePvt ("WBT2HTML", @WHOLESECTION, strAppIni)
IniWritePvt ("WBT2HTML", "--- Precept = ", "> Do not touch this section! ---", strAppIni)
IniWritePvt ("WBT2HTML", "InternalName", "wbt2html.wbt", strAppIni)
IniWritePvt ("WBT2HTML", "FileVersion", strAppVersion, strAppIni)
IniWritePvt ("WBT2HTML", "FileVersionDate", strAppVersionDate, strAppIni)
IniWritePvt ("WBT2HTML", "FileDescription", "WBT to coloured HTML Script Converter", strAppIni)
IniWritePvt ("WBT2HTML", "OriginalFilename", "WBT2HTML.WBT", strAppIni)
IniWritePvt ("WBT2HTML", "ProductName", strAppProduct, strAppIni)
IniWritePvt ("WBT2HTML", "ProductVersion", "3", strAppIni)
IniWritePvt ("WBT2HTML", "CompanyName", strAppCompanyName, strAppIni)
IniWritePvt ("WBT2HTML", "LegalCopyright", strAppCopyright, strAppIni)
IniWritePvt ("WBT2HTML", "CreationDate", strAppCreationDate, strAppIni)
IniWritePvt ("WBT2HTML", "Contact", "mailto:dd@dalitz-im-netz.de", strAppIni)
IniWritePvt ("WBT2HTML", "InstallPath", udfPathNameLong (FilePath (IntControl (1004, 0, 0, 0, 0))), strAppIni)
IniWritePvt ("WBT2HTML", "YmdHms", TimeYmdHms (), strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section Options.
IniDeletePvt ("Options", @WHOLESECTION, strAppIni)
IniWritePvt ("Options", "OptAllowOverwrite", 0, strAppIni)
IniWritePvt ("Options", "OptCase", 4, strAppIni)
IniWritePvt ("Options", "OptHtmlShortComment", 0, strAppIni)
IniWritePvt ("Options", "OptHtmlSpan", 1, strAppIni)
IniWritePvt ("Options", "OptHtmlToClipboard", 0, strAppIni)
IniWritePvt ("Options", "OptImageBg", "", strAppIni)
IniWritePvt ("Options", "OptLastFileIn", "", strAppIni)
IniWritePvt ("Options", "OptLastFileOut", "", strAppIni)
IniWritePvt ("Options", "OptLineNumberFiller", " ", strAppIni)
IniWritePvt ("Options", "OptLineNumberLen", -1, strAppIni)
IniWritePvt ("Options", "OptLineNumberLink", 0, strAppIni)
IniWritePvt ("Options", "OptMakeHtmlTag", 0, strAppIni)
IniWritePvt ("Options", "OptMsgStep", 10, strAppIni)
IniWritePvt ("Options", "OptNoIndentation", 0, strAppIni)
IniWritePvt ("Options", "OptPathFold", 1, strAppIni)
IniWritePvt ("Options", "OptRGB", 0, strAppIni)
IniWritePvt ("Options", "OptRunOutput", 1, strAppIni)
IniWritePvt ("Options", "OptTabReplaceSize", 3, strAppIni)
IniWritePvt ("Options", "OptVerbose", 1, strAppIni)
IniWritePvt ("Options", "OptWinPlaceSetBox", "700 100 980 400", strAppIni)
IniWritePvt ("Options", "OptWinPlaceSetTitle", "000 000 800 000", strAppIni)
IniWritePvt ("Options", "OptWriteLogfile", 1, strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section Options Info.
IniDeletePvt ("OptionInfo", @WHOLESECTION, strAppIni)
IniWritePvt ("OptionInfo", "--- Precept =", "> Do not touch this section! ---", strAppIni)
IniWritePvt ("OptionInfo", "OptAllowOverwrite..=", "> Suppress dialog when overwriting existing target html file may occur.", strAppIni)
IniWritePvt ("OptionInfo", "OptCase............=", "> 4=Case as defined in WIL.CLR, 3=Uppercase, 2=Lowercase, 1=Leave as is.", strAppIni)
IniWritePvt ("OptionInfo", "OptHtmlShortComment=", "> 0=Standard tag '<!--', 1=Short tag '<!' for use in WinBatch forum.", strAppIni)
IniWritePvt ("OptionInfo", "OptHtmlSpan........=", "> 0=FONT, 1=SPAN.", strAppIni)
IniWritePvt ("OptionInfo", "OptHtmlToClipboard.=", "> 0=No, 1=Yes, put HTML output to Clipboard.", strAppIni)
IniWritePvt ("OptionInfo", "OptImageBg.........=", "> Web related URL to the background image.", strAppIni)
IniWritePvt ("OptionInfo", "OptLastFileIn......=", "> Local URL of recently used input file from AskFilename dialog or from commandline parameter.", strAppIni)
IniWritePvt ("OptionInfo", "OptLastFileOut.....=", "> Local URL of recently used output file.", strAppIni)
IniWritePvt ("OptionInfo", "OptLineNumberFiller=", "> The padchar of the line number.", strAppIni)
IniWritePvt ("OptionInfo", "OptLineNumberLen...=", "> The width of the line number. 0=no number, -1=current max width, n=fix width of n chars.", strAppIni)
IniWritePvt ("OptionInfo", "OptLineNumberLink..=", "> 0=None, 1=A_NAME, 2=A_NAME and A_HREF.", strAppIni)
IniWritePvt ("OptionInfo", "OptMakeHtmlTag.....=", "> 0=PRE tag only, 1=PRE tag embedded in HTML tag.", strAppIni)
IniWritePvt ("OptionInfo", "OptMsgStep.........=", "> The number (1..n) of iterations in the main loop between two screen messages.", strAppIni)
IniWritePvt ("OptionInfo", "OptNoIndentation...=", "> 0=Leave indentation as is, 1=Shift all lines to the left margin.", strAppIni)
IniWritePvt ("OptionInfo", "OptPathFold........=", "> 0=Display filepath from left to right, 1=Display filepath from top to bottom.", strAppIni)
IniWritePvt ("OptionInfo", "OptRGB.............=", "> Font mode: 0='#000000', 1='rgb(0,0,0)'", strAppIni)
IniWritePvt ("OptionInfo", "OptRunOutput.......=", "> Run standard browser application after converting.", strAppIni)
IniWritePvt ("OptionInfo", "OptTabReplaceSize..=", "> Replace each @TAB with n spaces.", strAppIni)
IniWritePvt ("OptionInfo", "OptVerbose.........=", "> Info: 0=none, 1=normal, 2=more, 3=more detailed.", strAppIni)
IniWritePvt ("OptionInfo", "OptWinPlaceSetBox..=", "> Window position on virtual 1000x1000 screen, example '700 100 980 400'", strAppIni)
IniWritePvt ("OptionInfo", "OptWinPlaceSetTitle=", "> Window position on virtual 1000x1000 screen, example '0 0 800 0'", strAppIni)
IniWritePvt ("OptionInfo", "OptWriteLogfile....=", "> 0=No logfile, 1=Inistyle logfile will be created in a WBT2HTML subfolder of the current user tempfolder.", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section "Example settings."
;IniDeletePvt ("Example settings", @WHOLESECTION, strAppIni)
IniWritePvt ("Example settings", "Bracket", "000,128,000", strAppIni)
IniWritePvt ("Example settings", "Special", "000,032,128", strAppIni)
IniWritePvt ("Example settings", "WinPlaceSet Box Horizontal", "100 100 800 300", strAppIni)
IniWritePvt ("Example settings", "WinPlaceSet Box Vertical..", "700 100 999 900", strAppIni)
IniWritePvt ("Example settings", "WinPlaceSet Box Vertical..", "700 100 980 400", strAppIni)
IniWritePvt ("Example settings", "WinPlaceSet Title Bar.....", "000 000 800 000", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section COLORS.
IniDeletePvt ("Colors", @WHOLESECTION, strAppIni)
IniWritePvt ("Colors", "CON", "128,000,128", strAppIni)
IniWritePvt ("Colors", "EXT", "255,000,255", strAppIni)
IniWritePvt ("Colors", "CONSTANT", "000,128,255", strAppIni)
IniWritePvt ("Colors", "WED", "000,128,000", strAppIni)
IniWritePvt ("Colors", "Operator", "032,032,032", strAppIni)
IniWritePvt ("Colors", "Number", "096,000,000", strAppIni)
IniWritePvt ("Colors", "Bracket", "000,000,002", strAppIni)
IniWritePvt ("Colors", "Special", "000,000,001", strAppIni)
IniWritePvt ("Colors", "LineNumber", "160,160,160", strAppIni)
IniWritePvt ("Colors", "Background", "253,253,253", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section Keyword Table.
IniDeletePvt ("TableKeywords", @WHOLESECTION, strAppIni)
IniWritePvt ("TableKeywords", "--- Precept =", "> Do not touch this section! ---", strAppIni)
IniWritePvt ("TableKeywords", "URL", "", strAppIni)
IniWritePvt ("TableKeywords", "FileYmdHms", "", strAppIni)
IniWritePvt ("TableKeywords", "MD5", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section Color Table.
IniDeletePvt ("TableColors", @WHOLESECTION, strAppIni)
IniWritePvt ("TableColors", "--- Precept =", "> Do not touch this section! ---", strAppIni)
IniWritePvt ("TableColors", "URL", "", strAppIni)
IniWritePvt ("TableColors", "FileYmdHms", "", strAppIni)
IniWritePvt ("TableColors", "MD5", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
; The main resource where to find associations of "keyword=color" is the file "WIL.CLR".
; On each run of this script the current "WIL.CLR" file will be checked for changes.
; Usually the "WIL.CLR" is stored in the WinBatch system folder and can be located via filepath 'DirHome() : "WIL.CLR"'
;------------------------------------------------------------------------------------------------------------------------------------------
; Note: For compiled scripts: DirHome () returns the path to the compiled EXE file, ...
; ... but we need the folderpath to "WIL.CLR" within the WinBatch system environment.
;------------------------------------------------------------------------------------------------------------------------------------------
; Create section WIL Keywords.
strFileWilClr = udfGetPathToWilKeywords ()
IniDeletePvt ("WilKeywords", @WHOLESECTION, strAppIni)
IniWritePvt ("WilKeywords", "--- Precept =", "> Do not touch this section! ---", strAppIni)
IniWritePvt ("WilKeywords", "URL", strFileWilClr, strAppIni)
IniWritePvt ("WilKeywords", "FileYmdHms", "", strAppIni)
IniWritePvt ("WilKeywords", "MD5", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
IniWritePvt ("", "", "", strAppIni)
;------------------------------------------------------------------------------------------------------------------------------------------
Return
;==========================================================================================================================================



;==========================================================================================================================================
:WBERRORHANDLER
;------------------------------------------------------------------------------------------------------------------------------------------
WbError = LastError ()
WbTextcode = WbError
If (WbError == 1668 || WbError == 2669 || WbError == 3670)
   ; 1668 ; "Minor user-defined error"
   ; 2669 ; "Moderate user-defined error"
   ; 3670 ; "Severe user-defined error"
   WbError = ItemExtract (1, IntControl (34, -1, 0, 0, 0), ":")
   WbTextcode = -1
EndIf
WbErrorString = IntControl (34, WbTextcode, 0, 0, 0)
WbErrorDateTime = TimeYmdHms () : "|" : StrFixLeft (GetTickCount (), " ", 10) : "|"
If VersionDLL () <= "4.4add" Then WbErrorHandlerFile = IntControl (1004, 0, 0, 0, 0)   ; "4.4add" = "2004A"

; WbErrorFile = StrCat (DirWindows (0), "WWWBATCH.INI") ; Before Windows VISTA.
WbErrorFile = FileLocate (ShortCutDir ("AppData", 0, 0) : "\WinBatch\Settings\WWWBATCH.INI")
IniWritePvt (WbErrorDateTime, "CurrentScript", WbErrorHandlerFile, WbErrorFile)
IniWritePvt (WbErrorDateTime, "ErrorValue", WbError, WbErrorFile)
IniWritePvt (WbErrorDateTime, "ErrorString", WbErrorString, WbErrorFile)
IniWritePvt (WbErrorDateTime, "ScriptLine", WbErrorHandlerLine, WbErrorFile)
IniWritePvt (WbErrorDateTime, "ScriptOffset", WbErrorHandlerOffset, WbErrorFile)
IniWritePvt (WbErrorDateTime, "VarAssignment", WbErrorHandlerAssignment, WbErrorFile)
IniWritePvt ("", "", "", WbErrorFile)

WbErrorMsgText = WbErrorDateTime : @LF : @LF
WbErrorMsgText = WbErrorMsgText : "Current Script:" : @LF : WbErrorHandlerFile : @LF : @LF
WbErrorMsgText = WbErrorMsgText : "LastError value:" : @LF : WbError : @LF : @LF
WbErrorMsgText = WbErrorMsgText : "LastError string:" : @LF : WbErrorString : @LF : @LF
; Line in script that caused Error.
WbErrorMsgText = WbErrorMsgText : "WbErrorHandlerLine:" : @LF : WbErrorHandlerLine : @LF : @LF
; Offset into script of error line, in bytes.
WbErrorMsgText = WbErrorMsgText : "WbErrorHandlerOffset:" : @LF : WbErrorHandlerOffset : @LF : @LF
; Variable being assigned on error line, or "" if none.
WbErrorMsgText = WbErrorMsgText : "WbErrorHandlerAssignment:" : @LF : WbErrorHandlerAssignment : @LF : @LF
If WbErrorHandlerAssignment != "" Then %WbErrorHandlerAssignment% = "eeek"
ClipPut (WbErrorMsgText)
WbErrorMsgText = WbErrorMsgText : "Note: This error message is just copied to the clipboard for further usage."
Message (strAppProduct : " - WinBatch Error Handler", WbErrorMsgText)
Exit
;==========================================================================================================================================


;==========================================================================================================================================
; Changelog of WBT2HTML Version 3.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110327 Version 3.13b
;   - Changed:
;     - Changed section AddLineNumber from methods FileRead/FileWrite to ArrayFileGet/ArrayFilePut.
;     - Removed sections CreateTempFilenames, DeleteTempFilenames from the script, moved the involved code lines into the main section.
;     - TimeDelay for invoking the browser set up from 2 to 3 seconds.
;   - Added
;     - Added a first and second case in udfGetParams to check whether the file exists and if so, then get the long pathname.
;   - Removed
;     - Removed the usage of the second temp file from the script.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110308 Version 3.13a
;   - Changed:
;     - The function udfGetFileChecksum has been replaced by native function FileDigest.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110307 Version 3.13
;   - Changed:
;     - The program flow during the start phase has been changed slightly.
;     - The way of getting the temporary folderpath has been changed.
;     - The way of creating the temporary filenames has been changed.
;     - The way of checking initial setup and changes in associated files in section CheckProgIni has been changed.
;     - SubRoutine udsGetParams has been changed to Function udfGetParams.
;     - Replaced GoSub CreateListColorNamesUsed by Function udfGetListColorsUsed.
;     - Set maximum line length for FileRead to 8192 Bytes via IntControl 65 at start of the script.
;     - Names changed in Ini-file, section from [USER] to [Options], options from "Use..." to "Opt"..."
;     - Names changed in Ini-file, section from [USERINFO] to [OptionInfo]."
;     - Names changed in Ini-file, section from [COLORS] to [Colors]."
;     - Renamed user option OptClipPut to OptHtmlToClipboard.
;     - Some small changes here and there.
;   - Added:
;     - Function udfGetListColorsUsed.
;     - Function udfGetTempFolder.
;     - Function udfGetLogFolder.
;     - Function udfAskDirectory.
;     - Added a browse for folder dialog for selecting a folder for temporary files.
;       in case of the system standard temp folder cannot be accessed.
;     - Added a browse for folder dialog for selecting a folder for the log file
;       in case of the standard log folder cannot be accessed.
;     - Added user option "OptLastFileIn", which holds the filepath of the recently used input file
;       from the AskFilename dialog or from the commandline parameter.
;     - Added user option "OptLastFileOut", which holds the filepath of the recently used output file.
;   - Removed:
;     - Section CheckTempFolder.
;     - User Option "OptAskFilename" has been removed.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110305 Version 3.12b
;   - Changed:
;     - The way of getting the input filename via commandline or user dialog.
;     - The way of checking the input filename.
;     - The way of color datatype conversion in section CreateTableColors.
;       Color conversion from RGB to Hex now uses a BinaryBuffer solution.
;   - Added:
;     - Function udfAskYesNo
;     - Function udfAskFilename
;     - SubRoutine udsGetParams
;   - Removed:
;     - Function 'udfByteToHex' (replaced by conversion using a BinaryBuffer).
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110303 Version 3.12a
;   - Changed:
;     - The way of creating the list of characters, which have to be HTML encoded, has been changed.
;       Building the list by loop from 1 to 255 has been replaced by hardcoded hex string, to be converted by function ChrStringToHex().
;       This change speeds up initial loading of the script.
;     - The way of counting total number of input lines has been changed. ItemCount function has been replaced by ArrayFileGet function.
;     - Display the filepath in message boxes now folded by default.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20110301 Version 3.12
;   - Changed:
;     - Overall changes in the code, mostly cosmetics.
;     - Removed my xCAM array extender completely from the code.
;     - Functionality of direct access on associative array has been replaced by binary search access on sorted array.
;     - Script now uses WinBatch native array functions:
;       ArrayFileGetCSV, ArrayFilePutCSV, ArrayFromStr, Arrayize, ArrayRedim, ArraySearch, ArraySort, ArrDimension.
;     - Due to removing the xCAM array extender, the array dump file format has been changed to simple CSV format.
;     - Changes made in the "WIL.CLR" file will be reflected by DateTime stamp check, as usual.
;       User will be notified and a new CSV style keyword table dump file will be created automatically.
;     - On each run a current CSV style color table dump file will be created automatically.
;   - Added:
;     - New user options: OptClipPut, OptHtmlSpan, OptPathFold, OptWinPlaceSetBox, OptWinPlaceSetTitle.
;       - OptClipPut: controls whether the HTML output additionally should be copied to the Clipboard or not.
;       - OptHtmlSpan: controls whether HTML tag <FONT> or <SPAN> will be used.
;       - OptPathFold: useful when having vertical stretched window placement, filepath will be folded vertically.
;       - OptWinPlaceSetBox: preset a box window placement for the status information window while colorizing.
;       - OptWinPlaceSetTitle: preset a window title bar placement for the status information window while colorizing.
;     - Primitive user dialog feature.
;       User can choose the HTML comment tag style for normal HTML usage or crippled for WinBatch BBS posting.
;   - Removed:
;     - The copy process for the file "WIL.CLR" to a working file "MyWilClr" has been removed, it is simply not necessary.
;       WB Studio keyword file "WIL.CLR" will be used as the main resource for standard writing and colorizing, as usual.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20090709 Version 3.11
;   - Changed: All (= 96) StrCat() functions have been replaced by the colon ":" string concatenator.
;              Script reformatted with Les Ferch's Beautifier.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20090416 Version 3.10
;   - Added: UDF "udfGetGUID" for setting the name attribute of the <pre> section in html output to a GUID.
;   - Changed: Name of UDF "udfFileCheckSum" to "udfGetFileCheckSum".
;   - Changed: GoSub AddLineNumber: Name of Variable "strMaskAnchorNameId" to "strMaskAnchorId".
;   - Changed: GoSub AddLineNumber: Name of Variable "strAnchorNameId" to "strAnchorId".
;   - Changed: GoSub AddLineNumber: strMaskAnchorId set to line number only, no longer FileCRC info as id content.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20090404 Version 3.09
;   - Small changes in procedures GetParams and AskParams regarding detection of commandline parameter.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20081018 Version 3.08
;   - Some small changes, mostly cosmetics, for better readability of script code.
;   - Remember last used input filename in inifile for AskFilename dialog.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20080824 Version 3.07
;   - Some small changes, mostly cosmetics.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20040319 Version 3.06
;   - Changed "#0" to "#000000" because of css / htm compatibility.
;   - Workaround changes in "GoSub CollectColors" because of new WB2004B Beta version.
;   - Added wbErrorHandlerFile variable and 'if-then-construct' for WinBatch versions less equal than 2004A.
;   - Added "Background" color in section COLORS of wbt2html.ini.
;   - Added "." (point) to the string of stopchars.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20031030 Version 3.05
;------------------------------------------------------------------------------------------------------------------------------------------
;   20031026 Version 3.04
;   - Fixed some typographic errors.
;   - Fixed awkward usage of "Goto CANCEL" in procedure "GetParams".
;   - Removed some code that has been become unnecessary because of new xCAM extender functionalities.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20030910 Version 3.03
;   - Added an ini option 'OptHtmlShortComment' to set the opening html comment tag
;     as used in WinBatch BBS Forum or leave it as the standard tag.
;     'OptHtmlShortComment=0' ... Standard tag '<!--'
;     'OptHtmlShortComment=1' ... Short tag '<!'
;------------------------------------------------------------------------------------------------------------------------------------------
;   20030905 Version 3.02
;   - When encoding named entities, the ampersand has been encoded twice.
;     First, as it comes out of the text, and second, from the previously replaced named entity code sequence.
;     This error has been fixed by putting the ampersand char in front of the chars to be encoded, see variable sEncChars.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20030801 Version 3.01
;   - Fixed some minor errors.
;------------------------------------------------------------------------------------------------------------------------------------------
;   20030726 Version 3.00
;   - This version 3 release is an alternative programming approach on marking up a wbt script
;     with html font tags giving a colourful "colorized" html page.
;     This version 3 uses a line related, one pass method, which perhaps runs a little bit faster
;     than the file related, two pass, method, which has been introduced in WBT2HTML version 1 and 2,
;     because it has less complicated code.
;==========================================================================================================================================


; WSP-USER.MNU menu code snippet.
WBT2HTM&L
 WBT2HTM&L
    Switch FileExist (wGetFilename ())
    Case 1
       If !(1 & FileAttrGetEx (wGetFilename ())) Then wFileSave ()
       Break
    Case 0
       wFileSave ()
       Break
    Case 2
       Message ("Terminated", "File is currently open by another application in read deny mode." : @LF : wGetFilename ())
       Return
    EndSwitch
    Run (DirHome () : "WinBatch.exe", FileNameShort ("W:\WINBATCH\PROD\WBT2HTML\WBT2HTML.v313.wbt") : " " : FileNameShort (wGetFilename ()))
    Return
 &Text To WBT2HTML
    Call ("W:\WINBATCH\PROD\WBSTUDIO\WBStudio.TextToWBT2HTML.wbt", 0)
    Return
 Open &Ini File
    wFileOpen ("W:\WINBATCH\PROD\WBT2HTML\WBT2HTML.ini")
    Return