Index: doc/LaTeXmacros/common.sty
===================================================================
--- doc/LaTeXmacros/common.sty	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ doc/LaTeXmacros/common.sty	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Fri Sep 29 16:48:59 2023
-%% Update Count     : 587
+%% Last Modified On : Sun Jan 14 12:28:26 2024
+%% Update Count     : 631
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -273,5 +273,6 @@
 \setlength{\columnposn}{\gcolumnposn}
 \newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn}
-\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
+\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstCommentStyle{#2}}}
+\newcommand{\CD}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstBasicStyle{#2}}}
 \newcommand{\CRT}{\global\columnposn=\gcolumnposn}
 
@@ -292,5 +293,5 @@
 xleftmargin=\parindentlnth,				% indent code to paragraph indentation
 extendedchars=true,						% allow ASCII characters in the range 128-255
-escapechar=\$,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
+escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 mathescape=false,						% disable LaTeX math escape in CFA code $...$
 keepspaces=true,						%
@@ -302,5 +303,6 @@
 % replace/adjust listing characters that look bad in sanserif
 literate=
-  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
+%  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
+  {-}{\raisebox{-1pt}{\texttt{-}}}1
   {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
@@ -308,5 +310,5 @@
   {<-}{$\leftarrow$}2
   {=>}{$\Rightarrow$}2
-  {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,
+%  {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2,
 }% lstset
 }% CFAStyle
Index: doc/LaTeXmacros/common.tex
===================================================================
--- doc/LaTeXmacros/common.tex	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ doc/LaTeXmacros/common.tex	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Fri Sep 29 16:49:02 2023
-%% Update Count     : 590
+%% Last Modified On : Sun Jan 14 17:59:02 2024
+%% Update Count     : 592
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -276,5 +276,6 @@
 \setlength{\columnposn}{\gcolumnposn}
 \newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn}
-\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
+\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstCommentStyle{#2}}}
+\newcommand{\CD}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstBasicStyle{#2}}}
 \newcommand{\CRT}{\global\columnposn=\gcolumnposn}
 
@@ -296,5 +297,5 @@
 xleftmargin=\parindentlnth,				% indent code to paragraph indentation
 extendedchars=true,						% allow ASCII characters in the range 128-255
-escapechar=\$,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
+escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 mathescape=false,						% disable LaTeX math escape in CFA code $...$
 keepspaces=true,						%
@@ -306,5 +307,6 @@
 % replace/adjust listing characters that look bad in sanserif
 literate=
-  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
+%  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
+  {-}{\raisebox{-1pt}{\texttt{-}}}1
   {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
@@ -312,5 +314,5 @@
   {<-}{$\leftarrow$}2
   {=>}{$\Rightarrow$}2
-  {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,
+%  {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2,
 }% lstset
 }% CFAStyle
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ doc/user/user.tex	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Sat Sep 30 22:46:19 2023
-%% Update Count     : 5658
+%% Last Modified On : Sun Jan 14 17:27:41 2024
+%% Update Count     : 5764
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -55,8 +55,7 @@
 \SetWatermarkLightness{0.9}
 
-% Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
-% removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
-% AFTER HYPERREF.
-\renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
+% Default underscore is too low. Cannot use lstlisting "literate" as replacing underscore removes it
+% as a variable-name character so keywords in variables are highlighted. MUST APPEAR AFTER HYPERREF.
+\renewcommand{\textunderscore}{\makebox[1.4ex][c]{{\raisebox{1.25pt}{\char`\_}}}}
 
 \setlength{\topmargin}{-0.45in}							% move running title into header
@@ -67,5 +66,5 @@
 \CFAStyle												% use default CFA format-style
 \setgcolumn{2.25in}
-%\lstset{language=CFA}									% CFA default lnaguage
+\lstset{language=CFA}									% CFA default lnaguage
 \lstnewenvironment{C++}[1][]                            % use C++ style
 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
@@ -172,6 +171,6 @@
 \begin{tabular}{@{}lll@{}}
 \multicolumn{1}{@{}c}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	& \multicolumn{1}{c@{}}{\textbf{\CC}}	\\
-\begin{cfa}[tabsize=3]
-#include <stdio.h>$\indexc{stdio.h}$
+\begin{cfa}
+#include <stdio.h>§\indexc{stdio.h}§
 
 int main( void ) {
@@ -182,14 +181,14 @@
 &
 \begin{cfa}[tabsize=3]
-#include <fstream>$\indexc{fstream}$
+#include <fstream>§\indexc{fstream}§
 
 int main( void ) {
 	int x = 0, y = 1, z = 2;
-	®sout | x | y | z;®$\indexc{sout}$
+	®sout | x | y | z;®§\indexc{sout}§
 }
 \end{cfa}
 &
 \begin{cfa}[tabsize=3]
-#include <iostream>$\indexc{iostream}$
+#include <iostream>§\indexc{iostream}§
 using namespace std;
 int main() {
@@ -260,5 +259,5 @@
 \begin{cfa}
 ®forall( T )® T identity( T val ) { return val; }
-int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$
+int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§
 \end{cfa}
 % extending the C type system with parametric polymorphism and overloading, as opposed to the \Index*[C++]{\CC{}} approach of object-oriented extensions.
@@ -288,5 +287,5 @@
 
 double key = 5.0, vals[10] = { /* 10 sorted floating values */ };
-double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); $\C{// search sorted array}$
+double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§
 \end{cfa}
 which can be augmented simply with a polymorphic, type-safe, \CFA-overloaded wrappers:
@@ -297,8 +296,8 @@
 
 forall( T | { int ?<?( T, T ); } ) unsigned int bsearch( T key, const T * arr, size_t size ) {
-	T * result = bsearch( key, arr, size ); $\C{// call first version}$
-	return result ? result - arr : size; } $\C{// pointer subtraction includes sizeof(T)}$
-
-double * val = bsearch( 5.0, vals, 10 ); $\C{// selection based on return type}$
+	T * result = bsearch( key, arr, size ); §\C{// call first version}§
+	return result ? result - arr : size; } §\C{// pointer subtraction includes sizeof(T)}§
+
+double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§
 int posn = bsearch( 5.0, vals, 10 );
 \end{cfa}
@@ -312,5 +311,5 @@
 \begin{cfa}
 forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
-int * ip = malloc(); $\C{// select type and size from left-hand side}$
+int * ip = malloc(); §\C{// select type and size from left-hand side}§
 double * dp = malloc();
 struct S {...} * sp = malloc();
@@ -324,5 +323,5 @@
 \begin{cfa}
 char ®abs®( char );
-extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$
+extern "C" { int ®abs®( int ); } §\C{// use default C routine for int}§
 long int ®abs®( long int );
 long long int ®abs®( long long int );
@@ -349,5 +348,5 @@
 The command ©cfa© is used to compile a \CFA program and is based on the \Index{GNU} \Indexc{gcc} command, \eg:
 \begin{cfa}
-cfa$\indexc{cfa}\index{compilation!cfa@©cfa©}$ [ gcc/$\CFA{}$-options ] [ C/$\CFA{}$ source-files ] [ assembler/loader files ]
+cfa§\indexc{cfa}\index{compilation!cfa@©cfa©}§ [ gcc/§\CFA{}§-options ] [ C/§\CFA{}§ source-files ] [ assembler/loader files ]
 \end{cfa}
 There is no ordering among options (flags) and files, unless an option has an argument, which must appear immediately after the option possibly with or without a space separating option and argument.
@@ -438,7 +437,7 @@
 \begin{cfa}
 #ifndef __CFORALL__
-#include <stdio.h>$\indexc{stdio.h}$ $\C{// C header file}$
+#include <stdio.h>§\indexc{stdio.h}§ §\C{// C header file}§
 #else
-#include <fstream>$\indexc{fstream}$ $\C{// \CFA header file}$
+#include <fstream>§\indexc{fstream}§ §\C{// \CFA header file}§
 #endif
 \end{cfa}
@@ -450,10 +449,10 @@
 Each option must be escaped with \Indexc{-XCFA}\index{translator option!-XCFA@{©-XCFA©}} to direct it to the compiler step, similar to the ©-Xlinker© flag for the linker, \eg:
 \begin{lstlisting}[language=sh]
-cfa $test$.cfa -CFA -XCFA -p # print translated code without printing the standard prelude
-cfa $test$.cfa -XCFA -P -XCFA parse -XCFA -n # show program parse without prelude
+cfa §test§.cfa -CFA -XCFA -p # print translated code without printing the standard prelude
+cfa §test§.cfa -XCFA -P -XCFA parse -XCFA -n # show program parse without prelude
 \end{lstlisting}
-Alternatively, multiple flages can be specified separated with commas and \emph{without} spaces.
+Alternatively, multiple flags can be specified separated with commas and \emph{without} spaces.
 \begin{lstlisting}[language=sh,{moredelim=**[is][\protect\color{red}]{®}{®}}]
-cfa $test$.cfa -XCFA®,®-Pparse®,®-n # show program parse without prelude
+cfa §test§.cfa -XCFA®,®-Pparse®,®-n # show program parse without prelude
 \end{lstlisting}
 \begin{description}[topsep=5pt,itemsep=0pt,parsep=0pt]
@@ -537,5 +536,5 @@
 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
 \begin{cfa}
-int ®``®coroutine = 3;					$\C{// make keyword an identifier}$
+int ®``®coroutine = 3;					§\C{// make keyword an identifier}§
 double ®``®forall = 3.5;
 \end{cfa}
@@ -547,10 +546,10 @@
 \begin{cfa}
 // include file uses the CFA keyword "with".
-#if ! defined( with )					$\C{// nesting ?}$
-#define with ®``®with					$\C{// make keyword an identifier}$
+#if ! defined( with )					§\C{// nesting ?}§
+#define with ®``®with					§\C{// make keyword an identifier}§
 #define __CFA_BFD_H__
 #endif
-$\R{\#include\_next} <bfdlink.h>$		$\C{// must have internal check for multiple expansion}$
-#if defined( with ) && defined( __CFA_BFD_H__ )	$\C{// reset only if set}$
+§\R{\#include\_next} <bfdlink.h>§		§\C{// must have internal check for multiple expansion}§
+#if defined( with ) && defined( __CFA_BFD_H__ )	§\C{// reset only if set}§
 #undef with
 #undef __CFA_BFD_H__
@@ -566,14 +565,14 @@
 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg:
 \begin{cfa}
-2®_®147®_®483®_®648;					$\C{// decimal constant}$
-56®_®ul;								$\C{// decimal unsigned long constant}$
-0®_®377;								$\C{// octal constant}$
-0x®_®ff®_®ff;							$\C{// hexadecimal constant}$
-0x®_®ef3d®_®aa5c;						$\C{// hexadecimal constant}$
-3.141®_®592®_®654;						$\C{// floating constant}$
-10®_®e®_®+1®_®00;					 	$\C{// floating constant}$
-0x®_®ff®_®ff®_®p®_®3;					$\C{// hexadecimal floating}$
-0x®_®1.ffff®_®ffff®_®p®_®128®_®l;		$\C{// hexadecimal floating long constant}$
-L®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$
+2®_®147®_®483®_®648;					§\C{// decimal constant}§
+56®_®ul;								§\C{// decimal unsigned long constant}§
+0®_®377;								§\C{// octal constant}§
+0x®_®ff®_®ff;							§\C{// hexadecimal constant}§
+0x®_®ef3d®_®aa5c;						§\C{// hexadecimal constant}§
+3.141®_®592®_®654;						§\C{// floating constant}§
+10®_®e®_®+1®_®00;					 	§\C{// floating constant}§
+0x®_®ff®_®ff®_®p®_®3;					§\C{// hexadecimal floating}§
+0x®_®1.ffff®_®ffff®_®p®_®128®_®l;		§\C{// hexadecimal floating long constant}§
+L®_®§"\texttt{\textbackslash{x}}§®_®§\texttt{ff}§®_®§\texttt{ee}"§; §\C{// wide character constant}§
 \end{cfa}
 The rules for placement of underscores are:
@@ -635,13 +634,13 @@
 Declarations in the \Indexc{do}-©while© condition are not useful because they appear after the loop body.}
 \begin{cfa}
-if ( ®int x = f()® ) ...			$\C{// x != 0}$
-if ( ®int x = f(), y = g()® ) ...	$\C{// x != 0 \&\& y != 0}$
-if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
-if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$
-
-while ( ®int x = f()® ) ...			$\C{// x != 0}$
-while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
-while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
-while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... $\C{// relational expression}$
+if ( ®int x = f()® ) ...			§\C{// x != 0}§
+if ( ®int x = f(), y = g()® ) ...	§\C{// x != 0 \&\& y != 0}§
+if ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§
+if ( ®struct S { int i; } x = { f() }; x.i < 4® ) §\C{// relational expression}§
+
+while ( ®int x = f()® ) ...			§\C{// x != 0}§
+while ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§
+while ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§
+while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... §\C{// relational expression}§
 \end{cfa}
 Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical \Indexc{&&} operator.
@@ -713,7 +712,7 @@
 \begin{cfa}
 switch ( i ) {
-  case 1$\R{\textvisiblespace}$®...®4:
+  case 1§\R{\textvisiblespace}§®...®4:
 	...
-  case 10$\R{\textvisiblespace}$®...®13:
+  case 10§\R{\textvisiblespace}§®...®13:
 	...
 }
@@ -752,5 +751,5 @@
   case 1:
 	...
-	$\R{\LstCommentStyle{// fall-through}}$
+	§\R{\LstCommentStyle{// fall-through}}§
   case 2:
 	...
@@ -853,12 +852,12 @@
 \begin{cfa}
 switch ( x ) {
-	®int y = 1;® $\C{// unreachable initialization}$
-	®x = 7;® $\C{// unreachable code without label/branch}$
+	®int y = 1;® §\C{// unreachable initialization}§
+	®x = 7;® §\C{// unreachable code without label/branch}§
   case 0: ...
 	...
-	®int z = 0;® $\C{// unreachable initialization, cannot appear after case}$
+	®int z = 0;® §\C{// unreachable initialization, cannot appear after case}§
 	z = 2;
   case 1:
-	®x = z;® $\C{// without fall through, z is uninitialized}$
+	®x = z;® §\C{// without fall through, z is uninitialized}§
 }
 \end{cfa}
@@ -895,11 +894,11 @@
   case 1:  case 2:  case 3:
 	...
-	$\R{\LstCommentStyle{// implicit end of switch (break)}}$
+	§\R{\LstCommentStyle{// implicit end of switch (break)}}§
   case 5:
 	...
-	®fallthru®; $\C{// explicit fall through}$
+	®fallthru®; §\C{// explicit fall through}§
   case 7:
 	...
-	®break® $\C{// explicit end of switch (redundant)}$
+	®break® §\C{// explicit end of switch (redundant)}§
   default:
 	j = 3;
@@ -922,13 +921,13 @@
 \begin{cfa}
 switch ( x ) {
-	®int i = 0;®						$\C{// allowed only at start}$
+	®int i = 0;®						§\C{// allowed only at start}§
   case 0:
 	...
-	®int j = 0;®						$\C{// disallowed}$
+	®int j = 0;®						§\C{// disallowed}§
   case 1:
 	{
-		®int k = 0;®					$\C{// allowed at different nesting levels}$
+		®int k = 0;®					§\C{// allowed at different nesting levels}§
 		...
-	  ®case 2:®							$\C{// disallow case in nested statements}$
+	  ®case 2:®							§\C{// disallow case in nested statements}§
 	}
   ...
@@ -1004,47 +1003,47 @@
 while () { sout | "empty"; break; }
 do { sout | "empty"; break; } while ();
-for () { sout | "empty"; break; }							$\C[3in]{sout | nl | nlOff;}$
-
-for ( 0 ) { sout | "A"; } sout | "zero";					$\C{sout | nl;}$
-for ( 1 ) { sout | "A"; }									$\C{sout | nl;}$
-for ( 10 ) { sout | "A"; }									$\C{sout | nl;}$
-for ( ~= 10 ) { sout | "A"; }								$\C{sout | nl;}$
-for ( 1 ~= 10 ~ 2 ) { sout | "B"; }							$\C{sout | nl;}$
-for ( 1 -~= 10 ~ 2 ) { sout | "C"; }						$\C{sout | nl;}$
-for ( 0.5 ~ 5.5 ) { sout | "D"; }							$\C{sout | nl;}$
-for ( 0.5 -~ 5.5 ) { sout | "E"; }							$\C{sout | nl;}$
-for ( i; 10 ) { sout | i; }									$\C{sout | nl;}$
-for ( i; ~= 10 ) { sout | i; }								$\C{sout | nl;}$
-for ( i; 1 ~= 10 ~ 2 ) { sout | i; }						$\C{sout | nl;}$
-for ( i; 1 -~= 10 ~ 2 ) { sout | i; }						$\C{sout | nl;}$
-for ( i; 0.5 ~ 5.5 ) { sout | i; }							$\C{sout | nl;}$
-for ( i; 0.5 -~ 5.5 ) { sout | i; }							$\C{sout | nl;}$
-for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }					$\C{sout | nl;}$
-for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }					$\C{sout | nl | nl | nl;}$
+for () { sout | "empty"; break; }							§\C[3in]{sout | nl | nlOff;}§
+
+for ( 0 ) { sout | "A"; } sout | "zero";					§\C{sout | nl;}§
+for ( 1 ) { sout | "A"; }									§\C{sout | nl;}§
+for ( 10 ) { sout | "A"; }									§\C{sout | nl;}§
+for ( ~= 10 ) { sout | "A"; }								§\C{sout | nl;}§
+for ( 1 ~= 10 ~ 2 ) { sout | "B"; }							§\C{sout | nl;}§
+for ( 1 -~= 10 ~ 2 ) { sout | "C"; }						§\C{sout | nl;}§
+for ( 0.5 ~ 5.5 ) { sout | "D"; }							§\C{sout | nl;}§
+for ( 0.5 -~ 5.5 ) { sout | "E"; }							§\C{sout | nl;}§
+for ( i; 10 ) { sout | i; }									§\C{sout | nl;}§
+for ( i; ~= 10 ) { sout | i; }								§\C{sout | nl;}§
+for ( i; 1 ~= 10 ~ 2 ) { sout | i; }						§\C{sout | nl;}§
+for ( i; 1 -~= 10 ~ 2 ) { sout | i; }						§\C{sout | nl;}§
+for ( i; 0.5 ~ 5.5 ) { sout | i; }							§\C{sout | nl;}§
+for ( i; 0.5 -~ 5.5 ) { sout | i; }							§\C{sout | nl;}§
+for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }					§\C{sout | nl;}§
+for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }					§\C{sout | nl | nl | nl;}§
 
 enum { N = 10 };
-for ( N ) { sout | "N"; }									$\C{sout | nl;}$
-for ( i; N ) { sout | i; }									$\C{sout | nl;}$
-for ( i; -~ N ) { sout | i; }								$\C{sout | nl | nl | nl;}$
+for ( N ) { sout | "N"; }									§\C{sout | nl;}§
+for ( i; N ) { sout | i; }									§\C{sout | nl;}§
+for ( i; -~ N ) { sout | i; }								§\C{sout | nl | nl | nl;}§
 
 const int low = 3, high = 10, inc = 2;
-for ( i; low ~ high ~ inc + 1 ) { sout | i; }				$\C{sout | nl;}$
-for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; }			$\C{sout | nl;}$
-for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; }		$\C{sout | nl;}$
-for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; }		$\C{sout | nl;}$
-for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } $\C{sout | nl;}$
-for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; }	$\C{sout | nl;}$
-for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } $\C{sout | nl;}$
-for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					$\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					$\C{sout | nl;}$
-for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				$\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				$\C{sout | nl;}$
-for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					$\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					$\C{sout | nl;}$
-for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				$\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				$\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } $\C{sout | nl;}$
-for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } $\C{sout | nl;}$
-for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } $\C{sout | nl;}\CRT$
+for ( i; low ~ high ~ inc + 1 ) { sout | i; }				§\C{sout | nl;}§
+for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; }			§\C{sout | nl;}§
+for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; }		§\C{sout | nl;}§
+for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; }		§\C{sout | nl;}§
+for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } §\C{sout | nl;}§
+for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; }	§\C{sout | nl;}§
+for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } §\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }					§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }					§\C{sout | nl;}§
+for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }				§\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
+for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
+for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§
 \end{cfa}
 &
@@ -1117,7 +1116,7 @@
 The \Indexc{for}, \Indexc{while}, and \Indexc{do} loop-control allow an empty conditional, which implies a comparison value of ©1© (true).
 \begin{cfa}
-while ( ®/* empty */®  )				$\C{// while ( true )}$
-for ( ®/* empty */®  )					$\C{// for ( ; true; )}$
-do ... while ( ®/* empty */®  )			$\C{// do ... while ( true )}$
+while ( ®/* empty */®  )				§\C{// while ( true )}§
+for ( ®/* empty */®  )					§\C{// for ( ; true; )}§
+do ... while ( ®/* empty */®  )			§\C{// do ... while ( true )}§
 \end{cfa}
 
@@ -1149,7 +1148,7 @@
 If no type is specified for the loop index, it is the type of the high value H (when the low value is implicit) or the low value L.
 \begin{cfa}
-for ( ®5® )								$\C{// typeof(5) anonymous-index; 5 is high value}$
-for ( i; ®1.5® ~ 5.5 )					$\C{// typeof(1.5) i; 1.5 is low value}$
-for ( ®int i®; 0 ~ 10 ~ 2 )				$\C{// int i; type is explicit}$
+for ( ®5® )								§\C{// typeof(5) anonymous-index; 5 is high value}§
+for ( i; ®1.5® ~ 5.5 )					§\C{// typeof(1.5) i; 1.5 is low value}§
+for ( ®int i®; 0 ~ 10 ~ 2 )				§\C{// int i; type is explicit}§
 \end{cfa}
 
@@ -1159,37 +1158,37 @@
 H is implicit up-to exclusive range [0,H\R{)}.
 \begin{cfa}
-for ( ®5® )								$\C{// for ( typeof(5) i; i < 5; i += 1 )}$
+for ( ®5® )								§\C{// for ( typeof(5) i; i < 5; i += 1 )}§
 \end{cfa}
 \item
 ©~=© H is implicit up-to inclusive range [0,H\R{]}.
 \begin{cfa}
-for ( ®~=® 5 )							$\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
+for ( ®~=® 5 )							§\C{// for ( typeof(5) i; i <= 5; i += 1 )}§
 \end{cfa}
 \item
 L ©~©\index{~@©~©} H is explicit up-to exclusive range [L,H\R{)}.
 \begin{cfa}
-for ( 1 ®~® 5 )							$\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
+for ( 1 ®~® 5 )							§\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}§
 \end{cfa}
 \item
 L ©~=©\index{~=@©~=©} H is explicit up-to inclusive range [L,H\R{]}.
 \begin{cfa}
-for ( 1 ®~=® 5 )						$\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
+for ( 1 ®~=® 5 )						§\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}§
 \end{cfa}
 \item
 L ©-~©\index{-~@©-~©} H is explicit down-to exclusive range [H,L\R{)}, where L and H are implicitly interchanged to make the range down-to.
 \begin{cfa}
-for ( 1 ®-~® 5 )						$\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
+for ( 1 ®-~® 5 )						§\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}§
 \end{cfa}
 \item
 L ©-~=©\index{-~=@©-~=©} H is explicit down-to inclusive range [H,L\R{]}, where L and H are implicitly interchanged to make the range down-to.
 \begin{cfa}
-for ( 1 ®-~=® 5 )						$\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
+for ( 1 ®-~=® 5 )						§\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}§
 \end{cfa}
 \item
 ©@© means put nothing in this field.
 \begin{cfa}
-for ( i; 1 ~ ®@® ~ 2 )					$\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}$
-for ( i; 1 ~ 10 ~ ®@® )					$\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}$
-for ( i; 1 ~ ®@® ~ ®@® )				$\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}$
+for ( i; 1 ~ ®@® ~ 2 )					§\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}§
+for ( i; 1 ~ 10 ~ ®@® )					§\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}§
+for ( i; 1 ~ ®@® ~ ®@® )				§\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}§
 \end{cfa}
 L cannot be elided for the up-to range, \lstinline{@ ~ 5}, and H for the down-to range, \lstinline{1 -~ @}, because then the loop index is uninitialized.
@@ -1198,12 +1197,12 @@
 ©:© means low another index.
 \begin{cfa}
-for ( i; 5 ®:® j; 2 ~ 12 ~ 3 )			$\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}$
+for ( i; 5 ®:® j; 2 ~ 12 ~ 3 )			§\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}§
 \end{cfa}
 \end{itemize}
 \R{Warning}: specifying the down-to range maybe unexpected because the loop control \emph{implicitly} switches the L and H values (and toggles the increment/decrement for I):
 \begin{cfa}
-for ( i; 1 ~ 10 )						${\C{// up range}$
-for ( i; 1 -~ 10 )						${\C{// down range}$
-for ( i; ®10 -~ 1® )					${\C{// \R{WRONG down range!}}}$
+for ( i; 1 ~ 10 )						§{\C{// up range}§
+for ( i; 1 -~ 10 )						§{\C{// down range}§
+for ( i; ®10 -~ 1® )					§{\C{// \R{WRONG down range!}}}§
 \end{cfa}
 The reason for this semantics is that the range direction can be toggled by adding/removing the minus, ©'-'©, versus interchanging the L and H expressions, which has a greater chance of introducing errors.
@@ -1361,9 +1360,9 @@
 Grouping heterogeneous data into an \newterm{aggregate} (structure/union) is a common programming practice, and aggregates may be nested:
 \begin{cfa}
-struct Person {							$\C{// aggregate}$
-	struct Name {						$\C{// nesting}$
+struct Person {							§\C{// aggregate}§
+	struct Name {						§\C{// nesting}§
 		char first[20], last[20];
 	} name;
-	struct Address {					$\C{// nesting}$
+	struct Address {					§\C{// nesting}§
 		...
 	} address;
@@ -1374,11 +1373,11 @@
 \begin{cfa}
 Person p
-®p.®name; ®p.®address; ®p.®sex;			$\C{// access containing fields}$
+®p.®name; ®p.®address; ®p.®sex;			§\C{// access containing fields}§
 \end{cfa}
 which extends to multiple levels of qualification for nested aggregates and multiple aggregates.
 \begin{cfa}
 struct Ticket { ... } t;
-®p.name®.first; ®p.address®.street;		$\C{// access nested fields}$
-®t.®departure; ®t.®cost;				$\C{// access multiple aggregate}$
+®p.name®.first; ®p.address®.street;		§\C{// access nested fields}§
+®t.®departure; ®t.®cost;				§\C{// access multiple aggregate}§
 \end{cfa}
 Repeated aggregate qualification is tedious and makes code difficult to read.
@@ -1389,7 +1388,7 @@
 \begin{cfa}
 struct S {
-	struct $\R{\LstCommentStyle{/* unnamed */}}$  { int g,  h; } __attribute__(( aligned(64) ));
+	struct §\R{\LstCommentStyle{/* unnamed */}}§  { int g,  h; } __attribute__(( aligned(64) ));
 	int tag;
-	union $\R{\LstCommentStyle{/* unnamed */}}$  {
+	union §\R{\LstCommentStyle{/* unnamed */}}§  {
 		struct { char c1,  c2; } __attribute__(( aligned(128) ));
 		struct { int i1,  i2; };
@@ -1405,6 +1404,6 @@
 struct S {
 	char ®c®;   int ®i®;   double ®d®;
-	void f( /* S * this */ ) {			$\C{// implicit ``this'' parameter}$
-		®c®;   ®i®;   ®d®;				$\C{// this->c; this->i; this->d;}$
+	void f( /* S * this */ ) {			§\C{// implicit ``this'' parameter}§
+		®c®;   ®i®;   ®d®;				§\C{// this->c; this->i; this->d;}§
 	}
 }
@@ -1414,12 +1413,12 @@
 \begin{cfa}
 struct T {
-	char ®m®;   int ®i®;   double ®n®;	$\C{// derived class variables}$
+	char ®m®;   int ®i®;   double ®n®;	§\C{// derived class variables}§
 };
 struct S : public T {
-	char ®c®;   int ®i®;   double ®d®;	$\C{// class variables}$
+	char ®c®;   int ®i®;   double ®d®;	§\C{// class variables}§
 	void g( double ®d®, T & t ) {
-		d;   ®t®.m;   ®t®.i;   ®t®.n;	$\C{// function parameter}$
-		c;   i;   ®this->®d;   ®S::®d;	$\C{// class S variables}$
-		m;   ®T::®i;   n;				$\C{// class T variables}$
+		d;   ®t®.m;   ®t®.i;   ®t®.n;	§\C{// function parameter}§
+		c;   i;   ®this->®d;   ®S::®d;	§\C{// class S variables}§
+		m;   ®T::®i;   n;				§\C{// class T variables}§
 	}
 };
@@ -1431,13 +1430,13 @@
 Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block.
 \begin{cfa}
-void f( S & this ) ®with ( this )® {	$\C{// with statement}$
-	®c®;   ®i®;   ®d®;					$\C{// this.c, this.i, this.d}$
+void f( S & this ) ®with ( this )® {	§\C{// with statement}§
+	®c®;   ®i®;   ®d®;					§\C{// this.c, this.i, this.d}§
 }
 \end{cfa}
 with the generality of opening multiple aggregate-parameters:
 \begin{cfa}
-void g( S & s, T & t ) ®with ( s, t )® {$\C{// multiple aggregate parameters}$
-	c;   ®s.®i;   d;					$\C{// s.c, s.i, s.d}$
-	m;   ®t.®i;   n;					$\C{// t.m, t.i, t.n}$
+void g( S & s, T & t ) ®with ( s, t )® {§\C{// multiple aggregate parameters}§
+	c;   ®s.®i;   d;					§\C{// s.c, s.i, s.d}§
+	m;   ®t.®i;   n;					§\C{// t.m, t.i, t.n}§
 }
 \end{cfa}
@@ -1462,11 +1461,11 @@
 struct R { int ®i®; int j; double ®m®; } r, w;
 with ( r, q ) {
-	j + k;								$\C{// unambiguous, r.j + q.k}$
-	m = 5.0;							$\C{// unambiguous, q.m = 5.0}$
-	m = 1;								$\C{// unambiguous, r.m = 1}$
-	int a = m;							$\C{// unambiguous, a = r.i }$
-	double b = m;						$\C{// unambiguous, b = q.m}$
-	int c = r.i + q.i;					$\C{// disambiguate with qualification}$
-	(double)m;							$\C{// disambiguate with cast}$
+	j + k;								§\C{// unambiguous, r.j + q.k}§
+	m = 5.0;							§\C{// unambiguous, q.m = 5.0}§
+	m = 1;								§\C{// unambiguous, r.m = 1}§
+	int a = m;							§\C{// unambiguous, a = r.i }§
+	double b = m;						§\C{// unambiguous, b = q.m}§
+	int c = r.i + q.i;					§\C{// disambiguate with qualification}§
+	(double)m;							§\C{// disambiguate with cast}§
 }
 \end{cfa}
@@ -1476,7 +1475,7 @@
 \begin{cfa}
 with ( r ) {
-	i;									$\C{// unambiguous, r.i}$
+	i;									§\C{// unambiguous, r.i}§
 	with ( q ) {
-		i;								$\C{// unambiguous, q.i}$
+		i;								§\C{// unambiguous, q.i}§
 	}
 }
@@ -1485,6 +1484,6 @@
 A cast can also be used to disambiguate among overload variables in a ©with© \emph{expression}:
 \begin{cfa}
-with ( w ) { ... }						$\C{// ambiguous, same name and no context}$
-with ( (Q)w ) { ... }					$\C{// unambiguous, cast}$
+with ( w ) { ... }						§\C{// ambiguous, same name and no context}§
+with ( (Q)w ) { ... }					§\C{// unambiguous, cast}§
 \end{cfa}
 Because there is no left-side in the ©with© expression to implicitly disambiguate between the ©w© variables, it is necessary to explicitly disambiguate by casting ©w© to type ©Q© or ©R©.
@@ -1493,5 +1492,5 @@
 \begin{cfa}
 void f( S & s, char c ) with ( s ) {
-	®s.c = c;®  i = 3;  d = 5.5;		$\C{// initialize fields}$
+	®s.c = c;®  i = 3;  d = 5.5;		§\C{// initialize fields}§
 }
 \end{cfa}
@@ -1499,5 +1498,5 @@
 To solve this problem, parameters \emph{not} explicitly opened are treated like an initialized aggregate:
 \begin{cfa}
-struct Params {							$\C{// s explicitly opened so S \& s elided}$
+struct Params {							§\C{// s explicitly opened so S \& s elided}§
 	char c;
 } params;
@@ -1505,5 +1504,5 @@
 and implicitly opened \emph{after} a function-body open, to give them higher priority:
 \begin{cfa}
-void f( S & s, char ®c® ) with ( s ) ®with( $\emph{\R{params}}$ )® { // syntax not allowed, illustration only
+void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax not allowed, illustration only
 	s.c = ®c;®  i = 3;  d = 5.5;
 }
@@ -1538,14 +1537,14 @@
 
 \begin{cfa}
-exception_t E {}; $\C{// exception type}$
+exception_t E {}; §\C{// exception type}§
 void f(...) {
-	... throw E{}; ... $\C{// termination}$
-	... throwResume E{}; ... $\C{// resumption}$
+	... throw E{}; ... §\C{// termination}§
+	... throwResume E{}; ... §\C{// resumption}§
 }
 try {
 	f(...);
-} catch( E e ; $boolean-predicate$ ) {	$\C{// termination handler}$
+} catch( E e ; §boolean-predicate§ ) {	§\C{// termination handler}§
 	// recover and continue
-} catchResume( E e ; $boolean-predicate$ ) { $\C{// resumption handler}$
+} catchResume( E e ; §boolean-predicate§ ) { §\C{// resumption handler}§
 	// repair and return
 } finally {
@@ -1624,6 +1623,6 @@
 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
 \begin{cfa}
-int ®(*®f®())[®5®]® {...}; $\C{// definition}$
- ... ®(*®f®())[®3®]® += 1; $\C{// usage}$
+int ®(*®f®())[®5®]® {...}; §\C{// definition}§
+ ... ®(*®f®())[®3®]® += 1; §\C{// usage}§
 \end{cfa}
 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
@@ -1870,5 +1869,5 @@
 For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage
 \begin{cfa}
-p2 = p1 + x; $\C{// compiler infers *p2 = *p1 + x;}$
+p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§
 \end{cfa}
 Algol68 infers the following dereferencing ©*p2 = *p1 + x©, because adding the arbitrary integer value in ©x© to the address of ©p1© and storing the resulting address into ©p2© is an unlikely operation.
@@ -1878,11 +1877,11 @@
 In C, objects of pointer type always manipulate the pointer object's address:
 \begin{cfa}
-p1 = p2; $\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}$
-p2 = p1 + x; $\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}$
+p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§
+p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§
 \end{cfa}
 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant:
 \begin{cfa}
-p1 = p2; $\C{// pointer address assignment}$
-®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$
+p1 = p2; §\C{// pointer address assignment}§
+®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§
 \end{cfa}
 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
@@ -1901,9 +1900,9 @@
 \begin{cfa}
 int x, y, ®&® r1, ®&® r2, ®&&® r3;
-®&®r1 = &x; $\C{// r1 points to x}$
-®&®r2 = &r1; $\C{// r2 points to x}$
-®&®r1 = &y; $\C{// r1 points to y}$
-®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$
-r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$
+®&®r1 = &x; §\C{// r1 points to x}§
+®&®r2 = &r1; §\C{// r2 points to x}§
+®&®r1 = &y; §\C{// r1 points to y}§
+®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§
+r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§
 \end{cfa}
 Except for auto-dereferencing by the compiler, this reference example is the same as the previous pointer example.
@@ -1920,9 +1919,9 @@
 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
 \begin{cfa}
-(&®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$
+(&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§
 \end{cfa}
 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
 \begin{cfa}
-(&(&®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$
+(&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§
 \end{cfa}
 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
@@ -1932,11 +1931,11 @@
 int x, *p1 = &x, **p2 = &p1, ***p3 = &p2,
 		 &r1 = x,    &&r2 = r1,   &&&r3 = r2;
-***p3 = 3; $\C{// change x}$
-r3 = 3; $\C{// change x, ***r3}$
-**p3 = ...; $\C{// change p1}$
-&r3 = ...; $\C{// change r1, (\&*)**r3, 1 cancellation}$
-*p3 = ...; $\C{// change p2}$
-&&r3 = ...; $\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}$
-&&&r3 = p3; $\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}$
+***p3 = 3; §\C{// change x}§
+r3 = 3; §\C{// change x, ***r3}§
+**p3 = ...; §\C{// change p1}§
+&r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§
+*p3 = ...; §\C{// change p2}§
+&&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§
+&&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§
 \end{cfa}
 Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types.
@@ -1945,17 +1944,17 @@
 As for a pointer type, a reference type may have qualifiers:
 \begin{cfa}
-const int cx = 5; $\C{// cannot change cx;}$
-const int & cr = cx; $\C{// cannot change what cr points to}$
-®&®cr = &cx; $\C{// can change cr}$
-cr = 7; $\C{// error, cannot change cx}$
-int & const rc = x; $\C{// must be initialized}$
-®&®rc = &x; $\C{// error, cannot change rc}$
-const int & const crc = cx; $\C{// must be initialized}$
-crc = 7; $\C{// error, cannot change cx}$
-®&®crc = &cx; $\C{// error, cannot change crc}$
+const int cx = 5; §\C{// cannot change cx;}§
+const int & cr = cx; §\C{// cannot change what cr points to}§
+®&®cr = &cx; §\C{// can change cr}§
+cr = 7; §\C{// error, cannot change cx}§
+int & const rc = x; §\C{// must be initialized}§
+®&®rc = &x; §\C{// error, cannot change rc}§
+const int & const crc = cx; §\C{// must be initialized}§
+crc = 7; §\C{// error, cannot change cx}§
+®&®crc = &cx; §\C{// error, cannot change crc}§
 \end{cfa}
 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:
 \begin{cfa}
-int & const cr = *0; $\C{// where 0 is the int * zero}$
+int & const cr = *0; §\C{// where 0 is the int * zero}§
 \end{cfa}
 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management:
@@ -1964,5 +1963,5 @@
 cr = 5;
 free( &cr );
-cr = 7; $\C{// unsound pointer dereference}$
+cr = 7; §\C{// unsound pointer dereference}§
 \end{cfa}
 
@@ -1972,5 +1971,5 @@
 \begin{cquote}
 \begin{tabular}{@{}l@{\hspace{3em}}l@{}}
-\multicolumn{1}{c@{\hspace{3em}}}{\textbf{Cy}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
+\multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}}	& \multicolumn{1}{c}{\textbf{\CFA}}	\\
 \begin{cfa}
 const int * ®const® * ®const® ccp;
@@ -1988,10 +1987,10 @@
 Finally, like pointers, references are usable and composable with other type operators and generators.
 \begin{cfa}
-int w, x, y, z, & ar[3] = { x, y, z }; $\C{// initialize array of references}$
-&ar[1] = &w; $\C{// change reference array element}$
-typeof( ar[1] ) p; $\C{// (gcc) is int, \ie the type of referenced object}$
-typeof( &ar[1] ) q; $\C{// (gcc) is int \&, \ie the type of reference}$
-sizeof( ar[1] ) == sizeof( int ); $\C{// is true, \ie the size of referenced object}$
-sizeof( &ar[1] ) == sizeof( int *) $\C{// is true, \ie the size of a reference}$
+int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§
+&ar[1] = &w; §\C{// change reference array element}§
+typeof( ar[1] ) p; §\C{// (gcc) is int, \ie the type of referenced object}§
+typeof( &ar[1] ) q; §\C{// (gcc) is int \&, \ie the type of reference}§
+sizeof( ar[1] ) == sizeof( int ); §\C{// is true, \ie the size of referenced object}§
+sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, \ie the size of a reference}§
 \end{cfa}
 
@@ -2010,7 +2009,7 @@
 Therefore, for pointer/reference initialization, the initializing value must be an address not a value.
 \begin{cfa}
-int * p = &x; $\C{// assign address of x}$
-®int * p = x;® $\C{// assign value of x}$
-int & r = x; $\C{// must have address of x}$
+int * p = &x;				§\C{// assign address of x}§
+®int * p = x;®				§\C{// assign value of x}§
+int & r = x;				§\C{// must have address of x}§
 \end{cfa}
 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given).
@@ -2021,6 +2020,6 @@
 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason.
 \begin{cfa}
-int & f( int & r ); $\C{// reference parameter and return}$
-z = f( x ) + f( y ); $\C{// reference operator added, temporaries needed for call results}$
+int & f( int & r );			§\C{// reference parameter and return}§
+z = f( x ) + f( y );		§\C{// reference operator added, temporaries needed for call results}§
 \end{cfa}
 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©.
@@ -2049,6 +2048,6 @@
 void f( int & r );
 void g( int * p );
-f( 3 );			  g( ®&®3 ); $\C{// compiler implicit generates temporaries}$
-f( x + y );		g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$
+f( 3 );			  g( ®&®3 ); §\C{// compiler implicit generates temporaries}§
+f( x + y );		g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§
 \end{cfa}
 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
@@ -2061,19 +2060,19 @@
 \begin{cfa}
 void f( int i );
-void (* fp)( int ); $\C{// routine pointer}$
-fp = f; $\C{// reference initialization}$
-fp = &f; $\C{// pointer initialization}$
-fp = *f; $\C{// reference initialization}$
-fp(3); $\C{// reference invocation}$
-(*fp)(3); $\C{// pointer invocation}$
+void (* fp)( int );			§\C{// routine pointer}§
+fp = f;						§\C{// reference initialization}§
+fp = &f;					§\C{// pointer initialization}§
+fp = *f;					§\C{// reference initialization}§
+fp(3);						§\C{// reference invocation}§
+(*fp)(3);					§\C{// pointer invocation}§
 \end{cfa}
 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type.
 Instead, a routine object should be referenced by a ©const© reference:
 \begin{cfa}
-®const® void (®&® fr)( int ) = f; $\C{// routine reference}$
-fr = ... $\C{// error, cannot change code}$
-&fr = ...; $\C{// changing routine reference}$
-fr( 3 ); $\C{// reference call to f}$
-(*fr)(3); $\C{// error, incorrect type}$
+®const® void (®&® fr)( int ) = f; §\C{// routine reference}§
+fr = ...;					§\C{// error, cannot change code}§
+&fr = ...;					§\C{// changing routine reference}§
+fr( 3 );					§\C{// reference call to f}§
+(*fr)(3);					§\C{// error, incorrect type}§
 \end{cfa}
 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{
@@ -2097,9 +2096,9 @@
 int x, * px, ** ppx, *** pppx, **** ppppx;
 int & rx = x, && rrx = rx, &&& rrrx = rrx ;
-x = rrrx; $\C[2.0in]{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}$
-px = &rrrx; $\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}$
-ppx = &&rrrx; $\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}$
-pppx = &&&rrrx; $\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}$
-ppppx = &&&&rrrx; $\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}$
+x = rrrx;					§\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§
+px = &rrrx;					§\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}§
+ppx = &&rrrx;				§\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}§
+pppx = &&&rrrx;				§\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}§
+ppppx = &&&&rrrx;			§\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}§
 \end{cfa}
 The following example shows the second rule applied to different \Index{lvalue} contexts:
@@ -2107,8 +2106,8 @@
 int x, * px, ** ppx, *** pppx;
 int & rx = x, && rrx = rx, &&& rrrx = rrx ;
-rrrx = 2; $\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}$
-&rrrx = px; $\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (rx)}$
-&&rrrx = ppx; $\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (rrx)}$
-&&&rrrx = pppx; $\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (rrrx)}\CRT$
+rrrx = 2;					§\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§
+&rrrx = px;					§\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (rx)}§
+&&rrrx = ppx;				§\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (rrx)}§
+&&&rrrx = pppx;				§\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (rrrx)}§
 \end{cfa}
 
@@ -2123,5 +2122,5 @@
 \begin{cfa}
 int x;
-x + 1; $\C[2.0in]{// lvalue variable (int) converts to rvalue for expression}$
+x + 1;						§\C{// lvalue variable (int) converts to rvalue for expression}§
 \end{cfa}
 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped.
@@ -2133,5 +2132,5 @@
 \begin{cfa}
 int x, &r = x, f( int p );
-x = ®r® + f( ®r® ); $\C{// lvalue reference converts to rvalue}$
+x = ®r® + f( ®r® );			§\C{// lvalue reference converts to rvalue}§
 \end{cfa}
 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
@@ -2140,6 +2139,6 @@
 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]{lvalue-type cv1 T} converts to ©cv2 T &©, which allows implicitly converting variables to references.
 \begin{cfa}
-int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
-f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}\CRT$
+int x, &r = ®x®, f( int & p ); §\C{// lvalue variable (int) convert to reference (int \&)}§
+f( ®x® );					§\C{// lvalue variable (int) convert to reference (int \&)}§
 \end{cfa}
 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
@@ -2151,6 +2150,6 @@
 \begin{cfa}
 int x, & f( int & p );
-f( ®x + 3® );	$\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$
-®&f®(...) = &x;	$\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$
+f( ®x + 3® );				§\C{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}§
+®&f®(...) = &x;				§\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}§
 \end{cfa}
 In both case, modifications to the temporary are inaccessible (\Index{warning}).
@@ -2319,4 +2318,380 @@
 
 
+\section{\lstinline{string} Type}
+\label{s:stringType}
+
+The \CFA \Indexc{string} type is for manipulation of dynamically-size character-strings versus C \Indexc{char *} type for manipulation of statically-size null-terminated character-strings.
+That is, the amount of storage for a \CFA string changes dynamically at runtime to fit the string size, whereas the amount of storage for a C string is fixed at compile time.
+Hence, a ©string© declaration does not specify a maximum length;
+as a string dynamically grows and shrinks in size, so does its underlying storage.
+In contrast, a C string also dynamically grows and shrinks is size, but its underlying storage is fixed.
+The maximum storage for a \CFA ©string© value is ©size_t© characters, which is $2^{32}$ or $2^{64}$ respectively.
+A \CFA string manages its length separately from the string, so there is no null (©'\0'©) terminating value at the end of a string value.
+Hence, a \CFA string cannot be passed to a C string manipulation routine, such as ©strcat©.
+Like C strings, the characters in a ©string© are numbered starting from 0.
+
+The following operations have been defined to manipulate an instance of type ©string©.
+The discussion assumes the following declarations and assignment statements are executed.
+\begin{cfa}
+#include ®<string.hfa>®
+®string® s, peter, digit, alpha, punctuation, ifstmt;
+int i;
+peter  = "PETER";
+digit  = "0123456789";
+punctuation = "().,";
+ifstmt = "IF (A > B) {";
+\end{cfa}
+Note, the include file \Indexc{string.hfa} to access type ©string©.
+
+
+\subsection{Implicit String Conversions}
+
+The types ©char©, ©char *©, ©int©, ©double©, ©_Complex©, including signness and different sizes, implicitly convert to type ©string©.
+\VRef[Figure]{f:ImplicitStringConversions} shows examples of implicit conversion between C strings, integral, floating-point and complex types to ©string©
+The implicit conversions can be specified explicitly, as in:
+\begin{cfa}
+s = string( "abc" );		// converts char * to string
+s = string( 5 );			// converts int to string
+s = string( 5.5 );			// converts double to string
+\end{cfa}
+Conversions from ©string© to ©char *© are supported but with restrictions.
+Explicit As well, when a string is converted to a ©char *©, the storage for the ©char *© is created by the conversion operation, which must be subsequently deleted:
+\begin{cfa}
+string x = "abc";
+char *p = x;				// convert from string to char *
+...
+delete p;					// free storage created for p
+\end{cfa}
+
+\begin{figure}
+\begin{tabular}{@{}l@{\hspace{15pt}}|@{\hspace{15pt}}l@{}}
+\begin{cfa}
+//	string s = 5;					sout | s;
+	string s;
+	// conversion of char and char * to string
+	s = 'x';						§\CD{sout | s;}§
+	s = "abc";						§\CD{sout | s;}§
+	char cs[5] = "abc";
+	s = cs;							§\CD{sout | s;}§
+	// conversion of integral, floating-point, and complex to string
+	s = 45hh;						§\CD{sout | s;}§
+	s = 45h;						§\CD{sout | s;}§
+	s = -(ssize_t)MAX - 1;			§\CD{sout | s;}§
+	s = (size_t)MAX;				§\CD{sout | s;}§
+	s = 5.5;						§\CD{sout | s;}§
+	s = 5.5L;						§\CD{sout | s;}§
+	s = 5.5+3.4i;					§\CD{sout | s;}§
+	s = 5.5L+3.4Li;					§\CD{sout | s;}§
+	// safe conversion from string to char *
+	strncpy( cs, s, sizeof(cs) );	§\CD{sout | cs;}§
+	char * cp = s;					§\CD{sout | cp; // ownership}§
+	delete( cp );
+	cp = s + ' ' + s;				§\CD{sout | cp; // ownership}§
+	delete( cp );
+\end{cfa}
+&
+\begin{cfa}
+
+
+
+x
+abc
+
+abc
+
+45
+45
+-9223372036854775808
+18446744073709551615
+5.5
+5.5
+5.5+3.4i
+5.5+3.4i
+
+5.5+
+5.5+3.4i
+
+5.5+3.4i 5.5+3.4i
+
+\end{cfa}
+\end{tabular}
+\caption{Implicit String Conversions}
+\label{f:ImplicitStringConversions}
+\end{figure}
+
+
+\subsection{Comparison Operators}
+
+The binary relational and equality operators ©<©, ©<=©, ©>©, ©>=©, ©==©, ©!=© compare ©string© using lexicographical ordering, where longer strings are greater than shorter strings.
+
+
+\subsection{Concatenation}
+
+The binary operator ©+© concatenates two strings.
+\begin{cfa}
+s = peter + digit;					§\C{// s is assigned "PETER0123456789"}§
+s += peter;							§\C{// s is assigned "PETER0123456789PETER"}§
+\end{cfa}
+There is also an assignment form ©+=©.
+
+
+\subsection{Repetition}
+
+The binary operator \Indexc{*} returns a string that is the string repeated ©n© times.
+If ©n = 0©, a zero length string, ©""© is returned.
+\begin{cfa}
+s = (peter + ' ') * 3;				§\C{// s is assigned "PETER PETER PETER"}§
+\end{cfa}
+There is also an assignment form ©*=©.
+
+
+\subsection{Length}
+
+The ©length© operation
+\begin{cfa}
+int length()
+\end{cfa}
+returns the length of a string variable.
+\begin{cfa}
+i = peter.length();			§\C{// i is assigned the value 5}§
+\end{cfa}
+
+
+\subsection{Substring}
+The substring operation:
+\begin{cfa}
+string operator () (int start, int lnth);
+\end{cfa}
+performs a substring operation that returns the string starting at a specified position (©start©) in the current string, and having the specified length (©lnth©).
+A negative starting position is a specification from the right end of the string.
+A negative length means that characters are selected in the opposite (right to left) direction from the starting position.
+If the substring request extends beyond the beginning or end of the string, it is clipped (shortened) to the bounds of the string.
+If the substring request is completely outside of the original string, a null string located at the end of the original string is returned.
+\begin{cfa}
+s = peter( 2, 3 );			§\C{// s is assigned "ETE"}§
+s = peter( 4, -3 );			§\C{// s is assigned "ETE", length is opposite direction}§
+s = peter( 2, 8 );			§\C{// s is assigned "ETER", length is clipped to 4}§
+s = peter( 0, -1 );			§\C{// s is assigned "", beyond string so clipped to null}§
+s = peter(-1, -1 );			§\C{// s is assigned "R", start and length are negative}§
+\end{cfa}
+The substring operation can also appear on the left hand side of the assignment operator.
+The substring is replaced by the value on the right hand side of the assignment.
+The length of the right-hand-side value may be shorter, the same length, or longer than the length of the substring that is selected on the left hand side of the assignment.
+\begin{cfa}[mathescape=false]
+digit( 3, 3 ) = "";   		§\C{// digit is assigned "0156789"}§
+digit( 4, 3 ) = "xyz";		§\C{// digit is assigned "015xyz9"}§
+digit( 7, 0 ) = "***";		§\C{// digit is assigned "015xyz***9"}§
+digit(-4, 3 ) = "$$$";		§\C{// digit is assigned "015xyz\$\$\$9"}§
+\end{cfa}
+A substring is treated as a pointer into the base (substringed) string rather than creating a copy of the subtext.
+As with all pointers, if the item they are pointing at is changed, then the pointer is referring to the changed item.
+Pointers to the result value of a substring operation are defined to always start at the same location in their base string as long as that starting location exists, independent of changes to themselves or the base string.
+However, if the base string value changes, this may affect the values of one or more of the substrings to that base string.
+If the base string value shortens so that its end is before the starting location of a substring, resulting in the substring starting location disappearing, the substring becomes a null string located at the end of the base string.
+
+The following example illustrates passing the results of substring operations by reference and by value to a subprogram.
+Notice the side-effects to other reference parameters as one is modified.
+\begin{cfa}
+main() {
+	string x = "xxxxxxxxxxxxx";
+	test( x, x(1,3), x(3,3), x(5,5), x(9,5), x(9,5) );
+}
+
+// x, a, b, c, & d are substring results passed by reference
+// e is a substring result passed by value
+void test(string &x, string &a, string &b, string &c, string &d, string e) {
+							§\C{//   x			  	  a	 	  b	 	  c		  d		  e}§
+	a( 1, 2 ) = "aaa";		§\C{// aaaxxxxxxxxxxx	aaax	axx		xxxxx	xxxxx	xxxxx}§
+	b( 2, 12 ) = "bbb";		§\C{// aaabbbxxxxxxxxx	aaab	abbb	bbxxx	xxxxx	xxxxx}§
+	c( 4, 5 ) = "ccc";		§\C{// aaabbbxcccxxxxxx	aaab	abbb	bbxccc	ccxxx	xxxxx}§
+	c = "yyy";				§\C{// aaabyyyxxxxxx	aaab	abyy	yyy		xxxxx	xxxxx}§
+	d( 1, 3 ) = "ddd";		§\C{// aaabyyyxdddxx	aaab	abyy	yyy		dddxx	xxxxx}§
+	e( 1, 3 ) = "eee";		§\C{// aaabyyyxdddxx	aaab	abyy	yyy		dddxx	eeexx}§
+	x = e;					§\C{// eeexx			eeex	exx		x				eeexx}§
+}
+\end{cfa}
+
+There is an assignment form of substring in which only the starting position is specified and the length is assumed to be the remainder of the string.
+\begin{cfa}
+string operator () (int start);
+\end{cfa}
+For example:
+\begin{cfa}
+s = peter( 2 );				§\C{// s is assigned "ETER"}§
+peter( 2 ) = "IPER";		§\C{// peter is assigned "PIPER"}§
+\end{cfa}
+It is also possible to substring using a string as the index for selecting the substring portion of the string.
+\begin{cfa}
+string operator () (const string &index);
+\end{cfa}
+For example:
+\begin{cfa}[mathescape=false]
+digit( "xyz$$$" ) = "678"; 	§\C{// digit is assigned "0156789"}§
+digit( "234") = "***";		§\C{// digit is assigned "0156789***"}§
+\end{cfa}
+%$
+
+
+\subsection{Searching}
+
+The ©index© operation
+\begin{cfa}
+int index( const string &key, int start = 1, occurrence occ = first );
+\end{cfa}
+returns the position of the first or last occurrence of the ©key© (depending on the occurrence indicator ©occ© that is either ©first© or ©last©) in the current string starting the search at position ©start©.
+If the ©key© does not appear in the current string, the length of the current string plus one is returned.
+%If the ©key© has zero length, the value 1 is returned regardless of what the current string contains.
+A negative starting position is a specification from the right end of the string.
+\begin{cfa}
+i = digit.index( "567" );			§\C{// i is assigned 3}§
+i = digit.index( "567", 7 );		§\C{// i is assigned 11}§
+i = digit.index( "567", -1, last );	§\C{// i is assigned 3}§
+i = peter.index( "E", 5, last );	§\C{// i is assigned 4}§
+\end{cfa}
+
+The next two string operations test a string to see if it is or is not composed completely of a particular class of characters.
+For example, are the characters of a string all alphabetic or all numeric?
+Use of these operations involves a two step operation.
+First, it is necessary to create an instance of type ©strmask© and initialize it to a string containing the characters of the particular character class, as in:
+\begin{cfa}
+strmask digitmask = digit;
+strmask alphamask = string( "abcdefghijklmnopqrstuvwxyz" );
+\end{cfa}
+Second, the character mask is used in the functions ©include© and ©exclude© to check a string for compliance of its characters with the characters indicated by the mask.
+
+The ©include© operation
+\begin{cfa}
+int include( const strmask &, int = 1, occurrence occ = first );
+\end{cfa}
+returns the position of the first or last character (depending on the occurrence indicator, which is either ©first© or ©last©) in the current string that does not appear in the ©mask© starting the search at position ©start©;
+hence it skips over characters in the current string that are included (in) the ©mask©.
+The characters in the current string do not have to be in the same order as the ©mask©.
+If all the characters in the current string appear in the ©mask©, the length of the current string plus one is returned, regardless of which occurrence is being searched for.
+A negative starting position is a specification from the right end of the string.
+\begin{cfa}
+i = peter.include( digitmask );	§\C{// i is assigned 1}§
+i = peter.include( alphamask );	§\C{// i is assigned 6}§
+\end{cfa}
+
+The ©exclude© operation
+\begin{cfa}
+int exclude( string &mask, int start = 1, occurrence occ = first )
+\end{cfa}
+returns the position of the first or last character (depending on the occurrence indicator, which is either ©first© or ©last©) in the current string that does appear in the ©mask© string starting the search at position ©start©;
+hence it skips over characters in the current string that are excluded from (not in) in the ©mask© string.
+The characters in the current string do not have to be in the same order as the ©mask© string.
+If all the characters in the current string do NOT appear in the ©mask© string, the length of the current string plus one is returned, regardless of which occurrence is being searched for.
+A negative starting position is a specification from the right end of the string.
+\begin{cfa}
+i = peter.exclude( digitmask );		§\C{// i is assigned 6}§
+i = ifstmt.exclude( strmask( punctuation ) ); §\C{// i is assigned 4}§
+\end{cfa}
+
+The ©includeStr© operation:
+\begin{cfa}
+string includeStr( strmask &mask, int start = 1, occurrence occ = first )
+\end{cfa}
+returns the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) of the current string that ARE included in the ©mask© string starting the search at position ©start©.
+A negative starting position is a specification from the right end of the string.
+\begin{cfa}
+s = peter.includeStr( alphamask );	§\C{// s is assigned "PETER"}§
+s = ifstmt.includeStr( alphamask );	§\C{// s is assigned "IF"}§
+s = peter.includeStr( digitmask );	§\C{// s is assigned ""}§
+\end{cfa}
+
+The ©excludeStr© operation:
+\begin{cfa}
+string excludeStr( strmask &mask, int start = 1, occurrence = first )
+\end{cfa}
+returns the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) of the current string that are excluded (NOT) in the ©mask© string starting the search at position ©start©.
+A negative starting position is a specification from the right end of the string.
+\begin{cfa}
+s = peter.excludeStr( digitmask);	§\C{// s is assigned "PETER"}§
+s = ifstmt.excludeStr( strmask( punctuation ) ); §\C{// s is assigned "IF "}§
+s = peter.excludeStr( alphamask);	§\C{// s is assigned ""}§
+\end{cfa}
+
+
+\subsection{Miscellaneous}
+
+The ©trim© operation
+\begin{cfa}
+string trim( string &mask, occurrence occ = first )
+\end{cfa}
+returns a string in that is the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) which ARE included in the ©mask© are removed.
+\begin{cfa}
+// remove leading blanks
+s = string( "   ABC" ).trim( " " );			§\C{// s is assigned "ABC",}§
+// remove trailing blanks
+s = string( "ABC   " ).trim( " ", last );	§\C{// s is assigned "ABC",}§
+\end{cfa}
+
+The ©translate© operation
+\begin{cfa}
+string translate( string &from, string &to )
+\end{cfa}
+returns a string that is the same length as the original string in which all occurrences of the characters that appear in the ©from© string have been translated into their corresponding character in the ©to© string.
+Translation is done on a character by character basis between the ©from© and ©to© strings; hence these two strings must be the same length.
+If a character in the original string does not appear in the ©from© string, then it simply appears as is in the resulting string.
+\begin{cfa}
+// upper to lower case
+peter = peter.translate( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" );
+			// peter is assigned "peter"
+s = ifstmt.translate( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" );
+			// ifstmt is assigned "if (a > b) {"
+// lower to upper case
+peter = peter.translate( "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
+			// peter is assigned "PETER"
+\end{cfa}
+
+The ©replace© operation
+\begin{cfa}
+string replace( string &from, string &to )
+\end{cfa}
+returns a string in which all occurrences of the ©from© string in the current string have been replaced by the ©to© string.
+\begin{cfa}
+s = peter.replace( "E", "XX" );	§\C{// s is assigned "PXXTXXR"}§
+\end{cfa}
+The replacement is done left-to-right.
+When an instance of the ©from© string is found and changed to the ©to© string, it is NOT examined again for further replacement.
+
+
+\section{Returning N+1 on Failure}
+
+Any of the string search routines can fail at some point during the search.
+When this happens it is necessary to return indicating the failure.
+Many string types in other languages use some special value to indicate the failure.
+This value is often 0 or -1 (PL/I returns 0).
+This section argues that a value of N+1, where N is the length of the base string in the search, is a more useful value to return.
+The index-of function in APL returns N+1.
+These are the boundary situations and are often overlooked when designing a string type.
+
+The situation that can be optimized by returning N+1 is when a search is performed to find the starting location for a substring operation.
+For example, in a program that is extracting words from a text file, it is necessary to scan from left to right over whitespace until the first alphabetic character is found.
+\begin{cfa}
+line = line( line.exclude( alpha ) );
+\end{cfa}
+If a text line contains all whitespaces, the exclude operation fails to find an alphabetic character.
+If ©exclude© returns 0 or -1, the result of the substring operation is unclear.
+Most string types generate an error, or clip the starting value to 1, resulting in the entire whitespace string being selected.
+If ©exclude© returns N+1, the starting position for the substring operation is beyond the end of the string leaving a null string.
+
+The same situation occurs when scanning off a word.
+\begin{cfa}
+start = line.include(alpha);
+word = line(1, start - 1);
+\end{cfa}
+If the entire line is composed of a word, the include operation will  fail to find a non-alphabetic character.
+In general, returning 0 or -1 is not an appropriate starting position for the substring, which must substring off the word leaving a null string.
+However, returning N+1 will substring off the word leaving a null string.
+
+
+\subsection{Input/Output Operators}
+
+Both the \CC operators ©<<© and ©>>© are defined on type ©string©.
+However, input of a string value is different from input of a ©char *© value.
+When a string value is read, \emph{all} input characters from the current point in the input stream to either the end of line (©'\n'©) or the end of file are read.
+
+
 \section{Enumeration}
 
@@ -2332,8 +2707,8 @@
 Hence, enums may be overloaded with variable, enum, and function names.
 \begin{cfa}
-int Foo;			$\C{// type/variable separate namespaces}$
+int Foo;			§\C{// type/variable separate namespaces}§
 enum Foo { Bar };
-enum Goo { Bar };	$\C[1.75in]{// overload Foo.Bar}$
-double Bar;			$\C{// overload Foo.Bar, Goo.Bar}\CRT$
+enum Goo { Bar };	§\C[1.75in]{// overload Foo.Bar}§
+double Bar;			§\C{// overload Foo.Bar, Goo.Bar}\CRT§
 \end{cfa}
 An anonymous enumeration injects enums with specific values into a scope.
@@ -2408,15 +2783,15 @@
 The following examples illustrate the difference between the enumeration type and the type of its enums.
 \begin{cfa}
-Math m = PI;	$\C[1.5in]{// allowed}$
-double d = PI;	$\C{// allowed, conversion to base type}$
-m = E;			$\C{// allowed}$
-m = Alph;		$\C{// {\color{red}disallowed}}$
-m = 3.141597;	$\C{// {\color{red}disallowed}}$
-d = m;			$\C{// allowed}$
-d = Alph;		$\C{// {\color{red}disallowed}}$
-Letter l = A;	$\C{// allowed}$
-Greek g = Alph;	$\C{// allowed}$
-l = Alph;		$\C{// allowed, conversion to base type}$
-g = A;			$\C{// {\color{red}disallowed}}\CRT$
+Math m = PI;	§\C[1.5in]{// allowed}§
+double d = PI;	§\C{// allowed, conversion to base type}§
+m = E;			§\C{// allowed}§
+m = Alph;		§\C{// {\color{red}disallowed}}§
+m = 3.141597;	§\C{// {\color{red}disallowed}}§
+d = m;			§\C{// allowed}§
+d = Alph;		§\C{// {\color{red}disallowed}}§
+Letter l = A;	§\C{// allowed}§
+Greek g = Alph;	§\C{// allowed}§
+l = Alph;		§\C{// allowed, conversion to base type}§
+g = A;			§\C{// {\color{red}disallowed}}\CRT§
 \end{cfa}
 
@@ -2508,5 +2883,5 @@
 \begin{cfa}
 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) {
-	$\emph{routine body}$
+	§\emph{routine body}§
 }
 \end{cfa}
@@ -2519,11 +2894,11 @@
 Declaration qualifiers can only appear at the start of a routine definition, \eg:
 \begin{cfa}
-®extern® [ int x ] g( int y ) {$\,$}
+®extern® [ int x ] g( int y ) {§\,§}
 \end{cfa}
 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified;
 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in:
 \begin{cfa}
-[$\,$] g(); $\C{// no input or output parameters}$
-[ void ] g( void ); $\C{// no input or output parameters}$
+[§\,§] g(); §\C{// no input or output parameters}§
+[ void ] g( void ); §\C{// no input or output parameters}§
 \end{cfa}
 
@@ -2543,5 +2918,5 @@
 \begin{cfa}
 typedef int foo;
-int f( int (* foo) ); $\C{// foo is redefined as a parameter name}$
+int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§
 \end{cfa}
 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.
@@ -2551,12 +2926,12 @@
 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
 \begin{cfa}
-[ int ] f( * int, int * ); $\C{// returns an integer, accepts 2 pointers to integers}$
-[ * int, int * ] f( int ); $\C{// returns 2 pointers to integers, accepts an integer}$
+[ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§
+[ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§
 \end{cfa}
 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in:
 \begin{cfa}
 #define ptoa( n, d ) int (*n)[ d ]
-int f( ptoa( p, 5 ) ) ... $\C{// expands to int f( int (*p)[ 5 ] )}$
-[ int ] f( ptoa( p, 5 ) ) ... $\C{// expands to [ int ] f( int (*p)[ 5 ] )}$
+int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§
+[ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§
 \end{cfa}
 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms.
@@ -2580,5 +2955,5 @@
 	int z;
 	... x = 0; ... y = z; ...
-	®return;® $\C{// implicitly return x, y}$
+	®return;® §\C{// implicitly return x, y}§
 }
 \end{cfa}
@@ -2590,5 +2965,5 @@
 [ int x, int y ] f() {
 	...
-} $\C{// implicitly return x, y}$
+} §\C{// implicitly return x, y}§
 \end{cfa}
 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered.
@@ -2599,9 +2974,9 @@
 [ int x, int y ] f( int, x, int y ) {
 	...
-} $\C{// implicitly return x, y}$
+} §\C{// implicitly return x, y}§
 \end{cfa}
 This notation allows the compiler to eliminate temporary variables in nested routine calls.
 \begin{cfa}
-[ int x, int y ] f( int, x, int y ); $\C{// prototype declaration}$
+[ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§
 int a, b;
 [a, b] = f( f( f( a, b ) ) );
@@ -2617,8 +2992,8 @@
 as well, parameter names are optional, \eg:
 \begin{cfa}
-[ int x ] f (); $\C{// returning int with no parameters}$
-[ * int ] g (int y); $\C{// returning pointer to int with int parameter}$
-[ ] h ( int, char ); $\C{// returning no result with int and char parameters}$
-[ * int, int ] j ( int ); $\C{// returning pointer to int and int, with int parameter}$
+[ int x ] f (); §\C{// returning int with no parameters}§
+[ * int ] g (int y); §\C{// returning pointer to int with int parameter}§
+[ ] h ( int, char ); §\C{// returning no result with int and char parameters}§
+[ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§
 \end{cfa}
 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa).
@@ -2626,5 +3001,5 @@
 \begin{cfa}
 C :		const double bar1(), bar2( int ), bar3( double );
-$\CFA$:	[const double] foo(), foo( int ), foo( double ) { return 3.0; }
+§\CFA§:	[const double] foo(), foo( int ), foo( double ) { return 3.0; }
 \end{cfa}
 \CFA allows the last routine in the list to define its body.
@@ -2641,13 +3016,13 @@
 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:
 \begin{cfa}
-* [ int x ] () fp; $\C[2.25in]{// pointer to routine returning int with no parameters}$
-* [ * int ] (int y) gp; $\C{// pointer to routine returning pointer to int with int parameter}$
-* [ ] (int,char) hp; $\C{// pointer to routine returning no result with int and char parameters}$
-* [ * int,int ] ( int ) jp; $\C{// pointer to routine returning pointer to int and int, with int parameter}\CRT$
+* [ int x ] () fp; §\C[2.25in]{// pointer to routine returning int with no parameters}§
+* [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§
+* [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§
+* [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}\CRT§
 \end{cfa}
 While parameter names are optional, \emph{a routine name cannot be specified};
 for example, the following is incorrect:
 \begin{cfa}
-* [ int x ] f () fp; $\C{// routine name "f" is not allowed}$
+* [ int x ] f () fp; §\C{// routine name "f" is not allowed}§
 \end{cfa}
 
@@ -2672,5 +3047,5 @@
 whereas a named (keyword) call may be:
 \begin{cfa}
-p( z : 3, x : 4, y : 7 );  $\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}$
+p( z : 3, x : 4, y : 7 );  §\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}§
 \end{cfa}
 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
@@ -2689,9 +3064,9 @@
 For example, the following routine prototypes and definition are all valid.
 \begin{cfa}
-void p( int, int, int ); $\C{// equivalent prototypes}$
+void p( int, int, int ); §\C{// equivalent prototypes}§
 void p( int x, int y, int z );
 void p( int y, int x, int z );
 void p( int z, int y, int x );
-void p( int q, int r, int s ) {} $\C{// match with this definition}$
+void p( int q, int r, int s ) {} §\C{// match with this definition}§
 \end{cfa}
 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming.
@@ -2705,11 +3080,11 @@
 int f( int x, double y );
 
-f( j : 3, i : 4 ); $\C{// 1st f}$
-f( x : 7, y : 8.1 ); $\C{// 2nd f}$
-f( 4, 5 );  $\C{// ambiguous call}$
+f( j : 3, i : 4 ); §\C{// 1st f}§
+f( x : 7, y : 8.1 ); §\C{// 2nd f}§
+f( 4, 5 );  §\C{// ambiguous call}§
 \end{cfa}
 However, named arguments compound routine resolution in conjunction with conversions:
 \begin{cfa}
-f( i : 3, 5.7 ); $\C{// ambiguous call ?}$
+f( i : 3, 5.7 ); §\C{// ambiguous call ?}§
 \end{cfa}
 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous.
@@ -2725,16 +3100,16 @@
 the allowable positional calls are:
 \begin{cfa}
-p(); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}$
-p( 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}$
-p( 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}$
-p( 4, 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}$
+p(); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
+p( 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
+p( 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
+p( 4, 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}§
 // empty arguments
-p(  , 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}$
-p( 4,  , 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}$
-p( 4, 4,   ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}$
-p( 4,  ,   ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}$
-p(  , 4,   ); $\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}$
-p(  ,  , 4 ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}$
-p(  ,  ,   ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}$
+p(  , 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}§
+p( 4,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}§
+p( 4, 4,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
+p( 4,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
+p(  , 4,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}§
+p(  ,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}§
+p(  ,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
 \end{cfa}
 Here the missing arguments are inserted from the default values in the parameter list.
@@ -2760,7 +3135,7 @@
 Default values may only appear in a prototype versus definition context:
 \begin{cfa}
-void p( int x, int y = 2, int z = 3 ); $\C{// prototype: allowed}$
-void p( int, int = 2, int = 3 ); $\C{// prototype: allowed}$
-void p( int x, int y = 2, int z = 3 ) {} $\C{// definition: not allowed}$
+void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§
+void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§
+void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§
 \end{cfa}
 The reason for this restriction is to allow separate compilation.
@@ -2777,6 +3152,6 @@
 \begin{cfa}
 p( int x, int y, int z, ... );
-p( 1, 4, 5, 6, z : 3, y : 2 ); $\C{// assume p( /* positional */, ... , /* named */ );}$
-p( 1, z : 3, y : 2, 4, 5, 6 ); $\C{// assume p( /* positional */, /* named */, ... );}$
+p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
+p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
 \end{cfa}
 In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin.
@@ -2787,6 +3162,6 @@
 \begin{cfa}
 void p( int x, int y = 2, int z = 3... );
-p( 1, 4, 5, 6, z : 3 ); $\C{// assume p( /* positional */, ... , /* named */ );}$
-p( 1, z : 3, 4, 5, 6 ); $\C{// assume p( /* positional */, /* named */, ... );}$
+p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
+p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
 \end{cfa}
 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments;
@@ -2818,5 +3193,5 @@
 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as:
 \begin{cfa}
-p( 1, /* default */, 5 ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}$
+p( 1, /* default */, 5 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}§
 \end{cfa}
 
@@ -2831,10 +3206,10 @@
 \begin{cfa}
 struct {
-	int f1; $\C{// named field}$
-	int f2 : 4; $\C{// named field with bit field size}$
-	int : 3; $\C{// unnamed field for basic type with bit field size}$
-	int ; $\C{// disallowed, unnamed field}$
-	int *; $\C{// disallowed, unnamed field}$
-	int (*)( int ); $\C{// disallowed, unnamed field}$
+	int f1; §\C{// named field}§
+	int f2 : 4; §\C{// named field with bit field size}§
+	int : 3; §\C{// unnamed field for basic type with bit field size}§
+	int ; §\C{// disallowed, unnamed field}§
+	int *; §\C{// disallowed, unnamed field}§
+	int (*)( int ); §\C{// disallowed, unnamed field}§
 };
 \end{cfa}
@@ -2844,5 +3219,5 @@
 \begin{cfa}
 struct {
-	int , , ; $\C{// 3 unnamed fields}$
+	int , , ; §\C{// 3 unnamed fields}§
 }
 \end{cfa}
@@ -2938,9 +3313,9 @@
 const unsigned int size = 5;
 int ia[size];
-... $\C{// assign values to array ia}$
-qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$
+... §\C{// assign values to array ia}§
+qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§
 {
-	®int ?<?( int x, int y ) { return x > y; }® $\C{// nested routine}$
-	qsort( ia, size ); $\C{// sort descending order by local redefinition}$
+	®int ?<?( int x, int y ) { return x > y; }® §\C{// nested routine}§
+	qsort( ia, size ); §\C{// sort descending order by local redefinition}§
 }
 \end{cfa}
@@ -2950,14 +3325,14 @@
 The following program in undefined in \CFA (and Indexc{gcc})
 \begin{cfa}
-[* [int]( int )] foo() { $\C{// int (* foo())( int )}$
+[* [int]( int )] foo() { §\C{// int (* foo())( int )}§
 	int ®i® = 7;
 	int bar( int p ) {
-		®i® += 1; $\C{// dependent on local variable}$
+		®i® += 1; §\C{// dependent on local variable}§
 		sout | ®i®;
 	}
-	return bar; $\C{// undefined because of local dependence}$
+	return bar; §\C{// undefined because of local dependence}§
 }
 int main() {
-	* [int]( int ) fp = foo(); $\C{// int (* fp)( int )}$
+	* [int]( int ) fp = foo(); §\C{// int (* fp)( int )}§
 	sout | fp( 3 );
 }
@@ -2972,5 +3347,5 @@
 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
 \begin{cfa}
-f( ®2, x, 3 + i® ); $\C{// element list}$
+f( ®2, x, 3 + i® ); §\C{// element list}§
 \end{cfa}
 A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}.
@@ -2987,8 +3362,8 @@
 For example, consider C's \Indexc{div} function, which returns the quotient and remainder for a division of an integer value.
 \begin{cfa}
-typedef struct { int quot, rem; } div_t;	$\C[7cm]{// from include stdlib.h}$
+typedef struct { int quot, rem; } div_t;	§\C[7cm]{// from include stdlib.h}§
 div_t div( int num, int den );
-div_t qr = div( 13, 5 ); $\C{// return quotient/remainder aggregate}$
-printf( "%d %d\n", qr.quot, qr.rem ); $\C{// print quotient/remainder}$
+div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§
+printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§
 \end{cfa}
 This approach requires a name for the return type and fields, where \Index{naming} is a common programming-language issue.
@@ -3000,7 +3375,7 @@
 For example, consider C's \Indexc{modf} function, which returns the integral and fractional part of a floating value.
 \begin{cfa}
-double modf( double x, double * i ); $\C{// from include math.h}$
-double intp, frac = modf( 13.5, &intp ); $\C{// return integral and fractional components}$
-printf( "%g %g\n", intp, frac ); $\C{// print integral/fractional components}$
+double modf( double x, double * i ); §\C{// from include math.h}§
+double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§
+printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§
 \end{cfa}
 This approach requires allocating storage for the return values, which complicates the call site with a sequence of variable declarations leading to the call.
@@ -3029,8 +3404,8 @@
 When a function call is passed as an argument to another call, the best match of actual arguments to formal parameters is evaluated given all possible expression interpretations in the current scope.
 \begin{cfa}
-void g( int, int ); $\C{// 1}$
-void g( double, double ); $\C{// 2}$
-g( div( 13, 5 ) ); $\C{// select 1}$
-g( modf( 13.5 ) ); $\C{// select 2}$
+void g( int, int ); §\C{// 1}§
+void g( double, double ); §\C{// 2}§
+g( div( 13, 5 ) ); §\C{// select 1}§
+g( modf( 13.5 ) ); §\C{// select 2}§
 \end{cfa}
 In this case, there are two overloaded ©g© routines.
@@ -3041,9 +3416,9 @@
 The previous examples can be rewritten passing the multiple returned-values directly to the ©printf© function call.
 \begin{cfa}
-[ int, int ] div( int x, int y ); $\C{// from include stdlib}$
-printf( "%d %d\n", div( 13, 5 ) ); $\C{// print quotient/remainder}$
-
-[ double, double ] modf( double x ); $\C{// from include math}$
-printf( "%g %g\n", modf( 13.5 ) ); $\C{// print integral/fractional components}$
+[ int, int ] div( int x, int y ); §\C{// from include stdlib}§
+printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§
+
+[ double, double ] modf( double x ); §\C{// from include math}§
+printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§
 \end{cfa}
 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type.
@@ -3055,6 +3430,6 @@
 \begin{cfa}
 int quot, rem;
-[ quot, rem ] = div( 13, 5 ); $\C{// assign multiple variables}$
-printf( "%d %d\n", quot, rem ); $\C{// print quotient/remainder}\CRT$
+[ quot, rem ] = div( 13, 5 ); §\C{// assign multiple variables}§
+printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§
 \end{cfa}
 Here, the multiple return-values are matched in much the same way as passing multiple return-values to multiple parameters in a call.
@@ -3085,6 +3460,6 @@
 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}.
 \begin{cfa}
-[int, int] ®qr® = div( 13, 5 ); $\C{// initialize tuple variable}$
-printf( "%d %d\n", ®qr® ); $\C{// print quotient/remainder}$
+[int, int] ®qr® = div( 13, 5 ); §\C{// initialize tuple variable}§
+printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§
 \end{cfa}
 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}.
@@ -3092,5 +3467,5 @@
 One way to access the individual components of a tuple variable is with assignment.
 \begin{cfa}
-[ quot, rem ] = qr; $\C{// assign multiple variables}$
+[ quot, rem ] = qr; §\C{// assign multiple variables}§
 \end{cfa}
 
@@ -3115,9 +3490,9 @@
 [int, double] * p;
 
-int y = x.0; $\C{// access int component of x}$
-y = f().1; $\C{// access int component of f}$
-p->0 = 5; $\C{// access int component of tuple pointed-to by p}$
-g( x.1, x.0 ); $\C{// rearrange x to pass to g}$
-double z = [ x, f() ].0.1; $\C{// access second component of first component of tuple expression}$
+int y = x.0; §\C{// access int component of x}§
+y = f().1; §\C{// access int component of f}§
+p->0 = 5; §\C{// access int component of tuple pointed-to by p}§
+g( x.1, x.0 ); §\C{// rearrange x to pass to g}§
+double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§
 \end{cfa}
 Tuple-index expressions can occur on any tuple-typed expression, including tuple-returning functions, square-bracketed tuple expressions, and other tuple-index expressions, provided the retrieved component is also a tuple.
@@ -3187,8 +3562,8 @@
 double y;
 [int, double] z;
-[y, x] = 3.14; $\C{// mass assignment}$
-[x, y] = z;							    $\C{// multiple assignment}$
-z = 10;							        $\C{// mass assignment}$
-z = [x, y]; $\C{// multiple assignment}$
+[y, x] = 3.14; §\C{// mass assignment}§
+[x, y] = z;							    §\C{// multiple assignment}§
+z = 10;							        §\C{// mass assignment}§
+z = [x, y]; §\C{// multiple assignment}§
 \end{cfa}
 Let $L_i$ for $i$ in $[0, n)$ represent each component of the flattened left side, $R_i$ represent each component of the flattened right side of a multiple assignment, and $R$ represent the right side of a mass assignment.
@@ -3198,5 +3573,5 @@
 \begin{cfa}
 [ int, int ] x, y, z;
-[ x, y ] = z;						   $\C{// multiple assignment, invalid 4 != 2}$
+[ x, y ] = z;						   §\C{// multiple assignment, invalid 4 != 2}§
 \end{cfa}
 Multiple assignment assigns $R_i$ to $L_i$ for each $i$.
@@ -3234,5 +3609,5 @@
 	double c, d;
 	[ void ] f( [ int, int ] );
-	f( [ c, a ] = [ b, d ] = 1.5 ); $\C{// assignments in parameter list}$
+	f( [ c, a ] = [ b, d ] = 1.5 ); §\C{// assignments in parameter list}§
 \end{cfa}
 The tuple expression begins with a mass assignment of ©1.5© into ©[b, d]©, which assigns ©1.5© into ©b©, which is truncated to ©1©, and ©1.5© into ©d©, producing the tuple ©[1, 1.5]© as a result.
@@ -3247,12 +3622,12 @@
 \begin{cfa}
 struct S;
-void ?{}(S *); $\C{// (1)}$
-void ?{}(S *, int); $\C{// (2)}$
-void ?{}(S * double); $\C{// (3)}$
-void ?{}(S *, S); $\C{// (4)}$
-
-[S, S] x = [3, 6.28]; $\C{// uses (2), (3), specialized constructors}$
-[S, S] y; $\C{// uses (1), (1), default constructor}$
-[S, S] z = x.0; $\C{// uses (4), (4), copy constructor}$
+void ?{}(S *); §\C{// (1)}§
+void ?{}(S *, int); §\C{// (2)}§
+void ?{}(S * double); §\C{// (3)}§
+void ?{}(S *, S); §\C{// (4)}§
+
+[S, S] x = [3, 6.28]; §\C{// uses (2), (3), specialized constructors}§
+[S, S] y; §\C{// uses (1), (1), default constructor}§
+[S, S] z = x.0; §\C{// uses (4), (4), copy constructor}§
 \end{cfa}
 In this example, ©x© is initialized by the multiple constructor calls ©?{}(&x.0, 3)© and ©?{}(&x.1, 6.28)©, while ©y© is initialized by two default constructor calls ©?{}(&y.0)© and ©?{}(&y.1)©.
@@ -3295,6 +3670,6 @@
 A member-access tuple may be used anywhere a tuple can be used, \eg:
 \begin{cfa}
-s.[ y, z, x ] = [ 3, 3.2, 'x' ]; $\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}$
-f( s.[ y, z ] ); $\C{// equivalent to f( s.y, s.z )}$
+s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§
+f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§
 \end{cfa}
 Note, the fields appearing in a record-field tuple may be specified in any order;
@@ -3306,6 +3681,6 @@
 void f( double, long );
 
-f( x.[ 0, 3 ] ); $\C{// f( x.0, x.3 )}$
-x.[ 0, 1 ] = x.[ 1, 0 ]; $\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}$
+f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§
+x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§
 [ long, int, long ] y = x.[ 2, 0, 2 ];
 \end{cfa}
@@ -3324,5 +3699,5 @@
 \begin{cfa}
 [ int, float, double ] f();
-[ double, float ] x = f().[ 2, 1 ]; $\C{// f() called once}$
+[ double, float ] x = f().[ 2, 1 ]; §\C{// f() called once}§
 \end{cfa}
 
@@ -3337,9 +3712,9 @@
 That is, a cast can be used to select the type of an expression when it is ambiguous, as in the call to an overloaded function.
 \begin{cfa}
-int f(); $\C{// (1)}$
-double f(); $\C{// (2)}$
-
-f(); $\C{// ambiguous - (1),(2) both equally viable}$
-(int)f(); $\C{// choose (2)}$
+int f(); §\C{// (1)}§
+double f(); §\C{// (2)}§
+
+f(); §\C{// ambiguous - (1),(2) both equally viable}§
+(int)f(); §\C{// choose (2)}§
 \end{cfa}
 Since casting is a fundamental operation in \CFA, casts need to be given a meaningful interpretation in the context of tuples.
@@ -3349,9 +3724,9 @@
 void g();
 
-(void)f(); $\C{// valid, ignore results}$
-(int)g(); $\C{// invalid, void cannot be converted to int}$
+(void)f(); §\C{// valid, ignore results}§
+(int)g(); §\C{// invalid, void cannot be converted to int}§
 
 struct A { int x; };
-(struct A)f(); $\C{// invalid, int cannot be converted to A}$
+(struct A)f(); §\C{// invalid, int cannot be converted to A}§
 \end{cfa}
 In C, line 4 is a valid cast, which calls ©f© and discards its result.
@@ -3369,9 +3744,9 @@
 	[int, [int, int], int] g();
 
-	([int, double])f(); $\C{// (1) valid}$
-	([int, int, int])g(); $\C{// (2) valid}$
-	([void, [int, int]])g(); $\C{// (3) valid}$
-	([int, int, int, int])g(); $\C{// (4) invalid}$
-	([int, [int, int, int]])g(); $\C{// (5) invalid}$
+	([int, double])f(); §\C{// (1) valid}§
+	([int, int, int])g(); §\C{// (2) valid}§
+	([void, [int, int]])g(); §\C{// (3) valid}§
+	([int, int, int, int])g(); §\C{// (4) invalid}§
+	([int, [int, int, int]])g(); §\C{// (5) invalid}§
 \end{cfa}
 
@@ -3433,8 +3808,8 @@
 void f([int, int], int, int);
 
-f([0, 0], 0, 0); $\C{// no cost}$
-f(0, 0, 0, 0); $\C{// cost for structuring}$
-f([0, 0,], [0, 0]); $\C{// cost for flattening}$
-f([0, 0, 0], 0); $\C{// cost for flattening and structuring}$
+f([0, 0], 0, 0); §\C{// no cost}§
+f(0, 0, 0, 0); §\C{// cost for structuring}§
+f([0, 0,], [0, 0]); §\C{// cost for flattening}§
+f([0, 0, 0], 0); §\C{// cost for flattening and structuring}§
 \end{cfa}
 
@@ -3500,5 +3875,5 @@
 [ unsigned int, char ]
 [ double, double, double ]
-[ * int, int * ] $\C{// mix of CFA and ANSI}$
+[ * int, int * ] §\C{// mix of CFA and ANSI}§
 [ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ]
 \end{cfa}
@@ -3507,6 +3882,6 @@
 Examples of declarations using tuple types are:
 \begin{cfa}
-[ int, int ] x; $\C{// 2 element tuple, each element of type int}$
-* [ char, char ] y; $\C{// pointer to a 2 element tuple}$
+[ int, int ] x; §\C{// 2 element tuple, each element of type int}§
+* [ char, char ] y; §\C{// pointer to a 2 element tuple}§
 [ [ int, int ] ] z ([ int, int ]);
 \end{cfa}
@@ -3525,6 +3900,6 @@
 [ int, int ] w1;
 [ int, int, int ] w2;
-[ void ] f (int, int, int); $\C{// three input parameters of type int}$
-[ void ] g ([ int, int, int ]); $\C{3 element tuple as input}$
+[ void ] f (int, int, int); §\C{// three input parameters of type int}§
+[ void ] g ([ int, int, int ]); §\C{3 element tuple as input}§
 f( [ 1, 2, 3 ] );
 f( w1, 3 );
@@ -3607,5 +3982,5 @@
 [ int, int, int, int ] w = [ 1, 2, 3, 4 ];
 int x = 5;
-[ x, w ] = [ w, x ]; $\C{// all four tuple coercions}$
+[ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§
 \end{cfa}
 Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values;
@@ -3697,6 +4072,6 @@
 both these examples produce indeterminate results:
 \begin{cfa}
-f( x++, x++ ); $\C{// C routine call with side effects in arguments}$
-[ v1, v2 ] = [ x++, x++ ]; $\C{// side effects in right-hand side of multiple assignment}$
+f( x++, x++ ); §\C{// C routine call with side effects in arguments}§
+[ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in right-hand side of multiple assignment}§
 \end{cfa}
 
@@ -3797,5 +4172,5 @@
 \begin{cfa}
 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ];
-sout | t1 | t2; $\C{// print tuples}$
+sout | t1 | t2; §\C{// print tuples}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt]
@@ -3881,5 +4256,5 @@
 
 int main( int argc, char * argv[] ) {
-	®ifstream® in  = stdin;					$\C{// copy default files}$
+	®ifstream® in  = stdin;					§\C{// copy default files}§
 	®ofstream® out = stdout;
 
@@ -3887,24 +4262,24 @@
 		choose ( argc ) {
 		  case 2, 3:
-			®open®( in, argv[1] );			$\C{// open input file first as output creates file}$
-			if ( argc == 3 ) ®open®( out, argv[2] ); $\C{// do not create output unless input opens}$
-		  case 1: ;							$\C{// use default files}$
+			®open®( in, argv[1] );			§\C{// open input file first as output creates file}§
+			if ( argc == 3 ) ®open®( out, argv[2] ); §\C{// do not create output unless input opens}§
+		  case 1: ;							§\C{// use default files}§
 		  default:
 			®exit® | "Usage" | argv[0] | "[ input-file (default stdin) "
 				   "[ output-file (default stdout) ] ]";
 		} // choose
-	} catch( ®open_failure® * ex; ex->istream == &in ) { $\C{// input file errors}$
+	} catch( ®open_failure® * ex; ex->istream == &in ) { §\C{// input file errors}§
 		®exit® | "Unable to open input file" | argv[1];
-	} catch( ®open_failure® * ex; ex->ostream == &out ) { $\C{// output file errors}$
-		®close®( in );						$\C{// optional}$
+	} catch( ®open_failure® * ex; ex->ostream == &out ) { §\C{// output file errors}§
+		®close®( in );						§\C{// optional}§
 		®exit® | "Unable to open output file" | argv[2];
 	} // try
 
-	out | nlOff;							$\C{// turn off auto newline}$
-	in | nlOn;								$\C{// turn on reading newline}$
+	out | nlOff;							§\C{// turn off auto newline}§
+	in | nlOn;								§\C{// turn on reading newline}§
 	char ch;
-	for () {								$\C{// read/write characters}$
+	for () {								§\C{// read/write characters}§
 		in | ch;
-	  if ( eof( in ) ) break;				$\C{// eof ?}$
+	  if ( eof( in ) ) break;				§\C{// eof ?}§
 		out | ch;
 	} // for
@@ -3953,28 +4328,28 @@
 // *********************************** ofstream ***********************************
 
-bool fail( ofstream & );$\indexc{fail}\index{ofstream@©ofstream©!©fail©}$
-void clear( ofstream & );$\indexc{clear}\index{ofstream@©ofstream©!©clear©}$
-int flush( ofstream & );$\indexc{flush}\index{ofstream@©ofstream©!©flush©}$
-void open( ofstream &, const char name[], const char mode[] = "w" );$\indexc{open}\index{ofstream@©ofstream©!©open©}$
-void close( ofstream & );$\indexc{close}\index{ofstream@©ofstream©!©close©}$
-ofstream & write( ofstream &, const char data[], size_t size );$\indexc{write}\index{ofstream@©ofstream©!©write©}$
-
-void ?{}( ofstream & );$\index{ofstream@©ofstream©!©?{}©}$
+bool fail( ofstream & );§\indexc{fail}\index{ofstream@©ofstream©!©fail©}§
+void clear( ofstream & );§\indexc{clear}\index{ofstream@©ofstream©!©clear©}§
+int flush( ofstream & );§\indexc{flush}\index{ofstream@©ofstream©!©flush©}§
+void open( ofstream &, const char name[], const char mode[] = "w" );§\indexc{open}\index{ofstream@©ofstream©!©open©}§
+void close( ofstream & );§\indexc{close}\index{ofstream@©ofstream©!©close©}§
+ofstream & write( ofstream &, const char data[], size_t size );§\indexc{write}\index{ofstream@©ofstream©!©write©}§
+
+void ?{}( ofstream & );§\index{ofstream@©ofstream©!©?{}©}§
 void ?{}( ofstream &, const char name[], const char mode[] = "w" );
-void ^?{}( ofstream & );$\index{ofstream@©ofstream©!©^?{}©}$
+void ^?{}( ofstream & );§\index{ofstream@©ofstream©!©^?{}©}§
 
 // *********************************** ifstream ***********************************
 
-bool fail( ifstream & is );$\indexc{fail}\index{ifstream@©ifstream©!©fail©}$
-void clear( ifstream & );$\indexc{clear}\index{ifstream@©ifstream©!©clear©}$
-bool eof( ifstream & is );$\indexc{eof}\index{ifstream@©ifstream©!©eof©}$
-void open( ifstream & is, const char name[], const char mode[] = "r" );$\indexc{open}\index{ifstream@©ifstream©!©open©}$
-void close( ifstream & is );$\indexc{close}\index{ifstream@©ifstream©!©close©}$
-ifstream & read( ifstream & is, char data[], size_t size );$\indexc{read}\index{ifstream@©ifstream©!©read©}$
-ifstream & ungetc( ifstream & is, char c );$\indexc{unget}\index{ifstream@©ifstream©!©unget©}$
-
-void ?{}( ifstream & is );$\index{ifstream@©ifstream©!©?{}©}$
+bool fail( ifstream & is );§\indexc{fail}\index{ifstream@©ifstream©!©fail©}§
+void clear( ifstream & );§\indexc{clear}\index{ifstream@©ifstream©!©clear©}§
+bool eof( ifstream & is );§\indexc{eof}\index{ifstream@©ifstream©!©eof©}§
+void open( ifstream & is, const char name[], const char mode[] = "r" );§\indexc{open}\index{ifstream@©ifstream©!©open©}§
+void close( ifstream & is );§\indexc{close}\index{ifstream@©ifstream©!©close©}§
+ifstream & read( ifstream & is, char data[], size_t size );§\indexc{read}\index{ifstream@©ifstream©!©read©}§
+ifstream & ungetc( ifstream & is, char c );§\indexc{unget}\index{ifstream@©ifstream©!©unget©}§
+
+void ?{}( ifstream & is );§\index{ifstream@©ifstream©!©?{}©}§
 void ?{}( ifstream & is, const char name[], const char mode[] = "r" );
-void ^?{}( ifstream & is );$\index{ifstream@©ifstream©!©^?{}©}$
+void ^?{}( ifstream & is );§\index{ifstream@©ifstream©!©^?{}©}§
 \end{cfa}
 \caption{Stream Functions}
@@ -4063,5 +4438,5 @@
 The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
 \begin{cfa}[belowskip=0pt]
-sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$
+sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); §\C{// set separator from " " to ", \$"}§
 sout | 1 | 2 | 3 | " \"" | ®sepVal® | "\"";
 \end{cfa}
@@ -4070,5 +4445,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sepSet( sout, " " ); $\C{// reset separator to " "}$
+sepSet( sout, " " ); §\C{// reset separator to " "}§
 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\"";
 \end{cfa}
@@ -4078,7 +4453,7 @@
 ©sepGet© can be used to store a separator and then restore it:
 \begin{cfa}[belowskip=0pt]
-char store[®sepSize®]; $\C{// sepSize is the maximum separator size}$
-strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$
-sepSet( sout, "_" ); $\C{// change separator to underscore}$
+char store[®sepSize®]; §\C{// sepSize is the maximum separator size}§
+strcpy( store, sepGet( sout ) ); §\C{// copy current separator}§
+sepSet( sout, "_" ); §\C{// change separator to underscore}§
 sout | 1 | 2 | 3;
 \end{cfa}
@@ -4087,5 +4462,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sepSet( sout, store ); $\C{// change separator back to original}$
+sepSet( sout, store ); §\C{// change separator back to original}§
 sout | 1 | 2 | 3;
 \end{cfa}
@@ -4098,5 +4473,5 @@
 The tuple separator-string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
 \begin{cfa}[belowskip=0pt]
-sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$
+sepSetTuple( sout, " " ); §\C{// set tuple separator from ", " to " "}§
 sout | t1 | t2 | " \"" | ®sepTupleVal® | "\"";
 \end{cfa}
@@ -4105,5 +4480,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$
+sepSetTuple( sout, ", " ); §\C{// reset tuple separator to ", "}§
 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\"";
 \end{cfa}
@@ -4116,5 +4491,5 @@
 \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} and \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} globally toggle printing the separator.
 \begin{cfa}[belowskip=0pt]
-sout | ®sepOff® | 1 | 2 | 3; $\C{// turn off implicit separator}$
+sout | ®sepOff® | 1 | 2 | 3; §\C{// turn off implicit separator}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4122,5 +4497,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sout | ®sepOn® | 1 | 2 | 3; $\C{// turn on implicit separator}$
+sout | ®sepOn® | 1 | 2 | 3; §\C{// turn on implicit separator}§
 \end{cfa}
 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4131,5 +4506,5 @@
 \Indexc{sep}\index{manipulator!sep@©sep©} and \Indexc{nosep}\index{manipulator!nosep@©nosep©} locally toggle printing the separator with respect to the next printed item, and then return to the global separator setting.
 \begin{cfa}[belowskip=0pt]
-sout | 1 | ®nosep® | 2 | 3; $\C{// turn off implicit separator for the next item}$
+sout | 1 | ®nosep® | 2 | 3; §\C{// turn off implicit separator for the next item}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4137,5 +4512,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sout | sepOff | 1 | ®sep® | 2 | 3; $\C{// turn on implicit separator for the next item}$
+sout | sepOff | 1 | ®sep® | 2 | 3; §\C{// turn on implicit separator for the next item}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4144,5 +4519,5 @@
 The tuple separator also responses to being turned on and off.
 \begin{cfa}[belowskip=0pt]
-sout | t1 | ®nosep® | t2; $\C{// turn off implicit separator for the next item}$
+sout | t1 | ®nosep® | t2; §\C{// turn off implicit separator for the next item}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4152,5 +4527,5 @@
 Use ©sep© to accomplish this functionality.
 \begin{cfa}[belowskip=0pt]
-sout | ®sep® | 1 | 2 | 3 | ®sep®; $\C{// sep does nothing at start/end of line}$
+sout | ®sep® | 1 | 2 | 3 | ®sep®; §\C{// sep does nothing at start/end of line}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4158,5 +4533,5 @@
 \end{cfa}
 \begin{cfa}[belowskip=0pt]
-sout | ®sepVal® | 1 | 2 | 3 | ®sepVal® ; $\C{// use sepVal to print separator at start/end of line}$
+sout | ®sepVal® | 1 | 2 | 3 | ®sepVal® ; §\C{// use sepVal to print separator at start/end of line}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -4197,9 +4572,9 @@
 \Indexc{nl}\index{manipulator!nl@©nl©} inserts a newline.
 \begin{cfa}
-sout | ®nl®; $\C{// only print newline}$
-sout | 2; $\C{// implicit newline}$
-sout | 3 | ®nl® | 4 | ®nl®; $\C{// terminating nl merged with implicit newline}$
-sout | 5 | ®nl® | ®nl®; $\C{// again terminating nl merged with implicit newline}$
-sout | 6; $\C{// implicit newline}$
+sout | ®nl®; §\C{// only print newline}§
+sout | 2; §\C{// implicit newline}§
+sout | 3 | ®nl® | 4 | ®nl®; §\C{// terminating nl merged with implicit newline}§
+sout | 5 | ®nl® | ®nl®; §\C{// again terminating nl merged with implicit newline}§
+sout | 6; §\C{// implicit newline}§
 
 2
@@ -4648,5 +5023,5 @@
 ®mutex( sout )® {
 	sout | 1;
-	®mutex( sout ) sout® | 2 | 3;				$\C{// unnecessary, but ok because of recursive lock}$
+	®mutex( sout ) sout® | 2 | 3;				§\C{// unnecessary, but ok because of recursive lock}§
 	sout | 4;
 } // implicitly release sout lock
@@ -4660,5 +5035,5 @@
 	int x, y, z, w;
 	sin | x;
-	®mutex( sin )® sin | y | z;					$\C{// unnecessary, but ok because of recursive lock}$
+	®mutex( sin )® sin | y | z;					§\C{// unnecessary, but ok because of recursive lock}§
 	sin | w;
 } // implicitly release sin lock
@@ -4669,5 +5044,5 @@
 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
 \begin{cfa}
-®mutex( sout )® sout | "data:" | rtn( mon );	$\C{// mutex call on monitor}$
+®mutex( sout )® sout | "data:" | rtn( mon );	§\C{// mutex call on monitor}§
 \end{cfa}
 If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it.
@@ -4687,6 +5062,6 @@
 \begin{cfa}
 12®,®345®.®123		$\C[1.25in]{// comma separator, period decimal-point}$
-12®.®345®,®123		$\C{// period separator, comma decimal-point}$
-12$\Sp$345®,®123®.®	$\C{// space separator, comma decimal-point, period terminator}\CRT$
+12®.®345®,®123		§\C{// period separator, comma decimal-point}§
+12$\Sp$345®,®123®.®	§\C{// space separator, comma decimal-point, period terminator}\CRT§
 \end{cfa}
 A locale is selected with function ©setlocale©, and the corresponding locale package \emph{must} be installed on the underlying system;
@@ -4699,6 +5074,6 @@
 \begin{cfa}
 #include <fstream.hfa>
-#include <locale.h>							$\C{// setlocale}$
-#include <stdlib.h>							$\C{// getenv}$
+#include <locale.h>							§\C{// setlocale}§
+#include <stdlib.h>							§\C{// getenv}§
 
 int main() {
@@ -4772,15 +5147,15 @@
 int main() {
 	enum { size = 256 };
-	char buf[size]; $\C{// output buffer}$
-	®ostrstream osstr = { buf, size };® $\C{// bind output buffer/size}$
+	char buf[size]; §\C{// output buffer}§
+	®ostrstream osstr = { buf, size };® §\C{// bind output buffer/size}§
 	int i = 3, j = 5, k = 7;
 	double x = 12345678.9, y = 98765.4321e-11;
 
 	osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
-	write( osstr ); $\C{// write string to stdout}$
-	printf( "%s", buf ); $\C{// same lines of output}$
+	write( osstr ); §\C{// write string to stdout}§
+	printf( "%s", buf ); §\C{// same lines of output}§
 	sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
 
-	char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$
+	char buf2[] = "12 14 15 3.5 7e4 abc"; §\C{// input buffer}§
 	®istrstream isstr = { buf2 };®
 	char s[10];
@@ -4934,5 +5309,5 @@
 // Subsequent arguments can be specified for initialization
 
-void ?{}( Widget & w ) { $\C{// default constructor}$
+void ?{}( Widget & w ) { §\C{// default constructor}§
 	w.id = -1;
 	w.size = 0.0;
@@ -4948,5 +5323,5 @@
 
 // ^?{} is the destructor operator identifier
-void ^?{}( Widget & w ) { $\C{// destructor}$
+void ^?{}( Widget & w ) { §\C{// destructor}§
 	w.id = 0;
 	w.size = 0.0;
@@ -4957,10 +5332,10 @@
 }
 
-Widget baz; $\C{// reserve space only}$
-Widget foo{}; $\C{// calls default constructor}$
-Widget bar{ 23, 2.45 }; $\C{// calls constructor with values}$
-baz{ 24, 0.91 }; $\C{// calls constructor with values}$
-?{}( baz, 24, 0.91 ); $\C{// explicit call to constructor}$
-^?{} (bar ); $\C{// explicit call to destructor}$
+Widget baz; §\C{// reserve space only}§
+Widget foo{}; §\C{// calls default constructor}§
+Widget bar{ 23, 2.45 }; §\C{// calls constructor with values}§
+baz{ 24, 0.91 }; §\C{// calls constructor with values}§
+?{}( baz, 24, 0.91 ); §\C{// explicit call to constructor}§
+^?{} (bar ); §\C{// explicit call to destructor}§
 \end{cfa}
 \caption{Constructors and Destructors}
@@ -5480,25 +5855,25 @@
 
 ®coroutine® Fibonacci {
-	int fn; $\C{// used for communication}$
+	int fn; §\C{// used for communication}§
 };
 
-void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$
-	int fn1, fn2; $\C{// retained between resumes}$
-	fn = 0;  fn1 = fn; $\C{// 1st case}$
-	®suspend;® $\C{// restart last resume}$
-	fn = 1;  fn2 = fn1;  fn1 = fn; $\C{// 2nd case}$
-	®suspend;® $\C{// restart last resume}$
+void main( Fibonacci & fib ) with( fib ) { §\C{// called on first resume}§
+	int fn1, fn2; §\C{// retained between resumes}§
+	fn = 0;  fn1 = fn; §\C{// 1st case}§
+	®suspend;® §\C{// restart last resume}§
+	fn = 1;  fn2 = fn1;  fn1 = fn; §\C{// 2nd case}§
+	®suspend;® §\C{// restart last resume}§
 	for () {
-		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; $\C{// general case}$
-		®suspend;® $\C{// restart last resume}$
+		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; §\C{// general case}§
+		®suspend;® §\C{// restart last resume}§
 	}
 }
 int next( Fibonacci & fib ) with( fib ) {
-	®resume( fib );® $\C{// restart last suspend}$
+	®resume( fib );® §\C{// restart last suspend}§
 	return fn;
 }
 int main() {
 	Fibonacci f1, f2;
-	for ( 10 ) { $\C{// print N Fibonacci values}$
+	for ( 10 ) { §\C{// print N Fibonacci values}§
 		sout | next( f1 ) | next( f2 );
 	}
@@ -5538,10 +5913,10 @@
 int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; }
 int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; }
-forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$
+forall( ostype & | ostream( ostype ) ) { §\C{// print any stream}§
 	ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; }
 	void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); }
 }
 
-AtomicCnt global; $\C{// shared}$
+AtomicCnt global; §\C{// shared}§
 
 thread MyThread {};
@@ -5554,9 +5929,9 @@
 int main() {
 	enum { Threads = 4 };
-	processor p[Threads - 1]; $\C{// + starting processor}$
+	processor p[Threads - 1]; §\C{// + starting processor}§
 	{
 		MyThread t[Threads];
 	}
-	sout | global; $\C{// print 0}$
+	sout | global; §\C{// print 0}§
 }
 \end{cfa}
@@ -7031,6 +7406,6 @@
 In \CFA, there are ambiguous cases with dereference and operator identifiers, \eg ©int *?*?()©, where the string ©*?*?© can be interpreted as:
 \begin{cfa}
-*?$\Sp$*? $\C{// dereference operator, dereference operator}$
-*$\Sp$?*? $\C{// dereference, multiplication operator}$
+*?$\Sp$*? §\C{// dereference operator, dereference operator}§
+*$\Sp$?*? §\C{// dereference, multiplication operator}§
 \end{cfa}
 By default, the first interpretation is selected, which does not yield a meaningful parse.
@@ -7084,13 +7459,13 @@
 \eg:
 \begin{cfa}
-x; $\C{// int x}$
-*y; $\C{// int *y}$
-f( p1, p2 ); $\C{// int f( int p1, int p2 );}$
-g( p1, p2 ) int p1, p2; $\C{// int g( int p1, int p2 );}$
+x; §\C{// int x}§
+*y; §\C{// int *y}§
+f( p1, p2 ); §\C{// int f( int p1, int p2 );}§
+g( p1, p2 ) int p1, p2; §\C{// int g( int p1, int p2 );}§
 \end{cfa}
 \CFA continues to support K\&R routine definitions:
 \begin{cfa}
-f( a, b, c ) $\C{// default int return}$
-	int a, b; char c $\C{// K\&R parameter declarations}$
+f( a, b, c ) §\C{// default int return}§
+	int a, b; char c §\C{// K\&R parameter declarations}§
 {
 	...
@@ -7111,5 +7486,5 @@
 int rtn( int i );
 int rtn( char c );
-rtn( 'x' ); $\C{// programmer expects 2nd rtn to be called}$
+rtn( 'x' ); §\C{// programmer expects 2nd rtn to be called}§
 \end{cfa}
 \item[Rationale:] it is more intuitive for the call to ©rtn© to match the second version of definition of ©rtn© rather than the first.
@@ -7133,6 +7508,6 @@
 \item[Change:] make string literals ©const©:
 \begin{cfa}
-char * p = "abc"; $\C{// valid in C, deprecated in \CFA}$
-char * q = expr ? "abc" : "de"; $\C{// valid in C, invalid in \CFA}$
+char * p = "abc"; §\C{// valid in C, deprecated in \CFA}§
+char * q = expr ? "abc" : "de"; §\C{// valid in C, invalid in \CFA}§
 \end{cfa}
 The type of a string literal is changed from ©[] char© to ©const [] char©.
@@ -7141,5 +7516,5 @@
 \begin{cfa}
 char * p = "abc";
-p[0] = 'w'; $\C{// segment fault or change constant literal}$
+p[0] = 'w'; §\C{// segment fault or change constant literal}§
 \end{cfa}
 The same problem occurs when passing a string literal to a routine that changes its argument.
@@ -7153,7 +7528,7 @@
 \item[Change:] remove \newterm{tentative definitions}, which only occurs at file scope:
 \begin{cfa}
-int i; $\C{// forward definition}$
-int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$
-int i = 0; $\C{// definition}$
+int i; §\C{// forward definition}§
+int *j = ®&i®; §\C{// forward reference, valid in C, invalid in \CFA}§
+int i = 0; §\C{// definition}§
 \end{cfa}
 is valid in C, and invalid in \CFA because duplicate overloaded object definitions at the same scope level are disallowed.
@@ -7161,7 +7536,7 @@
 \begin{cfa}
 struct X { int i; struct X *next; };
-static struct X a; $\C{// forward definition}$
-static struct X b = { 0, ®&a® };$\C{// forward reference, valid in C, invalid in \CFA}$
-static struct X a = { 1, &b }; $\C{// definition}$
+static struct X a; §\C{// forward definition}§
+static struct X b = { 0, ®&a® };§\C{// forward reference, valid in C, invalid in \CFA}§
+static struct X a = { 1, &b }; §\C{// definition}§
 \end{cfa}
 \item[Rationale:] avoids having different initialization rules for builtin types and user-defined types.
@@ -7178,14 +7553,14 @@
 struct Person {
 	enum ®Colour® { R, G, B };	$\C[7cm]{// nested type}$
-	struct Face { $\C{// nested type}$
-		®Colour® Eyes, Hair; $\C{// type defined outside (1 level)}$
+	struct Face { §\C{// nested type}§
+		®Colour® Eyes, Hair; §\C{// type defined outside (1 level)}§
 	};
-	®.Colour® shirt; $\C{// type defined outside (top level)}$
-	®Colour® pants; $\C{// type defined same level}$
-	Face looks[10]; $\C{// type defined same level}$
+	®.Colour® shirt; §\C{// type defined outside (top level)}§
+	®Colour® pants; §\C{// type defined same level}§
+	Face looks[10]; §\C{// type defined same level}§
 };
-®Colour® c = R; $\C{// type/enum defined same level}$
-Person®.Colour® pc = Person®.®R;$\C{// type/enum defined inside}$
-Person®.®Face pretty; $\C{// type defined inside}\CRT$
+®Colour® c = R; §\C{// type/enum defined same level}§
+Person®.Colour® pc = Person®.®R;§\C{// type/enum defined inside}§
+Person®.®Face pretty; §\C{// type defined inside}\CRT§
 \end{cfa}
 In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing.
@@ -7204,5 +7579,5 @@
 \item[Difficulty of converting:] Semantic transformation. To make the struct type name visible in the scope of the enclosing struct, the struct tag could be declared in the scope of the enclosing struct, before the enclosing struct is defined. Example:
 \begin{cfa}
-struct Y; $\C{// struct Y and struct X are at the same scope}$
+struct Y; §\C{// struct Y and struct X are at the same scope}§
 struct X {
 	struct Y { /* ... */ } y;
@@ -7219,6 +7594,6 @@
 \begin{cfa}
 void foo() {
-	int * b = malloc( sizeof(int) ); $\C{// implicitly convert void * to int *}$
-	char * c = b; $\C{// implicitly convert int * to void *, and then void * to char *}$
+	int * b = malloc( sizeof(int) ); §\C{// implicitly convert void * to int *}§
+	char * c = b; §\C{// implicitly convert int * to void *, and then void * to char *}§
 }
 \end{cfa}
@@ -7462,7 +7837,7 @@
 Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
 \begin{cfa}
-int * ip = (int *)malloc( sizeof(int) );		$\C{// C}$
-int * ip = malloc();							$\C{// \CFA type-safe version of C malloc}$
-int * ip = alloc();								$\C{// \CFA type-safe uniform alloc}$
+int * ip = (int *)malloc( sizeof(int) );		§\C{// C}§
+int * ip = malloc();							§\C{// \CFA type-safe version of C malloc}§
+int * ip = alloc();								§\C{// \CFA type-safe uniform alloc}§
 \end{cfa}
 the latter two allocations determine the allocation size from the type of ©p© (©int©) and cast the pointer to the allocated storage to ©int *©.
@@ -7471,5 +7846,5 @@
 \begin{cfa}
 struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
-S * sp = malloc();								$\C{// honour type alignment}$
+S * sp = malloc();								§\C{// honour type alignment}§
 \end{cfa}
 the storage allocation is implicitly aligned to 128 rather than the default 16.
@@ -7486,13 +7861,13 @@
 \CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
 \begin{cfa}
-struct S { int i; };							$\C{// cache-line alignment}$
+struct S { int i; };							§\C{// cache-line alignment}§
 void ?{}( S & s, int i ) { s.i = i; }
 // assume ?|? operator for printing an S
 
-S & sp = *®new®( 3 );							$\C{// call constructor after allocation}$
+S & sp = *®new®( 3 );							§\C{// call constructor after allocation}§
 sout | sp.i;
 ®delete®( &sp );
 
-S * spa = ®anew®( 10, 5 );						$\C{// allocate array and initialize each array element}$
+S * spa = ®anew®( 10, 5 );						§\C{// allocate array and initialize each array element}§
 for ( i; 10 ) sout | spa[i] | nonl;
 sout | nl;
@@ -7533,25 +7908,25 @@
 	// $\CFA$ safe general allocation, fill, resize, alignment, array
 	T * alloc( void );$\indexc{alloc}$					$\C[3.5in]{// variable, T size}$
-	T * alloc( size_t dim );							$\C{// array[dim], T size elements}$
-	T * alloc( T ptr[], size_t dim );					$\C{// realloc array[dim], T size elements}$
-
-	T * alloc_set( char fill );$\indexc{alloc_set}$		$\C{// variable, T size, fill bytes with value}$
-	T * alloc_set( T fill );							$\C{// variable, T size, fill with value}$
-	T * alloc_set( size_t dim, char fill );				$\C{// array[dim], T size elements, fill bytes with value}$
-	T * alloc_set( size_t dim, T fill );				$\C{// array[dim], T size elements, fill elements with value}$
-	T * alloc_set( size_t dim, const T fill[] );		$\C{// array[dim], T size elements, fill elements with array}$
-	T * alloc_set( T ptr[], size_t dim, char fill );	$\C{// realloc array[dim], T size elements, fill bytes with value}$
-
-	T * alloc_align( size_t align );					$\C{// aligned variable, T size}$
-	T * alloc_align( size_t align, size_t dim );		$\C{// aligned array[dim], T size elements}$
-	T * alloc_align( T ptr[], size_t align );			$\C{// realloc new aligned array}$
-	T * alloc_align( T ptr[], size_t align, size_t dim ); $\C{// realloc new aligned array[dim]}$
-
-	T * alloc_align_set( size_t align, char fill );		$\C{// aligned variable, T size, fill bytes with value}$
-	T * alloc_align_set( size_t align, T fill );		$\C{// aligned variable, T size, fill with value}$
-	T * alloc_align_set( size_t align, size_t dim, char fill ); $\C{// aligned array[dim], T size elements, fill bytes with value}$
-	T * alloc_align_set( size_t align, size_t dim, T fill ); $\C{// aligned array[dim], T size elements, fill elements with value}$
-	T * alloc_align_set( size_t align, size_t dim, const T fill[] ); $\C{// aligned array[dim], T size elements, fill elements with array}$
-	T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); $\C{// realloc new aligned array[dim], fill new bytes with value}$
+	T * alloc( size_t dim );							§\C{// array[dim], T size elements}§
+	T * alloc( T ptr[], size_t dim );					§\C{// realloc array[dim], T size elements}§
+
+	T * alloc_set( char fill );$\indexc{alloc_set}$		§\C{// variable, T size, fill bytes with value}§
+	T * alloc_set( T fill );							§\C{// variable, T size, fill with value}§
+	T * alloc_set( size_t dim, char fill );				§\C{// array[dim], T size elements, fill bytes with value}§
+	T * alloc_set( size_t dim, T fill );				§\C{// array[dim], T size elements, fill elements with value}§
+	T * alloc_set( size_t dim, const T fill[] );		§\C{// array[dim], T size elements, fill elements with array}§
+	T * alloc_set( T ptr[], size_t dim, char fill );	§\C{// realloc array[dim], T size elements, fill bytes with value}§
+
+	T * alloc_align( size_t align );					§\C{// aligned variable, T size}§
+	T * alloc_align( size_t align, size_t dim );		§\C{// aligned array[dim], T size elements}§
+	T * alloc_align( T ptr[], size_t align );			§\C{// realloc new aligned array}§
+	T * alloc_align( T ptr[], size_t align, size_t dim ); §\C{// realloc new aligned array[dim]}§
+
+	T * alloc_align_set( size_t align, char fill );		§\C{// aligned variable, T size, fill bytes with value}§
+	T * alloc_align_set( size_t align, T fill );		§\C{// aligned variable, T size, fill with value}§
+	T * alloc_align_set( size_t align, size_t dim, char fill ); §\C{// aligned array[dim], T size elements, fill bytes with value}§
+	T * alloc_align_set( size_t align, size_t dim, T fill ); §\C{// aligned array[dim], T size elements, fill elements with value}§
+	T * alloc_align_set( size_t align, size_t dim, const T fill[] ); §\C{// aligned array[dim], T size elements, fill elements with array}§
+	T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); §\C{// realloc new aligned array[dim], fill new bytes with value}§
 
 	// $\CFA$ safe initialization/copy, i.e., implicit size specification
@@ -7614,8 +7989,8 @@
 \leavevmode
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-forall( T | { int ?<?( T, T ); } ) $\C{// location}$
+forall( T | { int ?<?( T, T ); } ) §\C{// location}§
 T * bsearch( T key, const T * arr, size_t dim );$\indexc{bsearch}$
 
-forall( T | { int ?<?( T, T ); } ) $\C{// position}$
+forall( T | { int ?<?( T, T ); } ) §\C{// position}§
 unsigned int bsearch( T key, const T * arr, size_t dim );
 
@@ -7624,6 +7999,6 @@
 
 forall( E | { int ?<?( E, E ); } ) {
-	E * bsearch( E key, const E * vals, size_t dim );$\indexc{bsearch}$ $\C{// location}$
-	size_t bsearch( E key, const E * vals, size_t dim );$\C{// position}$
+	E * bsearch( E key, const E * vals, size_t dim );$\indexc{bsearch}$ §\C{// location}§
+	size_t bsearch( E key, const E * vals, size_t dim );§\C{// position}§
 	E * bsearchl( E key, const E * vals, size_t dim );$\indexc{bsearchl}$
 	size_t bsearchl( E key, const E * vals, size_t dim );
@@ -7672,23 +8047,23 @@
 void srandom( unsigned int seed );$\indexc{srandom}$
 char random( void );$\indexc{random}$
-char random( char u ); $\C{// [0,u)}$
-char random( char l, char u ); $\C{// [l,u]}$
+char random( char u ); §\C{// [0,u)}§
+char random( char l, char u ); §\C{// [l,u]}§
 int random( void );
-int random( int u ); $\C{// [0,u)}$
-int random( int l, int u ); $\C{// [l,u]}$
+int random( int u ); §\C{// [0,u)}§
+int random( int l, int u ); §\C{// [l,u]}§
 unsigned int random( void );
-unsigned int random( unsigned int u ); $\C{// [0,u)}$
-unsigned int random( unsigned int l, unsigned int u ); $\C{// [l,u]}$
+unsigned int random( unsigned int u ); §\C{// [0,u)}§
+unsigned int random( unsigned int l, unsigned int u ); §\C{// [l,u]}§
 long int random( void );
-long int random( long int u ); $\C{// [0,u)}$
-long int random( long int l, long int u ); $\C{// [l,u]}$
+long int random( long int u ); §\C{// [0,u)}§
+long int random( long int l, long int u ); §\C{// [l,u]}§
 unsigned long int random( void );
-unsigned long int random( unsigned long int u ); $\C{// [0,u)}$
-unsigned long int random( unsigned long int l, unsigned long int u ); $\C{// [l,u]}$
-float random( void );						 $\C{// [0.0, 1.0)}$
-double random( void );						 $\C{// [0.0, 1.0)}$
-float _Complex random( void );				 $\C{// [0.0, 1.0)+[0.0, 1.0)i}$
-double _Complex random( void );				 $\C{// [0.0, 1.0)+[0.0, 1.0)i}$
-long double _Complex random( void );		 $\C{// [0.0, 1.0)+[0.0, 1.0)i}$
+unsigned long int random( unsigned long int u ); §\C{// [0,u)}§
+unsigned long int random( unsigned long int l, unsigned long int u ); §\C{// [l,u]}§
+float random( void );						 §\C{// [0.0, 1.0)}§
+double random( void );						 §\C{// [0.0, 1.0)}§
+float _Complex random( void );				 §\C{// [0.0, 1.0)+[0.0, 1.0)i}§
+double _Complex random( void );				 §\C{// [0.0, 1.0)+[0.0, 1.0)i}§
+long double _Complex random( void );		 §\C{// [0.0, 1.0)+[0.0, 1.0)i}§
 \end{cfa}
 
@@ -7889,5 +8264,5 @@
 long double atan2( long double, long double );
 
-float atan( float, float ); $\C{// alternative name for atan2}$
+float atan( float, float ); §\C{// alternative name for atan2}§
 double atan( double, double );$\indexc{atan}$
 long double atan( long double, long double );
@@ -8116,5 +8491,5 @@
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
 struct Duration {
-	int64_t tn; $\C{// nanoseconds}$
+	int64_t tn; §\C{// nanoseconds}§
 };
 
@@ -8261,5 +8636,5 @@
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
 struct Time {
-	uint64_t tn; $\C{// nanoseconds since UNIX epoch}$
+	uint64_t tn; §\C{// nanoseconds since UNIX epoch}§
 };
 
@@ -8326,24 +8701,24 @@
 \leavevmode
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-struct Clock { $\C{// virtual clock}$
-	Duration offset; $\C{// offset from computer real-time}$
+struct Clock { §\C{// virtual clock}§
+	Duration offset; §\C{// offset from computer real-time}§
 };
 
-void ?{}( Clock & clk ); $\C{// create no offset}$
-void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$
-void reset( Clock & clk, Duration adj ); $\C{// change offset}$
-
-Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$
-Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$
-
-Time timeHiRes(); $\C{// real time with nanoseconds}$
-Time time(); $\C{// real time without nanoseconds}$
-Time time( Clock & clk ); $\C{// real time for given clock}$
-Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$
-timeval time( Clock & clk ); $\C{// convert to C time format}$
+void ?{}( Clock & clk ); §\C{// create no offset}§
+void ?{}( Clock & clk, Duration adj ); §\C{// create with offset}§
+void reset( Clock & clk, Duration adj ); §\C{// change offset}§
+
+Duration resolutionHi(); §\C{// clock resolution in nanoseconds (fine)}§
+Duration resolution(); §\C{// clock resolution without nanoseconds (coarse)}§
+
+Time timeHiRes(); §\C{// real time with nanoseconds}§
+Time time(); §\C{// real time without nanoseconds}§
+Time time( Clock & clk ); §\C{// real time for given clock}§
+Time ?()( Clock & clk ); §\C{//\ \ \ \ alternative syntax}§
+timeval time( Clock & clk ); §\C{// convert to C time format}§
 tm time( Clock & clk );
-Duration processor(); $\C{// non-monotonic duration of kernel thread}$
-Duration program(); $\C{// non-monotonic duration of program CPU}$
-Duration boot(); $\C{// monotonic duration since computer boot}$
+Duration processor(); §\C{// non-monotonic duration of kernel thread}§
+Duration program(); §\C{// non-monotonic duration of program CPU}§
+Duration boot(); §\C{// monotonic duration since computer boot}§
 \end{cfa}
 
@@ -8386,12 +8761,12 @@
 \begin{cfa}
 struct PRNG { ... }; $\C[3.75in]{// opaque type}$
-void ?{}( PRNG & prng ); $\C{// random seed}$
-void ?{}( PRNG & prng, uint32_t seed ); $\C{// fixed seed}$
-void set_seed( PRNG & prng, uint32_t seed ); $\C{// set seed}$
-uint32_t get_seed( PRNG & prng ); $\C{// get seed}$
-uint32_t prng( PRNG & prng ); $\C{// [0,UINT\_MAX]}$
-uint32_t prng( PRNG & prng, uint32_t u ); $\C{// [0,u)}$
-uint32_t prng( PRNG & prng, uint32_t l, uint32_t u ); $\C{// [l,u]}$
-uint32_t calls( PRNG & prng ); $\C{// number of calls}\CRT$
+void ?{}( PRNG & prng ); §\C{// random seed}§
+void ?{}( PRNG & prng, uint32_t seed ); §\C{// fixed seed}§
+void set_seed( PRNG & prng, uint32_t seed ); §\C{// set seed}§
+uint32_t get_seed( PRNG & prng ); §\C{// get seed}§
+uint32_t prng( PRNG & prng ); §\C{// [0,UINT\_MAX]}§
+uint32_t prng( PRNG & prng, uint32_t u ); §\C{// [0,u)}§
+uint32_t prng( PRNG & prng, uint32_t l, uint32_t u ); §\C{// [l,u]}§
+uint32_t calls( PRNG & prng ); §\C{// number of calls}\CRT§
 \end{cfa}
 A ©PRNG© object is used to randomize behaviour or values during execution, \eg in games, a character makes a random move or an object takes on a random value.
@@ -8447,13 +8822,13 @@
 \begin{cfa}
 void set_seed( uint32_t seed ); $\C[3.75in]{// set global seed}$
-uint32_t get_seed(); $\C{// get global seed}$
+uint32_t get_seed(); §\C{// get global seed}§
 // SLOWER
-uint32_t prng(); $\C{// [0,UINT\_MAX]}$
-uint32_t prng( uint32_t u ); $\C{// [0,u)}$
-uint32_t prng( uint32_t l, uint32_t u ); $\C{// [l,u]}$
+uint32_t prng(); §\C{// [0,UINT\_MAX]}§
+uint32_t prng( uint32_t u ); §\C{// [0,u)}§
+uint32_t prng( uint32_t l, uint32_t u ); §\C{// [l,u]}§
 // FASTER
-uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th );	$\C{// [0,UINT\_MAX]}$
-uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t u );	$\C{// [0,u)}$
-uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t l, uint32_t u );	$\C{// [l,u]}\CRT$
+uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th );	§\C{// [0,UINT\_MAX]}§
+uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t u );	§\C{// [0,u)}§
+uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t l, uint32_t u );	§\C{// [l,u]}\CRT§
 \end{cfa}
 The only difference between the two sets of ©prng© routines is performance.
@@ -8536,5 +8911,5 @@
 
 \begin{cfa}
-void ?{}( Int * this ); $\C{// constructor/destructor}$
+void ?{}( Int * this ); §\C{// constructor/destructor}§
 void ?{}( Int * this, Int init );
 void ?{}( Int * this, zero_t );
@@ -8545,5 +8920,5 @@
 void ^?{}( Int * this );
 
-Int ?=?( Int * lhs, Int rhs ); $\C{// assignment}$
+Int ?=?( Int * lhs, Int rhs ); §\C{// assignment}§
 Int ?=?( Int * lhs, long int rhs );
 Int ?=?( Int * lhs, unsigned long int rhs );
@@ -8562,5 +8937,5 @@
 unsigned long int narrow( Int val );
 
-int ?==?( Int oper1, Int oper2 ); $\C{// comparison}$
+int ?==?( Int oper1, Int oper2 ); §\C{// comparison}§
 int ?==?( Int oper1, long int oper2 );
 int ?==?( long int oper2, Int oper1 );
@@ -8598,5 +8973,5 @@
 int ?>=?( unsigned long int oper1, Int oper2 );
 
-Int +?( Int oper ); $\C{// arithmetic}$
+Int +?( Int oper ); §\C{// arithmetic}§
 Int -?( Int oper );
 Int ~?( Int oper );
@@ -8680,5 +9055,5 @@
 Int ?>>=?( Int * lhs, mp_bitcnt_t shift );
 
-Int abs( Int oper ); $\C{// number functions}$
+Int abs( Int oper ); §\C{// number functions}§
 Int fact( unsigned long int N );
 Int gcd( Int oper1, Int oper2 );
@@ -8692,5 +9067,5 @@
 Int sqrt( Int oper );
 
-forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  $\C{// I/O}$
+forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
 \end{cfa}
@@ -8791,8 +9166,8 @@
 // implementation
 struct Rational {$\indexc{Rational}$
-	long int numerator, denominator; $\C{// invariant: denominator > 0}$
+	long int numerator, denominator; §\C{// invariant: denominator > 0}§
 }; // Rational
 
-Rational rational(); $\C{// constructors}$
+Rational rational(); §\C{// constructors}§
 Rational rational( long int n );
 Rational rational( long int n, long int d );
@@ -8800,10 +9175,10 @@
 void ?{}( Rational * r, one_t );
 
-long int numerator( Rational r ); $\C{// numerator/denominator getter/setter}$
+long int numerator( Rational r ); §\C{// numerator/denominator getter/setter}§
 long int numerator( Rational r, long int n );
 long int denominator( Rational r );
 long int denominator( Rational r, long int d );
 
-int ?==?( Rational l, Rational r ); $\C{// comparison}$
+int ?==?( Rational l, Rational r ); §\C{// comparison}§
 int ?!=?( Rational l, Rational r );
 int ?<?( Rational l, Rational r );
@@ -8812,5 +9187,5 @@
 int ?>=?( Rational l, Rational r );
 
-Rational -?( Rational r ); $\C{// arithmetic}$
+Rational -?( Rational r ); §\C{// arithmetic}§
 Rational ?+?( Rational l, Rational r );
 Rational ?-?( Rational l, Rational r );
@@ -8818,5 +9193,5 @@
 Rational ?/?( Rational l, Rational r );
 
-double widen( Rational r ); $\C{// conversion}$
+double widen( Rational r ); §\C{// conversion}§
 Rational narrow( double f, long int md );
 
Index: libcfa/src/Makefile.am
===================================================================
--- libcfa/src/Makefile.am	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/Makefile.am	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -48,4 +48,5 @@
 	math.trait.hfa \
 	math.hfa \
+	raii.hfa \
 	time_t.hfa \
 	virtual_dtor.hfa \
Index: libcfa/src/collections/array.hfa
===================================================================
--- libcfa/src/collections/array.hfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/collections/array.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -131,13 +131,27 @@
 
     static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
-
-    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
-    static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {
-        void ?{}( S (&inner)[N] ) {}
-        ?{}(this.strides);
-    }
-    static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
-        void ^?{}( S (&inner)[N] ) {}
-        ^?{}(this.strides);
+}
+
+// RAII pattern has workarounds for
+//  - Trac 226:  Simplest handling would be, require immediate element to be otype, let autogen
+//    raii happen.  Performance on even a couple dimensions is unacceptable because of exponential
+//    thunk creation: ?{}() needs all four otype funcs from next level, so does ^?{}(), so do the
+//    other two.  This solution offers ?{}() that needs only ?{}(), and similar for ^?{}.
+
+forall( [N], S & | sized(S), Timmed &, Tbase & | { void ?{}( Timmed & ); } )
+static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {    
+    void ?{}( S (&)[N] ) {}
+    ?{}(this.strides);
+
+    for (i; N) ?{}( (Timmed &) this.strides[i] );
+}
+
+forall( [N], S & | sized(S), Timmed &, Tbase & | { void ^?{}( Timmed & ); } )
+static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
+    void ^?{}( S (&)[N] ) {}
+    ^?{}(this.strides);
+
+    for (i; N ) {
+        ^?{}( (Timmed &) this.strides[N-i-1] );
     }
 }
@@ -147,5 +161,5 @@
 //
 
-forall( Te )
+forall( Te * )
 static inline Te mkar_( tag(Te) ) {}
 
Index: libcfa/src/collections/string.cfa
===================================================================
--- libcfa/src/collections/string.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/collections/string.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Oct 18 21:52:09 2023
-// Update Count     : 208
+// Last Modified On : Sun Jan 14 12:03:47 2024
+// Update Count     : 240
 //
 
@@ -29,39 +29,49 @@
 // string RAII
 
-
-void ?{}( string & this ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner );
-}
-
 // private (not in header)
-static void ?{}( string & this, string_res & src, size_t start, size_t end ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, src, SHARE_EDITS, start, end );
-}
-
-void ?{}( string & this, const string & other ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, *other.inner, COPY_VALUE );
-}
-
-void ?{}( string & this, string & other ) {
-    ?{}( this, (const string &) other );
-}
-
-void ?{}( string & this, const char * val ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, val );
-}
-
-void ?{}( string & this, const char * buffer, size_t bsize) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, buffer, bsize );
-}
-
-void ^?{}( string & this ) {
-    ^(*this.inner){};
-    free( this.inner );
-    this.inner = 0p;
+static void ?{}( string & s, string_res & src, size_t start, size_t len ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, src, SHARE_EDITS, start, len );
+}
+
+void ?{}( string & s ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner );
+}
+
+void ?{}( string & s, const string & c ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, *c.inner, COPY_VALUE );
+}
+
+void ?{}( string & s, const string & s2, size_t maxlen) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, *s2.inner, COPY_VALUE, maxlen );
+}
+
+
+void ?{}( string & s, string & c ) {
+    ?{}( s, (const string &) c );
+}
+
+void ?{}( string & s, const char c ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, c );
+}
+
+void ?{}( string & s, const char * c ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, c );
+}
+
+void ?{}( string & s, const char * c, size_t size) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, c, size );
+}
+
+void ^?{}( string & s ) {
+    ^(*s.inner){};
+    free( s.inner );
+    s.inner = 0p;
 }
 
@@ -69,11 +79,11 @@
 // Alternate construction: request shared edits
 
-string_WithSharedEdits ?`shareEdits( string & this ) {
-    string_WithSharedEdits ret = { &this };
-    return ret;
-}
-
-void ?{}( string & this, string_WithSharedEdits src ) {
-    ?{}( this, *src.s->inner, 0, src.s->inner->Handle.lnth);
+string_WithSharedEdits ?`shareEdits( string & s ) {
+    string_WithSharedEdits ret = { &s };
+    return ret;
+}
+
+void ?{}( string & s, string_WithSharedEdits src ) {
+    ?{}( s, *src.s->inner, 0, src.s->inner->Handle.lnth);
 }
 
@@ -81,19 +91,26 @@
 // Assignment
 
-void ?=?( string & this, const char * val ) {
-    (*this.inner) = val;
-}
-
-void ?=?(string & this, const string & other) {
-    (*this.inner) = (*other.inner);
-}
-
-void ?=?( string & this, char val ) {
-    (*this.inner) = val;
-}
-
-string & ?=?(string & this, string & other) { //// <---- straw man change
-    (*this.inner) = (*other.inner);
-    return this;
+void ?=?( string & s, const char * val ) {
+    (*s.inner) = val;
+}
+
+// with and without const on "other" argument helps keep prevent autogen ?=? calls
+void ?=?(string & s, const string & c) {
+    (*s.inner) = (*c.inner);
+}
+string & ?=?(string & s, string & c) {
+    (*s.inner) = (*c.inner);
+    return s;
+}
+
+void ?=?( string & s, char val ) {
+    (*s.inner) = val;
+}
+
+void assign(string & s, const string & c, size_t n) {
+    assign(*s.inner, *c.inner, n);
+}
+void assign(string & s, const char * c, size_t n) {
+    assign(*s.inner, c, n);
 }
 
@@ -102,10 +119,10 @@
 // Input-Output
 
-ofstream & ?|?( ofstream & out, const string & this ) {
-    return out | (*this.inner); // print internal string_res
-}
-
-void ?|?( ofstream & out, const string & this ) {
-    (ofstream &)(out | (*this.inner)); ends( out );
+ofstream & ?|?( ofstream & out, const string & s ) {
+    return out | (*s.inner); // print internal string_res
+}
+
+void ?|?( ofstream & out, const string & s ) {
+    (ofstream &)(out | (*s.inner)); ends( out );
 }
 
@@ -124,10 +141,10 @@
 }
 
-ifstream & ?|?(ifstream & in, string & this) {
-    return in | (*this.inner); // read to internal string_res
-}
-
-void ?|?( ifstream & in, string & this ) {
-    in | (*this.inner);
+ifstream & ?|?(ifstream & in, string & s) {
+    return in | (*s.inner); // read to internal string_res
+}
+
+void ?|?( ifstream & in, string & s ) {
+    in | (*s.inner);
 }
 
@@ -144,11 +161,11 @@
 // Slicing
 
-string ?()( string & this, size_t start, size_t end ) {
-    string ret = { *this.inner, start, end };
+string ?()( string & s, size_t start, size_t len ) {
+    string ret = { *s.inner, start, len };
     return ret`shareEdits;
 }
 
-string ?()( string & this, size_t start ) {
-    string ret = { *this.inner, start, size( this ) };
+string ?()( string & s, size_t start ) {
+    string ret = { *s.inner, start, size( s ) - start };
     return ret`shareEdits;
 }
@@ -157,27 +174,27 @@
 // Comparison
 
-int  cmp (const string &s1, const string &s2) { return cmp(*s1.inner ,  *s2.inner); }
-bool ?==?(const string &s1, const string &s2) { return     *s1.inner == *s2.inner ; }
-bool ?!=?(const string &s1, const string &s2) { return     *s1.inner != *s2.inner ; }
-bool ?>? (const string &s1, const string &s2) { return     *s1.inner >  *s2.inner ; }
-bool ?>=?(const string &s1, const string &s2) { return     *s1.inner >= *s2.inner ; }
-bool ?<=?(const string &s1, const string &s2) { return     *s1.inner <= *s2.inner ; }
-bool ?<? (const string &s1, const string &s2) { return     *s1.inner <  *s2.inner ; }
-
-int  cmp (const string &s1, const char*   s2) { return cmp(*s1.inner ,   s2      ); }
-bool ?==?(const string &s1, const char*   s2) { return     *s1.inner ==  s2       ; }
-bool ?!=?(const string &s1, const char*   s2) { return     *s1.inner !=  s2       ; }
-bool ?>? (const string &s1, const char*   s2) { return     *s1.inner >   s2       ; }
-bool ?>=?(const string &s1, const char*   s2) { return     *s1.inner >=  s2       ; }
-bool ?<=?(const string &s1, const char*   s2) { return     *s1.inner <=  s2       ; }
-bool ?<? (const string &s1, const char*   s2) { return     *s1.inner <   s2       ; }
-
-int  cmp (const char*   s1, const string &s2) { return cmp( s1       ,  *s2.inner); }
-bool ?==?(const char*   s1, const string &s2) { return      s1       == *s2.inner ; }
-bool ?!=?(const char*   s1, const string &s2) { return      s1       != *s2.inner ; }
-bool ?>? (const char*   s1, const string &s2) { return      s1       >  *s2.inner ; }
-bool ?>=?(const char*   s1, const string &s2) { return      s1       >= *s2.inner ; }
-bool ?<=?(const char*   s1, const string &s2) { return      s1       <= *s2.inner ; }
-bool ?<? (const char*   s1, const string &s2) { return      s1       <  *s2.inner ; }
+int  strcmp(const string & s1, const string & s2) { return strcmp(*s1.inner, *s2.inner); }
+bool ?==?(const string & s1, const string & s2) { return *s1.inner == *s2.inner; }
+bool ?!=?(const string & s1, const string & s2) { return *s1.inner != *s2.inner; }
+bool ?>? (const string & s1, const string & s2) { return *s1.inner >  *s2.inner; }
+bool ?>=?(const string & s1, const string & s2) { return *s1.inner >= *s2.inner; }
+bool ?<=?(const string & s1, const string & s2) { return *s1.inner <= *s2.inner; }
+bool ?<? (const string & s1, const string & s2) { return *s1.inner <  *s2.inner; }
+
+int  strcmp(const string & s1, const char * s2) { return strcmp(*s1.inner, s2 ); }
+bool ?==?(const string & s1, const char * s2) { return *s1.inner == s2; }
+bool ?!=?(const string & s1, const char * s2) { return *s1.inner != s2; }
+bool ?>? (const string & s1, const char * s2) { return *s1.inner >  s2; }
+bool ?>=?(const string & s1, const char * s2) { return *s1.inner >= s2; }
+bool ?<=?(const string & s1, const char * s2) { return *s1.inner <= s2; }
+bool ?<? (const string & s1, const char * s2) { return *s1.inner <  s2; }
+
+int  strcmp(const char * s1, const string & s2) { return strcmp( s1, *s2.inner); }
+bool ?==?(const char * s1, const string & s2) { return s1 == *s2.inner; }
+bool ?!=?(const char * s1, const string & s2) { return s1 != *s2.inner; }
+bool ?>? (const char * s1, const string & s2) { return s1 >  *s2.inner; }
+bool ?>=?(const char * s1, const string & s2) { return s1 >= *s2.inner; }
+bool ?<=?(const char * s1, const string & s2) { return s1 <= *s2.inner; }
+bool ?<? (const char * s1, const string & s2) { return s1 <  *s2.inner; }
 
 
@@ -186,5 +203,5 @@
 
 size_t size(const string & s) {
-    return size( * s.inner );
+    return size( *s.inner );
 }
 
@@ -192,6 +209,6 @@
 // Concatenation
 
-void ?+=?(string & s, char other) {
-    (*s.inner) += other;
+void ?+=?(string & s, char c) {
+    (*s.inner) += c;
 }
 
@@ -200,11 +217,19 @@
 }
 
-void ?+=?(string & s, const char * other) {
-    (*s.inner) += other;
-}
-
-string ?+?(const string & s, char other) {
+void append(string & s, const string & s2, size_t maxlen) {
+    append( (*s.inner), (*s2.inner), maxlen );
+}
+
+void ?+=?(string & s, const char * c) {
+    (*s.inner) += c;
+}
+
+void append(string & s, const char * buffer, size_t bsize) {
+    append( (*s.inner), buffer, bsize );
+}
+
+string ?+?(const string & s, char c) {
     string ret = s;
-    ret += other;
+    ret += c;
     return ret;
 }
@@ -222,7 +247,7 @@
 }
 
-string ?+?(const string & s, const char * other) {
+string ?+?(const string & s, const char * c) {
     string ret = s;
-    ret += other;
+    ret += c;
     return ret;
 }
@@ -231,19 +256,24 @@
 // Repetition
 
+void ?*=?(string & s, size_t factor) {
+    (*s.inner) *= factor;
+}
+
 string ?*?(const string & s, size_t factor) {
-    string ret = "";
-    for (factor) ret += s;
-    return ret;
-}
-
-string ?*?(char c, size_t size) {
-    string ret = "";
-    for ((size_t)size) ret += c;
-    return ret;
-}
-
-string ?*?(const char *s, size_t factor) {
-    string ss = s;
-    return ss * factor;
+    string ret = s;
+    ret *= factor;
+    return ret;
+}
+
+string ?*?(char c, size_t factor) {
+    string ret = c;
+    ret *= factor;
+    return ret;
+}
+
+string ?*?(const char * s, size_t factor) {
+    string ret = s;
+    ret *= factor;
+    return ret;
 }
 
@@ -256,5 +286,5 @@
 
 string ?[?](string & s, size_t index) {
-    string ret = { *s.inner, index, index + 1 };
+    string ret = { *s.inner, index, 1 };
     return ret`shareEdits;
 }
@@ -339,23 +369,23 @@
 // charclass, include, exclude
 
-void ?{}( charclass & this, const string & chars) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, *(const string_res *)chars.inner );
-}
-
-void ?{}( charclass & this, const char * chars ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, chars );
-}
-
-void ?{}( charclass & this, const char * chars, size_t charssize ) {
-    (this.inner) { malloc() };
-    ?{}( *this.inner, chars, charssize );
-}
-
-void ^?{}( charclass & this ) {
-    ^(*this.inner){};
-    free( this.inner );
-    this.inner = 0p;
+void ?{}( charclass & s, const string & chars) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, *(const string_res *)chars.inner );
+}
+
+void ?{}( charclass & s, const char * chars ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, chars );
+}
+
+void ?{}( charclass & s, const char * chars, size_t charssize ) {
+    (s.inner) { malloc() };
+    ?{}( *s.inner, chars, charssize );
+}
+
+void ^?{}( charclass & s ) {
+    ^(*s.inner){};
+    free( s.inner );
+    s.inner = 0p;
 }
 
Index: libcfa/src/collections/string.hfa
===================================================================
--- libcfa/src/collections/string.hfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/collections/string.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep  2 11:26:28 2023
-// Update Count     : 55
+// Last Modified On : Sun Jan 14 12:03:46 2024
+// Update Count     : 81
 //
 
@@ -29,18 +29,29 @@
 // Getters
 size_t size(const string & s);
+static inline size_t strlen(const string & s) { return size( s ); }
 
 // RAII, assignment
-void ?{}(string & this); // empty string
-void ?{}(string & s, const char * initial); // copy from string literal (NULL-terminated)
-void ?{}(string & s, const char * buffer, size_t bsize); // copy specific length from buffer
-
+void ?{}(string & s); // empty string
 void ?{}(string & s, const string & s2);
+void ?{}(string & s, const string & s2, size_t maxlen);
 void ?{}(string & s, string & s2);
 
-void ?=?(string & s, const char * other); // copy assignment from literal
-void ?=?(string & s, const string & other);
-void ?=?(string & s, char other);
-string & ?=?(string & s, string & other);  // surprising ret seems to help avoid calls to autogen
+void ?{}(string & s, char);
+void ?{}(string & s, const char * c); // copy from string literal (NULL-terminated)
+void ?{}(string & s, const char * c, size_t size); // copy specific length from buffer
+
+void ?=?(string & s, const char * c); // copy assignment from literal
+void ?=?(string & s, const string & c);
+void ?=?(string & s, char c);
+string & ?=?(string & s, string & c);  // surprising ret seems to help avoid calls to autogen
+void assign(string & s, const string & c, size_t n);
+void assign(string & s, const char * c, size_t n);
 //string ?=?( string &, string ) = void;
+
+static inline string & strcpy(string & s, const char * c) { s = c; return s; }
+static inline string & strncpy(string & s, const char * c, size_t n) { assign( s, c, n); return s; }
+static inline string & strcpy(string & s, const string & c) { s = c; return s; }
+static inline string & strncpy(string & s, const string & c, size_t n) { assign(s, c, n); return s; }
+
 void ^?{}(string & s);
 
@@ -49,6 +60,6 @@
     string * s;
 };
-string_WithSharedEdits ?`shareEdits( string & this );
-void ?{}( string & this, string_WithSharedEdits src );
+string_WithSharedEdits ?`shareEdits( string & s );
+void ?{}( string & s, string_WithSharedEdits src );
 
 // IO Operator
@@ -56,5 +67,5 @@
 void ?|?(ofstream & out, const string & s);
 ifstream & ?|?(ifstream & in, string & s);
-void ?|?( ifstream & in, string & this );
+void ?|?( ifstream & in, string & s );
 
 static inline {
@@ -81,8 +92,8 @@
 	_Istream_Sstr wdi( unsigned int rwd, string & s ) { return (_Istream_Sstr)@{ s, {{0p}, rwd, {.flags.rwd : true}} }; }
 	_Istream_Sstr getline( string & s, const char delimiter = '\n' ) {
-		return (_Istream_Sstr)@{ s, {{.delimiter : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };
+		return (_Istream_Sstr)@{ s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };
 	}
 	_Istream_Sstr & getline( _Istream_Sstr & fmt, const char delimiter = '\n' ) {
-		fmt.delimiter[0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
+		fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
 	}
 	_Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : false}} }; }
@@ -97,16 +108,25 @@
 
 // Concatenation
-void ?+=?(string & s, char other); // append a character
+void ?+=?(string & s, char c); // append a character
 void ?+=?(string & s, const string & s2); // append-concatenate to first string
-void ?+=?(string & s, const char * other); // append-concatenate to first string
-string ?+?(const string & s, char other); // add a character to a copy of the string
+void append(string & s, const string & s2, size_t maxlen);  // append-concatenate to first string, up to maxlen
+void ?+=?(string & s, const char * s2); // append-concatenate NULL-terminated string to first string
+void append(string & s, const char * buffer, size_t bsize);  // append-concatenate given range to first string
+
+string ?+?(const string & s, char c); // add a character to a copy of the string
 string ?+?(const string & s, const string & s2); // copy and concatenate both strings
-string ?+?(const char * s1, const char * s2); // concatenate both strings
-string ?+?(const string & s, const char * other); // copy and concatenate with NULL-terminated string
+string ?+?(const char * s1, const char * s2); // copy and concatenate both strings
+string ?+?(const string & s, const char * c); // copy and concatenate with NULL-terminated string
+
+static inline string & strcat(string & s, const string & s2) { s += s2; return s; }
+static inline string & strcat(string & s, const char * c) { s += c; return s; }
+static inline string & strncat(string & s, const string & s2, size_t maxlen) { append(s, s2, maxlen); return s; }
+static inline string & strncat(string & s, const char * buffer, size_t bsize) { append(s, buffer, bsize); return s; }
 
 // Repetition
 string ?*?(const string & s, size_t factor);
-string ?*?(char c, size_t size);
-string ?*?(const char *s, size_t size);
+void ?*=?(string & s, size_t factor);
+string ?*?(char c, size_t factor);
+string ?*?(const char *s, size_t factor);
 
 // Character access
@@ -116,5 +136,5 @@
 
 // Comparisons
-int  cmp (const string &, const string &);
+int  strcmp (const string &, const string &);
 bool ?==?(const string &, const string &);
 bool ?!=?(const string &, const string &);
@@ -124,24 +144,24 @@
 bool ?<? (const string &, const string &);
 
-int  cmp (const string &, const char*);
-bool ?==?(const string &, const char*);
-bool ?!=?(const string &, const char*);
-bool ?>? (const string &, const char*);
-bool ?>=?(const string &, const char*);
-bool ?<=?(const string &, const char*);
-bool ?<? (const string &, const char*);
-
-int  cmp (const char*, const string &);
-bool ?==?(const char*, const string &);
-bool ?!=?(const char*, const string &);
-bool ?>? (const char*, const string &);
-bool ?>=?(const char*, const string &);
-bool ?<=?(const char*, const string &);
-bool ?<? (const char*, const string &);
+int  strcmp (const string &, const char *);
+bool ?==?(const string &, const char *);
+bool ?!=?(const string &, const char *);
+bool ?>? (const string &, const char *);
+bool ?>=?(const string &, const char *);
+bool ?<=?(const string &, const char *);
+bool ?<? (const string &, const char *);
+
+int  strcmp (const char *, const string &);
+bool ?==?(const char *, const string &);
+bool ?!=?(const char *, const string &);
+bool ?>? (const char *, const string &);
+bool ?>=?(const char *, const string &);
+bool ?<=?(const char *, const string &);
+bool ?<? (const char *, const string &);
 
 
 // Slicing
-string ?()( string & this, size_t start, size_t end );  // TODO const?
-string ?()( string & this, size_t start);
+string ?()( string & s, size_t start, size_t len );  // TODO const?
+string ?()( string & s, size_t start);
 
 // String search
@@ -177,5 +197,4 @@
 
 
-
 struct charclass {
     charclass_res * inner;
Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/collections/string_res.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Oct 18 21:54:54 2023
-// Update Count     : 15
+// Last Modified On : Tue Jan 16 22:19:27 2024
+// Update Count     : 35
 //
 
@@ -22,5 +22,5 @@
 // Workaround is:  EndVbyte = TEMP_ALLOC(char, CurrSize)
 // Should be:      EndVbyte = alloc(CurrSize)
-#define TEMP_ALLOC(T, n) (( T* ) malloc( n * sizeof( T ) ))
+#define TEMP_ALLOC(T, n) (( T * ) malloc( n * sizeof( T ) ))
 
 #include <assert.h>
@@ -33,21 +33,20 @@
 
 struct VbyteHeap {
-
-    int NoOfCompactions;				// number of compactions of the byte area
-    int NoOfExtensions;					// number of extensions in the size of the byte area
-    int NoOfReductions;					// number of reductions in the size of the byte area
+    int NoOfCompactions;						// number of compactions of the byte area
+    int NoOfExtensions;							// number of extensions in the size of the byte area
+    int NoOfReductions;							// number of reductions in the size of the byte area
     
-    int InitSize;					// initial number of bytes in the byte-string area
-    int CurrSize;					// current number of bytes in the byte-string area
-    char *StartVbyte;					// pointer to the `st byte of the start of the byte-string area
-    char *EndVbyte;					// pointer to the next byte after the end of the currently used portion of byte-string area
-    void *ExtVbyte;					// pointer to the next byte after the end of the byte-string area
-
-    HandleNode Header;					// header node for handle list
+    int InitSize;								// initial number of bytes in the byte-string area
+    int CurrSize;								// current number of bytes in the byte-string area
+    char *StartVbyte;							// pointer to the `st byte of the start of the byte-string area
+    char *EndVbyte;								// pointer to the next byte after the end of the currently used portion of byte-string area
+    void *ExtVbyte;								// pointer to the next byte after the end of the byte-string area
+
+    HandleNode Header;							// header node for handle list
 }; // VbyteHeap
 
     
-static void compaction( VbyteHeap & );				// compaction of the byte area
-static void garbage( VbyteHeap &, int );				// garbage collect the byte area
+static void compaction( VbyteHeap & );			// compaction of the byte area
+static void garbage( VbyteHeap &, int );		// garbage collect the byte area
 static void extend( VbyteHeap &, int );			// extend the size of the byte area
 static void reduce( VbyteHeap &, int );			// reduce the size of the byte area
@@ -67,7 +66,7 @@
 // Allocate the storage for the variable sized area and intialize the heap variables.
 
-static void ?{}( VbyteHeap & this, size_t Size ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size;
+static void ?{}( VbyteHeap & s, size_t Size ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size;
 #endif // VbyteDebug
     NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
@@ -76,8 +75,8 @@
     ExtVbyte = (void *)( StartVbyte + CurrSize );
     Header.flink = Header.blink = &Header;
-    Header.ulink = & this;
+    Header.ulink = &s;
 #ifdef VbyteDebug
     HeaderPtr = &Header;
-    serr | "exit:VbyteHeap::VbyteHeap, this:" | &this;
+    serr | "exit:VbyteHeap::VbyteHeap, s:" | &s;
 #endif // VbyteDebug
 } // VbyteHeap
@@ -86,5 +85,5 @@
 // Release the dynamically allocated storage for the byte area.
 
-static void ^?{}( VbyteHeap & this ) with(this) {
+static void ^?{}( VbyteHeap & s ) with(s) {
     free( StartVbyte );
 } // ~VbyteHeap
@@ -97,12 +96,12 @@
 // creator.
 
-static void ?{}( HandleNode & this ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:HandleNode::HandleNode, this:" | &this;
+static void ?{}( HandleNode & s ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
     s = 0;
     lnth = 0;
 #ifdef VbyteDebug
-    serr | "exit:HandleNode::HandleNode, this:" | &this;
+    serr | "exit:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
 } // HandleNode
@@ -112,14 +111,14 @@
 // collection.
 
-static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:HandleNode::HandleNode, this:" | &this;
+static void ?{}( HandleNode & s, VbyteHeap & vh ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
     s = 0;
     lnth = 0;
     ulink = &vh;
-    AddThisAfter( this, *vh.Header.blink );
-#ifdef VbyteDebug
-    serr | "exit:HandleNode::HandleNode, this:" | &this;
+    AddThisAfter( s, *vh.Header.blink );
+#ifdef VbyteDebug
+    serr | "exit:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
 } // HandleNode
@@ -129,7 +128,7 @@
 // is the responsibility of the creator to destroy it.
 
-static void ^?{}( HandleNode & this ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:HandleNode::~HandleNode, this:" | & this;
+static void ^?{}( HandleNode & s ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:HandleNode::~HandleNode, s:" | & s;
     {
 	serr | nlOff;
@@ -142,5 +141,5 @@
     }
 #endif // VbyteDebug
-    DeleteNode( this );
+    DeleteNode( s );
 } // ~HandleNode
 
@@ -151,5 +150,5 @@
 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
 
-void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {
+void ?{}( string_sharectx & s, StringSharectx_Mode mode ) with( s ) {
     (older){ ambient_string_sharectx };
     if ( mode == NEW_SHARING ) {
@@ -159,15 +158,15 @@
         (activeHeap){ 0p };
     }
-    ambient_string_sharectx = & this;
-}
-
-void ^?{}( string_sharectx & this ) with( this ) {
+    ambient_string_sharectx = & s;
+}
+
+void ^?{}( string_sharectx & s ) with( s ) {
     if ( activeHeap ) delete( activeHeap );
 
-    // unlink this from older-list starting from ambient_string_sharectx
-    // usually, this==ambient_string_sharectx and the loop runs zero times
+    // unlink s from older-list starting from ambient_string_sharectx
+    // usually, s==ambient_string_sharectx and the loop runs zero times
     string_sharectx *& c = ambient_string_sharectx;
-    while ( c != &this ) &c = &c->older;              // find this
-    c = this.older;                                   // unlink
+    while ( c != &s ) &c = &c->older;              // find s
+    c = s.older;                                   // unlink
 }
 
@@ -181,5 +180,5 @@
 
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
-    return ((char*)heap->ExtVbyte) - heap->EndVbyte;
+    return ((char *)heap->ExtVbyte) - heap->EndVbyte;
 }
 
@@ -193,10 +192,10 @@
 
 // Returns the size of the string in bytes
-size_t size(const string_res &s) with(s) {
+size_t size(const string_res & s) with(s) {
     return Handle.lnth;
 }
 
 // Output operator
-ofstream & ?|?(ofstream &out, const string_res &s) {
+ofstream & ?|?(ofstream & out, const string_res & s) {
 	// CFA string is NOT null terminated, so print exactly lnth characters in a minimum width of 0.
 	out | wd( 0, s.Handle.lnth, s.Handle.s ) | nonl;
@@ -204,11 +203,10 @@
 }
 
-void ?|?(ofstream &out, const string_res &s) {
+void ?|?(ofstream & out, const string_res & s) {
 	(ofstream &)(out | s); ends( out );
 }
 
 // Input operator
-ifstream & ?|?(ifstream &in, string_res &s) {
-
+ifstream & ?|?(ifstream & in, string_res & s) {
     // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
     // If s is a substring of something larger, simple assignment takes care of that case correctly.
@@ -231,5 +229,5 @@
 
         // rest of heap is available to read into
-        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
+        int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
         assert (lenReadable >= 2);
 
@@ -238,5 +236,5 @@
 			*(temp.Handle.ulink->EndVbyte) = '\0';   // pre-assign empty cstring
             in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
-        } catch (cstring_length*) {
+        } catch (cstring_length *) {
             cont = true;
         }
@@ -252,6 +250,6 @@
 }
 
-void ?|?( ifstream & in, string_res & this ) {
-    (ifstream &)(in | this);
+void ?|?( ifstream & in, string_res & s ) {
+    (ifstream &)(in | s);
 }
 
@@ -274,6 +272,7 @@
 		cont = true;
 	} finally {
-		if ( ! cf.flags.ignore &&						// ok to initialize string
-				cstr[0] != '\0' ) {						// something was read
+		if ( ! cf.flags.ignore							// ok to initialize string
+//			 &&	cstr[0] != '\0'							// something was read
+			) {
 			*(f.s) = cstr;
 		}
@@ -287,6 +286,5 @@
 			cont = true;								// continue not allowed
 		} finally {
-			if ( ! cf.flags.ignore &&
-					cstr[0] != '\0' ) {					// something was read
+			if ( ! cf.flags.ignore && cstr[0] != '\0' ) { // something was read
 				*(f.s) += cstr;							// build string chunk at a time
 			}
@@ -302,5 +300,5 @@
 
 // Empty constructor
-void ?{}(string_res &s) with(s) {
+void ?{}(string_res & s) with(s) {
     if( ambient_string_sharectx->activeHeap ) {
         (Handle){ * ambient_string_sharectx->activeHeap };
@@ -317,5 +315,5 @@
 }
 
-static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) {
+static void eagerCopyCtorHelper(string_res & s, const char * rhs, size_t rhslnth) with(s) {
     if( ambient_string_sharectx->activeHeap ) {
         (Handle){ * ambient_string_sharectx->activeHeap };
@@ -333,10 +331,10 @@
 
 // Constructor from a raw buffer and size
-void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
+void ?{}(string_res & s, const char * rhs, size_t rhslnth) with(s) {
     eagerCopyCtorHelper(s, rhs, rhslnth);
 }
 
 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in
-void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
+void ?{}( string_res & s, VbyteHeap & heap, const char * rhs, size_t rhslnth ) with(s) {
     (Handle){ heap };
     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
@@ -348,7 +346,9 @@
 }
 
+
 // General copy constructor
-void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
-
+void ?{}(string_res & s, const string_res & s2, StrResInitMode mode, size_t start, size_t len ) {
+
+    size_t end = start + len;
     verify( start <= end && end <= s2.Handle.lnth );
 
@@ -394,5 +394,5 @@
 }
 
-static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
+static void assignEditSet(string_res & s, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
     char * resultSesStart,
     size_t resultSesLnth,
@@ -400,19 +400,19 @@
 
     char * beforeBegin = shareEditSetStartPeer->Handle.s;
-    size_t beforeLen = this.Handle.s - beforeBegin;
-
-    char * afterBegin = this.Handle.s + this.Handle.lnth;
+    size_t beforeLen = s.Handle.s - beforeBegin;
+
+    char * afterBegin = s.Handle.s + s.Handle.lnth;
     size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
 
-    size_t oldLnth = this.Handle.lnth;
-
-    this.Handle.s = resultSesStart + beforeLen;
-    this.Handle.lnth = bsize;
+    size_t oldLnth = s.Handle.lnth;
+
+    s.Handle.s = resultSesStart + beforeLen;
+    s.Handle.lnth = bsize;
     if (resultPadPosition)
-        MoveThisAfter( this.Handle, *resultPadPosition );
+        MoveThisAfter( s.Handle, *resultPadPosition );
 
     // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
     char *limit = resultSesStart + resultSesLnth;
-    for ( string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next ) {
+    for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) {
         verify (p->Handle.s >= beforeBegin);
         if ( p->Handle.s >= afterBegin ) {
@@ -439,5 +439,5 @@
                 // take end as end-anchored
                 // stretch-shrink p according to the edit
-                p->Handle.lnth += this.Handle.lnth;
+                p->Handle.lnth += s.Handle.lnth;
                 p->Handle.lnth -= oldLnth;
             }
@@ -452,5 +452,5 @@
                 // p ends during the edit; p does not include the last character replaced
                 // set p to empty string at start of edit
-                p->Handle.s = this.Handle.s;
+                p->Handle.s = s.Handle.s;
                 p->Handle.lnth = 0;
             } else {
@@ -458,5 +458,5 @@
                 // clip start of p to start at end of edit
                 int charsToClip = afterBegin - p->Handle.s;
-                p->Handle.s = this.Handle.s + this.Handle.lnth;
+                p->Handle.s = s.Handle.s + s.Handle.lnth;
                 p->Handle.lnth -= charsToClip;
             }
@@ -467,9 +467,9 @@
 }
 
-// traverse the share-edit set (SES) to recover the range of a base string to which `this` belongs
-static void locateInShareEditSet( string_res &this, string_res *&shareEditSetStartPeer, string_res *&shareEditSetEndPeer ) {
-    shareEditSetStartPeer = & this;
-    shareEditSetEndPeer = & this;
-    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
+// traverse the share-edit set (SES) to recover the range of a base string to which `s` belongs
+static void locateInShareEditSet( string_res & s, string_res *& shareEditSetStartPeer, string_res *& shareEditSetEndPeer ) {
+    shareEditSetStartPeer = & s;
+    shareEditSetEndPeer = & s;
+    for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) {
         if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
             shareEditSetStartPeer = editPeer;
@@ -481,29 +481,29 @@
 }
 
-static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
+static string_res & assign_(string_res & s, const char * buffer, size_t bsize, const string_res & valSrc) {
 
     string_res * shareEditSetStartPeer;
     string_res * shareEditSetEndPeer;
-    locateInShareEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer );
+    locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer );
 
     verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
     size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
-    verify( origEditSetLength >= this.Handle.lnth );
-
-    if ( this.shareEditSet_owns_ulink ) {                 // assigning to private context
+    verify( origEditSetLength >= s.Handle.lnth );
+
+    if ( s.shareEditSet_owns_ulink ) {                 // assigning to private context
         // ok to overwrite old value within LHS
         char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
-        int prefixLen = this.Handle.s - prefixStartOrig;
-        char * suffixStartOrig = this.Handle.s + this.Handle.lnth;
+        int prefixLen = s.Handle.s - prefixStartOrig;
+        char * suffixStartOrig = s.Handle.s + s.Handle.lnth;
         int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
 
-        int delta = bsize - this.Handle.lnth;
-        if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) {
+        int delta = bsize - s.Handle.lnth;
+        if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) {
             // growing: copy from old to new
-            char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta );
+            char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta );
             char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
             destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
             destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
-            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+            assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
                 dest,
                 origEditSetLength + delta,
@@ -513,7 +513,7 @@
             // room is already allocated in-place: bubble suffix and overwite middle
             memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
-            memcpy( this.Handle.s, buffer, bsize );
-
-            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+            memcpy( s.Handle.s, buffer, bsize );
+
+            assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
                 shareEditSetStartPeer->Handle.s,
                 origEditSetLength + delta,
@@ -522,10 +522,10 @@
 
     } else if (                                           // assigning to shared context
-        this.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
+        s.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
         & valSrc &&                                       // sourcing from a managed string
-        valSrc.Handle.ulink == this.Handle.ulink  ) {     // sourcing from same heap
+        valSrc.Handle.ulink == s.Handle.ulink  ) {     // sourcing from same heap
 
         // SES's result will only use characters from the source string => reuse source
-        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
             valSrc.Handle.s,
             valSrc.Handle.lnth,
@@ -537,24 +537,24 @@
 
         // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
-        // `this` occurs in the middle of it, to be replaced
+        // `s` occurs in the middle of it, to be replaced
         // build up the new text in `pasting`
 
         string_res pasting = {
-            * this.Handle.ulink,                               // maintain same heap, regardless of context
+            * s.Handle.ulink,                               // maintain same heap, regardless of context
             shareEditSetStartPeer->Handle.s,                   // start of SES
-            this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
+            s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s
         append( pasting,
-            buffer,                                            // start of replacement for this
-            bsize );                                           // length of replacement for this
+            buffer,                                            // start of replacement for s
+            bsize );                                           // length of replacement for s
         append( pasting,
-            this.Handle.s + this.Handle.lnth,                  // start of SES after this
+            s.Handle.s + s.Handle.lnth,                  // start of SES after s
             shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
-            (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
+            (s.Handle.s + s.Handle.lnth) );              // length of SES, after s
 
         // The above string building can trigger compaction.
         // The reference points (that are arguments of the string building) may move during that building.
-        // From this point on, they are stable.
-
-        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+        // From s point on, they are stable.
+
+        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
             pasting.Handle.s,
             pasting.Handle.lnth,
@@ -562,28 +562,32 @@
     }
 
-    return this;
-}
-
-string_res & assign(string_res &this, const char* buffer, size_t bsize) {
-    return assign_(this, buffer, bsize, *0p);
-}
-
-string_res & ?=?(string_res &s, char other) {
-    return assign(s, &other, 1);
+    return s;
+}
+
+string_res & assign(string_res & s, const string_res & src, size_t maxlen) {
+    return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p);
+}
+
+string_res & assign(string_res & s, const char * buffer, size_t bsize) {
+    return assign_(s, buffer, bsize, *0p);
+}
+
+string_res & ?=?(string_res & s, char c) {
+    return assign(s, &c, 1);
 }
 
 // Copy assignment operator
-string_res & ?=?(string_res & this, const string_res & rhs) with( this ) {
-    return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);
-}
-
-string_res & ?=?(string_res & this, string_res & rhs) with( this ) {
+string_res & ?=?(string_res & s, const string_res & rhs) with( s ) {
+    return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs);
+}
+
+string_res & ?=?(string_res & s, string_res & rhs) with( s ) {
     const string_res & rhs2 = rhs;
-    return this = rhs2;
+    return s = rhs2;
 }
 
 
 // Destructor
-void ^?{}(string_res &s) with(s) {
+void ^?{}(string_res & s) with(s) {
     // much delegated to implied ^VbyteSM
 
@@ -603,11 +607,14 @@
 // With unicode support, this may be different from just the byte at the given
 // offset from the start of the string.
-char ?[?](const string_res &s, size_t index) with(s) {
+char ?[?](const string_res & s, size_t index) with(s) {
     //TODO: Check if index is valid (no exceptions yet)
     return Handle.s[index];
 }
 
-void assignAt(const string_res &s, size_t index, char val) {
-    string_res editZone = { s, SHARE_EDITS, index, index+1 };
+void assignAt(const string_res & s, size_t index, char val) {
+    // caution: not tested (not reachable by string-api-coverage interface)
+    // equivalent form at string level is `s[index] = val`,
+    // which uses the overload that returns a length-1 string
+    string_res editZone = { s, SHARE_EDITS, index, 1 };
     assign(editZone, &val, 1);
 }
@@ -617,5 +624,5 @@
 // Concatenation
 
-void append(string_res &str1, const char * buffer, size_t bsize) {
+void append(string_res & str1, const char * buffer, size_t bsize) {
     size_t clnth = str1.Handle.lnth + bsize;
     if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
@@ -635,20 +642,32 @@
 }
 
-void ?+=?(string_res &str1, const string_res &str2) {
+void ?+=?(string_res & str1, const string_res & str2) {
     append( str1, str2.Handle.s, str2.Handle.lnth );
 }
 
-void ?+=?(string_res &s, char other) {
-    append( s, &other, 1 );
-}
-
-
-
-
+void append(string_res & str1, const string_res & str2, size_t maxlen) {
+    append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) );
+}
+
+void ?+=?(string_res & s, char c) {
+    append( s, & c, 1 );
+}
+void ?+=?(string_res & s, const char * c) {
+    append( s, c, strlen(c) );
+}
+
+///////////////////////////////////////////////////////////////////
+// Repetition
+
+void ?*=?(string_res & s, size_t factor) {
+    string_res s2 = { s, COPY_VALUE };
+    s = "";
+    for (factor) s += s2;
+}
 
 //////////////////////////////////////////////////////////
 // Comparisons
 
-int cmp(const string_res &s1, const string_res &s2) {
+int strcmp(const string_res & s1, const string_res & s2) {
     // return 0;
     int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
@@ -657,34 +676,34 @@
 }
 
-bool ?==?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) == 0; }
-bool ?!=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) != 0; }
-bool ?>? (const string_res &s1, const string_res &s2) { return cmp(s1, s2) >  0; }
-bool ?>=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) >= 0; }
-bool ?<=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) <= 0; }
-bool ?<? (const string_res &s1, const string_res &s2) { return cmp(s1, s2) <  0; }
-
-int cmp (const string_res &s1, const char* s2) {
+bool ?==?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) == 0; }
+bool ?!=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) != 0; }
+bool ?>? (const string_res & s1, const string_res & s2) { return strcmp(s1, s2) >  0; }
+bool ?>=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) >= 0; }
+bool ?<=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) <= 0; }
+bool ?<? (const string_res & s1, const string_res & s2) { return strcmp(s1, s2) <  0; }
+
+int strcmp (const string_res & s1, const char * s2) {
     string_res s2x = s2;
-    return cmp(s1, s2x);
-}
-
-bool ?==?(const string_res &s1, const char* s2) { return cmp(s1, s2) == 0; }
-bool ?!=?(const string_res &s1, const char* s2) { return cmp(s1, s2) != 0; }
-bool ?>? (const string_res &s1, const char* s2) { return cmp(s1, s2) >  0; }
-bool ?>=?(const string_res &s1, const char* s2) { return cmp(s1, s2) >= 0; }
-bool ?<=?(const string_res &s1, const char* s2) { return cmp(s1, s2) <= 0; }
-bool ?<? (const string_res &s1, const char* s2) { return cmp(s1, s2) <  0; }
-
-int cmp (const char* s1, const string_res & s2) {
+    return strcmp(s1, s2x);
+}
+
+bool ?==?(const string_res & s1, const char * s2) { return strcmp(s1, s2) == 0; }
+bool ?!=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) != 0; }
+bool ?>? (const string_res & s1, const char * s2) { return strcmp(s1, s2) >  0; }
+bool ?>=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) >= 0; }
+bool ?<=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) <= 0; }
+bool ?<? (const string_res & s1, const char * s2) { return strcmp(s1, s2) <  0; }
+
+int strcmp (const char * s1, const string_res & s2) {
     string_res s1x = s1;
-    return cmp(s1x, s2);
-}
-
-bool ?==?(const char* s1, const string_res &s2) { return cmp(s1, s2) == 0; }
-bool ?!=?(const char* s1, const string_res &s2) { return cmp(s1, s2) != 0; }
-bool ?>? (const char* s1, const string_res &s2) { return cmp(s1, s2) >  0; }
-bool ?>=?(const char* s1, const string_res &s2) { return cmp(s1, s2) >= 0; }
-bool ?<=?(const char* s1, const string_res &s2) { return cmp(s1, s2) <= 0; }
-bool ?<? (const char* s1, const string_res &s2) { return cmp(s1, s2) <  0; }
+    return strcmp(s1x, s2);
+}
+
+bool ?==?(const char * s1, const string_res & s2) { return strcmp(s1, s2) == 0; }
+bool ?!=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) != 0; }
+bool ?>? (const char * s1, const string_res & s2) { return strcmp(s1, s2) >  0; }
+bool ?>=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) >= 0; }
+bool ?<=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) <= 0; }
+bool ?<? (const char * s1, const string_res & s2) { return strcmp(s1, s2) <  0; }
 
 
@@ -693,5 +712,5 @@
 // Search
 
