xwords/xwords4/common/dictnry.c

777 lines
21 KiB
C
Raw Normal View History

2003-11-01 06:35:29 +01:00
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997-2000 by Eric House (xwords@eehouse.org). All rights reserved.
2003-11-01 06:35:29 +01:00
*
* 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
* of the License, 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef USE_STDIO
# include <stdio.h>
# include <stdlib.h>
#endif
#include "comtypes.h"
#include "dictnryp.h"
#include "xwstream.h"
#include "strutils.h"
#include "game.h"
2003-11-01 06:35:29 +01:00
#ifdef CPLUS
extern "C" {
#endif
/*****************************************************************************
*
****************************************************************************/
void
setBlankTile( DictionaryCtxt* dict )
2003-11-01 06:35:29 +01:00
{
XP_U16 ii;
2003-11-01 06:35:29 +01:00
dict->blankTile = -1; /* no known blank */
2003-11-01 06:35:29 +01:00
for ( ii = 0; ii < dict->nFaces; ++ii ) {
if ( dict->facePtrs[ii][0] == 0 ) {
XP_ASSERT( dict->blankTile == -1 ); /* only one passes test? */
dict->blankTile = (XP_S8)ii;
#ifndef DEBUG
2003-11-01 06:35:29 +01:00
break;
#endif
2003-11-01 06:35:29 +01:00
}
}
} /* setBlankTile */
/* #if defined BLANKS_FIRST || defined DEBUG */
2003-11-01 06:35:29 +01:00
XP_Bool
dict_hasBlankTile( const DictionaryCtxt* dict )
2003-11-01 06:35:29 +01:00
{
return dict->blankTile >= 0;
} /* dict_hasBlankTile */
/* #endif */
2003-11-01 06:35:29 +01:00
Tile
dict_getBlankTile( const DictionaryCtxt* dict )
2003-11-01 06:35:29 +01:00
{
XP_ASSERT( dict_hasBlankTile(dict) );
return (Tile)dict->blankTile;
} /* dict_getBlankTile */
XP_U16
dict_getTileValue( const DictionaryCtxt* dict, Tile tile )
2003-11-01 06:35:29 +01:00
{
if ( (tile & TILE_VALUE_MASK) != tile ) {
XP_ASSERT( tile == 32 &&
tile == dict_getBlankTile( dict ) );
}
2003-11-01 06:35:29 +01:00
XP_ASSERT( tile < dict->nFaces );
tile *= 2;
return dict->countsAndValues[tile+1];
} /* dict_getTileValue */
static const XP_UCHAR*
dict_getTileStringRaw( const DictionaryCtxt* dict, Tile tile )
{
XP_ASSERT( tile < dict->nFaces );
return dict->facePtrs[tile];
}
const XP_UCHAR*
dict_getTileString( const DictionaryCtxt* dict, Tile tile )
2003-11-01 06:35:29 +01:00
{
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tile );
if ( IS_SPECIAL(*facep) ) {
facep = dict->chars[(XP_U16)*facep];
}
return facep;
}
2003-11-01 06:35:29 +01:00
XP_U16
dict_numTiles( const DictionaryCtxt* dict, Tile tile )
2003-11-01 06:35:29 +01:00
{
tile *= 2;
return dict->countsAndValues[tile];
} /* dict_numTiles */
XP_U16
dict_numTileFaces( const DictionaryCtxt* dict )
2003-11-01 06:35:29 +01:00
{
return dict->nFaces;
} /* dict_numTileFaces */
XP_U16
dict_tilesToString( const DictionaryCtxt* dict, const Tile* tiles,
XP_U16 nTiles, XP_UCHAR* buf, XP_U16 bufSize )
2003-11-01 06:35:29 +01:00
{
XP_UCHAR* bufp = buf;
XP_UCHAR* end = bufp + bufSize;
XP_U16 result = 0;
2003-11-01 06:35:29 +01:00
while ( nTiles-- ) {
Tile tile = *tiles++;
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tile );
if ( IS_SPECIAL(*facep) ) {
XP_UCHAR* chars = dict->chars[(XP_U16)*facep];
XP_U16 len = XP_STRLEN( chars );
if ( bufp + len >= end ) {
bufp = NULL;
break;
}
XP_MEMCPY( bufp, chars, len );
bufp += len;
} else {
XP_ASSERT ( tile != dict->blankTile ); /* printing blank should be
handled by specials
mechanism */
if ( bufp + 1 >= end ) {
bufp = NULL;
break;
}
bufp += XP_SNPRINTF( bufp, end - bufp, XP_S, facep );
2003-11-01 06:35:29 +01:00
}
}
if ( bufp != NULL && bufp < end ) {
*bufp = '\0';
result = bufp - buf;
}
return result;
2003-11-01 06:35:29 +01:00
} /* dict_tilesToString */
/* dict_tileForString: used to map user keys to tiles in the tray. Returns
* EMPTY_TILE if no match found.
*/
2003-11-01 06:35:29 +01:00
Tile
dict_tileForString( const DictionaryCtxt* dict, const XP_UCHAR* key )
2003-11-01 06:35:29 +01:00
{
XP_U16 nFaces = dict_numTileFaces( dict );
Tile tile = EMPTY_TILE;
XP_U16 ii;
for ( ii = 0; ii < nFaces; ++ii ) {
if ( ii != dict->blankTile ) {
const XP_UCHAR* facep = dict_getTileString( dict, ii );
if ( 0 == XP_STRCMP( facep, key ) ) {
tile = (Tile)ii;
break;
2003-11-01 06:35:29 +01:00
}
}
}
return tile;
2003-11-01 06:35:29 +01:00
} /* dict_tileForChar */
XP_Bool
dict_tilesAreSame( const DictionaryCtxt* dict1, const DictionaryCtxt* dict2 )
2003-11-01 06:35:29 +01:00
{
XP_Bool result = XP_FALSE;
2011-04-26 05:17:54 +02:00
XP_ASSERT( !!dict1 );
XP_ASSERT( !!dict2 );
Tile ii;
2003-11-01 06:35:29 +01:00
XP_U16 nTileFaces = dict_numTileFaces( dict1 );
if ( nTileFaces == dict_numTileFaces( dict2 ) ) {
for ( ii = 0; ii < nTileFaces; ++ii ) {
2003-11-01 06:35:29 +01:00
const XP_UCHAR* face1;
const XP_UCHAR* face2;
2003-11-01 06:35:29 +01:00
if ( dict_getTileValue( dict1, ii )
!= dict_getTileValue( dict2, ii ) ){
2003-11-01 06:35:29 +01:00
break;
}
face1 = dict_getTileStringRaw( dict1, ii );
face2 = dict_getTileStringRaw( dict2, ii );
if ( IS_SPECIAL(*face1) != IS_SPECIAL(*face2) ) {
2003-11-01 06:35:29 +01:00
break;
}
if ( IS_SPECIAL(*face1) ) {
XP_UCHAR* chars1 = dict1->chars[(int)*face1];
XP_UCHAR* chars2 = dict2->chars[(int)*face2];
2003-11-01 06:35:29 +01:00
XP_U16 len = XP_STRLEN(chars1);
if ( 0 != XP_STRNCMP( chars1, chars2, len ) ) {
break;
}
} else if ( 0 != XP_STRCMP( face1, face2 ) ) {
2003-11-01 06:35:29 +01:00
break;
}
if ( dict_numTiles( dict1, ii ) != dict_numTiles( dict2, ii ) ) {
2003-11-01 06:35:29 +01:00
break;
}
}
result = ii == nTileFaces; /* did we get that far */
2003-11-01 06:35:29 +01:00
}
return result;
} /* dict_tilesAreSame */
#ifndef XWFEATURE_STANDALONE_ONLY
static void
ucharsToNarrow( const DictionaryCtxt* dict, XP_UCHAR* buf, XP_U16* bufsizep )
{
XP_U16 ii;
XP_U16 nUsed = 0;
XP_U16 bufsize = *bufsizep;
for ( ii = 0; ii < dict->nFaces; ++ii ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, ii );
if ( IS_SPECIAL(*facep) ) {
buf[nUsed++] = *facep;
} else {
nUsed += XP_SNPRINTF( &buf[nUsed], bufsize - nUsed, "%s", facep );
}
XP_ASSERT( nUsed < bufsize );
}
buf[nUsed] = 0;
*bufsizep = nUsed;
}
2003-11-01 06:35:29 +01:00
void
dict_writeToStream( const DictionaryCtxt* dict, XWStreamCtxt* stream )
2003-11-01 06:35:29 +01:00
{
XP_U16 maxCount = 0;
XP_U16 maxValue = 0;
XP_U16 ii, nSpecials;
2003-11-01 06:35:29 +01:00
XP_U16 maxCountBits, maxValueBits;
XP_UCHAR buf[64];
XP_U16 nBytes;
2003-11-01 06:35:29 +01:00
stream_putBits( stream, 6, dict->nFaces );
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
2003-11-01 06:35:29 +01:00
XP_U16 count, value;
count = dict->countsAndValues[ii];
2003-11-01 06:35:29 +01:00
if ( maxCount < count ) {
maxCount = count;
}
value = dict->countsAndValues[ii+1];
2003-11-01 06:35:29 +01:00
if ( maxValue < value ) {
maxValue = value;
}
}
maxCountBits = bitsForMax( maxCount );
maxValueBits = bitsForMax( maxValue );
stream_putBits( stream, 3, maxCountBits ); /* won't be bigger than 5 */
stream_putBits( stream, 3, maxValueBits );
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
stream_putBits( stream, maxCountBits, dict->countsAndValues[ii] );
stream_putBits( stream, maxValueBits, dict->countsAndValues[ii+1] );
2003-11-01 06:35:29 +01:00
}
/* Stream format of the faces is unchanged: chars run together, which
* happens to equal utf-8 for ascii. But now there may be more than one
* byte per face. Old code assumes that, but compatibility is ensured by
* the caller which will not accept an incoming message if the version's
* too new. And utf-8 dicts are flagged as newer by the sender.
*/
nBytes = sizeof(buf);
ucharsToNarrow( dict, buf, &nBytes );
stream_putU8( stream, nBytes );
stream_putBytes( stream, buf, nBytes );
2003-11-01 06:35:29 +01:00
for ( nSpecials = ii = 0; ii < dict->nFaces; ++ii ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, (Tile)ii );
if ( IS_SPECIAL( *facep ) ) {
2003-11-01 06:35:29 +01:00
stringToStream( stream, dict->chars[nSpecials++] );
}
}
} /* dict_writeToStream */
#endif
2003-11-01 06:35:29 +01:00
static void
freeSpecials( DictionaryCtxt* dict )
{
Tile tt;
2003-11-01 06:35:29 +01:00
XP_U16 nSpecials;
for ( nSpecials = tt = 0; tt < dict->nFaces; ++tt ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tt );
if ( IS_SPECIAL( *facep ) ) {
2003-11-01 06:35:29 +01:00
XP_ASSERT( !!dict->chars[nSpecials] );
XP_FREE( dict->mpool, dict->chars[nSpecials] );
XP_FREEP( dict->mpool, &dict->bitmaps[nSpecials].largeBM );
XP_FREEP( dict->mpool, &dict->bitmaps[nSpecials].smallBM );
2003-11-01 06:35:29 +01:00
++nSpecials;
}
}
if ( nSpecials > 0 ) {
XP_FREE( dict->mpool, dict->chars );
XP_FREE( dict->mpool, dict->bitmaps );
}
} /* freeSpecials */
static void
common_destructor( DictionaryCtxt* dict )
{
freeSpecials( dict );
XP_FREE( dict->mpool, dict->countsAndValues );
XP_FREE( dict->mpool, dict->faces );
XP_FREE( dict->mpool, dict->facePtrs );
2003-11-01 06:35:29 +01:00
XP_FREE( dict->mpool, dict );
} /* common_destructor */
2003-11-01 06:35:29 +01:00
#ifndef XWFEATURE_STANDALONE_ONLY
2003-11-01 06:35:29 +01:00
void
dict_loadFromStream( DictionaryCtxt* dict, XWStreamCtxt* stream )
{
XP_U8 nFaces, nFaceBytes;
2003-11-01 06:35:29 +01:00
XP_U16 maxCountBits, maxValueBits;
XP_U16 ii, nSpecials;
2003-11-01 06:35:29 +01:00
XP_UCHAR* localTexts[32];
XP_U8 utf8[MAX_UNIQUE_TILES];
2003-11-01 06:35:29 +01:00
XP_ASSERT( !dict->destructor );
dict->destructor = common_destructor;
dict->func_dict_getShortName = dict_getName; /* default */
2003-11-01 06:35:29 +01:00
nFaces = (XP_U8)stream_getBits( stream, 6 );
maxCountBits = (XP_U16)stream_getBits( stream, 3 );
maxValueBits = (XP_U16)stream_getBits( stream, 3 );
dict->nFaces = nFaces;
dict->countsAndValues =
(XP_U8*)XP_MALLOC( dict->mpool,
sizeof(dict->countsAndValues[0]) * nFaces * 2 );
for ( ii = 0; ii < dict->nFaces*2; ii+=2 ) {
dict->countsAndValues[ii] = (XP_U8)stream_getBits( stream,
maxCountBits );
dict->countsAndValues[ii+1] = (XP_U8)stream_getBits( stream,
maxValueBits );
2003-11-01 06:35:29 +01:00
}
nFaceBytes = (XP_U8)stream_getU8( stream );
XP_ASSERT( nFaceBytes < VSIZE(utf8) );
stream_getBytes( stream, utf8, nFaceBytes );
dict->isUTF8 = XP_TRUE; /* need to communicate this in stream */
dict_splitFaces( dict, utf8, nFaceBytes, nFaces );
for ( nSpecials = ii = 0; ii < nFaces; ++ii ) {
const XP_UCHAR* facep = dict_getTileStringRaw( dict, (Tile)ii );
if ( IS_SPECIAL( *facep ) ) {
XP_UCHAR* txt = stringFromStream( dict->mpool, stream );
2003-11-01 06:35:29 +01:00
XP_ASSERT( !!txt );
localTexts[nSpecials] = txt;
++nSpecials;
}
}
if ( nSpecials > 0 ) {
dict->bitmaps =
(SpecialBitmaps*)XP_MALLOC( dict->mpool,
nSpecials * sizeof(*dict->bitmaps) );
XP_MEMSET( dict->bitmaps, 0, nSpecials * sizeof(*dict->bitmaps) );
dict->chars = (XP_UCHAR**)XP_MALLOC( dict->mpool,
nSpecials * sizeof(*dict->chars) );
XP_MEMCPY(dict->chars, localTexts, nSpecials * sizeof(*dict->chars));
}
setBlankTile( dict );
} /* dict_loadFromStream */
#endif
2003-11-01 06:35:29 +01:00
#ifdef TEXT_MODEL
/* Return the strlen of the longest face, e.g. 1 for English and Italian;
2 for Spanish; 3 for Catalan */
XP_U16
dict_getMaxWidth( const DictionaryCtxt* dict )
{
XP_U16 result = 0;
Tile tile;
XP_U16 nFaces = dict_numTileFaces( dict );
for ( tile = 0; tile < nFaces; ++tile ) {
const XP_UCHAR* face = dict_getTileString( dict, tile );
XP_U16 len = XP_STRLEN( face );
if ( len > result ) {
result = len;
}
}
return result;
}
#endif
2006-09-24 17:28:15 +02:00
const XP_UCHAR*
dict_getName( const DictionaryCtxt* dict )
2003-11-01 06:35:29 +01:00
{
XP_ASSERT( !!dict );
XP_ASSERT( !!dict->name );
2003-11-01 06:35:29 +01:00
return dict->name;
} /* dict_getName */
XP_Bool
dict_isUTF8( const DictionaryCtxt* dict )
{
XP_ASSERT( !!dict );
return dict->isUTF8;
}
2003-11-01 06:35:29 +01:00
XP_Bool
dict_faceIsBitmap( const DictionaryCtxt* dict, Tile tile )
2003-11-01 06:35:29 +01:00
{
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tile );
return IS_SPECIAL(*facep) && (tile != dict->blankTile);
2003-11-01 06:35:29 +01:00
} /* dict_faceIsBitmap */
void
dict_getFaceBitmaps( const DictionaryCtxt* dict, Tile tile, XP_Bitmaps* bmps )
2003-11-01 06:35:29 +01:00
{
SpecialBitmaps* bitmaps;
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tile );
2003-11-01 06:35:29 +01:00
XP_ASSERT( dict_faceIsBitmap( dict, tile ) );
XP_ASSERT( !!dict->bitmaps );
bitmaps = &dict->bitmaps[(XP_U16)*facep];
bmps->nBitmaps = 2;
bmps->bmps[0] = bitmaps->smallBM;
bmps->bmps[1] = bitmaps->largeBM;
2009-01-25 21:31:13 +01:00
} /* dict_getFaceBitmaps */
2003-11-01 06:35:29 +01:00
XP_LangCode
dict_getLangCode( const DictionaryCtxt* dict )
{
return dict->langCode;
}
2010-12-07 03:24:31 +01:00
XP_U32
dict_getWordCount( const DictionaryCtxt* dict )
{
return dict->nWords;
}
2003-11-01 06:35:29 +01:00
#ifdef STUBBED_DICT
#define BLANK_FACE '\0'
static XP_U8 stub_english_data[] = {
/* count value face */
2008-05-31 05:26:16 +02:00
9, 1, 'A',
2, 3, 'B',
2, 3, 'C',
4, 2, 'D',
12, 1, 'E',
2, 4, 'F',
3, 2, 'G',
2, 4, 'H',
9, 1, 'I',
1, 8, 'J',
1, 5, 'K',
4, 1, 'L',
2, 3, 'M',
6, 1, 'N',
8, 1, 'O',
2, 3, 'P',
1, 10, 'Q',
6, 1, 'R',
4, 1, 'S',
6, 1, 'T',
4, 1, 'U',
2, 4, 'V',
2, 4, 'W',
1, 8, 'X',
2, 4, 'Y',
1, 10, 'Z',
2, 0, BLANK_FACE, /* BLANK1 */
2003-11-01 06:35:29 +01:00
};
void
setStubbedSpecials( DictionaryCtxt* dict )
{
2005-01-04 05:06:37 +01:00
dict->chars = (XP_UCHAR**)XP_MALLOC( dict->mpool, sizeof(char*) );
2003-11-01 06:35:29 +01:00
dict->chars[0] = "_";
} /* setStubbedSpecials */
void
destroy_stubbed_dict( DictionaryCtxt* dict )
{
XP_FREE( dict->mpool, dict->countsAndValues );
2010-01-02 02:40:25 +01:00
XP_FREE( dict->mpool, dict->faces );
2003-11-01 06:35:29 +01:00
XP_FREE( dict->mpool, dict->chars );
XP_FREE( dict->mpool, dict->name );
XP_FREE( dict->mpool, dict->langName );
2003-11-01 06:35:29 +01:00
XP_FREE( dict->mpool, dict->bitmaps );
XP_FREE( dict->mpool, dict );
} /* destroy_stubbed_dict */
DictionaryCtxt*
make_stubbed_dict( MPFORMAL_NOCOMMA )
{
2005-01-04 05:06:37 +01:00
DictionaryCtxt* dict = (DictionaryCtxt*)XP_MALLOC( mpool, sizeof(*dict) );
2003-11-01 06:35:29 +01:00
XP_U8* data = stub_english_data;
XP_U16 datasize = sizeof(stub_english_data);
2010-01-02 02:40:25 +01:00
XP_U16 ii;
2003-11-01 06:35:29 +01:00
XP_MEMSET( dict, 0, sizeof(*dict) );
MPASSIGN( dict->mpool, mpool );
2006-09-15 09:32:39 +02:00
dict->name = copyString( mpool, "Stub dictionary" );
2003-11-01 06:35:29 +01:00
dict->nFaces = datasize/3;
dict->destructor = destroy_stubbed_dict;
2010-01-02 02:40:25 +01:00
dict->faces = (XP_UCHAR*)
XP_MALLOC( mpool, 2 * dict->nFaces * sizeof(dict->faces[0]) );
dict->facePtrs = (XP_UCHAR**)
XP_MALLOC( mpool, dict->nFaces * sizeof(dict->facePtrs[0]) );
XP_UCHAR* nextChar = dict->faces;
XP_UCHAR** nextPtr = dict->facePtrs;
for ( ii = 0; ii < datasize/3; ++ii ) {
*nextPtr++ = nextChar;
*nextChar++ = (XP_UCHAR)data[(ii*3)+2];
*nextChar++ = '\0';
2003-11-01 06:35:29 +01:00
}
2005-01-04 05:06:37 +01:00
dict->countsAndValues = (XP_U8*)XP_MALLOC( mpool, dict->nFaces*2 );
2010-01-02 02:40:25 +01:00
for ( ii = 0; ii < datasize/3; ++ii ) {
dict->countsAndValues[ii*2] = data[(ii*3)];
dict->countsAndValues[(ii*2)+1] = data[(ii*3)+1];
2003-11-01 06:35:29 +01:00
}
2005-01-04 05:06:37 +01:00
dict->bitmaps = (SpecialBitmaps*)XP_MALLOC( mpool, sizeof(SpecialBitmaps) );
2003-11-01 06:35:29 +01:00
dict->bitmaps->largeBM = dict->bitmaps->largeBM = NULL;
setStubbedSpecials( dict );
setBlankTile( dict );
return dict;
} /* make_subbed_dict */
#endif /* STUBBED_DICT */
static array_edge*
dict_super_edge_for_index( const DictionaryCtxt* dict, XP_U32 index )
2003-11-01 06:35:29 +01:00
{
array_edge* result;
if ( index == 0 ) {
result = NULL;
} else {
XP_ASSERT( index < dict->numEdges );
#ifdef NODE_CAN_4
/* avoid long-multiplication lib call on Palm... */
if ( dict->nodeSize == 3 ) {
index += (index << 1);
} else {
XP_ASSERT( dict->nodeSize == 4 );
index <<= 2;
}
2003-11-01 06:35:29 +01:00
#else
index += (index << 1);
2003-11-01 06:35:29 +01:00
#endif
result = &dict->base[index];
}
return result;
} /* dict_edge_for_index */
static array_edge*
dict_super_getTopEdge( const DictionaryCtxt* dict )
{
return dict->topEdge;
} /* dict_super_getTopEdge */
static unsigned long
dict_super_index_from( const DictionaryCtxt* dict, array_edge* p_edge )
{
unsigned long result;
#ifdef NODE_CAN_4
array_edge_new* edge = (array_edge_new*)p_edge;
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
if ( dict->is_4_byte ) {
result |= ((XP_U32)edge->moreBits) << 16;
} else {
XP_ASSERT( dict->nodeSize == 3 );
if ( (edge->bits & EXTRABITMASK_NEW) != 0 ) {
result |= 0x00010000; /* using | instead of + saves 4 bytes */
}
}
#else
array_edge_old* edge = (array_edge_old*)p_edge;
result = ((edge->highByte << 8) | edge->lowByte) & 0x0000FFFF;
if ( (edge->bits & EXTRABITMASK_OLD) != 0 ) {
result |= 0x00010000; /* using | instead of + saves 4 bytes */
}
#endif
return result;
} /* dict_super_index_from */
static array_edge*
dict_super_follow( const DictionaryCtxt* dict, array_edge* in )
{
XP_U32 index = dict_index_from( dict, in );
array_edge* result = index > 0?
dict_edge_for_index( dict, index ): (array_edge*)NULL;
return result;
} /* dict_super_follow */
void
dict_super_init( DictionaryCtxt* dict )
{
/* subclass may change these later.... */
dict->func_edge_for_index = dict_super_edge_for_index;
dict->func_dict_getTopEdge = dict_super_getTopEdge;
dict->func_dict_index_from = dict_super_index_from;
dict->func_dict_follow = dict_super_follow;
dict->func_dict_getShortName = dict_getName;
} /* dict_super_init */
2003-11-01 06:35:29 +01:00
const XP_UCHAR*
dict_getLangName( const DictionaryCtxt* ctxt )
{
return ctxt->langName;
}
#ifdef XWFEATURE_WALKDICT
static void
edgesToIndices( const DictionaryCtxt* dict, XP_U16 nEdges,
array_edge** edges, DictWord* word )
{
XP_U16 ii;
word->nTiles = nEdges;
for ( ii = 0; ii < nEdges; ++ii ) {
word->indices[ii] = edges[ii] - dict->base;
}
}
static void
indicesToEdges( const DictionaryCtxt* dict,
DictWord* word, array_edge** edges )
{
XP_U16 nEdges = word->nTiles;
XP_U16 ii;
for ( ii = 0; ii < nEdges; ++ii ) {
edges[ii] = &dict->base[word->indices[ii]];
}
}
/* On entry and exit, edge at end of array should be ACCEPTING. The job of
* this function is to iterate from one such edge to the next. Steps are: 1)
* try to follow the edge, to expand to a longer word with the last one as a
* prefix. 2) If we're at the end of the array, back off the top tile (and
* repeat while at end of array); 3) Once the current top edge is not a
* LAST_EDGE, try with its next-letter neighbor.
*/
static XP_Bool
nextWord( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nTilesP )
{
XP_U16 nTiles = *nTilesP;
XP_Bool success = XP_FALSE;
while ( 0 < nTiles && ! success ) {
array_edge* next = dict_follow( dict, edges[nTiles-1] );
if ( !!next ) {
edges[nTiles++] = next;
success = ISACCEPTING( dict, next );
continue; /* try with longer word */
}
while ( IS_LAST_EDGE( dict, edges[nTiles-1] ) && 0 < --nTiles ) {
}
if ( 0 < nTiles ) {
edges[nTiles-1] += dict->nodeSize;
success = ISACCEPTING( dict, edges[nTiles-1] );
}
}
*nTilesP = nTiles;
return success;
}
XP_Bool
dict_firstWord( const DictionaryCtxt* dict, DictWord* word )
{
array_edge* edges[MAX_COLS];
XP_U16 nEdges = 0;
edges[nEdges++] = dict_getTopEdge( dict );
XP_Bool success = ISACCEPTING( dict, edges[0] ) /* */
|| nextWord( dict, edges, &nEdges );
if ( success ) {
edgesToIndices( dict, nEdges, edges, word );
}
return success;
}
XP_Bool
dict_getNextWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_U16 nTiles = word->nTiles;
array_edge* edges[MAX_COLS];
indicesToEdges( dict, word, edges );
XP_Bool success = nextWord( dict, edges, &nTiles );
if ( success ) {
edgesToIndices( dict, nTiles, edges, word );
}
return success;
}
XP_Bool
dict_lastWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_ASSERT( 0 );
XP_USE( dict );
word->nTiles = 0;
return XP_FALSE;
}
XP_Bool
dict_getPrevWord( const DictionaryCtxt* dict, DictWord* word )
{
XP_USE( dict );
XP_ASSERT( 0 );
return word->nTiles > 0;
}
void
dict_wordToString( const DictionaryCtxt* dict, DictWord* word,
XP_UCHAR* buf, XP_U16 buflen )
{
XP_U16 ii;
array_edge* edges[MAX_COLS];
Tile tiles[MAX_COLS];
indicesToEdges( dict, word, edges );
for ( ii = 0; ii < word->nTiles; ++ii ) {
tiles[ii] = EDGETILE( dict, edges[ii] );
}
(void)dict_tilesToString( dict, tiles, word->nTiles, buf, buflen );
}
#endif /* XWFEATURE_WALKDICT */
2003-11-01 06:35:29 +01:00
#ifdef CPLUS
}
#endif