diff options
| author | Ben Winston | 2024-05-02 20:14:24 -0400 | 
|---|---|---|
| committer | Ben Winston | 2024-05-02 20:14:24 -0400 | 
| commit | 501d47b8a7694de7ec33f2a44cbe6744113aebb9 (patch) | |
| tree | dd8317075bf8b2ae8f83fbb2d10d7e6958722136 /main.c | |
initial commit
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; +} | 
