#include #include #include #include #include #include #include #include #include #include #include "util/debug.h" #include "util/error.h" #include "util/option.h" #include "util/versie.h" static char *shufrange = NULL; static char **lines = NULL; static size_t nlines = 0; static size_t random_size_t_r(struct random_data *buf) { size_t res = 0; unsigned nbytes = 0; while (nbytes < sizeof(size_t)) { int32_t value; int ret = random_r(buf, &value); if (ret == -1) { fprintf(stderr, "hus: Kon willekeurigheid niet verlengen\n"); exit(1); } res |= (size_t)value << (8 * nbytes); nbytes += 4; } return res; } static void shuf_lines() { size_t *js = calloc(nlines, sizeof(size_t)); errno = 0; if (getrandom(js, nlines*sizeof(size_t), 0) == -1) exit(1); for (ssize_t i = nlines - 1; i > 0; i--) { size_t j = js[i] % (nlines-1); if (j - 1 + (nlines-1) < j) { struct random_data buf; int ret = srandom_r(js[i], &buf); if (ret == -1) { fprintf(stderr, "hus: Kon willekeurigheidsverlenging niet instellen\n"); exit(1); } do j = random_size_t_r(&buf) % (nlines-1); while (j - 1 + (nlines-1) < j); } char *x = lines[i]; lines[i] = lines[j]; lines[j] = x; } free(js); } static const char *usage_string = "Gebruik: hus [-hV] [BESTAND]\n" " hus -i LA-HO [-hV]\n" "\n" "Hussel de regels van het gegeven bestand.\n" "Als er geen bestand gegeven is, of bestand is -, hussel dan de regels op standaard invoer.\n" "\n" " -i LA-HO Genereer regels van laag naar hoog en hussel deze\n" " -h Toon deze hulptekst\n" " -V Toon versienummer\n"; static char** parse_options(int argc, char **argv) { const struct option_spec spec[] = { {'i', OPTION_WITHARG(&shufrange)}, {'h', OPTION_HELPUSAGE(usage_string)}, {'V', OPTION_VERSION()}, OPTION_SPEC_END }; return option_parse(argc, argv, spec); } static int exec_shufrange() { assert(shufrange != NULL); char *seploc = NULL; if ((seploc = strchr(shufrange, '-')) != NULL) { *seploc = '\0'; const long long start = strtoll(shufrange, NULL, 10); const long long end = strtoll(seploc+1, NULL, 10); if (start > end) { fprintf(stderr, "hus: LA groter dan HO\n"); return 1; } nlines = end - start + 1; lines = calloc(nlines, sizeof(char*)); for (long long i = 0; i <= start+end; i++) { long long n = i + start; asprintf(lines + i, "%lld", n); } } else { fprintf(stderr, "hus: geen LA en HO waarde opgegeven\n"); return 1; } return 0; } static int exec_shufstream(FILE *restrict stream) { size_t cap = 1 << 8; lines = malloc(sizeof(char*)*cap); char *line = NULL; size_t linen = 0; ssize_t nread = 0; while ((errno = 0, nread = getline(&line, &linen, stream)) != -1) { if (nread > 0 && line[nread-1] == '\n') line[--nread] = '\0'; if (nlines == cap) { cap *= 2; lines = realloc(lines, sizeof(char*)*cap); } lines[nlines] = strdup(line); nlines++; } free(line); return 0; } int entry_hus(int argc, char **argv) { int res; #define CHECK(f) if ((res = f) != 0) return res; char **args = parse_options(argc, argv); // count the amount of arguments provided size_t nargs; for (nargs = 0; args[nargs] != NULL; nargs++); if (shufrange) { CHECK(exec_shufrange()); } else if (nargs == 0 || (nargs == 1 && strcmp(args[0], "-") == 0)) { CHECK(exec_shufstream(stdin)); } else if (nargs == 1) { FILE *stream = fopen(args[0], "r"); if (stream == NULL) { fprintf(stderr, "hus: %s: kon bestand niet openen\n", args[0]); return 1; } CHECK(exec_shufstream(stream)); fclose(stream); } else { fprintf(stderr, "hus: teveel argumenten gegeven\n"); return 1; } shuf_lines(); for (size_t i = 0; i < nlines; i++) { printf("%s\n", lines[i]); } return 0; }