blob: a04c458572786e0491d7023615c3abd6f03ffa56 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_CLL_SMacro_Functions
//
// Purpose:
// This module contains the implementation of generic EPTF_CLL_SMacro functions.
//
// Module depends on:
// <EPTF_CLL_SMacro_Definitions>
// <EPTF_CLL_Commmon_Functions>
// <EPTF_CLL_HashMap_Functions>
// <EPTF_CLL_HashMapStr2Int_Functions>
// <EPTF_CLL_FBQ_Functions>
// <EPTF_CLL_Logging_Functions>
// <EPTF_CLL_Logging_Definitions>
// <EPTF_CLL_Common_Definitions>
//
//
// Current Owner:
// Jozsef Gyurusi (ETHJGI)
//
// Last Review Date:
// 2009-05-14
//
// Detailed Comments:
// This module contains the interface functions for the EPTF_CLL_SMacro.
// Public functions:
// <f_EPTF_SMacro_init_CT>
// <f_EPTF_SMacro_define>
// <f_EPTF_SMacro_undefine>
// <f_EPTF_SMacro_registerCalcFn>
// <f_EPTF_SMacro_deregisterCalcFn>
// <f_EPTF_SMacro_resolve>
// <f_EPTF_SMacro_calcFn_EVAL>
//
///////////////////////////////////////////////////////////////
module EPTF_CLL_SMacro_Functions {
import from EPTF_CLL_SMacro_Definitions all;
import from EPTF_CLL_Base_Functions all;
import from EPTF_CLL_HashMap_Functions all;
import from EPTF_CLL_HashMapStr2Int_Functions all;
import from EPTF_CLL_FBQ_Functions all;
import from EPTF_CLL_Logging_Functions all;
import from EPTF_CLL_Logging_Definitions all;
import from EPTF_CLL_Common_Definitions all;
import from TCCConversion_Functions all;
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_init_CT
//
// Purpose:
// Initialises the EPTF_SMacro_CT component
//
// Parameters:
// pl_selfName - *in charstring* - name of the component
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// This function should be called before using the EPTF SMacro
// component.
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_init_CT(in charstring pl_selfName) runs on EPTF_SMacro_CT {
if (v_EPTF_SMacro_initialized) {
return;
}
f_EPTF_Base_init_CT(pl_selfName);
f_EPTF_HashMap_init_CT(pl_selfName);
f_EPTF_FBQ_init_CT(pl_selfName);
f_EPTF_Logging_init_CT(pl_selfName);
v_SMacro_loggingMaskId := f_EPTF_Logging_registerComponentMasks(c_EPTF_SMacro_loggingComponentMask, c_EPTF_SMacro_loggingEventClasses, EPTF_Logging_CLL);
if(tsp_debug_EPTF_SMacro_Functions) {
f_EPTF_Logging_enableLocalMask(v_SMacro_loggingMaskId, c_EPTF_SMacro_loggingClassIdx_Debug);
} else {
f_EPTF_Logging_disableLocalMask(v_SMacro_loggingMaskId, c_EPTF_SMacro_loggingClassIdx_Debug);
}
//own component varible init
v_EPTF_SMacro_definitions := {};
v_SMacro_definitionStr2IntHashMapId := f_EPTF_str2int_HashMap_New("definition");
f_EPTF_FBQ_initFreeBusyQueue(v_SMacro_definitionFBQId);
v_EPTF_SMacro_calcFunctions := {};
v_SMacro_calcFuntionStr2IntHashMapId := f_EPTF_str2int_HashMap_New("calcFuntion");
f_EPTF_FBQ_initFreeBusyQueue(v_SMacro_calcFuntionFBQId);
// register built-in macros:
if(f_EPTF_SMacro_define(c_EPTF_SMacro_macroName_EVAL, "f_EPTF_SMacro_calcFn_EVAL") == 0) {
f_EPTF_SMacro_registerCalcFn(
pl_functionName := "f_EPTF_SMacro_calcFn_EVAL",
pl_macro_function := refers(f_EPTF_SMacro_calcFn_EVAL)
);
}
v_EPTF_SMacro_initialized := true;
f_EPTF_Base_registerCleanup(refers(f_EPTF_SMacro_cleanup_CT));
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_cleanup_CT
//
// Purpose:
// Cleans up SMacro feature.
//
// Parameters:
// -
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_SMacro_cleanup_CT() runs on EPTF_SMacro_CT {
if (v_EPTF_SMacro_initialized == false) {
return;
}
v_EPTF_SMacro_initialized := false;
// clean up own component variables
v_EPTF_SMacro_definitions := {};
f_EPTF_str2int_HashMap_DeleteById(v_SMacro_definitionStr2IntHashMapId);
v_SMacro_definitionStr2IntHashMapId := -1;
f_EPTF_FBQ_deleteFreeBusyQueue(v_SMacro_definitionFBQId);
v_SMacro_definitionFBQId := -1;
v_EPTF_SMacro_calcFunctions := {};
f_EPTF_str2int_HashMap_DeleteById(v_SMacro_calcFuntionStr2IntHashMapId);
v_SMacro_calcFuntionStr2IntHashMapId := -1;
f_EPTF_FBQ_deleteFreeBusyQueue(v_SMacro_calcFuntionFBQId);
v_SMacro_calcFuntionFBQId := -1;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_define
//
// Purpose:
// Define string-macro.
//
// Parameters:
// pl_macro_name - *in charstring* - name of the string-macro to be defined
// pl_macro_value - *in charstring* - value of the string-macro
//
// Return Value:
// integer - zero if successful, non-zero otherwise
//
// Errors:
// -
//
// Detailed Comments:
// This function assigns the value given by pl_macro_value to the macro pl_macro_name.
// The pl_macro_value can also be the name of a function that returns the macro value.
// If the function with that name is not registered by <f_EPTF_SMacro_registerCalcFn>
// function, the value of the macro will be given by pl_macro_value.
//
// If the function is called multiple times with the same pl_macro_name but
// with different pl_macro_value, the last value will be used to determine
// the value of the macro. That is the macro can be redefined with this function.
//
// The pl_macro_name can only contain the characters a..z, A..Z, _, 0..9
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_define(
in charstring pl_macro_name,
in charstring pl_macro_value
) runs on EPTF_SMacro_CT return integer {
// checking macro_name: a..z, A..Z, _, 0..9
if(f_EPTF_SMacro_checkName(pl_macro_name) != 0)
{
f_EPTF_SMacro_warning(log2str(%definitionId&": Warning: macro name ",pl_macro_name,
" is invalid, should contain only characters 'a..z', 'A..Z', '_', '0..9'. Macro definition ignored."
));
return 1;
}
// search macro
var integer vl_itemIdx;
if(f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_definitionStr2IntHashMapId,
pl_key := pl_macro_name,
pl_data := vl_itemIdx
)) {
f_EPTF_SMacro_debug(log2str(%definitionId&": Macro name ",pl_macro_name,
" is already defined with value ",v_EPTF_SMacro_definitions[vl_itemIdx].macro_value,
". It will be redefined as ", pl_macro_value));
}
else {
// reserve free slot in the DB for the new item
vl_itemIdx := f_EPTF_FBQ_getOrCreateFreeSlot(v_SMacro_definitionFBQId);
f_EPTF_FBQ_moveFromFreeToBusyTail(vl_itemIdx,v_SMacro_definitionFBQId);
f_EPTF_str2int_HashMap_Insert(
pl_id := v_SMacro_definitionStr2IntHashMapId,
pl_key := pl_macro_name,
pl_data := vl_itemIdx
);
}
// define or re-define macro in the DB
v_EPTF_SMacro_definitions[vl_itemIdx] := {
macro_name := pl_macro_name,
macro_value := pl_macro_value
};
return 0;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_undefine
//
// Purpose:
// Undefine the string-macro.
//
// Parameters:
// pl_macro_name - *in charstring* - name of the string-macro to be undefined
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// This function clears the assignment between the last value of the macro and the macro name.
// The given macro will be undefined after calling this function, that is the
// function <f_EPTF_SMacro_resolve> will leave it unchanged in the input string.
// It is the same if the <f_EPTF_SMacro_define> was not called with this macro name.
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_undefine(in charstring pl_macro_name) runs on EPTF_SMacro_CT {
// search macro
var integer vl_itemIdx;
if(not f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_definitionStr2IntHashMapId,
pl_key := pl_macro_name,
pl_data := vl_itemIdx
)) {
return; // if not found do nothing
}
// delete macro from DB
f_EPTF_str2int_HashMap_Erase(
pl_id := v_SMacro_definitionStr2IntHashMapId,
pl_key := pl_macro_name
);
v_EPTF_SMacro_definitions[vl_itemIdx] := c_EPTF_SMacro_Definition_init;
f_EPTF_FBQ_moveFromBusyToFreeTail(vl_itemIdx,v_SMacro_definitionFBQId);
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_registerCalcFn
//
// Purpose:
// Registers string-macro calculator function.
//
// Parameters:
// pl_functionName - *in charstring* - name of the string-macro calculator function.
// If not specified (or default value is given: ""), the function name will be set
// automatically to log2str(pl_macro_function) with and without the "refers()".
// pl_macro_function - *in* <f_EPTF_CLL_SMacro_calc_FT> - reference of the function
// that can be used to calculate the value of a string-macro
// pl_userArgs - *in* <EPTF_IntegerList> - user given parameters that will be passed
// to the pl_macro_function when it is called.
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// It is possible to register the same pl_macro_function with different names.
// If different pl_macro_function-s are registered with same pl_functionName,
// only the last will be used (i.e. the function reference for that name can be redefined).
//
// If pl_macro_function is null: it means the same as if no function was registered.
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_registerCalcFn(
in charstring pl_functionName := "",
in f_EPTF_CLL_SMacro_calc_FT pl_macro_function,
in EPTF_IntegerList pl_userArgs := {}
) runs on EPTF_SMacro_CT {
// // check if macro function is null
// if(pl_macro_function == null) {
// f_EPTF_SMacro_warning(log2str(%definitionId&": Macro calculator function ignored, because it is null"));
// return;
// }
// checking function name
var charstring vl_functionName := pl_functionName;
if(lengthof(vl_functionName) == 0) {
// default function name will be used
var integer vl_strLen := lengthof(log2str(pl_macro_function));
vl_functionName := substr(log2str(pl_macro_function),7,vl_strLen-8); // cut the refers()
f_EPTF_SMacro_debug(log2str(%definitionId&": Function name:", vl_functionName,
" was calculated automatically for function ",pl_macro_function));
}
// define function in the DB
f_EPTF_SMacro_debug(log2str(%definitionId&": Registering macro calculator function:",pl_macro_function,
" with name ",vl_functionName));
var integer vl_itemIdx := -1;
if (not f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_calcFuntionStr2IntHashMapId,
pl_key := vl_functionName,
pl_data := vl_itemIdx
)) {
vl_itemIdx := f_EPTF_FBQ_getOrCreateFreeSlot(v_SMacro_calcFuntionFBQId);
f_EPTF_FBQ_moveFromFreeToBusyTail(vl_itemIdx,v_SMacro_calcFuntionFBQId);
f_EPTF_str2int_HashMap_Insert(
pl_id := v_SMacro_calcFuntionStr2IntHashMapId,
pl_key := vl_functionName,
pl_data := vl_itemIdx
);
} else {
f_EPTF_SMacro_debug(log2str(%definitionId&": Macro calculator function ",pl_macro_function,
" will redefine the old function ",v_EPTF_SMacro_calcFunctions[vl_itemIdx].funcRef,
", it was already registered with the same name: ",vl_functionName));
}
// updating database:
v_EPTF_SMacro_calcFunctions[vl_itemIdx] := {
functionName := vl_functionName,
funcRef:= pl_macro_function,
userArgs := pl_userArgs
};
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_deregisterCalcFn
//
// Purpose:
// Deregisters string-macro calculator function from the function name.
//
// Parameters:
// pl_functionName - *in charstring* - name of the string-macro calculator function
// to be deregistered.
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// After calling this function the value of the string-macro will
// be the same as if the <f_EPTF_SMacro_registerCalcFn> was not called.
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_deregisterCalcFn(
in charstring pl_functionName := ""
) runs on EPTF_SMacro_CT {
// search function
var integer vl_itemIdx;
if(not f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_calcFuntionStr2IntHashMapId,
pl_key := pl_functionName,
pl_data := vl_itemIdx
)) {
return; // if not found do nothing
}
// delete function from DB
f_EPTF_str2int_HashMap_Erase(
pl_id := v_SMacro_calcFuntionStr2IntHashMapId,
pl_key := pl_functionName
);
f_EPTF_FBQ_moveFromBusyToFreeTail(vl_itemIdx,v_SMacro_calcFuntionFBQId);
v_EPTF_SMacro_calcFunctions[vl_itemIdx] := c_EPTF_SMacro_CalcFunction_init;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_resolve
//
// Purpose:
// Replaces every occurences of defined string-macros in the input string.
//
// Parameters:
// pl_functionName - *in charstring* - name of the string-macro calculator function
// to be deregistered.
// pl_autoEVAL - *in boolean* - if true the EVAL macro will be called automatically.
// (default: false)
//
// Return Value:
// charstring - the input string where the defined string-macros are replaced by their
// corresponding values
//
// Errors:
// -
//
// Detailed Comments:
// The input string should contain the string macros in the following formats:
// "$MACRO0"
// "$(MACRO1)"
// "$(MACRO2, \" par1 \", \" par2 \" )" -> f_MACRO2(pl_args:= {" par1 ", " par2 ""})
// "$(MACRO3, \" $(MACRO2, \\\" par1 \\\") \" )" -> f_MACRO3(pl_args:= {" $(MACRO2, \" par1 \") " }) -> f_MACRO3(pl_args:= " "&f_MACRO2(pl_args := { " par1 "})&" ")
//
// If the macro is not found it will not be changed and will remain in the output as it was originally
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_resolve(
in charstring pl_stringTemplate,
in boolean pl_autoEVAL := false
) runs on EPTF_SMacro_CT return charstring {
var integer vl_currentPos := 0;
var charstring vl_stringTemplate := pl_stringTemplate;
// repeat until end of string is reached
var charstring vl_currentStringTemplate := vl_stringTemplate;
while(lengthof(vl_stringTemplate)>vl_currentPos or (vl_currentPos == lengthof(vl_stringTemplate) and (vl_currentStringTemplate != vl_stringTemplate))) {
if (vl_currentPos == lengthof(vl_stringTemplate)) {
//action("**** template string was changed, recheck needed from pos 0");
vl_currentPos := 0; // recheck
vl_currentStringTemplate := vl_stringTemplate;
}
// search first macro, based only on the syntax:
var charstring vl_macroName, vl_macroValue;
var EPTF_CharstringList vl_macroPars;
var integer vl_macroLen;
//action("*** vl_stringTemplate: ", vl_stringTemplate);
var integer vl_offset := f_EPTF_SMacro_getFirstMacro(vl_stringTemplate, vl_currentPos, vl_macroName, vl_macroPars, vl_macroLen);
//action("*** vl_macroName: ", vl_macroName);
//action("*** vl_offset: ", vl_offset);
// if macro is defined
if (f_EPTF_SMacro_getMacroValue(vl_macroName,vl_macroValue)!=0) {
vl_currentPos := vl_offset + vl_macroLen; // not defined
continue; // while
}
// if macro has a function calculate the function result
// if not use the defined macro value
var charstring vl_macroFunction := vl_macroValue;
f_EPTF_SMacro_calcMacroValue(vl_macroFunction,vl_macroPars,vl_macroValue);
// replace the macro with the value in the template string
f_EPTF_SMacro_replaceMacroWithValue(vl_stringTemplate, vl_offset, vl_macroLen, vl_macroValue);
// update the current position in the new string:
vl_currentPos := vl_offset + lengthof(vl_macroValue);
// search from the last character of the inserted value for new macro (== continue the while-cycle)
} // end of repeat;
//action("*** template string resolved to: ", vl_stringTemplate);
//call EVAL macro if enabled:
if (pl_autoEVAL) {
vl_stringTemplate := f_EPTF_SMacro_calcFn_EVAL({vl_stringTemplate});
//action("*** template string after EVAL: ", vl_stringTemplate);
}
// return the result string
return vl_stringTemplate;
}
// finds the first macro in the stringTemplate from currentPos, returns the offset of the first char ($) where the macro begins,
// sets the name, parameters and the length of the macro string (distance between the $ and the last macro character)
private function f_EPTF_SMacro_getFirstMacro(
in charstring pl_stringTemplate,
in integer pl_currentPos,
out charstring pl_macro_name,
out EPTF_CharstringList pl_macro_params,
out integer pl_macroLen
) runs on EPTF_SMacro_CT return integer{
//action("**** f_EPTF_SMacro_getFirstMacro start at pos ", pl_currentPos);
pl_macro_name := "";
pl_macro_params := {};
pl_macroLen := 0;
var integer vl_macroOffset := lengthof(pl_stringTemplate); // position of the first char ($) of the valid macro
var integer vl_currentOffset := pl_currentPos;
while(vl_currentOffset<lengthof(pl_stringTemplate)) {
// search $
var integer vl_macroBeginOffset := f_strstr(
s1 := pl_stringTemplate,
s2 := "$",
offset:=vl_currentOffset
);
if (vl_macroBeginOffset == -1) {
return vl_macroOffset; // no $ found => no macro in template
}
// $ found
// find syntax: $MACRO_NAME
var charstring vl_macro_name_guess := f_EPTF_SMacro_getSimpleMacroName(pl_stringTemplate,vl_macroBeginOffset);
if (vl_macro_name_guess != "") {
//syntax matched!! :)
vl_macroOffset := vl_macroBeginOffset;
pl_macro_name := vl_macro_name_guess;
pl_macroLen := lengthof(pl_macro_name)+1; // +1: $
return vl_macroOffset;
}
// syntax can be other
//find syntax $(macro)
vl_macro_name_guess := f_EPTF_SMacro_getMacroName(pl_stringTemplate,vl_macroBeginOffset);
if (vl_macro_name_guess != "") {
//syntax matched!! :)
vl_macroOffset := vl_macroBeginOffset;
pl_macro_name := vl_macro_name_guess;
pl_macroLen := lengthof(pl_macro_name)+3; // +3: $()
return vl_macroOffset;
}
//find syntax $(macro,"par","par2"...)
var integer vl_parNum := 0;
var charstring vl_parString := "";
var charstring vl_macro_with_par := f_EPTF_SMacro_getMacroWithPar(pl_stringTemplate,vl_macroBeginOffset, vl_macro_name_guess, vl_parString);
while(lengthof(vl_parString)>0) {
var charstring vl_param := f_EPTF_SMacro_getMacroParam(vl_parString);
//decrease escape level:
string2ttcn(vl_param,vl_param);
pl_macro_params[vl_parNum] := vl_param;
vl_parNum := vl_parNum + 1;
}
//action("***** done.");
if (vl_macro_name_guess != "") {
//syntax matched!! :)
vl_macroOffset := vl_macroBeginOffset;
pl_macro_name := vl_macro_name_guess;
pl_macroLen := lengthof(vl_macro_with_par)+3; // +3: $()
return vl_macroOffset;
}
// none of the macro syntaxes matched. This $ is not macro, have to continue the search:
vl_currentOffset := vl_macroBeginOffset + 1;
} // while
return vl_macroOffset;
}
// replace the macro with its value in the template string
private function f_EPTF_SMacro_replaceMacroWithValue(
inout charstring pl_stringTemplate, // in this string
in integer pl_offset, // from the char at this position
in integer vl_macroLen, // with this length will be replaced
in charstring pl_macroValue // with this value
) runs on EPTF_SMacro_CT {
var charstring vl_firstPart := substr(pl_stringTemplate,0,pl_offset);
var charstring vl_lastPart := substr(pl_stringTemplate,pl_offset+vl_macroLen,lengthof(pl_stringTemplate)-pl_offset-vl_macroLen);
pl_stringTemplate := vl_firstPart&pl_macroValue&vl_lastPart;
}
// return macro value:
private function f_EPTF_SMacro_getMacroValue(in charstring pl_macro_name, out charstring pl_macro_value) runs on EPTF_SMacro_CT return integer {
// search macro
var integer vl_itemIdx;
if(not f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_definitionStr2IntHashMapId,
pl_key := pl_macro_name,
pl_data := vl_itemIdx
)) {
//f_EPTF_SMacro_warning(log2str(%definitionId&": Macro with name ",pl_macro_name, " not found"));
return 1; // not found
}
pl_macro_value := v_EPTF_SMacro_definitions[vl_itemIdx].macro_value;
return 0; // ok
};
// return the calculated macro value from the registered calc function:
// if macro has a function calculate the function result
// if not use the defined macro value
private function f_EPTF_SMacro_calcMacroValue(
in charstring pl_macro_functionName,
in EPTF_CharstringList pl_macro_params,
out charstring pl_macro_value
) runs on EPTF_SMacro_CT {
pl_macro_value := pl_macro_functionName;
// search function
var integer vl_itemIdx;
if(not f_EPTF_str2int_HashMap_Find(
pl_id := v_SMacro_calcFuntionStr2IntHashMapId,
pl_key := pl_macro_functionName,
pl_data := vl_itemIdx
)) {
return; // not found
}
if (v_EPTF_SMacro_calcFunctions[vl_itemIdx].funcRef == null) {
return; // function is null
}
var EPTF_CharstringList vl_resolved_macro_params := {};
for(var integer i:=0; i<sizeof(pl_macro_params);i:=i+1) {
vl_resolved_macro_params[i] := f_EPTF_SMacro_resolve(pl_macro_params[i]);
}
pl_macro_value := v_EPTF_SMacro_calcFunctions[vl_itemIdx].funcRef.apply(vl_resolved_macro_params,v_EPTF_SMacro_calcFunctions[vl_itemIdx].userArgs);
};
////////////////////////////////////////////////////
// Built-in Macros
///////////////////////////////////////////////////
//--------------- EVAL MACRO -----------------------------------------------
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_calcFn_EVAL
//
// Purpose:
// Macro calculator callback function for the EVAL macro
//
// Parameters:
// pl_macroArgs - *in* <EPTF_CharstringList> - mathematical expression
// pl_userArgs - *in* <EPTF_IntegerList> - further parameters can be passed with this, in this case it is unused
//
// Return Value:
// charstring - calculated value of the expression which is a number
//
// Errors:
// -
//
// Detailed Comments:
// Example:
// mathematical expression: "1+2.0*3/4*2-6e01"
// return value "-58.500000"
//
///////////////////////////////////////////////////////////
public function f_EPTF_SMacro_calcFn_EVAL(
in EPTF_CharstringList pl_macroArgs,
in EPTF_IntegerList pl_userArgs := {}
) runs on EPTF_SMacro_CT return charstring {
if(sizeof(pl_macroArgs) == 0){
return "";
}
var charstring vl_inputStr := pl_macroArgs[0];
var charstring vl_originalInputStr := "";
while (vl_originalInputStr != vl_inputStr) {
vl_originalInputStr := vl_inputStr;
// calculate all expressions with the "(" precedence
vl_inputStr := f_EPTF_SMacro_calculateAll_EVALExprs(vl_inputStr,c_EPTF_SMacro_paranthesesOp);
// calculate all expressions with the "*" precedence
vl_inputStr := f_EPTF_SMacro_calculateAll_EVALExprs(vl_inputStr,c_EPTF_SMacro_multiplicationOps);
// calculate all expressions with the "+" precedence
vl_inputStr := f_EPTF_SMacro_calculateAll_EVALExprs(vl_inputStr,c_EPTF_SMacro_additionOps);
}
//Result may contain only number if pl_macroArgs[0] is 1:
var boolean vl_strictChecking := sizeof(pl_macroArgs)>1 and pl_macroArgs[1]=="strict";
var charstring vl_result;
if (vl_strictChecking) {
// vl_result := regexp(vl_inputStr,c_EPTF_SMacro_floatNumber,0);
vl_result := f_EPTF_SMacro_isFloat(vl_inputStr);
if (vl_result!=vl_inputStr) {
// if (not f_EPTF_SMacro_isFloat(vl_inputStr)) {
// result is not number, contains other characters as well
vl_result := pl_macroArgs[0]; // returns original string
}
} else {
vl_result := vl_inputStr;
}
// calculates the signums at the begining of the string
vl_result:= f_EPTF_SMacro_calcSignum(vl_result);
return vl_result;
}
private function f_EPTF_SMacro_getFirst_EVALExpr(
in charstring pl_inputStr,
in charstring pl_ops,
out charstring pl_prefix,
out charstring pl_postfix
) runs on EPTF_SMacro_CT return charstring {
var charstring vl_expression := f_EPTF_SMacro_getFirstExpression(pl_inputStr,pl_ops,pl_prefix,pl_postfix);
//action("*** pl_prefix: ", pl_prefix);
//action("*** vl_expression: ", vl_expression);
//action("*** pl_postfix: ", pl_postfix);
return vl_expression;
}
private function f_EPTF_SMacro_calculate_EVALExpr(
in charstring pl_inputStr,
in charstring pl_ops
) runs on EPTF_SMacro_CT return charstring {
// parantheses : ('floatNumber')
if (pl_ops==c_EPTF_SMacro_paranthesesOp) {
return substr(pl_inputStr,1,lengthof(pl_inputStr)-2);
}
var charstring vl_firstArgSignStr, vl_firstArg, vl_operator, vl_secondArgSignStr,vl_secondArg,vl_firstIntStr,vl_secondIntStr;
f_EPTF_SMacro_getExpression(pl_inputStr,vl_firstArgSignStr,vl_firstArg,vl_operator,vl_secondArgSignStr,vl_secondArg,vl_firstIntStr,vl_secondIntStr);
//action("*** vl_firstArg: ", vl_firstArgSignStr&vl_firstArg, " vl_operator: ", vl_operator, " vl_secondArg: ", vl_secondArgSignStr&vl_secondArg);
// calculate the signs:
var float vl_firstArgSign := 1.0;
var float vl_secondArgSign := 1.0;
for (var integer i:=0; i<lengthof(vl_firstArgSignStr); i:=i+1) {
if (vl_firstArgSignStr[i]=="-") {
vl_firstArgSign := -1.0*vl_firstArgSign;
}
}
for (var integer i:=0; i<lengthof(vl_secondArgSignStr); i:=i+1) {
if (vl_secondArgSignStr[i]=="-") {
vl_secondArgSign := -1.0*vl_secondArgSign;
}
}
var float vl_firstNum;
var float vl_secondNum;
var float vl_resultNum;
if (vl_firstIntStr!="") {
vl_firstNum := vl_firstArgSign*int2float(str2int(vl_firstIntStr));
} else {
vl_firstNum := vl_firstArgSign*str2float(vl_firstArg);
}
if (vl_secondIntStr!="") {
vl_secondNum := vl_secondArgSign*int2float(str2int(vl_secondIntStr));
} else {
vl_secondNum := vl_secondArgSign*str2float(vl_secondArg);
}
if (vl_operator==c_EPTF_SMacro_multiplicationOp) {
vl_resultNum := vl_firstNum*vl_secondNum;
} else if (vl_operator==c_EPTF_SMacro_divisionOp and vl_firstIntStr != "" and vl_secondIntStr != "") {
if (float2int(vl_secondNum) == 0) {
return "(EVAL: Error: Division by zero.)"; // division by zero: return original expression
}
vl_resultNum := int2float(float2int(vl_firstNum)/float2int(vl_secondNum));
} else if (vl_operator==c_EPTF_SMacro_divisionOp) {
if (vl_secondNum == 0.0) {
return "(EVAL: Error: Division by zero.)"; // division by zero: return original expression
}
vl_resultNum := vl_firstNum/vl_secondNum;
} else if (vl_operator==c_EPTF_SMacro_remainderOp and vl_firstIntStr != "" and vl_secondIntStr != "") {
if (vl_secondNum == 0.0) {
return "(EVAL: Error: Division by zero.)"; // division by zero: return original expression
}
vl_resultNum := int2float(float2int(vl_firstNum) rem float2int(vl_secondNum));
} else if (vl_operator==c_EPTF_SMacro_remainderOp) {
// error: arguments are not integers
//f_EPTF_SMacro_debug(log2str(%definitionId&": Cannot calculate expression ",pl_inputStr,". Remainder operator (%) does not support float numbers!"));
return pl_inputStr; // return the original expression on error
} else if (vl_operator==c_EPTF_SMacro_additionOp) {
vl_resultNum := vl_firstNum+vl_secondNum;
} else if (vl_operator==c_EPTF_SMacro_subtractionOp) {
vl_resultNum := vl_firstNum-vl_secondNum;
}
if (vl_firstIntStr != "" and vl_secondIntStr != "") {
return int2str(float2int(vl_resultNum));
}
return float2str(vl_resultNum);
}
private function f_EPTF_SMacro_calculateAll_EVALExprs(
in charstring pl_inputStr,
in charstring pl_ops
) runs on EPTF_SMacro_CT return charstring {
//action("*****-----------------------------------");
//action("***** Processing pl_inputStr: ", pl_inputStr, "for operator: ",pl_ops);
var boolean vl_recheckNeeded := true;
var charstring vl_outputStr := "";
var charstring vl_inputStr := pl_inputStr;
while (vl_recheckNeeded) {
var charstring vl_prefix;
var charstring vl_postfix;
var charstring vl_firstExpr := f_EPTF_SMacro_getFirst_EVALExpr(vl_inputStr,pl_ops,vl_prefix, vl_postfix);
if (vl_firstExpr!="") {
// calculate the value:
var charstring vl_valueStr := f_EPTF_SMacro_calculate_EVALExpr(vl_firstExpr,pl_ops);
if (vl_valueStr != vl_firstExpr) {
vl_outputStr := vl_outputStr&vl_prefix; // prefix goes to the output
vl_inputStr := vl_valueStr&vl_postfix; // value remains in the input
} else {
// some error occured: value is the same as the expression => leave this out and continue searching the next expression
// cut the last float number and place it to the beginning of the input:
var charstring vl_lastFloat:=f_EPTF_SMacro_getLastFloat(vl_valueStr); // vl_valueStr is overwritten by the rest of the string
vl_outputStr := vl_outputStr&vl_prefix&vl_valueStr; //move everything before the last float number to the output
vl_inputStr := vl_lastFloat&vl_postfix; // put the last float into the input
}
} else {
vl_recheckNeeded := false;
vl_outputStr := vl_outputStr&vl_prefix&vl_postfix;
}
}
return vl_outputStr;
}
//--------------- EXTERNAL FUNCTIONS --------------------------------------------
// checks if the macro name is valid, returns nonzero if invalid
private external function f_EPTF_SMacro_checkName(
in charstring pl_macro_name
) return integer
// returns with macro name in case of simple macro
private external function f_EPTF_SMacro_getSimpleMacroName(
in charstring pl_stringTemplate,
in integer pl_macroBeginOffset
) return charstring;
// returns with macro name
private external function f_EPTF_SMacro_getMacroName(
in charstring pl_stringTemplate,
in integer pl_macroBeginOffset
) return charstring;
// macro_name + parameter string as parameter, returns with macro with par
private external function f_EPTF_SMacro_getMacroWithPar(
in charstring pl_stringTemplate,
in integer pl_macroBeginOffset,
out charstring pl_macro_name,
out charstring pl_parString
) return charstring;
// returns with the macro param
private external function f_EPTF_SMacro_getMacroParam(
inout charstring pl_parString
) return charstring;
// returns with signum+arguments and operator
private external function f_EPTF_SMacro_getExpression(
in charstring pl_inputStr,
out charstring pl_firstArgSignStr,
out charstring pl_firstArg,
out charstring pl_operator,
out charstring pl_secondArgSignStr,
out charstring pl_secondArg,
out charstring pl_firstIntStr,
out charstring pl_secondIntStr
)
// checks whether the string is float number
private external function f_EPTF_SMacro_isFloat(
in charstring pl_inputStr
) return charstring;
// return with first expression, prefix
private external function f_EPTF_SMacro_getFirstExpression(
in charstring pl_inputStr,
in charstring pl_ops,
out charstring pl_prefix,
out charstring pl_postfix
) return charstring
// calc signums at the negining of the string
private external function f_EPTF_SMacro_calcSignum(
in charstring pl_inputStr
) return charstring
// returns with the last float, rest of valueStr
private external function f_EPTF_SMacro_getLastFloat(
inout charstring pl_valueStr
) return charstring;
//--------------- LOGGING --------------------------------------------
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_debug
//
// Purpose:
// Function to log a debug message from SMacro feature.
//
// Parameters:
// pl_message - *in* *charstring* - message to be logged
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_SMacro_debug(in @lazy charstring pl_msg) runs on EPTF_SMacro_CT {
f_EPTF_Logging_debugV2(pl_msg, v_SMacro_loggingMaskId, {c_EPTF_SMacro_loggingClassIdx_Debug});
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_warning
//
// Purpose:
// Function to log a warning from SMacro feature.
//
// Parameters:
// pl_msg - *in* *charstring* - message to be logged
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_SMacro_warning(in @lazy charstring pl_msg) runs on EPTF_SMacro_CT {
f_EPTF_Logging_warningV2(pl_msg, v_SMacro_loggingMaskId, {c_EPTF_SMacro_loggingClassIdx_Warning});
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_SMacro_error
//
// Purpose:
// Function to log an error from SMacro feature.
//
// Parameters:
// pl_msg - *in* *charstring* - message to be logged
//
// Return Value:
// -
//
// Errors:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////
private function f_EPTF_SMacro_error(in charstring pl_msg) runs on EPTF_SMacro_CT {
f_EPTF_Logging_error( true, pl_msg);
f_EPTF_Base_stopAll();
}
} // end of module