/* * ======================================================================== * FILE: MSWIN_ASPELL.C * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * ======================================================================== */ #include #include "mswin_aspell.h" /* * Aspell typedefs */ typedef struct AspellConfig AspellConfig; typedef struct AspellSpeller AspellSpeller; typedef struct AspellCanHaveError AspellCanHaveError; typedef struct AspellStringEnumeration AspellStringEnumeration; typedef struct AspellWordList AspellWordList; typedef struct AspellError AspellError; /* * Aspell function prototypes */ typedef AspellCanHaveError * (__cdecl NEW_ASPELL_SPELLER)(AspellConfig * config); typedef AspellConfig * (__cdecl NEW_ASPELL_CONFIG)(); typedef AspellSpeller * (__cdecl TO_ASPELL_SPELLER)(AspellCanHaveError * obj); typedef int (__cdecl ASPELL_CONFIG_REPLACE)(AspellConfig * ths, const char * key, const char * value); typedef void (__cdecl DELETE_ASPELL_CONFIG)(AspellConfig * ths); typedef const char * (__cdecl ASPELL_CONFIG_RETRIEVE)(AspellConfig * ths, const char * key); typedef int (__cdecl ASPELL_SPELLER_ADD_TO_PERSONAL)(AspellSpeller * ths, const char * word, int word_size); typedef int (__cdecl ASPELL_SPELLER_ADD_TO_SESSION)(AspellSpeller * ths, const char * word, int word_size); typedef int (__cdecl ASPELL_SPELLER_CHECK)(AspellSpeller * ths, const char * word, int word_size); typedef const AspellWordList * (__cdecl ASPELL_SPELLER_SUGGEST)(AspellSpeller * ths, const char * word, int word_size); typedef int (__cdecl ASPELL_SPELLER_SAVE_ALL_WORD_LISTS)(AspellSpeller * ths); typedef int (__cdecl ASPELL_SPELLER_STORE_REPLACEMENT)(AspellSpeller * ths, const char * mis, int mis_size, const char * cor, int cor_size); typedef const char * (__cdecl ASPELL_STRING_ENUMERATION_NEXT)(AspellStringEnumeration * ths); typedef AspellStringEnumeration *(__cdecl ASPELL_WORD_LIST_ELEMENTS)(const AspellWordList * ths); typedef void (__cdecl DELETE_ASPELL_SPELLER)(AspellSpeller * ths); typedef void (__cdecl DELETE_ASPELL_STRING_ENUMERATION)(AspellStringEnumeration * ths); typedef void (__cdecl DELETE_ASPELL_CAN_HAVE_ERROR)(AspellCanHaveError * ths); typedef const char * (__cdecl ASPELL_ERROR_MESSAGE)(const AspellCanHaveError * ths); typedef unsigned int (__cdecl ASPELL_ERROR_NUMBER)(const AspellCanHaveError * ths); typedef const AspellError * (__cdecl ASPELL_SPELLER_ERROR)(const AspellSpeller * ths); typedef const char * (__cdecl ASPELL_SPELLER_ERROR_MESSAGE)(const struct AspellSpeller * ths); typedef AspellConfig * (__cdecl ASPELL_SPELLER_CONFIG)(AspellSpeller * ths); /* * MsWin speller information structure */ typedef struct ASPELLINFO { AspellSpeller *speller; AspellStringEnumeration *suggestion_elements; const char *error_message; AspellCanHaveError *err; HMODULE mod_aspell; NEW_ASPELL_SPELLER *new_aspell_speller; NEW_ASPELL_CONFIG *new_aspell_config; TO_ASPELL_SPELLER *to_aspell_speller; ASPELL_CONFIG_REPLACE *aspell_config_replace; DELETE_ASPELL_CONFIG *delete_aspell_config; ASPELL_CONFIG_RETRIEVE *aspell_config_retrieve; ASPELL_SPELLER_ADD_TO_PERSONAL *aspell_speller_add_to_personal; ASPELL_SPELLER_ADD_TO_SESSION *aspell_speller_add_to_session; ASPELL_SPELLER_CHECK *aspell_speller_check; ASPELL_SPELLER_SUGGEST *aspell_speller_suggest; ASPELL_SPELLER_SAVE_ALL_WORD_LISTS *aspell_speller_save_all_word_lists; ASPELL_SPELLER_STORE_REPLACEMENT *aspell_speller_store_replacement; ASPELL_STRING_ENUMERATION_NEXT *aspell_string_enumeration_next; ASPELL_WORD_LIST_ELEMENTS *aspell_word_list_elements; DELETE_ASPELL_SPELLER *delete_aspell_speller; DELETE_ASPELL_STRING_ENUMERATION *delete_aspell_string_enumeration; DELETE_ASPELL_CAN_HAVE_ERROR *delete_aspell_can_have_error; ASPELL_ERROR_MESSAGE *aspell_error_message; ASPELL_ERROR_NUMBER *aspell_error_number; ASPELL_SPELLER_ERROR *aspell_speller_error; ASPELL_SPELLER_ERROR_MESSAGE *aspell_speller_error_message; ASPELL_SPELLER_CONFIG *aspell_speller_config; } ASPELLINFO; /* * Find, aspell-15.dll, load it, and attempt to initialize our func pointers. * 1:success, 0:failed */ static int speller_load_aspell_library(ASPELLINFO *aspellinfo) { HKEY hKey; int success = 1; HMODULE mod_aspell = NULL; TCHAR aspell_fullname[MAX_PATH + 1]; static const TCHAR aspell_name[] = TEXT("aspell-15.dll"); aspell_fullname[0] = '\0'; // Try to open the Aspell Registry key. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Aspell"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD dtype; TCHAR aspell_path[MAX_PATH + 1]; DWORD aspell_path_len = sizeof(aspell_path); // Query the path. if(RegQueryValueEx(hKey, TEXT("Path"), NULL, &dtype, (LPBYTE)aspell_path, &aspell_path_len) == ERROR_SUCCESS) { _sntprintf(aspell_fullname, ARRAYSIZE(aspell_fullname), TEXT("%s\\%s"), aspell_path, aspell_name); aspell_fullname[ARRAYSIZE(aspell_fullname) - 1] = 0; } RegCloseKey(hKey); } // If the registry thing didn't work, then just try doing a Loadlibrary // using the standard Windows LoadLibrary search gunk. if(!aspell_fullname[0]) { _tcsncpy(aspell_fullname, aspell_name, ARRAYSIZE(aspell_fullname)); aspell_fullname[ARRAYSIZE(aspell_fullname) - 1] = 0; } // Load the library. mod_aspell = LoadLibrary(aspell_fullname); if(!mod_aspell) { // Failed. success = 0; } else { // Found the library - now try to initialize our function pointers. // #define GET_ASPELL_PROC_ADDR(_functype, _func) \ aspellinfo->_func = (_functype *)GetProcAddress(mod_aspell, #_func); \ if(!aspellinfo->_func) \ success = 0 GET_ASPELL_PROC_ADDR(NEW_ASPELL_SPELLER, new_aspell_speller); GET_ASPELL_PROC_ADDR(NEW_ASPELL_CONFIG, new_aspell_config); GET_ASPELL_PROC_ADDR(TO_ASPELL_SPELLER, to_aspell_speller); GET_ASPELL_PROC_ADDR(ASPELL_CONFIG_REPLACE, aspell_config_replace); GET_ASPELL_PROC_ADDR(DELETE_ASPELL_CONFIG, delete_aspell_config); GET_ASPELL_PROC_ADDR(ASPELL_CONFIG_RETRIEVE, aspell_config_retrieve); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_ADD_TO_PERSONAL, aspell_speller_add_to_personal); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_ADD_TO_SESSION, aspell_speller_add_to_session); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_CHECK, aspell_speller_check); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_SUGGEST, aspell_speller_suggest); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_SAVE_ALL_WORD_LISTS, aspell_speller_save_all_word_lists); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_STORE_REPLACEMENT, aspell_speller_store_replacement); GET_ASPELL_PROC_ADDR(ASPELL_STRING_ENUMERATION_NEXT, aspell_string_enumeration_next); GET_ASPELL_PROC_ADDR(ASPELL_WORD_LIST_ELEMENTS, aspell_word_list_elements); GET_ASPELL_PROC_ADDR(DELETE_ASPELL_SPELLER, delete_aspell_speller); GET_ASPELL_PROC_ADDR(DELETE_ASPELL_STRING_ENUMERATION, delete_aspell_string_enumeration); GET_ASPELL_PROC_ADDR(DELETE_ASPELL_CAN_HAVE_ERROR, delete_aspell_can_have_error); GET_ASPELL_PROC_ADDR(ASPELL_ERROR_MESSAGE, aspell_error_message); GET_ASPELL_PROC_ADDR(ASPELL_ERROR_NUMBER, aspell_error_number); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_ERROR, aspell_speller_error); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_ERROR_MESSAGE, aspell_speller_error_message); GET_ASPELL_PROC_ADDR(ASPELL_SPELLER_CONFIG, aspell_speller_config); #undef GET_ASPELL_PROC_ADDR if(!success) { FreeLibrary(mod_aspell); mod_aspell = NULL; } } aspellinfo->mod_aspell = mod_aspell; return success; } /* * Find, load, and initialize the aspell library. * NULL on failure, otherwise an ASPELLINFO pointer. */ ASPELLINFO * speller_init(char *lang) { ASPELLINFO *aspellinfo; aspellinfo = (ASPELLINFO *)malloc(sizeof(ASPELLINFO)); if(aspellinfo) { AspellConfig *config; AspellSpeller *speller; memset(aspellinfo, 0, sizeof(ASPELLINFO)); // Load the aspell library and set up our function pointers, etc. if(!speller_load_aspell_library(aspellinfo)) { speller_close(aspellinfo); return NULL; } config = aspellinfo->new_aspell_config(); if(lang) { aspellinfo->aspell_config_replace(config, "lang", lang); } aspellinfo->aspell_config_replace(config, "encoding", "utf-8"); aspellinfo->err = aspellinfo->new_aspell_speller(config); aspellinfo->delete_aspell_config(config); if(aspellinfo->aspell_error_number(aspellinfo->err)) { aspellinfo->error_message = aspellinfo->aspell_error_message(aspellinfo->err); } else { aspellinfo->speller = aspellinfo->to_aspell_speller(aspellinfo->err); aspellinfo->err = NULL; /* TODO: Log the current speller config somewhere? config = aspell_speller_config(speller); fputs("Using: ", stdout); fputs(aspell_config_retrieve(config, "lang"), stdout); fputs("-", stdout); fputs(aspell_config_retrieve(config, "jargon"), stdout); fputs("-", stdout); fputs(aspell_config_retrieve(config, "size"), stdout); fputs("-", stdout); fputs(aspell_config_retrieve(config, "module"), stdout); fputs("\n\n", stdout); */ } } return aspellinfo; } /* * Get the last aspell error message. */ const char * speller_get_error_message(ASPELLINFO *aspellinfo) { return aspellinfo ? aspellinfo->error_message : NULL; } /* * Close up shop. */ void speller_close(ASPELLINFO *aspellinfo) { if(aspellinfo) { // Make sure someone hasn't missed a speller_suggestion_close assert(!aspellinfo->suggestion_elements); if(aspellinfo->err) { aspellinfo->delete_aspell_can_have_error(aspellinfo->err); aspellinfo->err = NULL; } if(aspellinfo->speller) { aspellinfo->delete_aspell_speller(aspellinfo->speller); aspellinfo->speller = NULL; } if(aspellinfo->mod_aspell) { FreeLibrary(aspellinfo->mod_aspell); aspellinfo->mod_aspell = NULL; } free(aspellinfo); } } /* * Check the dictionary for a word. * 1:found, 0:not found, -1:error */ int speller_check_word(ASPELLINFO *aspellinfo, const char *word, int word_size) { int have = 1; if(!isdigit(*word)) { have = aspellinfo->aspell_speller_check(aspellinfo->speller, word, word_size); if(have == -1) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); } } return have; } /* * Add word to dictionary. * 1:success, 0:failed */ int speller_add_to_dictionary(ASPELLINFO *aspellinfo, const char *word, int word_size) { aspellinfo->aspell_speller_add_to_personal(aspellinfo->speller, word, word_size); if(aspellinfo->aspell_speller_error(aspellinfo->speller)) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); return 0; } aspellinfo->aspell_speller_save_all_word_lists(aspellinfo->speller); if(aspellinfo->aspell_speller_error(aspellinfo->speller)) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); return 0; } return 1; } /* * Add this word to the current spelling session. * 1:success, 0:failed */ int speller_ignore_all(ASPELLINFO *aspellinfo, const char *word, int word_size) { aspellinfo->aspell_speller_add_to_session(aspellinfo->speller, word, word_size); if(aspellinfo->aspell_speller_error(aspellinfo->speller)) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); return 0; } return 1; } /* * Replace a word. * 1:success, 0:failed */ int speller_replace_word(ASPELLINFO *aspellinfo, const char * mis, int mis_size, const char * cor, int cor_size) { int ret; ret = aspellinfo->aspell_speller_store_replacement(aspellinfo->speller, mis, mis_size, cor, cor_size); if(ret == -1) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); return 0; } return 1; } /* * Init the suggestions element array for a specific word. * 1:success, 0:failed */ int speller_suggestion_init(ASPELLINFO *aspellinfo, const char *word, int word_size) { const AspellWordList *suggestions; // Make sure someone hasn't missed a speller_suggestion_close assert(!aspellinfo->suggestion_elements); suggestions = aspellinfo->aspell_speller_suggest(aspellinfo->speller, word, word_size); if(!suggestions) { aspellinfo->error_message = aspellinfo->aspell_speller_error_message(aspellinfo->speller); return 0; } aspellinfo->suggestion_elements = aspellinfo->aspell_word_list_elements(suggestions); return 1; } /* * Find next suggestion. Returns NULL when no more are left. */ const char * speller_suggestion_getnext(ASPELLINFO *aspellinfo) { return aspellinfo->aspell_string_enumeration_next( aspellinfo->suggestion_elements); } /* * Close the suggestion element array. */ void speller_suggestion_close(ASPELLINFO *aspellinfo) { aspellinfo->delete_aspell_string_enumeration(aspellinfo->suggestion_elements); aspellinfo->suggestion_elements = NULL; }