Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raw mode bugfix #1

Open
matthewfleming opened this issue Apr 6, 2017 · 3 comments
Open

Raw mode bugfix #1

matthewfleming opened this issue Apr 6, 2017 · 3 comments

Comments

@matthewfleming
Copy link

Hi!

Thanks for the tutorial! It's been handy refresher for my c skills.

Raw mode still blocks for me (Windows 10 / Bash on Ubuntu on Windows) because STDIN is set to block.

I was going to submit a pull request but then the steps.diff isn't really human editable. It's a 1 liner anyway!

~~~ step: vmin-vtime c2
diff --git a/kilo.c b/kilo.c
--- a/kilo.c
+++ b/kilo.c
@@ -19,6 +19,11 @@ void enableRawMode() {
   raw.c_oflag &= ~(OPOST);
   raw.c_cflag |= (CS8);
   raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+  raw.c_cc[VMIN] = 0;
+  raw.c_cc[VTIME] = 1;

   tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
+
+  // Ensure STDIN is in non-blocking mode
+  fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
 }
@paigeruten
Copy link
Contributor

Thanks, I was aware of this issue but didn't know how to fix it.

Setting O_NONBLOCK does get it to stop blocking, but for me read() still doesn't wait 0.1 seconds before timing out, it just returns 0 immediately. In the final version of the editor, this causes the arrow keys to not work, I guess because it's reading input faster than the terminal can send the arrow key escape sequence.

Unsetting FNDELAY using fcntl() as suggested here seems to make the arrow keys work, even though read() still seems to return pretty much immediately instead of waiting 0.1 seconds.

I'm going to have to look into this more to find the proper solution. Or maybe someone who knows this stuff better will come along and help out...

@matthewfleming
Copy link
Author

You're right! I didn't notice that it stopped blocking entirely!

It seems that FNDELAY and O_NONBLOCK are basically the same thing just different standards:
https://mail.python.org/pipermail/python-list/1999-May/013687.html

It's possible that VTIME just doesn't work in this environment? In any case I went with this so I can continue the tutorial:

#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

struct termios orig_termios;

void disableRawMode() {
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
}

void enableRawMode() {

    tcgetattr(STDIN_FILENO, &orig_termios);
    atexit(disableRawMode);

+   fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);

    struct termios raw = orig_termios;

    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    raw.c_oflag &= ~(OPOST);
    raw.c_cflag |= (CS8);
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);

    raw.c_cc[VMIN] = 0;
-   raw.c_cc[VTIME] = 1;
+   raw.c_cc[VTIME] = 0;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}

int main() {
    enableRawMode();
    while (1) {
        char c = '\0';
        read(STDIN_FILENO, &c, 1);
+       if(errno==EAGAIN) {
+           struct timespec ts = {0,100000000};
+           nanosleep(&ts, NULL);
+       }
        if (isprint(c)) {
            printf("%d ('%c')\r\n", c, c);
        } else {
            printf("%d\r\n", c);
        }
        if (c == 'q') {
            break;
        }
    }
    return 0;
}

@matthewfleming
Copy link
Author

Okay so I've continued along (I'm not bothering to sleep anymore - but this creates another problem at step 32 - we don't get the answer on STD_OUT immediately so we have to check for EAGAIN and continue without incrementing.

This doesn't create an infinite loop in practice because the answer (ending with R) does come eventually.

I'm not sure why the answer isn't immediately available - perhaps STDOUT isn't blocking now either? Maybe this explains some other problems that happen in O_NONBLOCK mode?

int getCursorPosition(int *rows, int *cols) {
    char buf[32];
    unsigned int i = 0;

    if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1;

    char c;
    while (i < sizeof(buf) - 1) {
-       if (read(STDIN_FILENO, &buf[i], 1) != 1) break;
+       if (read(STDIN_FILENO, &buf[i], 1) != 1) {
+           if (errno == EAGAIN) continue;
+           break;
+       }
        if (buf[i] == 'R') break;
        i++;
    }
    buf[i] = '\0';

    printf("\r\n&buf[1]: '%s'\r\n", &buf[1]);

    editorReadKey();

    return -1;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants