diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 569bdf10c0..7ce029d188 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,30 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-01-21 01:09 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/contrib/hbnetio/netiocli.c + * harbour/contrib/hbnetio/readme.txt + + added new client side function: + NETIO_DECODE( [@], [@], [@], [@], ; + [@], [@], [@] ) + -> + Decode connection parameters from and default settings. + Return .T. if contains any connection settings. + should not contain "net:" prefix. + + * harbour/src/rtl/itemseri.c + + added support for hash array flags and default value serialization + Warning: before this modification hash arrays were always restored + with binary sorting with default auto assign setting and + without any default value and resorted if necessary. Now + only non binary hash arrays are resorted what may cause + problems for hash arrays not using binary sorting serialized + by old code and restored by the current one. In such case + it's necessary to restore original flags manually using + hb_h*() functions to force resorting. + - removed my TODO note: + "extended hash format with default value and hash flags" + 2010-01-21 00:52 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) * INSTALL + Added new item to TROUBLESHOOTING section describing diff --git a/harbour/contrib/hbnetio/netiocli.c b/harbour/contrib/hbnetio/netiocli.c index 3a962f4283..9fbbc0c9b5 100644 --- a/harbour/contrib/hbnetio/netiocli.c +++ b/harbour/contrib/hbnetio/netiocli.c @@ -8,14 +8,17 @@ * very simple TCP/IP file server with RPC support * All files which names starts 'net:' are redirected to this API. * This is client code with - * NETIO_CONNECT( [], [], [], + * NETIO_CONNECT( [], [], [], * [], [], [] ) * -> * function which register alternative RDD IO API, sets server * address and port and connection timeout parameter. * Then it tries to connect to the server and returns .T. on success. * This code also provides the following .prg functions: - * NETIO_DISCONNECT( [], [] ) -> + * NETIO_DISCONNECT( [], [] ) -> + * NETIO_DECODE( [@], [@], [@], [@], + * [@], [@], [@] ) + * -> * NETIO_PROCEXISTS( ) -> * NETIO_PROCEXEC( [, ] ) -> * NETIO_PROCEXECW( [, ] ) -> @@ -399,7 +402,114 @@ static void s_fileGetConnParam( const char ** pszServer, int * piPort, int * piT } } -static PHB_CONCLI s_fileConnect( const char ** pszFilename, +static const char * s_fileDecode( const char * pszFilename, + char * buffer, const char ** pServer, + int * piPort, int * piTimeOut, + const char ** pPasswd, int * piPassLen, + int * piLevel, int * piStrategy ) +{ + HB_SYMBOL_UNUSED( piTimeOut ); + HB_SYMBOL_UNUSED( piLevel ); + HB_SYMBOL_UNUSED( piStrategy ); + + if( pszFilename ) + { + /* decode server address and port if given as part of file name + * in format like: + * "192.168.0.1:2941:path/to/file" + * or: + * "192.168.0.1:2941:passwd:path/to/file" + * or: + * "//192.168.0.1:2941/path/to/file" + */ + const char * psz, * pth = NULL; + + if( ( pszFilename[ 0 ] == '/' || pszFilename[ 0 ] == '\\' ) && + pszFilename[ 0 ] == pszFilename[ 1 ] ) + { + pszFilename += 2; + pth = strchr( pszFilename, '/' ); + psz = strchr( pszFilename, '\\' ); + if( !pth || ( psz && psz < pth ) ) + { + pth = psz; + if( !pth ) + pth = pszFilename + strlen( pszFilename ); + } + } + + psz = strchr( pszFilename, ':' ); + if( pth && ( !psz || pth < psz ) ) + psz = pth; + + if( psz ) + { + int iLen = ( int ) ( psz - pszFilename ); + + if( pth || iLen == 0 || iLen > 1 ) + { + char port_buf[ 10 ], c; + + if( iLen >= NETIO_SERVERNAME_MAX ) + iLen = NETIO_SERVERNAME_MAX - 1; + if( iLen > 0 ) + { + hb_strncpy( buffer, pszFilename, iLen ); + *pServer = buffer; + } + pszFilename = psz + 1; + if( !pth || psz < pth ) + { + iLen = 0; + while( HB_ISDIGIT( pszFilename[ iLen ] ) && + iLen < ( int ) sizeof( port_buf ) - 1 ) + { + port_buf[ iLen ] = pszFilename[ iLen ]; + ++iLen; + } + c = pszFilename[ iLen ]; + if( c == ':' || c == '/' || c == '\\' ) + { + if( iLen > 0 ) + { + int iOverflow; + HB_LONG llPort; + + port_buf[ iLen ] = '\0'; + llPort = hb_strValInt( port_buf, &iOverflow ); + + if( !iOverflow && llPort > 0 && llPort < 0x10000 ) + { + pszFilename += iLen; + *piPort = ( int ) llPort; + } + } + if( c == ':' ) + { + ++pszFilename; + iLen = 0; + while( pszFilename[ iLen ] && + pszFilename[ iLen ] != ':' ) + ++iLen; + if( pszFilename[ iLen ] == ':' ) + { + *pPasswd = pszFilename; + pszFilename += iLen + 1; + if( iLen > NETIO_PASSWD_MAX ) + iLen = NETIO_PASSWD_MAX; + *piPassLen = iLen; + } + } + } + } + } + } + } + + return pszFilename; +} + +static PHB_CONCLI s_fileConnect( const char ** pFilename, const char * pszServer, int iPort, int iTimeOut, const char * pszPasswd, int iPassLen, @@ -412,89 +522,10 @@ static PHB_CONCLI s_fileConnect( const char ** pszFilename, s_fileGetConnParam( &pszServer, &iPort, &iTimeOut, &pszPasswd, &iPassLen ); - if( pszFilename ) - { - /* decode server address and port if given as part of file name - * in format like: - * "192.168.0.1:2941:path/to/file" - * or: - * "192.168.0.1:2941:passwd:path/to/file" - * or: - * "//192.168.0.1:2941/path/to/file" - */ - const char * psz, * tmp; - - if( ( ( *pszFilename )[ 0 ] == '/' || ( *pszFilename )[ 0 ] == '\\' ) && - ( *pszFilename )[ 0 ] == ( *pszFilename )[ 1 ] ) - { - *pszFilename += 2; - psz = strchr( *pszFilename, '/' ); - tmp = strchr( *pszFilename, '\\' ); - if( tmp < psz ) - psz = tmp; - } - else - psz = strchr( *pszFilename, ':' ); - - if( psz ) - { - int iLen = ( int ) ( psz - *pszFilename ); - - if( iLen == 0 || iLen > 1 ) - { - char port_buf[ 10 ], c; - if( iLen >= ( int ) sizeof( server ) ) - iLen = ( int ) sizeof( server ) - 1; - if( iLen > 0 ) - { - hb_strncpy( server, *pszFilename, iLen ); - pszServer = server; - } - *pszFilename = psz + 1; - iLen = 0; - while( HB_ISDIGIT( ( *pszFilename )[ iLen ] ) && - iLen < ( int ) sizeof( port_buf ) - 1 ) - { - port_buf[ iLen ] = ( *pszFilename )[ iLen ]; - ++iLen; - } - c = ( *pszFilename )[ iLen ]; - if( c == ':' || c == '/' || c == '\\' ) - { - if( iLen > 0 ) - { - int iOverflow; - HB_LONG llPort; - - port_buf[ iLen ] = '\0'; - llPort = hb_strValInt( port_buf, &iOverflow ); - - if( !iOverflow && llPort > 0 && llPort < 0x10000 ) - { - *pszFilename += iLen; - iPort = ( int ) llPort; - } - } - if( c == ':' ) - { - ++( *pszFilename ); - iLen = 0; - while( ( *pszFilename )[ iLen ] && - ( *pszFilename )[ iLen ] != ':' ) - ++iLen; - if( ( *pszFilename )[ iLen ] == ':' ) - { - pszPasswd = *pszFilename; - *pszFilename += iLen + 1; - iPassLen = iLen; - if( iPassLen > NETIO_PASSWD_MAX ) - iPassLen = NETIO_PASSWD_MAX; - } - } - } - } - } - } + if( pFilename ) + *pFilename = s_fileDecode( *pFilename, server, + &pszServer, &iPort, &iTimeOut, + &pszPasswd, &iPassLen, &iLevel, &iStrategy ); if( iLevel == HB_ZLIB_COMPRESSION_DISABLE && iPassLen ) iLevel = HB_ZLIB_COMPRESSION_DEFAULT; @@ -618,7 +649,55 @@ static void s_netio_init( void * cargo ) } } -/* NETIO_CONNECT( [], [], [], ; +/* NETIO_DECODE( [@], [@], [@], [@], ; + * [@], [@], [@] ) -> + */ +HB_FUNC( NETIO_DECODE ) +{ + char server[ NETIO_SERVERNAME_MAX ]; + const char * pszFullName = hb_parc( 1 ); + const char * pszServer, * pszPasswd, * pszFile; + int iPort, iTimeOut, iPassLen, iLevel, iStrategy; + HB_BOOL fResult = FALSE; + + pszServer = NULL; + pszPasswd = NULL; + iPort = iTimeOut = iPassLen = 0; + iLevel = HB_ZLIB_COMPRESSION_DISABLE; + iStrategy = HB_ZLIB_STRATEGY_DEFAULT; + + s_fileGetConnParam( &pszServer, &iPort, &iTimeOut, &pszPasswd, &iPassLen ); + + pszFile = s_fileDecode( pszFullName, server, + &pszServer, &iPort, &iTimeOut, + &pszPasswd, &iPassLen, &iLevel, &iStrategy ); + + if( iLevel == HB_ZLIB_COMPRESSION_DISABLE && iPassLen ) + iLevel = HB_ZLIB_COMPRESSION_DEFAULT; + + hb_storc( pszServer, 2 ); + hb_storni( iPort, 3 ); + hb_storni( iTimeOut, 4 ); + hb_storclen( pszPasswd, iPassLen, 5 ); + hb_storni( iLevel, 6 ); + hb_storni( iStrategy, 7 ); + + fResult = pszFile != pszFullName; + if( fResult && HB_ISBYREF( 1 ) ) + { + if( * pszFile ) + { + char * pszFileName = hb_strdup( pszFile ); + if( !hb_storclen_buffer( pszFileName, strlen( pszFileName ), 1 ) ) + hb_xfree( pszFileName ); + } + else + hb_storc( NULL, 1 ); + } + hb_retl( fResult ); +} + +/* NETIO_CONNECT( [], [], [], ; * [], [], [] ) -> */ HB_FUNC( NETIO_CONNECT ) @@ -658,7 +737,7 @@ HB_FUNC( NETIO_CONNECT ) hb_retl( conn != NULL ); } -/* NETIO_DISCONNECT( [], [] ) -> +/* NETIO_DISCONNECT( [], [] ) -> */ HB_FUNC( NETIO_DISCONNECT ) { diff --git a/harbour/contrib/hbnetio/readme.txt b/harbour/contrib/hbnetio/readme.txt index 8dc14a00ff..2f0cb36fcc 100644 --- a/harbour/contrib/hbnetio/readme.txt +++ b/harbour/contrib/hbnetio/readme.txt @@ -14,7 +14,7 @@ RDDs with name starting with "net:" are redirected to the hbnetio server. Client side functions: ====================== - NETIO_CONNECT( [], [], [], ; + NETIO_CONNECT( [], [], [], ; [], [], [] ) -> Register HBNETIO as alternative RDD IO API redirecting all files @@ -59,10 +59,17 @@ Client side functions: given then default connection is chosen. - NETIO_DISCONNECT( [], [] ) -> + NETIO_DISCONNECT( [], [] ) -> Close the connection created by NETIO_CONNECT() + NETIO_DECODE( [@], [@], [@], [@], ; + [@], [@], [@] ) + -> + Decode connection parameters from and default settings. + Return .T. if contains any connection settings. + should not contain "net:" prefix. + NETIO_PROCEXISTS( ) -> Check if function or procedure exists on the server side. diff --git a/harbour/src/rtl/itemseri.c b/harbour/src/rtl/itemseri.c index aceaaae762..e935c2c7c2 100644 --- a/harbour/src/rtl/itemseri.c +++ b/harbour/src/rtl/itemseri.c @@ -56,10 +56,6 @@ #include "hbapicdp.h" -/* -TODO: extended hash format with default value and hash flags -*/ - /* UCHAR [ 1 ] - item type 0. NIL 0 @@ -102,6 +98,8 @@ UCHAR [ 1 ] - item type 37. INT64NUM 8+1 38. DBLNUM 8+1+1 39. TIMESTAMP 8 + 40. HASHFLAGS 2 + 41. HASHDEFAULT VALUE 0 */ #define HB_SERIAL_NIL 0 @@ -144,6 +142,8 @@ UCHAR [ 1 ] - item type #define HB_SERIAL_INT64NUM 37 #define HB_SERIAL_DBLNUM 38 #define HB_SERIAL_TIMESTAMP 39 +#define HB_SERIAL_HASHFLAGS 40 +#define HB_SERIAL_HASHDEFVAL 41 #define HB_SERIAL_DUMMYOFFSET ( ( ULONG ) -1 ) @@ -280,6 +280,7 @@ static ULONG hb_itemSerialSize( PHB_ITEM pItem, HB_BOOL fNumSize, ULONG ulSize, ulLen, u; HB_LONG lVal; USHORT uiClass; + PHB_ITEM pDefVal; const char * szVal; if( HB_IS_BYREF( pItem ) ) @@ -388,13 +389,24 @@ static ULONG hb_itemSerialSize( PHB_ITEM pItem, HB_BOOL fNumSize, } else { - ulLen = hb_hashLen( pItem ); - if( ulLen <= 255 ) - ulSize = 2; - else if( ulLen <= UINT16_MAX ) + if( hb_hashGetFlags( pItem ) != HB_HASH_FLAG_DEFAULT ) ulSize = 3; else - ulSize = 5; + ulSize = 0; + pDefVal = hb_hashGetDefault( pItem ); + if( pDefVal ) + { + ulSize++; + ulSize += hb_itemSerialSize( pDefVal, fNumSize, + cdpIn, cdpOut, pRefPtr, ulOffset + ulSize ); + } + ulLen = hb_hashLen( pItem ); + if( ulLen <= 255 ) + ulSize += 2; + else if( ulLen <= UINT16_MAX ) + ulSize += 3; + else + ulSize += 5; for( u = 1; u <= ulLen; u++ ) { ulSize += hb_itemSerialSize( hb_hashGetKeyAt( pItem, u ), fNumSize, @@ -697,6 +709,21 @@ static ULONG hb_serializeItem( PHB_ITEM pItem, HB_BOOL fNumSize, } else { + int iFlags = hb_hashGetFlags( pItem ); + PHB_ITEM pDefVal = hb_hashGetDefault( pItem ); + + if( iFlags != HB_HASH_FLAG_DEFAULT ) + { + pBuffer[ ulOffset++ ] = HB_SERIAL_HASHFLAGS; + HB_PUT_LE_UINT16( &pBuffer[ ulOffset ], iFlags ); + ulOffset += 2; + } + if( pDefVal ) + { + pBuffer[ ulOffset++ ] = HB_SERIAL_HASHDEFVAL; + ulOffset = hb_serializeItem( pDefVal, fNumSize, + cdpIn, cdpOut, pBuffer, ulOffset, pRef ); + } ulLen = hb_hashLen( pItem ); if( ulLen <= 255 ) { @@ -762,7 +789,7 @@ static ULONG hb_deserializeHash( PHB_ITEM pItem, #else PHB_ITEM pKey, pVal; - hb_hashSetFlags( pItem, HB_HASH_BINARY | HB_HASH_RESORT ); + hb_hashSetFlags( pItem, HB_HASH_BINARY /* | HB_HASH_RESORT */ ); hb_hashPreallocate( pItem, ulLen ); while( ulLen-- ) { @@ -1026,6 +1053,30 @@ static ULONG hb_deserializeItem( PHB_ITEM pItem, break; } + case HB_SERIAL_HASHFLAGS: + { + int iFlags = HB_GET_LE_UINT16( &pBuffer[ ulOffset ] ); + ulOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + ulOffset + 2, pRef ); + hb_hashClearFlags( pItem, HB_HASH_FLAG_MASK ); + if( ( iFlags & HB_HASH_BINARY ) == 0 ) + iFlags |= HB_HASH_RESORT; + hb_hashSetFlags( pItem, iFlags ); + break; + } + + case HB_SERIAL_HASHDEFVAL: + { + PHB_ITEM pDefVal = hb_itemNew( NULL ); + ulOffset = hb_deserializeItem( pDefVal, cdpIn, cdpOut, pBuffer, + ulOffset, pRef ); + ulOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + ulOffset, pRef ); + hb_hashSetDefault( pItem, pDefVal ); + hb_itemRelease( pDefVal ); + break; + } + default: hb_itemClear( pItem ); break; @@ -1192,6 +1243,14 @@ static HB_BOOL hb_deserializeTest( const UCHAR ** pBufferPtr, ULONG * pulSize, } ulLen = 1; break; + case HB_SERIAL_HASHFLAGS: + ulSize = 3; + ulLen = 1; + break; + case HB_SERIAL_HASHDEFVAL: + ulSize = 1; + ulLen = 2; + break; default: ulSize = 1; break;