204 lines
4.5 KiB
C
204 lines
4.5 KiB
C
#include <ctype.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define lenof(x) (sizeof((x)) / sizeof(*(x)))
|
|
|
|
#define MAX_LINE_LEN 256
|
|
#define MAX_RCOL 32
|
|
#define RCOL_LEN 64
|
|
|
|
#define RED "\033[0;31m"
|
|
#define GREEN "\033[0;32m"
|
|
#define YELLOW "\033[0;33m"
|
|
|
|
#define HRED "\033[0;91m"
|
|
#define HGREEN "\033[0;92m"
|
|
#define HYELLOW "\033[0;93m"
|
|
|
|
#define RESET "\033[0m"
|
|
|
|
unsigned hash(char const *buf) {
|
|
unsigned res = 5381;
|
|
for (; *buf; buf++) {
|
|
res = (res << 5) + res + *buf;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void err_misfmt_input(char const *reason) {
|
|
fprintf(stderr, "error: misformatted input: %s\n", reason);
|
|
exit(1);
|
|
}
|
|
|
|
char buf[MAX_LINE_LEN];
|
|
|
|
struct counters {
|
|
unsigned char pfs[3];
|
|
};
|
|
|
|
unsigned num_rcol = 0;
|
|
unsigned rcol_hashes[MAX_RCOL] = {0};
|
|
char rcol_values[MAX_RCOL][RCOL_LEN];
|
|
struct counters rcol_ctr[MAX_RCOL] = {0};
|
|
|
|
unsigned rcol_lut(unsigned hash) {
|
|
unsigned *p;
|
|
for (p = rcol_hashes; *p; p++)
|
|
if (*p == hash)
|
|
return p - rcol_hashes + 1;
|
|
return 0;
|
|
}
|
|
|
|
void rstrip(char *buf) {
|
|
char *sub;
|
|
for (; *buf; buf++) {
|
|
if (isspace(*buf)) {
|
|
for (sub = buf + 1; *sub && isspace(*sub); sub++)
|
|
;
|
|
if (!*sub) {
|
|
*buf = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void put(int pfs_mode) {
|
|
if (pfs_mode == 0)
|
|
printf(HGREEN "* " RESET);
|
|
else if (pfs_mode == 1)
|
|
printf(HRED "X " RESET);
|
|
else
|
|
printf(HYELLOW "- " RESET);
|
|
}
|
|
|
|
void finish(int last_lc, unsigned last_rcol_idx) {
|
|
if (last_lc == 0)
|
|
return;
|
|
|
|
for (; last_rcol_idx < num_rcol; last_rcol_idx++) {
|
|
put(2);
|
|
rcol_ctr[last_rcol_idx].pfs[2] += 1;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int lcol_width;
|
|
unsigned last_lc = 0;
|
|
char *p, *lcol, *rcol;
|
|
unsigned lcol_hash, rcol_hash, rcol_idx, last_rcol_idx = 0,
|
|
actual_last_rcol_idx, i, j, pfs_mode;
|
|
struct counters sum = {0};
|
|
|
|
if (argc != 2 || !((lcol_width = atoi(argv[1])))) {
|
|
fprintf(stderr, "usage: %s <left column width>\n", *argv);
|
|
return 1;
|
|
}
|
|
|
|
while (buf == fgets(buf, lenof(buf), stdin)) {
|
|
p = buf;
|
|
for (; isspace(*p); p++)
|
|
;
|
|
if (*p == '#' || !*p)
|
|
continue;
|
|
|
|
lcol = strtok(p, " \t");
|
|
rcol = strtok(0, " \t");
|
|
p = strtok(0, " \t");
|
|
rstrip(p);
|
|
|
|
if (!p || p[1])
|
|
err_misfmt_input("3rd column invalid");
|
|
|
|
if (*p == '0')
|
|
pfs_mode = 1;
|
|
else if (*p == '1')
|
|
pfs_mode = 0;
|
|
else if (*p == '-')
|
|
pfs_mode = 2;
|
|
else
|
|
err_misfmt_input("3rd column invalid");
|
|
|
|
lcol_hash = hash(lcol);
|
|
rcol_hash = hash(rcol);
|
|
|
|
actual_last_rcol_idx = last_rcol_idx;
|
|
if (lcol_hash != last_lc) {
|
|
last_rcol_idx = 0;
|
|
}
|
|
|
|
rcol_idx = rcol_lut(rcol_hash);
|
|
if (rcol_idx == 0) {
|
|
rcol_idx = ++num_rcol;
|
|
/* TODO: validate length */
|
|
rcol_hashes[rcol_idx - 1] = rcol_hash;
|
|
/* TODO: validate length */
|
|
strcpy(rcol_values[rcol_idx - 1], rcol);
|
|
} else if (rcol_idx <= last_rcol_idx && last_rcol_idx != 0) {
|
|
err_misfmt_input("ordering different from last time");
|
|
}
|
|
|
|
rcol_ctr[rcol_idx - 1].pfs[pfs_mode] += 1;
|
|
|
|
if (lcol[0] == '-' && lcol[1] == 0)
|
|
continue;
|
|
|
|
if (lcol_hash != last_lc) {
|
|
finish(last_lc, actual_last_rcol_idx);
|
|
if (last_lc != 0)
|
|
putchar('\n');
|
|
last_lc = lcol_hash;
|
|
last_rcol_idx = 0;
|
|
printf("%*s ", lcol_width, lcol);
|
|
}
|
|
|
|
for (i = last_rcol_idx + 1; i < rcol_idx; i++) {
|
|
put(2);
|
|
rcol_ctr[i - 1].pfs[2]++;
|
|
}
|
|
|
|
put(pfs_mode);
|
|
last_rcol_idx = rcol_idx;
|
|
|
|
fflush(stdout);
|
|
}
|
|
|
|
finish(last_lc, last_rcol_idx);
|
|
if (last_lc != 0)
|
|
putchar('\n');
|
|
|
|
for (i = 0; i <= num_rcol; i++) {
|
|
for (j = 0; j < lcol_width + (num_rcol - i) * 2; j++)
|
|
putchar(' ');
|
|
if (i != num_rcol) {
|
|
putchar('^');
|
|
sum.pfs[0] += rcol_ctr[i].pfs[0];
|
|
sum.pfs[1] += rcol_ctr[i].pfs[1];
|
|
sum.pfs[2] += rcol_ctr[i].pfs[2];
|
|
} else
|
|
putchar(' ');
|
|
if (i != 0) {
|
|
printf(" %s \t(%u/%u passed", rcol_values[num_rcol - i],
|
|
rcol_ctr[num_rcol - i].pfs[0],
|
|
rcol_ctr[num_rcol - i].pfs[0] + rcol_ctr[num_rcol - i].pfs[1]);
|
|
if (rcol_ctr[num_rcol - i].pfs[2])
|
|
printf(", %u skipped", rcol_ctr[num_rcol - i].pfs[2]);
|
|
printf(")");
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
printf("\nSummary:\n");
|
|
if (sum.pfs[0])
|
|
printf(HGREEN " %u passed" RESET "\n", sum.pfs[0]);
|
|
if (sum.pfs[1])
|
|
printf(HRED " %u failed" RESET "\n", sum.pfs[1]);
|
|
if (sum.pfs[2])
|
|
printf(HYELLOW " %u skipped" RESET "\n", sum.pfs[2]);
|
|
|
|
return 0;
|
|
}
|