main.c
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <time.h> 4 5 #include "typer.h" 6 #include "opt.h" 7 8 #define TRUE 1 9 #define FALSE 0 10 #define MAX_PROMPT_LENGTH 1024 11 #define MAX_LINES 100 12 13 char prompt_buffer[MAX_PROMPT_LENGTH]; 14 int jumps_buffer[MAX_PROMPT_LENGTH]; 15 int line_lengths_buffer[MAX_LINES]; 16 char chars_printed_buffer[MAX_PROMPT_LENGTH]; 17 18 const char * usage =\ 19 "Usage: typie [-l] [-o OUTFILE] [-t TIME] PROMPT" "\n"\ 20 "\n"\ 21 " -l no backspacing, incorrect keys not accepted" "\n"\ 22 " -o OUTFILE file to write output to (defaults to stdout)" "\n"\ 23 " -t TIME exit after TIME seconds" "\n"\ 24 /* " -m output mistakes after completion" "\n" */\ 25 "\n"\ 26 "See the man page for more details." "\n"\ 27 "\n"; 28 29 long int 30 get_time_millis() 31 { 32 struct timespec now; 33 timespec_get(&now, TIME_UTC); 34 return now.tv_sec * 1000 + now.tv_nsec / 1000000; 35 } 36 37 int 38 type(State * state) 39 { 40 int keypress_kind; 41 int started = FALSE; 42 43 for (;;) { 44 char c = getchar(); 45 46 long int keypress_millis = get_time_millis(); 47 long int elapsed_millis = keypress_millis - state->start_millis; 48 if ( 49 started && 50 state->duration_millis != 0 && 51 elapsed_millis > state->duration_millis 52 ) { 53 state->timed_out = TRUE; 54 return 0; 55 } 56 57 state->end_millis = keypress_millis; 58 59 keypress_kind = handle_keypress(state, c); 60 fflush(stdout); 61 62 switch (keypress_kind) { 63 case KEYPRESS_EXIT: 64 return 1; 65 66 case KEYPRESS_CORRECT: /* FALLTHROUGH */ 67 state->chars_correct++; 68 if (state->prompt[state->index] == '\0') 69 return 0; 70 case KEYPRESS_INCORRECT: 71 state->chars_total++; 72 if (!started) { 73 started = TRUE; 74 state->start_millis = get_time_millis(); 75 fflush(stdout); 76 } 77 break; 78 79 case KEYPRESS_ENTER: 80 return 0; 81 break; 82 83 case KEYPRESS_BACKSPACE: 84 break; 85 86 case KEYPRESS_NONE: 87 break; 88 } 89 } 90 } 91 92 void 93 write_output(State state) 94 { 95 FILE * out; 96 int correct = state.chars_correct, 97 total = state.chars_total; 98 99 double time_millis = state.timed_out ? 100 state.duration_millis : 101 state.end_millis - state.start_millis; 102 double time_seconds = time_millis / 1000; 103 double time_minutes = time_seconds / 60; 104 105 int wpm = (correct / 5.0) / time_minutes; 106 107 int accuracy = ((double) correct / total) * 100; 108 109 out = stdout; 110 if (state.flags & FLAG_FILE) 111 out = fopen(state.outfile, "w"); 112 113 fprintf( 114 out, 115 "millis %d" "\n"\ 116 "wpm %d" "\n"\ 117 "accuracy %d%%", 118 (int) time_millis, 119 wpm, 120 accuracy 121 ); 122 123 if (state.flags & FLAG_FILE) { 124 fclose(out); 125 } else { 126 fprintf(out, "\n"); 127 } 128 } 129 130 int 131 get_length(const char * string) 132 { 133 int index = 0; 134 for (;;) { 135 if (string[index] == '\0') 136 break; 137 index++; 138 } 139 return index; 140 } 141 142 143 void 144 init_state(State * state) 145 { 146 state->flags = 0; 147 state->index = 0; 148 state->jumps.buffer = jumps_buffer; 149 state->jumps.length = 0; 150 state->line_lengths = line_lengths_buffer; 151 state->chars_printed = chars_printed_buffer; 152 state->chars_printed_index = 0; 153 state->index = 0; 154 state->row = 0; 155 state->max_row = 0; 156 state->column = 0; 157 state->line_lengths[0] = 0; 158 } 159 160 int 161 main(int argc, const char * argv[]) 162 { 163 struct termios termios_original; 164 State state; 165 int result; 166 167 init_state(&state); 168 169 result = set_flags(&state, argc, argv); 170 if (result > 0) { 171 printf("%s", usage); 172 exit(1); 173 } 174 state.prompt = argv[argc-1]; 175 state.prompt_length = get_length(state.prompt); 176 177 if (state.prompt_length >= MAX_PROMPT_LENGTH) { 178 fprintf(stderr, COLOR_RED "Max prompt length exceeded." "\n"); 179 return 1; 180 } 181 182 tcgetattr(0, &termios_original); 183 setup_termios(termios_original); 184 185 start_typing(&state); 186 fflush(stdout); 187 188 result = type(&state); 189 if (result > 0) { 190 restore_termios(termios_original); 191 exit(1); 192 } 193 194 printf("\033[%dB", state.max_row - state.row - 1); 195 restore_termios(termios_original); 196 printf(COLOR_RESET "\n"); 197 198 write_output(state); 199 200 return 0; 201 }