summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLieuwe Rooijakkers <lieuwerooijakkers@gmail.com>2024-09-08 21:57:14 +0200
committerLieuwe Rooijakkers <lieuwerooijakkers@gmail.com>2024-09-08 21:57:19 +0200
commitf11bd88153ca6ab57d9ebb58807f8771cbd40924 (patch)
treea93687462190c7af232b1b49562e6a6d94e5921d
parent43d5a40971b825cb78ce9ff56211c0c021109d07 (diff)
hus
-rw-r--r--src/hus.c160
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;
+}