diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hus.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/hus.c b/src/hus.c new file mode 100644 index 0000000..9604954 --- /dev/null +++ b/src/hus.c @@ -0,0 +1,160 @@ +#include <assert.h> +#include <errno.h> +#include <getopt.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/random.h> +#include <sys/types.h> +#include <unistd.h> + +#include "util/debug.h" +#include "util/error.h" +#include "util/versie.h" + +static char *shufrange = NULL; + +static char **lines = NULL; +static size_t nlines = 0; + +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); + + char *x = lines[i]; + lines[i] = lines[j]; + lines[j] = x; + } + + free(js); +} + +static void usage(FILE *f) { + fprintf(f, + "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) { + int opt; + while ((opt = getopt(argc, argv, "i:hV")) != -1) { + switch (opt) { + case 'i': + shufrange = optarg; + break; + + case 'h': + usage(stdout); + exit(0); + + case 'V': + drukkedoos_print_versie(stdout); + exit(0); + + case '?': + fprintf(stderr, "hus: Ongeldige optie: -%c\n", optopt); + usage(stderr); + exit(1); + } + } + + return argv + optind; +} + +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: HO groter dan LA\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; +} |