#include #include #include #include #include #include #include #include #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; }