From 7a2e38d00390007348ebba3e75efb65b2e8d4fd8 Mon Sep 17 00:00:00 2001 From: Ben Winston Date: Sun, 5 May 2024 18:13:45 -0400 Subject: main.c -> booki.c --- booki.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 312 ---------------------------------------------------------------- 2 files changed, 312 insertions(+), 312 deletions(-) create mode 100644 booki.c delete mode 100644 main.c diff --git a/booki.c b/booki.c new file mode 100644 index 0000000..b7bb92f --- /dev/null +++ b/booki.c @@ -0,0 +1,312 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "toml.h" + +#define BOOKI_FILE_REL ".local/share/booki/books.toml" + +#define MAX_SEARCH_OPTS 5 + +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[] = { + {"show", no_argument, 0, 's'}, + {0, 0, 0, 0} // marks the end of the array +}; + +struct search_opt { + int show; + int count; + char* opts[MAX_SEARCH_OPTS]; + char* args[MAX_SEARCH_OPTS]; +}; + +struct search_opt parse_search_options(int argc, char* argv[]) { + + // return struct + struct search_opt opt_out; + int count = 0; + int show = false; + + // opt options + int opt; + int opt_idx = 0; + opterr = 0; // turn off getopt error messages + + // look at each option + while ((opt = getopt_long_only(argc, argv, "", search_options, &opt_idx)) != -1) { + switch(opt) { + case 's': + show = true; + break; + case '?': + // optind points at the argument (one past the option) + opt_out.opts[count] = argv[optind-1] + 2; // '--example' -> 'example' + opt_out.args[count] = argv[optind]; + count++; + break; + default: + printf("something went wrong with parsing!\n"); + break; + } + } + + // set the count/show values + opt_out.count = count; + opt_out.show = show; + + return opt_out; +} + +char** search(int argc, char* argv[]) { + toml_table_t* data = get_toml_data(BOOKI_FILE); + + if (!data) { + return NULL; + } + + struct search_opt search_opts = parse_search_options(argc, argv); + bool print = false; + + // get the books array + toml_array_t* books = toml_array_in(data, "books"); + if (!books) { + printf("no such array: 'books'"); + return NULL; + } + + // book loop + for (int i = 0; ; i++) { + toml_table_t* book = toml_table_at(books, i); + if (!book) break; + + if (search_opts.count == 0) { + print = true; + } else { + toml_datum_t datapoint; + char* field; + bool inner_print = true; + + // loop through all options + int i; + for (i = 0; i < search_opts.count; i++) { + field = search_opts.opts[i]; + + // if the key doesn't exist, we won't print + if (!toml_key_exists(book, field)) { + break; + } + + // try and get a string + datapoint = toml_string_in(book, field); + if (datapoint.ok) { + if (!regex_match(search_opts.args[i], datapoint.u.s)) { + free(datapoint.u.s); + break; + } + free(datapoint.u.s); + } else { + // try and get an integer + datapoint = toml_int_in(book, field); + int ret; + if (datapoint.ok) { + ret = atoi(search_opts.args[i]); + if (ret == 0) { + printf("not an int: %s\n", search_opts.args[i]); + break; + } else if (ret != datapoint.u.i) { + break; + } + } else { + break; + } + } + } + + // if we made it all the way through the loop, + // we should print + print = i == search_opts.count; + } + + // get title and author for printing + 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); + } + + // print! + if (print) { + printf("%s by %s\n", book_title.u.s, author_str); + if (search_opts.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; +} diff --git a/main.c b/main.c deleted file mode 100644 index b7bb92f..0000000 --- a/main.c +++ /dev/null @@ -1,312 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "toml.h" - -#define BOOKI_FILE_REL ".local/share/booki/books.toml" - -#define MAX_SEARCH_OPTS 5 - -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[] = { - {"show", no_argument, 0, 's'}, - {0, 0, 0, 0} // marks the end of the array -}; - -struct search_opt { - int show; - int count; - char* opts[MAX_SEARCH_OPTS]; - char* args[MAX_SEARCH_OPTS]; -}; - -struct search_opt parse_search_options(int argc, char* argv[]) { - - // return struct - struct search_opt opt_out; - int count = 0; - int show = false; - - // opt options - int opt; - int opt_idx = 0; - opterr = 0; // turn off getopt error messages - - // look at each option - while ((opt = getopt_long_only(argc, argv, "", search_options, &opt_idx)) != -1) { - switch(opt) { - case 's': - show = true; - break; - case '?': - // optind points at the argument (one past the option) - opt_out.opts[count] = argv[optind-1] + 2; // '--example' -> 'example' - opt_out.args[count] = argv[optind]; - count++; - break; - default: - printf("something went wrong with parsing!\n"); - break; - } - } - - // set the count/show values - opt_out.count = count; - opt_out.show = show; - - return opt_out; -} - -char** search(int argc, char* argv[]) { - toml_table_t* data = get_toml_data(BOOKI_FILE); - - if (!data) { - return NULL; - } - - struct search_opt search_opts = parse_search_options(argc, argv); - bool print = false; - - // get the books array - toml_array_t* books = toml_array_in(data, "books"); - if (!books) { - printf("no such array: 'books'"); - return NULL; - } - - // book loop - for (int i = 0; ; i++) { - toml_table_t* book = toml_table_at(books, i); - if (!book) break; - - if (search_opts.count == 0) { - print = true; - } else { - toml_datum_t datapoint; - char* field; - bool inner_print = true; - - // loop through all options - int i; - for (i = 0; i < search_opts.count; i++) { - field = search_opts.opts[i]; - - // if the key doesn't exist, we won't print - if (!toml_key_exists(book, field)) { - break; - } - - // try and get a string - datapoint = toml_string_in(book, field); - if (datapoint.ok) { - if (!regex_match(search_opts.args[i], datapoint.u.s)) { - free(datapoint.u.s); - break; - } - free(datapoint.u.s); - } else { - // try and get an integer - datapoint = toml_int_in(book, field); - int ret; - if (datapoint.ok) { - ret = atoi(search_opts.args[i]); - if (ret == 0) { - printf("not an int: %s\n", search_opts.args[i]); - break; - } else if (ret != datapoint.u.i) { - break; - } - } else { - break; - } - } - } - - // if we made it all the way through the loop, - // we should print - print = i == search_opts.count; - } - - // get title and author for printing - 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); - } - - // print! - if (print) { - printf("%s by %s\n", book_title.u.s, author_str); - if (search_opts.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; -} -- cgit v1.2.3