Click here to Skip to main content
15,896,154 members
Articles / Desktop Programming / WTL

A WTL Hunspell-checked Edit Control

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
21 Jun 2009CPOL12 min read 42K   2.9K   30  
A WTL Hunspell-checked edit control.
  • wtlspell_src.zip
  • wtlspell_demo.zip
    • en_AU.aff
    • en_AU.dic
    • wtlspell.exe
  • wtlspell_src_incl_hunspell.zip
    • hunspell-1.2.8
      • ABOUT-NLS
      • aclocal.m4
      • AUTHORS
      • AUTHORS.myspell
      • BUGS
      • ChangeLog
      • ChangeLog.O
      • config.guess
      • config.h.in
      • config.sub
      • configure
      • configure.ac
      • COPYING
      • COPYING.LGPL
      • COPYING.MPL
      • depcomp
      • hunspell.pc.in
      • INSTALL
      • install-sh
      • intl
        • bindtextdom.c
        • ChangeLog
        • config.charset
        • dcgettext.c
        • dcigettext.c
        • dcngettext.c
        • dgettext.c
        • dngettext.c
        • eval-plural.h
        • explodename.c
        • finddomain.c
        • gettext.c
        • gettextP.h
        • gmo.h
        • hash-string.h
        • intl-compat.c
        • l10nflist.c
        • libgnuintl.h
        • loadinfo.h
        • loadmsgcat.c
        • localcharset.c
        • locale.alias
        • localealias.c
        • localename.c
        • Makefile.in
        • ngettext.c
        • os2compat.c
        • os2compat.h
        • osdep.c
        • plural.c
        • plural.y
        • plural-exp.c
        • plural-exp.h
        • ref-add.sin
        • ref-del.sin
        • textdomain.c
        • VERSION
        • license.hunspell
        • license.myspell
        • ltmain.sh
        • m4
        • Makefile.am
        • Makefile.in
        • man
        • missing
        • mkinstalldirs
        • NEWS
        • po
          • boldquot.sed
          • en@boldquot.header
          • en@quot.header
          • hu.gmo
          • hu.po
          • hunspell.pot
          • insert-header.sin
          • LINGUAS
          • Makefile.in.in
          • Makevars
          • POTFILES.in
          • quot.sed
          • remove-potcdate.sin
          • Rules-quot
        • README
        • README.myspell
        • src
        • tests
          • 1463589.aff
          • 1463589.dic
          • 1463589.sug
          • 1463589.test
          • 1463589.wrong
          • 1463589_utf.aff
          • 1463589_utf.dic
          • 1463589_utf.sug
          • 1463589_utf.test
          • 1463589_utf.wrong
          • 1592880.aff
          • 1592880.dic
          • 1592880.good
          • 1592880.test
          • 1695964.aff
          • 1695964.dic
          • 1695964.sug
          • 1695964.test
          • 1695964.wrong
          • 1706659.aff
          • 1706659.dic
          • 1706659.test
          • 1706659.wrong
          • 1975530.aff
          • 1975530.dic
          • 1975530.good
          • 1975530.test
          • 1975530.wrong
          • affixes.aff
          • affixes.dic
          • affixes.good
          • affixes.test
          • alias.aff
          • alias.dic
          • alias.good
          • alias.test
          • alias2.aff
          • alias2.dic
          • alias2.good
          • alias2.morph
          • alias2.test
          • alias3.aff
          • alias3.dic
          • alias3.good
          • alias3.morph
          • alias3.test
          • allcaps.aff
          • allcaps.dic
          • allcaps.good
          • allcaps.sug
          • allcaps.test
          • allcaps.wrong
          • allcaps_utf.aff
          • allcaps_utf.dic
          • allcaps_utf.good
          • allcaps_utf.sug
          • allcaps_utf.test
          • allcaps_utf.wrong
          • allcaps2.aff
          • allcaps2.dic
          • allcaps2.good
          • allcaps2.sug
          • allcaps2.test
          • allcaps2.wrong
          • allcaps3.aff
          • allcaps3.dic
          • allcaps3.good
          • allcaps3.test
          • allcaps3.wrong
          • base.aff
          • base.dic
          • base.good
          • base.sug
          • base.test
          • base.wrong
          • base_utf.aff
          • base_utf.dic
          • base_utf.good
          • base_utf.sug
          • base_utf.test
          • base_utf.wrong
          • break.aff
          • break.dic
          • break.good
          • break.test
          • break.wrong
          • breakdefault.aff
          • breakdefault.dic
          • breakdefault.good
          • breakdefault.sug
          • breakdefault.test
          • breakdefault.wrong
          • checkcompoundcase.aff
          • checkcompoundcase.dic
          • checkcompoundcase.good
          • checkcompoundcase.test
          • checkcompoundcase.wrong
          • checkcompoundcase2.aff
          • checkcompoundcase2.dic
          • checkcompoundcase2.good
          • checkcompoundcase2.test
          • checkcompoundcase2.wrong
          • checkcompoundcaseutf.aff
          • checkcompoundcaseutf.dic
          • checkcompoundcaseutf.good
          • checkcompoundcaseutf.test
          • checkcompoundcaseutf.wrong
          • checkcompounddup.aff
          • checkcompounddup.dic
          • checkcompounddup.good
          • checkcompounddup.test
          • checkcompounddup.wrong
          • checkcompoundpattern.aff
          • checkcompoundpattern.dic
          • checkcompoundpattern.good
          • checkcompoundpattern.test
          • checkcompoundpattern.wrong
          • checkcompoundpattern2.aff
          • checkcompoundpattern2.dic
          • checkcompoundpattern2.good
          • checkcompoundpattern2.test
          • checkcompoundpattern2.wrong
          • checkcompoundpattern3.aff
          • checkcompoundpattern3.dic
          • checkcompoundpattern3.good
          • checkcompoundpattern3.test
          • checkcompoundpattern3.wrong
          • checkcompoundpattern4.aff
          • checkcompoundpattern4.dic
          • checkcompoundpattern4.good
          • checkcompoundpattern4.test
          • checkcompoundpattern4.wrong
          • checkcompoundrep.aff
          • checkcompoundrep.dic
          • checkcompoundrep.good
          • checkcompoundrep.test
          • checkcompoundrep.wrong
          • checkcompoundtriple.aff
          • checkcompoundtriple.dic
          • checkcompoundtriple.good
          • checkcompoundtriple.test
          • checkcompoundtriple.wrong
          • checksharps.aff
          • checksharps.dic
          • checksharps.good
          • checksharps.sug
          • checksharps.test
          • checksharps.wrong
          • checksharpsutf.aff
          • checksharpsutf.dic
          • checksharpsutf.good
          • checksharpsutf.sug
          • checksharpsutf.test
          • checksharpsutf.wrong
          • circumfix.aff
          • circumfix.dic
          • circumfix.good
          • circumfix.morph
          • circumfix.test
          • circumfix.wrong
          • colons_in_words.aff
          • colons_in_words.dic
          • colons_in_words.test
          • complexprefixes.aff
          • complexprefixes.dic
          • complexprefixes.good
          • complexprefixes.test
          • complexprefixes.wrong
          • complexprefixes2.aff
          • complexprefixes2.dic
          • complexprefixes2.good
          • complexprefixes2.test
          • complexprefixesutf.aff
          • complexprefixesutf.dic
          • complexprefixesutf.good
          • complexprefixesutf.test
          • complexprefixesutf.wrong
          • compoundaffix.aff
          • compoundaffix.dic
          • compoundaffix.good
          • compoundaffix.test
          • compoundaffix.wrong
          • compoundaffix2.aff
          • compoundaffix2.dic
          • compoundaffix2.good
          • compoundaffix2.test
          • compoundaffix3.aff
          • compoundaffix3.dic
          • compoundaffix3.good
          • compoundaffix3.test
          • compoundaffix3.wrong
          • compoundflag.aff
          • compoundflag.dic
          • compoundflag.good
          • compoundflag.test
          • compoundflag.wrong
          • compoundrule.aff
          • compoundrule.dic
          • compoundrule.good
          • compoundrule.test
          • compoundrule.wrong
          • compoundrule2.aff
          • compoundrule2.dic
          • compoundrule2.good
          • compoundrule2.test
          • compoundrule2.wrong
          • compoundrule3.aff
          • compoundrule3.dic
          • compoundrule3.good
          • compoundrule3.test
          • compoundrule3.wrong
          • compoundrule4.aff
          • compoundrule4.dic
          • compoundrule4.good
          • compoundrule4.test
          • compoundrule4.wrong
          • compoundrule5.aff
          • compoundrule5.dic
          • compoundrule5.good
          • compoundrule5.morph
          • compoundrule5.test
          • compoundrule5.wrong
          • compoundrule6.aff
          • compoundrule6.dic
          • compoundrule6.good
          • compoundrule6.test
          • compoundrule6.wrong
          • compoundrule7.aff
          • compoundrule7.dic
          • compoundrule7.good
          • compoundrule7.test
          • compoundrule7.wrong
          • compoundrule8.aff
          • compoundrule8.dic
          • compoundrule8.good
          • compoundrule8.test
          • compoundrule8.wrong
          • condition.aff
          • condition.dic
          • condition.good
          • condition.test
          • condition.wrong
          • condition_utf.aff
          • condition_utf.dic
          • condition_utf.good
          • condition_utf.test
          • condition_utf.wrong
          • conditionalprefix.aff
          • conditionalprefix.dic
          • conditionalprefix.good
          • conditionalprefix.morph
          • conditionalprefix.test
          • conditionalprefix.wrong
          • digits_in_words.aff
          • digits_in_words.dic
          • digits_in_words.test
          • digits_in_words.wrong
          • flag.aff
          • flag.dic
          • flag.good
          • flag.test
          • flaglong.aff
          • flaglong.dic
          • flaglong.good
          • flaglong.test
          • flagnum.aff
          • flagnum.dic
          • flagnum.good
          • flagnum.test
          • flagutf8.aff
          • flagutf8.dic
          • flagutf8.good
          • flagutf8.test
          • fogemorpheme.aff
          • fogemorpheme.dic
          • fogemorpheme.good
          • fogemorpheme.test
          • fogemorpheme.wrong
          • forbiddenword.aff
          • forbiddenword.dic
          • forbiddenword.good
          • forbiddenword.test
          • forbiddenword.wrong
          • fullstrip.aff
          • fullstrip.dic
          • fullstrip.good
          • fullstrip.test
          • germancompounding.aff
          • germancompounding.dic
          • germancompounding.good
          • germancompounding.test
          • germancompounding.wrong
          • germancompoundingold.aff
          • germancompoundingold.dic
          • germancompoundingold.good
          • germancompoundingold.test
          • germancompoundingold.wrong
          • i35725.aff
          • i35725.dic
          • i35725.good
          • i35725.sug
          • i35725.test
          • i35725.wrong
          • i53643.aff
          • i53643.dic
          • i53643.good
          • i53643.test
          • i53643.wrong
          • i54633.aff
          • i54633.dic
          • i54633.good
          • i54633.sug
          • i54633.test
          • i54633.wrong
          • i54980.aff
          • i54980.dic
          • i54980.good
          • i54980.test
          • i58202.aff
          • i58202.dic
          • i58202.good
          • i58202.sug
          • i58202.test
          • i58202.wrong
          • i68568.aff
          • i68568.dic
          • i68568.test
          • i68568.wrong
          • i68568utf.aff
          • i68568utf.dic
          • i68568utf.test
          • i68568utf.wrong
          • iconv.aff
          • iconv.dic
          • iconv.good
          • iconv.test
          • ignore.aff
          • ignore.dic
          • ignore.good
          • ignore.test
          • ignoreutf.aff
          • ignoreutf.dic
          • ignoreutf.good
          • ignoreutf.test
          • IJ.aff
          • IJ.dic
          • IJ.good
          • IJ.sug
          • IJ.test
          • IJ.wrong
          • keepcase.aff
          • keepcase.dic
          • keepcase.good
          • keepcase.sug
          • keepcase.test
          • keepcase.wrong
          • Makefile.am
          • Makefile.in
          • map.aff
          • map.dic
          • map.sug
          • map.test
          • map.wrong
          • maputf.aff
          • maputf.dic
          • maputf.sug
          • maputf.test
          • maputf.wrong
          • morph.aff
          • morph.dic
          • morph.good
          • morph.morph
          • morph.test
          • needaffix.aff
          • needaffix.dic
          • needaffix.good
          • needaffix.test
          • needaffix.wrong
          • needaffix2.aff
          • needaffix2.dic
          • needaffix2.good
          • needaffix2.morph
          • needaffix2.test
          • needaffix3.aff
          • needaffix3.dic
          • needaffix3.good
          • needaffix3.test
          • needaffix3.wrong
          • needaffix4.aff
          • needaffix4.dic
          • needaffix4.good
          • needaffix4.test
          • needaffix5.aff
          • needaffix5.dic
          • needaffix5.good
          • needaffix5.test
          • needaffix5.wrong
          • ngram_utf_fix.aff
          • ngram_utf_fix.dic
          • ngram_utf_fix.good
          • ngram_utf_fix.sug
          • ngram_utf_fix.test
          • ngram_utf_fix.wrong
          • nosuggest.aff
          • nosuggest.dic
          • nosuggest.good
          • nosuggest.sug
          • nosuggest.test
          • nosuggest.wrong
          • oconv.aff
          • oconv.dic
          • oconv.good
          • oconv.sug
          • oconv.test
          • oconv.wrong
          • onlyincompound.aff
          • onlyincompound.dic
          • onlyincompound.good
          • onlyincompound.sug
          • onlyincompound.test
          • onlyincompound.wrong
          • phone.aff
          • phone.dic
          • phone.sug
          • phone.test
          • phone.wrong
          • rep.aff
          • rep.dic
          • rep.sug
          • rep.test
          • rep.wrong
          • reputf.aff
          • reputf.dic
          • reputf.sug
          • reputf.test
          • reputf.wrong
          • simplifiedtriple.aff
          • simplifiedtriple.dic
          • simplifiedtriple.good
          • simplifiedtriple.test
          • simplifiedtriple.wrong
          • slash.aff
          • slash.dic
          • slash.good
          • slash.test
          • sug.aff
          • sug.dic
          • sug.sug
          • sug.test
          • sug.wrong
          • suggestiontest
          • sugutf.aff
          • sugutf.dic
          • sugutf.sug
          • sugutf.test
          • sugutf.wrong
          • test.sh
          • utf8.aff
          • utf8.dic
          • utf8.good
          • utf8.test
          • utf8_bom.aff
          • utf8_bom.dic
          • utf8_bom.good
          • utf8_bom.test
          • utf8_bom2.aff
          • utf8_bom2.dic
          • utf8_bom2.good
          • utf8_bom2.test
          • utf8_nonbmp.aff
          • utf8_nonbmp.dic
          • utf8_nonbmp.good
          • utf8_nonbmp.test
          • utf8_nonbmp.wrong
          • utfcompound.aff
          • utfcompound.dic
          • utfcompound.good
          • utfcompound.test
          • utfcompound.wrong
          • zeroaffix.aff
          • zeroaffix.dic
          • zeroaffix.good
          • zeroaffix.morph
          • zeroaffix.test
        • THANKS
        • TODO
      • wtlspell.sln
      • wtlspell
