typetest

Typing speed benchmarker
git clone https://git.sinitax.com/sinitax/typetest
Log | Files | Refs | LICENSE | sfeed.txt

commit 6cb461a040f4b53f0f01421da92007fc682a7310
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon, 21 Jun 2021 12:05:58 +0200

Initial prototype

Diffstat:
A.gitignore | 1+
AMakefile | 4++++
Amain.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +typetest diff --git a/Makefile b/Makefile @@ -0,0 +1,4 @@ +CFLAGS=-I . -g + +typetest: main.c + $(CC) -o $@ $< $(CFLAGS) $(LDLIBS) diff --git a/main.c b/main.c @@ -0,0 +1,184 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <termio.h> +#include <stdarg.h> +#include <unistd.h> +#include <time.h> + +#define LINTERP(a,b,v) ((a) * (v) + (b) * (1 - (v))) + +enum { + C_EOF = 0x03, + C_EOT = 0x04, + C_DEL = 0x7f +}; + +enum { + STYLE_END = -1, + + STYLE_RESET = 0, + + STYLE_BOLD = 1, + STYLE_FAINT = 2, + STYLE_ITALIC = 3, + STYLE_UNDERLINE = 4, + STYLE_BLINK = 5, + STYLE_INVERT = 7, + STYLE_CROSSED_OUT = 9, + + STYLE_BLACK_FG = 30, + STYLE_RED_FG = 31, + STYLE_GREEN_FG = 32, + STYLE_YELLOW_FG = 33, + STYLE_BLUE_FG = 34, + STYLE_MAGENTA_FG = 35, + STYLE_CYAN_FG = 36, + STYLE_WHITE_FG = 37, +}; + +static const int style_wrong[] = { STYLE_RED_FG, STYLE_BOLD, STYLE_END }; +static const int style_right[] = { STYLE_GREEN_FG, STYLE_END }; +static const int style_reset[] = { STYLE_RESET, STYLE_END }; + +struct termios oldt; + +int typed = 0; +float gcps; + +void +die(const char *fmtstr, ...) +{ + va_list ap; + + va_start(ap, fmtstr); + vprintf(fmtstr, ap); + va_end(ap); + + exit(EXIT_FAILURE); +} + +void +print_style(const int *props) +{ + const int *iter; + + if (!props || *props == STYLE_END) return; + + printf("\x1b["); + for (iter = props; *iter != STYLE_END; iter++) + printf("%i%c", *iter, (iter[1] == STYLE_END) ? 'm' : ';'); +} + +void +time_sub(struct timespec *new, struct timespec *old) +{ + new->tv_sec -= old->tv_sec; + new->tv_nsec -= old->tv_nsec; + + if (new->tv_nsec < 0) { + new->tv_sec -= 1; + new->tv_nsec += 1e9; + } +} + +int +type(const char *text) +{ + char input[1024]; + int c, right, wrong, tlen; + struct timespec start = { 0 }, end; + float cps; + + printf("%s", text); + + tlen = strlen(text); + right = wrong = 0; + while ((c = getchar()) > 0) { + printf("\x1b[2K"); /* clear line */ + printf("\r"); /* cursor to beginning of line */ + + if (!start.tv_sec) + clock_gettime(CLOCK_REALTIME, &start); + + switch (c) { + case C_EOF: + case C_EOT: + return 1; + case C_DEL: + if (wrong) wrong--; + else right--; + break; + case u'\n': + break; + default: + if (right + wrong == tlen) break; + if (right + wrong == sizeof(input)) break; + if (c == text[right + wrong] && !wrong) right++; + else wrong++; + break; + } + + print_style(style_right); + printf("%.*s", right, text); + print_style(style_wrong); + printf("%.*s", wrong, text + right); + print_style(style_reset); + printf("%.*s", tlen - right - wrong, text + right + wrong); + + if (!wrong && right + wrong == tlen) break; + } + + clock_gettime(CLOCK_REALTIME, &end); + time_sub(&end, &start); + + cps = tlen / (end.tv_sec + end.tv_nsec / 1e9f); + if (!typed) gcps = cps; + else gcps = LINTERP(gcps, cps, typed * 1.f / (typed + tlen)); + + printf("\n\r"); + return 0; +} + +void +reset() +{ + tcsetattr(0, TCSANOW, &oldt); +} + +int +main(int argc, const char **argv) +{ + struct termios t; + char linebuf[256]; + FILE *f; + + if (argc < 2) + die("USAGE: typetest <FILE>\n"); + + if (!(f = fopen(argv[1], "r"))) + die("Failed to read file\n"); + + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + tcgetattr(0, &t); + memcpy(&oldt, &t, sizeof(struct termios)); + + cfmakeraw(&t); + + if (!tcsetattr(0, TCSANOW, &t)) atexit(reset); + + while (fgets(linebuf, sizeof(linebuf), f) > 0) { + if (!*linebuf) break; + if (linebuf[strlen(linebuf)-1] == '\n') + linebuf[strlen(linebuf)-1] = '\0'; + if (!*linebuf) continue; + if (type(linebuf)) break; + } + + printf("CPM: %0.2f\n\r", gcps * 60); + + fclose(f); +}