diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 8ed2cbf9a4..296dbef995 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,21 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-12-29 14:34 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbapi.h + * harbour/src/common/hbprintf.c + + added new function 'int hb_printf_params( const char * format )' which + returns number of parameters necessary for format string + + * harbour/src/common/hbtrace.c + * added protection against recursive calls when number of parameters + used by HB_TRACE message us bigger then 16 and fm.c module was compiled + with HB_TR_DEBUG macro + % use the same number of characters for unicode and byte string buffers + % use common memory area (union) for unicode and byte messages to reduce + C stack usage + Please test these modifications in real MS-Windows systems. + 2009-12-29 00:41 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) * contrib/hbqt/qtgui/QTextCursor.cpp * contrib/hbqt/qtgui/TQTextCursor.prg diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index c96d6569d2..3ff2aefa3c 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -935,6 +935,7 @@ extern HB_EXPORT BOOL hb_strToNum( const char * szNum, HB_LONG * plVal, dou extern HB_EXPORT BOOL hb_strnToNum( const char * szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal ); /* converts string to number, returns HB_TRUE if results is double */ extern HB_EXPORT int hb_snprintf( char * buffer, size_t bufsize, const char * format, ... ) HB_PRINTF_FORMAT( 3, 4 ); /* snprintf() equivalent */ extern HB_EXPORT int hb_vsnprintf( char * buffer, size_t bufsize, const char * format, va_list ap ); /* vsnprintf() equivalent */ +extern HB_EXPORT int hb_printf_params( const char * format ); extern HB_EXPORT BOOL hb_strMatchFile( const char * pszString, const char * szPattern ); /* compare two strings using platform dependent rules for file matching */ extern HB_EXPORT BOOL hb_strMatchRegExp( const char * szString, const char * szPattern ); /* compare two strings using a regular expression pattern */ diff --git a/harbour/src/common/hbprintf.c b/harbour/src/common/hbprintf.c index cab3e8e1ac..4fc80dd361 100644 --- a/harbour/src/common/hbprintf.c +++ b/harbour/src/common/hbprintf.c @@ -728,6 +728,187 @@ static size_t put_str( char *buffer, size_t bufsize, size_t size, return size; } +int hb_printf_params( const char * format ) +{ + int iParam = 0, iMax = 0; + char c; + + do + { + c = *format++; + if( c == '%' ) + { + const char * pattern = format; + int value, param = 0; + + c = *format++; + if( c != 0 && c != '%' ) + { + /* parameter position */ + if( c >= '0' && c <= '9' ) + { + c = get_decimal( c, &format, ¶m ); + if( c != '$' ) + format = pattern; + c = *format++; + } + + /* flags */ + value = 0; + while( !value ) switch( c ) + { + case '#': + case '0': + case '-': + case ' ': + case '+': +#ifdef _SUSV2_COMPAT_ + case '\'': /* group with locale thousands' grouping characters */ +#endif + c = *format++; + break; + default: + value = 1; + break; + } + + /* field width */ + if( c == '*' ) + { + c = *format++; + if( c >= '0' && c <= '9' ) + { + c = get_decimal( c, &format, &value ); + if( c == '$' ) + { + if( value > iMax ) + iMax = value; + c = *format++; + } + /* else error, wrong format */ + } + else + ++iParam; + } + else if( c >= '0' && c <= '9' ) + c = get_decimal( c, &format, &value ); + + /* precision */ + if( c == '.' ) + { + c = *format++; + if( c == '*' ) + { + c = *format++; + if( c >= '0' && c <= '9' ) + { + c = get_decimal( c, &format, &value ); + if( c == '$' ) + { + if( value > iMax ) + iMax = value; + c = *format++; + } + /* else error, wrong format */ + } + else + ++iParam; + } + else if( c >= '0' && c <= '9' ) + c = get_decimal( c, &format, &value ); + } + + /* length modifier */ + switch( c ) + { + case 'h': + c = *format++; + if( c == 'h' ) + c = *format++; + break; + case 'l': + c = *format++; + if( c == 'l' ) + c = *format++; + break; + case 'L': + c = *format++; + break; + case 'j': + c = *format++; + break; + case 'z': + c = *format++; + break; + case 't': + c = *format++; + break; + case 'I': /* MS-Windows extension */ + if( format[ 0 ] == '6' && format[ 1 ] == '4' ) + { + format += 2; + c = *format++; + break; + } + else if( format[ 0 ] == '1' && format[ 1 ] == '6' ) + { + format += 2; + c = *format++; + break; + } + else if( format[ 0 ] == '3' && format[ 1 ] == '2' ) + { + format += 2; + c = *format++; + } + /* no break; */ + default: + break; + } + + /* conversion specifier */ + switch( c ) + { +#ifndef __NO_DOUBLE__ + case 'a': + case 'A': + case 'e': + case 'E': + case 'g': + case 'G': + case 'f': /* double decimal notation */ + case 'F': /* double decimal notation */ +#endif + case 'd': + case 'i': /* signed int decimal conversion */ + case 'o': /* unsigned int octal conversion */ + case 'u': /* unsigned int decimal conversion */ + case 'x': /* unsigned int hexadecimal conversion */ + case 'X': /* unsigned int hexadecimal conversion */ + case 'p': /* void * pointer */ + case 'c': /* signed int casted to unsigned char */ + case 's': /* const char * */ + case 'n': /* store current result size in int * arg */ + if( param == 0 ) + ++iParam; + else if( param > iMax ) + iMax = param; + break; + case '%': /* store % consuming arguments % */ + break; + default: /* error, wrong format, store pattern */ + format = pattern; + c = '%'; + break; + } + } + } + } + while( c ); + + return iParam > iMax ? iParam : iMax; +} + int hb_vsnprintf( char * buffer, size_t bufsize, const char * format, va_list ap ) { va_list args; @@ -779,15 +960,10 @@ int hb_vsnprintf( char * buffer, size_t bufsize, const char * format, va_list ap { c = get_decimal( c, &format, &value ); if( c == '$' ) - { param = value; - c = *format++; - } else - { format = pattern; - c = *format++; - } + c = *format++; } /* flags */ @@ -934,7 +1110,6 @@ int hb_vsnprintf( char * buffer, size_t bufsize, const char * format, va_list ap } /* conversion specifier */ - switch( c ) { #ifndef __NO_DOUBLE__ diff --git a/harbour/src/common/hbtrace.c b/harbour/src/common/hbtrace.c index 800352a457..07d5f9e6cb 100644 --- a/harbour/src/common/hbtrace.c +++ b/harbour/src/common/hbtrace.c @@ -223,30 +223,33 @@ static void hb_tracelog_( int level, const char * file, int line, const char * p if( s_winout ) { - char buffer1[ 1024 ]; - char buffer2[ 1024 ]; + char message[ 1024 ]; + union + { + char psz[ 1024 ]; + TCHAR lp[ 1024 ]; + } buf; - /* TOFIX: This might invoke recursive call to tracee engine when - there is more than 16 format strings. */ - hb_vsnprintf( buffer1, sizeof( buffer1 ), fmt, ap ); - - /* We add \r\n at the end of the buffer to make WinDbg display look readable. */ - if( proc ) - hb_snprintf( buffer2, sizeof( buffer2 ), "%s:%d:%s() %s %s\n", - file, line, proc, pszLevel, buffer1 ); + /* NOTE: This is protection against recursive call to trace engine when + there is more than 16 parameters in format string */ + if( hb_xtraced() && hb_printf_params( fmt ) > 16 ) + hb_snprintf( message, sizeof( message ), "more then 16 parameters in message '%s'", fmt ); else - hb_snprintf( buffer2, sizeof( buffer2 ), "%s:%d: %s %s\n", - file, line, pszLevel, buffer1 ); + hb_vsnprintf( message, sizeof( message ), fmt, ap ); + + /* We add \n at the end of the buffer to make WinDbg display look readable. */ + if( proc ) + hb_snprintf( buf.psz, sizeof( buf.psz ), "%s:%d:%s() %s %s\n", + file, line, proc, pszLevel, message ); + else + hb_snprintf( buf.psz, sizeof( buf.psz ), "%s:%d: %s %s\n", + file, line, pszLevel, message ); #if defined( UNICODE ) - { - TCHAR lpOutputString[ 2048 ]; - MultiByteToWideChar( CP_ACP, 0, buffer2, -1, lpOutputString, HB_SIZEOFARRAY( lpOutputString ) ); - OutputDebugString( lpOutputString ); - } - #else - OutputDebugString( buffer2 ); + memcpy( message, buf.psz, sizeof( message ) ); + MultiByteToWideChar( CP_ACP, 0, message, -1, buf.lp, HB_SIZEOFARRAY( buf.lp ) ); #endif + OutputDebugString( buf.lp ); } #endif