// $Id$
//
// Copyright � 2009 Phil Cairns
// This code is published under the Code Project Open Licence. See
// http://www.codeproject.com/info/cpol10.aspx for licence details.
//

#include "stdafx.h"
#include "SpellCheck.h"

SpellCheck::SpellCheck(void) : _ready(false), _psc(0)
{
	InitializeCriticalSection(&csProt);
}

SpellCheck::~SpellCheck(void)
{
	// Make sure that we're not in the middle of loading
	// or using the spell checker at this point
	EnterCriticalSection(&csProt);
	_ready = false;
	delete _psc;
	_psc = 0;
	LeaveCriticalSection(&csProt);

	// Now close down the critical sections
	DeleteCriticalSection(&csProt);
}

void SpellCheck::loadThread(void* pv)
{
	// Call the load method
	SpellCheck* pThis = (SpellCheck*)pv;
	EnterCriticalSection(&pThis->csProt);
	try
	{
		// If we're already loaded, we need to unload
		if (pThis->_psc != 0)
		{
			delete pThis->_psc;
		}

		// This loads the main dictionary
		pThis->_psc = new Hunspell(pThis->_affPath.c_str(), pThis->_dicPath.c_str());

		// Now we load the extra words that have been added
		FILE* pf;
		if (0 == fopen_s(&pf, pThis->_extPath.c_str(), "rt"))
		{
			char word[1024];
			while (!feof(pf) && !ferror(pf) && 0 != fgets(word, sizeof(word), pf))
			{
				size_t len = strlen(word);
				if (len > 2)
				{
					if (word[len - 1] == '\n')
					{
						word[len - 1] = 0;	// get rid of the '\n'
					}
					pThis->_psc->add(word);
				}
			}
			fclose(pf);
		}

		// Indicate that we're ready to go
		pThis->_ready = true;
	}
	catch (...)
	{
		// Whatever happens, we need to be able
		// to leave the critical section
		ATLTRACE("Unhandled exception while loading dictionaries\n");
	}
	LeaveCriticalSection(&pThis->csProt);
}

