From: Bigos on 15 Nov 2009 03:40 On Nov 15, 1:56 am, r...(a)rpw3.org (Rob Warnock) wrote: > Bigos <ruby.obj...(a)googlemail.com> wrote: > > +--------------- > | r...(a)rpw3.org (Rob Warnock) wrote: > ...[how to do raw/cbreak input from within CMCUL]... > | > As I said, this is CMUCL-specific, but almost any CL implementation > | > should provide you *some* way to make "ioctl()" calls... > | > | I use sbcl and it doesn't seem to work for me. > +--------------- > > (*Ahem!*) As I *SAID*, my code is CMUCL-specific, but almost any CL > implementation should provide you *some* way to make "ioctl()" calls. > > SBCL certainly provides such a way, but it's not at all surprising > that it's *different* from CMUCL -- see the SBCL documentation for > how to do the corresponding thing. > > +--------------- > | Also I am surprised that you need so much code for such seemingly > | trivial function. I the other language I use it's only 3 lines of > | code. > | > | system("stty raw -echo") #execute command in subshell raw mode, no > | echo > | char=STDIN.getc #read character from standard input > | system("stty -raw echo") #reset terminal mode > +--------------- > > You're "fork()/exec()"-ing *two* external programs!! > My example code does everything those two external > program executions do *inside* the original process. > > Anyway, who cares how much code it is? You're going to > use an application-specific wrapper function around it > anyway, aren't you? > > +--------------- > | Is something similar possible with sbcl? > +--------------- > > Yes. RTFM. > > -Rob > > ----- > Rob Warnock <r...(a)rpw3.org> > 627 26th Avenue <URL:http://rpw3.org/> > San Mateo, CA 94403 (650)572-2607
From: Bigos on 15 Nov 2009 04:02 On Nov 15, 1:56 am, r...(a)rpw3.org (Rob Warnock) wrote: > Bigos <ruby.obj...(a)googlemail.com> wrote: > > +--------------- > | r...(a)rpw3.org (Rob Warnock) wrote: > ...[how to do raw/cbreak input from within CMCUL]... > | > As I said, this is CMUCL-specific, but almost any CL implementation > | > should provide you *some* way to make "ioctl()" calls... > | > | I use sbcl and it doesn't seem to work for me. > +--------------- > > (*Ahem!*) As I *SAID*, my code is CMUCL-specific, but almost any CL > implementation should provide you *some* way to make "ioctl()" calls. > > SBCL certainly provides such a way, but it's not at all surprising > that it's *different* from CMUCL -- see the SBCL documentation for > how to do the corresponding thing. > > +--------------- > | Also I am surprised that you need so much code for such seemingly > | trivial function. I the other language I use it's only 3 lines of > | code. > | > | system("stty raw -echo") #execute command in subshell raw mode, no > | echo > | char=STDIN.getc #read character from standard input > | system("stty -raw echo") #reset terminal mode > +--------------- > > You're "fork()/exec()"-ing *two* external programs!! > My example code does everything those two external > program executions do *inside* the original process. > > Anyway, who cares how much code it is? You're going to > use an application-specific wrapper function around it > anyway, aren't you? > > +--------------- > | Is something similar possible with sbcl? > +--------------- > > Yes. RTFM. > > -Rob > > ----- > Rob Warnock <r...(a)rpw3.org> > 627 26th Avenue <URL:http://rpw3.org/> > San Mateo, CA 94403 (650)572-2607 yes, I have READ THE FRACTIOUS MANUAL and my problem is that I don't understand it. When I tried to write my own code based on my understanding of the documentation and all I got was error messages having something to do with provided arguments. I found some code snippet on the web, got rid of error messages, but still didn't achieve expected behaviour. (defvar char1) (sb-ext:run-program "stty raw -echo" nil :input t :output t :wait nil :pty t ) (setf char1 (read-char )) (sb-ext:run-program "stty -raw echo" nil :input t :output t :wait nil :pty t ) (format t "~a~%" char1) The code fragment above still requires pressing enter to work, so my expected trick didn't work. Please be patient with me. Some of you are experts and my daft questions might annoy you, but I please understand, I will not begin to understand Lisp documentation overnight. Some time will have to pass before I get to your level. Lot of it still feels like a foreign language to me. I spent much time on Friday and Saturday looking for the answers, and if I have managed to find the answers myself I wouldn't bother anyone. Regards, Jack
From: Rob Warnock on 15 Nov 2009 05:56 Bigos <ruby.object(a)googlemail.com> wrote: +--------------- | rpw3(a)rpw3.org (Rob Warnock) wrote: | > Bigos �<ruby.obj...(a)googlemail.com> wrote: | > +--------------- | > | I use sbcl and it doesn't seem to work for me. | > +--------------- | > | > (*Ahem!*) As I *SAID*, my code is CMUCL-specific, but almost any CL | > implementation should provide you *some* way to make "ioctl()" calls. | > | > SBCL certainly provides such a way, but it's not at all surprising | > that it's *different* from CMUCL -- see the SBCL documentation for | > how to do the corresponding thing. +--------------- By "corresponding thing" I did *not* mean the RUN-PROGRAM hack, but rather "the corresponding way in SBCL to do terminal ioctl()s *within* the SBCL process without running an external program". What does (APROPOS "TCGETATTR") say in SBCL? Ditto (APROPOS "TCSETATTR")? Those are the routines you should be looking to use. Or if those aren't there, what about (APROPOS "IOCTL")? I strongly suspect at least SB-UNIX:UNIX-IOCTL is there, though you might have to figure out how to use it to invoke TCGETATTR/TCSETATTR/etc.. +--------------- | yes, I have READ THE FRACTIOUS MANUAL and my problem is that I don't | understand it. When I tried to write my own code based on my | understanding of the documentation and all I got was error messages | having something to do with provided arguments. I found some code | snippet on the web, got rid of error messages, but still didn't | achieve expected behaviour. .... | (sb-ext:run-program "stty raw -echo" nil :input t :output t :wait | nil :pty t ) +--------------- Well, there's a big part of your problem: You're supplying the wrong args to SB-EXT:RUN-PROGRAM! The first args *isn't* a shell command, but an absolute program pathname string [but see "p.s." below], and the second arg [which you set NIL] is a *list* of string arguments to the command. And :WAIT NIL means that you're *not* waiting until the program finishes before doing the next thing [your READ-CHAR], so no *wonder* it doesn't work!! And you don't want :PTY T, since you want "stty" to work on the *current* terminal, not some random PTY. Try this instead: (sb-ext:run-program "/bin/stty" '("-icanon" "-echo" "-echoe" "-echok" "-echonl") :input t :output t :error t :wait t) and then of course afetr READ-CHAR to turn echoing & line-editing back on: (sb-ext:run-program "/bin/stty" '("icanon" "echo" "echoe" "echok" "echonl") :input t :output t :error t :wait t) Note: These work exactly as you seem to want them to on CMUCL, albeit using EXT:RUN-PROGRAM rather than SB-EXT:RUN-PROGRAM, but there might be some reason it wouldn't work on SBCL. [I don't know, not being an SBCL user...] In any case, do a (DESCRIBE 'SB-EXT:RUN-PROGRAM) and study the output carefully. +--------------- | The code fragment above still requires pressing enter to work, so my | expected trick didn't work. +--------------- Of course not: (1) The first SB-EXT:RUN-PROGRAM had the wrong args, and (2) you didn't wait for the command to finish before doing READ-CHAR. Anyway, I strongly recommend that you *not* continue to try the external program method for twiddling the terminal state, but instead learn how to do [or find an example somewhere of doing] "ioctl()"s from *within* SBCL [approximating more or less my code for CMUCL]. That's more likely to be reliable. -Rob p.s. I see that with SB-EXT:RUN-PROGRAM you can use the keyword arg :SEARCH T to look in your $PATH instead of having to provide an absolute path. That is, instead of the first example above you *should* be able to do this: (sb-ext:run-program "stty" '("-icanon" "-echo" "-echoe" "-echok" "-echonl") :search t :input t :output t :error t :wait t) p.p.s. One more hint. Try running this: (sb-ext:run-program "stty" '("-a") :search t :input t :output t :error t :wait t) If that works -- that is, prints out the state of your terminal -- but the examples which alter the TTY state *don't* appear to work, then SBCL may be saving/restoring the terminal state across sub-process executions [the way some shells do], in which case the external program method for twiddling the terminal state is *never* going to work!! In that case you *must* learn & use the internal "ioctl()" method. ----- Rob Warnock <rpw3(a)rpw3.org> 627 26th Avenue <URL:http://rpw3.org/> San Mateo, CA 94403 (650)572-2607
From: Thomas F. Burdick on 15 Nov 2009 08:41 On Nov 14, 2:28 pm, r...(a)rpw3.org (Rob Warnock) wrote: > Here's a little function I hacked up in CMUCL some years ago when I > needed single character terminal input for an interactive program > [running on FreeBSD & Linux]: > > (use-package :alien) > (use-package :unix) > > #| What "less" does: > s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); > s.c_oflag |= (OPOST|ONLCR|TAB3); > s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); > s.c_cc[VMIN] = 1; > s.c_cc[VTIME] = 0; > |# > > (defun read-char-no-echo-cbreak (&optional (stream *query-io*)) > (with-alien ((old (struct termios)) > (new (struct termios))) > (let ((e0 (unix-tcgetattr 0 old)) > (e1 (unix-tcgetattr 0 new)) > (bits (logior tty-icanon tty-echo tty-echoe tty-echok tty-echonl))) > (declare (ignorable e0 e1)) > (unwind-protect > (progn > (setf (slot new 'c-lflag) (logandc2 (slot old 'c-lflag) bits)) > (setf (deref (slot new 'c-cc) vmin) 1) > (setf (deref (slot new 'c-cc) vtime) 0) > (unix-tcsetattr 0 tcsadrain new) > (read-char stream)) > (unix-tcsetattr 0 tcsadrain old))))) [snip] > As I said, this is CMUCL-specific, but almost any CL implementation > should provide you *some* way to make "ioctl()" calls... Indeed, and the translation to use the SB-POSIX package (sb-unix being internals) was dead simple. Where Rob's CMUCL version stack allocates the alien structures, this one heap allocates both them and their CLOS wrappers. If that were to ever be a performance issue, I bet you'd want to refactor this into a with-no-echo-cbreak macro and just call read-char directly without twiddling the terminal on every read. (require :sb-posix) (import '(sb-posix:termios sb-posix:termios-lflag sb-posix:termios-cc sb-posix:tcgetattr sb-posix:tcsetattr sb-posix:tcsadrain sb-posix:icanon sb-posix:echo sb-posix:echoe sb-posix:echok sb-posix:echonl sb-posix:vmin sb-posix:vtime)) #| What "less" does: s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); s.c_oflag |= (OPOST|ONLCR|TAB3); s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); s.c_cc[VMIN] = 1; s.c_cc[VTIME] = 0; |# (defun read-char-no-echo-cbreak (&optional (stream *query-io*)) (let ((old (tcgetattr 0)) (new (tcgetattr 0)) (bits (logior icanon echo echoe echok echonl))) (unwind-protect (progn (setf (termios-lflag new) (logandc2 (termios-lflag old) bits) (aref (termios-cc new) vmin) 1 (aref (termios-cc new) vtime) 0) (tcsetattr 0 tcsadrain new) (read-char stream)) (tcsetattr 0 tcsadrain old))))
From: Bigos on 15 Nov 2009 18:18
On Nov 15, 10:56 am, r...(a)rpw3.org (Rob Warnock) wrote: > Bigos <ruby.obj...(a)googlemail.com> wrote: > > +--------------- > | r...(a)rpw3.org (Rob Warnock) wrote: > | > Bigos <ruby.obj...(a)googlemail.com> wrote: > | > +--------------- > | > | I use sbcl and it doesn't seem to work for me. > | > +--------------- > | > > | > (*Ahem!*) As I *SAID*, my code is CMUCL-specific, but almost any CL > | > implementation should provide you *some* way to make "ioctl()" calls. > | > > | > SBCL certainly provides such a way, but it's not at all surprising > | > that it's *different* from CMUCL -- see the SBCL documentation for > | > how to do the corresponding thing. > +--------------- > > By "corresponding thing" I did *not* mean the RUN-PROGRAM hack, but > rather "the corresponding way in SBCL to do terminal ioctl()s *within* > the SBCL process without running an external program". > > What does (APROPOS "TCGETATTR") say in SBCL? Ditto (APROPOS "TCSETATTR")? > Those are the routines you should be looking to use. > > Or if those aren't there, what about (APROPOS "IOCTL")? I strongly suspect > at least SB-UNIX:UNIX-IOCTL is there, though you might have to figure out > how to use it to invoke TCGETATTR/TCSETATTR/etc.. > > +--------------- > | yes, I have READ THE FRACTIOUS MANUAL and my problem is that I don't > | understand it. When I tried to write my own code based on my > | understanding of the documentation and all I got was error messages > | having something to do with provided arguments. I found some code > | snippet on the web, got rid of error messages, but still didn't > | achieve expected behaviour. > ... > | (sb-ext:run-program "stty raw -echo" nil :input t :output t :wait > | nil :pty t ) > +--------------- > > Well, there's a big part of your problem: You're supplying the wrong > args to SB-EXT:RUN-PROGRAM! The first args *isn't* a shell command, > but an absolute program pathname string [but see "p.s." below], and > the second arg [which you set NIL] is a *list* of string arguments > to the command. And :WAIT NIL means that you're *not* waiting until > the program finishes before doing the next thing [your READ-CHAR], > so no *wonder* it doesn't work!! And you don't want :PTY T, since you > want "stty" to work on the *current* terminal, not some random PTY. > Try this instead: > > (sb-ext:run-program "/bin/stty" > '("-icanon" "-echo" "-echoe" "-echok" "-echonl") > :input t :output t :error t :wait t) > > and then of course afetr READ-CHAR to turn echoing & line-editing > back on: > > (sb-ext:run-program "/bin/stty" > '("icanon" "echo" "echoe" "echok" "echonl") > :input t :output t :error t :wait t) > > Note: These work exactly as you seem to want them to on CMUCL, albeit > using EXT:RUN-PROGRAM rather than SB-EXT:RUN-PROGRAM, but there might > be some reason it wouldn't work on SBCL. [I don't know, not being an > SBCL user...] > > In any case, do a (DESCRIBE 'SB-EXT:RUN-PROGRAM) and study the output > carefully. > > +--------------- > | The code fragment above still requires pressing enter to work, so my > | expected trick didn't work. > +--------------- > > Of course not: (1) The first SB-EXT:RUN-PROGRAM had the wrong args, > and (2) you didn't wait for the command to finish before doing READ-CHAR. > > Anyway, I strongly recommend that you *not* continue to try the external > program method for twiddling the terminal state, but instead learn how > to do [or find an example somewhere of doing] "ioctl()"s from *within* > SBCL [approximating more or less my code for CMUCL]. That's more likely > to be reliable. > > -Rob > > p.s. I see that with SB-EXT:RUN-PROGRAM you can use the keyword arg > :SEARCH T to look in your $PATH instead of having to provide an > absolute path. That is, instead of the first example above you > *should* be able to do this: > > (sb-ext:run-program "stty" > '("-icanon" "-echo" "-echoe" "-echok" "-echonl") > :search t :input t :output t :error t :wait t) > > p.p.s. One more hint. Try running this: > > (sb-ext:run-program "stty" '("-a") > :search t :input t :output t :error t :wait t) > > If that works -- that is, prints out the state of your terminal -- > but the examples which alter the TTY state *don't* appear to work, > then SBCL may be saving/restoring the terminal state across sub-process > executions [the way some shells do], in which case the external program > method for twiddling the terminal state is *never* going to work!! > In that case you *must* learn & use the internal "ioctl()" method. > > ----- > Rob Warnock <r...(a)rpw3.org> > 627 26th Avenue <URL:http://rpw3.org/> > San Mateo, CA 94403 (650)572-2607 I have run sbcl in terminal window and got following: This is SBCL 1.0.29.11.debian, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (APROPOS "TCGETATTR") SB-POSIX:TCGETATTR (fbound) * (APROPOS "TCSETATTR") SB-POSIX:TCSETATTR (fbound) * (APROPOS "IOCTL") SB-POSIX:IOCTL (fbound) SB-POSIX::IOCTL-WITH-INT-ARG (fbound) SB-POSIX::IOCTL-WITH-POINTER-ARG (fbound) SB-POSIX::IOCTL-WITHOUT-ARG (fbound) SB-UNIX:UNIX-IOCTL (fbound) * (sb-ext:run-program "stty" '("-a") :search t :input t :output t :error t :wait t) speed 38400 baud; rows 24; columns 80; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts -ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop - echoprt echoctl echoke I will search for more information about the subject tomorrow. I need some rest so I can think properly and analyse the information I got so far. |