Index: tests/collections/.expect/string-istream-manip.txt
===================================================================
--- tests/collections/.expect/string-istream-manip.txt	(revision 8a33777063862817f6f9b06eedc39d326a95ca25)
+++ tests/collections/.expect/string-istream-manip.txt	(revision da227269b26a7a010962a9e91d1695f095c5d2e5)
@@ -70,4 +70,14 @@
 14 
 15 
+16 get this line
+17 @# this line 1)-{}
+18 @# this line 1)-{}
+19 abc
+20 abc  
+21  d d
+
+d 
+22 		ZC44%
+23 		ZC44%
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -85,2 +95,12 @@
 14 
 15 
+16 get this line
+17 @# this line 1)-{}
+18 @# this line 1)-{}
+19 abc
+20 abc  
+21  d d
+
+d 
+22 		ZC44%
+23 		ZC44%
Index: tests/collections/.in/string-istream-manip.txt
===================================================================
--- tests/collections/.in/string-istream-manip.txt	(revision 8a33777063862817f6f9b06eedc39d326a95ca25)
+++ tests/collections/.in/string-istream-manip.txt	(revision da227269b26a7a010962a9e91d1695f095c5d2e5)
@@ -38,4 +38,14 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwwwaaaaaaaawwwwwwww
 uuuuu
+get this line
+@# this line 1)-{}%
+@# this line 2)-{}%
+    "abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
+X		ZC55%Y
 abc 
 cccccb 
@@ -45,2 +55,12 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwwwaaaaaaaawwwwwwww
 uuuuu
+get this line
+@# this line 1)-{}%
+@# this line 2)-{}%
+    "abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
+X		ZC55%Y
Index: tests/collections/string-istream-manip.cfa
===================================================================
--- tests/collections/string-istream-manip.cfa	(revision 8a33777063862817f6f9b06eedc39d326a95ca25)
+++ tests/collections/string-istream-manip.cfa	(revision da227269b26a7a010962a9e91d1695f095c5d2e5)
@@ -10,194 +10,212 @@
 // The test cases that use plainjane(-) are exercising the via-manipulator code path,
 // just with trivial manipulation.