void SpellCheck::loadDicts(const char* affPath, const char* dicPath, const char* extPath)
{
	EnterCriticalSection(&csProt);
	_affPath = affPath;
	_dicPath = dicPath;
	_extPath = extPath;
	LeaveCriticalSection(&csProt);
	_beginthread(loadThread, 0, this);
}

void SpellCheck::loadDicts(const std::string& affPath, const std::string& dicPath, const std::string& extPath)
{
	EnterCriticalSection(&csProt);
	_affPath = affPath;
	_dicPath = dicPath;
	_extPath = extPath;
	LeaveCriticalSection(&csProt);
	_beginthread(loadThread, 0, this);
}

bool SpellCheck::wordIsOK(const char* szWord)
{
	// Protect use of the spell checker
	EnterCriticalSection(&csProt);

	// If we're not ready, just say that it's OK
	if (!_ready)
	{
		LeaveCriticalSection(&csProt);
		return true;
	}

	bool ret = true;	// Assume innocent
	try
	{
		ret = (_psc->spell(szWord) != 0);
	}
	catch (...)
	{
		// Whatever happens, we need to be able
		// to leave the critical section
	}
	LeaveCriticalSection(&csProt);
	return ret;
}

bool SpellCheck::wordIsOK(const std::string& sWord)
{
	return wordIsOK(sWord.c_str());
}

void SpellCheck::suggest(const char* szWord, STRINGLIST& opts)
{
	opts.clear();

	// Protect use of the spell checker
	EnterCriticalSection(&csProt);

	// If we're not ready, just bug out with no options
	if (!_ready)
	{
		LeaveCriticalSection(&csProt);
		return;
	}

	// Try to find the suggestions
	try
	{
		char** wordList;
		int wordCount = _psc->suggest(&wordList, szWord);
		for (int i = 0; i < wordCount; i++)
		{
			opts.push_back(wordList[i]);
		}
		_psc->free_list(&wordList, wordCount);
	}
	catch (...)
	{
		// Whatever happens, we need to be able
		// to leave the critical section
	}
	LeaveCriticalSection(&csProt);
}

void SpellCheck::suggest(const std::string& sWord, STRINGLIST& opts)
{
	suggest(sWord.c_str(), opts);
}

void SpellCheck::addWord(const char* szWord)
{
	// Protect use of the spell checker
	EnterCriticalSection(&csProt);

	// If we're not ready, just bug out with no options
	if (!_ready)
	{
		LeaveCriticalSection(&csProt);
		return;
	}

	// Try to add the word to the current dictionary
	try
	{
		_psc->add(szWord);

		// Add the word to the permanent custom dictionary.
		FILE* pf;
		if (0 == fopen_s(&pf, _extPath.c_str(), "at"))
		{
			fputs(szWord, pf);
			fputc('\n', pf);
			fclose(pf);
		}
	}
	catch (...)
	{
		// Whatever happens, we need to be able
		// to leave the critical section
	}
	LeaveCriticalSection(&csProt);
}

void SpellCheck::addWord(const std::string& sWord)
{
	addWord(sWord.c_str());
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions