diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 3e7a4737fd..fc88733136 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,50 @@ 2002-12-01 13:30 UTC+0100 Foo Bar */ +2007-03-13 19:40 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbapi.h + * harbour/include/hbapiitm.h + * harbour/source/vm/garbage.c + * harbour/source/vm/extend.c + * harbour/source/vm/itemapi.c + + added hb_gcFunc(), hb_parptrGC(), hb_itemGetPtrGC() + hb_parptrGC() and hb_itemGetPtrGC() uses GC cleanup function address + to validate if pointer item points to expected memory block type + + * harbour/source/common/hbhash.c + * harbour/source/compiler/hbident.c + * formatting and minor modifications + + * harbour/source/pp/pplib.c + * harbour/source/pp/pplib2.c + * use hb_parptrGC() to be sure that given pointer item points + to PP structure + + + harbour/include/hbregex.h + + harbour/source/rtl/hbregex.c + * harbour/source/rtl/Makefile + * harbour/common.mak + + added support for regular expressions. Now it's enabled by default + only in *nixes (POSIX regex) and BCC 5.5 (PCRE regex). Setting + HB_PCRE_REGEX macro enables Perl-Compatible Regular Expressions + and HB_POSIX_REGEX - POSIX regular expressions. In xHarbour regex + support is enabled for all builds because PCRE source code is stored + in CVS. If you will want we can make the same. + + the following C functions are available: + hb_regexCompile(), hb_regexGet(), hb_regexFree(), hb_regexMatch() + + the following PGR functions are available: + HB_REGEXCOMP(), HB_ISREGEX(), HB_ATX(), HB_REGEX(), HB_REGEXMATCH(), + HB_REGEXSPLIT(), HB_REGEXATX(), HB_REGEXALL() + They are working in similar way to the ones in xHarbour with the + exception to some bug fixes and form of compiled regular expression. + In Harbour it's pointer item for which HB_ISREGEX() returns TRUE when + in xHarbour it's binary string. + + * harbour/source/rdd/dbfcdx/dbfcdx1.c + * harbour/source/rdd/dbfntx/dbfntx1.c + * enabled code to seek in index using regular expressions + (DBOI_SKIPREGEX[BACK]) + 2007-03-12 14:30 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/hbexpra.c * emulate xHarbour HB_ENUMINDEX() inside FOR EACH loop when diff --git a/harbour/common.mak b/harbour/common.mak index 0e9b2bd9d9..94c08853eb 100644 --- a/harbour/common.mak +++ b/harbour/common.mak @@ -379,6 +379,7 @@ RTL_LIB_OBJS = \ $(OBJ_DIR)\hbffind.obj \ $(OBJ_DIR)\hbgtcore.obj \ $(OBJ_DIR)\hbrandom.obj \ + $(OBJ_DIR)\hbregex.obj \ $(OBJ_DIR)\idle.obj \ $(OBJ_DIR)\inkey.obj \ $(OBJ_DIR)\is.obj \ diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index 3935c13849..a33aacf2b8 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -408,6 +408,101 @@ typedef USHORT ERRCODE; extern HB_SYMB hb_symEval; +extern HB_EXPORT void hb_xinit( void ); /* Initialize fixed memory subsystem */ +extern HB_EXPORT void hb_xexit( void ); /* Deinitialize fixed memory subsystem */ +extern HB_EXPORT void * hb_xalloc( ULONG ulSize ); /* allocates memory, returns NULL on failure */ +extern HB_EXPORT void * hb_xgrab( ULONG ulSize ); /* allocates memory, exits on failure */ +extern HB_EXPORT void hb_xfree( void * pMem ); /* frees memory */ +extern HB_EXPORT void * hb_xrealloc( void * pMem, ULONG ulSize ); /* reallocates memory */ +extern HB_EXPORT ULONG hb_xsize( void * pMem ); /* returns the size of an allocated memory block */ +extern HB_EXPORT ULONG hb_xquery( USHORT uiMode ); /* Query different types of memory information */ + +#ifdef _HB_API_INTERNAL_ +extern void hb_xRefInc( void * pMem ); /* increment reference counter */ +extern BOOL hb_xRefDec( void * pMem ); /* decrement reference counter, return TRUE when 0 reached */ +extern void hb_xRefFree( void * pMem ); /* decrement reference counter and free the block when 0 reached */ +extern HB_COUNTER hb_xRefCount( void * pMem ); /* return number of references */ +extern void * hb_xRefResize( void * pMem, ULONG ulSave, ULONG ulSize ); /* reallocates memory, create copy if reference counter greater then 1 */ + +#if 0 + +/* + * I used this macros only to test some speed overhead, + * They may not be supported in the future so please do + * not create any code which needs them. [druzus] + */ + +#define hb_xRefInc( p ) (++(*HB_COUNTER_PTR( p ))) +#define hb_xRefDec( p ) (--(*HB_COUNTER_PTR( p ))==0) +#define hb_xRefFree( p ) do { \ + if( hb_xRefDec( p ) ) \ + hb_xfree( p ); \ + } while( 0 ) +#define hb_xRefCount( p ) (*HB_COUNTER_PTR( p )) + +#endif + +#endif /* _HB_API_INTERNAL_ */ + +/* #if UINT_MAX == ULONG_MAX */ +/* it fails on 64bit platforms where int has 32 bit and long has 64 bit. + we need these functions only when max(size_t) < max(long) + and only on 16bit platforms, so the below condition seems to be + more reasonable. */ +#if UINT_MAX > USHRT_MAX + /* NOTE: memcpy/memset can work with ULONG data blocks */ + #define hb_xmemcpy memcpy + #define hb_xmemset memset +#else + /* NOTE: otherwise, the hb_xmemcpy and hb_xmemset functions + will be used to copy and/or set ULONG data blocks */ +extern HB_EXPORT void * hb_xmemcpy( void * pDestArg, void * pSourceArg, ULONG ulLen ); /* copy more than memcpy() can */ +extern HB_EXPORT void * hb_xmemset( void * pDestArg, int iFill, ULONG ulLen ); /* set more than memset() can */ +#endif + +/* garbage collector */ +#define HB_GARBAGE_FUNC( hbfunc ) void hbfunc( void * Cargo ) /* callback function for cleaning garbage memory pointer */ +typedef HB_GARBAGE_FUNC( HB_GARBAGE_FUNC_ ); +typedef HB_GARBAGE_FUNC_ * HB_GARBAGE_FUNC_PTR; + +#define HB_GARBAGE_SWEEPER( hbfunc ) BOOL hbfunc( void * Cargo ) /* callback function for cleaning garbage memory pointer */ +typedef HB_GARBAGE_SWEEPER( HB_GARBAGE_SWEEPER_ ); +typedef HB_GARBAGE_SWEEPER_ * HB_GARBAGE_SWEEPER_PTR; + +extern void hb_gcRegisterSweep( HB_GARBAGE_SWEEPER_PTR pSweep, void * Cargo ); + +extern PHB_ITEM hb_gcGripGet( HB_ITEM_PTR pItem ); +extern void hb_gcGripDrop( HB_ITEM_PTR pItem ); + +extern HB_EXPORT void *hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pFunc ); /* allocates a memory controlled by the garbage collector */ +extern void hb_gcFree( void *pAlloc ); /* deallocates a memory allocated by the garbage collector */ +extern void * hb_gcLock( void *pAlloc ); /* do not release passed memory block */ +extern void * hb_gcUnlock( void *pAlloc ); /* passed block is allowed to be released */ +#ifdef _HB_API_INTERNAL_ +HB_GARBAGE_FUNC_PTR hb_gcFunc( void *pBlock ); /* return cleanup function pointer */ +extern void hb_gcItemRef( HB_ITEM_PTR pItem ); /* checks if passed item refers passed memory block pointer */ +extern void hb_vmIsLocalRef( void ); /* hvm.c - mark all local variables as used */ +extern void hb_vmIsStaticRef( void ); /* hvm.c - mark all static variables as used */ +extern void hb_memvarsIsMemvarRef( void ); /* memvars.c - mark all memvar variables as used */ +extern void hb_gcReleaseAll( void ); /* release all memory blocks unconditionally */ + +extern void hb_gcRefCheck( void * pBlock ); /* Check if block still cannot be access after destructor execution */ +extern void hb_gcRefInc( void * pAlloc ); /* increment reference counter */ +extern BOOL hb_gcRefDec( void * pAlloc ); /* decrement reference counter, return TRUE when 0 reached */ +extern void hb_gcRefFree( void * pAlloc ); /* decrement reference counter and free the block when 0 reached */ +extern HB_COUNTER hb_gcRefCount( void * pAlloc ); /* return number of references */ + +#if 0 +#define hb_gcRefInc( p ) hb_xRefInc( HB_GC_PTR( p ) ) +#define hb_gcRefDec( p ) hb_xRefDec( HB_GC_PTR( p ) ) +#define hb_gcRefCount( p ) hb_xRefCount( HB_GC_PTR( p ) ) +#define hb_gcFunc( p ) ( HB_GC_PTR( p )->pFunc ) +#endif + +#endif /* _HB_API_INTERNAL_ */ +extern void hb_gcCollect( void ); /* checks if a single memory block can be released */ +extern void hb_gcCollectAll( void ); /* checks if all memory blocks can be released */ + /* Extend API */ extern HB_EXPORT char * hb_parc( int iParam, ... ); /* retrieve a string parameter */ extern HB_EXPORT char * hb_parcx( int iParam, ... ); /* retrieve a string parameter */ @@ -424,6 +519,7 @@ extern HB_EXPORT int hb_parni( int iParam, ... ); /* retrieve a numeric p extern HB_EXPORT long hb_parnl( int iParam, ... ); /* retrieve a numeric parameter as a long */ extern HB_EXPORT HB_LONG hb_parnint( int iParam, ... ); /* retrieve a numeric parameter as a HB_LONG */ extern HB_EXPORT void * hb_parptr( int iParam, ... ); /* retrieve a parameter as a pointer */ +extern HB_EXPORT void * hb_parptrGC( HB_GARBAGE_FUNC_PTR pFunc, int iParam, ... ); /* retrieve a parameter as a pointer if it's a pointer to GC allocated block */ extern HB_EXPORT PHB_ITEM hb_param( int iParam, long lMask ); /* retrieve a generic parameter */ extern HB_EXPORT PHB_ITEM hb_paramError( int iParam ); /* Returns either the generic parameter or a NIL item if param not provided */ extern HB_EXPORT BOOL hb_extIsArray( int iParam ); @@ -525,99 +621,6 @@ extern HB_EXPORT int hb_storptrGC( void * pointer, int iParam, ... ); /* stor extern HB_EXPORT int hb_stornll( LONGLONG lValue, int iParam, ... ); /* stores a long long on a variable by reference */ #endif -extern HB_EXPORT void hb_xinit( void ); /* Initialize fixed memory subsystem */ -extern HB_EXPORT void hb_xexit( void ); /* Deinitialize fixed memory subsystem */ -extern HB_EXPORT void * hb_xalloc( ULONG ulSize ); /* allocates memory, returns NULL on failure */ -extern HB_EXPORT void * hb_xgrab( ULONG ulSize ); /* allocates memory, exits on failure */ -extern HB_EXPORT void hb_xfree( void * pMem ); /* frees memory */ -extern HB_EXPORT void * hb_xrealloc( void * pMem, ULONG ulSize ); /* reallocates memory */ -extern HB_EXPORT ULONG hb_xsize( void * pMem ); /* returns the size of an allocated memory block */ -extern HB_EXPORT ULONG hb_xquery( USHORT uiMode ); /* Query different types of memory information */ - -#ifdef _HB_API_INTERNAL_ -extern void hb_xRefInc( void * pMem ); /* increment reference counter */ -extern BOOL hb_xRefDec( void * pMem ); /* decrement reference counter, return TRUE when 0 reached */ -extern void hb_xRefFree( void * pMem ); /* decrement reference counter and free the block when 0 reached */ -extern HB_COUNTER hb_xRefCount( void * pMem ); /* return number of references */ -extern void * hb_xRefResize( void * pMem, ULONG ulSave, ULONG ulSize ); /* reallocates memory, create copy if reference counter greater then 1 */ - -#if 0 - -/* - * I used this macros only to test some speed overhead, - * They may not be supported in the future so please do - * not create any code which needs them. [druzus] - */ - -#define hb_xRefInc( p ) (++(*HB_COUNTER_PTR( p ))) -#define hb_xRefDec( p ) (--(*HB_COUNTER_PTR( p ))==0) -#define hb_xRefFree( p ) do { \ - if( hb_xRefDec( p ) ) \ - hb_xfree( p ); \ - } while( 0 ) -#define hb_xRefCount( p ) (*HB_COUNTER_PTR( p )) - -#endif - -#endif /* _HB_API_INTERNAL_ */ - -/* #if UINT_MAX == ULONG_MAX */ -/* it fails on 64bit platforms where int has 32 bit and long has 64 bit. - we need these functions only when max(size_t) < max(long) - and only on 16bit platforms, so the below condition seems to be - more reasonable. */ -#if UINT_MAX > USHRT_MAX - /* NOTE: memcpy/memset can work with ULONG data blocks */ - #define hb_xmemcpy memcpy - #define hb_xmemset memset -#else - /* NOTE: otherwise, the hb_xmemcpy and hb_xmemset functions - will be used to copy and/or set ULONG data blocks */ -extern HB_EXPORT void * hb_xmemcpy( void * pDestArg, void * pSourceArg, ULONG ulLen ); /* copy more than memcpy() can */ -extern HB_EXPORT void * hb_xmemset( void * pDestArg, int iFill, ULONG ulLen ); /* set more than memset() can */ -#endif - -/* garbage collector */ -#define HB_GARBAGE_FUNC( hbfunc ) void hbfunc( void * Cargo ) /* callback function for cleaning garbage memory pointer */ -typedef HB_GARBAGE_FUNC( HB_GARBAGE_FUNC_ ); -typedef HB_GARBAGE_FUNC_ * HB_GARBAGE_FUNC_PTR; - -#define HB_GARBAGE_SWEEPER( hbfunc ) BOOL hbfunc( void * Cargo ) /* callback function for cleaning garbage memory pointer */ -typedef HB_GARBAGE_SWEEPER( HB_GARBAGE_SWEEPER_ ); -typedef HB_GARBAGE_SWEEPER_ * HB_GARBAGE_SWEEPER_PTR; - -extern void hb_gcRegisterSweep( HB_GARBAGE_SWEEPER_PTR pSweep, void * Cargo ); - -extern PHB_ITEM hb_gcGripGet( HB_ITEM_PTR pItem ); -extern void hb_gcGripDrop( HB_ITEM_PTR pItem ); - -extern HB_EXPORT void *hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pFunc ); /* allocates a memory controlled by the garbage collector */ -extern void hb_gcFree( void *pAlloc ); /* deallocates a memory allocated by the garbage collector */ -extern void * hb_gcLock( void *pAlloc ); /* do not release passed memory block */ -extern void * hb_gcUnlock( void *pAlloc ); /* passed block is allowed to be released */ -#ifdef _HB_API_INTERNAL_ -extern void hb_gcItemRef( HB_ITEM_PTR pItem ); /* checks if passed item refers passed memory block pointer */ -extern void hb_vmIsLocalRef( void ); /* hvm.c - mark all local variables as used */ -extern void hb_vmIsStaticRef( void ); /* hvm.c - mark all static variables as used */ -extern void hb_memvarsIsMemvarRef( void ); /* memvars.c - mark all memvar variables as used */ -extern void hb_gcReleaseAll( void ); /* release all memory blocks unconditionally */ - -extern void hb_gcRefCheck( void * pBlock ); /* Check if block still cannot be access after destructor execution */ -extern void hb_gcRefInc( void * pAlloc ); /* increment reference counter */ -extern BOOL hb_gcRefDec( void * pAlloc ); /* decrement reference counter, return TRUE when 0 reached */ -extern void hb_gcRefFree( void * pAlloc ); /* decrement reference counter and free the block when 0 reached */ -extern HB_COUNTER hb_gcRefCount( void * pAlloc ); /* return number of references */ - -#if 0 -#define hb_gcRefInc( p ) hb_xRefInc( HB_GC_PTR( p ) ) -#define hb_gcRefDec( p ) hb_xRefDec( HB_GC_PTR( p ) ) -#define hb_gcRefCount( p ) hb_xRefCount( HB_GC_PTR( p ) ) -#endif - -#endif /* _HB_API_INTERNAL_ */ -extern void hb_gcCollect( void ); /* checks if a single memory block can be released */ -extern void hb_gcCollectAll( void ); /* checks if all memory blocks can be released */ - /* array management */ extern HB_EXPORT BOOL hb_arrayNew( PHB_ITEM pItem, ULONG ulLen ); /* creates a new array */ extern HB_EXPORT ULONG hb_arrayLen( PHB_ITEM pArray ); /* retrieves the array len */ diff --git a/harbour/include/hbapiitm.h b/harbour/include/hbapiitm.h index 1f93cc8351..1f028b2f9e 100644 --- a/harbour/include/hbapiitm.h +++ b/harbour/include/hbapiitm.h @@ -95,6 +95,7 @@ extern HB_EXPORT long hb_itemGetNL ( PHB_ITEM pItem ); extern HB_EXPORT HB_LONG hb_itemGetNInt ( PHB_ITEM pItem ); extern HB_EXPORT void hb_itemGetNLen ( PHB_ITEM pItem, int * piWidth, int * piDec ); extern HB_EXPORT void * hb_itemGetPtr ( PHB_ITEM pItem ); +extern HB_EXPORT void * hb_itemGetPtrGC ( PHB_ITEM pItem, HB_GARBAGE_FUNC_PTR pFunc ); extern HB_EXPORT PHB_SYMB hb_itemGetSymbol( PHB_ITEM pItem ); extern HB_EXPORT PHB_ITEM hb_itemNew ( PHB_ITEM pNull ); extern HB_EXPORT void hb_itemInit ( PHB_ITEM pItem ); diff --git a/harbour/include/hbregex.h b/harbour/include/hbregex.h new file mode 100644 index 0000000000..b46c32ffa3 --- /dev/null +++ b/harbour/include/hbregex.h @@ -0,0 +1,132 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * + * + * Copyright 2007 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * 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. + * + */ + +#ifndef HB_REGEX_H_ +#define HB_REGEX_H_ + +#include "hbapi.h" + +#if defined( _HB_REGEX_INTERNAL_ ) + +#if defined( __BORLANDC__ ) +# if __BORLANDC__ >= 0x550 && !defined( HB_PCRE_REGEX_BCC ) +# define HB_PCRE_REGEX_BCC +# endif +#elif defined( OS_UNIX_COMPATIBLE ) && !defined( __WATCOMC__ ) +# if !defined( HB_POSIX_REGEX ) +# define HB_POSIX_REGEX +# endif +#endif + +#if defined( HB_PCRE_REGEX_BCC ) +# include +# include +# if !defined( HB_PCRE_REGEX ) +# define HB_PCRE_REGEX +# endif +#elif defined( HB_PCRE_REGEX ) +# include +# include +#elif defined( HB_POSIX_REGEX ) +# include +#else +# undef _HB_REGEX_INTERNAL_ +#endif + +#endif /* _HB_REGEX_INTERNAL_ */ + +#if defined( _HB_REGEX_INTERNAL_ ) + +typedef struct +{ + regex_t reg; + regmatch_t aMatches[1]; + BOOL fFree; + int iCFlags; + int iEFlags; +} HB_REGEX; +typedef HB_REGEX * PHB_REGEX; + +#ifndef REG_EXTENDED +# define REG_EXTENDED 0x00 +#endif +#ifndef REG_NOSUB +# define REG_NOSUB 0x00 +#endif + +#else + +typedef void * PHB_REGEX; + +#endif /* _HB_REGEX_INTERNAL_ */ + +#define HBREG_ICASE 0x01 +#define HBREG_NEWLINE 0x02 +#define HBREG_NOTBOL 0x04 +#define HBREG_NOTEOL 0x08 +#define HBREG_EXTENDED 0x10 +#define HBREG_NOSUB 0x20 + +#ifndef REGEX_MAX_GROUPS +# define REGEX_MAX_GROUPS 16 +#endif + +HB_EXTERN_BEGIN + +extern HB_EXPORT PHB_REGEX hb_regexCompile( const char *szRegEx, ULONG ulLen, int iFlags ); +extern HB_EXPORT PHB_REGEX hb_regexGet( PHB_ITEM pRegExItm, int iFlags ); +extern HB_EXPORT void hb_regexFree( PHB_REGEX pRegEx ); +extern HB_EXPORT BOOL hb_regexMatch( PHB_REGEX pRegEx, const char *szString, BOOL fFull ); + +HB_EXTERN_END + +#endif /* HB_REGEX_H_ */ diff --git a/harbour/source/common/hbhash.c b/harbour/source/common/hbhash.c index 53a72882d9..f4fb6091d8 100644 --- a/harbour/source/common/hbhash.c +++ b/harbour/source/common/hbhash.c @@ -55,7 +55,7 @@ static HB_HASH_ITEM_PTR hb_hashItemNew( ULONG ulKey, void *pKey, void * pValue ) { HB_HASH_ITEM_PTR pItem = (HB_HASH_ITEM_PTR) hb_xgrab( sizeof( HB_HASH_ITEM ) ); - + pItem->key = ulKey; pItem->KeyPtr = pKey; pItem->ValPtr = pValue; @@ -64,8 +64,10 @@ static HB_HASH_ITEM_PTR hb_hashItemNew( ULONG ulKey, void *pKey, void * pValue ) return pItem; } -static void hb_hashItemDelete( HB_HASH_ITEM_PTR pItem ) +static void hb_hashItemDelete( HB_HASH_TABLE_PTR pTable, HB_HASH_ITEM_PTR pItem ) { + if( pTable->pDeleteItemFunc ) + ( pTable->pDeleteItemFunc )( pTable, pItem->KeyPtr, pItem->ValPtr ); hb_xfree( (void *) pItem ); } @@ -85,16 +87,16 @@ HB_HASH_TABLE_PTR hb_hashTableCreate( ULONG ulSize, HB_HASH_FUNC_PTR pComp ) { HB_HASH_TABLE_PTR pTable = ( HB_HASH_TABLE_PTR ) hb_xgrab( sizeof( HB_HASH_TABLE ) ); - + pTable->ulTableSize = ulSize; pTable->pKeyFunc = pHashFunc; pTable->pDeleteItemFunc = pDelete; pTable->pCompFunc = pComp; pTable->ulCount = pTable->ulUsed = 0; - + pTable->pItems = ( HB_HASH_ITEM_PTR * ) hb_xgrab( sizeof( HB_HASH_ITEM_PTR ) * ulSize ); memset( pTable->pItems, 0, sizeof( HB_HASH_ITEM_PTR ) * ulSize ); - + return pTable; } @@ -108,16 +110,13 @@ void hb_hashTableKill( HB_HASH_TABLE_PTR pTable ) { if( pTable->pItems[ ulSize ] ) { - HB_HASH_ITEM_PTR pItem; - HB_HASH_ITEM_PTR pNext; + HB_HASH_ITEM_PTR pItem, pFree; pItem = pTable->pItems[ ulSize ]; while( pItem ) { - if( pTable->pDeleteItemFunc ) - ( pTable->pDeleteItemFunc )( pTable, pItem->KeyPtr, pItem->ValPtr ); - pNext = pItem->next; - hb_xfree( ( void * ) pItem ); - pItem = pNext; + pFree = pItem; + pItem = pItem->next; + hb_hashItemDelete( pTable, pFree ); } } ++ulSize; @@ -131,26 +130,26 @@ HB_HASH_TABLE_PTR hb_hashTableResize( HB_HASH_TABLE_PTR pTable, ULONG ulNewSize { HB_HASH_TABLE_PTR pNew; ULONG ulSize = 0; - + if( ulNewSize == 0 ) ulNewSize = 2 * pTable->ulTableSize + 1; pNew = hb_hashTableCreate( ulNewSize, - pTable->pKeyFunc, - pTable->pDeleteItemFunc, - pTable->pCompFunc ); - + pTable->pKeyFunc, + pTable->pDeleteItemFunc, + pTable->pCompFunc ); + while( ulSize < pTable->ulTableSize ) { if( pTable->pItems[ ulSize ] ) { HB_HASH_ITEM_PTR pItem; - + pItem = pTable->pItems[ ulSize ]; while( pItem ) { ULONG ulKey; HB_HASH_ITEM_PTR pNewItem, pNext; - + pNext = pItem->next; ulKey = ( pTable->pKeyFunc )( pNew, pItem->KeyPtr, pItem->ValPtr ); pNewItem = pNew->pItems[ ulKey ]; @@ -184,7 +183,7 @@ BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pKey, void *pValue ) { ULONG ulKey; HB_HASH_ITEM_PTR pItem; - + ulKey = ( pTable->pKeyFunc )( pTable, pKey, pValue ); pItem = pTable->pItems[ ulKey ]; if( pItem ) @@ -199,7 +198,7 @@ BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pKey, void *pValue ) ++pTable->ulUsed; } ++pTable->ulCount; - + return TRUE; } @@ -210,14 +209,14 @@ void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pKey ) ULONG ulKey; HB_HASH_ITEM_PTR pItem; void * pFound = NULL; - + ulKey = ( pTable->pKeyFunc )( pTable, pKey, NULL ); pItem = pTable->pItems[ ulKey ]; if( pItem ) { while( pItem && (( pTable->pCompFunc )( pTable, pItem->KeyPtr, pKey ) != 0) ) pItem = pItem->next; - + if( pItem ) pFound = pItem->ValPtr; } @@ -235,11 +234,11 @@ BOOL hb_hashTableDel( HB_HASH_TABLE_PTR pTable, void *pKey ) HB_HASH_ITEM_PTR pItem; HB_HASH_ITEM_PTR pPrev = NULL; BOOL bFound = FALSE; - + ulKey = ( pTable->pKeyFunc )( pTable, pKey, NULL ); if( ulKey > pTable->ulTableSize ) return FALSE; - + pItem = pTable->pItems[ ulKey ]; while( pItem && !bFound ) { @@ -258,12 +257,9 @@ BOOL hb_hashTableDel( HB_HASH_TABLE_PTR pTable, void *pKey ) pTable->pItems[ ulKey ] = NULL; } } - - if( pTable->pDeleteItemFunc ) - ( pTable->pDeleteItemFunc )( pTable, pItem->KeyPtr, pItem->ValPtr ); - hb_hashItemDelete( pItem ); - bFound = TRUE; --pTable->ulCount; + hb_hashItemDelete( pTable, pItem ); + bFound = TRUE; } else { diff --git a/harbour/source/compiler/hbident.c b/harbour/source/compiler/hbident.c index ce4e5e6998..0262915676 100644 --- a/harbour/source/compiler/hbident.c +++ b/harbour/source/compiler/hbident.c @@ -72,7 +72,7 @@ static HB_HASH_FUNC( hb_comp_IdentKey ) /* ULONG func (void *Value, void *Car HB_SYMBOL_UNUSED( HashPtr ); HB_SYMBOL_UNUSED( Cargo ); - + return ulSum % HB_IDENT_TABLE_SIZE; } diff --git a/harbour/source/pp/pplib.c b/harbour/source/pp/pplib.c index e7a6aa1d11..91988a6d19 100644 --- a/harbour/source/pp/pplib.c +++ b/harbour/source/pp/pplib.c @@ -119,9 +119,10 @@ static void hb_pp_StdRules( PHB_PP_STATE pState ) } } -static PHB_PP_STATE hb_pp_Param( int iParam ) +PHB_PP_STATE hb_pp_Param( int iParam ) { - PHB_PP_STATE * pStatePtr = ( PHB_PP_STATE * ) hb_parptr( iParam ); + PHB_PP_STATE * pStatePtr = + ( PHB_PP_STATE * ) hb_parptrGC( hb_pp_Destructor, iParam ); if( pStatePtr ) return * pStatePtr; diff --git a/harbour/source/pp/pplib2.c b/harbour/source/pp/pplib2.c index 968691773d..5d0000d925 100644 --- a/harbour/source/pp/pplib2.c +++ b/harbour/source/pp/pplib2.c @@ -56,12 +56,12 @@ #include "hbpp.h" #include "hbapi.h" +extern PHB_PP_STATE hb_pp_Param( int iParam ); + HB_FUNC( __PP_STDRULES ) { - PHB_PP_STATE * pStatePtr = ( PHB_PP_STATE * ) hb_parptr( 1 ); + PHB_PP_STATE pState = hb_pp_Param( 1 ); - if( pStatePtr && * pStatePtr ) - { - hb_pp_setStdRules( * pStatePtr ); - } + if( pState ) + hb_pp_setStdRules( pState ); } diff --git a/harbour/source/rdd/dbfcdx/dbfcdx1.c b/harbour/source/rdd/dbfcdx/dbfcdx1.c index ff7070234c..0332091d92 100644 --- a/harbour/source/rdd/dbfcdx/dbfcdx1.c +++ b/harbour/source/rdd/dbfcdx/dbfcdx1.c @@ -80,9 +80,7 @@ #include "hbrddcdx.h" #include "hbmath.h" #include "rddsys.ch" -#ifdef __XHARBOUR__ #include "hbregex.h" -#endif #ifndef HB_CDP_SUPPORT_OFF /* for nation sorting support */ @@ -5508,8 +5506,6 @@ static BOOL hb_cdxDBOISkipWild( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, return fFound; } -#if defined(__XHARBOUR__) - static BOOL hb_cdxRegexMatch( CDXAREAP pArea, PHB_REGEX pRegEx, LPCDXKEY pKey ) { char * szKey = ( char * ) pKey->val; @@ -5535,14 +5531,14 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, PHB_ITEM pRegExItm ) { BOOL fFound = FALSE, fFirst = TRUE; - HB_REGEX RegEx; + PHB_REGEX pRegEx; HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipRegEx(%p, %p, %i, %p)", pArea, pTag, fForward, pRegExItm)); if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FALSE; - if( !pTag || pTag->uiType != 'C' || !hb_regexGet( &RegEx, pRegExItm, 0, 0 ) ) + if( !pTag || pTag->uiType != 'C' || ( pRegEx = hb_regexGet( pRegExItm, 0 ) ) == NULL ) { if ( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE ) return FALSE; @@ -5569,12 +5565,12 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, hb_cdxTagSkipNext( pTag ); while ( !pTag->TagEOF ) { - if( hb_cdxRegexMatch( pArea, &RegEx, pTag->CurKey ) ) + if( hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) { ULONG ulRecNo = pArea->ulRecNo; SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); if ( pArea->ulRecNo == ulRecNo || - hb_cdxRegexMatch( pArea, &RegEx, pTag->CurKey ) ) + hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) { fFound = TRUE; break; @@ -5590,12 +5586,12 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, hb_cdxTagSkipPrev( pTag ); while ( !pTag->TagBOF ) { - if( hb_cdxRegexMatch( pArea, &RegEx, pTag->CurKey ) ) + if( hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) { ULONG ulRecNo = pArea->ulRecNo; SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); if ( pArea->ulRecNo == ulRecNo || - hb_cdxRegexMatch( pArea, &RegEx, pTag->CurKey ) ) + hb_cdxRegexMatch( pArea, pRegEx, pTag->CurKey ) ) { fFound = TRUE; break; @@ -5619,11 +5615,10 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, else pArea->fEof = FALSE; - hb_regexFree( &RegEx ); + hb_regexFree( pRegEx ); return fFound; } -#endif /* * evaluate given C function in given scope @@ -7953,7 +7948,6 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO hb_cdxDBOISkipWild( pArea, pTag, FALSE, pOrderInfo->itmNewVal ) ); break; -#if defined(__XHARBOUR__) case DBOI_SKIPREGEX: pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, hb_cdxDBOISkipRegEx( pArea, pTag, TRUE, pOrderInfo->itmNewVal ) ); @@ -7963,7 +7957,6 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, hb_cdxDBOISkipRegEx( pArea, pTag, FALSE, pOrderInfo->itmNewVal ) ); break; -#endif case DBOI_SCOPEEVAL: if ( pTag && pOrderInfo->itmNewVal && diff --git a/harbour/source/rdd/dbfntx/dbfntx1.c b/harbour/source/rdd/dbfntx/dbfntx1.c index dc43fd5600..babdab55d1 100644 --- a/harbour/source/rdd/dbfntx/dbfntx1.c +++ b/harbour/source/rdd/dbfntx/dbfntx1.c @@ -143,9 +143,7 @@ #include "hbmath.h" #include "hbrddntx.h" #include "rddsys.ch" -#ifdef __XHARBOUR__ #include "hbregex.h" -#endif #ifndef HB_CDP_SUPPORT_OFF #include "hbapicdp.h" #endif @@ -4281,8 +4279,6 @@ static BOOL hb_ntxOrdSkipWild( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pWildItm return fFound; } -#if defined(__XHARBOUR__) - static BOOL hb_ntxRegexMatch( LPTAGINFO pTag, PHB_REGEX pRegEx, char * szKey ) { #ifndef HB_CDP_SUPPORT_OFF @@ -4307,11 +4303,11 @@ static BOOL hb_ntxOrdSkipRegEx( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pRegExIt { NTXAREAP pArea = pTag->Owner->Owner; BOOL fFound = FALSE; - HB_REGEX RegEx; + PHB_REGEX pRegEx; HB_TRACE(HB_TR_DEBUG, ("hb_ntxOrdSkipRegEx(%p, %d, %p)", pTag, fForward, pRegExItm)); - if( pTag->KeyType != 'C' || !hb_regexGet( &RegEx, pRegExItm, 0, 0 ) ) + if( pTag->KeyType != 'C' || ( pRegEx = hb_regexGet( pRegExItm, 0 ) ) == NULL ) { if( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) != SUCCESS ) return FALSE; @@ -4341,12 +4337,12 @@ static BOOL hb_ntxOrdSkipRegEx( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pRegExIt if( SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ) != SUCCESS ) break; - if( hb_ntxRegexMatch( pTag, &RegEx, ( char * ) pTag->CurKeyInfo->key ) ) + if( hb_ntxRegexMatch( pTag, pRegEx, ( char * ) pTag->CurKeyInfo->key ) ) { ULONG ulRecNo = pArea->ulRecNo; if( SELF_SKIPFILTER( ( AREAP ) pArea, fForward ? 1 : -1 ) != SUCCESS || pArea->ulRecNo == ulRecNo || - hb_ntxRegexMatch( pTag, &RegEx, ( char * ) pTag->CurKeyInfo->key ) ) + hb_ntxRegexMatch( pTag, pRegEx, ( char * ) pTag->CurKeyInfo->key ) ) { fFound = TRUE; break; @@ -4378,11 +4374,10 @@ static BOOL hb_ntxOrdSkipRegEx( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pRegExIt else pArea->fEof = FALSE; - hb_regexFree( &RegEx ); + hb_regexFree( pRegEx ); return fFound; } -#endif /* * add key to custom tag (ordKeyAdd()) @@ -6945,13 +6940,11 @@ static ERRCODE ntxOrderInfo( NTXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipWild( pTag, uiIndex == DBOI_SKIPWILD, pInfo->itmNewVal ) ); break; -#if defined(__XHARBOUR__) case DBOI_SKIPREGEX: case DBOI_SKIPREGEXBACK: hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipRegEx( pTag, uiIndex == DBOI_SKIPREGEX, pInfo->itmNewVal ) ); break; -#endif case DBOI_FINDREC: case DBOI_FINDRECCONT: hb_itemPutL( pInfo->itmResult, hb_ntxOrdFindRec( pTag, diff --git a/harbour/source/rtl/Makefile b/harbour/source/rtl/Makefile index 4dfe361bc1..19eea0d3de 100644 --- a/harbour/source/rtl/Makefile +++ b/harbour/source/rtl/Makefile @@ -51,6 +51,7 @@ C_SOURCES=\ hbffind.c \ hbgtcore.c \ hbrandom.c \ + hbregex.c \ idle.c \ inkey.c \ is.c \ diff --git a/harbour/source/rtl/hbregex.c b/harbour/source/rtl/hbregex.c new file mode 100644 index 0000000000..bd86e81ed3 --- /dev/null +++ b/harbour/source/rtl/hbregex.c @@ -0,0 +1,559 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * + * + * Copyright 2007 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * 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. + * + */ + +/* #define HB_PCRE_REGEX */ + +#define _HB_REGEX_INTERNAL_ +#include "hbregex.h" +#include "hbapiitm.h" +#include "hbapierr.h" + +/* This releases regex when called from the garbage collector */ +static HB_GARBAGE_FUNC( hb_regexRelease ) +{ +#ifdef _HB_REGEX_INTERNAL_ + PHB_REGEX pRegEx = ( PHB_REGEX ) Cargo; + regfree( &pRegEx->reg ); +#else + HB_SYMBOL_UNUSED( Cargo ); +#endif +} + +PHB_REGEX hb_regexCompile( const char *szRegEx, ULONG ulLen, int iFlags ) +{ +#ifdef _HB_REGEX_INTERNAL_ + PHB_REGEX pRegEx; + + HB_SYMBOL_UNUSED( ulLen ); + + pRegEx = ( PHB_REGEX ) hb_gcAlloc( sizeof( HB_REGEX ), hb_regexRelease ); + hb_gcLock( pRegEx ); + memset( pRegEx, 0, sizeof( HB_REGEX ) ); + pRegEx->fFree = TRUE; + pRegEx->iCFlags = REG_EXTENDED | + ( ( iFlags & HBREG_ICASE ) ? REG_ICASE : 0 ) | + ( ( iFlags & HBREG_NEWLINE ) ? REG_NEWLINE : 0 ) | + ( ( iFlags & HBREG_NOSUB ) ? REG_NOSUB : 0 ); + pRegEx->iEFlags = ( ( iFlags & HBREG_NOTBOL ) ? REG_NOTBOL : 0 ) | + ( ( iFlags & HBREG_NOTEOL ) ? REG_NOTBOL : 0 ); + + if( regcomp( &pRegEx->reg, szRegEx, pRegEx->iCFlags ) != 0 ) + { + hb_gcFree( pRegEx ); + pRegEx = NULL; + } + + return pRegEx; + +#else + HB_SYMBOL_UNUSED( szRegEx ); + HB_SYMBOL_UNUSED( ulLen ); + HB_SYMBOL_UNUSED( iFlags ); + + return NULL; +#endif +} + +PHB_REGEX hb_regexGet( PHB_ITEM pRegExItm, int iFlags ) +{ + PHB_REGEX pRegEx = NULL; + + if( pRegExItm ) + { + if( HB_IS_POINTER( pRegExItm ) ) + { + pRegEx = ( PHB_REGEX ) hb_itemGetPtrGC( pRegExItm, hb_regexRelease ); + } + else if( HB_IS_STRING( pRegExItm ) ) + { + ULONG ulLen = hb_itemGetCLen( pRegExItm ); + char * szRegEx = hb_itemGetCPtr( pRegExItm ); + if( ulLen > 0 ) + pRegEx = hb_regexCompile( szRegEx, ulLen, iFlags ); + } + } + + if( !pRegEx ) + hb_errRT_BASE_SubstR( EG_ARG, 3012, "Invalid Regular expression", &hb_errFuncName, 1, pRegExItm ); + + return pRegEx; +} + +void hb_regexFree( PHB_REGEX pRegEx ) +{ +#ifdef _HB_REGEX_INTERNAL_ + if( pRegEx && pRegEx->fFree ) + { + regfree( &pRegEx->reg ); + hb_gcFree( pRegEx ); + } +#else + HB_SYMBOL_UNUSED( pRegEx ); +#endif +} + +BOOL hb_regexMatch( PHB_REGEX pRegEx, const char *szString, BOOL fFull ) +{ +#ifdef _HB_REGEX_INTERNAL_ + BOOL fMatch; + + fMatch = regexec( &pRegEx->reg, szString, 1, pRegEx->aMatches, pRegEx->iEFlags ) == 0; + + return fMatch && ( !fFull || + ( pRegEx->aMatches[0].rm_so == 0 && + pRegEx->aMatches[0].rm_eo == (int) strlen( szString ) ) ); +#else + HB_SYMBOL_UNUSED( pRegEx ); + HB_SYMBOL_UNUSED( szString ); + HB_SYMBOL_UNUSED( fFull ); + return FALSE; +#endif +} + + +HB_FUNC( HB_REGEXCOMP ) +{ +#ifdef _HB_REGEX_INTERNAL_ + ULONG ulLen = hb_parclen( 1 ); + + if( ulLen == 0 ) + hb_errRT_BASE_SubstR( EG_ARG, 3012, "Wrong parameter count/type", + &hb_errFuncName, HB_ERR_ARGS_BASEPARAMS ); + else + { + int iFlags = HBREG_EXTENDED; + PHB_REGEX pRegEx; + + if( ISLOG( 2 ) && !hb_parl( 2 ) ) + iFlags |= HBREG_ICASE; + if( hb_parl( 3 ) ) + iFlags |= HBREG_NEWLINE; + + pRegEx = hb_regexCompile( hb_parc( 1 ), ulLen, iFlags ); + if( pRegEx ) + { + pRegEx->fFree = FALSE; + hb_retptrGC( pRegEx ); + hb_gcUnlock( pRegEx ); + } + } +#endif +} + +HB_FUNC( HB_ISREGEX ) +{ + hb_retl( hb_parptrGC( hb_regexRelease, 1 ) != NULL ); +} + +HB_FUNC( HB_ATX ) +{ +#ifdef _HB_REGEX_INTERNAL_ + char * pszString, * pszCopy = NULL; + ULONG ulLen, ulStart, ulEnd; + regmatch_t aMatches[ 1 ]; + PHB_REGEX pRegEx; + PHB_ITEM pString; + int iPCount = hb_pcount(); + + pString = hb_param( 2, HB_IT_STRING ); + if( !pString ) + { + hb_errRT_BASE_SubstR( EG_ARG, 3012, "Wrong parameters", + &hb_errFuncName, HB_ERR_ARGS_BASEPARAMS ); + return; + } + pszString = hb_itemGetCPtr( pString ); + ulLen = hb_itemGetCLen( pString ); + pRegEx = hb_regexGet( hb_param( 1, HB_IT_ANY ), + ISLOG( 3 ) && !hb_parl( 3 ) ? HBREG_ICASE : 0 ); + if( !pRegEx ) + return; + + ulStart = hb_parnl( 4 ); + ulEnd = hb_parnl( 5 ); + + if( ulLen && ulStart <= ulLen && ulStart <= ulEnd ) + { + if( ulEnd > 0 && ulEnd < ulLen && pszString[ ulEnd ] != 0 ) + { + if( ulStart > 1 ) + { + pszString += ulStart - 1; + ulEnd -= ulStart - 1; + } + pszCopy = ( char * ) hb_xgrab( ulEnd + 1 ); + memcpy( pszCopy, pszString, ulEnd ); + pszCopy[ ulEnd ] = '\0'; + pszString = pszCopy; + } + + if( regexec( &pRegEx->reg, pszString, 1, aMatches, 0 ) == 0 ) + { + ulStart = aMatches[0].rm_so + 1; + ulLen = aMatches[0].rm_eo - aMatches[0].rm_so; + hb_retclen( pszString + aMatches[0].rm_so, ulLen ); + } + else + ulStart = ulLen = 0; + } + else + ulStart = ulLen = 0; + + hb_regexFree( pRegEx ); + if( pszCopy ) + hb_xfree( pszCopy ); + + if( iPCount > 3 ) + { + hb_stornl( ulStart, 4 ); + if( iPCount > 4 ) + hb_stornl( ulLen, 5 ); + } +#endif +} + +static BOOL hb_regex( int iRequest ) +{ +#ifdef _HB_REGEX_INTERNAL_ + regmatch_t aMatches[ REGEX_MAX_GROUPS ]; + PHB_ITEM pRetArray, pMatch, pString; + int i, iMatches, iMaxMatch; + BOOL fResult = FALSE; + PHB_REGEX pRegEx; + char * pszString; + ULONG ulLen; + + pString = hb_param( 2, HB_IT_STRING ); + if( !pString ) + { + hb_errRT_BASE_SubstR( EG_ARG, 3012, "Wrong parameters", + &hb_errFuncName, HB_ERR_ARGS_BASEPARAMS ); + return FALSE; + } + pRegEx = hb_regexGet( hb_param( 1, HB_IT_ANY ), + ( ISLOG( 3 ) && !hb_parl( 3 ) ? HBREG_ICASE : 0 ) | + ( hb_parl( 4 ) ? HBREG_NEWLINE : 0 ) ); + if( !pRegEx ) + return FALSE; + + pszString = hb_itemGetCPtr( pString ); + ulLen = hb_itemGetCLen( pString ); + iMatches = 0; + iMaxMatch = iRequest == 0 || iRequest == 4 || iRequest == 5 ? + REGEX_MAX_GROUPS : 1; + aMatches[0].rm_so = 0; + aMatches[0].rm_eo = ulLen; + if( regexec( &pRegEx->reg, pszString, iMaxMatch, aMatches, 0 ) == 0 ) + { + switch ( iRequest ) + { + case 0: + /* Count sucessful matches */ + for( i = 0; i < iMaxMatch; i++ ) + { + if( aMatches[i].rm_eo != -1 ) + iMatches = i; + } + iMatches++; + pRetArray = hb_itemArrayNew( iMatches ); + for( i = 0; i < iMatches; i++ ) + { + if( aMatches[i].rm_eo > -1 ) + hb_itemPutCL( hb_arrayGetItemPtr( pRetArray, i + 1 ), + pszString + aMatches[i].rm_so, + aMatches[i].rm_eo - aMatches[i].rm_so ); + else + hb_itemPutCL( hb_arrayGetItemPtr( pRetArray, i + 1 ), "", 0 ); + } + hb_itemRelease( hb_itemReturnForward( pRetArray ) ); + fResult = TRUE; + break; + + case 1: /* LIKE */ + fResult = aMatches[0].rm_so == 0 && + ( ULONG ) aMatches[0].rm_eo == ulLen; + break; + + case 2: /* MATCH */ + fResult = TRUE; + break; + + case 3: /* SPLIT */ + iMaxMatch = hb_parni( 5 ); + pRetArray = hb_itemArrayNew( 0 ); + pMatch = hb_itemNew( NULL ); + do + { + hb_itemPutCL( pMatch, pszString, aMatches[0].rm_so ); + hb_arrayAddForward( pRetArray, pMatch ); + ulLen -= aMatches[0].rm_eo; + pszString += aMatches[ 0 ].rm_eo; + iMatches++; + } + while( aMatches[0].rm_eo && ulLen && ( iMaxMatch == 0 || iMatches < iMaxMatch ) && + regexec( &pRegEx->reg, pszString, 1, aMatches, 0 ) == 0 ); + + /* last match must be done also in case that pszString is empty; + this would mean an empty split field at the end of the string */ + /* if( ulLen ) */ + { + hb_itemPutCL( pMatch, pszString, ulLen ); + hb_arrayAddForward( pRetArray, pMatch ); + } + hb_itemRelease( pMatch ); + + hb_itemRelease( hb_itemReturnForward( pRetArray ) ); + fResult = TRUE; + break; + + case 4: /* results AND positions */ + /* Count sucessful matches */ + for( i = 0; i < iMaxMatch; i++ ) + { + if( aMatches[i].rm_eo != -1 ) + iMatches = i; + } + iMatches++; + pRetArray = hb_itemArrayNew( iMatches ); + + for( i = 0; i < iMatches; i++ ) + { + pMatch = hb_arrayGetItemPtr( pRetArray, i + 1 ); + hb_arrayNew( pMatch, 3 ); + if ( aMatches[i].rm_eo != -1 ) + { + /* matched string */ + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), pszString + aMatches[i].rm_so, aMatches[i].rm_eo - aMatches[i].rm_so ); + /* begin of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), aMatches[i].rm_so + 1 ); + /* End of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), aMatches[i].rm_eo ); + } + else + { + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), "", 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), 0 ); + } + } + hb_itemRelease( hb_itemReturnForward( pRetArray ) ); + fResult = TRUE; + break; + + case 5: /* _ALL_ results AND positions */ + { + PHB_ITEM pAtxArray; + int iMax = hb_parni( 5 ); /* max nuber of matches I want, 0 = unlimited */ + int iGetMatch = hb_parni( 6 ); /* Gets if want only one single match or a sub-match */ + BOOL fOnlyMatch = !ISLOG( 7 ) || hb_parl( 7 ); /* if TRUE returns only matches and sub-matches, not positions */ + ULONG ulOffSet = 0; + int iCount = 0; + + /* Set new array */ + pRetArray = hb_itemArrayNew( 0 ); + do + { + /* Count sucessful matches */ + for( i = 0; i < iMaxMatch; i++ ) + { + if( aMatches[i].rm_eo != -1 ) + iMatches = i; + } + iMatches++; + + /* If I want all matches */ + if( iGetMatch == 0 || // Check boundaries + ( iGetMatch < 0 || iGetMatch > iMatches ) ) + { + pAtxArray = hb_itemArrayNew( iMatches ); + for( i = 0; i < iMatches; i++ ) + { + pMatch = hb_arrayGetItemPtr( pAtxArray, i + 1 ); + if( !fOnlyMatch ) + { + hb_arrayNew( pMatch, 3 ); + if ( aMatches[i].rm_eo != -1 ) + { + /* matched string */ + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), pszString + aMatches[i].rm_so, aMatches[i].rm_eo - aMatches[i].rm_so ); + /* begin of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), ulOffSet + aMatches[i].rm_so + 1 ); + /* End of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), ulOffSet + aMatches[i].rm_eo ); + } + else + { + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), "", 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), 0 ); + } + } + else + { + if( aMatches[i].rm_eo != -1 ) + /* matched string */ + hb_itemPutCL( pMatch, pszString + aMatches[i].rm_so, aMatches[i].rm_eo - aMatches[i].rm_so ); + else + hb_itemPutCL( pMatch, "", 0 ); + } + } + hb_arrayAddForward( pRetArray, pAtxArray ); + hb_itemRelease( pAtxArray ); + } + else /* Here I get only single matches */ + { + i = iGetMatch - 1; + pMatch = hb_itemNew( NULL ); + if( !fOnlyMatch ) + { + hb_arrayNew( pMatch, 3 ); + if( aMatches[i].rm_eo != -1 ) + { + /* matched string */ + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), pszString + aMatches[i].rm_so, aMatches[i].rm_eo - aMatches[i].rm_so ); + /* begin of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), ulOffSet + aMatches[i].rm_so + 1 ); + /* End of match */ + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), ulOffSet + aMatches[i].rm_eo ); + } + else + { + hb_itemPutCL( hb_arrayGetItemPtr( pMatch, 1 ), "", 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 2 ), 0 ); + hb_itemPutNI( hb_arrayGetItemPtr( pMatch, 3 ), 0 ); + } + } + else + { + if( aMatches[i].rm_eo != -1 ) + /* matched string */ + hb_itemPutCL( pMatch, pszString + aMatches[i].rm_so, aMatches[i].rm_eo - aMatches[i].rm_so ); + else + hb_itemPutCL( pMatch, "", 0 ); + } + hb_arrayAddForward( pRetArray, pMatch ); + hb_itemRelease( pMatch ); + } + + ulLen -= aMatches[0].rm_eo; + pszString += aMatches[ 0 ].rm_eo; + ulOffSet += aMatches[0].rm_eo; + iCount++; + } + while( aMatches[0].rm_eo && ulLen && ( iMax == 0 || iCount < iMax ) && + regexec( &pRegEx->reg, pszString, iMaxMatch, aMatches, 0 ) == 0 ); + hb_itemRelease( hb_itemReturnForward( pRetArray ) ); + fResult = TRUE; + break; + } + } + } + else if( iRequest == 3 ) + { + pRetArray = hb_itemArrayNew( 1 ); + hb_arraySet( pRetArray, 1, pString ); + hb_itemRelease( hb_itemReturnForward( pRetArray ) ); + fResult = TRUE; + } + + hb_regexFree( pRegEx ); + return fResult; +#else + HB_SYMBOL_UNUSED( iRequest ); + return FALSE; +#endif +} + +/* Returns array of Match + Sub-Matches. */ +HB_FUNC( HB_REGEX ) +{ + hb_regex( 0 ); +} + +/* Returns just .T. if match found or .F. otherwise. */ +HB_FUNC( HB_REGEXMATCH ) +{ + hb_retl( hb_regex( hb_parl( 3 ) ? 1 : 2 ) ); +} + +/* Splits the string in an array of matched expressions */ +HB_FUNC( HB_REGEXSPLIT ) +{ + hb_regex( 3 ); +} + +/* Returns array of { Match, start, end }, { Sub-Matches, start, end } */ +HB_FUNC( HB_REGEXATX ) +{ + hb_regex( 4 ); +} + +/* 2005-12-16 - Francesco Saverio Giudice + HB_RegExAll( cRegex, cString, lCaseSensitive, lNewLine, nMaxMatches, nGetMatch, lOnlyMatch ) -> aAllRegexMatches + + This function return all matches from a Regex search. + It is a mix from hb_RegEx() and hb_RegExAtX() + + PARAMETERS: + cRegex - Regex pattern string or precompiled Regex + cString - The string you want to search + lCaseSensitive - default = FALSE + lNewLine - default = FALSE + nMaxMatches - default = unlimited, this limit number of matches that have to return + nGetMatch - default = unlimited, this returns only one from Match + Sub-Matches + lOnlyMatch - default = TRUE, if TRUE returns Matches, otherwise it returns also start and end positions + */ + +HB_FUNC( HB_REGEXALL ) +{ + hb_regex( 5 ); +} diff --git a/harbour/source/vm/extend.c b/harbour/source/vm/extend.c index 3d03f27075..7f9770a53e 100644 --- a/harbour/source/vm/extend.c +++ b/harbour/source/vm/extend.c @@ -621,6 +621,43 @@ HB_EXPORT void * hb_parptr( int iParam, ... ) return NULL; } +HB_EXPORT void * hb_parptrGC( HB_GARBAGE_FUNC_PTR pFunc, int iParam, ... ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_parptrGC(%p,%d, ...)", pFunc, iParam)); + + if( ( iParam >= 0 && iParam <= hb_pcount() ) || ( iParam == -1 ) ) + { + PHB_ITEM pItem = ( iParam == -1 ) ? hb_stackReturnItem() : hb_stackItemFromBase( iParam ); + + if( HB_IS_BYREF( pItem ) ) + pItem = hb_itemUnRef( pItem ); + + if( HB_IS_POINTER( pItem ) ) + { + if( pItem->item.asPointer.collect && + hb_gcFunc( pItem->item.asPointer.value ) == pFunc ) + return pItem->item.asPointer.value; + } + else if( HB_IS_ARRAY( pItem ) ) + { + va_list va; + ULONG ulArrayIndex; + + va_start( va, iParam ); + ulArrayIndex = va_arg( va, ULONG ); + va_end( va ); + + pItem = hb_arrayGetItemPtr( pItem, ulArrayIndex ); + if( pItem && HB_IS_POINTER( pItem ) && + pItem->item.asPointer.collect && + hb_gcFunc( pItem->item.asPointer.value ) == pFunc ) + return pItem->item.asPointer.value; + } + } + + return NULL; +} + HB_EXPORT ULONG hb_parinfa( int iParamNum, ULONG uiArrayIndex ) { PHB_ITEM pArray; diff --git a/harbour/source/vm/garbage.c b/harbour/source/vm/garbage.c index 8934e84845..2a8e2ec851 100644 --- a/harbour/source/vm/garbage.c +++ b/harbour/source/vm/garbage.c @@ -206,6 +206,12 @@ void hb_gcFree( void *pBlock ) } } +/* return cleanup function pointer */ +HB_GARBAGE_FUNC_PTR hb_gcFunc( void *pBlock ) +{ + return HB_GC_PTR( pBlock )->pFunc; +} + /* increment reference counter */ #undef hb_gcRefInc void hb_gcRefInc( void * pBlock ) diff --git a/harbour/source/vm/itemapi.c b/harbour/source/vm/itemapi.c index 246728dc21..e626ef5928 100644 --- a/harbour/source/vm/itemapi.c +++ b/harbour/source/vm/itemapi.c @@ -603,6 +603,18 @@ HB_EXPORT void * hb_itemGetPtr( PHB_ITEM pItem ) return NULL; } +HB_EXPORT void * hb_itemGetPtrGC( PHB_ITEM pItem, HB_GARBAGE_FUNC_PTR pFunc ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_itemGetPtrGC(%p,%p)", pItem, pFunc)); + + if( pItem && HB_IS_POINTER( pItem ) && + pItem->item.asPointer.collect && + hb_gcFunc( pItem->item.asPointer.value ) == pFunc ) + return pItem->item.asPointer.value; + else + return NULL; +} + HB_EXPORT PHB_SYMB hb_itemGetSymbol( PHB_ITEM pItem ) { HB_TRACE(HB_TR_DEBUG, ("hb_itemGetSymbol(%p)", pItem));