blob: 5dd1f6a99687a6d7fa76217334108d5e88b1a3fc [file] [log] [blame]
// This program checks spelling and suggests corrections for misspelled words.
//
// This example illustrates the use of the sandboxed_hunspell library with an
// affix file (definitions for the dictionary) and a dictionary file to check
// the contents of the WORDS_TO_CHECK file.
#include <unistd.h>
#include <cstdlib>
#include <string>
#include "base/init_google.h"
#include "file/base/filelineiter.h"
#include "third_party/absl/flags/flag.h"
#include "third_party/absl/log/flags.h"
#include "third_party/absl/log/log.h"
#include "third_party/absl/status/status.h"
#include "third_party/absl/status/statusor.h"
#include "third_party/hunspell/sandbox/sandbox.h"
#include "third_party/hunspell/sandbox/sandboxed_hunspell.sapi.h"
#include "third_party/sandboxed_api/util/status_macros.h"
#include "third_party/sandboxed_api/var_array.h"
#include "third_party/sandboxed_api/var_int.h"
#include "third_party/sandboxed_api/var_ptr.h"
ABSL_FLAG(std::string, affix_file, "", "File path to affix file.");
ABSL_FLAG(std::string, dict_file, "", "File path to dictionarie file.");
ABSL_FLAG(std::string, in_file, "", "File path to file to check.");
absl::Status PrintSuggest(sandboxed_hunspell::LibHunspellApi& api,
sapi::v::RemotePtr& hunspellrp,
sapi::v::ConstCStr& word) {
sapi::v::GenericPtr outptr;
SAPI_ASSIGN_OR_RETURN(
int nlist,
api.Hunspell_suggest(&hunspellrp, outptr.PtrAfter(), word.PtrBefore()));
if (nlist == 0) {
LOG(INFO) << "No suggestions.";
return absl::OkStatus();
}
sapi::v::Array<char*> suggestion_listp(nlist);
suggestion_listp.SetRemote(reinterpret_cast<void*>(outptr.GetValue()));
SAPI_RETURN_IF_ERROR(
api.GetSandbox()->TransferFromSandboxee(&suggestion_listp));
LOG(INFO) << "Suggestions:";
for (int i = 0; i < nlist; ++i) {
sapi::v::RemotePtr sugrp(suggestion_listp[i]);
SAPI_ASSIGN_OR_RETURN(std::string sugestion,
api.GetSandbox()->GetCString(sugrp));
LOG(INFO) << sugestion;
}
return api.Hunspell_free_list(&hunspellrp, outptr.PtrNone(), nlist);
}
int main(int argc, char* argv[]) {
InitGoogle(argv[0], &argc, &argv, /*remove_flags=*/true);
// Always log to stderr
absl::SetFlag(&FLAGS_logtostderr, true);
if (absl::GetFlag(FLAGS_affix_file).empty() ||
absl::GetFlag(FLAGS_dict_file).empty()) {
LOG(ERROR) << "--" << absl::GetFlagReflectionHandle(FLAGS_affix_file).Name()
<< ", --"
<< absl::GetFlagReflectionHandle(FLAGS_dict_file).Name()
<< ", and --"
<< absl::GetFlagReflectionHandle(FLAGS_in_file).Name()
<< " are required";
return EXIT_FAILURE;
}
std::string affix_file = absl::GetFlag(FLAGS_affix_file);
std::string dict_file = absl::GetFlag(FLAGS_dict_file);
sandboxed_hunspell::LibHunspellSapiSandbox sandbox(affix_file, dict_file);
if (!sandbox.Init().ok()) {
LOG(ERROR) << "Unable to start sandbox";
return EXIT_FAILURE;
}
sapi::v::ConstCStr c_affix_file(affix_file.c_str());
sapi::v::ConstCStr c_dictionary_file(dict_file.c_str());
sandboxed_hunspell::LibHunspellApi api(&sandbox);
absl::StatusOr<sandboxed_hunspell::Hunhandle*> hunspell = api.Hunspell_create(
c_affix_file.PtrBefore(), c_dictionary_file.PtrBefore());
if (!hunspell.ok()) {
LOG(ERROR) << "Could not initialize hunsepll";
return EXIT_FAILURE;
}
sapi::v::RemotePtr hunspellrp(*hunspell);
for (std::string& buf :
FileLines(absl::GetFlag(FLAGS_in_file), FileLineIterator::NO_LF)) {
sapi::v::ConstCStr cbuf(buf.c_str());
absl::StatusOr<int> result =
api.Hunspell_spell(&hunspellrp, cbuf.PtrBefore());
if (!result.ok()) {
LOG(ERROR) << "Could not check word" << result.status();
return EXIT_FAILURE;
}
if (*result) {
LOG(INFO) << "Word " << buf << " is ok";
continue;
}
LOG(INFO) << "Word " << buf << " is incorrect";
absl::Status status = PrintSuggest(api, hunspellrp, cbuf);
if (!status.ok()) {
LOG(ERROR) << "Unable to get all suggestion" << status;
return EXIT_FAILURE;
}
}
if (!api.Hunspell_destroy(&hunspellrp).ok()) {
LOG(ERROR) << "Unable to destroy hunspell";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}