diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 49573dd68c..fb797e4b54 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,40 @@ +19991013-19:05 EDT David G. Holm + + * include/itemapi.h + + Added a prototype for hb_itemString(). + + Added a prototype for hb_itemValToStr(). + + * source/compiler/harbour.l + ! Removed yy_strdup() call from yy_ConvertNumber(). + + * source/rtl/console.c + - Removed the string conversion code from hb_out(). + + Added a call to hb_itemString() to hb_out(). + + * source/rtl/dates.c + ! Corrected two erroneous instances of 'hb_stack.szDate' in + hb_dateDecStr() to use the 'szDate' parameter instead. + + * source/rtl/itemapi.c + + Moved hb_itemStr() from source/rtl/strings.c + + New function hb_itemString() converts practically any value + to a string (this is a modification of the string conversion + code that used to be in hb_out() in source/rtl/console.c). + + New function hb_itemValToStr(), suggested by Antonio Linares. + + * source/rtl/strings.c + - Moved hb_itemStr() to source/rtl/itemapi.c + + New function HB_HB_VALTOSTR(), suggested by Antonio Linares. + + * tests/rtl_test.prg + + Added several HB_VALTOSTR() tests. + + + Note: hb_itemStr() is not re-entrant and probably not thread-safe. + I'm not sure how to correct for that without requiring that + the caller free up strings allocated by this function, which + I would very much like to avoid. Any ideas? + 19991013-13:46 GMT+8 Ron Pinkas * harbour.y + added MACROOP (last session also added MACROALIAS) diff --git a/harbour/include/itemapi.h b/harbour/include/itemapi.h index c74c428f8a..f5b7ceadcd 100644 --- a/harbour/include/itemapi.h +++ b/harbour/include/itemapi.h @@ -97,6 +97,8 @@ extern int hb_itemStrCmp ( PHB_ITEM pFirst, PHB_ITEM pSecond, BOOL bForce extern void hb_itemCopy ( PHB_ITEM pDest, PHB_ITEM pSource ); /* copies an item to one place to another respecting its containts */ extern void hb_itemClear ( PHB_ITEM pItem ); extern PHB_ITEM hb_itemUnRef ( PHB_ITEM pItem ); /* de-references passed variable */ -extern char * hb_itemStr ( PHB_ITEM pNumber, PHB_ITEM pWidth, PHB_ITEM pDec ); /* convert number to string */ +extern char * hb_itemStr ( PHB_ITEM pNumber, PHB_ITEM pWidth, PHB_ITEM pDec ); /* convert a number to a string */ +extern char * hb_itemString ( PHB_ITEM pItem, ULONG * ulLen ); /* Convert any scalar to a string */ +extern PHB_ITEM hb_itemValToStr ( PHB_ITEM pItem ); /* Convert any scalar to a string */ #endif /* HB_ITEMAPI_H_ */ diff --git a/harbour/source/compiler/harbour.l b/harbour/source/compiler/harbour.l index 618d78f22e..e09f33b882 100644 --- a/harbour/source/compiler/harbour.l +++ b/harbour/source/compiler/harbour.l @@ -1299,8 +1299,6 @@ static int yy_ConvertNumber( char * szBuffer ) char * ptr; yylval.dNum.dNumber = atof( szBuffer ); - yylval.string = yy_strdup( yytext ); - ptr = strchr( szBuffer, '.' ); if( ptr ) { diff --git a/harbour/source/rtl/console.c b/harbour/source/rtl/console.c index 13a0d6032c..626ddfd579 100644 --- a/harbour/source/rtl/console.c +++ b/harbour/source/rtl/console.c @@ -287,48 +287,10 @@ typedef void hb_out_func_typedef( char *, ULONG ); /* Format items for output, then call specified output function */ static void hb_out( USHORT uiParam, hb_out_func_typedef * hb_out_func ) { + ULONG ulLen; PHB_ITEM pItem = hb_param( uiParam, IT_ANY ); - - switch( pItem->type ) - { - case IT_STRING: - hb_out_func( hb_itemGetCPtr( pItem ), hb_itemGetCLen( pItem ) ); - break; - - case IT_DATE: - { - char szBuffer[ 11 ]; - hb_dtoc( hb_pards( uiParam ), szBuffer, hb_set.HB_SET_DATEFORMAT ); - hb_out_func( szBuffer, strlen( szBuffer ) ); - break; - } - - case IT_DOUBLE: - case IT_INTEGER: - case IT_LONG: - { - char * szText = hb_itemStr( pItem, NULL, NULL ); /* Let hb_itemStr() do the hard work */ - if( szText ) - { - hb_out_func( szText, strlen( szText ) ); - hb_xfree( szText ); - } - break; - } - case IT_NIL: - hb_out_func( "NIL", 3 ); - break; - - case IT_LOGICAL: - if( hb_itemGetL( pItem ) ) - hb_out_func( ".T.", 3 ); - else - hb_out_func( ".F.", 3 ); - break; - - default: - break; - } + char * pString = hb_itemString( pItem, &ulLen ); + hb_out_func( pString, ulLen ); } /* Output an item to STDOUT */ diff --git a/harbour/source/rtl/dates.c b/harbour/source/rtl/dates.c index c29e76a9c0..c51e140fac 100644 --- a/harbour/source/rtl/dates.c +++ b/harbour/source/rtl/dates.c @@ -219,8 +219,8 @@ char * hb_dateDecStr( char * szDate, long lJulian ) long lDay, lMonth, lYear; hb_dateDecode( lJulian, &lDay, &lMonth, &lYear ); - hb_dateStrPut( hb_stack.szDate, lDay, lMonth, lYear ); - hb_stack.szDate[ 8 ] = '\0'; + hb_dateStrPut( szDate, lDay, lMonth, lYear ); + szDate[ 8 ] = '\0'; return szDate; } diff --git a/harbour/source/rtl/itemapi.c b/harbour/source/rtl/itemapi.c index e1da40bbad..fac372ad41 100644 --- a/harbour/source/rtl/itemapi.c +++ b/harbour/source/rtl/itemapi.c @@ -57,6 +57,9 @@ * Copyright 1999 Eddie Runia * hb_itemStrCmp() * + * Copyright 1999 David G. Holm + * hb_itemStr(), hb_itemString(), and hb_itemValToStr(). + * * See doc/license.txt for licensing terms. * */ @@ -68,6 +71,9 @@ #include "dates.h" #include "set.h" +/* DJGPP can sprintf a float that is almost 320 digits long */ +#define HB_MAX_DOUBLE_LENGTH 320 + BOOL hb_evalNew( PEVALINFO pEvalInfo, PHB_ITEM pItem ) { BOOL bResult; @@ -959,3 +965,182 @@ int hb_itemStrCmp( PHB_ITEM pFirst, PHB_ITEM pSecond, BOOL bForceExact ) return iRet; } + +/* converts a numeric to a string with optional width & precision. + This function should be used by any function that wants to format numeric + data for displaying, printing, or putting in a database. + + Note: The caller is responsible for calling hb_xfree to free the results + buffer, but ONLY if the return value is not a NULL pointer! (If a NULL + pointer is returned, then there was a conversion error.) +*/ +char * hb_itemStr( PHB_ITEM pNumber, PHB_ITEM pWidth, PHB_ITEM pDec ) +{ + char * szResult = NULL; + + if( pNumber ) + { + /* Default to the width and number of decimals specified by the item, + with a limit of 20 integer places and 9 decimal places, plus one + space for the sign. */ + int iWidth; + int iDec; + + hb_itemGetNLen( pNumber, &iWidth, &iDec ); + + if( iWidth > 20 ) + iWidth = 20; + if( iDec > 9 ) + iDec = 9; + if( hb_set.HB_SET_FIXED ) + iDec = hb_set.HB_SET_DECIMALS; + + if( pWidth ) + { + /* If the width parameter is specified, override the default value + and set the number of decimals to zero */ + int iWidthPar = hb_itemGetNI( pWidth ); + + if( iWidthPar < 1 ) + iWidth = 10; /* If 0 or negative, use default */ + else + iWidth = iWidthPar; + + iDec = 0; + } + + if( pDec ) + { + /* This function does not include the decimal places in the width, + so the width must be adjusted downwards, if the decimal places + parameter is greater than 0 */ + int iDecPar = hb_itemGetNI( pDec ); + + if( iDecPar < 0 ) + iDec = 0; + else if( iDecPar > 0 ) + { + iDec = iDecPar; + iWidth -= ( iDec + 1 ); + } + } + + if( iWidth ) + { + /* We at least have a width value */ + int iBytes; + int iSize = ( iDec ? iWidth + 1 + iDec : iWidth ); + + /* Be paranoid and use a large amount of padding */ + szResult = ( char * ) hb_xgrab( HB_MAX_DOUBLE_LENGTH ); + + if( IS_DOUBLE( pNumber ) || iDec != 0 ) + { + double dNumber = hb_itemGetND( pNumber ); + +#ifdef HARBOUR_STRICT_CLIPPER_COMPATIBILITY + if( pNumber->item.asDouble.length == 99 || dNumber == s_dInfinity || dNumber == -s_dInfinity ) + /* Numeric overflow */ + iBytes = iSize + 1; + else +#endif + { + if( IS_DOUBLE( pNumber ) && iDec < pNumber->item.asDouble.decimal ) + dNumber = hb_numRound( dNumber, iDec ); + + if( iDec == 0 ) + iBytes = sprintf( szResult, "%*.0f", iSize, dNumber ); + else + iBytes = sprintf( szResult, "%*.*f", iSize, iDec, dNumber ); + } + } + else + { + switch( pNumber->type & ~IT_BYREF ) + { + case IT_INTEGER: + iBytes = sprintf( szResult, "%*i", iWidth, pNumber->item.asInteger.value ); + break; + + case IT_LONG: + iBytes = sprintf( szResult, "%*li", iWidth, pNumber->item.asLong.value ); + break; + + default: + iBytes = 0; + szResult[ 0 ] = '\0'; /* null string */ + break; + } + } + + /* Set to asterisks in case of overflow */ + if( iBytes > iSize ) + { + memset( szResult, '*', iSize ); + szResult[ iSize ] = '\0'; + } + } + } + + return szResult; +} + +char * hb_itemString( PHB_ITEM pItem, ULONG * ulLen ) +{ + static char buffer[ 32 ]; /* NOTE: Not re-entrant. Probably not thread safe. */ + char * pointer; + switch( pItem->type ) + { + case IT_STRING: + pointer = hb_itemGetCPtr( pItem ); + * ulLen = hb_itemGetCLen( pItem ); + break; + case IT_DATE: + { + char szDate[ 9 ]; + hb_dateDecStr( szDate, pItem->item.asDate.value ); + hb_dtoc( szDate, buffer, hb_set.HB_SET_DATEFORMAT ); + pointer = buffer; + * ulLen = strlen( buffer ); + } + break; + case IT_DOUBLE: + case IT_INTEGER: + case IT_LONG: + pointer = hb_itemStr( pItem, NULL, NULL ); + if( pointer ) + { + strncpy( buffer, pointer, sizeof( buffer ) ); + buffer[ sizeof( buffer ) - 1 ] = '\0'; + hb_xfree( pointer ); + pointer = buffer; + * ulLen = strlen( buffer ); + } + break; + case IT_NIL: + strcpy( buffer, "NIL" ); + pointer = buffer; + * ulLen = 3; + break; + case IT_LOGICAL: + if( hb_itemGetL( pItem ) ) + strcpy( buffer, ".T." ); + else + strcpy( buffer, ".F." ); + pointer = buffer; + * ulLen = 3; + break; + default: + buffer[ 0 ] = '\0'; + pointer = buffer; + * ulLen = 0; + } + return pointer; +} + +PHB_ITEM hb_itemValToStr( PHB_ITEM pItem ) +{ + ULONG ulLen; + char * pointer = hb_itemString( pItem, &ulLen ); + return hb_itemPutCL( NULL, pointer, ulLen ); +} diff --git a/harbour/source/rtl/strings.c b/harbour/source/rtl/strings.c index aa1552192e..40f2c4e2fe 100644 --- a/harbour/source/rtl/strings.c +++ b/harbour/source/rtl/strings.c @@ -38,7 +38,7 @@ * www - http://www.harbour-project.org * * Copyright 1999 David G. Holm - * hb_stricmp() + * hb_stricmp() and HB_HB_VALTOSTR(). * * Copyright 1999 Victor Szel * hb_strEmpty() @@ -64,9 +64,6 @@ ( c ) == HB_CHAR_CR || \ ( c ) == ' ' ) -/* DJGPP can sprintf a float that is almost 320 digits long */ -#define HB_MAX_DOUBLE_LENGTH 320 - #ifdef HARBOUR_STRICT_CLIPPER_COMPATIBILITY #include "init.h" @@ -1201,125 +1198,6 @@ HARBOUR HB_VAL( void ) hb_errRT_BASE( EG_ARGCOUNT, 3000, NULL, "VAL" ); /* NOTE: Clipper catches this at compile time! */ } -/* converts a numeric to a string with optional width & precision. - This function should be used by any function that wants to format numeric - data for displaying, printing, or putting in a database. - - Note: The caller is responsible for calling hb_xfree to free the results buffer, - but ONLY if the return value is not a NULL pointer! -*/ -/* TODO: Move it to itemapi.c */ -char * hb_itemStr( PHB_ITEM pNumber, PHB_ITEM pWidth, PHB_ITEM pDec ) -{ - char * szResult = NULL; - - if( pNumber ) - { - /* Default to the width and number of decimals specified by the item, - with a limit of 20 integer places and 9 decimal places */ - int iWidth; - int iDec; - - hb_itemGetNLen( pNumber, &iWidth, &iDec ); - - if( iWidth > 20 ) - iWidth = 20; - if( iDec > 9 ) - iDec = 9; - if( hb_set.HB_SET_FIXED ) - iDec = hb_set.HB_SET_DECIMALS; - - if( pWidth ) - { - /* If the width parameter is specified, override the default value - and set the number of decimals to zero */ - int iWidthPar = hb_itemGetNI( pWidth ); - - if( iWidthPar < 1 ) - iWidth = 10; /* If 0 or negative, use default */ - else - iWidth = iWidthPar; - - iDec = 0; - } - - if( pDec ) - { - /* This function does not include the decimal places in the width, - so the width must be adjusted downwards, if the decimal places - parameter is greater than 0 */ - int iDecPar = hb_itemGetNI( pDec ); - - if( iDecPar < 0 ) - iDec = 0; - else if( iDecPar > 0 ) - { - iDec = iDecPar; - iWidth -= ( iDec + 1 ); - } - } - - if( iWidth ) - { - /* We at least have a width value */ - int iBytes; - int iSize = ( iDec ? iWidth + 1 + iDec : iWidth ); - - /* Be paranoid and use a large amount of padding */ - szResult = ( char * ) hb_xgrab( HB_MAX_DOUBLE_LENGTH ); - - if( IS_DOUBLE( pNumber ) || iDec != 0 ) - { - double dNumber = hb_itemGetND( pNumber ); - -#ifdef HARBOUR_STRICT_CLIPPER_COMPATIBILITY - if( pNumber->item.asDouble.length == 99 || dNumber == s_dInfinity || dNumber == -s_dInfinity ) - /* Numeric overflow */ - iBytes = iSize + 1; - else -#endif - { - if( IS_DOUBLE( pNumber ) && iDec < pNumber->item.asDouble.decimal ) - dNumber = hb_numRound( dNumber, iDec ); - - if( iDec == 0 ) - iBytes = sprintf( szResult, "%*.0f", iSize, dNumber ); - else - iBytes = sprintf( szResult, "%*.*f", iSize, iDec, dNumber ); - } - } - else - { - switch( pNumber->type & ~IT_BYREF ) - { - case IT_INTEGER: - iBytes = sprintf( szResult, "%*i", iWidth, pNumber->item.asInteger.value ); - break; - - case IT_LONG: - iBytes = sprintf( szResult, "%*li", iWidth, pNumber->item.asLong.value ); - break; - - default: - iBytes = 0; - szResult[ 0 ] = '\0'; /* null string */ - break; - } - } - - /* Set to asterisks in case of overflow */ - if( iBytes > iSize ) - { - memset( szResult, '*', iSize ); - szResult[ iSize ] = '\0'; - } - } - } - - return szResult; -} - - /* $DOC$ * $FUNCNAME$ * STR @@ -1617,3 +1495,45 @@ int hb_strgreater( char * szText1, char * szText2 ) return HB_STRGREATER_EQUAL; } + +/* $DOC$ + * $FUNCNAME$ + * HB_VALTOSTR + * $CATEGORY$ + * Strings + * $ONELINER$ + * Converts any scalar type to a string. + * $SYNTAX$ + * HB_VALTOSTR( ) + * $ARGUMENTS$ + * is any scalar argument. + * $RETURNS$ + * A string representation of using default conversions. + * $DESCRIPTION$ + * HB_VALTOSTR can be used to convert any scalar value to a string. + * $EXAMPLES$ + * ? HB_VALTOSTR( 4 ) + * ? HB_VALTOSTR( "String" ) + * $TESTS$ + * ? HB_VALTOSTR( 4 ) == " 4" + * ? HB_VALTOSTR( 4.0 / 2 ) == " 2.00" + * ? HB_VALTOSTR( "String" ) == "String" + * ? HB_VALTOSTR( CTOD( "01/01/2001" ) ) == "01/01/01" + * ? HB_VALTOSTR( NIL ) == "NIL" + * ? HB_VALTOSTR( .F. ) == ".F." + * ? HB_VALTOSTR( .T. ) == ".T." + * $STATUS$ + * C + * $COMPLIANCE$ + * HB_VALTOSTR is a Harbour enhancement. + * $SEEALSO$ + * STR(), VAL() + * $END$ + */ + +HARBOUR HB_HB_VALTOSTR( void ) +{ + ULONG ulLen; + char * pointer = hb_itemString( hb_param( 1, IT_ANY ), &ulLen ); + hb_retclen( pointer, ulLen ); +} diff --git a/harbour/tests/rtl_test.prg b/harbour/tests/rtl_test.prg index c6e2cc7247..44121bc3c0 100644 --- a/harbour/tests/rtl_test.prg +++ b/harbour/tests/rtl_test.prg @@ -146,6 +146,7 @@ FUNCTION Main( cPar1, cPar2 ) Main_MATH() Main_STRINGS() #ifdef __HARBOUR__ + New_STRINGS() Long_STRINGS() #endif Main_MISC() @@ -1653,6 +1654,16 @@ STATIC FUNCTION Main_STRINGS() RETURN NIL #ifdef __HARBOUR__ +STATIC FUNCTION New_STRINGS() + TEST_LINE( HB_VALTOSTR( 4 ) , " 4" ) + TEST_LINE( HB_VALTOSTR( 4.0 / 2 ) , " 2.00" ) + TEST_LINE( HB_VALTOSTR( "String" ) , "String" ) + TEST_LINE( HB_VALTOSTR( CTOD( "2001/01/01" ) ), "2001.01.01" ) + TEST_LINE( HB_VALTOSTR( NIL ) , "NIL" ) + TEST_LINE( HB_VALTOSTR( .F. ) , ".F." ) + TEST_LINE( HB_VALTOSTR( .T. ) , ".T." ) + RETURN NIL + STATIC FUNCTION Long_STRINGS() TEST_LINE( RIGHT( SPACE( 64 * 1024 - 5 ) + "12345 7890", 10 ), "12345 7890" )