Home > Software design >  Why does setting VMIN to 0 mess up the "DSR" ANSI escape sequence response to stdin?
Why does setting VMIN to 0 mess up the "DSR" ANSI escape sequence response to stdin?

Time:11-22

I was trying to implement this great response to my question about getting the terminal size with ANSI escape sequences. It didn't work, so I tried to see what the differences between the proposed code and mine were. I don't know if it is the main problem, but I followed the breadcrumbs to the one obvious differences (which I have also been able to replicate in a minimal example) - I use VMIN = 0, and the solution uses VMIN = 1.

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>

#define SIZE 100

int main ( void) {
    int ch = 0;
    int i = 0;
    struct termios original, changed;

    // change terminal settings
    tcgetattr( STDIN_FILENO, &original);
    changed = original;
    changed.c_lflag &= ~( ICANON | ECHO);
    changed.c_cc[VMIN] = 1;
    changed.c_cc[VTIME] = 0;
    tcsetattr( STDIN_FILENO, TCSANOW, &changed);

    printf ( "\033[9999;9999H");            // cursor should move as far as it can

    printf ( "\033[6n");                    // ask for cursor position
    printf ( "\033[2J");                    //clear screen
    printf ( "\033[1;1H");                  // move to upper left corner

    while ( ( ch = getchar ()) != 'R') {    // R terminates the response
        if ( EOF == ch)
            break;
        if ( isprint ( ch))                 // print out only normal chars to not mess up display
            printf("stdin[%d]\t==\t%d\t==\t%c\n", i, ch, ch);
        else
            printf("stdin[%d]\t==\t%d\t==\t\n", i, ch);
        i  ;
    }

    // restore terminal settings
    tcsetattr( STDIN_FILENO, TCSANOW, &original);

    return 0;
}

Here is a slightly shortened version of the proposed solution which showcases the problem. If you keep VMIN at 1, everything will work fine. However, if you set it to 0, you will lose the first part of ESC[rows;colsR, and it will only get printed out after the program finishes.

My actual code is too big and fragmented to post here, but what I am experiencing is a total freeze of the program if I set VMIN to 1 (I am read()-ing STDIN(1) in an infinite loop), and nothing happens when I run \033[6n (as if stdin is empty - I can get nothing out with getchar nor fread nor read)

If you have any info about this peculiarity, please share.

Thank you.

CodePudding user response:

Try a function that modifies the terminal settings, requests the cursor position, captures the position and restores the terminal settings.

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>

#define SIZE 100

void getscrnsize ( struct termios *set, int *row, int *col) {
    struct termios temp;
    temp = *set;
    temp.c_cc[VMIN] = 1;
    tcsetattr( STDIN_FILENO, TCSANOW, &temp); // use temp settings
    printf ( "\033[6n");                    // ask for cursor position
    scanf ( "\033[%d;%dR", row, col);
    tcsetattr( STDIN_FILENO, TCSANOW, set); // restore settings
}

int main ( void) {
    int row = 0;
    int col = 0;
    struct termios original, changed;

    // change terminal settings
    tcgetattr( STDIN_FILENO, &original);
    changed = original;
    changed.c_lflag &= ~( ICANON | ECHO);
    changed.c_cc[VMIN] = 0;
    changed.c_cc[VTIME] = 0;
    tcsetattr( STDIN_FILENO, TCSANOW, &changed);

    printf ( "\033[9999;9999H");            // cursor should move as far as it can

    getscrnsize ( &changed, &row, &col);

    printf ( "\033[2J");                    //clear screen
    printf ( "\033[1;1H");                  // move to upper left corner

    printf ( "rows %d\tcols %d\n", row, col);


    // restore terminal settings
    tcsetattr( STDIN_FILENO, TCSANOW, &original);

    return 0;
}

CodePudding user response:

ncurses is another option.
link with -lncurses
This uses the pipe character '|' to exit.

#include <stdio.h>
#include <ncurses.h>

int main ( void) {
    int ch = 0;
    int row = 0;
    int col = 0;

    initscr ( );
    halfdelay ( 2); // tenths of a second that getch waits for input
    noecho ( );
    getmaxyx ( stdscr, row, col);
    move ( 1, 1);
    printw ( "row %d\tcol %d\n", row, col);

    while ( ( ch = getch ( ))) {
        if ( ERR != ch) {
            printw ( "%c", ch);
            if ( '|' == ch) {
                break;
            }
        }
    }
    getyx ( stdscr, row, col);
    printw ( "\nrow %d \tcol %d", row, col);
    printw ( "\n\npress enter\n");
    while ( ( ch = getch ( ))) {
        if ( '\n' == ch) {
            break;
        }
    }
    endwin ( );
    return 0;
}
  •  Tags:  
  • c
  • Related