mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-30 08:34:16 +01:00
fix crashes when filter strings are too long
This commit is contained in:
parent
b6a74b7d15
commit
7a43e95aa8
7 changed files with 259 additions and 188 deletions
|
@ -700,10 +700,14 @@ public class DictBrowseDelegate extends DelegateBase
|
||||||
public void run() {
|
public void run() {
|
||||||
stopProgress();
|
stopProgress();
|
||||||
|
|
||||||
m_browseState.onFilterAccepted( m_dict, null );
|
if ( null != wrapper ) {
|
||||||
initList( wrapper );
|
m_browseState.onFilterAccepted( m_dict, null );
|
||||||
setFindPats( m_browseState.m_pats );
|
initList( wrapper );
|
||||||
|
setFindPats( m_browseState.m_pats );
|
||||||
|
} else {
|
||||||
|
makeOkOnlyBuilder(R.string.alrt_bad_filter )
|
||||||
|
.show();
|
||||||
|
}
|
||||||
newFeatureAlert();
|
newFeatureAlert();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -619,9 +619,13 @@ public class XwJNI {
|
||||||
new Thread( new Runnable() {
|
new Thread( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
IterWrapper wrapper = null;
|
||||||
long iterPtr = di_init( jniState, dictPtr, pats,
|
long iterPtr = di_init( jniState, dictPtr, pats,
|
||||||
minLen, maxLen );
|
minLen, maxLen );
|
||||||
callback.onIterReady( new IterWrapper(iterPtr) );
|
if ( 0 != iterPtr ) {
|
||||||
|
wrapper = new IterWrapper(iterPtr);
|
||||||
|
}
|
||||||
|
callback.onIterReady( wrapper );
|
||||||
}
|
}
|
||||||
} ).start();
|
} ).start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1615,6 +1615,8 @@
|
||||||
<!-- Shown when user tries to make a wordlist filter where max < min -->
|
<!-- Shown when user tries to make a wordlist filter where max < min -->
|
||||||
<string name="error_min_gt_max">The minimum length value cannot be
|
<string name="error_min_gt_max">The minimum length value cannot be
|
||||||
greater than the maximum value.</string>
|
greater than the maximum value.</string>
|
||||||
|
<!-- shown when something goes wrong building a filter -->
|
||||||
|
<string name="alrt_bad_filter">Unable to apply filter.</string>
|
||||||
|
|
||||||
<!-- Title of progress alert shown while wordlist is loading. For
|
<!-- Title of progress alert shown while wordlist is loading. For
|
||||||
huge lists like Polish this can take a few seconds. -->
|
huge lists like Polish this can take a few seconds. -->
|
||||||
|
|
|
@ -2656,34 +2656,32 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1init
|
||||||
|
|
||||||
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
DictionaryCtxt* dict = (DictionaryCtxt*)dictPtr;
|
||||||
if ( !!dict ) {
|
if ( !!dict ) {
|
||||||
DictIterData* data = XP_CALLOC( globalState->mpool, sizeof(*data) );
|
|
||||||
data->globalState = globalState;
|
|
||||||
data->dict = dict_ref( dict, env );
|
|
||||||
data->depth = 2;
|
|
||||||
#ifdef DEBUG
|
|
||||||
data->guard = GI_GUARD;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PatDesc patDescs[3];
|
PatDesc patDescs[3];
|
||||||
XP_MEMSET( patDescs, 0, VSIZE(patDescs) * sizeof(patDescs[0]) );
|
XP_MEMSET( patDescs, 0, VSIZE(patDescs) * sizeof(patDescs[0]) );
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
bool formatOK = true;
|
||||||
if ( !!jPatsArr ) {
|
if ( !!jPatsArr ) {
|
||||||
len = (*env)->GetArrayLength( env, jPatsArr );
|
len = (*env)->GetArrayLength( env, jPatsArr );
|
||||||
XP_ASSERT( len == 3 );
|
XP_ASSERT( len == 3 );
|
||||||
for ( int ii = 0; ii < len ; ++ii ) {
|
for ( int ii = 0; formatOK && ii < len ; ++ii ) {
|
||||||
jobject jdesc = (*env)->GetObjectArrayElement( env, jPatsArr, ii );
|
jobject jdesc = (*env)->GetObjectArrayElement( env, jPatsArr, ii );
|
||||||
if ( !!jdesc ) {
|
if ( !!jdesc ) {
|
||||||
jbyteArray jtiles;
|
jbyteArray jtiles;
|
||||||
if ( getObject( env, jdesc, "tilePat", "[B", &jtiles ) ) {
|
if ( getObject( env, jdesc, "tilePat", "[B", &jtiles ) ) {
|
||||||
int nTiles = (*env)->GetArrayLength( env, jtiles );
|
int nTiles = (*env)->GetArrayLength( env, jtiles );
|
||||||
if ( 0 < nTiles ) {
|
if ( 0 < nTiles ) {
|
||||||
patDescs[ii].nTiles = nTiles;
|
PatDesc* pd = &patDescs[ii];
|
||||||
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
/* If user adds too many tiles, we'll see it here */
|
||||||
XP_MEMCPY( &patDescs[ii].tiles[0], tiles,
|
if ( nTiles <= VSIZE(pd->tiles) ) {
|
||||||
nTiles * sizeof(patDescs[ii].tiles[0]) );
|
pd->nTiles = nTiles;
|
||||||
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
jbyte* tiles = (*env)->GetByteArrayElements( env, jtiles, NULL );
|
||||||
patDescs[ii].anyOrderOk = getBool( env, jdesc, "anyOrderOk" );
|
XP_MEMCPY( &pd->tiles[0], tiles, nTiles * sizeof(pd->tiles[0]) );
|
||||||
|
(*env)->ReleaseByteArrayElements( env, jtiles, tiles, 0 );
|
||||||
|
pd->anyOrderOk = getBool( env, jdesc, "anyOrderOk" );
|
||||||
|
} else {
|
||||||
|
formatOK = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deleteLocalRef( env, jtiles );
|
deleteLocalRef( env, jtiles );
|
||||||
}
|
}
|
||||||
|
@ -2692,14 +2690,27 @@ Java_org_eehouse_android_xw4_jni_XwJNI_di_1init
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DIMinMax mm = { .min = minLen, .max = maxLen };
|
DictIter* iter = NULL;
|
||||||
data->iter = di_makeIter( data->dict, env, &mm, NULL, 0,
|
if ( formatOK ) {
|
||||||
!!jPatsArr ? patDescs : NULL, VSIZE(patDescs) );
|
DIMinMax mm = { .min = minLen, .max = maxLen };
|
||||||
|
iter = di_makeIter( dict, env, &mm, NULL, 0,
|
||||||
|
!!jPatsArr ? patDescs : NULL, VSIZE(patDescs) );
|
||||||
|
}
|
||||||
|
|
||||||
makeIndex( data );
|
if ( !!iter ) {
|
||||||
(void)di_firstWord( data->iter );
|
DictIterData* data = XP_CALLOC( globalState->mpool, sizeof(*data) );
|
||||||
|
data->iter = iter;
|
||||||
|
data->globalState = globalState;
|
||||||
|
data->dict = dict_ref( dict, env );
|
||||||
|
data->depth = 2;
|
||||||
|
#ifdef DEBUG
|
||||||
|
data->guard = GI_GUARD;
|
||||||
|
#endif
|
||||||
|
makeIndex( data );
|
||||||
|
(void)di_firstWord( data->iter );
|
||||||
|
|
||||||
closure = (jlong)data;
|
closure = (jlong)data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return closure;
|
return closure;
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,27 @@ typedef enum { PatErrNone,
|
||||||
PatErrDupInSet,
|
PatErrDupInSet,
|
||||||
} PatErr;
|
} PatErr;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static const XP_UCHAR*
|
||||||
|
patErrToStr( PatErr err )
|
||||||
|
{
|
||||||
|
const XP_UCHAR* result = NULL;
|
||||||
|
# define CASESTR(s) case s: result = #s; break
|
||||||
|
switch ( err ) {
|
||||||
|
CASESTR(PatErrNone);
|
||||||
|
CASESTR(PatErrMissingClose);
|
||||||
|
CASESTR(PatErrMultipleSpellings);
|
||||||
|
CASESTR(PatErrBadCountTerm);
|
||||||
|
CASESTR(PatErrNoDigit);
|
||||||
|
CASESTR(PatErrTooComplex);
|
||||||
|
CASESTR(PatErrBogusTiles);
|
||||||
|
CASESTR(PatErrDupInSet);
|
||||||
|
}
|
||||||
|
# undef CASESTR
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _ParseState {
|
typedef struct _ParseState {
|
||||||
const DictionaryCtxt* dict;
|
const DictionaryCtxt* dict;
|
||||||
const XP_UCHAR* pat;
|
const XP_UCHAR* pat;
|
||||||
|
@ -263,7 +284,19 @@ onFoundTiles( void* closure, const Tile* tiles, int len )
|
||||||
}
|
}
|
||||||
return 1 == len && PatErrNone == data->err;
|
return 1 == len && PatErrNone == data->err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PatErr
|
||||||
|
addElem( ParseState* ps, PatElem* elem )
|
||||||
|
{
|
||||||
|
PatErr err = PatErrNone;
|
||||||
|
if ( ps->elemIndex < VSIZE(ps->elems) ) {
|
||||||
|
ps->elems[ps->elemIndex++] = *elem;
|
||||||
|
} else {
|
||||||
|
err = PatErrTooComplex;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static PatErr
|
static PatErr
|
||||||
parseTile( ParseState* ps )
|
parseTile( ParseState* ps )
|
||||||
{
|
{
|
||||||
|
@ -390,9 +423,10 @@ compileParent( ParseState* ps )
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static PatErr
|
||||||
initPS( ParseState* ps, const DictionaryCtxt* dict )
|
initPS( ParseState* ps, const DictionaryCtxt* dict )
|
||||||
{
|
{
|
||||||
|
PatErr result = PatErrNone;
|
||||||
XP_MEMSET( ps, 0, sizeof(*ps) );
|
XP_MEMSET( ps, 0, sizeof(*ps) );
|
||||||
XP_ASSERT( !!dict );
|
XP_ASSERT( !!dict );
|
||||||
ps->dict = dict;
|
ps->dict = dict;
|
||||||
|
@ -407,8 +441,9 @@ initPS( ParseState* ps, const DictionaryCtxt* dict )
|
||||||
|
|
||||||
#ifdef WITH_START
|
#ifdef WITH_START
|
||||||
PatElem start = { .typ = START, };
|
PatElem start = { .typ = START, };
|
||||||
ps->elems[ps->elemIndex++] = start;
|
result = addElem( ps, &start );
|
||||||
#endif
|
#endif
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static XP_Bool
|
static XP_Bool
|
||||||
|
@ -416,19 +451,13 @@ compilePat( ParseState* ps, const XP_UCHAR* strPat )
|
||||||
{
|
{
|
||||||
ps->pat = strPat;
|
ps->pat = strPat;
|
||||||
ps->patIndex = 0;
|
ps->patIndex = 0;
|
||||||
// XP_ASSERT( !!iter->dict );
|
|
||||||
|
|
||||||
/* ParseState ps = { .dict = iter->dict, */
|
|
||||||
/* .pat = strPat, */
|
|
||||||
/* .blankMask = ((TileSet)1) << dict_getBlankTile( iter->dict ), */
|
|
||||||
/* }; */
|
|
||||||
PatErr err = compileParent( ps );
|
PatErr err = compileParent( ps );
|
||||||
|
|
||||||
XP_Bool success = err == PatErrNone && 0 < ps->elemIndex;
|
XP_Bool success = err == PatErrNone && 0 < ps->elemIndex;
|
||||||
/* if ( success ) { */
|
if ( !success ) {
|
||||||
/* XP_ASSERT( ps.elemIndex < VSIZE(ps.elems) ); */
|
XP_LOGFF( "=> %s", patErrToStr(err) );
|
||||||
/* replacePat( iter, &ps ); */
|
}
|
||||||
/* } */
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,34 +1338,40 @@ firstWord( DictIter* iter, XP_Bool log )
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static XP_Bool
|
||||||
addTilePats( ParseState* ps, const PatDesc* pd )
|
addTilePats( ParseState* ps, const PatDesc* pd )
|
||||||
{
|
{
|
||||||
|
XP_Bool success = XP_TRUE;
|
||||||
XP_Bool anyOrderOk = pd->anyOrderOk;
|
XP_Bool anyOrderOk = pd->anyOrderOk;
|
||||||
PatElem elem = { .typ = CHILD,
|
PatElem elem = { .typ = CHILD,
|
||||||
.minMatched = 1,
|
.minMatched = 1,
|
||||||
.maxMatched = 1,
|
.maxMatched = 1,
|
||||||
};
|
};
|
||||||
for ( int ii = 0; ii < pd->nTiles; ++ii ) {
|
for ( int ii = 0; success && ii < pd->nTiles; ++ii ) {
|
||||||
#ifdef MULTI_SET
|
#ifdef MULTI_SET
|
||||||
++elem.u.child.tiles.cnts[pd->tiles[ii]];
|
++elem.u.child.tiles.cnts[pd->tiles[ii]];
|
||||||
#else
|
#else
|
||||||
elem.u.child.tiles |= 1 << pd->tiles[ii];
|
elem.u.child.tiles |= 1 << pd->tiles[ii];
|
||||||
#endif
|
#endif
|
||||||
if ( !anyOrderOk ) {
|
if ( !anyOrderOk ) {
|
||||||
ps->elems[ps->elemIndex++] = elem;
|
success = ps->elemIndex < VSIZE(ps->elems);
|
||||||
|
if ( success ) {
|
||||||
|
success = PatErrNone == addElem( ps, &elem );
|
||||||
#ifdef MULTI_SET
|
#ifdef MULTI_SET
|
||||||
XP_MEMSET( &elem.u.child.tiles, 0, sizeof(elem.u.child.tiles) );
|
XP_MEMSET( &elem.u.child.tiles, 0, sizeof(elem.u.child.tiles) );
|
||||||
#else
|
#else
|
||||||
elem.u.child.tiles = 0;
|
elem.u.child.tiles = 0;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( anyOrderOk ) {
|
if ( anyOrderOk ) {
|
||||||
elem.u.child.flags |= FLAG_SINGLE;
|
elem.u.child.flags |= FLAG_SINGLE;
|
||||||
elem.minMatched = elem.maxMatched = pd->nTiles;
|
elem.minMatched = elem.maxMatched = pd->nTiles;
|
||||||
ps->elems[ps->elemIndex++] = elem;
|
success = PatErrNone == addElem( ps, &elem );
|
||||||
}
|
}
|
||||||
|
LOG_RETURNF( "%s", boolToStr(success) );
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1351,7 +1386,12 @@ addWildcard( ParseState* ps )
|
||||||
#else
|
#else
|
||||||
elem.u.child.tiles = ps->blankMask;
|
elem.u.child.tiles = ps->blankMask;
|
||||||
#endif
|
#endif
|
||||||
ps->elems[ps->elemIndex++] = elem;
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
PatErr err =
|
||||||
|
#endif
|
||||||
|
addElem( ps, &elem );
|
||||||
|
XP_ASSERT( err == PatErrNone );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1404,11 +1444,13 @@ di_makeIter( const DictionaryCtxt* dict, XWEnv xwe, const DIMinMax* minmax,
|
||||||
if ( ii != STARTS_WITH ) {
|
if ( ii != STARTS_WITH ) {
|
||||||
addWildcard( &ps );
|
addWildcard( &ps );
|
||||||
}
|
}
|
||||||
addTilePats( &ps, ta );
|
success = addTilePats( &ps, ta );
|
||||||
if ( ii != ENDS_WITH ) {
|
if ( success ) {
|
||||||
addWildcard( &ps );
|
if ( ii != ENDS_WITH ) {
|
||||||
|
addWildcard( &ps );
|
||||||
|
}
|
||||||
|
copyParsedPat( dict, &pats[nUsed++], &ps, NULL );
|
||||||
}
|
}
|
||||||
copyParsedPat( dict, &pats[nUsed++], &ps, NULL );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ typedef struct DictIter DictIter;
|
||||||
* ends-with. The first is more powerful but I'm not sure it'll ever be part
|
* ends-with. The first is more powerful but I'm not sure it'll ever be part
|
||||||
* of a shipping UI.*/
|
* of a shipping UI.*/
|
||||||
typedef struct _PatDesc {
|
typedef struct _PatDesc {
|
||||||
Tile tiles[16];
|
Tile tiles[MAX_COLS_DICT];
|
||||||
XP_U16 nTiles;
|
XP_U16 nTiles;
|
||||||
XP_Bool anyOrderOk;
|
XP_Bool anyOrderOk;
|
||||||
} PatDesc;
|
} PatDesc;
|
||||||
|
|
|
@ -1948,7 +1948,6 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) )
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct _FTD {
|
typedef struct _FTD {
|
||||||
PatDesc* desc;
|
PatDesc* desc;
|
||||||
XP_Bool called;
|
XP_Bool called;
|
||||||
|
@ -1960,9 +1959,7 @@ onFoundTiles2( void* closure, const Tile* tiles, int nTiles )
|
||||||
FTD* data = (FTD*)closure;
|
FTD* data = (FTD*)closure;
|
||||||
if ( data->called ) {
|
if ( data->called ) {
|
||||||
XP_LOGFF( "ERROR: called more than once; Hungarian case???" );
|
XP_LOGFF( "ERROR: called more than once; Hungarian case???" );
|
||||||
} else if ( nTiles > VSIZE(data->desc->tiles) ) {
|
} else if ( nTiles <= VSIZE(data->desc->tiles) ) {
|
||||||
XP_ASSERT(0);
|
|
||||||
} else {
|
|
||||||
data->called = XP_TRUE;
|
data->called = XP_TRUE;
|
||||||
data->desc->nTiles = nTiles;
|
data->desc->nTiles = nTiles;
|
||||||
XP_MEMCPY( &data->desc->tiles[0], tiles, nTiles * sizeof(tiles[0]) );
|
XP_MEMCPY( &data->desc->tiles[0], tiles, nTiles * sizeof(tiles[0]) );
|
||||||
|
@ -2014,7 +2011,10 @@ patsParamsToIter( const LaunchParams* params, const DictionaryCtxt* dict )
|
||||||
}
|
}
|
||||||
|
|
||||||
DictIter* iter = di_makeIter( dict, NULL_XWE, dimmp, strPats, nStrPats,
|
DictIter* iter = di_makeIter( dict, NULL_XWE, dimmp, strPats, nStrPats,
|
||||||
descs, nPatDescs );
|
nPatDescs == 0 ? NULL : descs, nPatDescs );
|
||||||
|
if ( !iter ) {
|
||||||
|
XP_LOGFF( "Unable to build iter" );
|
||||||
|
}
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2025,37 +2025,39 @@ testGetNthWord( const LaunchParams* params, const DictionaryCtxt* dict,
|
||||||
const IndexData* data )
|
const IndexData* data )
|
||||||
{
|
{
|
||||||
DictIter* iter = patsParamsToIter( params, dict );
|
DictIter* iter = patsParamsToIter( params, dict );
|
||||||
XP_U32 half = di_countWords( iter, NULL ) / 2;
|
if ( !!iter ) {
|
||||||
XP_U32 interval = half / 100;
|
XP_U32 half = di_countWords( iter, NULL ) / 2;
|
||||||
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
XP_U32 interval = half / 100;
|
||||||
if ( interval == 0 ) {
|
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
||||||
++interval;
|
if ( interval == 0 ) {
|
||||||
}
|
++interval;
|
||||||
|
}
|
||||||
|
|
||||||
XP_UCHAR buf[64];
|
XP_UCHAR buf[64];
|
||||||
int ii, jj;
|
int ii, jj;
|
||||||
for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) {
|
for ( ii = 0, jj = half; ii < half; ii += interval, jj += interval ) {
|
||||||
if ( di_getNthWord( iter, NULL_XWE, ii, depth, data ) ) {
|
if ( di_getNthWord( iter, NULL_XWE, ii, depth, data ) ) {
|
||||||
XP_UCHAR buf[64];
|
XP_UCHAR buf[64];
|
||||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||||
XP_ASSERT( 0 == strcmp( buf, words[ii] ) );
|
XP_ASSERT( 0 == strcmp( buf, words[ii] ) );
|
||||||
# ifdef PRINT_ALL
|
# ifdef PRINT_ALL
|
||||||
XP_LOGFF( "word[%d]: %s", ii, buf );
|
XP_LOGFF( "word[%d]: %s", ii, buf );
|
||||||
# endif
|
# endif
|
||||||
} else {
|
} else {
|
||||||
XP_ASSERT( 0 );
|
XP_ASSERT( 0 );
|
||||||
}
|
}
|
||||||
if ( di_getNthWord( iter, NULL_XWE, jj, depth, data ) ) {
|
if ( di_getNthWord( iter, NULL_XWE, jj, depth, data ) ) {
|
||||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||||
XP_ASSERT( 0 == strcmp( buf, words[jj] ) );
|
XP_ASSERT( 0 == strcmp( buf, words[jj] ) );
|
||||||
# ifdef PRINT_ALL
|
# ifdef PRINT_ALL
|
||||||
XP_LOGFF( "word[%d]: %s", jj, buf );
|
XP_LOGFF( "word[%d]: %s", jj, buf );
|
||||||
# endif
|
# endif
|
||||||
} else {
|
} else {
|
||||||
XP_ASSERT( 0 );
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
di_freeIter( iter, NULL_XWE );
|
||||||
}
|
}
|
||||||
di_freeIter( iter, NULL_XWE );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _FTData {
|
typedef struct _FTData {
|
||||||
|
@ -2109,124 +2111,126 @@ walk_dict_test( MPFORMAL const LaunchParams* params, const DictionaryCtxt* dict,
|
||||||
{
|
{
|
||||||
|
|
||||||
DictIter* iter = patsParamsToIter( params, dict );
|
DictIter* iter = patsParamsToIter( params, dict );
|
||||||
LengthsArray lens;
|
if ( !!iter ) {
|
||||||
XP_U32 count = di_countWords( iter, &lens );
|
LengthsArray lens;
|
||||||
|
XP_U32 count = di_countWords( iter, &lens );
|
||||||
|
|
||||||
XP_U32 sum = 0;
|
XP_U32 sum = 0;
|
||||||
for ( long ii = 0; ii < VSIZE(lens.lens); ++ii ) {
|
for ( long ii = 0; ii < VSIZE(lens.lens); ++ii ) {
|
||||||
XP_LOGF( "%d words of length %ld", lens.lens[ii], ii );
|
XP_LOGF( "%d words of length %ld", lens.lens[ii], ii );
|
||||||
sum += lens.lens[ii];
|
sum += lens.lens[ii];
|
||||||
}
|
|
||||||
XP_ASSERT( sum == count );
|
|
||||||
|
|
||||||
if ( count > 0 ) {
|
|
||||||
const XP_UCHAR* delim = params->dumpDelim;
|
|
||||||
XP_Bool gotOne;
|
|
||||||
long jj;
|
|
||||||
char** words = g_malloc( count * sizeof(char*) );
|
|
||||||
XP_ASSERT( !!words );
|
|
||||||
|
|
||||||
for ( jj = 0, gotOne = di_firstWord( iter );
|
|
||||||
gotOne;
|
|
||||||
gotOne = di_getNextWord( iter ) ) {
|
|
||||||
XP_ASSERT( di_getPosition( iter ) == jj );
|
|
||||||
XP_UCHAR buf[64];
|
|
||||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
|
||||||
# ifdef PRINT_ALL
|
|
||||||
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
|
||||||
# endif
|
|
||||||
if ( !!words ) {
|
|
||||||
words[jj] = g_strdup( buf );
|
|
||||||
}
|
|
||||||
++jj;
|
|
||||||
}
|
}
|
||||||
XP_ASSERT( count == jj );
|
XP_ASSERT( sum == count );
|
||||||
|
|
||||||
XP_LOGFF( "comparing runs in both directions" );
|
if ( count > 0 ) {
|
||||||
for ( jj = 0, gotOne = di_lastWord( iter );
|
const XP_UCHAR* delim = params->dumpDelim;
|
||||||
gotOne;
|
XP_Bool gotOne;
|
||||||
++jj, gotOne = di_getPrevWord( iter ) ) {
|
long jj;
|
||||||
XP_ASSERT( di_getPosition(iter) == count-jj-1 );
|
char** words = g_malloc( count * sizeof(char*) );
|
||||||
XP_UCHAR buf[64];
|
XP_ASSERT( !!words );
|
||||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
|
||||||
|
for ( jj = 0, gotOne = di_firstWord( iter );
|
||||||
|
gotOne;
|
||||||
|
gotOne = di_getNextWord( iter ) ) {
|
||||||
|
XP_ASSERT( di_getPosition( iter ) == jj );
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||||
# ifdef PRINT_ALL
|
# ifdef PRINT_ALL
|
||||||
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||||
# endif
|
# endif
|
||||||
if ( !!words ) {
|
if ( !!words ) {
|
||||||
if ( strcmp( buf, words[count-jj-1] ) ) {
|
words[jj] = g_strdup( buf );
|
||||||
fprintf( stderr, "failure at %ld: %s going forward; %s "
|
}
|
||||||
"going backward\n", jj, words[count-jj-1], buf );
|
++jj;
|
||||||
break;
|
}
|
||||||
|
XP_ASSERT( count == jj );
|
||||||
|
|
||||||
|
XP_LOGFF( "comparing runs in both directions" );
|
||||||
|
for ( jj = 0, gotOne = di_lastWord( iter );
|
||||||
|
gotOne;
|
||||||
|
++jj, gotOne = di_getPrevWord( iter ) ) {
|
||||||
|
XP_ASSERT( di_getPosition(iter) == count-jj-1 );
|
||||||
|
XP_UCHAR buf[64];
|
||||||
|
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||||
|
# ifdef PRINT_ALL
|
||||||
|
fprintf( stderr, "%.6ld: %s\n", jj, buf );
|
||||||
|
# endif
|
||||||
|
if ( !!words ) {
|
||||||
|
if ( strcmp( buf, words[count-jj-1] ) ) {
|
||||||
|
fprintf( stderr, "failure at %ld: %s going forward; %s "
|
||||||
|
"going backward\n", jj, words[count-jj-1], buf );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
XP_ASSERT( count == jj );
|
||||||
XP_ASSERT( count == jj );
|
XP_LOGFF( "FINISHED comparing runs in both directions" );
|
||||||
XP_LOGFF( "FINISHED comparing runs in both directions" );
|
|
||||||
|
|
||||||
XP_LOGFF( "testing getNth" );
|
XP_LOGFF( "testing getNth" );
|
||||||
testGetNthWord( params, dict, words, 0, NULL );
|
testGetNthWord( params, dict, words, 0, NULL );
|
||||||
XP_LOGFF( "FINISHED testing getNth" );
|
XP_LOGFF( "FINISHED testing getNth" );
|
||||||
|
|
||||||
XP_U16 depth = 2;
|
XP_U16 depth = 2;
|
||||||
XP_U16 maxCount = dict_numTileFaces( dict );
|
XP_U16 maxCount = dict_numTileFaces( dict );
|
||||||
IndexData data;
|
IndexData data;
|
||||||
data.count = maxCount * maxCount; /* squared because depth == 2! */
|
data.count = maxCount * maxCount; /* squared because depth == 2! */
|
||||||
data.indices = XP_MALLOC( mpool,
|
data.indices = XP_MALLOC( mpool,
|
||||||
data.count * depth * sizeof(data.indices[0]) );
|
data.count * depth * sizeof(data.indices[0]) );
|
||||||
data.prefixes = XP_MALLOC( mpool,
|
data.prefixes = XP_MALLOC( mpool,
|
||||||
depth * data.count * sizeof(data.prefixes[0]) );
|
depth * data.count * sizeof(data.prefixes[0]) );
|
||||||
|
|
||||||
XP_LOGF( "making index..." );
|
XP_LOGF( "making index..." );
|
||||||
di_makeIndex( iter, depth, &data );
|
di_makeIndex( iter, depth, &data );
|
||||||
XP_LOGF( "DONE making index (have %d indices)", data.count );
|
XP_LOGF( "DONE making index (have %d indices)", data.count );
|
||||||
|
|
||||||
/* Resize 'em in case not all slots filled */
|
/* Resize 'em in case not all slots filled */
|
||||||
data.indices = XP_REALLOC( mpool, data.indices,
|
data.indices = XP_REALLOC( mpool, data.indices,
|
||||||
data.count * depth * sizeof(*data.indices) );
|
data.count * depth * sizeof(*data.indices) );
|
||||||
data.prefixes = XP_REALLOC( mpool, data.prefixes,
|
data.prefixes = XP_REALLOC( mpool, data.prefixes,
|
||||||
depth * data.count * sizeof(*data.prefixes) );
|
depth * data.count * sizeof(*data.prefixes) );
|
||||||
#if 0
|
#if 0
|
||||||
for ( ii = 0; ii < nIndices; ++ii ) {
|
for ( ii = 0; ii < nIndices; ++ii ) {
|
||||||
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
|
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
|
||||||
XP_ASSERT( 0 );
|
XP_ASSERT( 0 );
|
||||||
|
}
|
||||||
|
XP_ASSERT( word.index == indices[ii] );
|
||||||
|
XP_UCHAR buf1[64];
|
||||||
|
dict_wordToString( dict, &word, buf1, VSIZE(buf1), delim );
|
||||||
|
XP_UCHAR buf2[64] = {0};
|
||||||
|
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
|
||||||
|
dict_wordToString( dict, &word, buf2, VSIZE(buf2), delim );
|
||||||
|
}
|
||||||
|
char prfx[8];
|
||||||
|
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx,
|
||||||
|
VSIZE(prfx), NULL );
|
||||||
|
fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
|
||||||
|
ii, indices[ii], prfx, buf1, buf2 );
|
||||||
}
|
}
|
||||||
XP_ASSERT( word.index == indices[ii] );
|
|
||||||
XP_UCHAR buf1[64];
|
|
||||||
dict_wordToString( dict, &word, buf1, VSIZE(buf1), delim );
|
|
||||||
XP_UCHAR buf2[64] = {0};
|
|
||||||
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
|
|
||||||
dict_wordToString( dict, &word, buf2, VSIZE(buf2), delim );
|
|
||||||
}
|
|
||||||
char prfx[8];
|
|
||||||
dict_tilesToString( dict, &prefixes[depth*ii], depth, prfx,
|
|
||||||
VSIZE(prfx), NULL );
|
|
||||||
fprintf( stderr, "%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
|
|
||||||
ii, indices[ii], prfx, buf1, buf2 );
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
XP_LOGFF( "testing getNth WITH INDEXING" );
|
XP_LOGFF( "testing getNth WITH INDEXING" );
|
||||||
testGetNthWord( params, dict, words, depth, &data );
|
testGetNthWord( params, dict, words, depth, &data );
|
||||||
XP_LOGFF( "DONE testing getNth WITH INDEXING" );
|
XP_LOGFF( "DONE testing getNth WITH INDEXING" );
|
||||||
|
|
||||||
if ( !!testPrefixes ) {
|
if ( !!testPrefixes ) {
|
||||||
int ii;
|
int ii;
|
||||||
guint count = g_slist_length( testPrefixes );
|
guint count = g_slist_length( testPrefixes );
|
||||||
for ( ii = 0; ii < count; ++ii ) {
|
for ( ii = 0; ii < count; ++ii ) {
|
||||||
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
|
gchar* prefix = (gchar*)g_slist_nth_data( testPrefixes, ii );
|
||||||
XP_LOGFF( "prefix %d: %s", ii, prefix );
|
XP_LOGFF( "prefix %d: %s", ii, prefix );
|
||||||
|
|
||||||
FTData foundTilesData = { .iter = iter, .words = words,
|
FTData foundTilesData = { .iter = iter, .words = words,
|
||||||
.depth = depth, .data = &data,
|
.depth = depth, .data = &data,
|
||||||
.prefix = prefix, };
|
.prefix = prefix, };
|
||||||
dict_tilesForString( dict, prefix, 0, onFoundTiles, &foundTilesData );
|
dict_tilesForString( dict, prefix, 0, onFoundTiles, &foundTilesData );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
XP_FREE( mpool, data.indices );
|
||||||
|
XP_FREE( mpool, data.prefixes );
|
||||||
}
|
}
|
||||||
XP_FREE( mpool, data.indices );
|
di_freeIter( iter, NULL_XWE );
|
||||||
XP_FREE( mpool, data.prefixes );
|
|
||||||
}
|
}
|
||||||
di_freeIter( iter, NULL_XWE );
|
XP_LOGFF( "done" );
|
||||||
XP_LOGF( "done" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2253,15 +2257,17 @@ static void
|
||||||
dumpDict( const LaunchParams* params, DictionaryCtxt* dict )
|
dumpDict( const LaunchParams* params, DictionaryCtxt* dict )
|
||||||
{
|
{
|
||||||
DictIter* iter = patsParamsToIter( params, dict );
|
DictIter* iter = patsParamsToIter( params, dict );
|
||||||
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
if ( !!iter ) {
|
||||||
for ( XP_Bool result = di_firstWord( iter );
|
const XP_UCHAR* delim = params->dumpDelim; /* NULL is ok */
|
||||||
result;
|
for ( XP_Bool result = di_firstWord( iter );
|
||||||
result = di_getNextWord( iter ) ) {
|
result;
|
||||||
XP_UCHAR buf[32];
|
result = di_getNextWord( iter ) ) {
|
||||||
di_wordToString( iter, buf, VSIZE(buf), delim );
|
XP_UCHAR buf[32];
|
||||||
fprintf( stdout, "%s\n", buf );
|
di_wordToString( iter, buf, VSIZE(buf), delim );
|
||||||
|
fprintf( stdout, "%s\n", buf );
|
||||||
|
}
|
||||||
|
di_freeIter( iter, NULL_XWE );
|
||||||
}
|
}
|
||||||
di_freeIter( iter, NULL_XWE );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2662,10 +2668,12 @@ testOneString( const LaunchParams* params, GSList* testDicts )
|
||||||
params->useMmap );
|
params->useMmap );
|
||||||
if ( NULL != dict ) {
|
if ( NULL != dict ) {
|
||||||
DictIter* iter = patsParamsToIter( params, dict );
|
DictIter* iter = patsParamsToIter( params, dict );
|
||||||
if ( ! di_stringMatches( iter, params->iterTestPatStr ) ) {
|
if ( !!iter ) {
|
||||||
result = 1;
|
if ( ! di_stringMatches( iter, params->iterTestPatStr ) ) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
di_freeIter( iter, NULL_XWE );
|
||||||
}
|
}
|
||||||
di_freeIter( iter, NULL_XWE );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Add table
Reference in a new issue