simulate unknown Function of UDF in IndexKey()

simulate unknown Function of UDF in IndexKey()

Postby Jimmy » Fri May 05, 2023 4:42 am

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
Code: Select all  Expand view  RUN
  RECOVER oError

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
Code: Select all  Expand view  RUN
FUNCTION Dummy()
RETURN .T.

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 :idea:
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1732
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Fri May 05, 2023 8:43 am

Dear Jimmy,

To build it:
hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_

create.prg
Code: Select all  Expand view  RUN
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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Fri May 05, 2023 9:21 am

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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Fri May 05, 2023 10:52 am

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 view  RUN
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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Fri May 05, 2023 11:29 am

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 view  RUN
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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Sat May 06, 2023 7:57 am

Using hashes from low level to support multiple codeblocks :-D

Remember to build it this way:
hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_

Code: Select all  Expand view  RUN
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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Jimmy » Mon May 08, 2023 12:42 pm

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 view  RUN
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
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1732
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Mon May 08, 2023 7:04 pm

Dear Jimmy,

I use this go.bat
Code: Select all  Expand view  RUN
set path=c:\bcc7\bin
c:\harbour\bin\win\bcc\hbmk2.exe create.prg -cflag=-D_HB_API_INTERNAL_
create
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: simulate unknown Function of UDF in IndexKey()

Postby Jimmy » Tue May 09, 2023 8:23 pm

hi Antonio,

thx for go.bat
now it work :D
greeting,
Jimmy
User avatar
Jimmy
 
Posts: 1732
Joined: Thu Sep 05, 2019 5:32 am
Location: Hamburg, Germany

Re: simulate unknown Function of UDF in IndexKey()

Postby Antonio Linares » Sun May 14, 2023 7:17 am

Przemek solution using the Harbour error handler:

Code: Select all  Expand view  RUN
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 )
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 35 guests