How to strip/merge comments from/to WBT source file?
;==========================================================================================================================================
;
; How to strip/merge comments from/to WBT source file?
;
;==========================================================================================================================================


;==========================================================================================================================================
; Name:
;    StripAndMergeComments.wbt
;
; Purpose:
;    Remove comments from WinBatch source code file.
;    Create related comment list file.
;    Create new anonymous comment-less wbt code file for production environment.
;    Merge previously stripped comments with production code file giving back complete source code file.
;
; Note:
;    This feasibility study contains only rudimentary error or consistency checking.
;
;------------------------------------------------------------------------------------------------------------------------------------------
;
; Author:
;    Detlev Dalitz.20090411.20120110.
;
; With contributions from:
;    Les Ferch.20090410.
;
; Based on the motivating request from:
;    Doug Blaze.20090410.
;
;------------------------------------------------------------------------------------------------------------------------------------------
;
; This theme is based on:
;
; Topic: Remove comments from code
; Conf:  WinBatch
; From:  dblaze1
; Date:  Friday, April 10, 2009 01:14 PM
;
; We're going to be undergoing a security audit that includes reviewing our coding policies and
; ... we were told by a QSA consultant that it is bad practice to have commented code in a production environment.
; ... He said it just gives information to someone who breaks in and gets hold of the code - which makes sense.
; ... He said the correct way of doing it is to make a production copy in which all comments are removed.
; ... Now, I don't know about the rest of you, but I add lots of comments to my code and it would take forever
;     to have to remove them all before moving to a production environment.
; ... Has anyone heard of this before?
; ... Has anyone attempted to do this with Winbatch?
; Thanks,
; Doug
;==========================================================================================================================================


; Test comment 1.
      ; Test comment 2. : This comment is intentionally indented.
; Test comment 3.


GoSub Define_Functions

blnResult = DirChange (DirScript ())
strThisScript = IntControl (1004, 0, 0, 0, 0)

; The original source file.
; strFileWbt = "W:\Folder\WinbatchScriptFile.wbt"
strFileWbt = strThisScript ; We use this script file as test input.

; Files to be created.
strFileProd = ItemReplace (`prod.wbt`, -1, strThisScript, `.`)       ; The "Production File': to be used in the wild.
strFileComment = ItemReplace (`comment.txt`, -1, strThisScript, `.`) ; The 'Comment File' ..: to be used for maintenance purposes.
strFileMerged = ItemReplace (`merged.wbt`, -1, strThisScript, `.`)   ; The 'Merged File' ...: to be used for maintenance purposes.


:Step1 ; Remove comments from wbt script and save them to external CSV file.
udfRemoveWbtComments (strFileWbt, strFileProd, strFileComment)


:Step2 ; Restore comments from external CSV file.
If udfCheckFileCsv (strFileComment, ",", @TRUE)
   udfRestoreWBTComments (strFileMerged, strFileComment)
EndIf


:Step3 ; Display all involved files.
strWBStudio = DirHome () : `WinBatch Studio.exe`
Run (strWBStudio, `"` : strFileProd : `"`)
Run (strWBStudio, `"` : strFileComment : `"`)
Run (strWBStudio, `"` : strFileMerged : `"`)

:CANCEL
Exit


;==========================================================================================================================================
:Define_Functions
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfSplitWbtCodeLine (strLine)
y = 0
z = 0
strQuoteChars = `'` : `"` : "`"
While @TRUE
   x = StrScan (strLine, strQuoteChars, y + 1, @FWDSCAN)
   If x == 0 Then Break
   strQuoteChar = StrSub (strLine, x, 1)
   z = y
   y = StrIndex (strLine, strQuoteChar, x + 1, @FWDSCAN)
   If y == 0
      y = z
      Break
   EndIf
EndWhile
x = StrIndex (strLine, `;`, y + 1, @FWDSCAN)
strComment = ``
If x > 0
   strComment = StrSub (strLine, x, -1)
   strLine = StrSub (strLine, 1, x - 1)
