Page 1 of 1
simulate unknown Function of UDF in IndexKey()
Posted: Fri May 05, 2023 4:42 am
by Jimmy
hi,
when Index have a UDF in Indexkey() it will crash when open Index and don´t have that missing Function
Question :
how can i get "Name" of missing Function when use
i will get
oError:description, oError:operation, oError:osCode
---
let say i got Function Name XYZ()
Question : is it possible to "simulate" Function XYZ() "on-fly"
---
if i have a
i can use #xtranslate XYZ -> Dummy so i can call XYZ() without "real" existing Function XYZ()
---
so when i can get Function Name from oError the Idea is to "
redirect" to existing Function Dummy()
is there a Way to use this Idea
Re: simulate unknown Function of UDF in IndexKey()
Posted: Fri May 05, 2023 8:43 am
by Antonio Linares
Dear Jimmy,
To build it:
hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_
create.prg
Code: Select all | Expand
function Main()
CreateFunction( "xyz" )
? HB_IsFunction( "xyz" )
&( "xyz()" )
? "ok"
return nil
function Dummy()
? "inside dummy"
return nil
#pragma BEGINDUMP
#include <hbvmpub.h>
const char * hb_parvc( int iParam, ... );
PHB_DYNS hb_dynsymGet( const char * szName );
PHB_DYNS hb_dynsymFindName( const char * szName );
PHB_SYMB hb_dynsymSymbol( PHB_DYNS pDynSym );
HB_FUNC( CREATEFUNCTION )
{
PHB_DYNS pDynSym = hb_dynsymGet( hb_parvc( 1 ) );
PHB_SYMB pSymDummy = hb_dynsymSymbol( hb_dynsymFindName( "DUMMY" ) );
pDynSym->pSymbol->value.pFunPtr = pSymDummy->value.pFunPtr;
}
#pragma ENDDUMP
Re: simulate unknown Function of UDF in IndexKey()
Posted: Fri May 05, 2023 9:21 am
by Antonio Linares
I guess the next challenge would be to assign a codeblock to such created function...
Then we would have a way to assign functions to codebloks
Re: simulate unknown Function of UDF in IndexKey()
Posted: Fri May 05, 2023 10:52 am
by Antonio Linares
First prototype to create a function at runtime at assign a codeblock to it:
1. As we are using a static PHB_ITEM pCodeBlock, next call to CreateFunction() will overwrite it, so we need to find a solution for this.
2. We could enhance CreateFunction() to allow parameters: CreateFunction( cFunctionName, { | x, y, ... | ... } )
Code: Select all | Expand
function Main()
CreateFunction( "xyz", { || QOut( "inside codeblock " ) } )
? HB_IsFunction( "xyz" )
&( "xyz()" )
? "ok"
return nil
#pragma BEGINDUMP
#include <hbapi.h>
#include <hbapiitm.h>
static PHB_ITEM pCodeBlock;
static void evalBlock( void )
{
hb_evalBlock0( pCodeBlock );
}
HB_FUNC( CREATEFUNCTION )
{
PHB_DYNS pDynSym = hb_dynsymGet( hb_parvc( 1 ) );
pCodeBlock = hb_itemNew( hb_param( 2, HB_IT_BLOCK ) );
pDynSym->pSymbol->value.pFunPtr = evalBlock;
}
#pragma ENDDUMP
Re: simulate unknown Function of UDF in IndexKey()
Posted: Fri May 05, 2023 11:29 am
by Antonio Linares
Enhanced version supporting n parameters:
We have to solve where to store the codeblocks, or next call to hb_CreateFunction() will overwrite the previous one.
Code: Select all | Expand
function Main()
hb_CreateFunction( "xyz", { | a, b, c | QOut( c ) } )
? hb_IsFunction( "xyz" )
&( "xyz( ,, 'Hello world' )" )
return nil
#pragma BEGINDUMP
#include <hbapi.h>
#include <hbapiitm.h>
#include <hbvm.h>
static PHB_ITEM pCodeBlock;
static void evalBlock( void )
{
HB_USHORT ui, uiParams = hb_pcount();
hb_vmPushEvalSym();
hb_vmPush( pCodeBlock );
for( ui = 0; ui < uiParams; ui++ )
hb_vmPush( hb_param( ui + 1, HB_IT_ANY ) );
hb_vmSend( uiParams );
}
HB_FUNC( HB_CREATEFUNCTION )
{
PHB_DYNS pDynSym = hb_dynsymGet( hb_parvc( 1 ) );
pCodeBlock = hb_itemNew( hb_param( 2, HB_IT_BLOCK ) );
pDynSym->pSymbol->value.pFunPtr = evalBlock;
}
#pragma ENDDUMP
Re: simulate unknown Function of UDF in IndexKey()
Posted: Sat May 06, 2023 7:57 am
by Antonio Linares
Using hashes from low level to support multiple codeblocks
Remember to build it this way:
hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_
Code: Select all | Expand
function Main()
hb_CreateFunction( "xyz", { || QOut( "from XYZ()" ) } )
hb_CreateFunction( "abcd", { || QOut( "from ABDC()" ) } )
hb_CreateFunction( "another", { | c | QOut( ProcName( 1 ) ), QOut( c ) } )
&( "XYZ()" )
&( "ABCD()" )
&( "another( 'Hello world' )")
return nil
#pragma BEGINDUMP
#include <hbapi.h>
#include <hbapiitm.h>
#include <hbvm.h>
#include <hbapicdp.h>
static PHB_ITEM pHash = NULL;
static void evalBlock( void )
{
HB_USHORT ui, uiParams = hb_pcount();
char szProcName[ HB_SYMBOL_NAME_LEN + HB_SYMBOL_NAME_LEN + 5 ];
PHB_ITEM pKey, pValue;
hb_procname( 0, szProcName, HB_FALSE );
pKey = hb_itemPutC( NULL, szProcName );
pValue = hb_hashGetItemPtr( pHash, pKey, HB_HASH_AUTOADD_ACCESS );
if( pValue )
{
hb_vmPushEvalSym();
hb_vmPush( pValue );
for( ui = 0; ui < uiParams; ui++ )
hb_vmPush( hb_param( ui + 1, HB_IT_ANY ) );
hb_vmSend( uiParams );
}
}
HB_FUNC( HB_CREATEFUNCTION )
{
const char * szSymbolName = hb_parvc( 1 );
PHB_ITEM pText = hb_param( 1, HB_IT_STRING );
HB_SIZE nLen;
char * pszBuffer;
PHB_DYNS pDynSym = hb_dynsymGet( szSymbolName );
if( ! pHash )
pHash = hb_hashNew( NULL );
nLen = hb_itemGetCLen( pText );
pszBuffer = hb_cdpnDupUpper( hb_vmCDP(),
hb_itemGetCPtr( pText ), &nLen );
hb_hashAdd( pHash, hb_itemPutC( NULL, pszBuffer ), hb_itemNew( hb_param( 2, HB_IT_BLOCK ) ) );
pDynSym->pSymbol->value.pFunPtr = evalBlock;
}
#pragma ENDDUMP
Re: simulate unknown Function of UDF in IndexKey()
Posted: Mon May 08, 2023 12:42 pm
by Jimmy
hi Antonio,
Antonio Linares wrote:
To build it:
hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_
i try to use 1st Sample using
Code: Select all | Expand
set FWDIR=c:\fwh
set fwh=c:\fwh
set HBDIR=c:\harbour
set hdirl=%hdir%\lib\win\bcc
set bcdir=c:\bcc7
c:\Harbour\bin\hbmk2.exe %1 -cflag=-D_HB_API_INTERNAL_
del %1.map
del %1.tds
del %1.obj
del %1.c
del %1.ppo
del b32.bc
but i got
hbmk2: Error: Referenced, missing, but unknown function(s): HB_ISFUNCTION()
can you please provide a *.BAT which will work with these Sample, thx
Re: simulate unknown Function of UDF in IndexKey()
Posted: Mon May 08, 2023 7:04 pm
by Antonio Linares
Dear Jimmy,
I use this go.bat
Code: Select all | Expand
set path=c:\bcc7\bin
c:\harbour\bin\win\bcc\hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_
create
Re: simulate unknown Function of UDF in IndexKey()
Posted: Tue May 09, 2023 8:23 pm
by Jimmy
hi Antonio,
thx for go.bat
now it work
Re: simulate unknown Function of UDF in IndexKey()
Posted: Sun May 14, 2023 7:17 am
by Antonio Linares
Przemek solution using the Harbour error handler:
Code: Select all | Expand
FUNCTION Main()
LOCAL cFuncName
cFuncName := "SOME_FUNC"
UDF_DEFFUN( cFuncName, @MY_FUNC() ) // add redirection
? &cFuncName( 'abc', 123, Date() ) // show my_func() result
UDF_DEFFUN( cFuncName, {| p | Upper( p ) } ) // change redirection
? &cFuncName( 'abc', 123, Date() ) // show "ABC"
UDF_DEFFUN( cFuncName ) // remove redirection
? &cFuncName( 'abc', 123, Date() ) // gen RTE
RETURN NIL
STATIC FUNCTION MY_FUNC( ... )
RETURN hb_ValToExp( { ... } )
/* missing function redirector based on standard error handler */
#include "error.ch"
FUNCTION UDF_DEFFUN( cFuncName, bCode )
STATIC s_hUdfSubst
LOCAL bError
IF HB_ISHASHKEY( cFuncName )
IF s_hUdfSubst == NIL
s_hUdfSubst := { => }
bError := ErrorBlock( {| oError | UDF_ErrorCode( oError, bError, s_hUdfSubst ) } )
ENDIF
IF HB_ISEVALITEM( bCode )
s_hUdfSubst[ cFuncName ] := bCode
ELSE
hb_HDel( s_hUdfSubst, cFuncName )
ENDIF
ENDIF
RETURN NIL
STATIC FUNCTION UDF_ErrorCode( oError, bError, hUdfSubst )
LOCAL bFunc
IF oError:genCode == EG_NOFUNC .AND. oError:subCode == 1001 .AND. ;
oError:canSubstitute .AND. ;
( bFunc := hb_HGetDef( hUdfSubst, oError:operation ) ) != NIL
RETURN Eval( bFunc, hb_ArrayToParams( oError:args ) )
ENDIF
RETURN Eval( bError, oError )