| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // 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 |