diff --git a/08-writev/writev.c b/08-writev/writev.c
index ff60089..97038e6 100644
--- a/08-writev/writev.c
+++ b/08-writev/writev.c
@@ -13,8 +13,66 @@
#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
+// We define ourselves a helper structure to have a growable iovec
+// structure. If we would use C++, we could simply use std::vector.
+struct dynamic_iovec {
+ struct iovec *vec; // An heap allocated iovector
+ int count; // ... that currently contains count elements
+ int capacity; // ... that can hold up to capacity elements
+};
+
+// An initializer list to correctly initialize an dynamic_iovec instance
+#define DYNAMIC_IOVEC_INIT() {.vec = NULL, .count=0, .capacity=0}
+
+// Adds an element to our dynamic iovector. Grow it if there is not enough capacity.
+void dynamic_iovec_add(struct dynamic_iovec *vec, void* data, ssize_t len) {
+ // Resize our I/O vector if the capacity is not sufficiently
+ // large. This test also works if capacity and count are zero.
+ if ((vec->count + 1) > vec->capacity) {
+ vec->capacity = 2 * (vec->count + 1);
+ vec->vec = realloc(vec->vec, vec->capacity * sizeof(struct iovec));
+ if (!vec) die("realloc");
+ }
+
+ // Add the element to the I/O vector
+ vec->vec[vec->count].iov_base = data;
+ vec->vec[vec->count].iov_len = len;
+ vec->count++;
+}
+
int main() {
- // FIXME: Read in lines (HINT: getline(3))
- // FIXME: Shuffle lines (HINT: random(3))
- // FIXME: Dump lines with writev(2)
+ // We stack-allocate an dynamic_iovec to hold our lines.
+ // (one line = tuple of char * and length).
+ struct dynamic_iovec lines = DYNAMIC_IOVEC_INIT();
+
+ // We use getline(3) to read lines from stdin. Please consult the
+ // man page to understand the semantic of dummy!
+ ssize_t nread;
+ size_t dummy;
+ char *line;
+ while ((dummy = 0, nread = getline(&line, &dummy, stdin)) != -1) {
+ // Add the line to the dynamic vector
+ dynamic_iovec_add(&lines, line, nread);
+ }
+
+ // Initialize the random number generator with the current time
+ // with gettimeofday(2). We use the nanoseconds within this second
+ // to get some randomness as a seed for srand(3).
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_usec);
+
+ // We shuffle the I/O vector by randomly selecting another element
+ // for each line and swap those entries.
+ for (unsigned int A = 0; A < lines.count; A++) {
+ unsigned int B = random() % lines.count;
+ struct iovec tmp = lines.vec[A];
+ lines.vec[A] = lines.vec[B];
+ lines.vec[B] = tmp;
+ }
+
+ // After shuffling, we use a single system call to dump all lines
+ // in one go.
+ writev(STDOUT_FILENO, lines.vec, lines.count);
+
}