--- /dev/null
+// Copyright (2013) Jann Horn <jann@thejh.net>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+HEADER typedef struct {
+HEADER int width, height;
+HEADER unsigned char *data;
+HEADER int data_size;
+HEADER } pnm_image;
+
+pnm_image *read_image(char *path) {
+ int saved_errno = 0;
+
+ // prepare stuff
+ FILE *f = fopen(path, "r");
+ if (!f) return NULL;
+ pnm_image *result = malloc(sizeof(pnm_image));
+ if (!result) { saved_errno = errno; goto out_close; }
+
+ // read header
+ int line = 0;
+ int bufsize = 1024;
+ char *buf = malloc(bufsize);
+ while (line < 3) {
+ assert(fgets(buf, bufsize, f) == buf);
+ if (buf[0] == '#') continue;
+ switch (line) {
+ case 0: {
+ if (strcmp(buf, "P6\n")) {
+ saved_errno = ENOEXEC;
+ free(result);
+ goto out_freebuf;
+ }
+ break;
+ }
+ case 1: {
+ sscanf(buf, "%i %i", &result->width, &result->height);
+ result->data_size = 3 * result->width * result->height;
+ result->data = malloc(result->data_size);
+ // FIXME NULL check?
+ break;
+ }
+ case 2: {
+ if (strcmp(buf, "255\n")) {
+ saved_errno = EINVAL;
+ free(result->data);
+ free(result);
+ goto out_freebuf;
+ }
+ break;
+ }
+ default: assert(0);
+ }
+ line++;
+ }
+
+ // read pixel data
+ assert(fread(result->data, result->data_size, 1, f) == 1);
+
+ // clean up
+out_freebuf:
+ free(buf);
+out_close:
+ fclose(f);
+ if (saved_errno) errno = saved_errno;
+ return result;
+}
\ No newline at end of file