Writing a MACRO for a macro controlled string CHANGE

Writing a MACRO for a macro controlled string CHANGE


Structure of a MACRO for use in a Macro Controlled CHANGE


A macro to be used in a Macro Controlled CHANGE command (let's call these E-macros for short) communicates with the CHANGE command via two reserved macro functions:


Get_E_Source$()

This macro function will return the value of the string which was successfully found by the CHANGE command


Set_E_Result()

This macro function is used to pass back to CHANGE the string which is to replace the found string.


A macro can utilize whatever logic is needed to determine what it will pass back as a string to be used by CHANGE.


Initialization and Execution Calls


Since the macro may have optional operands which may require validation, or have other activities which may need to be performed on a one time basis, the E-macro will be called once per CHANGE command to allow this initialization to be performed.  Subsequently, the macro will be called once per found string to perform the actual CHANGE processing.   These are called the Initialization and Execution calls.  


For example, a command CHANGE ALL P"@@##" E"MyMacro" would be called once for Initialization and repeatedly for Execution as the CHANGE command locates each matching search string.


So how does the macro know which call is being made?

Since SPFLite FIND and CHANGE cannot 'find' a null string, the Initialization call is identified by Get_E_Source$() returning a null string.   Any returned non-null string is an Execution call.


Failing an Initialization Call

If, during the Initialization call, the E-macro determines it has a problem with the macro operands, or some other failure in initialization, it should exit the macro via a Halt(FAIL, "Error message describing the failure") command.


Successful Initialization Call

If Initialization is successful, the E-macro should exit with a Halt("OK") command.


Not all E-macros will require any processing at Initialization time, but must still be prepared to handle the call itself.   All that is required for that is a simple one line at the start of the macro containing

     if Get_E_Source$() = "" then Halt("OK")


Results from Execution Calls


There is no support for error returns from Execution calls.   Your E-macro must return a new CHANGE value via Set_E_Result(), even if it is simply a copy of the found string, or null.  It may return an Error message, but doing so will not terminate CHANGE processing.  i.e. a CHANGE ALL will continue normally.


Example / Case study


Following is an example of an E-macro.   This macro performs a table lookup to locate and return a replacement string for the found string.   The table of old/new string values is maintained in an external table file so that the E-macro itself does not need to be altered as the table data changes.


Since the table is an external file, we certainly do not want to have to Open and read the file for every CHANGE command, so the macro will only do this on the Initialization call and will keep the table resident.  This means all Execution calls will not require external file access.


The Initialization code starts off with:


str = Get_E_Source$()                                 ' Get the passed found string  

if str = "" then                                      ' If null, its the initialize call  

  TableLoaded = Get_Gbl_Num("TableLkupOK")           ' See if table already loaded  

  if TableLoaded > 0 then                            ' Yes, say all is well  

     Set_E_Result("OK")                              ' and

     Halt(OK)                                        ' exit quickly

  end if                                             '


It starts with the standard test for the Initialization call and then checks the Global variable TableLkupOK which is used to track whether the table file has already been loaded.   If it has, it simply returns "OK" to indicate initialization is complete.


Next is the routine to load the external file when needed


'----- Need to load the table file

  fHandle = FILE_OPEN("D:\Documents\SPFLite\Macros\TableLkup.Data", "INPUT")

  if fHandle = 0 then halt(fail, "TableLkup.Data load failed, cannot open file")

  do while isfalse file_eof(fHandle)                 ' read file

     dline = FILE_LineInput(fHandle)                 ' Get a line


     '-----  Create a lookup key by preceding the string with "TL_"

     operand1 = "TL_" + parse$(dline, ",", 1)        ' Build key by prefixing with TL_          

     operand2 = parse$(dline, ",", 2)                ' Extract the return data          

     Set_Gbl_Str(operand1, operand2)                 ' Save entry in table in Global storage

  loop                                               '

  i = FILE_Close(fHandle)                            ' Close file, we're done

  Set_Gbl_Num("TableLkupOK", 1)                      ' Remember we've loaded the table

  Set_E_Result("OK")                                 ' Tell mainline we're done

  Halt(OK)                                           '

This code uses the standard thinBasic FILE module for File access.   If the file does not open successfully, it shows how to exit with an error message.


The table is stored using the normal SPFLite Global string support.   The lookup keys are prefixed with TL_ to make them unique in global storage.


' The external file is only loaded once per SPFLite session.  The format is simply

' 2 entries per line separated by a comma.  e.g.

'  AA12,ABCD

'  AA13,ABCE

'  BB01,DEFG

'  CC99,HIJK

'  XX00,ZZZZ


The remainder of the macro is the execution call


'----- It's the normal execution call

else

  operand1 = "TL_" + str                             ' Build lookup key

  operand2 = Get_Gbl_Str$(operand1)                  ' Fetch the data

  ErrMsg = Get_Msg$                                  ' Catch any error message

  if Get_RC = 0 then                                 ' If OK, pass back answer  

     Set_E_Result(operand2)                          '

     halt(ok)                                        ' return

  else                                               '

     Set_E_Result(str)                               ' Pass back unchanged string

     halt(Fail, "TableLkup: " + ErrMsg + " in line: " + format$(Get_LNum(Get_Find_Lptr)))  ' Else error

  end if                                             '  

end if


This routine simple uses the found string to build the table lookup key, fetches the replacement string and passes it back via Set_E_Result().


If the lookup fails, it passes back the original string and issues an error message.   Even though an error does not interrupt a CHANGE ALL type command, the error messages are stacked and made available to the user via a HELP command immediately after the CHANGE command completes.


Here's the complete E-macro for review:


' TableLkup.macro

'

' This macro shows how to use an E'xxxx' macro to provide a table lookup

' facility.  The macro is invoked as part of a normal CHANGE command

'   e.g.   CHANGE P'@@##' WORD ALL E'TableLkup'

' This command searches for all 'words' consisting of 2 Alpha and 2 numeric characters,

'

' The located words are passed to this routine to be replaced via a table lookup of

' an external table (in this case in the file 'TableLkup.data')

' The external file is only loaded once per SPFLite session.  The format is simply

' 2 entries per line separated by a comma.  e.g.

'  AA12,ABCD

'  AA13,ABCE

'  BB01,DEFG

'  CC99,HIJK

'  XX00,ZZZZ


uses "FILE"                                           ' Attach the FILE module

dim str, dline, operand1, operand2, ErrMsg as string

dim fHandle as dword

dim i, TableLoaded as number


'----- See if this is an initialize call, if so, load the table

str = Get_E_Source$()                                 ' Get the passed found string  


if str = "" then                                      ' If null, its the initialize call  

  TableLoaded = Get_Gbl_Num("TableLkupOK")           ' See if table already loaded  

  if TableLoaded > 0 then                            ' Yes, say all is well  

     Set_E_Result("OK")                              ' and

     Halt(OK)                                        ' exit quickly

  end if                                             '

  '----- Need to load the table file

  fHandle = FILE_OPEN("D:\Documents\SPFLite\Macros\TableLkup.Data", "INPUT")

  if fHandle = 0 then halt(fail, "TableLkup.Data load failed, cannot open file")

  do while isfalse file_eof(fHandle)                 ' read file

     dline = FILE_LineInput(fHandle)                 ' Get a line


     '-----  Create a lookup key by preceding the string with "TL_"

     operand1 = "TL_" + parse$(dline, ",", 1)        ' Build key by prefixing with TL_          

     operand2 = parse$(dline, ",", 2)                ' Extract the return data          

     Set_Gbl_Str(operand1, operand2)                 ' Save entry in table in Global storage

  loop                                               '

  i = FILE_Close(fHandle)                            ' Close file, we're done

  Set_Gbl_Num("TableLkupOK", 1)                      ' Remember we've loaded the table

  Set_E_Result("OK")                                 ' Tell mainline we're done

  Halt(OK)                                           '

'----- It's the normal execution call

else

  operand1 = "TL_" + str                             ' Build lookup key

  operand2 = Get_Gbl_Str$(operand1)                  ' Fetch the data

  ErrMsg = Get_Msg$                                  ' Catch any error message

  if Get_RC = 0 then                                 ' If OK, pass back answer  

     Set_E_Result(operand2)                          '

     halt(ok)                                        ' return

  else                                               '

     Set_E_Result(str)                               ' Pass back unchanged string

     halt(Fail, "TableLkup: " + ErrMsg + " in line: " + format$(Get_LNum(Get_Find_Lptr)))                         ' Else error

  end if                                             '  

end if




Created with the Personal Edition of HelpNDoc: News and information about help authoring tools and software