dict @ 03aa0fe6c664f74e8e4e5877ef89b4e053b30bc5

feat: Add initial ncurses support

Alongside with loading and saving data from the dict.cc's text.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2614aa6f52b569feba19c53168c92e37ffaa32d3..c34734d2daf984075b1bed87f236c2ac33e5ded2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,5 +7,5 @@ add_executable(dict ${src})
 
 target_compile_options(dict PRIVATE -Wall -Wextra -Wpedantic -Werror)
 target_include_directories(dict PUBLIC "${PROJECT_BINARY_DIR}")
-target_link_libraries(dict sqlite3)
+target_link_libraries(dict sqlite3 ncursesw)
 
diff --git a/data.c b/data.c
index 5a9a103daf2dd02f9b494385a08cbbe4a8e316ea..777dcdf58b260a0ecf8c50fb56132b34d0a6c35d 100644
--- a/data.c
+++ b/data.c
@@ -25,7 +25,7 @@     sqlite3_close(data->db);
     free(data);
 }
 
-void insert(Data* data, char* line) {
+void insert(Data* data, char* line, int len) {
     sqlite3_stmt *stmt; 
     int r = sqlite3_prepare_v2(data->db, insert_into, -1, &stmt, NULL);
 
@@ -37,7 +37,7 @@         return;
     }
 
     // binds the paremets to the statement, in this case the line;
-    sqlite3_bind_text(stmt, 1, line, -1, NULL);
+    sqlite3_bind_text(stmt, 1, line, len, NULL);
 
     int c = sqlite3_step(stmt);
     if (c != SQLITE_DONE) {
@@ -45,6 +45,8 @@         printf("Error executing insert: ");
         print_result_code(r);
         printf("\n");
     }
+
+    sqlite3_finalize(stmt);
 }
 
 void bootstrap(Data* data) {
@@ -64,6 +66,8 @@         printf("Error executing bootstrap: ");
         print_result_code(r);
         printf("\n");
     }
+
+    sqlite3_finalize(stmt);
 }
 
 LIST* select(Data* data) {
diff --git a/data.h b/data.h
index db8aedc2a5e9ea62ef2f577718b9dbf8418c9a4c..393f8308c1ccf9032745260ee3ef84b9d5af3462 100644
--- a/data.h
+++ b/data.h
@@ -34,7 +34,7 @@
 /*
  * insert line into database.
  */
-void insert(Data*, char*);
+void insert(Data*, char*, int);
 
 /*
  * Select all words.
diff --git a/main.c b/main.c
index 720871ca2071734484ce7c6feb3b9ae706e2c4a1..dae1f2aa50de122aa0d00c8cfec74b3f939a5bfc 100644
--- a/main.c
+++ b/main.c
@@ -1,20 +1,101 @@
+#include <locale.h>
 #include <stdio.h>
 #include <sqlite3.h>
-
+#include <ncurses.h>
 #include "data.h"
 
+#define BUF_SIZE 100
+
+unsigned int count_lines(FILE* file);
+int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave);
+
 int main() {
     Data *data = new_data(":memory:");
 
     bootstrap(data);
-    for (int x = 0; x < 10000; x++)
-        insert(data, "LINE X");
 
-    LIST *list = select(data);
+    setlocale(LC_ALL, "");
+    initscr();
 
-    for (unsigned int x = 0; x < list->size; x++) 
-        printf("This is a line: %s\n", ((Word*)list->list[x])->Line);
+    int maxx=getmaxx(stdscr);
 
-    list_free(list);
+    FILE *f = fopen("dict.txt", "r");
+    unsigned int lines = count_lines(f);
+    fseek(f, 0, SEEK_SET);
+
+    char * line = NULL;
+    size_t len = 0;
+    ssize_t read;
+    int count = 0;
+    while ((read = getline(&line, &len, f)) != -1) {
+        if (line[0] == '#' || line[0] == '\n')
+            continue;
+
+        insert(data, line, read-1);
+        count ++;
+        move(0,0);
+        float total = ((float)count/(float)lines);
+        printw("%03.0f%% ", total*100);
+        for (int x = 0; x < ((maxx-4)*total); x++) {
+            printw("█");
+        }
+        move(1,0);
+        printw("%d/%d",count,lines);
+        refresh();
+    }
+
+    move(2,0);
+    printw("Saving db...");
+    refresh();
+    load_or_save_db(data->db, "backup.db", 1);
+
+    clear();
+    refresh();
     return 0;
 }
+
+int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave){
+  int rc;                   /* Function return code */
+  sqlite3 *pFile;           /* Database connection opened on zFilename */
+  sqlite3_backup *pBackup;  /* Backup object used to copy data */
+  sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
+  sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */
+
+  rc = sqlite3_open(zFilename, &pFile);
+  if( rc==SQLITE_OK ){
+    pFrom = (isSave ? pInMemory : pFile);
+    pTo   = (isSave ? pFile     : pInMemory);
+
+    pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
+    if( pBackup ){
+      (void)sqlite3_backup_step(pBackup, -1);
+      (void)sqlite3_backup_finish(pBackup);
+    }
+    rc = sqlite3_errcode(pTo);
+  }
+
+  (void)sqlite3_close(pFile);
+  return rc;
+}
+
+unsigned int count_lines(FILE* file)
+{
+    char buf[BUF_SIZE];
+    unsigned int counter = 0;
+    for(;;)
+    {
+        size_t res = fread(buf, 1, BUF_SIZE, file);
+        if (ferror(file))
+            return -1;
+
+        size_t i;
+        for(i = 0; i < res; i++)
+            if (buf[i] == '\n')
+                counter++;
+
+        if (feof(file))
+            break;
+    }
+
+    return counter;
+}