!

! (c) Copyright 2010-2013, Sage Software Canada Ltd. (Ontario, Canada)

 

/*

 * Build information:

! ** @Author Fred McGuirk

 

! ** This observer will scan the current source file (in the build process) and

! ** remove all lines with duplicate line numbers; if the source file does not

! ** have line numbers, this observer will do nothing.

 */

 

def class "del_dupe_lines"

       like "EventManagerObserver"

 

       ! ** Private property to maintain the name of the temporary file that is created

       ! ** during the Pre-Process so that it can be deleted during the Post-Process.

       local tempSourceFile$

 

       ! ** Override values for description / NotificationFlag

       local theDescription$="Remove lines with duplicate line numbers"

       local theNotificationFlag=_pvxConstants'_idePrePostProcess

 

       ! ** Internal method to scan source file and remove remark lines with duplicate line numbers

       ! ** @param theSrcFile The source file to be processed

       ! ** @param newSrcFile The modified version of the source file

       ! ** @returns A simple boolean (0=False, 1=True) to indicate if any modifications were made

       function local processFile(theSrcFile$,newSrcFile$)                  processFile

 

/*

       ! ** The logic to be executed when the observer is triggered.  This logic must

       ! ** check the major and minor codes to determine the current event and then

       ! ** decide what action is to be performed.

       ! **

       ! ** If this observer is set to watch both Pre-Process and Post-Process states

       ! ** for events, the logic in the 'update' method must check the state of the

       ! ** _pvxState'getArgument(_pvxConstants'_iEventNotificationFlag$) flag to

       ! ** determine the appropriate code to be executed.

       ! **

       ! ** @param state A reference to an object of class %PvxClass(PvxState)%

 */

       function update(initPvxState)                                                     update

end def

 

/*

 * The update routine will be executed by the event manager during the

 * pre/post process logic depending on how this observer registers

 * itself through the getEventNotification() method.

 */

update:

enter aPvxState

 

       local oPvxUtility,psMajor$,psMinor$,source,tempSourceFile$,enfState,x

 

       ! Get the Major/Minor codes that identify the current action

       psMajor$=aPvxState'getMajor$(), \

       psMinor$=aPvxState'getMinor$()

 

       /*

        * This observer is for the program build event only; all other events

        * should be ignored.

        */

       if (psMajor$=_pvxConstants'Incremental_Build$ \

                     or psMajor$=_pvxConstants'Incremental_Build_Alt_Exe$) \

              and psMinor$=_pvxConstants'BuildType_BuildOne$ {

 

              ! Check the current state of processing for the ProvideX Event Manager

              enfState=aPvxState'getArgumentValue(_pvxConstants'_iEventNotificationFlag$)

              switch enfState

              case _pvxConstants'_idePreProcess

 

                     ! Get the the source file associated with the current action

                     source$=aPvxState'getArgumentValue$(_pvxConstants'SrcFile$)

 

                     /*

                      * Get a temporary file to be used as new source

                      */

                     oPvxUtility=new("pvx_utility")

                     tempSourceFile$=oPvxUtility'getWorkFile$("WRK_dup_lines")

                     drop object oPvxUtility

 

                     ! Create a new temporary file

                     serial tempSourceFile$,err=*next

 

                     ! Process this Source File to remove remarks and place modified version into the tempSourceFile$

                     isModified=_obj'processFile(source$,tempSourceFile$)

                     if isModified {

                           ! Update task state information to override the source file

                            aPvxState'setArgument(_pvxConstants'SrcFile$,tempSourceFile$)

                     } else {

                           erase tempSourceFile$,err=*next

                           tempSourceFile$=""

                     }

                     break

              case _pvxConstants'_idePostProcess

                     ! erase the temporary source file

                     if not(nul(tempSourceFile$)) {

                           erase tempSourceFile$,err=*next

                           tempSourceFile$=""

                     }

                     break

              end switch

       }

return 0

 

processFile:

       enter (theSourceFile$),(newSourceFile$),err=*next

       local lastLine,lineFeeds,thisLine,outFN,oPvxUtility,pgmLine$,pr,retVal,srcText$,theType,wrkfile$

 

       /* Now, to update the source file based on user preferences */

       pr=new("program_reader",theSourceFile$,err=*next)

       if pr {

              theType=pr'getSourceFileType()

              /*

               * Skip any source file that is not a test file or does not have line numbers.

               */

              if theType<>1 or not(pr'hasLineNumbers()) {

                     drop object pr; pr=0

              }

       }

 

       if pr {

              open lock (hfn,err=*next)newSourceFile$;

              outFN=lfo

              if outFN {

                     lastLine=0

                     oPvxUtility=new("pvx_utility")

                     /*

                      * Read through the source file and check:

                      * - source file is using line numbers

                      * - drop duplicate line number

                      */

                     while not(pr'getEOF())

                           pgmLine$=pr'read$()

                           if not(pr'getEOF()) {

                                  srcText$=pr'getSourceText$()

                                  srcText$=oPvxUtility'stripBlockComments$(srcText$)

                                  /*

                                   * Do NOT replace non-ASCII characters to allow accented

                                   * characters to remain in the final tokenized program; just

                                   * remove known control characters

                                   */

                                  srcText$=sub(srcText$,$09$," ",0) /* Replace all TAB characters */

                                  srcText$=sub(srcText$,$0D$,"",0/* Remove all CR characters */

                                  /*

                                   * Keep track of the number of LineFeeds in original source line;

                                   * strip the trailing linefeeds - they will be added back on later

                                   */

                                  lineFeeds=pos($0A$=srcText$,1,0)

                                  srcText$=stp(srcText$,2,$0A$)

                                  if nul(srcText$) {

                                         srcText$=""

                                  } else {

                                         /*

                                          * This logic will assume that the line number is either 4 or 5

                                          * characters in length followed by a space and will therefore

                                          * simply check the first five characters of the source line to

                                          * get the line number.  This logic can be easily changed to

                                          * look for the first space in the line and then use the value

                                          * before the space as the line number.

                                          */

                                         thisLine=num(mid(srcText$,1,5),err=*break)

                                         /*

                                          * Check:

                                          *   - line number ZERO

                                          *   - duplicate line number

                                          * If either condition is true:

                                          *   - Clear Source Text

                                          *   - Set return value to indicate source file has changed

                                          *

                                          * This logic can be easily enhanced to restrict the duplicate

                                          * line number check to only REMARK lines, for exanple by

                                          * capturing the position of the first directive in the source

                                          * line and adding a check in the condition below.

                                          */

                                         if thisLine<1 or thisLine=lastLine {

                                                srcText$="", \

                                                retVal=1

                                         }

                                         if thisLine>0 { lastLine=thisLine }

                                  }

                                  /*

                                   * Add Line Feeds to END of source text to maintain line

                                   * reference count with original source file

                                   */

                                  srcText$+=dim(lineFeeds,$0A$)

                                  write record(outFN)srcText$

                           }

                     wend

                     close (outFN)

                     drop object oPvxUtility; oPvxUtility=0

              }

              drop object pr; pr=0

       }

return retVal

 

end