+ in the interest of robustness, I added
  utility.c :: cstring_alloc()
  utility.c :: cstring_lineFromFile()	/* they're at the bottom */
  so that I could read in lines of arbitrary length from FILE*s
  (instead of using fgets(huge_ass_buffer,...)).
+ I tested it out on sort, and it seems to be fine.
diff --git a/utility.c b/utility.c
index c3a102c..42b8dc1 100644
--- a/utility.c
+++ b/utility.c
@@ -1521,6 +1521,57 @@
 }
 #endif
 
+const unsigned int CSTRING_BUFFER_LENGTH = 128;
+/* recursive parser that returns cstrings of arbitrary length
+ * from a FILE* 
+ */
+static char *
+cstring_alloc(FILE* f, int depth)
+{
+    char *cstring;
+    char buffer[CSTRING_BUFFER_LENGTH];
+    int	 target = CSTRING_BUFFER_LENGTH * depth;
+    int  i, len;
+    int  size;
+
+    /* fill buffer */
+    i = 0;
+    while ((buffer[i] = fgetc(f)) != EOF) {
+		if (buffer[i++] == 0x0a) { break; }
+		if (i == CSTRING_BUFFER_LENGTH) { break; }
+    }
+    len = i;
+
+    /* recurse or malloc? */
+    if (len == CSTRING_BUFFER_LENGTH) {
+		cstring = cstring_alloc(f, (depth + 1));
+    } else {
+		/* [special case] EOF */
+		if ((depth | len) == 0) { return NULL; }
+
+		/* malloc */
+		size = target + len + 1;
+		cstring = malloc(size);
+		if (!cstring) { return NULL; }
+		cstring[size - 1] = 0;
+    }
+
+    /* copy buffer */
+    if (cstring) {
+		memcpy(&cstring[target], buffer, len);
+    }
+    return cstring;
+}
+
+/* 
+ * wrapper around recursive cstring_alloc 
+ * it's the caller's responsibility to free the cstring
+ */ 
+char *
+cstring_lineFromFile(FILE *f)
+{
+    return cstring_alloc(f, 0);
+}
 
 /* END CODE */
 /*