Snippet POSIX STDIN mode

From C

Jump to: navigation, search

PoppaVic provided these two functions and a test, for switching between tty input modes, along with the following statement "Be advised: 'very' raw tends to require you run 'reset' on your terminal". (Note: MacOSX did not have this issue, and there is a new #ifndef that helps even there)

pfv_stdin_raw.h:

/* pfv_stdin_raw.h
 *      Set stdin to raw, (two types), or back to cooked.
 * (c) 2002 PoppaVic #c @freenode.net
 *
 * This snippet is PD - don't blame me if it melts your system.
 */
#ifndef PFV_STDIN_RAW_H_
#define PFV_STDIN_RAW_H_

#ifdef __cplusplus
extern "C" {
#endif

extern int pfv_stdin_raw(int very);     /* zero or non-zero */
extern int pfv_stdin_cooked(void);


#ifdef __cplusplus
}
#endif

#endif /* PFV_STDIN_RAW_H_ */

pfv_stdin_raw.c:

/* pfv_stdin_raw.c
 *      Set stdin to raw, (two types), or back to cooked.
 * (c) 2002 PoppaVic #c @freenode.net
 *
 * This snippet is PD - don't blame me if it melts your system.
 *
 * Compiling a test:
 *      gcc -DTEST_STDIN_RAW -o test pfv_stdin_raw.c
 *      ./test
 */
#include <stdio.h>      /* perror() */
#include <errno.h>      /* errno */
#include <unistd.h>     /* these two: tcgetattr & friends */
#include <termios.h>
#include "pfv_stdin_raw.h"

static  char            loaded=0;
static  struct termios  t;

int pfv_stdin_raw(int very)
{ struct termios  now;

    if(!loaded)
    {
        if( tcgetattr(STDIN_FILENO, &t)<0 )
        {
            perror("tcgetattr");
            return -1;
        }
        else
            loaded=1;
    }
    memcpy(&now, &t, sizeof(struct termios) );

    if(very)
    {
        /* The below is supposed to be equiv. to cfmakeraw( &now ); */
        now.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
        /* NOTE:
          *      Following is equiv, but commenting it OUT tests-out
          *      a whole lot more neatly!
          */
    #ifndef TEST_STDIN_RAW
         now.c_oflag &= ~OPOST;
    #endif 
        now.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
        now.c_cflag &= ~(CSIZE|PARENB);
        now.c_cflag |= CS8;
        if( tcsetattr(STDIN_FILENO, TCSANOW, &now)<0 )
        {
            perror("tcsetattr");
            return -1;
        }
    }
    else
    {
        now.c_lflag &= ~ICANON;
        if( tcsetattr(STDIN_FILENO, TCSANOW, &now)<0 )
        {
            perror("tcsetattr");
            return -1;
        }
        /*setbuf(stdin, NULL);*/
    }
    return 0;
}

int pfv_stdin_cooked(void)
{
    if(!loaded)
    {
        errno=EPERM;
        perror("already cooked");
        return -1;
    }
    if( tcsetattr(STDIN_FILENO, TCSANOW, &t)<0 )
    {
        perror("tcsetattr");
        return -1;
    }
    return 0;
}


#ifdef TEST_STDIN_RAW
#include <sys/poll.h>   /* poll() */
#include <string.h>     /* strerror() */
int main(int argc, char **argv)
{ char foo;
  int cc;
  struct pollfd incoming[1];
  int ret, ret2;

    incoming[0].fd= fileno(stdin);
    incoming[0].events= POLLIN;

    printf("Testing pfv_stdin_raw(%d): start typing!\n", argc>1);
    pfv_stdin_raw(argc>1);
    cc=0;

    do
    {
        foo=EOF;
        /* Human/console timespans: 2 seconds */
         ret = poll(incoming, 1, 2000);
        switch( ret )
        {
               case -1:    /* Got an error/eof... */
                                fprintf(stderr, "%d=poll re=%04x(%d: %s)\n",
                                    ret, incoming[0].revents, errno,
                                    strerror(errno));
                                    break;
                case  1:    /* Got readable activity... */
                                if (read(fileno(stdin), &foo, 1) == 1)
                                {
                                    /* Kernel/Kbd timespans: 2 millisec */
                                    ret2= poll(incoming, 1, 2);

                                    fprintf(stderr, "\t(x%02x;'%c')",
                                        foo, (foo < 32 ? '.' : foo) );
                                    fprintf(stderr, "%s",
                                        ret2==1 ? "" : "\n" );
                                    cc++;
                                }
                                break;
                default:    /* Zero is 'timeout' */
                                break;
                }
    } while(foo!=EOF && foo!=0x04);
    pfv_stdin_cooked();
}
#endif

Category Snippets

Personal tools