Skip to content

Commit

Permalink
Allow creating dictionary database from preferences window
Browse files Browse the repository at this point in the history
  • Loading branch information
btrkeks committed Aug 23, 2024
1 parent b127184 commit d1d2c0d
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 137 deletions.
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ set(DICTLOOKUP_SRCS
# ${DEINFLECTION_RULES_C} # Doesn't get generated if put in here
)

set(DICTPOPUP_CREATE_SRCS
src/dictpopup_create/dictpopup_create.c
src/dictpopup_create/objects.c
src/dictpopup_create/yomichan_parser.c
)

# ##############################################################################
# Cppcheck
# ##############################################################################
Expand Down Expand Up @@ -248,13 +254,14 @@ add_executable(dictpopup
src/platformdep/file_operations.c
src/platformdep/windowtitle.c
src/objects/freqentry.c
src/objects/color.c
${DICTPOPUP_CREATE_SRCS}
${JPPRON_SRCS}
${ANKICONNECTC_SRCS}
${DICTLOOKUP_SRCS}
${GRESOURCE_C}
${DEINFLECTION_RULES_C}
${COMPILED_SETTINGS_SCHEMA}
src/objects/color.c
)
target_compile_definitions(dictpopup PUBLIC NOTIFICATIONS CLIPBOARD GTK3)
target_link_libraries(dictpopup PRIVATE
Expand Down Expand Up @@ -286,6 +293,7 @@ add_executable(dictpopup-config
src/deinflector/kata2hira.c # Remove?
src/utils/utf8.c # Remove?
src/platformdep/audio.c # Remove?
${DICTPOPUP_CREATE_SRCS}
${JPPRON_SRCS}
${ANKICONNECTC_SRCS}
${GRESOURCE_C}
Expand All @@ -295,6 +303,7 @@ target_link_libraries(dictpopup-config PRIVATE
LMDB::LMDB
PkgConfig::GTK3
CURL::libcurl
libzip::zip
)

# ##############################################################################
Expand Down
14 changes: 4 additions & 10 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,22 @@

High priority

- think about set_index_visible

- Left and right buttons should be greyed out if there is only one result
- Enter in 'Edit Lookup' window should press apply

- pronfiles and exists dot should be consistent with current dictionary state
-> add to dict_state manager
- Investigate why デジタル大辞泉 appears twice in dictionary sort order
- Fix update of dictionary sort order not working

- Suspended + new cards indicator?

- Proper error handling for faulty Anki settings

- Add database version to metadata of database

- Remove margin to border in general settings

- What happens if some random folder was selected for pronunciation index?
-> Proper error message

- More tests, esp. for gui components?
- More tests (esp. for gui components?)

Mid priority
- Close settings window with escape
- Remove duplication of full path in every jppron database entry
- Safe prefix to indices in metadata and concatenate at runtime
- Allow creating dictpopup db from preferences window
Expand Down
4 changes: 2 additions & 2 deletions include/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ void _nonnull_ db_append_lookup(const database_t *db, s8 headword, Dict dict[sta
bool is_deinflection);
s8Buf db_get_dictnames(database_t *db);

bool db_check_exists(s8 dbpath);
void db_remove(s8 dbpath);
bool db_check_exists(void);
void db_remove(void);

DEFINE_DROP_FUNC(database_t *, db_close)

Expand Down
9 changes: 9 additions & 0 deletions include/dictpopup_create.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef DICTPOPUP_CREATE_H
#define DICTPOPUP_CREATE_H

#include <stdbool.h>
#include <stdatomic.h>

void _nonnull_ dictpopup_create(const char *dictionaries_path,
bool (*should_overwrite_existing_db)(void *user_data), void *user_data, atomic_bool *cancel_flag);
#endif // DICTPOPUP_CREATE_H
2 changes: 1 addition & 1 deletion include/dictpopup_create/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "objects/freqentry.h"

typedef struct {
void (*foreach_dictentry)(void *, dictentry);
void (*foreach_dictentry)(void *, Dictentry);
void *userdata_de;
void (*foreach_freqentry)(void *, freqentry);
void *userdata_fe;
Expand Down
4 changes: 3 additions & 1 deletion include/yomichan_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#define YOMICHAN_PARSER_H

#include <dictpopup_create/objects.h>
#include <stdbool.h>
#include <stdatomic.h>

void parse_yomichan_dict(const char *zipfn, ParserCallbacks callbacks);
void parse_yomichan_dict(const char *zipfn, ParserCallbacks callbacks, atomic_bool *cancel_flag);

#endif // YOMICHAN_PARSER_H
6 changes: 4 additions & 2 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,14 @@ s8Buf db_get_dictnames(database_t *db) {
return names;
}

bool db_check_exists(s8 dbpath) {
bool db_check_exists(void) {
s8 dbpath = db_get_dbpath();
_drop_(frees8) s8 dbfile = buildpath(dbpath, S("data.mdb"));
return check_file_exists((char *)dbfile.s);
}

void db_remove(s8 dbpath) {
void db_remove() {
s8 dbpath = db_get_dbpath();
_drop_(frees8) s8 dbfile = buildpath(dbpath, S("data.mdb"));
rem((char *)dbfile.s);
}
104 changes: 21 additions & 83 deletions src/dictpopup_create/dictpopup_create.c
Original file line number Diff line number Diff line change
@@ -1,70 +1,20 @@
#include <errno.h>
#include <signal.h> // Catch SIGINT
#include <stdio.h>
#include <unistd.h> // getopt

#include <ctype.h>
#include <dirent.h> // opendir
#include <time.h>

#include "db.h"
#include "dictpopup_create.h"
#include "utils/messages.h"
#include "utils/util.h"
#include "yomichan_parser.h"

#include "platformdep/file_operations.h"

typedef struct {
s8 dictspath;
} config;

DEFINE_DROP_FUNC(FILE *, fclose)
DEFINE_DROP_FUNC(DIR *, closedir)

static bool askyn(const char *prompt) {
printf("%s [y/n] ", prompt);
char resp = tolower(getchar());
return resp == 'y';
}

volatile sig_atomic_t sigint_received = 0;

static void sigint_handler(int s) {
sigint_received = 1;
}

static void setup_sighandler(void) {
struct sigaction act;
act.sa_handler = sigint_handler;
sigaction(SIGINT, &act, NULL);
}

static void parse_cmd_line(int argc, char **argv, config *cfg) {
int c;
opterr = 0;

while ((c = getopt(argc, argv, "hd:i:")) != -1)
switch (c) {
case 'i':
cfg->dictspath = s8dup(fromcstr_(optarg));
break;
case 'h':
puts("See 'man dictpopup-create' for help.");
exit(EXIT_SUCCESS);
case '?':
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
exit(EXIT_FAILURE);
default:
abort();
}
}

static void set_default_values(config *cfg) {
if (!cfg->dictspath.len) {
cfg->dictspath = S(".");
}
}

static ParserCallbacks get_callbacks(database_t *db) {
return (ParserCallbacks){.foreach_dictentry = (void (*)(void *, Dictentry))db_put_dictent,
.userdata_de = db,
Expand All @@ -74,46 +24,34 @@ static ParserCallbacks get_callbacks(database_t *db) {
.userdata_dn = db};
}

int main(int argc, char *argv[]) {
setup_sighandler();

config cfg = {0};
parse_cmd_line(argc, argv, &cfg);
set_default_values(&cfg);

static void create_db_dir_if_necessary(void) {
s8 dbpath = db_get_dbpath();
createdir(dbpath);
}

msg("Using directory '%.*s' as dictionary path.", (int)cfg.dictspath.len,
(char *)cfg.dictspath.s);
msg("Storing database in: %.*s", (int)dbpath.len, (char *)dbpath.s);
void _nonnull_ dictpopup_create(const char *dictionaries_path,
bool (*should_overwrite_existing_db)(void *user_data), void *user_data,
atomic_bool *cancel_flag) {
if (db_check_exists()) {
if(!should_overwrite_existing_db(user_data))
return;

if (db_check_exists(dbpath)) {
if (askyn("A database file already exists. "
"Would you like to delete the old one?"))
db_remove(dbpath);
else
exit(EXIT_FAILURE);
} else
createdir(dbpath);
db_remove();
}

_drop_(db_close) database_t *db = db_open(dbpath, false);
_drop_(closedir) DIR *dir = opendir((char *)cfg.dictspath.s);
die_on(!dir, "Error opening directory '%s': %s", (char *)cfg.dictspath.s, strerror(errno));
create_db_dir_if_necessary();

ParserCallbacks callbacks = get_callbacks(db);
_drop_(db_close) database_t *db = db_open(false);
_drop_(closedir) DIR *dir = opendir(dictionaries_path);
die_on(!dir, "Error opening directory '%s': %s", dictionaries_path, strerror(errno));

double startTime = (double)clock() / CLOCKS_PER_SEC;
ParserCallbacks callbacks = get_callbacks(db);

struct dirent *entry;
while ((entry = readdir(dir)) && !sigint_received) {
_drop_(frees8) s8 fn = buildpath(cfg.dictspath, fromcstr_(entry->d_name));
while ((entry = readdir(dir)) && !atomic_load(cancel_flag)) {
_drop_(frees8) s8 fn =
buildpath(fromcstr_((char *)dictionaries_path), fromcstr_(entry->d_name));
if (endswith(fn, S(".zip")))
parse_yomichan_dict((char *)fn.s, callbacks);
parse_yomichan_dict((char *)fn.s, callbacks, cancel_flag);
}

double endTime = (double)clock() / CLOCKS_PER_SEC;
printf("Time taken: %.1fs\n", endTime - startTime);

s8Buf dictnames = db_get_dictnames(db);
s8_buf_print(dictnames);
}
5 changes: 3 additions & 2 deletions src/dictpopup_create/yomichan_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ static s8 _nonnull_ extract_dictname_from_zip(const char *zipfn, zip_t *zipfile)
return dictname;
}

void parse_yomichan_dict(const char *zipfn, ParserCallbacks callbacks) {
void parse_yomichan_dict(const char *zipfn, ParserCallbacks callbacks, atomic_bool *cancel_flag) {
zip_t *zipfile = open_zip(zipfn);
return_on(!zipfile);

Expand All @@ -403,7 +403,8 @@ void parse_yomichan_dict(const char *zipfn, ParserCallbacks callbacks) {

struct zip_stat finfo;
zip_stat_init(&finfo);
for (int i = 0; (zip_stat_index(zipfile, i, 0, &finfo)) == 0; i++) {
for (int i = 0; (zip_stat_index(zipfile, i, 0, &finfo)) == 0 && !atomic_load(cancel_flag);
i++) {
s8 fn = fromcstr_((char *)finfo.name);
if (startswith(fn, S("term_bank_"))) {
_drop_(frees8) s8 buffer = unzip_file(zipfile, finfo.name);
Expand Down
1 change: 1 addition & 0 deletions src/frontends/gtk3popup/dictpopup-application.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static bool can_lookup(DpApplication *app) {
return false;
}

// TODO: Move?
if (!db_check_exists(db_get_dbpath())) {
set_database_not_found(app);
return false;
Expand Down
Loading

0 comments on commit d1d2c0d

Please sign in to comment.