summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/toilet.c123
-rw-r--r--src/util/map.c2
-rw-r--r--src/util/map.h1
3 files changed, 125 insertions, 1 deletions
diff --git a/src/toilet.c b/src/toilet.c
new file mode 100644
index 0000000..24b19a4
--- /dev/null
+++ b/src/toilet.c
@@ -0,0 +1,123 @@
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "util/versie.h"
+#include "util/error.h"
+#include "util/debug.h"
+#include "util/map.h"
+
+static void usage(FILE *f) {
+ fprintf(f,
+ "Gebruik: toilet [-nchV] [BESTAND]...\n"
+ "\n"
+ "Toon de hoevelheeid regels, woorden en beten for elk BESTAND\n"
+ "\n"
+ " -c Geef het aantal beten weer\n"
+ " -w Geef het aantal woorden weer\n"
+ " -l Geef het aantal regels weer\n"
+ " -h Toon deze hulptekst\n"
+ " -V Toon versienummer\n");
+}
+
+enum MODE {
+ M_BYTES,
+ M_WORDS,
+ M_LINES,
+};
+
+// Returns pointer to argument array containing the file names
+static char** parse_options(int argc, char **argv, enum MODE *mode) {
+ int opt;
+ while ((opt = getopt(argc, argv, "cwlhV")) != -1) {
+ switch (opt) {
+ case 'c':
+ *mode = M_BYTES;
+ break;
+
+ case 'w':
+ *mode = M_WORDS;
+ break;
+
+ case 'l':
+ *mode = M_LINES;
+ break;
+
+ case 'h':
+ usage(stdout);
+ exit(0);
+
+ case 'V':
+ drukkedoos_print_versie(stdout, "toilet");
+ exit(0);
+
+ case '?':
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ return argv + optind;
+}
+
+size_t get_count(enum MODE mode, struct map *map) {
+ switch (mode) {
+ case M_BYTES:
+ return map->sb.st_size;
+
+ case M_WORDS: {
+ size_t words = 0;
+
+ assert(map->sb.st_size >= 0);
+ for (size_t i = 0; i < (size_t)map->sb.st_size;) {
+ size_t previ = i;
+ while (!isspace(map->addr[i])) i++;
+ words += i != previ;
+ while (isspace(map->addr[i])) i++;
+ }
+
+ return words;
+ }
+
+ case M_LINES: {
+ size_t lines = 0;
+
+ while (map->addr != map->end) {
+ if (*map->addr == '\n') lines++;
+ map->addr++;
+ }
+
+ if (*(map->addr - 1) != '\n') {
+ lines++;
+ }
+
+ return lines;
+ }
+ }
+}
+
+int entry_toilet(int argc, char **argv) {
+ enum MODE mode;
+ char **args = parse_options(argc, argv, &mode);
+
+
+ while (*args != NULL) {
+ struct map *map = open_map(*args);
+ if (map == NULL) {
+ fprintf(stderr, "toilet: fout bij lezen bestand");
+ return 1;
+ }
+
+ size_t count = get_count(mode, map);
+ printf("%li %s\n", count, *args);
+
+ close_map(map);
+ args++;
+ }
+
+ return 0;
+}
diff --git a/src/util/map.c b/src/util/map.c
index 35e1b49..cd2da42 100644
--- a/src/util/map.c
+++ b/src/util/map.c
@@ -25,8 +25,8 @@ struct map *open_map(const char *fname) {
}
struct map *res = calloc(1, sizeof(struct map));
-
res->addr = addr;
+ res->end = addr + sb.st_size;
res->sb = sb;
res->fd = fd;
return res;
diff --git a/src/util/map.h b/src/util/map.h
index 232720f..67beb9c 100644
--- a/src/util/map.h
+++ b/src/util/map.h
@@ -2,6 +2,7 @@
struct map {
char *addr;
+ char *end;
struct stat sb;
int fd;
};