doesn't work because READ waits until an expression is entered.
use (read-line) instead of (read)
Sam Steingold (http://www.podval.org/~sds)
Support Israel's right to defend herself! <http://www.i-charity.com/go/israel>
Read what the Arab leaders say to their people on <http://www.memri.org/>
Lisp: Serious empowerment.
(do ((x (read-char)))
((char-equal #\Newline x)))
> > * In message <9pklps$5gn$1...@suaar1ac.prod.compuserve.com>
> > * On the subject of "Pause for keystroke"
> > * Sent on Fri, 5 Oct 2001 10:06:16 -0700
> > * Honorable "Roy Mash" <Roy_...@ci.sf.ca.us> writes:
> > I'd like my program to pause for the user to hit RETURN or enter, but
> > (format t "Pausing ... Press ENTER to continue")
> > (read)
> > doesn't work because READ waits until an expression is entered.
> use (read-line) instead of (read)
And what if you want to read (as opposed to read-line) something, but
newline is OK, too? I'm asking this because I'm slightly irritated by
having to type something to CMUCL's toplevel in order to get back the
prompt if the previous output wasn't terminated by a newline.
Now however, I find that if a replace (read *query-io*) with either
(do ((x (read-char *query-io* )))
((char-equal #\Newline x)))
I get a nice dialog box in Lispworks with the OK button grayed out!
(read-from-string (read-line) nil nil)
(remove #\space "coby . beck @ opentechgroup . com")
Why are you tying it to *query-io*?
Because in Lispworks (read) by itself produces an error
if you're not in the Listener environment.
Lispworks does have various prompt-for idioms but these
wouldn't be portable to CLISP.
>>>>> On Fri, 5 Oct 2001 13:49:21 -0700, Roy Mash ("Roy") writes:
Roy> Now however, I find that if a replace (read *query-io*) with either
Roy> (read-line *query-io*)
Roy> (do ((x (read-char *query-io* )))
Roy> ((char-equal #\Newline x)))
Roy> I get a nice dialog box in Lispworks with the OK button grayed out!
Geoff>> Why are you tying it to *query-io*?
Roy> Because in Lispworks (read) by itself produces an error if
Roy> you're not in the Listener environment. Lispworks does have
Roy> various prompt-for idioms but these wouldn't be portable to CLISP.
Common Lisp doesn't really define how the IO streams are implemented;
there's nothing in the language that necessarily gets you a console
like the Listener that's available in most development environments.
Whether IO gets you some kind of keyboard terminal, a GUI, or a pipe
organ keyboard and pedals, is implementation dependants.
Lispworks for Windows can make a "console" application, which does IO
inside the console ("DOS box") that you run invoke it from. You can
also ask for a CAPI application, which is the same except it pops up
the console window for you. I didn't try to start CAPI explicitly,
but my experiments didn't get any CAPI query window like you describe.
In either of those two delivery environments, READ-CHAR on *TERMINAL-IO*
or *QUERY-IO* works in line-mode, so you have to press ENTER after the
input character. Unfortunately, the #\Newline generated by pressing
the ENTER key is placed into the stream. This makes every other
call to READ-CHAR immediately return a leftover #\Newline.
Did I see something going by about CLISP behaving the same way, with
the recommendation that the user flush the stream after each input?
This behaviour seems like a bug to me. Either READ-CHAR should be
doing character-at-a-time (preferable), or else the ENTER key should
only perform the activation and not feed a #\Newline into the stream.
After all, even READ-LINE is defined not to return the #\Newline!
If you use CAPI then you can program the input model of window panes
(set up a callback for keyboard events), but of course that's not ANSI CL.
Is there a way in Lispworks to simply wait for and read one character?
How is this done in CMUCL, Franz, and CLISP?
I don't recall C stdio programs having this design bug for STDIN
(although maybe you have to do some OS-specific fcntl frobbing of
the input descriptor to get the activation mode you want...
I don't remember. But at least there's a standard IO call to do it!)
For what it might be worth, this little page shows the kind of thing you
have to do in the usual Unix system calls framework.
I do not think this should comfort anyone.
There are a number of useful things in the C streams model that are not
available in Common Lisp streams, such as line buffering, which are
neither pretty nor easy to request from Common Lisp and consequently
cause the Common Lisp environments to lack these features.
> "Andras Simon" <asi...@math.bme.hu> wrote in message
> > Sam Steingold <s...@gnu.org> writes:
> > >
> > > use (read-line) instead of (read)
> > >
> > And what if you want to read (as opposed to read-line) something, but
> > newline is OK, too?
> How about
> (read-from-string (read-line) nil nil)
Thanks, but since this is for the toplevel repl, I'd like to ignore
newlines that are in the middle of a form being typed. I.e. when I
USER(23): (defun foo (bar)
(declare (ignore bar)))
it should read the whole (defun foo (bar) (declare (ignore bar))).
With (read-from-string (read-line) nil nil) READ-LINE reads the first
line only (of course) and READ then complains about eof.
Yes, but that won't allow you to read more that one line. I'd suggest:
(defun maybe-read (&rest args)
(loop for char = (apply 'read-char args)
until (char= char #\Newline)
unless (whitespacep char)
do (unread-char char (car args))
(apply 'read args)))
whitespacep should be defined to return true for whitespace characters in
the current readtable, but I can't find any way to do that. Can it be done
without messing with implementation defined stuff?
This is not a trivial problem, unfortunately. The most appropriate way
to read Common Lisp input from an untrusted source is to obey the rules
of the source, and if that is lines instead of expressions, you need to
work with prompts and various forms of input editing. E.g., it would be
nice if the prompt could contain an indication of unclosed delimiters, as
well as some way to discard the unfinished form. The only time it is
appropriate to call the function read directly is when you "know" that
the source will contain a Common Lisp expression, or, in other words,
when you are prepared to deal with errors coming from violating that
knowledge. (This is why it is a very good idea to use Emacs interfaces
to Common Lisp environments.)
E.g., if you want to read interactive user input, I think the appropriate
way to do this is to collect a syntactically valid form first, _then_
process it. Many input processors tend to be built around the assumption
that it is easier to backtrack than to validate before processing. Much
of the parsing literature that exists unquestioningly _assumes_ that the
_only_ way to get any match at all is to confuse the validation and
parsing processes. This is in part caused by the largely unfounded
belief in context-free grammars, which has many strongly appealing
theoretical aspects, but also a large number of negative human factors
that detract from readability and processability. (The influence of
these bad theories on the retarded notion of "ambiguity" in SGML/XML/etc
has caused a large increase in the cost of designing document types and
applications, not the least that of educating/training/hurting developers
and users alike so they stop wanting something completely reasonable.)
Part of the problem of this mode of thinking is that most streams are
very naively implemented one-pass structures. E.g., if you want to
collect a line of input, you copy characters from the stream (buffer) to
some (other) buffer while looking for a line terminator character. If
you could instead push a "mark" on the stream (buffer), tell the stream
to skip characters until a line terminator was seen, and return with it,
you could extract the portion of the buffer from the mark until the
current position, if you needed to: it should also be possible to refer
to the characters in the stream buffer via a displaced array. Naturally,
the simple-minded single-buffer approach to buffering input and output is
also at fault. As long as you refill the same buffer with new data, you
cannot work with buffer marks. (Neither can you ask the operating system
to kindly pre-fill the next buffer while you are doing something else, so
you end up with a _guessing_ operating system and completely unnecessary
delays at the buffer edges.) Designing an SGML entity manager and parser
around these ideas (in 1993-1994) caused a dramatic 5-fold speed increase
over the naive C stream implementation.
So much interesting work remains in the Common Lisp reader if one wants
to support a better interactive environment, and that includes _much_
better error recovery when reading Common Lisp files that have not been
produced by a competent expression-oriented environment like Emacs with
an intelligent user. The common way of de-coupling the input processing
from the "terminal" also leaves much to be desired. Those who remember
TOPS-20's command line processor will know what I mean and miss, but
others may need to have several layers of blinders removed after only
having been exposed to the ultra-primitive Microsoft command line and
only somewhat better Unix command line, especially if they think that GNU
readline is an improvement. A typewriter remain a typewriter no matter
how much chrome you add to it, and Unix even has an error message to tell
you that you have violated its assumptions: "ENOTTY -- Not a typewriter".
Unfortunately, nigh the whole world is now duped into thinking that silly
fill-in forms on web pages is the way to do user interfaces. It is not
unlikely that this is a sort of improvement over the typewriter, but that
is about all there is to it.
On the other hand, given a C FFI, it ought to be pretty easy to
construct something like:
(with-cbreak (port stdin)
for i from 1 to 10
do (format stdout "Type a character:")
do (flush stdout)
do (setf ch (read-byte stdin))
do (format stdout "~C~%" ch)
do (flush stdout)))
(concatenate 'string "cbbrowne" "@cbbrowne.com")
"Is your pencil Y2K certified? Do you know the possible effects if it