kjv_render.c (3832B)
1 #include <stdbool.h> 2 #include <signal.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <sys/wait.h> 6 #include <unistd.h> 7 8 #include "kjv_data.h" 9 #include "kjv_match.h" 10 #include "kjv_render.h" 11 12 #define ESC_BOLD "\033[1m" 13 #define ESC_UNDERLINE "\033[4m" 14 #define ESC_RESET "\033[m" 15 16 static void 17 kjv_output_verse(const kjv_verse *verse, FILE *f, const kjv_config *config) 18 { 19 fprintf( 20 f, 21 config->highlighting ? 22 ESC_BOLD "%d:%d" ESC_RESET "\t" : 23 "%d:%d\t", 24 verse->chapter, verse->verse 25 ); 26 27 char verse_text[1024]; 28 strcpy(verse_text, verse->text); 29 size_t characters_printed = 0; 30 char *word = strtok(verse_text, " "); 31 while (word != NULL) { 32 size_t word_length = strlen(word); 33 if (characters_printed + word_length + (characters_printed > 0 ? 1 : 0) > config->maximum_line_length - 8 - 2) { 34 fprintf(f, "\n\t"); 35 characters_printed = 0; 36 } 37 if (characters_printed > 0) { 38 fprintf(f, " "); 39 characters_printed++; 40 } 41 fprintf(f, "%s", word); 42 characters_printed += word_length; 43 word = strtok(NULL, " "); 44 } 45 fprintf(f, "\n"); 46 } 47 48 static bool 49 kjv_output(const kjv_ref *ref, FILE *f, const kjv_config *config) 50 { 51 kjv_next_data next = { 52 .current = 0, 53 .next_match = -1, 54 .matches = { 55 {-1, -1}, 56 {-1, -1}, 57 }, 58 }; 59 60 kjv_verse *last_printed = NULL; 61 for (int verse_id; (verse_id = kjv_next_verse(ref, config, &next)) != -1; ) { 62 kjv_verse *verse = &kjv_verses[verse_id]; 63 kjv_book *book = &kjv_books[verse->book - 1]; 64 65 if (config->pretty) { 66 if (last_printed == NULL || verse->book != last_printed->book) { 67 if (last_printed != NULL) { 68 fprintf(f, "\n"); 69 } 70 fprintf( 71 f, 72 config->highlighting ? 73 ESC_UNDERLINE "%s" ESC_RESET "\n\n" : 74 "%s\n\n", 75 book->name 76 ); 77 } 78 kjv_output_verse(verse, f, config); 79 } else { 80 fprintf( 81 f, 82 config->highlighting ? 83 ESC_UNDERLINE "%s" ESC_RESET " " ESC_BOLD "%d:%d" ESC_RESET " %s\n" : 84 "%s %d:%d %s\n", 85 book->name, 86 verse->chapter, 87 verse->verse, 88 verse->text 89 ); 90 } 91 last_printed = verse; 92 } 93 return last_printed != NULL; 94 } 95 96 static int 97 kjv_render_pretty(const kjv_ref *ref, const kjv_config *config) 98 { 99 int fds[2]; 100 if (pipe(fds) == -1) { 101 return 1; 102 } 103 104 pid_t pid = fork(); 105 if (pid == 0) { 106 close(fds[1]); 107 dup2(fds[0], STDIN_FILENO); 108 char *args[9] = {NULL}; 109 int arg = 0; 110 args[arg++] = "less"; 111 args[arg++] = "-J"; 112 args[arg++] = "-I"; 113 if (ref->search_str != NULL) { 114 args[arg++] = "-p"; 115 args[arg++] = ref->search_str; 116 } 117 args[arg++] = "-R"; 118 args[arg++] = "-f"; 119 args[arg++] = "-"; 120 args[arg++] = NULL; 121 execvp("less", args); 122 printf("unable not exec less\n"); 123 _exit(0); 124 } else if (pid == -1) { 125 printf("unable to fork\n"); 126 return 2; 127 } 128 close(fds[0]); 129 FILE *output = fdopen(fds[1], "w"); 130 bool printed = kjv_output(ref, output, config); 131 if (!printed) { 132 kill(pid, SIGTERM); 133 } 134 fclose(output); 135 waitpid(pid, NULL, 0); 136 return 0; 137 } 138 139 int 140 kjv_render(const kjv_ref *ref, const kjv_config *config) 141 { 142 if (config->pretty) { 143 return kjv_render_pretty(ref, config); 144 } 145 kjv_output(ref, stdout, config); 146 return 0; 147 }