Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

how to read 1 char from standard in?

1 view
Skip to first unread message

Eric

unread,
Aug 22, 2004, 2:35:03 PM8/22/04
to

Mdk 9.2 on x86 using g++ (gcc) 3.3.1-
How do i read a single char from stdin? I want to get the first key
(or redirected char) someone hits and not have to wait for <ENTER> to be
pressed.
getchar and fgetc seem to want <ENTER> to be pressed before they return
anything.
Thanks
Eric

Kasper Dupont

unread,
Aug 22, 2004, 3:14:34 PM8/22/04
to

Eric

unread,
Aug 22, 2004, 3:41:32 PM8/22/04
to
Kasper Dupont wrote:

> Eric wrote:
>>
>> Mdk 9.2 on x86 using g++ (gcc) 3.3.1-
>> How do i read a single char from stdin? I want to get the first key
>> (or redirected char) someone hits and not have to wait for <ENTER> to be
>> pressed.
>> getchar and fgetc seem to want <ENTER> to be pressed before they return
>> anything.
>> Thanks
>> Eric
>
> http://www.daimi.au.dk/~kasperd/comp.os.linux.development.faq.html#termios
>

Thanks, that does it.
Eric

Eric

unread,
Aug 22, 2004, 8:11:23 PM8/22/04
to
Eric wrote:

One thing, shouldnt something like this be part of the stdlib for linux or
at least in a normally included or normally distributed lib for linux? It
just seems like it must be a very common need.
Eric

Floyd L. Davidson

unread,
Aug 22, 2004, 9:12:40 PM8/22/04
to

You'll find that trying to generalize it is difficult. Hence
there is no one implementation that fits all needs (unless you
want to look at something like ncurses, readline, and perhaps
other libraries, but those are much larger packages with a great
deal more functionality than just this one item).

Instead, each and every program that requires raw input is
necessarily customized for specific needs, and the standard
POSIX functionality (and the libraries which support it) are
indeed included with every Linux distribution.

--
FloydL. Davidson <http://web.newsguy.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska) fl...@barrow.com

Last2Know

unread,
Aug 22, 2004, 10:33:46 PM8/22/04
to

It has been standardized for Unix. It's just not part of libc
and the non-portable parts of the link above are not intrinsic
to the desired functionality.

Floyd L. Davidson

unread,
Aug 22, 2004, 10:48:53 PM8/22/04
to

What parts are either non-portable, or not intrinsic to the
desired functionality?

Eric

unread,
Aug 22, 2004, 11:41:45 PM8/22/04
to
Last2Know wrote:

Well, forget kbhit for the moment - cant a simple getc from stdin be
portable? Why are we always reinventing the wheel? put this getc in stdlib,
put in whatever code is necessary to make it work across the main
distributions and be done with it. The code referenced above doesn't seem
that difficult to implement across multiple distributions does it? I mean
it didnt have any ifdef Debian then ... else if defined Mandrake then ...
else if defined Redhat etc etc stuff in it. Or am i missing something?
(wont be the first time I've missed a completely obvious point)
Eric

Floyd L. Davidson

unread,
Aug 23, 2004, 12:05:35 AM8/23/04
to

That misses the point though. The code, including the kbhit()
example, is POSIX compliant and will compile not only across all
Linux distributions, but on virtually all modern unixes. (The
example code has evolved over the years, and the original
predated Linux by several years.)

But that code does *not* implement a single universal solution.
It merely demonstrates how to go about writing such solutions,
and gives one example. But each and every program will have
different requirements, and the code in the examples does *not*
provide answers for all or even most of those program
requirements.

Last2Know

unread,
Aug 23, 2004, 12:31:01 AM8/23/04
to

The ioctl call mainly. Also select() should come from
/usr/include/sys/select.h in modern POSIX code.


Last2Know

unread,
Aug 23, 2004, 12:39:18 AM8/23/04
to

getc() from stdin is portable. It just doesn't have the
semantics that you want. I'm reading your remarks above to
mean, basically, that you would have liked the standard
library for the C language to have a different design
or promise a different functionality than what it does.


> That misses the point though. The code, including the kbhit()
> example, is POSIX compliant and will compile not only across all
> Linux distributions, but on virtually all modern unixes. (The
> example code has evolved over the years, and the original
> predated Linux by several years.)
>
> But that code does *not* implement a single universal solution.
> It merely demonstrates how to go about writing such solutions,
> and gives one example. But each and every program will have
> different requirements, and the code in the examples does *not*
> provide answers for all or even most of those program
> requirements.

What you mean by a universal solution?
To which problem?


Floyd L. Davidson

unread,
Aug 23, 2004, 6:27:59 AM8/23/04
to

The Open Group Base Specifications Issue 6, IEEE Std 1003.1,
2004 Edition, available online at

<http://www.unix.org/single_unix_specification/>

The POSIX man page for select() specifies that <sys/time.h> is
the appropriate header to include for select(). The Linux man
pages on my system (possibly years out of date) specify <unistd.h>.

The FIONREAD ioctl command is not POSIX. And it is true that in
the example code cited that is only used in the kbhit()
function, which in not part of the OP's requested functionality.
Indeed, kbhit() could be re-written using the same POSIX
functions that getch() uses, though obviously it would not be an
elegant solution.

However, even though FIONREAD is not essential to the OP's
request, it is 1) useful and closely related (which is why it is
bundled with the getch() example) and 2) FIONREAD is available
on not only Linux but all modern variations of unix.

