typie | Minimal typing practice tool |
| download: https://git.y1.nz/archives/typie.tar.gz | |
| README | Files | Log | Refs | LICENSE |
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 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.