Thanks for the pointer to CinOut::overflow(). That's the part I was missing.
The attached patch ensures that no_readline() changes pad characters to spaces before pushing the prompt onto stdin. I've also reverted your patch to CInOut::overflow(). Here's the explanation: aplwrap watches both stout and stderr. When there's a prompted quote-quad input, aplwrap sees the printed prompt. It also sees -- on stderr -- the prompt as pushed back onto stdin. Because these two prompts print on different streams, aplwrap is able to match them and suppress printing of the stderr version of the prompt. With CInOut::overflow() echoing stdin to stdout (as it does in SVN 447), aplwrap sees a doubled prompt on stdout, leaving no way for aplwrap to infer the presence of a prompt and suppress the doubled output. That's why I reverted CInOut::overflow() to echo to stderr. The second part of the patch ensures that pad characters in the quote-quad prompt aren't pushed onto stdin. With this patch, the stdout and stderr representations of the prompt are identical.
Index: src/Output.cc =================================================================== --- src/Output.cc (revision 447) +++ src/Output.cc (working copy) @@ -150,7 +150,7 @@ if (!InputFile::echo_current_file()) return 0; Output::set_color_mode(Output::COLM_INPUT); - cout << (char)c; + cerr << (char)c; return 0; } //----------------------------------------------------------------------------- Index: src/Input.cc =================================================================== --- src/Input.cc (revision 447) +++ src/Input.cc (working copy) @@ -107,8 +107,9 @@ { if (prompt) { - CIN << '\r' << *prompt << flush; - UTF8_string prompt_utf(*prompt); + UCS_string prompt_no_pad = prompt->no_pad(); + CIN << '\r' << prompt_no_pad << flush; + UTF8_string prompt_utf(prompt_no_pad); loop(p, prompt_utf.size()) { const int cc = prompt_utf[prompt_utf.size() - p - 1];