* contrib/hbnf/doc/en/clrsel.txt
* contrib/hbnf/doc/en/kspeed.txt
* contrib/hbnf/doc/en/mouse1.txt
* contrib/hbnf/doc/en/mouse2.txt
* contrib/xhb/htmutil.prg
* contrib/xhb/ttable.prg
* extras/gfspell/spell.prg
* extras/hbvpdf/hbvpdf.prg
* extras/hbvpdf/hbvpdft.prg
* extras/hbxlsxml/xlsxml_y.prg
* extras/httpsrv/cgifunc.prg
* utils/hbtest/rt_misc.prg
* contrib/hbnf/aredit.prg
* contrib/hbnf/clrsel.prg
* contrib/hbnf/dispmsg.prg
* contrib/hbnf/menu1.prg
* contrib/hbnf/mouse1.prg
* contrib/hbnf/mouse2.prg
* contrib/hbnf/pegs.prg
* contrib/hbnf/popadder.prg
* contrib/hbnf/tbwhile.prg
! further removing high 8-bit chars
1653 lines
48 KiB
Plaintext
1653 lines
48 KiB
Plaintext
/*
|
||
* $Id$
|
||
*/
|
||
|
||
* Program...: SpellLib.prg
|
||
* Author....: Joseph D. Booth
|
||
* Copyright.: (C)1993, Joseph D. Booth, All Rights Reserved
|
||
*
|
||
* Purpose...: Library of functions to allow a Clipper program to
|
||
* spell check a string and to also work with individual
|
||
* words.
|
||
*
|
||
* SP_Add() - Add word to the dictionary
|
||
* SP_Cache() - Add word to spelling cache
|
||
* SP_Check() - Is word spelled correctly?
|
||
* SP_Clear() - Clear the spelling cache
|
||
* SP_Init() - Initialize the spelling dictionary
|
||
* SP_GetSet() - Get/Set global parameters
|
||
* SP_LoadAux() - Loads an auxiliary dictionary
|
||
* SP_Suggest() - Offer list of sound alike suggestions
|
||
* SP_Quick() - Offer list of suggested spellings
|
||
* SP_WildCard() - List of wildcard matches
|
||
*
|
||
* DBF2Dic() - Convert a DBF file to a DIC file
|
||
* Dic2DBF() - Convert a DIC file to a DBF file
|
||
*
|
||
****************************************************************************
|
||
|
||
|
||
#xtranslate StoreWord(<cWord>) => Xform(<cWord>)
|
||
#xtranslate ExtractWord(<cWord>) => Xunform(<cWord>)
|
||
|
||
#define NSIZE 26*26*6
|
||
#define EACH_WORD 6
|
||
#define CRLF chr(13)+chr(10)
|
||
#define FOUR_BYTES chr(0)+chr(0)+chr(0)+chr(0)
|
||
#define MAX_STRING 40000
|
||
|
||
#define COMMON_WORDS aGlobal[ 1]
|
||
#define CACHE_WORDS aGlobal[ 2]
|
||
#define DICTIONARY_PATH aGlobal[ 3]
|
||
#define DICTIONARY_NAME aGlobal[ 4]
|
||
#define AUXILIARY_DICTIONARY aGlobal[ 5]
|
||
#define EXTRA_CODE_BLOCK aGlobal[ 6]
|
||
#define ADD_SUFFIXES aGlobal[ 7]
|
||
#define ADD_PREFIXES aGlobal[ 8]
|
||
#define ADD_PLURALS aGlobal[ 9]
|
||
#define SORT_SUGGESTIONS aGlobal[10]
|
||
#define SUGGEST_PREFERENCE aGlobal[11]
|
||
#define MINIMUM_WORD_LENGTH aGlobal[12]
|
||
#define METAPHONE_SIZE aGlobal[13]
|
||
#define MAX_DIFFERENCE aGlobal[14]
|
||
#define THESAURUS_NAME aGlobal[15]
|
||
#define CHECK_RUNONS aGlobal[16]
|
||
|
||
|
||
* #define REDUCE_MEMORY_NEEDS
|
||
|
||
|
||
|
||
|
||
THREAD STATIC aGlobal := { NIL,;
|
||
"",;
|
||
"",;
|
||
"DICT.DIC",;
|
||
"",;
|
||
NIL,;
|
||
.T.,;
|
||
.T.,;
|
||
.T.,;
|
||
.T.,;
|
||
"B",; // (M)etaphone, (A)lgorithmic, (B)oth
|
||
2,;
|
||
5,;
|
||
1,;
|
||
"THES.DIC",;
|
||
.T. }
|
||
|
||
STATIC aContracts := { { "CAN'T" ,"CANNOT" },;
|
||
{ "WON'T" ,"WILL NOT" },;
|
||
{ "AREN'T" ,"ARE NOT" },;
|
||
{ "AIN'T" ,"ARE NOT" },;
|
||
{ "THEY'RE" ,"THEY ARE" },;
|
||
{ "THEY'VE" ,"THEY HAVE" },;
|
||
{ "IT'S" ,"IT IS" },;
|
||
{ "I'LL" ,"I WILL" },;
|
||
{ "I'D" ,"I WOULD" },;
|
||
{ "DON'T" ,"DO NOT" } }
|
||
|
||
|
||
|
||
THREAD STATIC nHandle := 0
|
||
THREAD STATIC cOffsets
|
||
|
||
|
||
|
||
// Function: SP_Add()
|
||
// Purpose: Adds a word to the dictionary
|
||
// Syntax: <logical> := SP_Add(cWord)
|
||
// Arguments: cWord - Word to add to the auxiliary dictionary
|
||
// Returns: <logical> - TRUE if added,
|
||
// FALSE otherwise
|
||
//
|
||
// Notes: Does not check to see if the word already exists in the
|
||
// dictionary.
|
||
//
|
||
////////////////////////////
|
||
function SP_Add(cWord)
|
||
LOCAL was_added := .F. // Was word written to dictionary?
|
||
LOCAL nAuxHandle // Dictionary file handle
|
||
LOCAL nWritten // Number of bytes written
|
||
|
||
// Initialize the spell checker and make sure
|
||
// an auxiliary dictionary name was specified
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_ADD"
|
||
|
||
if SP_Init() .and. !empty( AUXILIARY_DICTIONARY )
|
||
cWord := upper(alltrim(cWord))
|
||
|
||
//
|
||
// If the auxiliary dictionary does not exist,
|
||
// we will create it for the user
|
||
//
|
||
|
||
if file( AUXILIARY_DICTIONARY )
|
||
nAuxHandle := fopen( AUXILIARY_DICTIONARY,2+32 )
|
||
else
|
||
nAuxHandle := fcreate( AUXILIARY_DICTIONARY )
|
||
endif
|
||
if nAuxHandle >= 0
|
||
|
||
Fseek(nAuxHandle,0,2) // Bottom of the file
|
||
nWritten := Fwrite(nAuxHandle,; // Write word into file
|
||
cWord+CRLF,len(cWord)+2)
|
||
|
||
Fclose(nAuxHandle) // Close the file
|
||
SP_Cache(cWord) // Add word to cache
|
||
|
||
was_added := (nWritten == len(cWord)+2)
|
||
endif
|
||
endif
|
||
return was_added
|
||
*******************************************************************************
|
||
|
||
//
|
||
// Function: Sp_cache()
|
||
// Purpose: To add a word to the cache list
|
||
// Syntax: <logical> := Sp_cache(cWord)
|
||
// Arguments: cWord - upper case, all trimmed word to add
|
||
// Returns: <logical> - TRUE if added,
|
||
// FALSE otherwise
|
||
//
|
||
// Static: CACHE_WORDS - String of cache words
|
||
//
|
||
// Notes: Check to see if the word already exists in the cache
|
||
//
|
||
////////////////////////
|
||
function Sp_cache(cWord)
|
||
|
||
LOCAL cTemp := "|"+upper(alltrim(cWord))+"|"
|
||
LOCAL lAdded := .F.
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_cache"
|
||
|
||
if ! cTemp $ CACHE_WORDS .and. len(CACHE_WORDS) < MAX_STRING
|
||
CACHE_WORDS += cTemp
|
||
lAdded := .T.
|
||
endif
|
||
return lAdded
|
||
*******************************************************************************
|
||
|
||
//
|
||
// Function: Sp_check()
|
||
// Purpose: To check the spelling of a word
|
||
// Syntax: <logical> := Sp_check(cWord)
|
||
// Arguments: cWord - upper case, all trimmed word to check
|
||
// Returns: <logical> - TRUE if valid spelling
|
||
// FALSE otherwise
|
||
//
|
||
// Static: CACHE_WORDS - String of cache words
|
||
// COMMON_WORDS - String of common words
|
||
// cOffSets -
|
||
// nHandle - Handle DIC file is opened on
|
||
//
|
||
// Notes:
|
||
//
|
||
//
|
||
////////////////////////
|
||
function SP_Check(cWord)
|
||
|
||
STATIC cBuf := ""
|
||
STATIC cLast
|
||
|
||
|
||
STATIC nDicCount := 0
|
||
STATIC nCacheCount := 0
|
||
STATIC nBuffCount := 0
|
||
|
||
|
||
LOCAL ok := .T.
|
||
LOCAL cLookup := upper(trim(cWord))
|
||
LOCAL nRow
|
||
LOCAL nCol
|
||
LOCAL x
|
||
LOCAL y
|
||
LOCAL z := 4
|
||
LOCAL cTemp
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_init"
|
||
|
||
if sp_init()
|
||
if len(cLookup) == 1 .and. cLookup$"IA"
|
||
return .T.
|
||
endif
|
||
if len(cLookup) < MINIMUM_WORD_LENGTH
|
||
return .T.
|
||
endif
|
||
if right(cLookup,2)="'S"
|
||
cLookUp := substr(cLookup,1, len(cLookup)-2 )
|
||
endif
|
||
cTemp := "|"+cLookup+"|"
|
||
if fat(cTemp, COMMON_WORDS) == 0 // Check the common words first
|
||
if fat(cTemp,CACHE_WORDS) == 0 // then check the cache words
|
||
ok := .F.
|
||
nRow := asc(substr(cLookup,1,1))-64
|
||
nCol := asc(substr(cLookup,2,1))-64
|
||
if (nRow>0 .and. nRow<=26) .and. (nCol>0 .and. nCol<=26)
|
||
|
||
#ifdef REDUCE_MEMORY_NEEDS
|
||
|
||
cOffsets := space(6)
|
||
fseek(nHandle,((nRow-1)*156)+((nCol-1)*6+1)+5,0)
|
||
fread(nHandle,@cOffsets,6)
|
||
x := bin2l(substr(cOffsets,1,4))
|
||
y := bin2w(substr(cOffsets,5,2))
|
||
|
||
#else
|
||
|
||
x := bin2l(substr(cOffsets,((nRow-1)*156)+((nCol-1)*EACH_WORD+1),4))
|
||
y := bin2w(substr(cOffsets,((nRow-1)*156)+((nCol-1)*EACH_WORD+5),2))
|
||
|
||
#endif
|
||
|
||
if !empty(x)
|
||
if !(cLast==substr(cLookup,1,2))
|
||
cBuf := space(y)
|
||
fseek(nHandle,x,0)
|
||
fread(nHandle,@cBuf,y)
|
||
nDicCount++
|
||
else
|
||
nBuffCount++
|
||
endif
|
||
if len(cLookup)=3
|
||
z := asc(substr(cLookup,3,1))-64
|
||
ok := bit(cBuf,z)
|
||
elseif len(cLookup) < 3
|
||
ok := bit(cBuf,27)
|
||
elseif y > 4
|
||
cTemp := StoreWord(cLookup)
|
||
do while z < y
|
||
z := fat( cTemp, cBuf,z )
|
||
if z < 6
|
||
exit
|
||
elseif substr(cBuf,z-1,1) < Chr( 128 )
|
||
z++
|
||
else
|
||
exit
|
||
endif
|
||
enddo
|
||
ok := z > 4 .and. z<y
|
||
endif
|
||
cLast := substr(cLookup,1,2)
|
||
endif
|
||
endif
|
||
else
|
||
nCacheCount++
|
||
endif
|
||
else
|
||
nCacheCount++
|
||
endif
|
||
else
|
||
ok := .F.
|
||
endif
|
||
if !ok .and. EXTRA_CODE_BLOCK != NIL
|
||
ok := eval( EXTRA_CODE_BLOCK,cWord )
|
||
endif
|
||
return ok
|
||
*******************************************************************************
|
||
|
||
//
|
||
// Function: Sp_GetBuf()
|
||
// Purpose: To get all words within the buffer
|
||
// Syntax: Sp_GetBuf( <cLetters> )
|
||
// Arguments: <cLetters> - First two letters
|
||
// Returns: cString - Buffer string from DIC file
|
||
//
|
||
////////////////////////
|
||
STATIC function sp_GetBuf(cLetters)
|
||
LOCAL x
|
||
LOCAL y
|
||
LOCAL cBuf := ""
|
||
LOCAL nRow := asc(substr(cLetters,1,1))-64
|
||
LOCAL nCol := asc(substr(cLetters,2,1))-64
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_getbuf"
|
||
|
||
if (nRow>0 .and. nRow<=26) .and. (nCol>0 .and. nCol<=26)
|
||
x := bin2l(substr(cOffsets,((nRow-1)*156)+((nCol-1)*EACH_WORD+1),4))
|
||
if !empty(x)
|
||
y := bin2w(substr(cOffsets,((nRow-1)*156)+((nCol-1)*EACH_WORD+5),2))
|
||
cBuf := space(y)
|
||
fseek(nHandle,x+4,0)
|
||
fread(nHandle,@cBuf,y-4)
|
||
endif
|
||
endif
|
||
return cBuf
|
||
******************************************************************************
|
||
|
||
//
|
||
// Function: Sp_clear()
|
||
// Purpose: To clear out the cache list
|
||
// Syntax: Sp_clear()
|
||
// Arguments: NONE
|
||
// Returns: NIL
|
||
//
|
||
// Static: CACHE_WORDS - String of cache words
|
||
//
|
||
////////////////////////
|
||
function sp_clear
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_clear"
|
||
|
||
CACHE_WORDS := ""
|
||
return NIL
|
||
******************************************************************************
|
||
|
||
// Function: Sp_GetSet()
|
||
// Purpose: To get/set a parameter for the spell check function
|
||
// Syntax: <xOldValue> := Sp_GetSet( nWhich [,xNewSetting] )
|
||
// Parameters: nWhich - Which parameter to get/set
|
||
// xNewSetting - Value to set parameter to
|
||
//
|
||
// Returns: <logical> TRUE if word succesfully added
|
||
// FALSE if an error occurs, usually network lock
|
||
// problem
|
||
//
|
||
//////////////////////////////////////
|
||
function Sp_GetSet(nWhich,xNewSetting)
|
||
LOCAL xOld := NIL
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_getset"
|
||
|
||
if nWhich != NIL .and. (nWhich>0 .and. nWhich<=len(aGlobal))
|
||
xOld := aGlobal[nWhich]
|
||
if valtype(xNewSetting) == valtype(xOld)
|
||
aGlobal[nWhich] := xNewSetting
|
||
endif
|
||
endif
|
||
return xOld
|
||
******************************************************************************
|
||
|
||
// Function: Sp_LoadAux()
|
||
// Purpose: To load an auxiliary dictionary of words
|
||
// Syntax:
|
||
// Parameters:
|
||
//
|
||
//
|
||
// Returns:
|
||
//
|
||
//
|
||
//
|
||
//////////////////////////////////////
|
||
function Sp_LoadAux(cFile)
|
||
LOCAL is_ok := .F.
|
||
LOCAL x := 0
|
||
LOCAL cStr := ""
|
||
LOCAL nSize
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_loadaux"
|
||
|
||
if !empty(cFile)
|
||
if file(cFile)
|
||
x := fopen(cFile,64)
|
||
else
|
||
x := fcreate(cFile)
|
||
endif
|
||
SP_GetSet(5,cFile)
|
||
|
||
if x > 0
|
||
nSize := fseek(x,0,2)
|
||
if nSize < MAX_STRING
|
||
cStr := space(nSize)
|
||
fseek(x,0,0)
|
||
fread(x,@cStr,nSize)
|
||
cStr := "|"+strtran(cStr,CRLF,"|")
|
||
CACHE_WORDS += upper(cStr)
|
||
is_ok := .T.
|
||
endif
|
||
fclose(x)
|
||
endif
|
||
endif
|
||
return is_ok
|
||
******************************************************************************
|
||
|
||
//
|
||
// Function: Sp_Suggest()
|
||
// Purpose: To return an array of possible spellings
|
||
// Syntax: aSuggest_ := Sp_Suggest(cWord [,lInclude] )
|
||
// Arguments: cWord - Word to look for suggestions for
|
||
// lInclude - Should word be included in list?
|
||
// Returns: aSuggest_ - List of suggested words
|
||
//
|
||
///////////////////////////////////
|
||
function Sp_Suggest(cWord,lInclude)
|
||
|
||
STATIC aParts_ := { {"A" ,{"AI","AO","AU","AY","EA","EI","EIGH","ET","EY","E","I","O"}},;
|
||
{"AIR" ,{"ARE"}},;
|
||
{"AIT" ,{"ATE"}},;
|
||
{"C" ,{"CK"}},;
|
||
{"CH" ,{"TCH","TI","TU"}},;
|
||
{"CKS" ,{"X"}},;
|
||
{"D" ,{"ED"}},;
|
||
{"E" ,{"A","AE","AI","AY","EA","EI","EO","IE","I","U","O"}},;
|
||
{"EM" ,{"TEM"}},;
|
||
{"ER" ,{"OUR","RE","URE","YR"}},;
|
||
{"ERE" ,{"EIR","EAR","IER"}},;
|
||
{"F" ,{"GH","LF","PH","G"}},;
|
||
{"FIZ" ,{"PHYS"}},;
|
||
{"G" ,{"GH","GU","GUE"}},;
|
||
{"GZ" ,{"X"}},;
|
||
{"H" ,{"WH"}},;
|
||
{"I" ,{"A","E","EE","IA","IE","O","U","UI","Y","YE","UY","EI","IGH"}},;
|
||
{"IS" ,{"US","ACE","ICE"}},;
|
||
{"ISE" ,{"IZE"}},;
|
||
{"J" ,{"D","DG","DI","DJ","G","GG"}},;
|
||
{"K" ,{"C","CC","CH","CK","CQU","CU","LK","Q","QU","QUE"}},;
|
||
{"KW" ,{"QU"}},;
|
||
{"L" ,{"SL"}},;
|
||
{"LE" ,{"TLE","AL"}},;
|
||
{"M" ,{"CHM","GM","LM","MB","MN","N"}},;
|
||
{"N" ,{"M","PN","GN","KN","MN"}},;
|
||
{"NG" ,{"N","NGUE"}},;
|
||
{"O" ,{"AU","EAU","EO","EW","OA","OE","OH","OU","OUGH","OW","A","AH","AW","UO","E"}},;
|
||
{"OE" ,{"OWE","OUGH"}},;
|
||
{"OO" ,{"O","EU","EW","OE","OU","OUGH","U","UE","UI"}},;
|
||
{"OU" ,{"OUGH","OW"}},;
|
||
{"PER" ,{"PRO","PRI","PRA","PRU"}},;
|
||
{"PRE" ,{"PRO","PRI","PRA","PRU"}},;
|
||
{"R" ,{"RH","WR"}},;
|
||
{"S" ,{"C","CE","PS","SC","SCH"}},;
|
||
{"SH" ,{"CE","CH","CI","S","SCH","SCI","SE","SI","SS","SSI","TI"}},;
|
||
{"SI" ,{"PSY","CY"}},;
|
||
{"T" ,{"ED","GHT","PT","TH"}},;
|
||
{"TION" ,{"SION","CION","CEAN","CIAN"}},;
|
||
{"TIOUS",{"SEOUS"}},;
|
||
{"TURE" ,{"TEUR"}},;
|
||
{"U" ,{"O","OE","OO","OU","EUA","EU","EUE","EW","IEU","IEW","UE","UI","YOU","YU"}},;
|
||
{"UR" ,{"EAR","ER","IR","YR"}},;
|
||
{"V" ,{"F","LV","PH"}},;
|
||
{"W" ,{"O","U","WH"}},;
|
||
{"X" ,{"CKS","GZ","K"}},;
|
||
{"Y" ,{"I","J","IE","EI"}},;
|
||
{"Z" ,{"S","SC","SS","X","GE","SI","ZI"}},;
|
||
{"ZI" ,{"XY"}} }
|
||
|
||
STATIC aEnds := { "ED","ER","ING","LY","AL","FUL","NESS","MENT","IVE" }
|
||
STATIC aBegs := { "UN","IN","DIS","MIS","EN","WEL","AL" }
|
||
|
||
LOCAL jj,kk,zz,ii
|
||
LOCAL cHold
|
||
LOCAL aRet_ := {} // List of suggested words
|
||
LOCAL cTemp
|
||
LOCAL nSugg
|
||
LOCAL nSize := len(aParts_)
|
||
LOCAL nSuffix := len(aEnds)
|
||
LOCAL cMeta
|
||
LOCAL cFirst
|
||
LOCAL cKey
|
||
LOCAL arr_
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_suggest"
|
||
|
||
cWord := upper(trim(cWord))
|
||
zz := len(cWord)
|
||
|
||
if zz =1 // Don't offer suggestions for
|
||
return aRet_ // single letter words
|
||
endif
|
||
|
||
if lInclude == NIL ; lInclude := .F. ; endif
|
||
|
||
//
|
||
// Should the current word be included?
|
||
//
|
||
//////////////////////////////////
|
||
if Sp_Check(cWord)
|
||
Aadd(aRet_,"A0AA"+cWord)
|
||
endif
|
||
|
||
if "'" $ cWord
|
||
cHold := SP_Expand(cWord)
|
||
if !empty(cHold)
|
||
Aadd(aRet_,"A1AA"+cHold)
|
||
endif
|
||
endif
|
||
|
||
if CHECK_RUNONS
|
||
arr_ := SP_Split( cWord )
|
||
for jj := 1 to len(arr_)
|
||
Aadd(aRet_,"A1AA"+arr_[jj] )
|
||
next
|
||
endif
|
||
|
||
if SUGGEST_PREFERENCE $ "AB"
|
||
|
||
//
|
||
// Step One - Do letter doubling
|
||
//
|
||
//////////////////////////////////
|
||
for jj := 2 to zz
|
||
if substr(cWord,jj,1)$"BCDEFGKLMNOPRSTZ"
|
||
cHold := left(cWord,jj)+substr(cWord,jj, 1)+;
|
||
substr(cWord,jj+1)
|
||
//
|
||
// If the word is not already in the list, then check
|
||
// to see if it is a valid word.
|
||
//
|
||
//////////////////////////////////////////
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
endif
|
||
next
|
||
|
||
//
|
||
// Step Two - Remove extra letters
|
||
//
|
||
//////////////////////////////////
|
||
for jj := 1 to zz
|
||
cHold := left(cWord,jj-1)+substr(cWord,jj+1)
|
||
//
|
||
// If the word is not already in the list, then check
|
||
// to see if it is a valid word.
|
||
//
|
||
//////////////////////////////////////////
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
next
|
||
|
||
//
|
||
// Step Three - Transpose the letters
|
||
//
|
||
//////////////////////////
|
||
for jj := 2 to zz
|
||
cHold := left(cWord,jj-2)+substr(cWord,jj, 1)+;
|
||
substr(cWord,jj-1,1)+substr(cWord,jj+1)
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
next
|
||
|
||
//
|
||
// Step Four - Try adding a silent E to the end
|
||
//
|
||
//////////////////
|
||
|
||
cHold := cWord+"E"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
|
||
//
|
||
// Step Five - Do sound alike substitutions
|
||
//
|
||
//////////////////////////////////
|
||
for jj := 1 to nSize
|
||
if aParts_[jj,1]$cWord
|
||
if aParts_[jj,1]$"AEIOUT"
|
||
ii := 0
|
||
do while (ii := fat(aParts_[jj,1],cWord,ii))>0
|
||
for kk := 1 to len(aParts_[jj,2])
|
||
cHold := substr(cWord,1,ii-1)+aParts_[jj,2,kk]+substr(cWord,ii+1)
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
next
|
||
ii++
|
||
enddo
|
||
else
|
||
for kk := 1 to len(aParts_[jj,2])
|
||
cHold := strtran(cWord,aParts_[jj,1],aParts_[jj,2,kk])
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0 .and. Sp_Check(cHold)
|
||
Aadd(aRet_,"B"+SP_Rate(cHold,cWord)+cHold)
|
||
endif
|
||
next
|
||
endif
|
||
endif
|
||
next
|
||
nSugg := len(aRet_)
|
||
|
||
//
|
||
// At this point, we have a list of words in aRet_, which now need to
|
||
// be checked for suffixes, prefixes, and plurals.
|
||
//
|
||
|
||
for jj := 1 to nSugg
|
||
cHold := trim(substr(aRet_[jj],5)) // Extract the word
|
||
zz := len(cHold)
|
||
//
|
||
// Check suffixes
|
||
//
|
||
////////////////
|
||
if ADD_SUFFIXES
|
||
for kk := 1 to nSuffix
|
||
cTemp := cHold+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
Sp_Check(cTemp)
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
//
|
||
// Try doubling the last letter
|
||
//
|
||
//////////
|
||
for kk := 1 to nSuffix
|
||
cTemp := cHold+substr(cHold,zz,1)+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
//
|
||
// Accomodate words ending in C
|
||
//
|
||
//////////
|
||
if substr(cHold,-1,1)=="C"
|
||
for kk := 1 to nSuffix
|
||
cTemp := cHold+"K"+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
endif
|
||
//
|
||
// Accomodate words ending in ND
|
||
//
|
||
//////////
|
||
if substr(cHold,-2,2)=="ND"
|
||
cTemp := substr(cHold,1,zz-1)+"SE"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
for kk := 1 to nSuffix
|
||
cTemp := substr(cHold,1,zz-1)+"SE"+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
cTemp := substr(cHold,1,zz-1)+"S"+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
endif
|
||
//
|
||
// Words ending in E, remove the E and try
|
||
//
|
||
///////////////////////////////////////
|
||
if substr(cHold,zz,1)=="E"
|
||
for kk := 1 to nSuffix
|
||
cTemp := substr(cHold,1,zz-1)+aEnds[kk]
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
endif
|
||
endif
|
||
|
||
if ADD_PREFIXES
|
||
for kk := 1 to 7
|
||
cTemp := aBegs[kk]+cHold
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check( cTemp )
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
next
|
||
endif
|
||
|
||
if ADD_PLURALS
|
||
cTemp := cHold+"S"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check(cTemp)
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
|
||
if substr(cHold,zz,1)=="Y"
|
||
cTemp := substr(cHold,1,zz-1)+"IES"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check(cTemp)
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
elseif substr(cHold,zz,1)=="F"
|
||
cTemp := substr(cHold,1,zz-1)+"VES"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check(cTemp)
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
elseif substr(cHold,zz,1)=="O"
|
||
cTemp := cHold+"ES"
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cTemp}) == 0 .and. ;
|
||
SP_Check(cTemp)
|
||
Aadd( aRet_,"C"+SP_Rate(cTemp,cWord)+cTemp )
|
||
endif
|
||
endif
|
||
endif
|
||
next
|
||
endif
|
||
|
||
//
|
||
// Check metaphone matches, only if SUGGEST_PREFERENCE is metafone or both,
|
||
// because this search can slow things down a bit
|
||
//
|
||
////////////////////////////
|
||
if SUGGEST_PREFERENCE $ "MB"
|
||
if METAPHONE_SIZE == 0
|
||
zz := min( 5,len(cWord))
|
||
if zz < 3
|
||
zz := 3
|
||
endif
|
||
else
|
||
zz := METAPHONE_SIZE
|
||
endif
|
||
cTemp := SP_GetBuf(cWord)
|
||
ii := len(cTemp)
|
||
cMeta := C_Metafone(cWord,zz)
|
||
zz := len(cMeta)
|
||
cFirst := substr(cWord,1,2)
|
||
|
||
if ii > 0
|
||
|
||
if substr(cMeta,2,1) >= "N"
|
||
|
||
kk := ii-5
|
||
jj := ii-4
|
||
|
||
do while kk > 0
|
||
if asc(substr(cTemp,kk,1)) >= 128 // End of word
|
||
cHold := cFirst+xUnForm(substr(cTemp,kk+1,jj-kk))
|
||
cKey := c_metafone(cHold,zz)
|
||
if cMeta == c_Metafone(cHold,zz)
|
||
if MAX_DIFFERENCE < 0 .or. abs(len(cWord)-len(cHold)) <= MAX_DIFFERENCE
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0
|
||
Aadd( aRet_,"B"+SP_Rate(cHold,cWord)+cHold )
|
||
endif
|
||
endif
|
||
elseif cKey < cMeta
|
||
exit
|
||
endif
|
||
jj := kk
|
||
endif
|
||
kk--
|
||
enddo
|
||
|
||
|
||
else
|
||
kk := 1
|
||
jj := 1
|
||
|
||
do while kk < ii
|
||
if asc(substr(cTemp,kk,1)) >= 128 // End of word
|
||
cHold := cFirst+xUnForm(substr(cTemp,jj,kk-jj+1))
|
||
cKey := c_metafone(cHold,zz)
|
||
if cMeta == c_Metafone(cHold,zz)
|
||
if MAX_DIFFERENCE < 0 .or. abs(len(cWord)-len(cHold)) <= MAX_DIFFERENCE
|
||
if ascan(aRet_,{ |xx| substr(xx,5)==cHold}) == 0
|
||
Aadd( aRet_,"B"+SP_Rate(cHold,cWord)+cHold )
|
||
endif
|
||
endif
|
||
elseif cKey > cMeta
|
||
exit
|
||
endif
|
||
jj := kk+1
|
||
endif
|
||
kk++
|
||
enddo
|
||
endif
|
||
|
||
endif
|
||
endif
|
||
|
||
|
||
nSugg := len(aRet_)
|
||
if nSugg > 1 .and. SORT_SUGGESTIONS
|
||
Asort(aRet_)
|
||
endif
|
||
|
||
for kk := 1 to nSugg
|
||
aRet_[kk] := substr(aRet_[kk],5)
|
||
next
|
||
|
||
return aRet_
|
||
*******************************************************************************
|
||
|
||
**
|
||
** Function: Sp_Quick()
|
||
** Purpose: To return an array of quick spellings
|
||
** Syntax: aSuggest := Sp_Quick( cWord )
|
||
** Arguments: cWord - Word to look for suggestions for
|
||
** Returns: aSuggest - List of suggested words
|
||
**
|
||
******************************************************************************
|
||
function Sp_Quick( cWord )
|
||
|
||
STATIC aTryThese := { "AI$AO$AU$AY$EA$EI$EIGH$ET$EY$E$O$",;
|
||
"A$AE$AI$AY$EA$EI$EO$IE$U$O$",;
|
||
"A$E$EE$IA$IE$O$U$UI$Y$YE$UY$EI$IGH$",;
|
||
"AU$EAU$EO$EW$OA$OE$OH$OU$OUGH$OW$A$AH$AW$UO$E$",;
|
||
"O$OE$OO$OU$EUA$EU$EUE$EW$IEU$IEW$UE$UI$YOU$YU$",;
|
||
"ED$GHT$PT$TH$" }
|
||
|
||
LOCAL ii := 0
|
||
LOCAL nOld,jj,kk
|
||
LOCAL zz := len(cWord)
|
||
LOCAL arr_ := {}
|
||
LOCAL cHold,ll,cTemp
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_quick"
|
||
|
||
cWord := upper(trim(cWord))
|
||
|
||
if zz < 3 && Don't offer suggestions for
|
||
return {} && one or two letter words
|
||
endif
|
||
|
||
|
||
**
|
||
** Step One - Do letter doubling
|
||
**
|
||
**********************************
|
||
for jj := 2 to zz
|
||
if substr(cWord,jj,1)$"BCDEFGKLMNOPRSTZ"
|
||
cHold := left(cWord,jj)+substr(cWord,jj, 1)+;
|
||
substr(cWord,jj+1)
|
||
**
|
||
** If the word is not already in the list, then check
|
||
** to see if it is a valid word.
|
||
**
|
||
******************************************
|
||
if ascan(arr_,cHold) == 0 .and. Sp_Check(cHold)
|
||
Aadd(arr_,cHold)
|
||
endif
|
||
endif
|
||
next
|
||
|
||
**
|
||
** Step Two - Remove extra letters
|
||
**
|
||
**********************************
|
||
for jj := 1 to zz
|
||
cHold := left(cWord,jj-1)+substr(cWord,jj+1)
|
||
**
|
||
** If the word is not already in the list, then check
|
||
** to see if it is a valid word.
|
||
**
|
||
******************************************
|
||
if ascan(arr_,cHold) == 0 .and. Sp_Check(cHold)
|
||
Aadd(arr_,cHold)
|
||
endif
|
||
next
|
||
|
||
**
|
||
** Step Three - Transpose the letters
|
||
**
|
||
**************************
|
||
for jj := 2 to zz
|
||
cHold := left(cWord,jj-2)+substr(cWord,jj, 1)+;
|
||
substr(cWord,jj-1,1)+substr(cWord,jj+1)
|
||
if ascan(arr_,cHold) == 0 .and. Sp_Check(cHold)
|
||
Aadd(arr_,cHold)
|
||
endif
|
||
next
|
||
|
||
**
|
||
** Step Four - Try adding a silent E to the end
|
||
**
|
||
******************
|
||
|
||
cHold := cWord+"E"
|
||
if ascan(arr_,cHold) == 0 .and. Sp_Check(cHold)
|
||
Aadd(arr_,cHold)
|
||
endif
|
||
|
||
**
|
||
** Step Five - Do sound alike substitutions
|
||
**
|
||
**********************************
|
||
|
||
|
||
for jj := 1 to 6
|
||
if substr("AEIOUT",jj,1)$cWord
|
||
ii := fat(substr("AEIOUT",jj,1),cWord,ii)
|
||
nold := 1
|
||
do while ii > 0
|
||
for kk := 1 to chrcount("$",aTryThese[jj])
|
||
ll := fat("$",aTryThese[jj],nOld)
|
||
cTemp := substr(aTryThese[jj],nOld,ll-nOld)
|
||
nOld := ll +1
|
||
cHold := substr(cWord,1,ii-1)+cTemp+substr(cWord,ii+1)
|
||
if ascan(arr_,cHold) == 0 .and. Sp_Check(cHold)
|
||
Aadd(arr_,cHold)
|
||
endif
|
||
next
|
||
ii++
|
||
ii := fat(substr("AEIOUT",jj,1),cWord,ii)
|
||
enddo
|
||
endif
|
||
next
|
||
|
||
return arr_
|
||
|
||
STATIC function ChrCount(cChar,cString)
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At ChrCount"
|
||
|
||
return len(cString)-len(strTran(cString,cChar,""))
|
||
|
||
**
|
||
** Function: Sp_Split()
|
||
** Purpose:
|
||
** Syntax:
|
||
** Arguments:
|
||
** Returns:
|
||
**
|
||
******************************************************************************
|
||
function Sp_Split( cWord )
|
||
LOCAL arr_ := {}
|
||
LOCAL x
|
||
LOCAL cWord1
|
||
LOCAL cWord2
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_split"
|
||
|
||
for x := 2 to len(cWord)
|
||
cWord1 := left(cWord,x-1)
|
||
cWord2 := substr(cWord,x)
|
||
if len(cWord1) > 1 .and. len(cWord2) > 1
|
||
if SP_Check(cWord1) .and. SP_Check(cWord2)
|
||
Aadd(arr_,cWord1+' '+cWord2)
|
||
endif
|
||
endif
|
||
next
|
||
return arr_
|
||
******************************************************************************
|
||
|
||
|
||
**
|
||
** Function: Sp_Expand()
|
||
** Purpose:
|
||
** Syntax:
|
||
** Arguments:
|
||
** Returns:
|
||
**
|
||
******************************************************************************
|
||
function SP_Expand(cWord)
|
||
LOCAL x
|
||
LOCAL cExpand
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_expand"
|
||
|
||
cWord := upper(alltrim(cWord))
|
||
x := ascan( aContracts, { |jj|jj[1]=cWord } )
|
||
if x > 0
|
||
cExpand := aContracts[x,2]
|
||
endif
|
||
return cExpand
|
||
******************************************************************************
|
||
|
||
|
||
|
||
**
|
||
** Function: Sp_WildCard()
|
||
** Purpose: To return an array of wildcard matches
|
||
** Syntax: aSuggest := Sp_WildCard( cPattern )
|
||
** Arguments: cPattern - Pattern to match using * or ?'s
|
||
** Returns: aSuggest - List of matching words
|
||
**
|
||
******************************************************************************
|
||
function Sp_Wildcard( cPattern )
|
||
LOCAL cTemp
|
||
LOCAL ii,kk,jj,cFirst,cHold,x,z
|
||
LOCAL arr_ := {}
|
||
LOCAL nStart,nEnd
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_wildcard"
|
||
|
||
cPattern := upper(cPattern)
|
||
|
||
if SP_Init()
|
||
x := fat("*",cPattern)
|
||
if x == 0
|
||
x := fat("?",cPattern)
|
||
endif
|
||
if x == 1 // Can't handle wildcards in first position
|
||
return arr_
|
||
endif
|
||
if x == 2
|
||
nStart := 1
|
||
nEnd := 26
|
||
else
|
||
nStart := asc(substr(cPattern,2,1))-64
|
||
nEnd := nStart
|
||
endif
|
||
|
||
|
||
for z := nStart to nEnd
|
||
cTemp := SP_GetBuf(substr(cPattern,1,1)+chr(z+64) )
|
||
ii := len(cTemp)
|
||
cFirst := substr(cPattern,1,1)+chr(z+64)
|
||
|
||
if ii > 0
|
||
kk := 1
|
||
jj := 1
|
||
do while kk < ii
|
||
if asc(substr(cTemp,kk,1)) >= 128 // End of word
|
||
cHold := cFirst+xUnForm(substr(cTemp,jj,kk-jj+1))
|
||
if WildCard(cPattern,cHold)
|
||
Aadd( arr_,cHold )
|
||
endif
|
||
jj := kk+1
|
||
endif
|
||
kk++
|
||
enddo
|
||
endif
|
||
next
|
||
endif
|
||
return arr_
|
||
|
||
|
||
|
||
******************************************************************************
|
||
* The following functions are internal and should not be modified. *
|
||
******************************************************************************
|
||
|
||
// Function: SP_Init()
|
||
// Purpose: Internal function to initialize the dictionary
|
||
// Arguments: NONE
|
||
// Returns: <logical> - Was dictionary initialized?
|
||
//
|
||
// Notes:
|
||
//
|
||
////////////////////////////
|
||
function Sp_init
|
||
LOCAL isok := .T.
|
||
LOCAL cBuf
|
||
LOCAL i
|
||
LOCAL j
|
||
LOCAL nOther := 0
|
||
LOCAL cOther := ""
|
||
LOCAL nFileSize
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_init"
|
||
|
||
if cOffsets == NIL
|
||
isok := .F.
|
||
nHandle := fopen(DICTIONARY_PATH+DICTIONARY_NAME,32)
|
||
if nHandle > 0
|
||
|
||
#ifdef REDUCE_MEMORY_NEEDS
|
||
|
||
cBuf := space(6)
|
||
fread(nHandle,@cBuf,6)
|
||
|
||
#else
|
||
|
||
cBuf := space(NSIZE+6)
|
||
fread(nHandle,@cBuf,NSIZE+6)
|
||
|
||
#endif
|
||
|
||
if substr(cBuf,1,2)=="JJ"
|
||
nOther := bin2l(substr(cBuf,3,4))
|
||
|
||
#ifndef REDUCE_MEMORY_NEEDS
|
||
|
||
cOffSets := substr(cBuf,7)
|
||
|
||
#endif
|
||
|
||
nFileSize := fseek(nHandle,0,2)
|
||
if nFileSize-nOther > 0
|
||
cOther := space(nFileSize-nOther)
|
||
fseek(nHandle,nOther,0)
|
||
fread(nHandle,@cOther,(nFileSize-nOther))
|
||
endif
|
||
aGlobal[2] += cOther
|
||
isok := .T.
|
||
endif
|
||
if !empty( AUXILIARY_DICTIONARY )
|
||
SP_LoadAux( AUXILIARY_DICTIONARY )
|
||
endif
|
||
endif
|
||
if aGlobal[1] == NIL
|
||
SP_Common()
|
||
endif
|
||
|
||
** Thesaurus comented out as not needed
|
||
* if !empty( THESAURUS_NAME )
|
||
* if file( DICTIONARY_PATH+THESAURUS_NAME )
|
||
* SP_OpenThes( DICTIONARY_PATH+THESAURUS_NAME )
|
||
* elseif file( THESAURUS_NAME )
|
||
* SP_OpenThes( THESAURUS_NAME )
|
||
* endif
|
||
* endif
|
||
|
||
endif
|
||
|
||
return isok
|
||
******************************************************************************
|
||
|
||
|
||
//
|
||
// Function: DBF2Dic()
|
||
// Purpose: To create a DIC file from a DBF list of words
|
||
// Syntax: nStatus := DBF2Dic( <cDBF_file>,<cDIC_file> )
|
||
// Arguments: <cDBF_File> - DBF containing sorted list of upper
|
||
// case words. The field name must be
|
||
// WORD and of type character
|
||
// <cDIC_File> - Name of DIC file to create, assumes
|
||
// DICT.DIC
|
||
// Returns: nStatus - 0 if successful
|
||
// -1 DBF file does not exist
|
||
// -2 Field WORD does not exist in DBF
|
||
// >0 File error occurred, see FERROR()
|
||
//
|
||
// Calls:
|
||
//
|
||
//////////////////////////////////
|
||
function DBF2Dic(cDbf,cDictionary,lTalk)
|
||
|
||
LOCAL nStatus := 0 // Status code
|
||
LOCAL i // Loop counters
|
||
LOCAL j
|
||
LOCAL x
|
||
LOCAL nH // File handle
|
||
LOCAL nWhere
|
||
LOCAL temp
|
||
LOCAL cBits
|
||
LOCAL cSave
|
||
LOCAL nSize
|
||
LOCAL cOther := ""
|
||
LOCAL nCurRec := 0
|
||
|
||
//
|
||
// DEFAULT name for dictionary file
|
||
//
|
||
//////////////////////////////////////
|
||
**DEBUG**
|
||
@24,30 SAY "At DBF2DIC"
|
||
|
||
if cDictionary == NIL
|
||
cDictionary := "DICT.DIC"
|
||
endif
|
||
|
||
if lTalk == NIL
|
||
lTalk := .F.
|
||
endif
|
||
|
||
|
||
//
|
||
// See if the DBF file exists
|
||
//
|
||
//////////////////////////////////////
|
||
if .not. "."$cDBF
|
||
cDBF += ".DBF"
|
||
endif
|
||
|
||
if !file( cDBF )
|
||
return -1
|
||
endif
|
||
|
||
use (cDbf) alias DICT new
|
||
if fieldpos("WORD") == 0
|
||
use
|
||
return -2
|
||
endif
|
||
|
||
if lTalk
|
||
|
||
cSave := SaveScreen(8,30,11,48)
|
||
DispBox(8,30,11,48,,"W+/R")
|
||
@ 8,33 say " Creating DIC " color "W+/R"
|
||
@ 9,31 say " Indexing words " color "W/R"
|
||
@ 10,31 say " " color "W/R"
|
||
|
||
nSize := DICT->(lastrec())
|
||
|
||
endif
|
||
|
||
index on substr(DICT->word,1,2)+padr(c_metafone(alltrim(DICT->word),5),6) to $$temp
|
||
go top
|
||
|
||
|
||
if lTalk
|
||
@ 9,31 say "Percent " color "W/R"
|
||
@ 10,31 say "Complete: " color "W/R"
|
||
endif
|
||
|
||
//
|
||
// Create the dictionary file
|
||
//
|
||
//////////////////////////////////////
|
||
&& ADDED - 02/08/96 - JAMES
|
||
IF nHandle > 0 && Is dictionary already open?
|
||
FCLOSE(nHandle) && Yes, close it
|
||
nHandle := 0
|
||
ENDIF && END OF ADDITION
|
||
|
||
nH := fcreate(cDictionary)
|
||
|
||
if nH >= 0
|
||
//
|
||
// Write out enough bytes to hold the index information
|
||
//
|
||
/////////////////////////////////////////////////////////////////////////
|
||
fwrite(nH,"JJ"+l2bin(NSIZE+4)+replicate(chr(0),NSIZE)+space(10),NSIZE+16)
|
||
|
||
for i := 1 to 26
|
||
do while substr(DICT->word,1,1)==chr(i+64) .and. !eof()
|
||
for j := 1 to 26
|
||
temp := ""
|
||
cBits := FOUR_BYTES
|
||
do while !isAlpha(substr(DICT->word,2,1)) .and. !eof()
|
||
if len(alltrim(DICT->word)) > 0
|
||
cOther += "|"+alltrim(DICT->word)
|
||
endif
|
||
skip +1
|
||
enddo
|
||
do while substr(DICT->word,2,1)==chr(j+64) .and. !eof()
|
||
if len(trim(DICT->word))=3
|
||
Bit(cBits,asc(substr(DICT->word,3,1))-64,.T.)
|
||
elseif len(trim(DICT->word))==2
|
||
Bit(cBits,27,.T.)
|
||
else
|
||
temp += StoreWord(trim(DICT->word))
|
||
endif
|
||
skip +1
|
||
if lTalk
|
||
nCurRec++
|
||
@ 10,41 say (nCurRec/nSize) * 100 picture "999.9%" color "W+/R"
|
||
endif
|
||
enddo
|
||
if !empty(temp) .or. cBits != FOUR_BYTES
|
||
|
||
nWhere := fseek(nH,0,2)
|
||
|
||
Fseek(nH,((i-1)*26*EACH_WORD)+((j-1)*EACH_WORD)+6)
|
||
Fwrite(nH,l2bin(nWhere)+i2bin(len(temp)+4),EACH_WORD)
|
||
Fseek(nH,0,2)
|
||
Fwrite(nH,cBits+temp,len(temp)+4)
|
||
endif
|
||
next
|
||
enddo
|
||
next
|
||
j := fseek(nH,0,2)
|
||
fseek(nH,2,0)
|
||
fwrite(nH,l2bin(j),4)
|
||
if !empty(cOther)
|
||
fseek(nH,j,0)
|
||
cOther += "|"
|
||
fwrite(nH,cOther,len(cOther))
|
||
endif
|
||
fclose(nH)
|
||
else
|
||
nStatus := nH
|
||
endif
|
||
|
||
if lTalk
|
||
RestScreen(8,30,11,48,cSave)
|
||
endif
|
||
|
||
select DICT
|
||
use
|
||
// ferase("$$TEMP"+indexext())
|
||
return nStatus
|
||
*******************************************************************************
|
||
|
||
//
|
||
// Function: Dic2DBF()
|
||
// Purpose: To create a DBF file from a DIC file
|
||
// Syntax: nStatus := DIC2DBF( <cDIC_file>,<cDBF_file> )
|
||
// Arguments: <cDIC_File> - Name of DIC file to read, assumes
|
||
// DICT.DIC
|
||
// <cDBF_File> - Name of DBF to create, assumes DICT.DBF
|
||
// It will contain a single field called
|
||
// WORD of type character
|
||
// Returns: nStatus - 0 if successful
|
||
// -1 DIC file does not exist
|
||
// -2 DIC file is not a valid dictionary
|
||
//
|
||
// Calls:
|
||
//
|
||
//////////////////////////////////
|
||
function DIC2DBF(cDictionary,cDBF,lTalk)
|
||
|
||
LOCAL nStatus := 0 // Status code
|
||
LOCAL i // Loop counters
|
||
LOCAL j
|
||
LOCAL x,y,z
|
||
LOCAL temp
|
||
LOCAL cBuf
|
||
LOCAL cWord
|
||
LOCAL cSave
|
||
LOCAL nSize
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At DIC2DBF"
|
||
|
||
//
|
||
// DEFAULT name for dictionary file
|
||
//
|
||
//////////////////////////////////////
|
||
if cDictionary == NIL
|
||
cDictionary := "DICT.DIC"
|
||
endif
|
||
|
||
if lTalk == NIL
|
||
lTalk := .F.
|
||
endif
|
||
|
||
if !file(cDictionary)
|
||
return -1
|
||
endif
|
||
|
||
DICTIONARY_NAME := cDictionary
|
||
|
||
//
|
||
// Read the dictionary file
|
||
//
|
||
//////////////////////////////////////
|
||
if !SP_Init()
|
||
return -2
|
||
endif
|
||
//
|
||
// See if the DBF file exists
|
||
//
|
||
//////////////////////////////////////
|
||
if .not. "."$cDBF
|
||
cDBF += ".DBF"
|
||
endif
|
||
|
||
dbcreate( cDbf,{ {"WORD","C",25,0} } )
|
||
|
||
use (cDbf) alias DICT new
|
||
|
||
if lTalk
|
||
cSave := SaveScreen(8,30,12,48)
|
||
DispBox(8,30,12,48,,"W+/R")
|
||
@ 8,34 say " Creating DBF " color "W+/R"
|
||
@ 9,31 say "Percent " color "W/R"
|
||
@ 10,31 say "Complete: " color "W/R"
|
||
@ 11,31 say " Record: " color "W/R"
|
||
|
||
temp := directory(cDictionary)
|
||
nSize := temp[1,2]
|
||
|
||
endif
|
||
|
||
|
||
j := 2
|
||
|
||
for i := 2 to len(CACHE_WORDS)
|
||
if substr(CACHE_WORDS,i,1)=="|"
|
||
append blank
|
||
replace DICT->word with substr(CACHE_WORDS,j,i-j)
|
||
j := i +1
|
||
endif
|
||
next
|
||
|
||
|
||
for i := 1 to 26
|
||
for j := 1 to 26
|
||
temp := chr(i+64)+chr(j+64)
|
||
x := bin2l(substr(cOffsets,((i-1)*156)+((j-1)*EACH_WORD+1),4))
|
||
if !empty(x)
|
||
y := bin2w(substr(cOffsets,((i-1)*156)+((j-1)*EACH_WORD+5),2))
|
||
|
||
if lTalk
|
||
@ 10,43 say (x/nSize) * 100 picture "999%" color "W+/R"
|
||
@ 11,41 say lastrec() picture "99,999" color "W+/R"
|
||
endif
|
||
|
||
cBuf := space(y)
|
||
fseek(nHandle,x,0)
|
||
fread(nHandle,@cBuf,y)
|
||
for z := 1 to 26
|
||
if bit(cBuf,z)
|
||
append blank
|
||
replace DICT->word with temp+chr(z+64)
|
||
endif
|
||
next
|
||
if bit(cBuf,27)
|
||
append blank
|
||
replace DICT->word with temp
|
||
endif
|
||
cBuf := substr(cBuf,5)
|
||
z := 1
|
||
do while !empty(cBuf)
|
||
if substr(cBuf,z,1)>=Chr(128)
|
||
cWord := substr(cBuf,1,z)
|
||
append blank
|
||
replace DICT->word with temp+ExtractWord(cWord)
|
||
cWord := ""
|
||
cBuf := substr(cBuf,z+1)
|
||
z := 1
|
||
|
||
if lTalk
|
||
@ 11,41 say lastrec() picture "99,999" color "W+/R"
|
||
endif
|
||
|
||
else
|
||
z++
|
||
endif
|
||
enddo
|
||
if !empty(cWord)
|
||
endif
|
||
cWord := ""
|
||
endif
|
||
next
|
||
next
|
||
|
||
if lTalk
|
||
RestScreen(8,30,12,48,cSave)
|
||
endif
|
||
|
||
select DICT
|
||
use
|
||
return nStatus
|
||
********************************************************************************
|
||
|
||
// Function: SP_Common()
|
||
// Purpose: Loads the COMMON word static array element
|
||
// Syntax: SP_Common()
|
||
// Arguments: <NONE>
|
||
// Returns: NIL
|
||
//
|
||
// Notes: The common word list represents some of the most commonly
|
||
// used English words. They are stored in RAM to prevent a
|
||
// dictionary lookup for 70-80% of the words.
|
||
//
|
||
///////////////////////////
|
||
STATIC function SP_common
|
||
|
||
#ifDef REDUCE_MEMORY_NEEDS
|
||
|
||
aGlobal_[1] := "|THE|OF|AND|TO|A|IN|THAT|FOR|IS|WAS|IT|HE|I|AS"+;
|
||
"|WITH|ON|HIS|BE|AT|BY|NOT|THIS|HAD|HAVE|YOU|BUT"+;
|
||
"|FROM|ARE|OR|WHICH|AN|THEY|WILL|ONE|WERE|ALL|WE"+;
|
||
"|HER|SHE|WOULD|THERE|HAS|BEEN|HIM|THEIR|IF|WHEN"+;
|
||
"|SO|MORE|NO|WHO|YOUR|OUT|MY|I'VE|I'D|I'LL|CAN'T|"
|
||
|
||
#else
|
||
|
||
aGlobal[1] := "|THE|OF|AND|TO|A|IN|THAT|FOR|IS|WAS|IT|HE|I|AS|WITH|ON|HIS|BE|AT|BY"+;
|
||
"|NOT|THIS|HAD|HAVE|YOU|BUT|FROM|ARE|OR|WHICH|AN|THEY|WILL|ONE|WERE|ALL"+;
|
||
"|WE|HER|SHE|WOULD|THERE|HAS|BEEN|HIM|THEIR|IF|WHEN|SO|MORE|NO|WHO|YOUR"+;
|
||
"|OUT|MY|WHAT|UP|CAN|THEM|ABOUT|INTO|ITS|TIME|SOME|THAN|ME|OTHER|ONLY|NEW"+;
|
||
"|COULD|SAID|ANY|THESE|MAY|TWO|THEN|DO|FIRST|NOW|MAN|SUCH|VERY|LIKE|OVER"+;
|
||
"|OUR|EVEN|MOST|AFTER|MADE|ALSO|DID|MANY|SHOULD|BEFORE|MUST|THROUGH|YEARS"+;
|
||
"|WHERE|MUCH|WAY|WELL|DOWN|GOOD|BECAUSE|HERE|EACH|THOSE|PEOPLE|STATE|HOW"+;
|
||
"|TOO|LITTLE|WORLD|LAST|WORK|STILL|BACK|OWN|SEE|MEN|LONG|GET|JUST|GO|HOUSE"+;
|
||
"|BETWEEN|BOTH|LIFE|BEING|UNDER|YEAR|NEVER|DAY|SAME|ANOTHER|KNOW|WHILE|MIGHT"+;
|
||
"|US|GREAT|OLD|OFF|COME|AGAINST|SINCE|CAME|RIGHT|TAKE|USED|THREE|SMALL|MAKE"+;
|
||
"|STATES|HIMSELF|FEW|DURING|WITHOUT|AGAIN|PLACE|AROUND|HOWEVER|HOME|FOUND"+;
|
||
"|SAY|WHOSE|THOUGHT|NIGHT|DEAR|ONCE|WENT|GENERAL|HIGH|UPON|SCHOOL|EVERY|PART"+;
|
||
"|DON'T|DOES|GOT|UNITED|LEFT|NUMBER|COURSE|WAR|GOING|UNTIL|ALWAYS|AWAY"+;
|
||
"|SOMETHING|FACT|THOUGH|WATER|LESS|PUBLIC|PUT|THINK|ALMOST|HAND|ENOUGH|FAR"+;
|
||
"|TOOK|YET|GOVERNMENT|SYSTEM|BETTER|EYES|SET|TOLD|NOTHING|PRESIDENT|END"+;
|
||
"|HEAD|WHY|CALLED|DIDN'T|FIND|LOOK|ASKED|LATER|POINT|NEXT|PROGRAM|KNEW|CITY"+;
|
||
"|BUSINESS|GIVE|GROUP|TOWARD|YOUNG|DAYS|LET|ROOM|WITHIN|CHILDREN|SIDE|SOCIAL"+;
|
||
"|GIVEN|ORDER|PRESENT|SEVERAL|NATIONAL|USE|RATHER|SECOND|FACE|PER|POSSIBLE"+;
|
||
"|AMONG|FORM|IMPORTANT|OFTEN|THINGS|LOOKED|EARLY|WHITE|BECOME|CASE|SEND"+;
|
||
"|BIG|LARGE|NEED|FOUR|FELT|ALONG|GOD|SAW|BEST|CHURCH|EVER|LEAST|POWER"+;
|
||
"|DEVELOPMENT|LIGHT|THING|FAMILY|INTEREST|SEEMED|WANT|TODAY|MEMBERS|MIND"+;
|
||
"|COUNTRY|AREA|OTHERS|TURNED|ALTHOUGH|DONE|OPEN|SERVICE|CERTAIN|KIND|PROBLEM"+;
|
||
"|BEGAN|DIFFERENT|DOOR|THUS|HELP|MEANS|SENSE|WHOLE|MATTER|PERHAPS|ITSELF"+;
|
||
"|IT'S|TIMES|HUMAN|LAW|LINE|ABOVE|NAME|EXAMPLE|COMPANY|HANDS|LOCAL|SHOW"+;
|
||
"|BODY|FIVE|HISTORY|WHETHER|GAVE|EITHER|ACROSS|ACT|ACTION|FEET|ANYTHING"+;
|
||
"|PAST|QUITE|TAKEN|HAVING|SEEN|DEATH|EXPERIENCE|HALF|REALLY|WEEK|WORDS"+;
|
||
"|CAR|FIELD|MONEY|WORD|ALREADY|THEMSELVES|INFORMATION|I'M|TELL|CLOSE"+;
|
||
"|COLLEGE|PERIOD|SHALL|TOGETHER|HELD|KEEP|SURE|PROBABLY|FREE|REAL|BEHIND"+;
|
||
"|SEEMS|CANNOT|POLITICAL|AIR|QUESTION|OFFICE|WOMAN|BROUGHT|MAJOR|MOTHER"+;
|
||
"|SPECIAL|HEARD|PROBLEMS|AGO|BECAME|AVAILABLE|FEDERAL|MOMENT|STUDY"+;
|
||
"|KNOWN|RESULT|STREET|BOY|ECONOMIC|CHANGE|POSITION|REASON|SOUTH|BOARD"+;
|
||
"|INDIVIDUAL|JOB|SOCIETY|AREAS|WEST|SPACE|TURN|LOVE|COMMUNITY|TOWN|TRUE"+;
|
||
"|COURT|FORCE|FULL|SEEM|AGE|AM|COST|WIFE|FUTURE|VOICE|WANTED|CAN'T|DEPARTMENT"+;
|
||
"|USE|CENTER|COMMON|CONTROL|NECESSARY|POLICY|FOLLOWING|FRONTSOMETIMES|FATHER"+;
|
||
"|GIRL|SIX|WOMEN|CLEAR|MILITARY|FURTHER|ABLE|FIGURE|LAND|FEEL|MUSIC|PARTY"+;
|
||
"|PROVIDE|CENTURY|EDUCATION|UNIVERSITY|CHILD|EFFECT|STUDENTS|RUN|SHORT"+;
|
||
"|STOOD|MORNING|TOTAL|OUTSIDE|ART|RATE|SAYS|YOU'RE|CLASS|TYPE|EVIDENCE"+;
|
||
"|EXCEPT|LEAVE|MILLION|MISS|NORTH|PLAN|SOUND|THEREFORE|TOP|USUALLY|BLACK"+;
|
||
"|HARD|SCHOOLS|STRONG|BELIEVE|PLAY|VARIOUS|SURFACE|MAKING|MEAN|SOON|VALUE"+;
|
||
"|LINES|MODERN|NEAR|TABLE|PRIVATE|RED|ROAD|TAX|ALONE|MINUTES|PERSONAL|PROCESS"+;
|
||
"|SITUATION|THAT'S|GONE|IDEA|INCREASE|NOR|PEACE|SECTION|LIVING|STARTED|BOOK"+;
|
||
"|LONGER|CUT|FINALLY|NATURE|SECRETARY|MONTHS|THIRD|CALL|COMPLETE|GREATER"
|
||
|
||
aGlobal[1] += "|EXPECTED|FIRE|NEEDED|KEPT|VALUES|VIEW|BASIS|DARK|EVERYTHING|PRESSURE"+;
|
||
"|GROUND|EAST|RECENT|REQUIRED|SPIRIT|UNION|HOPE|I'LL|MOVED|NATIONS|WROTE"+;
|
||
"|CONDITIONS|RETURN|SUPPORT|ATTENTION|LATE|PARTICULAR|BROWN|COSTS|ELSE|NATION"+;
|
||
"|BEYOND|COULDN'T|FORCES|HOURS|NUCLEAR|PERSON|TAKING|COMING|DEAD|INSIDE|LOW"+;
|
||
"|MATERIAL|REPORT|STAGE|ADDED|AMOUNT|BASIC|DATA|FEELING|FOLLOWED|HEART|INSTEAD"+;
|
||
"|LOOKING|LOST|MILES|PAY|SINGLE|COLD|HUNDRED|INCLUDING|INDUSTRY|MOVE|RESEARCH"+;
|
||
"|SHOWN|BRIDGE|DEVELOPED|SIMPLY|TRIED|HOLD|REACHED|SHARE|SORT|COMMITTEE|DEFENSE"+;
|
||
"|EQUIPMENT|ISLAND|SENDING|ACTUALLY|EARTH|BEGINNING|RELIGIOUS|RIVER|TEN|CENTRAL"+;
|
||
"|DOING|GETTING|LETTER|RECEIVED|REST|TERMS|TRYING|CARE|FRIENDS|INDEED|MEDICAL"+;
|
||
"|PICTURE|DIFFICULT|FINE|SIMPLE|STATUS|SUBJECT|BUILDING|ESPECIALLY|HIGHER|RANGE"+;
|
||
"|WALL|BRING|MEETING|WALKED|CENT|FLOOR|FOREIGN|NEEDS|PAPER|PASSED|SIMILAR"+;
|
||
"|FINAL|NATURAL|PROPERTY|TRAINING|COUNTY|GROWTH|HOT|INTERNATIONAL|LIVE"+;
|
||
"|MARKET|POLICE|START|TALK|WASN'T|WRITTEN|BOOKS|ANSWER|CONGRESS|HEAR|PRIMARY"+;
|
||
"|STORY|SUDDENLY|CONSIDERED|COUNTRIES|HALL|ISSUE|LIKELY|PARTICULARLY|TRULY"+;
|
||
"|WORKING|EFFORT|SAT|ENTIRE|HAPPENED|LABOR|PURPOSE|RESULTS|CASES|DIFFERENCE"+;
|
||
"|HAIR|PRODUCTION|STAND|I'VE|I'D|WON'T|"
|
||
|
||
|
||
#endif
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At SP_common"
|
||
|
||
return NIL
|
||
******************************************************************************
|
||
|
||
function WildCard(cPattern,cString)
|
||
LOCAL lMatch := .F.
|
||
LOCAL x := at("*",cPattern)
|
||
LOCAL cBefore
|
||
LOCAL cAfter
|
||
LOCAL y
|
||
LOCAL nStrSize,nPatSize
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At wildcard"
|
||
|
||
cString := upper(alltrim(cString))
|
||
|
||
if cPattern == "*"
|
||
return .T.
|
||
endif
|
||
//
|
||
// Do a * match
|
||
//
|
||
if x > 0
|
||
cBefore := upper(substr(cPattern,1,x-1))
|
||
cAfter := upper(substr(cPattern,x+1))
|
||
do case
|
||
case empty(cBefore)
|
||
lMatch := right(cString,len(cAfter))==cAfter
|
||
case empty(cAfter)
|
||
lMatch := left(cString,len(cBefore))==cBefore
|
||
otherwise
|
||
lMatch := ( left(cString,len(cBefore))==cBefore ) .and. ;
|
||
right(cString,len(cAfter))==cAfter
|
||
endcase
|
||
else
|
||
x := at("?",cPattern)
|
||
if x > 0
|
||
nPatSize := len(cPattern)
|
||
nStrSize := len(cString)
|
||
if nPatSize == nStrSize
|
||
lMatch := .T.
|
||
for y := 1 to nPatSize
|
||
if substr(cPattern,y,1)!="?" .and. ;
|
||
substr(cPattern,y,1)!= substr(cString,y,1)
|
||
lMatch := .F.
|
||
exit
|
||
endif
|
||
next
|
||
endif
|
||
else
|
||
lMatch := upper(cPattern)=upper(cString)
|
||
endif
|
||
endif
|
||
return lMatch
|
||
******************************************************************************
|
||
#ifndef CLIP52
|
||
function aWords(cLine)
|
||
LOCAL aWords_ := {}
|
||
LOCAL nSize := len(trim(cLine))
|
||
LOCAL x,y,z
|
||
LOCAL cWord := ""
|
||
LOCAL nOffset
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At clip52"
|
||
|
||
z := 0
|
||
do while z <= nSize
|
||
z++
|
||
y := asc(substr(cLine,z,1))
|
||
if y >=48 .and. ! chr(y)$ ":;<=>?@[\^]_`{|}~"
|
||
nOffset := z
|
||
cWord := chr(y)
|
||
z++
|
||
y := asc(substr(cLine,z,1))
|
||
while ( y >=48 .and. ! chr(y)$ ":;<=>?@[\^]_`{|}~" ) .or. y == 39
|
||
cWord += chr(y)
|
||
z++
|
||
if z > nSize
|
||
exit
|
||
endif
|
||
y := asc(substr(cLine,z,1))
|
||
enddo
|
||
Aadd(aWords_,{cWord,nOffset})
|
||
endif
|
||
enddo
|
||
return aWords_
|
||
#endif
|
||
|
||
* Find an occurrence of 'f_str' in 'l_str' starting from position 'f_rom'
|
||
FUNCTION FAT(f_str, l_str, f_rom)
|
||
|
||
LOCAL ret_val
|
||
|
||
**DEBUG**
|
||
@24,30 SAY "At FAT"
|
||
|
||
IF PCOUNT() < 3 && Is f_rom passed?
|
||
f_rom := 1
|
||
ENDIF
|
||
|
||
ret_val := AT(f_str, SUBSTR(l_str, f_rom))
|
||
|
||
RETURN ret_val
|