aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..f9acb47
--- /dev/null
+++ b/main.c
@@ -0,0 +1,251 @@
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "toml.h"
+
+#define BOOKI_FILE_REL ".local/share/booki/books.toml"
+
+char* BOOKI_FILE;
+
+const char* get_last_word(const char* str) {
+ const char* last_space = strrchr(str, ' ');
+ if ((last_space - str) > 0)
+ return last_space + 1;
+ else
+ return 0;
+}
+
+bool regex_match(const char* pattern, const char* text) {
+
+ // empty pattern matches everything
+ if (!*pattern) return true;
+
+ // get lengths
+ int pattern_length = strlen(pattern);
+ int text_length = strlen(text);
+
+ if (pattern_length > text_length) return false;
+
+ // we only need to compare while remaining text is
+ // as long or longer than pattern (without special)
+ for (int i = 0; i <= (text_length - pattern_length); i++) {
+ if (strncasecmp(pattern, text + i, pattern_length) == 0) return true;
+ }
+
+ return false;
+}
+
+toml_table_t* get_toml_data(const char* filename) {
+ FILE* fp;
+ char errbuf[200];
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ printf("can't open file :(");
+ return 0;
+ }
+
+ toml_table_t* conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
+ fclose(fp);
+
+ return conf;
+}
+
+static struct option search_options[] = {
+ {"title", required_argument, 0, 't'},
+ {"author", required_argument, 0, 'a'},
+ {"show", no_argument, 0, 's'},
+ {0, 0, 0, 0} // marks the end of the array
+};
+
+char** search(int argc, char* argv[]) {
+ toml_table_t* data = get_toml_data(BOOKI_FILE);
+
+ if (!data) {
+ return NULL;
+ }
+
+ int opt;
+ int opt_idx = 0;
+ char* title = NULL;
+ char* author = NULL;
+ int show = 0;
+
+ while ((opt = getopt_long(argc, argv, "t:a:", search_options, &opt_idx)) != -1) {
+ switch(opt) {
+ case 't':
+ title = optarg;
+ break;
+ case 'a':
+ author = optarg;
+ break;
+ case 's':
+ show = 1;
+ break;
+ case '?':
+ if (optopt == 't' || optopt == 'a')
+ fprintf(stderr, "search flags require an argument");
+ break;
+ default:
+ printf("bad arg\n");
+ return NULL;
+ }
+ }
+
+ // get the books array
+ toml_array_t* books = toml_array_in(data, "books");
+ if (!books) {
+ printf("no such array: 'books'");
+ return NULL;
+ }
+
+
+ for (int i = 0; ; i++) {
+ toml_table_t* book = toml_table_at(books, i);
+ if (!book) break;
+
+ toml_datum_t book_title = toml_string_in(book, "title");
+ if (!book_title.ok) {
+ continue;
+ }
+
+ // author can be a string or a list
+ toml_datum_t book_author = toml_string_in(book, "author");
+ char author_str[100];
+ char* tmp;
+ if (!book_author.ok) {
+ toml_array_t* book_author_array = toml_array_in(book, "author");
+ if (!book_author_array) {
+ continue;
+ }
+ int len = toml_array_nelem(book_author_array);
+ tmp = toml_string_at(book_author_array, 0).u.s;
+ strcpy(author_str, tmp);
+ free(tmp);
+ for (int i = 1; i < len; i++) {
+ book_author = toml_string_at(book_author_array, i);
+ tmp = book_author.u.s;
+ if (i == len-1) {
+ strcat(author_str, " and ");
+ } else {
+ strcat(author_str, ", ");
+ }
+ strcat(author_str, book_author.u.s);
+ free(tmp);
+ }
+ } else {
+ strcpy(author_str, book_author.u.s);
+ free(book_author.u.s);
+ }
+
+ // always print on no search terms
+ bool print_title = (title == NULL);
+ bool print_author = (author == NULL);
+ if (title != NULL)
+ print_title = regex_match(title, book_title.u.s);
+ if (author != NULL)
+ print_author = regex_match(author, author_str);
+
+
+ if (print_title && print_author) {
+ printf("%s by %s\n", book_title.u.s, author_str);
+ if (show) {
+ //toml_datum_t d;
+ for (int i = 0; ; i++) {
+ const char* key = toml_key_in(book, i);
+ if (!key) break;
+
+ /*
+ if (strcmp("pages", key) == 0) {
+ d = toml_int_in(book, key);
+ if (d.ok) {
+ printf(" - %s: %d\n",
+ }
+ }
+ */
+
+
+ // currently we support strings and ints
+ toml_datum_t s = toml_string_in(book, key);
+ if (s.ok) {
+ printf(" - %s: %s\n", key, s.u.s);
+ free(s.u.s);
+ }
+ toml_datum_t i = toml_int_in(book, key);
+ if (i.ok) {
+ printf(" - %s: %d\n", key, i.u.i);
+ }
+
+ }
+ }
+ }
+
+ free(book_title.u.s);
+ //free(book_author.u.s);
+ }
+
+ toml_free(data);
+
+ return argv + optind;
+}
+
+void open() {
+
+ char* home = getenv("HOME");
+ if (!home) {
+ printf("no home?\n");
+ home = "/"; // no way
+ }
+ char* editor = getenv("EDITOR");
+ if (!editor)
+ editor = "nano";
+
+ pid_t pid;
+ int status;
+ switch ((pid = fork())) {
+ case -1:
+ printf("fork has failed!\n");
+ break;
+ case 0:
+ execlp(editor, editor, BOOKI_FILE, NULL);
+ printf("child failed :(\n");
+ break;
+ default:
+ // wait for the child to finish
+ pid = wait(&status);
+ break;
+ }
+}
+
+void help(bool err) {
+ printf("booki! it's a thing\n");
+ if (err) {
+ printf("you did something wrong\n");
+ }
+}
+
+int main(int argc, char* argv[]) {
+
+ char* home = getenv("HOME");
+ char booki_file[strlen(home) + strlen(BOOKI_FILE_REL) + 1];
+ sprintf(booki_file, "%s/%s", home, BOOKI_FILE_REL);
+ BOOKI_FILE = booki_file;
+ char** remaining = NULL;
+
+ if (argc == 1) {
+ help(false);
+ return 0;
+ } else if (strcmp(argv[1], "open") == 0) {
+ open();
+ } else if (strcmp(argv[1], "search") == 0) {
+ remaining = search(argc - 1, argv + 1);
+ }
+
+ return 0;
+}