diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 5d8de05c0e..818d804def 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,22 @@ The license applies to all entries newer than 2009-04-28. */ +2010-07-14 11:46 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) + * include/hbapi.h + * src/common/Makefile + + src/common/hbstrbm.c + + Added hb_strAtTBM() which provides fast text search using + Turbo Boyer-Moore(-Crochemore) algorithm. The interface is + the same as hb_strAt(). + HB_AT()/AT() could use it beyond some haystack sizes to + speed up the results. + + + contrib/hbqt/tests/testbrow.prg + + Added useful browse example implemented using QT. + + * tests/utf8at.prg + + Changed to not use high chars. + 2010-07-14 10:10 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * include/hbapicdp.h * src/rtl/cdpapi.c diff --git a/harbour/contrib/hbqt/tests/testbrow.prg b/harbour/contrib/hbqt/tests/testbrow.prg new file mode 100644 index 0000000000..e2e5c772c8 --- /dev/null +++ b/harbour/contrib/hbqt/tests/testbrow.prg @@ -0,0 +1,182 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * + * Copyright 2010 Carlos Bacco + * www - http://harbour-project.org + * + */ + +/* + * NOTES: + * + * This is only a basic browse test. Production code must check + * parameters, test if database really opened, and so on. + * + * Also, we are using absolute sizes. Proper Qt coding rely on + * font metrics obtained by QFont and similar techniques. Modern + * interfaces assume that font size and system colors is user + * choice. + * + * For production code is advised that the user creates a basic + * data caching system, to avoid unnecessary disk access while + * browsing large data sets. + * + */ + +#include "hbqt.ch" +#include "common.ch" + +STATIC qApp +STATIC oWnd + +STATIC oDA +STATIC oSize +STATIC aStru1 + +STATIC oColorC +STATIC oColorN +STATIC oColorD +STATIC oColorLY +STATIC oColorLN + +REQUEST HB_QT + +INIT PROCEDURE Qt_Start() + qApp := QApplication():new() + RETURN + +EXIT PROCEDURE Qt_End() + qApp:quit() + RETURN + +PROCEDURE Main() + LOCAL tb1, mo1, lay1, lay2, bt1, bt2, bt3, hd1, i + + SET DATE ANSI + SET CENTURY ON + + oColorN := QColor():New( 100, 0,100 ) + oColorD := QColor():New( 150, 100, 0 ) + oColorLY:= QColor():New( 0, 150, 0 ) + oColorLN:= QColor():New( 200, 0, 0 ) + + oWnd := QMainWindow():new() + oWnd:resize(640,460 ) + + oDA := QWidget():new() + oWnd:setCentralWidget( oDA ) + lay1 := QVBoxLayout():new( oDA ) + + DBUseArea( .T., NIL, '../../../tests/test.dbf','T1', .F., .T.) + aStru1 := DBStruct() + tb1 := QTableView():new() + mo1 := HBQAbstractItemModel():New( {| t, r, x, y| my_browse( 1, aStru1, t, r, x, y ) } ) + tb1:setModel( mo1 ) + + hd1 := QHeaderView():from(tb1:horizontalHeader()) + FOR i := 1 To Len( aStru1 ) + hd1:resizeSection( i-1, aStru1[ i ,3 ] * 6 + 60 ) + NEXT + QHeaderView():from( tb1:verticalHeader() ):setDefaultSectionSize( 24 ) + + oSize := QSize():new(50,24) + + lay1:addWidget( tb1 ) + + lay2 := QHBoxLayout():new() + lay1:addlayout( lay2 ) + + ( bt1 := QPushButton():new() ):SetText( "Dummy 1" ) + ( bt2 := QPushButton():new() ):SetText( "Dummy 2" ) + ( bt3 := QPushButton():new() ):SetText( "Dummy 3" ) + + lay2:addWidget( bt1 ) + lay2:addStretch() + lay2:addWidget( bt2 ) + lay2:addWidget( bt3 ) + + oWnd:Show() + qApp:exec() + + RETURN + +STATIC FUNCTION my_browse( nArea, aStru, t, role, x, y ) + DBSelectArea( nArea ) + + SWITCH t + CASE HBQT_QAIM_data + + SWITCH role + CASE Qt_DisplayRole + DBGoto( y + 1 ) + SWITCH aStru[ x + 1, 2 ] + CASE 'C' + RETURN AllTrim( FieldGet( x + 1 ) ) + CASE 'N' + RETURN hb_NToS( FieldGet( x + 1 ) ) + CASE 'L' + RETURN IIf( FieldGet( x + 1 ), 'Yes', 'No' ) + CASE 'D' + RETURN DToC( FieldGet( x + 1 ) ) + ENDSWITCH + RETURN '?' + + CASE Qt_ForegroundRole + SWITCH aStru[ x + 1, 2 ] + CASE 'N' + RETURN oColorN + CASE 'L' + DBGoto( y + 1 ) + RETURN IIf( FieldGet( x + 1), oColorLY, oColorLN ) + CASE 'D' + RETURN oColorD + ENDSWITCH + RETURN NIL + + CASE Qt_BackgroundRole + RETURN NIL + + CASE Qt_TextAlignmentRole + SWITCH aStru[ x + 1, 2 ] + CASE 'C' + RETURN Qt_AlignVCenter + Qt_AlignLeft + CASE 'N' + RETURN Qt_AlignVCenter + Qt_AlignRight + ENDSWITCH + RETURN Qt_AlignCenter + ENDSWITCH + RETURN NIL + + CASE HBQT_QAIM_headerData + SWITCH role + CASE Qt_DisplayRole + IF x == Qt_Horizontal + RETURN aStru[ y + 1, 1 ] + ELSE + RETURN hb_NToS( y + 1 ) + ENDIF + + CASE Qt_TextAlignmentRole + IF x == Qt_Horizontal + RETURN Qt_AlignCenter + ELSE + RETURN Qt_AlignVCenter + Qt_AlignRight + ENDIF + + CASE Qt_SizeHintRole + RETURN oSize + ENDSWITCH + RETURN NIL + + CASE HBQT_QAIM_rowCount + RETURN LastRec() + + CASE HBQT_QAIM_columnCount + RETURN Len( aStru) + ENDSWITCH + + RETURN NIL diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index f52063aaea..d700e5f0cf 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -945,6 +945,7 @@ extern HB_EXPORT HB_BOOL hb_strMatchCaseWildExact( const char * szString, cons extern HB_EXPORT HB_BOOL hb_strEmpty( const char * szText, HB_SIZE nLen ); /* returns whether a string contains only white space */ extern HB_EXPORT void hb_strDescend( char * szStringTo, const char * szStringFrom, HB_SIZE nLen ); /* copy a string to a buffer, inverting each character */ extern HB_EXPORT HB_SIZE hb_strAt( const char * szSub, HB_SIZE nSubLen, const char * szText, HB_SIZE nLen ); /* returns an index to a sub-string within another string */ +extern HB_EXPORT HB_ISIZ hb_strAtTBM( const char * needle, HB_ISIZ m, const char * haystack, HB_ISIZ n ); extern HB_EXPORT char * hb_strUpper( char * szText, HB_SIZE nLen ); /* convert an existing string buffer to upper case */ extern HB_EXPORT char * hb_strLower( char * szText, HB_SIZE nLen ); /* convert an existing string buffer to lower case */ extern HB_EXPORT HB_BOOL hb_charIsDigit( int iChar ); diff --git a/harbour/src/common/Makefile b/harbour/src/common/Makefile index ea8d006394..6f747b3662 100644 --- a/harbour/src/common/Makefile +++ b/harbour/src/common/Makefile @@ -18,6 +18,7 @@ C_SOURCES := \ hbmem.c \ hbprintf.c \ hbstr.c \ + hbstrbm.c \ hbtrace.c \ hbver.c \ hbverdsp.c \ diff --git a/harbour/src/common/hbstrbm.c b/harbour/src/common/hbstrbm.c new file mode 100644 index 0000000000..92a69f8811 --- /dev/null +++ b/harbour/src/common/hbstrbm.c @@ -0,0 +1,175 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * Turbo Boyer-Moore (Crochemore) string search + * Based on this code: + * http://www-igm.univ-mlv.fr/~lecroq/string/node15.html + * Authors: + * Christian Charras, Thierry Lecroq + * + * Copyright 2010 Viktor Szakats (harbour.01 syenar.hu) + * www - http://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. + * + */ + +#include "hbapi.h" + +#define ASIZE UCHAR_MAX + +static void preBmBc( const char * needle, HB_ISIZ m, HB_ISIZ bmBc[] ) +{ + HB_ISIZ i; + + for( i = 0; i < ASIZE; ++i ) + bmBc[ i ] = m; + for( i = 0; i < m - 1; ++i ) + bmBc[ ( HB_UCHAR ) needle[ i ] ] = m - i - 1; +} + +static void suffixes( const char * needle, HB_ISIZ m, HB_ISIZ * suff ) +{ + HB_ISIZ f, g, i; + + f = 0; /* NOTE: Fix added by me [vszakats] */ + suff[ m - 1 ] = m; + g = m - 1; + for( i = m - 2; i >= 0; --i ) + { + if( i > g && suff[ i + m - 1 - f ] < i - g ) + suff[ i ] = suff[ i + m - 1 - f ]; + else + { + if( i < g ) + g = i; + f = i; + while( g >= 0 && needle[ g ] == needle[ g + m - 1 - f ] ) + --g; + suff[ i ] = f - g; + } + } +} + +static void preBmGs( const char * needle, HB_ISIZ m, HB_ISIZ bmGs[] ) +{ + HB_ISIZ i, j; + HB_ISIZ * suff = ( HB_ISIZ * ) hb_xgrab( m * sizeof( HB_ISIZ ) ); + + suffixes( needle, m, suff ); + + for( i = 0; i < m; ++i ) + bmGs[ i ] = m; + + j = 0; + + for( i = m - 1; i >= 0; --i ) + if( suff[ i ] == i + 1 ) + for( ; j < m - 1 - i; ++j ) + if( bmGs[ j ] == m ) + bmGs[ j ] = m - 1 - i; + + for( i = 0; i <= m - 2; ++i ) + bmGs[ m - 1 - suff[ i ] ] = m - 1 - i; + + hb_xfree( suff ); +} + +HB_ISIZ hb_strAtTBM( const char * needle, HB_ISIZ m, const char * haystack, HB_ISIZ n ) +{ + HB_ISIZ r = 0; + HB_ISIZ bcShift, i, j, shift, u, v, turboShift; + HB_ISIZ bmBc[ ASIZE ]; + HB_ISIZ * bmGs; + + bmGs = ( HB_ISIZ * ) hb_xgrab( m * sizeof( HB_ISIZ ) ); + + /* Preprocessing */ + preBmGs( needle, m, bmGs ); + preBmBc( needle, m, bmBc ); + + /* Searching */ + j = u = 0; + shift = m; + while( j <= n - m ) + { + i = m - 1; + while( i >= 0 && needle[ i ] == haystack[ i + j ] ) + { + --i; + if( u != 0 && i == m - 1 - shift ) + i -= u; + } + + if( i < 0 ) + { + r = j + 1; + break; +#if 0 /* To continue search */ + shift = bmGs[ 0 ]; + u = m - shift; +#endif + } + else + { + v = m - 1 - i; + turboShift = u - v; + bcShift = bmBc[ ( HB_UCHAR ) haystack[ i + j ] ] - m + 1 + i; + shift = HB_MAX( turboShift, bcShift ); + shift = HB_MAX( shift, bmGs[ i ] ); + if( shift == bmGs[ i ] ) + u = HB_MIN( m - shift, v ); + else + { + if( turboShift < bcShift ) + shift = HB_MAX( shift, u + 1 ); + u = 0; + } + } + j += shift; + } + + hb_xfree( bmGs ); + + return r; +} diff --git a/harbour/tests/utf8at.prg b/harbour/tests/utf8at.prg index ae6c9faab9..f57a1d0a7b 100644 --- a/harbour/tests/utf8at.prg +++ b/harbour/tests/utf8at.prg @@ -2,8 +2,6 @@ * $Id$ */ -/* WARNING: UTF-8 strings */ - /* hb_utf8at / hb_utf8rat test UTF8 Aware hb_at()/hb_rat() */ @@ -14,11 +12,14 @@ REQUEST HB_CODEPAGE_FRISO PROCEDURE Main() - LOCAL u := "Une rêve est la moitié d'une réalité." + #define _UTF8_E_ACUTE Chr( 0xC3 ) + Chr( 0xA9 ) + #define _UTF8_E_CIRCUMFLEX Chr( 0xC3 ) + Chr( 0xAA ) + + LOCAL u := "Une r" + _UTF8_E_CIRCUMFLEX + "ve est la moiti" + _UTF8_E_ACUTE + " d'une r" + _UTF8_E_ACUTE + "alit" + _UTF8_E_ACUTE + "." LOCAL i := hb_translate( u, "UTF8", "FRISO" ) LOCAL d := hb_translate( u, "UTF8", "FR850" ) - LOCAL uu :="é" + LOCAL uu := _UTF8_E_ACUTE LOCAL ii := hb_translate( uu, "UTF8", "FRISO" ) LOCAL dd := hb_translate( uu, "UTF8", "FR850" )