0

I am writing a program that changes the color of the characters based on their position in the terminal. I need to get the cursor position at least once in order to do this. I do not need the row, only the column is of interest.

I looked it up and I found the ANSI escape sequence ESC[6n which is supposed to return the current position of the cursor in stdin, in the following format: ESC[<row>;<col>R.

I wrote a small test program (largely inspired by this answer) through which I tried to isolate the behavior of this escape sequence, and it is able to get the row number correctly, but for some reason, the column is always 1.

Here's a piece of relevant C code:

#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>

int main() {
    // This will shift the cursor right a few places
    printf("some text");

    struct termios restore;
    tcgetattr(0, &restore);

    // Disable flags in order to read the response
    struct termios term;
    tcgetattr(0, &term);
    term.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(0, TCSANOW, &term);

    // Write ANSI escape sequence for cursor position
    write(1, "\033[6n", 4);

    // Read back response
    char buffer[16] = { 0 };
    int idx = 0;
    char ch;
    while (ch != 'R') {
        read(0, &ch, 1);
        buffer[idx] = ch;
        ++idx;
    }
    buffer[idx] = '\0';

    // Restore original settings
    tcsetattr(0, TCSANOW, &restore);

    // +1 because the first character is ESC
    puts(buffer + 1);

    return 0;
}

On my terminal (mintty), this code has the following output:

$ ./main
some text[3;1R

The row was, indeed, 3. However, the column should have been 10, not 1, because of the text it printed earlier. What is the reason for this behavior? Is there something wrong with my code, or could the problem be with the terminal? Alternatively, is there another standard/more correct way of getting the column of the cursor?

Thanks in advance.

CJames
  • 59
  • 2
  • 9
  • 1
    I would expect it's because the output of `printf()` is buffered. Try `fflush(stdout)` afterwards. – ssbssa Apr 22 '21 at 11:48
  • @ssbssa Yes, that actually fixed the problem. Thanks a lot! I suggest writing an answer so I can mark it as accepted. – CJames Apr 22 '21 at 12:31

1 Answers1

2

Replace printf("some text"); with write(1,"some text", 9); and you'll get the expected cursor position.

You make a wrong assertion about cursor position moved with clib printf, POSIX/ANSI C doesn't specify that this one should move the cursor.

Zilog80
  • 2,534
  • 2
  • 15
  • 20
  • Thank you, I didn't think about that. I was hoping there would be some way of getting the actual position. I guess I'll try to work around this. – CJames Apr 22 '21 at 11:46