diff options
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 251 |
1 files changed, 251 insertions, 0 deletions
@@ -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; +} |
