6

I've been Googling around with no luck. I'm looking for a way to do getc() or gets() or whatever that does not echo to the terminal. I saw kbhit() but this doesn't appear to be part of ANSI. Ideally, I'd like code that looks like

char s[100];
no_echo_gets(s); /* Won't echo to screen while being typed */
printf("%s\n", s);

Does anybody know a good ANSI compliant way to do this?

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Scott
  • 10,407
  • 13
  • 37
  • 35

8 Answers8

12

For UNIX-like systems you want to play with the ECHO flag...

#include <termios.h>
...
struct termios t;
tcgetattr(fd, &t);
t.c_lflag &= ~ECHO;
tcsetattr(fd, TCSANOW, &t);
...
luqui
  • 59,485
  • 12
  • 145
  • 204
dwc
  • 24,196
  • 7
  • 44
  • 55
5

The getpass command is present in Linux. But you can make a prettier version, the system echo alone doesn't kill the need for an enter command, while knocking down buffering doesn't kill the production of a carraige return after data entry. Combining the two gives a good approximation of a quiet entry. You can add an asterisk to give a secret entry appearance so here is a combination of two suggestions:

    #include <stdio.h>
    #include <termios.h>
    #include <unistd.h>
    int getche(void);
    int main(int argc, char **argv){
    int i=0;       
    char d,c='h',s[6];
    printf("Enter five secret letters\n");
    s[5]='\0'; //Set string terminator for string five letters long
    do{
      d=getche();//Fake getche command silently digests each character
    printf("*");
      s[i++]=d;} while (i<5);
    printf("\nThank you!!\n Now enter one more letter.\n");
    c=getchar();
    printf("You just typed %c,\nbut the last letter of your secret string was %c\n",c,d);   
    printf("Your secret string was: %s\n",s);   
        return 0;
    }
    /* reads from keypress, echoes */
        int getche(void)
        {
            struct termios oldattr, newattr;
            int ch;
            tcgetattr( STDIN_FILENO, &oldattr );
            newattr = oldattr;
            newattr.c_lflag &= ~( ICANON | ECHO);\\knock down keybuffer
            tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
            system("stty -echo");\\shell out to kill echo
            ch = getchar();
            system("stty echo");
            tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
            return ch;
        }
4

Maybe you can try like this:

#include<stdio.h>
char s[100];
system("stty -echo");
scanf("%s",s); /* Won't echo to screen while being typed */
system("stty echo");
printf("You have entered:");
printf("%s\n", s);
return 0;
}

In Linux, the system function "stty -echo" is to type in sth without echo. Hope this will help.

rjzii
  • 14,236
  • 12
  • 79
  • 119
Luis
  • 77
  • 1
  • 10
3

You can't do it in a cross-platform manner using ANSI C. You'll have to use some OS-specific code, or use a library such as ncurses.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

Since your task is fairly basic, if you're lucky your system will have the getpass() function:

char * getpass(const char *prompt);

If you don't want a prompt, just do:

char *s = getpass("");
if (s != NULL)
    printf("Your password was %s!\n", s);

getpass(), like all C functions related to echo and buffering, is non-standard, but present on Mac OS X, probably Linux, and is listed in the GNU C library, so it's probably present on any system using glibc.

The ANSI and ISO standards, as stated previously, do not specify a standard way to read input without echoing, or to read unbuffered input (i.e. on character at a time).

Kijewski
  • 25,517
  • 12
  • 101
  • 143
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • On Mac OS X 10.7.5, getpass() returns an invalid pointer which will crash the program if you try to use it. – Michael Feb 01 '13 at 17:42
  • @Michael - I'm still on Snow Leopard myself, but at the time I wrote that regular old Leopard was the most recent OS X. Weird how things change... – Chris Lutz Feb 03 '13 at 03:32
  • Not sure why, but the problem is that the compiler is generating 64-bit code, but is linking a 32-bit version of getpass(). Since getpass() is part of libc, I'm at a loss as to why this is happening. (compiling as 32-bit fixes the problem) – Michael Feb 03 '13 at 15:32
0

There isn't one; neither ANSI C nor ISO C++ have such a thing.

0

This will depend on your environment, it is not something that the language provides. If you intend to do extensive character mode I/O, you might look into a library like curses. Otherwise, you will have to manipulate the terminal or the windows console manually.

Jonathan Adelson
  • 3,275
  • 5
  • 29
  • 39
-2

ANSI and ISO C do not define this functionality, however most C compilers have getch() or a close variation.

You'll need to do a preprocessor define for each compiler you're using that has a different library and function for this. It's not difficult, though you might consider it annoying.

-Adam

Adam Davis
  • 91,931
  • 60
  • 264
  • 330
  • Does getch() prevent the terminal echoing the character? I thought it was only useful for grabbing control keys as well as regular chars. – Martin Beckett Feb 17 '09 at 18:23
  • The C compiler doesn't have getch(), that's part of the curses library. And getch() doesn't necessarily echo, but you have to use the other curses library functions to turn off echoing. Otherwise, it will echo by default. – Chris Lutz Feb 17 '09 at 18:32
  • getch() is also part of conio.h in windows and it does not echo by default. – Carson Myers May 17 '09 at 18:29