-bool contains(const string_res &s, char ch) {
+bool contains(const string_res & s, char ch) {
     for ( i; size(s) ) {
         if (s[i] == ch) return true;
@@ -700,9 +719,9 @@
 }
 
-int find(const string_res &s, char search) {
+int find(const string_res & s, char search) {
     return findFrom(s, 0, search);
 }
 
-int findFrom(const string_res &s, size_t fromPos, char search) {
+int findFrom(const string_res & s, size_t fromPos, char search) {
     // FIXME: This paricular overload (find of single char) is optimized to use memchr.
     // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
@@ -715,24 +734,24 @@
 }
 
-int find(const string_res &s, const string_res &search) {
+int find(const string_res & s, const string_res & search) {
     return findFrom(s, 0, search);
 }
 
-int findFrom(const string_res &s, size_t fromPos, const string_res &search) {
+int findFrom(const string_res & s, size_t fromPos, const string_res & search) {
     return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
 }
 
-int find(const string_res &s, const char* search) {
+int find(const string_res & s, const char * search) {
     return findFrom(s, 0, search);
 }
-int findFrom(const string_res &s, size_t fromPos, const char* search) {
+int findFrom(const string_res & s, size_t fromPos, const char * search) {
     return findFrom(s, fromPos, search, strlen(search));
 }
 
-int find(const string_res &s, const char* search, size_t searchsize) {
+int find(const string_res & s, const char * search, size_t searchsize) {
     return findFrom(s, 0, search, searchsize);
 }
 
-int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize) {
+int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize) {
 
     /* Remaining implementations essentially ported from Sunjay's work */
@@ -771,25 +790,25 @@
 }
 
-bool includes(const string_res &s, const string_res &search) {
+bool includes(const string_res & s, const string_res & search) {
     return includes(s, search.Handle.s, search.Handle.lnth);
 }
 
-bool includes(const string_res &s, const char* search) {
+bool includes(const string_res & s, const char * search) {
     return includes(s, search, strlen(search));
 }
 
-bool includes(const string_res &s, const char* search, size_t searchsize) {
+bool includes(const string_res & s, const char * search, size_t searchsize) {
     return find(s, search, searchsize) < s.Handle.lnth;
 }
 
-bool startsWith(const string_res &s, const string_res &prefix) {
+bool startsWith(const string_res & s, const string_res & prefix) {
     return startsWith(s, prefix.Handle.s, prefix.Handle.lnth);
 }
 
-bool startsWith(const string_res &s, const char* prefix) {
+bool startsWith(const string_res & s, const char * prefix) {
     return startsWith(s, prefix, strlen(prefix));
 }
 
-bool startsWith(const string_res &s, const char* prefix, size_t prefixsize) {
+bool startsWith(const string_res & s, const char * prefix, size_t prefixsize) {
     if (s.Handle.lnth < prefixsize) {
         return false;
@@ -798,13 +817,13 @@
 }
 
-bool endsWith(const string_res &s, const string_res &suffix) {
+bool endsWith(const string_res & s, const string_res & suffix) {
     return endsWith(s, suffix.Handle.s, suffix.Handle.lnth);
 }
 
-bool endsWith(const string_res &s, const char* suffix) {
+bool endsWith(const string_res & s, const char * suffix) {
     return endsWith(s, suffix, strlen(suffix));
 }
 
-bool endsWith(const string_res &s, const char* suffix, size_t suffixsize) {
+bool endsWith(const string_res & s, const char * suffix, size_t suffixsize) {
     if (s.Handle.lnth < suffixsize) {
         return false;
@@ -822,19 +841,19 @@
 // charclass, include, exclude
 
-void ?{}( charclass_res & this, const string_res & chars) {
-    (this){ chars.Handle.s, chars.Handle.lnth };
-}
-
-void ?{}( charclass_res & this, const char * chars ) {
-    (this){ chars, strlen(chars) };
-}
-
-void ?{}( charclass_res & this, const char * chars, size_t charssize ) {
-    (this.chars){ chars, charssize };
+void ?{}( charclass_res & s, const string_res & chars) {
+    (s){ chars.Handle.s, chars.Handle.lnth };
+}
+
+void ?{}( charclass_res & s, const char * chars ) {
+    (s){ chars, strlen(chars) };
+}
+
+void ?{}( charclass_res & s, const char * chars, size_t charssize ) {
+    (s.chars){ chars, charssize };
     // now sort it ?
 }
 
-void ^?{}( charclass_res & this ) {
-    ^(this.chars){};
+void ^?{}( charclass_res & s ) {
+    ^(s.chars){};
 }
 
@@ -844,5 +863,5 @@
 }
 
-int exclude(const string_res &s, const charclass_res &mask) {
+int exclude(const string_res & s, const charclass_res & mask) {
     for ( i; size(s) ) {
         if ( test(mask, s[i]) ) return i;
@@ -851,5 +870,5 @@
 }
 
-int include(const string_res &s, const charclass_res &mask) {
+int include(const string_res & s, const charclass_res & mask) {
     for ( i; size(s) ) {
         if ( ! test(mask, s[i]) ) return i;
@@ -863,15 +882,15 @@
 // Add a new HandleNode node n after the current HandleNode node.
 
-static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;
+static void AddThisAfter( HandleNode & s, HandleNode & n ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:AddThisAfter, s:" | &s | " n:" | &n;
 #endif // VbyteDebug
     // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be).
     verify( n.ulink != 0p );
-    verify( this.ulink == n.ulink );
+    verify( s.ulink == n.ulink );
     flink = n.flink;
     blink = &n;
-    n.flink->blink = &this;
-    n.flink = &this;
+    n.flink->blink = &s;
+    n.flink = &s;
 #ifdef VbyteDebug
     {
@@ -894,7 +913,7 @@
 // Delete the current HandleNode node.
 
-static void DeleteNode( HandleNode & this ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:DeleteNode, this:" | &this;
+static void DeleteNode( HandleNode & s ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:DeleteNode, s:" | &s;
 #endif // VbyteDebug
     flink->blink = blink;
@@ -906,9 +925,8 @@
 
 
-
 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the
 // allocation, the garbage collection routine is called.
 
-static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
+static char * VbyteAlloc( VbyteHeap & s, int size ) with(s) {
 #ifdef VbyteDebug
     serr | "enter:VbyteAlloc, size:" | size;
@@ -918,6 +936,6 @@
 
     NoBytes = ( uintptr_t )EndVbyte + size;
-    if ( NoBytes > ( uintptr_t )ExtVbyte ) {		// enough room for new byte-string ?
-		garbage( this, size );					// firer up the garbage collector
+    if ( NoBytes > ( uintptr_t )ExtVbyte ) {			// enough room for new byte-string ?
+		garbage( s, size );								// firer up the garbage collector
 		verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte  && "garbage run did not free up required space" );
     } // if
@@ -939,6 +957,5 @@
 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.
 
-static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {
-
+static char * VbyteTryAdjustLast( VbyteHeap & s, int delta ) with(s) {
     if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
         // room available
@@ -961,10 +978,10 @@
 // the address in the byte string area.
 
-static void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
-#ifdef VbyteDebug
-    serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;
+static void MoveThisAfter( HandleNode & s, const HandleNode  & h ) with(s) {
+#ifdef VbyteDebug
+    serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h;
 #endif // VbyteDebug
     verify( h.ulink != 0p );
-    verify( this.ulink == h.ulink );
+    verify( s.ulink == h.ulink );
     if ( s < h.s ) {					// check argument values
 		// serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
@@ -976,7 +993,7 @@
     HandleNode *i;
     for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h
-    if ( & this != i->blink ) {
-		DeleteNode( this );
-		AddThisAfter( this, *i->blink );
+    if ( & s != i->blink ) {
+		DeleteNode( s );
+		AddThisAfter( s, *i->blink );
     } // if
 #ifdef VbyteDebug
@@ -1058,5 +1075,5 @@
 // the containing string has been moved. Hence, they only require that their string pointers be adjusted.
 
-void compaction(VbyteHeap & this) with(this) {
+void compaction(VbyteHeap & s) with(s) {
     HandleNode *h;
     char *obase, *nbase, *limit;
@@ -1098,5 +1115,5 @@
 // the heap.  The heap is then compacted in the existing heap or into the newly allocated heap.
 
-void garbage(VbyteHeap & this, int minreq ) with(this) {
+void garbage(VbyteHeap & s, int minreq ) with(s) {
 #ifdef VbyteDebug
     serr | "enter:garbage";
@@ -1124,5 +1141,5 @@
     if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {	// free space less than threshold or not enough to serve cur request
 
-		extend( this, max( CurrSize, minreq ) );				// extend the heap
+		extend( s, max( CurrSize, minreq ) );				// extend the heap
 
 			//  Peter says, "This needs work before it should be used."
@@ -1133,5 +1150,5 @@
 
     } else {
-        compaction(this);					// in-place
+        compaction(s);					// in-place
     }// if
 #ifdef VbyteDebug
@@ -1159,5 +1176,5 @@
 // area is deleted.
 
-void extend( VbyteHeap & this, int size ) with (this) {
+void extend( VbyteHeap & s, int size ) with (s) {
 #ifdef VbyteDebug
     serr | "enter:extend, size:" | size;
@@ -1171,5 +1188,5 @@
     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     ExtVbyte = (void *)( StartVbyte + CurrSize );
-    compaction(this);					// copy from old heap to new & adjust pointers to new heap
+    compaction(s);					// copy from old heap to new & adjust pointers to new heap
     free( OldStartVbyte );				// release old heap
 #ifdef VbyteDebug
Index: libcfa/src/collections/string_res.hfa
===================================================================
--- libcfa/src/collections/string_res.hfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/collections/string_res.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Aug 12 15:45:47 2023
-// Update Count     : 2
+// Last Modified On : Thu Jan  4 11:28:06 2024
+// Update Count     : 27
 //
 
@@ -70,37 +70,45 @@
 
 // Getters
-size_t size(const string_res &s);
+size_t size(const string_res & s);
 
 // Constructors, Assignment Operators, Destructor
-void ?{}(string_res &s); // empty string
-void ?{}(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
-static inline void ?{}(string_res &s, const char* rhs) { // copy from string literal (NULL-terminated)
+void ?{}(string_res & s); // empty string
+void ?{}(string_res & s, const char * buffer, size_t bsize); // copy specific length from buffer
+static inline void ?{}(string_res & s, const char * rhs) { // copy from string literal (NULL-terminated)
     (s){ rhs, strlen(rhs) };
 }
-
-void ?{}(string_res &s, const string_res & s2) = void;
-void ?{}(string_res &s, string_res & s2) = void;
+static inline void ?{}(string_res & s, char c ) {
+    ?{}( s, &c, 1);
+}
+
+// Deleting the copy constructors makes the compiler reject an attempt to call/return by value
+void ?{}(string_res & s, const string_res & s2) = void;
+void ?{}(string_res & s, string_res & s2) = void;
 
 enum StrResInitMode { COPY_VALUE, SHARE_EDITS };
-void ?{}(string_res &s, const string_res & src, StrResInitMode, size_t start, size_t end );
-static inline void ?{}(string_res &s, const string_res & src, StrResInitMode mode ) {
+void ?{}(string_res & s, const string_res & src, StrResInitMode, size_t start, size_t len );
+static inline void ?{}(string_res & s, const string_res & src, StrResInitMode mode ) {
     ?{}( s, src, mode, 0, size(src));
 }
-
-string_res & assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
-static inline string_res & ?=?(string_res &s, const char* other) {  // copy from string literal (NULL-terminated)
-    return assign(s, other, strlen(other));
-}
-string_res & ?=?(string_res &s, const string_res &other);
-string_res & ?=?(string_res &s, string_res &other);
-string_res & ?=?(string_res &s, char other);
-
-void ^?{}(string_res &s);
+static inline void ?{}(string_res & s, const string_res & src, StrResInitMode mode, size_t maxlen ) {
+    ?{}( s, src, mode, 0, (size(src) > maxlen)?maxlen:size(src) );
+}
+
+string_res & assign(string_res & s, const string_res & src, size_t maxlen); // copy specific length from other string
+string_res & assign(string_res & s, const char * buffer, size_t bsize); // copy specific length from buffer
+static inline string_res & ?=?(string_res & s, const char * c) {  // copy from string literal (NULL-terminated)
+    return assign(s, c, strlen(c));
+}
+string_res & ?=?(string_res & s, const string_res & c);
+string_res & ?=?(string_res & s, string_res & c);
+string_res & ?=?(string_res & s, char c);
+
+void ^?{}(string_res & s);
 
 // IO Operator
-ofstream & ?|?(ofstream &out, const string_res &s);
-void ?|?(ofstream &out, const string_res &s);
-ifstream & ?|?(ifstream &in, string_res &s);
-void ?|?( ifstream & in, string_res & this );
+ofstream & ?|?(ofstream & out, const string_res & s);
+void ?|?(ofstream & out, const string_res & s);
+ifstream & ?|?(ifstream & in, string_res & s);
+void ?|?( ifstream & in, string_res & s );
 
 struct _Istream_Rstr {
@@ -113,8 +121,8 @@
 	_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}} };
+		return (_Istream_Rstr)@{ &s, {{.delimiters : { 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;
+		fmt.delimiters[0] = delimiter; fmt.delimiters[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}} }; }
@@ -129,18 +137,25 @@
 
 // Concatenation
-void append(string_res &s, const char* buffer, size_t bsize);
-void ?+=?(string_res &s, char other); // append a character
-void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string
-static inline void ?+=?(string_res &s, const char* other) {
-    append( s, other, strlen(other) );
-}
+void ?+=?(string_res & s, const string_res & s2);
+void ?+=?(string_res & s, char c);
+void append(string_res & s, const string_res & s2, size_t maxlen);
+void ?+=?(string_res & s, const char * c);
+void append(string_res & s, const char * buffer, size_t bsize);
+
+static inline string_res & strcat(string_res & s, const string_res & s2) { s += s2; return s; }
+static inline string_res & strcat(string_res & s, const char * c) { s += c; return s; }
+static inline string_res & strncat(string_res & s, const string_res & s2, size_t maxlen) { append(s, s2, maxlen); return s; }
+static inline string_res & strncat(string_res & s, const char * buffer, size_t bsize) { append(s, buffer, bsize); return s; }
+
+// Repetition
+void ?*=?(string_res & s, size_t factor);
 
 // Character access
-void assignAt(const string_res &s, size_t index, char val);
-char ?[?](const string_res &s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's
-//char codePointAt(const string_res &s, size_t index); // revisit under Unicode
+void assignAt(const string_res & s, size_t index, char val);
+char ?[?](const string_res & s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's
+//char codePointAt(const string_res & s, size_t index); // revisit under Unicode
 
 // Comparisons
-int  cmp (const string_res &, const string_res &);
+int  strcmp (const string_res &, const string_res &);
 bool ?==?(const string_res &, const string_res &);
 bool ?!=?(const string_res &, const string_res &);
@@ -150,52 +165,52 @@
 bool ?<? (const string_res &, const string_res &);
 
-int  cmp (const string_res &, const char*);
-bool ?==?(const string_res &, const char*);
-bool ?!=?(const string_res &, const char*);
-bool ?>? (const string_res &, const char*);
-bool ?>=?(const string_res &, const char*);
-bool ?<=?(const string_res &, const char*);
-bool ?<? (const string_res &, const char*);
-
-int  cmp (const char*, const string_res &);
-bool ?==?(const char*, const string_res &);
-bool ?!=?(const char*, const string_res &);
-bool ?>? (const char*, const string_res &);
-bool ?>=?(const char*, const string_res &);
-bool ?<=?(const char*, const string_res &);
-bool ?<? (const char*, const string_res &);
+int  strcmp(const string_res &, const char *);
+bool ?==?(const string_res &, const char *);
+bool ?!=?(const string_res &, const char *);
+bool ?>? (const string_res &, const char *);
+bool ?>=?(const string_res &, const char *);
+bool ?<=?(const string_res &, const char *);
+bool ?<? (const string_res &, const char *);
+
+int  strcmp(const char *, const string_res &);
+bool ?==?(const char *, const string_res &);
+bool ?!=?(const char *, const string_res &);
+bool ?>? (const char *, const string_res &);
+bool ?>=?(const char *, const string_res &);
+bool ?<=?(const char *, const string_res &);
+bool ?<? (const char *, const string_res &);
 
 // String search
-bool contains(const string_res &s, char ch); // single character
-
-int find(const string_res &s, char search);
-int find(const string_res &s, const string_res &search);
-int find(const string_res &s, const char* search);
-int find(const string_res &s, const char* search, size_t searchsize);
-
-int findFrom(const string_res &s, size_t fromPos, char search);
-int findFrom(const string_res &s, size_t fromPos, const string_res &search);
-int findFrom(const string_res &s, size_t fromPos, const char* search);
-int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize);
-
-bool includes(const string_res &s, const string_res &search);
-bool includes(const string_res &s, const char* search);
-bool includes(const string_res &s, const char* search, size_t searchsize);
-
-bool startsWith(const string_res &s, const string_res &prefix);
-bool startsWith(const string_res &s, const char* prefix);
-bool startsWith(const string_res &s, const char* prefix, size_t prefixsize);
-
-bool endsWith(const string_res &s, const string_res &suffix);
-bool endsWith(const string_res &s, const char* suffix);
-bool endsWith(const string_res &s, const char* suffix, size_t suffixsize);
-
-int include(const string_res &s, const charclass_res &mask);
-int exclude(const string_res &s, const charclass_res &mask);
+bool contains(const string_res & s, char ch); // single character
+
+int find(const string_res & s, char search);
+int find(const string_res & s, const string_res & search);
+int find(const string_res & s, const char * search);
+int find(const string_res & s, const char * search, size_t searchsize);
+
+int findFrom(const string_res & s, size_t fromPos, char search);
+int findFrom(const string_res & s, size_t fromPos, const string_res & search);
+int findFrom(const string_res & s, size_t fromPos, const char * search);
+int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize);
+
+bool includes(const string_res & s, const string_res & search);
+bool includes(const string_res & s, const char * search);
+bool includes(const string_res & s, const char * search, size_t searchsize);
+
+bool startsWith(const string_res & s, const string_res & prefix);
+bool startsWith(const string_res & s, const char * prefix);
+bool startsWith(const string_res & s, const char * prefix, size_t prefixsize);
+
+bool endsWith(const string_res & s, const string_res & suffix);
+bool endsWith(const string_res & s, const char * suffix);
+bool endsWith(const string_res & s, const char * suffix, size_t suffixsize);
+
+int include(const string_res & s, const charclass_res & mask);
+int exclude(const string_res & s, const charclass_res & mask);
 
 // Modifiers
-void padStart(string_res &s, size_t n);
-void padStart(string_res &s, size_t n, char padding);
-void padEnd(string_res &s, size_t n);
+void padStart(string_res & s, size_t n);
+void padStart(string_res & s, size_t n, char padding);
+void padEnd(string_res & s, size_t n);
 void padEnd(string_res &s, size_t n, char padding);
 
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/heap.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep 30 17:31:15 2023
-// Update Count     : 1617
+// Last Modified On : Wed Jan  3 21:30:54 2024
+// Update Count     : 1619
 //
 
@@ -27,5 +27,5 @@
 #include "bits/align.hfa"								// libAlign
 #include "bits/defs.hfa"								// likely, unlikely
-#include "concurrency/kernel/fwd.hfa"					// __POLL_PREEMPTION
+#include "concurrency/kernel/fwd.hfa"					// disable_interrupts, enable_interrupts
 #include "startup.hfa"									// STARTUP_PRIORITY_MEMORY
 #include "math.hfa"										// ceiling, min
Index: libcfa/src/interpose.cfa
===================================================================
--- libcfa/src/interpose.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/interpose.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar 29 16:10:31 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar 27 21:09:03 2023
-// Update Count     : 196
+// Last Modified On : Thu Jan 11 18:45:31 2024
+// Update Count     : 218
 //
 
@@ -18,4 +18,7 @@
 extern "C" {
 #include <dlfcn.h>										// dlopen, dlsym
+//#include <link.h>										// dl_iterate_phdr
+struct dl_phdr_info;
+int dl_iterate_phdr( int (*)( struct dl_phdr_info *, size_t, void * ), void * );
 #include <execinfo.h>									// backtrace, messages
 }
@@ -23,4 +26,5 @@
 #include "bits/defs.hfa"
 #include "bits/signal.hfa"								// sigHandler_?
+#include "concurrency/kernel/fwd.hfa"					// disable_interrupts, enable_interrupts
 #include "startup.hfa"									// STARTUP_PRIORITY_CORE
 #include <assert.h>
@@ -87,4 +91,5 @@
 	void (* exit)( int ) __attribute__(( __noreturn__ ));
 	void (* abort)( void ) __attribute__(( __noreturn__ ));
+	int (* dl_iterate_phdr)( int (*)( struct dl_phdr_info *, size_t, void * ), void * );
 } __cabi_libc;
 
@@ -102,5 +107,6 @@
 		#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
 		INTERPOSE_LIBC( abort, version );
-		INTERPOSE_LIBC( exit , version );
+		INTERPOSE_LIBC( exit, version );
+		INTERPOSE_LIBC( dl_iterate_phdr, version );
 		#pragma GCC diagnostic pop
 
@@ -150,4 +156,11 @@
 	}
 }
+
+extern "C" int dl_iterate_phdr( int (* callback)( struct dl_phdr_info *, size_t, void * ), void * data ) {
+	disable_interrupts();
+	int ret = __cabi_libc.dl_iterate_phdr( callback, data ); // call real routine
+	enable_interrupts( false );
+	return ret;
+} // dl_iterate_phdr
 
 //=============================================================================================
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/iostream.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov 17 13:33:12 2023
-// Update Count     : 1853
+// Last Modified On : Wed Jan  3 10:53:13 2024
+// Update Count     : 1898
 //
 
@@ -984,5 +984,5 @@
 	}
 
-	istype & ?|?( istype & is, _Istream_Cquoted f ) {
+	istype & ?|?( istype & is, _Istream_Cquoted f ) with( f ) {
 		char fmtstr[32];								// storage scanset and format codes
 		fmtstr[0] = '%';
@@ -992,36 +992,33 @@
 		bool check = true;
 
-		if ( f.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; }
-		int rwd = f.wd;
-		if ( f.wd != -1 ) {								// => just ignore versus ignore with width
+		if ( cstr.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; }
+		int rwd = cstr.wd;
+		if ( cstr.wd != -1 ) {						// => just ignore versus ignore with width
 			// wd is buffer bytes available (for input chars + null terminator)
 			// rwd is count of input chars
 			// no maximum width necessary because text ignored => width is read width
-			if ( f.flags.rwd ) check = false;
-			else rwd = f.wd - 1;
+			if ( cstr.flags.rwd ) check = false;
+			else rwd = cstr.wd - 1;
 			pos += sprintf( &fmtstr[pos], "%d", rwd );
 		} // if
 
 		int len = 0;									// may not be set in fmt
-		if ( ! f.flags.inex ) {							// => quoted getline
-			// fprintf( stderr, "quoted\n" );
+		char enddelim;
+		if ( ! cstr.flags.inex ) {						// => quoted getline
 			args = fmt( is, "%*[ \f\n\r\t\v]" );		// remove leading whitespace
 			if ( eof( is ) ) goto Eof;
-//			args = fmt( is, (const char *)f.delimiter ); // remove leading quote
-			args = fmt( is, "'%n", &len ); // remove leading quote
-			fprintf( stderr, "quoted %d %d\n", args, len );
+			char rfmt[4] = { cstr.delimiters[0], '%', 'n', '\0' };
+			args = fmt( is, rfmt, &len );				// remove leading quote
 			if ( len == 0 || eof( is ) ) goto Eof;
 		} // if
-		sprintf( &fmtstr[pos], "[^%c]%%n", f.delimiter[0] );
-		// fprintf( stderr, "getline %s %d\n", fmtstr, f.wd );
-		if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
-		else args = fmt( is, fmtstr, f.s, &len );
-		// fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) );
+		enddelim = cstr.delimiters[1] == '\0' ? cstr.delimiters[0] : cstr.delimiters[1];
+		sprintf( &fmtstr[pos], "[^%c]%%n", enddelim );
+		if ( cstr.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
+		else args = fmt( is, fmtstr, cstr.s, &len );
 		if ( check && len == rwd && ! eof( is ) ) {		// might not fit
 			char peek;
 			fmt( is, "%c", &peek );						// check for delimiter
-			// fprintf( stderr, "peek %d '%c'\n", args, peek );
 			if ( ! eof( is ) ) {
-				if ( peek != f.delimiter[0] ) {
+				if ( peek != enddelim ) {
 					ungetc( is, peek );
 					throwResume ExceptionInst( cstring_length );
@@ -1030,7 +1027,6 @@
 		} else fmt( is, "%*c" );						// remove delimiter
 	  Eof: ;
-		if ( rwd > 0 && args == 0 ) f.s[0] = '\0';		// read failed => no pattern match => set string to null
+		if ( rwd > 0 && args == 0 ) cstr.s[0] = '\0';	// read failed => no pattern match => set string to null
 		if ( args == 1 && eof( is ) ) {					// data but scan ended at EOF
-			// fprintf( stderr, "clear\n" );
 			clear( is );								// => reset EOF => detect again on next read
 		} // if
@@ -1038,8 +1034,8 @@
 	}
 
-	istype & ?|?( istype & is, _Istream_Cstr f ) {
+	istype & ?|?( istype & is, _Istream_Cstr f ) with( f ) {
 		const char * scanset;
 		size_t nscanset = 0;
-		if ( f.flags.delimiter ) scanset = f.delimiter;	// getline ?
+		if ( flags.delimiter ) scanset = delimiters;	// getline ?
 		else scanset = f.scanset;
 		if ( scanset ) nscanset = strlen( scanset );
@@ -1084,30 +1080,18 @@
 			if ( f.flags.delimiter ) {					// getline
 				int len = 0;							// may not be set in fmt
-				if ( ! f.flags.inex ) {					// => quoted getline
-					// fprintf( stderr, "quoted\n" );
-					args = fmt( is, "%*[ \f\n\r\t\v]" ); // remove leading whitespace
-					if ( eof( is ) ) goto X;
-					args = fmt( is, "\"" );				// remove leading quote
-					if ( eof( is ) ) goto X;
-				} // if
-				// fprintf( stderr, "getline\n" );
-				// sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset );
-				sprintf( &fmtstr[pos], "[^%s]%%n", scanset );
-				// fprintf( stderr, "getline %s %d\n", fmtstr, f.wd );
+				sprintf( &fmtstr[pos], "[^%c]%%n", f.delimiters[0] );
 				if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
 				else args = fmt( is, fmtstr, f.s, &len );
-				// fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) );
 				if ( check && len == rwd && ! eof( is ) ) {	// might not fit
-					char peek;
-					fmt( is, "%c", &peek );				// check for delimiter
-					// fprintf( stderr, "peek %d '%c'\n", args, peek );
+					fmtstr[0] = f.delimiters[0]; fmtstr[1] = '%'; fmtstr[2] = 'n'; fmtstr[3] = '\0';
+					fmt( is, fmtstr, &len );			// remove delimiter
 					if ( ! eof( is ) ) {
-						if ( peek != f.delimiter[0] ) {
-							ungetc( is, peek );
+//						if ( peek != f.delimiter[0] ) {
+						if ( len != 1 ) {
+//							ungetc( is, peek );
 							throwResume ExceptionInst( cstring_length );
 						} // if
 					} // if
-				} else fmt( is, "%*c" );			// remove delimiter
-			  X: ;
+				} else fmt( is, "%*c" );				// remove delimiter
 			} else {
 				// incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ libcfa/src/iostream.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Nov 15 17:55:31 2023
-// Update Count     : 596
+// Last Modified On : Wed Jan  3 10:53:18 2024
+// Update Count     : 610
 //
 
@@ -392,5 +392,5 @@
 	union {
 		const char * scanset;
-		char delimiter[2];
+		char delimiters[3];								// [0] => left, [1] => right
 	};
 	int wd;												// width
@@ -412,6 +412,5 @@
 
 struct _Istream_Cquoted {
-	char * s;
-	inline _Istream_str_base;
+	_Istream_Cstr cstr;
 }; // _Istream_Cquoted
 
@@ -419,15 +418,15 @@
 	// width must include room for null terminator
 	_Istream_Cstr wdi( unsigned int wd, char s[] ) { return (_Istream_Cstr)@{ s, { {0p}, wd, {.all : 0} } }; }
-	// read width does not include null terminator
 	_Istream_Cstr wdi( unsigned int wd, unsigned int rwd, char s[] ) {
 		if ( wd <= rwd ) throw (cstring_length){ &cstring_length_vt };
 		return (_Istream_Cstr)@{ s, { {0p}, rwd, {.flags.rwd : true} } };
 	}
-	_Istream_Cquoted & quoted( _Istream_Cstr & fmt, const char delimiter = '"' ) {
-		fmt.delimiter[0] = delimiter; fmt.delimiter[1] = '\0';
+	_Istream_Cquoted & quoted( _Istream_Cstr & fmt, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) {
+		fmt.delimiters[0] = Ldelimiter;  fmt.delimiters[1] = Rdelimiter;  fmt.delimiters[2] = '\0';
 		return (_Istream_Cquoted &)fmt;
 	}
 	_Istream_Cstr & getline( _Istream_Cstr & fmt, const char delimiter = '\n' ) {
-		fmt.delimiter[0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; }
+		fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
+	}
 	_Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
 	_Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
Index: libcfa/src/raii.hfa
===================================================================
--- libcfa/src/raii.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ libcfa/src/raii.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,109 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2023 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// raii.hfa -- PUBLIC
+// Utilities for advanced RAII (constructor/destructor) patterns
+//
+// Author           : Mike Brooks
+// Created On       : Fri Sep 22 15:00:00 2023
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+#pragma once
+
+// Provides access to unititialized storage.
+// Intended to make cheap delayed intialization possible.
+// Similar to uC++ uNoCtor.
+// Regardless of what constructors T offers, the declaration
+//   uninit(T) x;
+// makes x:
+//   - assignable to T,
+//   - be, at first, uninitialized, and
+//   - receive a T-destructor call when x goes out of scope.
+// This sitation means the user becomes responsible for making a placement constructor call
+// on x before its first use, even if this first use is the implicit destructor call.
+// This sitation contrasts with that of
+//   T y @= {};
+// in that y does not receive an implied destructor call when it goes out of scope.
+// This sitation contrasts with that of
+//   optional(T) z;
+// in that z receives a T-destructor call conditionally upon the runtime-tracked state,
+// and that z's assignability to T is guarded by the runtime-tracked state.
+//
+// Implementation note: the uninit RAII that follows is a parade of cfa-cpp quirk exploitations.
+//
+forall( T* )
+struct uninit {
+    inline T;
+};
+
+// Parameterless ctor: leaves bits within uninitialized.
+forall( T* )
+void  ?{}( uninit(T) & this ) { 
+
+    // Implementation takes advantage of CFA-available unsoundness.
+    // It could be called a bug; if it's fixed, then uninit needs an escape hatch,
+    // or to find a different loophole.
+
+    // Fundamental unsoundness: Here is a constructor for a T, whatever T is.
+    // Sound compiler reaction: We don't know what fields T has,
+    // so the programmer is surely failing to initialize all of T's fields,
+    // for some choice of T.
+    // Current compiler reaction: Ok, it initializes all the fields we know about.
+    void ?{}( T & ) {}
+
+    // Now for some ado about nothing.
+    // We need to call the above constructor on the inline T field.
+    //   Becasue the compiler holds us accountable for intizliing every field of uninit(T).
+    //   We are happy to do so and are not trying to get out of it.
+    // But the compiler doesn't recognize this form as a field initialization
+    //   T & inner = this;
+    //   ( inner ){};
+    // And the compiler doesn't offer this feature
+    //   ( (return T &) this ){};
+    // It does recognize this form...
+
+    ( (T&) this ){};
+
+    // ...though it probably shouldn't.
+    // The problem with this form is that it doesn't actually mean the Plan-9 base field.
+    // It means to reinterpret `this` with type T.
+    // For a plan-9 use in which the base-type field is not first,
+    // this form would send the wrong address to the called ctor.
+    // Fortunately, uninit has the base-type field first.
+    // For an RAII use in which the constructor does something,
+    // getting the wrong address would matter.
+    // Fortunately, ?{}(T&) is a no-op.
+}
+
+// dtor: pass-through
+forall( T* | { void ^?{}( T& ); } )
+void ^?{}( uninit(T) & this) {
+    // an inner dtor call is implied
+
+    // In fact, an autogen'd dtor would have sufficed.
+    // But there is no autogen'd dtor because no T-dtor is asserted on the struct declaration.
+    // Adding assertions to the struct decl would make the intended ctor (implemented above)
+    // a less preferred candidate than the declared, but undefined, (ugh!) autogen ctor.
+}
+
+// Optional explicit inner-ctor invoation helper.
+// Generally optional, because 1 and 2 below are equivalent:
+//   struct Foo;
+//   void ?{}( Foo &, X, Y, Z );
+//   uninit(Foo) uf;
+//   ?( uf ){ x, y, z };      // 1
+//   emplace( uf, x, y, z );  // 2
+// Is necessary for reaching a parameterless constructor 
+//   void ?{}( Foo & );
+//   ?( uf ){};               // calls ?{}( uninit(Foo) & ), which does nothing
+//   emplace( uf );           // calls ?{}( Foo & ), probably what you want
+forall( T*, Args... | { void ?{}( T&, Args ); } )
+void emplace( uninit(T) & this, Args a ) {
+    T & inner = this;
+    ( inner ){ a };
+}
Index: src/AST/Attribute.cpp
===================================================================
--- src/AST/Attribute.cpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/AST/Attribute.cpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -38,9 +38,9 @@
 
 bool Attribute::isValidOnFuncParam() const {
-	// attributes such as aligned, cleanup, etc. produce GCC errors when they appear
-	// on function parameters. Maintain here a whitelist of attribute names that are
-	// allowed to appear on parameters.
+	// Attributes produce GCC errors when they appear on function
+	// parameters. Names on the previous allow-list implementation:
+	// unused, noreturn, __vector_size__
 	std::string norm = normalizedName();
-	return norm == "unused" || norm == "noreturn";
+	return norm != "aligned" && norm != "packed" && norm != "used";
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/AST/Decl.hpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -29,5 +29,4 @@
 #include "StorageClasses.hpp"
 #include "Visitor.hpp"
-#include "Common/utility.h"
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/AST/Pass.proto.hpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -19,4 +19,5 @@
 #include "Common/Iterate.hpp"
 #include "Common/Stats/Heap.h"
+#include "Common/utility.h"
 namespace ast {
 	template<typename core_t> class Pass;
Index: src/CodeGen/CodeGenerator.hpp
===================================================================
--- src/CodeGen/CodeGenerator.hpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/CodeGen/CodeGenerator.hpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -21,4 +21,5 @@
 #include "AST/Pass.hpp"          // for WithGuards, WithShortCircuiting, ...
 #include "CodeGen/Options.h"     // for Options
+#include "Common/Indenter.h"     // for Indenter
 
 
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Common/utility.h	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Feb 17 15:25:00 2023
-// Update Count     : 53
+// Last Modified On : Wed Jan 17 14:40:00 2024
+// Update Count     : 54
 //
 
@@ -17,114 +17,13 @@
 
 #include <cassert>
-#include <cctype>
 #include <algorithm>
-#include <iostream>
 #include <list>
-#include <memory>
 #include <string>
 #include <type_traits>
 #include <vector>
-#include <cstring>										// memcmp
-
-#include "Common/Indenter.h"
-
-class Expression;
-
-/// bring std::move into global scope
-using std::move;
 
 /// partner to move that copies any copyable type
 template<typename T>
 T copy( const T & x ) { return x; }
-
-template< typename T >
-static inline T * maybeClone( const T *orig ) {
-	if ( orig ) {
-		return orig->clone();
-	} else {
-		return 0;
-	} // if
-}
-
-template< typename Input_iterator >
-void printEnums( Input_iterator begin, Input_iterator end, const char * const *name_array, std::ostream &os ) {
-	for ( Input_iterator i = begin; i != end; ++i ) {
-		os << name_array[ *i ] << ' ';
-	} // for
-}
-
-template< typename Container >
-void deleteAll( const Container &container ) {
-	for ( const auto &i : container ) {
-		delete i;
-	} // for
-}
-
-template< typename Container >
-void printAll( const Container &container, std::ostream &os, Indenter indent = {} ) {
-	for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
-		if ( *i ) {
-			os << indent;
-			(*i)->print( os, indent );
-			// need an endl after each element because it's not easy to know when each individual item should end
-			os << std::endl;
-		} // if
-	} // for
-}
-
-template< typename SrcContainer, typename DestContainer >
-void cloneAll( const SrcContainer &src, DestContainer &dest ) {
-	typename SrcContainer::const_iterator in = src.begin();
-	std::back_insert_iterator< DestContainer > out( dest );
-	while ( in != src.end() ) {
-		*out++ = (*in++)->clone();
-	} // while
-}
-
-template< typename SrcContainer, typename DestContainer, typename Predicate >
-void cloneAll_if( const SrcContainer &src, DestContainer &dest, Predicate pred ) {
-	std::back_insert_iterator< DestContainer > out( dest );
-	for ( auto x : src ) {
-		if ( pred(x) ) {
-			*out++ = x->clone();
-		}
-	} // while
-}
-
-template< typename Container >
-void assertAll( const Container &container ) {
-	int count = 0;
-	for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
-		if ( !(*i) ) {
-			std::cerr << count << " is null" << std::endl;
-		} // if
-	} // for
-}
-
-template < typename T >
-std::list<T> tail( std::list<T> l ) {
-	if ( ! l.empty() ) {
-		std::list<T> ret(++(l.begin()), l.end());
-		return ret;
-	} // if
-}
-
-template < typename T >
-std::list<T> flatten( std::list < std::list<T> > l) {
-	typedef std::list <T> Ts;
-
-	Ts ret;
-
-	switch ( l.size() ) {
-	  case 0:
-		return ret;
-	  case 1:
-		return l.front();
-	  default:
-		ret = flatten(tail(l));
-		ret.insert(ret.begin(), l.front().begin(), l.front().end());
-		return ret;
-	} // switch
-}
 
 /// Splice src onto the end of dst, clearing src
@@ -143,24 +42,5 @@
 }
 
-template< typename... Args >
-auto filter(Args&&... args) -> decltype(std::copy_if(std::forward<Args>(args)...)) {
-  return std::copy_if(std::forward<Args>(args)...);
-}
-
-template <typename E, typename UnaryPredicate, template< typename, typename...> class Container, typename... Args >
-void filter( Container< E *, Args... > & container, UnaryPredicate pred, bool doDelete ) {
-	auto i = begin( container );
-	while ( i != end( container ) ) {
-		auto it = next( i );
-		if ( pred( *i ) ) {
-			if ( doDelete ) {
-				delete *i;
-			} // if
-			container.erase( i );
-		} // if
-		i = it;
-	} // while
-}
-
+/// Remove elements that match pred from the container.
 template<typename Container, typename Pred>
 void erase_if( Container & cont, Pred && pred ) {
Index: src/InitTweak/FixInit.cpp
===================================================================
--- src/InitTweak/FixInit.cpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/InitTweak/FixInit.cpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -581,5 +581,7 @@
 	}
 
-	if ( ! dtor->env ) dtor->env = maybeClone( env );
+	if ( nullptr == dtor->env && nullptr != env ) {
+		dtor->env = ast::shallowCopy( env );
+	}
 	auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore );
 
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Parser/DeclarationNode.cc	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -35,5 +35,5 @@
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/UniqueName.h"     // for UniqueName
-#include "Common/utility.h"        // for maybeClone
+#include "Common/utility.h"        // for copy, spliceBegin
 #include "Parser/ExpressionNode.h" // for ExpressionNode
 #include "Parser/InitializerNode.h"// for InitializerNode
@@ -41,6 +41,4 @@
 #include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
 #include "TypedefTable.h"          // for TypedefTable
-
-class Initializer;
 
 extern TypedefTable typedefTable;
@@ -101,29 +99,29 @@
 DeclarationNode * DeclarationNode::clone() const {
 	DeclarationNode * newnode = new DeclarationNode;
-	newnode->set_next( maybeClone( get_next() ) );
+	newnode->set_next( maybeCopy( get_next() ) );
 	newnode->name = name ? new string( *name ) : nullptr;
 
 	newnode->builtin = NoBuiltinType;
-	newnode->type = maybeClone( type );
+	newnode->type = maybeCopy( type );
 	newnode->inLine = inLine;
 	newnode->storageClasses = storageClasses;
 	newnode->funcSpecs = funcSpecs;
-	newnode->bitfieldWidth = maybeClone( bitfieldWidth );
-	newnode->enumeratorValue.reset( maybeClone( enumeratorValue.get() ) );
+	newnode->bitfieldWidth = maybeCopy( bitfieldWidth );
+	newnode->enumeratorValue.reset( maybeCopy( enumeratorValue.get() ) );
 	newnode->hasEllipsis = hasEllipsis;
 	newnode->linkage = linkage;
 	newnode->asmName = maybeCopy( asmName );
 	newnode->attributes = attributes;
-	newnode->initializer = maybeClone( initializer );
+	newnode->initializer = maybeCopy( initializer );
 	newnode->extension = extension;
-	newnode->asmStmt = maybeClone( asmStmt );
+	newnode->asmStmt = maybeCopy( asmStmt );
 	newnode->error = error;
 
 //	newnode->variable.name = variable.name ? new string( *variable.name ) : nullptr;
 	newnode->variable.tyClass = variable.tyClass;
-	newnode->variable.assertions = maybeClone( variable.assertions );
-	newnode->variable.initializer = maybeClone( variable.initializer );
-
-	newnode->assert.condition = maybeClone( assert.condition );
+	newnode->variable.assertions = maybeCopy( variable.assertions );
+	newnode->variable.initializer = maybeCopy( variable.initializer );
+
+	newnode->assert.condition = maybeCopy( assert.condition );
 	newnode->assert.message = maybeCopy( assert.message );
 	return newnode;
@@ -664,5 +662,5 @@
 				dst->base->aggInst.aggregate = src;
 				if ( src->kind == TypeData::Aggregate ) {
-					dst->base->aggInst.params = maybeClone( src->aggregate.actuals );
+					dst->base->aggInst.params = maybeCopy( src->aggregate.actuals );
 				} // if
 				dst->base->qualifiers |= src->qualifiers;
@@ -694,5 +692,5 @@
 					if ( o->type->kind == TypeData::Aggregate ) {
 						type->aggInst.hoistType = o->type->aggregate.body;
-						type->aggInst.params = maybeClone( o->type->aggregate.actuals );
+						type->aggInst.params = maybeCopy( o->type->aggregate.actuals );
 					} else {
 						type->aggInst.hoistType = o->type->enumeration.body;
@@ -860,5 +858,5 @@
 				p->type->base->aggInst.aggregate = type;
 				if ( type->kind == TypeData::Aggregate ) {
-					p->type->base->aggInst.params = maybeClone( type->aggregate.actuals );
+					p->type->base->aggInst.params = maybeCopy( type->aggregate.actuals );
 				} // if
 				p->type->base->qualifiers |= type->qualifiers;
@@ -897,5 +895,5 @@
 			lastArray->base->aggInst.aggregate = type;
 			if ( type->kind == TypeData::Aggregate ) {
-				lastArray->base->aggInst.params = maybeClone( type->aggregate.actuals );
+				lastArray->base->aggInst.params = maybeCopy( type->aggregate.actuals );
 			} // if
 			lastArray->base->qualifiers |= type->qualifiers;
@@ -950,5 +948,5 @@
 DeclarationNode * DeclarationNode::cloneType( string * name ) {
 	DeclarationNode * newnode = newName( name );
-	newnode->type = maybeClone( type );
+	newnode->type = maybeCopy( type );
 	newnode->copySpecifiers( this );
 	return newnode;
@@ -984,5 +982,5 @@
 		} // if
 
-		newType->forall = maybeClone( type->forall );
+		newType->forall = maybeCopy( type->forall );
 		if ( ! o->type ) {
 			o->type = newType;
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Parser/ParseNode.h	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -30,5 +30,4 @@
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/UniqueName.h"     // for UniqueName
-#include "Common/utility.h"        // for maybeClone
 #include "Parser/parserutility.h"  // for maybeBuild, maybeCopy
 
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Parser/TypeData.cc	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -167,6 +167,6 @@
 	TypeData * newtype = new TypeData( kind );
 	newtype->qualifiers = qualifiers;
-	newtype->base = maybeClone( base );
-	newtype->forall = maybeClone( forall );
+	newtype->base = maybeCopy( base );
+	newtype->forall = maybeCopy( forall );
 
 	switch ( kind ) {
@@ -185,21 +185,21 @@
 		break;
 	case Array:
-		newtype->array.dimension = maybeClone( array.dimension );
+		newtype->array.dimension = maybeCopy( array.dimension );
 		newtype->array.isVarLen = array.isVarLen;
 		newtype->array.isStatic = array.isStatic;
 		break;
 	case Function:
-		newtype->function.params = maybeClone( function.params );
-		newtype->function.idList = maybeClone( function.idList );
-		newtype->function.oldDeclList = maybeClone( function.oldDeclList );
-		newtype->function.body = maybeClone( function.body );
-		newtype->function.withExprs = maybeClone( function.withExprs );
+		newtype->function.params = maybeCopy( function.params );
+		newtype->function.idList = maybeCopy( function.idList );
+		newtype->function.oldDeclList = maybeCopy( function.oldDeclList );
+		newtype->function.body = maybeCopy( function.body );
+		newtype->function.withExprs = maybeCopy( function.withExprs );
 		break;
 	case Aggregate:
 		newtype->aggregate.kind = aggregate.kind;
 		newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
-		newtype->aggregate.params = maybeClone( aggregate.params );
-		newtype->aggregate.actuals = maybeClone( aggregate.actuals );
-		newtype->aggregate.fields = maybeClone( aggregate.fields );
+		newtype->aggregate.params = maybeCopy( aggregate.params );
+		newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
+		newtype->aggregate.fields = maybeCopy( aggregate.fields );
 		newtype->aggregate.body = aggregate.body;
 		newtype->aggregate.anon = aggregate.anon;
@@ -208,11 +208,11 @@
 		break;
 	case AggregateInst:
-		newtype->aggInst.aggregate = maybeClone( aggInst.aggregate );
-		newtype->aggInst.params = maybeClone( aggInst.params );
+		newtype->aggInst.aggregate = maybeCopy( aggInst.aggregate );
+		newtype->aggInst.params = maybeCopy( aggInst.params );
 		newtype->aggInst.hoistType = aggInst.hoistType;
 		break;
 	case Enum:
 		newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr;
-		newtype->enumeration.constants = maybeClone( enumeration.constants );
+		newtype->enumeration.constants = maybeCopy( enumeration.constants );
 		newtype->enumeration.body = enumeration.body;
 		newtype->enumeration.anon = enumeration.anon;
@@ -221,15 +221,15 @@
 	case SymbolicInst:
 		newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
-		newtype->symbolic.params = maybeClone( symbolic.params );
-		newtype->symbolic.actuals = maybeClone( symbolic.actuals );
-		newtype->symbolic.assertions = maybeClone( symbolic.assertions );
+		newtype->symbolic.params = maybeCopy( symbolic.params );
+		newtype->symbolic.actuals = maybeCopy( symbolic.actuals );
+		newtype->symbolic.assertions = maybeCopy( symbolic.assertions );
 		newtype->symbolic.isTypedef = symbolic.isTypedef;
 		break;
 	case Tuple:
-		newtype->tuple = maybeClone( tuple );
+		newtype->tuple = maybeCopy( tuple );
 		break;
 	case Typeof:
 	case Basetypeof:
-		newtype->typeexpr = maybeClone( typeexpr );
+		newtype->typeexpr = maybeCopy( typeexpr );
 		break;
 	case Vtable:
@@ -240,6 +240,6 @@
 		break;
 	case Qualified:
-		newtype->qualified.parent = maybeClone( qualified.parent );
-		newtype->qualified.child = maybeClone( qualified.child );
+		newtype->qualified.parent = maybeCopy( qualified.parent );
+		newtype->qualified.child = maybeCopy( qualified.child );
 		break;
 	} // switch
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Parser/parser.yy	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -1960,5 +1960,5 @@
 			// Append the return type at the start (left-hand-side) to each identifier in the list.
 			DeclarationNode * ret = new DeclarationNode;
-			ret->type = maybeClone( $1->type->base );
+			ret->type = maybeCopy( $1->type->base );
 			$$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
 		}
Index: src/Parser/parserutility.h
===================================================================
--- src/Parser/parserutility.h	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Parser/parserutility.h	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -36,5 +36,5 @@
 
 template<typename node_t>
-node_t * maybeCopy( node_t const * node ) {
+static inline node_t * maybeCopy( node_t const * node ) {
 	return node ? ast::shallowCopy( node ) : nullptr;
 }
Index: src/SymTab/GenImplicitCall.cpp
===================================================================
--- src/SymTab/GenImplicitCall.cpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/SymTab/GenImplicitCall.cpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -25,4 +25,5 @@
 #include "CodeGen/OperatorTable.h"       // for isCtorDtor
 #include "Common/UniqueName.h"           // for UniqueName
+#include "Common/utility.h"              // for splice
 
 namespace SymTab {
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Validate/Autogen.cpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -445,5 +445,7 @@
 
 		auto * paramType = ast::deepCopy( member->get_type() );
-		paramType->attributes.clear();
+		erase_if( paramType->attributes, []( ast::Attribute const * attr ){
+			return !attr->isValidOnFuncParam();
+		} );
 		ast::ObjectDecl * param = new ast::ObjectDecl(
 			getLocation(), member->name, paramType );
Index: src/Validate/ReplaceTypedef.cpp
===================================================================
--- src/Validate/ReplaceTypedef.cpp	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ src/Validate/ReplaceTypedef.cpp	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -25,16 +25,4 @@
 
 namespace {
-
-bool isNonParameterAttribute( ast::Attribute const * attr ) {
-	static const std::vector<std::string> bad_names = {
-		"aligned", "__aligned__",
-	};
-	for ( auto name : bad_names ) {
-		if ( name == attr->name ) {
-			return true;
-		}
-	}
-	return false;
-}
 
 struct ReplaceTypedefCore final :
@@ -101,5 +89,7 @@
 		// by typedef. GCC appears to do the same thing.
 		if ( isAtFunctionTop ) {
-			erase_if( ret->attributes, isNonParameterAttribute );
+			erase_if( ret->attributes, []( ast::Attribute const * attr ){
+				return !attr->isValidOnFuncParam();
+			} );
 		}
 		for ( const auto & attribute : type->attributes ) {
Index: tests/Makefile.am
===================================================================
--- tests/Makefile.am	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/Makefile.am	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -92,5 +92,6 @@
 	concurrency/channels/parallel_harness.hfa \
 	array-collections/dimexpr-match.hfa \
-	array-collections/dimexpr-match-detail.sh
+	array-collections/dimexpr-match-detail.sh \
+	array-collections/array-raii.hfa
 
 dist-hook:
Index: tests/array-collections/.expect/array-raii-c.txt
===================================================================
--- tests/array-collections/.expect/array-raii-c.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ tests/array-collections/.expect/array-raii-c.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,109 @@
+=== builtins
+some nonzero
+silly: some nonzero
+=== custom
+ [1]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [2]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+ctor 5
+func 0 at (0, 0)
+func 1 at (0, 1)
+func 2 at (0, 2)
+func 3 at (1, 0)
+func 4 at (1, 1)
+func 5 at (1, 2)
+dtor 5
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [3]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [4]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+=== uninit
+ [1]
+before ctors
+ctor 0
+ctor 999
+ctor 888
+ctor 3
+ctor 4
+func 0
+func 999
+func 888
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 888
+dtor 999
+dtor 0
+ [2]
+before ctors
+ctor 100
+ctor 101
+ctor 102
+ctor 110
+ctor 999
+ctor 888
+func 100 at (0, 0)
+func 101 at (0, 1)
+func 102 at (0, 2)
+func 110 at (1, 0)
+func 999 at (1, 1)
+func 888 at (1, 2)
+dtor 888
+dtor 999
+dtor 110
+dtor 102
+dtor 101
+dtor 100
Index: tests/array-collections/.expect/array-raii-cfa.txt
===================================================================
--- tests/array-collections/.expect/array-raii-cfa.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ tests/array-collections/.expect/array-raii-cfa.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,109 @@
+=== builtins
+some nonzero
+silly: some nonzero
+=== custom
+ [1]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [2]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+ctor 5
+func 0 at (0, 0)
+func 1 at (0, 1)
+func 2 at (0, 2)
+func 3 at (1, 0)
+func 4 at (1, 1)
+func 5 at (1, 2)
+dtor 5
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [3]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+ [4]
+ctor 0
+ctor 1
+ctor 2
+ctor 3
+ctor 4
+func 0
+func 1
+func 2
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 2
+dtor 1
+dtor 0
+=== uninit
+ [1]
+before ctors
+ctor 0
+ctor 999
+ctor 888
+ctor 3
+ctor 4
+func 0
+func 999
+func 888
+func 3
+func 4
+dtor 4
+dtor 3
+dtor 888
+dtor 999
+dtor 0
+ [2]
+before ctors
+ctor 100
+ctor 101
+ctor 102
+ctor 110
+ctor 999
+ctor 888
+func 100 at (0, 0)
+func 101 at (0, 1)
+func 102 at (0, 2)
+func 110 at (1, 0)
+func 999 at (1, 1)
+func 888 at (1, 2)
+dtor 888
+dtor 999
+dtor 110
+dtor 102
+dtor 101
+dtor 100
Index: tests/array-collections/array-raii-c.cfa
===================================================================
--- tests/array-collections/array-raii-c.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ tests/array-collections/array-raii-c.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,21 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2023 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// array-raii-c.cfa -- checks RAII on C arrays of initialized elements
+//
+// Author           : Mike Brooks
+// Created On       : Fri Sep 22 15:00:00 2023
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+// C array means like `float x[17];`, as used within CFA
+
+#define ADECL1(X, El, N)    El X[N];
+#define ADECL2(X, El, M, N) El X[M][N];
+
+#include "array-raii.hfa"
Index: tests/array-collections/array-raii-cfa.cfa
===================================================================
--- tests/array-collections/array-raii-cfa.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ tests/array-collections/array-raii-cfa.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,23 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2023 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// array-raii-cfa.cfa -- checks RAII on CFA arrays of initialized elements
+//
+// Author           : Mike Brooks
+// Created On       : Fri Sep 22 15:00:00 2023
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+// CFA array means like `array(float, 17) x;`
+
+#include <collections/array.hfa>
+
+#define ADECL1(X, El, N)    array(El, N) X;
+#define ADECL2(X, El, M, N) array(El, M, N) X;
+
+#include "array-raii.hfa"
Index: tests/array-collections/array-raii.hfa
===================================================================
--- tests/array-collections/array-raii.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
+++ tests/array-collections/array-raii.hfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -0,0 +1,174 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2023 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// array-raii.hfa -- combined test implementation for both -c and -cfa versions
+//
+// Author           : Mike Brooks
+// Created On       : Fri Sep 22 15:00:00 2023
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+
+#include <raii.hfa>
+
+// To keep C- vs CFA-array compatibility simple. these tests
+// - use only single-place subscripting, like `m[1][2]`, while deferring 
+//   equivalence of m[1][2] vs m[1,2] to array-md-sbscr-cases
+// - declare arrays via test-specific ADECL macros
+
+
+
+volatile bool checkme = false;
+char junkref[] = "junk";
+extern "C" {
+    char* strcpy(char* destination, const char* source);
+}
+
+// Array of built-in type does not get zeroed
+//   (Surprised?)
+//   Because it has nothing to do with arrays.
+//   Built-in types have no-op ctors.
+//   (Still surprised?  Me too.)
+// If pigs flew and built-ins zeroed themselves, then
+//   Array of built-in type gets zeroed
+//   Array of user-defined type with autogen ctors gets wrapped builtins zeroed (intended purpose of case2 when originally written)
+//   Expected outcome becomes "all zero" twice
+// As is
+//   case1 pretty much just shows the summary statement above and
+//   verifying the case2-wrapper behaviour is just silly, so
+//   the quality of respecting autogens is checked (for real this time) under test_custom
+void test_builtins() {
+    void writeJunkOnStack(int depth) {
+        if (depth == 0) return;
+        char junk[5];
+        strcpy(junk, junkref);
+        writeJunkOnStack(depth-1);
+        if (checkme) printf("%s\n", junk);
+    }
+    void checkzero(float f0, float f1, float f2, float f3, float f4) {
+        if (f0 == 0.f && f1 == 0.f && f2 == 0.f && f3 == 0.f && f4 == 0.f) {
+            printf("all zero\n");
+        } else {
+            printf("some nonzero\n");
+          //printf("%f %f %f %f %f\n", f0, f1, f2, f3, f4);
+        }
+    }
+    void case1() {
+        ADECL1(x, float, 5)
+        checkzero(x[0], x[1], x[2], x[3], x[4]);
+    }
+    struct ffloat { float f; };
+    void case2() {
+        ADECL1(x, ffloat, 5)
+        checkzero(x[0].f, x[1].f, x[2].f, x[3].f, x[4].f);
+    }
+
+    writeJunkOnStack(5);
+    case1();
+    printf("silly: ");
+    writeJunkOnStack(5);
+    case2();
+}
+
+// Array of type with custom raii sees cdtors called
+// Array of user-defined type with autogen cdtors gets wrapped cdtors called
+void test_custom() {
+    int nctorcalls;
+    struct thing { int mem; };
+    void ?{}( thing & this ) {
+        (this.mem){ nctorcalls++ };
+        printf("ctor %d\n", this.mem);
+    }
+    void ^?{}( thing & this ) {
+        printf("dtor %d\n", this.mem);
+    }
+    struct wrapper1 { thing inner; };
+    forall( T ) struct wrapper2 { T inner; };
+    printf(" [1]\n");
+    {
+        nctorcalls = 0;
+        ADECL1(a, thing, 5)
+        for(i; 5) printf("func %d\n", a[i].mem);
+    }
+    printf(" [2]\n");
+    {
+        // White-box note: For the CFA array, the array cdtor is satisfying
+        // its own assertion, in a two-level recursive setup.
+        nctorcalls = 0;
+        ADECL2(a, thing, 2, 3)
+        for(i; 2) for(j; 3) printf("func %d at (%d, %d)\n", a[i][j].mem, i, j);
+    }
+    printf(" [3]\n");
+    {
+        nctorcalls = 0;
+        ADECL1(a, wrapper1, 5)
+        for(i; 5) printf("func %d\n", a[i].inner.mem);
+    }
+    printf(" [4]\n");
+    {
+        nctorcalls = 0;
+        ADECL1(a, wrapper2(thing), 5)
+        for(i; 5) printf("func %d\n", a[i].inner.mem);
+    }
+}
+
+// Array of uninits sees explicit ctor calls (only), and implied dtor calls
+void test_uninit() {
+    struct thing { int mem; };
+    void ?{}( thing & this, int i ) {
+        (this.mem){ i };
+        printf("ctor %d\n", this.mem);
+    }
+    void ?{}( thing & this ) {
+        (this){ 999 };
+    }
+    void ^?{}( thing & this ) {
+        printf("dtor %d\n", this.mem);
+    }
+    printf(" [1]\n");
+    {
+        ADECL1(a, uninit(thing), 5)
+        printf("before ctors\n");
+        for(i; 5) {
+            if (i == 1)
+                emplace(a[i]);
+            else if (i == 2)
+                emplace(a[i], 888);
+            else
+                (a[i]){i};
+        }
+        for(i; 5) printf("func %d\n", a[i].mem);
+    }
+    printf(" [2]\n");
+    {
+        ADECL2(a, uninit(thing), 2, 3)
+        printf("before ctors\n");
+        for(i; 2) for(j; 3) {
+            if (i == 1 && j == 1)
+                emplace(a[i][j]);
+            else if (i == 1 && j == 2)
+                emplace(a[i][j], 888);
+            else
+                (a[i][j]){100 + 10 * i + j};
+        }
+        for(i; 2) for(j; 3) {
+            printf("func %d at (%d, %d)\n", a[i][j].mem, i, j);
+        }
+    }
+}
+
+int main() {
+    printf("=== builtins\n");
+    test_builtins();
+
+    printf("=== custom\n");
+    test_custom();
+
+    printf("=== uninit\n");
+    test_uninit();
+}
Index: tests/collections/.expect/string-api-coverage.txt
===================================================================
--- tests/collections/.expect/string-api-coverage.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/.expect/string-api-coverage.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -14,10 +14,22 @@
 true false
 true false
+1234567
 123
 hello
+hell
 hello
 world
 hello
 world
+Q
+1234567
+hello
+Q
+123
+hell
+1234567
+hello
+123
+hell
 5
 helloworld
@@ -29,7 +41,16 @@
 hello, friend
 bye, friend
+ohello
+ohell
+ohell
+omydarling
+omy
+omy
+hellohellohellohello
 hellohellohello
 QQQ
 asdfasdfasdf
+lo
+hello heliocentric
 e
 help!!!o
Index: tests/collections/.expect/string-compare.txt
===================================================================
--- tests/collections/.expect/string-compare.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/.expect/string-compare.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -1,4 +1,4 @@
 ------- string -------
-(cmp(s_, s_) == 0) ok
+(strcmp(s_, s_) == 0) ok
 (s_ == s_) ok
 !(s_ != s_) ok
@@ -7,5 +7,5 @@
 (s_ <= s_) ok
 !(s_ < s_) ok
-(cmp("", s_) == 0) ok
+(strcmp("", s_) == 0) ok
 ("" == s_) ok
 !("" != s_) ok
@@ -14,5 +14,5 @@
 ("" <= s_) ok
 !("" < s_) ok
-(cmp(s_, "") == 0) ok
+(strcmp(s_, "") == 0) ok
 (s_ == "") ok
 !(s_ != "") ok
@@ -21,5 +21,5 @@
 (s_ <= "") ok
 !(s_ < "") ok
-(cmp(s_, s_a) < 0) ok
+(strcmp(s_, s_a) < 0) ok
 !(s_ == s_a) ok
 (s_ != s_a) ok
@@ -28,5 +28,5 @@
 (s_ <= s_a) ok
 (s_ < s_a) ok
-(cmp("", s_a) < 0) ok
+(strcmp("", s_a) < 0) ok
 !("" == s_a) ok
 ("" != s_a) ok
@@ -35,5 +35,5 @@
 ("" <= s_a) ok
 ("" < s_a) ok
-(cmp(s_, "a") < 0) ok
+(strcmp(s_, "a") < 0) ok
 !(s_ == "a") ok
 (s_ != "a") ok
@@ -42,5 +42,5 @@
 (s_ <= "a") ok
 (s_ < "a") ok
-(cmp(s_a, s_) > 0) ok
+(strcmp(s_a, s_) > 0) ok
 !(s_a == s_) ok
 (s_a != s_) ok
@@ -49,5 +49,5 @@
 !(s_a <= s_) ok
 !(s_a < s_) ok
-(cmp("a", s_) > 0) ok
+(strcmp("a", s_) > 0) ok
 !("a" == s_) ok
 ("a" != s_) ok
@@ -56,5 +56,5 @@
 !("a" <= s_) ok
 !("a" < s_) ok
-(cmp(s_a, "") > 0) ok
+(strcmp(s_a, "") > 0) ok
 !(s_a == "") ok
 (s_a != "") ok
@@ -63,5 +63,5 @@
 !(s_a <= "") ok
 !(s_a < "") ok
-(cmp(s_, s_aa) < 0) ok
+(strcmp(s_, s_aa) < 0) ok
 !(s_ == s_aa) ok
 (s_ != s_aa) ok
@@ -70,5 +70,5 @@
 (s_ <= s_aa) ok
 (s_ < s_aa) ok
-(cmp("", s_aa) < 0) ok
+(strcmp("", s_aa) < 0) ok
 !("" == s_aa) ok
 ("" != s_aa) ok
@@ -77,5 +77,5 @@
 ("" <= s_aa) ok
 ("" < s_aa) ok
-(cmp(s_, "aa") < 0) ok
+(strcmp(s_, "aa") < 0) ok
 !(s_ == "aa") ok
 (s_ != "aa") ok
@@ -84,5 +84,5 @@
 (s_ <= "aa") ok
 (s_ < "aa") ok
-(cmp(s_aa, s_) > 0) ok
+(strcmp(s_aa, s_) > 0) ok
 !(s_aa == s_) ok
 (s_aa != s_) ok
@@ -91,5 +91,5 @@
 !(s_aa <= s_) ok
 !(s_aa < s_) ok
-(cmp("aa", s_) > 0) ok
+(strcmp("aa", s_) > 0) ok
 !("aa" == s_) ok
 ("aa" != s_) ok
@@ -98,5 +98,5 @@
 !("aa" <= s_) ok
 !("aa" < s_) ok
-(cmp(s_aa, "") > 0) ok
+(strcmp(s_aa, "") > 0) ok
 !(s_aa == "") ok
 (s_aa != "") ok
@@ -105,5 +105,5 @@
 !(s_aa <= "") ok
 !(s_aa < "") ok
-(cmp(s_a, s_aa) < 0) ok
+(strcmp(s_a, s_aa) < 0) ok
 !(s_a == s_aa) ok
 (s_a != s_aa) ok
@@ -112,5 +112,5 @@
 (s_a <= s_aa) ok
 (s_a < s_aa) ok
-(cmp("a", s_aa) < 0) ok
+(strcmp("a", s_aa) < 0) ok
 !("a" == s_aa) ok
 ("a" != s_aa) ok
@@ -119,5 +119,5 @@
 ("a" <= s_aa) ok
 ("a" < s_aa) ok
-(cmp(s_a, "aa") < 0) ok
+(strcmp(s_a, "aa") < 0) ok
 !(s_a == "aa") ok
 (s_a != "aa") ok
@@ -126,5 +126,5 @@
 (s_a <= "aa") ok
 (s_a < "aa") ok
-(cmp(s_aa, s_a) > 0) ok
+(strcmp(s_aa, s_a) > 0) ok
 !(s_aa == s_a) ok
 (s_aa != s_a) ok
@@ -133,5 +133,5 @@
 !(s_aa <= s_a) ok
 !(s_aa < s_a) ok
-(cmp("aa", s_a) > 0) ok
+(strcmp("aa", s_a) > 0) ok
 !("aa" == s_a) ok
 ("aa" != s_a) ok
@@ -140,5 +140,5 @@
 !("aa" <= s_a) ok
 !("aa" < s_a) ok
-(cmp(s_aa, "a") > 0) ok
+(strcmp(s_aa, "a") > 0) ok
 !(s_aa == "a") ok
 (s_aa != "a") ok
@@ -147,5 +147,5 @@
 !(s_aa <= "a") ok
 !(s_aa < "a") ok
-(cmp(s_a, s_a) == 0) ok
+(strcmp(s_a, s_a) == 0) ok
 (s_a == s_a) ok
 !(s_a != s_a) ok
@@ -154,5 +154,5 @@
 (s_a <= s_a) ok
 !(s_a < s_a) ok
-(cmp("a", s_a) == 0) ok
+(strcmp("a", s_a) == 0) ok
 ("a" == s_a) ok
 !("a" != s_a) ok
@@ -161,5 +161,5 @@
 ("a" <= s_a) ok
 !("a" < s_a) ok
-(cmp(s_a, "a") == 0) ok
+(strcmp(s_a, "a") == 0) ok
 (s_a == "a") ok
 !(s_a != "a") ok
@@ -168,5 +168,5 @@
 (s_a <= "a") ok
 !(s_a < "a") ok
-(cmp(s_aa, s_aa) == 0) ok
+(strcmp(s_aa, s_aa) == 0) ok
 (s_aa == s_aa) ok
 !(s_aa != s_aa) ok
@@ -175,5 +175,5 @@
 (s_aa <= s_aa) ok
 !(s_aa < s_aa) ok
-(cmp("aa", s_aa) == 0) ok
+(strcmp("aa", s_aa) == 0) ok
 ("aa" == s_aa) ok
 !("aa" != s_aa) ok
@@ -182,5 +182,5 @@
 ("aa" <= s_aa) ok
 !("aa" < s_aa) ok
-(cmp(s_aa, "aa") == 0) ok
+(strcmp(s_aa, "aa") == 0) ok
 (s_aa == "aa") ok
 !(s_aa != "aa") ok
@@ -189,5 +189,5 @@
 (s_aa <= "aa") ok
 !(s_aa < "aa") ok
-(cmp(s_a, s_b) < 0) ok
+(strcmp(s_a, s_b) < 0) ok
 !(s_a == s_b) ok
 (s_a != s_b) ok
@@ -196,5 +196,5 @@
 (s_a <= s_b) ok
 (s_a < s_b) ok
-(cmp("a", s_b) < 0) ok
+(strcmp("a", s_b) < 0) ok
 !("a" == s_b) ok
 ("a" != s_b) ok
@@ -203,5 +203,5 @@
 ("a" <= s_b) ok
 ("a" < s_b) ok
-(cmp(s_a, "b") < 0) ok
+(strcmp(s_a, "b") < 0) ok
 !(s_a == "b") ok
 (s_a != "b") ok
@@ -210,5 +210,5 @@
 (s_a <= "b") ok
 (s_a < "b") ok
-(cmp(s_b, s_a) > 0) ok
+(strcmp(s_b, s_a) > 0) ok
 !(s_b == s_a) ok
 (s_b != s_a) ok
@@ -217,5 +217,5 @@
 !(s_b <= s_a) ok
 !(s_b < s_a) ok
-(cmp("b", s_a) > 0) ok
+(strcmp("b", s_a) > 0) ok
 !("b" == s_a) ok
 ("b" != s_a) ok
@@ -224,5 +224,5 @@
 !("b" <= s_a) ok
 !("b" < s_a) ok
-(cmp(s_b, "a") > 0) ok
+(strcmp(s_b, "a") > 0) ok
 !(s_b == "a") ok
 (s_b != "a") ok
@@ -231,5 +231,5 @@
 !(s_b <= "a") ok
 !(s_b < "a") ok
-(cmp(s_a, s_ba) < 0) ok
+(strcmp(s_a, s_ba) < 0) ok
 !(s_a == s_ba) ok
 (s_a != s_ba) ok
@@ -238,5 +238,5 @@
 (s_a <= s_ba) ok
 (s_a < s_ba) ok
-(cmp("a", s_ba) < 0) ok
+(strcmp("a", s_ba) < 0) ok
 !("a" == s_ba) ok
 ("a" != s_ba) ok
@@ -245,5 +245,5 @@
 ("a" <= s_ba) ok
 ("a" < s_ba) ok
-(cmp(s_a, "ba") < 0) ok
+(strcmp(s_a, "ba") < 0) ok
 !(s_a == "ba") ok
 (s_a != "ba") ok
@@ -252,5 +252,5 @@
 (s_a <= "ba") ok
 (s_a < "ba") ok
-(cmp(s_ba, s_a) > 0) ok
+(strcmp(s_ba, s_a) > 0) ok
 !(s_ba == s_a) ok
 (s_ba != s_a) ok
@@ -259,5 +259,5 @@
 !(s_ba <= s_a) ok
 !(s_ba < s_a) ok
-(cmp("ba", s_a) > 0) ok
+(strcmp("ba", s_a) > 0) ok
 !("ba" == s_a) ok
 ("ba" != s_a) ok
@@ -266,5 +266,5 @@
 !("ba" <= s_a) ok
 !("ba" < s_a) ok
-(cmp(s_ba, "a") > 0) ok
+(strcmp(s_ba, "a") > 0) ok
 !(s_ba == "a") ok
 (s_ba != "a") ok
@@ -273,5 +273,5 @@
 !(s_ba <= "a") ok
 !(s_ba < "a") ok
-(cmp(s_aa, s_ab) < 0) ok
+(strcmp(s_aa, s_ab) < 0) ok
 !(s_aa == s_ab) ok
 (s_aa != s_ab) ok
@@ -280,5 +280,5 @@
 (s_aa <= s_ab) ok
 (s_aa < s_ab) ok
-(cmp("aa", s_ab) < 0) ok
+(strcmp("aa", s_ab) < 0) ok
 !("aa" == s_ab) ok
 ("aa" != s_ab) ok
@@ -287,5 +287,5 @@
 ("aa" <= s_ab) ok
 ("aa" < s_ab) ok
-(cmp(s_aa, "ab") < 0) ok
+(strcmp(s_aa, "ab") < 0) ok
 !(s_aa == "ab") ok
 (s_aa != "ab") ok
@@ -294,5 +294,5 @@
 (s_aa <= "ab") ok
 (s_aa < "ab") ok
-(cmp(s_ab, s_aa) > 0) ok
+(strcmp(s_ab, s_aa) > 0) ok
 !(s_ab == s_aa) ok
 (s_ab != s_aa) ok
@@ -301,5 +301,5 @@
 !(s_ab <= s_aa) ok
 !(s_ab < s_aa) ok
-(cmp("ab", s_aa) > 0) ok
+(strcmp("ab", s_aa) > 0) ok
 !("ab" == s_aa) ok
 ("ab" != s_aa) ok
@@ -308,5 +308,5 @@
 !("ab" <= s_aa) ok
 !("ab" < s_aa) ok
-(cmp(s_ab, "aa") > 0) ok
+(strcmp(s_ab, "aa") > 0) ok
 !(s_ab == "aa") ok
 (s_ab != "aa") ok
@@ -315,5 +315,5 @@
 !(s_ab <= "aa") ok
 !(s_ab < "aa") ok
-(cmp(s_ba, s_bb) < 0) ok
+(strcmp(s_ba, s_bb) < 0) ok
 !(s_ba == s_bb) ok
 (s_ba != s_bb) ok
@@ -322,5 +322,5 @@
 (s_ba <= s_bb) ok
 (s_ba < s_bb) ok
-(cmp("ba", s_bb) < 0) ok
+(strcmp("ba", s_bb) < 0) ok
 !("ba" == s_bb) ok
 ("ba" != s_bb) ok
@@ -329,5 +329,5 @@
 ("ba" <= s_bb) ok
 ("ba" < s_bb) ok
-(cmp(s_ba, "bb") < 0) ok
+(strcmp(s_ba, "bb") < 0) ok
 !(s_ba == "bb") ok
 (s_ba != "bb") ok
@@ -336,5 +336,5 @@
 (s_ba <= "bb") ok
 (s_ba < "bb") ok
-(cmp(s_bb, s_ba) > 0) ok
+(strcmp(s_bb, s_ba) > 0) ok
 !(s_bb == s_ba) ok
 (s_bb != s_ba) ok
@@ -343,5 +343,5 @@
 !(s_bb <= s_ba) ok
 !(s_bb < s_ba) ok
-(cmp("bb", s_ba) > 0) ok
+(strcmp("bb", s_ba) > 0) ok
 !("bb" == s_ba) ok
 ("bb" != s_ba) ok
@@ -350,5 +350,5 @@
 !("bb" <= s_ba) ok
 !("bb" < s_ba) ok
-(cmp(s_bb, "ba") > 0) ok
+(strcmp(s_bb, "ba") > 0) ok
 !(s_bb == "ba") ok
 (s_bb != "ba") ok
@@ -357,5 +357,5 @@
 !(s_bb <= "ba") ok
 !(s_bb < "ba") ok
-(cmp(s_aa, s_b) < 0) ok
+(strcmp(s_aa, s_b) < 0) ok
 !(s_aa == s_b) ok
 (s_aa != s_b) ok
@@ -364,5 +364,5 @@
 (s_aa <= s_b) ok
 (s_aa < s_b) ok
-(cmp("aa", s_b) < 0) ok
+(strcmp("aa", s_b) < 0) ok
 !("aa" == s_b) ok
 ("aa" != s_b) ok
@@ -371,5 +371,5 @@
 ("aa" <= s_b) ok
 ("aa" < s_b) ok
-(cmp(s_aa, "b") < 0) ok
+(strcmp(s_aa, "b") < 0) ok
 !(s_aa == "b") ok
 (s_aa != "b") ok
@@ -378,5 +378,5 @@
 (s_aa <= "b") ok
 (s_aa < "b") ok
-(cmp(s_b, s_aa) > 0) ok
+(strcmp(s_b, s_aa) > 0) ok
 !(s_b == s_aa) ok
 (s_b != s_aa) ok
@@ -385,5 +385,5 @@
 !(s_b <= s_aa) ok
 !(s_b < s_aa) ok
-(cmp("b", s_aa) > 0) ok
+(strcmp("b", s_aa) > 0) ok
 !("b" == s_aa) ok
 ("b" != s_aa) ok
@@ -392,5 +392,5 @@
 !("b" <= s_aa) ok
 !("b" < s_aa) ok
-(cmp(s_b, "aa") > 0) ok
+(strcmp(s_b, "aa") > 0) ok
 !(s_b == "aa") ok
 (s_b != "aa") ok
@@ -400,5 +400,5 @@
 !(s_b < "aa") ok
 ------- string_res -------
-(cmp(s_, s_) == 0) ok
+(strcmp(s_, s_) == 0) ok
 (s_ == s_) ok
 !(s_ != s_) ok
@@ -407,5 +407,5 @@
 (s_ <= s_) ok
 !(s_ < s_) ok
-(cmp("", s_) == 0) ok
+(strcmp("", s_) == 0) ok
 ("" == s_) ok
 !("" != s_) ok
@@ -414,5 +414,5 @@
 ("" <= s_) ok
 !("" < s_) ok
-(cmp(s_, "") == 0) ok
+(strcmp(s_, "") == 0) ok
 (s_ == "") ok
 !(s_ != "") ok
@@ -421,5 +421,5 @@
 (s_ <= "") ok
 !(s_ < "") ok
-(cmp(s_, s_a) < 0) ok
+(strcmp(s_, s_a) < 0) ok
 !(s_ == s_a) ok
 (s_ != s_a) ok
@@ -428,5 +428,5 @@
 (s_ <= s_a) ok
 (s_ < s_a) ok
-(cmp("", s_a) < 0) ok
+(strcmp("", s_a) < 0) ok
 !("" == s_a) ok
 ("" != s_a) ok
@@ -435,5 +435,5 @@
 ("" <= s_a) ok
 ("" < s_a) ok
-(cmp(s_, "a") < 0) ok
+(strcmp(s_, "a") < 0) ok
 !(s_ == "a") ok
 (s_ != "a") ok
@@ -442,5 +442,5 @@
 (s_ <= "a") ok
 (s_ < "a") ok
-(cmp(s_a, s_) > 0) ok
+(strcmp(s_a, s_) > 0) ok
 !(s_a == s_) ok
 (s_a != s_) ok
@@ -449,5 +449,5 @@
 !(s_a <= s_) ok
 !(s_a < s_) ok
-(cmp("a", s_) > 0) ok
+(strcmp("a", s_) > 0) ok
 !("a" == s_) ok
 ("a" != s_) ok
@@ -456,5 +456,5 @@
 !("a" <= s_) ok
 !("a" < s_) ok
-(cmp(s_a, "") > 0) ok
+(strcmp(s_a, "") > 0) ok
 !(s_a == "") ok
 (s_a != "") ok
@@ -463,5 +463,5 @@
 !(s_a <= "") ok
 !(s_a < "") ok
-(cmp(s_, s_aa) < 0) ok
+(strcmp(s_, s_aa) < 0) ok
 !(s_ == s_aa) ok
 (s_ != s_aa) ok
@@ -470,5 +470,5 @@
 (s_ <= s_aa) ok
 (s_ < s_aa) ok
-(cmp("", s_aa) < 0) ok
+(strcmp("", s_aa) < 0) ok
 !("" == s_aa) ok
 ("" != s_aa) ok
@@ -477,5 +477,5 @@
 ("" <= s_aa) ok
 ("" < s_aa) ok
-(cmp(s_, "aa") < 0) ok
+(strcmp(s_, "aa") < 0) ok
 !(s_ == "aa") ok
 (s_ != "aa") ok
@@ -484,5 +484,5 @@
 (s_ <= "aa") ok
 (s_ < "aa") ok
-(cmp(s_aa, s_) > 0) ok
+(strcmp(s_aa, s_) > 0) ok
 !(s_aa == s_) ok
 (s_aa != s_) ok
@@ -491,5 +491,5 @@
 !(s_aa <= s_) ok
 !(s_aa < s_) ok
-(cmp("aa", s_) > 0) ok
+(strcmp("aa", s_) > 0) ok
 !("aa" == s_) ok
 ("aa" != s_) ok
@@ -498,5 +498,5 @@
 !("aa" <= s_) ok
 !("aa" < s_) ok
-(cmp(s_aa, "") > 0) ok
+(strcmp(s_aa, "") > 0) ok
 !(s_aa == "") ok
 (s_aa != "") ok
@@ -505,5 +505,5 @@
 !(s_aa <= "") ok
 !(s_aa < "") ok
-(cmp(s_a, s_aa) < 0) ok
+(strcmp(s_a, s_aa) < 0) ok
 !(s_a == s_aa) ok
 (s_a != s_aa) ok
@@ -512,5 +512,5 @@
 (s_a <= s_aa) ok
 (s_a < s_aa) ok
-(cmp("a", s_aa) < 0) ok
+(strcmp("a", s_aa) < 0) ok
 !("a" == s_aa) ok
 ("a" != s_aa) ok
@@ -519,5 +519,5 @@
 ("a" <= s_aa) ok
 ("a" < s_aa) ok
-(cmp(s_a, "aa") < 0) ok
+(strcmp(s_a, "aa") < 0) ok
 !(s_a == "aa") ok
 (s_a != "aa") ok
@@ -526,5 +526,5 @@
 (s_a <= "aa") ok
 (s_a < "aa") ok
-(cmp(s_aa, s_a) > 0) ok
+(strcmp(s_aa, s_a) > 0) ok
 !(s_aa == s_a) ok
 (s_aa != s_a) ok
@@ -533,5 +533,5 @@
 !(s_aa <= s_a) ok
 !(s_aa < s_a) ok
-(cmp("aa", s_a) > 0) ok
+(strcmp("aa", s_a) > 0) ok
 !("aa" == s_a) ok
 ("aa" != s_a) ok
@@ -540,5 +540,5 @@
 !("aa" <= s_a) ok
 !("aa" < s_a) ok
-(cmp(s_aa, "a") > 0) ok
+(strcmp(s_aa, "a") > 0) ok
 !(s_aa == "a") ok
 (s_aa != "a") ok
@@ -547,5 +547,5 @@
 !(s_aa <= "a") ok
 !(s_aa < "a") ok
-(cmp(s_a, s_a) == 0) ok
+(strcmp(s_a, s_a) == 0) ok
 (s_a == s_a) ok
 !(s_a != s_a) ok
@@ -554,5 +554,5 @@
 (s_a <= s_a) ok
 !(s_a < s_a) ok
-(cmp("a", s_a) == 0) ok
+(strcmp("a", s_a) == 0) ok
 ("a" == s_a) ok
 !("a" != s_a) ok
@@ -561,5 +561,5 @@
 ("a" <= s_a) ok
 !("a" < s_a) ok
-(cmp(s_a, "a") == 0) ok
+(strcmp(s_a, "a") == 0) ok
 (s_a == "a") ok
 !(s_a != "a") ok
@@ -568,5 +568,5 @@
 (s_a <= "a") ok
 !(s_a < "a") ok
-(cmp(s_aa, s_aa) == 0) ok
+(strcmp(s_aa, s_aa) == 0) ok
 (s_aa == s_aa) ok
 !(s_aa != s_aa) ok
@@ -575,5 +575,5 @@
 (s_aa <= s_aa) ok
 !(s_aa < s_aa) ok
-(cmp("aa", s_aa) == 0) ok
+(strcmp("aa", s_aa) == 0) ok
 ("aa" == s_aa) ok
 !("aa" != s_aa) ok
@@ -582,5 +582,5 @@
 ("aa" <= s_aa) ok
 !("aa" < s_aa) ok
-(cmp(s_aa, "aa") == 0) ok
+(strcmp(s_aa, "aa") == 0) ok
 (s_aa == "aa") ok
 !(s_aa != "aa") ok
@@ -589,5 +589,5 @@
 (s_aa <= "aa") ok
 !(s_aa < "aa") ok
-(cmp(s_a, s_b) < 0) ok
+(strcmp(s_a, s_b) < 0) ok
 !(s_a == s_b) ok
 (s_a != s_b) ok
@@ -596,5 +596,5 @@
 (s_a <= s_b) ok
 (s_a < s_b) ok
-(cmp("a", s_b) < 0) ok
+(strcmp("a", s_b) < 0) ok
 !("a" == s_b) ok
 ("a" != s_b) ok
@@ -603,5 +603,5 @@
 ("a" <= s_b) ok
 ("a" < s_b) ok
-(cmp(s_a, "b") < 0) ok
+(strcmp(s_a, "b") < 0) ok
 !(s_a == "b") ok
 (s_a != "b") ok
@@ -610,5 +610,5 @@
 (s_a <= "b") ok
 (s_a < "b") ok
-(cmp(s_b, s_a) > 0) ok
+(strcmp(s_b, s_a) > 0) ok
 !(s_b == s_a) ok
 (s_b != s_a) ok
@@ -617,5 +617,5 @@
 !(s_b <= s_a) ok
 !(s_b < s_a) ok
-(cmp("b", s_a) > 0) ok
+(strcmp("b", s_a) > 0) ok
 !("b" == s_a) ok
 ("b" != s_a) ok
@@ -624,5 +624,5 @@
 !("b" <= s_a) ok
 !("b" < s_a) ok
-(cmp(s_b, "a") > 0) ok
+(strcmp(s_b, "a") > 0) ok
 !(s_b == "a") ok
 (s_b != "a") ok
@@ -631,5 +631,5 @@
 !(s_b <= "a") ok
 !(s_b < "a") ok
-(cmp(s_a, s_ba) < 0) ok
+(strcmp(s_a, s_ba) < 0) ok
 !(s_a == s_ba) ok
 (s_a != s_ba) ok
@@ -638,5 +638,5 @@
 (s_a <= s_ba) ok
 (s_a < s_ba) ok
-(cmp("a", s_ba) < 0) ok
+(strcmp("a", s_ba) < 0) ok
 !("a" == s_ba) ok
 ("a" != s_ba) ok
@@ -645,5 +645,5 @@
 ("a" <= s_ba) ok
 ("a" < s_ba) ok
-(cmp(s_a, "ba") < 0) ok
+(strcmp(s_a, "ba") < 0) ok
 !(s_a == "ba") ok
 (s_a != "ba") ok
@@ -652,5 +652,5 @@
 (s_a <= "ba") ok
 (s_a < "ba") ok
-(cmp(s_ba, s_a) > 0) ok
+(strcmp(s_ba, s_a) > 0) ok
 !(s_ba == s_a) ok
 (s_ba != s_a) ok
@@ -659,5 +659,5 @@
 !(s_ba <= s_a) ok
 !(s_ba < s_a) ok
-(cmp("ba", s_a) > 0) ok
+(strcmp("ba", s_a) > 0) ok
 !("ba" == s_a) ok
 ("ba" != s_a) ok
@@ -666,5 +666,5 @@
 !("ba" <= s_a) ok
 !("ba" < s_a) ok
-(cmp(s_ba, "a") > 0) ok
+(strcmp(s_ba, "a") > 0) ok
 !(s_ba == "a") ok
 (s_ba != "a") ok
@@ -673,5 +673,5 @@
 !(s_ba <= "a") ok
 !(s_ba < "a") ok
-(cmp(s_aa, s_ab) < 0) ok
+(strcmp(s_aa, s_ab) < 0) ok
 !(s_aa == s_ab) ok
 (s_aa != s_ab) ok
@@ -680,5 +680,5 @@
 (s_aa <= s_ab) ok
 (s_aa < s_ab) ok
-(cmp("aa", s_ab) < 0) ok
+(strcmp("aa", s_ab) < 0) ok
 !("aa" == s_ab) ok
 ("aa" != s_ab) ok
@@ -687,5 +687,5 @@
 ("aa" <= s_ab) ok
 ("aa" < s_ab) ok
-(cmp(s_aa, "ab") < 0) ok
+(strcmp(s_aa, "ab") < 0) ok
 !(s_aa == "ab") ok
 (s_aa != "ab") ok
@@ -694,5 +694,5 @@
 (s_aa <= "ab") ok
 (s_aa < "ab") ok
-(cmp(s_ab, s_aa) > 0) ok
+(strcmp(s_ab, s_aa) > 0) ok
 !(s_ab == s_aa) ok
 (s_ab != s_aa) ok
@@ -701,5 +701,5 @@
 !(s_ab <= s_aa) ok
 !(s_ab < s_aa) ok
-(cmp("ab", s_aa) > 0) ok
+(strcmp("ab", s_aa) > 0) ok
 !("ab" == s_aa) ok
 ("ab" != s_aa) ok
@@ -708,5 +708,5 @@
 !("ab" <= s_aa) ok
 !("ab" < s_aa) ok
-(cmp(s_ab, "aa") > 0) ok
+(strcmp(s_ab, "aa") > 0) ok
 !(s_ab == "aa") ok
 (s_ab != "aa") ok
@@ -715,5 +715,5 @@
 !(s_ab <= "aa") ok
 !(s_ab < "aa") ok
-(cmp(s_ba, s_bb) < 0) ok
+(strcmp(s_ba, s_bb) < 0) ok
 !(s_ba == s_bb) ok
 (s_ba != s_bb) ok
@@ -722,5 +722,5 @@
 (s_ba <= s_bb) ok
 (s_ba < s_bb) ok
-(cmp("ba", s_bb) < 0) ok
+(strcmp("ba", s_bb) < 0) ok
 !("ba" == s_bb) ok
 ("ba" != s_bb) ok
@@ -729,5 +729,5 @@
 ("ba" <= s_bb) ok
 ("ba" < s_bb) ok
-(cmp(s_ba, "bb") < 0) ok
+(strcmp(s_ba, "bb") < 0) ok
 !(s_ba == "bb") ok
 (s_ba != "bb") ok
@@ -736,5 +736,5 @@
 (s_ba <= "bb") ok
 (s_ba < "bb") ok
-(cmp(s_bb, s_ba) > 0) ok
+(strcmp(s_bb, s_ba) > 0) ok
 !(s_bb == s_ba) ok
 (s_bb != s_ba) ok
@@ -743,5 +743,5 @@
 !(s_bb <= s_ba) ok
 !(s_bb < s_ba) ok
-(cmp("bb", s_ba) > 0) ok
+(strcmp("bb", s_ba) > 0) ok
 !("bb" == s_ba) ok
 ("bb" != s_ba) ok
@@ -750,5 +750,5 @@
 !("bb" <= s_ba) ok
 !("bb" < s_ba) ok
-(cmp(s_bb, "ba") > 0) ok
+(strcmp(s_bb, "ba") > 0) ok
 !(s_bb == "ba") ok
 (s_bb != "ba") ok
@@ -757,5 +757,5 @@
 !(s_bb <= "ba") ok
 !(s_bb < "ba") ok
-(cmp(s_aa, s_b) < 0) ok
+(strcmp(s_aa, s_b) < 0) ok
 !(s_aa == s_b) ok
 (s_aa != s_b) ok
@@ -764,5 +764,5 @@
 (s_aa <= s_b) ok
 (s_aa < s_b) ok
-(cmp("aa", s_b) < 0) ok
+(strcmp("aa", s_b) < 0) ok
 !("aa" == s_b) ok
 ("aa" != s_b) ok
@@ -771,5 +771,5 @@
 ("aa" <= s_b) ok
 ("aa" < s_b) ok
-(cmp(s_aa, "b") < 0) ok
+(strcmp(s_aa, "b") < 0) ok
 !(s_aa == "b") ok
 (s_aa != "b") ok
@@ -778,5 +778,5 @@
 (s_aa <= "b") ok
 (s_aa < "b") ok
-(cmp(s_b, s_aa) > 0) ok
+(strcmp(s_b, s_aa) > 0) ok
 !(s_b == s_aa) ok
 (s_b != s_aa) ok
@@ -785,5 +785,5 @@
 !(s_b <= s_aa) ok
 !(s_b < s_aa) ok
-(cmp("b", s_aa) > 0) ok
+(strcmp("b", s_aa) > 0) ok
 !("b" == s_aa) ok
 ("b" != s_aa) ok
@@ -792,5 +792,5 @@
 !("b" <= s_aa) ok
 !("b" < s_aa) ok
-(cmp(s_b, "aa") > 0) ok
+(strcmp(s_b, "aa") > 0) ok
 !(s_b == "aa") ok
 (s_b != "aa") ok
Index: tests/collections/.expect/string-istream-manip.txt
===================================================================
--- tests/collections/.expect/string-istream-manip.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/.expect/string-istream-manip.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -69,5 +69,5 @@
 13 wwwwwwww
 14 cccc
-15 q
+15 
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -84,3 +84,3 @@
 13 wwwwwwww
 14 cccc
-15 q
+15 
Index: tests/collections/string-api-coverage.cfa
===================================================================
--- tests/collections/string-api-coverage.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/string-api-coverage.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -51,12 +51,12 @@
     sout | (s == "hello") | (s == "world");
     sout | (s != "world") | (s != "hello");
-    sout | ( frag == s(1,4) ) | ( s3   == s(1,4) );
-    sout | ( s3   != s(1,4) ) | ( frag != s(1,4) );
-    sout | ( s2(1,4) == s(1,4) ) | ( s3(1,4)   == s(1,4) );
-    sout | ( s3(1,4) != s(1,4) ) | ( s2(1,4)   != s(1,4) );
-    sout | ( s(1,4) == frag ) | ( s(1,4) == s3   );
-    sout | ( s(1,4) != s3   ) | ( s(1,4) != frag );
-    sout | ( s(1,4) == "ell"   ) | ( s(1,4) == "world" );
-    sout | ( s(1,4) != "world" ) | ( s(1,4) != "ell"   );
+    sout | ( frag == s(1,3) ) | ( s3   == s(1,3) );
+    sout | ( s3   != s(1,3) ) | ( frag != s(1,3) );
+    sout | ( s2(1,3) == s(1,3) ) | ( s3(1,3)   == s(1,3) );
+    sout | ( s3(1,3) != s(1,3) ) | ( s2(1,3)   != s(1,3) );
+    sout | ( s(1,3) == frag ) | ( s(1,3) == s3   );
+    sout | ( s(1,3) != s3   ) | ( s(1,3) != frag );
+    sout | ( s(1,3) == "ell"   ) | ( s(1,3) == "world" );
+    sout | ( s(1,3) != "world" ) | ( s(1,3) != "ell"   );
 
 
@@ -66,9 +66,15 @@
     //
     {
-        string b1 = { "1234567", 3 };
-        sout | b1; // 123
+        string b1 = "1234567";
+        sout | b1; // 1234567
+
+        string b1x = { "1234567", 3 };
+        sout | b1x; // 123
 
         string b2 = s;
         sout | b2; // hello
+
+        string b2x = { s, 4 };
+        sout | b2x; // hell
 
         // todo: a plain string &
@@ -88,6 +94,55 @@
         b4 = s_constref;
         sout | b4;  // world
+
+        string b5 = 'Q';
+        sout | b5; // Q
+
+
     }
                                             assertWellFormedHandleList( 10 );
+    //
+    // Assignments
+    //
+    {
+        string b = "xxx";
+
+        b = "1234567";
+        sout | b; // 1234567
+
+        b = "xxx";
+        b = s;
+        sout | b; // hello
+        
+        b = "xxx";
+        b = 'Q';
+        sout | b; // Q
+        
+        b = "xxx";
+        assign( b, "1234567", 3 );
+        sout | b; // 123
+
+        b = "xxx";
+        assign( b, s, 4 );
+        sout | b; // hell
+
+        b = "xxx";
+        strcpy(b, "1234567");
+        sout | b; // 1234567
+
+        b = "xxx";
+        strcpy(b, s);
+        sout | b; // hello
+        
+        b = "xxx";
+        strncpy( b, "1234567", 3 );
+        sout | b; // 123
+
+        b = "xxx";
+        strncpy( b, s, 4 );
+        sout | b; // hell
+    }
+                                            assertWellFormedHandleList( 10 );
+
+
 
     sout | size(s); // 5
@@ -126,7 +181,36 @@
     sout | sx; // bye, friend
 
+    sx = "o";
+    strcat( sx, s );
+    sout | sx; // ohello
+
+    sx = "o";
+    append( sx, s, 4 );
+    sout | sx; // ohell
+
+    sx = "o";
+    strncat( sx, s, 4 );
+    sout | sx; // ohell
+
+    sx = "o";
+    strcat( sx, "mydarling" );
+    sout | sx; // omydarling
+
+    sx = "o";
+    append( sx, "mydarling", 2 );
+    sout | sx; // omy
+
+    sx = "o";
+    strncat( sx, "mydarling", 2 );
+    sout | sx; // omy
+
     //
     // repetition
     //
+
+    sx = s;
+    sx *= 4;
+    sout | sx; // hellohellohellohello
+
     sx = s * 3;
     sout | sx; // hellohellohello
@@ -142,5 +226,12 @@
     //
 
-    //...
+    // Range cases treated thoroughly in "string-overwrite" test.
+    // Composability with comparison and search are demoed above and below.
+    // Coverage here adds the single-argument ("rest of string") overload.
+
+    sx = s;
+    sout | sx(3); // lo
+    sx(3) = "iocentric";
+    sout | s | sx; // hello heliocentric
 
     //
@@ -244,8 +335,8 @@
         | find( alphabet        , "def")  // 3
         | find( alphabet( 0, 26), "def")  // 3
-        | find( alphabet( 2, 26), "def")  // 1
-        | find( alphabet( 3, 26), "def")  // 0
-        | find( alphabet( 4, 26), "def")  // 22, not found
-        | find( alphabet( 4, 26),  "ef")  // 0
+        | find( alphabet( 2, 24), "def")  // 1
+        | find( alphabet( 3, 23), "def")  // 0
+        | find( alphabet( 4, 22), "def")  // 22, not found
+        | find( alphabet( 4, 22),  "ef")  // 0
         | find( alphabet( 0,  6), "def")  // 3
         | find( alphabet( 0,  5), "def")  // 5, not found
@@ -255,8 +346,8 @@
         | includes( alphabet        , "def")  // true
         | includes( alphabet( 0, 26), "def")  // true
-        | includes( alphabet( 2, 26), "def")  // true
-        | includes( alphabet( 3, 26), "def")  // true
-        | includes( alphabet( 4, 26), "def")  // false
-        | includes( alphabet( 4, 26),  "ef")  // true
+        | includes( alphabet( 2, 24), "def")  // true
+        | includes( alphabet( 3, 23), "def")  // true
+        | includes( alphabet( 4, 22), "def")  // false
+        | includes( alphabet( 4, 22),  "ef")  // true
         | includes( alphabet( 0,  6), "def")  // true
         | includes( alphabet( 0,  5), "def")  // false
@@ -266,6 +357,6 @@
         | startsWith( alphabet        , "abc")  // true
         | startsWith( alphabet( 0, 26), "abc")  // true
-        | startsWith( alphabet( 1, 26), "abc")  // false
-        | startsWith( alphabet( 1, 26),  "bc")  // true
+        | startsWith( alphabet( 1, 25), "abc")  // false
+        | startsWith( alphabet( 1, 25),  "bc")  // true
         | startsWith( alphabet( 0, 26), "abc")  // true
         | startsWith( alphabet( 0,  4), "abc")  // true
@@ -281,7 +372,7 @@
         | endsWith( alphabet( 0, 25), "xy" )  // true
         | endsWith( alphabet( 0, 26), "xyz")  // true
-        | endsWith( alphabet(23, 26), "xyz")  // true
-        | endsWith( alphabet(24, 26), "xyz")  // false
-        | endsWith( alphabet(24, 26),  "yz")  // true
+        | endsWith( alphabet(23,  3), "xyz")  // true
+        | endsWith( alphabet(24,  2), "xyz")  // false
+        | endsWith( alphabet(24,  2),  "yz")  // true
         | endsWith( alphabet        , "abc"); // false
 
Index: tests/collections/string-compare.cfa
===================================================================
--- tests/collections/string-compare.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/string-compare.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -3,5 +3,5 @@
 
 #define test_eq_(l, r) \
-    chk( (cmp(l, r) == 0) ) \
+    chk( (strcmp(l, r) == 0) ) \
     chk(  (l == r) ) \
     chk( !(l != r) ) \
@@ -17,5 +17,5 @@
 
 #define test_lt_(l, r) \
-    chk( (cmp(l, r) < 0) ) \
+    chk( (strcmp(l, r) < 0) ) \
     chk( !(l == r) ) \
     chk(  (l != r) ) \
@@ -26,5 +26,5 @@
 
 #define test_gt_(l, r) \
-    chk( (cmp(l, r) > 0) ) \
+    chk( (strcmp(l, r) > 0) ) \
     chk( !(l == r) ) \
     chk(  (l != r) ) \
Index: tests/collections/string-overwrite.cfa
===================================================================
--- tests/collections/string-overwrite.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/collections/string-overwrite.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -9,6 +9,8 @@
 MS = modifier start
 ME = modifier end
+ML = modifier length
 WS = witness start
 WE = witness end
+WL = witness length
 
 The test does:
@@ -71,11 +73,14 @@
 
 
-void showOneReplacement(string & s, int ms, int me, int ws, int we, const char* replaceWith) {
+void showOneReplacement(string & s, int ms, int ml, int ws, int wl, const char* replaceWith) {
+
+    int me = ms + ml;
+    int we = ws + wl;
 
     assert( ms >= 0 && ms <= me && me <= size(s) );
     assert( ws >= 0 && ws <= we && we <= size(s) );
 
-    string mod = s(ms, me)`shareEdits;
-    string wit = s(ws, we)`shareEdits;
+    string mod = s(ms, ml)`shareEdits;
+    string wit = s(ws, wl)`shareEdits;
 
     string modOld = mod;
@@ -118,115 +123,115 @@
 void runReplaceCases() {
     char * alphabetTemplate = "abcdefghijklmnopqrstuvwxyz";
-    struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = {
-        { 12, 14, 10, 20, "xxxxx", "warmup" },
-        { 10, 10, 10, 10, "=====", "1"      },
-        { 10, 10, 10, 10, "=="   , ""       },
-        { 10, 10, 10, 10, "="    , ""       },
-        { 10, 10, 10, 10, ""     , ""       },
-        { 10, 12, 12, 12, "=====", "2"      },
-        { 10, 12, 12, 12, "=="   , ""       },
-        { 10, 12, 12, 12, "="    , ""       },
-        { 10, 12, 12, 12, ""     , ""       },
-        { 12, 12, 10, 12, "=====", "3"      },
-        { 12, 12, 10, 12, "=="   , ""       },
-        { 12, 12, 10, 12, "="    , ""       },
-        { 12, 12, 10, 12, ""     , ""       },
-        { 10, 10, 12, 12, "=====", "4"      },
-        { 10, 10, 12, 12, "=="   , ""       },
-        { 10, 10, 12, 12, "="    , ""       },
-        { 10, 10, 12, 12, ""     , ""       },
-        { 12, 12, 10, 10, "=====", "5"      },
-        { 12, 12, 10, 10, "=="   , ""       },
-        { 12, 12, 10, 10, "="    , ""       },
-        { 12, 12, 10, 10, ""     , ""       },
-        { 10, 12, 10, 12, "=====", "6"      },
-        { 10, 12, 10, 12, "=="   , ""       },
-        { 10, 12, 10, 12, "="    , ""       },
-        { 10, 12, 10, 12, ""     , ""       },
-        { 10, 12, 10, 10, "=====", "7"      },
-        { 10, 12, 10, 10, "=="   , ""       },
-        { 10, 12, 10, 10, "="    , ""       },
-        { 10, 12, 10, 10, ""     , ""       },
-        { 10, 10, 10, 12, "=====", "8"      },
-        { 10, 10, 10, 12, "=="   , ""       },
-        { 10, 10, 10, 12, "="    , ""       },
-        { 10, 10, 10, 12, ""     , ""       },
-        { 10, 12, 14, 14, "=====", "9"      },
-        { 10, 12, 14, 14, "=="   , ""       },
-        { 10, 12, 14, 14, "="    , ""       },
-        { 10, 12, 14, 14, ""     , ""       },
-        { 10, 14, 12, 14, "=====", "10"     },
-        { 10, 14, 12, 14, "=="   , ""       },
-        { 10, 14, 12, 14, "="    , ""       },  // FORMERLY unrunnable bug: tries to print seemingly infinite string
-        { 10, 14, 12, 14, ""     , ""       },  // ditto
-        { 14, 14, 10, 12, "=====", "11"     },
-        { 14, 14, 10, 12, "=="   , ""       },
-        { 14, 14, 10, 12, "="    , ""       },
-        { 14, 14, 10, 12, ""     , ""       },
-        { 12, 14, 10, 14, "=====", "12"     }, // correctness observation:  watching klmn while mn |-> xxx gives klxxx because the mn is inside what I'm watching
-        { 12, 14, 10, 14, "=="   , ""       },
-        { 12, 14, 10, 14, "="    , ""       },
-        { 12, 14, 10, 14, ""     , ""       },
-        { 10, 12, 12, 14, "=====", "13"     },
-        { 10, 12, 12, 14, "=="   , ""       },
-        { 10, 12, 12, 14, "="    , ""       },
-        { 10, 12, 12, 14, ""     , ""       },
-        { 10, 14, 12, 12, "=====", "14"     },
-        { 10, 14, 12, 12, "=="   , ""       },
-        { 10, 14, 12, 12, "="    , ""       },
-        { 10, 14, 12, 12, ""     , ""       },
-        { 12, 14, 10, 12, "=====", "15"     },
-        { 12, 14, 10, 12, "=="   , ""       },
-        { 12, 14, 10, 12, "="    , ""       },
-        { 12, 14, 10, 12, ""     , ""       },
-        { 12, 12, 10, 14, "=====", "16"     },
-        { 12, 12, 10, 14, "=="   , ""       },
-        { 12, 12, 10, 14, "="    , ""       },
-        { 12, 12, 10, 14, ""     , ""       },
-        { 10, 14, 10, 12, "=====", "17"     },
-        { 10, 14, 10, 12, "=="   , ""       },
-        { 10, 14, 10, 12, "="    , ""       },
-        { 10, 14, 10, 12, ""     , ""       },
-        { 10, 10, 12, 14, "=====", "18"     },
-        { 10, 10, 12, 14, "=="   , ""       },
-        { 10, 10, 12, 14, "="    , ""       },
-        { 10, 10, 12, 14, ""     , ""       },
-        { 10, 12, 10, 14, "=====", "19"     },
-        { 10, 12, 10, 14, "=="   , ""       },
-        { 10, 12, 10, 14, "="    , ""       },
-        { 10, 12, 10, 14, ""     , ""       },
-        { 12, 14, 10, 10, "=====", "20"     },
-        { 12, 14, 10, 10, "=="   , ""       },
-        { 12, 14, 10, 10, "="    , ""       },
-        { 12, 14, 10, 10, ""     , ""       },
-        { 10, 12, 14, 16, "=====", "21"     },
-        { 10, 12, 14, 16, "=="   , ""       },
-        { 10, 12, 14, 16, "="    , ""       },
-        { 10, 12, 14, 16, ""     , ""       },
-        { 10, 14, 12, 16, "=====", "22"     },
-        { 10, 14, 12, 16, "=="   , ""       },
-        { 10, 14, 12, 16, "="    , ""       },
-        { 10, 14, 12, 16, ""     , ""       },
-        { 10, 16, 12, 14, "=====", "23"     },
-        { 10, 16, 12, 14, "=="   , ""       },
-        { 10, 16, 12, 14, "="    , ""       },
-        { 10, 16, 12, 14, ""     , ""       },
-        { 14, 16, 10, 12, "=====", "24"     },
-        { 14, 16, 10, 12, "=="   , ""       },
-        { 14, 16, 10, 12, "="    , ""       },
-        { 14, 16, 10, 12, ""     , ""       },
-        { 12, 16, 10, 14, "=====", "25"     },
-        { 12, 16, 10, 14, "=="   , ""       },
-        { 12, 16, 10, 14, "="    , ""       },
-        { 12, 16, 10, 14, ""     , ""       },
-        { 12, 14, 10, 16, "=====", "26"     },
-        { 12, 14, 10, 16, "=="   , ""       },
-        { 12, 14, 10, 16, "="    , ""       },
-        { 12, 14, 10, 16, ""     , ""       },
+    struct { int ms; int ml; int ws; int wl; char *replaceWith; char *label; } cases[] = {
+        { 12,  2, 10, 10, "xxxxx", "warmup" },
+        { 10,  0, 10,  0, "=====", "1"      },
+        { 10,  0, 10,  0, "=="   , ""       },
+        { 10,  0, 10,  0, "="    , ""       },
+        { 10,  0, 10,  0, ""     , ""       },
+        { 10,  2, 12,  0, "=====", "2"      },
+        { 10,  2, 12,  0, "=="   , ""       },
+        { 10,  2, 12,  0, "="    , ""       },
+        { 10,  2, 12,  0, ""     , ""       },
+        { 12,  0, 10,  2, "=====", "3"      },
+        { 12,  0, 10,  2, "=="   , ""       },
+        { 12,  0, 10,  2, "="    , ""       },
+        { 12,  0, 10,  2, ""     , ""       },
+        { 10,  0, 12,  0, "=====", "4"      },
+        { 10,  0, 12,  0, "=="   , ""       },
+        { 10,  0, 12,  0, "="    , ""       },
+        { 10,  0, 12,  0, ""     , ""       },
+        { 12,  0, 10,  0, "=====", "5"      },
+        { 12,  0, 10,  0, "=="   , ""       },
+        { 12,  0, 10,  0, "="    , ""       },
+        { 12,  0, 10,  0, ""     , ""       },
+        { 10,  2, 10,  2, "=====", "6"      },
+        { 10,  2, 10,  2, "=="   , ""       },
+        { 10,  2, 10,  2, "="    , ""       },
+        { 10,  2, 10,  2, ""     , ""       },
+        { 10,  2, 10,  0, "=====", "7"      },
+        { 10,  2, 10,  0, "=="   , ""       },
+        { 10,  2, 10,  0, "="    , ""       },
+        { 10,  2, 10,  0, ""     , ""       },
+        { 10,  0, 10,  2, "=====", "8"      },
+        { 10,  0, 10,  2, "=="   , ""       },
+        { 10,  0, 10,  2, "="    , ""       },
+        { 10,  0, 10,  2, ""     , ""       },
+        { 10,  2, 14,  0, "=====", "9"      },
+        { 10,  2, 14,  0, "=="   , ""       },
+        { 10,  2, 14,  0, "="    , ""       },
+        { 10,  2, 14,  0, ""     , ""       },
+        { 10,  4, 12,  2, "=====", "10"     },
+        { 10,  4, 12,  2, "=="   , ""       },
+        { 10,  4, 12,  2, "="    , ""       },  // FORMERLY unrunnable bug: tries to print seemingly infinite string
+        { 10,  4, 12,  2, ""     , ""       },  // ditto
+        { 14,  0, 10,  2, "=====", "11"     },
+        { 14,  0, 10,  2, "=="   , ""       },
+        { 14,  0, 10,  2, "="    , ""       },
+        { 14,  0, 10,  2, ""     , ""       },
+        { 12,  2, 10,  4, "=====", "12"     }, // correctness observation:  watching klmn while mn |-> xxx gives klxxx because the mn is inside what I'm watching
+        { 12,  2, 10,  4, "=="   , ""       },
+        { 12,  2, 10,  4, "="    , ""       },
+        { 12,  2, 10,  4, ""     , ""       },
+        { 10,  2, 12,  2, "=====", "13"     },
+        { 10,  2, 12,  2, "=="   , ""       },
+        { 10,  2, 12,  2, "="    , ""       },
+        { 10,  2, 12,  2, ""     , ""       },
+        { 10,  4, 12,  0, "=====", "14"     },
+        { 10,  4, 12,  0, "=="   , ""       },
+        { 10,  4, 12,  0, "="    , ""       },
+        { 10,  4, 12,  0, ""     , ""       },
+        { 12,  2, 10,  2, "=====", "15"     },
+        { 12,  2, 10,  2, "=="   , ""       },
+        { 12,  2, 10,  2, "="    , ""       },
+        { 12,  2, 10,  2, ""     , ""       },
+        { 12,  0, 10,  4, "=====", "16"     },
+        { 12,  0, 10,  4, "=="   , ""       },
+        { 12,  0, 10,  4, "="    , ""       },
+        { 12,  0, 10,  4, ""     , ""       },
+        { 10,  4, 10,  2, "=====", "17"     },
+        { 10,  4, 10,  2, "=="   , ""       },
+        { 10,  4, 10,  2, "="    , ""       },
+        { 10,  4, 10,  2, ""     , ""       },
+        { 10,  0, 12,  2, "=====", "18"     },
+        { 10,  0, 12,  2, "=="   , ""       },
+        { 10,  0, 12,  2, "="    , ""       },
+        { 10,  0, 12,  2, ""     , ""       },
+        { 10,  2, 10,  4, "=====", "19"     },
+        { 10,  2, 10,  4, "=="   , ""       },
+        { 10,  2, 10,  4, "="    , ""       },
+        { 10,  2, 10,  4, ""     , ""       },
+        { 12,  2, 10,  0, "=====", "20"     },
+        { 12,  2, 10,  0, "=="   , ""       },
+        { 12,  2, 10,  0, "="    , ""       },
+        { 12,  2, 10,  0, ""     , ""       },
+        { 10,  2, 14,  2, "=====", "21"     },
+        { 10,  2, 14,  2, "=="   , ""       },
+        { 10,  2, 14,  2, "="    , ""       },
+        { 10,  2, 14,  2, ""     , ""       },
+        { 10,  4, 12,  4, "=====", "22"     },
+        { 10,  4, 12,  4, "=="   , ""       },
+        { 10,  4, 12,  4, "="    , ""       },
+        { 10,  4, 12,  4, ""     , ""       },
+        { 10,  6, 12,  2, "=====", "23"     },
+        { 10,  6, 12,  2, "=="   , ""       },
+        { 10,  6, 12,  2, "="    , ""       },
+        { 10,  6, 12,  2, ""     , ""       },
+        { 14,  2, 10,  2, "=====", "24"     },
+        { 14,  2, 10,  2, "=="   , ""       },
+        { 14,  2, 10,  2, "="    , ""       },
+        { 14,  2, 10,  2, ""     , ""       },
+        { 12,  4, 10,  4, "=====", "25"     },
+        { 12,  4, 10,  4, "=="   , ""       },
+        { 12,  4, 10,  4, "="    , ""       },
+        { 12,  4, 10,  4, ""     , ""       },
+        { 12,  2, 10,  6, "=====", "26"     },
+        { 12,  2, 10,  6, "=="   , ""       },
+        { 12,  2, 10,  6, "="    , ""       },
+        { 12,  2, 10,  6, ""     , ""       },
     };
     for ( i; sizeof(cases)/sizeof(cases[0]) ) {
         sout | "------------------------------------------------------------------------" | cases[i].label;
         string replaceIn = alphabetTemplate;
-        showOneReplacement( replaceIn, cases[i].ms, cases[i].me, cases[i].ws, cases[i].we, cases[i].replaceWith );
+        showOneReplacement( replaceIn, cases[i].ms, cases[i].ml, cases[i].ws, cases[i].wl, cases[i].replaceWith );
     }
 }
@@ -244,10 +249,10 @@
     string s = "abcdefghijklmnopqrstuvwxyz";
 
-    s(5,10) = "qqqqq";  // start=5, end=10, len=5
-
-    sout | s;
-
-
-    s(5,5) = "-----";  // start=5, end=5, len=0
+    s(5,5) = "qqqqq";  // start=5, end=10, len=5
+
+    sout | s;
+
+
+    s(5,0) = "-----";  // start=5, end=5, len=0
 
     sout | s;
Index: tests/concurrency/examples/quickSort.cfa
===================================================================
--- tests/concurrency/examples/quickSort.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/concurrency/examples/quickSort.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -11,12 +11,12 @@
 // Created On       : Wed Dec  6 12:15:52 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Feb 12 18:24:47 2020
-// Update Count     : 177
-//
-
-#include <fstream.hfa>
-#include <stdlib.hfa>
-#include <kernel.hfa>
+// Last Modified On : Mon Jan  1 12:07:59 2024
+// Update Count     : 188
+//
+
+#include <fstream.hfa>									// sin/sout
+#include <stdlib.hfa>									// convert
 #include <thread.hfa>
+#include <math.hfa>										// sqrt
 #include <string.h>										// strcmp
 
@@ -82,61 +82,72 @@
 } // main
 
-
-bool convert( int & val, const char * nptr ) {			// convert C string to integer
-	char * eptr;
-	int temp = strto( nptr, &eptr, 10 );				// do not change val on false
-	// true => entire string valid with no extra characters
-	return *nptr != '\0' && *eptr == '\0' ? val = temp, true : false;
-} // convert
-
-void usage( char * argv[] ) {
-	sout | "Usage:" | argv[0] | "( -s unsorted-file [ sorted-file ] | -t size (>= 0) [ depth (>= 0) ] )";
-	exit( EXIT_FAILURE );								// TERMINATE!
-} // usage
-
+// convert(...) throws out_of_range or invalid_argument
+ExceptionDecl( cmd_error );
 
 int main( int argc, char * argv[] ) {
-	ifstream & unsortedfile = sin;
-	ofstream & sortedfile = sout;						// default value
-	int depth = 0, size;
-
-	if ( argc != 1 ) {									// do not use defaults
-		if ( argc < 2 || argc > 4 ) usage( argv );		// wrong number of options
-		if ( strcmp( argv[1], "-t" ) == 0 ) {			// timing ?
-			&unsortedfile = (ifstream *)0;				// no input
+	ifstream unsortedfile = sin;						// default values
+	ofstream sortedfile = sout;
+	// Must be signed because of the conversion routine.
+	intmax_t depth = 0;
+	intmax_t size = -1;									// -1 means time mode not activated
+
+	try {
+		if ( 1 < argc && strcmp( argv[1], "-t" ) == 0 ) { // time mode ?
 			choose ( argc ) {
 			  case 4:
-				if ( ! convert( depth, argv[3] ) || depth < 0 ) usage( argv );
+				depth = convert( argv[3] );				// invalid integer ?
+				if ( depth < 0 ) throw ExceptionInst( cmd_error );
 				fallthrough;
 			  case 3:
-				if ( ! convert( size, argv[2] ) || size < 0 ) usage( argv );
+				size = convert( argv[2] );				// invalid integer ?
+				if ( size < 0 ) throw ExceptionInst( cmd_error );
+			  default:									// wrong number of options
+				throw ExceptionInst( cmd_error );
 			} // choose
 		} else {										// sort file
 			choose ( argc ) {
-			  case 3:
-				&sortedfile = new( (const char *)argv[2] ); // open the output file
-				if ( fail( sortedfile ) ) {
-					serr | "Error! Could not open sorted output file \"" | argv[2] | "\"";
-					usage( argv );
+			  case 4:
+				depth = convert( argv[3] );				// invalid integer ?
+				if ( depth < 0 ) throw ExceptionInst( cmd_error );
+				fallthrough;
+			  case 3: case 2:
+				if ( strcmp( argv[1], "d" ) != 0 ) {
+					try {								// open input file first as output creates file
+						open( unsortedfile, argv[1] );
+					} catch( open_failure * ) {			// open failed ?
+						serr | "Error! Could not open unsorted input file \"" | argv[1] | "\"";
+						throw ExceptionInst( cmd_error );
+					} // try
+				} // if
+				if ( argc > 2 && strcmp( argv[2], "d" ) != 0 ) {
+					try {
+						open( sortedfile, argv[2] );
+					} catch( open_failure * ) {			// open failed ?
+						serr | "Error! Could not open sorted output file \"" | argv[2] | "\"";
+						throw ExceptionInst( cmd_error );
+					} // try
 				} // if
 				fallthrough;
-			  case 2:
-				&unsortedfile = new( (const char *)argv[1] ); // open the input file
-				if ( fail( unsortedfile ) ) {
-					serr | "Error! Could not open unsorted input file \"" | argv[1] | "\"";
-					usage( argv );
-				} // if
+			  case 1: ;									// defaults
+			  default:									// wrong number of options
+				throw ExceptionInst( cmd_error );
 			} // choose
 		} // if
-	} // if
+	} catch( exception_t * ) {							// catch any
+		exit | "Usage: " | argv[0] |					// TERMINATE
+			" ( [ unsorted-file | 'd' [ sorted-file | 'd' [ depth (>= 0) ] ] ]"
+			" | -t size (>= 0) [ depth (>= 0) ] )";
+	} //  try
+
+	enum { ValuesPerLine = 22 };						// number of values printed per line
+
 	sortedfile | nlOff;									// turn off auto newline
 
-	enum { ValuesPerLine = 22 };						// number of values printed per line
-
-	if ( &unsortedfile ) {								// generate output ?
+	if ( size == -1 ) {									// generate output ?
 		for () {
 			unsortedfile | size;						// read number of elements in the list
 		  if ( eof( unsortedfile ) ) break;
-			int * values = alloc( size );				// values to be sorted, too large to put on stack
+
+			int * values = aalloc( size );				// values to be sorted, too large to put on stack
 			for ( counter; size ) {						// read unsorted numbers
 				unsortedfile | values[counter];
@@ -146,4 +157,5 @@
 			} // for
 			sortedfile | nl;
+
 			if ( size > 0 ) {							// values to sort ?
 				Quicksort QS = { values, size - 1, 0 }; // sort values
@@ -158,15 +170,16 @@
 			delete( values );
 		} // for
-		if ( &unsortedfile != &sin ) delete( &unsortedfile ); // close input/output files
-		if ( &sortedfile != &sout ) delete( &sortedfile );
-	} else {
+	} else {											// timing
+		PRNG prng;										
 		processor processors[ (1 << depth) - 1 ] __attribute__(( unused )); // create 2^depth-1 kernel threads
-
-		int * values = alloc( size );					// values to be sorted, too large to put on stack
+		int * values = aalloc( size );					// values to be sorted, too large to put on stack
+
 		for ( counter; size ) {							// generate unsorted numbers
 			values[counter] = size - counter;			// descending values
 		} // for
-		for ( i; 200 ) {								// random shuffle a few values
-			swap( values[rand() % size], values[rand() % size] );
+
+		unsigned int times = sqrt( size );
+		for ( unsigned int counter = 0; counter < times; counter += 1 ) {
+			swap( values[0], values[prng(size)] );		// randomize unsorted numbers
 		} // for
 		{
Index: tests/exceptions/hotpotato.cfa
===================================================================
--- tests/exceptions/hotpotato.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/exceptions/hotpotato.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -5,7 +5,7 @@
 
 struct Potato {
-        PRNG & prng;
-        unsigned int deadline;                                                          // when timer goes off
-        unsigned int timer;                                                                     // up counter to deadline
+	PRNG & prng;
+	unsigned int deadline;								// when timer goes off
+	unsigned int timer;									// up counter to deadline
 }; // Potato
 
@@ -16,11 +16,11 @@
 	&potato.prng = &prng;
 	reset( potato, maxTicks );
-} // Potato
+		} // Potato
 
 coroutine Player {
-        PRNG & prng;
-        int id;                                                                                         // player identity
-        Potato & potato;                                                                        // potato being tossed
-        Player * partner[2];                                                            // left and right player
+	PRNG & prng;
+	int id;												// player identity
+	Potato & potato;									// potato being tossed
+	Player * partner[2];								// left and right player
 }; // Player
 
@@ -29,5 +29,5 @@
 	player.id = id;
 	&player.potato = &potato;
-} // Player
+		} // Player
 
 Player & umpire;
@@ -39,5 +39,5 @@
 
 void reset( Potato & potato, unsigned int maxTicks ) with(potato) {
-  if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
+	if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
 	deadline = prng( prng, 1, maxTicks );
 	timer = 0;
@@ -60,6 +60,6 @@
 enum { LEFT = 0, RIGHT = 1 };
 
-static void vote( Player & player, Election & election ) {					// cause partner to vote
-    resumeAt( player, election );
+static void vote( Player & player, Election & election ) { // cause partner to vote
+	resumeAt( player, election );
 	resume( player );
 } // vote
@@ -76,24 +76,24 @@
 
 void main( Player & player ) with(player) {
-    suspend;									// return immediately after establishing starter
+	suspend;											// return immediately after establishing starter
 	try {
-        for ( ;; ) {
-            poll();                                     // check for non-local exceptions before proceeding
-
-            if ( partner[LEFT] == &player ) {			// stop when only one player
-                sout | id | " wins the Match!";
-                return;
-            } // exit
-            
-            countdown( potato );				// player is eliminated if countdown() returned true
-            
-            size_t side = prng( prng, 2 );
-            sout | id | " -> " | nonl;
-            resume( *partner[ side ] );			// random toss left/right
-        } // for
+		for ( ;; ) {
+			poll();										// check for non-local exceptions before proceeding
+
+			if ( partner[LEFT] == &player ) {			// stop when only one player
+				sout | id | " wins the Match!";
+				return;
+			} // exit
+
+			countdown( potato );						// player is eliminated if countdown() returned true
+
+			size_t side = prng( prng, 2 );
+			sout | id | " -> " | nonl;
+			resume( *partner[ side ] );					// random toss left/right
+		} // for
 	} catchResume( Terminate * v ) {
 		v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node
 		v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT];
-        delete( v->victim );
+		delete( v->victim );
 		reset( potato );
 		sout | "U " | nonl;								// start new game
@@ -102,18 +102,18 @@
 		sout | "election";
 		sout | " -> " | id | nonl;
-		if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far
+		if ( id > getId( umpire ) ) &umpire = &player;	// set umpire to highest id so far
 		vote( *partner[RIGHT], *election );
 	} catchResume ( Explode * ) {
-        sout | id | " is eliminated";
-        if ( &player == &umpire ) {
-            id = -1;					// remove from election
-            vote( *partner[RIGHT], ExceptionInst( Election ) );		// start election
-            try { poll(); } catchResume( Election * election ) {} // handle end of election
-            sout | " : umpire " | getId( umpire );
-        } // if
-        resumeAt( umpire, ExceptionInst( Terminate, &player ) );
-        resume( umpire );                   // resume umpire to terminate this player
-        assert( false );					// no return
-    } // try
+		sout | id | " is eliminated";
+		if ( &player == &umpire ) {
+			id = -1;									// remove from election
+			vote( *partner[RIGHT], ExceptionInst( Election ) );	// start election
+			try { poll(); } catchResume( Election * election ) {} // handle end of election
+			sout | " : umpire " | getId( umpire );
+		} // if
+		resumeAt( umpire, ExceptionInst( Terminate, &player ) );
+		resume( umpire );								// resume umpire to terminate this player
+		assert( false );								// no return
+	} // try
 } // main
 
@@ -151,11 +151,11 @@
 		  case 1: ;										// defaults
 		  default:										// too many arguments
-			throw ExceptionInst( cmd_error );
+			  throw ExceptionInst( cmd_error );
 		} // choose
 	} catch( exception_t * ) {							// catch any
 		exit | "Usage: " | argv[0]
-			 | " [ games (>=0) | 'd' (default " | DefaultGames
-			 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
-			 | ") [ seed (>0) | 'd' (random) ] ] ]";
+			| " [ games (>=0) | 'd' (default " | DefaultGames
+			| ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
+			| ") [ seed (>0) | 'd' (random) ] ] ]";
 	} // try
 	sout | numGames | numPlayers | seed;
Index: tests/exceptions/hotpotato_checked.cfa
===================================================================
--- tests/exceptions/hotpotato_checked.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/exceptions/hotpotato_checked.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -5,7 +5,7 @@
 
 struct Potato {
-        PRNG & prng;
-        unsigned int deadline;                                                          // when timer goes off
-        unsigned int timer;                                                                     // up counter to deadline
+	PRNG & prng;
+	unsigned int deadline;								// when timer goes off
+	unsigned int timer;									// up counter to deadline
 }; // Potato
 
@@ -16,11 +16,11 @@
 	&potato.prng = &prng;
 	reset( potato, maxTicks );
-} // Potato
+		} // Potato
 
 coroutine Player {
-        PRNG & prng;
-        int id;                                                                                         // player identity
-        Potato & potato;                                                                        // potato being tossed
-        Player * partner[2];                                                            // left and right player
+	PRNG & prng;
+	int id;												// player identity
+	Potato & potato;									// potato being tossed
+	Player * partner[2];								// left and right player
 }; // Player
 
@@ -29,5 +29,5 @@
 	player.id = id;
 	&player.potato = &potato;
-} // Player
+		} // Player
 
 Player & umpire;
@@ -39,5 +39,5 @@
 
 void reset( Potato & potato, unsigned int maxTicks ) with(potato) {
-  if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
+	if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
 	deadline = prng( prng, 1, maxTicks );
 	timer = 0;
@@ -66,6 +66,6 @@
 static void terminate( Player & player ) {				// resume umpire
 	resume( player ); 
-    checked_poll();
-    sout | "THIS SHOULD NOT BE REACHED";
+	checked_poll();
+	sout | "THIS SHOULD NOT BE REACHED";
 } // terminate
 
@@ -74,5 +74,5 @@
 	partner[RIGHT] = &rp;
 	resume( player );									// establish main as starter for termination
-    checked_poll();
+	checked_poll();
 } // init
 
@@ -82,5 +82,5 @@
 
 void toss( Player & player ) {							// tossed the potato
-    resume( player );
+	resume( player );
 	checked_poll();
 } // toss
@@ -88,26 +88,26 @@
 void main( Player & player ) with(player) {
 	try {
-        enable_ehm();								// allow delivery of nonlocal exceptions
-        suspend;									// return immediately after establishing starter
-        checked_poll();
-
-        for ( ;; ) {
-            checked_poll();
-            if ( partner[LEFT] == &player ) {			// stop when only one player
-                sout | id | " wins the Match!";
-                return;
-            } // exit
-
-            countdown( potato );				// player is eliminated if countdown() returned true
-
-            size_t side = prng( prng, 2 );
-            sout | id | " -> " | nonl;
-            toss( *partner[ side ] );			// random toss left/right
-        } // for
-        disable_ehm();
+		enable_ehm();									// allow delivery of nonlocal exceptions
+		suspend;										// return immediately after establishing starter
+		checked_poll();
+
+		for ( ;; ) {
+			checked_poll();
+			if ( partner[LEFT] == &player ) {			// stop when only one player
+				sout | id | " wins the Match!";
+				return;
+			} // exit
+
+			countdown( potato );						// player is eliminated if countdown() returned true
+
+			size_t side = prng( prng, 2 );
+			sout | id | " -> " | nonl;
+			toss( *partner[ side ] );					// random toss left/right
+		} // for
+		disable_ehm();
 	} catchResume( Terminate * v ) {
 		v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node
 		v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT];
-        delete( v->victim );
+		delete( v->victim );
 		reset( potato );
 		sout | "U " | nonl;								// start new game
@@ -116,25 +116,25 @@
 		sout | "election";
 		sout | " -> " | id | nonl;
-		if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far
-        resumeAt( *partner[RIGHT], *election );
-        disable_ehm();              // disable ehm since we can't handle execption thrown in vote here and want to poll later
+		if ( id > getId( umpire ) ) &umpire = &player;	// set umpire to highest id so far
+		resumeAt( *partner[RIGHT], *election );
+		disable_ehm();									// disable ehm since we can't handle execption thrown in vote here and want to poll later
 		vote( *partner[RIGHT] );
-        enable_ehm();               // enable after vote
+		enable_ehm();									// enable after vote
 	} catchResume( Explode * ) {
-        sout | id | " is eliminated";
-        if ( &player == &umpire ) {
-            try {
-                id = -1;					// remove from election
-                resumeAt( *partner[RIGHT], ExceptionInst( Election ) );
-                vote( *partner[RIGHT] );		// start election
-                checked_poll(); 
-            } catchResume( Election * election ) {
-                sout | " : umpire " | getId( umpire );
-            } // try
-        } // if
-        resumeAt( umpire, ExceptionInst( Terminate, &player ) );
-        terminate( umpire );
-        assert( false );					// no return
-    } // try
+		sout | id | " is eliminated";
+		if ( &player == &umpire ) {
+			try {
+				id = -1;								// remove from election
+				resumeAt( *partner[RIGHT], ExceptionInst( Election ) );
+				vote( *partner[RIGHT] );				// start election
+				checked_poll(); 
+			} catchResume( Election * election ) {
+				sout | " : umpire " | getId( umpire );
+			} // try
+		} // if
+		resumeAt( umpire, ExceptionInst( Terminate, &player ) );
+		terminate( umpire );
+		assert( false );								// no return
+	} // try
 } // main
 
@@ -172,11 +172,11 @@
 		  case 1: ;										// defaults
 		  default:										// too many arguments
-			throw ExceptionInst( cmd_error );
+			  throw ExceptionInst( cmd_error );
 		} // choose
 	} catch( exception_t * ) {							// catch any
 		exit | "Usage: " | argv[0]
-			 | " [ games (>=0) | 'd' (default " | DefaultGames
-			 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
-			 | ") [ seed (>0) | 'd' (random) ] ] ]";
+			| " [ games (>=0) | 'd' (default " | DefaultGames
+			| ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
+			| ") [ seed (>0) | 'd' (random) ] ] ]";
 	} // try
 	sout | numGames | numPlayers | seed;
Index: tests/io/.expect/manipulatorsInput.arm64.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.arm64.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/io/.expect/manipulatorsInput.arm64.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -20,4 +20,12 @@
 14 rc=1, cccc
 15 rc=0, q
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20  d d
+
+d 
+21 		ZC44%
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -35,4 +43,12 @@
 14 cccc
 15
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20 d d
+
+d 
+21		ZC44%
 a
 a
Index: tests/io/.expect/manipulatorsInput.x64.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.x64.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/io/.expect/manipulatorsInput.x64.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -20,4 +20,12 @@
 14 rc=1, cccc
 15 rc=0, q
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20  d d
+
+d 
+21 		ZC44%
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -35,4 +43,12 @@
 14 cccc
 15
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20 d d
+
+d 
+21		ZC44%
 a
 a
Index: tests/io/.expect/manipulatorsInput.x86.txt
===================================================================
--- tests/io/.expect/manipulatorsInput.x86.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/io/.expect/manipulatorsInput.x86.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -20,4 +20,12 @@
 14 rc=1, cccc
 15 rc=0, q
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20  d d
+
+d 
+21 		ZC44%
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -35,4 +43,12 @@
 14 cccc
 15
+16 get this line
+17 @# this line 1)-{}
+18 abc
+19 abc  
+20 d d
+
+d 
+21		ZC44%
 a
 a
Index: tests/io/.in/manipulatorsInput.txt
===================================================================
--- tests/io/.in/manipulatorsInput.txt	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/io/.in/manipulatorsInput.txt	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -10,4 +10,12 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
 uuuuuccccuuuuu
+get this line
+@# this line 1)-{}%
+"abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
 abc 
 cccccb 
@@ -17,4 +25,12 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww
 uuuuuccccuuuuu
+get this line
+@# this line 1)-{}%
+"abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
 ab
 0xff 017 15-15
Index: tests/io/manipulatorsInput.cfa
===================================================================
--- tests/io/manipulatorsInput.cfa	(revision 59c8dff49bbb5284b39ab27da894a644327a531a)
+++ tests/io/manipulatorsInput.cfa	(revision f988834af650698a46072a2a91bb190224a866bd)
@@ -7,6 +7,6 @@
 // Created On       : Sat Jun  8 17:58:54 2019
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Sep  2 14:27:46 2023
-// Update Count     : 65
+// Last Modified On : Wed Jan  3 11:15:04 2024
+// Update Count     : 103
 // 
 
@@ -77,6 +77,17 @@
 		s[0] = 'q'; s[1] = '\0'; rc = 99;
 		rc = scanf( "%[^u]", s );						printf( "15 rc=%d, %s\n", rc, s );
-		scanf( "%*[u]" );
-		scanf("\n");
+		scanf( "%*[u]\n" );
+		scanf( "%[^\n]\n", s );							printf( "16 %s\n", s );
+		scanf( "%[^%%]%%\n", s );						printf( "17 %s\n", s );
+
+		scanf( "%*[ \f\n\r\t\v]" );						// ignore whitespace
+		scanf( "\"%[^\"]\"", s );						printf( "18 %s\n", s );
+		scanf( "%*[ \f\n\r\t\v]" );						// ignore whitespace
+		scanf( "'%[^']'", s );							printf( "19 %s\n", s );
+		scanf( "%*[ \f\n\r\t\v]" );						// ignore whitespace
+		scanf( "{%[^}]}", s );							printf( "20 %s\n", s );
+		scanf( "%*[ \f\n\r\t\v]" );						// ignore whitespace
+		scanf( "X%[^Y]Y", s );							printf( "21 %s\n", s );
+		scanf( "\n" );									// must start next line
 	}
 	{
@@ -102,8 +113,14 @@
 		s[0] = 'q'; s[1] = '\0';
 		sin | excl( "u", wdi( sizeof(s), s ) );			sout | "15" | s;
-		sin | skip( "u" );
-		sin | "\n";
-	}
-    /* Keep harmonized with collections/string-istream-manip */
+		sin | skip( "u" ) | "\n";
+		sin | getline( wdi( sizeof(s), s ) );			sout | "16" | s;
+		sin | getline( wdi( sizeof(s), s ), '%' ) | "\n"; sout | "17" | s;
+
+		sin | quoted( wdi( sizeof(s), s ) );			sout | "18" | s;
+		sin | quoted( wdi( sizeof(s), s ), '\'' );		sout | "19" | s;
+		sin | quoted( wdi( sizeof(s), s ), '{', '}' );	sout | "20" | s;
+		sin | quoted( wdi( sizeof(s), s ), 'X', 'Y' );	sout | "21" | s;
+	}
+    // Keep harmonized with collections/string-istream-manip
 	{
 		char c;