Hence, the example is in fact *very* portable.

Hence, as I've said elsewhere, portability is not the problem.
The problem is that the example is not a general solution, but
rather one specific example which can be used as a model. It
does well for that purpose, but would not be appropriate as a
library function. The "problem" is there would need to be half
a dozen or more functions to fit all potential program needs.

Floyd L. Davidson

unread,
Aug 23, 2004, 6:34:06 AM8/23/04
to

It is not a universal solution to single character input for unix.

There are half a dozen or more variations necessary to fit
different minor requirements. Flush the input buffer first, or
not? Echo the character, or not? Block waiting for a
character, or not? Time input strings looking for escape
sequences, or not?

Those are just the obvious ones.

Villy Kruse

unread,
Aug 23, 2004, 8:52:55 AM8/23/04
to
On Mon, 23 Aug 2004 02:27:59 -0800,
Floyd L. Davidson <fl...@barrow.com> wrote:


>
> The Open Group Base Specifications Issue 6, IEEE Std 1003.1,
> 2004 Edition, available online at
>
> <http://www.unix.org/single_unix_specification/>
>
> The POSIX man page for select() specifies that <sys/time.h> is
> the appropriate header to include for select(). The Linux man
> pages on my system (possibly years out of date) specify <unistd.h>.
>


Or was it <sys/select.h>? I know it used to be <sys/time.h> but that
seems not to be a logical header for it, except that is where struct
timeval is defined.


|
| The Open Group Base Specifications Issue 6

| IEEE Std 1003.1, 2004 Edition
| Copyright © 2001-2004 The IEEE and The Open Group, All Rights
| reserved.
| _________________________________________________________________
|
| NAME
|
| pselect, select - synchronous I/O multiplexing
|
| SYNOPSIS
|
| #include <sys/select.h>
| int pselect(int nfds, fd_set *restrict readfds,
| fd_set *restrict writefds, fd_set *restrict errorfds,
| const struct timespec *restrict timeout,
| const sigset_t *restrict sigmask);
| int select(int nfds, fd_set *restrict readfds,
| fd_set *restrict writefds, fd_set *restrict errorfds,
| struct timeval *restrict timeout);
| void FD_CLR(int fd, fd_set *fdset);
| int FD_ISSET(int fd, fd_set *fdset);
| void FD_SET(int fd, fd_set *fdset);
| void FD_ZERO(fd_set *fdset);
|


Villy

Floyd L. Davidson

unread,
Aug 23, 2004, 10:19:52 AM8/23/04
to
Villy Kruse <v...@station02.ohout.pharmapartners.nl> wrote:
>On Mon, 23 Aug 2004 02:27:59 -0800,
> Floyd L. Davidson <fl...@barrow.com> wrote:
>
>>
>> The Open Group Base Specifications Issue 6, IEEE Std 1003.1,
>> 2004 Edition, available online at
>>
>> <http://www.unix.org/single_unix_specification/>
>>
>> The POSIX man page for select() specifies that <sys/time.h> is
>> the appropriate header to include for select(). The Linux man
>> pages on my system (possibly years out of date) specify <unistd.h>.
>>
>
>Or was it <sys/select.h>? I know it used to be <sys/time.h> but that
>seems not to be a logical header for it, except that is where struct
>timeval is defined.

You're right! The Single UNIX Specification, Version 2, lists
<sys/time.h>, but Version 3 lists <sys/select.h>.

>| The Open Group Base Specifications Issue 6
>| IEEE Std 1003.1, 2004 Edition
>| Copyright © 2001-2004 The IEEE and The Open Group, All Rights
>| reserved.
>| _________________________________________________________________
>|
>| NAME
>|
>| pselect, select - synchronous I/O multiplexing
>|
>| SYNOPSIS
>|
>| #include <sys/select.h>


The Single UNIX ® Specification, Version 2
Copyright © 1997 The Open Group

NAME

select - synchronous I/O multiplexing

SYNOPSIS

#include <sys/time.h>


I had in fact looked at both of them, and obviously misread the Version 3
man page based on what Version 2 was.

Floyd L. Davidson

unread,
Aug 23, 2004, 10:29:53 AM8/23/04
to
Villy Kruse <v...@station02.ohout.pharmapartners.nl> wrote:
>On Mon, 23 Aug 2004 02:27:59 -0800,
> Floyd L. Davidson <fl...@barrow.com> wrote:
>
>>
>> The Open Group Base Specifications Issue 6, IEEE Std 1003.1,
>> 2004 Edition, available online at
>>
>> <http://www.unix.org/single_unix_specification/>
>>
>> The POSIX man page for select() specifies that <sys/time.h> is
>> the appropriate header to include for select(). The Linux man
>> pages on my system (possibly years out of date) specify <unistd.h>.
>>
>
>Or was it <sys/select.h>? I know it used to be <sys/time.h> but that
>seems not to be a logical header for it, except that is where struct
>timeval is defined.

One additional note... <sys/time.h> includes <sys/select.h>, but not
the other way around. Or at least that is true with GNU/Linux headers.

Last2Know

unread,
Aug 23, 2004, 11:41:41 AM8/23/04
to

I don't really think that the original poster was asking
for a library that does mind reading of all his application
needs and design. Rather I think he was non-plussed to
discover that the intuitive functionality of interactive
character I/O in raw mode isn't available directly within
the nominally "close to the metal" C programming language.


Eric

unread,
Aug 23, 2004, 10:28:30 PM8/23/04
to
Last2Know wrote:

Yes, kinda. I find it odd that fgetc(stdin) in stdlib needs
a CR to read its input, I thought that was how fgets(stdin)
was supposed to work.

Grant Edwards

unread,
Aug 23, 2004, 10:47:53 PM8/23/04
to
On 2004-08-24, Eric <notV...@comcast.net> wrote:

>> I don't really think that the original poster was asking
>> for a library that does mind reading of all his application
>> needs and design. Rather I think he was non-plussed to
>> discover that the intuitive functionality of interactive
>> character I/O in raw mode isn't available directly within
>> the nominally "close to the metal" C programming language.
>
> Yes, kinda. I find it odd that fgetc(stdin) in stdlib needs
> a CR to read its input, I thought that was how fgets(stdin)
> was supposed to work.

I presume you have a lack of history working with serial
terminals. Canonical (line-buffered) mode vs. raw mode is a
very fundamental concept that goes way, way back in the Unix
tty world. Calling fgetc() instead of fgets() on stdin
wouldn't be expected to change the buffering mode of the
underlying tty device any more than it would be expected to
change the baud rate or parity.

--
Grant Edwards grante Yow! I appoint you
at ambassador to Fantasy
visi.com Island!!!

Last2Know

unread,
Aug 23, 2004, 10:58:33 PM8/23/04
to

You are right about fgetc and fgets but a little off in your
model of what stdin is.

You are not typing directly to stdin on your desktop.

The input stream is a logical abstraction comprised of
sequential chars. It's not a device. Consider the analogy
with a file read from disk. The underlying reality is very
different from the file abstraction at many, many levels
(there are multiple different heads reading simultaneously
from spinning magnetic media, various caches that buffer requests,
a filesystem breaking the sequence of the device into many
different nodes of different sizes, and connecting non-adjacent
nodes in a single "file sequence", etc. The portable C language
doesn't give you away to specifically read a single node from the
filesystem either, it only gives you access to the file abstraction.
By default, on Unix-like desktops, terminal devices start in
"cooked mode" where chars don't become part of the stdin abstract
sequence until the user hits enter. MS-DOS also followed the
older Unix tradition in this. In both cases, there are ways
to put the device underlying stdin into "raw" mode, but they
are not part of C which doesn't deal with devices. The
analogous command for FILE I/O, fsync(), is also not part of C.

0 new messages