Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision f54e6ec8f379b4f45d0b911f99fb6ac3c6e9c9c5)
+++ libcfa/src/collections/string_res.cfa	(revision ff56dd2ecab3303a94714001d031262b4ca2a831)
@@ -245,4 +245,44 @@
     s = temp;
     return in;
+}
+
+void ?|?( ifstream & in, string_res & this ) {
+    (ifstream &)(in | this); ends( in );
+}
+
+ifstream & ?|?( ifstream & is, _Istream_Rstr f ) {
+ 	// .---------------,
+ 	// | | | | |...|0|0| null terminator and guard if missing
+ 	// `---------------'
+	enum { gwd = 128 + 1, wd = gwd - 1 };				// guard and unguard width
+	char cstr[gwd];										// read in chunks
+	bool cont = false;
+
+	_Istream_Cstr cf = { cstr, (_Istream_str_base)f };
+	if ( ! cf.flags.rwd ) cf.wd = wd;
+
+	cstr[wd] = '\0';									// guard null terminate string
+	try {
+		is | cf;
+	} catch( cstring_length * ) {
+		cont = true;
+	} finally {
+        if ( ! cf.flags.ignore ) *(f.s) = cstr;			// ok to initialize string
+	} // try
+	for ( ; cont; )  {									// overflow read ?
+		cont = false;
+		try {
+			is | cf;
+		} catch( cstring_length * ) {
+			cont = true;								// continue not allowed
+		} finally {
+			if ( ! cf.flags.ignore ) *(f.s) += cstr;	// build string chunk at a time
+		} // try
+	} // for
+	return is;
+} // ?|?
+
+void ?|?( ifstream & in, _Istream_Rstr f ) {
+    (ifstream &)(in | f); ends( in );
 }
 
Index: libcfa/src/collections/string_res.hfa
===================================================================
--- libcfa/src/collections/string_res.hfa	(revision f54e6ec8f379b4f45d0b911f99fb6ac3c6e9c9c5)
+++ libcfa/src/collections/string_res.hfa	(revision ff56dd2ecab3303a94714001d031262b4ca2a831)
@@ -102,4 +102,29 @@
 void ?|?(ofstream &out, const string_res &s);
 ifstream & ?|?(ifstream &in, string_res &s);
+void ?|?( ifstream & in, string_res & this );
+
+struct _Istream_Rstr {
+	string_res * s;
+	inline _Istream_str_base;
+}; // _Istream_Rstr
+
+static inline {
+	// read width does not include null terminator
+	_Istream_Rstr wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, rwd, {.flags.rwd : true}} }; }
+	_Istream_Rstr getline( string_res & s, const char delimiter = '\n' ) {
+		return (_Istream_Rstr)@{ &s, {{.delimiter : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };
+	}
+	_Istream_Rstr & getline( _Istream_Rstr & fmt, const char delimiter = '\n' ) {
+		fmt.delimiter[0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
+	}
+	_Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : false}} }; }
+	_Istream_Rstr & incl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
+	_Istream_Rstr excl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : true}} }; }
+	_Istream_Rstr & excl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
+	_Istream_Rstr ignore( string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.ignore : true}} }; }
+	_Istream_Rstr & ignore( _Istream_Rstr & fmt ) { fmt.flags.ignore = true; return fmt; }
+} // distribution
+ifstream & ?|?( ifstream & is, _Istream_Rstr f );
+void ?|?( ifstream & is, _Istream_Rstr t );
 
 // Concatenation