-static _Istream_Sstr plainjane( string     & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
+static _Istream_Sstr plainjane( string & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
 static _Istream_Rstr plainjane( string_res & s )  { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.rwd : false}} }; }
 
 static void forceStringHeapFreeSpaceTo(int desiredSize) {
-    for (1_000_000) {
-        string x = "a";
-        (void)x;
-      if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
-    }
-    sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
+	for (1_000_000) {
+		string x = "a";
+		(void)x;
+		if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
+	}
+	sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
 }
 
 int main() {
-    // These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
-    // The acceptance criterion is simpler but driving the cases is harder.
-    // The tests just read strings and echo what they read; acceptance of simple echoing assures
-    // no spurious splitting merging.
-    // The lengths of the strings are chosen to match white-box knowledge of when the string layer
-    // has tor drive the cstring layer through a second iteration:
-    //  - for no-manip, lengths are near the room at end of string heap
-    //    (chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
-    //  - for manip, lengths are near the auxiliary buffer size of 128
-    // Only first case repeats for string_res; rest run only from the passthru string layer.
-    // Similarly, the manipulator breadth isn't checked at the cstring layer either.
-    {
-        // S: string, no manipulator
-        void echoTillX(const char * casename) {
-            string s;
-            // loop assumes behaviour not tested until main-case #15:
-            // on reading nothing, the prior string value is left alone
-            do {
-                s = "";
-                forceStringHeapFreeSpaceTo(9);
-                sin | s;
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preS1");
-        echoTillX("preS2");
-        echoTillX("preS3");
-        echoTillX("preS4");
-    }
-    {
-        // SMN: string, manipulator for no-op
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | plainjane( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMN1");
-        echoTillX("preSMN2");
-        echoTillX("preSMN3");
-        echoTillX("preSMN4");
-    }
-    {
-        // RMN: string_res, manipulator for no-op
-        void echoTillX(const char * casename) {
-            string_res s;
-            do {
-                s = "";
-                sin | plainjane( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preRMN1");
-        echoTillX("preRMN2");
-        echoTillX("preRMN3");
-        echoTillX("preRMN4");
-    }
-    {
-        // SMI: string, manipulator `incl`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | skip("-\n");
-                sin | incl( ".:|# x", s );
-                sout | casename | " \"" | s | "\"";
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMI1");
-        echoTillX("preSMI2");
-        echoTillX("preSMI3");
-        echoTillX("preSMI4");
-    }
-    {
-        // SME: string, manipulator `excl`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | skip("-\n");
-                sin | excl( "-\n", s );
-                sout | casename | " \"" | s | "\"";
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSME1");
-        echoTillX("preSME2");
-        echoTillX("preSME3");
-        echoTillX("preSME4");
-    }
-    sin | skip("-\n");
-    {
-        // SMG: string, manipulator `getline`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | getline( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMG1");
-        echoTillX("preSMG2");
-        echoTillX("preSMG3");
-        echoTillX("preSMG4");
-    }
-    {
-        // SMD: string, manipulator (`getline` with custom) delimiter
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | getline( s, '@' );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-            sin | skip(" \n");
-        }
-        echoTillX("preSMD1");
-        echoTillX("preSMD2");
-        echoTillX("preSMD3");
-        echoTillX("preSMD4");
-    }
-
-    /* Keep harmonized with io/manipulatorsInput */
-    {
-        string s = "yyyyyyyyyyyyyyyyyyyy";
-        char sk[] = "abc";
-        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
-        sin | s;                                        sout | "2" | s;
-        sin | ignore( s );                              sout | "3" | s;
-        sin | wdi( 8, s );                              sout | "4" | s;
-        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
-
-        sin | incl( "abc", s );                         sout | "6" | s;
-        sin | excl( "abc", s );                         sout | "7" | s;
-        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
-        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
-        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
-        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
-        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
-        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
+	// These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
+	// The acceptance criterion is simpler but driving the cases is harder.
+	// The tests just read strings and echo what they read; acceptance of simple echoing assures
+	// no spurious splitting merging.
+	// The lengths of the strings are chosen to match white-box knowledge of when the string layer
+	// has tor drive the cstring layer through a second iteration:
+	//  - for no-manip, lengths are near the room at end of string heap
+	//	(chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
+	//  - for manip, lengths are near the auxiliary buffer size of 128
+	// Only first case repeats for string_res; rest run only from the passthru string layer.
+	// Similarly, the manipulator breadth isn't checked at the cstring layer either.
+	{
+		// S: string, no manipulator
+		void echoTillX(const char * casename) {
+			string s;
+			// loop assumes behaviour not tested until main-case #15:
+			// on reading nothing, the prior string value is left alone
+			do {
+				s = "";
+				forceStringHeapFreeSpaceTo(9);
+				sin | s;
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preS1");
+		echoTillX("preS2");
+		echoTillX("preS3");
+		echoTillX("preS4");
+	}
+	{
+		// SMN: string, manipulator for no-op
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | plainjane( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMN1");
+		echoTillX("preSMN2");
+		echoTillX("preSMN3");
+		echoTillX("preSMN4");
+	}
+	{
+		// RMN: string_res, manipulator for no-op
+		void echoTillX(const char * casename) {
+			string_res s;
+			do {
+				s = "";
+				sin | plainjane( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preRMN1");
+		echoTillX("preRMN2");
+		echoTillX("preRMN3");
+		echoTillX("preRMN4");
+	}
+	{
+		// SMI: string, manipulator `incl`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | skip("-\n");
+				sin | incl( ".:|# x", s );
+				sout | casename | " \"" | s | "\"";
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMI1");
+		echoTillX("preSMI2");
+		echoTillX("preSMI3");
+		echoTillX("preSMI4");
+	}
+	{
+		// SME: string, manipulator `excl`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | skip("-\n");
+				sin | excl( "-\n", s );
+				sout | casename | " \"" | s | "\"";
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSME1");
+		echoTillX("preSME2");
+		echoTillX("preSME3");
+		echoTillX("preSME4");
+	}
+	sin | skip("-\n");
+	{
+		// SMG: string, manipulator `getline`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | getline( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMG1");
+		echoTillX("preSMG2");
+		echoTillX("preSMG3");
+		echoTillX("preSMG4");
+	}
+	{
+		// SMD: string, manipulator (`getline` with custom) delimiter
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | getline( s, '@' );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+			sin | skip(" \n");
+		}
+		echoTillX("preSMD1");
+		echoTillX("preSMD2");
+		echoTillX("preSMD3");
+		echoTillX("preSMD4");
+	}
+	// Keep harmonized with io/manipulatorsInput.
+	{
+		string s = "yyyyyyyyyyyyyyyyyyyy";
+		char sk[] = "abc";
+		sin | "abc " | skip( sk ) | skip( 5 );			sout | "1" | s;
+		sin | s;										sout | "2" | s;
+		sin | ignore( s );								sout | "3" | s;
+		sin | wdi( 8, s );								sout | "4" | s;
+		sin | ignore( wdi( 8, s ) );					sout | "5" | s;
+
+		sin | incl( "abc", s );							sout | "6" | s;
+		sin | excl( "abc", s );							sout | "7" | s;
+		sin | ignore( incl( "abc", s ) );				sout | "8" | s;
+		sin | ignore( excl( "abc", s ) );				sout | "9" | s;
+		sin | incl( "abc", wdi( 8, s ) );				sout | "10" | s;
+		sin | excl( "abc", wdi( 8, s ) );				sout | "11" | s;
+		sin | ignore( incl( "abc", wdi( 8, s ) ) );		sout | "12" | s;
+		sin | ignore( excl( "abc", wdi( 8, s ) ) );		sout | "13" | s;
+		sin | nl;
+
+		s = "q";
+		sin | incl( "abc", s );							sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );							sout | "15" | s;
+		sin | skip( "u" ) | nl;
+
+		sin | getline( s );								sout | "16" | s;
+		sin | getline( s, '%' ) | nl;					sout | "17" | s;
+		sin | ignore( getline( s, '%' ) ) | nl;			sout | "18" | s;
+
+		sin | quoted( s );								sout | "19" | s;
+		sin | quoted( s, '\'' );						sout | "20" | s;
+		sin | quoted( s, '{', '}' );					sout | "21" | s;
+		sin | quoted( s, 'X', 'Y' );					sout | "22" | s;
+		sin | ignore( quoted( s, 'X', 'Y' ) );			sout | "23" | s;
+		sin | nl;
+	}
+	// Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
+	{
+		string_res s = "yyyyyyyyyyyyyyyyyyyy";
+		char sk[] = "abc";
+		sin | "abc " | skip( sk ) | skip( 5 );			sout | "1" | s;
+		sin | s;										sout | "2" | s;
+		sin | ignore( s );								sout | "3" | s;
+		sin | wdi( 8, s );								sout | "4" | s;
+		sin | ignore( wdi( 8, s ) );					sout | "5" | s;
+
+		sin | incl( "abc", s );							sout | "6" | s;
+		sin | excl( "abc", s );							sout | "7" | s;
+		sin | ignore( incl( "abc", s ) );				sout | "8" | s;
+		sin | ignore( excl( "abc", s ) );				sout | "9" | s;
+		sin | incl( "abc", wdi( 8, s ) );				sout | "10" | s;
+		sin | excl( "abc", wdi( 8, s ) );				sout | "11" | s;
+		sin | ignore( incl( "abc", wdi( 8, s ) ) );		sout | "12" | s;
+		sin | ignore( excl( "abc", wdi( 8, s ) ) );		sout | "13" | s;
 		sin | "\n";
 
 		s = "q";
-		sin | incl( "abc", s );                         sout | "14" | s;
-		s = "q";
-		sin | excl( "u", s );                           sout | "15" | s;
+		sin | incl( "abc", s );							sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );							sout | "15" | s;
 		sin | skip( "u" );
 		sin | "\n";
-	}
-    // Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
-    {
-        string_res s = "yyyyyyyyyyyyyyyyyyyy";
-        char sk[] = "abc";
-        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
-        sin | s;                                        sout | "2" | s;
-        sin | ignore( s );                              sout | "3" | s;
-        sin | wdi( 8, s );                              sout | "4" | s;
-        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
-
-        sin | incl( "abc", s );                         sout | "6" | s;
-        sin | excl( "abc", s );                         sout | "7" | s;
-        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
-        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
-        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
-        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
-        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
-        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
-		sin | "\n";
-
-		s = "q";
-		sin | incl( "abc", s );                         sout | "14" | s;
-		s = "q";
-		sin | excl( "u", s );                           sout | "15" | s;
-		sin | skip( "u" );
-		sin | "\n";
-    }
+		sin | getline( s );								sout | "16" | s;
+		sin | getline( s, '%' ) | nl;					sout | "17" | s;
+		sin | ignore( getline( s, '%' ) ) | nl;			sout | "18" | s;
+
+		sin | quoted( s );								sout | "19" | s;
+		sin | quoted( s, '\'' );						sout | "20" | s;
+		sin | quoted( s, '{', '}' );					sout | "21" | s;
+		sin | quoted( s, 'X', 'Y' );					sout | "22" | s;
+		sin | ignore( quoted( s, 'X', 'Y' ) );			sout | "23" | s;
+	}
 }
