mirror of
https://github.com/Dushistov/sdcv.git
synced 2025-12-16 09:51:56 +00:00
Add option --json-output (-j)
If given -j, format the output of -l and of searches as JSON.
This commit is contained in:
@@ -22,6 +22,7 @@ matrix:
|
|||||||
- g++-4.8
|
- g++-4.8
|
||||||
- cmake
|
- cmake
|
||||||
- libglib2.0-dev
|
- libglib2.0-dev
|
||||||
|
- jq
|
||||||
# - env: COMPILER_VERSION=3.5
|
# - env: COMPILER_VERSION=3.5
|
||||||
# os: linux
|
# os: linux
|
||||||
# compiler: clang++
|
# compiler: clang++
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ if (BUILD_TESTS)
|
|||||||
add_sdcv_shell_test(t_use)
|
add_sdcv_shell_test(t_use)
|
||||||
add_sdcv_shell_test(t_only_data_dir)
|
add_sdcv_shell_test(t_only_data_dir)
|
||||||
add_sdcv_shell_test(t_synonyms)
|
add_sdcv_shell_test(t_synonyms)
|
||||||
|
add_sdcv_shell_test(t_json)
|
||||||
add_sdcv_shell_test(t_interactive)
|
add_sdcv_shell_test(t_interactive)
|
||||||
add_sdcv_shell_test(t_utf8output)
|
add_sdcv_shell_test(t_utf8output)
|
||||||
add_sdcv_shell_test(t_utf8input)
|
add_sdcv_shell_test(t_utf8input)
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ void Library::LookupData(const std::string &str, TSearchResultList& res_list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Library::print_search_result(FILE *out, const TSearchResult & res)
|
void Library::print_search_result(FILE *out, const TSearchResult & res, bool &first_result)
|
||||||
{
|
{
|
||||||
std::string loc_bookname, loc_def, loc_exp;
|
std::string loc_bookname, loc_def, loc_exp;
|
||||||
|
|
||||||
@@ -257,7 +257,18 @@ void Library::print_search_result(FILE *out, const TSearchResult & res)
|
|||||||
loc_def = utf8_to_locale_ign_err(res.def);
|
loc_def = utf8_to_locale_ign_err(res.def);
|
||||||
loc_exp = utf8_to_locale_ign_err(res.exp);
|
loc_exp = utf8_to_locale_ign_err(res.exp);
|
||||||
}
|
}
|
||||||
|
if(json_) {
|
||||||
|
if(!first_result) {
|
||||||
|
fputs(",", out);
|
||||||
|
} else {
|
||||||
|
first_result=false;
|
||||||
|
}
|
||||||
|
fprintf(out,"{\"dict\": \"%s\",\"word\":\"%s\",\"definition\":\"%s\"}",
|
||||||
|
json_escape_string(res.bookname).c_str(),
|
||||||
|
json_escape_string(res.def).c_str(),
|
||||||
|
json_escape_string(res.exp).c_str());
|
||||||
|
|
||||||
|
} else {
|
||||||
fprintf(out,
|
fprintf(out,
|
||||||
"-->%s%s%s\n"
|
"-->%s%s%s\n"
|
||||||
"-->%s%s%s\n"
|
"-->%s%s%s\n"
|
||||||
@@ -269,6 +280,7 @@ void Library::print_search_result(FILE *out, const TSearchResult & res)
|
|||||||
utf8_output_ ? res.def.c_str() : loc_def.c_str(),
|
utf8_output_ ? res.def.c_str() : loc_def.c_str(),
|
||||||
colorize_output_ ? ESC_END : "",
|
colorize_output_ ? ESC_END : "",
|
||||||
utf8_output_ ? res.exp.c_str() : loc_exp.c_str());
|
utf8_output_ ? res.exp.c_str() : loc_exp.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -346,6 +358,11 @@ bool Library::process_phrase(const char *loc_str, IReadLine &io, bool force)
|
|||||||
/*nothing*/;
|
/*nothing*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdcv_pager pager(force);
|
||||||
|
bool first_result = true;
|
||||||
|
if(json_) {
|
||||||
|
fputc('[', pager.get_stream());
|
||||||
|
}
|
||||||
if (!res_list.empty()) {
|
if (!res_list.empty()) {
|
||||||
/* try to be more clever, if there are
|
/* try to be more clever, if there are
|
||||||
one or zero results per dictionary show all
|
one or zero results per dictionary show all
|
||||||
@@ -370,6 +387,7 @@ bool Library::process_phrase(const char *loc_str, IReadLine &io, bool force)
|
|||||||
}//if (!force)
|
}//if (!force)
|
||||||
|
|
||||||
if (!show_all_results && !force) {
|
if (!show_all_results && !force) {
|
||||||
|
if(!json_)
|
||||||
printf(_("Found %zu items, similar to %s.\n"), res_list.size(),
|
printf(_("Found %zu items, similar to %s.\n"), res_list.size(),
|
||||||
utf8_output_ ? get_impl(str) : utf8_to_locale_ign_err(get_impl(str)).c_str());
|
utf8_output_ ? get_impl(str) : utf8_to_locale_ign_err(get_impl(str)).c_str());
|
||||||
for (size_t i = 0; i < res_list.size(); ++i) {
|
for (size_t i = 0; i < res_list.size(); ++i) {
|
||||||
@@ -390,9 +408,8 @@ bool Library::process_phrase(const char *loc_str, IReadLine &io, bool force)
|
|||||||
choice_readline->read(_("Your choice[-1 to abort]: "), str_choise);
|
choice_readline->read(_("Your choice[-1 to abort]: "), str_choise);
|
||||||
sscanf(str_choise.c_str(), "%d", &choise);
|
sscanf(str_choise.c_str(), "%d", &choise);
|
||||||
if (choise >= 0 && choise < int(res_list.size())) {
|
if (choise >= 0 && choise < int(res_list.size())) {
|
||||||
sdcv_pager pager;
|
|
||||||
io.add_to_history(res_list[choise].def.c_str());
|
io.add_to_history(res_list[choise].def.c_str());
|
||||||
print_search_result(pager.get_stream(), res_list[choise]);
|
print_search_result(pager.get_stream(), res_list[choise], first_result);
|
||||||
break;
|
break;
|
||||||
} else if (choise == -1){
|
} else if (choise == -1){
|
||||||
break;
|
break;
|
||||||
@@ -401,20 +418,24 @@ bool Library::process_phrase(const char *loc_str, IReadLine &io, bool force)
|
|||||||
res_list.size()-1);
|
res_list.size()-1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sdcv_pager pager(force);
|
for (const TSearchResult& search_res : res_list) {
|
||||||
|
if(!json_)
|
||||||
fprintf(pager.get_stream(), _("Found %zu items, similar to %s.\n"),
|
fprintf(pager.get_stream(), _("Found %zu items, similar to %s.\n"),
|
||||||
res_list.size(), utf8_output_ ? get_impl(str) : utf8_to_locale_ign_err(get_impl(str)).c_str());
|
res_list.size(), utf8_output_ ? get_impl(str) : utf8_to_locale_ign_err(get_impl(str)).c_str());
|
||||||
for (const TSearchResult& search_res : res_list)
|
print_search_result(pager.get_stream(), search_res, first_result);
|
||||||
print_search_result(pager.get_stream(), search_res);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::string loc_str;
|
std::string loc_str;
|
||||||
if (!utf8_output_)
|
if (!utf8_output_)
|
||||||
loc_str = utf8_to_locale_ign_err(get_impl(str));
|
loc_str = utf8_to_locale_ign_err(get_impl(str));
|
||||||
|
if(!json_)
|
||||||
printf(_("Nothing similar to %s, sorry :(\n"), utf8_output_ ? get_impl(str) : loc_str.c_str());
|
printf(_("Nothing similar to %s, sorry :(\n"), utf8_output_ ? get_impl(str) : loc_str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(json_) {
|
||||||
|
fputs("]\n", pager.get_stream());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,19 +25,22 @@ typedef std::vector<TSearchResult> TSearchResultList;
|
|||||||
//of it
|
//of it
|
||||||
class Library : public Libs {
|
class Library : public Libs {
|
||||||
public:
|
public:
|
||||||
Library(bool uinput, bool uoutput, bool colorize_output):
|
Library(bool uinput, bool uoutput, bool colorize_output, bool use_json)
|
||||||
utf8_input_(uinput), utf8_output_(uoutput), colorize_output_(colorize_output) {}
|
: utf8_input_(uinput), utf8_output_(uoutput), colorize_output_(colorize_output), json_(use_json) {
|
||||||
|
setVerbose(!use_json);
|
||||||
|
}
|
||||||
|
|
||||||
bool process_phrase(const char *loc_str, IReadLine &io, bool force = false);
|
bool process_phrase(const char *loc_str, IReadLine &io, bool force = false);
|
||||||
private:
|
private:
|
||||||
bool utf8_input_;
|
bool utf8_input_;
|
||||||
bool utf8_output_;
|
bool utf8_output_;
|
||||||
bool colorize_output_;
|
bool colorize_output_;
|
||||||
|
bool json_;
|
||||||
|
|
||||||
void SimpleLookup(const std::string &str, TSearchResultList& res_list);
|
void SimpleLookup(const std::string &str, TSearchResultList& res_list);
|
||||||
void LookupWithFuzzy(const std::string &str, TSearchResultList& res_list);
|
void LookupWithFuzzy(const std::string &str, TSearchResultList& res_list);
|
||||||
void LookupWithRule(const std::string &str, TSearchResultList& res_lsit);
|
void LookupWithRule(const std::string &str, TSearchResultList& res_lsit);
|
||||||
void LookupData(const std::string &str, TSearchResultList& res_list);
|
void LookupData(const std::string &str, TSearchResultList& res_list);
|
||||||
void print_search_result(FILE *out, const TSearchResult & res);
|
void print_search_result(FILE *out, const TSearchResult & res, bool &first_result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
28
src/sdcv.cpp
28
src/sdcv.cpp
@@ -59,7 +59,7 @@ namespace glib
|
|||||||
using StrArr = ResourceWrapper<gchar *, gchar *, free_str_array>;
|
using StrArr = ResourceWrapper<gchar *, gchar *, free_str_array>;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_dicts(const std::list<std::string> &dicts_dir_list);
|
static void list_dicts(const std::list<std::string> &dicts_dir_list, bool use_json);
|
||||||
|
|
||||||
int main(int argc, char *argv[]) try {
|
int main(int argc, char *argv[]) try {
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
@@ -75,6 +75,7 @@ int main(int argc, char *argv[]) try {
|
|||||||
gboolean show_list_dicts = FALSE;
|
gboolean show_list_dicts = FALSE;
|
||||||
glib::StrArr use_dict_list;
|
glib::StrArr use_dict_list;
|
||||||
gboolean non_interactive = FALSE;
|
gboolean non_interactive = FALSE;
|
||||||
|
gboolean json_output = FALSE;
|
||||||
gboolean utf8_output = FALSE;
|
gboolean utf8_output = FALSE;
|
||||||
gboolean utf8_input = FALSE;
|
gboolean utf8_input = FALSE;
|
||||||
glib::CharStr opt_data_dir;
|
glib::CharStr opt_data_dir;
|
||||||
@@ -91,6 +92,8 @@ int main(int argc, char *argv[]) try {
|
|||||||
_("bookname") },
|
_("bookname") },
|
||||||
{ "non-interactive", 'n', 0, G_OPTION_ARG_NONE, &non_interactive,
|
{ "non-interactive", 'n', 0, G_OPTION_ARG_NONE, &non_interactive,
|
||||||
_("for use in scripts"), nullptr },
|
_("for use in scripts"), nullptr },
|
||||||
|
{ "json-output", 'j', 0, G_OPTION_ARG_NONE, &json_output,
|
||||||
|
_("print the result formatted as JSON."), nullptr },
|
||||||
{ "utf8-output", '0', 0, G_OPTION_ARG_NONE, &utf8_output,
|
{ "utf8-output", '0', 0, G_OPTION_ARG_NONE, &utf8_output,
|
||||||
_("output must be in utf8"), nullptr },
|
_("output must be in utf8"), nullptr },
|
||||||
{ "utf8-input", '1', 0, G_OPTION_ARG_NONE, &utf8_input,
|
{ "utf8-input", '1', 0, G_OPTION_ARG_NONE, &utf8_input,
|
||||||
@@ -144,7 +147,7 @@ int main(int argc, char *argv[]) try {
|
|||||||
dicts_dir_list.push_back(std::string(homedir) + G_DIR_SEPARATOR + ".stardict" + G_DIR_SEPARATOR + "dic");
|
dicts_dir_list.push_back(std::string(homedir) + G_DIR_SEPARATOR + ".stardict" + G_DIR_SEPARATOR + "dic");
|
||||||
dicts_dir_list.push_back(data_dir);
|
dicts_dir_list.push_back(data_dir);
|
||||||
if (show_list_dicts) {
|
if (show_list_dicts) {
|
||||||
list_dicts(dicts_dir_list);
|
list_dicts(dicts_dir_list, json_output);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +199,7 @@ int main(int argc, char *argv[]) try {
|
|||||||
fprintf(stderr, _("g_mkdir failed: %s\n"), strerror(errno));
|
fprintf(stderr, _("g_mkdir failed: %s\n"), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
Library lib(utf8_input, utf8_output, colorize);
|
Library lib(utf8_input, utf8_output, colorize, json_output);
|
||||||
lib.load(dicts_dir_list, order_list, disable_list);
|
lib.load(dicts_dir_list, order_list, disable_list);
|
||||||
|
|
||||||
std::unique_ptr<IReadLine> io(create_readline_object());
|
std::unique_ptr<IReadLine> io(create_readline_object());
|
||||||
@@ -224,17 +227,32 @@ int main(int argc, char *argv[]) try {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_dicts(const std::list<std::string> &dicts_dir_list)
|
static void list_dicts(const std::list<std::string> &dicts_dir_list, bool use_json)
|
||||||
{
|
{
|
||||||
|
bool first_entry = true;
|
||||||
|
if(!use_json)
|
||||||
printf(_("Dictionary's name Word count\n"));
|
printf(_("Dictionary's name Word count\n"));
|
||||||
|
else
|
||||||
|
fputc('[', stdout);
|
||||||
std::list<std::string> order_list, disable_list;
|
std::list<std::string> order_list, disable_list;
|
||||||
for_each_file(dicts_dir_list, ".ifo", order_list,
|
for_each_file(dicts_dir_list, ".ifo", order_list,
|
||||||
disable_list, [](const std::string &filename, bool) -> void {
|
disable_list, [use_json, &first_entry](const std::string &filename, bool) -> void {
|
||||||
DictInfo dict_info;
|
DictInfo dict_info;
|
||||||
if (dict_info.load_from_ifo_file(filename, false)) {
|
if (dict_info.load_from_ifo_file(filename, false)) {
|
||||||
const std::string bookname = utf8_to_locale_ign_err(dict_info.bookname);
|
const std::string bookname = utf8_to_locale_ign_err(dict_info.bookname);
|
||||||
|
if(use_json) {
|
||||||
|
if(first_entry) {
|
||||||
|
first_entry=false;
|
||||||
|
} else {
|
||||||
|
fputc(',', stdout); // comma between entries
|
||||||
|
}
|
||||||
|
printf("{\"name\": \"%s\", \"wordcount\": \"%d\"}", json_escape_string(bookname).c_str(), dict_info.wordcount);
|
||||||
|
} else {
|
||||||
printf("%s %d\n", bookname.c_str(), dict_info.wordcount);
|
printf("%s %d\n", bookname.c_str(), dict_info.wordcount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if(use_json)
|
||||||
|
fputs("]\n", stdout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,7 +439,7 @@ namespace {
|
|||||||
if (idxfile)
|
if (idxfile)
|
||||||
fclose(idxfile);
|
fclose(idxfile);
|
||||||
}
|
}
|
||||||
bool load(const std::string& url, gulong wc, gulong fsize) override;
|
bool load(const std::string& url, gulong wc, gulong fsize, bool verbose) override;
|
||||||
const gchar *get_key(glong idx) override;
|
const gchar *get_key(glong idx) override;
|
||||||
void get_data(glong idx) override { get_key(idx); }
|
void get_data(glong idx) override { get_key(idx); }
|
||||||
const gchar *get_key_and_data(glong idx) override {
|
const gchar *get_key_and_data(glong idx) override {
|
||||||
@@ -481,7 +481,7 @@ namespace {
|
|||||||
const gchar *read_first_on_page_key(glong page_idx);
|
const gchar *read_first_on_page_key(glong page_idx);
|
||||||
const gchar *get_first_on_page_key(glong page_idx);
|
const gchar *get_first_on_page_key(glong page_idx);
|
||||||
bool load_cache(const std::string& url);
|
bool load_cache(const std::string& url);
|
||||||
bool save_cache(const std::string& url);
|
bool save_cache(const std::string& url, bool verbose);
|
||||||
static std::list<std::string> get_cache_variant(const std::string& url);
|
static std::list<std::string> get_cache_variant(const std::string& url);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@ namespace {
|
|||||||
public:
|
public:
|
||||||
WordListIndex() : idxdatabuf(nullptr) {}
|
WordListIndex() : idxdatabuf(nullptr) {}
|
||||||
~WordListIndex() { g_free(idxdatabuf); }
|
~WordListIndex() { g_free(idxdatabuf); }
|
||||||
bool load(const std::string& url, gulong wc, gulong fsize) override;
|
bool load(const std::string& url, gulong wc, gulong fsize, bool verbose) override;
|
||||||
const gchar *get_key(glong idx) override { return wordlist[idx]; }
|
const gchar *get_key(glong idx) override { return wordlist[idx]; }
|
||||||
void get_data(glong idx) override;
|
void get_data(glong idx) override;
|
||||||
const gchar *get_key_and_data(glong idx) override {
|
const gchar *get_key_and_data(glong idx) override {
|
||||||
@@ -592,7 +592,7 @@ namespace {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OffsetIndex::save_cache(const std::string& url)
|
bool OffsetIndex::save_cache(const std::string& url, bool verbose)
|
||||||
{
|
{
|
||||||
const std::list<std::string> vars = get_cache_variant(url);
|
const std::list<std::string> vars = get_cache_variant(url);
|
||||||
for (const std::string& item : vars) {
|
for (const std::string& item : vars) {
|
||||||
@@ -604,13 +604,15 @@ namespace {
|
|||||||
if (fwrite(&wordoffset[0], sizeof(wordoffset[0]), wordoffset.size(), out)!=wordoffset.size())
|
if (fwrite(&wordoffset[0], sizeof(wordoffset[0]), wordoffset.size(), out)!=wordoffset.size())
|
||||||
continue;
|
continue;
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
if(verbose) {
|
||||||
printf("save to cache %s\n", url.c_str());
|
printf("save to cache %s\n", url.c_str());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OffsetIndex::load(const std::string& url, gulong wc, gulong fsize)
|
bool OffsetIndex::load(const std::string& url, gulong wc, gulong fsize, bool verbose)
|
||||||
{
|
{
|
||||||
wordcount=wc;
|
wordcount=wc;
|
||||||
gulong npages=(wc-1)/ENTR_PER_PAGE+2;
|
gulong npages=(wc-1)/ENTR_PER_PAGE+2;
|
||||||
@@ -633,7 +635,7 @@ namespace {
|
|||||||
p1 += index_size;
|
p1 += index_size;
|
||||||
}
|
}
|
||||||
wordoffset[j]=p1-idxdatabuffer;
|
wordoffset[j]=p1-idxdatabuffer;
|
||||||
if (!save_cache(url))
|
if (!save_cache(url, verbose))
|
||||||
fprintf(stderr, "cache update failed\n");
|
fprintf(stderr, "cache update failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +743,7 @@ namespace {
|
|||||||
return bFound;
|
return bFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WordListIndex::load(const std::string& url, gulong wc, gulong fsize)
|
bool WordListIndex::load(const std::string& url, gulong wc, gulong fsize, bool verbose)
|
||||||
{
|
{
|
||||||
gzFile in = gzopen(url.c_str(), "rb");
|
gzFile in = gzopen(url.c_str(), "rb");
|
||||||
if (in == nullptr)
|
if (in == nullptr)
|
||||||
@@ -856,7 +858,7 @@ bool Dict::Lookup(const char *str, glong &idx) {
|
|||||||
return idx_file->lookup(str, idx);
|
return idx_file->lookup(str, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dict::load(const std::string& ifofilename)
|
bool Dict::load(const std::string& ifofilename, bool verbose)
|
||||||
{
|
{
|
||||||
gulong idxfilesize;
|
gulong idxfilesize;
|
||||||
if (!load_ifofile(ifofilename, idxfilesize))
|
if (!load_ifofile(ifofilename, idxfilesize))
|
||||||
@@ -890,7 +892,7 @@ bool Dict::load(const std::string& ifofilename)
|
|||||||
idx_file.reset(new OffsetIndex);
|
idx_file.reset(new OffsetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!idx_file->load(fullfilename, wordcount, idxfilesize))
|
if (!idx_file->load(fullfilename, wordcount, idxfilesize, verbose))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fullfilename=ifofilename;
|
fullfilename=ifofilename;
|
||||||
@@ -944,7 +946,7 @@ Libs::~Libs()
|
|||||||
void Libs::load_dict(const std::string& url)
|
void Libs::load_dict(const std::string& url)
|
||||||
{
|
{
|
||||||
Dict *lib=new Dict;
|
Dict *lib=new Dict;
|
||||||
if (lib->load(url))
|
if (lib->load(url, verbose_))
|
||||||
oLib.push_back(lib);
|
oLib.push_back(lib);
|
||||||
else
|
else
|
||||||
delete lib;
|
delete lib;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public:
|
|||||||
guint32 wordentry_size;
|
guint32 wordentry_size;
|
||||||
|
|
||||||
virtual ~IIndexFile() {}
|
virtual ~IIndexFile() {}
|
||||||
virtual bool load(const std::string& url, gulong wc, gulong fsize) = 0;
|
virtual bool load(const std::string& url, gulong wc, gulong fsize, bool verbose) = 0;
|
||||||
virtual const gchar *get_key(glong idx) = 0;
|
virtual const gchar *get_key(glong idx) = 0;
|
||||||
virtual void get_data(glong idx) = 0;
|
virtual void get_data(glong idx) = 0;
|
||||||
virtual const gchar *get_key_and_data(glong idx) = 0;
|
virtual const gchar *get_key_and_data(glong idx) = 0;
|
||||||
@@ -107,7 +107,7 @@ public:
|
|||||||
Dict() {}
|
Dict() {}
|
||||||
Dict(const Dict&) = delete;
|
Dict(const Dict&) = delete;
|
||||||
Dict& operator=(const Dict&) = delete;
|
Dict& operator=(const Dict&) = delete;
|
||||||
bool load(const std::string& ifofilename);
|
bool load(const std::string& ifofilename, bool verbose);
|
||||||
|
|
||||||
gulong narticles() const { return wordcount; }
|
gulong narticles() const { return wordcount; }
|
||||||
const std::string& dict_name() const { return bookname; }
|
const std::string& dict_name() const { return bookname; }
|
||||||
@@ -144,6 +144,7 @@ public:
|
|||||||
progress_func = f;
|
progress_func = f;
|
||||||
iMaxFuzzyDistance = MAX_FUZZY_DISTANCE; //need to read from cfg.
|
iMaxFuzzyDistance = MAX_FUZZY_DISTANCE; //need to read from cfg.
|
||||||
}
|
}
|
||||||
|
void setVerbose(bool verbose) { verbose_ = verbose; }
|
||||||
~Libs();
|
~Libs();
|
||||||
Libs(const Libs&) = delete;
|
Libs(const Libs&) = delete;
|
||||||
Libs& operator=(const Libs&) = delete;
|
Libs& operator=(const Libs&) = delete;
|
||||||
@@ -181,6 +182,7 @@ private:
|
|||||||
std::vector<Dict *> oLib; // word Libs.
|
std::vector<Dict *> oLib; // word Libs.
|
||||||
int iMaxFuzzyDistance;
|
int iMaxFuzzyDistance;
|
||||||
std::function<void(void)> progress_func;
|
std::function<void(void)> progress_func;
|
||||||
|
bool verbose_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
@@ -90,3 +92,27 @@ void for_each_file(const std::list<std::string>& dirs_list, const std::string& s
|
|||||||
for (const std::string& item : dirs_list)
|
for (const std::string& item : dirs_list)
|
||||||
__for_each_file(item, suff, order_list, disable_list, f);
|
__for_each_file(item, suff, order_list, disable_list, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// based on https://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c/33799784#33799784
|
||||||
|
std::string json_escape_string(const std::string &s) {
|
||||||
|
std::ostringstream o;
|
||||||
|
for (auto c = s.cbegin(); c != s.cend(); c++) {
|
||||||
|
switch (*c) {
|
||||||
|
case '"': o << "\\\""; break;
|
||||||
|
case '\\': o << "\\\\"; break;
|
||||||
|
case '\b': o << "\\b"; break;
|
||||||
|
case '\f': o << "\\f"; break;
|
||||||
|
case '\n': o << "\\n"; break;
|
||||||
|
case '\r': o << "\\r"; break;
|
||||||
|
case '\t': o << "\\t"; break;
|
||||||
|
default:
|
||||||
|
if ('\x00' <= *c && *c <= '\x1f') {
|
||||||
|
o << "\\u"
|
||||||
|
<< std::hex << std::setw(4) << std::setfill('0') << (int)*c;
|
||||||
|
} else {
|
||||||
|
o << *c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o.str();
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,3 +60,4 @@ extern std::string utf8_to_locale_ign_err(const std::string& utf8_str);
|
|||||||
extern void for_each_file(const std::list<std::string>& dirs_list, const std::string& suff,
|
extern void for_each_file(const std::list<std::string>& dirs_list, const std::string& suff,
|
||||||
const std::list<std::string>& order_list, const std::list<std::string>& disable_list,
|
const std::list<std::string>& order_list, const std::list<std::string>& disable_list,
|
||||||
const std::function<void (const std::string&, bool)>& f);
|
const std::function<void (const std::string&, bool)>& f);
|
||||||
|
extern std::string json_escape_string(const std::string &str);
|
||||||
|
|||||||
25
tests/t_json
Executable file
25
tests/t_json
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SDCV="$1"
|
||||||
|
TEST_DIR="$2"
|
||||||
|
|
||||||
|
unset SDCV_PAGER
|
||||||
|
unset STARDICT_DATA_DIR
|
||||||
|
|
||||||
|
test_json() {
|
||||||
|
PARAMS="$1"
|
||||||
|
EXPECTED=$(echo "$2" | jq 'sort')
|
||||||
|
RESULT=$($SDCV $PARAMS | jq 'sort')
|
||||||
|
if [ "$EXPECTED" != "$RESULT"]; then
|
||||||
|
echo "expected $EXPECTED but got $RESULT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_json "-x -j -l -n --data-dir \"$TEST_DIR\"" "[{\"name\": \"Test synonyms\", \"wordcount\": \"1\"},{\"name\": \"Sample 1 test dictionary\", \"wordcount\": \"1\"},{\"name\": \"test_dict\", \"wordcount\": \"1\"}]"
|
||||||
|
test_json "-x -j -n --data-dir \"$TEST_DIR\" foo" "[{\"dict\": \"Test synonyms\",\"word\":\"test\",\"definition\":\"\nresult of test\"}]"
|
||||||
|
test_json "-x -j -n --data-dir \"$TEST_DIR\" foobarbaaz" "[]"
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user