dict @ d102e028aee6571c0fd9dfd4074cfb3c15f4594e

ref: Refactor newer folder structure

Create a lib dict and importer project.

* dict: holds the main application
* importer: code to read from source to a common database.
* lib: shared code
  1diff --git a/CMakeLists.txt b/CMakeLists.txt
  2index f253be6cd6bd7109239ee826e9c19e0ce59e03b2..a88fc556f01258b3ea3de17980acb4881a84de81 100644
  3--- a/CMakeLists.txt
  4+++ b/CMakeLists.txt
  5@@ -2,12 +2,6 @@ cmake_minimum_required(VERSION 3.26)
  6 
  7 project(dict VERSION 0.1 LANGUAGES C)
  8 
  9-file(GLOB src CONFIGURE_DEPENDS "*.h" "*.c")
 10-add_executable(dict ${src})
 11-
 12-target_compile_options(dict PRIVATE -Wall -Wextra -Wpedantic -Werror)
 13-target_include_directories(dict PUBLIC "${PROJECT_BINARY_DIR}")
 14-target_link_libraries(dict sqlite3 ncursesw m c)
 15-
 16-
 17 add_subdirectory(ext)
 18+add_subdirectory(importer)
 19+add_subdirectory(lib)
 20diff --git a/data.c b/lib/data.c
 21rename from data.c
 22rename to lib/data.c
 23index 2c3f3bb0bbc811c9a8c3552e84d60f8c50714892..7ebf597ca8ab317c76ac1960882f19669994d18e 100644
 24--- a/data.c
 25+++ b/lib/data.c
 26@@ -1,10 +1,11 @@
 27+#include <string.h>
 28 #include <stdlib.h>
 29 #include <stdio.h>
 30 
 31 #include "data.h"
 32 
 33 const char *insert_into = "INSERT INTO words (LINE) VALUES($VVV);";
 34-const char *select_words = "SELECT Id, Line FROM words LIMIT 10;";
 35+const char *select_words = "SELECT Id, Line FROM words WHERE line like $VVV LIMIT 10;";
 36 const char *create_table =  "CREATE TABLE IF NOT EXISTS words (ID INTEGER PRIMARY KEY AUTOINCREMENT, LINE TEXT NOT NULL);";
 37 
 38 Data* new_data(const char* con) {
 39@@ -42,7 +43,6 @@         printf("\n");
 40         return;
 41     }
 42 
 43-    // binds the paremets to the statement, in this case the line;
 44     sqlite3_bind_text(stmt, 1, line, len, NULL);
 45 
 46     int c = sqlite3_step(stmt);
 47@@ -76,7 +76,7 @@
 48     sqlite3_finalize(stmt);
 49 }
 50 
 51-LIST* data_select(Data* data) {
 52+LIST* data_select(Data* data, char *sch, int len) {
 53     sqlite3_stmt *stmt; 
 54     int r = sqlite3_prepare_v2(data->db, select_words, -1, &stmt, NULL);
 55 
 56@@ -89,15 +89,19 @@     }
 57 
 58     LIST *list = NULL;
 59 
 60+    sqlite3_bind_text(stmt, 1, sch, len, NULL);
 61+
 62     int m =  sqlite3_step(stmt);
 63     while(m == SQLITE_ROW) {
 64         Word *word = (Word*)malloc(sizeof(Word));
 65 
 66         int id = sqlite3_column_int(stmt, 0);
 67         const unsigned char *line = sqlite3_column_text(stmt, 1);
 68+        unsigned char *line2 = malloc(sizeof(char*)+strlen((char*)line));
 69+        memcpy(line2, line, strlen((char*)line));
 70 
 71         word->Id = id;
 72-        word->Line = line;
 73+        word->Line = line2;
 74         list = list_add(list, word);
 75 
 76         m = sqlite3_step(stmt);
 77diff --git a/data.h b/lib/data.h
 78rename from data.h
 79rename to lib/data.h
 80index 8bc30e9396446df274a6dd39022d5e32f5d42033..56edd34841971064ac48a0a3acae93ce5d7690aa 100644
 81--- a/data.h
 82+++ b/lib/data.h
 83@@ -39,7 +39,7 @@
 84 /*
 85  * Select all words.
 86  */
 87-LIST* data_select(Data*);
 88+LIST* data_select(Data*, char*, int);
 89 
 90 /*
 91  * Print result code from sqlite.
 92diff --git a/dict/CMakeLists.txt b/dict/CMakeLists.txt
 93new file mode 100644
 94index 0000000000000000000000000000000000000000..051635bf187ec677b57b1a26edb60050bc63b50a
 95--- /dev/null
 96+++ b/dict/CMakeLists.txt
 97@@ -0,0 +1,6 @@
 98+file(GLOB src CONFIGURE_DEPENDS "*.c")
 99+add_executable(dict ${src})
100+
101+target_compile_options(dict PRIVATE -Wall -Wextra -Wpedantic -Werror)
102+target_include_directories(dict PUBLIC "${PROJECT_BINARY_DIR}")
103+target_link_libraries(dict sqlite3 ncursesw m c lib)
104diff --git a/dict/main.c b/dict/main.c
105new file mode 100644
106index 0000000000000000000000000000000000000000..8240b756f55aa57482b2a2fa13a0cbb00fa7f58d
107--- /dev/null
108+++ b/dict/main.c
109@@ -0,0 +1,111 @@
110+#include <unistd.h>
111+#include <string.h>
112+#include <locale.h>
113+#include <stdio.h>
114+#include <sqlite3.h>
115+#include <ncurses.h>
116+
117+#include "../lib/data.h"
118+#include "../lib/ui.h"
119+#include "../lib/util.h"
120+
121+Data *data;
122+
123+void search(char*, int);
124+int run(const char*, const char*);
125+
126+int main(int argc, char** argv) {
127+    int opt;
128+    char* txt = NULL;
129+    char* db = NULL;
130+
131+    while ((opt = getopt(argc, argv, "t:d:h")) != -1) {
132+        switch(opt) {
133+            case 't':
134+                txt = copy_achar(optarg);
135+                break;
136+            case 'd':
137+                db = copy_achar(optarg);
138+                break;
139+            case 'h':
140+                  // fall through
141+            default:
142+                printf("Usage: %s", argv[0]);
143+                goto end;
144+        }
145+    }
146+
147+    int r = run(db, txt);
148+
149+end:
150+    if (txt != NULL)
151+        free(txt);
152+    if (db != NULL)
153+        free(db);
154+
155+    return r;
156+}
157+
158+int run(const char *db, const char *txt) {
159+    data = new_data(db);
160+    bootstrap(data);
161+
162+    setlocale(LC_ALL, "");
163+    initscr(); 
164+    noecho();
165+    cbreak();
166+    keypad(stdscr, TRUE);
167+
168+    FILE *f = fopen(txt, "r");
169+    unsigned int lines = count_file_lines(f);
170+    fseek(f, 0, SEEK_SET);
171+
172+    char * line = NULL;
173+    size_t len = 0;
174+    ssize_t read;
175+    PROGRESS_BAR *bar = new_progress_bar(stdscr, lines);
176+    while ((read = getline(&line, &len, f)) != -1) {
177+        if (line[0] == '#' || line[0] == '\n')
178+            continue;
179+
180+        insert(data, line, read-1);
181+        bar_step(bar, 1);
182+    }
183+
184+    move(2,0);
185+    printw("Saving db...");
186+    refresh();
187+    load_or_save_db(data->db, "backup.db", 1);
188+
189+    clear();
190+    refresh();
191+
192+    TEXT_BOX *box = new_text_box(stdscr, 100);
193+    get_char(box, search);
194+
195+    clear();
196+    refresh();
197+
198+    endwin();
199+
200+    free_data(data);
201+    return 0;
202+}
203+
204+void search(char *sch, int len) {
205+    char s[len+2];
206+
207+    sprintf(s, "%%%*s%%", len, sch);
208+
209+    LIST* l = data_select(data, s, len+2);
210+
211+    for (int y = 1; y < 20; y++) {
212+        move(y, 0);
213+        Word *item = (Word*)list_get(l, y);
214+        if (item != NULL)
215+            printw("%s", item->Line);
216+    }
217+    refresh();
218+}
219+
220+
221diff --git a/importer/CMakeLists.txt b/importer/CMakeLists.txt
222new file mode 100644
223index 0000000000000000000000000000000000000000..587952ece1ff225046dfb50ce6c0a9f896f50cd7
224--- /dev/null
225+++ b/importer/CMakeLists.txt
226@@ -0,0 +1,9 @@
227+project(dict_importer VERSION 0.1 LANGUAGES C)
228+
229+file(GLOB src CONFIGURE_DEPENDS "*.c")
230+add_executable(dict_importer ${src})
231+
232+target_compile_options(dict_importer PRIVATE -Wall -Wextra -Wpedantic -Werror)
233+target_include_directories(dict_importer PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}")
234+target_link_libraries(dict_importer sqlite3 lib)
235+
236diff --git a/importer/main.c b/importer/main.c
237new file mode 100644
238index 0000000000000000000000000000000000000000..a1850f830b62b9e0166f1a72735883e56f338003
239--- /dev/null
240+++ b/importer/main.c
241@@ -0,0 +1,71 @@
242+#include <stdlib.h>
243+#include <stdio.h>
244+#include <unistd.h>
245+
246+#include "../lib/util.h"
247+#include "../lib/data.h"
248+
249+int run(const char *db, const char *txt);
250+
251+int main(int argc, char** argv) {
252+    int opt;
253+    char* txt = NULL;
254+    char* db = NULL;
255+
256+    while ((opt = getopt(argc, argv, "t:d:h")) != -1) {
257+        switch(opt) {
258+            case 't':
259+                txt = copy_achar(optarg);
260+                break;
261+            case 'd':
262+                db = copy_achar(optarg);
263+                break;
264+            case 'h':
265+                  // fall through
266+            default:
267+                printf("Usage: %s", argv[0]);
268+                goto end;
269+        }
270+    }
271+
272+
273+    int r = run(db, txt);
274+
275+end:
276+    if (txt != NULL)
277+        free(txt);
278+    if (db != NULL)
279+        free(db);
280+
281+    return r;
282+}
283+
284+int run(const char *db, const char *txt) {
285+    char * line = NULL;
286+    size_t len = 0;
287+    int count = 0;
288+    ssize_t read;
289+    Data *data;
290+    FILE *f;
291+    int total;
292+
293+    data = new_data(":memory:");
294+    f = fopen(txt, "r");
295+
296+    bootstrap(data);
297+
298+    total = count_file_lines(f);
299+    fseek(f, 0, SEEK_SET);
300+
301+    while ((read = getline(&line, &len, f)) != -1) {
302+        if (line[0] == '#' || line[0] == '\n')
303+            continue;
304+
305+        insert(data, line, read-1);
306+
307+        float t = ((float)count/(float)total)*100;
308+        printf("\rLoading data [%03.0f%%] %d/%d", t, count, total);
309+    }
310+
311+    return load_or_save_db(data->db, db, 1);
312+}
313diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
314new file mode 100644
315index 0000000000000000000000000000000000000000..023cdf1338199643645914f83bd5af6dfb3297b3
316--- /dev/null
317+++ b/lib/CMakeLists.txt
318@@ -0,0 +1,5 @@
319+file(GLOB lib CONFIGURE_DEPENDS "*.h" "*.c")
320+
321+add_library(lib ${lib})
322+target_compile_options(lib PRIVATE -Wall -Wextra -Wpedantic -Werror)
323+target_link_libraries(lib sqlite3 ncursesw m c)
324diff --git a/lib/util.c b/lib/util.c
325new file mode 100644
326index 0000000000000000000000000000000000000000..6720082ac9e4f530f85d26e47416487702fac414
327--- /dev/null
328+++ b/lib/util.c
329@@ -0,0 +1,61 @@
330+#include <stdlib.h>
331+#include <stdio.h>
332+#include <string.h>
333+
334+#include "util.h"
335+
336+#define BUF_SIZE 100
337+
338+char* copy_achar(const char* src) {
339+    int len = strlen(src) + 1;
340+    char* dest = (char*)malloc(sizeof(char)*len);
341+    strcpy(dest, src);
342+
343+    return dest;
344+}
345+
346+
347+int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave){
348+    int rc;                   /* Function return code */
349+    sqlite3 *pFile;           /* Database connection opened on zFilename */
350+    sqlite3_backup *pBackup;  /* Backup object used to copy data */
351+    sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
352+    sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */
353+
354+    rc = sqlite3_open(zFilename, &pFile);
355+    if( rc==SQLITE_OK ){
356+        pFrom = (isSave ? pInMemory : pFile);
357+        pTo   = (isSave ? pFile     : pInMemory);
358+
359+        pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
360+        if( pBackup ){
361+            (void)sqlite3_backup_step(pBackup, -1);
362+            (void)sqlite3_backup_finish(pBackup);
363+        }
364+        rc = sqlite3_errcode(pTo);
365+    }
366+
367+    (void)sqlite3_close(pFile);
368+    return rc;
369+}
370+
371+unsigned int count_file_lines(FILE *file) {
372+    char buf[BUF_SIZE];
373+    unsigned int counter = 0;
374+    for(;;)
375+    {
376+        size_t res = fread(buf, 1, BUF_SIZE, file);
377+        if (ferror(file))
378+            return -1;
379+
380+        size_t i;
381+        for(i = 0; i < res; i++)
382+            if (buf[i] == '\n')
383+                counter++;
384+
385+        if (feof(file))
386+            break;
387+    }
388+
389+    return counter;
390+}
391diff --git a/lib/util.h b/lib/util.h
392new file mode 100644
393index 0000000000000000000000000000000000000000..c03dbae7654b1ac748acd438ed6ab0f4975a2427
394--- /dev/null
395+++ b/lib/util.h
396@@ -0,0 +1,15 @@
397+#pragma once
398+
399+#include <sqlite3.h>
400+#include <stdio.h>
401+
402+/*
403+ * Copy of a char to a newly created string of the same size.
404+ */
405+char* copy_achar(const char*);
406+
407+
408+int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave);
409+
410+
411+unsigned int count_file_lines(FILE *file);
412diff --git a/list.c b/lib/list.c
413rename from list.c
414rename to lib/list.c
415index a40dd576db2dcc385a4bb2f4fb8f6f4e99102793..fc0fddfd3e82dc239d36563fd7953e5522aa1ff0 100644
416--- a/list.c
417+++ b/lib/list.c
418@@ -42,3 +42,14 @@
419     free(list->list);
420     free(list);
421 }
422+
423+
424+void *list_get(LIST *list, unsigned int index) {
425+    if (list == NULL)
426+        return NULL;
427+
428+    if (index < list->size) 
429+        return list->list[index];
430+
431+    return NULL;
432+}
433diff --git a/list.h b/lib/list.h
434rename from list.h
435rename to lib/list.h
436index e33bf017753ff3c93db620c320e024cd2b18ec8a..dd28722a34ace46877267b9eea10edb154148bdf 100644
437--- a/list.h
438+++ b/lib/list.h
439@@ -22,6 +22,8 @@ * Remove an item from a given list
440 * @list: array list structure.
441 * @pos: position of item to be removed.
442 */
443-LIST* list_remove(LIST* list, unsigned int pos);
444+LIST *list_remove(LIST *list, unsigned int pos);
445 
446 void list_free(LIST* list);
447+
448+void *list_get(LIST *list, unsigned int index);
449diff --git a/main.c b/main.c
450deleted file mode 100644
451index 026b4b5e244137c725d6f3a6e21f789a7f9bf88f..0000000000000000000000000000000000000000
452--- a/main.c
453+++ /dev/null
454@@ -1,104 +0,0 @@
455-#include <locale.h>
456-#include <stdio.h>
457-#include <sqlite3.h>
458-#include <ncurses.h>
459-#include "data.h"
460-#include "ui.h"
461-
462-#define BUF_SIZE 100
463-
464-unsigned int count_lines(FILE* file);
465-int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave);
466-
467-int main() {
468-    Data *data = new_data(":memory:");
469-    bootstrap(data);
470-
471-    setlocale(LC_ALL, "");
472-    noecho();
473-    cbreak();
474-	nonl();
475-    keypad(stdscr, TRUE);
476-    initscr(); 
477-
478-    FILE *f = fopen("dict.txt", "r");
479-    unsigned int lines = count_lines(f);
480-    fseek(f, 0, SEEK_SET);
481-
482-    char * line = NULL;
483-    size_t len = 0;
484-    ssize_t read;
485-    PROGRESS_BAR *bar = new_progress_bar(stdscr, lines);
486-    while ((read = getline(&line, &len, f)) != -1) {
487-        if (line[0] == '#' || line[0] == '\n')
488-            continue;
489-
490-        insert(data, line, read-1);
491-        bar_step(bar, 1);
492-    }
493-
494-    move(2,0);
495-    printw("Saving db...");
496-    refresh();
497-    load_or_save_db(data->db, "backup.db", 1);
498-
499-    clear();
500-    refresh();
501-
502-    TEXT_BOX *box = new_text_box(stdscr, 10);
503-    get_char(box);
504-
505-    clear();
506-    refresh();
507-
508-    endwin();
509-
510-    free_data(data);
511-    return 0;
512-}
513-
514-int load_or_save_db(sqlite3 *pInMemory, const char *zFilename, int isSave){
515-  int rc;                   /* Function return code */
516-  sqlite3 *pFile;           /* Database connection opened on zFilename */
517-  sqlite3_backup *pBackup;  /* Backup object used to copy data */
518-  sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
519-  sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */
520-
521-  rc = sqlite3_open(zFilename, &pFile);
522-  if( rc==SQLITE_OK ){
523-    pFrom = (isSave ? pInMemory : pFile);
524-    pTo   = (isSave ? pFile     : pInMemory);
525-
526-    pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
527-    if( pBackup ){
528-      (void)sqlite3_backup_step(pBackup, -1);
529-      (void)sqlite3_backup_finish(pBackup);
530-    }
531-    rc = sqlite3_errcode(pTo);
532-  }
533-
534-  (void)sqlite3_close(pFile);
535-  return rc;
536-}
537-
538-unsigned int count_lines(FILE* file)
539-{
540-    char buf[BUF_SIZE];
541-    unsigned int counter = 0;
542-    for(;;)
543-    {
544-        size_t res = fread(buf, 1, BUF_SIZE, file);
545-        if (ferror(file))
546-            return -1;
547-
548-        size_t i;
549-        for(i = 0; i < res; i++)
550-            if (buf[i] == '\n')
551-                counter++;
552-
553-        if (feof(file))
554-            break;
555-    }
556-
557-    return counter;
558-}
559diff --git a/ui.c b/lib/ui.c
560rename from ui.c
561rename to lib/ui.c
562index 9762859cc6dadb17f0c06acc2387f0027477af5f..1a285a00e407566b783917c1541883301ab838c7 100644
563--- a/ui.c
564+++ b/lib/ui.c
565@@ -58,7 +58,7 @@     memset(text->text, '\0', length);
566     return text;
567 }
568 
569-void get_char(TEXT_BOX* text) {
570+void get_char(TEXT_BOX* text, void (*sch)(char*, int)) {
571     while(1){
572         wchar_t c;
573         get_wch((wint_t*)&c);
574@@ -75,6 +75,11 @@                     text->text[text->current] = c;
575                     text->text[++text->current] = '\0';
576                 }
577         }
578+
579+        char str[text->length];
580+        wcstombs(str, text->text, sizeof(text->text));
581+        sch(str, (int)strlen(str));
582+
583         move(0,0);
584         wrefresh(text->scr);
585         wprintw(text->scr, "%*ls", text->current,text->text);
586diff --git a/ui.h b/lib/ui.h
587rename from ui.h
588rename to lib/ui.h
589index cdc0539b61f5d717ee843d9ac164d6c18c54ca7a..90b352ff9f0cd7dcc853c3e6695fb9ce74d2b10a 100644
590--- a/ui.h
591+++ b/lib/ui.h
592@@ -1,3 +1,4 @@
593+#pragma once
594 #include <ncurses.h>
595 
596 typedef struct progress_bar {
597@@ -18,5 +19,5 @@     WINDOW *scr;
598 } TEXT_BOX;
599 
600 TEXT_BOX* new_text_box(WINDOW*, int);
601-void get_char(TEXT_BOX* text);
602+void get_char(TEXT_BOX* text, void (*sch)(char*, int));
603