mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
When unable to open a dictionary whose path has been saved, look for
it elsewhere in the set of possible directories. This should help ease the transition to there being a limited number of places where dicts can be, since games saved previously will still work after the dicts they reference have been moved. Also, clean up callbacks making their return values consistent: true means done.
This commit is contained in:
parent
6687984bf0
commit
3b94d0f0a2
4 changed files with 117 additions and 52 deletions
|
@ -30,7 +30,6 @@ typedef struct CEDictionaryCtxt {
|
|||
DictionaryCtxt super;
|
||||
HANDLE mappedFile;
|
||||
void* mappedBase;
|
||||
/* size_t dictSize; */
|
||||
} CEDictionaryCtxt;
|
||||
|
||||
static void ce_dict_destroy( DictionaryCtxt* dict );
|
||||
|
@ -47,8 +46,10 @@ static XP_U8* openMappedFile( MPFORMAL const wchar_t* name,
|
|||
static void closeMappedFile( MPFORMAL XP_U8* base, HANDLE mappedFile );
|
||||
static XP_Bool checkIfDictAndLegal( MPFORMAL wchar_t* path, XP_U16 pathLen,
|
||||
wchar_t* name );
|
||||
static XP_Bool findAlternateDict( CEAppGlobals* globals, wchar_t* dictName );
|
||||
|
||||
#define ALIGN_COUNT 2
|
||||
#define CE_MAXDICTS 0x7FFF
|
||||
|
||||
DictionaryCtxt*
|
||||
ce_dictionary_make( CEAppGlobals* globals, XP_UCHAR* dictName )
|
||||
|
@ -60,6 +61,7 @@ ce_dictionary_make( CEAppGlobals* globals, XP_UCHAR* dictName )
|
|||
HANDLE hFile;
|
||||
XP_U8* ptr;
|
||||
XP_U32 dictLength;
|
||||
XP_UCHAR buf[CE_MAX_PATH_LEN+1]; /* in case we have to look */
|
||||
|
||||
XP_ASSERT( !!dictName );
|
||||
XP_DEBUGF( "looking for dict %s", dictName );
|
||||
|
@ -69,6 +71,17 @@ ce_dictionary_make( CEAppGlobals* globals, XP_UCHAR* dictName )
|
|||
|
||||
ptr = openMappedFile( MPPARM(globals->mpool) nameBuf, &mappedFile,
|
||||
&hFile, &dictLength );
|
||||
if ( !ptr ) {
|
||||
if ( findAlternateDict( globals, nameBuf ) ) {
|
||||
(void)WideCharToMultiByte( CP_ACP, 0, nameBuf, -1,
|
||||
buf, sizeof(buf), NULL, NULL );
|
||||
ptr = openMappedFile( MPPARM(globals->mpool) nameBuf, &mappedFile,
|
||||
&hFile, &dictLength );
|
||||
if ( !!ptr ) {
|
||||
dictName = buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while( !!ptr ) { /* lets us break.... */
|
||||
XP_U32 offset;
|
||||
|
@ -486,7 +499,7 @@ openMappedFile( MPFORMAL const wchar_t* name, HANDLE* mappedFileP,
|
|||
|
||||
*hFileP = NULL; /* nothing to close later */
|
||||
if ( sizep != NULL ) {
|
||||
*sizep = GetFileSize( hFile, NULL );
|
||||
*sizep = size;
|
||||
}
|
||||
*mappedFileP = (HANDLE)ptr;
|
||||
}
|
||||
|
@ -555,13 +568,13 @@ checkIfDictAndLegal( MPFORMAL wchar_t* path, XP_U16 pathLen,
|
|||
return result;
|
||||
} /* checkIfDictAndLegal */
|
||||
|
||||
static void
|
||||
static XP_Bool
|
||||
locateOneDir( MPFORMAL wchar_t* path, OnePathCB cb, void* ctxt, XP_U16 nSought,
|
||||
XP_U16* nFoundP )
|
||||
{
|
||||
WIN32_FIND_DATA data;
|
||||
HANDLE fileH;
|
||||
XP_Bool result = XP_FALSE;
|
||||
XP_Bool done = XP_FALSE;
|
||||
XP_U16 startLen;
|
||||
|
||||
lstrcat( path, L"\\" );
|
||||
|
@ -587,9 +600,10 @@ locateOneDir( MPFORMAL wchar_t* path, OnePathCB cb, void* ctxt, XP_U16 nSought,
|
|||
/* skip . and .. */
|
||||
} else {
|
||||
lstrcpy( path+startLen, data.cFileName );
|
||||
locateOneDir( MPPARM(mpool) path, cb, ctxt, nSought,
|
||||
nFoundP );
|
||||
if ( *nFoundP == nSought ) {
|
||||
done = locateOneDir( MPPARM(mpool) path, cb, ctxt,
|
||||
nSought, nFoundP );
|
||||
XP_ASSERT( done || *nFoundP < nSought );
|
||||
if ( done ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -600,11 +614,9 @@ locateOneDir( MPFORMAL wchar_t* path, OnePathCB cb, void* ctxt, XP_U16 nSought,
|
|||
XP_ASSERT( *nFoundP < nSought );
|
||||
|
||||
lstrcpy( path+startLen, data.cFileName );
|
||||
if ( !(*cb)( path, (*nFoundP)++, ctxt ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( *nFoundP == nSought ) {
|
||||
done = (*cb)( path, (*nFoundP)++, ctxt )
|
||||
|| *nFoundP == nSought;
|
||||
if ( done ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -618,11 +630,13 @@ locateOneDir( MPFORMAL wchar_t* path, OnePathCB cb, void* ctxt, XP_U16 nSought,
|
|||
|
||||
(void)FindClose( fileH );
|
||||
}
|
||||
return done;
|
||||
} /* locateOneDir */
|
||||
|
||||
#define USE_FOREACH /* FOREACH avoids code duplication, but may not be worth
|
||||
the extra complexity. Size is the same. */
|
||||
#ifdef USE_FOREACH
|
||||
/* return true when done */
|
||||
typedef XP_Bool (*ForEachCB)( wchar_t* dir, void* ctxt );
|
||||
|
||||
static void
|
||||
|
@ -636,7 +650,7 @@ forEachDictDir( HINSTANCE hInstance, ForEachCB cb, void* ctxt )
|
|||
break;
|
||||
}
|
||||
|
||||
if ( !(*cb)( pathBuf, ctxt ) ) {
|
||||
if ( (*cb)( pathBuf, ctxt ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -656,13 +670,9 @@ locateOneDirCB( wchar_t* dir, void* ctxt )
|
|||
{
|
||||
LocateOneData* datap = (LocateOneData*)ctxt;
|
||||
|
||||
locateOneDir( MPPARM(datap->mpool) dir, datap->cb,
|
||||
datap->ctxt, datap->nSought, &datap->nFound );
|
||||
|
||||
if ( datap->nFound >= datap->nSought ) {
|
||||
return XP_FALSE;
|
||||
}
|
||||
return XP_TRUE;
|
||||
return locateOneDir( MPPARM(datap->mpool) dir, datap->cb,
|
||||
datap->ctxt, datap->nSought, &datap->nFound )
|
||||
|| datap->nFound >= datap->nSought;
|
||||
} /* locateOneDirCB */
|
||||
|
||||
XP_U16
|
||||
|
@ -705,7 +715,7 @@ formatDirsCB( wchar_t* dir, void* ctxt )
|
|||
narrow, sizeof(narrow)/sizeof(narrow[0]),
|
||||
NULL, NULL );
|
||||
stream_putBytes( datap->stream, narrow, len-1 ); /* skip null */
|
||||
return XP_TRUE;
|
||||
return XP_FALSE;
|
||||
} /* formatDirsCB */
|
||||
|
||||
void
|
||||
|
@ -770,6 +780,52 @@ ceFormatDictDirs( XWStreamCtxt* stream, HINSTANCE hInstance )
|
|||
}
|
||||
#endif /* USE_FOREACH */
|
||||
|
||||
typedef struct FindOneData {
|
||||
wchar_t* result;
|
||||
const wchar_t* sought;
|
||||
XP_Bool found;
|
||||
} FindOneData;
|
||||
|
||||
static XP_Bool
|
||||
matchShortName( const wchar_t* wPath, XP_U16 index, void* ctxt )
|
||||
{
|
||||
FindOneData* datap = (FindOneData*)ctxt;
|
||||
wchar_t buf[CE_MAX_PATH_LEN+1];
|
||||
wchar_t* name;
|
||||
|
||||
LOG_FUNC();
|
||||
|
||||
XP_ASSERT( !datap->found );
|
||||
|
||||
name = wbname( buf, sizeof(buf), wPath );
|
||||
if ( 0 == wcscmp( name, datap->sought ) ) {
|
||||
wcscpy( datap->result, wPath );
|
||||
datap->found = XP_TRUE;
|
||||
}
|
||||
return datap->found;
|
||||
} /* matchShortName */
|
||||
|
||||
/* Users sometimes move dicts. Given a path to a dict that doesn't exist, See
|
||||
* if another with the same short name exists somewhere else we're willing to
|
||||
* look.
|
||||
*/
|
||||
static XP_Bool
|
||||
findAlternateDict( CEAppGlobals* globals, wchar_t* path )
|
||||
{
|
||||
wchar_t shortPath[CE_MAX_PATH_LEN+1];
|
||||
wchar_t* shortName;
|
||||
XP_U16 nFound;
|
||||
FindOneData data;
|
||||
|
||||
XP_MEMSET( &data, 0, sizeof(data) );
|
||||
data.sought = wbname( shortPath, sizeof(shortPath), path );
|
||||
data.result = path;
|
||||
|
||||
(void)ceLocateNDicts( MPPARM(globals->mpool) globals->hInst, CE_MAXDICTS,
|
||||
matchShortName, &data );
|
||||
return data.found;
|
||||
} /* findAlternateDict */
|
||||
|
||||
static XP_U32
|
||||
n_ptr_tohl( XP_U8** inp )
|
||||
{
|
||||
|
@ -804,4 +860,27 @@ bname( XP_UCHAR* in )
|
|||
return out + 1;
|
||||
} /* bname */
|
||||
|
||||
wchar_t*
|
||||
wbname( wchar_t* buf, XP_U16 buflen, const wchar_t* in )
|
||||
{
|
||||
int len;
|
||||
wchar_t* result;
|
||||
|
||||
_snwprintf( buf, buflen, L"%s", in );
|
||||
result = buf + wcslen( buf ) - 1;
|
||||
|
||||
/* wipe out extension */
|
||||
while ( *result != '.' ) {
|
||||
--result;
|
||||
XP_ASSERT( result > buf );
|
||||
}
|
||||
*result = 0;
|
||||
|
||||
while ( result >= buf && *result != '\\' ) {
|
||||
--result;
|
||||
}
|
||||
|
||||
return result + 1;
|
||||
} /* wbname */
|
||||
|
||||
#endif /* ifndef STUBBED_DICT */
|
||||
|
|
|
@ -33,14 +33,20 @@ typedef struct CEBitmapInfo {
|
|||
DictionaryCtxt* ce_dictionary_make(CEAppGlobals* globals, XP_UCHAR* name);
|
||||
DictionaryCtxt* ce_dictionary_make_empty( CEAppGlobals* globals );
|
||||
|
||||
/* Callback: return true if done; false to continue */
|
||||
typedef XP_Bool (*OnePathCB)( const wchar_t* wPath, XP_U16 index, void* ctxt );
|
||||
|
||||
/* ceLocateNDicts: Allocate and store in bufs ptrs to up to nSought paths to
|
||||
* dict files. Return the number actually found. Caller is responsible for
|
||||
* making sure bufs contains nSought slots.
|
||||
*/
|
||||
typedef XP_Bool (*OnePathCB)( const wchar_t* wPath, XP_U16 index, void* ctxt );
|
||||
XP_U16 ceLocateNDicts( MPFORMAL HINSTANCE hInstance, XP_U16 nSought,
|
||||
OnePathCB cb, void* ctxt );
|
||||
void ceFormatDictDirs( XWStreamCtxt* stream, HINSTANCE hInstance );
|
||||
|
||||
/* return just the name, no extension, of dict, written to buf, pointed to by
|
||||
return value (which is into buf, but not necessarily the first char.) */
|
||||
wchar_t* wbname( wchar_t* buf, XP_U16 buflen, const wchar_t* in );
|
||||
|
||||
XP_UCHAR* bname( XP_UCHAR* in );
|
||||
#endif
|
||||
|
|
|
@ -46,29 +46,6 @@ ceCountLocalIn( HWND hDlg, XP_U16 nPlayers )
|
|||
#endif
|
||||
|
||||
|
||||
static wchar_t*
|
||||
wbname( wchar_t* buf, XP_U16 buflen, const wchar_t* in )
|
||||
{
|
||||
int len;
|
||||
wchar_t* result;
|
||||
|
||||
_snwprintf( buf, buflen, L"%s", in );
|
||||
result = buf + wcslen( buf ) - 1;
|
||||
|
||||
/* wipe out extension */
|
||||
while ( *result != '.' ) {
|
||||
--result;
|
||||
XP_ASSERT( result > buf );
|
||||
}
|
||||
*result = 0;
|
||||
|
||||
while ( result >= buf && *result != '\\' ) {
|
||||
--result;
|
||||
}
|
||||
|
||||
return result + 1;
|
||||
} /* wbname */
|
||||
|
||||
static XP_Bool
|
||||
addDictToMenu( const wchar_t* wPath, XP_U16 index, void* ctxt )
|
||||
{
|
||||
|
@ -128,7 +105,7 @@ addDictToMenu( const wchar_t* wPath, XP_U16 index, void* ctxt )
|
|||
}
|
||||
}
|
||||
|
||||
return XP_TRUE;
|
||||
return XP_FALSE;
|
||||
} /* addDictToMenu */
|
||||
|
||||
static void
|
||||
|
|
|
@ -574,7 +574,7 @@ ceInitAndStartBoard( CEAppGlobals* globals, XP_Bool newGame, CeGamePrefs* gp,
|
|||
#else
|
||||
XP_ASSERT( !!newDictName );
|
||||
XP_DEBUGF( "calling ce_dictionary_make" );
|
||||
dict = ce_dictionary_make( globals, copyString( MEMPOOL newDictName ));
|
||||
dict = ce_dictionary_make( globals, newDictName);
|
||||
#endif
|
||||
XP_ASSERT( !!dict );
|
||||
model_setDictionary( globals->game.model, dict );
|
||||
|
@ -1044,7 +1044,7 @@ ceSetDictName( const wchar_t* wPath, XP_U16 index, void* ctxt )
|
|||
str = copyString( MPPARM(globals->mpool) buf );
|
||||
XP_ASSERT( NULL == globals->gameInfo.dictName );
|
||||
globals->gameInfo.dictName = str;
|
||||
return NULL != str;
|
||||
return XP_FALSE;
|
||||
} /* ceSetDictName */
|
||||
|
||||
static XP_Bool
|
||||
|
@ -1185,7 +1185,7 @@ ceDoNewGame( CEAppGlobals* globals, XP_Bool silent )
|
|||
|
||||
if ( !giState.userCancelled
|
||||
#ifndef STUBBED_DICT
|
||||
&& ((XP_U16)XP_STRLEN(giState.newDictName) > 0)
|
||||
&& ( giState.newDictName[0] != '\0' )
|
||||
#endif
|
||||
) {
|
||||
|
||||
|
@ -1251,9 +1251,12 @@ ceChooseAndOpen( CEAppGlobals* globals )
|
|||
}
|
||||
|
||||
globals->curGameName = name;
|
||||
ceLoadSavedGame( globals );
|
||||
ceInitAndStartBoard( globals, XP_FALSE, NULL, NULL );
|
||||
ceSetTitleFromName( globals );
|
||||
if ( ceLoadSavedGame( globals ) ) {
|
||||
ceInitAndStartBoard( globals, XP_FALSE, NULL, NULL );
|
||||
ceSetTitleFromName( globals );
|
||||
} else {
|
||||
XP_LOGF( "failed to open chosen game" );
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* ceChooseAndOpen */
|
||||
|
|
Loading…
Reference in a new issue