Hi, I am writing, done actually, a littl app that carries on a few things that I ask it to do. There is a point where I need my app to wait till I press any key so it can keep moving. I tried with getchar, even doing fflush(stdin) first, but the app goes right throught it, it seems like something forces a bypass over getchar, so I decided to try read() and wait for 1 character. It works great.. but is it elegant and convenient to use a system call for a usermode app ? Shouldnt I use a library wrapper? What glibc function should I use to wait for a return(enter) or any other key to be pressed? This is C. Thanks, Raul
Raúl Gutiérrez Segalés wrote:
Hi, Hi
I am writing, done actually, a littl app that carries on a few things that I ask it to do. There is a point where I need my app to wait till I press any key so it can keep moving.
I tried with getchar, even doing fflush(stdin) first, but the app goes right throught it, it seems like something forces a bypass over getchar, so I decided to try read() and wait for 1 character.
fflush can only be used on writeable streams, because, actually, when
you fflush a stream, glibc calls write() on its descriptor. So,
fflush(stdin) must *not* be used (on some systems, it may even cause an
error).
What are the characters you receive after having called getchar() ??
Don't forget also that, by default, the Linux terminal is in cooked
mode. That is, you have to press <enter> before receiving any character.
For example, execute the simple program :
#include
It works great.. but is it elegant and convenient to use a system call for a usermode app ? Shouldnt I use a library wrapper?
Well, IMHO it is elegant not to mix system calls with glibc functions...
What glibc function should I use to wait for a return(enter) or any other key to be pressed?
You can simply ;) put your terminal in raw mode. man cfmakeraw will tell you what to do. You may also find some tips in the Serial Programming HOW-TO (available at http://www.linuxdocs.org/HOWTOs/Serial-Programming-HOWTO/ ) Don't forget to put your terminal back in its previous state when exiting your app. It will make the user a *lot* more happy ;)
This is C.
Thanks, Raul
I hope this was helpful, Nicolas
Over the years I've had to do this on various Unix systems. The
following C code will work under SuSE Linux and most POSIX compliant
systems.
---------------------------------------------------------------------
#include
Jerry Feldman
void GetOne()
<nitpick> This isn't a valid Prototype in ISO C, because the compiler can't distinguish between an empty parameter list and K&R definitions. So it should be void GetOne(void) </nitpick>
int main()
<nitpick> Same here, this should be int main (void) </nitpick> And you should have added that on Linux this needs to be linked against libncurses to get the lowlevel termio functions. cheers Philipp -- Philipp Thomas work: pthomas@suse.de Development, SuSE Linux AG private: philipp.thomas@t-link.de
Jerry Feldman
[Fri, 30 May 2003 22:15:29 -0400]: void GetOne()
<nitpick> This isn't a valid Prototype in ISO C, because the compiler can't distinguish between an empty parameter list and K&R definitions. So it should be void GetOne(void) </nitpick> I would agree with your nitpick here, but C89 very specifically allows
On Sat, 31 May 2003 05:49:51 +0200
Philipp Thomas
int main()
<nitpick> Same here, this should be int main (void) </nitpick> Main is rarely used with a void argument list, but I guess it is more correct to specify void.
And you should have added that on Linux this needs to be linked against libncurses to get the lowlevel termio functions. Not true. Termios(3) is not dependent upon libncurses at all. I think you are confusing termio with termios. Check the man page for termios. The termios functions are in libc. gaf@gaf:~/src> nm /usr/lib/libncurses.a | grep tcgetattr U tcgetattr Note that this is an external reference. gaf@gaf:~/src> nm /usr/lib/libc.a | grep tcgetattr U __tcgetattr tcgetattr.o: 00000000 T __tcgetattr 00000000 W tcgetattr U __tcgetattr
In this case, in libc, tcgetattr is a weak symbol and __tcgetattr is the
actual function name.
--
Jerry Feldman
Jerry Feldman
void GetOne()
<nitpick> This isn't a valid Prototype in ISO C, because the compiler can't distinguish between an empty parameter list and K&R definitions. So it should be void GetOne(void) </nitpick>
I would agree with your nitpick here, but C89 very specifically allows this.
I should have been more precise, sorry. At least C89 allows it (can't check ISO C98 as it's at work). It's the compiler that can't distinguish between empty parameter list and K&R definition and thus won't flag passing parameters as an error. That's why I *always* change code to use void and have caught a few bugs in packages where functions first took a parameter and later none but as there was only a K&R prototype the compiler didn't catch it.
Not true. Termios(3) is not dependent upon libncurses at all. I think you are confusing termio with termios. Check the man page for termios.
Yepp, you're right, I confused them. Shows how often I use that stuff myself :) Philipp
On Sat, 31 May 2003 16:08:49 +0200
Philipp Thomas
I should have been more precise, sorry. At least C89 allows it (can't check ISO C98 as it's at work). It's the compiler that can't distinguish between empty parameter list and K&R definition and thus won't flag passing parameters as an error. This is true to some extent. A good compiler should be able to catch the error in some cases. Lint on Tru64 Unix was able to do it, and it used a YACC parser. It is relatively easy for the compiler if the function is defined first. But, I don't think that gcc has that capability.
That's why I *always* change code to use void and have caught a few bugs in packages where functions first took a parameter and later none but as there was only a K&R prototype the compiler didn't catch it. It is a good practice to always use ANSI prototypes and ANSI function definitions. The only exception might be main() which is a special case in that it takes either 0 or 2 parameters (or 3 in archaic cases).
In C++, an empty parameter list is equivalent to using void as the
parameter list since C++ does not permit K&R function types.
But, other than the howto, in answer to the original person's question,
"s read() evil in usermode", the answer is no. It is appropriate to use
standard Unix/Linux system calls in any code that is intended for use in
a Unix-like system. My only comment is that it is better to use the more
portable interfaces, which is why I used termios(3) and not ioctl(2).
Additionally, read(2), write(2), open(2) and close(2) are normally
available in non-Unix systems.
--
Jerry Feldman
On Sat, 31 May 2003, Jerry Feldman wrote:
On Sat, 31 May 2003 16:08:49 +0200 Philipp Thomas
wrote: I should have been more precise, sorry. At least C89 allows it (can't check ISO C98 as it's at work). It's the compiler that can't distinguish between empty parameter list and K&R definition and thus won't flag passing parameters as an error. This is true to some extent. A good compiler should be able to catch the error in some cases. Lint on Tru64 Unix was able to do it, and it used a YACC parser. It is relatively easy for the compiler if the function is defined first. But, I don't think that gcc has that capability.
That's why I *always* change code to use void and have caught a few bugs in packages where functions first took a parameter and later none but as there was only a K&R prototype the compiler didn't catch it. It is a good practice to always use ANSI prototypes and ANSI function definitions. The only exception might be main() which is a special case in that it takes either 0 or 2 parameters (or 3 in archaic cases).
In C++, an empty parameter list is equivalent to using void as the parameter list since C++ does not permit K&R function types.
But, other than the howto, in answer to the original person's question, "s read() evil in usermode", the answer is no. It is appropriate to use standard Unix/Linux system calls in any code that is intended for use in a Unix-like system. My only comment is that it is better to use the more portable interfaces, which is why I used termios(3) and not ioctl(2). Additionally, read(2), write(2), open(2) and close(2) are normally available in non-Unix systems.
Finally, thanks! This is arrises a new question, since both using read() or using termio to put the terminal out of cooked mode solve the problem, using which of this builds up a better coding style, or better said: the correct coding style.
-- Jerry Feldman
Boston Linux and Unix user group http://www.blu.org PGP key id:C5061EA9 PGP Key fingerprint:053C 73EC 3AC1 5C44 3E14 9245 FB00 3ED5 C506 1EA9
This is arrises a new question, since both using read() or using termio to put the terminal out of cooked mode solve the problem, using which of this builds up a better coding style, or better said: the correct coding style. First, these function make for somewhat unportable code. The code that I
On Sun, 1 Jun 2003 11:03:20 -0400 (PYT)
Raúl Gutiérrez Segalés
On 1 Jun 2003 at 12:37, Jerry Feldman wrote:
Date sent: Sun, 1 Jun 2003 12:37:09 -0400
From: Jerry Feldman
First, these function make for somewhat unportable code. The code that I presented should work on most Unix and Linux systems (except maybe SCO), but on Windows, you might want to use the conio functions. As I created a separate function to wait for a keypress, it is best to make non-portable code into separate entities such that you can easily add that functionality on another platform. (by separate entity, I mean a separate function or macro).
-- Jerry Feldman
read() is pretty portable - it's POSIX compliant, so it should be available on all Unixes, and it's also available on Win32 (Ugh!). I agree with the point about keeping potentially non-portable code seperate. I/O code often falls into this category, so it's as well to get into the habit of doing it anyway, even if you don't think there are going to be any problems. alan -- http://www.ibgames.net/alan Registered Linux user #6822 http://counter.li.org Winding Down - Weekly Tech Newsletter - subscribe at http://www.ibgames.net/alan/winding/mailing.html
<nitpick> This isn't a valid Prototype in ISO C, because the compiler can't distinguish between an empty parameter list and K&R definitions. So it should be void GetOne(void) </nitpick> In any case, I decided to make a slight change to the function. It would be more useful for the function to take the file descriptor as the
On Sat, 31 May 2003 05:49:51 +0200
Philipp Thomas
participants (5)
-
alan@ibgames.com
-
Jerry Feldman
-
Nicolas Bellido
-
Philipp Thomas
-
Raúl Gutiérrez Segalés