EndIf
Return Arrayize (strLine : @LF : strComment, @LF)
;..........................................................................................................................................
; This UDF "udfSplitWbtCodeLine" was originally designed to remove a comment which follows the code on the same line.
; Now the returning dim-1 array contains both parts of the line: the code part and the comment part.
;
; Les Ferch.20090410.
; Detlev Dalitz.????????.20090411.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfRemoveWbtComments (strFileWbt, strFileProd, strFileComment)
arrData = ArrayFileGet (strFileWbt)
intDataLines = ArrInfo (arrData, 1)
intDataLast = intDataLines - 1
arrNew = ArrDimension (intDataLines)
arrComment = ArrDimension (intDataLines + 1, 3) ; Dim-2 array, will be saved as CSV array.
intNumberFmt = StrLen (intDataLines) ; Measure width of the last line number.
intCommentNr = 0
For intElem = 0 To intDataLast
   strLine = arrData [intElem]
   intLineNr = intElem + 1
   If 1 == StrIndex (StrTrim (strLine), `;`, 1, @FWDSCAN)
      intCommentNr = intCommentNr + 1
      strCommentFmt = StrFixLeft (intCommentNr, `0`, intNumberFmt)
      strLineNrFmt = StrFixLeft (intLineNr, `0`, intNumberFmt)
      arrComment [intElem, 0] = strLineNrFmt
      arrComment [intElem, 1] = strCommentFmt
      arrComment [intElem, 2] = StrTrim (strLine)
      arrNew [intElem] = StrFill (` `, StrIndex (strLine, `;`, 1, @FWDSCAN) - 1) : `; #` : strCommentFmt
   Else
      arrTmp = udfSplitWbtCodeLine (strLine)
      arrNew [intElem] = arrTmp [0]
      If arrTmp [1] != ``
         intCommentNr = intCommentNr + 1
         strCommentFmt = StrFixLeft (intCommentNr, `0`, intNumberFmt)
         strLineNrFmt = StrFixLeft (intLineNr, `0`, intNumberFmt)
         arrComment [intElem, 0] = strLineNrFmt
         arrComment [intElem, 1] = strCommentFmt
         arrComment [intElem, 2] = arrTmp [1]
         arrNew [intElem] = arrTmp [0] : `; #` : strCommentFmt
      EndIf
   EndIf
Next
arrComment [intDataLast + 1, 0] = intDataLines
arrComment [intDataLast + 1, 1] = strCommentFmt
arrComment [intDataLast + 1, 2] = strFileProd
intBytesWritten = ArrayFilePutCSV (strFileComment, arrComment)
intBytesWritten = ArrayFilePut (strFileProd, arrNew)

; For sure delete empty lines from comment file.
strData = FileGet (strFileComment)
strSearch = @CRLF : @CRLF
While !!StrIndex (strData, strSearch, 1, @FWDSCAN)
   strData = StrReplace (strData, strSearch, @CRLF)
EndWhile
intBytesWritten = FilePut (strFileComment, strData) ; Test comment 4. : This comment is inline.
Return
;..........................................................................................................................................
; This UDF "udfRemoveWbtComments" removes comments from WBT source text ...
; ... and creates two text files:
;    - the 'Production File', with all the literal comment strings replaced by placeholder token;
;    - the 'Comment File', with all the comments from the original wbt script file.
;
; Les Ferch.20090410.
; Detlev Dalitz.20090411..20120110.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfRestoreWBTComments (strFileMerged, strFileComment)
arrComment = ArrayFileGetCSV (strFileComment, 0, `,`)
intCommentLines = ArrInfo (arrComment, 1)
intCommentLast = intCommentLines - 1

strFileWbt = arrComment [intCommentLast, 2]
intCommentLast = intCommentLast - 1

arrData = ArrayFileGet (strFileWbt)
intDataLines = ArrInfo (arrData, 1)
intDataLast = intDataLines - 1

For intElem = 0 To intCommentLast
   intLineNr = arrComment [intElem, 0]
   intCommentNr = arrComment [intElem, 1]
   intCommentText = arrComment [intElem, 2]

   strTemp = arrData [intLineNr - 1]
   strTemp = StrReplace (strTemp, `; #` : intCommentNr, intCommentText)
   arrData [intLineNr - 1] = strTemp
Next

intBytesWritten = ArrayFilePut (strFileMerged, arrData)
Return
;..........................................................................................................................................
; This UDF "udfRestoreWBTComments" restores all the comments from the comment ressource CSV file ...
; ... and creates the 'Merged' file with all the code lines and comments merged together, giving back the original WBT source file.
;
; Detlev Dalitz.20090411.20120110.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;-----------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfCheckFileCsv (strFileCsv, strDelimiter, blnTrim)
IntControl (72, 1, @TRUE, "", 0) ; On next cancel event goto label :CANCEL.
IntControl (73, 0, @TRUE, "", 0) ; p2=0 Normal error processing (default).
blnResult = @TRUE
If !!blnTrim Then udfTrimFile (strFileCsv) ; Remove leading and trailing empty lines.
intLastEM = ErrorMode (@OFF)
LastError ()
arrCsv = ArrayFileGetCSV (strFileCsv, 0, strDelimiter)
intLastError = LastError ()
ErrorMode (intLastEM)
If intLastError > 0   ; Possible error message can be: 1808 File contains invalid CSV line(s).
   blnResult = @FALSE
   Pause ("udfCheckFileCsv | Error in CSV File", "File: " : strFileCsv : @LF : @LF : wberroradditionalinfo : @LF : @LF : "Repair CSV data and try again.")
