/* * Base-routines for OOPS system * * Copyright 1999 Antonio Linares * Copyright 1999 Eddie Runia * :CLASSSEL() * __clsDelMsg() * __clsModMsg() * __clsInstSuper() * __cls_CntClsData() * __cls_CntData() * __cls_DecData() * __cls_IncData() * __objClone() * __objHasMsg() * __objSendMsg() * * Copyright 1999-2001 Viktor Szakats (vszakats.net/harbour) * __classNew() * __classInstance() * __classAdd() * __className() * __classSel() (based on hb___msgClsSel()) * * Copyright 1999 Janica Lubos * hb_clsDictRealloc() * * Copyright 2000-2007 JF. Lefebvre & RA. Cuylen * hb_clsDictRealloc() New version * Now support of shared and not shared class data * Multiple data declarations fully supported * * Copyright 2000 Ryszard Glab * Garbage collector fixes * * Copyright 2001 JF. Lefebvre * Super msg corrected * Scoping: working for PROTECTED, HIDDEN and READONLY * To Many enhancement and correction to give a full list :-) * Improved Class(y) compatibility * Improved TopClass compatibility * __CLS_PAR00() (Allow the creation of class which not autoinherit of the default HBObject()) * Adding HB_CLS_ENFORCERO FLAG to disable Write access to RO VAR * outside of Constructors /!\ Could be related to some incompatibility * Added hb_objGetRealClsName() to keep a full class tree (for 99% cases) * Fixed hb_clsIsParent() * hb_objGetMthd() & __clsAddMsg() modified to translate operators * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file LICENSE.txt. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include "hbvmopt.h" #include "hbapi.h" #include "hbapicls.h" #include "hbstack.h" #include "hbapierr.h" #include "hbapiitm.h" #include "hbvm.h" #include "hbthread.h" #include "hboo.ch" typedef struct { HB_USHORT uiClass; HB_USHORT uiOffset; } HB_CLSCAST, * PHB_CLSCAST; typedef struct { PHB_ITEM pInitValue; /* Init Value for data */ HB_USHORT uiType; /* HB_OO_MSG_DATA, HB_OO_MSG_CLASSDATA or HB_OO_MSG_INITIALIZED */ HB_USHORT uiData; /* Item position in instance area or class data */ HB_USHORT uiOffset; /* Super cast instance area offset for HB_OO_MSG_DATA or real class item position */ HB_USHORT uiSprClass; /* The real class where method were defined */ } INITDATA, * PINITDATA; typedef struct { PHB_DYNS pMessage; /* Method symbolic name */ PHB_DYNS pAccMsg; /* Corresponding access method symbolic name */ PHB_SYMB pFuncSym; /* Function symbol */ PHB_SYMB pRealSym; /* Real function symbol when wrapper is used */ HB_TYPE itemType; /* Type of item in restricted assignment */ HB_USHORT uiSprClass; /* Original class handle (super or current class handle if not inherited). [RAC&JF] */ HB_USHORT uiScope; /* Scoping value */ HB_USHORT uiData; /* Item position for instance data, class data and shared data (Harbour like, begin from 1), supercast class or delegated message index object */ HB_USHORT uiOffset; /* position in pInitData for class datas (from 1) or offset to instance area in inherited instance data and supercast messages (from 0) */ HB_USHORT uiPrevCls; HB_USHORT uiPrevMth; #ifndef HB_NO_PROFILER HB_ULONG ulCalls; /* profiler support */ HB_ULONG ulTime; /* profiler support */ HB_ULONG ulRecurse; /* profiler support */ #endif } METHOD, * PMETHOD; #define HB_MSG_POOL typedef struct { char * szName; /* Class name */ PHB_DYNS pClassSym; /* Class symbolic name */ PMETHOD pMethods; /* Class methods */ PHB_SYMB pClassFuncSym; /* Class function symbol */ PHB_SYMB pFriendModule; /* Class friend symbols */ PINITDATA pInitData; /* Class/instance Initialization data */ PHB_ITEM pClassDatas; /* Harbour Array for Class Datas */ PHB_ITEM pSharedDatas; /* Harbour Array for Class Shared Datas */ PHB_ITEM pInlines; /* Array for inline codeblocks */ PHB_ITEM pMutex; /* Class sync method mutex */ PHB_SYMB * pFriendSyms; /* Friend functions' symbols */ PHB_CLSCAST pSuperClasses; /* Super classes */ HB_U32 nOpFlags; /* Flags for overloaded operators */ HB_USHORT uiClass; /* This class handle */ HB_USHORT fHasDestructor; /* has the class destructor message? */ HB_USHORT fHasOnError; /* has the class OnError message? */ HB_USHORT fLocked; /* Class is locked against modifications */ HB_USHORT uiMethods; /* Total Method initialized Counter */ HB_USHORT uiInitDatas; /* Total Method initialized Counter */ HB_USHORT uiDatas; /* Total Data Counter */ HB_USHORT uiDataFirst; /* First instance item from this class */ HB_USHORT uiSuperClasses; /* Number of super classes */ HB_USHORT uiFriendSyms; /* Number of friend function's symbols */ HB_USHORT uiFriendModule; /* Number of friend symbols in pFriendModule */ HB_USHORT uiMutexOffset; /* Offset in instance area to SYNC method mutex */ HB_SIZE nHashKey; #ifdef HB_MSG_POOL HB_USHORT uiMethodCount; HB_USHORT * puiMsgIdx; #endif } CLASS, * PCLASS; #define BUCKETBITS 2 #define BUCKETSIZE ( 1 << BUCKETBITS ) #define BUCKETMASK ( BUCKETSIZE - 1 ) #define HASHBITS 3 #define HASH_KEY ( ( 1 << HASHBITS ) - 1 ) #define HASH_KEYMAX ( 1 << ( 32 - BUCKETBITS ) ) #define hb_clsInited(p) ( (p)->pMethods != NULL ) #define hb_clsBucketPos( p, m ) ( ( ( HB_SIZE ) (p)->uiSymNum & (m) ) << BUCKETBITS ) #ifdef HB_MSG_POOL # define hb_clsMthNum( p ) ( ( HB_SIZE ) ( p )->uiMethodCount ) #else # define hb_clsMthNum( p ) ( ( ( p )->nHashKey + 1 ) << BUCKETBITS ) #endif #if defined( HB_REAL_BLOCK_SCOPE ) # undef HB_CLASSY_BLOCK_SCOPE #elif ! defined( HB_CLASSY_BLOCK_SCOPE ) # define HB_REAL_BLOCK_SCOPE #endif #if ! defined( HB_CLASSY_BLOCK_SCOPE ) # define hb_clsSenderOffset() hb_stackBaseProcOffset( 1 ) #endif HB_FUNC_STATIC( msgGetData ); HB_FUNC_STATIC( msgSetData ); HB_FUNC_STATIC( msgGetClsData ); HB_FUNC_STATIC( msgSetClsData ); HB_FUNC_STATIC( msgGetShrData ); HB_FUNC_STATIC( msgSetShrData ); HB_FUNC_STATIC( msgEvalInline ); HB_FUNC_STATIC( msgVirtual ); HB_FUNC_STATIC( msgSuper ); HB_FUNC_STATIC( msgRealClass ); HB_FUNC_STATIC( msgPerform ); HB_FUNC_STATIC( msgDelegate ); HB_FUNC_STATIC( msgSync ); HB_FUNC_STATIC( msgSyncClass ); HB_FUNC_STATIC( msgNoMethod ); HB_FUNC_STATIC( msgScopeErr ); HB_FUNC_STATIC( msgTypeErr ); HB_FUNC_STATIC( msgNull ); HB_FUNC_STATIC( msgClassH ); HB_FUNC_STATIC( msgClassName ); HB_FUNC_STATIC( msgClassSel ); #if 0 HB_FUNC_STATIC( msgClass ); HB_FUNC_STATIC( msgClassParent ); #endif /* --- */ /* static variables and structures initialized at HVM startup which * do not need any synchronization mechanism in MT mode, [druzus] */ /* The positions of items in symbol table below have to correspond * to HB_OO_OP_* constants in hbapicls.h, [druzus] */ static HB_SYMB s_opSymbols[ HB_OO_MAX_OPERATOR + 1 ] = { { "__OPPLUS", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 00 */ { "__OPMINUS", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 01 */ { "__OPMULT", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 02 */ { "__OPDIVIDE", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 03 */ { "__OPMOD", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 04 */ { "__OPPOWER", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 05 */ { "__OPINC", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 06 */ { "__OPDEC", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 07 */ { "__OPEQUAL", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 08 */ { "__OPEXACTEQUAL", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 09 */ { "__OPNOTEQUAL", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 10 */ { "__OPLESS", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 11 */ { "__OPLESSEQUAL", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 12 */ { "__OPGREATER", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 13 */ { "__OPGREATEREQUAL", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 14 */ { "__OPASSIGN", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 15 */ { "__OPINSTRING", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 16 */ { "__OPINCLUDE", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 17 */ { "__OPNOT", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 18 */ { "__OPAND", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 19 */ { "__OPOR", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 20 */ { "__OPARRAYINDEX", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 21 */ { "__ENUMINDEX", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 22 */ { "__ENUMBASE", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 23 */ { "__ENUMVALUE", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 24 */ { "__ENUMSTART", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 25 */ { "__ENUMSKIP", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 26 */ { "__ENUMSTOP", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 27 */ { "__ENUMISFIRST", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 28 */ { "__ENUMISLAST", {HB_FS_MESSAGE}, {NULL}, NULL }, /* 29 */ }; static HB_SYMB s___msgDestructor = { "__msgDestructor", {HB_FS_MESSAGE}, {NULL}, NULL }; static HB_SYMB s___msgOnError = { "__msgOnError", {HB_FS_MESSAGE}, {NULL}, NULL }; static HB_SYMB s___msgSetData = { "__msgSetData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetData )}, NULL }; static HB_SYMB s___msgGetData = { "__msgGetData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetData )}, NULL }; static HB_SYMB s___msgSetClsData = { "__msgSetClsData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetClsData )}, NULL }; static HB_SYMB s___msgGetClsData = { "__msgGetClsData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetClsData )}, NULL }; static HB_SYMB s___msgSetShrData = { "__msgSetShrData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetShrData )}, NULL }; static HB_SYMB s___msgGetShrData = { "__msgGetShrData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetShrData )}, NULL }; static HB_SYMB s___msgEvalInline = { "__msgEvalInline", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgEvalInline )}, NULL }; static HB_SYMB s___msgVirtual = { "__msgVirtual", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgVirtual )}, NULL }; static HB_SYMB s___msgSuper = { "__msgSuper", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSuper )}, NULL }; static HB_SYMB s___msgRealClass = { "__msgRealClass", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgRealClass )}, NULL }; static HB_SYMB s___msgPerform = { "__msgPerform", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgPerform )}, NULL }; static HB_SYMB s___msgDelegate = { "__msgDelegate", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgDelegate )}, NULL }; static HB_SYMB s___msgSync = { "__msgSync", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSync )}, NULL }; static HB_SYMB s___msgSyncClass = { "__msgSyncClass", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSyncClass )}, NULL }; static HB_SYMB s___msgNoMethod = { "__msgNoMethod", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNoMethod )}, NULL }; static HB_SYMB s___msgScopeErr = { "__msgScopeErr", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgScopeErr )}, NULL }; static HB_SYMB s___msgTypeErr = { "__msgTypeErr", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgTypeErr )}, NULL }; static HB_SYMB s___msgNew = { "NEW", {HB_FS_MESSAGE}, {NULL}, NULL }; static HB_SYMB s___msgSymbol = { "SYMBOL", {HB_FS_MESSAGE}, {NULL}, NULL }; static HB_SYMB s___msgClassName = { "CLASSNAME", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassName )}, NULL }; static HB_SYMB s___msgClassH = { "CLASSH", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassH )}, NULL }; static HB_SYMB s___msgClassSel = { "CLASSSEL", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassSel )}, NULL }; static HB_SYMB s___msgExec = { "EXEC", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgName = { "NAME", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; /* static HB_SYMB s___msgClsParent = { "ISDERIVEDFROM", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassParent )},NULL }; static HB_SYMB s___msgClass = { "CLASS", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClass )}, NULL }; */ static HB_SYMB s___msgKeys = { "KEYS", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgValues = { "VALUES", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; /* Default enumerator methods (FOR EACH) */ static HB_SYMB s___msgEnumIndex = { "__ENUMINDEX", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgEnumBase = { "__ENUMBASE", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgEnumKey = { "__ENUMKEY", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgEnumValue = { "__ENUMVALUE", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgEnumIsFirst = { "__ENUMISFIRST", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgEnumIsLast = { "__ENUMISLAST", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; /* WITH OBJECT base value access/assign methods (:__withobject) */ static HB_SYMB s___msgWithObjectPush = { "__WITHOBJECT", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; static HB_SYMB s___msgWithObjectPop = { "___WITHOBJECT", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )}, NULL }; /* --- */ /* Scalar classes' handles */ /* If user wants to change scalar classes at runtime in MT mode then * he must resolve thread synchronization problem himself, [druzus] */ static HB_USHORT s_uiArrayClass = 0; static HB_USHORT s_uiBlockClass = 0; static HB_USHORT s_uiCharacterClass = 0; static HB_USHORT s_uiDateClass = 0; static HB_USHORT s_uiTimeStampClass = 0; static HB_USHORT s_uiHashClass = 0; static HB_USHORT s_uiLogicalClass = 0; static HB_USHORT s_uiNilClass = 0; static HB_USHORT s_uiNumericClass = 0; static HB_USHORT s_uiSymbolClass = 0; static HB_USHORT s_uiPointerClass = 0; static HB_USHORT s_uiObjectClass = 0; /* --- */ /* Class definition holder */ /* In MT mode we are allocating array big enough to hold all * class definitions so we do not have to worry about runtime * s_pClasses reallocation, [druzus] */ #if defined( HB_MT_VM ) # include "hbthread.h" # define HB_CLASS_POOL_SIZE 16382 # define HB_CLASS_LOCK() hb_threadEnterCriticalSection( &s_clsMtx ) # define HB_CLASS_UNLOCK() hb_threadLeaveCriticalSection( &s_clsMtx ) static HB_CRITICAL_NEW( s_clsMtx ); #else # define HB_CLASS_POOL_SIZE 0 # define HB_CLASS_LOCK() do {} while( 0 ) # define HB_CLASS_UNLOCK() do {} while( 0 ) #endif #define HB_CLASS_POOL_RESIZE 64 static PCLASS * s_pClasses = NULL; static HB_USHORT s_uiClsSize = 0; static HB_USHORT s_uiClasses = 0; static PHB_ITEM s_pClassMtx = NULL; /* --- */ #if 0 static HB_SIZE hb_clsBucketPos( PHB_DYNS pMsg, HB_SIZE uiMask ) { /* we can use PHB_DYNS address as base for hash key. * This value is perfectly unique and we do not need anything more * but it's not continuous so we will have to add dynamic BUCKETSIZE * modification to be 100% sure that we can resolve all symbol name * conflicts (though even without it it's rather theoretical problem). * [druzus] */ /* Safely divide it by 16 - it's minimum memory allocated for single * HB_DYNS structure */ /* return ( ( HB_USHORT ) ( ( HB_PTRUINT ) pMsg >> 4 ) & uiMask ) << BUCKETBITS; */ /* Using continuous symbol numbers we are 100% sure that we will cover * the whole 16-bit area and we will never have any problems until number * of symbols is limited to 2^16. [druzus] */ return ( pMsg->uiSymNum & uiMask ) << BUCKETBITS; } #endif /* hb_clsDictRealloc( PCLASS ) * * Realloc (widen) class */ static HB_BOOL hb_clsDictRealloc( PCLASS pClass ) { HB_SIZE nNewHashKey, nLimit, n; #ifdef HB_MSG_POOL HB_USHORT * puiMsgIdx; #else PMETHOD pNewMethods; #endif HB_TRACE( HB_TR_DEBUG, ( "hb_clsDictRealloc(%p)", ( void * ) pClass ) ); nNewHashKey = pClass->nHashKey + 1; nLimit = nNewHashKey << BUCKETBITS; do { nNewHashKey <<= 1; if( nNewHashKey > HASH_KEYMAX ) hb_errInternal( 6002, "Could not realloc class message in __clsDictRealloc()", NULL, NULL ); #ifdef HB_MSG_POOL puiMsgIdx = ( HB_USHORT * ) hb_xgrabz( ( nNewHashKey << BUCKETBITS ) * sizeof( HB_USHORT ) ); for( n = 0; n < nLimit; n++ ) { HB_USHORT uiMsg = pClass->puiMsgIdx[ n ]; if( pClass->puiMsgIdx[ n ] ) { HB_USHORT uiBucket = BUCKETSIZE; HB_USHORT * puiIdx = puiMsgIdx + hb_clsBucketPos( pClass->pMethods[ uiMsg ].pMessage, nNewHashKey - 1 ); do { if( *puiIdx == 0 ) /* this message position is empty */ { *puiIdx = uiMsg; break; } ++puiIdx; } while( --uiBucket ); /* Not enough go back to the beginning */ if( ! uiBucket ) { hb_xfree( puiMsgIdx ); break; } } } } while( n < nLimit ); pClass->nHashKey = nNewHashKey - 1; hb_xfree( pClass->puiMsgIdx ); pClass->puiMsgIdx = puiMsgIdx; #else pNewMethods = ( PMETHOD ) hb_xgrabz( ( nNewHashKey << BUCKETBITS ) * sizeof( METHOD ) ); for( n = 0; n < nLimit; n++ ) { PHB_DYNS pMessage = ( PHB_DYNS ) pClass->pMethods[ n ].pMessage; if( pMessage ) { PMETHOD pMethod = pNewMethods + hb_clsBucketPos( pMessage, nNewHashKey - 1 ); HB_USHORT uiBucket = BUCKETSIZE; do { if( ! pMethod->pMessage ) /* this message position is empty */ { memcpy( pMethod, pClass->pMethods + n, sizeof( METHOD ) ); break; } ++pMethod; } while( --uiBucket ); /* Not enough go back to the beginning */ if( ! uiBucket ) { hb_xfree( pNewMethods ); break; } } } } while( n < nLimit ); pClass->nHashKey = nNewHashKey - 1; hb_xfree( pClass->pMethods ); pClass->pMethods = pNewMethods; #endif return HB_TRUE; } static void hb_clsDictInit( PCLASS pClass, HB_SIZE nHashKey ) { HB_SIZE nSize; HB_TRACE( HB_TR_DEBUG, ( "hb_clsDictInit(%p,%" HB_PFS "u)", ( void * ) pClass, nHashKey ) ); pClass->nHashKey = nHashKey; #ifdef HB_MSG_POOL nSize = ( ( nHashKey + 1 ) << BUCKETBITS ) * sizeof( HB_USHORT ); pClass->puiMsgIdx = ( HB_USHORT * ) hb_xgrabz( nSize ); pClass->uiMethodCount = 1; pClass->pMethods = ( PMETHOD ) hb_xgrabz( sizeof( METHOD ) ); #else nSize = ( ( nHashKey + 1 ) << BUCKETBITS ) * sizeof( METHOD ); pClass->pMethods = ( PMETHOD ) hb_xgrabz( nSize ); #endif } static PMETHOD hb_clsFindMsg( PCLASS pClass, PHB_DYNS pMsg ) { #ifdef HB_MSG_POOL HB_USHORT uiBucket, * puiMsgIdx; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) ); puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey ); uiBucket = BUCKETSIZE; do { PMETHOD pMethod = &pClass->pMethods[ *puiMsgIdx ]; if( pMethod->pMessage == pMsg ) return pMethod; ++puiMsgIdx; } while( --uiBucket ); #else PMETHOD pMethod; HB_USHORT uiBucket; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) ); pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey ); uiBucket = BUCKETSIZE; do { if( pMethod->pMessage == pMsg ) return pMethod; ++pMethod; } while( --uiBucket ); #endif return NULL; } static PMETHOD hb_clsAllocMsg( PCLASS pClass, PHB_DYNS pMsg ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsAllocMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) ); do { #ifdef HB_MSG_POOL HB_USHORT uiBucket = BUCKETSIZE, * puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey ); do { if( *puiMsgIdx == 0 ) { pClass->pMethods = ( PMETHOD ) hb_xrealloc( pClass->pMethods, sizeof( METHOD ) * ( pClass->uiMethodCount + 1 ) ); memset( &pClass->pMethods[ pClass->uiMethodCount ], 0, sizeof( METHOD ) ); *puiMsgIdx = pClass->uiMethodCount++; return &pClass->pMethods[ *puiMsgIdx ]; } else if( pClass->pMethods[ *puiMsgIdx ].pMessage == pMsg ) return &pClass->pMethods[ *puiMsgIdx ]; ++puiMsgIdx; } while( --uiBucket ); #else PMETHOD pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey ); HB_USHORT uiBucket = BUCKETSIZE; do { if( ! pMethod->pMessage || pMethod->pMessage == pMsg ) return pMethod; ++pMethod; } while( --uiBucket ); #endif } while( hb_clsDictRealloc( pClass ) ); hb_errInternal( 6001, "Could not allocate new message", NULL, NULL ); return NULL; } static HB_BOOL hb_clsCanClearMethod( PMETHOD pMethod, HB_BOOL fError ) { HB_SYMBOL_UNUSED( pMethod ); HB_SYMBOL_UNUSED( fError ); #if 0 if( pMethod->pFuncSym == &s___msgSuper ) { if( fError ) hb_errRT_BASE( EG_ARG, 3000, "Cannot delete supercast messages", HB_ERR_FUNCNAME, 0 ); return HB_FALSE; } #endif return HB_TRUE; } static void hb_clsFreeMsg( PCLASS pClass, PHB_DYNS pMsg ) { #ifdef HB_MSG_POOL HB_USHORT uiBucket, * puiMsgIdx; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFreeMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) ); puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey ); uiBucket = BUCKETSIZE; do { if( *puiMsgIdx && pClass->pMethods[ *puiMsgIdx ].pMessage == pMsg ) { if( hb_clsCanClearMethod( &pClass->pMethods[ *puiMsgIdx ], HB_TRUE ) ) { memset( &pClass->pMethods[ *puiMsgIdx ], 0, sizeof( METHOD ) ); *puiMsgIdx = 0; pClass->uiMethods--; /* Decrease number of messages */ } return; } ++puiMsgIdx; } while( --uiBucket ); #else PMETHOD pMethod; HB_USHORT uiBucket; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFreeMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) ); pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey ); HB_USHORT = BUCKETSIZE; do { if( pMethod->pMessage == pMsg ) { if( hb_clsCanClearMethod( pMethod, HB_TRUE ) ) { /* Move messages */ while( --uiBucket ) { memcpy( pMethod, pMethod + 1, sizeof( METHOD ) ); pMethod++; } memset( pMethod, 0, sizeof( METHOD ) ); pClass->uiMethods--; /* Decrease number of messages */ } return; } ++pMethod; } while( --uiBucket ); #endif } static HB_BOOL hb_clsHasParentClass( PCLASS pClass, HB_USHORT uiParentCls ) { HB_USHORT uiCount = pClass->uiSuperClasses; while( uiCount ) { if( pClass->pSuperClasses[ --uiCount ].uiClass == uiParentCls ) return HB_TRUE; } return HB_FALSE; /* alternative method but can give wrong results * if user overloads super casting method, [druzus]. */ /* PMETHOD pMethod = hb_clsFindMsg( pClass, s_pClasses[ uiParentCls ]->pClassSym ); return pMethod && pMethod->pFuncSym == &s___msgSuper; */ } static HB_USHORT hb_clsGetParent( PCLASS pClass, PHB_DYNS pParentSym ) { HB_USHORT uiCount = pClass->uiSuperClasses; while( uiCount ) { HB_USHORT uiClass = pClass->pSuperClasses[ --uiCount ].uiClass; if( s_pClasses[ uiClass ]->pClassSym == pParentSym ) return uiClass; } return 0; /* alternative method but can give wrong results * if user overloads super casting method, [druzus]. */ /* PMETHOD pMethod = hb_clsFindMsg( pClass, pParentSym ); return pMethod && pMethod->pFuncSym == &s___msgSuper; */ } static HB_USHORT hb_clsParentInstanceOffset( PCLASS pClass, HB_USHORT uiParentCls ) { HB_USHORT uiCount = pClass->uiSuperClasses; while( uiCount ) { if( pClass->pSuperClasses[ --uiCount ].uiClass == uiParentCls ) return pClass->pSuperClasses[ uiCount ].uiOffset; } return 0; } #if 0 static HB_USHORT hb_clsParentInstanceOffset( PCLASS pClass, HB_USHORT uiParentCls ) { PMETHOD pMethod = hb_clsFindMsg( pClass, s_pClasses[ uiParentCls ]->pClassSym ); return ( pMethod && pMethod->pFuncSym == &s___msgSuper ) ? pMethod->uiOffset : 0; } #endif static HB_USHORT hb_clsAddInitValue( PCLASS pClass, PHB_ITEM pItem, HB_USHORT uiType, HB_USHORT uiData, HB_USHORT uiOffset, HB_USHORT uiSprClass ) { PINITDATA pInitData; HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddInitValue(%p,%p,%hu,%hu,%hu,%hu)", ( void * ) pClass, ( void * ) pItem, uiType, uiData, uiOffset, uiSprClass ) ); if( ! pItem || HB_IS_NIL( pItem ) ) return 0; if( ! pClass->uiInitDatas ) { pClass->pInitData = ( PINITDATA ) hb_xgrab( sizeof( INITDATA ) ); pInitData = pClass->pInitData + pClass->uiInitDatas++; } else { HB_USHORT ui = pClass->uiInitDatas; pInitData = pClass->pInitData; do { if( pInitData->uiType == uiType && pInitData->uiData + pInitData->uiOffset == uiData + uiOffset ) { hb_itemRelease( pInitData->pInitValue ); break; } ++pInitData; } while( --ui ); if( ui == 0 ) { pClass->pInitData = ( PINITDATA ) hb_xrealloc( pClass->pInitData, ( HB_SIZE ) ( pClass->uiInitDatas + 1 ) * sizeof( INITDATA ) ); pInitData = pClass->pInitData + pClass->uiInitDatas++; } } pInitData->pInitValue = hb_itemClone( pItem ); pInitData->uiType = uiType; pInitData->uiData = uiData; pInitData->uiOffset = uiOffset; pInitData->uiSprClass = uiSprClass; return pClass->uiInitDatas; } static HB_USHORT hb_clsFindRealClassDataOffset( PMETHOD pMethod ) { PMETHOD pRealMth; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindRealClassDataOffset(%p)", ( void * ) pMethod ) ); pRealMth = hb_clsFindMsg( s_pClasses[ pMethod->uiSprClass ], pMethod->pMessage ); if( pRealMth && pRealMth->uiSprClass == pMethod->uiSprClass && ( pRealMth->pFuncSym == &s___msgSetClsData || pRealMth->pFuncSym == &s___msgGetClsData ) ) { return pRealMth->uiData; } return 0; } static HB_USHORT hb_clsFindClassDataOffset( PCLASS pClass, PMETHOD pNewMethod ) { HB_USHORT uiData; HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindClassDataOffset(%p,%p)", ( void * ) pClass, ( void * ) pNewMethod ) ); uiData = hb_clsFindRealClassDataOffset( pNewMethod ); if( uiData ) { HB_SIZE nLimit = hb_clsMthNum( pClass ); PMETHOD pMethod = pClass->pMethods; do { if( pMethod->pMessage && pMethod != pNewMethod && pMethod->uiSprClass == pNewMethod->uiSprClass && ( pMethod->pFuncSym == &s___msgSetClsData || pMethod->pFuncSym == &s___msgGetClsData ) && uiData == hb_clsFindRealClassDataOffset( pMethod ) ) { return pMethod->uiData; } ++pMethod; } while( --nLimit ); } return 0; } static HB_BOOL hb_clsUpdateHiddenMessages( PMETHOD pSrcMethod, PMETHOD pDstMethod, PCLASS pDstClass ) { PMETHOD pNewMethod = pSrcMethod; HB_TRACE( HB_TR_DEBUG, ( "hb_clsUpdateHiddenMessages(%p,%p,%p)", ( void * ) pSrcMethod, ( void * ) pDstMethod, ( void * ) pDstClass ) ); if( ! pDstMethod->pMessage || ( hb_clsCanClearMethod( pDstMethod, HB_FALSE ) && pDstMethod->uiPrevCls != pDstMethod->uiSprClass && ( pDstMethod->uiScope & HB_OO_CLSTP_HIDDEN ) && ( pDstMethod->uiScope & HB_OO_CLSTP_NONVIRTUAL ) ) ) { while( pNewMethod && pNewMethod->uiPrevCls != pNewMethod->uiSprClass && ( pNewMethod->uiScope & HB_OO_CLSTP_HIDDEN ) && ( pNewMethod->uiScope & HB_OO_CLSTP_NONVIRTUAL ) ) { pNewMethod = hb_clsFindMsg( s_pClasses[ pNewMethod->uiPrevCls ], pNewMethod->pMessage ); } if( pNewMethod && pNewMethod != pSrcMethod && ! ( pNewMethod->uiScope & HB_OO_CLSTP_HIDDEN ) && hb_clsCanClearMethod( pDstMethod, HB_FALSE ) ) { HB_USHORT uiPrevCls = pDstMethod->uiPrevCls, uiPrevMth = pDstMethod->uiPrevMth; PHB_SYMB pFuncSym; memcpy( pDstMethod, pNewMethod, sizeof( METHOD ) ); pDstMethod->uiPrevCls = uiPrevCls; pDstMethod->uiPrevMth = uiPrevMth; pDstMethod->uiScope |= HB_OO_CLSTP_OVERLOADED | HB_OO_CLSTP_SUPER; pFuncSym = pDstMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pDstMethod->pRealSym; if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { pDstMethod->uiOffset = hb_clsParentInstanceOffset( pDstClass, pDstMethod->uiSprClass ); } else if( pFuncSym == &s___msgSetClsData || pFuncSym == &s___msgGetClsData ) { PCLASS pSrcClass = s_pClasses[ pDstMethod->uiSprClass ]; HB_USHORT uiData; /* check if we already have corresponding access or assign * message for this class var to reuse its index */ uiData = hb_clsFindClassDataOffset( pDstClass, pDstMethod ); if( uiData == 0 ) { uiData = ( HB_USHORT ) hb_arrayLen( pDstClass->pClassDatas ) + 1; hb_arraySize( pDstClass->pClassDatas, uiData ); } if( pDstMethod->uiOffset ) { pDstMethod->uiOffset = hb_clsAddInitValue( pDstClass, pSrcClass->pInitData[ pDstMethod->uiOffset - 1 ].pInitValue, HB_OO_MSG_CLASSDATA, uiData, 0, pDstMethod->uiSprClass ); } pDstMethod->uiData = uiData; } return HB_TRUE; } } return HB_FALSE; } static void hb_clsAddSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_USHORT uiOffset ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddSuperClass(%p,%hu,%hu)", ( void * ) pClass, uiSuperCls, uiOffset ) ); pClass->pSuperClasses = ( PHB_CLSCAST ) hb_xrealloc( pClass->pSuperClasses, ( pClass->uiSuperClasses + 1 ) * sizeof( HB_CLSCAST ) ); pClass->pSuperClasses[ pClass->uiSuperClasses ].uiClass = uiSuperCls; pClass->pSuperClasses[ pClass->uiSuperClasses++ ].uiOffset = uiOffset; } static void hb_clsDefineSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_BOOL fNew ) { PMETHOD pMethod; PCLASS pSprCls; HB_TRACE( HB_TR_DEBUG, ( "hb_clsDefineSuperClass(%p,%hu,%d)", ( void * ) pClass, uiSuperCls, fNew ) ); pSprCls = s_pClasses[ uiSuperCls ]; if( ! hb_clsHasParentClass( pClass, uiSuperCls ) ) { if( fNew ) { hb_clsAddSuperClass( pClass, uiSuperCls, pClass->uiDatas ); pClass->uiDatas += pSprCls->uiDatas - pSprCls->uiDataFirst; } else hb_clsAddSuperClass( pClass, uiSuperCls, pSprCls->uiDataFirst ); } pMethod = hb_clsAllocMsg( pClass, pSprCls->pClassSym ); if( pMethod->pMessage == NULL ) { pClass->uiMethods++; pMethod->pMessage = pSprCls->pClassSym; pMethod->uiSprClass = pClass->uiClass; pMethod->uiData = uiSuperCls; pMethod->uiScope = HB_OO_CLSTP_EXPORTED; pMethod->pFuncSym = &s___msgSuper; pMethod->uiOffset = hb_clsParentInstanceOffset( pClass, uiSuperCls ); } else { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgSuper && pMethod->uiData == uiSuperCls ) pMethod->uiOffset = hb_clsParentInstanceOffset( pClass, uiSuperCls ); } } static void hb_clsCopyClass( PCLASS pClsDst, PCLASS pClsSrc ) { PMETHOD pMethod; HB_SIZE nLimit; HB_TRACE( HB_TR_DEBUG, ( "hb_clsCopyClass(%p,%p)", ( void * ) pClsDst, ( void * ) pClsSrc ) ); hb_clsDictInit( pClsDst, pClsSrc->nHashKey ); pClsDst->fHasOnError = pClsSrc->fHasOnError; pClsDst->fHasDestructor = pClsSrc->fHasDestructor; /* CLASS DATA Not Shared ( new array, new value ) */ #if 0 /* enable this code if you want to inherit class variables values * from ancestor classes when new class is dynamically created. * (compatibility with older [x]Harbour versions) */ pClsDst->pClassDatas = hb_arrayClone( pClsSrc->pClassDatas ); #else pClsDst->pClassDatas = hb_itemArrayNew( hb_arrayLen( pClsSrc->pClassDatas ) ); #endif /* do not copy shared data array - just simply create new one */ pClsDst->pSharedDatas = hb_itemArrayNew( 0 ); pClsDst->pInlines = hb_arrayClone( pClsSrc->pInlines ); pClsDst->uiDatas = pClsSrc->uiDatas; pClsDst->uiMutexOffset = pClsSrc->uiMutexOffset; pClsDst->nOpFlags = pClsSrc->nOpFlags; if( pClsSrc->pMutex ) pClsDst->pMutex = hb_threadMutexCreate(); if( pClsSrc->uiInitDatas ) { HB_SIZE nSize = ( HB_SIZE ) pClsSrc->uiInitDatas * sizeof( INITDATA ); HB_USHORT uiData; pClsDst->uiInitDatas = pClsSrc->uiInitDatas; pClsDst->pInitData = ( PINITDATA ) hb_xgrab( nSize ); memcpy( pClsDst->pInitData, pClsSrc->pInitData, nSize ); for( uiData = 0; uiData < pClsDst->uiInitDatas; ++uiData ) { if( pClsDst->pInitData[ uiData ].uiType == HB_OO_MSG_INITIALIZED ) pClsDst->pInitData[ uiData ].uiType = HB_OO_MSG_CLASSDATA; pClsDst->pInitData[ uiData ].pInitValue = hb_itemNew( pClsDst->pInitData[ uiData ].pInitValue ); } } nLimit = hb_clsMthNum( pClsSrc ); #ifdef HB_MSG_POOL memcpy( pClsDst->puiMsgIdx, pClsSrc->puiMsgIdx, ( ( pClsSrc->nHashKey + 1 ) << BUCKETBITS ) * sizeof( HB_USHORT ) ); pClsDst->uiMethodCount = pClsSrc->uiMethodCount; pClsDst->pMethods = ( PMETHOD ) hb_xrealloc( pClsDst->pMethods, nLimit * sizeof( METHOD ) ); #endif memcpy( pClsDst->pMethods, pClsSrc->pMethods, nLimit * sizeof( METHOD ) ); pClsDst->uiMethods = pClsSrc->uiMethods; if( pClsSrc->uiSuperClasses ) { pClsDst->uiSuperClasses = pClsSrc->uiSuperClasses; pClsDst->pSuperClasses = ( PHB_CLSCAST ) hb_xgrab( pClsSrc->uiSuperClasses * sizeof( HB_CLSCAST ) ); memcpy( pClsDst->pSuperClasses, pClsSrc->pSuperClasses, pClsSrc->uiSuperClasses * sizeof( HB_CLSCAST ) ); } hb_clsDefineSuperClass( pClsDst, pClsSrc->uiClass, HB_FALSE ); pMethod = pClsDst->pMethods; do { if( pMethod->pMessage ) { hb_clsUpdateHiddenMessages( pMethod, pMethod, pClsDst ); pMethod->uiScope |= HB_OO_CLSTP_SUPER; } ++pMethod; } while( --nLimit ); } static HB_BOOL hb_clsIsFriendSymbol( PCLASS pClass, PHB_SYMB pSym ) { HB_USHORT uiCount; HB_TRACE( HB_TR_DEBUG, ( "hb_clsIsFriendSymbol(%p,%p)", ( void * ) pClass, ( void * ) pSym ) ); if( pClass->pFriendModule && pSym >= pClass->pFriendModule && pSym < pClass->pFriendModule + pClass->uiFriendModule ) return HB_TRUE; for( uiCount = 0; uiCount < pClass->uiFriendSyms; ++uiCount ) { if( pClass->pFriendSyms[ uiCount ] == pSym ) return HB_TRUE; } return HB_FALSE; } static void hb_clsAddFriendSymbol( PCLASS pClass, PHB_SYMB pSym ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddFriendSymbol(%p,%p)", ( void * ) pClass, ( void * ) pSym ) ); if( ! hb_clsIsFriendSymbol( pClass, pSym ) ) { if( pClass->uiFriendSyms == 0 ) { pClass->pFriendSyms = ( PHB_SYMB * ) hb_xgrab( sizeof( PHB_SYMB ) ); pClass->pFriendSyms[ 0 ] = pSym; pClass->uiFriendSyms++; } else { pClass->pFriendSyms = ( PHB_SYMB * ) hb_xrealloc( pClass->pFriendSyms, ( pClass->uiFriendSyms + 1 ) * sizeof( PHB_SYMB ) ); pClass->pFriendSyms[ pClass->uiFriendSyms++ ] = pSym; } } } /* initialize Classy/OO system at HVM startup */ void hb_clsInit( void ) { PHB_SYMB pOpSym; HB_USHORT uiOperator; HB_TRACE( HB_TR_DEBUG, ( "hb_clsInit()" ) ); for( uiOperator = 0, pOpSym = s_opSymbols; uiOperator <= HB_OO_MAX_OPERATOR; ++uiOperator, ++pOpSym ) { pOpSym->pDynSym = hb_dynsymGetCase( pOpSym->szName ); } s___msgDestructor.pDynSym = hb_dynsymGetCase( s___msgDestructor.szName ); s___msgOnError.pDynSym = hb_dynsymGetCase( s___msgOnError.szName ); s___msgClassName.pDynSym = hb_dynsymGetCase( s___msgClassName.szName ); /* Standard messages */ s___msgClassH.pDynSym = hb_dynsymGetCase( s___msgClassH.szName ); /* Not present in classdef. */ s___msgClassSel.pDynSym = hb_dynsymGetCase( s___msgClassSel.szName ); s___msgExec.pDynSym = hb_dynsymGetCase( s___msgExec.szName ); s___msgName.pDynSym = hb_dynsymGetCase( s___msgName.szName ); s___msgNew.pDynSym = hb_dynsymGetCase( s___msgNew.szName ); s___msgSymbol.pDynSym = hb_dynsymGetCase( s___msgSymbol.szName ); s___msgKeys.pDynSym = hb_dynsymGetCase( s___msgKeys.szName ); s___msgValues.pDynSym = hb_dynsymGetCase( s___msgValues.szName ); /* s___msgClsParent.pDynSym = hb_dynsymGetCase( s___msgClsParent.szName ); s___msgClass.pDynSym = hb_dynsymGetCase( s___msgClass.szName ); */ s___msgEnumIndex.pDynSym = hb_dynsymGetCase( s___msgEnumIndex.szName ); s___msgEnumBase.pDynSym = hb_dynsymGetCase( s___msgEnumBase.szName ); s___msgEnumKey.pDynSym = hb_dynsymGetCase( s___msgEnumKey.szName ); s___msgEnumValue.pDynSym = hb_dynsymGetCase( s___msgEnumValue.szName ); s___msgEnumIsFirst.pDynSym = hb_dynsymGetCase( s___msgEnumIsFirst.szName ); s___msgEnumIsLast.pDynSym = hb_dynsymGetCase( s___msgEnumIsLast.szName ); s___msgWithObjectPush.pDynSym = hb_dynsymGetCase( s___msgWithObjectPush.szName ); s___msgWithObjectPop.pDynSym = hb_dynsymGetCase( s___msgWithObjectPop.szName ); s_uiClsSize = HB_CLASS_POOL_SIZE; s_uiClasses = 0; s_pClasses = ( PCLASS * ) hb_xgrab( ( ( HB_SIZE ) s_uiClsSize + 1 ) * sizeof( PCLASS ) ); s_pClasses[ 0 ] = NULL; #if defined( HB_MT_VM ) s_pClassMtx = hb_threadMutexCreate(); #endif } /* initialize Classy/OO system .prg functions */ void hb_clsDoInit( void ) { static const char * s_pszFuncNames[] = { "HBARRAY", "HBBLOCK", "HBCHARACTER", "HBDATE", "HBTIMESTAMP", "HBHASH", "HBLOGICAL", "HBNIL", "HBNUMERIC", "HBSYMBOL", "HBPOINTER", "HBOBJECT" }; static HB_USHORT * s_puiHandles[] = { &s_uiArrayClass, &s_uiBlockClass, &s_uiCharacterClass, &s_uiDateClass, &s_uiTimeStampClass, &s_uiHashClass, &s_uiLogicalClass, &s_uiNilClass, &s_uiNumericClass, &s_uiSymbolClass, &s_uiPointerClass, &s_uiObjectClass }; HB_STACK_TLS_PRELOAD int i; HB_TRACE( HB_TR_DEBUG, ( "hb_clsDoInit()" ) ); for( i = 0; i < ( int ) HB_SIZEOFARRAY( s_puiHandles ); ++i ) { PHB_DYNS pFuncSym = hb_dynsymFindName( s_pszFuncNames[i] ); if( pFuncSym && hb_dynsymIsFunction( pFuncSym ) ) { PHB_ITEM pReturn = hb_stackReturnItem(); hb_itemSetNil( pReturn ); hb_vmPushDynSym( pFuncSym ); hb_vmPushNil(); hb_vmProc( 0 ); if( HB_IS_OBJECT( pReturn ) ) *( s_puiHandles[ i ] ) = pReturn->item.asArray.value->uiClass; } } } /* hb_clsRelease( ) * * Release a class from memory */ static void hb_clsRelease( PCLASS pClass ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsRelease(%p)", ( void * ) pClass ) ); if( pClass->uiInitDatas ) { HB_USHORT ui = pClass->uiInitDatas; PINITDATA pInitData = pClass->pInitData; do { hb_itemRelease( pInitData->pInitValue ); ++pInitData; } while( --ui ); hb_xfree( pClass->pInitData ); } if( pClass->szName ) hb_xfree( pClass->szName ); if( pClass->pMethods ) hb_xfree( pClass->pMethods ); if( pClass->uiFriendSyms ) hb_xfree( pClass->pFriendSyms ); if( pClass->pSuperClasses ) hb_xfree( pClass->pSuperClasses ); #ifdef HB_MSG_POOL if( pClass->puiMsgIdx ) hb_xfree( pClass->puiMsgIdx ); #endif if( pClass->pClassDatas ) hb_itemRelease( pClass->pClassDatas ); if( pClass->pSharedDatas ) hb_itemRelease( pClass->pSharedDatas ); if( pClass->pInlines ) hb_itemRelease( pClass->pInlines ); hb_xfree( pClass ); } /* hb_clsReleaseAll() * * Release all classes */ void hb_clsReleaseAll( void ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsReleaseAll()" ) ); if( s_uiClasses ) { HB_USHORT uiClass = s_uiClasses; /* It blocks destructor execution - don't move. [druzus] */ s_uiClasses = 0; do { hb_clsRelease( s_pClasses[ uiClass ] ); } while( --uiClass ); } if( s_pClasses ) { hb_xfree( s_pClasses ); s_pClasses = NULL; s_uiClsSize = 0; } if( s_pClassMtx ) { hb_itemRelease( s_pClassMtx ); s_pClassMtx = NULL; } } /* Mark all internal data as used so it will not be released by the * garbage collector */ void hb_clsIsClassRef( void ) { /* All internal items are allocated with hb_itemNew() * GC knows them and scan itself so it's not necessary * to repeat scanning here [druzus]. */ #if 0 HB_USHORT uiClass = s_uiClasses; HB_TRACE( HB_TR_DEBUG, ( "hb_clsIsClassRef()" ) ); while( uiClass ) { PCLASS pClass = s_pClasses[ uiClass-- ]; if( pClass->pInlines ) hb_gcItemRef( pClass->pInlines ); if( pClass->pClassDatas ) hb_gcItemRef( pClass->pClassDatas ); if( pClass->pSharedDatas ) hb_gcItemRef( pClass->pSharedDatas ); if( pClass->uiInitDatas ) { HB_USHORT ui = pClass->uiInitDatas; PINITDATA pInitData = pClass->pInitData; do { if( HB_IS_GCITEM( pInitData->pInitValue ) ) hb_gcItemRef( pInitData->pInitValue ); ++pInitData; } while( --ui ); } } #endif } HB_BOOL hb_clsIsParent( HB_USHORT uiClass, const char * szParentName ) { if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; if( strcmp( pClass->szName, szParentName ) == 0 ) return HB_TRUE; else { PHB_DYNS pMsg = hb_dynsymFindName( szParentName ); if( pMsg ) return hb_clsGetParent( pClass, pMsg ) != 0; } } return HB_FALSE; } HB_USHORT hb_objGetClass( PHB_ITEM pItem ) { if( pItem && HB_IS_ARRAY( pItem ) ) return pItem->item.asArray.value->uiClass; else return 0; } /* get object class handle using class name and class function name */ HB_USHORT hb_objSetClass( PHB_ITEM pItem, const char * szClass, const char * szFunc ) { HB_USHORT uiClass = 0; if( pItem && HB_IS_ARRAY( pItem ) && pItem->item.asArray.value->uiClass == 0 ) { uiClass = pItem->item.asArray.value->uiClass = hb_clsFindClass( szClass, szFunc ); } return uiClass; } /* --- */ /* Get the class handle */ static HB_USHORT hb_objGetClassH( PHB_ITEM pObject ) { HB_TRACE( HB_TR_DEBUG, ( "hb_objGetClassH(%p)", ( void * ) pObject ) ); if( HB_IS_ARRAY( pObject ) ) { if( pObject->item.asArray.value->uiClass != 0 ) return pObject->item.asArray.value->uiClass; else return s_uiArrayClass; } /* built in types */ else if( HB_IS_NIL( pObject ) ) return s_uiNilClass; else if( HB_IS_STRING( pObject ) ) return s_uiCharacterClass; else if( HB_IS_NUMERIC( pObject ) ) return s_uiNumericClass; else if( HB_IS_DATE( pObject ) ) return s_uiDateClass; else if( HB_IS_TIMESTAMP( pObject ) ) return s_uiTimeStampClass; else if( HB_IS_LOGICAL( pObject ) ) return s_uiLogicalClass; else if( HB_IS_BLOCK( pObject ) ) return s_uiBlockClass; else if( HB_IS_HASH( pObject ) ) return s_uiHashClass; else if( HB_IS_POINTER( pObject ) ) return s_uiPointerClass; else if( HB_IS_SYMBOL( pObject ) ) return s_uiSymbolClass; return 0; } /* Get the class name of an object */ const char * hb_objGetClsName( PHB_ITEM pObject ) { HB_TRACE( HB_TR_DEBUG, ( "hb_objGetClsName(%p)", ( void * ) pObject ) ); if( HB_IS_ARRAY( pObject ) ) { if( pObject->item.asArray.value->uiClass != 0 ) return s_pClasses[ pObject->item.asArray.value->uiClass ]->szName; else return "ARRAY"; } /* built in types */ else if( HB_IS_NIL( pObject ) ) return "NIL"; else if( HB_IS_STRING( pObject ) ) return "CHARACTER"; else if( HB_IS_NUMERIC( pObject ) ) return "NUMERIC"; else if( HB_IS_DATE( pObject ) ) return "DATE"; else if( HB_IS_TIMESTAMP( pObject ) ) return "TIMESTAMP"; else if( HB_IS_LOGICAL( pObject ) ) return "LOGICAL"; else if( HB_IS_BLOCK( pObject ) ) return "BLOCK"; else if( HB_IS_HASH( pObject ) ) return "HASH"; else if( HB_IS_POINTER( pObject ) ) return "POINTER"; else if( HB_IS_SYMBOL( pObject ) ) return "SYMBOL"; else return "UNKNOWN"; } const char * hb_clsName( HB_USHORT uiClass ) { if( uiClass && uiClass <= s_uiClasses ) return s_pClasses[ uiClass ]->szName; else return NULL; } const char * hb_clsFuncName( HB_USHORT uiClass ) { if( uiClass && uiClass <= s_uiClasses ) return s_pClasses[ uiClass ]->pClassFuncSym ? s_pClasses[ uiClass ]->pClassFuncSym->szName : ""; else return NULL; } PHB_SYMB hb_clsFuncSym( HB_USHORT uiClass ) { if( uiClass && uiClass <= s_uiClasses ) return s_pClasses[ uiClass ]->pClassFuncSym; else return NULL; } const char * hb_clsMethodName( HB_USHORT uiClass, HB_USHORT uiMethod ) { if( uiClass && uiClass <= s_uiClasses && ( HB_UINT ) uiMethod < ( HB_UINT ) hb_clsMthNum( s_pClasses[ uiClass ] ) ) { PMETHOD pMethod = s_pClasses[ uiClass ]->pMethods + uiMethod; if( pMethod->pMessage ) return pMethod->pMessage->pSymbol->szName; } return NULL; } static HB_SIZE hb_clsGetVarIndexEx( HB_USHORT uiClass, PHB_DYNS pVarSym, HB_USHORT uiSuper ) { PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiSuper ], pVarSym ); if( pMethod ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { return ( HB_SIZE ) pMethod->uiData + ( uiClass != uiSuper ? hb_clsParentInstanceOffset( s_pClasses[ uiClass ], uiSuper ) : pMethod->uiOffset ); } } return 0; } HB_SIZE hb_clsGetVarIndex( HB_USHORT uiClass, PHB_DYNS pVarSym ) { if( uiClass && uiClass <= s_uiClasses ) return hb_clsGetVarIndexEx( uiClass, pVarSym, uiClass ); else return 0; } HB_USHORT hb_clsFindClass( const char * szClass, const char * szClassFunc ) { HB_USHORT uiClass; for( uiClass = 1; uiClass <= s_uiClasses; uiClass++ ) { if( strcmp( szClass, s_pClasses[ uiClass ]->szName ) == 0 && ( ! szClassFunc || ( ! s_pClasses[ uiClass ]->pClassFuncSym ? ! *szClassFunc : strcmp( szClassFunc, s_pClasses[ uiClass ]->pClassFuncSym->szName ) == 0 ) ) ) { return uiClass; } } return 0; } static HB_USHORT hb_clsFindClassByFunc( PHB_SYMB pClassFuncSym ) { HB_USHORT uiClass; for( uiClass = 1; uiClass <= s_uiClasses; uiClass++ ) { if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym ) { return uiClass; } } return 0; } /* Get the real method symbol for given stack symbol */ PHB_SYMB hb_clsMethodSym( PHB_ITEM pBaseSymbol ) { PHB_STACK_STATE pStack = pBaseSymbol->item.asSymbol.stackstate; if( pStack->uiClass ) { PMETHOD pMethod = s_pClasses[ pStack->uiClass ]->pMethods + pStack->uiMethod; PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgEvalInline ) { PHB_ITEM pItem = hb_arrayGetItemPtr( s_pClasses[ pMethod->uiSprClass ]->pInlines, pMethod->uiData ); return pItem ? pItem->item.asBlock.value->pDefSymb : NULL; } /* else if( pFuncSym == &s___msgPerform ) */ else if( pFuncSym == &s___msgDelegate ) return s_pClasses[ pStack->uiClass ]->pMethods[ pMethod->uiData ].pFuncSym; else return pFuncSym; } return pBaseSymbol->item.asSymbol.value; } /* Get the real class name of an object message * Will return the class name from wich the message is inherited in case * of inheritance. */ const char * hb_objGetRealClsName( PHB_ITEM pObject, const char * szName ) { HB_USHORT uiClass; HB_TRACE( HB_TR_DEBUG, ( "hb_objGetrealClsName(%p,%s)", ( void * ) pObject, szName ) ); uiClass = hb_objGetClassH( pObject ); if( uiClass && uiClass <= s_uiClasses ) { PHB_DYNS pMsg = hb_dynsymFindName( szName ); if( pMsg ) { PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsg ); if( pMethod ) uiClass = pMethod->uiSprClass; } if( uiClass && uiClass <= s_uiClasses ) return s_pClasses[ uiClass ]->szName; } return hb_objGetClsName( pObject ); } #if defined( HB_CLASSY_BLOCK_SCOPE ) static HB_ISIZ hb_clsSenderOffset( void ) { HB_ISIZ nOffset = hb_stackBaseProcOffset( 1 ); if( nOffset > 0 ) { /* Is it inline method? */ if( nOffset > 0 && HB_IS_BLOCK( hb_stackItem( nOffset + 1 ) ) && ( hb_stackItem( nOffset )->item.asSymbol.value == &hb_symEval || hb_stackItem( nOffset )->item.asSymbol.value->pDynSym == hb_symEval.pDynSym ) ) { nOffset = hb_stackItem( nOffset )->item.asSymbol.stackstate->nBaseItem; /* I do not like it but Class(y) makes something like that. [druzus] */ while( nOffset > 0 && hb_stackItem( nOffset )->item.asSymbol.stackstate->uiClass == 0 ) nOffset = hb_stackItem( nOffset )->item.asSymbol.stackstate->nBaseItem; } return nOffset; } return -1; } #endif #if 0 static HB_USHORT hb_clsSenderClass( void ) { HB_ISIZ nOffset = hb_clsSenderOffset(); if( nOffset > 0 ) return hb_stackItem( nOffset )->item.asSymbol.stackstate->uiClass; else return 0; } #endif static HB_USHORT hb_clsSenderMethodClass( void ) { HB_ISIZ nOffset = hb_clsSenderOffset(); if( nOffset > 0 ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackItem( nOffset )->item.asSymbol.stackstate; if( pStack->uiClass ) return ( s_pClasses[ pStack->uiClass ]->pMethods + pStack->uiMethod )->uiSprClass; } return 0; } static PHB_SYMB hb_clsSenderSymbol( void ) { PHB_SYMB pSym = NULL; HB_ISIZ nOffset = hb_clsSenderOffset(); if( nOffset > 0 ) { HB_STACK_TLS_PRELOAD pSym = hb_stackItem( nOffset )->item.asSymbol.value; if( pSym == &hb_symEval || pSym->pDynSym == hb_symEval.pDynSym ) { PHB_ITEM pBlock = hb_stackItem( nOffset + 1 ); if( HB_IS_BLOCK( pBlock ) ) pSym = pBlock->item.asBlock.value->pDefSymb; } } return hb_vmGetRealFuncSym( pSym ); } static HB_USHORT hb_clsSenderObjectClass( void ) { HB_ISIZ nOffset = hb_clsSenderOffset(); if( nOffset > 0 ) { HB_STACK_TLS_PRELOAD PHB_ITEM pSender = hb_stackItem( nOffset + 1 ); if( HB_IS_ARRAY( pSender ) ) return pSender->item.asArray.value->uiClass; } return 0; } static PHB_SYMB hb_clsValidScope( PMETHOD pMethod, PHB_STACK_STATE pStack ) { if( pMethod->uiScope & ( HB_OO_CLSTP_HIDDEN | HB_OO_CLSTP_PROTECTED | HB_OO_CLSTP_OVERLOADED ) ) { HB_USHORT uiSenderClass = hb_clsSenderMethodClass(); if( uiSenderClass == pMethod->uiSprClass ) return pMethod->pFuncSym; else if( uiSenderClass ) { /* Warning!!! Friends cannot access overloaded non virtual methods. * This feature is available _ONLY_ for real class members, [druzus] */ if( pMethod->uiScope & HB_OO_CLSTP_OVERLOADED && hb_clsHasParentClass( s_pClasses[ pStack->uiClass ], uiSenderClass ) ) { PCLASS pClass = s_pClasses[ uiSenderClass ]; PMETHOD pHiddenMthd = hb_clsFindMsg( pClass, pMethod->pMessage ); if( pHiddenMthd && ( pHiddenMthd->uiScope & HB_OO_CLSTP_NONVIRTUAL ) && pHiddenMthd->uiSprClass == uiSenderClass ) { pStack->uiClass = uiSenderClass; pStack->uiMethod = ( HB_USHORT ) ( pHiddenMthd - pClass->pMethods ); return pHiddenMthd->pFuncSym; } } if( pMethod->uiScope & HB_OO_CLSTP_HIDDEN ) { if( ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ], s_pClasses[ uiSenderClass ]->pClassFuncSym ) ) return &s___msgScopeErr; } else if( pMethod->uiScope & HB_OO_CLSTP_PROTECTED && ! hb_clsHasParentClass( s_pClasses[ pStack->uiClass ], uiSenderClass ) && ! hb_clsHasParentClass( s_pClasses[ uiSenderClass ], pStack->uiClass ) && ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ], s_pClasses[ uiSenderClass ]->pClassFuncSym ) && ( pStack->uiClass == pMethod->uiSprClass || ! hb_clsIsFriendSymbol( s_pClasses[ pStack->uiClass ], s_pClasses[ uiSenderClass ]->pClassFuncSym ) ) ) return &s___msgScopeErr; } else if( pMethod->uiScope & ( HB_OO_CLSTP_HIDDEN | HB_OO_CLSTP_PROTECTED ) ) { PHB_SYMB pSym = hb_clsSenderSymbol(); if( ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ], pSym ) ) { if( ( pMethod->uiScope & HB_OO_CLSTP_HIDDEN ) || ! hb_clsIsFriendSymbol( s_pClasses[ pStack->uiClass ], pSym ) ) return &s___msgScopeErr; } } } return pMethod->pFuncSym; } static PHB_SYMB hb_clsScalarMethod( PCLASS pClass, PHB_DYNS pMsg, PHB_STACK_STATE pStack ) { PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg ); if( pStack ) { pStack->uiClass = pClass->uiClass; if( pMethod ) { pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods ); return hb_clsValidScope( pMethod, pStack ); } } else if( pMethod ) return pMethod->pFuncSym; return NULL; } static void hb_clsMakeSuperObject( PHB_ITEM pDest, PHB_ITEM pObject, HB_USHORT uiSuperClass ) { HB_TRACE( HB_TR_DEBUG, ( "hb_clsMakeSuperObject(%p, %p, %hu)", ( void * ) pDest, ( void * ) pObject, uiSuperClass ) ); /* create a fake object array */ hb_arrayNew( pDest, 1 ); /* Now save the Self object as the 1st elem. */ hb_arraySet( pDest, 1, pObject ); /* And transform it into a fake object */ /* backup of actual handle */ pDest->item.asArray.value->uiPrevCls = hb_objGetClassH( pObject ); /* superclass handle casting */ pDest->item.asArray.value->uiClass = uiSuperClass; } /* = hb_objGetMethod( , , ) * * Internal function to the function pointer of a message of an object */ PHB_SYMB hb_objGetMethod( PHB_ITEM pObject, PHB_SYMB pMessage, PHB_STACK_STATE pStack ) { HB_STACK_TLS_PRELOAD PCLASS pClass = NULL; PHB_DYNS pMsg; HB_TRACE( HB_TR_DEBUG, ( "hb_objGetMethod(%p, %p, %p)", ( void * ) pObject, ( void * ) pMessage, ( void * ) pStack ) ); pMsg = pMessage->pDynSym; if( HB_IS_ARRAY( pObject ) ) { if( pObject->item.asArray.value->uiClass ) { pClass = s_pClasses[ pObject->item.asArray.value->uiClass ]; if( pStack ) { pStack->uiClass = pObject->item.asArray.value->uiClass; if( pObject->item.asArray.value->uiPrevCls ) { if( pObject->item.asArray.value->nLen ) { /* Copy real object - do not move! the same super casted * object can be used more then once and we mustn't * destroy it. We can safely use hb_stackReturnItem() here. */ hb_itemCopy( hb_stackReturnItem(), pObject->item.asArray.value->pItems ); /* move real object back to the stack */ hb_itemMove( pObject, hb_stackReturnItem() ); } else /* Someone tried to manipulate with supercast array */ hb_itemClear( pObject ); } #ifdef HB_MSG_POOL { HB_USHORT uiBucket = BUCKETSIZE, * puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey ); do { PMETHOD pMethod = &pClass->pMethods[ *puiMsgIdx ]; if( pMethod->pMessage == pMsg ) { pStack->uiMethod = *puiMsgIdx; return hb_clsValidScope( pMethod, pStack ); } ++puiMsgIdx; } while( --uiBucket ); } #else { PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg ); if( pMethod ) { pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods ); return hb_clsValidScope( pMethod, pStack ); } } #endif } else { PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg ); if( pMethod ) return pMethod->pFuncSym; } } else if( s_uiArrayClass ) { pClass = s_pClasses[ s_uiArrayClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_BLOCK( pObject ) ) { if( pMsg == hb_symEval.pDynSym ) return &hb_symEval; else if( s_uiBlockClass ) { pClass = s_pClasses[ s_uiBlockClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_BYREF( pObject ) ) { if( pStack ) { /* method of enumerator variable from FOR EACH statement */ PHB_ITEM pEnum = hb_itemUnRefOnce( pObject ); if( HB_IS_ENUM( pEnum ) ) { /* Do actions here - we already have unreferenced pEnum so * it will be a little bit faster but in the future it's * possible that I'll move it to separate function when * I'll add enumerators overloading. [druzus] */ if( pMsg == s___msgEnumIndex.pDynSym ) { hb_itemPutNS( hb_stackReturnItem(), pEnum->item.asEnum.offset ); if( hb_pcount() > 0 && HB_ISNUM( 1 ) ) pEnum->item.asEnum.offset = hb_itemGetNS( hb_param( 1, HB_IT_ANY ) ); return &s___msgEnumIndex; } else if( pMsg == s___msgEnumKey.pDynSym ) { PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ? hb_itemUnRef( pEnum->item.asEnum.basePtr ) : pEnum->item.asEnum.basePtr; if( HB_IS_HASH( pBase ) ) { pBase = hb_hashGetKeyAt( pBase, pEnum->item.asEnum.offset ); if( pBase ) hb_itemCopy( hb_stackReturnItem(), pBase ); } return &s___msgEnumKey; } else if( pMsg == s___msgEnumBase.pDynSym ) { if( HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ) hb_itemCopy( hb_stackReturnItem(), hb_itemUnRef( pEnum->item.asEnum.basePtr ) ); else hb_itemCopy( hb_stackReturnItem(), pEnum->item.asEnum.basePtr ); if( hb_pcount() > 0 ) hb_itemCopy( pEnum->item.asEnum.basePtr, hb_itemUnRef( hb_stackItemFromBase( 1 ) ) ); return &s___msgEnumBase; } else if( pMsg == s___msgEnumValue.pDynSym ) { pEnum = hb_itemUnRef( pEnum ); hb_itemCopy( hb_stackReturnItem(), pEnum ); if( hb_pcount() > 0 ) hb_itemCopy( pEnum, hb_itemUnRef( hb_stackItemFromBase( 1 ) ) ); return &s___msgEnumValue; } else if( pMsg == s___msgEnumIsFirst.pDynSym ) { PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ? hb_itemUnRef( pEnum->item.asEnum.basePtr ) : pEnum->item.asEnum.basePtr; if( HB_IS_OBJECT( pBase ) && hb_objHasOperator( pBase, HB_OO_OP_ENUMISFIRST ) ) return hb_objGetMethod( pBase, pMessage, pStack ); hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset <= 1 ); return &s___msgEnumIsFirst; } else if( pMsg == s___msgEnumIsLast.pDynSym ) { PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ? hb_itemUnRef( pEnum->item.asEnum.basePtr ) : pEnum->item.asEnum.basePtr; if( HB_IS_ARRAY( pBase ) ) { if( HB_IS_OBJECT( pBase ) && hb_objHasOperator( pBase, HB_OO_OP_ENUMISLAST ) ) return hb_objGetMethod( pBase, pMessage, pStack ); else hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_arrayLen( pBase ) ); } else if( HB_IS_HASH( pBase ) ) hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_hashLen( pBase ) ); else if( HB_IS_STRING( pBase ) ) hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_itemGetCLen( pBase ) ); return &s___msgEnumIsLast; } } } } else if( HB_IS_SYMBOL( pObject ) ) { if( s_uiSymbolClass ) { pClass = s_pClasses[ s_uiSymbolClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } if( pMsg == s___msgExec.pDynSym || pMsg == hb_symEval.pDynSym ) { if( ! pObject->item.asSymbol.value->value.pFunPtr && pObject->item.asSymbol.value->pDynSym ) return pObject->item.asSymbol.value->pDynSym->pSymbol; else return pObject->item.asSymbol.value; } else if( pMsg == s___msgName.pDynSym ) { hb_itemPutC( hb_stackReturnItem(), pObject->item.asSymbol.value->szName ); return &s___msgName; } } else if( HB_IS_HASH( pObject ) ) { if( s_uiHashClass ) { pClass = s_pClasses[ s_uiHashClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } if( pMsg == s___msgKeys.pDynSym ) { hb_itemReturnRelease( hb_hashGetKeys( pObject ) ); return &s___msgKeys; } else if( pMsg == s___msgValues.pDynSym ) { hb_itemReturnRelease( hb_hashGetValues( pObject ) ); return &s___msgValues; } #if defined( HB_HASH_MSG_ITEMS ) else { if( hb_pcount() == 1 && pMessage->szName[ 0 ] == '_' ) /* ASSIGN */ { PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName + 1 ); PHB_ITEM pDest = hb_hashGetItemPtr( pObject, pIndex, HB_HASH_AUTOADD_ASSIGN ); hb_stackPop(); if( pDest ) { PHB_ITEM pValue = hb_param( 1, HB_IT_ANY ); hb_itemCopyFromRef( pDest, pValue ); hb_itemReturn( pValue ); return &s___msgVirtual; } } else if( hb_pcount() == 0 ) /* ACCESS */ { PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName ); PHB_ITEM pValue = hb_hashGetItemPtr( pObject, pIndex, HB_HASH_AUTOADD_ACCESS ); hb_stackPop(); if( pValue ) { hb_itemReturn( pValue ); return &s___msgVirtual; } } } #endif } else if( HB_IS_STRING( pObject ) ) { if( s_uiCharacterClass ) { pClass = s_pClasses[ s_uiCharacterClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_DATE( pObject ) ) { if( s_uiDateClass ) { pClass = s_pClasses[ s_uiDateClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_TIMESTAMP( pObject ) ) { if( s_uiTimeStampClass ) { pClass = s_pClasses[ s_uiTimeStampClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_NUMERIC( pObject ) ) { if( s_uiNumericClass ) { pClass = s_pClasses[ s_uiNumericClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_LOGICAL( pObject ) ) { if( s_uiLogicalClass ) { pClass = s_pClasses[ s_uiLogicalClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_POINTER( pObject ) ) { if( s_uiPointerClass ) { pClass = s_pClasses[ s_uiPointerClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } else if( HB_IS_NIL( pObject ) ) { if( s_uiNilClass ) { pClass = s_pClasses[ s_uiNilClass ]; { PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack ); if( pExecSym ) return pExecSym; } } } /* Default messages here */ if( pMsg == s___msgWithObjectPush.pDynSym ) { if( pStack ) { PHB_ITEM pItem = hb_stackWithObjectItem(); if( pItem ) { /* push current WITH OBJECT object */ hb_itemCopy( hb_stackReturnItem(), pItem ); return &s___msgWithObjectPush; } } } else if( pMsg == s___msgWithObjectPop.pDynSym ) { if( pStack ) { PHB_ITEM pItem = hb_stackWithObjectItem(); if( pItem ) { /* replace current WITH OBJECT object */ hb_itemCopy( pItem, hb_stackItemFromBase( 1 ) ); hb_itemCopy( hb_stackReturnItem(), pItem ); return &s___msgWithObjectPop; } } } else if( pMsg == s___msgClassName.pDynSym ) return &s___msgClassName; else if( pMsg == s___msgClassH.pDynSym ) return &s___msgClassH; else if( pMsg == s___msgClassSel.pDynSym ) return &s___msgClassSel; /* else if( pMsg == s___msgClsParent.pDynSym ) return &s___msgClsParent; else if( pMsg == s___msgClass.pDynSym ) return &s___msgClass; */ if( pStack ) { if( pClass && pClass->fHasOnError ) { PMETHOD pMethod = hb_clsFindMsg( pClass, s___msgOnError.pDynSym ); if( pMethod ) { pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods ); return pMethod->pFuncSym; } } /* remove this line if you want default HVM error message */ return &s___msgNoMethod; } return NULL; } HB_BOOL hb_objGetVarRef( PHB_ITEM pObject, PHB_SYMB pMessage, PHB_STACK_STATE pStack ) { PHB_SYMB pExecSym; #if defined( HB_HASH_MSG_ITEMS ) if( HB_IS_HASH( pObject ) ) { HB_STACK_TLS_PRELOAD PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName + 1 ); PHB_ITEM pValue = hb_hashGetItemRefPtr( pObject, pIndex ); hb_stackPop(); if( pValue ) hb_itemReturn( pValue ); return pValue != NULL; } #endif pExecSym = hb_objGetMethod( pObject, pMessage, pStack ); if( pExecSym ) { HB_STACK_TLS_PRELOAD if( pExecSym == &s___msgSetData ) { HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass; PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; HB_SIZE nIndex = pMethod->uiData; if( pStack->uiClass != uiObjClass ) nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ], pMethod->uiSprClass ); else nIndex += pMethod->uiOffset; /* will arise only if the class has been modified after first instance */ if( nIndex > hb_arrayLen( pObject ) ) /* Resize needed */ hb_arraySize( pObject, nIndex ); /* Make large enough */ return hb_arrayGetItemRef( pObject, nIndex, hb_stackReturnItem() ); } else if( pExecSym == &s___msgSetClsData ) { PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; return hb_arrayGetItemRef( pClass->pClassDatas, pMethod->uiData, hb_stackReturnItem() ); } else if( pExecSym == &s___msgSetShrData ) { PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; return hb_arrayGetItemRef( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas, pMethod->uiData, hb_stackReturnItem() ); } else if( pExecSym == &s___msgScopeErr ) { pExecSym->value.pFunPtr(); } else if( pStack->uiClass ) { PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; if( pMethod->pMessage == s___msgOnError.pDynSym ) return hb_vmMsgReference( pObject, pMessage->pDynSym, NULL ); if( ! pMethod->pAccMsg ) pMethod->pAccMsg = hb_dynsymGetCase( pMessage->szName + 1 ); return hb_vmMsgReference( pObject, pMessage->pDynSym, pMethod->pAccMsg ); } } return HB_FALSE; } /* Check if class has object destructors */ HB_BOOL hb_clsHasDestructor( HB_USHORT uiClass ) { if( uiClass && uiClass <= s_uiClasses ) return s_pClasses[ uiClass ]->fHasDestructor; else return HB_FALSE; } /* Call all known super destructors */ static void hb_objSuperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) { #if 0 HB_STACK_TLS_PRELOAD PMETHOD pMethod = pClass->pMethods; HB_SIZE nLimit = hb_clsMthNum( pClass ); char * pcClasses; HB_USHORT uiClass; pcClasses = ( char * ) hb_xgrabz( ( HB_SIZE ) s_uiClasses + 1 ); do { if( pMethod->pMessage ) { if( pMethod->pFuncSym == &s___msgSuper ) { PCLASS pSuperClass = s_pClasses[ pMethod->uiData ]; if( pSuperClass->fHasDestructor && pSuperClass != pClass ) pcClasses[ pMethod->uiData ] |= 1; } else if( pMethod->pMessage == s___msgDestructor.pDynSym ) pcClasses[ pMethod->uiSprClass ] |= 2; } ++pMethod; } while( --nLimit ); for( uiClass = s_uiClasses; uiClass; --uiClass ) { if( pcClasses[ uiClass ] == 1 ) { PMETHOD pDestructor = hb_clsFindMsg( s_pClasses[ uiClass ], s___msgDestructor.pDynSym ); if( pDestructor ) { if( pcClasses[ pDestructor->uiSprClass ] == 1 ) { hb_vmPushSymbol( &s___msgDestructor ); hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiClass ); hb_vmSend( 0 ); if( hb_vmRequestQuery() != 0 ) break; pcClasses[ pDestructor->uiSprClass ] |= 2; } } } } hb_xfree( pcClasses ); #else HB_STACK_TLS_PRELOAD HB_USHORT uiCount, uiDtorClass; uiDtorClass = hb_clsFindMsg( pClass, s___msgDestructor.pDynSym )->uiSprClass; uiCount = pClass->uiSuperClasses; while( uiCount-- ) { HB_USHORT uiParentCls = pClass->pSuperClasses[ uiCount ].uiClass; if( uiParentCls != uiDtorClass && uiParentCls != pClass->uiClass ) { PCLASS pSuperClass = s_pClasses[ uiParentCls ]; if( pSuperClass->fHasDestructor ) { PMETHOD pDestructor = hb_clsFindMsg( s_pClasses[ uiParentCls ], s___msgDestructor.pDynSym ); if( pDestructor && pDestructor->uiSprClass == uiParentCls ) { hb_vmPushSymbol( &s___msgDestructor ); hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiParentCls ); hb_vmSend( 0 ); if( hb_vmRequestQuery() != 0 ) break; } } } } #endif } /* Call object destructor */ void hb_objDestructorCall( PHB_ITEM pObject ) { if( HB_IS_OBJECT( pObject ) && pObject->item.asArray.value->uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ pObject->item.asArray.value->uiClass ]; if( pClass->fHasDestructor ) { if( hb_vmRequestReenter() ) { hb_vmPushSymbol( &s___msgDestructor ); hb_vmPush( pObject ); hb_vmSend( 0 ); if( hb_vmRequestQuery() == 0 ) hb_objSuperDestructorCall( pObject, pClass ); hb_vmRequestRestore(); } } } } /* Check if object has a given operator */ HB_BOOL hb_objHasOperator( PHB_ITEM pObject, HB_USHORT uiOperator ) { HB_USHORT uiClass; HB_TRACE( HB_TR_DEBUG, ( "hb_objHasOperator(%p,%hu)", ( void * ) pObject, uiOperator ) ); uiClass = hb_objGetClassH( pObject ); if( uiClass && uiClass <= s_uiClasses ) { return ( s_pClasses[ uiClass ]->nOpFlags & ( 1 << uiOperator ) ) != 0; } return HB_FALSE; } /* Call object operator. If pMsgArg is NULL then operator is unary. * Function return HB_TRUE when object class overloads given operator * and HB_FALSE otherwise. [druzus] */ HB_BOOL hb_objOperatorCall( HB_USHORT uiOperator, PHB_ITEM pResult, PHB_ITEM pObject, PHB_ITEM pMsgArg1, PHB_ITEM pMsgArg2 ) { HB_TRACE( HB_TR_DEBUG, ( "hb_objOperatorCall(%hu,%p,%p,%p,%p)", uiOperator, ( void * ) pResult, ( void * ) pObject, ( void * ) pMsgArg1, ( void * ) pMsgArg2 ) ); if( hb_objHasOperator( pObject, uiOperator ) ) { HB_STACK_TLS_PRELOAD hb_vmPushSymbol( s_opSymbols + uiOperator ); hb_vmPush( pObject ); hb_itemSetNil( hb_stackReturnItem() ); if( pMsgArg1 ) { hb_vmPush( pMsgArg1 ); if( pMsgArg2 ) { hb_vmPush( pMsgArg2 ); hb_vmSend( 2 ); } else hb_vmSend( 1 ); } else hb_vmSend( 0 ); /* store the return value */ hb_itemMove( pResult, hb_stackReturnItem() ); return HB_TRUE; } return HB_FALSE; } /* return HB_TRUE if object has a given message */ HB_BOOL hb_objHasMessage( PHB_ITEM pObject, PHB_DYNS pMessage ) { return hb_objGetMethod( pObject, pMessage->pSymbol, NULL ) != NULL; } /* = hb_objHasMsg( , ) * * Check whether is an existing message for object. * * should be read as a boolean */ HB_BOOL hb_objHasMsg( PHB_ITEM pObject, const char * szString ) { PHB_DYNS pDynSym; HB_TRACE( HB_TR_DEBUG, ( "hb_objHasMsg(%p, %s)", ( void * ) pObject, szString ) ); pDynSym = hb_dynsymFindName( szString ); if( pDynSym ) return hb_objGetMethod( pObject, pDynSym->pSymbol, NULL ) != NULL; else return HB_FALSE; } PHB_ITEM hb_objSendMessage( PHB_ITEM pObject, PHB_DYNS pMsgSym, HB_ULONG ulArg, ... ) { if( pObject && pMsgSym ) { hb_vmPushSymbol( pMsgSym->pSymbol ); hb_vmPush( pObject ); if( ulArg ) { HB_ULONG i; va_list ap; va_start( ap, ulArg ); for( i = 0; i < ulArg; i++ ) { hb_vmPush( va_arg( ap, PHB_ITEM ) ); } va_end( ap ); } hb_vmSend( ( HB_USHORT ) ulArg ); } else hb_errRT_BASE( EG_ARG, 3000, NULL, "__objSendMessage()", 0 ); { HB_STACK_TLS_PRELOAD return hb_stackReturnItem(); } } PHB_ITEM hb_objSendMsg( PHB_ITEM pObject, const char * szMsg, HB_ULONG ulArg, ... ) { hb_vmPushSymbol( hb_dynsymGet( szMsg )->pSymbol ); hb_vmPush( pObject ); if( ulArg ) { HB_ULONG i; va_list ap; va_start( ap, ulArg ); for( i = 0; i < ulArg; i++ ) { hb_vmPush( va_arg( ap, PHB_ITEM ) ); } va_end( ap ); } hb_vmSend( ( HB_USHORT ) ulArg ); { HB_STACK_TLS_PRELOAD return hb_stackReturnItem(); } } PHB_ITEM hb_objGetVarPtr( PHB_ITEM pObject, PHB_DYNS pVarMsg ) { if( pObject && HB_IS_OBJECT( pObject ) && pVarMsg ) { HB_USHORT uiClass = pObject->item.asArray.value->uiClass; PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = hb_clsFindMsg( pClass, pVarMsg ); if( pMethod ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { HB_SIZE nIndex = pMethod->uiData + pMethod->uiOffset; if( pObject->item.asArray.value->uiPrevCls ) { pObject = hb_arrayGetItemPtr( pObject, 1 ); if( ! pObject ) return NULL; if( uiClass != pObject->item.asArray.value->uiClass ) nIndex = pMethod->uiData + hb_clsParentInstanceOffset( s_pClasses[ pObject->item.asArray.value->uiClass ], pMethod->uiSprClass ); } return hb_arrayGetItemPtr( pObject, nIndex ); } } } return NULL; } static PHB_DYNS hb_objGetMsgSym( PHB_ITEM pMessage ) { PHB_DYNS pDynSym = NULL; if( pMessage ) { const char * szMsg = NULL; if( HB_IS_STRING( pMessage ) ) szMsg = pMessage->item.asString.value; else if( HB_IS_SYMBOL( pMessage ) ) { pDynSym = pMessage->item.asSymbol.value->pDynSym; if( ! pDynSym ) szMsg = pMessage->item.asSymbol.value->szName; } if( szMsg && *szMsg ) pDynSym = hb_dynsymGet( szMsg ); } return pDynSym; } static PHB_SYMB hb_objGetFuncSym( PHB_ITEM pItem ) { if( pItem ) { if( HB_IS_SYMBOL( pItem ) ) return pItem->item.asSymbol.value; else if( HB_IS_STRING( pItem ) ) { PHB_DYNS pDynSym = hb_dynsymFindName( hb_itemGetCPtr( pItem ) ); if( pDynSym && pDynSym->pSymbol->value.pFunPtr ) return pDynSym->pSymbol; } } return NULL; } /* clone object if user defined clone method or copy it */ void hb_objCloneBody( PHB_ITEM pDest, PHB_ITEM pObject, PHB_NESTED_CLONED pClonedList ) { HB_TRACE( HB_TR_DEBUG, ( "hb_objCloneBody(%p,%p,%p)", ( void * ) pDest, ( void * ) pObject, ( void * ) pClonedList ) ); HB_SYMBOL_UNUSED( pClonedList ); /* TODO: add support for user defined clone operation */ hb_itemCopy( pDest, pObject ); } /* clone object if user defined clone method or copy it */ PHB_ITEM hb_objCloneTo( PHB_ITEM pDest, PHB_ITEM pObject ) { HB_TRACE( HB_TR_DEBUG, ( "hb_objCloneTo(%p,%p)", ( void * ) pDest, ( void * ) pObject ) ); hb_objCloneBody( pDest, pObject, NULL ); return pDest; } /* send message which allows to set execution context for debugger */ void hb_dbg_objSendMessage( int iProcLevel, PHB_ITEM pObject, PHB_ITEM pMessage, int iParamOffset ) { HB_STACK_TLS_PRELOAD PHB_DYNS pMsgSym; pMsgSym = hb_objGetMsgSym( pMessage ); if( pObject && pMsgSym ) { HB_USHORT uiParams = 0; /* set requested sender class and method id for scope verification */ if( iProcLevel > 0 ) { int iLevel = hb_stackCallDepth(); if( iProcLevel < iLevel ) { HB_ISIZ nOffset = hb_stackBaseProcOffset( iLevel - iProcLevel ); if( nOffset > 0 ) { PHB_ITEM pItem = hb_stackItem( nOffset ); PHB_ITEM pBase = hb_stackBaseItem(); pBase->item.asSymbol.stackstate->uiClass = pItem->item.asSymbol.stackstate->uiClass; pBase->item.asSymbol.stackstate->uiMethod = pItem->item.asSymbol.stackstate->uiMethod; } } } else if( iProcLevel == 0 ) { /* set scope like for internal object messages to any visible method without respecting overloaded methods */ HB_USHORT uiClass = hb_objGetClassH( pObject ); if( uiClass && uiClass <= s_uiClasses ) { PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsgSym ); if( pMethod ) { PHB_ITEM pBase = hb_stackBaseItem(); pBase->item.asSymbol.stackstate->uiClass = uiClass; pBase->item.asSymbol.stackstate->uiMethod = ( HB_USHORT ) ( pMethod - s_pClasses[ uiClass ]->pMethods ); } } } hb_vmPushSymbol( pMsgSym->pSymbol ); hb_vmPush( pObject ); if( iParamOffset > 0 ) { int iPCount = hb_pcount(); while( iParamOffset <= iPCount ) { hb_vmPush( hb_stackItemFromBase( iParamOffset ) ); ++uiParams; ++iParamOffset; } } hb_vmSend( uiParams ); } else hb_errRT_BASE( EG_ARG, 3000, NULL, "hb_dbg_objSendMessage()", 2, pObject, pMsgSym ); } static HB_USHORT hb_clsUpdateScope( HB_USHORT uiScope, HB_BOOL fAssign ) { if( ! fAssign ) uiScope &= ~HB_OO_CLSTP_READONLY; else { uiScope &= ~HB_OO_CLSTP_PERSIST; if( ( uiScope & HB_OO_CLSTP_READONLY ) && !( uiScope & HB_OO_CLSTP_HIDDEN ) ) { /* Class(y) does not allow to write to HIDDEN+READONLY instance variables, [druzus] */ uiScope &= ~HB_OO_CLSTP_READONLY; uiScope |= ( uiScope & HB_OO_CLSTP_PROTECTED ) ? HB_OO_CLSTP_HIDDEN : HB_OO_CLSTP_PROTECTED; } } return uiScope; } static HB_TYPE hb_clsGetItemType( PHB_ITEM pItem, HB_TYPE nDefault ) { if( pItem ) { if( HB_IS_STRING( pItem ) ) { switch( hb_itemGetCPtr( pItem )[ 0 ] ) { case 'C': case 'c': if( hb_strnicmp( hb_itemGetCPtr( pItem ), "code", 4 ) == 0 ) return HB_IT_BLOCK; /* fallthrough */ case '\0': return HB_IT_STRING; case 'S': case 's': if( hb_strnicmp( hb_itemGetCPtr( pItem ), "str", 3 ) == 0 ) return HB_IT_STRING; else return HB_IT_SYMBOL; case 'B': case 'b': return HB_IT_BLOCK; case 'D': case 'd': if( hb_strnicmp( hb_itemGetCPtr( pItem ), "datet", 5 ) == 0 ) return HB_IT_TIMESTAMP; else return HB_IT_DATE; case 'T': case 't': return HB_IT_TIMESTAMP; case 'L': case 'l': return HB_IT_LOGICAL; case 'I': case 'i': return HB_IT_NUMINT; case 'N': case 'n': if( hb_stricmp( hb_itemGetCPtr( pItem ), "nil" ) == 0 ) return HB_IT_NIL; else return HB_IT_NUMERIC; case 'A': case 'a': return HB_IT_ARRAY; case 'P': case 'p': return HB_IT_POINTER; case 'H': case 'h': return HB_IT_HASH; } } else if( HB_IS_ARRAY( pItem ) ) { if( pItem->item.asArray.value->uiClass == 0 ) return HB_IT_ARRAY; } else if( HB_IS_NUMINT( pItem ) ) return HB_IT_NUMINT; else if( HB_IS_NUMERIC( pItem ) ) return HB_IT_NUMERIC; else if( HB_IS_DATE( pItem ) ) return HB_IT_DATE; else if( HB_IS_TIMESTAMP( pItem ) ) return HB_IT_TIMESTAMP; else if( HB_IS_LOGICAL( pItem ) ) return HB_IT_LOGICAL; else if( HB_IS_BLOCK( pItem ) ) return HB_IT_BLOCK; else if( HB_IS_POINTER( pItem ) ) return HB_IT_POINTER; else if( HB_IS_SYMBOL( pItem ) ) return HB_IT_SYMBOL; else if( HB_IS_NIL( pItem ) ) return HB_IT_NIL; } return nDefault; } /* --- */ /* * HB_OO_MSG_METHOD : standard method * HB_OO_MSG_ONERROR : error handler method * HB_OO_MSG_DESTRUCTOR : destructor method * HB_OO_MSG_INLINE : inline (codeblock) method * HB_OO_MSG_ASSIGN : assign instance data * HB_OO_MSG_ACCESS : access instance data * HB_OO_MSG_CLSASSIGN : assign class data * HB_OO_MSG_CLSACCESS : access class data * HB_OO_MSG_SUPER : supercasting * HB_OO_MSG_REALCLASS : caller method real class casting * HB_OO_MSG_PERFORM : perform method * HB_OO_MSG_VIRTUAL : virtual method * HB_OO_MSG_DELEGATE : delegate method * * HB_OO_CLSTP_EXPORTED 1 : default for data and method * HB_OO_CLSTP_PROTECTED 2 : method or data protected * HB_OO_CLSTP_HIDDEN 4 : method or data hidden * * HB_OO_CLSTP_CTOR 8 : method constructor * HB_OO_CLSTP_READONLY 16 : data read only * HB_OO_CLSTP_SHARED 32 : (method or) data shared * HB_OO_CLSTP_CLASS 64 : message is class message not object * * HB_OO_CLSTP_SUPER 128 : message is inherited * HB_OO_CLSTP_PERSIST 256 : message is persistent (PROPERTY) * HB_OO_CLSTP_NONVIRTUAL 512 : Non Virtual message - should not be covered by subclass(es) messages with the same name when executed from a given class message * HB_OO_CLSTP_OVERLOADED 1024 : message overload NONVIRTUAL one * HB_OO_CLSTP_SYNC 2048 : message synchronized by object or class mutex * * HB_OO_MSG_METHOD : \ * HB_OO_MSG_ONERROR : > Pointer to function * HB_OO_MSG_DESTRUCTOR : / * HB_OO_MSG_INLINE : Code block * HB_OO_MSG_ASSIGN : Index to instance area array 1 based (without offset) * HB_OO_MSG_ACCESS : / * HB_OO_MSG_CLSASSIGN : Index class data array * HB_OO_MSG_CLSACCESS : / * HB_OO_MSG_SUPER : Instance area offset for class casting * HB_OO_MSG_DELEGATE : Delegated message symbol * * HB_OO_MSG_ACCESS : Optional initializer for (Class)DATA * HB_OO_MSG_CLSACCESS : / * HB_OO_MSG_ASSIGN : Item type restriction in assignment * HB_OO_MSG_CLSASSIGN : / * HB_OO_MSG_SUPER : Superclass handle * HB_OO_MSG_DELEGATE : Object symbol for delegated message */ static HB_BOOL hb_clsAddMsg( HB_USHORT uiClass, const char * szMessage, HB_USHORT uiType, HB_USHORT uiScope, PHB_ITEM pFunction, PHB_ITEM pInit ) { if( szMessage && uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; PHB_DYNS pMessage; PMETHOD pNewMeth; HB_USHORT uiOperator, uiSprClass = 0, uiIndex = 0, uiPrevCls, uiPrevMth; PHB_SYMB pOpSym, pFuncSym = NULL; HB_BOOL fOK; HB_U32 nOpFlags = 0; if( pClass->fLocked ) return HB_FALSE; if( ! ( uiScope & ( HB_OO_CLSTP_EXPORTED | HB_OO_CLSTP_PROTECTED | HB_OO_CLSTP_HIDDEN ) ) ) uiScope |= HB_OO_CLSTP_EXPORTED; /* translate names of operator overloading messages */ if( uiType == HB_OO_MSG_DESTRUCTOR ) pMessage = s___msgDestructor.pDynSym; else if( uiType == HB_OO_MSG_ONERROR ) pMessage = s___msgOnError.pDynSym; else if( strcmp( "+", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_PLUS )->pDynSym; else if( strcmp( "-", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_MINUS )->pDynSym; else if( strcmp( "*", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_MULT )->pDynSym; else if( strcmp( "/", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_DIVIDE )->pDynSym; else if( strcmp( "%", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_MOD )->pDynSym; else if( strcmp( "^", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_POWER )->pDynSym; else if( strcmp( "**", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_POWER )->pDynSym; else if( strcmp( "++", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_INC )->pDynSym; else if( strcmp( "--", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_DEC )->pDynSym; else if( strcmp( "==", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_EXACTEQUAL )->pDynSym; else if( strcmp( "=", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_EQUAL )->pDynSym; else if( strcmp( "!=", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym; else if( strcmp( "<>", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym; else if( strcmp( "#", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym; else if( strcmp( "<", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_LESS )->pDynSym; else if( strcmp( "<=", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_LESSEQUAL )->pDynSym; else if( strcmp( ">", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_GREATER )->pDynSym; else if( strcmp( ">=", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_GREATEREQUAL )->pDynSym; else if( strcmp( ":=", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_ASSIGN )->pDynSym; else if( strcmp( "$", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_INSTRING )->pDynSym; else if( strcmp( "$$", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_INCLUDE )->pDynSym; else if( strcmp( "!", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_NOT )->pDynSym; else if( hb_stricmp( ".NOT.", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_NOT )->pDynSym; else if( hb_stricmp( ".AND.", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_AND )->pDynSym; else if( hb_stricmp( ".OR.", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_OR )->pDynSym; else if( strcmp( "[]", szMessage ) == 0 ) pMessage = ( s_opSymbols + HB_OO_OP_ARRAYINDEX )->pDynSym; else pMessage = hb_dynsymGet( szMessage ); for( uiOperator = 0, pOpSym = s_opSymbols; uiOperator <= HB_OO_MAX_OPERATOR; ++uiOperator, ++pOpSym ) { if( pOpSym->pDynSym == pMessage ) { nOpFlags |= 1 << uiOperator; break; } } /* basic parameter validation */ switch( uiType ) { case HB_OO_MSG_METHOD: case HB_OO_MSG_ONERROR: case HB_OO_MSG_DESTRUCTOR: pFuncSym = hb_objGetFuncSym( pFunction ); fOK = pFuncSym != NULL; break; case HB_OO_MSG_INLINE: fOK = pFunction && HB_IS_BLOCK( pFunction ); break; case HB_OO_MSG_SUPER: uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction ); uiSprClass = ( HB_USHORT ) hb_itemGetNI( pInit ); fOK = uiSprClass && uiSprClass <= s_uiClasses && uiIndex <= pClass->uiDatas; break; case HB_OO_MSG_ASSIGN: case HB_OO_MSG_ACCESS: uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction ); /* This validation can break buggy .prg code which wrongly * sets data offsets but IMHO it will help to clean the code. * [druzus] */ fOK = uiIndex && uiIndex <= pClass->uiDatas - pClass->uiDataFirst; break; case HB_OO_MSG_CLSASSIGN: case HB_OO_MSG_CLSACCESS: uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction ); fOK = uiIndex != 0; break; case HB_OO_MSG_DELEGATE: { PHB_DYNS pDelegMsg = hb_objGetMsgSym( pFunction ); if( pDelegMsg ) { pNewMeth = hb_clsFindMsg( pClass, pDelegMsg ); if( pNewMeth ) uiIndex = ( HB_USHORT ) ( pNewMeth - pClass->pMethods ); } fOK = pFunction == NULL || HB_IS_NIL( pFunction ) || uiIndex != 0; if( fOK ) { pDelegMsg = hb_objGetMsgSym( pInit ); if( pDelegMsg ) { pNewMeth = hb_clsFindMsg( pClass, pDelegMsg ); if( pNewMeth ) uiSprClass = ( HB_USHORT ) ( pNewMeth - pClass->pMethods ); } fOK = ( pInit == NULL || HB_IS_NIL( pInit ) || uiSprClass != 0 ) && ( uiIndex != 0 || uiSprClass != 0 ); } break; } case HB_OO_MSG_REALCLASS: case HB_OO_MSG_VIRTUAL: case HB_OO_MSG_PERFORM: fOK = HB_TRUE; break; default: fOK = HB_FALSE; } if( ! fOK ) { hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); return HB_FALSE; } pNewMeth = hb_clsAllocMsg( pClass, pMessage ); uiPrevCls = uiClass; uiPrevMth = ( HB_USHORT ) ( pClass->pMethods - pNewMeth ); #ifndef HB_VIRTUAL_HIDDEN if( uiScope & HB_OO_CLSTP_HIDDEN ) uiScope |= HB_OO_CLSTP_NONVIRTUAL; #endif if( ! pNewMeth->pMessage ) pClass->uiMethods++; /* One more message */ else { HB_BOOL fOverLoad = ( pNewMeth->uiScope & HB_OO_CLSTP_OVERLOADED ) || ( ( pNewMeth->uiScope & HB_OO_CLSTP_NONVIRTUAL ) && pNewMeth->uiSprClass != uiClass ); uiPrevCls = pNewMeth->uiPrevCls; uiPrevMth = pNewMeth->uiPrevMth; if( ! hb_clsCanClearMethod( pNewMeth, HB_TRUE ) ) return HB_FALSE; memset( pNewMeth, 0, sizeof( METHOD ) ); if( fOverLoad ) uiScope |= HB_OO_CLSTP_OVERLOADED; } pNewMeth->pMessage = pMessage; pNewMeth->uiSprClass = uiClass; pNewMeth->uiPrevCls = uiPrevCls; pNewMeth->uiPrevMth = uiPrevMth; switch( uiType ) { case HB_OO_MSG_METHOD: pNewMeth->pFuncSym = pFuncSym; pNewMeth->uiScope = uiScope; break; case HB_OO_MSG_ASSIGN: pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_TRUE ); /* Class(y) does not allow to write to HIDDEN+READONLY instance variables, [druzus] */ if( pNewMeth->uiScope & HB_OO_CLSTP_READONLY && pNewMeth->uiScope & HB_OO_CLSTP_HIDDEN ) pNewMeth->pFuncSym = &s___msgScopeErr; else { pNewMeth->pFuncSym = &s___msgSetData; pNewMeth->uiData = uiIndex; pNewMeth->uiOffset = pClass->uiDataFirst; pNewMeth->itemType = hb_clsGetItemType( pInit, 0 ); } break; case HB_OO_MSG_ACCESS: pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_FALSE ); pNewMeth->uiData = uiIndex; pNewMeth->uiOffset = pClass->uiDataFirst; hb_clsAddInitValue( pClass, pInit, HB_OO_MSG_DATA, pNewMeth->uiData, pNewMeth->uiOffset, uiClass ); pNewMeth->pFuncSym = &s___msgGetData; break; case HB_OO_MSG_CLSASSIGN: pNewMeth->uiData = uiIndex; pNewMeth->itemType = hb_clsGetItemType( pInit, 0 ); pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_TRUE ); /* Class(y) does not allow to write to HIDDEN+READONLY instance variables, [druzus] */ if( pNewMeth->uiScope & HB_OO_CLSTP_READONLY && pNewMeth->uiScope & HB_OO_CLSTP_HIDDEN ) pNewMeth->pFuncSym = &s___msgScopeErr; else if( pNewMeth->uiScope & HB_OO_CLSTP_SHARED ) { if( hb_arrayLen( pClass->pSharedDatas ) < ( HB_SIZE ) pNewMeth->uiData ) hb_arraySize( pClass->pSharedDatas, pNewMeth->uiData ); pNewMeth->pFuncSym = &s___msgSetShrData; } else { if( hb_arrayLen( pClass->pClassDatas ) < ( HB_SIZE ) pNewMeth->uiData ) hb_arraySize( pClass->pClassDatas, pNewMeth->uiData ); pNewMeth->pFuncSym = &s___msgSetClsData; } break; case HB_OO_MSG_CLSACCESS: pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_FALSE ); pNewMeth->uiData = uiIndex; if( pNewMeth->uiScope & HB_OO_CLSTP_SHARED ) { if( hb_arrayLen( pClass->pSharedDatas ) < ( HB_SIZE ) pNewMeth->uiData ) hb_arraySize( pClass->pSharedDatas, pNewMeth->uiData ); if( pInit && ! HB_IS_NIL( pInit ) ) /* Initializer found */ { /* Shared Classdata need to be initialized only once * ACCESS/ASSIGN methods will be inherited by subclasses * and will operate on this value so it's not necessary * to keep the init value. [druzus] */ hb_itemCloneTo( hb_arrayGetItemPtr( pClass->pSharedDatas, pNewMeth->uiData ), pInit ); } pNewMeth->pFuncSym = &s___msgGetShrData; } else { if( hb_arrayLen( pClass->pClassDatas ) < ( HB_SIZE ) pNewMeth->uiData ) hb_arraySize( pClass->pClassDatas, pNewMeth->uiData ); /* uiOffset is used to copy ancestor class data initializers when * new class is created */ pNewMeth->uiOffset = hb_clsAddInitValue( pClass, pInit, HB_OO_MSG_CLASSDATA, pNewMeth->uiData, 0, uiClass ); pNewMeth->pFuncSym = &s___msgGetClsData; } break; case HB_OO_MSG_INLINE: pNewMeth->pFuncSym = &s___msgEvalInline; pNewMeth->uiScope = uiScope; hb_arrayAdd( pClass->pInlines, pFunction ); pNewMeth->uiData = ( HB_USHORT ) hb_arrayLen( pClass->pInlines ); break; case HB_OO_MSG_VIRTUAL: pNewMeth->pFuncSym = &s___msgVirtual; pNewMeth->uiScope = uiScope; break; case HB_OO_MSG_SUPER: pNewMeth->uiData = uiSprClass; /* store the super handle */ pNewMeth->uiOffset = uiIndex; /* offset to instance area */ pNewMeth->uiScope = uiScope; pNewMeth->pFuncSym = &s___msgSuper; break; case HB_OO_MSG_REALCLASS: pNewMeth->pFuncSym = &s___msgRealClass; pNewMeth->uiScope = uiScope; break; case HB_OO_MSG_PERFORM: pNewMeth->pFuncSym = &s___msgPerform; pNewMeth->uiScope = uiScope; break; case HB_OO_MSG_DELEGATE: pNewMeth->pFuncSym = &s___msgDelegate; pNewMeth->uiScope = uiScope; pNewMeth->uiData = uiIndex; break; case HB_OO_MSG_ONERROR: pNewMeth->pFuncSym = pFuncSym; pClass->fHasOnError = HB_TRUE; break; case HB_OO_MSG_DESTRUCTOR: pNewMeth->pFuncSym = pFuncSym; pClass->fHasDestructor = HB_TRUE; break; default: hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__clsAddMsg()", NULL ); } pClass->nOpFlags |= nOpFlags; if( uiScope & HB_OO_CLSTP_SYNC ) { pNewMeth->pRealSym = pNewMeth->pFuncSym; if( uiScope & HB_OO_CLSTP_CLASS ) { if( ! pClass->pMutex ) pClass->pMutex = hb_threadMutexCreate(); pNewMeth->pFuncSym = &s___msgSyncClass; } else { if( ! pClass->uiMutexOffset ) pClass->uiMutexOffset = pClass->uiDatas + 1; pNewMeth->pFuncSym = &s___msgSync; } } } return HB_TRUE; } /* __clsAddMsg( , , , , [xInit], , [xType] ) * * Add a message to the class. * * Class handle * Message * HB_OO_MSG_METHOD : \ * HB_OO_MSG_ONERROR : > Pointer to function * HB_OO_MSG_DESTRUCTOR : / * HB_OO_MSG_INLINE : Code block * HB_OO_MSG_DATA : \ * HB_OO_MSG_ASSIGN : > Index to instance area array * HB_OO_MSG_ACCESS : / * HB_OO_MSG_CLASSDATA : \ * HB_OO_MSG_CLSASSIGN : > Index class data array * HB_OO_MSG_CLSACCESS : / * HB_OO_MSG_SUPER : Handle of super class * HB_OO_MSG_DELEGATE : delegated message symbol * * see HB_OO_MSG_* above and: * HB_OO_MSG_REALCLASS : caller method real class casting * HB_OO_MSG_PERFORM : perform message * HB_OO_MSG_VIRTUAL : virtual message * HB_OO_MSG_DELEGATE : delegate method * * HB_OO_MSG_ACCESS : \ * HB_OO_MSG_CLSACCESS : > Optional initializer for DATA * HB_OO_MSG_DATA : / * HB_OO_MSG_CLASSDATA : / * HB_OO_MSG_SUPER : Superclass handle * HB_OO_MSG_ASSIGN : \ item type restriction in assignment not * HB_OO_MSG_CLSASSIGN: : empty character value where first letter * is item type or item of a given value * * HB_OO_CLSTP_EXPORTED 1 : default for data and method * HB_OO_CLSTP_PROTECTED 2 : method or data protected * HB_OO_CLSTP_HIDDEN 4 : method or data hidden * * HB_OO_CLSTP_CTOR 8 : method constructor * HB_OO_CLSTP_READONLY 16 : data read only * HB_OO_CLSTP_SHARED 32 : (method or) data shared * * HB_OO_CLSTP_CLASS 64 : message is class message not object * * HB_OO_CLSTP_SUPER 128 : message is inherited * HB_OO_CLSTP_PERSIST 256 : message is persistent (PROPERTY) * HB_OO_CLSTP_NONVIRTUAL 512 : Class method constructor * HB_OO_CLSTP_OVERLOADED 1024 : Class method constructor * HB_OO_CLSTP_SYNC 2048 : message synchronized by object or class mutex * * HB_OO_MSG_PROPERTY : > optional item type restriction in assignment * HB_OO_MSG_CLASSPROPERTY : / */ HB_FUNC( __CLSADDMSG ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); const char * szMessage = hb_parc( 2 ); if( szMessage && uiClass && uiClass <= s_uiClasses ) { HB_USHORT nType = ( HB_USHORT ) hb_parni( 4 ); HB_USHORT uiScope = ( HB_USHORT ) hb_parni( 6 ); PHB_ITEM pFunction = hb_param( 3, HB_IT_ANY ); PHB_ITEM pInit = hb_param( 5, HB_IT_ANY ); if( nType == HB_OO_MSG_DATA ) { nType = szMessage[ 0 ] == '_' ? HB_OO_MSG_ASSIGN : HB_OO_MSG_ACCESS; } else if( nType == HB_OO_MSG_CLASSDATA ) { nType = szMessage[ 0 ] == '_' ? HB_OO_MSG_CLSASSIGN : HB_OO_MSG_CLSACCESS; } /* to make xHarbour users happy ;-) */ else if( nType == HB_OO_MSG_PROPERTY || nType == HB_OO_MSG_CLASSPROPERTY ) { PHB_ITEM pType = hb_param( 7, HB_IT_ANY ); char szAssign[ HB_SYMBOL_NAME_LEN + 1 ]; int iLen = ( int ) hb_parclen( 2 ); if( iLen >= HB_SYMBOL_NAME_LEN ) iLen = HB_SYMBOL_NAME_LEN - 1; szAssign[ 0 ] = '_'; memcpy( szAssign + 1, szMessage, iLen ); szAssign[ iLen + 1 ] = '\0'; uiScope = ( uiScope | HB_OO_CLSTP_EXPORTED ) & ~( HB_OO_CLSTP_PROTECTED | HB_OO_CLSTP_HIDDEN ); if( nType == HB_OO_MSG_PROPERTY ) { hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_ASSIGN, ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ), pFunction, pType ); nType = HB_OO_MSG_ACCESS; } else { hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_CLSASSIGN, ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ), pFunction, pType ); nType = HB_OO_MSG_CLSACCESS; } } hb_clsAddMsg( uiClass, szMessage, nType, uiScope, pFunction, pInit ); } } /* __clsNew( , , * [], [], * [] ) --> * * Create a new class * * Name of the class * Number of DATAs in the class * Optional array with handle(s) of superclass(es) * Class function symbol, when NULL public function * with the same name as szClassName is used * when true all functions and classes from the same * module as pClassFunc are defined as friends */ static HB_USHORT hb_clsNew( const char * szClassName, HB_USHORT uiDatas, PHB_ITEM pSuperArray, PHB_SYMB pClassFunc, HB_BOOL fModuleFriendly ) { PCLASS pNewCls; PMETHOD pMethod; HB_USHORT ui, uiSuper, uiSuperCls; HB_USHORT * puiClassData = NULL, uiClassDataSize = 0; HB_BOOL fClsMutex = HB_FALSE; uiSuper = ( HB_USHORT ) ( pSuperArray ? hb_arrayLen( pSuperArray ) : 0 ); pClassFunc = hb_vmGetRealFuncSym( pClassFunc ); pNewCls = ( PCLASS ) hb_xgrabz( sizeof( CLASS ) ); HB_CLASS_LOCK(); if( s_uiClasses == s_uiClsSize ) { s_uiClsSize += HB_CLASS_POOL_RESIZE; s_pClasses = ( PCLASS * ) hb_xrealloc( s_pClasses, sizeof( PCLASS ) * ( ( HB_SIZE ) s_uiClsSize + 1 ) ); } pNewCls->uiClass = s_uiClasses + 1; s_pClasses[ pNewCls->uiClass ] = pNewCls; ++s_uiClasses; HB_CLASS_UNLOCK(); pNewCls->szName = hb_strdup( szClassName ); pNewCls->pClassSym = hb_dynsymGet( pNewCls->szName ); if( ! pClassFunc ) pClassFunc = hb_vmGetRealFuncSym( pNewCls->pClassSym->pSymbol ); pNewCls->pClassFuncSym = pClassFunc; if( fModuleFriendly ) hb_vmFindModuleSymbols( pClassFunc, &pNewCls->pFriendModule, &pNewCls->uiFriendModule ); for( ui = 1; ui <= uiSuper; ++ui ) { uiSuperCls = ( HB_USHORT ) hb_arrayGetNI( pSuperArray, ui ); if( uiSuperCls && uiSuperCls < pNewCls->uiClass ) { PCLASS pSprCls; pSprCls = s_pClasses[ uiSuperCls ]; if( ! hb_clsInited( pNewCls ) ) /* This is the first superclass */ { hb_clsCopyClass( pNewCls, pSprCls ); } else if( ! hb_clsHasParentClass( pNewCls, uiSuperCls ) ) { HB_SIZE n, nLimit; HB_USHORT nLenClsDatas; HB_USHORT uiCount; /* create class data translation tables */ nLenClsDatas = ( HB_USHORT ) hb_itemSize( pSprCls->pClassDatas ); if( nLenClsDatas ) { if( nLenClsDatas > uiClassDataSize ) { puiClassData = ( HB_USHORT * ) hb_xrealloc( puiClassData, sizeof( HB_USHORT ) * nLenClsDatas ); uiClassDataSize = nLenClsDatas; } memset( puiClassData, 0, sizeof( HB_USHORT ) * nLenClsDatas ); } /* Copy super class handles */ for( uiCount = 0; uiCount < pSprCls->uiSuperClasses; ++uiCount ) hb_clsDefineSuperClass( pNewCls, pSprCls->pSuperClasses[ uiCount ].uiClass, HB_TRUE ); hb_clsDefineSuperClass( pNewCls, uiSuperCls, HB_TRUE ); /* Copy instance area init data */ if( pSprCls->uiInitDatas ) { HB_USHORT u; for( u = 0; u < pSprCls->uiInitDatas; ++u ) { if( pSprCls->pInitData[ u ].uiType == HB_OO_MSG_DATA ) { HB_USHORT uiCls = pSprCls->pInitData[ u ].uiSprClass; hb_clsAddInitValue( pNewCls, pSprCls->pInitData[ u ].pInitValue, HB_OO_MSG_DATA, pSprCls->pInitData[ u ].uiData, hb_clsParentInstanceOffset( pNewCls, uiCls ), uiCls ); } } } /* Now working on other methods */ nLimit = hb_clsMthNum( pSprCls ); for( n = 0; n < nLimit; ++n ) { if( pSprCls->pMethods[ n ].pMessage ) { pMethod = hb_clsAllocMsg( pNewCls, pSprCls->pMethods[ n ].pMessage ); /* update instance area offset */ if( pMethod->pMessage && pMethod->pFuncSym == &s___msgSuper ) pMethod->uiOffset = hb_clsParentInstanceOffset( pNewCls, pMethod->uiData ); /* Ok, this bucket is empty */ if( pMethod->pMessage == NULL || ( hb_clsCanClearMethod( pMethod, HB_FALSE ) && ( pMethod->pFuncSym == &s___msgVirtual || ( s_uiObjectClass != 0 && pMethod->uiSprClass == s_uiObjectClass ) ) ) ) { if( pMethod->pMessage == NULL ) /* Now, we can increment the msg count */ pNewCls->uiMethods++; memcpy( pMethod, pSprCls->pMethods + n, sizeof( METHOD ) ); if( ! hb_clsUpdateHiddenMessages( pMethod, pMethod, pNewCls ) ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgSetClsData || pFuncSym == &s___msgGetClsData ) { if( pMethod->uiData > nLenClsDatas ) hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__clsNew()", NULL ); if( puiClassData[ pMethod->uiData - 1 ] == 0 ) { puiClassData[ pMethod->uiData - 1 ] = ( HB_USHORT ) hb_arrayLen( pNewCls->pClassDatas ) + 1; hb_arraySize( pNewCls->pClassDatas, puiClassData[ pMethod->uiData - 1 ] ); } if( pMethod->uiOffset ) { pMethod->uiOffset = hb_clsAddInitValue( pNewCls, pSprCls->pInitData[ pMethod->uiOffset - 1 ].pInitValue, HB_OO_MSG_CLASSDATA, puiClassData[ pMethod->uiData - 1 ], 0, uiSuperCls ); } pMethod->uiData = puiClassData[ pMethod->uiData - 1 ]; } else if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { pMethod->uiOffset = hb_clsParentInstanceOffset( pNewCls, pMethod->uiSprClass ); } pMethod->uiScope |= HB_OO_CLSTP_SUPER; } } else { if( pSprCls->pMethods[ n ].uiScope & ( HB_OO_CLSTP_OVERLOADED | HB_OO_CLSTP_NONVIRTUAL ) ) pMethod->uiScope |= HB_OO_CLSTP_OVERLOADED; hb_clsUpdateHiddenMessages( pSprCls->pMethods + n, pMethod, pNewCls ); } } } if( pSprCls->fHasOnError ) pNewCls->fHasOnError = HB_TRUE; if( pSprCls->fHasDestructor ) pNewCls->fHasDestructor = HB_TRUE; pNewCls->nOpFlags |= pSprCls->nOpFlags; if( pSprCls->uiMutexOffset ) pNewCls->uiMutexOffset = 1; if( pSprCls->pMutex ) fClsMutex = HB_TRUE; } } } if( puiClassData ) hb_xfree( puiClassData ); if( ! hb_clsInited( pNewCls ) ) { hb_clsDictInit( pNewCls, HASH_KEY ); pNewCls->pClassDatas = hb_itemArrayNew( 0 ); pNewCls->pSharedDatas = hb_itemArrayNew( 0 ); pNewCls->pInlines = hb_itemArrayNew( 0 ); } /* add self class casting */ pNewCls->uiDataFirst = pNewCls->uiDatas; hb_clsDefineSuperClass( pNewCls, pNewCls->uiClass, HB_FALSE ); pNewCls->uiDatas += uiDatas; if( pNewCls->uiMutexOffset ) pNewCls->uiMutexOffset = pNewCls->uiDatas + 1; if( fClsMutex && ! pNewCls->pMutex ) pNewCls->pMutex = hb_threadMutexCreate(); return pNewCls->uiClass; } /* __clsNew( , , [], [], [] ) --> * * Create a new class * * Name of the class * Number of DATAs in the class * Optional array with handle(s) of superclass(es) * Class function symbol * when true all functions and classes from the same * module as pClassFunc are defined as friends */ HB_FUNC( __CLSNEW ) { const char * szClassName; PHB_ITEM pDatas, pSuperArray, pClassFunc, pModFriend; szClassName = hb_parc( 1 ); pDatas = hb_param( 2, HB_IT_ANY ); pSuperArray = hb_param( 3, HB_IT_ANY ); if( pSuperArray && HB_IS_NIL( pSuperArray ) ) pSuperArray = NULL; pClassFunc = hb_param( 4, HB_IT_ANY ); if( pClassFunc && HB_IS_NIL( pClassFunc ) ) pClassFunc = NULL; pModFriend = hb_param( 5, HB_IT_ANY ); if( pModFriend && HB_IS_NIL( pModFriend ) ) pModFriend = NULL; if( szClassName && ( ! pDatas || HB_IS_NUMERIC( pDatas ) ) && ( ! pSuperArray || HB_IS_ARRAY( pSuperArray ) ) && ( ! pClassFunc || HB_IS_SYMBOL( pClassFunc ) ) && ( ! pModFriend || HB_IS_LOGICAL( pModFriend ) ) ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass; uiClass = hb_clsNew( szClassName, ( HB_USHORT ) hb_itemGetNI( pDatas ), pSuperArray, hb_itemGetSymbol( pClassFunc ), hb_itemGetL( pModFriend ) ); hb_retni( uiClass ); } else hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } /* __clsAddFriend( , ) * * Add friend function */ HB_FUNC( __CLSADDFRIEND ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; if( ! pClass->fLocked ) { PHB_SYMB pSym = hb_vmGetRealFuncSym( hb_itemGetSymbol( hb_param( 2, HB_IT_SYMBOL ) ) ); if( pSym ) hb_clsAddFriendSymbol( pClass, pSym ); } } } /* __clsDelMsg( , ) * * Delete message (only for INLINE and METHOD) * * class handle * message */ HB_FUNC( __CLSDELMSG ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pString = hb_param( 2, HB_IT_STRING ); if( uiClass && uiClass <= s_uiClasses && pString && ! s_pClasses[ uiClass ]->fLocked ) { PHB_DYNS pMsg = hb_dynsymFindName( pString->item.asString.value ); if( pMsg ) hb_clsFreeMsg( s_pClasses[ uiClass ], pMsg ); } } /* hb_clsInst( ) --> * * Create a new object from class definition */ static PHB_ITEM hb_clsInst( HB_USHORT uiClass ) { PHB_ITEM pSelf = NULL; if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; HB_USHORT uiDatas = pClass->uiDatas; if( pClass->uiMutexOffset ) ++uiDatas; pSelf = hb_itemNew( NULL ); hb_arrayNew( pSelf, uiDatas ); pSelf->item.asArray.value->uiClass = uiClass; if( pClass->uiMutexOffset ) { PHB_ITEM pMutex = hb_threadMutexCreate(); hb_arraySet( pSelf, pClass->uiMutexOffset, pMutex ); hb_itemRelease( pMutex ); } /* Initialise value if initialisation was requested */ if( pClass->uiInitDatas ) { PINITDATA pInitData = pClass->pInitData; HB_USHORT ui = pClass->uiInitDatas; PHB_ITEM pDestItm; do { if( pInitData->uiType == HB_OO_MSG_DATA ) pDestItm = hb_arrayGetItemPtr( pSelf, pInitData->uiData + pInitData->uiOffset ); else if( pInitData->uiType == HB_OO_MSG_CLASSDATA ) { pDestItm = hb_arrayGetItemPtr( pClass->pClassDatas, pInitData->uiData ); /* do not initialize it again */ pInitData->uiType = HB_OO_MSG_INITIALIZED; } else pDestItm = NULL; if( pDestItm ) hb_itemCloneTo( pDestItm, pInitData->pInitValue ); ++pInitData; } while( --ui ); } } return pSelf; } /* __clsInst( ) --> * * Create a new object from class definition */ HB_FUNC( __CLSINST ) { PHB_ITEM pSelf = hb_clsInst( ( HB_USHORT ) hb_parni( 1 ) ); if( pSelf ) hb_itemReturnRelease( pSelf ); } /* __clsLock( ) * * Block farther class modifications */ HB_FUNC( __CLSLOCK ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); if( uiClass && uiClass <= s_uiClasses ) s_pClasses[ uiClass ]->fLocked = HB_TRUE; } /* __clsModMsg( , , ) * * Modify message (only for INLINE and METHOD) */ HB_FUNC( __CLSMODMSG ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pString = hb_param( 2, HB_IT_STRING ); if( uiClass && uiClass <= s_uiClasses && pString && ! s_pClasses[ uiClass ]->fLocked ) { PHB_DYNS pMsg = hb_dynsymFindName( pString->item.asString.value ); if( pMsg ) { PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg ); if( pMethod ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DATA item", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgSetClsData || pFuncSym == &s___msgGetClsData ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a CLASSDATA item", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgSetShrData || pFuncSym == &s___msgGetShrData ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SHARED DATA item", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgSuper || pFuncSym == &s___msgRealClass ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SUPER class casting", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgDestructor ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DESTRUCTOR method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgOnError ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a ONERROR method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgScopeErr ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SCOPE ERROR method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgPerform ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a PERFORM method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgDelegate ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DELEGATE method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgSync ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SYNC method", HB_ERR_FUNCNAME, 0 ); } else if( pFuncSym == &s___msgSyncClass ) { hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a CLASS SYNC method", HB_ERR_FUNCNAME, 0 ); } else { PHB_ITEM pBlock = hb_param( 3, HB_IT_BLOCK ); if( pBlock ) { if( pFuncSym == &s___msgEvalInline && pMethod->uiSprClass == uiClass ) { hb_arraySet( s_pClasses[ pMethod->uiSprClass ]->pInlines, pMethod->uiData, pBlock ); } else { hb_arrayAdd( pClass->pInlines, pBlock ); pMethod->uiData = ( HB_USHORT ) hb_arrayLen( pClass->pInlines ); } } else { pFuncSym = hb_objGetFuncSym( hb_param( 3, HB_IT_ANY ) ); if( pFuncSym ) { pMethod->pFuncSym = pFuncSym; pMethod->uiData = 0; } else hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, 0 ); } } } } } } /* __objGetClsName( | ) --> * * Returns class name of or */ HB_FUNC( __OBJGETCLSNAME ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); HB_USHORT uiClass; if( pObject ) uiClass = pObject->item.asArray.value->uiClass; else uiClass = ( HB_USHORT ) hb_parni( 1 ); hb_retc( hb_clsName( uiClass ) ); } /* __objHasMsg( , | ) --> * * Is a valid message for the */ HB_FUNC( __OBJHASMSG ) { PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) ); if( pMessage ) { HB_STACK_TLS_PRELOAD hb_retl( hb_objHasMessage( hb_param( 1, HB_IT_ANY ), pMessage ) ); } else hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } /* __objHasMsgAssigned( , | ) --> * * checks if function exists and is not virtual */ HB_FUNC( __OBJHASMSGASSIGNED ) { PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) ); if( pMessage ) { HB_STACK_TLS_PRELOAD PHB_SYMB pExecSym = hb_objGetMethod( hb_param( 1, HB_IT_ANY ), pMessage->pSymbol, NULL ); hb_retl( pExecSym && pExecSym != &s___msgVirtual ); } else hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } /* __objSendMsg( , | , ) --> * * Send a message to an object */ HB_FUNC( __OBJSENDMSG ) { PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) ); if( pMessage ) { HB_STACK_TLS_PRELOAD HB_USHORT uiPCount = hb_pcount(); HB_USHORT uiParam; hb_vmPushSymbol( pMessage->pSymbol ); /* Push message symbol */ hb_vmPush( hb_param( 1, HB_IT_ANY ) ); /* Push object */ for( uiParam = 3; uiParam <= uiPCount; ++uiParam ) /* Push arguments on stack */ hb_vmPush( hb_stackItemFromBase( uiParam ) ); hb_vmSend( ( HB_USHORT ) ( uiPCount - 2 ) ); /* Execute message */ } else hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } /* __objClone( ) --> * * Clone an object. Note the similarity with aClone ;-) */ HB_FUNC( __OBJCLONE ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); if( pObject ) hb_arrayCloneTo( hb_stackReturnItem(), pObject ); else hb_errRT_BASE( EG_ARG, 3001, NULL, HB_ERR_FUNCNAME, 0 ); } /* __clsInstSuper( | ) --> * * Instance super class and return class handle */ HB_FUNC( __CLSINSTSUPER ) { HB_STACK_TLS_PRELOAD PHB_ITEM pItem = hb_param( 1, HB_IT_STRING | HB_IT_SYMBOL ); HB_USHORT uiClassH = 0, uiClass; PHB_SYMB pClassFuncSym = NULL; char szDesc[ 128 ]; if( pItem ) { if( HB_IS_SYMBOL( pItem ) ) pClassFuncSym = hb_itemGetSymbol( pItem ); else if( HB_IS_STRING( pItem ) ) { PHB_DYNS pDynSym = hb_dynsymFindName( hb_itemGetCPtr( pItem ) ); if( pDynSym ) pClassFuncSym = pDynSym->pSymbol; } pClassFuncSym = hb_vmGetRealFuncSym( pClassFuncSym ); } if( pClassFuncSym ) { uiClassH = hb_clsFindClassByFunc( pClassFuncSym ); if( uiClassH == 0 ) { hb_vmPushSymbol( pClassFuncSym ); hb_vmPushNil(); hb_vmProc( 0 ); /* Execute super class */ if( hb_vmRequestQuery() == 0 ) { PHB_ITEM pObject = hb_stackReturnItem(); if( HB_IS_OBJECT( pObject ) ) { uiClass = pObject->item.asArray.value->uiClass; if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym ) uiClassH = uiClass; else { uiClassH = hb_clsFindClassByFunc( pClassFuncSym ); /* still not found, try to send NEW() message */ if( uiClassH == 0 ) { hb_vmPushSymbol( &s___msgNew ); hb_vmPush( pObject ); hb_vmSend( 0 ); pObject = hb_stackReturnItem(); if( HB_IS_OBJECT( pObject ) ) { uiClass = pObject->item.asArray.value->uiClass; if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym ) uiClassH = uiClass; } } } } /* This disables destructor execution for this object */ if( uiClassH && HB_IS_OBJECT( pObject ) ) pObject->item.asArray.value->uiClass = 0; else if( hb_vmRequestQuery() == 0 ) { hb_snprintf( szDesc, sizeof( szDesc ), "Super class '%s' does not return an object", pClassFuncSym->szName ); hb_errRT_BASE( EG_ARG, 3002, szDesc, HB_ERR_FUNCNAME, 0 ); } } } } else { const char * pszName; pClassFuncSym = hb_itemGetSymbol( pItem ); if( pClassFuncSym ) pszName = pClassFuncSym->szName; else pszName = hb_itemGetCPtr( pItem ); hb_snprintf( szDesc, sizeof( szDesc ), "Cannot find super class '%s'", pszName ); hb_errRT_BASE( EG_ARG, 3003, szDesc, HB_ERR_FUNCNAME, 0 ); } hb_retni( uiClassH ); } /* __clsAssocType( , ) --> * * Associate class with given basic type */ HB_FUNC( __CLSASSOCTYPE ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pType = hb_param( 2, HB_IT_ANY ); HB_BOOL fResult = HB_FALSE; if( uiClass && uiClass <= s_uiClasses && pType ) { HB_TYPE nType = hb_clsGetItemType( pType, HB_IT_ANY ); if( s_pClasses[ uiClass ]->uiDatas ) hb_errRT_BASE( EG_ARG, 3005, "Scalar class can not contain instance variables", HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); else if( nType != HB_IT_ANY ) { switch( nType ) { case HB_IT_ARRAY: s_uiArrayClass = uiClass; break; case HB_IT_BLOCK: s_uiBlockClass = uiClass; break; case HB_IT_STRING: s_uiCharacterClass = uiClass; break; case HB_IT_DATE: s_uiDateClass = uiClass; break; case HB_IT_TIMESTAMP: s_uiTimeStampClass = uiClass; break; case HB_IT_HASH: s_uiHashClass = uiClass; break; case HB_IT_LOGICAL: s_uiLogicalClass = uiClass; break; case HB_IT_NIL: s_uiNilClass = uiClass; break; case HB_IT_NUMERIC: s_uiNumericClass = uiClass; break; case HB_IT_SYMBOL: s_uiSymbolClass = uiClass; break; case HB_IT_POINTER: s_uiPointerClass = uiClass; break; default: uiClass = 0; } fResult = uiClass != 0; } } hb_retl( fResult ); } /* __clsCntClasses() --> * * Return number of classes */ HB_FUNC( __CLSCNTCLASSES ) { HB_STACK_TLS_PRELOAD hb_retni( ( int ) s_uiClasses ); } /* __cls_CntClsData( ) --> * * Return number of class datas */ HB_FUNC( __CLS_CNTCLSDATA ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); hb_retni( uiClass && uiClass <= s_uiClasses ? ( HB_USHORT ) hb_arrayLen( s_pClasses[ uiClass ]->pClassDatas ) : 0 ); } /* __cls_CntShrData( ) --> * * Return number of class datas */ HB_FUNC( __CLS_CNTSHRDATA ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); hb_retni( uiClass && uiClass <= s_uiClasses ? ( HB_USHORT ) hb_arrayLen( s_pClasses[ uiClass ]->pSharedDatas ) : 0 ); } /* __cls_CntData( ) --> * * Return number of datas */ HB_FUNC( __CLS_CNTDATA ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); hb_retni( uiClass && uiClass <= s_uiClasses ? s_pClasses[ uiClass ]->uiDatas : 0 ); } /* __cls_DecData( ) --> * * Decrease number of datas and return new value */ HB_FUNC( __CLS_DECDATA ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); if( uiClass && uiClass <= s_uiClasses && s_pClasses[ uiClass ]->uiDatas > s_pClasses[ uiClass ]->uiDataFirst ) { if( ! s_pClasses[ uiClass ]->fLocked ) s_pClasses[ uiClass ]->uiDatas--; hb_retni( s_pClasses[ uiClass ]->uiDatas - s_pClasses[ uiClass ]->uiDataFirst ); } else hb_retni( 0 ); } /* __cls_IncData( ) --> * * Increase number of datas and return offset to new value */ HB_FUNC( __CLS_INCDATA ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); if( uiClass && uiClass <= s_uiClasses ) { if( ! s_pClasses[ uiClass ]->fLocked ) s_pClasses[ uiClass ]->uiDatas++; hb_retni( s_pClasses[ uiClass ]->uiDatas - s_pClasses[ uiClass ]->uiDataFirst ); } else hb_retni( 0 ); } /* NOTE: Undocumented Clipper function */ /* see for parameter compatibility with Clipper. */ HB_FUNC_TRANSLATE( __CLASSNEW, __CLSNEW ) /* NOTE: Undocumented Clipper function */ HB_FUNC_TRANSLATE( __CLASSINSTANCE, __CLSINST ) /* NOTE: Undocumented Clipper function */ HB_FUNC_TRANSLATE( __CLASSADD, __CLSADDMSG ) /* NOTE: Undocumented Clipper function */ HB_FUNC( __CLASSNAME ) { HB_STACK_TLS_PRELOAD hb_retc( hb_clsName( ( HB_USHORT ) hb_parni( 1 ) ) ); } /* NOTE: Undocumented Clipper function */ HB_FUNC( __CLASSSEL ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pReturn = hb_itemNew( NULL ); if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods; HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0; hb_arrayNew( pReturn, pClass->uiMethods ); /* Create a transfer array */ do { if( pMethod->pMessage ) /* Hash Entry used ? */ hb_arraySetC( pReturn, ++nPos, pMethod->pMessage->pSymbol->szName ); ++pMethod; } while( --nLimit ); if( nPos < ( HB_SIZE ) pClass->uiMethods ) hb_arraySize( pReturn, nPos ); } hb_itemReturnRelease( pReturn ); } /* to be used from Classes ERROR HANDLER method */ HB_FUNC( __GETMESSAGE ) { HB_STACK_TLS_PRELOAD hb_retc( hb_stackItem ( hb_stackBaseItem()->item.asSymbol.stackstate->nBaseItem )->item.asSymbol.value->szName ); } /* __clsParent( , ) --> * Checks if is parent of */ HB_FUNC( __CLSPARENT ) { HB_STACK_TLS_PRELOAD const char * szParentName = hb_parc( 2 ); hb_retl( szParentName && hb_clsIsParent( ( HB_USHORT ) hb_parni( 1 ), szParentName ) ); } /* __Sender() --> | NIL * returns sender object */ HB_FUNC( __SENDER ) { HB_STACK_TLS_PRELOAD HB_ISIZ nOffset = hb_stackBaseProcOffset( 2 ); if( nOffset > 0 ) { PHB_ITEM pSelf = hb_stackItem( nOffset + 1 ); /* Is it inline method? */ if( nOffset > 0 && HB_IS_BLOCK( pSelf ) && hb_stackItem( nOffset )->item.asSymbol.value == &hb_symEval ) { pSelf = hb_stackItem( hb_stackItem( nOffset )-> item.asSymbol.stackstate->nBaseItem + 1 ); } if( HB_IS_OBJECT( pSelf ) ) { hb_itemReturn( pSelf ); } } } HB_FUNC( __CLSSYNCSIGNAL ) { #if defined( HB_MT_VM ) hb_threadMutexSyncSignal( hb_param( 1, HB_IT_ANY ) ); #endif /* HB_MT_VM */ } HB_FUNC( __CLSSYNCWAIT ) { #if defined( HB_MT_VM ) HB_STACK_TLS_PRELOAD PHB_ITEM pMutex = NULL; HB_ULONG ulMilliSec = HB_THREAD_INFINITE_WAIT; HB_ISIZ nOffset = hb_stackBaseProcOffset( 2 ); if( nOffset > 0 ) { PHB_ITEM pBase = hb_stackItem( nOffset ); PHB_STACK_STATE pStack = pBase->item.asSymbol.stackstate; HB_USHORT uiClass = pStack->uiClass; if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; if( pMethod->pFuncSym == &s___msgSync ) { PHB_ITEM pSelf = hb_stackItem( nOffset + 1 ); /* Is it inline method? */ if( HB_IS_BLOCK( pSelf ) && pBase->item.asSymbol.value == &hb_symEval ) pSelf = hb_stackItem( pBase->item.asSymbol.stackstate->nBaseItem + 1 ); uiClass = hb_objGetClass( pSelf ); if( uiClass && uiClass <= s_uiClasses ) pMutex = hb_arrayGetItemPtr( pSelf, s_pClasses[ uiClass ]->uiMutexOffset ); } else if( pMethod->pFuncSym == &s___msgSyncClass ) pMutex = pClass->pMutex; } } if( HB_ISNUM( 2 ) ) { double dTimeOut = hb_parnd( 2 ); if( dTimeOut > 0 ) ulMilliSec = ( HB_ULONG ) ( dTimeOut * 10 ); } hb_retl( hb_threadMutexSyncWait( hb_param( 1, HB_IT_ANY ), ulMilliSec, pMutex ) ); #endif /* HB_MT_VM */ } /* __classH( ) --> * * Returns class handle of */ HB_FUNC( __CLASSH ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_param( 1, HB_IT_ANY ); hb_retni( pObject ? hb_objGetClassH( pObject ) : 0 ); } /* --- */ /* := :ClassH() * * Returns class handle of */ HB_FUNC_STATIC( msgClassH ) { HB_STACK_TLS_PRELOAD hb_retni( hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ); } /* := :ClassName() * * Return class name of . Can also be used for all types. */ HB_FUNC_STATIC( msgClassName ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass; if( uiClass ) hb_retc( s_pClasses[ uiClass ]->szName ); else hb_retc( hb_objGetClsName( hb_stackSelfItem() ) ); } static int hb_methodType( PMETHOD pMethod ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if ( pFuncSym == &s___msgSetClsData || pFuncSym == &s___msgGetClsData || pFuncSym == &s___msgSetShrData || pFuncSym == &s___msgGetShrData ) return HB_OO_MSG_CLASSDATA; else if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) return HB_OO_MSG_DATA; else if( pFuncSym == &s___msgEvalInline ) return HB_OO_MSG_INLINE; else if( pFuncSym == &s___msgVirtual ) return HB_OO_MSG_VIRTUAL; else if( pFuncSym == &s___msgSuper ) return HB_OO_MSG_SUPER; else if( pFuncSym == &s___msgRealClass ) return HB_OO_MSG_REALCLASS; else if( pFuncSym == &s___msgDelegate ) return HB_OO_MSG_DELEGATE; else if( pFuncSym == &s___msgPerform ) return HB_OO_MSG_PERFORM; else if( pMethod->pMessage == s___msgOnError.pDynSym ) return HB_OO_MSG_ONERROR; else if( pMethod->pMessage == s___msgDestructor.pDynSym ) return HB_OO_MSG_DESTRUCTOR; else return HB_OO_MSG_METHOD; } /* := :ClassSel() * * Returns all the messages in */ HB_FUNC_STATIC( msgClassSel ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass; if( uiClass && uiClass <= s_uiClasses ) { PHB_ITEM pReturn; PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods; HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0; HB_USHORT nParam, nScope; HB_BOOL lFull; nParam = ( HB_USHORT ) hb_parnidef( 1, HB_MSGLISTALL ); nScope = ( HB_USHORT ) hb_parni( 2 ); lFull = hb_parl( 3 ); pReturn = hb_itemArrayNew( pClass->uiMethods ); do { if( pMethod->pMessage ) /* Hash Entry used ? */ { if( ( nParam == HB_MSGLISTALL ) || ( nParam == HB_MSGLISTCLASS && hb_methodType( pMethod ) == HB_OO_MSG_CLASSDATA ) || ( nParam == HB_MSGLISTPURE && hb_methodType( pMethod ) != HB_OO_MSG_CLASSDATA ) ) { if( nScope == 0 || ( pMethod->uiScope & nScope ) != 0 ) { if( lFull ) { PHB_ITEM pItem = hb_arrayGetItemPtr( pReturn, ++nPos ); if( pItem ) { hb_arrayNew( pItem, 4 ); hb_arraySetC( pItem, HB_OO_DATA_SYMBOL, pMethod->pMessage->pSymbol->szName ); hb_arraySetNI( pItem, HB_OO_DATA_TYPE, hb_methodType( pMethod ) ); hb_arraySetNI( pItem, HB_OO_DATA_SCOPE, pMethod->uiScope ); } } else hb_arraySetC( pReturn, ++nPos, pMethod->pMessage->pSymbol->szName ); } } } ++pMethod; } while( --nLimit && nPos < ( HB_SIZE ) pClass->uiMethods ); if( nPos < ( HB_SIZE ) pClass->uiMethods ) hb_arraySize( pReturn, nPos ); hb_itemReturnRelease( pReturn ); } } #if 0 /* __msgClass() * * Internal function to return Self at Self:Class call (classy compatibility) */ HB_FUNC_STATIC( msgClass ) { hb_itemReturnForward( hb_stackSelfItem() ); } /* Added by JfL&RaC * <= :IsDerivedFrom( xParam ) * * Return true if is derived from xParam. * xParam can be either an obj or a classname */ HB_FUNC_STATIC( msgClassParent ) { HB_BOOL fHasParent = HB_FALSE; PHB_ITEM pItem; HB_USHORT uiClass; uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass; pItemParam = hb_param( 1, HB_IT_ANY ); if( pItemParam && uiClass && uiClass <= s_uiClasses ) { if( HB_IS_OBJECT( pItemParam ) ) fHasParent = hb_clsHasParentClass( s_pClasses[ uiClass ], pItemParam->item.asArray.value->uiClass ); else if( HB_IS_STRING( pItemParam ) ) fHasParent = hb_clsIsParent( uiClass, hb_parc( pItemParam ) ) } hb_retl( fHasParent ); } #endif /* __msgEvalInline() * * Internal function executed for inline methods */ HB_FUNC_STATIC( msgEvalInline ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate; PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; HB_USHORT uiPCount = hb_pcount(), uiParam; PHB_ITEM pBlock; hb_vmPushEvalSym(); hb_vmPush( hb_arrayGetItemPtr( s_pClasses[ pMethod->uiSprClass ]->pInlines, pMethod->uiData ) ); pBlock = hb_stackItemFromTop( -1 ); /* Push block */ pBlock->item.asBlock.hclass = pStack->uiClass; pBlock->item.asBlock.method = pStack->uiMethod; hb_vmPush( hb_stackSelfItem() ); /* Push self as first argument */ for( uiParam = 1; uiParam <= uiPCount; uiParam++ ) { hb_vmPush( hb_stackItemFromBase( uiParam ) ); } hb_vmEval( ( HB_USHORT ) ( uiPCount + 1 ) ); } HB_FUNC_STATIC( msgPerform ) { HB_STACK_TLS_PRELOAD PHB_ITEM pItem = hb_param( 1, HB_IT_ANY ); if( pItem ) { HB_USHORT uiPCount = hb_pcount(), uiParam; PHB_SYMB pSym = NULL; if( HB_IS_SYMBOL( pItem ) ) pSym = pItem->item.asSymbol.value; else if( HB_IS_OBJECT( pItem ) && s_pClasses[ pItem->item.asArray.value->uiClass ]->pClassSym == s___msgSymbol.pDynSym ) { /* Dirty hack */ pItem = hb_arrayGetItemPtr( pItem, 1 ); if( pItem && HB_IS_SYMBOL( pItem ) ) pSym = pItem->item.asSymbol.value; } if( pSym ) { hb_vmPushSymbol( pSym ); hb_vmPush( hb_stackSelfItem() ); for( uiParam = 2; uiParam <= uiPCount; uiParam++ ) { hb_vmPush( hb_stackItemFromBase( uiParam ) ); } hb_vmSend( ( HB_USHORT ) ( uiPCount - 1 ) ); } } } HB_FUNC_STATIC( msgDelegate ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate; PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; PHB_SYMB pExecSym = pClass->pMethods[ pMethod->uiData ].pFuncSym; if( pExecSym ) HB_VM_FUNCUNREF( pExecSym ); if( pExecSym && HB_VM_ISFUNC( pExecSym ) ) { HB_VM_EXECUTE( pExecSym ); } else { HB_FUNC_EXEC( msgNoMethod ); } } HB_FUNC_STATIC( msgSync ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate; PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; PHB_SYMB pExecSym = pMethod->pRealSym; if( pExecSym ) HB_VM_FUNCUNREF( pExecSym ); if( pExecSym && HB_VM_ISFUNC( pExecSym ) ) { PHB_ITEM pObject = hb_stackSelfItem(); HB_USHORT uiClass = hb_objGetClass( pObject ); PHB_ITEM pMutex = NULL; if( uiClass && uiClass <= s_uiClasses ) pMutex = hb_arrayGetItemPtr( pObject, s_pClasses[ uiClass ]->uiMutexOffset ); if( ! pMutex || hb_threadMutexLock( pMutex ) ) { HB_VM_EXECUTE( pExecSym ); if( pMutex ) hb_threadMutexUnlock( pMutex ); } } else { HB_FUNC_EXEC( msgNoMethod ); } } HB_FUNC_STATIC( msgSyncClass ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate; PCLASS pClass = s_pClasses[ pStack->uiClass ]; PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; PHB_SYMB pExecSym = pMethod->pRealSym; if( pExecSym ) HB_VM_FUNCUNREF( pExecSym ); if( pExecSym && HB_VM_ISFUNC( pExecSym ) ) { if( ! pClass->pMutex || hb_threadMutexLock( pClass->pMutex ) ) { HB_VM_EXECUTE( pExecSym ); if( pClass->pMutex ) hb_threadMutexUnlock( pClass->pMutex ); } } else { HB_FUNC_EXEC( msgNoMethod ); } } /* __msgNoMethod() * * Internal function for generating error when not existing message is sent */ HB_FUNC_STATIC( msgNoMethod ) { HB_STACK_TLS_PRELOAD PHB_SYMB pSym = hb_itemGetSymbol( hb_stackBaseItem() ); #if 1 /* Clipper compatible error message */ if( pSym->szName[ 0 ] == '_' ) hb_errRT_BASE_SubstR( EG_NOVARMETHOD, 1005, NULL, pSym->szName + 1, HB_ERR_ARGS_SELFPARAMS ); else hb_errRT_BASE_SubstR( EG_NOMETHOD, 1004, NULL, pSym->szName, HB_ERR_ARGS_SELFPARAMS ); #else char szDesc[ 40 + HB_SYMBOL_NAME_LEN ]; if( pSym->szName[ 0 ] == '_' ) { hb_snprintf( szDesc, sizeof( szDesc ), "Class: '%s' has no property", hb_objGetClsName( hb_stackSelfItem() ) ); hb_errRT_BASE_SubstR( EG_NOVARMETHOD, 1005, szDesc, pSym->szName + 1, HB_ERR_ARGS_BASEPARAMS ); } else { hb_snprintf( szDesc, sizeof( szDesc ), "Class: '%s' has no exported method", hb_objGetClsName( hb_stackSelfItem() ) ); hb_errRT_BASE_SubstR( EG_NOMETHOD, 1004, szDesc, pSym->szName, HB_ERR_ARGS_BASEPARAMS ); } #endif } /* __msgScopeErr() * * Internal function for generating error when not existing message is sent */ HB_FUNC_STATIC( msgScopeErr ) { HB_STACK_TLS_PRELOAD char * pszProcName; PHB_ITEM pObject = hb_stackSelfItem(); PMETHOD pMethod = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; pszProcName = hb_xstrcpy( NULL, hb_objGetClsName( pObject ), ":", pMethod->pMessage->pSymbol->szName, NULL ); if( pMethod->uiScope & HB_OO_CLSTP_HIDDEN ) hb_errRT_BASE( EG_NOMETHOD, 41, "Scope violation (hidden)", pszProcName, 0 ); else hb_errRT_BASE( EG_NOMETHOD, 42, "Scope violation (protected)", pszProcName, 0 ); hb_xfree( pszProcName ); } HB_FUNC_STATIC( msgTypeErr ) { HB_STACK_TLS_PRELOAD char * pszProcName; PHB_ITEM pObject = hb_stackSelfItem(); PMETHOD pMethod = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; pszProcName = hb_xstrcpy( NULL, hb_objGetClsName( pObject ), ":", pMethod->pMessage->pSymbol->szName + 1, NULL ); hb_errRT_BASE( EG_NOMETHOD, 44, "Assigned value is wrong class", pszProcName, HB_ERR_ARGS_BASEPARAMS ); hb_xfree( pszProcName ); } /* __msgSuper() * * Internal function to return a superobject */ HB_FUNC_STATIC( msgSuper ) { HB_STACK_TLS_PRELOAD PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate; hb_clsMakeSuperObject( hb_stackReturnItem(), hb_stackSelfItem(), s_pClasses[ pStack->uiClass ]->pMethods[ pStack->uiMethod ].uiData ); } /* __msgRealClass() * * Internal function to return a superobject of class where the method was * defined */ HB_FUNC_STATIC( msgRealClass ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_stackSelfItem(); HB_USHORT uiClass = hb_clsSenderMethodClass(); HB_USHORT uiCurClass = hb_objGetClassH( pObject ); if( uiClass && uiClass != uiCurClass && hb_clsSenderObjectClass() == uiCurClass ) { hb_clsMakeSuperObject( hb_stackReturnItem(), pObject, uiClass ); } else { hb_itemReturnForward( pObject ); } } /* __msgGetClsData() * * Internal function to return a CLASSDATA */ HB_FUNC_STATIC( msgGetClsData ) { HB_STACK_TLS_PRELOAD PCLASS pClass = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; hb_arrayGet( pClass->pClassDatas, pMethod->uiData, hb_stackReturnItem() ); } /* __msgSetClsData() * * Internal function to set a CLASSDATA */ HB_FUNC_STATIC( msgSetClsData ) { HB_STACK_TLS_PRELOAD PCLASS pClass = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; PHB_ITEM pReturn = hb_param( 1, HB_IT_ANY ); if( ! pReturn ) hb_arrayGet( pClass->pClassDatas, pMethod->uiData, hb_stackReturnItem() ); else { if( pMethod->itemType && ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) ) { if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) ) hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) ); else { ( s___msgTypeErr.value.pFunPtr )(); return; } } hb_arraySet( pClass->pClassDatas, pMethod->uiData, pReturn ); hb_itemReturn( pReturn ); } } /* __msgGetShrData() * * Internal function to return a SHAREDDATA */ HB_FUNC_STATIC( msgGetShrData ) { HB_STACK_TLS_PRELOAD PCLASS pClass = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; hb_arrayGet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas, pMethod->uiData, hb_stackReturnItem() ); } /* __msgSetShrData() * * Internal function to set a SHAREDDATA */ HB_FUNC_STATIC( msgSetShrData ) { HB_STACK_TLS_PRELOAD PCLASS pClass = s_pClasses[ hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; PHB_ITEM pReturn = hb_param( 1, HB_IT_ANY ); if( ! pReturn ) hb_arrayGet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas, pMethod->uiData, hb_stackReturnItem() ); else { if( pMethod->itemType && ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) ) { if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) ) hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) ); else { ( s___msgTypeErr.value.pFunPtr )(); return; } } hb_arraySet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas, pMethod->uiData, pReturn ); hb_itemReturn( pReturn ); } } /* __msgGetData() * * Internal function to return a DATA */ HB_FUNC_STATIC( msgGetData ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_stackSelfItem(); if( HB_IS_ARRAY( pObject ) ) { HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass; HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass; PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; HB_SIZE nIndex = pMethod->uiData; if( uiClass != uiObjClass ) { nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ], pMethod->uiSprClass ); } else { nIndex += pMethod->uiOffset; } hb_arrayGet( pObject, nIndex, hb_stackReturnItem() ); } } /* __msgSetData() * * Internal function to set a DATA */ HB_FUNC_STATIC( msgSetData ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_stackSelfItem(); if( HB_IS_ARRAY( pObject ) ) { PHB_ITEM pReturn = hb_param( 1, HB_IT_ANY ); HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass; HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass; PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods + hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; HB_SIZE nIndex = pMethod->uiData; if( uiClass != uiObjClass ) { nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ], pMethod->uiSprClass ); } else { nIndex += pMethod->uiOffset; } if( ! pReturn ) hb_arrayGet( pObject, nIndex, hb_stackReturnItem() ); else { if( pMethod->itemType && ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) ) { if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) ) hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) ); else { ( s___msgTypeErr.value.pFunPtr )(); return; } } /* will arise only if the class has been modified after first instance */ if( nIndex > hb_arrayLen( pObject ) ) /* Resize needed ? */ hb_arraySize( pObject, nIndex ); /* Make large enough */ hb_arraySet( pObject, nIndex, pReturn ); hb_itemReturn( pReturn ); } } } /* No comment :-) */ HB_FUNC_STATIC( msgVirtual ) { #if 0 hb_ret(); /* NOTE: It's safe to have this commented out. */ #endif } HB_FUNC_STATIC( msgNull ) { } #ifndef HB_NO_PROFILER void hb_mthAddTime( HB_ULONG ulClockTicks ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_stackSelfItem(); PCLASS pClass = s_pClasses[ hb_objGetClassH( pObject ) ]; HB_USHORT uiMethod = hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod; if( pClass && uiMethod < hb_clsMthNum( pClass ) ) { PMETHOD pMethod = pClass->pMethods + uiMethod; pMethod->ulCalls++; pMethod->ulTime += ulClockTicks; return; } if( HB_IS_BLOCK( pObject ) ) { PHB_SYMB pSym = hb_stackBaseItem()->item.asSymbol.value; if( pSym == &hb_symEval || pSym->pDynSym == hb_symEval.pDynSym ) { pSym->pDynSym->ulCalls++; if( --pSym->pDynSym->ulRecurse == 0 ) pSym->pDynSym->ulTime += ulClockTicks; } } } #endif /* __GetMsgPrf( , ) --> { { , }, ... } */ HB_FUNC( __GETMSGPRF ) /* profiler: returns a method called and consumed times */ { HB_STACK_TLS_PRELOAD #ifndef HB_NO_PROFILER HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); const char * cMsg = hb_parc( 2 ); hb_reta( 2 ); if( uiClass && uiClass <= s_uiClasses && cMsg && *cMsg ) { PHB_DYNS pMsg = hb_dynsymFindName( cMsg ); if( pMsg ) { PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsg ); if( pMethod ) { hb_storvnl( pMethod->ulCalls, -1, 1 ); hb_storvnl( pMethod->ulTime, -1, 2 ); return; } } } #else hb_reta( 2 ); #endif hb_storvnl( 0, -1, 1 ); hb_storvnl( 0, -1, 2 ); } typedef struct { PMETHOD pMethod; HB_USHORT uiClass; HB_USHORT uiStatus; } HB_IVARINFO, * PHB_IVARINFO; static PHB_ITEM hb_objGetIVars( PHB_ITEM pObject, HB_USHORT uiScope, HB_BOOL fChanged ) { PHB_IVARINFO pIndex, pInfo; PCLASS pClass; PMETHOD pMethod; PHB_ITEM pReturn, pItem; HB_SIZE nLimit, nLen, nCount, nSize, nIndex, nOffset; HB_USHORT uiClass, uiSuperClasses; if( ! pObject || ! HB_IS_OBJECT( pObject ) ) return NULL; uiClass = pObject->item.asArray.value->uiClass; pClass = s_pClasses[ uiClass ]; nLen = nCount = hb_arrayLen( pObject ); nSize = 0; pIndex = nLen ? ( PHB_IVARINFO ) hb_xgrabz( nLen * sizeof( HB_IVARINFO ) ) : NULL; if( fChanged && pClass->uiInitDatas ) { PINITDATA pInitData = pClass->pInitData; nLimit = pClass->uiInitDatas; do { if( pInitData->uiType == HB_OO_MSG_DATA ) { nIndex = pInitData->uiData + pInitData->uiOffset; pItem = hb_arrayGetItemPtr( pObject, nIndex ); if( pItem ) { if( hb_itemEqual( pItem, pInitData->pInitValue ) ) { pIndex[ nIndex - 1 ].uiStatus = 3; --nCount; } else pIndex[ nIndex - 1 ].uiStatus = 1; } } ++pInitData; } while( --nLimit ); } uiSuperClasses = pClass->uiSuperClasses; nOffset = 0; nLimit = hb_clsMthNum( pClass ); pMethod = pClass->pMethods; while( nCount && nLimit ) { if( pMethod->pMessage && ( uiScope == 0 || ( pMethod->uiScope & uiScope ) != 0 ) && ( uiClass == pClass->uiClass || uiClass == pMethod->uiSprClass ) ) { PHB_SYMB pFuncSym = pMethod->pFuncSym; if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) pFuncSym = pMethod->pRealSym; if( pFuncSym == &s___msgGetData || pFuncSym == &s___msgSetData ) { HB_USHORT uiStatus = pFuncSym == &s___msgGetData ? 3 : 2; nIndex = ( uiClass == pClass->uiClass ? ( HB_SIZE ) pMethod->uiOffset : nOffset ) + pMethod->uiData; if( nIndex == 0 || nIndex > nLen ) hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__objGetIVars()", NULL ); pInfo = &pIndex[ nIndex - 1 ]; if( pInfo->uiStatus < uiStatus ) { pItem = hb_arrayGetItemPtr( pObject, nIndex ); if( ! pItem || ( pInfo->uiStatus == 0 && HB_IS_NIL( pItem ) ) ) uiStatus = 3; else { if( ! pInfo->pMethod ) ++nSize; pInfo->pMethod = pMethod; pInfo->uiClass = uiClass; } pInfo->uiStatus = uiStatus; if( uiStatus == 3 ) --nCount; } } } ++pMethod; if( --nLimit == 0 ) { if( uiSuperClasses-- ) { if( uiClass == pClass->pSuperClasses[ uiSuperClasses ].uiClass ) if( uiSuperClasses-- == 0 ) break; uiClass = pClass->pSuperClasses[ uiSuperClasses ].uiClass; nOffset = pClass->pSuperClasses[ uiSuperClasses ].uiOffset; nLimit = hb_clsMthNum( s_pClasses[ uiClass ] ); pMethod = s_pClasses[ uiClass ]->pMethods; } } } nCount = 0; pReturn = hb_itemArrayNew( nSize ); for( nIndex = 1; nIndex <= nLen && nCount < nSize; ++nIndex ) { pInfo = &pIndex[ nIndex - 1 ]; if( pInfo->pMethod ) { const char * pszVar = pInfo->pMethod->pMessage->pSymbol->szName; PHB_ITEM pValue = hb_arrayGetItemPtr( pReturn, ++nCount ); hb_arrayNew( pValue, 2 ); if( pInfo->uiClass != pClass->uiClass ) { char * pszCast = hb_xstrcpy( NULL, s_pClasses[ pInfo->uiClass ]->szName, ":", pszVar, NULL ); hb_arraySetCPtr( pValue, 1, pszCast ); } else hb_arraySetCConst( pValue, 1, pszVar ); hb_arraySet( pValue, 2, hb_arrayGetItemPtr( pObject, nIndex ) ); } } if( pIndex ) hb_xfree( pIndex ); return pReturn; } static void hb_objSetIVars( PHB_ITEM pObject, PHB_ITEM pArray ) { if( pObject && HB_IS_OBJECT( pObject ) && pArray && HB_IS_ARRAY( pArray ) && pArray->item.asArray.value->uiClass == 0 ) { HB_USHORT uiClass = pObject->item.asArray.value->uiClass; HB_SIZE nPos, nIndex, nLen; PHB_ITEM pValue; nPos = 0; while( ( pValue = hb_arrayGetItemPtr( pArray, ++nPos ) ) != NULL ) { const char * pszMethod = hb_arrayGetCPtr( pValue, 1 ); PHB_DYNS pVarSym = hb_dynsymFind( pszMethod ); PHB_ITEM pNewVal = hb_arrayGetItemPtr( pValue, 2 ); HB_USHORT uiSuper = uiClass; if( ! pVarSym ) { const char * pszClass = strchr( pszMethod, ':' ); if( pszClass ) { nLen = pszClass - pszMethod; if( nLen ) { PHB_DYNS pParentSym; char szClassName[ HB_SYMBOL_NAME_LEN + 1 ]; if( nLen > HB_SYMBOL_NAME_LEN ) nLen = HB_SYMBOL_NAME_LEN; memcpy( szClassName, pszMethod, nLen ); szClassName[ nLen ] = '\0'; pParentSym = hb_dynsymFindName( szClassName ); uiSuper = pParentSym == NULL ? 0 : hb_clsGetParent( s_pClasses[ uiClass ], pParentSym ); } pVarSym = hb_dynsymFindName( pszClass + 1 ); } else pVarSym = hb_dynsymFindName( pszMethod ); } if( uiSuper && pNewVal && pVarSym && ( nIndex = hb_clsGetVarIndexEx( uiClass, pVarSym, uiSuper ) ) != 0 ) { hb_arraySet( pObject, nIndex, pNewVal ); } } } } /* __objGetIVars( , [], [] ) * --> { { , }, ... } */ HB_FUNC( __OBJGETIVARS ) { PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); HB_USHORT uiScope = ( HB_USHORT ) hb_parni( 2 ); HB_BOOL fChanged = hb_parldef( 3, HB_TRUE ); hb_itemReturnRelease( hb_objGetIVars( pObject, uiScope, fChanged ) ); } /* __objSetIVars( | | | , * ) --> */ HB_FUNC( __OBJSETIVARS ) { PHB_ITEM pObject = hb_param( 1, HB_IT_ANY ); PHB_ITEM pArray = hb_param( 2, HB_IT_ARRAY ); if( pObject && pArray ) { PHB_ITEM pNewObj = NULL; if( HB_IS_NUMERIC( pObject ) ) pObject = pNewObj = hb_clsInst( ( HB_USHORT ) hb_itemGetNI( pObject ) ); else if( HB_IS_STRING( pObject ) ) pObject = pNewObj = hb_clsInst( hb_clsFindClass( hb_itemGetCPtr( pObject ), NULL ) ); else if( HB_IS_SYMBOL( pObject ) ) pObject = pNewObj = hb_clsInst( hb_clsFindClassByFunc( hb_itemGetSymbol( pObject ) ) ); else if( ! HB_IS_OBJECT( pObject ) ) pObject = NULL; hb_objSetIVars( pObject, pArray ); if( pObject ) hb_itemReturn( pObject ); if( pNewObj ) hb_itemRelease( pNewObj ); } } /* __objRestoreIVars( , | | [, ] ) --> */ HB_FUNC( __OBJRESTOREIVARS ) { PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY ); PHB_ITEM pClass = hb_param( 2, HB_IT_NUMERIC | HB_IT_STRING | HB_IT_SYMBOL ); if( pClass && pArray && pArray->item.asArray.value->uiClass == 0 ) { PHB_ITEM pObject = NULL; if( HB_IS_NUMERIC( pClass ) ) pObject = hb_clsInst( ( HB_USHORT ) hb_itemGetNI( pClass ) ); else if( HB_IS_STRING( pClass ) ) pObject = hb_clsInst( hb_clsFindClass( hb_itemGetCPtr( pClass ), hb_parc( 3 ) ) ); else if( HB_IS_SYMBOL( pClass ) ) pObject = hb_clsInst( hb_clsFindClassByFunc( hb_itemGetSymbol( pClass ) ) ); if( pObject ) { hb_objSetIVars( pObject, pArray ); hb_arraySwap( pObject, pArray ); hb_itemRelease( pObject ); } } hb_itemReturn( pArray ); } /* __clsGetProperties( , [] ) --> * Notice that this function works quite similar to __classSel() * except that just returns the name of the datas and methods * that have been declared as PROPERTY (PERSISTENT) or also EXPORTED * if second parameter is true and message has corresponding * assign message (with "_" prefix) */ HB_FUNC( __CLSGETPROPERTIES ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pReturn = hb_itemNew( NULL ); if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod, pAccMth; HB_SIZE nLimit, nCount; HB_USHORT uiScope = HB_OO_CLSTP_PERSIST; if( hb_parl( 2 ) ) uiScope |= HB_OO_CLSTP_EXPORTED; nCount = 0; nLimit = hb_clsMthNum( pClass ); pMethod = pClass->pMethods; do { if( pMethod->pMessage && ( pMethod->uiScope & uiScope ) != 0 ) { if( ( pMethod->uiScope & HB_OO_CLSTP_PERSIST ) != 0 ) ++nCount; else if( pMethod->pMessage->pSymbol->szName[ 0 ] == '_' ) { if( ! pMethod->pAccMsg ) pMethod->pAccMsg = hb_dynsymGetCase( pMethod->pMessage->pSymbol->szName + 1 ); pAccMth = hb_clsFindMsg( pClass, pMethod->pAccMsg ); if( pAccMth && ( pAccMth->uiScope & HB_OO_CLSTP_PERSIST ) == 0 ) ++nCount; } } ++pMethod; } while( --nLimit ); hb_arrayNew( pReturn, nCount ); nCount = 0; nLimit = hb_clsMthNum( pClass ); pMethod = pClass->pMethods; do { if( pMethod->pMessage && ( pMethod->uiScope & uiScope ) != 0 ) { if( ( pMethod->uiScope & HB_OO_CLSTP_PERSIST ) != 0 ) hb_arraySetC( pReturn, ++nCount, pMethod->pMessage->pSymbol->szName ); else if( pMethod->pMessage->pSymbol->szName[ 0 ] == '_' && pMethod->pAccMsg ) { pAccMth = hb_clsFindMsg( pClass, pMethod->pAccMsg ); if( pAccMth && ( pAccMth->uiScope & HB_OO_CLSTP_PERSIST ) == 0 ) hb_arraySetC( pReturn, ++nCount, pMethod->pMessage->pSymbol->szName + 1 ); } } ++pMethod; } while( --nLimit ); } hb_itemReturnRelease( pReturn ); } /* __clsGetAncestors( ) --> { , , ... } */ HB_FUNC( __CLSGETANCESTORS ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ), uiCount; if( uiClass && uiClass <= s_uiClasses ) { HB_STACK_TLS_PRELOAD PHB_ITEM pReturn = hb_stackReturnItem(); PCLASS pClass = s_pClasses[ uiClass ]; HB_SIZE nPos = 0; uiCount = pClass->uiSuperClasses; hb_arrayNew( pReturn, uiCount ); while( uiCount-- ) { HB_USHORT uiSuperCls = pClass->pSuperClasses[ uiCount ].uiClass; if( uiSuperCls != uiClass ) hb_arraySetNI( pReturn, ++nPos, uiSuperCls ); } hb_arraySize( pReturn, nPos ); } } /* __clsMsgType( , | ) --> * * return type of method attached to given message, * is one of HB_OO_MSG_* values defined in hboo.ch or * -1 if message is not supported. */ HB_FUNC( __CLSMSGTYPE ) { PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) ); if( pMessage ) { HB_STACK_TLS_PRELOAD HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PMETHOD pMethod = NULL; if( uiClass && uiClass <= s_uiClasses ) pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMessage ); hb_retni( pMethod ? hb_methodType( pMethod ) : -1 ); } else hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } /* extend the size of classes buffer to given value to avoid later * RT reallocations. It may be useful in some very seldom cases * for MT programs which will allocate dynamically at runtime * more then 16386 classes. In practice rather impossible though * who knows ;-) * __clsPreallocate( [] ) --> */ HB_FUNC( __CLSPREALLOCATE ) { HB_STACK_TLS_PRELOAD HB_LONG lNewSize = hb_parnl( 1 ); if( lNewSize > ( HB_LONG ) USHRT_MAX ) lNewSize = USHRT_MAX; HB_CLASS_LOCK(); if( lNewSize > ( HB_LONG ) s_uiClsSize ) { s_uiClsSize = ( HB_USHORT ) lNewSize; s_pClasses = ( PCLASS * ) hb_xrealloc( s_pClasses, sizeof( PCLASS ) * ( ( HB_SIZE ) s_uiClsSize + 1 ) ); } HB_CLASS_UNLOCK(); hb_retnl( s_uiClsSize ); } /* __clsLockDef( ) --> */ HB_FUNC( __CLSLOCKDEF ) { HB_STACK_TLS_PRELOAD PHB_ITEM pClsItm = hb_param( 1, HB_IT_BYREF ); HB_BOOL fLocked = HB_FALSE; if( pClsItm && HB_IS_NIL( pClsItm ) ) { if( ! s_pClassMtx || hb_threadMutexLock( s_pClassMtx ) ) { if( HB_IS_NIL( pClsItm ) ) fLocked = HB_TRUE; else if( s_pClassMtx ) hb_threadMutexUnlock( s_pClassMtx ); } } hb_retl( fLocked ); } /* __clsUnlockDef( @, ) */ HB_FUNC( __CLSUNLOCKDEF ) { PHB_ITEM pClsDst = hb_param( 1, HB_IT_BYREF ), pClsSrc = hb_param( 2, HB_IT_ANY ); if( pClsDst && pClsSrc && HB_IS_NIL( pClsDst ) && ! HB_ISBYREF( 2 ) ) { /* special core code only macro used to eliminate race condition * in unprotected readonly access to pClsDst variable. */ hb_itemSafeMove( pClsDst, pClsSrc ); } if( s_pClassMtx ) hb_threadMutexUnlock( s_pClassMtx ); } /* Dirty functions which converts array to object of given class * __objSetClass( , [, ] ) --> */ HB_FUNC( __OBJSETCLASS ) { PHB_ITEM pObject = hb_param( 1, HB_IT_ARRAY ); if( pObject && pObject->item.asArray.value->uiClass == 0 ) { const char * szClass = hb_parc( 2 ); if( szClass ) hb_objSetClass( pObject, szClass, hb_parc( 3 ) ); } hb_itemReturn( pObject ); } /* Real dirty function, though very useful under certain circumstances: * It allows to change the class handle of an object into another class handle, * so the object behaves like a different Class of object. * Based on objects.lib SetClsHandle() * __objSetClassHandle( , ) --> */ HB_FUNC( __OBJSETCLASSHANDLE ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); HB_USHORT uiPrevClassHandle = 0; if( pObject ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 2 ); uiPrevClassHandle = pObject->item.asArray.value->uiClass; if( uiClass <= s_uiClasses ) pObject->item.asArray.value->uiClass = uiClass; } hb_retnl( uiPrevClassHandle ); } #if defined( HB_LEGACY_LEVEL5 ) HB_FUNC_TRANSLATE( HB_SETCLSHANDLE, __OBJSETCLASSHANDLE ) #endif /* Harbour equivalent for Clipper internal __mdCreate() */ HB_USHORT hb_clsCreate( HB_USHORT usSize, const char * szClassName ) { return hb_clsNew( szClassName, usSize, NULL, NULL, HB_FALSE ); } /* Harbour equivalent for Clipper internal __mdAdd() */ void hb_clsAdd( HB_USHORT usClassH, const char * szMethodName, PHB_FUNC pFuncPtr ) { PHB_SYMB pExecSym; PHB_ITEM pFuncItem; /* We can use empty name "" for this symbol in hb_symbolNew() * It's only envelop for function with additional execution * information for HVM not registered symbol. [druzus] */ pExecSym = hb_symbolNew( "" ); pExecSym->value.pFunPtr = pFuncPtr; pFuncItem = hb_itemPutSymbol( NULL, pExecSym ); hb_clsAddMsg( usClassH, szMethodName, HB_OO_MSG_METHOD, 0, pFuncItem, NULL ); hb_itemRelease( pFuncItem ); } /* Harbour equivalent for Clipper internal __mdAssociate() */ void hb_clsAssociate( HB_USHORT usClassH ) { PHB_ITEM pSelf = hb_clsInst( usClassH ); if( pSelf ) hb_itemReturnRelease( pSelf ); else { HB_STACK_TLS_PRELOAD hb_ret(); } } HB_FUNC( __CLSVERIFY ) { HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ); PHB_ITEM pReturn = hb_itemNew( NULL ); if( uiClass && uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ uiClass ]; PMETHOD pMethod = pClass->pMethods; HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0; hb_arrayNew( pReturn, pClass->uiMethods ); do { if( pMethod->pMessage ) { PHB_DYNS pDynSym = hb_dynsymFind( pMethod->pMessage->pSymbol->szName ); if( pMethod->pMessage != pDynSym || hb_clsFindMsg( pClass, pDynSym ) != pMethod ) hb_arraySetC( pReturn, ++nPos, pMethod->pMessage->pSymbol->szName ); } ++pMethod; } while( --nLimit ); if( nPos < ( HB_SIZE ) pClass->uiMethods ) hb_arraySize( pReturn, nPos ); } hb_itemReturnRelease( pReturn ); } #if 0 /* return real function name ignoring aliasing */ const char * hb_clsRealMethodName( void ) { HB_ISIZ nOffset = hb_stackBaseProcOffset( 1 ); const char * szName = NULL; if( nOffset > 0 ) { PHB_STACK_STATE pStack = hb_stackItem( nOffset )->item.asSymbol.stackstate; if( pStack->uiClass && pStack->uiClass <= s_uiClasses ) { PCLASS pClass = s_pClasses[ pStack->uiClass ]; if( ( HB_SIZE ) pStack->uiMethod < hb_clsMthNum( pClass ) ) { PMETHOD pMethod = pClass->pMethods + pStack->uiMethod; if( pMethod->pMessage ) szName = pMethod->pMessage->pSymbol->szName; } } } return szName; } #endif