Solved

_getch kbhit in linux

Posted on 2003-11-12
17
3,424 Views
Last Modified: 2012-06-27
i'm trying to make a little software in linux, which ask for password.

i want that each single character that pressed to output '*'.

0
Comment
Question by:yahelb
  • 6
  • 4
  • 4
  • +1
17 Comments
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9729448
getpass()
0
 
LVL 45

Assisted Solution

by:sunnycoder
sunnycoder earned 20 total points
ID: 9729514
altrnatively, you can use curses library
noecho();

next in a loop, do  a
getch();
putc(); //put *
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9729525
0
 
LVL 1

Author Comment

by:yahelb
ID: 9729811
Hi  sunnycoder:
1. getpass block the echo output &&  qoute: "This function is obsolete. Do not use it.".
2. there is nothing good for me in that link _getch is not ansi function.

3. i'm trying to avoid the curses library, but if there is no ather solution...

        maybe i should ask that diffrently.

i want to react for each single character that have been pressed.
you should not think about that as a password attempts (i just thout this would help).

0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9729940
Given your constraints I cannot think of anything but curses... the way I listed in my second post
0
 
LVL 45

Assisted Solution

by:Kdo
Kdo earned 20 total points
ID: 9731880

Hi yahelb,

If you're going to capture and record input yourself, there's some other housekeeping that you should probably do:


cbreak();  /*  disable control break  */
noecho();  /*  disable character echo  */

while (1)  /*  Loop on input, exit when CR pressed, reset input and screen buffer when ESC pressed?  */
{
}

echo ();
nocbreak ();



Kent
0
 
LVL 5

Accepted Solution

by:
g0rath earned 85 total points
ID: 9732289
Here is a way to do this without using curses...

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/termios.h>


// Local prototypes
int suppress_echo( void );
int make_echo( void );
char *tty_path( void );
static struct termios default_stty, stty;

int main( void )
{
        char buf[128];
        int i=0;
        char ch;

        memset(&buf,0,128);

        suppress_echo();

        printf("Enter you password: ");
        while ((ch = getchar()) != '\n')
        {
                if (i > 127)
                        break;
                else
                        buf[i++] = ch;
        }

        fflush(stdin);
        fflush(stdout);

        make_echo();

        printf("\n\nbuf = %s\n", buf);
        return 0;
}

int suppress_echo( void )
{
        int fd;
        fd = open(tty_path(), O_RDWR);
        if (fd < 0)
                return -1;

        if (ioctl(fd, TCGETS, &default_stty) < 0)
                return -2;

        bcopy(&default_stty, &stty, sizeof(struct termios));

        stty.c_lflag &= ~(ECHO | CLOCAL);  // suppress echo

        if (ioctl(fd, TCSETS, &stty) < 0)
                return -3;

        close(fd);
        return 0;
}

int make_echo( void )
{
        int fd;

        fd = open(tty_path(), O_RDWR);
        if (fd < 0)
                return -1;

        // just return to our previous tty state
        if (ioctl(fd, TCSETS, &default_stty) < 0)
                return -2;

        close(fd);
        return 0;
}

This just toggles the echo bit for your current tty

char *tty_path( void )
{
        static char buf[128];
        memset(&buf,0,128);

        if (readlink("/proc/self/fd/0", buf,128) == -1)
                return NULL;

        return buf;
}
0
 
LVL 1

Author Comment

by:yahelb
ID: 9739058
explain:
this answers is not solve my problem i'm moving on to look how to do that the curses way.

so i gave points to you all.

g0rath was the closest to what i looking for, but the problem is that getchar only breaks on '\n'.


thanks/
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 45

Expert Comment

by:Kdo
ID: 9739145

You can break on any character that you want by changing these lines in main():

        while ((ch = getchar()) != '\n')
        {
                if (i > 127)
                        break;
                else
                        buf[i++] = ch;
        }

to:

while (1)
{
  ch == getchar();
  /*
      break on Carriage Return, Line Feed, ESC, or '*'.
      '*' is simply to demonstrate that you can break on any character(s) that you choose
  */
  if (ch == '\n' || ch == '\r' || ch == 27 || ch == '*' || ch > 127)
    break;
  buf[i++] = ch;
}


