Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision 8cffa4f21ad8d447fa5f37d523e6acfb4906f3d0)
+++ libcfa/src/collections/string_res.cfa	(revision 0860d9c0c788c565776cbf08f223cede6a4d6ebc)
@@ -218,5 +218,7 @@
     // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
     // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
-    for (;;) {
+    for (bool cont = true; cont; ) {
+        cont = false;
+
         // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
         // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
@@ -228,10 +230,14 @@
         temp.Handle.ulink->EndVbyte -= 2;
 
-        // rest of heap, less 1 byte for null terminator, is available to read into
-        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte - 1;
-        assert (lenReadable >= 1);
+        // rest of heap is available to read into
+        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
+        assert (lenReadable >= 2);
 
         // get bytes
-        in | wdi( lenReadable + 1, lenReadable, temp.Handle.ulink->EndVbyte );
+        try {
+            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
+        } catch (cstring_length*) {
+            cont = true;
+        }
         int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
 
@@ -239,6 +245,4 @@
         temp.Handle.lnth += lenWasRead;
         temp.Handle.ulink->EndVbyte += lenWasRead;
-
-      if (lenWasRead < lenReadable) break;
     }
 
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 8cffa4f21ad8d447fa5f37d523e6acfb4906f3d0)
+++ libcfa/src/iostream.cfa	(revision 0860d9c0c788c565776cbf08f223cede6a4d6ebc)
@@ -22,4 +22,5 @@
 #include <float.h>										// DBL_DIG, LDBL_DIG
 #include <complex.h>									// creal, cimag
+#include <ctype.h>										// isspace
 //#include <stdio.h>
 
@@ -29,4 +30,5 @@
 extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
+extern char *strchr(const char *str, int ch);
 } // extern "C"
 
@@ -991,5 +993,12 @@
 			// wd is buffer bytes available (for input chars + null terminator)
 			// rwd is count of input chars
-			int rwd = f.flags.rwd ? f.wd : (f.wd - 1);
+			int rwd;
+			if (f.flags.rwd) {
+				verify (f.wd >= 0);
+				rwd = f.wd;
+			} else {
+				verify (f.wd >= 1);
+				rwd = f.wd - 1;
+			} // if
 			start += sprintf( &fmtstr[start], "%d", rwd );
 		}
@@ -1018,6 +1027,22 @@
 		//fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s );
 
-		if (! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) // sentinel overwritten ?
-			throw (cstring_length){ &cstring_length_vt };
+		if ( ! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) { // sentinel overwritten ?
+			// buffer filled, but would we have kept going?
+			if ( ! eof( is ) ) {
+				char peek;
+				fmt( is, "%c", &peek );
+				ungetc( is, peek );
+				bool hasMore;
+				if (f.flags.delimiter) { // getline
+					hasMore = (peek != f.delimiter[0]);
+				} else if (f.scanset) { // incl/excl
+					bool peekMatch = strchr(f.scanset, peek) != 0p;
+					hasMore = f.flags.inex ? (!peekMatch) : (peekMatch);
+				} else { // %s
+					hasMore = !isspace(peek);
+				}
+				if (hasMore) throw (cstring_length){ &cstring_length_vt };
+			} // if
+		} // if
 
 		if ( f.flags.delimiter ) {						// getline ?
