kjv_main.c (4493B)
1 /* 2 kjv: Read the Word of God from your terminal 3 4 License: Public domain 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <stdbool.h> 11 #include <signal.h> 12 #include <readline/readline.h> 13 #include <readline/history.h> 14 #include <sys/ioctl.h> 15 16 #include "kjv_config.h" 17 #include "kjv_data.h" 18 #include "kjv_ref.h" 19 #include "kjv_render.h" 20 #include "strutil.h" 21 22 const char * 23 usage = "usage: kjv [flags] [reference...]\n" 24 "\n" 25 "Flags:\n" 26 " -A num show num verses of context after matching verses\n" 27 " -B num show num verses of context before matching verses\n" 28 " -C show matching verses in context of the chapter\n" 29 " -e highlighting of chapters and verse numbers\n" 30 " (default when output is a TTY)\n" 31 " -p output to less with chapter grouping, spacing, indentation,\n" 32 " and line wrapping\n" 33 " (default when output is a TTY)\n" 34 " -l list books\n" 35 " -h show help\n" 36 "\n" 37 "Reference:\n" 38 " <Book>\n" 39 " Individual book\n" 40 " <Book>:<Chapter>\n" 41 " Individual chapter of a book\n" 42 " <Book>:<Chapter>:<Verse>[,<Verse>]...\n" 43 " Individual verse(s) of a specific chapter of a book\n" 44 " <Book>:<Chapter>-<Chapter>\n" 45 " Range of chapters in a book\n" 46 " <Book>:<Chapter>:<Verse>-<Verse>\n" 47 " Range of verses in a book chapter\n" 48 " <Book>:<Chapter>:<Verse>-<Chapter>:<Verse>\n" 49 " Range of chapters and verses in a book\n" 50 "\n" 51 " /<Search>\n" 52 " All verses that match a pattern\n" 53 " <Book>/<Search>\n" 54 " All verses in a book that match a pattern\n" 55 " <Book>:<Chapter>/<Search>\n" 56 " All verses in a chapter of a book that match a pattern\n"; 57 58 int 59 main(int argc, char *argv[]) 60 { 61 bool is_atty = isatty(STDOUT_FILENO) == 1; 62 kjv_config config = { 63 .highlighting = is_atty, 64 .pretty = is_atty, 65 66 .maximum_line_length = 80, 67 68 .context_before = 0, 69 .context_after = 0, 70 .context_chapter = false, 71 }; 72 73 bool list_books = false; 74 75 opterr = 0; 76 for (int opt; (opt = getopt(argc, argv, "A:B:CeplWh")) != -1; ) { 77 char *endptr; 78 switch (opt) { 79 case 'A': 80 config.context_after = strtol(optarg, &endptr, 10); 81 if (endptr[0] != '\0') { 82 fprintf(stderr, "kjv: invalid flag value for -A\n\n%s", usage); 83 return 1; 84 } 85 break; 86 case 'B': 87 config.context_before = strtol(optarg, &endptr, 10); 88 if (endptr[0] != '\0') { 89 fprintf(stderr, "kjv: invalid flag value for -B\n\n%s", usage); 90 return 1; 91 } 92 break; 93 case 'C': 94 config.context_chapter = true; 95 break; 96 case 'e': 97 config.highlighting = true; 98 break; 99 case 'p': 100 config.pretty = true; 101 break; 102 case 'l': 103 list_books = true; 104 break; 105 case 'h': 106 printf("%s", usage); 107 return 0; 108 case '?': 109 fprintf(stderr, "kjv: invalid flag -%c\n\n%s", optopt, usage); 110 return 1; 111 } 112 } 113 114 if (list_books) { 115 for (int i = 0; i < kjv_books_length; i++) { 116 kjv_book *book = &kjv_books[i]; 117 printf("%s (%s)\n", book->name, book->abbr); 118 } 119 return 0; 120 } 121 122 struct winsize ttysize; 123 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ttysize) == 0 && ttysize.ws_col > 0) { 124 config.maximum_line_length = ttysize.ws_col; 125 } 126 127 signal(SIGPIPE, SIG_IGN); 128 129 if (argc == optind) { 130 using_history(); 131 while (true) { 132 char *input = readline("kjv> "); 133 if (input == NULL) { 134 break; 135 } 136 add_history(input); 137 kjv_ref *ref = kjv_newref(); 138 int success = kjv_parseref(ref, input); 139 free(input); 140 if (success == 0) { 141 kjv_render(ref, &config); 142 } 143 kjv_freeref(ref); 144 } 145 } else { 146 char *ref_str = str_join(argc-optind, &argv[optind]); 147 kjv_ref *ref = kjv_newref(); 148 int success = kjv_parseref(ref, ref_str); 149 free(ref_str); 150 if (success == 0) { 151 kjv_render(ref, &config); 152 } 153 kjv_freeref(ref); 154 } 155 156 return 0; 157 }