Kent
0
 
LVL 5

Expert Comment

by:g0rath
ID: 9739184
the getchar() is setup so that you can use any char, I gave code as example, you can modify it to whatever you need...the real meat of the issue was turning off the echo at the tty...everything else is up to you
0
 
LVL 5

Expert Comment

by:g0rath
ID: 9739275
well your line
ch == getchar();
should be
ch = getchar();

and your the last arg of your if()

ch > 127
should be
i > 127

there is only 128 bytes in that buffer, and with you logic you could have a buffer over run
it's > 127 since it's zero based counting.
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9739352

Sorry g0rath,

I was trying to point out to the original poster that your solution could, in fact, break on any character the he chose.

It's certainly not the first time that my head and fingers were going in opposite directions.  ;)'


Kent
0
 
LVL 5

Expert Comment

by:g0rath
ID: 9739404
oh no problem, it just appeard that the poster was just cut and pasting code rather then attempting to modify.... :)
0
 
LVL 1

Author Comment

by:yahelb
ID: 9740636
maybe i just dont undestand you.

here is a source code.

#include <stdio.h>

int main(){

        char ch;

        puts("enter somthing: ");
        ch = getchar();

        printf("char is: %c", ch);
        return 0;
}

now what i am saying is that getchar() wont return until the user will press <enter>.

Kent: i pasted your code. it acts really wierd infinit loop.
         did you tested it ?


g0rath: i took your code and replaced the char '\n' with 'a' and it just dont work for me.
           its not stops at 'a'.
           it always stops at '\n'.

did you tested it ?


if you 2 tested the code and it works for you what can cause it not to work here ?


0
 
LVL 5

Expert Comment

by:g0rath
ID: 9741308
first all of this I/O is buffered and these functions work on NEWLINES, so it blocks until the char '\n' is sent, then the whole block is sent through this section, and it'll repeat until the buffer has been emptied.

You said this was for a password box, so on enter is usually what happens...if you want it to stop on the 'a' then you must go to unbuffered I/O...

So that getch never blocks and it aways goes throught he check.

If you want this, then the whole newline buffering doesn't work since the terminal is in raw mode rather then normal...then your at the mercy of the emulator your working with, etc....

basically at this point you're rewriting curses and should have been using it in the first place.

if you want to go down this route, you'll have to do this:

struct termios orig_term;
struct termios raw_term;

if (tcgetattr(0, &orig_term) != 0) return 1; //save terminal settings
if (tcsetattr(0, TCSANOW, &raw_term) != 0) return 1; //set to raw
fcntl(0, F_SETFL, O_NONBLOCK);

// do the old while loop
while (1)
{
        ch = getc(stdin);
        // in unbuffered mode 255 gets sent, and for sanity
        // 3 is equal to CTRL-C
        if (ch == 255 || ch == 3)
                continue;
        // maybe you'll recognize CR and LF, which my terminal
        // doesn't map correctly in raw mode
        if (ch == 'a' || ch == 13 || ch == 10)
                break;
        printf("(%c) (%d) (0x%x)\n", ch, ch, ch);
        if (!isalpha(ch))
                continue;
        if (i > 127)
                break;
        else
                buf[i++] = ch;
}

if (tcsetattr(0, TCSANOW, &orig_term) != 0) return 1; //restore

Now this will work as unbuffered I/O, but Enter no longer maps in my terminal, only CTRL-ENTER....

None of the answers here are 'C' Grade level since they are all far above the simple "Just use curses answer"
0
 
LVL 5

Expert Comment

by:g0rath
ID: 9741323
all of my code works and was tested except the Raw Terminal I/O code
0
 
LVL 1

Author Comment

by:yahelb
ID: 9741777
1. thanks you g0raph and Kent.
2. i will use the curses way. i just thout ANSI have a function that do that(apperenly not).
3. g0raph: when i gave you 'C' grade i did that cause none of the answers was helpful for me (in fact but the curses way nothing was new! ).
which means: "Avarage".

now i do think you and kent should get more then 'C' grade or more points.
Can I do that ?

thanks again
yahel.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now