{"id":4001,"date":"2020-02-29T00:01:53","date_gmt":"2020-02-29T08:01:53","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=4001"},"modified":"2020-02-22T09:20:10","modified_gmt":"2020-02-22T17:20:10","slug":"suppressing-a-terminals-character-echo","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=4001","title":{"rendered":"Suppressing a Terminal&#8217;s Character Echo"},"content":{"rendered":"<p>Back in the bad old days, you used a terminal connected to a mainframe to do your computer work. The terminal had a monitor and keyboard and just enough smarts to configure itself for communications with the mainframe. One of those configuration options was character echo.<br \/>\n<!--more--><br \/>\nOn today&#8217;s systems, the configuration options are set and forgotten, though they can still be programmed. The functions are available in the C library, defined in the <code>termios.h<\/code> header file. I must confess that <em>Termios<\/em> sounds like some Marvel supervillain, though it means Terminal I\/O System.<\/p>\n<p>The <em>man<\/em> page for <em>termios<\/em> goes on and on about communications, which may seem boring, but back in the day such details were vital in getting terminals connected to a central processing system. For purposes of programming the terminal with regards to character echo, a C coder deals with the <em>termios<\/em> structure, specifically its <em>c_lflag<\/em> member and the <code>ECHO<\/code> constant.<\/p>\n<p>To fill the <em>termios<\/em> structure with details about a terminal&#8217;s current configuration, use the <em>tcgetattr()<\/em> function. It has two arguments: the terminal&#8217;s file descriptor number and the address of a <em>termios<\/em> structure:<\/p>\n<p><code>int tcgetattr(int fildes, struct termios *termios_p);<\/code><\/p>\n<p>To set a terminal&#8217;s configuration, use the <em>tcsetattr()<\/em> function. It sports the same two arguments as <em>tcgetattr()<\/em>.<\/p>\n<p>The <code>fildes<\/code> (file descriptor) argument is an integer representing the terminal&#8217;s open device. Rather than probe for the device name and use the <em>open()<\/em> function, use the defined constant <code>STDIN_FILENO<\/code>, set to 0 by default. File descriptor zero always describes the current, standard input device. Because the <code>STDIN_FILENO<\/code> constant may not be defined, my sample code tests for it manually (see below).<\/p>\n<p>The integer return value is zero upon success, -1 otherwise with the <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=1735\"><code>errno<\/code><\/a> constant set appropriately.<\/p>\n<p>Once the current terminal&#8217;s details are obtained, the <em>termios<\/em> structure&#8217;s <em>c_lflag<\/em> member has its <code>ECHO<\/code> flag bit reset. When the bit is ON (set to 1), characters are echoed. Resetting it to zero turns off the echo. To reset this bit, I use the <code>ECHO<\/code> constant and bitwise XOR (exclusive OR) operator, <code>^<\/code>, as shown in the sample code:<\/p>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;termios.h&gt;\r\n\r\n#ifndef STDIN_FILENO\r\n#define STDIN_FILENO 0\r\n#endif <span class=\"comments\">\/* STDIN_FILENO *\/<\/span>\r\n\r\n#define SIZE 16\r\n\r\nint main()\r\n{\r\n    struct termios original,noecho;\r\n    char buffer[SIZE];\r\n    int x;\r\n\r\n    <span class=\"comments\">\/* obtain the current terminal configuration *\/<\/span>\r\n    tcgetattr(STDIN_FILENO,&amp;original);\r\n    <span class=\"comments\">\/* duplicate it *\/<\/span>\r\n    noecho = original;\r\n    <span class=\"comments\">\/* turn off full duplex *\/<\/span>\r\n    noecho.c_lflag = noecho.c_lflag ^ ECHO;\r\n    <span class=\"comments\">\/* set the terminal *\/<\/span>\r\n    tcsetattr(STDIN_FILENO, TCSANOW, &amp;noecho);\r\n\r\n    <span class=\"comments\">\/* prompt for and input the password *\/<\/span>\r\n    printf(\"Test: \");\r\n    fgets(buffer,SIZE,stdin);\r\n    <span class=\"comments\">\/* remove newline *\/<\/span>\r\n    for( x=0; x&lt;SIZE; x++)\r\n    {\r\n        if( buffer[x]=='\\n' )\r\n        {\r\n            buffer[x]='\\0';\r\n            break;\r\n        }\r\n    }\r\n    putchar('\\n');\r\n\r\n    <span class=\"comments\">\/* restore the terminal settings *\/<\/span>\r\n    tcsetattr(STDIN_FILENO, TCSANOW, &amp;original);\r\n    <span class=\"comments\">\/* output the result *\/<\/span>\r\n    printf(\"Your password is '%s'\\n\",buffer);\r\n\r\n    return(0);\r\n}<\/pre>\n<p>Line 17 uses the <em>tcgetattr()<\/em> function to read the current terminal configuration into the <code>original<\/code> structure. This structure is duplicated to the <code>noecho<\/code> structure at Line 19.<\/p>\n<p>At Line 21, the <code>ECHO<\/code> flag in the <code>noecho<\/code> structure&#8217;s <em>c_lflag<\/em> member is reset:<\/p>\n<p><code>noecho.c_lflag = noecho.c_lflag ^ ECHO;<\/code><\/p>\n<p>The <code>^<\/code> (XOR) operator flips only the <code>ECHO<\/code> bit, retaining the other configuration settings. This statement could also be shortened to:<\/p>\n<p><code>noecho.c_lflag ^= ECHO;<\/code><\/p>\n<p>At Line 23, the <em>tcsetattr()<\/em> function sets the new terminal configuration in structure variable <code>noecho<\/code>. From this point forward, local echo is suppressed on the current terminal. So when the <em>fgets()<\/em> function is called at Line 27, text output is suppressed.<\/p>\n<p>The <em>tcsetattr()<\/em> function at Line 40 re-establishes the original terminal configuration.<\/p>\n<p>Here&#8217;s a sample run:<\/p>\n<p><code>Password:<br \/>\nYour password is 'hello'<\/code><\/p>\n<p>This operation duplicates what the <em>getpass()<\/em> function accomplishes, which was the topic of <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3991\">last week&#8217;s Lesson<\/a>. Obviously, using <em>getpass()<\/em> is easier, but there&#8217;s something delightfully nerdy about terminal programming &mdash; especially when it&#8217;s no longer a tedium you must endure to get a terminal up and running.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can manually deactivate local echo in a Linxu\/Unix shell to create your own password input function. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=4001\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-4001","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4001","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4001"}],"version-history":[{"count":4,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4001\/revisions"}],"predecessor-version":[{"id":4017,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4001\/revisions\/4017"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}