readchar.cc


      //  readchar.cc
      
      /*  Sample code to read from the console a character at a time.
       *
       *    CS-701
       *    Spring 2003
       */
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <termios.h>
      #include <unistd.h>
      
      static struct termios saved, raw;
      
      //  restoreTTY()
      //  ------------------------------------------------------------------
      void 
      restoreTTY( void )
      {
        tcsetattr( STDIN_FILENO, 0, &saved );
        exit( 0 );
      }
        
      //  main()
      //  ------------------------------------------------------------------
      int
      main(int argc, char*argv[], char*envp[])
      {
      
        //  Make sure it makes sense to process input a char at a time.
        const char  notATTY[] = "Stdin is not a terminal\n";
        if ( 0 == isatty( 0 ) )
        {
          write( 1, notATTY, strlen( notATTY ) );
          exit( 1 );
        }
      
        //  Save original tty state, and set up to restore it at exit.
        if ( -1 == tcgetattr( STDIN_FILENO, &saved ) )
        {
          perror( "Unable to save tty attributes" );
          exit( 1 );
        }
        if ( -1 == atexit( restoreTTY ) )
        {
          perror( "Unable to intercept exit calls" );
          exit( 1 );
        }
      
        //  Put tty into raw mode
        raw               = saved;
        raw.c_lflag      &= ~ICANON & ~ECHO;
        raw.c_cc[ VMIN ]  = 1;
        raw.c_cc[ VTIME ] = 0;
      
        tcsetattr( STDIN_FILENO, 0, &raw );
        const char  prompt[]  = "jsh> ";
        const char  crlf[]    = "\r\n";
        char        aChar;
        char        inBuf[ 10 ];
        bool        endline = false;
      
        for ( ;; )
        {
          endline = false;
          memset( inBuf, '\0', sizeof( inBuf ) );
          write( STDOUT_FILENO, prompt, strlen( prompt) );
          for (unsigned int i = 0; i < (sizeof( inBuf ) - 2); i++ )
          {
            int numRead = read( STDIN_FILENO, &aChar, 1 );
            if ( numRead < 1 )
            {
              perror( "\n\rError Reading" );
              exit( 1 );
            }
      
            //  Examples of things you can do in raw mode.
            switch (aChar )
            {
              case '\x004':
                // Control-D
                write( STDOUT_FILENO, "^D", 2 );
                if ( 0 == i )
                {
                  //  EOF
                  write( STDOUT_FILENO, crlf, sizeof( crlf ) );
                  exit( 0 );
                }
                endline = true;
                break;
      
              case '\n':
                //  Newline
                write( STDOUT_FILENO, "^J", 2 );
                endline = true;
                break;
      
              default:
                inBuf[i] = aChar;
            }
            if ( endline )
            {
              break;
            }
            write( STDOUT_FILENO, &aChar, 1 );
          }
          printf( "\nYou typed \"%s\"\n", inBuf );
        }
      }