EndIf
:CANCEL
Return blnResult
;..........................................................................................................................................
; This UDF "udfCheckFileCsv" is a simple helper to check a given CSV file for possible formatting errors.
;
; The checkup itself relies on the built-in rules of the WinBatch function ArrayFileGetCSV.
; If an input line cannot be accepted to be a correct CSV line, then the function ArrayFileGetCSV
; returns the minor error "1808 File contains invalid CSV line(s)" and provides a hint on which line the error has been occurred.
; This UDF catches the error and offers a simple message to the user.
;
; This UDF expects that the given CSV File
; - has @CRLF end of line delimiters;
; - has not any @TAB character;
; - allows read and write access when removing leading and trailing empty lines.
;
; This UDF returns the boolean value @TRUE (1) or @FALSE (0) to indicate that the given file can be used as a CSV file or not.
;
; Detlev Dalitz.20100814.20120110
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfTrimFile (strFilename)
strText = FileGet (strFilename)
If strText == "" Then Return 0 ; No Change.
If strText == @CRLF Then Return FilePut (strFilename, "") ; Write empty file.
strText = StrTrim (FileGet (strFilename))
If strText == "" Then Return FilePut (strFilename, "") ; Write empty file.
intPosL = 1
While intPosL == StrIndex (strText, @CRLF, intPosL, @FWDSCAN)
   intPosL = intPosL + 2
EndWhile
intPosR = StrByteCount (strText, -1) - 1
While intPosR == StrIndex (strText, @CRLF, intPosR, @FWDSCAN)
   intPosR = intPosR - 2
EndWhile
strText = StrSub (strText, intPosL, 2 + IntPosR - intPosL) : @CRLF
If strText == FileGet (strFilename) Then Return 0 ; No change.
Return FilePut (strFilename, strText) ; Write trimmed file.
;------------------------------------------------------------------------------------------------------------------------------------------
; This UDF "udfTrimFile" removes leading and trailing blank lines from the given text file.
; The return value is the number of bytes written to the disk file.
;
; Detlev Dalitz.20120110.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;==========================================================================================================================================
Return ; from GoSub Define_Functions
;==========================================================================================================================================


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Reduced example of an anonymous comment-less wbt production file.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;   ; #001
;   ; #002
;   ; #003
;   ; #004
;   ; #005
;   ; #006
;   ; #007
;   ; #008
;   ; #009
;
;   ; #010
;   #DefineFunction StripComment (strLine)
;   ...
;   #EndFunction
;
;   ; #011
;   #DefineFunction RemoveWBTComments (strFileWbt, strNewFile, strFileComment)
;   ...
;      intLineNr = intElem + 1
;      ; #012
;      If StrSub (StrTrim (strLine), 1, 1) == `;`
;   ...
;   intBytesWritten = ArrayFilePut (strNewFile, arrNew)
;
;   ; #013
;   strData = FileGet (strFileComment)
;   ...
;   #EndFunction
;
;   ; #014
;   blnResult = DirChange (DirScript ())
;   strThisScript = IntControl (1004, 0, 0, 0, 0)  ; #015
;   ...
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; CSV-Format of the related comment file.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Comment entries:
; Col-1 = Line number within code file.
; Col-2 = Comment number.
; Col-3 = Comment text.
;
; Footer line:
; Col-1 = Number of lines in production file.
; Col-2 = Number of comment replacements.
; Col-3 = Filepath to the corresponding production file.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; "001","001",";~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
; "002","002","; Name: StripComments.wbt"
; "003","003",";          Create new anonymous comment-less wbt code file."
; "005","005",";          Create related comment list file."
; "006","006",";~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
; "007","007","; Author: Les Ferch."
; "008","008","; Modified by: Detlev Dalitz.20090411."
; "009","009",";~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
; "011","010","; This function is called by the main function to remove comments on same Line as code."
; "036","011","; Call this function to remove comments from WBT source."
; "048","012","; Test: This comment is indented."
; "070","013","; Delete empty lines from comment file."
; "079","014","; Test."
; "081","015","; Test: This comment is inline."
; "119","015","W:\WINBATCH\TEST\2009\20090410.Test.Remove comments from code.prod.wbt"
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~