Procedures are set-up (declared in script) using the keyword Procedure as the prefix.  And just like a function, you can write your own user‑defined procedures.  

But just writing and naming a user-defined procedure does not actually allow it to run.  All procedures (and functions for that matter) need to be enveloped in a script wrapper or envelope, within a special procedure name that is recognised by Statelake.    

For a procedure to be run within a custom script this wrapper is called ScriptEvent.    When the Statelake core system comes to this ScriptEvent procedure in its processing, it pauses at that point whatever processing is taking place and runs the code contained within the ScriptEvent wrapper.  

There are other procedures of course that run outside of this custom ScriptEvent wrapper – but these procedures have their own system generated wrapper.    These other wrappers are found within the Statelake Map, and are BeforeMap, OnStartMap, OnEndMap, LinkedData, AfterMap, AfterDetailMap, and OnMap.   

The wrappers will always be in the same format.  The wrapper code will occupy the first line with the unnamed variables within parentheses (i.e. OnMapEvent(var Value:variant);).  

The following lines contain the code that will be run, with the final line as the wrapper closing instruction end;.    The final character on both of these top and bottom wrapper lines is a semi-colon (;).

The following example shows a simple basic procedure to send a text string to the script log using the pre-defined function LogInfo, enveloped by the ScriptEvent wrapper.   

procedure ScriptEvent(var Value:variant);
begin
LogInfo('Hello there. Welcome to our system!');
end;

This custom script ScriptEvent procedure uses the two variables CustName and HomeNum to supply the information necessary to generate the function result as a string.

procedure ScriptEvent(var Value:variant);
ContactFunc(CustName:string;HomeNum:integer):string;
begin
Result := 'Please contact '+CustName+' on '+IntToStr(HomeNum);
end;

Procedures can be as complicated as they need to be. 

This following procedure is called by the script wrapper OnMapEvent within the Statelake Map, and tests for the presence of multiple address fields with an IF statement, to build an address string with no blank or redundant data.   

The square brackets [ ] signify that the contents within the brackets is a field name.

procedure OnMapEvent(var Value:variant); //ADDRESS
begin
Value := '';
If (CR_ACCS['ADDRESS3'].AsString <> '') then
Value := CR_ACCS['ADDRESS1'].AsString+', '+CR_ACCS['ADDRESS2'].AsString+', '+CR_ACCS['ADDRESS3'].AsString;
else if (CR_ACCS['ADDRESS2'].AsString <> '') then
Value := CR_ACCS['ADDRESS1'].AsString+', '+CR_ACCS['ADDRESS2'].AsString;
else
Value := CR_ACCS['ADDRESS1'].AsString;
end;

Within a procedure wrapper you can have any combination of instructions, including other procedure calls. 

The procedure LogInfo will write an entry into the action Log file for the configuration in which it runs.  

In this one‑line procedure declaration, the input parameters are contained within the parentheses ( ), with the name of the parameter and data type separated by a colon.   This procedure only requires a single string parameter called MyMessage.     If MyMessage contains the string “All the records have now been written.” then when the procedure executes, and the exact line of text will be written into the log file.

procedure LogInfo(MyMessage:string);

As with functions, multiple parameters of the same data type can be entered in the shorthand version, with a comma between the parameters such as the following example using the Delete procedure. 

This example deletes HowMany characters from Message starting at position WhereFrom – where the starting position in a string is number 1

procedure Delete(Message:string;WhereFrom,HowMany:integer);

Some procedures will use the keyword var to modify the parameters that are passed in, effectively returning one or more results.    

This following example of the procedure Delete has three input variables - MyMesssage, which is a string, and two others called Index and Count which are both integers.   Index specifies how many characters into the string MyMessage the procedure is to start at, and Count specifies the number of characters to be deleted.  

However, since MyMessage is prefixed by the keyword var, this value of this variable will be modified and updated with the string value after the given number of characters specified in the remaining parameters have been deleted.   Any further use of this variable after completion of the procedure will be using the updated value.

procedure Delete(var MyMessage:string;Index,Count:integer);

This user-defined procedure called RemoveNonKeyboardChars can be called from a custom script to remove any characters from a string before any further processing – such as where you need to remove any non-keyboard characters. But this procedure could easily be amended to remove other characters such as apostrophe’s, double spaces, dashes or line breaks.

procedure RemoveNonKeyboardChars(var MyString:string);
var
OutStr : string;
C : integer;
begin
OutStr := '';
For C := 1 to length(MyString) do
begin
If ((Ord(MyString[c]) >= 32) and (Ord(MyString[c]) <= 126)) then
OutStr := OutStr + MyString[c];
//Else character is not a keyboard character, therefore SKIP
end;
MyString := OutStr; //Return the amended string
end;

The following procedure called DumpDataview loops through a Dataview and displays the record number and contents of the INVNO field to the Log - from the FIrst record until EOF is reached. <DatasetName> is a placeholder for the actual Dataview name.

procedure DumpDataview;
var
RecNum : integer;
begin
RecNum := 0;
<DatasetName>.First;
While not <DatasetName>.EOF do
begin
RecNum := RecNum + 1;
LogInfo('RecNum = '+IntToStr(RecNum)+' '+<DatasetName>['INVNO'].AsString);
<DatasetName>.Next;
end;
end;